2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "RouteController.h"
20 #include "NetdConstants.h"
22 #include <logwrap/logwrap.h>
27 const uint32_t RULE_PRIORITY_PER_NETWORK_EXPLICIT = 300;
28 const uint32_t RULE_PRIORITY_PER_NETWORK_INTERFACE = 400;
29 const uint32_t RULE_PRIORITY_PER_NETWORK_NORMAL = 700;
30 const uint32_t RULE_PRIORITY_DEFAULT_NETWORK = 900;
32 const bool FWMARK_USE_NET_ID = true;
33 const bool FWMARK_USE_EXPLICIT = true;
34 const bool FWMARK_USE_PROTECT = true;
36 uint32_t getRouteTableForInterface(const char* interface) {
37 uint32_t index = if_nametoindex(interface);
38 return index ? index + RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX : 0;
41 bool runIpRuleCommand(const char* action, uint32_t priority, uint32_t table,
42 uint32_t fwmark, uint32_t mask, const char* interface) {
43 char priorityString[UINT32_STRLEN];
44 snprintf(priorityString, sizeof(priorityString), "%u", priority);
46 char tableString[UINT32_STRLEN];
47 snprintf(tableString, sizeof(tableString), "%u", table);
49 char fwmarkString[sizeof("0x12345678/0x12345678")];
50 snprintf(fwmarkString, sizeof(fwmarkString), "0x%x/0x%x", fwmark, mask);
52 const char* version[] = {"-4", "-6"};
53 for (size_t i = 0; i < ARRAY_SIZE(version); ++i) {
57 argv[argc++] = IP_PATH;
58 argv[argc++] = version[i];
59 argv[argc++] = "rule";
60 argv[argc++] = action;
61 argv[argc++] = "priority";
62 argv[argc++] = priorityString;
63 argv[argc++] = "table";
64 argv[argc++] = tableString;
66 argv[argc++] = "fwmark";
67 argv[argc++] = fwmarkString;
71 argv[argc++] = interface;
73 if (android_fork_execvp(argc, const_cast<char**>(argv), NULL, false, false)) {
81 bool runIpRouteCommand(const char* action, uint32_t table, const char* interface,
82 const char* destination, const char* nexthop) {
83 char tableString[UINT32_STRLEN];
84 snprintf(tableString, sizeof(tableString), "%u", table);
89 argv[argc++] = IP_PATH;
90 argv[argc++] = "route";
91 argv[argc++] = action;
92 argv[argc++] = "table";
93 argv[argc++] = tableString;
95 argv[argc++] = destination;
97 argv[argc++] = interface;
100 argv[argc++] = nexthop;
104 return android_fork_execvp(argc, const_cast<char**>(argv), NULL, false, false);
107 bool modifyPerNetworkRules(unsigned netId, const char* interface, Permission permission, bool add,
108 bool modifyIptables) {
109 uint32_t table = getRouteTableForInterface(interface);
114 const char* action = add ? ADD : DEL;
116 // A rule to route traffic based on an explicitly chosen network.
118 // Supports apps that use the multinetwork APIs to restrict their traffic to a network.
120 // We don't really need to check the permission bits of the fwmark here, as they would've been
121 // checked at the time the netId was set into the fwmark, but we do so to be consistent.
122 uint32_t fwmark = getFwmark(netId, FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission);
123 uint32_t mask = getFwmarkMask(FWMARK_USE_NET_ID, FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT,
125 if (!runIpRuleCommand(action, RULE_PRIORITY_PER_NETWORK_EXPLICIT, table, fwmark, mask, NULL)) {
129 // A rule to route traffic based on a chosen outgoing interface.
131 // Supports apps that use SO_BINDTODEVICE or IP_PKTINFO options and the kernel that already
132 // knows the outgoing interface (typically for link-local communications).
133 fwmark = getFwmark(0, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission);
134 mask = getFwmark(!FWMARK_USE_NET_ID, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission);
135 if (!runIpRuleCommand(action, RULE_PRIORITY_PER_NETWORK_INTERFACE, table, fwmark, mask,
140 // A rule to route traffic based on the chosen network.
142 // This is for sockets that have not explicitly requested a particular network, but have been
143 // bound to one when they called connect(). This ensures that sockets connected on a particular
144 // network stay on that network even if the default network changes.
145 fwmark = getFwmark(netId, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission);
146 mask = getFwmarkMask(FWMARK_USE_NET_ID, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission);
147 if (!runIpRuleCommand(action, RULE_PRIORITY_PER_NETWORK_NORMAL, table, fwmark, mask, NULL)) {
151 // An iptables rule to mark incoming packets on a network with the netId of the network.
153 // This is so that the kernel can:
154 // + Use the right fwmark for (and thus correctly route) replies (e.g.: TCP RST, ICMP errors,
156 // + Mark sockets that accept connections from this interface so that the connection stays on
157 // the same interface.
158 if (modifyIptables) {
159 action = add ? "-A" : "-D";
160 char markString[UINT32_HEX_STRLEN];
161 snprintf(markString, sizeof(markString), "0x%x", netId);
162 if (execIptables(V4V6, "-t", "mangle", action, "INPUT", "-i", interface, "-j", "MARK",
163 "--set-mark", markString, NULL)) {
171 bool modifyDefaultNetworkRules(const char* interface, Permission permission, const char* action) {
172 uint32_t table = getRouteTableForInterface(interface);
177 uint32_t fwmark = getFwmark(0, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission);
178 uint32_t mask = getFwmarkMask(FWMARK_USE_NET_ID, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT,
181 return runIpRuleCommand(action, RULE_PRIORITY_DEFAULT_NETWORK, table, fwmark, mask, NULL);
184 bool modifyRoute(const char* interface, const char* destination, const char* nexthop, bool add) {
185 uint32_t table = getRouteTableForInterface(interface);
190 return runIpRouteCommand(add ? ADD : DEL, table, interface, destination, nexthop);
193 bool flushRoutes(const char* interface) {
194 uint32_t table = getRouteTableForInterface(interface);
199 return runIpRouteCommand("flush", table, NULL, NULL, NULL);
204 bool RouteController::createNetwork(unsigned netId, const char* interface, Permission permission) {
205 return modifyPerNetworkRules(netId, interface, permission, true, true);
208 bool RouteController::destroyNetwork(unsigned netId, const char* interface, Permission permission) {
209 return modifyPerNetworkRules(netId, interface, permission, false, true) &&
210 flushRoutes(interface);
213 bool RouteController::modifyNetworkPermission(unsigned netId, const char* interface,
214 Permission oldPermission, Permission newPermission) {
215 // Add the new rules before deleting the old ones, to avoid race conditions.
216 return modifyPerNetworkRules(netId, interface, newPermission, true, false) &&
217 modifyPerNetworkRules(netId, interface, oldPermission, false, false);
220 bool RouteController::addDefaultNetwork(const char* interface, Permission permission) {
221 return modifyDefaultNetworkRules(interface, permission, ADD);
224 bool RouteController::removeDefaultNetwork(const char* interface, Permission permission) {
225 return modifyDefaultNetworkRules(interface, permission, DEL);
228 bool RouteController::addRoute(const char* interface, const char* destination,
229 const char* nexthop) {
230 return modifyRoute(interface, destination, nexthop, true);
233 bool RouteController::removeRoute(const char* interface, const char* destination,
234 const char* nexthop) {
235 return modifyRoute(interface, destination, nexthop, false);