blob: af5df0477506251248a359dd5e18ab8c264c139b [file] [log] [blame]
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "RouteController.h"
18
19#include "Fwmark.h"
20#include "NetdConstants.h"
21
Lorenzo Colittiba25df92014-06-18 00:22:17 +090022#include <arpa/inet.h>
23#include <errno.h>
Lorenzo Colitti4753afd2014-06-20 23:03:29 +090024#include <linux/fib_rules.h>
Lorenzo Colittiba25df92014-06-18 00:22:17 +090025#include <linux/netlink.h>
Sreeram Ramachandran8fe9c8e2014-04-16 12:08:05 -070026#include <linux/rtnetlink.h>
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070027#include <logwrap/logwrap.h>
Paul Jensena561e122014-06-12 16:46:37 -040028#include <map>
Lorenzo Colittiba25df92014-06-18 00:22:17 +090029#include <netinet/in.h>
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070030#include <net/if.h>
Lorenzo Colittiba25df92014-06-18 00:22:17 +090031#include <sys/socket.h>
32#include <sys/uio.h>
33#include <unistd.h>
34
35// Avoids "non-constant-expression cannot be narrowed from type 'unsigned int' to 'unsigned short'"
36// warnings when using RTA_LENGTH(x) inside static initializers (even when x is already uint16_t).
37#define U16_RTA_LENGTH(x) static_cast<uint16_t>(RTA_LENGTH((x)))
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070038
39namespace {
40
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -070041const uint32_t RULE_PRIORITY_PRIVILEGED_LEGACY = 11000;
Sreeram Ramachandran8fe9c8e2014-04-16 12:08:05 -070042const uint32_t RULE_PRIORITY_PER_NETWORK_EXPLICIT = 13000;
43const uint32_t RULE_PRIORITY_PER_NETWORK_INTERFACE = 14000;
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -070044const uint32_t RULE_PRIORITY_LEGACY = 16000;
Sreeram Ramachandran8fe9c8e2014-04-16 12:08:05 -070045const uint32_t RULE_PRIORITY_PER_NETWORK_NORMAL = 17000;
46const uint32_t RULE_PRIORITY_DEFAULT_NETWORK = 19000;
47const uint32_t RULE_PRIORITY_MAIN = 20000;
Sreeram Ramachandran56afacf2014-05-28 15:07:00 -070048// TODO: Uncomment once we are sure everything works.
49#if 0
Sreeram Ramachandran8fe9c8e2014-04-16 12:08:05 -070050const uint32_t RULE_PRIORITY_UNREACHABLE = 21000;
Sreeram Ramachandran56afacf2014-05-28 15:07:00 -070051#endif
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070052
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -070053// TODO: These should be turned into per-UID tables once the kernel supports UID-based routing.
54const int ROUTE_TABLE_PRIVILEGED_LEGACY = RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX - 901;
55const int ROUTE_TABLE_LEGACY = RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX - 902;
56
Lorenzo Colitti4753afd2014-06-20 23:03:29 +090057const uint16_t kNetlinkRequestFlags = NLM_F_REQUEST | NLM_F_ACK;
58const uint16_t kNetlinkCreateRequestFlags = kNetlinkRequestFlags | NLM_F_CREATE | NLM_F_EXCL;
59
Paul Jensena561e122014-06-12 16:46:37 -040060std::map<std::string, uint32_t> interfaceToIndex;
61
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070062uint32_t getRouteTableForInterface(const char* interface) {
Sreeram Ramachandrana4811802014-04-10 12:10:24 -070063 uint32_t index = if_nametoindex(interface);
Paul Jensena561e122014-06-12 16:46:37 -040064 if (index) {
65 interfaceToIndex[interface] = index;
66 } else {
67 // If the interface goes away if_nametoindex() will return 0 but we still need to know
68 // the index so we can remove the rules and routes.
69 std::map<std::string, uint32_t>::iterator it = interfaceToIndex.find(interface);
70 if (it != interfaceToIndex.end())
71 index = it->second;
72 }
Sreeram Ramachandrana4811802014-04-10 12:10:24 -070073 return index ? index + RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX : 0;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070074}
75
Lorenzo Colitti4753afd2014-06-20 23:03:29 +090076// Sends a netlink request and expects an ack.
77// |iov| is an array of struct iovec that contains the netlink message payload.
78// The netlink header is generated by this function based on |action| and |flags|.
79// Returns -errno if there was an error or if the kernel reported an error.
80int sendNetlinkRequest(uint16_t action, uint16_t flags, iovec* iov, int iovlen) {
81 nlmsghdr nlmsg = {
82 .nlmsg_type = action,
83 .nlmsg_flags = flags,
84 };
85 iov[0].iov_base = &nlmsg;
86 iov[0].iov_len = sizeof(nlmsg);
87 for (int i = 0; i < iovlen; ++i) {
88 nlmsg.nlmsg_len += iov[i].iov_len;
89 }
90
91 int ret;
92 struct {
93 nlmsghdr msg;
94 nlmsgerr err;
95 } response;
96
97 sockaddr_nl kernel = {AF_NETLINK, 0, 0, 0};
98 int sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
99 if (sock != -1 &&
100 connect(sock, reinterpret_cast<sockaddr*>(&kernel), sizeof(kernel)) != -1 &&
101 writev(sock, iov, iovlen) != -1 &&
102 (ret = recv(sock, &response, sizeof(response), 0)) != -1) {
103 if (ret == sizeof(response)) {
104 ret = response.err.error; // Netlink errors are negative errno.
105 } else {
106 ret = -EBADMSG;
107 }
108 } else {
109 ret = -errno;
110 }
111
112 if (sock != -1) {
113 close(sock);
114 }
115
116 return ret;
117}
118
Sreeram Ramachandran8fe9c8e2014-04-16 12:08:05 -0700119// Adds or removes a routing rule for IPv4 and IPv6.
120//
121// + If |table| is non-zero, the rule points at the specified routing table. Otherwise, the rule
122// returns ENETUNREACH.
123// + If |mask| is non-zero, the rule matches the specified fwmark and mask. Otherwise, |fwmark| is
124// ignored.
125// + If |interface| is non-NULL, the rule matches the specified outgoing interface.
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900126//
127// Returns 0 on success or negative errno on failure.
128int modifyIpRule(uint16_t action, uint32_t priority, uint32_t table, uint32_t fwmark, uint32_t mask,
129 const char* interface) {
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900130 // The interface name must include exactly one terminating NULL and be properly padded, or older
131 // kernels will refuse to delete rules.
132 uint8_t padding[RTA_ALIGNTO] = {0, 0, 0, 0};
133 uint16_t paddingLength = 0;
134 size_t interfaceLength = 0;
135 char oifname[IFNAMSIZ];
136 if (interface) {
137 interfaceLength = strlcpy(oifname, interface, IFNAMSIZ) + 1;
138 if (interfaceLength > IFNAMSIZ) {
139 return -ENAMETOOLONG;
Sreeram Ramachandran8fe9c8e2014-04-16 12:08:05 -0700140 }
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900141 paddingLength = RTA_SPACE(interfaceLength) - RTA_LENGTH(interfaceLength);
142 }
143
144 // Assemble a rule request and put it in an array of iovec structures.
145 fib_rule_hdr rule = {
146 .action = static_cast<uint8_t>(table ? FR_ACT_TO_TBL : FR_ACT_UNREACHABLE),
147 };
148
149 rtattr fra_priority = { U16_RTA_LENGTH(sizeof(priority)), FRA_PRIORITY };
150 rtattr fra_table = { U16_RTA_LENGTH(sizeof(table)), FRA_TABLE };
151 rtattr fra_fwmark = { U16_RTA_LENGTH(sizeof(fwmark)), FRA_FWMARK };
152 rtattr fra_fwmask = { U16_RTA_LENGTH(sizeof(mask)), FRA_FWMASK };
153 rtattr fra_oifname = { U16_RTA_LENGTH(interfaceLength), FRA_OIFNAME };
154
155 iovec iov[] = {
156 { NULL, 0 },
157 { &rule, sizeof(rule) },
158 { &fra_priority, sizeof(fra_priority) },
159 { &priority, sizeof(priority) },
160 { &fra_table, table ? sizeof(fra_table) : 0 },
161 { &table, table ? sizeof(table) : 0 },
162 { &fra_fwmark, mask ? sizeof(fra_fwmark) : 0 },
163 { &fwmark, mask ? sizeof(fwmark) : 0 },
164 { &fra_fwmask, mask ? sizeof(fra_fwmask) : 0 },
165 { &mask, mask ? sizeof(mask) : 0 },
166 { &fra_oifname, interface ? sizeof(fra_oifname) : 0 },
167 { oifname, interfaceLength },
168 { padding, paddingLength },
169 };
170
171 uint16_t flags = (action == RTM_NEWRULE) ? kNetlinkCreateRequestFlags : kNetlinkRequestFlags;
172 uint8_t family[] = {AF_INET, AF_INET6};
173 for (size_t i = 0; i < ARRAY_SIZE(family); ++i) {
174 rule.family = family[i];
175 int ret = sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov));
176 if (ret) {
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900177 return ret;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700178 }
179 }
180
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900181 return 0;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700182}
183
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900184// Adds or deletes an IPv4 or IPv6 route.
185// Returns 0 on success or negative errno on failure.
186int modifyIpRoute(uint16_t action, uint32_t table, const char* interface, const char* destination,
187 const char* nexthop) {
188 // At least the destination must be non-null.
189 if (!destination) {
190 return -EFAULT;
191 }
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700192
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900193 // Parse the prefix.
194 uint8_t rawAddress[sizeof(in6_addr)];
195 uint8_t family, prefixLength;
196 int rawLength = parsePrefix(destination, &family, rawAddress, sizeof(rawAddress),
197 &prefixLength);
198 if (rawLength < 0) {
199 return rawLength;
200 }
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700201
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900202 if (static_cast<size_t>(rawLength) > sizeof(rawAddress)) {
203 return -ENOBUFS; // Cannot happen; parsePrefix only supports IPv4 and IPv6.
204 }
205
206 // If an interface was specified, find the ifindex.
207 uint32_t ifindex;
208 if (interface) {
209 ifindex = if_nametoindex(interface);
210 if (!ifindex) {
211 return -ENODEV;
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700212 }
213 }
214
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900215 // If a nexthop was specified, parse it as the same family as the prefix.
216 uint8_t rawNexthop[sizeof(in6_addr)];
217 if (nexthop && !inet_pton(family, nexthop, rawNexthop)) {
218 return -EINVAL;
219 }
220
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900221 // Assemble a rtmsg and put it in an array of iovec structures.
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900222 rtmsg rtmsg = {
223 .rtm_protocol = RTPROT_STATIC,
224 .rtm_type = RTN_UNICAST,
225 .rtm_family = family,
226 .rtm_dst_len = prefixLength,
227 };
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900228
229 rtattr rta_table = { U16_RTA_LENGTH(sizeof(table)), RTA_TABLE };
230 rtattr rta_oif = { U16_RTA_LENGTH(sizeof(ifindex)), RTA_OIF };
231 rtattr rta_dst = { U16_RTA_LENGTH(rawLength), RTA_DST };
232 rtattr rta_gateway = { U16_RTA_LENGTH(rawLength), RTA_GATEWAY };
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900233
234 iovec iov[] = {
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900235 { NULL, 0 },
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900236 { &rtmsg, sizeof(rtmsg) },
237 { &rta_table, sizeof(rta_table) },
238 { &table, sizeof(table) },
239 { &rta_dst, sizeof(rta_dst) },
240 { rawAddress, static_cast<size_t>(rawLength) },
241 { &rta_oif, interface ? sizeof(rta_oif) : 0 },
Sreeram Ramachandran7f972fb2014-06-24 16:09:21 -0700242 { &ifindex, interface ? sizeof(ifindex) : 0 },
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900243 { &rta_gateway, nexthop ? sizeof(rta_gateway) : 0 },
244 { rawNexthop, nexthop ? static_cast<size_t>(rawLength) : 0 },
245 };
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900246
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900247 uint16_t flags = (action == RTM_NEWROUTE) ? kNetlinkCreateRequestFlags : kNetlinkRequestFlags;
248 return sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov));
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700249}
250
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900251int modifyPerNetworkRules(unsigned netId, const char* interface, Permission permission, bool add,
252 bool modifyIptables) {
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700253 uint32_t table = getRouteTableForInterface(interface);
254 if (!table) {
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900255 return -ESRCH;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700256 }
257
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900258 uint16_t action = add ? RTM_NEWRULE : RTM_DELRULE;
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900259 int ret;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700260
Sreeram Ramachandran122f5812014-05-11 20:29:49 -0700261 Fwmark fwmark;
262 fwmark.permission = permission;
263
264 Fwmark mask;
265 mask.permission = permission;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700266
267 // A rule to route traffic based on a chosen outgoing interface.
268 //
269 // Supports apps that use SO_BINDTODEVICE or IP_PKTINFO options and the kernel that already
270 // knows the outgoing interface (typically for link-local communications).
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900271 if ((ret = modifyIpRule(action, RULE_PRIORITY_PER_NETWORK_INTERFACE, table, fwmark.intValue,
272 mask.intValue, interface)) != 0) {
273 return ret;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700274 }
275
276 // A rule to route traffic based on the chosen network.
277 //
278 // This is for sockets that have not explicitly requested a particular network, but have been
279 // bound to one when they called connect(). This ensures that sockets connected on a particular
280 // network stay on that network even if the default network changes.
Sreeram Ramachandran122f5812014-05-11 20:29:49 -0700281 fwmark.netId = netId;
282 mask.netId = FWMARK_NET_ID_MASK;
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900283 if ((ret = modifyIpRule(action, RULE_PRIORITY_PER_NETWORK_NORMAL, table, fwmark.intValue,
284 mask.intValue, NULL)) != 0) {
285 return ret;
Sreeram Ramachandran122f5812014-05-11 20:29:49 -0700286 }
287
288 // A rule to route traffic based on an explicitly chosen network.
289 //
290 // Supports apps that use the multinetwork APIs to restrict their traffic to a network.
291 //
292 // We don't really need to check the permission bits of the fwmark here, as they would've been
293 // checked at the time the netId was set into the fwmark, but we do so to be consistent.
294 fwmark.explicitlySelected = true;
295 mask.explicitlySelected = true;
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900296 if ((ret = modifyIpRule(action, RULE_PRIORITY_PER_NETWORK_EXPLICIT, table, fwmark.intValue,
297 mask.intValue, NULL)) != 0) {
298 return ret;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700299 }
300
301 // An iptables rule to mark incoming packets on a network with the netId of the network.
302 //
303 // This is so that the kernel can:
304 // + Use the right fwmark for (and thus correctly route) replies (e.g.: TCP RST, ICMP errors,
Sreeram Ramachandrana4811802014-04-10 12:10:24 -0700305 // ping replies).
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700306 // + Mark sockets that accept connections from this interface so that the connection stays on
307 // the same interface.
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700308 if (modifyIptables) {
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900309 const char* iptablesAction = add ? "-A" : "-D";
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700310 char markString[UINT32_HEX_STRLEN];
311 snprintf(markString, sizeof(markString), "0x%x", netId);
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900312 if (execIptables(V4V6, "-t", "mangle", iptablesAction, "INPUT", "-i", interface,
313 "-j", "MARK", "--set-mark", markString, NULL)) {
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900314 return -EREMOTEIO;
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700315 }
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700316 }
317
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900318 return 0;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700319}
320
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900321int modifyDefaultNetworkRules(const char* interface, Permission permission, uint16_t action) {
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700322 uint32_t table = getRouteTableForInterface(interface);
323 if (!table) {
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900324 return -ESRCH;
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700325 }
326
Sreeram Ramachandran122f5812014-05-11 20:29:49 -0700327 Fwmark fwmark;
328 fwmark.netId = 0;
329 fwmark.permission = permission;
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700330
Sreeram Ramachandran122f5812014-05-11 20:29:49 -0700331 Fwmark mask;
332 mask.netId = FWMARK_NET_ID_MASK;
333 mask.permission = permission;
334
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900335 return modifyIpRule(action, RULE_PRIORITY_DEFAULT_NETWORK, table, fwmark.intValue,
336 mask.intValue, NULL);
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700337}
338
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900339// Adds or removes an IPv4 or IPv6 route to the specified table and, if it's directly-connected
340// route, to the main table as well.
341// Returns 0 on success or negative errno on failure.
342int modifyRoute(const char* interface, const char* destination, const char* nexthop,
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900343 uint16_t action, RouteController::TableType tableType, unsigned /* uid */) {
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700344 uint32_t table = 0;
345 switch (tableType) {
346 case RouteController::INTERFACE: {
347 table = getRouteTableForInterface(interface);
348 break;
349 }
350 case RouteController::LEGACY: {
351 // TODO: Use the UID to assign a unique table per UID instead of this fixed table.
352 table = ROUTE_TABLE_LEGACY;
353 break;
354 }
355 case RouteController::PRIVILEGED_LEGACY: {
356 // TODO: Use the UID to assign a unique table per UID instead of this fixed table.
357 table = ROUTE_TABLE_PRIVILEGED_LEGACY;
358 break;
359 }
360 }
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700361 if (!table) {
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900362 return -ESRCH;
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700363 }
364
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900365 int ret = modifyIpRoute(action, table, interface, destination, nexthop);
366 if (ret != 0) {
367 return ret;
Sreeram Ramachandranc9213372014-04-16 12:32:18 -0700368 }
369
370 // If there's no nexthop, this is a directly connected route. Add it to the main table also, to
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900371 // let the kernel find it when validating nexthops when global routes are added.
372 if (!nexthop) {
373 ret = modifyIpRoute(action, RT_TABLE_MAIN, interface, destination, NULL);
374 // A failure with action == ADD && errno == EEXIST means that the route already exists in
375 // the main table, perhaps because the kernel added it automatically as part of adding the
376 // IP address to the interface. Ignore this, but complain about everything else.
377 if (ret != 0 && !(action == RTM_NEWROUTE && ret == -EEXIST)) {
378 return ret;
379 }
Sreeram Ramachandranc9213372014-04-16 12:32:18 -0700380 }
381
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900382 return 0;
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700383}
384
Sreeram Ramachandran92b66c42014-04-15 14:28:55 -0700385bool flushRoutes(const char* interface) {
386 uint32_t table = getRouteTableForInterface(interface);
387 if (!table) {
388 return false;
389 }
Paul Jensena561e122014-06-12 16:46:37 -0400390 interfaceToIndex.erase(interface);
Sreeram Ramachandran92b66c42014-04-15 14:28:55 -0700391
Lorenzo Colitti357e5622014-06-17 16:14:17 +0900392 char tableString[UINT32_STRLEN];
393 snprintf(tableString, sizeof(tableString), "%u", table);
394
395 const char* version[] = {"-4", "-6"};
396 for (size_t i = 0; i < ARRAY_SIZE(version); ++i) {
397 const char* argv[] = {
398 IP_PATH,
399 version[i],
400 "route"
401 "flush",
402 "table",
403 tableString,
404 };
405 int argc = ARRAY_SIZE(argv);
406
407 if (!android_fork_execvp(argc, const_cast<char**>(argv), NULL, false, false)) {
408 return false;
409 }
410 }
411
412 return true;
Sreeram Ramachandran92b66c42014-04-15 14:28:55 -0700413}
414
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700415} // namespace
416
Sreeram Ramachandran8fe9c8e2014-04-16 12:08:05 -0700417void RouteController::Init() {
418 // Add a new rule to look up the 'main' table, with the same selectors as the "default network"
419 // rule, but with a lower priority. Since the default network rule points to a table with a
420 // default route, the rule we're adding will never be used for normal routing lookups. However,
421 // the kernel may fall-through to it to find directly-connected routes when it validates that a
422 // nexthop (in a route being added) is reachable.
Sreeram Ramachandran122f5812014-05-11 20:29:49 -0700423 Fwmark fwmark;
424 fwmark.netId = 0;
425
426 Fwmark mask;
427 mask.netId = FWMARK_NET_ID_MASK;
428
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900429 modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_MAIN, RT_TABLE_MAIN, fwmark.intValue, mask.intValue,
430 NULL);
Sreeram Ramachandran8fe9c8e2014-04-16 12:08:05 -0700431
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700432 // Add rules to allow lookup of legacy routes.
433 //
434 // TODO: Remove these once the kernel supports UID-based routing. Instead, add them on demand
435 // when routes are added.
436 fwmark.netId = 0;
437 mask.netId = 0;
438
439 fwmark.explicitlySelected = false;
440 mask.explicitlySelected = true;
441
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900442 modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_LEGACY, ROUTE_TABLE_LEGACY, fwmark.intValue,
443 mask.intValue, NULL);
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700444
445 fwmark.permission = PERMISSION_CONNECTIVITY_INTERNAL;
446 mask.permission = PERMISSION_CONNECTIVITY_INTERNAL;
447
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900448 modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_PRIVILEGED_LEGACY, ROUTE_TABLE_PRIVILEGED_LEGACY,
449 fwmark.intValue, mask.intValue, NULL);
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700450
Sreeram Ramachandran8fe9c8e2014-04-16 12:08:05 -0700451// TODO: Uncomment once we are sure everything works.
452#if 0
453 // Add a rule to preempt the pre-defined "from all lookup main" rule. This ensures that packets
454 // that are already marked with a specific NetId don't fall-through to the main table.
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900455 modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_UNREACHABLE, 0, 0, 0, NULL);
Sreeram Ramachandran8fe9c8e2014-04-16 12:08:05 -0700456#endif
457}
458
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900459int RouteController::addInterfaceToNetwork(unsigned netId, const char* interface,
460 Permission permission) {
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700461 return modifyPerNetworkRules(netId, interface, permission, true, true);
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700462}
463
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900464int RouteController::removeInterfaceFromNetwork(unsigned netId, const char* interface,
465 Permission permission) {
Sreeram Ramachandran92b66c42014-04-15 14:28:55 -0700466 return modifyPerNetworkRules(netId, interface, permission, false, true) &&
467 flushRoutes(interface);
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700468}
469
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900470int RouteController::modifyNetworkPermission(unsigned netId, const char* interface,
471 Permission oldPermission, Permission newPermission) {
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700472 // Add the new rules before deleting the old ones, to avoid race conditions.
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700473 return modifyPerNetworkRules(netId, interface, newPermission, true, false) &&
474 modifyPerNetworkRules(netId, interface, oldPermission, false, false);
475}
476
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900477int RouteController::addToDefaultNetwork(const char* interface, Permission permission) {
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900478 return modifyDefaultNetworkRules(interface, permission, RTM_NEWRULE);
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700479}
480
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900481int RouteController::removeFromDefaultNetwork(const char* interface, Permission permission) {
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900482 return modifyDefaultNetworkRules(interface, permission, RTM_DELRULE);
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700483}
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700484
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900485int RouteController::addRoute(const char* interface, const char* destination,
486 const char* nexthop, TableType tableType, unsigned uid) {
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900487 return modifyRoute(interface, destination, nexthop, RTM_NEWROUTE, tableType, uid);
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700488}
489
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900490int RouteController::removeRoute(const char* interface, const char* destination,
491 const char* nexthop, TableType tableType, unsigned uid) {
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900492 return modifyRoute(interface, destination, nexthop, RTM_DELROUTE, tableType, uid);
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700493}