RouteController.cpp revision 4753afd79e130d5f1c888f549c36b4da92dbe680
15c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran/* 25c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran * Copyright (C) 2014 The Android Open Source Project 35c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran * 45c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran * Licensed under the Apache License, Version 2.0 (the "License"); 55c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran * you may not use this file except in compliance with the License. 65c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran * You may obtain a copy of the License at 75c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran * 85c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran * http://www.apache.org/licenses/LICENSE-2.0 95c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran * 105c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran * Unless required by applicable law or agreed to in writing, software 115c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran * distributed under the License is distributed on an "AS IS" BASIS, 125c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran * See the License for the specific language governing permissions and 145c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran * limitations under the License. 155c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran */ 165c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 175c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran#include "RouteController.h" 185c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 195c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran#include "Fwmark.h" 205c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran#include "NetdConstants.h" 215c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 22ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti#include <arpa/inet.h> 23ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti#include <errno.h> 244753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti#include <linux/fib_rules.h> 25ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti#include <linux/netlink.h> 268fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran#include <linux/rtnetlink.h> 275c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran#include <logwrap/logwrap.h> 28a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen#include <map> 29ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti#include <netinet/in.h> 305c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran#include <net/if.h> 31ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti#include <sys/socket.h> 32ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti#include <sys/uio.h> 33ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti#include <unistd.h> 34ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti 35ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti// Avoids "non-constant-expression cannot be narrowed from type 'unsigned int' to 'unsigned short'" 36ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti// warnings when using RTA_LENGTH(x) inside static initializers (even when x is already uint16_t). 37ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti#define U16_RTA_LENGTH(x) static_cast<uint16_t>(RTA_LENGTH((x))) 385c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 395c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandrannamespace { 405c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 4138b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandranconst uint32_t RULE_PRIORITY_PRIVILEGED_LEGACY = 11000; 428fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandranconst uint32_t RULE_PRIORITY_PER_NETWORK_EXPLICIT = 13000; 438fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandranconst uint32_t RULE_PRIORITY_PER_NETWORK_INTERFACE = 14000; 4438b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandranconst uint32_t RULE_PRIORITY_LEGACY = 16000; 458fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandranconst uint32_t RULE_PRIORITY_PER_NETWORK_NORMAL = 17000; 468fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandranconst uint32_t RULE_PRIORITY_DEFAULT_NETWORK = 19000; 478fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandranconst uint32_t RULE_PRIORITY_MAIN = 20000; 4856afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran// TODO: Uncomment once we are sure everything works. 4956afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran#if 0 508fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandranconst uint32_t RULE_PRIORITY_UNREACHABLE = 21000; 5156afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran#endif 525c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 5338b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran// TODO: These should be turned into per-UID tables once the kernel supports UID-based routing. 5438b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandranconst int ROUTE_TABLE_PRIVILEGED_LEGACY = RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX - 901; 5538b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandranconst int ROUTE_TABLE_LEGACY = RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX - 902; 5638b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran 574753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitticonst uint16_t kNetlinkRequestFlags = NLM_F_REQUEST | NLM_F_ACK; 584753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitticonst uint16_t kNetlinkCreateRequestFlags = kNetlinkRequestFlags | NLM_F_CREATE | NLM_F_EXCL; 594753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti 60a561e121c724e9163b2e256e15eef660e3a326daPaul Jensenstd::map<std::string, uint32_t> interfaceToIndex; 61a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen 625c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandranuint32_t getRouteTableForInterface(const char* interface) { 63a48118062412f16ae712bfc8c8a539d3b6a85e47Sreeram Ramachandran uint32_t index = if_nametoindex(interface); 64a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen if (index) { 65a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen interfaceToIndex[interface] = index; 66a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen } else { 67a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen // If the interface goes away if_nametoindex() will return 0 but we still need to know 68a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen // the index so we can remove the rules and routes. 69a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen std::map<std::string, uint32_t>::iterator it = interfaceToIndex.find(interface); 70a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen if (it != interfaceToIndex.end()) 71a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen index = it->second; 72a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen } 73a48118062412f16ae712bfc8c8a539d3b6a85e47Sreeram Ramachandran return index ? index + RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX : 0; 745c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran} 755c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 764753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti// Sends a netlink request and expects an ack. 774753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti// |iov| is an array of struct iovec that contains the netlink message payload. 784753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti// The netlink header is generated by this function based on |action| and |flags|. 794753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti// Returns -errno if there was an error or if the kernel reported an error. 804753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colittiint sendNetlinkRequest(uint16_t action, uint16_t flags, iovec* iov, int iovlen) { 814753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti nlmsghdr nlmsg = { 824753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti .nlmsg_type = action, 834753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti .nlmsg_flags = flags, 844753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti }; 854753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti iov[0].iov_base = &nlmsg; 864753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti iov[0].iov_len = sizeof(nlmsg); 874753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti for (int i = 0; i < iovlen; ++i) { 884753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti nlmsg.nlmsg_len += iov[i].iov_len; 894753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti } 904753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti 914753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti int ret; 924753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti struct { 934753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti nlmsghdr msg; 944753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti nlmsgerr err; 954753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti } response; 964753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti 974753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti sockaddr_nl kernel = {AF_NETLINK, 0, 0, 0}; 984753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti int sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); 994753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti if (sock != -1 && 1004753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti connect(sock, reinterpret_cast<sockaddr*>(&kernel), sizeof(kernel)) != -1 && 1014753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti writev(sock, iov, iovlen) != -1 && 1024753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti (ret = recv(sock, &response, sizeof(response), 0)) != -1) { 1034753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti if (ret == sizeof(response)) { 1044753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti ret = response.err.error; // Netlink errors are negative errno. 1054753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti } else { 1064753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti ret = -EBADMSG; 1074753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti } 1084753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti } else { 1094753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti ret = -errno; 1104753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti } 1114753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti 1124753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti if (sock != -1) { 1134753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti close(sock); 1144753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti } 1154753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti 1164753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti return ret; 1174753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti} 1184753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti 1198fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran// Adds or removes a routing rule for IPv4 and IPv6. 1208fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran// 1218fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran// + If |table| is non-zero, the rule points at the specified routing table. Otherwise, the rule 1228fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran// returns ENETUNREACH. 1238fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran// + If |mask| is non-zero, the rule matches the specified fwmark and mask. Otherwise, |fwmark| is 1248fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran// ignored. 1258fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran// + If |interface| is non-NULL, the rule matches the specified outgoing interface. 1264753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colittibool modifyIpRule(uint16_t action, uint32_t priority, uint32_t table, uint32_t fwmark, 1274753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti uint32_t mask, const char* interface) { 1284753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti // The interface name must include exactly one terminating NULL and be properly padded, or older 1294753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti // kernels will refuse to delete rules. 1304753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti uint8_t padding[RTA_ALIGNTO] = {0, 0, 0, 0}; 1314753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti uint16_t paddingLength = 0; 1324753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti size_t interfaceLength = 0; 1334753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti char oifname[IFNAMSIZ]; 1344753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti if (interface) { 1354753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti interfaceLength = strlcpy(oifname, interface, IFNAMSIZ) + 1; 1364753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti if (interfaceLength > IFNAMSIZ) { 1374753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti return -ENAMETOOLONG; 1384753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti } 1394753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti paddingLength = RTA_SPACE(interfaceLength) - RTA_LENGTH(interfaceLength); 1404753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti } 1417619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran 1424753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti // Assemble a rule request and put it in an array of iovec structures. 1434753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti fib_rule_hdr rule = { 1444753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti .action = static_cast<uint8_t>(table ? FR_ACT_TO_TBL : FR_ACT_UNREACHABLE), 1454753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti }; 146a10ac3214f6a582b7fdb66acc43c702731e53d81Lorenzo Colitti 1474753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti rtattr fra_priority = { U16_RTA_LENGTH(sizeof(priority)), FRA_PRIORITY }; 1484753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti rtattr fra_table = { U16_RTA_LENGTH(sizeof(table)), FRA_TABLE }; 1494753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti rtattr fra_fwmark = { U16_RTA_LENGTH(sizeof(fwmark)), FRA_FWMARK }; 1504753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti rtattr fra_fwmask = { U16_RTA_LENGTH(sizeof(mask)), FRA_FWMASK }; 1514753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti rtattr fra_oifname = { U16_RTA_LENGTH(interfaceLength), FRA_OIFNAME }; 152a10ac3214f6a582b7fdb66acc43c702731e53d81Lorenzo Colitti 1534753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti iovec iov[] = { 1544753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti { NULL, 0 }, 1554753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti { &rule, sizeof(rule) }, 1564753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti { &fra_priority, sizeof(fra_priority) }, 1574753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti { &priority, sizeof(priority) }, 1584753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti { &fra_table, table ? sizeof(fra_table) : 0 }, 1594753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti { &table, table ? sizeof(table) : 0 }, 1604753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti { &fra_fwmark, mask ? sizeof(fra_fwmark) : 0 }, 1614753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti { &fwmark, mask ? sizeof(fwmark) : 0 }, 1624753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti { &fra_fwmask, mask ? sizeof(fra_fwmask) : 0 }, 1634753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti { &mask, mask ? sizeof(mask) : 0 }, 1644753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti { &fra_oifname, interface ? sizeof(fra_oifname) : 0 }, 1654753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti { oifname, interfaceLength }, 1664753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti { padding, paddingLength }, 1674753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti }; 1684753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti 1694753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti uint16_t flags = (action == RTM_NEWRULE) ? kNetlinkCreateRequestFlags : kNetlinkRequestFlags; 1704753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti uint8_t family[] = {AF_INET, AF_INET6}; 1714753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti for (size_t i = 0; i < ARRAY_SIZE(family); ++i) { 1724753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti rule.family = family[i]; 1734753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti int ret = sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov)); 1744753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti if (ret) { 1754753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti errno = -ret; 1765c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran return false; 1775c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran } 1785c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran } 1795c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 1805c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran return true; 1815c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran} 1825c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 183ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti// Adds or deletes an IPv4 or IPv6 route. 184ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti// Returns 0 on success or negative errno on failure. 185ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colittiint modifyIpRoute(uint16_t action, uint32_t table, const char* interface, const char* destination, 186ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti const char* nexthop) { 187ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti // At least the destination must be non-null. 188ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti if (!destination) { 189ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti return -EFAULT; 190ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti } 191ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti 192ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti // Parse the prefix. 193ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti uint8_t rawAddress[sizeof(in6_addr)]; 194ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti uint8_t family, prefixLength; 195ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti int rawLength = parsePrefix(destination, &family, rawAddress, sizeof(rawAddress), 196ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti &prefixLength); 197ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti if (rawLength < 0) { 198ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti return rawLength; 199ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti } 2007619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran 201ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti if (static_cast<size_t>(rawLength) > sizeof(rawAddress)) { 202ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti return -ENOBUFS; // Cannot happen; parsePrefix only supports IPv4 and IPv6. 203ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti } 204ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti 205ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti // If an interface was specified, find the ifindex. 206ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti uint32_t ifindex; 207ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti if (interface) { 208ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti ifindex = if_nametoindex(interface); 209ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti if (!ifindex) { 210ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti return -ENODEV; 2117619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran } 2127619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran } 2137619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran 214ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti // If a nexthop was specified, parse it as the same family as the prefix. 215ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti uint8_t rawNexthop[sizeof(in6_addr)]; 216ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti if (nexthop && !inet_pton(family, nexthop, rawNexthop)) { 217ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti return -EINVAL; 218ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti } 219ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti 2204753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti // Assemble a rtmsg and put it in an array of iovec structures. 221ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti rtmsg rtmsg = { 222ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti .rtm_protocol = RTPROT_STATIC, 223ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti .rtm_type = RTN_UNICAST, 224ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti .rtm_family = family, 225ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti .rtm_dst_len = prefixLength, 226ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti }; 2274753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti 2284753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti rtattr rta_table = { U16_RTA_LENGTH(sizeof(table)), RTA_TABLE }; 2294753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti rtattr rta_oif = { U16_RTA_LENGTH(sizeof(ifindex)), RTA_OIF }; 2304753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti rtattr rta_dst = { U16_RTA_LENGTH(rawLength), RTA_DST }; 2314753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti rtattr rta_gateway = { U16_RTA_LENGTH(rawLength), RTA_GATEWAY }; 232ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti 233ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti iovec iov[] = { 2344753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti { NULL, 0 }, 235ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { &rtmsg, sizeof(rtmsg) }, 236ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { &rta_table, sizeof(rta_table) }, 237ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { &table, sizeof(table) }, 238ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { &rta_dst, sizeof(rta_dst) }, 239ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { rawAddress, static_cast<size_t>(rawLength) }, 240ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { &rta_oif, interface ? sizeof(rta_oif) : 0 }, 2417f972fb1cd3c26af76779a7a3220b9cf5fb63a0aSreeram Ramachandran { &ifindex, interface ? sizeof(ifindex) : 0 }, 242ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { &rta_gateway, nexthop ? sizeof(rta_gateway) : 0 }, 243ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { rawNexthop, nexthop ? static_cast<size_t>(rawLength) : 0 }, 244ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti }; 245ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti 2464753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti uint16_t flags = (action == RTM_NEWROUTE) ? kNetlinkCreateRequestFlags : kNetlinkRequestFlags; 2474753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti return sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov)); 2487619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran} 2497619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran 2509c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandranbool modifyPerNetworkRules(unsigned netId, const char* interface, Permission permission, bool add, 2519c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran bool modifyIptables) { 2525c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran uint32_t table = getRouteTableForInterface(interface); 2535c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran if (!table) { 2545c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran return false; 2555c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran } 2565c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 2574753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti uint16_t action = add ? RTM_NEWRULE : RTM_DELRULE; 2585c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 259122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran Fwmark fwmark; 260122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran fwmark.permission = permission; 261122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran 262122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran Fwmark mask; 263122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran mask.permission = permission; 2645c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 2655c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // A rule to route traffic based on a chosen outgoing interface. 2665c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // 2675c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // Supports apps that use SO_BINDTODEVICE or IP_PKTINFO options and the kernel that already 2685c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // knows the outgoing interface (typically for link-local communications). 2694753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti if (!modifyIpRule(action, RULE_PRIORITY_PER_NETWORK_INTERFACE, table, fwmark.intValue, 2704753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti mask.intValue, interface)) { 2715c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran return false; 2725c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran } 2735c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 2745c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // A rule to route traffic based on the chosen network. 2755c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // 2765c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // This is for sockets that have not explicitly requested a particular network, but have been 2775c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // bound to one when they called connect(). This ensures that sockets connected on a particular 2785c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // network stay on that network even if the default network changes. 279122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran fwmark.netId = netId; 280122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran mask.netId = FWMARK_NET_ID_MASK; 2814753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti if (!modifyIpRule(action, RULE_PRIORITY_PER_NETWORK_NORMAL, table, fwmark.intValue, 2824753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti mask.intValue, NULL)) { 283122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran return false; 284122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran } 285122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran 286122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran // A rule to route traffic based on an explicitly chosen network. 287122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran // 288122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran // Supports apps that use the multinetwork APIs to restrict their traffic to a network. 289122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran // 290122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran // We don't really need to check the permission bits of the fwmark here, as they would've been 291122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran // checked at the time the netId was set into the fwmark, but we do so to be consistent. 292122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran fwmark.explicitlySelected = true; 293122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran mask.explicitlySelected = true; 2944753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti if (!modifyIpRule(action, RULE_PRIORITY_PER_NETWORK_EXPLICIT, table, fwmark.intValue, 2954753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti mask.intValue, NULL)) { 2965c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran return false; 2975c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran } 2985c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 2995c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // An iptables rule to mark incoming packets on a network with the netId of the network. 3005c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // 3015c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // This is so that the kernel can: 3025c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // + Use the right fwmark for (and thus correctly route) replies (e.g.: TCP RST, ICMP errors, 303a48118062412f16ae712bfc8c8a539d3b6a85e47Sreeram Ramachandran // ping replies). 3045c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // + Mark sockets that accept connections from this interface so that the connection stays on 3055c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // the same interface. 306379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran if (modifyIptables) { 3074753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti const char* iptablesAction = add ? "-A" : "-D"; 308379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran char markString[UINT32_HEX_STRLEN]; 309379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran snprintf(markString, sizeof(markString), "0x%x", netId); 3104753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti if (execIptables(V4V6, "-t", "mangle", iptablesAction, "INPUT", "-i", interface, 3114753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti "-j", "MARK", "--set-mark", markString, NULL)) { 312379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran return false; 313379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran } 3145c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran } 3155c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 3165c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran return true; 3175c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran} 3185c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 3194753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colittibool modifyDefaultNetworkRules(const char* interface, Permission permission, uint16_t action) { 3209c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran uint32_t table = getRouteTableForInterface(interface); 3219c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran if (!table) { 3229c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran return false; 3239c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran } 3249c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran 325122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran Fwmark fwmark; 326122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran fwmark.netId = 0; 327122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran fwmark.permission = permission; 328122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran 329122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran Fwmark mask; 330122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran mask.netId = FWMARK_NET_ID_MASK; 331122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran mask.permission = permission; 3329c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran 3334753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti return modifyIpRule(action, RULE_PRIORITY_DEFAULT_NETWORK, table, fwmark.intValue, 3344753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti mask.intValue, NULL); 3357619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran} 3367619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran 337f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti// Adds or removes an IPv4 or IPv6 route to the specified table and, if it's directly-connected 338f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti// route, to the main table as well. 339f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti// Returns 0 on success or negative errno on failure. 340f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colittiint modifyRoute(const char* interface, const char* destination, const char* nexthop, 3414753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti uint16_t action, RouteController::TableType tableType, unsigned /* uid */) { 34238b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran uint32_t table = 0; 34338b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran switch (tableType) { 34438b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran case RouteController::INTERFACE: { 34538b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran table = getRouteTableForInterface(interface); 34638b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran break; 34738b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran } 34838b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran case RouteController::LEGACY: { 34938b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran // TODO: Use the UID to assign a unique table per UID instead of this fixed table. 35038b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran table = ROUTE_TABLE_LEGACY; 35138b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran break; 35238b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran } 35338b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran case RouteController::PRIVILEGED_LEGACY: { 35438b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran // TODO: Use the UID to assign a unique table per UID instead of this fixed table. 35538b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran table = ROUTE_TABLE_PRIVILEGED_LEGACY; 35638b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran break; 35738b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran } 35838b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran } 3597619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran if (!table) { 360f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti return -ESRCH; 3619c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran } 3629c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran 363f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti int ret = modifyIpRoute(action, table, interface, destination, nexthop); 364f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti if (ret != 0) { 365f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti return ret; 366c92133732378aae815120c39edd62a7b4eb773b3Sreeram Ramachandran } 367c92133732378aae815120c39edd62a7b4eb773b3Sreeram Ramachandran 368c92133732378aae815120c39edd62a7b4eb773b3Sreeram Ramachandran // If there's no nexthop, this is a directly connected route. Add it to the main table also, to 369f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti // let the kernel find it when validating nexthops when global routes are added. 370f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti if (!nexthop) { 371f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti ret = modifyIpRoute(action, RT_TABLE_MAIN, interface, destination, NULL); 372f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti // A failure with action == ADD && errno == EEXIST means that the route already exists in 373f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti // the main table, perhaps because the kernel added it automatically as part of adding the 374f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti // IP address to the interface. Ignore this, but complain about everything else. 375f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti if (ret != 0 && !(action == RTM_NEWROUTE && ret == -EEXIST)) { 376f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti return ret; 377f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti } 378c92133732378aae815120c39edd62a7b4eb773b3Sreeram Ramachandran } 379c92133732378aae815120c39edd62a7b4eb773b3Sreeram Ramachandran 380f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti return 0; 3819c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran} 3829c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran 38392b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandranbool flushRoutes(const char* interface) { 38492b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran uint32_t table = getRouteTableForInterface(interface); 38592b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran if (!table) { 38692b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran return false; 38792b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran } 388a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen interfaceToIndex.erase(interface); 38992b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran 390357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti char tableString[UINT32_STRLEN]; 391357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti snprintf(tableString, sizeof(tableString), "%u", table); 392357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti 393357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti const char* version[] = {"-4", "-6"}; 394357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti for (size_t i = 0; i < ARRAY_SIZE(version); ++i) { 395357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti const char* argv[] = { 396357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti IP_PATH, 397357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti version[i], 398357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti "route" 399357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti "flush", 400357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti "table", 401357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti tableString, 402357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti }; 403357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti int argc = ARRAY_SIZE(argv); 404357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti 405357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti if (!android_fork_execvp(argc, const_cast<char**>(argv), NULL, false, false)) { 406357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti return false; 407357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti } 408357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti } 409357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti 410357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti return true; 41192b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran} 41292b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran 4135c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran} // namespace 4145c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 4158fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandranvoid RouteController::Init() { 4168fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran // Add a new rule to look up the 'main' table, with the same selectors as the "default network" 4178fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran // rule, but with a lower priority. Since the default network rule points to a table with a 4188fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran // default route, the rule we're adding will never be used for normal routing lookups. However, 4198fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran // the kernel may fall-through to it to find directly-connected routes when it validates that a 4208fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran // nexthop (in a route being added) is reachable. 421122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran Fwmark fwmark; 422122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran fwmark.netId = 0; 423122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran 424122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran Fwmark mask; 425122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran mask.netId = FWMARK_NET_ID_MASK; 426122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran 4274753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_MAIN, RT_TABLE_MAIN, fwmark.intValue, mask.intValue, 4284753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti NULL); 4298fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran 43038b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran // Add rules to allow lookup of legacy routes. 43138b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran // 43238b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran // TODO: Remove these once the kernel supports UID-based routing. Instead, add them on demand 43338b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran // when routes are added. 43438b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran fwmark.netId = 0; 43538b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran mask.netId = 0; 43638b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran 43738b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran fwmark.explicitlySelected = false; 43838b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran mask.explicitlySelected = true; 43938b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran 4404753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_LEGACY, ROUTE_TABLE_LEGACY, fwmark.intValue, 4414753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti mask.intValue, NULL); 44238b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran 44338b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran fwmark.permission = PERMISSION_CONNECTIVITY_INTERNAL; 44438b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran mask.permission = PERMISSION_CONNECTIVITY_INTERNAL; 44538b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran 4464753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_PRIVILEGED_LEGACY, ROUTE_TABLE_PRIVILEGED_LEGACY, 4474753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti fwmark.intValue, mask.intValue, NULL); 44838b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran 4498fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran// TODO: Uncomment once we are sure everything works. 4508fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran#if 0 4518fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran // Add a rule to preempt the pre-defined "from all lookup main" rule. This ensures that packets 4528fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran // that are already marked with a specific NetId don't fall-through to the main table. 4534753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_UNREACHABLE, 0, 0, 0, NULL); 4548fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran#endif 4558fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran} 4568fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran 457ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensenbool RouteController::addInterfaceToNetwork(unsigned netId, const char* interface, 458ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen Permission permission) { 4599c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran return modifyPerNetworkRules(netId, interface, permission, true, true); 4605c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran} 4615c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 462ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensenbool RouteController::removeInterfaceFromNetwork(unsigned netId, const char* interface, 463ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen Permission permission) { 46492b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran return modifyPerNetworkRules(netId, interface, permission, false, true) && 46592b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran flushRoutes(interface); 466379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran} 467379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran 468379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandranbool RouteController::modifyNetworkPermission(unsigned netId, const char* interface, 469379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran Permission oldPermission, Permission newPermission) { 470379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran // Add the new rules before deleting the old ones, to avoid race conditions. 4719c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran return modifyPerNetworkRules(netId, interface, newPermission, true, false) && 4729c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran modifyPerNetworkRules(netId, interface, oldPermission, false, false); 4739c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran} 4749c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran 47572604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandranbool RouteController::addToDefaultNetwork(const char* interface, Permission permission) { 4764753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti return modifyDefaultNetworkRules(interface, permission, RTM_NEWRULE); 4779c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran} 4789c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran 47972604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandranbool RouteController::removeFromDefaultNetwork(const char* interface, Permission permission) { 4804753afd79e130d5f1c888f549c36b4da92dbe680Lorenzo Colitti return modifyDefaultNetworkRules(interface, permission, RTM_DELRULE); 4815c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran} 4827619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran 483f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colittiint RouteController::addRoute(const char* interface, const char* destination, 484f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti const char* nexthop, TableType tableType, unsigned uid) { 485ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti return modifyRoute(interface, destination, nexthop, RTM_NEWROUTE, tableType, uid); 4867619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran} 4877619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran 488f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colittiint RouteController::removeRoute(const char* interface, const char* destination, 489f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti const char* nexthop, TableType tableType, unsigned uid) { 490ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti return modifyRoute(interface, destination, nexthop, RTM_DELROUTE, tableType, uid); 4917619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran} 492