Garrick Evans | f0ab713 | 2019-06-18 14:50:42 +0900 | [diff] [blame] | 1 | // 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 Evans | c7ae82c | 2019-09-04 16:25:10 +0900 | [diff] [blame] | 7 | #include <fcntl.h> |
| 8 | #include <linux/if_tun.h> |
| 9 | #include <linux/sockios.h> |
| 10 | #include <net/if.h> |
| 11 | #include <net/if_arp.h> |
| 12 | #include <netinet/in.h> |
| 13 | #include <string.h> |
| 14 | #include <sys/ioctl.h> |
| 15 | #include <sys/socket.h> |
| 16 | |
| 17 | #include <base/files/scoped_file.h> |
| 18 | #include <base/logging.h> |
Garrick Evans | 5486162 | 2019-07-19 09:05:09 +0900 | [diff] [blame] | 19 | #include <base/strings/string_number_conversions.h> |
| 20 | |
Garrick Evans | c7ae82c | 2019-09-04 16:25:10 +0900 | [diff] [blame] | 21 | #include "arc/network/net_util.h" |
| 22 | |
Garrick Evans | f0ab713 | 2019-06-18 14:50:42 +0900 | [diff] [blame] | 23 | namespace arc_networkd { |
Garrick Evans | 5486162 | 2019-07-19 09:05:09 +0900 | [diff] [blame] | 24 | |
Garrick Evans | c7ae82c | 2019-09-04 16:25:10 +0900 | [diff] [blame] | 25 | namespace { |
Garrick Evans | 8a949dc | 2019-07-18 16:17:53 +0900 | [diff] [blame] | 26 | constexpr char kDefaultNetmask[] = "255.255.255.252"; |
Garrick Evans | c7ae82c | 2019-09-04 16:25:10 +0900 | [diff] [blame] | 27 | constexpr char kDefaultIfname[] = "vmtap%d"; |
| 28 | constexpr char kTunDev[] = "/dev/net/tun"; |
| 29 | } // namespace |
Garrick Evans | 5486162 | 2019-07-19 09:05:09 +0900 | [diff] [blame] | 30 | |
| 31 | std::string ArcVethHostName(std::string ifname) { |
| 32 | return "veth_" + ifname; |
| 33 | } |
| 34 | |
| 35 | std::string ArcVethPeerName(std::string ifname) { |
| 36 | return "peer_" + ifname; |
| 37 | } |
Garrick Evans | f0ab713 | 2019-06-18 14:50:42 +0900 | [diff] [blame] | 38 | |
| 39 | Datapath::Datapath(MinijailedProcessRunner* process_runner) |
Garrick Evans | c7ae82c | 2019-09-04 16:25:10 +0900 | [diff] [blame] | 40 | : Datapath(process_runner, ioctl) {} |
| 41 | |
| 42 | Datapath::Datapath(MinijailedProcessRunner* process_runner, ioctl_t ioctl_hook) |
| 43 | : process_runner_(process_runner), ioctl_(ioctl_hook) { |
Garrick Evans | f0ab713 | 2019-06-18 14:50:42 +0900 | [diff] [blame] | 44 | CHECK(process_runner_); |
| 45 | } |
| 46 | |
Garrick Evans | 260ff30 | 2019-07-25 11:22:50 +0900 | [diff] [blame] | 47 | MinijailedProcessRunner& Datapath::runner() const { |
| 48 | return *process_runner_; |
| 49 | } |
| 50 | |
Garrick Evans | 8a949dc | 2019-07-18 16:17:53 +0900 | [diff] [blame] | 51 | bool Datapath::AddBridge(const std::string& ifname, |
| 52 | const std::string& ipv4_addr) { |
| 53 | // Configure the persistent Chrome OS bridge interface with static IP. |
| 54 | if (process_runner_->Run({kBrctlPath, "addbr", ifname}) != 0) { |
| 55 | return false; |
| 56 | } |
| 57 | |
| 58 | if (process_runner_->Run({kIfConfigPath, ifname, ipv4_addr, "netmask", |
| 59 | kDefaultNetmask, "up"}) != 0) { |
| 60 | RemoveBridge(ifname); |
| 61 | return false; |
| 62 | } |
| 63 | |
| 64 | // See nat.conf in chromeos-nat-init for the rest of the NAT setup rules. |
| 65 | if (process_runner_->Run({kIpTablesPath, "-t", "mangle", "-A", "PREROUTING", |
| 66 | "-i", ifname, "-j", "MARK", "--set-mark", "1", |
| 67 | "-w"}) != 0) { |
| 68 | RemoveBridge(ifname); |
| 69 | return false; |
| 70 | } |
| 71 | |
| 72 | return true; |
| 73 | } |
| 74 | |
| 75 | void Datapath::RemoveBridge(const std::string& ifname) { |
| 76 | process_runner_->Run({kIpTablesPath, "-t", "mangle", "-D", "PREROUTING", "-i", |
| 77 | ifname, "-j", "MARK", "--set-mark", "1", "-w"}); |
| 78 | process_runner_->Run({kIfConfigPath, ifname, "down"}); |
| 79 | process_runner_->Run({kBrctlPath, "delbr", ifname}); |
| 80 | } |
| 81 | |
Garrick Evans | c7ae82c | 2019-09-04 16:25:10 +0900 | [diff] [blame] | 82 | std::string Datapath::AddTAP(const std::string& name, |
| 83 | const MacAddress& mac_addr, |
| 84 | const SubnetAddress& ipv4_addr, |
| 85 | uid_t user_id) { |
| 86 | base::ScopedFD dev(open(kTunDev, O_RDWR | O_NONBLOCK)); |
| 87 | if (!dev.is_valid()) { |
| 88 | PLOG(ERROR) << "Failed to open " << kTunDev; |
| 89 | return ""; |
| 90 | } |
| 91 | |
| 92 | struct ifreq ifr; |
| 93 | memset(&ifr, 0, sizeof(ifr)); |
| 94 | strncpy(ifr.ifr_name, name.empty() ? kDefaultIfname : name.c_str(), |
| 95 | sizeof(ifr.ifr_name)); |
| 96 | ifr.ifr_flags = IFF_TAP | IFF_NO_PI; |
| 97 | |
| 98 | // If a template was given as the name, ifr_name will be updated with the |
| 99 | // actual interface name. |
| 100 | if ((*ioctl_)(dev.get(), TUNSETIFF, &ifr) != 0) { |
| 101 | PLOG(ERROR) << "Failed to create tap interface " << name << " {" |
| 102 | << ipv4_addr.ToCidrString() << "}"; |
| 103 | return ""; |
| 104 | } |
| 105 | const char* ifname = ifr.ifr_name; |
| 106 | |
| 107 | if ((*ioctl_)(dev.get(), TUNSETPERSIST, 1) != 0) { |
| 108 | PLOG(ERROR) << "Failed to persist the interface " << ifname << " {" |
| 109 | << ipv4_addr.ToCidrString() << "}"; |
| 110 | return ""; |
| 111 | } |
| 112 | |
| 113 | if (user_id != -1 && (*ioctl_)(dev.get(), TUNSETOWNER, user_id) != 0) { |
| 114 | PLOG(ERROR) << "Failed to set owner " << user_id << " of tap interface " |
| 115 | << ifname << " {" << ipv4_addr.ToCidrString() << "}"; |
| 116 | RemoveTAP(ifname); |
| 117 | return ""; |
| 118 | } |
| 119 | |
Hugo Benichi | b9b93fe | 2019-10-25 23:36:01 +0900 | [diff] [blame^] | 120 | // Create control socket for configuring the interface. |
Garrick Evans | c7ae82c | 2019-09-04 16:25:10 +0900 | [diff] [blame] | 121 | base::ScopedFD sock(socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0)); |
| 122 | if (!sock.is_valid()) { |
| 123 | PLOG(ERROR) << "Failed to create control socket for tap interface " |
| 124 | << ifname << " {" << ipv4_addr.ToCidrString() << "}"; |
| 125 | RemoveTAP(ifname); |
| 126 | return ""; |
| 127 | } |
| 128 | |
| 129 | struct sockaddr_in* addr = |
| 130 | reinterpret_cast<struct sockaddr_in*>(&ifr.ifr_addr); |
| 131 | addr->sin_family = AF_INET; |
| 132 | addr->sin_addr.s_addr = static_cast<in_addr_t>(ipv4_addr.Address()); |
| 133 | if ((*ioctl_)(sock.get(), SIOCSIFADDR, &ifr) != 0) { |
| 134 | PLOG(ERROR) << "Failed to set ip address for vmtap interface " << ifname |
| 135 | << " {" << ipv4_addr.ToCidrString() << "}"; |
| 136 | RemoveTAP(ifname); |
| 137 | return ""; |
| 138 | } |
| 139 | |
| 140 | struct sockaddr_in* netmask = |
| 141 | reinterpret_cast<struct sockaddr_in*>(&ifr.ifr_netmask); |
| 142 | netmask->sin_family = AF_INET; |
| 143 | netmask->sin_addr.s_addr = static_cast<in_addr_t>(ipv4_addr.Netmask()); |
| 144 | if ((*ioctl_)(sock.get(), SIOCSIFNETMASK, &ifr) != 0) { |
| 145 | PLOG(ERROR) << "Failed to set netmask for vmtap interface " << ifname |
| 146 | << " {" << ipv4_addr.ToCidrString() << "}"; |
| 147 | RemoveTAP(ifname); |
| 148 | return ""; |
| 149 | } |
| 150 | |
| 151 | struct sockaddr* hwaddr = &ifr.ifr_hwaddr; |
| 152 | hwaddr->sa_family = ARPHRD_ETHER; |
| 153 | memcpy(&hwaddr->sa_data, &mac_addr, sizeof(mac_addr)); |
| 154 | if ((*ioctl_)(sock.get(), SIOCSIFHWADDR, &ifr) != 0) { |
| 155 | PLOG(ERROR) << "Failed to set mac address for vmtap interface " << ifname |
| 156 | << " {" << ipv4_addr.ToCidrString() << "}"; |
| 157 | RemoveTAP(ifname); |
| 158 | return ""; |
| 159 | } |
| 160 | |
| 161 | if ((*ioctl_)(sock.get(), SIOCGIFFLAGS, &ifr) != 0) { |
| 162 | PLOG(ERROR) << "Failed to get flags for tap interface " << ifname << " {" |
| 163 | << ipv4_addr.ToCidrString() << "}"; |
| 164 | RemoveTAP(ifname); |
| 165 | return ""; |
| 166 | } |
| 167 | |
| 168 | ifr.ifr_flags |= (IFF_UP | IFF_RUNNING); |
| 169 | if ((*ioctl_)(sock.get(), SIOCSIFFLAGS, &ifr) != 0) { |
| 170 | PLOG(ERROR) << "Failed to enable tap interface " << ifname << " {" |
| 171 | << ipv4_addr.ToCidrString() << "}"; |
| 172 | RemoveTAP(ifname); |
| 173 | return ""; |
| 174 | } |
| 175 | |
| 176 | return ifname; |
| 177 | } |
| 178 | |
| 179 | void Datapath::RemoveTAP(const std::string& ifname) { |
| 180 | process_runner_->Run({kIpPath, "tuntap", "del", ifname, "mode", "tap"}); |
| 181 | } |
| 182 | |
Garrick Evans | 5486162 | 2019-07-19 09:05:09 +0900 | [diff] [blame] | 183 | std::string Datapath::AddVirtualBridgedInterface(const std::string& ifname, |
| 184 | const std::string& mac_addr, |
| 185 | const std::string& br_ifname) { |
| 186 | const std::string veth = ArcVethHostName(ifname); |
| 187 | const std::string peer = ArcVethPeerName(ifname); |
| 188 | |
| 189 | RemoveInterface(veth); |
| 190 | if (process_runner_->Run({kIpPath, "link", "add", veth, "type", "veth", |
| 191 | "peer", "name", peer}) != 0) { |
| 192 | return ""; |
| 193 | } |
| 194 | |
| 195 | if (process_runner_->Run({kIfConfigPath, veth, "up"}) != 0) { |
| 196 | RemoveInterface(veth); |
| 197 | RemoveInterface(peer); |
| 198 | return ""; |
| 199 | } |
| 200 | |
| 201 | if (process_runner_->Run({kIpPath, "link", "set", "dev", peer, "addr", |
| 202 | mac_addr, "down"}) != 0) { |
| 203 | RemoveInterface(veth); |
| 204 | RemoveInterface(peer); |
| 205 | return ""; |
| 206 | } |
| 207 | |
| 208 | if (process_runner_->Run({kBrctlPath, "addif", br_ifname, veth}) != 0) { |
| 209 | RemoveInterface(veth); |
| 210 | RemoveInterface(peer); |
| 211 | return ""; |
| 212 | } |
| 213 | |
| 214 | return peer; |
| 215 | } |
| 216 | |
| 217 | void Datapath::RemoveInterface(const std::string& ifname) { |
| 218 | process_runner_->Run({kIpPath, "link", "delete", ifname}, false /* log */); |
| 219 | } |
| 220 | |
| 221 | bool Datapath::AddInterfaceToContainer(int ns, |
| 222 | const std::string& src_ifname, |
| 223 | const std::string& dst_ifname, |
| 224 | const std::string& dst_ipv4, |
| 225 | bool fwd_multicast) { |
| 226 | const std::string pid = base::IntToString(ns); |
| 227 | return (process_runner_->Run( |
| 228 | {kIpPath, "link", "set", src_ifname, "netns", pid}) == 0) && |
| 229 | (process_runner_->AddInterfaceToContainer(src_ifname, dst_ifname, |
| 230 | dst_ipv4, kDefaultNetmask, |
| 231 | fwd_multicast, pid) == 0); |
| 232 | } |
| 233 | |
Garrick Evans | f0ab713 | 2019-06-18 14:50:42 +0900 | [diff] [blame] | 234 | bool Datapath::AddLegacyIPv4DNAT(const std::string& ipv4_addr) { |
| 235 | // Forward "unclaimed" packets to Android to allow inbound connections |
| 236 | // from devices on the LAN. |
| 237 | if (process_runner_->Run( |
| 238 | {kIpTablesPath, "-t", "nat", "-N", "dnat_arc", "-w"}) != 0) |
| 239 | return false; |
| 240 | |
| 241 | if (process_runner_->Run({kIpTablesPath, "-t", "nat", "-A", "dnat_arc", "-j", |
| 242 | "DNAT", "--to-destination", ipv4_addr, "-w"}) != |
| 243 | 0) { |
Garrick Evans | 5486162 | 2019-07-19 09:05:09 +0900 | [diff] [blame] | 244 | RemoveLegacyIPv4DNAT(); |
Garrick Evans | f0ab713 | 2019-06-18 14:50:42 +0900 | [diff] [blame] | 245 | return false; |
| 246 | } |
| 247 | |
| 248 | // This chain is dynamically updated whenever the default interface |
| 249 | // changes. |
| 250 | if (process_runner_->Run( |
| 251 | {kIpTablesPath, "-t", "nat", "-N", "try_arc", "-w"}) != 0) { |
| 252 | RemoveLegacyIPv4DNAT(); |
| 253 | return false; |
| 254 | } |
| 255 | |
| 256 | if (process_runner_->Run({kIpTablesPath, "-t", "nat", "-A", "PREROUTING", |
| 257 | "-m", "socket", "--nowildcard", "-j", "ACCEPT", |
| 258 | "-w"}) != 0) { |
| 259 | RemoveLegacyIPv4DNAT(); |
| 260 | return false; |
| 261 | } |
| 262 | |
| 263 | if (process_runner_->Run({kIpTablesPath, "-t", "nat", "-A", "PREROUTING", |
| 264 | "-p", "tcp", "-j", "try_arc", "-w"}) != 0) { |
| 265 | RemoveLegacyIPv4DNAT(); |
| 266 | return false; |
| 267 | } |
| 268 | |
| 269 | if (process_runner_->Run({kIpTablesPath, "-t", "nat", "-A", "PREROUTING", |
| 270 | "-p", "udp", "-j", "try_arc", "-w"}) != 0) { |
| 271 | RemoveLegacyIPv4DNAT(); |
| 272 | return false; |
| 273 | } |
| 274 | |
| 275 | return true; |
| 276 | } |
| 277 | |
| 278 | void Datapath::RemoveLegacyIPv4DNAT() { |
| 279 | process_runner_->Run({kIpTablesPath, "-t", "nat", "-D", "PREROUTING", "-p", |
| 280 | "udp", "-j", "try_arc", "-w"}); |
| 281 | process_runner_->Run({kIpTablesPath, "-t", "nat", "-D", "PREROUTING", "-p", |
| 282 | "tcp", "-j", "try_arc", "-w"}); |
| 283 | process_runner_->Run({kIpTablesPath, "-t", "nat", "-D", "PREROUTING", "-m", |
| 284 | "socket", "--nowildcard", "-j", "ACCEPT", "-w"}); |
| 285 | process_runner_->Run({kIpTablesPath, "-t", "nat", "-F", "try_arc", "-w"}); |
| 286 | process_runner_->Run({kIpTablesPath, "-t", "nat", "-X", "try_arc", "-w"}); |
| 287 | process_runner_->Run({kIpTablesPath, "-t", "nat", "-F", "dnat_arc", "-w"}); |
| 288 | process_runner_->Run({kIpTablesPath, "-t", "nat", "-X", "dnat_arc", "-w"}); |
| 289 | } |
| 290 | |
Garrick Evans | 5486162 | 2019-07-19 09:05:09 +0900 | [diff] [blame] | 291 | bool Datapath::AddLegacyIPv4InboundDNAT(const std::string& ifname) { |
| 292 | return (process_runner_->Run({kIpTablesPath, "-t", "nat", "-A", "try_arc", |
| 293 | "-i", ifname, "-j", "dnat_arc", "-w"}) != 0); |
| 294 | } |
| 295 | |
| 296 | void Datapath::RemoveLegacyIPv4InboundDNAT() { |
| 297 | process_runner_->Run({kIpTablesPath, "-t", "nat", "-F", "try_arc", "-w"}); |
| 298 | } |
| 299 | |
Garrick Evans | f0ab713 | 2019-06-18 14:50:42 +0900 | [diff] [blame] | 300 | bool Datapath::AddInboundIPv4DNAT(const std::string& ifname, |
| 301 | const std::string& ipv4_addr) { |
| 302 | // Direct ingress IP traffic to existing sockets. |
| 303 | if (process_runner_->Run({kIpTablesPath, "-t", "nat", "-A", "PREROUTING", |
| 304 | "-i", ifname, "-m", "socket", "--nowildcard", "-j", |
| 305 | "ACCEPT", "-w"}) != 0) |
| 306 | return false; |
| 307 | |
| 308 | // Direct ingress TCP & UDP traffic to ARC interface for new connections. |
| 309 | if (process_runner_->Run({kIpTablesPath, "-t", "nat", "-A", "PREROUTING", |
| 310 | "-i", ifname, "-p", "tcp", "-j", "DNAT", |
| 311 | "--to-destination", ipv4_addr, "-w"}) != 0) { |
| 312 | RemoveInboundIPv4DNAT(ifname, ipv4_addr); |
| 313 | return false; |
| 314 | } |
| 315 | if (process_runner_->Run({kIpTablesPath, "-t", "nat", "-A", "PREROUTING", |
| 316 | "-i", ifname, "-p", "udp", "-j", "DNAT", |
| 317 | "--to-destination", ipv4_addr, "-w"}) != 0) { |
| 318 | RemoveInboundIPv4DNAT(ifname, ipv4_addr); |
| 319 | return false; |
| 320 | } |
| 321 | |
| 322 | return true; |
| 323 | } |
| 324 | |
| 325 | void Datapath::RemoveInboundIPv4DNAT(const std::string& ifname, |
| 326 | const std::string& ipv4_addr) { |
| 327 | process_runner_->Run({kIpTablesPath, "-t", "nat", "-D", "PREROUTING", "-i", |
| 328 | ifname, "-p", "udp", "-j", "DNAT", "--to-destination", |
| 329 | ipv4_addr, "-w"}); |
| 330 | process_runner_->Run({kIpTablesPath, "-t", "nat", "-D", "PREROUTING", "-i", |
| 331 | ifname, "-p", "tcp", "-j", "DNAT", "--to-destination", |
| 332 | ipv4_addr, "-w"}); |
| 333 | process_runner_->Run({kIpTablesPath, "-t", "nat", "-D", "PREROUTING", "-i", |
| 334 | ifname, "-m", "socket", "--nowildcard", "-j", "ACCEPT", |
| 335 | "-w"}); |
| 336 | } |
| 337 | |
| 338 | bool Datapath::AddOutboundIPv4(const std::string& ifname) { |
| 339 | return process_runner_->Run({kIpTablesPath, "-t", "filter", "-A", "FORWARD", |
| 340 | "-o", ifname, "-j", "ACCEPT", "-w"}) == 0; |
| 341 | } |
| 342 | |
| 343 | void Datapath::RemoveOutboundIPv4(const std::string& ifname) { |
| 344 | process_runner_->Run({kIpTablesPath, "-t", "filter", "-D", "FORWARD", "-o", |
| 345 | ifname, "-j", "ACCEPT", "-w"}); |
| 346 | } |
| 347 | |
Garrick Evans | 260ff30 | 2019-07-25 11:22:50 +0900 | [diff] [blame] | 348 | bool Datapath::AddIPv6GatewayRoutes(const std::string& ifname, |
| 349 | const std::string& ipv6_addr, |
| 350 | const std::string& ipv6_router, |
| 351 | int ipv6_prefix_len, |
| 352 | int routing_table) { |
| 353 | std::string ipv6_addr_cidr = |
| 354 | ipv6_addr + "/" + std::to_string(ipv6_prefix_len); |
| 355 | |
| 356 | process_runner_->Run( |
| 357 | {kIpPath, "-6", "addr", "add", ipv6_addr_cidr, "dev", ifname}); |
| 358 | |
| 359 | process_runner_->Run({kIpPath, "-6", "route", "add", ipv6_router, "dev", |
| 360 | ifname, "table", std::to_string(routing_table)}); |
| 361 | |
| 362 | process_runner_->Run({kIpPath, "-6", "route", "add", "default", "via", |
| 363 | ipv6_router, "dev", ifname, "table", |
| 364 | std::to_string(routing_table)}); |
| 365 | return true; |
| 366 | } |
| 367 | |
| 368 | void Datapath::RemoveIPv6GatewayRoutes(const std::string& ifname, |
| 369 | const std::string& ipv6_addr, |
| 370 | const std::string& ipv6_router, |
| 371 | int ipv6_prefix_len, |
| 372 | int routing_table) { |
| 373 | std::string ipv6_addr_cidr = |
| 374 | ipv6_addr + "/" + std::to_string(ipv6_prefix_len); |
| 375 | |
| 376 | process_runner_->Run({kIpPath, "-6", "route", "del", "default", "via", |
| 377 | ipv6_router, "dev", ifname, "table", |
| 378 | std::to_string(routing_table)}); |
| 379 | process_runner_->Run({kIpPath, "-6", "route", "del", ipv6_router, "dev", |
| 380 | ifname, "table", std::to_string(routing_table)}); |
| 381 | process_runner_->Run( |
| 382 | {kIpPath, "-6", "addr", "del", ipv6_addr_cidr, "dev", ifname}, false); |
| 383 | } |
| 384 | |
| 385 | bool Datapath::AddIPv6HostRoute(const std::string& ifname, |
| 386 | const std::string& ipv6_addr, |
| 387 | int ipv6_prefix_len) { |
| 388 | std::string ipv6_addr_cidr = |
| 389 | ipv6_addr + "/" + std::to_string(ipv6_prefix_len); |
| 390 | |
| 391 | return process_runner_->Run({kIpPath, "-6", "route", "add", ipv6_addr_cidr, |
| 392 | "dev", ifname}) == 0; |
| 393 | } |
| 394 | |
| 395 | void Datapath::RemoveIPv6HostRoute(const std::string& ifname, |
| 396 | const std::string& ipv6_addr, |
| 397 | int ipv6_prefix_len) { |
| 398 | std::string ipv6_addr_cidr = |
| 399 | ipv6_addr + "/" + std::to_string(ipv6_prefix_len); |
| 400 | |
| 401 | process_runner_->Run( |
| 402 | {kIpPath, "-6", "route", "del", ipv6_addr_cidr, "dev", ifname}); |
| 403 | } |
| 404 | |
| 405 | bool Datapath::AddIPv6Neighbor(const std::string& ifname, |
| 406 | const std::string& ipv6_addr) { |
| 407 | return process_runner_->Run({kIpPath, "-6", "neigh", "add", "proxy", |
| 408 | ipv6_addr, "dev", ifname}) == 0; |
| 409 | } |
| 410 | |
| 411 | void Datapath::RemoveIPv6Neighbor(const std::string& ifname, |
| 412 | const std::string& ipv6_addr) { |
| 413 | process_runner_->Run( |
| 414 | {kIpPath, "-6", "neigh", "del", "proxy", ipv6_addr, "dev", ifname}); |
| 415 | } |
| 416 | |
| 417 | bool Datapath::AddIPv6Forwarding(const std::string& ifname1, |
| 418 | const std::string& ifname2) { |
| 419 | if (process_runner_->Run({kIp6TablesPath, "-A", "FORWARD", "-i", ifname1, |
| 420 | "-o", ifname2, "-j", "ACCEPT", "-w"}) != 0) { |
| 421 | return false; |
| 422 | } |
| 423 | |
| 424 | if (process_runner_->Run({kIp6TablesPath, "-A", "FORWARD", "-i", ifname2, |
| 425 | "-o", ifname1, "-j", "ACCEPT", "-w"}) != 0) { |
| 426 | RemoveIPv6Forwarding(ifname1, ifname2); |
| 427 | return false; |
| 428 | } |
| 429 | |
| 430 | return true; |
| 431 | } |
| 432 | |
| 433 | void Datapath::RemoveIPv6Forwarding(const std::string& ifname1, |
| 434 | const std::string& ifname2) { |
| 435 | process_runner_->Run({kIp6TablesPath, "-D", "FORWARD", "-i", ifname1, "-o", |
| 436 | ifname2, "-j", "ACCEPT", "-w"}); |
| 437 | |
| 438 | process_runner_->Run({kIp6TablesPath, "-D", "FORWARD", "-i", ifname2, "-o", |
| 439 | ifname1, "-j", "ACCEPT", "-w"}); |
| 440 | } |
| 441 | |
Garrick Evans | f0ab713 | 2019-06-18 14:50:42 +0900 | [diff] [blame] | 442 | } // namespace arc_networkd |