OSDN Git Service

e7b212332bf51d564b1be40322ae81309dbfee4a
[android-x86/system-netd.git] / RouteController.cpp
1 /*
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
22 #include <logwrap/logwrap.h>
23 #include <net/if.h>
24
25 namespace {
26
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;
31
32 const bool FWMARK_USE_NET_ID   = true;
33 const bool FWMARK_USE_EXPLICIT = true;
34 const bool FWMARK_USE_PROTECT  = true;
35
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;
39 }
40
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);
45
46     char tableString[UINT32_STRLEN];
47     snprintf(tableString, sizeof(tableString), "%u", table);
48
49     char fwmarkString[sizeof("0x12345678/0x12345678")];
50     snprintf(fwmarkString, sizeof(fwmarkString), "0x%x/0x%x", fwmark, mask);
51
52     const char* version[] = {"-4", "-6"};
53     for (size_t i = 0; i < ARRAY_SIZE(version); ++i) {
54         int argc = 0;
55         const char* argv[16];
56
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;
65         if (mask) {
66             argv[argc++] = "fwmark";
67             argv[argc++] = fwmarkString;
68         }
69         if (interface) {
70             argv[argc++] = "oif";
71             argv[argc++] = interface;
72         }
73         if (android_fork_execvp(argc, const_cast<char**>(argv), NULL, false, false)) {
74             return false;
75         }
76     }
77
78     return true;
79 }
80
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);
85
86     int argc = 0;
87     const char* argv[16];
88
89     argv[argc++] = IP_PATH;
90     argv[argc++] = "route";
91     argv[argc++] = action;
92     argv[argc++] = "table";
93     argv[argc++] = tableString;
94     if (destination) {
95         argv[argc++] = destination;
96         argv[argc++] = "dev";
97         argv[argc++] = interface;
98         if (nexthop) {
99             argv[argc++] = "via";
100             argv[argc++] = nexthop;
101         }
102     }
103
104     return android_fork_execvp(argc, const_cast<char**>(argv), NULL, false, false);
105 }
106
107 bool modifyPerNetworkRules(unsigned netId, const char* interface, Permission permission, bool add,
108                            bool modifyIptables) {
109     uint32_t table = getRouteTableForInterface(interface);
110     if (!table) {
111         return false;
112     }
113
114     const char* action = add ? ADD : DEL;
115
116     // A rule to route traffic based on an explicitly chosen network.
117     //
118     // Supports apps that use the multinetwork APIs to restrict their traffic to a network.
119     //
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,
124                                   permission);
125     if (!runIpRuleCommand(action, RULE_PRIORITY_PER_NETWORK_EXPLICIT, table, fwmark, mask, NULL)) {
126         return false;
127     }
128
129     // A rule to route traffic based on a chosen outgoing interface.
130     //
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,
136                           interface)) {
137         return false;
138     }
139
140     // A rule to route traffic based on the chosen network.
141     //
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)) {
148         return false;
149     }
150
151     // An iptables rule to mark incoming packets on a network with the netId of the network.
152     //
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,
155     //   ping replies).
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)) {
164             return false;
165         }
166     }
167
168     return true;
169 }
170
171 bool modifyDefaultNetworkRules(const char* interface, Permission permission, const char* action) {
172     uint32_t table = getRouteTableForInterface(interface);
173     if (!table) {
174         return false;
175     }
176
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,
179                                   permission);
180
181     return runIpRuleCommand(action, RULE_PRIORITY_DEFAULT_NETWORK, table, fwmark, mask, NULL);
182 }
183
184 bool modifyRoute(const char* interface, const char* destination, const char* nexthop, bool add) {
185     uint32_t table = getRouteTableForInterface(interface);
186     if (!table) {
187         return false;
188     }
189
190     return runIpRouteCommand(add ? ADD : DEL, table, interface, destination, nexthop);
191 }
192
193 bool flushRoutes(const char* interface) {
194     uint32_t table = getRouteTableForInterface(interface);
195     if (!table) {
196         return false;
197     }
198
199     return runIpRouteCommand("flush", table, NULL, NULL, NULL);
200 }
201
202 }  // namespace
203
204 bool RouteController::createNetwork(unsigned netId, const char* interface, Permission permission) {
205     return modifyPerNetworkRules(netId, interface, permission, true, true);
206 }
207
208 bool RouteController::destroyNetwork(unsigned netId, const char* interface, Permission permission) {
209     return modifyPerNetworkRules(netId, interface, permission, false, true) &&
210            flushRoutes(interface);
211 }
212
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);
218 }
219
220 bool RouteController::addDefaultNetwork(const char* interface, Permission permission) {
221     return modifyDefaultNetworkRules(interface, permission, ADD);
222 }
223
224 bool RouteController::removeDefaultNetwork(const char* interface, Permission permission) {
225     return modifyDefaultNetworkRules(interface, permission, DEL);
226 }
227
228 bool RouteController::addRoute(const char* interface, const char* destination,
229                                const char* nexthop) {
230     return modifyRoute(interface, destination, nexthop, true);
231 }
232
233 bool RouteController::removeRoute(const char* interface, const char* destination,
234                                   const char* nexthop) {
235     return modifyRoute(interface, destination, nexthop, false);
236 }