blob: 736b5fecc424899c69068d420919c7d5266dc3f1 [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";
JP Abgrall9440e7f2013-11-20 17:27:01 -080040const char* SecondaryTableController::LOCAL_MANGLE_POSTROUTING = "st_mangle_POSTROUTING";
Chad Brubaker4a946092013-07-10 12:08:08 -070041const char* SecondaryTableController::LOCAL_MANGLE_EXEMPT = "st_mangle_EXEMPT";
Chad Brubaker2251c0f2013-06-27 17:20:39 -070042const char* SecondaryTableController::LOCAL_MANGLE_IFACE_FORMAT = "st_mangle_%s_OUTPUT";
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -070043const char* SecondaryTableController::LOCAL_NAT_POSTROUTING = "st_nat_POSTROUTING";
Chad Brubaker2251c0f2013-06-27 17:20:39 -070044const char* SecondaryTableController::LOCAL_FILTER_OUTPUT = "st_filter_OUTPUT";
Chad Brubaker9a508892013-05-31 20:51:46 -070045
Chad Brubakerd2617932013-06-21 15:26:35 -070046SecondaryTableController::SecondaryTableController(UidMarkMap *map) : mUidMarkMap(map) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -070047 int i;
48 for (i=0; i < INTERFACES_TRACKED; i++) {
49 mInterfaceTable[i][0] = 0;
50 // TODO - use a hashtable or other prebuilt container class
51 mInterfaceRuleCount[i] = 0;
52 }
53}
54
55SecondaryTableController::~SecondaryTableController() {
56}
57
Chad Brubaker2251c0f2013-06-27 17:20:39 -070058int SecondaryTableController::setupIptablesHooks() {
59 int res = execIptables(V4V6,
60 "-t",
61 "mangle",
62 "-F",
63 LOCAL_MANGLE_OUTPUT,
64 NULL);
Chad Brubaker4a946092013-07-10 12:08:08 -070065 res |= execIptables(V4V6,
66 "-t",
67 "mangle",
68 "-F",
69 LOCAL_MANGLE_EXEMPT,
70 NULL);
Chad Brubaker2349aa62013-07-15 15:28:59 -070071 // rule for skipping anything marked with the PROTECT_MARK
Chad Brubaker2251c0f2013-06-27 17:20:39 -070072 char protect_mark_str[11];
73 snprintf(protect_mark_str, sizeof(protect_mark_str), "%d", PROTECT_MARK);
74 res |= execIptables(V4V6,
75 "-t",
76 "mangle",
77 "-A",
78 LOCAL_MANGLE_OUTPUT,
79 "-m",
80 "mark",
81 "--mark",
82 protect_mark_str,
83 "-j",
84 "RETURN",
85 NULL);
86
Chad Brubaker2349aa62013-07-15 15:28:59 -070087 // protect the legacy VPN daemons from routes.
88 // TODO: Remove this when legacy VPN's are removed.
Chad Brubaker2251c0f2013-06-27 17:20:39 -070089 res |= execIptables(V4V6,
90 "-t",
91 "mangle",
92 "-A",
93 LOCAL_MANGLE_OUTPUT,
94 "-m",
95 "owner",
96 "--uid-owner",
97 "vpn",
98 "-j",
99 "RETURN",
100 NULL);
101 return res;
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700102}
103
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700104int SecondaryTableController::findTableNumber(const char *iface) {
105 int i;
106 for (i = 0; i < INTERFACES_TRACKED; i++) {
Jaime A Lopez-Sollano3c207872012-01-11 16:29:28 -0800107 // compare through the final null, hence +1
108 if (strncmp(iface, mInterfaceTable[i], IFNAMSIZ + 1) == 0) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700109 return i;
110 }
111 }
112 return -1;
113}
114
115int SecondaryTableController::addRoute(SocketClient *cli, char *iface, char *dest, int prefix,
116 char *gateway) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700117 int tableIndex = findTableNumber(iface);
118 if (tableIndex == -1) {
119 tableIndex = findTableNumber(""); // look for an empty slot
120 if (tableIndex == -1) {
Steve Block5ea0c052012-01-06 19:18:11 +0000121 ALOGE("Max number of NATed interfaces reached");
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700122 errno = ENODEV;
123 cli->sendMsg(ResponseCode::OperationFailed, "Max number NATed", true);
124 return -1;
125 }
Jaime A Lopez-Sollanod14fd4f2012-01-11 16:29:28 -0800126 strncpy(mInterfaceTable[tableIndex], iface, IFNAMSIZ);
127 // Ensure null termination even if truncation happened
128 mInterfaceTable[tableIndex][IFNAMSIZ] = 0;
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700129 }
130
Robert Greenwalt063af322011-11-18 15:32:13 -0800131 return modifyRoute(cli, ADD, iface, dest, prefix, gateway, tableIndex);
132}
133
Robert Greenwaltc4621772012-01-31 12:46:45 -0800134int SecondaryTableController::modifyRoute(SocketClient *cli, const char *action, char *iface,
135 char *dest, int prefix, char *gateway, int tableIndex) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800136 char dest_str[44]; // enough to store an IPv6 address + 3 character bitmask
137 char tableIndex_str[11];
138 int ret;
139
140 // IP tool doesn't like "::" - the equiv of 0.0.0.0 that it accepts for ipv4
141 snprintf(dest_str, sizeof(dest_str), "%s/%d", dest, prefix);
142 snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex + BASE_TABLE_NUMBER);
Robert Greenwalt063af322011-11-18 15:32:13 -0800143
144 if (strcmp("::", gateway) == 0) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800145 const char *cmd[] = {
146 IP_PATH,
147 "route",
148 action,
149 dest_str,
150 "dev",
151 iface,
152 "table",
153 tableIndex_str
154 };
155 ret = runCmd(ARRAY_SIZE(cmd), cmd);
Robert Greenwalt063af322011-11-18 15:32:13 -0800156 } else {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800157 const char *cmd[] = {
158 IP_PATH,
159 "route",
160 action,
161 dest_str,
162 "via",
163 gateway,
164 "dev",
165 iface,
166 "table",
167 tableIndex_str
168 };
169 ret = runCmd(ARRAY_SIZE(cmd), cmd);
Robert Greenwalt063af322011-11-18 15:32:13 -0800170 }
171
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800172 if (ret) {
Steve Block5ea0c052012-01-06 19:18:11 +0000173 ALOGE("ip route %s failed: %s route %s %s/%d via %s dev %s table %d", action,
Robert Greenwalt063af322011-11-18 15:32:13 -0800174 IP_PATH, action, dest, prefix, gateway, iface, tableIndex+BASE_TABLE_NUMBER);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700175 errno = ENODEV;
Robert Greenwalt063af322011-11-18 15:32:13 -0800176 cli->sendMsg(ResponseCode::OperationFailed, "ip route modification failed", true);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700177 return -1;
178 }
Robert Greenwalt063af322011-11-18 15:32:13 -0800179
180 if (strcmp(action, ADD) == 0) {
181 mInterfaceRuleCount[tableIndex]++;
182 } else {
183 if (--mInterfaceRuleCount[tableIndex] < 1) {
184 mInterfaceRuleCount[tableIndex] = 0;
185 mInterfaceTable[tableIndex][0] = 0;
186 }
187 }
Robert Greenwaltc4621772012-01-31 12:46:45 -0800188 modifyRuleCount(tableIndex, action);
Robert Greenwalt063af322011-11-18 15:32:13 -0800189 cli->sendMsg(ResponseCode::CommandOkay, "Route modified", false);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700190 return 0;
191}
192
Robert Greenwaltc4621772012-01-31 12:46:45 -0800193void SecondaryTableController::modifyRuleCount(int tableIndex, const char *action) {
194 if (strcmp(action, ADD) == 0) {
195 mInterfaceRuleCount[tableIndex]++;
196 } else {
197 if (--mInterfaceRuleCount[tableIndex] < 1) {
198 mInterfaceRuleCount[tableIndex] = 0;
199 mInterfaceTable[tableIndex][0] = 0;
200 }
201 }
202}
203
204int SecondaryTableController::verifyTableIndex(int tableIndex) {
205 if ((tableIndex < 0) ||
206 (tableIndex >= INTERFACES_TRACKED) ||
207 (mInterfaceTable[tableIndex][0] == 0)) {
208 return -1;
209 } else {
210 return 0;
211 }
212}
213
214const char *SecondaryTableController::getVersion(const char *addr) {
215 if (strchr(addr, ':') != NULL) {
216 return "-6";
217 } else {
218 return "-4";
219 }
220}
221
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700222IptablesTarget SecondaryTableController::getIptablesTarget(const char *addr) {
223 if (strchr(addr, ':') != NULL) {
224 return V6;
225 } else {
226 return V4;
227 }
228}
229
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700230int SecondaryTableController::removeRoute(SocketClient *cli, char *iface, char *dest, int prefix,
231 char *gateway) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700232 int tableIndex = findTableNumber(iface);
233 if (tableIndex == -1) {
Steve Block5ea0c052012-01-06 19:18:11 +0000234 ALOGE("Interface not found");
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700235 errno = ENODEV;
236 cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
237 return -1;
238 }
239
Robert Greenwalt063af322011-11-18 15:32:13 -0800240 return modifyRoute(cli, DEL, iface, dest, prefix, gateway, tableIndex);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700241}
242
Robert Greenwaltc4621772012-01-31 12:46:45 -0800243int SecondaryTableController::modifyFromRule(int tableIndex, const char *action,
244 const char *addr) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800245 char tableIndex_str[11];
Robert Greenwaltc4621772012-01-31 12:46:45 -0800246
247 if (verifyTableIndex(tableIndex)) {
248 return -1;
249 }
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800250
251 snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex +
252 BASE_TABLE_NUMBER);
253 const char *cmd[] = {
254 IP_PATH,
255 getVersion(addr),
256 "rule",
257 action,
258 "from",
259 addr,
260 "table",
261 tableIndex_str
262 };
263 if (runCmd(ARRAY_SIZE(cmd), cmd)) {
Robert Greenwaltc4621772012-01-31 12:46:45 -0800264 return -1;
265 }
266
267 modifyRuleCount(tableIndex, action);
268 return 0;
269}
270
271int SecondaryTableController::modifyLocalRoute(int tableIndex, const char *action,
272 const char *iface, const char *addr) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800273 char tableIndex_str[11];
Robert Greenwaltc4621772012-01-31 12:46:45 -0800274
275 if (verifyTableIndex(tableIndex)) {
276 return -1;
277 }
278
279 modifyRuleCount(tableIndex, action); // some del's will fail as the iface is already gone.
280
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800281 snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex +
282 BASE_TABLE_NUMBER);
283 const char *cmd[] = {
284 IP_PATH,
285 "route",
286 action,
287 addr,
288 "dev",
289 iface,
290 "table",
291 tableIndex_str
292 };
293
294 return runCmd(ARRAY_SIZE(cmd), cmd);
Robert Greenwaltc4621772012-01-31 12:46:45 -0800295}
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700296int SecondaryTableController::addFwmarkRule(const char *iface) {
297 return setFwmarkRule(iface, true);
298}
299
300int SecondaryTableController::removeFwmarkRule(const char *iface) {
301 return setFwmarkRule(iface, false);
302}
303
304int SecondaryTableController::setFwmarkRule(const char *iface, bool add) {
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700305 int tableIndex = findTableNumber(iface);
306 if (tableIndex == -1) {
307 tableIndex = findTableNumber(""); // look for an empty slot
308 if (tableIndex == -1) {
309 ALOGE("Max number of NATed interfaces reached");
310 errno = ENODEV;
311 return -1;
312 }
313 strncpy(mInterfaceTable[tableIndex], iface, IFNAMSIZ);
314 // Ensure null termination even if truncation happened
315 mInterfaceTable[tableIndex][IFNAMSIZ] = 0;
316 }
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700317 int mark = tableIndex + BASE_TABLE_NUMBER;
318 char mark_str[11];
319 int ret;
320
321 //fail fast if any rules already exist for this interface
322 if (mUidMarkMap->anyRulesForMark(mark)) {
323 errno = EBUSY;
324 return -1;
325 }
326
327 snprintf(mark_str, sizeof(mark_str), "%d", mark);
328 //add the catch all route to the tun. Route rules will make sure the right packets hit the table
329 const char *route_cmd[] = {
330 IP_PATH,
331 "route",
332 add ? "add" : "del",
333 "default",
334 "dev",
335 iface,
336 "table",
337 mark_str
338 };
339 ret = runCmd(ARRAY_SIZE(route_cmd), route_cmd);
340
341 const char *fwmark_cmd[] = {
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700342 IP_PATH,
343 "rule",
344 add ? "add" : "del",
Chad Brubaker2349aa62013-07-15 15:28:59 -0700345 "prio",
346 RULE_PRIO,
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700347 "fwmark",
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700348 mark_str,
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700349 "table",
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700350 mark_str
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700351 };
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700352 ret = runCmd(ARRAY_SIZE(fwmark_cmd), fwmark_cmd);
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700353 if (ret) return ret;
354
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700355 //add rules for v6
356 const char *route6_cmd[] = {
357 IP_PATH,
358 "-6",
359 "route",
360 add ? "add" : "del",
361 "default",
362 "dev",
363 iface,
364 "table",
365 mark_str
366 };
367 ret = runCmd(ARRAY_SIZE(route6_cmd), route6_cmd);
368
369 const char *fwmark6_cmd[] = {
370 IP_PATH,
371 "-6",
372 "rule",
373 add ? "add" : "del",
Chad Brubaker2349aa62013-07-15 15:28:59 -0700374 "prio",
375 RULE_PRIO,
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700376 "fwmark",
377 mark_str,
378 "table",
379 mark_str
380 };
381 ret = runCmd(ARRAY_SIZE(fwmark6_cmd), fwmark6_cmd);
382
383
384 if (ret) return ret;
385
386 //create the route rule chain
387 char chain_str[IFNAMSIZ + 18];
388 snprintf(chain_str, sizeof(chain_str), LOCAL_MANGLE_IFACE_FORMAT, iface);
389 //code split due to ordering requirements
390 if (add) {
391 ret = execIptables(V4V6,
392 "-t",
393 "mangle",
394 "-N",
395 chain_str,
396 NULL);
397 //set up the rule for sending premarked packets to the VPN chain
398 //Insert these at the top of the chain so they trigger before any UID rules
399 ret |= execIptables(V4V6,
400 "-t",
401 "mangle",
402 "-I",
403 LOCAL_MANGLE_OUTPUT,
404 "3",
405 "-m",
406 "mark",
407 "--mark",
408 mark_str,
409 "-g",
410 chain_str,
411 NULL);
412 //add a rule to clear the mark in the VPN chain
413 //packets marked with SO_MARK already have the iface's mark set but unless they match a
414 //route they should hit the network instead of the VPN
415 ret |= execIptables(V4V6,
416 "-t",
417 "mangle",
418 "-A",
419 chain_str,
420 "-j",
421 "MARK",
422 "--set-mark",
423 "0",
424 NULL);
425
JP Abgrall9440e7f2013-11-20 17:27:01 -0800426 /* Best effort, because some kernels might not have the needed TCPMSS */
427 execIptables(V4V6,
428 "-t",
429 "mangle",
430 "-A",
431 LOCAL_MANGLE_POSTROUTING,
432 "-p", "tcp", "-o", iface, "--tcp-flags", "SYN,RST", "SYN",
433 "-j",
434 "TCPMSS",
435 "--clamp-mss-to-pmtu",
436 NULL);
437
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700438 } else {
439 ret = execIptables(V4V6,
440 "-t",
441 "mangle",
442 "-D",
443 LOCAL_MANGLE_OUTPUT,
444 "-m",
445 "mark",
446 "--mark",
447 mark_str,
448 "-g",
449 chain_str,
450 NULL);
451
452 //clear and delete the chain
453 ret |= execIptables(V4V6,
454 "-t",
455 "mangle",
456 "-F",
457 chain_str,
458 NULL);
459
460 ret |= execIptables(V4V6,
461 "-t",
462 "mangle",
463 "-X",
464 chain_str,
465 NULL);
JP Abgrall9440e7f2013-11-20 17:27:01 -0800466
467 /* Best effort, because some kernels might not have the needed TCPMSS */
468 execIptables(V4V6,
469 "-t",
470 "mangle",
471 "-D",
472 LOCAL_MANGLE_POSTROUTING,
473 "-p", "tcp", "-o", iface, "--tcp-flags", "SYN,RST", "SYN",
474 "-j",
475 "TCPMSS",
476 "--clamp-mss-to-pmtu",
477 NULL);
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700478 }
479
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700480 //set up the needed source IP rewriting
481 //NOTE: Without ipv6 NAT in the kernel <3.7 only support V4 NAT
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700482 ret = execIptables(V4,
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700483 "-t",
484 "nat",
485 add ? "-A" : "-D",
486 LOCAL_NAT_POSTROUTING,
487 "-o",
488 iface,
489 "-m",
490 "mark",
491 "--mark",
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700492 mark_str,
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700493 "-j",
494 "MASQUERADE",
495 NULL);
496
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700497 if (ret) return ret;
498
499 //try and set up for ipv6. ipv6 nat came in the kernel only in 3.7, so this can fail
500 ret = execIptables(V6,
501 "-t",
502 "nat",
503 add ? "-A" : "-D",
504 LOCAL_NAT_POSTROUTING,
505 "-o",
506 iface,
507 "-m",
508 "mark",
509 "--mark",
510 mark_str,
511 "-j",
512 "MASQUERADE",
513 NULL);
514 if (ret) {
515 //Without V6 NAT we can't do V6 over VPNs.
516 ret = execIptables(V6,
517 "-t",
518 "filter",
519 add ? "-A" : "-D",
520 LOCAL_FILTER_OUTPUT,
521 "-m",
522 "mark",
523 "--mark",
524 mark_str,
525 "-j",
526 "REJECT",
527 NULL);
528 }
529 return ret;
530
531}
532
533int SecondaryTableController::addFwmarkRoute(const char* iface, const char *dest, int prefix) {
534 return setFwmarkRoute(iface, dest, prefix, true);
535}
536
537int SecondaryTableController::removeFwmarkRoute(const char* iface, const char *dest, int prefix) {
538 return setFwmarkRoute(iface, dest, prefix, true);
539}
540
541int SecondaryTableController::setFwmarkRoute(const char* iface, const char *dest, int prefix,
542 bool add) {
543 int tableIndex = findTableNumber(iface);
544 if (tableIndex == -1) {
545 errno = EINVAL;
546 return -1;
547 }
548 int mark = tableIndex + BASE_TABLE_NUMBER;
549 char mark_str[11] = {0};
550 char chain_str[IFNAMSIZ + 18];
551 char dest_str[44]; // enough to store an IPv6 address + 3 character bitmask
552
553 snprintf(mark_str, sizeof(mark_str), "%d", mark);
554 snprintf(chain_str, sizeof(chain_str), LOCAL_MANGLE_IFACE_FORMAT, iface);
555 snprintf(dest_str, sizeof(dest_str), "%s/%d", dest, prefix);
556 return execIptables(getIptablesTarget(dest),
557 "-t",
558 "mangle",
559 add ? "-A" : "-D",
560 chain_str,
561 "-d",
562 dest_str,
563 "-j",
564 "MARK",
565 "--set-mark",
566 mark_str,
567 NULL);
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700568}
Robert Greenwaltc4621772012-01-31 12:46:45 -0800569
Chad Brubaker8830b942013-06-12 10:51:55 -0700570int SecondaryTableController::addUidRule(const char *iface, int uid_start, int uid_end) {
571 return setUidRule(iface, uid_start, uid_end, true);
Chad Brubaker9a508892013-05-31 20:51:46 -0700572}
573
Chad Brubaker8830b942013-06-12 10:51:55 -0700574int SecondaryTableController::removeUidRule(const char *iface, int uid_start, int uid_end) {
575 return setUidRule(iface, uid_start, uid_end, false);
Chad Brubaker9a508892013-05-31 20:51:46 -0700576}
577
Chad Brubaker8830b942013-06-12 10:51:55 -0700578int SecondaryTableController::setUidRule(const char *iface, int uid_start, int uid_end, bool add) {
Chad Brubaker9a508892013-05-31 20:51:46 -0700579 int tableIndex = findTableNumber(iface);
580 if (tableIndex == -1) {
Chad Brubakerd2617932013-06-21 15:26:35 -0700581 errno = EINVAL;
Chad Brubaker9a508892013-05-31 20:51:46 -0700582 return -1;
583 }
Chad Brubakerd2617932013-06-21 15:26:35 -0700584 int mark = tableIndex + BASE_TABLE_NUMBER;
585 if (add) {
586 if (!mUidMarkMap->add(uid_start, uid_end, mark)) {
587 errno = EINVAL;
588 return -1;
589 }
590 } else {
591 if (!mUidMarkMap->remove(uid_start, uid_end, mark)) {
592 errno = EINVAL;
593 return -1;
594 }
595 }
Chad Brubaker8830b942013-06-12 10:51:55 -0700596 char uid_str[24] = {0};
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700597 char chain_str[IFNAMSIZ + 18];
Chad Brubaker8830b942013-06-12 10:51:55 -0700598 snprintf(uid_str, sizeof(uid_str), "%d-%d", uid_start, uid_end);
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700599 snprintf(chain_str, sizeof(chain_str), LOCAL_MANGLE_IFACE_FORMAT, iface);
Chad Brubaker9a508892013-05-31 20:51:46 -0700600 return execIptables(V4V6,
601 "-t",
602 "mangle",
603 add ? "-A" : "-D",
604 LOCAL_MANGLE_OUTPUT,
605 "-m",
606 "owner",
607 "--uid-owner",
Chad Brubaker8830b942013-06-12 10:51:55 -0700608 uid_str,
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700609 "-g",
610 chain_str,
Chad Brubaker9a508892013-05-31 20:51:46 -0700611 NULL);
612}
613
Chad Brubaker4a946092013-07-10 12:08:08 -0700614int SecondaryTableController::addHostExemption(const char *host) {
615 return setHostExemption(host, true);
616}
617
618int SecondaryTableController::removeHostExemption(const char *host) {
619 return setHostExemption(host, false);
620}
621
622int SecondaryTableController::setHostExemption(const char *host, bool add) {
623 IptablesTarget target = !strcmp(getVersion(host), "-4") ? V4 : V6;
624 char protect_mark_str[11];
625 snprintf(protect_mark_str, sizeof(protect_mark_str), "%d", PROTECT_MARK);
Chad Brubaker2349aa62013-07-15 15:28:59 -0700626 int ret = execIptables(target,
Chad Brubaker4a946092013-07-10 12:08:08 -0700627 "-t",
628 "mangle",
629 add ? "-A" : "-D",
630 LOCAL_MANGLE_EXEMPT,
631 "-d",
632 host,
633 "-j",
634 "MARK",
635 "--set-mark",
636 protect_mark_str,
637 NULL);
Chad Brubaker2349aa62013-07-15 15:28:59 -0700638 const char *cmd[] = {
639 IP_PATH,
640 getVersion(host),
641 "rule",
642 add ? "add" : "del",
643 "prio",
644 EXEMPT_PRIO,
645 "to",
646 host,
647 "table",
648 "main"
649 };
650 ret |= runCmd(ARRAY_SIZE(cmd), cmd);
651 return ret;
Chad Brubaker4a946092013-07-10 12:08:08 -0700652}
653
Chad Brubakerda7df7c2013-07-11 12:05:39 -0700654void SecondaryTableController::getUidMark(SocketClient *cli, int uid) {
655 int mark = mUidMarkMap->getMark(uid);
656 char mark_str[11];
657 snprintf(mark_str, sizeof(mark_str), "%d", mark);
658 cli->sendMsg(ResponseCode::GetMarkResult, mark_str, false);
659}
660
661void SecondaryTableController::getProtectMark(SocketClient *cli) {
662 char protect_mark_str[11];
663 snprintf(protect_mark_str, sizeof(protect_mark_str), "%d", PROTECT_MARK);
664 cli->sendMsg(ResponseCode::GetMarkResult, protect_mark_str, false);
665}
666
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800667int SecondaryTableController::runCmd(int argc, const char **argv) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700668 int ret = 0;
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800669
670 ret = android_fork_execvp(argc, (char **)argv, NULL, false, false);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700671 return ret;
672}