| // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "debugd/src/packet_capture_tool.h" |
| |
| #include <base/strings/string_util.h> |
| |
| #include "debugd/src/error_utils.h" |
| #include "debugd/src/process_with_id.h" |
| #include "debugd/src/variant_utils.h" |
| |
| namespace { |
| |
| const char kPacketCaptureToolErrorString[] = |
| "org.chromium.debugd.error.PacketCapture"; |
| |
| bool ValidateInterfaceName(const std::string& name) { |
| for (char c : name) { |
| // These are the only plausible interface name characters. |
| if (!base::IsAsciiAlpha(c) && |
| !base::IsAsciiDigit(c) && c != '-' && c != '_') |
| return false; |
| } |
| return true; |
| } |
| |
| bool AddValidatedStringOption(debugd::ProcessWithId* p, |
| const brillo::VariantDictionary& options, |
| const std::string& dbus_option, |
| const std::string& command_line_option, |
| brillo::ErrorPtr* error) { |
| std::string name; |
| switch (debugd::GetOption(options, dbus_option, &name, error)) { |
| case debugd::ParseResult::NOT_PRESENT: |
| return true; |
| case debugd::ParseResult::PARSE_ERROR: |
| return false; |
| case debugd::ParseResult::PARSED: |
| break; |
| } |
| |
| if (!ValidateInterfaceName(name)) { |
| DEBUGD_ADD_ERROR_FMT(error, |
| kPacketCaptureToolErrorString, |
| "\"%s\" is not a valid interface name", |
| name.c_str()); |
| return false; |
| } |
| |
| p->AddStringOption(command_line_option, name); |
| return true; |
| } |
| |
| } // namespace |
| |
| namespace debugd { |
| |
| bool PacketCaptureTool::Start( |
| const base::ScopedFD& status_fd, |
| const base::ScopedFD& output_fd, |
| const brillo::VariantDictionary& options, |
| std::string* out_id, |
| brillo::ErrorPtr* error) { |
| std::string exec_path; |
| if (!SandboxedProcess::GetHelperPath("capture_utility.sh", &exec_path)) { |
| DEBUGD_ADD_ERROR( |
| error, kPacketCaptureToolErrorString, "Helper path is too long"); |
| return false; |
| } |
| |
| ProcessWithId* p = |
| CreateProcess(false /* sandboxed */, false /* access_root_mount_ns */); |
| if (!p) { |
| DEBUGD_ADD_ERROR(error, |
| kPacketCaptureToolErrorString, |
| "Failed to create helper process"); |
| return false; |
| } |
| p->AddArg(exec_path); |
| if (!AddValidatedStringOption(p, options, "device", "--device", error)) |
| return false; |
| if (!AddIntOption(p, options, "frequency", "--frequency", error)) |
| return false; |
| if (!AddValidatedStringOption( |
| p, options, "ht_location", "--ht-location", error)) |
| return false; |
| if (!AddValidatedStringOption( |
| p, options, "monitor_connection_on", "--monitor-connection-on", error)) |
| return false; |
| |
| // Pass the output fd of the pcap as a command line option to the child |
| // process. |
| int child_output_fd = STDERR_FILENO + 1; |
| p->AddStringOption("--output-file", |
| base::StringPrintf("/dev/fd/%d", child_output_fd)); |
| p->BindFd(output_fd.get(), child_output_fd); |
| |
| p->BindFd(status_fd.get(), STDOUT_FILENO); |
| p->BindFd(status_fd.get(), STDERR_FILENO); |
| LOG(INFO) << "packet_capture: running process id: " << p->id(); |
| p->Start(); |
| *out_id = p->id(); |
| return true; |
| } |
| |
| } // namespace debugd |