blob: adde6d0f02e87db9a6a7d4733a6f5ec75b459a22 [file] [log] [blame]
Garrick Evansf0ab7132019-06-18 14:50:42 +09001// Copyright 2019 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_DATAPATH_H_
6#define PATCHPANEL_DATAPATH_H_
Garrick Evansf0ab7132019-06-18 14:50:42 +09007
Hugo Benichie8758b52020-04-03 14:49:01 +09008#include <net/route.h>
Hugo Benichi33860d72020-07-09 16:34:01 +09009#include <sys/types.h>
Hugo Benichie8758b52020-04-03 14:49:01 +090010
Hugo Benichifcf81022020-12-04 11:01:37 +090011#include <iostream>
Hugo Benichi2a940542020-10-26 18:50:49 +090012#include <set>
Garrick Evansf0ab7132019-06-18 14:50:42 +090013#include <string>
Hugo Benichi2a940542020-10-26 18:50:49 +090014#include <vector>
Garrick Evansf0ab7132019-06-18 14:50:42 +090015
16#include <base/macros.h>
Hugo Benichi82ed5cf2020-09-08 21:30:22 +090017#include <gtest/gtest_prod.h> // for FRIEND_TEST
Garrick Evansf0ab7132019-06-18 14:50:42 +090018
Jason Jeremy Imana7273a32020-08-04 11:25:31 +090019#include "patchpanel/firewall.h"
Garrick Evans3388a032020-03-24 11:25:55 +090020#include "patchpanel/mac_address_generator.h"
21#include "patchpanel/minijailed_process_runner.h"
Hugo Benichi8d622b52020-08-13 15:24:12 +090022#include "patchpanel/routing_service.h"
Garrick Evans3388a032020-03-24 11:25:55 +090023#include "patchpanel/subnet.h"
Garrick Evansf0ab7132019-06-18 14:50:42 +090024
Garrick Evans3388a032020-03-24 11:25:55 +090025namespace patchpanel {
Garrick Evansf0ab7132019-06-18 14:50:42 +090026
Hugo Benichifcf81022020-12-04 11:01:37 +090027// Struct holding parameters for Datapath::StartRoutingNamespace requests.
28struct ConnectedNamespace {
29 // The pid of the client network namespace.
30 pid_t pid;
31 // The name attached to the client network namespace.
32 std::string netns_name;
33 // Name of the shill device for routing outbound traffic from the client
34 // namespace. Empty if outbound traffic should be forwarded to the highest
35 // priority network (physical or virtual).
36 std::string outbound_ifname;
37 // Name of the "local" veth device visible on the host namespace.
38 std::string host_ifname;
39 // Name of the "remote" veth device moved into the client namespace.
40 std::string peer_ifname;
41 // IPv4 subnet assigned to the client namespace.
42 std::unique_ptr<Subnet> peer_subnet;
43 // MAC address of the "remote" veth device.
44 MacAddress peer_mac_addr;
45};
46
47std::ostream& operator<<(std::ostream& stream,
48 const ConnectedNamespace& nsinfo);
49
Hugo Benichid82d8832020-08-14 10:05:03 +090050// Simple enum of bitmasks used for specifying a set of IP family values.
51enum IpFamily {
52 NONE = 0,
53 IPv4 = 1 << 0,
54 IPv6 = 1 << 1,
Taoyu Lia0727dc2020-09-24 19:54:59 +090055 Dual = IPv4 | IPv6, // (1 << 0) | (1 << 1);
Hugo Benichid82d8832020-08-14 10:05:03 +090056};
57
Taoyu Li90c13912019-11-26 17:56:54 +090058// cros lint will yell to force using int16/int64 instead of long here, however
59// note that unsigned long IS the correct signature for ioctl in Linux kernel -
60// it's 32 bits on 32-bit platform and 64 bits on 64-bit one.
61using ioctl_req_t = unsigned long;
62typedef int (*ioctl_t)(int, ioctl_req_t, ...);
Garrick Evansc7ae82c2019-09-04 16:25:10 +090063
Garrick Evans54861622019-07-19 09:05:09 +090064// Returns for given interface name the host name of a ARC veth pair.
Garrick Evans2f581a02020-05-11 10:43:35 +090065std::string ArcVethHostName(const std::string& ifname);
Garrick Evans54861622019-07-19 09:05:09 +090066
Garrick Evans8a067562020-05-11 12:47:30 +090067// Returns the ARC bridge interface name for the given interface.
68std::string ArcBridgeName(const std::string& ifname);
69
Garrick Evansf0ab7132019-06-18 14:50:42 +090070// ARC networking data path configuration utility.
Garrick Evans54861622019-07-19 09:05:09 +090071// IPV4 addresses are always specified in singular dotted-form (a.b.c.d)
72// (not in CIDR representation
Garrick Evansf0ab7132019-06-18 14:50:42 +090073class Datapath {
74 public:
Jason Jeremy Imana7273a32020-08-04 11:25:31 +090075 // |process_runner| and |firewall| must not be null; it is not owned.
76 Datapath(MinijailedProcessRunner* process_runner, Firewall* firewall);
Garrick Evansc7ae82c2019-09-04 16:25:10 +090077 // Provided for testing only.
Jason Jeremy Imana7273a32020-08-04 11:25:31 +090078 Datapath(MinijailedProcessRunner* process_runner,
79 Firewall* firewall,
80 ioctl_t ioctl_hook);
Qijiang Fan6bc59e12020-11-11 02:51:06 +090081 Datapath(const Datapath&) = delete;
82 Datapath& operator=(const Datapath&) = delete;
83
Garrick Evansf0ab7132019-06-18 14:50:42 +090084 virtual ~Datapath() = default;
85
Hugo Benichibf811c62020-09-07 17:30:45 +090086 // Start and stop the Datapath, creating or destroying the initial iptables
87 // setup needed for forwarding traffic from VMs and containers and for
88 // fwmark based routing.
89 virtual void Start();
90 virtual void Stop();
91
Hugo Benichi33860d72020-07-09 16:34:01 +090092 // Attaches the name |netns_name| to a network namespace identified by
93 // |netns_pid|. If |netns_name| had already been created, it will be deleted
94 // first.
95 virtual bool NetnsAttachName(const std::string& netns_name, pid_t netns_pid);
96
97 // Deletes the name |netns_name| of a network namespace.
98 virtual bool NetnsDeleteName(const std::string& netns_name);
99
Garrick Evans8a949dc2019-07-18 16:17:53 +0900100 virtual bool AddBridge(const std::string& ifname,
Garrick Evans7a1a9ee2020-01-28 11:03:57 +0900101 uint32_t ipv4_addr,
102 uint32_t ipv4_prefix_len);
Garrick Evans8a949dc2019-07-18 16:17:53 +0900103 virtual void RemoveBridge(const std::string& ifname);
104
Garrick Evans621ed262019-11-13 12:28:43 +0900105 virtual bool AddToBridge(const std::string& br_ifname,
106 const std::string& ifname);
107
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900108 // Adds a new TAP device.
109 // |name| may be empty, in which case a default device name will be used;
110 // it may be a template (e.g. vmtap%d), in which case the kernel will
111 // generate the name; or it may be fully defined. In all cases, upon success,
112 // the function returns the actual name of the interface.
Garrick Evans621ed262019-11-13 12:28:43 +0900113 // |mac_addr| and |ipv4_addr| should be null if this interface will be later
114 // bridged.
Garrick Evans4f9f5572019-11-26 10:25:16 +0900115 // If |user| is empty, no owner will be set
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900116 virtual std::string AddTAP(const std::string& name,
Garrick Evans621ed262019-11-13 12:28:43 +0900117 const MacAddress* mac_addr,
118 const SubnetAddress* ipv4_addr,
Garrick Evans4f9f5572019-11-26 10:25:16 +0900119 const std::string& user);
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900120
121 // |ifname| must be the actual name of the interface.
122 virtual void RemoveTAP(const std::string& ifname);
123
124 // The following are iptables methods.
125 // When specified, |ipv4_addr| is always singlar dotted-form (a.b.c.d)
126 // IPv4 address (not a CIDR representation).
127
Hugo Benichi76675592020-04-08 14:29:57 +0900128 // Creates a virtual interface pair split across the current namespace and the
129 // namespace corresponding to |pid|, and set up the remote interface
130 // |peer_ifname| according // to the given parameters.
131 virtual bool ConnectVethPair(pid_t pid,
Hugo Benichi33860d72020-07-09 16:34:01 +0900132 const std::string& netns_name,
Hugo Benichi76675592020-04-08 14:29:57 +0900133 const std::string& veth_ifname,
134 const std::string& peer_ifname,
135 const MacAddress& remote_mac_addr,
136 uint32_t remote_ipv4_addr,
137 uint32_t remote_ipv4_prefix_len,
138 bool remote_multicast_flag);
139
Garrick Evans54861622019-07-19 09:05:09 +0900140 virtual void RemoveInterface(const std::string& ifname);
141
Hugo Benichi321f23b2020-09-25 15:42:05 +0900142 // Create (or delete) an OUTPUT DROP rule for any locally originated traffic
143 // whose src IPv4 matches |src_ip| and would exit |oif|. This is mainly used
144 // for dropping Chrome webRTC traffic incorrectly bound on ARC and other
145 // guests virtual interfaces (chromium:898210).
146 virtual bool AddSourceIPv4DropRule(const std::string& oif,
147 const std::string& src_ip);
148 virtual bool RemoveSourceIPv4DropRule(const std::string& oif,
149 const std::string& src_ip);
150
Hugo Benichi7c342672020-09-08 09:18:14 +0900151 // Creates a virtual ethernet interface pair shared with the client namespace
Hugo Benichifcf81022020-12-04 11:01:37 +0900152 // of |nsinfo.pid| and sets up routing outside and inside the client namespace
153 // for connecting the client namespace to the network.
154 bool StartRoutingNamespace(const ConnectedNamespace& nsinfo);
Hugo Benichi7c342672020-09-08 09:18:14 +0900155 // Destroys the virtual ethernet interface, routing, and network namespace
Hugo Benichifcf81022020-12-04 11:01:37 +0900156 // name set for |nsinfo.netns_name| by StartRoutingNamespace. The default
157 // route set inside the |nsinfo.netns_name| by patchpanel is not destroyed and
158 // it is assumed the client will teardown the namespace.
159 void StopRoutingNamespace(const ConnectedNamespace& nsinfo);
Hugo Benichi7c342672020-09-08 09:18:14 +0900160
Hugo Benichi8d622b52020-08-13 15:24:12 +0900161 // Sets up IPv4 SNAT, IP forwarding, and traffic marking for the given
162 // virtual device |int_ifname| associated to |source|. if |ext_ifname| is
163 // empty, the device is implicitly routed through the highest priority
164 // network.
165 virtual void StartRoutingDevice(const std::string& ext_ifname,
166 const std::string& int_ifname,
167 uint32_t int_ipv4_addr,
168 TrafficSource source);
169
170 // Removes IPv4 iptables, IP forwarding, and traffic marking for the given
171 // virtual device |int_ifname|.
172 virtual void StopRoutingDevice(const std::string& ext_ifname,
173 const std::string& int_ifname,
174 uint32_t int_ipv4_addr,
175 TrafficSource source);
176
Hugo Benichi76be34a2020-08-26 22:35:54 +0900177 // Starts or stops marking conntrack entries routed to |ext_ifname| with its
178 // associated fwmark routing tag. Once a conntrack entry is marked with the
179 // fwmark routing tag of a external device, the connection will be pinned
180 // to that deviced if conntrack fwmark restore is set for the source.
181 virtual void StartConnectionPinning(const std::string& ext_ifname);
182 virtual void StopConnectionPinning(const std::string& ext_ifname);
Hugo Benichi2a940542020-10-26 18:50:49 +0900183 // Starts or stops VPN routing for:
184 // - Local sockets of binaries running under uids eligible to be routed
185 // through VPN connections. These uids are defined by |kLocalSourceTypes|
186 // in routing_service.h
187 // - Forwarded virtual devices tracking the default network.
188 virtual void StartVpnRouting(const std::string& vpn_ifname);
189 virtual void StopVpnRouting(const std::string& vpn_ifname);
Hugo Benichi76be34a2020-08-26 22:35:54 +0900190
Taoyu Li90c13912019-11-26 17:56:54 +0900191 // Methods supporting IPv6 configuration for ARC.
Garrick Evans664a82f2019-12-17 12:18:05 +0900192 virtual bool MaskInterfaceFlags(const std::string& ifname,
193 uint16_t on,
194 uint16_t off = 0);
Garrick Evans260ff302019-07-25 11:22:50 +0900195
Hugo Benichid82d8832020-08-14 10:05:03 +0900196 // Convenience functions for enabling or disabling IPv6 forwarding in both
197 // directions between a pair of interfaces
Taoyu Li90c13912019-11-26 17:56:54 +0900198 virtual bool AddIPv6Forwarding(const std::string& ifname1,
199 const std::string& ifname2);
200 virtual void RemoveIPv6Forwarding(const std::string& ifname1,
201 const std::string& ifname2);
202
Garrick Evans260ff302019-07-25 11:22:50 +0900203 virtual bool AddIPv6HostRoute(const std::string& ifname,
204 const std::string& ipv6_addr,
205 int ipv6_prefix_len);
206 virtual void RemoveIPv6HostRoute(const std::string& ifname,
207 const std::string& ipv6_addr,
208 int ipv6_prefix_len);
209
Taoyu Lia0727dc2020-09-24 19:54:59 +0900210 virtual bool AddIPv6Address(const std::string& ifname,
211 const std::string& ipv6_addr);
212 virtual void RemoveIPv6Address(const std::string& ifname,
213 const std::string& ipv6_addr);
Garrick Evans260ff302019-07-25 11:22:50 +0900214
Hugo Benichie8758b52020-04-03 14:49:01 +0900215 // Adds (or deletes) a route to direct to |gateway_addr| the traffic destined
216 // to the subnet defined by |addr| and |netmask|.
Garrick Evans3d97a392020-02-21 15:24:37 +0900217 virtual bool AddIPv4Route(uint32_t gateway_addr,
218 uint32_t addr,
219 uint32_t netmask);
Hugo Benichie8758b52020-04-03 14:49:01 +0900220 virtual bool DeleteIPv4Route(uint32_t gateway_addr,
221 uint32_t addr,
222 uint32_t netmask);
223 // Adds (or deletes) a route to direct to |ifname| the traffic destined to the
224 // subnet defined by |addr| and |netmask|.
225 virtual bool AddIPv4Route(const std::string& ifname,
226 uint32_t addr,
227 uint32_t netmask);
228 virtual bool DeleteIPv4Route(const std::string& ifname,
229 uint32_t addr,
230 uint32_t netmask);
Garrick Evans3d97a392020-02-21 15:24:37 +0900231
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900232 // Adds (or deletes) an iptables rule for ADB port forwarding.
233 virtual bool AddAdbPortForwardRule(const std::string& ifname);
234 virtual void DeleteAdbPortForwardRule(const std::string& ifname);
235
236 // Adds (or deletes) an iptables rule for ADB port access.
237 virtual bool AddAdbPortAccessRule(const std::string& ifname);
238 virtual void DeleteAdbPortAccessRule(const std::string& ifname);
239
Hugo Benichiaf9d8a72020-08-26 13:28:13 +0900240 // Set or override the interface name to index mapping for |ifname|.
241 // Only used for testing.
242 void SetIfnameIndex(const std::string& ifname, int ifindex);
243
Hugo Benichicd27f4e2020-11-19 18:32:23 +0900244 // Manipulates a chain |chain| in table |table|.
245 bool ModifyChain(IpFamily family,
246 const std::string& table,
247 const std::string& op,
248 const std::string& chain,
249 bool log_failures = true);
250
Garrick Evans260ff302019-07-25 11:22:50 +0900251 MinijailedProcessRunner& runner() const;
252
Garrick Evansf0ab7132019-06-18 14:50:42 +0900253 private:
Hugo Benichi82ed5cf2020-09-08 21:30:22 +0900254 // Creates a virtual interface pair.
255 bool AddVirtualInterfacePair(const std::string& netns_name,
256 const std::string& veth_ifname,
257 const std::string& peer_ifname);
258 // Sets the configuration of an interface.
259 bool ConfigureInterface(const std::string& ifname,
260 const MacAddress& mac_addr,
261 uint32_t ipv4_addr,
262 uint32_t ipv4_prefix_len,
263 bool up,
264 bool enable_multicast);
265 // Sets the link status.
266 bool ToggleInterface(const std::string& ifname, bool up);
267 // Starts or stops accepting IP traffic forwarded between |iif| and |oif|
268 // by adding or removing ACCEPT rules in the filter FORWARD chain of iptables
269 // and/or ip6tables. If |iif| is empty, only specifies |oif| as the output
270 // interface. If |iif| is empty, only specifies |iif| as the input interface.
271 // |oif| and |iif| cannot be both empty.
272 bool StartIpForwarding(IpFamily family,
273 const std::string& iif,
274 const std::string& oif);
275 bool StopIpForwarding(IpFamily family,
276 const std::string& iif,
277 const std::string& oif);
278 // Create (or delete) pre-routing rules allowing direct ingress on |ifname|
279 // to guest destination |ipv4_addr|.
280 bool AddInboundIPv4DNAT(const std::string& ifname,
281 const std::string& ipv4_addr);
282 void RemoveInboundIPv4DNAT(const std::string& ifname,
283 const std::string& ipv4_addr);
284 // Create (or delete) a forwarding rule for |ifname|.
Hugo Benichi82ed5cf2020-09-08 21:30:22 +0900285 // Creates (or deletes) the forwarding and postrouting rules for SNAT
286 // fwmarked IPv4 traffic.
287 bool AddSNATMarkRules();
288 void RemoveSNATMarkRules();
Hugo Benichi82ed5cf2020-09-08 21:30:22 +0900289 // Create (or delete) a mangle PREROUTING rule for marking IPv4 traffic
290 // outgoing of |ifname| with the SNAT fwmark value 0x1.
291 // TODO(hugobenichi) Refer to RoutingService to obtain the fwmark value and
292 // add a fwmark mask in the generated rule.
293 bool AddOutboundIPv4SNATMark(const std::string& ifname);
294 void RemoveOutboundIPv4SNATMark(const std::string& ifname);
Hugo Benichi82ed5cf2020-09-08 21:30:22 +0900295
Hugo Benichi76be34a2020-08-26 22:35:54 +0900296 bool ModifyConnmarkSetPostrouting(IpFamily family,
297 const std::string& op,
298 const std::string& oif);
Hugo Benichi3a9162b2020-09-09 15:47:40 +0900299 bool ModifyConnmarkSet(IpFamily family,
300 const std::string& chain,
301 const std::string& op,
302 const std::string& oif,
303 Fwmark mark,
304 Fwmark mask);
Hugo Benichiaf9d8a72020-08-26 13:28:13 +0900305 bool ModifyConnmarkRestore(IpFamily family,
306 const std::string& chain,
307 const std::string& op,
Hugo Benichi1af52392020-11-27 18:09:32 +0900308 const std::string& iif,
309 Fwmark mask);
310 bool ModifyConnmarkSave(IpFamily family,
311 const std::string& chain,
312 const std::string& op,
313 const std::string& oif,
314 Fwmark mask);
Hugo Benichi2a940542020-10-26 18:50:49 +0900315 bool ModifyFwmarkRoutingTag(const std::string& chain,
316 const std::string& op,
Hugo Benichiaf9d8a72020-08-26 13:28:13 +0900317 const std::string& ext_ifname,
318 const std::string& int_ifname);
Hugo Benichi9be19b12020-08-14 15:33:40 +0900319 bool ModifyFwmarkSourceTag(const std::string& op,
320 const std::string& iif,
321 TrafficSource source);
Hugo Benichi3a9162b2020-09-09 15:47:40 +0900322 bool ModifyFwmarkDefaultLocalSourceTag(const std::string& op,
323 TrafficSource source);
324 bool ModifyFwmarkLocalSourceTag(const std::string& op,
325 const LocalSourceSpecs& source);
326 bool ModifyFwmark(IpFamily family,
327 const std::string& chain,
328 const std::string& op,
329 const std::string& iif,
330 const std::string& uid_name,
Hugo Benichi7e3b1fc2020-11-19 15:47:05 +0900331 uint32_t classid,
Hugo Benichi3a9162b2020-09-09 15:47:40 +0900332 Fwmark mark,
333 Fwmark mask,
334 bool log_failures = true);
Hugo Benichid82d8832020-08-14 10:05:03 +0900335 bool ModifyIpForwarding(IpFamily family,
336 const std::string& op,
337 const std::string& iif,
338 const std::string& oif,
339 bool log_failures = true);
Hugo Benichi3ef370b2020-11-16 19:07:17 +0900340 bool ModifyFwmarkVpnJumpRule(const std::string& chain,
341 const std::string& op,
342 const std::string& iif,
343 Fwmark mark,
344 Fwmark mask);
Hugo Benichi3ef370b2020-11-16 19:07:17 +0900345 bool ModifyIptables(IpFamily family,
346 const std::string& table,
Hugo Benichi58f264a2020-10-16 18:16:05 +0900347 const std::vector<std::string>& argv,
348 bool log_failures = true);
Hugo Benichiaf9d8a72020-08-26 13:28:13 +0900349 bool ModifyRtentry(ioctl_req_t op, struct rtentry* route);
350 int FindIfIndex(const std::string& ifname);
Hugo Benichid82d8832020-08-14 10:05:03 +0900351
Garrick Evansf0ab7132019-06-18 14:50:42 +0900352 MinijailedProcessRunner* process_runner_;
Jason Jeremy Imana7273a32020-08-04 11:25:31 +0900353 Firewall* firewall_;
Garrick Evansc7ae82c2019-09-04 16:25:10 +0900354 ioctl_t ioctl_;
Garrick Evansf0ab7132019-06-18 14:50:42 +0900355
Hugo Benichi82ed5cf2020-09-08 21:30:22 +0900356 FRIEND_TEST(DatapathTest, AddInboundIPv4DNAT);
Hugo Benichi82ed5cf2020-09-08 21:30:22 +0900357 FRIEND_TEST(DatapathTest, AddOutboundIPv4SNATMark);
358 FRIEND_TEST(DatapathTest, AddSNATMarkRules);
359 FRIEND_TEST(DatapathTest, AddVirtualInterfacePair);
360 FRIEND_TEST(DatapathTest, ConfigureInterface);
Hugo Benichi82ed5cf2020-09-08 21:30:22 +0900361 FRIEND_TEST(DatapathTest, RemoveInboundIPv4DNAT);
Hugo Benichi82ed5cf2020-09-08 21:30:22 +0900362 FRIEND_TEST(DatapathTest, RemoveOutboundIPv4SNATMark);
363 FRIEND_TEST(DatapathTest, RemoveSNATMarkRules);
364 FRIEND_TEST(DatapathTest, StartStopIpForwarding);
365 FRIEND_TEST(DatapathTest, ToggleInterface);
366
Hugo Benichiaf9d8a72020-08-26 13:28:13 +0900367 // A map used for remembering the interface index of an interface. This
368 // information is necessary when cleaning up iptables fwmark rules that
369 // directly references the interface index. When removing these rules on
370 // an RTM_DELLINK event, the interface index cannot be retrieved anymore.
371 // A new entry is only added when a new physical device appears, and entries
372 // are not removed.
373 // TODO(b/161507671) Rely on RoutingService to obtain this information once
374 // shill/routing_table.cc has been migrated to patchpanel.
375 std::map<std::string, int> if_nametoindex_;
Garrick Evansf0ab7132019-06-18 14:50:42 +0900376};
377
Garrick Evans3388a032020-03-24 11:25:55 +0900378} // namespace patchpanel
Garrick Evansf0ab7132019-06-18 14:50:42 +0900379
Garrick Evans3388a032020-03-24 11:25:55 +0900380#endif // PATCHPANEL_DATAPATH_H_