RouteController.cpp revision f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755
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> 24ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti#include <linux/netlink.h> 258fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran#include <linux/rtnetlink.h> 265c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran#include <logwrap/logwrap.h> 27a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen#include <map> 28ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti#include <netinet/in.h> 295c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran#include <net/if.h> 30ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti#include <sys/socket.h> 31ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti#include <sys/uio.h> 32ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti#include <unistd.h> 33ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti 34ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti// Avoids "non-constant-expression cannot be narrowed from type 'unsigned int' to 'unsigned short'" 35ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti// warnings when using RTA_LENGTH(x) inside static initializers (even when x is already uint16_t). 36ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti#define U16_RTA_LENGTH(x) static_cast<uint16_t>(RTA_LENGTH((x))) 375c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 385c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandrannamespace { 395c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 4038b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandranconst uint32_t RULE_PRIORITY_PRIVILEGED_LEGACY = 11000; 418fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandranconst uint32_t RULE_PRIORITY_PER_NETWORK_EXPLICIT = 13000; 428fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandranconst uint32_t RULE_PRIORITY_PER_NETWORK_INTERFACE = 14000; 4338b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandranconst uint32_t RULE_PRIORITY_LEGACY = 16000; 448fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandranconst uint32_t RULE_PRIORITY_PER_NETWORK_NORMAL = 17000; 458fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandranconst uint32_t RULE_PRIORITY_DEFAULT_NETWORK = 19000; 468fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandranconst uint32_t RULE_PRIORITY_MAIN = 20000; 4756afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran// TODO: Uncomment once we are sure everything works. 4856afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran#if 0 498fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandranconst uint32_t RULE_PRIORITY_UNREACHABLE = 21000; 5056afacf838d24cf8e54d2cf0d8ab9182ab704125Sreeram Ramachandran#endif 515c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 5238b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran// TODO: These should be turned into per-UID tables once the kernel supports UID-based routing. 5338b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandranconst int ROUTE_TABLE_PRIVILEGED_LEGACY = RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX - 901; 5438b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandranconst int ROUTE_TABLE_LEGACY = RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX - 902; 5538b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran 56a561e121c724e9163b2e256e15eef660e3a326daPaul Jensenstd::map<std::string, uint32_t> interfaceToIndex; 57a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen 585c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandranuint32_t getRouteTableForInterface(const char* interface) { 59a48118062412f16ae712bfc8c8a539d3b6a85e47Sreeram Ramachandran uint32_t index = if_nametoindex(interface); 60a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen if (index) { 61a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen interfaceToIndex[interface] = index; 62a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen } else { 63a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen // If the interface goes away if_nametoindex() will return 0 but we still need to know 64a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen // the index so we can remove the rules and routes. 65a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen std::map<std::string, uint32_t>::iterator it = interfaceToIndex.find(interface); 66a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen if (it != interfaceToIndex.end()) 67a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen index = it->second; 68a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen } 69a48118062412f16ae712bfc8c8a539d3b6a85e47Sreeram Ramachandran return index ? index + RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX : 0; 705c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran} 715c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 728fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran// Adds or removes a routing rule for IPv4 and IPv6. 738fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran// 748fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran// + If |table| is non-zero, the rule points at the specified routing table. Otherwise, the rule 758fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran// returns ENETUNREACH. 768fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran// + If |mask| is non-zero, the rule matches the specified fwmark and mask. Otherwise, |fwmark| is 778fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran// ignored. 788fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran// + If |interface| is non-NULL, the rule matches the specified outgoing interface. 798fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandranbool runIpRuleCommand(const char* action, uint32_t priority, uint32_t table, uint32_t fwmark, 808fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran uint32_t mask, const char* interface) { 81a10ac3214f6a582b7fdb66acc43c702731e53d81Lorenzo Colitti char priorityString[UINT32_STRLEN]; 82a10ac3214f6a582b7fdb66acc43c702731e53d81Lorenzo Colitti snprintf(priorityString, sizeof(priorityString), "%u", priority); 837619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran 847619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran char tableString[UINT32_STRLEN]; 85a10ac3214f6a582b7fdb66acc43c702731e53d81Lorenzo Colitti snprintf(tableString, sizeof(tableString), "%u", table); 86a10ac3214f6a582b7fdb66acc43c702731e53d81Lorenzo Colitti 87a10ac3214f6a582b7fdb66acc43c702731e53d81Lorenzo Colitti char fwmarkString[sizeof("0x12345678/0x12345678")]; 88a10ac3214f6a582b7fdb66acc43c702731e53d81Lorenzo Colitti snprintf(fwmarkString, sizeof(fwmarkString), "0x%x/0x%x", fwmark, mask); 89a10ac3214f6a582b7fdb66acc43c702731e53d81Lorenzo Colitti 905c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran const char* version[] = {"-4", "-6"}; 915c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran for (size_t i = 0; i < ARRAY_SIZE(version); ++i) { 925c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran int argc = 0; 935c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran const char* argv[16]; 945c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 955c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran argv[argc++] = IP_PATH; 965c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran argv[argc++] = version[i]; 975c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran argv[argc++] = "rule"; 985c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran argv[argc++] = action; 995c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran argv[argc++] = "priority"; 100a10ac3214f6a582b7fdb66acc43c702731e53d81Lorenzo Colitti argv[argc++] = priorityString; 1018fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran if (table) { 1028fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran argv[argc++] = "table"; 1038fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran argv[argc++] = tableString; 1048fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran } else { 1058fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran argv[argc++] = "unreachable"; 1068fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran } 107a10ac3214f6a582b7fdb66acc43c702731e53d81Lorenzo Colitti if (mask) { 1085c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran argv[argc++] = "fwmark"; 109a10ac3214f6a582b7fdb66acc43c702731e53d81Lorenzo Colitti argv[argc++] = fwmarkString; 1105c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran } 1119c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran if (interface) { 1125c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran argv[argc++] = "oif"; 1139c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran argv[argc++] = interface; 1145c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran } 1155c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran if (android_fork_execvp(argc, const_cast<char**>(argv), NULL, false, false)) { 1165c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran return false; 1175c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran } 1185c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran } 1195c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 1205c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran return true; 1215c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran} 1225c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 123ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti// Adds or deletes an IPv4 or IPv6 route. 124ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti// Returns 0 on success or negative errno on failure. 125ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colittiint modifyIpRoute(uint16_t action, uint32_t table, const char* interface, const char* destination, 126ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti const char* nexthop) { 127ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti // At least the destination must be non-null. 128ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti if (!destination) { 129ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti return -EFAULT; 130ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti } 131ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti 132ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti // Parse the prefix. 133ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti uint8_t rawAddress[sizeof(in6_addr)]; 134ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti uint8_t family, prefixLength; 135ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti int rawLength = parsePrefix(destination, &family, rawAddress, sizeof(rawAddress), 136ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti &prefixLength); 137ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti if (rawLength < 0) { 138ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti return rawLength; 139ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti } 1407619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran 141ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti if (static_cast<size_t>(rawLength) > sizeof(rawAddress)) { 142ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti return -ENOBUFS; // Cannot happen; parsePrefix only supports IPv4 and IPv6. 143ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti } 144ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti 145ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti // If an interface was specified, find the ifindex. 146ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti uint32_t ifindex; 147ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti if (interface) { 148ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti ifindex = if_nametoindex(interface); 149ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti if (!ifindex) { 150ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti return -ENODEV; 1517619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran } 1527619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran } 1537619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran 154ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti // If a nexthop was specified, parse it as the same family as the prefix. 155ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti uint8_t rawNexthop[sizeof(in6_addr)]; 156ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti if (nexthop && !inet_pton(family, nexthop, rawNexthop)) { 157ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti return -EINVAL; 158ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti } 159ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti 160ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti // Assemble a netlink request and put it in an array of iovec structures. 161ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti nlmsghdr nlmsg = { 162ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti .nlmsg_type = action, 163ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, 164ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti }; 165ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti rtmsg rtmsg = { 166ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti .rtm_protocol = RTPROT_STATIC, 167ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti .rtm_type = RTN_UNICAST, 168ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti .rtm_family = family, 169ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti .rtm_dst_len = prefixLength, 170ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti }; 171ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti rtattr rta_table = { U16_RTA_LENGTH(sizeof(table)), RTA_TABLE }; 172ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti rtattr rta_oif = { U16_RTA_LENGTH(sizeof(ifindex)), RTA_OIF }; 173ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti rtattr rta_dst = { U16_RTA_LENGTH(rawLength), RTA_DST }; 174ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti rtattr rta_gateway = { U16_RTA_LENGTH(rawLength), RTA_GATEWAY }; 175ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti if (action == RTM_NEWROUTE) { 176ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti nlmsg.nlmsg_flags |= (NLM_F_CREATE | NLM_F_EXCL); 177ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti } 178ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti 179ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti iovec iov[] = { 180ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { &nlmsg, sizeof(nlmsg) }, 181ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { &rtmsg, sizeof(rtmsg) }, 182ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { &rta_table, sizeof(rta_table) }, 183ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { &table, sizeof(table) }, 184ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { &rta_dst, sizeof(rta_dst) }, 185ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { rawAddress, static_cast<size_t>(rawLength) }, 186ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { &rta_oif, interface ? sizeof(rta_oif) : 0 }, 187ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { &ifindex, interface ? sizeof(interface) : 0 }, 188ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { &rta_gateway, nexthop ? sizeof(rta_gateway) : 0 }, 189ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti { rawNexthop, nexthop ? static_cast<size_t>(rawLength) : 0 }, 190ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti }; 191ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti int iovlen = ARRAY_SIZE(iov); 192ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti 193ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti for (int i = 0; i < iovlen; ++i) { 194ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti nlmsg.nlmsg_len += iov[i].iov_len; 195ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti } 196ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti 197ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti int ret; 198ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti struct { 199ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti nlmsghdr msg; 200ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti nlmsgerr err; 201ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti } response; 202ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti 203ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti sockaddr_nl kernel = {AF_NETLINK, 0, 0, 0}; 204ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti int sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); 205ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti if (sock != -1 && 206ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti connect(sock, reinterpret_cast<sockaddr *>(&kernel), sizeof(kernel)) != -1 && 207ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti writev(sock, iov, iovlen) != -1 && 208ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti (ret = recv(sock, &response, sizeof(response), 0)) != -1) { 209ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti if (ret == sizeof(response)) { 210ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti ret = response.err.error; // Netlink errors are negative errno. 211ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti } else { 212ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti ret = -EBADMSG; 213ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti } 214ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti } else { 215ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti ret = -errno; 216ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti } 217ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti 218ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti if (sock != -1) { 219ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti close(sock); 220ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti } 221ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti 222ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti return ret; 2237619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran} 2247619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran 2259c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandranbool modifyPerNetworkRules(unsigned netId, const char* interface, Permission permission, bool add, 2269c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran bool modifyIptables) { 2275c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran uint32_t table = getRouteTableForInterface(interface); 2285c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran if (!table) { 2295c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran return false; 2305c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran } 2315c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 2325c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran const char* action = add ? ADD : DEL; 2335c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 234122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran Fwmark fwmark; 235122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran fwmark.permission = permission; 236122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran 237122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran Fwmark mask; 238122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran mask.permission = permission; 2395c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 2405c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // A rule to route traffic based on a chosen outgoing interface. 2415c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // 2425c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // Supports apps that use SO_BINDTODEVICE or IP_PKTINFO options and the kernel that already 2435c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // knows the outgoing interface (typically for link-local communications). 244122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran if (!runIpRuleCommand(action, RULE_PRIORITY_PER_NETWORK_INTERFACE, table, fwmark.intValue, 245122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran mask.intValue, interface)) { 2465c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran return false; 2475c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran } 2485c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 2495c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // A rule to route traffic based on the chosen network. 2505c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // 2515c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // This is for sockets that have not explicitly requested a particular network, but have been 2525c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // bound to one when they called connect(). This ensures that sockets connected on a particular 2535c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // network stay on that network even if the default network changes. 254122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran fwmark.netId = netId; 255122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran mask.netId = FWMARK_NET_ID_MASK; 256122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran if (!runIpRuleCommand(action, RULE_PRIORITY_PER_NETWORK_NORMAL, table, fwmark.intValue, 257122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran mask.intValue, NULL)) { 258122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran return false; 259122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran } 260122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran 261122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran // A rule to route traffic based on an explicitly chosen network. 262122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran // 263122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran // Supports apps that use the multinetwork APIs to restrict their traffic to a network. 264122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran // 265122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran // We don't really need to check the permission bits of the fwmark here, as they would've been 266122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran // checked at the time the netId was set into the fwmark, but we do so to be consistent. 267122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran fwmark.explicitlySelected = true; 268122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran mask.explicitlySelected = true; 269122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran if (!runIpRuleCommand(action, RULE_PRIORITY_PER_NETWORK_EXPLICIT, table, fwmark.intValue, 270122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran mask.intValue, NULL)) { 2715c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran return false; 2725c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran } 2735c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 2745c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // An iptables rule to mark incoming packets on a network with the netId of the network. 2755c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // 2765c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // This is so that the kernel can: 2775c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // + Use the right fwmark for (and thus correctly route) replies (e.g.: TCP RST, ICMP errors, 278a48118062412f16ae712bfc8c8a539d3b6a85e47Sreeram Ramachandran // ping replies). 2795c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // + Mark sockets that accept connections from this interface so that the connection stays on 2805c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran // the same interface. 281379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran if (modifyIptables) { 282379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran action = add ? "-A" : "-D"; 283379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran char markString[UINT32_HEX_STRLEN]; 284379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran snprintf(markString, sizeof(markString), "0x%x", netId); 285379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran if (execIptables(V4V6, "-t", "mangle", action, "INPUT", "-i", interface, "-j", "MARK", 286379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran "--set-mark", markString, NULL)) { 287379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran return false; 288379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran } 2895c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran } 2905c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 2915c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran return true; 2925c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran} 2935c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 2949c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandranbool modifyDefaultNetworkRules(const char* interface, Permission permission, const char* action) { 2959c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran uint32_t table = getRouteTableForInterface(interface); 2969c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran if (!table) { 2979c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran return false; 2989c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran } 2999c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran 300122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran Fwmark fwmark; 301122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran fwmark.netId = 0; 302122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran fwmark.permission = permission; 303122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran 304122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran Fwmark mask; 305122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran mask.netId = FWMARK_NET_ID_MASK; 306122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran mask.permission = permission; 3079c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran 308122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran return runIpRuleCommand(action, RULE_PRIORITY_DEFAULT_NETWORK, table, fwmark.intValue, 309122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran mask.intValue, NULL); 3107619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran} 3117619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran 312f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti// Adds or removes an IPv4 or IPv6 route to the specified table and, if it's directly-connected 313f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti// route, to the main table as well. 314f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti// Returns 0 on success or negative errno on failure. 315f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colittiint modifyRoute(const char* interface, const char* destination, const char* nexthop, 316ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti int action, RouteController::TableType tableType, unsigned /* uid */) { 31738b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran uint32_t table = 0; 31838b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran switch (tableType) { 31938b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran case RouteController::INTERFACE: { 32038b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran table = getRouteTableForInterface(interface); 32138b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran break; 32238b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran } 32338b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran case RouteController::LEGACY: { 32438b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran // TODO: Use the UID to assign a unique table per UID instead of this fixed table. 32538b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran table = ROUTE_TABLE_LEGACY; 32638b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran break; 32738b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran } 32838b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran case RouteController::PRIVILEGED_LEGACY: { 32938b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran // TODO: Use the UID to assign a unique table per UID instead of this fixed table. 33038b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran table = ROUTE_TABLE_PRIVILEGED_LEGACY; 33138b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran break; 33238b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran } 33338b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran } 3347619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran if (!table) { 335f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti return -ESRCH; 3369c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran } 3379c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran 338f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti int ret = modifyIpRoute(action, table, interface, destination, nexthop); 339f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti if (ret != 0) { 340f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti return ret; 341c92133732378aae815120c39edd62a7b4eb773b3Sreeram Ramachandran } 342c92133732378aae815120c39edd62a7b4eb773b3Sreeram Ramachandran 343c92133732378aae815120c39edd62a7b4eb773b3Sreeram Ramachandran // If there's no nexthop, this is a directly connected route. Add it to the main table also, to 344f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti // let the kernel find it when validating nexthops when global routes are added. 345f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti if (!nexthop) { 346f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti ret = modifyIpRoute(action, RT_TABLE_MAIN, interface, destination, NULL); 347f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti // A failure with action == ADD && errno == EEXIST means that the route already exists in 348f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti // the main table, perhaps because the kernel added it automatically as part of adding the 349f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti // IP address to the interface. Ignore this, but complain about everything else. 350f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti if (ret != 0 && !(action == RTM_NEWROUTE && ret == -EEXIST)) { 351f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti return ret; 352f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti } 353c92133732378aae815120c39edd62a7b4eb773b3Sreeram Ramachandran } 354c92133732378aae815120c39edd62a7b4eb773b3Sreeram Ramachandran 355f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti return 0; 3569c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran} 3579c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran 35892b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandranbool flushRoutes(const char* interface) { 35992b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran uint32_t table = getRouteTableForInterface(interface); 36092b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran if (!table) { 36192b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran return false; 36292b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran } 363a561e121c724e9163b2e256e15eef660e3a326daPaul Jensen interfaceToIndex.erase(interface); 36492b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran 365357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti char tableString[UINT32_STRLEN]; 366357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti snprintf(tableString, sizeof(tableString), "%u", table); 367357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti 368357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti const char* version[] = {"-4", "-6"}; 369357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti for (size_t i = 0; i < ARRAY_SIZE(version); ++i) { 370357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti const char* argv[] = { 371357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti IP_PATH, 372357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti version[i], 373357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti "route" 374357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti "flush", 375357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti "table", 376357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti tableString, 377357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti }; 378357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti int argc = ARRAY_SIZE(argv); 379357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti 380357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti if (!android_fork_execvp(argc, const_cast<char**>(argv), NULL, false, false)) { 381357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti return false; 382357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti } 383357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti } 384357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti 385357e5629bb4c745296ab40340ec8679372337155Lorenzo Colitti return true; 38692b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran} 38792b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran 3885c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran} // namespace 3895c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 3908fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandranvoid RouteController::Init() { 3918fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran // Add a new rule to look up the 'main' table, with the same selectors as the "default network" 3928fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran // rule, but with a lower priority. Since the default network rule points to a table with a 3938fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran // default route, the rule we're adding will never be used for normal routing lookups. However, 3948fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran // the kernel may fall-through to it to find directly-connected routes when it validates that a 3958fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran // nexthop (in a route being added) is reachable. 396122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran Fwmark fwmark; 397122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran fwmark.netId = 0; 398122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran 399122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran Fwmark mask; 400122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran mask.netId = FWMARK_NET_ID_MASK; 401122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran 402122f581eb16e06c70cbbc40bd40995775075151fSreeram Ramachandran runIpRuleCommand(ADD, RULE_PRIORITY_MAIN, RT_TABLE_MAIN, fwmark.intValue, mask.intValue, NULL); 4038fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran 40438b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran // Add rules to allow lookup of legacy routes. 40538b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran // 40638b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran // TODO: Remove these once the kernel supports UID-based routing. Instead, add them on demand 40738b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran // when routes are added. 40838b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran fwmark.netId = 0; 40938b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran mask.netId = 0; 41038b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran 41138b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran fwmark.explicitlySelected = false; 41238b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran mask.explicitlySelected = true; 41338b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran 41438b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran runIpRuleCommand(ADD, RULE_PRIORITY_LEGACY, ROUTE_TABLE_LEGACY, fwmark.intValue, mask.intValue, 41538b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran NULL); 41638b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran 41738b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran fwmark.permission = PERMISSION_CONNECTIVITY_INTERNAL; 41838b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran mask.permission = PERMISSION_CONNECTIVITY_INTERNAL; 41938b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran 42038b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran runIpRuleCommand(ADD, RULE_PRIORITY_PRIVILEGED_LEGACY, ROUTE_TABLE_PRIVILEGED_LEGACY, 42138b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran fwmark.intValue, mask.intValue, NULL); 42238b7af1f2cb9579895465fabc37865f5dadcac25Sreeram Ramachandran 4238fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran// TODO: Uncomment once we are sure everything works. 4248fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran#if 0 4258fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran // Add a rule to preempt the pre-defined "from all lookup main" rule. This ensures that packets 4268fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran // that are already marked with a specific NetId don't fall-through to the main table. 4278fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran runIpRuleCommand(ADD, RULE_PRIORITY_UNREACHABLE, 0, 0, 0, NULL); 4288fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran#endif 4298fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran} 4308fe9c8e0a2b1c5cd2a34720efaccc641d9ab8fb6Sreeram Ramachandran 431ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensenbool RouteController::addInterfaceToNetwork(unsigned netId, const char* interface, 432ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen Permission permission) { 4339c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran return modifyPerNetworkRules(netId, interface, permission, true, true); 4345c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran} 4355c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran 436ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensenbool RouteController::removeInterfaceFromNetwork(unsigned netId, const char* interface, 437ae37e8a4f42b658d5aaf43f312f063944b4aeecbPaul Jensen Permission permission) { 43892b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran return modifyPerNetworkRules(netId, interface, permission, false, true) && 43992b66c4990b4a0ab608aa9c31da946f36085203bSreeram Ramachandran flushRoutes(interface); 440379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran} 441379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran 442379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandranbool RouteController::modifyNetworkPermission(unsigned netId, const char* interface, 443379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran Permission oldPermission, Permission newPermission) { 444379bd33f7640e2c4bef902be0ed6cb96378c8c2eSreeram Ramachandran // Add the new rules before deleting the old ones, to avoid race conditions. 4459c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran return modifyPerNetworkRules(netId, interface, newPermission, true, false) && 4469c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran modifyPerNetworkRules(netId, interface, oldPermission, false, false); 4479c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran} 4489c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran 44972604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandranbool RouteController::addToDefaultNetwork(const char* interface, Permission permission) { 4509c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran return modifyDefaultNetworkRules(interface, permission, ADD); 4519c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran} 4529c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran 45372604075e74af459fb4637404fbf030422c6b6b6Sreeram Ramachandranbool RouteController::removeFromDefaultNetwork(const char* interface, Permission permission) { 4549c0d313de6a3157fadd3b52a9927c77216ca435eSreeram Ramachandran return modifyDefaultNetworkRules(interface, permission, DEL); 4555c181bf8ca0c89bd9e3e6d8e40bac53d0ee7082fSreeram Ramachandran} 4567619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran 457f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colittiint RouteController::addRoute(const char* interface, const char* destination, 458f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti const char* nexthop, TableType tableType, unsigned uid) { 459ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti return modifyRoute(interface, destination, nexthop, RTM_NEWROUTE, tableType, uid); 4607619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran} 4617619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran 462f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colittiint RouteController::removeRoute(const char* interface, const char* destination, 463f7fc8eccb0a6a4fbca4cafdf53f5c167c8f1d755Lorenzo Colitti const char* nexthop, TableType tableType, unsigned uid) { 464ba25df989b48f36b784ad39307a49a4fd9c3fd66Lorenzo Colitti return modifyRoute(interface, destination, nexthop, RTM_DELROUTE, tableType, uid); 4657619e1bbebdfe643c35ee6be4ac054f5255f0706Sreeram Ramachandran} 466