2 * Copyright (C) 2008 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.
22 #include <sys/socket.h>
24 #include <sys/types.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <resolv_netid.h>
31 #define LOG_TAG "SecondaryTablController"
32 #include <cutils/log.h>
33 #include <cutils/properties.h>
34 #include <logwrap/logwrap.h>
36 #include "ResponseCode.h"
37 #include "NetdConstants.h"
38 #include "SecondaryTableController.h"
40 const char* SecondaryTableController::LOCAL_MANGLE_OUTPUT = "st_mangle_OUTPUT";
41 const char* SecondaryTableController::LOCAL_MANGLE_POSTROUTING = "st_mangle_POSTROUTING";
42 const char* SecondaryTableController::LOCAL_NAT_POSTROUTING = "st_nat_POSTROUTING";
44 SecondaryTableController::SecondaryTableController(NetworkController* controller) :
45 mNetCtrl(controller) {
48 SecondaryTableController::~SecondaryTableController() {
51 int SecondaryTableController::setupIptablesHooks() {
52 int res = execIptables(V4V6,
58 // Do not mark sockets that have already been marked elsewhere(for example in DNS or protect).
59 res |= execIptables(V4V6,
73 // protect the legacy VPN daemons from routes.
74 // TODO: Remove this when legacy VPN's are removed.
75 res |= execIptables(V4V6,
90 int SecondaryTableController::addRoute(SocketClient *cli, char *iface, char *dest, int prefix,
92 return modifyRoute(cli, ADD, iface, dest, prefix, gateway, mNetCtrl->getNetworkId(iface));
95 int SecondaryTableController::modifyRoute(SocketClient *cli, const char *action, char *iface,
96 char *dest, int prefix, char *gateway, unsigned netId) {
97 char dest_str[44]; // enough to store an IPv6 address + 3 character bitmask
98 char tableIndex_str[11];
101 // IP tool doesn't like "::" - the equiv of 0.0.0.0 that it accepts for ipv4
102 snprintf(dest_str, sizeof(dest_str), "%s/%d", dest, prefix);
103 snprintf(tableIndex_str, sizeof(tableIndex_str), "%u", netId + BASE_TABLE_NUMBER);
105 if (strcmp("::", gateway) == 0) {
106 const char *cmd[] = {
116 ret = runCmd(ARRAY_SIZE(cmd), cmd);
118 const char *cmd[] = {
130 ret = runCmd(ARRAY_SIZE(cmd), cmd);
134 ALOGE("ip route %s failed: %s route %s %s/%d via %s dev %s table %u", action,
135 IP_PATH, action, dest, prefix, gateway, iface, netId + BASE_TABLE_NUMBER);
137 cli->sendMsg(ResponseCode::OperationFailed, "ip route modification failed", true);
141 modifyRuleCount(netId, action);
142 cli->sendMsg(ResponseCode::CommandOkay, "Route modified", false);
146 void SecondaryTableController::modifyRuleCount(unsigned netId, const char *action) {
147 if (strcmp(action, ADD) == 0) {
148 if (mNetIdRuleCount.count(netId) == 0)
149 mNetIdRuleCount[netId] = 0;
150 mNetIdRuleCount[netId]++;
152 if (mNetIdRuleCount.count(netId) > 0) {
153 if (--mNetIdRuleCount[netId] < 1) {
154 mNetIdRuleCount.erase(mNetIdRuleCount.find(netId));
160 const char *SecondaryTableController::getVersion(const char *addr) {
161 if (strchr(addr, ':') != NULL) {
168 IptablesTarget SecondaryTableController::getIptablesTarget(const char *addr) {
169 if (strchr(addr, ':') != NULL) {
176 int SecondaryTableController::removeRoute(SocketClient *cli, char *iface, char *dest, int prefix,
178 return modifyRoute(cli, DEL, iface, dest, prefix, gateway, mNetCtrl->getNetworkId(iface));
181 int SecondaryTableController::modifyFromRule(unsigned netId, const char *action,
183 char tableIndex_str[11];
185 snprintf(tableIndex_str, sizeof(tableIndex_str), "%u", netId + BASE_TABLE_NUMBER);
186 const char *cmd[] = {
196 if (runCmd(ARRAY_SIZE(cmd), cmd)) {
200 modifyRuleCount(netId, action);
204 int SecondaryTableController::modifyLocalRoute(unsigned netId, const char *action,
205 const char *iface, const char *addr) {
206 char tableIndex_str[11];
208 modifyRuleCount(netId, action); // some del's will fail as the iface is already gone.
209 snprintf(tableIndex_str, sizeof(tableIndex_str), "%u", netId + BASE_TABLE_NUMBER);
210 const char *cmd[] = {
221 return runCmd(ARRAY_SIZE(cmd), cmd);
223 int SecondaryTableController::addFwmarkRule(const char *iface) {
224 return setFwmarkRule(iface, true);
227 int SecondaryTableController::removeFwmarkRule(const char *iface) {
228 return setFwmarkRule(iface, false);
231 int SecondaryTableController::setFwmarkRule(const char *iface, bool add) {
232 unsigned netId = mNetCtrl->getNetworkId(iface);
234 // Fail fast if any rules already exist for this interface
235 if (mNetIdRuleCount.count(netId) > 0) {
242 snprintf(mark_str, sizeof(mark_str), "%u", netId + BASE_TABLE_NUMBER);
243 // Flush any marked routes we added
245 // iproute2 rule del will delete anything that matches, but only one rule at a time.
246 // So clearing the rules requires a bunch of calls.
247 // ip rule del will fail once there are no remaining rules that match.
248 const char *v4_cmd[] = {
258 while(!runCmd(ARRAY_SIZE(v4_cmd), v4_cmd)) {}
260 const char *v6_cmd[] = {
270 while(!runCmd(ARRAY_SIZE(v6_cmd), v6_cmd)) {}
272 // Add a route to the table to send all traffic to iface.
273 // We only need a default route because this table is only selected if a packet matches an
274 // IP rule that checks both the route and the mark.
275 const char *route_cmd[] = {
285 ret = runCmd(ARRAY_SIZE(route_cmd), route_cmd);
286 // The command might fail during delete if the iface is gone
287 if (add && ret) return ret;
290 const char *route6_cmd[] = {
301 ret = runCmd(ARRAY_SIZE(route6_cmd), route6_cmd);
302 // The command might fail during delete if the iface is gone
303 if (add && ret) return ret;
305 /* Best effort, because some kernels might not have the needed TCPMSS */
310 LOCAL_MANGLE_POSTROUTING,
311 "-p", "tcp", "-o", iface, "--tcp-flags", "SYN,RST", "SYN",
314 "--clamp-mss-to-pmtu",
317 // Because the mark gets set after the intial routing decision the source IP address is that
318 // of the original out interface. The only way to change the source IP address to that of the
319 // VPN iface is using source NAT.
320 // TODO: Remove this when we get the mark set correctly before the first routing pass.
321 ret = execIptables(V4,
325 LOCAL_NAT_POSTROUTING,
338 // Try and set up NAT for IPv6 as well. This was only added in Linux 3.7 so this may fail.
339 ret = execIptables(V6,
343 LOCAL_NAT_POSTROUTING,
354 // Without V6 NAT we can't do V6 over VPNs. If an IPv6 packet matches a VPN rule, then it
355 // will go out on the VPN interface, but without NAT, it will have the wrong source
356 // address. So reject all these packets.
357 // Due to rule application by the time the connection hits the output filter chain the
358 // routing pass based on the new mark has not yet happened. Reject in ip instead.
359 // TODO: Make the VPN code refuse to install IPv6 routes until we don't need IPv6 NAT.
360 const char *reject_cmd[] = {
364 add ? "replace" : "del",
370 ret = runCmd(ARRAY_SIZE(reject_cmd), reject_cmd);
371 // The command might fail during delete if the iface is gone
372 if (add && ret) return ret;
379 int SecondaryTableController::addFwmarkRoute(const char* iface, const char *dest, int prefix) {
380 return setFwmarkRoute(iface, dest, prefix, true);
383 int SecondaryTableController::removeFwmarkRoute(const char* iface, const char *dest, int prefix) {
384 return setFwmarkRoute(iface, dest, prefix, false);
387 int SecondaryTableController::setFwmarkRoute(const char* iface, const char *dest, int prefix,
389 unsigned netId = mNetCtrl->getNetworkId(iface);
390 char mark_str[11] = {0};
391 char dest_str[44]; // enough to store an IPv6 address + 3 character bitmask
393 snprintf(mark_str, sizeof(mark_str), "%u", netId + BASE_TABLE_NUMBER);
394 snprintf(dest_str, sizeof(dest_str), "%s/%d", dest, prefix);
395 const char *rule_cmd[] = {
397 getVersion(dest_str),
409 return runCmd(ARRAY_SIZE(rule_cmd), rule_cmd);
412 int SecondaryTableController::addUidRule(const char *iface, int uid_start, int uid_end) {
413 return setUidRule(iface, uid_start, uid_end, true);
416 int SecondaryTableController::removeUidRule(const char *iface, int uid_start, int uid_end) {
417 return setUidRule(iface, uid_start, uid_end, false);
420 int SecondaryTableController::setUidRule(const char *iface, int uid_start, int uid_end, bool add) {
421 unsigned netId = mNetCtrl->getNetworkId(iface);
422 if (!mNetCtrl->setNetworkForUidRange(uid_start, uid_end, add ? netId : 0, false)) {
427 char uid_str[24] = {0};
428 snprintf(uid_str, sizeof(uid_str), "%d-%d", uid_start, uid_end);
429 char mark_str[11] = {0};
430 snprintf(mark_str, sizeof(mark_str), "%u", netId + BASE_TABLE_NUMBER);
431 return execIptables(V4V6,
447 int SecondaryTableController::addHostExemption(const char *host) {
448 return setHostExemption(host, true);
451 int SecondaryTableController::removeHostExemption(const char *host) {
452 return setHostExemption(host, false);
455 int SecondaryTableController::setHostExemption(const char *host, bool add) {
456 const char *cmd[] = {
468 return runCmd(ARRAY_SIZE(cmd), cmd);
471 void SecondaryTableController::getUidMark(SocketClient *cli, int uid) {
472 unsigned netId = mNetCtrl->getNetwork(uid, NETID_UNSET, NetworkController::PID_UNSPECIFIED,
475 snprintf(mark_str, sizeof(mark_str), "%u", netId + BASE_TABLE_NUMBER);
476 cli->sendMsg(ResponseCode::GetMarkResult, mark_str, false);
479 void SecondaryTableController::getProtectMark(SocketClient *cli) {
480 char protect_mark_str[11];
481 snprintf(protect_mark_str, sizeof(protect_mark_str), "%d", PROTECT_MARK);
482 cli->sendMsg(ResponseCode::GetMarkResult, protect_mark_str, false);
485 int SecondaryTableController::runCmd(int argc, const char **argv) {
488 ret = android_fork_execvp(argc, (char **)argv, NULL, false, false);