blob: d12f4c870feb84483716aa5b71436dce776085b6 [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";
Chad Brubaker4a946092013-07-10 12:08:08 -070040const char* SecondaryTableController::LOCAL_MANGLE_EXEMPT = "st_mangle_EXEMPT";
Chad Brubaker2251c0f2013-06-27 17:20:39 -070041const char* SecondaryTableController::LOCAL_MANGLE_IFACE_FORMAT = "st_mangle_%s_OUTPUT";
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -070042const char* SecondaryTableController::LOCAL_NAT_POSTROUTING = "st_nat_POSTROUTING";
Chad Brubaker2251c0f2013-06-27 17:20:39 -070043const char* SecondaryTableController::LOCAL_FILTER_OUTPUT = "st_filter_OUTPUT";
Chad Brubaker9a508892013-05-31 20:51:46 -070044
Chad Brubakerd2617932013-06-21 15:26:35 -070045SecondaryTableController::SecondaryTableController(UidMarkMap *map) : mUidMarkMap(map) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -070046 int i;
47 for (i=0; i < INTERFACES_TRACKED; i++) {
48 mInterfaceTable[i][0] = 0;
49 // TODO - use a hashtable or other prebuilt container class
50 mInterfaceRuleCount[i] = 0;
51 }
52}
53
54SecondaryTableController::~SecondaryTableController() {
55}
56
Chad Brubaker2251c0f2013-06-27 17:20:39 -070057int SecondaryTableController::setupIptablesHooks() {
58 int res = execIptables(V4V6,
59 "-t",
60 "mangle",
61 "-F",
62 LOCAL_MANGLE_OUTPUT,
63 NULL);
Chad Brubaker4a946092013-07-10 12:08:08 -070064 res |= execIptables(V4V6,
65 "-t",
66 "mangle",
67 "-F",
68 LOCAL_MANGLE_EXEMPT,
69 NULL);
Chad Brubaker2349aa62013-07-15 15:28:59 -070070 // rule for skipping anything marked with the PROTECT_MARK
Chad Brubaker2251c0f2013-06-27 17:20:39 -070071 char protect_mark_str[11];
72 snprintf(protect_mark_str, sizeof(protect_mark_str), "%d", PROTECT_MARK);
73 res |= execIptables(V4V6,
74 "-t",
75 "mangle",
76 "-A",
77 LOCAL_MANGLE_OUTPUT,
78 "-m",
79 "mark",
80 "--mark",
81 protect_mark_str,
82 "-j",
83 "RETURN",
84 NULL);
85
Chad Brubaker2349aa62013-07-15 15:28:59 -070086 // protect the legacy VPN daemons from routes.
87 // TODO: Remove this when legacy VPN's are removed.
Chad Brubaker2251c0f2013-06-27 17:20:39 -070088 res |= execIptables(V4V6,
89 "-t",
90 "mangle",
91 "-A",
92 LOCAL_MANGLE_OUTPUT,
93 "-m",
94 "owner",
95 "--uid-owner",
96 "vpn",
97 "-j",
98 "RETURN",
99 NULL);
100 return res;
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700101}
102
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700103int SecondaryTableController::findTableNumber(const char *iface) {
104 int i;
105 for (i = 0; i < INTERFACES_TRACKED; i++) {
Jaime A Lopez-Sollano3c207872012-01-11 16:29:28 -0800106 // compare through the final null, hence +1
107 if (strncmp(iface, mInterfaceTable[i], IFNAMSIZ + 1) == 0) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700108 return i;
109 }
110 }
111 return -1;
112}
113
114int SecondaryTableController::addRoute(SocketClient *cli, char *iface, char *dest, int prefix,
115 char *gateway) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700116 int tableIndex = findTableNumber(iface);
117 if (tableIndex == -1) {
118 tableIndex = findTableNumber(""); // look for an empty slot
119 if (tableIndex == -1) {
Steve Block5ea0c052012-01-06 19:18:11 +0000120 ALOGE("Max number of NATed interfaces reached");
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700121 errno = ENODEV;
122 cli->sendMsg(ResponseCode::OperationFailed, "Max number NATed", true);
123 return -1;
124 }
Jaime A Lopez-Sollanod14fd4f2012-01-11 16:29:28 -0800125 strncpy(mInterfaceTable[tableIndex], iface, IFNAMSIZ);
126 // Ensure null termination even if truncation happened
127 mInterfaceTable[tableIndex][IFNAMSIZ] = 0;
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700128 }
129
Robert Greenwalt063af322011-11-18 15:32:13 -0800130 return modifyRoute(cli, ADD, iface, dest, prefix, gateway, tableIndex);
131}
132
Robert Greenwaltc4621772012-01-31 12:46:45 -0800133int SecondaryTableController::modifyRoute(SocketClient *cli, const char *action, char *iface,
134 char *dest, int prefix, char *gateway, int tableIndex) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800135 char dest_str[44]; // enough to store an IPv6 address + 3 character bitmask
136 char tableIndex_str[11];
137 int ret;
138
139 // IP tool doesn't like "::" - the equiv of 0.0.0.0 that it accepts for ipv4
140 snprintf(dest_str, sizeof(dest_str), "%s/%d", dest, prefix);
141 snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex + BASE_TABLE_NUMBER);
Robert Greenwalt063af322011-11-18 15:32:13 -0800142
143 if (strcmp("::", gateway) == 0) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800144 const char *cmd[] = {
145 IP_PATH,
146 "route",
147 action,
148 dest_str,
149 "dev",
150 iface,
151 "table",
152 tableIndex_str
153 };
154 ret = runCmd(ARRAY_SIZE(cmd), cmd);
Robert Greenwalt063af322011-11-18 15:32:13 -0800155 } else {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800156 const char *cmd[] = {
157 IP_PATH,
158 "route",
159 action,
160 dest_str,
161 "via",
162 gateway,
163 "dev",
164 iface,
165 "table",
166 tableIndex_str
167 };
168 ret = runCmd(ARRAY_SIZE(cmd), cmd);
Robert Greenwalt063af322011-11-18 15:32:13 -0800169 }
170
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800171 if (ret) {
Steve Block5ea0c052012-01-06 19:18:11 +0000172 ALOGE("ip route %s failed: %s route %s %s/%d via %s dev %s table %d", action,
Robert Greenwalt063af322011-11-18 15:32:13 -0800173 IP_PATH, action, dest, prefix, gateway, iface, tableIndex+BASE_TABLE_NUMBER);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700174 errno = ENODEV;
Robert Greenwalt063af322011-11-18 15:32:13 -0800175 cli->sendMsg(ResponseCode::OperationFailed, "ip route modification failed", true);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700176 return -1;
177 }
Robert Greenwalt063af322011-11-18 15:32:13 -0800178
179 if (strcmp(action, ADD) == 0) {
180 mInterfaceRuleCount[tableIndex]++;
181 } else {
182 if (--mInterfaceRuleCount[tableIndex] < 1) {
183 mInterfaceRuleCount[tableIndex] = 0;
184 mInterfaceTable[tableIndex][0] = 0;
185 }
186 }
Robert Greenwaltc4621772012-01-31 12:46:45 -0800187 modifyRuleCount(tableIndex, action);
Robert Greenwalt063af322011-11-18 15:32:13 -0800188 cli->sendMsg(ResponseCode::CommandOkay, "Route modified", false);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700189 return 0;
190}
191
Robert Greenwaltc4621772012-01-31 12:46:45 -0800192void SecondaryTableController::modifyRuleCount(int tableIndex, const char *action) {
193 if (strcmp(action, ADD) == 0) {
194 mInterfaceRuleCount[tableIndex]++;
195 } else {
196 if (--mInterfaceRuleCount[tableIndex] < 1) {
197 mInterfaceRuleCount[tableIndex] = 0;
198 mInterfaceTable[tableIndex][0] = 0;
199 }
200 }
201}
202
203int SecondaryTableController::verifyTableIndex(int tableIndex) {
204 if ((tableIndex < 0) ||
205 (tableIndex >= INTERFACES_TRACKED) ||
206 (mInterfaceTable[tableIndex][0] == 0)) {
207 return -1;
208 } else {
209 return 0;
210 }
211}
212
213const char *SecondaryTableController::getVersion(const char *addr) {
214 if (strchr(addr, ':') != NULL) {
215 return "-6";
216 } else {
217 return "-4";
218 }
219}
220
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700221IptablesTarget SecondaryTableController::getIptablesTarget(const char *addr) {
222 if (strchr(addr, ':') != NULL) {
223 return V6;
224 } else {
225 return V4;
226 }
227}
228
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700229int SecondaryTableController::removeRoute(SocketClient *cli, char *iface, char *dest, int prefix,
230 char *gateway) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700231 int tableIndex = findTableNumber(iface);
232 if (tableIndex == -1) {
Steve Block5ea0c052012-01-06 19:18:11 +0000233 ALOGE("Interface not found");
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700234 errno = ENODEV;
235 cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
236 return -1;
237 }
238
Robert Greenwalt063af322011-11-18 15:32:13 -0800239 return modifyRoute(cli, DEL, iface, dest, prefix, gateway, tableIndex);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700240}
241
Robert Greenwaltc4621772012-01-31 12:46:45 -0800242int SecondaryTableController::modifyFromRule(int tableIndex, const char *action,
243 const char *addr) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800244 char tableIndex_str[11];
Robert Greenwaltc4621772012-01-31 12:46:45 -0800245
246 if (verifyTableIndex(tableIndex)) {
247 return -1;
248 }
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800249
250 snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex +
251 BASE_TABLE_NUMBER);
252 const char *cmd[] = {
253 IP_PATH,
254 getVersion(addr),
255 "rule",
256 action,
257 "from",
258 addr,
259 "table",
260 tableIndex_str
261 };
262 if (runCmd(ARRAY_SIZE(cmd), cmd)) {
Robert Greenwaltc4621772012-01-31 12:46:45 -0800263 return -1;
264 }
265
266 modifyRuleCount(tableIndex, action);
267 return 0;
268}
269
270int SecondaryTableController::modifyLocalRoute(int tableIndex, const char *action,
271 const char *iface, const char *addr) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800272 char tableIndex_str[11];
Robert Greenwaltc4621772012-01-31 12:46:45 -0800273
274 if (verifyTableIndex(tableIndex)) {
275 return -1;
276 }
277
278 modifyRuleCount(tableIndex, action); // some del's will fail as the iface is already gone.
279
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800280 snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex +
281 BASE_TABLE_NUMBER);
282 const char *cmd[] = {
283 IP_PATH,
284 "route",
285 action,
286 addr,
287 "dev",
288 iface,
289 "table",
290 tableIndex_str
291 };
292
293 return runCmd(ARRAY_SIZE(cmd), cmd);
Robert Greenwaltc4621772012-01-31 12:46:45 -0800294}
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700295int SecondaryTableController::addFwmarkRule(const char *iface) {
296 return setFwmarkRule(iface, true);
297}
298
299int SecondaryTableController::removeFwmarkRule(const char *iface) {
300 return setFwmarkRule(iface, false);
301}
302
303int SecondaryTableController::setFwmarkRule(const char *iface, bool add) {
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700304 int tableIndex = findTableNumber(iface);
305 if (tableIndex == -1) {
306 tableIndex = findTableNumber(""); // look for an empty slot
307 if (tableIndex == -1) {
308 ALOGE("Max number of NATed interfaces reached");
309 errno = ENODEV;
310 return -1;
311 }
312 strncpy(mInterfaceTable[tableIndex], iface, IFNAMSIZ);
313 // Ensure null termination even if truncation happened
314 mInterfaceTable[tableIndex][IFNAMSIZ] = 0;
315 }
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700316 int mark = tableIndex + BASE_TABLE_NUMBER;
317 char mark_str[11];
318 int ret;
319
320 //fail fast if any rules already exist for this interface
321 if (mUidMarkMap->anyRulesForMark(mark)) {
322 errno = EBUSY;
323 return -1;
324 }
325
326 snprintf(mark_str, sizeof(mark_str), "%d", mark);
327 //add the catch all route to the tun. Route rules will make sure the right packets hit the table
328 const char *route_cmd[] = {
329 IP_PATH,
330 "route",
331 add ? "add" : "del",
332 "default",
333 "dev",
334 iface,
335 "table",
336 mark_str
337 };
338 ret = runCmd(ARRAY_SIZE(route_cmd), route_cmd);
339
340 const char *fwmark_cmd[] = {
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700341 IP_PATH,
342 "rule",
343 add ? "add" : "del",
Chad Brubaker2349aa62013-07-15 15:28:59 -0700344 "prio",
345 RULE_PRIO,
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700346 "fwmark",
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700347 mark_str,
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700348 "table",
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700349 mark_str
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700350 };
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700351 ret = runCmd(ARRAY_SIZE(fwmark_cmd), fwmark_cmd);
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700352 if (ret) return ret;
353
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700354 //add rules for v6
355 const char *route6_cmd[] = {
356 IP_PATH,
357 "-6",
358 "route",
359 add ? "add" : "del",
360 "default",
361 "dev",
362 iface,
363 "table",
364 mark_str
365 };
366 ret = runCmd(ARRAY_SIZE(route6_cmd), route6_cmd);
367
368 const char *fwmark6_cmd[] = {
369 IP_PATH,
370 "-6",
371 "rule",
372 add ? "add" : "del",
Chad Brubaker2349aa62013-07-15 15:28:59 -0700373 "prio",
374 RULE_PRIO,
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700375 "fwmark",
376 mark_str,
377 "table",
378 mark_str
379 };
380 ret = runCmd(ARRAY_SIZE(fwmark6_cmd), fwmark6_cmd);
381
382
383 if (ret) return ret;
384
385 //create the route rule chain
386 char chain_str[IFNAMSIZ + 18];
387 snprintf(chain_str, sizeof(chain_str), LOCAL_MANGLE_IFACE_FORMAT, iface);
388 //code split due to ordering requirements
389 if (add) {
390 ret = execIptables(V4V6,
391 "-t",
392 "mangle",
393 "-N",
394 chain_str,
395 NULL);
396 //set up the rule for sending premarked packets to the VPN chain
397 //Insert these at the top of the chain so they trigger before any UID rules
398 ret |= execIptables(V4V6,
399 "-t",
400 "mangle",
401 "-I",
402 LOCAL_MANGLE_OUTPUT,
403 "3",
404 "-m",
405 "mark",
406 "--mark",
407 mark_str,
408 "-g",
409 chain_str,
410 NULL);
411 //add a rule to clear the mark in the VPN chain
412 //packets marked with SO_MARK already have the iface's mark set but unless they match a
413 //route they should hit the network instead of the VPN
414 ret |= execIptables(V4V6,
415 "-t",
416 "mangle",
417 "-A",
418 chain_str,
419 "-j",
420 "MARK",
421 "--set-mark",
422 "0",
423 NULL);
424
425 } else {
426 ret = execIptables(V4V6,
427 "-t",
428 "mangle",
429 "-D",
430 LOCAL_MANGLE_OUTPUT,
431 "-m",
432 "mark",
433 "--mark",
434 mark_str,
435 "-g",
436 chain_str,
437 NULL);
438
439 //clear and delete the chain
440 ret |= execIptables(V4V6,
441 "-t",
442 "mangle",
443 "-F",
444 chain_str,
445 NULL);
446
447 ret |= execIptables(V4V6,
448 "-t",
449 "mangle",
450 "-X",
451 chain_str,
452 NULL);
453 }
454
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700455 //set up the needed source IP rewriting
456 //NOTE: Without ipv6 NAT in the kernel <3.7 only support V4 NAT
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700457 ret = execIptables(V4,
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700458 "-t",
459 "nat",
460 add ? "-A" : "-D",
461 LOCAL_NAT_POSTROUTING,
462 "-o",
463 iface,
464 "-m",
465 "mark",
466 "--mark",
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700467 mark_str,
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700468 "-j",
469 "MASQUERADE",
470 NULL);
471
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700472 if (ret) return ret;
473
474 //try and set up for ipv6. ipv6 nat came in the kernel only in 3.7, so this can fail
475 ret = execIptables(V6,
476 "-t",
477 "nat",
478 add ? "-A" : "-D",
479 LOCAL_NAT_POSTROUTING,
480 "-o",
481 iface,
482 "-m",
483 "mark",
484 "--mark",
485 mark_str,
486 "-j",
487 "MASQUERADE",
488 NULL);
489 if (ret) {
490 //Without V6 NAT we can't do V6 over VPNs.
491 ret = execIptables(V6,
492 "-t",
493 "filter",
494 add ? "-A" : "-D",
495 LOCAL_FILTER_OUTPUT,
496 "-m",
497 "mark",
498 "--mark",
499 mark_str,
500 "-j",
501 "REJECT",
502 NULL);
503 }
504 return ret;
505
506}
507
508int SecondaryTableController::addFwmarkRoute(const char* iface, const char *dest, int prefix) {
509 return setFwmarkRoute(iface, dest, prefix, true);
510}
511
512int SecondaryTableController::removeFwmarkRoute(const char* iface, const char *dest, int prefix) {
513 return setFwmarkRoute(iface, dest, prefix, true);
514}
515
516int SecondaryTableController::setFwmarkRoute(const char* iface, const char *dest, int prefix,
517 bool add) {
518 int tableIndex = findTableNumber(iface);
519 if (tableIndex == -1) {
520 errno = EINVAL;
521 return -1;
522 }
523 int mark = tableIndex + BASE_TABLE_NUMBER;
524 char mark_str[11] = {0};
525 char chain_str[IFNAMSIZ + 18];
526 char dest_str[44]; // enough to store an IPv6 address + 3 character bitmask
527
528 snprintf(mark_str, sizeof(mark_str), "%d", mark);
529 snprintf(chain_str, sizeof(chain_str), LOCAL_MANGLE_IFACE_FORMAT, iface);
530 snprintf(dest_str, sizeof(dest_str), "%s/%d", dest, prefix);
531 return execIptables(getIptablesTarget(dest),
532 "-t",
533 "mangle",
534 add ? "-A" : "-D",
535 chain_str,
536 "-d",
537 dest_str,
538 "-j",
539 "MARK",
540 "--set-mark",
541 mark_str,
542 NULL);
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700543}
Robert Greenwaltc4621772012-01-31 12:46:45 -0800544
Chad Brubaker8830b942013-06-12 10:51:55 -0700545int SecondaryTableController::addUidRule(const char *iface, int uid_start, int uid_end) {
546 return setUidRule(iface, uid_start, uid_end, true);
Chad Brubaker9a508892013-05-31 20:51:46 -0700547}
548
Chad Brubaker8830b942013-06-12 10:51:55 -0700549int SecondaryTableController::removeUidRule(const char *iface, int uid_start, int uid_end) {
550 return setUidRule(iface, uid_start, uid_end, false);
Chad Brubaker9a508892013-05-31 20:51:46 -0700551}
552
Chad Brubaker8830b942013-06-12 10:51:55 -0700553int SecondaryTableController::setUidRule(const char *iface, int uid_start, int uid_end, bool add) {
Chad Brubaker9a508892013-05-31 20:51:46 -0700554 int tableIndex = findTableNumber(iface);
555 if (tableIndex == -1) {
Chad Brubakerd2617932013-06-21 15:26:35 -0700556 errno = EINVAL;
Chad Brubaker9a508892013-05-31 20:51:46 -0700557 return -1;
558 }
Chad Brubakerd2617932013-06-21 15:26:35 -0700559 int mark = tableIndex + BASE_TABLE_NUMBER;
560 if (add) {
561 if (!mUidMarkMap->add(uid_start, uid_end, mark)) {
562 errno = EINVAL;
563 return -1;
564 }
565 } else {
566 if (!mUidMarkMap->remove(uid_start, uid_end, mark)) {
567 errno = EINVAL;
568 return -1;
569 }
570 }
Chad Brubaker8830b942013-06-12 10:51:55 -0700571 char uid_str[24] = {0};
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700572 char chain_str[IFNAMSIZ + 18];
Chad Brubaker8830b942013-06-12 10:51:55 -0700573 snprintf(uid_str, sizeof(uid_str), "%d-%d", uid_start, uid_end);
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700574 snprintf(chain_str, sizeof(chain_str), LOCAL_MANGLE_IFACE_FORMAT, iface);
Chad Brubaker9a508892013-05-31 20:51:46 -0700575 return execIptables(V4V6,
576 "-t",
577 "mangle",
578 add ? "-A" : "-D",
579 LOCAL_MANGLE_OUTPUT,
580 "-m",
581 "owner",
582 "--uid-owner",
Chad Brubaker8830b942013-06-12 10:51:55 -0700583 uid_str,
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700584 "-g",
585 chain_str,
Chad Brubaker9a508892013-05-31 20:51:46 -0700586 NULL);
587}
588
Chad Brubaker4a946092013-07-10 12:08:08 -0700589int SecondaryTableController::addHostExemption(const char *host) {
590 return setHostExemption(host, true);
591}
592
593int SecondaryTableController::removeHostExemption(const char *host) {
594 return setHostExemption(host, false);
595}
596
597int SecondaryTableController::setHostExemption(const char *host, bool add) {
598 IptablesTarget target = !strcmp(getVersion(host), "-4") ? V4 : V6;
599 char protect_mark_str[11];
600 snprintf(protect_mark_str, sizeof(protect_mark_str), "%d", PROTECT_MARK);
Chad Brubaker2349aa62013-07-15 15:28:59 -0700601 int ret = execIptables(target,
Chad Brubaker4a946092013-07-10 12:08:08 -0700602 "-t",
603 "mangle",
604 add ? "-A" : "-D",
605 LOCAL_MANGLE_EXEMPT,
606 "-d",
607 host,
608 "-j",
609 "MARK",
610 "--set-mark",
611 protect_mark_str,
612 NULL);
Chad Brubaker2349aa62013-07-15 15:28:59 -0700613 const char *cmd[] = {
614 IP_PATH,
615 getVersion(host),
616 "rule",
617 add ? "add" : "del",
618 "prio",
619 EXEMPT_PRIO,
620 "to",
621 host,
622 "table",
623 "main"
624 };
625 ret |= runCmd(ARRAY_SIZE(cmd), cmd);
626 return ret;
Chad Brubaker4a946092013-07-10 12:08:08 -0700627}
628
Chad Brubakerda7df7c2013-07-11 12:05:39 -0700629void SecondaryTableController::getUidMark(SocketClient *cli, int uid) {
630 int mark = mUidMarkMap->getMark(uid);
631 char mark_str[11];
632 snprintf(mark_str, sizeof(mark_str), "%d", mark);
633 cli->sendMsg(ResponseCode::GetMarkResult, mark_str, false);
634}
635
636void SecondaryTableController::getProtectMark(SocketClient *cli) {
637 char protect_mark_str[11];
638 snprintf(protect_mark_str, sizeof(protect_mark_str), "%d", PROTECT_MARK);
639 cli->sendMsg(ResponseCode::GetMarkResult, protect_mark_str, false);
640}
641
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800642int SecondaryTableController::runCmd(int argc, const char **argv) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700643 int ret = 0;
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800644
645 ret = android_fork_execvp(argc, (char **)argv, NULL, false, false);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700646 return ret;
647}