blob: c7d542252f755b1c2e152a1ea66856e8d107febf [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
Lorenzo Colitti59656512014-06-25 03:20:29 +090053const uid_t kInvalidUid = (uid_t) -1;
54
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -070055// TODO: These should be turned into per-UID tables once the kernel supports UID-based routing.
56const int ROUTE_TABLE_PRIVILEGED_LEGACY = RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX - 901;
57const int ROUTE_TABLE_LEGACY = RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX - 902;
58
Lorenzo Colitti59656512014-06-25 03:20:29 +090059// TODO: These values aren't defined by the Linux kernel, because our UID routing changes are not
60// upstream (yet?), so we can't just pick them up from kernel headers. When (if?) the changes make
61// it upstream, we'll remove this and rely on the kernel header values. For now, add a static assert
62// that will warn us if upstream has given these values some other meaning.
63const uint16_t FRA_UID_START = 18;
64const uint16_t FRA_UID_END = 19;
65static_assert(FRA_UID_START > FRA_MAX,
66 "Android-specific FRA_UID_{START,END} values also assigned in Linux uapi. "
67 "Check that these values match what the kernel does and then update this assertion.");
68
Lorenzo Colitti4753afd2014-06-20 23:03:29 +090069const uint16_t kNetlinkRequestFlags = NLM_F_REQUEST | NLM_F_ACK;
70const uint16_t kNetlinkCreateRequestFlags = kNetlinkRequestFlags | NLM_F_CREATE | NLM_F_EXCL;
71
Paul Jensena561e122014-06-12 16:46:37 -040072std::map<std::string, uint32_t> interfaceToIndex;
73
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070074uint32_t getRouteTableForInterface(const char* interface) {
Sreeram Ramachandrana4811802014-04-10 12:10:24 -070075 uint32_t index = if_nametoindex(interface);
Paul Jensena561e122014-06-12 16:46:37 -040076 if (index) {
77 interfaceToIndex[interface] = index;
78 } else {
79 // If the interface goes away if_nametoindex() will return 0 but we still need to know
80 // the index so we can remove the rules and routes.
81 std::map<std::string, uint32_t>::iterator it = interfaceToIndex.find(interface);
82 if (it != interfaceToIndex.end())
83 index = it->second;
84 }
Sreeram Ramachandrana4811802014-04-10 12:10:24 -070085 return index ? index + RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX : 0;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -070086}
87
Lorenzo Colitti4753afd2014-06-20 23:03:29 +090088// Sends a netlink request and expects an ack.
89// |iov| is an array of struct iovec that contains the netlink message payload.
90// The netlink header is generated by this function based on |action| and |flags|.
91// Returns -errno if there was an error or if the kernel reported an error.
92int sendNetlinkRequest(uint16_t action, uint16_t flags, iovec* iov, int iovlen) {
93 nlmsghdr nlmsg = {
94 .nlmsg_type = action,
95 .nlmsg_flags = flags,
96 };
97 iov[0].iov_base = &nlmsg;
98 iov[0].iov_len = sizeof(nlmsg);
99 for (int i = 0; i < iovlen; ++i) {
100 nlmsg.nlmsg_len += iov[i].iov_len;
101 }
102
103 int ret;
104 struct {
105 nlmsghdr msg;
106 nlmsgerr err;
107 } response;
108
109 sockaddr_nl kernel = {AF_NETLINK, 0, 0, 0};
110 int sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
111 if (sock != -1 &&
112 connect(sock, reinterpret_cast<sockaddr*>(&kernel), sizeof(kernel)) != -1 &&
113 writev(sock, iov, iovlen) != -1 &&
114 (ret = recv(sock, &response, sizeof(response), 0)) != -1) {
115 if (ret == sizeof(response)) {
116 ret = response.err.error; // Netlink errors are negative errno.
117 } else {
118 ret = -EBADMSG;
119 }
120 } else {
121 ret = -errno;
122 }
123
124 if (sock != -1) {
125 close(sock);
126 }
127
128 return ret;
129}
130
Sreeram Ramachandran8fe9c8e2014-04-16 12:08:05 -0700131// Adds or removes a routing rule for IPv4 and IPv6.
132//
133// + If |table| is non-zero, the rule points at the specified routing table. Otherwise, the rule
134// returns ENETUNREACH.
135// + If |mask| is non-zero, the rule matches the specified fwmark and mask. Otherwise, |fwmark| is
136// ignored.
137// + If |interface| is non-NULL, the rule matches the specified outgoing interface.
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900138//
139// Returns 0 on success or negative errno on failure.
140int modifyIpRule(uint16_t action, uint32_t priority, uint32_t table, uint32_t fwmark, uint32_t mask,
Lorenzo Colitti59656512014-06-25 03:20:29 +0900141 const char* interface, uid_t uidStart, uid_t uidEnd) {
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900142 // The interface name must include exactly one terminating NULL and be properly padded, or older
143 // kernels will refuse to delete rules.
144 uint8_t padding[RTA_ALIGNTO] = {0, 0, 0, 0};
145 uint16_t paddingLength = 0;
146 size_t interfaceLength = 0;
147 char oifname[IFNAMSIZ];
148 if (interface) {
149 interfaceLength = strlcpy(oifname, interface, IFNAMSIZ) + 1;
150 if (interfaceLength > IFNAMSIZ) {
151 return -ENAMETOOLONG;
Sreeram Ramachandran8fe9c8e2014-04-16 12:08:05 -0700152 }
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900153 paddingLength = RTA_SPACE(interfaceLength) - RTA_LENGTH(interfaceLength);
154 }
155
Lorenzo Colitti59656512014-06-25 03:20:29 +0900156 // Either both start and end UID must be specified, or neither.
157 if ((uidStart == kInvalidUid) != (uidStart == kInvalidUid)) {
158 return -EUSERS;
159 }
160 bool isUidRule = (uidStart != kInvalidUid);
161
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900162 // Assemble a rule request and put it in an array of iovec structures.
163 fib_rule_hdr rule = {
164 .action = static_cast<uint8_t>(table ? FR_ACT_TO_TBL : FR_ACT_UNREACHABLE),
165 };
166
Lorenzo Colitti59656512014-06-25 03:20:29 +0900167 rtattr fra_priority = { U16_RTA_LENGTH(sizeof(priority)), FRA_PRIORITY };
168 rtattr fra_table = { U16_RTA_LENGTH(sizeof(table)), FRA_TABLE };
169 rtattr fra_fwmark = { U16_RTA_LENGTH(sizeof(fwmark)), FRA_FWMARK };
170 rtattr fra_fwmask = { U16_RTA_LENGTH(sizeof(mask)), FRA_FWMASK };
171 rtattr fra_oifname = { U16_RTA_LENGTH(interfaceLength), FRA_OIFNAME };
172 rtattr fra_uid_start = { U16_RTA_LENGTH(sizeof(uidStart)), FRA_UID_START };
173 rtattr fra_uid_end = { U16_RTA_LENGTH(sizeof(uidEnd)), FRA_UID_END };
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900174
175 iovec iov[] = {
Lorenzo Colitti59656512014-06-25 03:20:29 +0900176 { NULL, 0 },
177 { &rule, sizeof(rule) },
178 { &fra_priority, sizeof(fra_priority) },
179 { &priority, sizeof(priority) },
180 { &fra_table, table ? sizeof(fra_table) : 0 },
181 { &table, table ? sizeof(table) : 0 },
182 { &fra_fwmark, mask ? sizeof(fra_fwmark) : 0 },
183 { &fwmark, mask ? sizeof(fwmark) : 0 },
184 { &fra_fwmask, mask ? sizeof(fra_fwmask) : 0 },
185 { &mask, mask ? sizeof(mask) : 0 },
186 { &fra_uid_start, isUidRule ? sizeof(fra_uid_start) : 0 },
187 { &uidStart, isUidRule ? sizeof(uidStart) : 0 },
188 { &fra_uid_end, isUidRule ? sizeof(fra_uid_end) : 0 },
189 { &uidEnd, isUidRule ? sizeof(uidEnd) : 0 },
190 { &fra_oifname, interface ? sizeof(fra_oifname) : 0 },
191 { oifname, interfaceLength },
192 { padding, paddingLength },
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900193 };
194
195 uint16_t flags = (action == RTM_NEWRULE) ? kNetlinkCreateRequestFlags : kNetlinkRequestFlags;
196 uint8_t family[] = {AF_INET, AF_INET6};
197 for (size_t i = 0; i < ARRAY_SIZE(family); ++i) {
198 rule.family = family[i];
199 int ret = sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov));
200 if (ret) {
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900201 return ret;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700202 }
203 }
204
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900205 return 0;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700206}
207
Lorenzo Colitti59656512014-06-25 03:20:29 +0900208int modifyIpRule(uint16_t action, uint32_t priority, uint32_t table,
209 uint32_t fwmark, uint32_t mask, const char* interface) {
210 return modifyIpRule(action, priority, table, fwmark, mask, interface, kInvalidUid, kInvalidUid);
211}
212
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900213// Adds or deletes an IPv4 or IPv6 route.
214// Returns 0 on success or negative errno on failure.
215int modifyIpRoute(uint16_t action, uint32_t table, const char* interface, const char* destination,
216 const char* nexthop) {
217 // At least the destination must be non-null.
218 if (!destination) {
219 return -EFAULT;
220 }
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700221
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900222 // Parse the prefix.
223 uint8_t rawAddress[sizeof(in6_addr)];
224 uint8_t family, prefixLength;
225 int rawLength = parsePrefix(destination, &family, rawAddress, sizeof(rawAddress),
226 &prefixLength);
227 if (rawLength < 0) {
228 return rawLength;
229 }
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700230
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900231 if (static_cast<size_t>(rawLength) > sizeof(rawAddress)) {
232 return -ENOBUFS; // Cannot happen; parsePrefix only supports IPv4 and IPv6.
233 }
234
235 // If an interface was specified, find the ifindex.
236 uint32_t ifindex;
237 if (interface) {
238 ifindex = if_nametoindex(interface);
239 if (!ifindex) {
240 return -ENODEV;
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700241 }
242 }
243
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900244 // If a nexthop was specified, parse it as the same family as the prefix.
245 uint8_t rawNexthop[sizeof(in6_addr)];
246 if (nexthop && !inet_pton(family, nexthop, rawNexthop)) {
247 return -EINVAL;
248 }
249
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900250 // Assemble a rtmsg and put it in an array of iovec structures.
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900251 rtmsg rtmsg = {
252 .rtm_protocol = RTPROT_STATIC,
253 .rtm_type = RTN_UNICAST,
254 .rtm_family = family,
255 .rtm_dst_len = prefixLength,
256 };
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900257
258 rtattr rta_table = { U16_RTA_LENGTH(sizeof(table)), RTA_TABLE };
259 rtattr rta_oif = { U16_RTA_LENGTH(sizeof(ifindex)), RTA_OIF };
260 rtattr rta_dst = { U16_RTA_LENGTH(rawLength), RTA_DST };
261 rtattr rta_gateway = { U16_RTA_LENGTH(rawLength), RTA_GATEWAY };
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900262
263 iovec iov[] = {
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900264 { NULL, 0 },
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900265 { &rtmsg, sizeof(rtmsg) },
266 { &rta_table, sizeof(rta_table) },
267 { &table, sizeof(table) },
268 { &rta_dst, sizeof(rta_dst) },
269 { rawAddress, static_cast<size_t>(rawLength) },
270 { &rta_oif, interface ? sizeof(rta_oif) : 0 },
Sreeram Ramachandran7f972fb2014-06-24 16:09:21 -0700271 { &ifindex, interface ? sizeof(ifindex) : 0 },
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900272 { &rta_gateway, nexthop ? sizeof(rta_gateway) : 0 },
273 { rawNexthop, nexthop ? static_cast<size_t>(rawLength) : 0 },
274 };
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900275
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900276 uint16_t flags = (action == RTM_NEWROUTE) ? kNetlinkCreateRequestFlags : kNetlinkRequestFlags;
277 return sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov));
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700278}
279
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900280int modifyPerNetworkRules(unsigned netId, const char* interface, Permission permission, bool add,
281 bool modifyIptables) {
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700282 uint32_t table = getRouteTableForInterface(interface);
283 if (!table) {
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900284 return -ESRCH;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700285 }
286
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900287 uint16_t action = add ? RTM_NEWRULE : RTM_DELRULE;
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900288 int ret;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700289
Sreeram Ramachandran122f5812014-05-11 20:29:49 -0700290 Fwmark fwmark;
291 fwmark.permission = permission;
292
293 Fwmark mask;
294 mask.permission = permission;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700295
296 // A rule to route traffic based on a chosen outgoing interface.
297 //
298 // Supports apps that use SO_BINDTODEVICE or IP_PKTINFO options and the kernel that already
299 // knows the outgoing interface (typically for link-local communications).
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900300 if ((ret = modifyIpRule(action, RULE_PRIORITY_PER_NETWORK_INTERFACE, table, fwmark.intValue,
301 mask.intValue, interface)) != 0) {
302 return ret;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700303 }
304
305 // A rule to route traffic based on the chosen network.
306 //
307 // This is for sockets that have not explicitly requested a particular network, but have been
308 // bound to one when they called connect(). This ensures that sockets connected on a particular
309 // network stay on that network even if the default network changes.
Sreeram Ramachandran122f5812014-05-11 20:29:49 -0700310 fwmark.netId = netId;
311 mask.netId = FWMARK_NET_ID_MASK;
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900312 if ((ret = modifyIpRule(action, RULE_PRIORITY_PER_NETWORK_NORMAL, table, fwmark.intValue,
313 mask.intValue, NULL)) != 0) {
314 return ret;
Sreeram Ramachandran122f5812014-05-11 20:29:49 -0700315 }
316
317 // A rule to route traffic based on an explicitly chosen network.
318 //
319 // Supports apps that use the multinetwork APIs to restrict their traffic to a network.
320 //
321 // We don't really need to check the permission bits of the fwmark here, as they would've been
322 // checked at the time the netId was set into the fwmark, but we do so to be consistent.
323 fwmark.explicitlySelected = true;
324 mask.explicitlySelected = true;
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900325 if ((ret = modifyIpRule(action, RULE_PRIORITY_PER_NETWORK_EXPLICIT, table, fwmark.intValue,
326 mask.intValue, NULL)) != 0) {
327 return ret;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700328 }
329
330 // An iptables rule to mark incoming packets on a network with the netId of the network.
331 //
332 // This is so that the kernel can:
333 // + Use the right fwmark for (and thus correctly route) replies (e.g.: TCP RST, ICMP errors,
Sreeram Ramachandrana4811802014-04-10 12:10:24 -0700334 // ping replies).
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700335 // + Mark sockets that accept connections from this interface so that the connection stays on
336 // the same interface.
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700337 if (modifyIptables) {
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900338 const char* iptablesAction = add ? "-A" : "-D";
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700339 char markString[UINT32_HEX_STRLEN];
340 snprintf(markString, sizeof(markString), "0x%x", netId);
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900341 if (execIptables(V4V6, "-t", "mangle", iptablesAction, "INPUT", "-i", interface,
342 "-j", "MARK", "--set-mark", markString, NULL)) {
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900343 return -EREMOTEIO;
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700344 }
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700345 }
346
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900347 return 0;
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700348}
349
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900350int modifyDefaultNetworkRules(const char* interface, Permission permission, uint16_t action) {
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700351 uint32_t table = getRouteTableForInterface(interface);
352 if (!table) {
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900353 return -ESRCH;
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700354 }
355
Sreeram Ramachandran122f5812014-05-11 20:29:49 -0700356 Fwmark fwmark;
357 fwmark.netId = 0;
358 fwmark.permission = permission;
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700359
Sreeram Ramachandran122f5812014-05-11 20:29:49 -0700360 Fwmark mask;
361 mask.netId = FWMARK_NET_ID_MASK;
362 mask.permission = permission;
363
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900364 return modifyIpRule(action, RULE_PRIORITY_DEFAULT_NETWORK, table, fwmark.intValue,
365 mask.intValue, NULL);
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700366}
367
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900368// Adds or removes an IPv4 or IPv6 route to the specified table and, if it's directly-connected
369// route, to the main table as well.
370// Returns 0 on success or negative errno on failure.
371int modifyRoute(const char* interface, const char* destination, const char* nexthop,
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900372 uint16_t action, RouteController::TableType tableType, unsigned /* uid */) {
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700373 uint32_t table = 0;
374 switch (tableType) {
375 case RouteController::INTERFACE: {
376 table = getRouteTableForInterface(interface);
377 break;
378 }
379 case RouteController::LEGACY: {
380 // TODO: Use the UID to assign a unique table per UID instead of this fixed table.
381 table = ROUTE_TABLE_LEGACY;
382 break;
383 }
384 case RouteController::PRIVILEGED_LEGACY: {
385 // TODO: Use the UID to assign a unique table per UID instead of this fixed table.
386 table = ROUTE_TABLE_PRIVILEGED_LEGACY;
387 break;
388 }
389 }
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700390 if (!table) {
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900391 return -ESRCH;
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700392 }
393
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900394 int ret = modifyIpRoute(action, table, interface, destination, nexthop);
395 if (ret != 0) {
396 return ret;
Sreeram Ramachandranc9213372014-04-16 12:32:18 -0700397 }
398
399 // 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 +0900400 // let the kernel find it when validating nexthops when global routes are added.
401 if (!nexthop) {
402 ret = modifyIpRoute(action, RT_TABLE_MAIN, interface, destination, NULL);
403 // A failure with action == ADD && errno == EEXIST means that the route already exists in
404 // the main table, perhaps because the kernel added it automatically as part of adding the
405 // IP address to the interface. Ignore this, but complain about everything else.
406 if (ret != 0 && !(action == RTM_NEWROUTE && ret == -EEXIST)) {
407 return ret;
408 }
Sreeram Ramachandranc9213372014-04-16 12:32:18 -0700409 }
410
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900411 return 0;
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700412}
413
Sreeram Ramachandran92b66c42014-04-15 14:28:55 -0700414bool flushRoutes(const char* interface) {
415 uint32_t table = getRouteTableForInterface(interface);
416 if (!table) {
417 return false;
418 }
Paul Jensena561e122014-06-12 16:46:37 -0400419 interfaceToIndex.erase(interface);
Sreeram Ramachandran92b66c42014-04-15 14:28:55 -0700420
Lorenzo Colitti357e5622014-06-17 16:14:17 +0900421 char tableString[UINT32_STRLEN];
422 snprintf(tableString, sizeof(tableString), "%u", table);
423
424 const char* version[] = {"-4", "-6"};
425 for (size_t i = 0; i < ARRAY_SIZE(version); ++i) {
426 const char* argv[] = {
427 IP_PATH,
428 version[i],
429 "route"
430 "flush",
431 "table",
432 tableString,
433 };
434 int argc = ARRAY_SIZE(argv);
435
436 if (!android_fork_execvp(argc, const_cast<char**>(argv), NULL, false, false)) {
437 return false;
438 }
439 }
440
441 return true;
Sreeram Ramachandran92b66c42014-04-15 14:28:55 -0700442}
443
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700444} // namespace
445
Sreeram Ramachandran8fe9c8e2014-04-16 12:08:05 -0700446void RouteController::Init() {
447 // Add a new rule to look up the 'main' table, with the same selectors as the "default network"
448 // rule, but with a lower priority. Since the default network rule points to a table with a
449 // default route, the rule we're adding will never be used for normal routing lookups. However,
450 // the kernel may fall-through to it to find directly-connected routes when it validates that a
451 // nexthop (in a route being added) is reachable.
Sreeram Ramachandran122f5812014-05-11 20:29:49 -0700452 Fwmark fwmark;
453 fwmark.netId = 0;
454
455 Fwmark mask;
456 mask.netId = FWMARK_NET_ID_MASK;
457
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900458 modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_MAIN, RT_TABLE_MAIN, fwmark.intValue, mask.intValue,
459 NULL);
Sreeram Ramachandran8fe9c8e2014-04-16 12:08:05 -0700460
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700461 // Add rules to allow lookup of legacy routes.
462 //
463 // TODO: Remove these once the kernel supports UID-based routing. Instead, add them on demand
464 // when routes are added.
465 fwmark.netId = 0;
466 mask.netId = 0;
467
468 fwmark.explicitlySelected = false;
469 mask.explicitlySelected = true;
470
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900471 modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_LEGACY, ROUTE_TABLE_LEGACY, fwmark.intValue,
472 mask.intValue, NULL);
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700473
474 fwmark.permission = PERMISSION_CONNECTIVITY_INTERNAL;
475 mask.permission = PERMISSION_CONNECTIVITY_INTERNAL;
476
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900477 modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_PRIVILEGED_LEGACY, ROUTE_TABLE_PRIVILEGED_LEGACY,
478 fwmark.intValue, mask.intValue, NULL);
Sreeram Ramachandran38b7af12014-05-22 14:21:49 -0700479
Sreeram Ramachandran8fe9c8e2014-04-16 12:08:05 -0700480// TODO: Uncomment once we are sure everything works.
481#if 0
482 // Add a rule to preempt the pre-defined "from all lookup main" rule. This ensures that packets
483 // that are already marked with a specific NetId don't fall-through to the main table.
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900484 modifyIpRule(RTM_NEWRULE, RULE_PRIORITY_UNREACHABLE, 0, 0, 0, NULL);
Sreeram Ramachandran8fe9c8e2014-04-16 12:08:05 -0700485#endif
486}
487
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900488int RouteController::addInterfaceToNetwork(unsigned netId, const char* interface,
489 Permission permission) {
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700490 return modifyPerNetworkRules(netId, interface, permission, true, true);
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700491}
492
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900493int RouteController::removeInterfaceFromNetwork(unsigned netId, const char* interface,
494 Permission permission) {
Sreeram Ramachandran92b66c42014-04-15 14:28:55 -0700495 return modifyPerNetworkRules(netId, interface, permission, false, true) &&
496 flushRoutes(interface);
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700497}
498
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900499int RouteController::modifyNetworkPermission(unsigned netId, const char* interface,
500 Permission oldPermission, Permission newPermission) {
Sreeram Ramachandran379bd332014-04-10 19:58:06 -0700501 // Add the new rules before deleting the old ones, to avoid race conditions.
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700502 return modifyPerNetworkRules(netId, interface, newPermission, true, false) &&
503 modifyPerNetworkRules(netId, interface, oldPermission, false, false);
504}
505
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900506int RouteController::addToDefaultNetwork(const char* interface, Permission permission) {
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900507 return modifyDefaultNetworkRules(interface, permission, RTM_NEWRULE);
Sreeram Ramachandran9c0d3132014-04-10 20:35:04 -0700508}
509
Lorenzo Colitti96f261e2014-06-23 15:09:54 +0900510int RouteController::removeFromDefaultNetwork(const char* interface, Permission permission) {
Lorenzo Colitti4753afd2014-06-20 23:03:29 +0900511 return modifyDefaultNetworkRules(interface, permission, RTM_DELRULE);
Sreeram Ramachandran5c181bf2014-04-07 14:10:04 -0700512}
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700513
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900514int RouteController::addRoute(const char* interface, const char* destination,
515 const char* nexthop, TableType tableType, unsigned uid) {
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900516 return modifyRoute(interface, destination, nexthop, RTM_NEWROUTE, tableType, uid);
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700517}
518
Lorenzo Colittif7fc8ec2014-06-18 00:41:58 +0900519int RouteController::removeRoute(const char* interface, const char* destination,
520 const char* nexthop, TableType tableType, unsigned uid) {
Lorenzo Colittiba25df92014-06-18 00:22:17 +0900521 return modifyRoute(interface, destination, nexthop, RTM_DELROUTE, tableType, uid);
Sreeram Ramachandran7619e1b2014-04-15 14:23:08 -0700522}