blob: f9ad012c3fc1b39af5067dacf412e9efc2be21b7 [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
5#include "arc/network/datapath.h"
6
Garrick Evans54861622019-07-19 09:05:09 +09007#include <base/strings/string_number_conversions.h>
8
Garrick Evansf0ab7132019-06-18 14:50:42 +09009namespace arc_networkd {
Garrick Evans54861622019-07-19 09:05:09 +090010
Garrick Evans8a949dc2019-07-18 16:17:53 +090011constexpr char kDefaultNetmask[] = "255.255.255.252";
Garrick Evans54861622019-07-19 09:05:09 +090012
13std::string ArcVethHostName(std::string ifname) {
14 return "veth_" + ifname;
15}
16
17std::string ArcVethPeerName(std::string ifname) {
18 return "peer_" + ifname;
19}
Garrick Evansf0ab7132019-06-18 14:50:42 +090020
21Datapath::Datapath(MinijailedProcessRunner* process_runner)
22 : process_runner_(process_runner) {
23 CHECK(process_runner_);
24}
25
Garrick Evans8a949dc2019-07-18 16:17:53 +090026bool Datapath::AddBridge(const std::string& ifname,
27 const std::string& ipv4_addr) {
28 // Configure the persistent Chrome OS bridge interface with static IP.
29 if (process_runner_->Run({kBrctlPath, "addbr", ifname}) != 0) {
30 return false;
31 }
32
33 if (process_runner_->Run({kIfConfigPath, ifname, ipv4_addr, "netmask",
34 kDefaultNetmask, "up"}) != 0) {
35 RemoveBridge(ifname);
36 return false;
37 }
38
39 // See nat.conf in chromeos-nat-init for the rest of the NAT setup rules.
40 if (process_runner_->Run({kIpTablesPath, "-t", "mangle", "-A", "PREROUTING",
41 "-i", ifname, "-j", "MARK", "--set-mark", "1",
42 "-w"}) != 0) {
43 RemoveBridge(ifname);
44 return false;
45 }
46
47 return true;
48}
49
50void Datapath::RemoveBridge(const std::string& ifname) {
51 process_runner_->Run({kIpTablesPath, "-t", "mangle", "-D", "PREROUTING", "-i",
52 ifname, "-j", "MARK", "--set-mark", "1", "-w"});
53 process_runner_->Run({kIfConfigPath, ifname, "down"});
54 process_runner_->Run({kBrctlPath, "delbr", ifname});
55}
56
Garrick Evans54861622019-07-19 09:05:09 +090057std::string Datapath::AddVirtualBridgedInterface(const std::string& ifname,
58 const std::string& mac_addr,
59 const std::string& br_ifname) {
60 const std::string veth = ArcVethHostName(ifname);
61 const std::string peer = ArcVethPeerName(ifname);
62
63 RemoveInterface(veth);
64 if (process_runner_->Run({kIpPath, "link", "add", veth, "type", "veth",
65 "peer", "name", peer}) != 0) {
66 return "";
67 }
68
69 if (process_runner_->Run({kIfConfigPath, veth, "up"}) != 0) {
70 RemoveInterface(veth);
71 RemoveInterface(peer);
72 return "";
73 }
74
75 if (process_runner_->Run({kIpPath, "link", "set", "dev", peer, "addr",
76 mac_addr, "down"}) != 0) {
77 RemoveInterface(veth);
78 RemoveInterface(peer);
79 return "";
80 }
81
82 if (process_runner_->Run({kBrctlPath, "addif", br_ifname, veth}) != 0) {
83 RemoveInterface(veth);
84 RemoveInterface(peer);
85 return "";
86 }
87
88 return peer;
89}
90
91void Datapath::RemoveInterface(const std::string& ifname) {
92 process_runner_->Run({kIpPath, "link", "delete", ifname}, false /* log */);
93}
94
95bool Datapath::AddInterfaceToContainer(int ns,
96 const std::string& src_ifname,
97 const std::string& dst_ifname,
98 const std::string& dst_ipv4,
99 bool fwd_multicast) {
100 const std::string pid = base::IntToString(ns);
101 return (process_runner_->Run(
102 {kIpPath, "link", "set", src_ifname, "netns", pid}) == 0) &&
103 (process_runner_->AddInterfaceToContainer(src_ifname, dst_ifname,
104 dst_ipv4, kDefaultNetmask,
105 fwd_multicast, pid) == 0);
106}
107
Garrick Evansf0ab7132019-06-18 14:50:42 +0900108bool Datapath::AddLegacyIPv4DNAT(const std::string& ipv4_addr) {
109 // Forward "unclaimed" packets to Android to allow inbound connections
110 // from devices on the LAN.
111 if (process_runner_->Run(
112 {kIpTablesPath, "-t", "nat", "-N", "dnat_arc", "-w"}) != 0)
113 return false;
114
115 if (process_runner_->Run({kIpTablesPath, "-t", "nat", "-A", "dnat_arc", "-j",
116 "DNAT", "--to-destination", ipv4_addr, "-w"}) !=
117 0) {
Garrick Evans54861622019-07-19 09:05:09 +0900118 RemoveLegacyIPv4DNAT();
Garrick Evansf0ab7132019-06-18 14:50:42 +0900119 return false;
120 }
121
122 // This chain is dynamically updated whenever the default interface
123 // changes.
124 if (process_runner_->Run(
125 {kIpTablesPath, "-t", "nat", "-N", "try_arc", "-w"}) != 0) {
126 RemoveLegacyIPv4DNAT();
127 return false;
128 }
129
130 if (process_runner_->Run({kIpTablesPath, "-t", "nat", "-A", "PREROUTING",
131 "-m", "socket", "--nowildcard", "-j", "ACCEPT",
132 "-w"}) != 0) {
133 RemoveLegacyIPv4DNAT();
134 return false;
135 }
136
137 if (process_runner_->Run({kIpTablesPath, "-t", "nat", "-A", "PREROUTING",
138 "-p", "tcp", "-j", "try_arc", "-w"}) != 0) {
139 RemoveLegacyIPv4DNAT();
140 return false;
141 }
142
143 if (process_runner_->Run({kIpTablesPath, "-t", "nat", "-A", "PREROUTING",
144 "-p", "udp", "-j", "try_arc", "-w"}) != 0) {
145 RemoveLegacyIPv4DNAT();
146 return false;
147 }
148
149 return true;
150}
151
152void Datapath::RemoveLegacyIPv4DNAT() {
153 process_runner_->Run({kIpTablesPath, "-t", "nat", "-D", "PREROUTING", "-p",
154 "udp", "-j", "try_arc", "-w"});
155 process_runner_->Run({kIpTablesPath, "-t", "nat", "-D", "PREROUTING", "-p",
156 "tcp", "-j", "try_arc", "-w"});
157 process_runner_->Run({kIpTablesPath, "-t", "nat", "-D", "PREROUTING", "-m",
158 "socket", "--nowildcard", "-j", "ACCEPT", "-w"});
159 process_runner_->Run({kIpTablesPath, "-t", "nat", "-F", "try_arc", "-w"});
160 process_runner_->Run({kIpTablesPath, "-t", "nat", "-X", "try_arc", "-w"});
161 process_runner_->Run({kIpTablesPath, "-t", "nat", "-F", "dnat_arc", "-w"});
162 process_runner_->Run({kIpTablesPath, "-t", "nat", "-X", "dnat_arc", "-w"});
163}
164
Garrick Evans54861622019-07-19 09:05:09 +0900165bool Datapath::AddLegacyIPv4InboundDNAT(const std::string& ifname) {
166 return (process_runner_->Run({kIpTablesPath, "-t", "nat", "-A", "try_arc",
167 "-i", ifname, "-j", "dnat_arc", "-w"}) != 0);
168}
169
170void Datapath::RemoveLegacyIPv4InboundDNAT() {
171 process_runner_->Run({kIpTablesPath, "-t", "nat", "-F", "try_arc", "-w"});
172}
173
Garrick Evansf0ab7132019-06-18 14:50:42 +0900174bool Datapath::AddInboundIPv4DNAT(const std::string& ifname,
175 const std::string& ipv4_addr) {
176 // Direct ingress IP traffic to existing sockets.
177 if (process_runner_->Run({kIpTablesPath, "-t", "nat", "-A", "PREROUTING",
178 "-i", ifname, "-m", "socket", "--nowildcard", "-j",
179 "ACCEPT", "-w"}) != 0)
180 return false;
181
182 // Direct ingress TCP & UDP traffic to ARC interface for new connections.
183 if (process_runner_->Run({kIpTablesPath, "-t", "nat", "-A", "PREROUTING",
184 "-i", ifname, "-p", "tcp", "-j", "DNAT",
185 "--to-destination", ipv4_addr, "-w"}) != 0) {
186 RemoveInboundIPv4DNAT(ifname, ipv4_addr);
187 return false;
188 }
189 if (process_runner_->Run({kIpTablesPath, "-t", "nat", "-A", "PREROUTING",
190 "-i", ifname, "-p", "udp", "-j", "DNAT",
191 "--to-destination", ipv4_addr, "-w"}) != 0) {
192 RemoveInboundIPv4DNAT(ifname, ipv4_addr);
193 return false;
194 }
195
196 return true;
197}
198
199void Datapath::RemoveInboundIPv4DNAT(const std::string& ifname,
200 const std::string& ipv4_addr) {
201 process_runner_->Run({kIpTablesPath, "-t", "nat", "-D", "PREROUTING", "-i",
202 ifname, "-p", "udp", "-j", "DNAT", "--to-destination",
203 ipv4_addr, "-w"});
204 process_runner_->Run({kIpTablesPath, "-t", "nat", "-D", "PREROUTING", "-i",
205 ifname, "-p", "tcp", "-j", "DNAT", "--to-destination",
206 ipv4_addr, "-w"});
207 process_runner_->Run({kIpTablesPath, "-t", "nat", "-D", "PREROUTING", "-i",
208 ifname, "-m", "socket", "--nowildcard", "-j", "ACCEPT",
209 "-w"});
210}
211
212bool Datapath::AddOutboundIPv4(const std::string& ifname) {
213 return process_runner_->Run({kIpTablesPath, "-t", "filter", "-A", "FORWARD",
214 "-o", ifname, "-j", "ACCEPT", "-w"}) == 0;
215}
216
217void Datapath::RemoveOutboundIPv4(const std::string& ifname) {
218 process_runner_->Run({kIpTablesPath, "-t", "filter", "-D", "FORWARD", "-o",
219 ifname, "-j", "ACCEPT", "-w"});
220}
221
Garrick Evansf0ab7132019-06-18 14:50:42 +0900222} // namespace arc_networkd