blob: 4b10f626340b55dd9d85faae5f3220f1412be6ca [file] [log] [blame]
Robert Greenwaltfc97b822011-11-02 16:48:36 -07001/*
2 * Copyright (C) 2008 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 <stdlib.h>
18#include <errno.h>
19#include <fcntl.h>
20#include <string.h>
21
22#include <sys/socket.h>
23#include <sys/stat.h>
24#include <sys/types.h>
25#include <sys/wait.h>
26
27#include <netinet/in.h>
28#include <arpa/inet.h>
29
30#define LOG_TAG "SecondaryTablController"
31#include <cutils/log.h>
32#include <cutils/properties.h>
Rom Lemarchand001f0a42013-01-31 12:41:03 -080033#include <logwrap/logwrap.h>
JP Abgrall9e5e0ce2011-12-14 15:20:59 -080034
Robert Greenwaltfc97b822011-11-02 16:48:36 -070035#include "ResponseCode.h"
Robert Greenwaltc4621772012-01-31 12:46:45 -080036#include "NetdConstants.h"
Robert Greenwaltfc97b822011-11-02 16:48:36 -070037#include "SecondaryTableController.h"
38
Chad Brubaker9a508892013-05-31 20:51:46 -070039const char* SecondaryTableController::LOCAL_MANGLE_OUTPUT = "st_mangle_OUTPUT";
40
Robert Greenwaltfc97b822011-11-02 16:48:36 -070041SecondaryTableController::SecondaryTableController() {
42 int i;
43 for (i=0; i < INTERFACES_TRACKED; i++) {
44 mInterfaceTable[i][0] = 0;
45 // TODO - use a hashtable or other prebuilt container class
46 mInterfaceRuleCount[i] = 0;
47 }
48}
49
50SecondaryTableController::~SecondaryTableController() {
51}
52
53int SecondaryTableController::findTableNumber(const char *iface) {
54 int i;
55 for (i = 0; i < INTERFACES_TRACKED; i++) {
Jaime A Lopez-Sollano3c207872012-01-11 16:29:28 -080056 // compare through the final null, hence +1
57 if (strncmp(iface, mInterfaceTable[i], IFNAMSIZ + 1) == 0) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -070058 return i;
59 }
60 }
61 return -1;
62}
63
64int SecondaryTableController::addRoute(SocketClient *cli, char *iface, char *dest, int prefix,
65 char *gateway) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -070066 int tableIndex = findTableNumber(iface);
67 if (tableIndex == -1) {
68 tableIndex = findTableNumber(""); // look for an empty slot
69 if (tableIndex == -1) {
Steve Block5ea0c052012-01-06 19:18:11 +000070 ALOGE("Max number of NATed interfaces reached");
Robert Greenwaltfc97b822011-11-02 16:48:36 -070071 errno = ENODEV;
72 cli->sendMsg(ResponseCode::OperationFailed, "Max number NATed", true);
73 return -1;
74 }
Jaime A Lopez-Sollanod14fd4f2012-01-11 16:29:28 -080075 strncpy(mInterfaceTable[tableIndex], iface, IFNAMSIZ);
76 // Ensure null termination even if truncation happened
77 mInterfaceTable[tableIndex][IFNAMSIZ] = 0;
Robert Greenwaltfc97b822011-11-02 16:48:36 -070078 }
79
Robert Greenwalt063af322011-11-18 15:32:13 -080080 return modifyRoute(cli, ADD, iface, dest, prefix, gateway, tableIndex);
81}
82
Robert Greenwaltc4621772012-01-31 12:46:45 -080083int SecondaryTableController::modifyRoute(SocketClient *cli, const char *action, char *iface,
84 char *dest, int prefix, char *gateway, int tableIndex) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -080085 char dest_str[44]; // enough to store an IPv6 address + 3 character bitmask
86 char tableIndex_str[11];
87 int ret;
88
89 // IP tool doesn't like "::" - the equiv of 0.0.0.0 that it accepts for ipv4
90 snprintf(dest_str, sizeof(dest_str), "%s/%d", dest, prefix);
91 snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex + BASE_TABLE_NUMBER);
Robert Greenwalt063af322011-11-18 15:32:13 -080092
93 if (strcmp("::", gateway) == 0) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -080094 const char *cmd[] = {
95 IP_PATH,
96 "route",
97 action,
98 dest_str,
99 "dev",
100 iface,
101 "table",
102 tableIndex_str
103 };
104 ret = runCmd(ARRAY_SIZE(cmd), cmd);
Robert Greenwalt063af322011-11-18 15:32:13 -0800105 } else {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800106 const char *cmd[] = {
107 IP_PATH,
108 "route",
109 action,
110 dest_str,
111 "via",
112 gateway,
113 "dev",
114 iface,
115 "table",
116 tableIndex_str
117 };
118 ret = runCmd(ARRAY_SIZE(cmd), cmd);
Robert Greenwalt063af322011-11-18 15:32:13 -0800119 }
120
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800121 if (ret) {
Steve Block5ea0c052012-01-06 19:18:11 +0000122 ALOGE("ip route %s failed: %s route %s %s/%d via %s dev %s table %d", action,
Robert Greenwalt063af322011-11-18 15:32:13 -0800123 IP_PATH, action, dest, prefix, gateway, iface, tableIndex+BASE_TABLE_NUMBER);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700124 errno = ENODEV;
Robert Greenwalt063af322011-11-18 15:32:13 -0800125 cli->sendMsg(ResponseCode::OperationFailed, "ip route modification failed", true);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700126 return -1;
127 }
Robert Greenwalt063af322011-11-18 15:32:13 -0800128
129 if (strcmp(action, ADD) == 0) {
130 mInterfaceRuleCount[tableIndex]++;
131 } else {
132 if (--mInterfaceRuleCount[tableIndex] < 1) {
133 mInterfaceRuleCount[tableIndex] = 0;
134 mInterfaceTable[tableIndex][0] = 0;
135 }
136 }
Robert Greenwaltc4621772012-01-31 12:46:45 -0800137 modifyRuleCount(tableIndex, action);
Robert Greenwalt063af322011-11-18 15:32:13 -0800138 cli->sendMsg(ResponseCode::CommandOkay, "Route modified", false);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700139 return 0;
140}
141
Robert Greenwaltc4621772012-01-31 12:46:45 -0800142void SecondaryTableController::modifyRuleCount(int tableIndex, const char *action) {
143 if (strcmp(action, ADD) == 0) {
144 mInterfaceRuleCount[tableIndex]++;
145 } else {
146 if (--mInterfaceRuleCount[tableIndex] < 1) {
147 mInterfaceRuleCount[tableIndex] = 0;
148 mInterfaceTable[tableIndex][0] = 0;
149 }
150 }
151}
152
153int SecondaryTableController::verifyTableIndex(int tableIndex) {
154 if ((tableIndex < 0) ||
155 (tableIndex >= INTERFACES_TRACKED) ||
156 (mInterfaceTable[tableIndex][0] == 0)) {
157 return -1;
158 } else {
159 return 0;
160 }
161}
162
163const char *SecondaryTableController::getVersion(const char *addr) {
164 if (strchr(addr, ':') != NULL) {
165 return "-6";
166 } else {
167 return "-4";
168 }
169}
170
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700171int SecondaryTableController::removeRoute(SocketClient *cli, char *iface, char *dest, int prefix,
172 char *gateway) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700173 int tableIndex = findTableNumber(iface);
174 if (tableIndex == -1) {
Steve Block5ea0c052012-01-06 19:18:11 +0000175 ALOGE("Interface not found");
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700176 errno = ENODEV;
177 cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
178 return -1;
179 }
180
Robert Greenwalt063af322011-11-18 15:32:13 -0800181 return modifyRoute(cli, DEL, iface, dest, prefix, gateway, tableIndex);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700182}
183
Robert Greenwaltc4621772012-01-31 12:46:45 -0800184int SecondaryTableController::modifyFromRule(int tableIndex, const char *action,
185 const char *addr) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800186 char tableIndex_str[11];
Robert Greenwaltc4621772012-01-31 12:46:45 -0800187
188 if (verifyTableIndex(tableIndex)) {
189 return -1;
190 }
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800191
192 snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex +
193 BASE_TABLE_NUMBER);
194 const char *cmd[] = {
195 IP_PATH,
196 getVersion(addr),
197 "rule",
198 action,
199 "from",
200 addr,
201 "table",
202 tableIndex_str
203 };
204 if (runCmd(ARRAY_SIZE(cmd), cmd)) {
Robert Greenwaltc4621772012-01-31 12:46:45 -0800205 return -1;
206 }
207
208 modifyRuleCount(tableIndex, action);
209 return 0;
210}
211
212int SecondaryTableController::modifyLocalRoute(int tableIndex, const char *action,
213 const char *iface, const char *addr) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800214 char tableIndex_str[11];
Robert Greenwaltc4621772012-01-31 12:46:45 -0800215
216 if (verifyTableIndex(tableIndex)) {
217 return -1;
218 }
219
220 modifyRuleCount(tableIndex, action); // some del's will fail as the iface is already gone.
221
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800222 snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex +
223 BASE_TABLE_NUMBER);
224 const char *cmd[] = {
225 IP_PATH,
226 "route",
227 action,
228 addr,
229 "dev",
230 iface,
231 "table",
232 tableIndex_str
233 };
234
235 return runCmd(ARRAY_SIZE(cmd), cmd);
Robert Greenwaltc4621772012-01-31 12:46:45 -0800236}
237
Chad Brubaker9a508892013-05-31 20:51:46 -0700238int SecondaryTableController::addUidRule(const char *iface, const char *uid) {
239 return setUidRule(iface, uid, true);
240}
241
242int SecondaryTableController::removeUidRule(const char *iface, const char *uid) {
243 return setUidRule(iface, uid, false);
244}
245
246int SecondaryTableController::setUidRule(const char *iface, const char *uid, bool add) {
247 int tableIndex = findTableNumber(iface);
248 if (tableIndex == -1) {
249 return -1;
250 }
251 char tableIndex_str[11] = {0};
252 snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex + BASE_TABLE_NUMBER);
253 return execIptables(V4V6,
254 "-t",
255 "mangle",
256 add ? "-A" : "-D",
257 LOCAL_MANGLE_OUTPUT,
258 "-m",
259 "owner",
260 "--uid-owner",
261 uid,
262 "-j",
263 "MARK",
264 "--set-mark",
265 tableIndex_str,
266 NULL);
267}
268
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800269int SecondaryTableController::runCmd(int argc, const char **argv) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700270 int ret = 0;
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800271
272 ret = android_fork_execvp(argc, (char **)argv, NULL, false, false);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700273 return ret;
274}