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