RouteController.cpp revision a10ac3214f6a582b7fdb66acc43c702731e53d81
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
25namespace {
26
27const uint32_t RULE_PRIORITY_PER_NETWORK_EXPLICIT = 300;
28const uint32_t RULE_PRIORITY_PER_NETWORK_OIF = 400;
29const uint32_t RULE_PRIORITY_PER_NETWORK_NORMAL = 700;
30
31const bool FWMARK_USE_NET_ID = true;
32const bool FWMARK_USE_EXPLICIT = true;
33const bool FWMARK_USE_PROTECT = true;
34
35uint32_t getRouteTableForInterface(const char* interface) {
36    uint32_t index = if_nametoindex(interface);
37    return index ? index + RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX : 0;
38}
39
40bool runIpRuleCommand(const char* action, uint32_t priority, uint32_t table,
41                      uint32_t fwmark, uint32_t mask, const char* oif) {
42
43    char priorityString[UINT32_STRLEN];
44    char tableString[UINT32_STRLEN];
45    snprintf(priorityString, sizeof(priorityString), "%u", priority);
46    snprintf(tableString, sizeof(tableString), "%u", table);
47
48    char fwmarkString[sizeof("0x12345678/0x12345678")];
49    snprintf(fwmarkString, sizeof(fwmarkString), "0x%x/0x%x", fwmark, mask);
50
51    const char* version[] = {"-4", "-6"};
52    for (size_t i = 0; i < ARRAY_SIZE(version); ++i) {
53        int argc = 0;
54        const char* argv[16];
55
56        argv[argc++] = IP_PATH;
57        argv[argc++] = version[i];
58        argv[argc++] = "rule";
59        argv[argc++] = action;
60        argv[argc++] = "priority";
61        argv[argc++] = priorityString;
62        argv[argc++] = "table";
63        argv[argc++] = tableString;
64        if (mask) {
65            argv[argc++] = "fwmark";
66            argv[argc++] = fwmarkString;
67        }
68        if (oif) {
69            argv[argc++] = "oif";
70            argv[argc++] = oif;
71        }
72        if (android_fork_execvp(argc, const_cast<char**>(argv), NULL, false, false)) {
73            return false;
74        }
75    }
76
77    return true;
78}
79
80bool modifyNetwork(unsigned netId, const char* interface, Permission permission, bool add) {
81    uint32_t table = getRouteTableForInterface(interface);
82    if (!table) {
83        return false;
84    }
85
86    const char* action = add ? ADD : DEL;
87
88    // A rule to route traffic based on an explicitly chosen network.
89    //
90    // Supports apps that use the multinetwork APIs to restrict their traffic to a network.
91    //
92    // We don't really need to check the permission bits of the fwmark here, as they would've been
93    // checked at the time the netId was set into the fwmark, but we do so to be consistent.
94    uint32_t fwmark = getFwmark(netId, FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission);
95    uint32_t mask = getFwmarkMask(FWMARK_USE_NET_ID, FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT,
96                                  permission);
97    if (!runIpRuleCommand(action, RULE_PRIORITY_PER_NETWORK_EXPLICIT, table, fwmark, mask, NULL)) {
98        return false;
99    }
100
101    // A rule to route traffic based on a chosen outgoing interface.
102    //
103    // Supports apps that use SO_BINDTODEVICE or IP_PKTINFO options and the kernel that already
104    // knows the outgoing interface (typically for link-local communications).
105    fwmark = getFwmark(0, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission);
106    mask = getFwmark(!FWMARK_USE_NET_ID, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission);
107    if (!runIpRuleCommand(action, RULE_PRIORITY_PER_NETWORK_OIF, table, fwmark, mask, interface)) {
108        return false;
109    }
110
111    // A rule to route traffic based on the chosen network.
112    //
113    // This is for sockets that have not explicitly requested a particular network, but have been
114    // bound to one when they called connect(). This ensures that sockets connected on a particular
115    // network stay on that network even if the default network changes.
116    fwmark = getFwmark(netId, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission);
117    mask = getFwmarkMask(FWMARK_USE_NET_ID, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission);
118    if (!runIpRuleCommand(action, RULE_PRIORITY_PER_NETWORK_NORMAL, table, fwmark, mask, NULL)) {
119        return false;
120    }
121
122    // An iptables rule to mark incoming packets on a network with the netId of the network.
123    //
124    // This is so that the kernel can:
125    // + Use the right fwmark for (and thus correctly route) replies (e.g.: TCP RST, ICMP errors,
126    //   ping replies).
127    // + Mark sockets that accept connections from this interface so that the connection stays on
128    //   the same interface.
129    action = add ? "-A" : "-D";
130    char markString[UINT32_HEX_STRLEN];
131    snprintf(markString, sizeof(markString), "0x%x", netId);
132    if (execIptables(V4V6, "-t", "mangle", action, "INPUT", "-i", interface, "-j", "MARK",
133                     "--set-mark", markString, NULL)) {
134        return false;
135    }
136
137    return true;
138}
139
140}  // namespace
141
142bool RouteController::createNetwork(unsigned netId, const char* interface, Permission permission) {
143    return modifyNetwork(netId, interface, permission, true);
144}
145
146bool RouteController::destroyNetwork(unsigned netId, const char* interface, Permission permission) {
147    return modifyNetwork(netId, interface, permission, false);
148}
149