blob: 4b721a5dd62be1e0118aeacf78b4bb7c9acc531a [file] [log] [blame] [edit]
// Copyright 2019 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PATCHPANEL_DBUS_CLIENT_H_
#define PATCHPANEL_DBUS_CLIENT_H_
#include <initializer_list>
#include <memory>
#include <ostream>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/files/scoped_file.h"
#include "base/functional/callback.h"
#include <brillo/brillo_export.h>
// Ignore Wconversion warnings in dbus headers.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#include <dbus/bus.h>
#include <dbus/object_proxy.h>
#pragma GCC diagnostic pop
namespace patchpanel {
// Simple wrapper around patchpanel DBus API. All public functions are blocking
// DBus calls to patchpaneld (asynchronous calls are mentioned explicitly). The
// method names and protobuf schema used by patchpanel DBus API are defined in
// platform2/system_api/dbus/patchpanel. Types and classes generated from the
// patchpanel protobuf schema are not directly used and are instead wrapped with
// lightweight structs and enums defined in this file. Access control for
// clients is defined // in platform2/patchpanel/dbus.
class BRILLO_EXPORT Client {
public:
// See TrafficCounter.IpFamily in patchpanel_service.proto.
enum class IPFamily {
kIPv4,
kIPv6,
};
// See IPv4Subnet in patchpanel_service.proto.
struct IPv4Subnet {
std::vector<uint8_t> base_addr;
int prefix_len;
};
// See TrafficCounter.Source in patchpanel_service.proto.
enum class TrafficSource {
kUnknown,
kChrome,
kUser,
kArc,
kCrosVm,
kPluginVm,
kUpdateEngine,
kVpn,
kSystem,
};
static constexpr std::initializer_list<TrafficSource> kAllTrafficSources = {
TrafficSource::kUnknown, TrafficSource::kChrome,
TrafficSource::kUser, TrafficSource::kArc,
TrafficSource::kCrosVm, TrafficSource::kPluginVm,
TrafficSource::kUpdateEngine, TrafficSource::kVpn,
TrafficSource::kSystem,
};
// See TrafficCounter in patchpanel_service.proto.
struct TrafficCounter {
uint64_t rx_bytes;
uint64_t tx_bytes;
uint64_t rx_packets;
uint64_t tx_packets;
TrafficSource source;
std::string ifname;
IPFamily ip_family;
};
// See NetworkDevice.GuestType in patchpanel_service.proto.
enum class GuestType {
kArcContainer,
kArcVm,
kTerminaVm,
kPluginVm,
};
// See NetworkDeviceChangedSignal in patchpanel_service.proto.
enum class VirtualDeviceEvent {
kAdded,
kRemoved,
};
// See NetworkDevice in patchpanel_service.proto.
struct VirtualDevice {
std::string ifname;
std::string phys_ifname;
std::string guest_ifname;
std::vector<uint8_t> ipv4_addr;
std::vector<uint8_t> host_ipv4_addr;
IPv4Subnet ipv4_subnet;
GuestType guest_type;
std::vector<uint8_t> dns_proxy_ipv4_addr;
std::vector<uint8_t> dns_proxy_ipv6_addr;
};
// See ConnectNamespaceResponse in patchpanel_service.proto.
struct ConnectedNamespace {
IPv4Subnet ipv4_subnet;
std::string peer_ifname;
std::vector<uint8_t> peer_ipv4_address;
std::string host_ifname;
std::vector<uint8_t> host_ipv4_address;
std::string netns_name;
};
// See DownstreamNetwork in patchpanel_service.proto.
struct DownstreamNetwork {
std::string ifname;
IPv4Subnet ipv4_subnet;
std::vector<uint8_t> ipv4_gateway_addr;
};
// See NetworkClientInfo in patchpanel_service.proto.
struct NetworkClientInfo {
std::vector<uint8_t> mac_addr;
std::vector<uint8_t> ipv4_addr;
std::vector<std::vector<uint8_t>> ipv6_addresses;
std::string hostname;
std::string vendor_class;
};
// See ModifyPortRuleRequest.Operation in patchpanel_service.proto.
enum class FirewallRequestOperation {
kCreate,
kDelete,
};
// See ModifyPortRuleRequest.RuleType in patchpanel_service.proto.
enum class FirewallRequestType {
kAccess,
kLockdown,
kForwarding,
};
// See ModifyPortRuleRequest.Protocol in patchpanel_service.proto.
enum class FirewallRequestProtocol {
kTcp,
kUdp,
};
// See SetDnsRedirectionRuleRequest in patchpanel_service.proto.
enum class DnsRedirectionRequestType {
kDefault,
kArc,
kUser,
kExcludeDestination,
};
// See NeighborReachabilityEventSignal.Role in patchpanel_service.proto.
enum class NeighborRole {
kGateway,
kDnsServer,
kGatewayAndDnsServer,
};
// See NeighborReachabilityEventSignal.EventType in patchpanel_service.proto.
enum class NeighborStatus {
kFailed,
kReachable,
};
// See NeighborReachabilityEventSignal in patchpanel_service.proto.
struct NeighborReachabilityEvent {
int ifindex;
std::string ip_addr;
NeighborRole role;
NeighborStatus status;
};
// Contains the options for creating the IPv4 DHCP server.
struct DHCPOptions {
std::vector<std::array<uint8_t, 4>> dns_server_addresses;
std::vector<std::string> domain_search_list;
};
using GetTrafficCountersCallback =
base::OnceCallback<void(const std::vector<TrafficCounter>&)>;
using NeighborReachabilityEventHandler =
base::RepeatingCallback<void(const NeighborReachabilityEvent&)>;
using VirtualDeviceEventHandler =
base::RepeatingCallback<void(VirtualDeviceEvent, const VirtualDevice&)>;
using CreateTetheredNetworkCallback =
base::OnceCallback<void(base::ScopedFD)>;
using CreateLocalOnlyNetworkCallback =
base::OnceCallback<void(base::ScopedFD)>;
using DownstreamNetworkInfoCallback =
base::OnceCallback<void(bool success,
const DownstreamNetwork& downstream_network,
const std::vector<NetworkClientInfo>& clients)>;
// This variation creates a dbus object internally
static std::unique_ptr<Client> New();
static std::unique_ptr<Client> New(const scoped_refptr<dbus::Bus>& bus);
// Only used in tests.
static std::unique_ptr<Client> New(const scoped_refptr<dbus::Bus>& bus,
dbus::ObjectProxy* proxy);
static bool IsArcGuest(GuestType guest_type);
static std::string TrafficSourceName(TrafficSource source);
static std::string ProtocolName(FirewallRequestProtocol protocol);
static std::string NeighborRoleName(NeighborRole role);
static std::string NeighborStatusName(NeighborStatus status);
virtual ~Client() = default;
virtual void RegisterOnAvailableCallback(
base::RepeatingCallback<void(bool)> callback) = 0;
// |callback| will be invoked if patchpanel exits and/or the DBus service
// owner changes. The parameter will be false if the process is gone (no
// owner) or true otherwise.
virtual void RegisterProcessChangedCallback(
base::RepeatingCallback<void(bool)> callback) = 0;
virtual bool NotifyArcStartup(pid_t pid) = 0;
virtual bool NotifyArcShutdown() = 0;
virtual std::vector<VirtualDevice> NotifyArcVmStartup(uint32_t cid) = 0;
virtual bool NotifyArcVmShutdown(uint32_t cid) = 0;
virtual bool NotifyTerminaVmStartup(uint32_t cid,
VirtualDevice* device,
IPv4Subnet* container_subnet) = 0;
virtual bool NotifyTerminaVmShutdown(uint32_t cid) = 0;
virtual bool NotifyPluginVmStartup(uint64_t vm_id,
int subnet_index,
VirtualDevice* device) = 0;
virtual bool NotifyPluginVmShutdown(uint64_t vm_id) = 0;
// Reset the VPN routing intent mark on a socket to the default policy for
// the current uid. This is in general incorrect to call this method for
// a socket that is already connected.
virtual bool DefaultVpnRouting(int socket) = 0;
// Mark a socket to be always routed through a VPN if there is one.
// Must be called before the socket is connected.
virtual bool RouteOnVpn(int socket) = 0;
// Mark a socket to be always routed through the physical network.
// Must be called before the socket is connected.
virtual bool BypassVpn(int socket) = 0;
// Sends a ConnectNamespaceRequest for the given namespace pid. Returns a
// pair with a valid ScopedFD and the ConnectedNamespace response
// received if the request succeeded. Closing the ScopedFD will teardown the
// veth and routing setup and free the allocated IPv4 subnet.
virtual std::pair<base::ScopedFD, ConnectedNamespace> ConnectNamespace(
pid_t pid,
const std::string& outbound_ifname,
bool forward_user_traffic,
bool route_on_vpn,
TrafficSource traffic_source) = 0;
// Gets the traffic counters kept by patchpanel asynchronously, |callback|
// will be called with the counters once they are ready, or with an empty
// vector when an error happen. |devices| is the set of interfaces (shill
// devices) for which counters should be returned, any unknown interfaces will
// be ignored. If |devices| is empty, counters for all known interfaces will
// be returned.
virtual void GetTrafficCounters(const std::set<std::string>& devices,
GetTrafficCountersCallback callback) = 0;
// Sends a ModifyPortRuleRequest to modify iptables ingress rules.
// This should only be called by permission_broker's 'devbroker'.
virtual bool ModifyPortRule(FirewallRequestOperation op,
FirewallRequestType type,
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) = 0;
// Start or stop VPN lockdown. When VPN lockdown is enabled and no VPN
// connection exists, any non-ARC traffic that would be routed to a VPN
// connection is instead rejected. ARC traffic is ignored because Android
// already implements VPN lockdown.
virtual bool SetVpnLockdown(bool enable) = 0;
// Sends a SetDnsRedirectionRuleRequest to modify iptables rules for DNS
// proxy. This should only be called by 'dns-proxy'. If successful, it returns
// a ScopedFD. The rules lifetime is tied to the file descriptor. This returns
// an invalid file descriptor upon failure.
virtual base::ScopedFD RedirectDns(
DnsRedirectionRequestType type,
const std::string& input_ifname,
const std::string& proxy_address,
const std::vector<std::string>& nameservers,
const std::string& host_ifname) = 0;
// Obtains a list of NetworkDevices currently managed by patchpanel.
virtual std::vector<VirtualDevice> GetDevices() = 0;
// Registers a handler that will be called upon receiving a signal indicating
// that a network device managed by patchpanel was added or removed.
virtual void RegisterVirtualDeviceEventHandler(
VirtualDeviceEventHandler handler) = 0;
// Registers a handler that will be called on receiving a neighbor
// reachability event. Currently these events are generated only for WiFi
// devices. The handler is registered for as long as this patchpanel::Client
// instance is alive.
virtual void RegisterNeighborReachabilityEventHandler(
NeighborReachabilityEventHandler handler) = 0;
// Sends request for creating an L3 network on |downstream_ifname|, sharing
// the Internet connection of |upstream_ifname| with the created network.
// Returns true if the request was successfully sent, false otherwise. After
// the request completes successfully, |callback| is ran with a file
// descriptor controlling the lifetime of the tethering setup. The tethering
// setup is torn down when the file descriptor is closed by the client. If the
// request failed, |callback| is ran with an invalid ScopedFD value.
virtual 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) = 0;
// Sends request for creating a local-only L3 network on |ifname|.
// Returns true if the request was successfully sent, false otherwise. After
// the request completes successfully, |callback| is ran with a file
// descriptor controlling the lifetime of the local only network setup. The
// local only network setup is torn down when the file descriptor is closed by
// the client. If the request failed, |callback| is ran with an invalid
// ScopedFD value.
virtual bool CreateLocalOnlyNetwork(
const std::string& ifname, CreateLocalOnlyNetworkCallback callback) = 0;
// Gets L3 information about a downstream network created with
// CreateTetheredNetwork or CreateLocalOnlyNetwork on |ifname|
// and all its connected clients. Returns true if the request was successfully
// sent, false otherwise. |callback| is ran after the request has completed.
virtual bool GetDownstreamNetworkInfo(
const std::string& ifname, DownstreamNetworkInfoCallback callback) = 0;
protected:
Client() = default;
};
BRILLO_EXPORT std::ostream& operator<<(
std::ostream& stream, const Client::NeighborReachabilityEvent& event);
} // namespace patchpanel
#endif // PATCHPANEL_DBUS_CLIENT_H_