blob: ececf1b3861dec3aa941698661f79b73a9603a0c [file] [log] [blame] [edit]
// Copyright 2016 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "patchpanel/dbus/client.h"
#include <fcntl.h>
#include <string.h>
#include <algorithm>
#include <optional>
#include <base/functional/bind.h>
#include <base/logging.h>
#include <base/memory/weak_ptr.h>
#include <base/strings/string_util.h>
#include <brillo/dbus/dbus_proxy_util.h>
#include <chromeos/dbus/service_constants.h>
#include <dbus/message.h>
#include <dbus/object_path.h>
#include <patchpanel/proto_bindings/patchpanel_service.pb.h>
#include "patchpanel/net_util.h"
namespace patchpanel {
namespace {
void CopyBytes(const std::string& from, std::vector<uint8_t>* to) {
to->assign(from.begin(), from.end());
}
patchpanel::TrafficCounter::Source ConvertTrafficSource(
Client::TrafficSource source) {
switch (source) {
case Client::TrafficSource::kUnknown:
return patchpanel::TrafficCounter::UNKNOWN;
case Client::TrafficSource::kChrome:
return patchpanel::TrafficCounter::CHROME;
case Client::TrafficSource::kUser:
return patchpanel::TrafficCounter::USER;
case Client::TrafficSource::kArc:
return patchpanel::TrafficCounter::ARC;
case Client::TrafficSource::kCrosVm:
return patchpanel::TrafficCounter::CROSVM;
case Client::TrafficSource::kPluginVm:
return patchpanel::TrafficCounter::PLUGINVM;
case Client::TrafficSource::kUpdateEngine:
return patchpanel::TrafficCounter::UPDATE_ENGINE;
case Client::TrafficSource::kVpn:
return patchpanel::TrafficCounter::VPN;
case Client::TrafficSource::kSystem:
return patchpanel::TrafficCounter::SYSTEM;
}
}
Client::TrafficSource ConvertTrafficSource(
patchpanel::TrafficCounter::Source source) {
switch (source) {
case patchpanel::TrafficCounter::CHROME:
return Client::TrafficSource::kChrome;
case patchpanel::TrafficCounter::USER:
return Client::TrafficSource::kUser;
case patchpanel::TrafficCounter::ARC:
return Client::TrafficSource::kArc;
case patchpanel::TrafficCounter::CROSVM:
return Client::TrafficSource::kCrosVm;
case patchpanel::TrafficCounter::PLUGINVM:
return Client::TrafficSource::kPluginVm;
case patchpanel::TrafficCounter::UPDATE_ENGINE:
return Client::TrafficSource::kUpdateEngine;
case patchpanel::TrafficCounter::VPN:
return Client::TrafficSource::kVpn;
case patchpanel::TrafficCounter::SYSTEM:
return Client::TrafficSource::kSystem;
default:
return Client::TrafficSource::kUnknown;
}
}
patchpanel::NeighborReachabilityEventSignal::Role ConvertNeighborRole(
Client::NeighborRole role) {
switch (role) {
case Client::NeighborRole::kGateway:
return patchpanel::NeighborReachabilityEventSignal::GATEWAY;
case Client::NeighborRole::kDnsServer:
return patchpanel::NeighborReachabilityEventSignal::DNS_SERVER;
case Client::NeighborRole::kGatewayAndDnsServer:
return patchpanel::NeighborReachabilityEventSignal::
GATEWAY_AND_DNS_SERVER;
}
}
patchpanel::NeighborReachabilityEventSignal::EventType ConvertNeighborStatus(
Client::NeighborStatus status) {
switch (status) {
case Client::NeighborStatus::kFailed:
return patchpanel::NeighborReachabilityEventSignal::FAILED;
case Client::NeighborStatus::kReachable:
return patchpanel::NeighborReachabilityEventSignal::REACHABLE;
}
}
patchpanel::ModifyPortRuleRequest::Operation ConvertFirewallRequestOperation(
Client::FirewallRequestOperation op) {
switch (op) {
case Client::FirewallRequestOperation::kCreate:
return ModifyPortRuleRequest::CREATE;
case Client::FirewallRequestOperation::kDelete:
return ModifyPortRuleRequest::DELETE;
}
}
patchpanel::ModifyPortRuleRequest::RuleType ConvertFirewallRequestType(
Client::FirewallRequestType type) {
switch (type) {
case Client::FirewallRequestType::kAccess:
return ModifyPortRuleRequest::ACCESS;
case Client::FirewallRequestType::kLockdown:
return ModifyPortRuleRequest::LOCKDOWN;
case Client::FirewallRequestType::kForwarding:
return ModifyPortRuleRequest::FORWARDING;
}
}
patchpanel::ModifyPortRuleRequest::Protocol ConvertFirewallRequestProtocol(
Client::FirewallRequestProtocol protocol) {
switch (protocol) {
case Client::FirewallRequestProtocol::kTcp:
return ModifyPortRuleRequest::TCP;
case Client::FirewallRequestProtocol::kUdp:
return ModifyPortRuleRequest::UDP;
}
}
patchpanel::SetDnsRedirectionRuleRequest::RuleType
ConvertDnsRedirectionRequestType(Client::DnsRedirectionRequestType type) {
switch (type) {
case Client::DnsRedirectionRequestType::kDefault:
return patchpanel::SetDnsRedirectionRuleRequest::DEFAULT;
case Client::DnsRedirectionRequestType::kArc:
return patchpanel::SetDnsRedirectionRuleRequest::ARC;
case Client::DnsRedirectionRequestType::kUser:
return patchpanel::SetDnsRedirectionRuleRequest::USER;
case Client::DnsRedirectionRequestType::kExcludeDestination:
return patchpanel::SetDnsRedirectionRuleRequest::EXCLUDE_DESTINATION;
}
}
std::vector<uint8_t> ConvertIPv4Addr(uint32_t in) {
std::vector<uint8_t> out;
out.resize(4);
memcpy(out.data(), &in, sizeof(in));
return out;
}
Client::IPv4Subnet ConvertIPv4Subnet(const IPv4Subnet& in) {
Client::IPv4Subnet out = {};
out.base_addr.assign(in.addr().begin(), in.addr().begin());
CopyBytes(in.addr(), &out.base_addr);
out.prefix_len = static_cast<int>(in.prefix_len());
return out;
}
std::optional<Client::TrafficCounter> ConvertTrafficCounter(
const TrafficCounter& in) {
auto out = std::make_optional<Client::TrafficCounter>();
out->rx_bytes = in.rx_bytes();
out->tx_bytes = in.tx_bytes();
out->rx_packets = in.rx_packets();
out->tx_packets = in.tx_packets();
out->ifname = in.device();
out->source = ConvertTrafficSource(in.source());
switch (in.ip_family()) {
case patchpanel::TrafficCounter::IPV4:
out->ip_family = Client::IPFamily::kIPv4;
break;
case patchpanel::TrafficCounter::IPV6:
out->ip_family = Client::IPFamily::kIPv6;
break;
default:
LOG(ERROR) << __func__ << ": Unknown IpFamily "
<< patchpanel::TrafficCounter::IpFamily_Name(in.ip_family());
return std::nullopt;
}
return out;
}
std::optional<Client::VirtualDevice> ConvertVirtualDevice(
const NetworkDevice& in) {
auto out = std::make_optional<Client::VirtualDevice>();
out->ifname = in.ifname();
out->phys_ifname = in.phys_ifname();
out->guest_ifname = in.guest_ifname();
out->ipv4_addr = ConvertIPv4Addr(in.ipv4_addr());
out->host_ipv4_addr = ConvertIPv4Addr(in.host_ipv4_addr());
out->ipv4_subnet = ConvertIPv4Subnet(in.ipv4_subnet());
CopyBytes(in.dns_proxy_ipv4_addr(), &out->dns_proxy_ipv4_addr);
CopyBytes(in.dns_proxy_ipv6_addr(), &out->dns_proxy_ipv6_addr);
switch (in.guest_type()) {
case patchpanel::NetworkDevice::ARC:
out->guest_type = Client::GuestType::kArcContainer;
break;
case patchpanel::NetworkDevice::ARCVM:
out->guest_type = Client::GuestType::kArcVm;
break;
case patchpanel::NetworkDevice::TERMINA_VM:
out->guest_type = Client::GuestType::kTerminaVm;
break;
case patchpanel::NetworkDevice::PLUGIN_VM:
out->guest_type = Client::GuestType::kPluginVm;
break;
default:
LOG(ERROR) << __func__ << ": Unknown GuestType "
<< patchpanel::NetworkDevice::GuestType_Name(in.guest_type());
return std::nullopt;
}
return out;
}
Client::NetworkClientInfo ConvertNetworkClientInfo(
const NetworkClientInfo& in) {
Client::NetworkClientInfo out;
std::copy(in.mac_addr().begin(), in.mac_addr().end(),
std::back_inserter(out.mac_addr));
std::copy(in.ipv4_addr().begin(), in.ipv4_addr().end(),
std::back_inserter(out.ipv4_addr));
for (const auto& ipv6_addr : in.ipv6_addresses()) {
out.ipv6_addresses.emplace_back(ipv6_addr.begin(), ipv6_addr.end());
}
out.hostname = in.hostname();
out.vendor_class = in.vendor_class();
return out;
}
Client::DownstreamNetwork ConvertDownstreamNetwork(
const DownstreamNetwork& in) {
Client::DownstreamNetwork out;
out.ifname = in.downstream_ifname();
out.ipv4_subnet = ConvertIPv4Subnet(in.ipv4_subnet());
CopyBytes(in.ipv4_gateway_addr(), &out.ipv4_gateway_addr);
return out;
}
std::optional<Client::NeighborReachabilityEvent>
ConvertNeighborReachabilityEvent(const NeighborReachabilityEventSignal& in) {
auto out = std::make_optional<Client::NeighborReachabilityEvent>();
out->ifindex = in.ifindex();
out->ip_addr = in.ip_addr();
switch (in.role()) {
case patchpanel::NeighborReachabilityEventSignal::GATEWAY:
out->role = Client::NeighborRole::kGateway;
break;
case patchpanel::NeighborReachabilityEventSignal::DNS_SERVER:
out->role = Client::NeighborRole::kDnsServer;
break;
case patchpanel::NeighborReachabilityEventSignal::GATEWAY_AND_DNS_SERVER:
out->role = Client::NeighborRole::kGatewayAndDnsServer;
break;
default:
LOG(ERROR) << __func__ << ": Unknown NeighborReachability role "
<< patchpanel::NeighborReachabilityEventSignal::Role_Name(
in.role());
return std::nullopt;
}
switch (in.type()) {
case patchpanel::NeighborReachabilityEventSignal::FAILED:
out->status = Client::NeighborStatus::kFailed;
break;
case patchpanel::NeighborReachabilityEventSignal::REACHABLE:
out->status = Client::NeighborStatus::kReachable;
break;
default:
LOG(ERROR) << __func__ << ": Unknown NeighborReachability event type "
<< patchpanel::NeighborReachabilityEventSignal::EventType_Name(
in.type());
return std::nullopt;
}
return out;
}
std::optional<Client::VirtualDeviceEvent> ConvertVirtualDeviceEvent(
const NetworkDeviceChangedSignal& in) {
switch (in.event()) {
case patchpanel::NetworkDeviceChangedSignal::DEVICE_ADDED:
return Client::VirtualDeviceEvent::kAdded;
case patchpanel::NetworkDeviceChangedSignal::DEVICE_REMOVED:
return Client::VirtualDeviceEvent::kRemoved;
default:
LOG(ERROR) << __func__ << ": Unknown NetworkDeviceChangedSignal event "
<< patchpanel::NetworkDeviceChangedSignal::Event_Name(
in.event());
return std::nullopt;
}
}
Client::ConnectedNamespace ConvertConnectedNamespace(
const ConnectNamespaceResponse& in) {
Client::ConnectedNamespace out;
out.ipv4_subnet = ConvertIPv4Subnet(in.ipv4_subnet());
out.peer_ifname = in.peer_ifname();
out.peer_ipv4_address = ConvertIPv4Addr(in.peer_ipv4_address());
out.host_ifname = in.host_ifname();
out.host_ipv4_address = ConvertIPv4Addr(in.host_ipv4_address());
out.netns_name = in.netns_name();
return out;
}
std::ostream& operator<<(std::ostream& stream,
const ModifyPortRuleRequest& request) {
stream << "{ operation: "
<< ModifyPortRuleRequest::Operation_Name(request.op())
<< ", rule type: "
<< ModifyPortRuleRequest::RuleType_Name(request.type())
<< ", protocol: "
<< ModifyPortRuleRequest::Protocol_Name(request.proto());
if (!request.input_ifname().empty()) {
stream << ", input interface name: " << request.input_ifname();
}
if (!request.input_dst_ip().empty()) {
stream << ", input destination IP: " << request.input_dst_ip();
}
stream << ", input destination port: " << request.input_dst_port();
if (!request.dst_ip().empty()) {
stream << ", destination IP: " << request.dst_ip();
}
if (request.dst_port() != 0) {
stream << ", destination port: " << request.dst_port();
}
stream << " }";
return stream;
}
std::ostream& operator<<(std::ostream& stream,
const SetDnsRedirectionRuleRequest& request) {
stream << "{ proxy type: "
<< SetDnsRedirectionRuleRequest::RuleType_Name(request.type());
if (!request.input_ifname().empty()) {
stream << ", input interface name: " << request.input_ifname();
}
if (!request.proxy_address().empty()) {
stream << ", proxy IPv4 address: " << request.proxy_address();
}
if (!request.nameservers().empty()) {
std::vector<std::string> nameservers;
for (const auto& ns : request.nameservers()) {
nameservers.emplace_back(ns);
}
stream << ", nameserver(s): " << base::JoinString(nameservers, ",");
}
stream << " }";
return stream;
}
// Prepares a pair of ScopedFDs corresponding to the write end (pair first
// element) and read end (pair second lemenet) of a Linux pipe and appends the
// read end to the given |writer| to send to patchpanel. The client must keep
// the read end alive until the DBus request is successfully sent. The client
// must keep the write end alive until the setup requested from patchpanel is
// not necessary anymore.
std::pair<base::ScopedFD, base::ScopedFD> CommitLifelineFd(
dbus::MessageWriter* writer) {
int pipe_fds[2] = {-1, -1};
if (pipe2(pipe_fds, O_CLOEXEC) < 0) {
PLOG(ERROR) << "Failed to create a pair of fds with pipe2()";
return {};
}
// MessageWriter::AppendFileDescriptor duplicates the fd, so the original read
// fd is given back to the caller using ScopedFD to make sure the it is
// eventually closed.
writer->AppendFileDescriptor(pipe_fds[1]);
return {base::ScopedFD(pipe_fds[0]), base::ScopedFD(pipe_fds[1])};
}
void OnGetTrafficCountersDBusResponse(
Client::GetTrafficCountersCallback callback,
dbus::Response* dbus_response) {
if (!dbus_response) {
LOG(ERROR) << "Failed to send TrafficCountersRequest message to patchpanel "
"service";
std::move(callback).Run({});
return;
}
TrafficCountersResponse response;
dbus::MessageReader reader(dbus_response);
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << "Failed to parse TrafficCountersResponse proto";
std::move(callback).Run({});
return;
}
std::vector<Client::TrafficCounter> counters;
for (const auto& proto_counter : response.counters()) {
auto client_counter = ConvertTrafficCounter(proto_counter);
if (client_counter) {
counters.push_back(*client_counter);
}
}
std::move(callback).Run(counters);
}
void OnNetworkDeviceChangedSignal(
const Client::VirtualDeviceEventHandler& handler, dbus::Signal* signal) {
dbus::MessageReader reader(signal);
NetworkDeviceChangedSignal proto;
if (!reader.PopArrayOfBytesAsProto(&proto)) {
LOG(ERROR) << "Failed to parse NetworkDeviceChangedSignal proto";
return;
}
const auto event = ConvertVirtualDeviceEvent(proto);
if (!event) {
return;
}
const auto device = ConvertVirtualDevice(proto.device());
if (device) {
handler.Run(*event, *device);
}
}
void OnNeighborReachabilityEventSignal(
const Client::NeighborReachabilityEventHandler& handler,
dbus::Signal* signal) {
dbus::MessageReader reader(signal);
NeighborReachabilityEventSignal proto;
if (!reader.PopArrayOfBytesAsProto(&proto)) {
LOG(ERROR) << "Failed to parse NeighborConnectedStateChangedSignal proto";
return;
}
const auto event = ConvertNeighborReachabilityEvent(proto);
if (event) {
handler.Run(*event);
}
}
void OnSignalConnectedCallback(const std::string& interface_name,
const std::string& signal_name,
bool success) {
if (!success)
LOG(ERROR) << "Failed to connect to " << signal_name;
}
// Helper static function to process answers to CreateTetheredNetwork calls.
void OnTetheredNetworkResponse(Client::CreateTetheredNetworkCallback callback,
base::ScopedFD fd_local,
dbus::Response* dbus_response) {
if (!dbus_response) {
LOG(ERROR)
<< kCreateTetheredNetworkMethod
<< ": Failed to send TetheredNetworkRequest message to patchpanel";
std::move(callback).Run({});
return;
}
TetheredNetworkResponse response;
dbus::MessageReader reader(dbus_response);
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << kCreateTetheredNetworkMethod
<< ": Failed to parse TetheredNetworkResponse proto";
std::move(callback).Run({});
return;
}
if (response.response_code() != DownstreamNetworkResult::SUCCESS) {
LOG(ERROR) << kCreateTetheredNetworkMethod << " failed: "
<< patchpanel::DownstreamNetworkResult_Name(
response.response_code());
std::move(callback).Run({});
return;
}
std::move(callback).Run(std::move(fd_local));
}
// Helper static function to process answers to CreateLocalOnlyNetwork calls.
void OnLocalOnlyNetworkResponse(Client::CreateLocalOnlyNetworkCallback callback,
base::ScopedFD fd_local,
dbus::Response* dbus_response) {
if (!dbus_response) {
LOG(ERROR)
<< kCreateLocalOnlyNetworkMethod
<< ": Failed to send LocalOnlyNetworkRequest message to patchpanel";
std::move(callback).Run({});
return;
}
LocalOnlyNetworkResponse response;
dbus::MessageReader reader(dbus_response);
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << kCreateLocalOnlyNetworkMethod
<< ": Failed to parse LocalOnlyNetworkResponse proto";
std::move(callback).Run({});
return;
}
if (response.response_code() != DownstreamNetworkResult::SUCCESS) {
LOG(ERROR) << kCreateLocalOnlyNetworkMethod << " failed: "
<< patchpanel::DownstreamNetworkResult_Name(
response.response_code());
std::move(callback).Run({});
return;
}
std::move(callback).Run(std::move(fd_local));
}
// Helper static function to process answers to DownstreamNetworkInfo calls.
void OnDownstreamNetworkInfoResponse(
Client::DownstreamNetworkInfoCallback callback,
dbus::Response* dbus_response) {
if (!dbus_response) {
LOG(ERROR) << kDownstreamNetworkInfoMethod
<< ": Failed to send DownstreamNetworkInfoRequest message to "
"patchpanel";
std::move(callback).Run(false, {}, {});
return;
}
DownstreamNetworkInfoResponse response;
dbus::MessageReader reader(dbus_response);
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << kDownstreamNetworkInfoMethod
<< ": Failed to parse DownstreamNetworkInfoResponse proto";
std::move(callback).Run(false, {}, {});
return;
}
auto downstream_network =
ConvertDownstreamNetwork(response.downstream_network());
std::vector<Client::NetworkClientInfo> clients_info;
for (const auto& ci : response.clients_info()) {
clients_info.push_back(ConvertNetworkClientInfo(ci));
}
std::move(callback).Run(true, downstream_network, clients_info);
}
class ClientImpl : public Client {
public:
ClientImpl(const scoped_refptr<dbus::Bus>& bus,
dbus::ObjectProxy* proxy,
bool owns_bus)
: bus_(std::move(bus)), proxy_(proxy), owns_bus_(owns_bus) {}
ClientImpl(const ClientImpl&) = delete;
ClientImpl& operator=(const ClientImpl&) = delete;
~ClientImpl();
void RegisterOnAvailableCallback(
base::RepeatingCallback<void(bool)> callback) override;
void RegisterProcessChangedCallback(
base::RepeatingCallback<void(bool)> callback) override;
bool NotifyArcStartup(pid_t pid) override;
bool NotifyArcShutdown() override;
std::vector<Client::VirtualDevice> NotifyArcVmStartup(uint32_t cid) override;
bool NotifyArcVmShutdown(uint32_t cid) override;
bool NotifyTerminaVmStartup(uint32_t cid,
Client::VirtualDevice* device,
Client::IPv4Subnet* container_subnet) override;
bool NotifyTerminaVmShutdown(uint32_t cid) override;
bool NotifyPluginVmStartup(uint64_t vm_id,
int subnet_index,
Client::VirtualDevice* device) override;
bool NotifyPluginVmShutdown(uint64_t vm_id) override;
bool DefaultVpnRouting(int socket) override;
bool RouteOnVpn(int socket) override;
bool BypassVpn(int socket) override;
std::pair<base::ScopedFD, Client::ConnectedNamespace> ConnectNamespace(
pid_t pid,
const std::string& outbound_ifname,
bool forward_user_traffic,
bool route_on_vpn,
Client::TrafficSource traffic_source) override;
void GetTrafficCounters(const std::set<std::string>& devices,
GetTrafficCountersCallback callback) override;
bool ModifyPortRule(Client::FirewallRequestOperation op,
Client::FirewallRequestType type,
Client::FirewallRequestProtocol proto,
const std::string& input_ifname,
const std::string& input_dst_ip,
uint32_t input_dst_port,
const std::string& dst_ip,
uint32_t dst_port) override;
bool SetVpnLockdown(bool enable) override;
base::ScopedFD RedirectDns(Client::DnsRedirectionRequestType type,
const std::string& input_ifname,
const std::string& proxy_address,
const std::vector<std::string>& nameservers,
const std::string& host_ifname) override;
std::vector<Client::VirtualDevice> GetDevices() override;
void RegisterVirtualDeviceEventHandler(
VirtualDeviceEventHandler handler) override;
void RegisterNeighborReachabilityEventHandler(
NeighborReachabilityEventHandler handler) override;
bool CreateTetheredNetwork(const std::string& downstream_ifname,
const std::string& upstream_ifname,
const std::optional<DHCPOptions>& dhcp_options,
const std::optional<int>& mtu,
CreateTetheredNetworkCallback callback) override;
bool CreateLocalOnlyNetwork(const std::string& ifname,
CreateLocalOnlyNetworkCallback callback) override;
bool GetDownstreamNetworkInfo(
const std::string& ifname,
DownstreamNetworkInfoCallback callback) override;
private:
scoped_refptr<dbus::Bus> bus_;
dbus::ObjectProxy* proxy_ = nullptr; // owned by |bus_|
bool owns_bus_; // Yes if |bus_| is created by Client::New
base::RepeatingCallback<void(bool)> owner_callback_;
void OnOwnerChanged(const std::string& old_owner,
const std::string& new_owner);
bool SendSetVpnIntentRequest(int socket,
SetVpnIntentRequest::VpnRoutingPolicy policy);
base::WeakPtrFactory<ClientImpl> weak_factory_{this};
};
ClientImpl::~ClientImpl() {
if (bus_ && owns_bus_)
bus_->ShutdownAndBlock();
}
void ClientImpl::RegisterOnAvailableCallback(
base::RepeatingCallback<void(bool)> callback) {
if (!proxy_) {
LOG(ERROR) << "Cannot register callback - no proxy";
return;
}
proxy_->WaitForServiceToBeAvailable(callback);
}
void ClientImpl::RegisterProcessChangedCallback(
base::RepeatingCallback<void(bool)> callback) {
owner_callback_ = callback;
bus_->GetObjectProxy(kPatchPanelServiceName, dbus::ObjectPath{"/"})
->SetNameOwnerChangedCallback(base::BindRepeating(
&ClientImpl::OnOwnerChanged, weak_factory_.GetWeakPtr()));
}
void ClientImpl::OnOwnerChanged(const std::string& old_owner,
const std::string& new_owner) {
if (new_owner.empty()) {
LOG(INFO) << "Patchpanel lost";
if (!owner_callback_.is_null())
owner_callback_.Run(false);
return;
}
LOG(INFO) << "Patchpanel reset";
if (!owner_callback_.is_null())
owner_callback_.Run(true);
}
bool ClientImpl::NotifyArcStartup(pid_t pid) {
dbus::MethodCall method_call(kPatchPanelInterface, kArcStartupMethod);
dbus::MessageWriter writer(&method_call);
ArcStartupRequest request;
request.set_pid(pid);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode ArcStartupRequest proto";
return false;
}
std::unique_ptr<dbus::Response> dbus_response =
brillo::dbus_utils::CallDBusMethod(
bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
if (!dbus_response) {
LOG(ERROR) << "Failed to send dbus message to patchpanel service";
return false;
}
dbus::MessageReader reader(dbus_response.get());
ArcStartupResponse response;
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << "Failed to parse response proto";
return false;
}
return true;
}
bool ClientImpl::NotifyArcShutdown() {
dbus::MethodCall method_call(kPatchPanelInterface, kArcShutdownMethod);
dbus::MessageWriter writer(&method_call);
ArcShutdownRequest request;
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode ArcShutdownRequest proto";
return false;
}
std::unique_ptr<dbus::Response> dbus_response =
brillo::dbus_utils::CallDBusMethod(
bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
if (!dbus_response) {
LOG(ERROR) << "Failed to send dbus message to patchpanel service";
return false;
}
dbus::MessageReader reader(dbus_response.get());
ArcShutdownResponse response;
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << "Failed to parse response proto";
return false;
}
return true;
}
std::vector<Client::VirtualDevice> ClientImpl::NotifyArcVmStartup(
uint32_t cid) {
dbus::MethodCall method_call(kPatchPanelInterface, kArcVmStartupMethod);
dbus::MessageWriter writer(&method_call);
ArcVmStartupRequest request;
request.set_cid(cid);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode ArcVmStartupRequest proto";
return {};
}
std::unique_ptr<dbus::Response> dbus_response =
brillo::dbus_utils::CallDBusMethod(
bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
if (!dbus_response) {
LOG(ERROR) << "Failed to send dbus message to patchpanel service";
return {};
}
dbus::MessageReader reader(dbus_response.get());
ArcVmStartupResponse response;
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << "Failed to parse response proto";
return {};
}
std::vector<Client::VirtualDevice> devices;
for (const auto& d : response.devices()) {
const auto device = ConvertVirtualDevice(d);
if (device) {
devices.push_back(*device);
}
}
return devices;
}
bool ClientImpl::NotifyArcVmShutdown(uint32_t cid) {
dbus::MethodCall method_call(kPatchPanelInterface, kArcVmShutdownMethod);
dbus::MessageWriter writer(&method_call);
ArcVmShutdownRequest request;
request.set_cid(cid);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode ArcVmShutdownRequest proto";
return false;
}
std::unique_ptr<dbus::Response> dbus_response =
brillo::dbus_utils::CallDBusMethod(
bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
if (!dbus_response) {
LOG(ERROR) << "Failed to send dbus message to patchpanel service";
return false;
}
dbus::MessageReader reader(dbus_response.get());
ArcVmShutdownResponse response;
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << "Failed to parse response proto";
return false;
}
return true;
}
bool ClientImpl::NotifyTerminaVmStartup(uint32_t cid,
Client::VirtualDevice* device,
Client::IPv4Subnet* container_subnet) {
dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmStartupMethod);
dbus::MessageWriter writer(&method_call);
TerminaVmStartupRequest request;
request.set_cid(cid);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode TerminaVmStartupRequest proto";
return false;
}
std::unique_ptr<dbus::Response> dbus_response =
brillo::dbus_utils::CallDBusMethod(
bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
if (!dbus_response) {
LOG(ERROR) << "Failed to send dbus message to patchpanel service";
return false;
}
dbus::MessageReader reader(dbus_response.get());
TerminaVmStartupResponse response;
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << "Failed to parse response proto";
return false;
}
if (!response.has_device()) {
LOG(ERROR) << "No virtual device found";
return false;
}
const auto response_device = ConvertVirtualDevice(response.device());
if (!response_device) {
LOG(ERROR) << "Invalid virtual device response";
return false;
}
*device = *response_device;
if (response.has_container_subnet()) {
*container_subnet = ConvertIPv4Subnet(response.container_subnet());
} else {
LOG(WARNING) << "No container subnet found";
}
return true;
}
bool ClientImpl::NotifyTerminaVmShutdown(uint32_t cid) {
dbus::MethodCall method_call(kPatchPanelInterface, kTerminaVmShutdownMethod);
dbus::MessageWriter writer(&method_call);
TerminaVmShutdownRequest request;
request.set_cid(cid);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode TerminaVmShutdownRequest proto";
return false;
}
std::unique_ptr<dbus::Response> dbus_response =
brillo::dbus_utils::CallDBusMethod(
bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
if (!dbus_response) {
LOG(ERROR) << "Failed to send dbus message to patchpanel service";
return false;
}
dbus::MessageReader reader(dbus_response.get());
TerminaVmShutdownResponse response;
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << "Failed to parse response proto";
return false;
}
return true;
}
bool ClientImpl::NotifyPluginVmStartup(uint64_t vm_id,
int subnet_index,
Client::VirtualDevice* device) {
dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmStartupMethod);
dbus::MessageWriter writer(&method_call);
PluginVmStartupRequest request;
request.set_id(vm_id);
request.set_subnet_index(subnet_index);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode PluginVmStartupRequest proto";
return false;
}
std::unique_ptr<dbus::Response> dbus_response =
brillo::dbus_utils::CallDBusMethod(
bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
if (!dbus_response) {
LOG(ERROR) << "Failed to send dbus message to patchpanel service";
return false;
}
dbus::MessageReader reader(dbus_response.get());
PluginVmStartupResponse response;
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << "Failed to parse response proto";
return false;
}
if (!response.has_device()) {
LOG(ERROR) << "No virtual device found";
return false;
}
const auto response_device = ConvertVirtualDevice(response.device());
if (!response_device) {
LOG(ERROR) << "Invalid virtual device response";
return false;
}
*device = *response_device;
return true;
}
bool ClientImpl::NotifyPluginVmShutdown(uint64_t vm_id) {
dbus::MethodCall method_call(kPatchPanelInterface, kPluginVmShutdownMethod);
dbus::MessageWriter writer(&method_call);
PluginVmShutdownRequest request;
request.set_id(vm_id);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode PluginVmShutdownRequest proto";
return false;
}
std::unique_ptr<dbus::Response> dbus_response =
brillo::dbus_utils::CallDBusMethod(
bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
if (!dbus_response) {
LOG(ERROR) << "Failed to send dbus message to patchpanel service";
return false;
}
dbus::MessageReader reader(dbus_response.get());
PluginVmShutdownResponse response;
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << "Failed to parse response proto";
return false;
}
return true;
}
bool ClientImpl::DefaultVpnRouting(int socket) {
return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::DEFAULT_ROUTING);
}
bool ClientImpl::RouteOnVpn(int socket) {
return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::ROUTE_ON_VPN);
}
bool ClientImpl::BypassVpn(int socket) {
return SendSetVpnIntentRequest(socket, SetVpnIntentRequest::BYPASS_VPN);
}
bool ClientImpl::SendSetVpnIntentRequest(
int socket, SetVpnIntentRequest::VpnRoutingPolicy policy) {
dbus::MethodCall method_call(kPatchPanelInterface, kSetVpnIntentMethod);
dbus::MessageWriter writer(&method_call);
SetVpnIntentRequest request;
SetVpnIntentResponse response;
request.set_policy(policy);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode SetVpnIntentRequest proto";
return false;
}
writer.AppendFileDescriptor(socket);
std::unique_ptr<dbus::Response> dbus_response =
brillo::dbus_utils::CallDBusMethod(
bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
if (!dbus_response) {
LOG(ERROR)
<< "Failed to send SetVpnIntentRequest message to patchpanel service";
return false;
}
dbus::MessageReader reader(dbus_response.get());
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << "Failed to parse SetVpnIntentResponse proto";
return false;
}
if (!response.success()) {
LOG(ERROR) << "SetVpnIntentRequest failed";
return false;
}
return true;
}
std::pair<base::ScopedFD, Client::ConnectedNamespace>
ClientImpl::ConnectNamespace(pid_t pid,
const std::string& outbound_ifname,
bool forward_user_traffic,
bool route_on_vpn,
Client::TrafficSource traffic_source) {
// Prepare and serialize the request proto.
ConnectNamespaceRequest request;
request.set_pid(static_cast<int32_t>(pid));
request.set_outbound_physical_device(outbound_ifname);
request.set_allow_user_traffic(forward_user_traffic);
request.set_route_on_vpn(route_on_vpn);
request.set_traffic_source(ConvertTrafficSource(traffic_source));
dbus::MethodCall method_call(kPatchPanelInterface, kConnectNamespaceMethod);
dbus::MessageWriter writer(&method_call);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode ConnectNamespaceRequest proto";
return {};
}
// Prepare an fd pair and append one fd directly after the serialized request.
auto [fd_local, fd_remote] = CommitLifelineFd(&writer);
if (!fd_local.is_valid()) {
LOG(ERROR)
<< "Cannot send ConnectNamespace message to patchpanel: no lifeline fd";
return {};
}
std::unique_ptr<dbus::Response> dbus_response =
brillo::dbus_utils::CallDBusMethod(
bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
if (!dbus_response) {
LOG(ERROR) << "Failed to send ConnectNamespace message to patchpanel";
return {};
}
dbus::MessageReader reader(dbus_response.get());
ConnectNamespaceResponse response;
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << "Failed to parse ConnectNamespaceResponse proto";
return {};
}
if (response.peer_ifname().empty() || response.host_ifname().empty()) {
LOG(ERROR) << "ConnectNamespace for netns pid " << pid << " failed";
return {};
}
auto connected_ns = ConvertConnectedNamespace(response);
std::string subnet_info = IPv4AddressToCidrString(
connected_ns.ipv4_subnet.base_addr, connected_ns.ipv4_subnet.prefix_len);
LOG(INFO) << "ConnectNamespace for netns pid " << pid
<< " succeeded: peer_ifname=" << connected_ns.peer_ifname
<< " peer_ipv4_address="
<< IPv4AddressToString(connected_ns.peer_ipv4_address)
<< " host_ifname=" << connected_ns.host_ifname
<< " host_ipv4_address="
<< IPv4AddressToString(connected_ns.host_ipv4_address)
<< " subnet=" << subnet_info;
return std::make_pair(std::move(fd_local), std::move(connected_ns));
}
void ClientImpl::GetTrafficCounters(const std::set<std::string>& devices,
GetTrafficCountersCallback callback) {
dbus::MethodCall method_call(kPatchPanelInterface, kGetTrafficCountersMethod);
dbus::MessageWriter writer(&method_call);
TrafficCountersRequest request;
for (const auto& device : devices) {
request.add_devices(device);
}
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode TrafficCountersRequest proto";
std::move(callback).Run({});
return;
}
proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(&OnGetTrafficCountersDBusResponse, std::move(callback)));
}
bool ClientImpl::ModifyPortRule(Client::FirewallRequestOperation op,
Client::FirewallRequestType type,
Client::FirewallRequestProtocol proto,
const std::string& input_ifname,
const std::string& input_dst_ip,
uint32_t input_dst_port,
const std::string& dst_ip,
uint32_t dst_port) {
dbus::MethodCall method_call(kPatchPanelInterface, kModifyPortRuleMethod);
dbus::MessageWriter writer(&method_call);
ModifyPortRuleRequest request;
ModifyPortRuleResponse response;
request.set_op(ConvertFirewallRequestOperation(op));
request.set_type(ConvertFirewallRequestType(type));
request.set_proto(ConvertFirewallRequestProtocol(proto));
request.set_input_ifname(input_ifname);
request.set_input_dst_ip(input_dst_ip);
request.set_input_dst_port(input_dst_port);
request.set_dst_ip(dst_ip);
request.set_dst_port(dst_port);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode ModifyPortRuleRequest proto " << request;
return false;
}
std::unique_ptr<dbus::Response> dbus_response =
brillo::dbus_utils::CallDBusMethod(
bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
if (!dbus_response) {
LOG(ERROR)
<< "Failed to send ModifyPortRuleRequest message to patchpanel service "
<< request;
return false;
}
dbus::MessageReader reader(dbus_response.get());
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << "Failed to parse ModifyPortRuleResponse proto " << request;
return false;
}
if (!response.success()) {
LOG(ERROR) << "ModifyPortRuleRequest failed " << request;
return false;
}
return true;
}
bool ClientImpl::SetVpnLockdown(bool enable) {
dbus::MethodCall method_call(kPatchPanelInterface, kSetVpnLockdown);
dbus::MessageWriter writer(&method_call);
SetVpnLockdownRequest request;
SetVpnLockdownResponse response;
request.set_enable_vpn_lockdown(enable);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode SetVpnLockdownRequest proto";
return false;
}
std::unique_ptr<dbus::Response> dbus_response =
brillo::dbus_utils::CallDBusMethod(
bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
if (!dbus_response) {
LOG(ERROR) << "Failed to call SetVpnLockdown patchpanel API";
return false;
}
dbus::MessageReader reader(dbus_response.get());
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << "Failed to parse SetVpnLockdownResponse";
return false;
}
return true;
}
base::ScopedFD ClientImpl::RedirectDns(
Client::DnsRedirectionRequestType type,
const std::string& input_ifname,
const std::string& proxy_address,
const std::vector<std::string>& nameservers,
const std::string& host_ifname) {
dbus::MethodCall method_call(kPatchPanelInterface,
kSetDnsRedirectionRuleMethod);
dbus::MessageWriter writer(&method_call);
SetDnsRedirectionRuleRequest request;
SetDnsRedirectionRuleResponse response;
request.set_type(ConvertDnsRedirectionRequestType(type));
request.set_input_ifname(input_ifname);
request.set_proxy_address(proxy_address);
request.set_host_ifname(host_ifname);
for (const auto& nameserver : nameservers) {
request.add_nameservers(nameserver);
}
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode SetDnsRedirectionRuleRequest proto "
<< request;
return {};
}
// Prepare an fd pair and append one fd directly after the serialized request.
auto [fd_local, fd_remote] = CommitLifelineFd(&writer);
if (!fd_local.is_valid()) {
LOG(ERROR) << "Cannot send SetDnsRedirectionRuleRequest message to "
"patchpanel: no lifeline fd";
return {};
}
std::unique_ptr<dbus::Response> dbus_response =
brillo::dbus_utils::CallDBusMethod(
bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
if (!dbus_response) {
LOG(ERROR) << "Failed to send SetDnsRedirectionRuleRequest message to "
"patchpanel service "
<< request;
return {};
}
dbus::MessageReader reader(dbus_response.get());
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << "Failed to parse SetDnsRedirectionRuleResponse proto "
<< request;
return {};
}
if (!response.success()) {
LOG(ERROR) << "SetDnsRedirectionRuleRequest failed " << request;
return {};
}
return std::move(fd_local);
}
std::vector<Client::VirtualDevice> ClientImpl::GetDevices() {
dbus::MethodCall method_call(kPatchPanelInterface, kGetDevicesMethod);
dbus::MessageWriter writer(&method_call);
GetDevicesRequest request;
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode GetDevicesRequest proto";
return {};
}
std::unique_ptr<dbus::Response> dbus_response =
brillo::dbus_utils::CallDBusMethod(
bus_, proxy_, &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
if (!dbus_response) {
LOG(ERROR) << "Failed to send dbus message to patchpanel service";
return {};
}
dbus::MessageReader reader(dbus_response.get());
GetDevicesResponse response;
if (!reader.PopArrayOfBytesAsProto(&response)) {
LOG(ERROR) << "Failed to parse response proto";
return {};
}
std::vector<Client::VirtualDevice> devices;
for (const auto& d : response.devices()) {
const auto device = ConvertVirtualDevice(d);
if (device) {
devices.push_back(*device);
}
}
return devices;
}
void ClientImpl::RegisterVirtualDeviceEventHandler(
VirtualDeviceEventHandler handler) {
proxy_->ConnectToSignal(
kPatchPanelInterface, kNetworkDeviceChangedSignal,
base::BindRepeating(OnNetworkDeviceChangedSignal, handler),
base::BindOnce(OnSignalConnectedCallback));
}
void ClientImpl::RegisterNeighborReachabilityEventHandler(
NeighborReachabilityEventHandler handler) {
proxy_->ConnectToSignal(
kPatchPanelInterface, kNeighborReachabilityEventSignal,
base::BindRepeating(OnNeighborReachabilityEventSignal, handler),
base::BindOnce(OnSignalConnectedCallback));
}
bool ClientImpl::CreateTetheredNetwork(
const std::string& downstream_ifname,
const std::string& upstream_ifname,
const std::optional<DHCPOptions>& dhcp_options,
const std::optional<int>& mtu,
CreateTetheredNetworkCallback callback) {
dbus::MethodCall method_call(kPatchPanelInterface,
kCreateTetheredNetworkMethod);
dbus::MessageWriter writer(&method_call);
TetheredNetworkRequest request;
request.set_ifname(downstream_ifname);
request.set_upstream_ifname(upstream_ifname);
if (mtu) {
request.set_mtu(*mtu);
}
// TODO(b/239559602) Fill out DHCP options:
// - If the upstream network has a DHCP lease, copy relevant options.
// - Option 43 with ANDROID_METERED if the upstream network is metered.
// - Forward DHCP WPAD proxy configuration if advertised by the upstream
// network.
auto* ipv4_config = request.mutable_ipv4_config();
if (dhcp_options) {
ipv4_config->set_use_dhcp(true);
for (const auto& dns_server : dhcp_options->dns_server_addresses) {
ipv4_config->add_dns_servers(dns_server.data(), dns_server.size());
}
for (const auto& domain_search : dhcp_options->domain_search_list) {
ipv4_config->add_domain_searches(domain_search);
}
}
request.set_enable_ipv6(true);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << kCreateTetheredNetworkMethod << "(" << downstream_ifname
<< "," << upstream_ifname
<< "): Failed to encode TetheredNetworkRequest proto";
return false;
}
// Prepare an fd pair and append one fd directly after the serialized request.
auto [fd_local, fd_remote] = CommitLifelineFd(&writer);
if (!fd_local.is_valid()) {
LOG(ERROR) << kCreateTetheredNetworkMethod << "(" << downstream_ifname
<< "," << upstream_ifname << "): Cannot create lifeline fds";
return false;
}
proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(&OnTetheredNetworkResponse,
std::move(callback), std::move(fd_local)));
return true;
}
bool ClientImpl::CreateLocalOnlyNetwork(
const std::string& ifname, CreateLocalOnlyNetworkCallback callback) {
dbus::MethodCall method_call(kPatchPanelInterface,
kCreateLocalOnlyNetworkMethod);
dbus::MessageWriter writer(&method_call);
LocalOnlyNetworkRequest request;
request.set_ifname(ifname);
auto* ipv4_config = request.mutable_ipv4_config();
ipv4_config->set_use_dhcp(true);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << kCreateLocalOnlyNetworkMethod
<< ": Failed to encode LocalOnlyNetworkRequest proto";
return false;
}
// Prepare an fd pair and append one fd directly after the serialized request.
auto [fd_local, fd_remote] = CommitLifelineFd(&writer);
if (!fd_local.is_valid()) {
LOG(ERROR) << kCreateLocalOnlyNetworkMethod
<< ": Cannot create lifeline fds";
return false;
}
proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(&OnLocalOnlyNetworkResponse,
std::move(callback), std::move(fd_local)));
return true;
}
bool ClientImpl::GetDownstreamNetworkInfo(
const std::string& ifname, DownstreamNetworkInfoCallback callback) {
dbus::MethodCall method_call(kPatchPanelInterface,
kDownstreamNetworkInfoMethod);
dbus::MessageWriter writer(&method_call);
DownstreamNetworkInfoRequest request;
request.set_downstream_ifname(ifname);
if (!writer.AppendProtoAsArrayOfBytes(request)) {
LOG(ERROR) << "Failed to encode DownstreamNetworkInfoRequest proto";
return false;
}
proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::BindOnce(&OnDownstreamNetworkInfoResponse, std::move(callback)));
return true;
}
dbus::ObjectProxy* GetProxy(const scoped_refptr<dbus::Bus>& bus) {
dbus::ObjectProxy* proxy = bus->GetObjectProxy(
kPatchPanelServiceName, dbus::ObjectPath(kPatchPanelServicePath));
if (!proxy) {
LOG(ERROR) << "Unable to get dbus proxy for " << kPatchPanelServiceName;
}
return proxy;
}
} // namespace
// static
std::unique_ptr<Client> Client::New() {
dbus::Bus::Options opts;
opts.bus_type = dbus::Bus::SYSTEM;
scoped_refptr<dbus::Bus> bus(new dbus::Bus(std::move(opts)));
if (!bus->Connect()) {
LOG(ERROR) << "Failed to connect to system bus";
return nullptr;
}
dbus::ObjectProxy* proxy = GetProxy(bus);
if (!proxy)
return nullptr;
return std::make_unique<ClientImpl>(std::move(bus), proxy,
/*owns_bus=*/true);
}
std::unique_ptr<Client> Client::New(const scoped_refptr<dbus::Bus>& bus) {
dbus::ObjectProxy* proxy = GetProxy(bus);
if (!proxy)
return nullptr;
return std::make_unique<ClientImpl>(std::move(bus), proxy,
/*owns_bus=*/false);
}
std::unique_ptr<Client> Client::New(const scoped_refptr<dbus::Bus>& bus,
dbus::ObjectProxy* proxy) {
return std::make_unique<ClientImpl>(std::move(bus), proxy,
/*owns_bus=*/false);
}
// static
bool Client::IsArcGuest(Client::GuestType guest_type) {
switch (guest_type) {
case Client::GuestType::kArcContainer:
case Client::GuestType::kArcVm:
return true;
default:
return false;
}
}
// static
std::string Client::TrafficSourceName(
patchpanel::Client::TrafficSource source) {
return patchpanel::TrafficCounter::Source_Name(ConvertTrafficSource(source));
}
// static
std::string Client::ProtocolName(
patchpanel::Client::FirewallRequestProtocol protocol) {
return patchpanel::ModifyPortRuleRequest::Protocol_Name(
ConvertFirewallRequestProtocol(protocol));
}
// static
std::string Client::NeighborRoleName(patchpanel::Client::NeighborRole role) {
return NeighborReachabilityEventSignal::Role_Name(ConvertNeighborRole(role));
}
// static
std::string Client::NeighborStatusName(
patchpanel::Client::NeighborStatus status) {
return NeighborReachabilityEventSignal::EventType_Name(
ConvertNeighborStatus(status));
}
BRILLO_EXPORT std::ostream& operator<<(
std::ostream& stream, const Client::NeighborReachabilityEvent& event) {
return stream << "{ifindex: " << event.ifindex
<< ", ip_address: " << event.ip_addr
<< ", role: " << Client::NeighborRoleName(event.role)
<< ", status: " << Client::NeighborStatusName(event.status)
<< "}";
}
} // namespace patchpanel