blob: 74d1789f577cd927216886cd87480f8e7d35af7d [file] [log] [blame]
Hugo Benichi7d9d8db2020-03-30 15:56:56 +09001// Copyright 2020 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Garrick Evans3388a032020-03-24 11:25:55 +09005#ifndef PATCHPANEL_ROUTING_SERVICE_H_
6#define PATCHPANEL_ROUTING_SERVICE_H_
Hugo Benichi7d9d8db2020-03-30 15:56:56 +09007
Hugo Benichi08805972020-07-15 22:34:57 +09008#include <arpa/inet.h>
Hugo Benichi7d9d8db2020-03-30 15:56:56 +09009#include <stdint.h>
10#include <sys/socket.h>
11
Hugo Benichi08805972020-07-15 22:34:57 +090012#include <array>
13#include <string>
14
15#include <base/strings/stringprintf.h>
16
Hugo Benichi7d9d8db2020-03-30 15:56:56 +090017#include <patchpanel/proto_bindings/patchpanel_service.pb.h>
18
Garrick Evans3388a032020-03-24 11:25:55 +090019namespace patchpanel {
Hugo Benichi7d9d8db2020-03-30 15:56:56 +090020
Hugo Benichiaf9d8a72020-08-26 13:28:13 +090021// Constant used for establishing a stable mapping between routing table ids
22// and interface indexes. An interface with ifindex 2 will be assigned the
23// routing table with id 1002 by the routing layer. This stable mapping is used
24// for configuring ip rules, iptables fwmark mangle rules, and the
25// accept_ra_rt_table sysctl for all physical interfaces.
26// TODO(b/161507671) Consolidate with shill::kInterfaceTableIdIncrement
27// in platform2/shill/routing_table.cc once routing and ip rule configuration
28// is migrated to patchpanel.
29constexpr const uint32_t kInterfaceTableIdIncrement = 1000;
30
Hugo Benichi08805972020-07-15 22:34:57 +090031// The list of all sources of traffic that need to be distinguished
32// for routing or traffic accounting. Currently 6 bits are used for encoding
33// the TrafficSource enum in a fwmark. The enum is split into two groups:local
34// sources and forwarded sources. The enum values of forwarded sources are
35// offset by 0x20 so that their most significant bit is always set and can be
36// easily matched separately from local sources.
37enum TrafficSource {
38 UNKNOWN = 0,
39
40 // Local sources:
41 // Traffic corresponding to uid "chronos".
42 CHROME = 1,
43 // Other uids classified as "user" for traffic purposes: debugd, cups,
44 // tlsdate, pluginvm, etc.
45 USER = 2,
46 // Traffic from Update engine.
47 UPDATE_ENGINE = 3,
48 // Other system traffic.
49 SYSTEM = 4,
50 // Traffic emitted on an underlying physical network by the built-in OpenVPN
51 // and L2TP clients, or Chrome 3rd party VPN Apps. This traffic constitutes
52 // the VPN tunnel.
53 HOST_VPN = 5,
54
55 // Forwarded sources:
56 // ARC++ and ARCVM.
57 ARC = 0x20,
58 // Crostini VMs and lxc containers.
59 CROSVM = 0x21,
60 // Other plugin VMs.
61 PLUGINVM = 0x22,
62 // A tethered downstream network. Currently reserved for future use.
63 TETHER_DOWNSTREAM = 0x23,
64 // Traffic emitted by Android VPNs for their tunnelled connections.
65 ARC_VPN = 0x24,
66};
67
68// A representation of how fwmark bits are split and used for tagging and
69// routing traffic. The 32 bits of the fwmark are currently organized as such:
70// 0 1 2 3
71// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
72// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
73// | routing table id |VPN|source enum| reserved |*|
74// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
75//
76// routing table id (16bits): the routing table id of a physical device managed
77// by shill or of a virtual private network.
78// VPN (2bits): policy bits controlled by host application to force VPN routing
79// or bypass VPN routing.
80// source enum(6bits): policy bits controlled by patchpanel for grouping
81// originated traffic by domain.
82// reserved(7bits): no usage at the moment.
83// legacy SNAT(1bit): legacy bit used for setting up SNAT for ARC, Crostini, and
84// PluginVMs with iptables MASQUERADE.
85//
86// Note that bitfields are not a portable way to define a
87// stable Fwmark. Also note that the in-memory representation of values of
88// this union changes depending on endianness, so care must be taken when
89// serializing or deserializing Fwmark values, or when aliasing with raw bytes
90// through pointers. In practice client code should not rely on a specific
91// memory representation and should instead use ToString() and Value().
92union Fwmark {
93 struct {
94 // The LSB is currently only used for applying IPv4 SNAT to egress traffic
95 // from ARC and other VMs; indicated by a value of 1.
96 uint8_t legacy;
97 // The 3rd byte is used to store the intent and policy to be applied to the
98 // traffic. The first 2 bits are used for host processes to select a VPN
99 // routing intent via patchpanel SetVpnIntent API. The next 6 bits of are
100 // used for tagging the traffic with a source.
101 uint8_t policy;
102 // The 2 upper bytes corresponds to the routing table id associated with
103 // a shill device or a VPN.
104 uint16_t rt_table_id;
105 };
106 // The raw memory representation of this fwmark as a uint32_t.
107 uint32_t fwmark;
108
109 // Returns a String representation of this Fwmark. This should
110 std::string ToString() const {
111 return base::StringPrintf("0x%04x%02x%02x", rt_table_id, policy, legacy);
112 }
113
114 // Returns the logical uint32_t value of this Fwmark.
115 uint32_t Value() const { return rt_table_id << 16 | policy << 8 | legacy; }
116
117 constexpr TrafficSource Source() {
118 return static_cast<TrafficSource>(policy & 0x3f);
119 }
120
121 constexpr bool operator==(Fwmark that) const { return fwmark == that.fwmark; }
122
123 constexpr Fwmark operator|(Fwmark that) const {
124 return {.fwmark = fwmark | that.fwmark};
125 }
126
127 constexpr Fwmark operator&(Fwmark that) const {
128 return {.fwmark = fwmark & that.fwmark};
129 }
130
131 constexpr Fwmark operator~() const { return {.fwmark = ~fwmark}; }
132
133 static Fwmark FromSource(TrafficSource source) {
134 return {
135 .policy = static_cast<uint8_t>(source), .legacy = 0, .rt_table_id = 0};
136 }
Hugo Benichiaf9d8a72020-08-26 13:28:13 +0900137
138 static Fwmark FromIfIndex(uint32_t ifindex) {
139 uint32_t table_id = ifindex + kInterfaceTableIdIncrement;
140 return {.policy = 0,
141 .legacy = 0,
142 .rt_table_id = static_cast<uint16_t>(table_id)};
143 }
Hugo Benichi08805972020-07-15 22:34:57 +0900144};
145
146// All local sources
147constexpr std::array<TrafficSource, 5> kLocalSources{
148 {CHROME, USER, UPDATE_ENGINE, SYSTEM, HOST_VPN}};
149
150// All forwarded sources
151constexpr std::array<TrafficSource, 5> kForwardedSources{
152 {ARC, CROSVM, PLUGINVM, TETHER_DOWNSTREAM, ARC_VPN}};
153
154// Constant fwmark value for tagging traffic with the "route-on-vpn" intent.
155constexpr const Fwmark kFwmarkRouteOnVpn = {.policy = 0x80};
156// Constant fwmark value for tagging traffic with the "bypass-vpn" intent.
157constexpr const Fwmark kFwmarkBypassVpn = {.policy = 0x40};
158// constexpr const Fwmark kFwmarkVpnMask = kFwmarkRouteOnVpn | kFwmarkBypassVpn;
159constexpr const Fwmark kFwmarkVpnMask = {.policy = 0xc0};
160// A mask for matching fwmarks on the routing table id.
161constexpr const Fwmark kFwmarkRoutingMask = {.rt_table_id = 0xffff};
162// A mask for matching fwmarks on the source.
163constexpr const Fwmark kFwmarkAllSourcesMask = {.policy = 0x3f};
164// A mast for matching fwmarks of forwarded sources.
165constexpr const Fwmark kFwmarkForwardedSourcesMask = {.policy = 0x20};
166// Both the mask and fwmark values for legacy SNAT rules used for ARC and other
167// containers.
168constexpr const Fwmark kFwmarkLegacySNAT = {.legacy = 0x1};
169
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900170// Service implementing routing features of patchpanel.
171// TODO(hugobenichi) Explain how this coordinates with shill's RoutingTable.
172class RoutingService {
173 public:
174 RoutingService();
175 RoutingService(const RoutingService&) = delete;
176 RoutingService& operator=(const RoutingService&) = delete;
177 virtual ~RoutingService() = default;
178
179 // Sets the VPN bits of the fwmark for the given socket according to the
180 // given policy. Preserves any other bits of the fwmark already set.
181 bool SetVpnFwmark(int sockfd,
182 patchpanel::SetVpnIntentRequest::VpnRoutingPolicy policy);
183
184 // Sets the fwmark on the given socket with the given mask.
185 // Preserves any other bits of the fwmark already set.
Hugo Benichi08805972020-07-15 22:34:57 +0900186 bool SetFwmark(int sockfd, Fwmark mark, Fwmark mask);
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900187
188 protected:
189 // Can be overridden in tests.
190 virtual int GetSockopt(
191 int sockfd, int level, int optname, void* optval, socklen_t* optlen);
192 virtual int SetSockopt(
193 int sockfd, int level, int optname, const void* optval, socklen_t optlen);
194};
195
Garrick Evans3388a032020-03-24 11:25:55 +0900196} // namespace patchpanel
Hugo Benichi7d9d8db2020-03-30 15:56:56 +0900197
Garrick Evans3388a032020-03-24 11:25:55 +0900198#endif // PATCHPANEL_ROUTING_SERVICE_H_