blob: 5750b41fdc65dfc36ae5857cc4dd8702ae3834f7 [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 Brubaker7a6ce4b2013-06-06 21:42:53 -070041const char* SecondaryTableController::LOCAL_NAT_POSTROUTING = "st_nat_POSTROUTING";
Chad Brubaker9a508892013-05-31 20:51:46 -070042
Chad Brubakerd2617932013-06-21 15:26:35 -070043SecondaryTableController::SecondaryTableController(UidMarkMap *map) : mUidMarkMap(map) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -070044 int i;
45 for (i=0; i < INTERFACES_TRACKED; i++) {
46 mInterfaceTable[i][0] = 0;
47 // TODO - use a hashtable or other prebuilt container class
48 mInterfaceRuleCount[i] = 0;
49 }
50}
51
52SecondaryTableController::~SecondaryTableController() {
53}
54
Chad Brubaker2251c0f2013-06-27 17:20:39 -070055int SecondaryTableController::setupIptablesHooks() {
56 int res = execIptables(V4V6,
57 "-t",
58 "mangle",
59 "-F",
60 LOCAL_MANGLE_OUTPUT,
61 NULL);
Chad Brubaker797ec702014-02-06 13:38:41 -080062 // Do not mark sockets that have already been marked elsewhere(for example in DNS or protect).
Chad Brubaker2251c0f2013-06-27 17:20:39 -070063 res |= execIptables(V4V6,
64 "-t",
65 "mangle",
66 "-A",
67 LOCAL_MANGLE_OUTPUT,
68 "-m",
69 "mark",
Chad Brubaker797ec702014-02-06 13:38:41 -080070 "!",
Chad Brubaker2251c0f2013-06-27 17:20:39 -070071 "--mark",
Chad Brubaker797ec702014-02-06 13:38:41 -080072 "0",
Chad Brubaker2251c0f2013-06-27 17:20:39 -070073 "-j",
74 "RETURN",
75 NULL);
76
Chad Brubaker2349aa62013-07-15 15:28:59 -070077 // protect the legacy VPN daemons from routes.
78 // TODO: Remove this when legacy VPN's are removed.
Chad Brubaker2251c0f2013-06-27 17:20:39 -070079 res |= execIptables(V4V6,
80 "-t",
81 "mangle",
82 "-A",
83 LOCAL_MANGLE_OUTPUT,
84 "-m",
85 "owner",
86 "--uid-owner",
87 "vpn",
88 "-j",
89 "RETURN",
90 NULL);
91 return res;
Chad Brubaker2251c0f2013-06-27 17:20:39 -070092}
93
Robert Greenwaltfc97b822011-11-02 16:48:36 -070094int SecondaryTableController::findTableNumber(const char *iface) {
95 int i;
96 for (i = 0; i < INTERFACES_TRACKED; i++) {
Jaime A Lopez-Sollano3c207872012-01-11 16:29:28 -080097 // compare through the final null, hence +1
98 if (strncmp(iface, mInterfaceTable[i], IFNAMSIZ + 1) == 0) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -070099 return i;
100 }
101 }
102 return -1;
103}
104
105int SecondaryTableController::addRoute(SocketClient *cli, char *iface, char *dest, int prefix,
106 char *gateway) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700107 int tableIndex = findTableNumber(iface);
108 if (tableIndex == -1) {
109 tableIndex = findTableNumber(""); // look for an empty slot
110 if (tableIndex == -1) {
Steve Block5ea0c052012-01-06 19:18:11 +0000111 ALOGE("Max number of NATed interfaces reached");
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700112 errno = ENODEV;
113 cli->sendMsg(ResponseCode::OperationFailed, "Max number NATed", true);
114 return -1;
115 }
Jaime A Lopez-Sollanod14fd4f2012-01-11 16:29:28 -0800116 strncpy(mInterfaceTable[tableIndex], iface, IFNAMSIZ);
117 // Ensure null termination even if truncation happened
118 mInterfaceTable[tableIndex][IFNAMSIZ] = 0;
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700119 }
120
Robert Greenwalt063af322011-11-18 15:32:13 -0800121 return modifyRoute(cli, ADD, iface, dest, prefix, gateway, tableIndex);
122}
123
Robert Greenwaltc4621772012-01-31 12:46:45 -0800124int SecondaryTableController::modifyRoute(SocketClient *cli, const char *action, char *iface,
125 char *dest, int prefix, char *gateway, int tableIndex) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800126 char dest_str[44]; // enough to store an IPv6 address + 3 character bitmask
127 char tableIndex_str[11];
128 int ret;
129
130 // IP tool doesn't like "::" - the equiv of 0.0.0.0 that it accepts for ipv4
131 snprintf(dest_str, sizeof(dest_str), "%s/%d", dest, prefix);
132 snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex + BASE_TABLE_NUMBER);
Robert Greenwalt063af322011-11-18 15:32:13 -0800133
134 if (strcmp("::", gateway) == 0) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800135 const char *cmd[] = {
136 IP_PATH,
137 "route",
138 action,
139 dest_str,
140 "dev",
141 iface,
142 "table",
143 tableIndex_str
144 };
145 ret = runCmd(ARRAY_SIZE(cmd), cmd);
Robert Greenwalt063af322011-11-18 15:32:13 -0800146 } else {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800147 const char *cmd[] = {
148 IP_PATH,
149 "route",
150 action,
151 dest_str,
152 "via",
153 gateway,
154 "dev",
155 iface,
156 "table",
157 tableIndex_str
158 };
159 ret = runCmd(ARRAY_SIZE(cmd), cmd);
Robert Greenwalt063af322011-11-18 15:32:13 -0800160 }
161
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800162 if (ret) {
Steve Block5ea0c052012-01-06 19:18:11 +0000163 ALOGE("ip route %s failed: %s route %s %s/%d via %s dev %s table %d", action,
Robert Greenwalt063af322011-11-18 15:32:13 -0800164 IP_PATH, action, dest, prefix, gateway, iface, tableIndex+BASE_TABLE_NUMBER);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700165 errno = ENODEV;
Robert Greenwalt063af322011-11-18 15:32:13 -0800166 cli->sendMsg(ResponseCode::OperationFailed, "ip route modification failed", true);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700167 return -1;
168 }
Robert Greenwalt063af322011-11-18 15:32:13 -0800169
170 if (strcmp(action, ADD) == 0) {
171 mInterfaceRuleCount[tableIndex]++;
172 } else {
173 if (--mInterfaceRuleCount[tableIndex] < 1) {
174 mInterfaceRuleCount[tableIndex] = 0;
175 mInterfaceTable[tableIndex][0] = 0;
176 }
177 }
Robert Greenwaltc4621772012-01-31 12:46:45 -0800178 modifyRuleCount(tableIndex, action);
Robert Greenwalt063af322011-11-18 15:32:13 -0800179 cli->sendMsg(ResponseCode::CommandOkay, "Route modified", false);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700180 return 0;
181}
182
Robert Greenwaltc4621772012-01-31 12:46:45 -0800183void SecondaryTableController::modifyRuleCount(int tableIndex, const char *action) {
184 if (strcmp(action, ADD) == 0) {
185 mInterfaceRuleCount[tableIndex]++;
186 } else {
187 if (--mInterfaceRuleCount[tableIndex] < 1) {
188 mInterfaceRuleCount[tableIndex] = 0;
189 mInterfaceTable[tableIndex][0] = 0;
190 }
191 }
192}
193
194int SecondaryTableController::verifyTableIndex(int tableIndex) {
195 if ((tableIndex < 0) ||
196 (tableIndex >= INTERFACES_TRACKED) ||
197 (mInterfaceTable[tableIndex][0] == 0)) {
198 return -1;
199 } else {
200 return 0;
201 }
202}
203
204const char *SecondaryTableController::getVersion(const char *addr) {
205 if (strchr(addr, ':') != NULL) {
206 return "-6";
207 } else {
208 return "-4";
209 }
210}
211
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700212IptablesTarget SecondaryTableController::getIptablesTarget(const char *addr) {
213 if (strchr(addr, ':') != NULL) {
214 return V6;
215 } else {
216 return V4;
217 }
218}
219
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700220int SecondaryTableController::removeRoute(SocketClient *cli, char *iface, char *dest, int prefix,
221 char *gateway) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700222 int tableIndex = findTableNumber(iface);
223 if (tableIndex == -1) {
Steve Block5ea0c052012-01-06 19:18:11 +0000224 ALOGE("Interface not found");
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700225 errno = ENODEV;
226 cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true);
227 return -1;
228 }
229
Robert Greenwalt063af322011-11-18 15:32:13 -0800230 return modifyRoute(cli, DEL, iface, dest, prefix, gateway, tableIndex);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700231}
232
Robert Greenwaltc4621772012-01-31 12:46:45 -0800233int SecondaryTableController::modifyFromRule(int tableIndex, const char *action,
234 const char *addr) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800235 char tableIndex_str[11];
Robert Greenwaltc4621772012-01-31 12:46:45 -0800236
237 if (verifyTableIndex(tableIndex)) {
238 return -1;
239 }
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800240
241 snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex +
242 BASE_TABLE_NUMBER);
243 const char *cmd[] = {
244 IP_PATH,
245 getVersion(addr),
246 "rule",
247 action,
248 "from",
249 addr,
250 "table",
251 tableIndex_str
252 };
253 if (runCmd(ARRAY_SIZE(cmd), cmd)) {
Robert Greenwaltc4621772012-01-31 12:46:45 -0800254 return -1;
255 }
256
257 modifyRuleCount(tableIndex, action);
258 return 0;
259}
260
261int SecondaryTableController::modifyLocalRoute(int tableIndex, const char *action,
262 const char *iface, const char *addr) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800263 char tableIndex_str[11];
Robert Greenwaltc4621772012-01-31 12:46:45 -0800264
265 if (verifyTableIndex(tableIndex)) {
266 return -1;
267 }
268
269 modifyRuleCount(tableIndex, action); // some del's will fail as the iface is already gone.
270
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800271 snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex +
272 BASE_TABLE_NUMBER);
273 const char *cmd[] = {
274 IP_PATH,
275 "route",
276 action,
277 addr,
278 "dev",
279 iface,
280 "table",
281 tableIndex_str
282 };
283
284 return runCmd(ARRAY_SIZE(cmd), cmd);
Robert Greenwaltc4621772012-01-31 12:46:45 -0800285}
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700286int SecondaryTableController::addFwmarkRule(const char *iface) {
287 return setFwmarkRule(iface, true);
288}
289
290int SecondaryTableController::removeFwmarkRule(const char *iface) {
291 return setFwmarkRule(iface, false);
292}
293
294int SecondaryTableController::setFwmarkRule(const char *iface, bool add) {
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700295 int tableIndex = findTableNumber(iface);
296 if (tableIndex == -1) {
297 tableIndex = findTableNumber(""); // look for an empty slot
298 if (tableIndex == -1) {
299 ALOGE("Max number of NATed interfaces reached");
300 errno = ENODEV;
301 return -1;
302 }
303 strncpy(mInterfaceTable[tableIndex], iface, IFNAMSIZ);
304 // Ensure null termination even if truncation happened
305 mInterfaceTable[tableIndex][IFNAMSIZ] = 0;
306 }
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700307 int mark = tableIndex + BASE_TABLE_NUMBER;
308 char mark_str[11];
309 int ret;
310
311 //fail fast if any rules already exist for this interface
312 if (mUidMarkMap->anyRulesForMark(mark)) {
313 errno = EBUSY;
314 return -1;
315 }
316
317 snprintf(mark_str, sizeof(mark_str), "%d", mark);
Chad Brubaker797ec702014-02-06 13:38:41 -0800318 // Flush any marked routes we added
319 if (!add) {
320 // iproute2 rule del will delete anything that matches, but only one rule at a time.
321 // So clearing the rules requires a bunch of calls.
322 // ip rule del will fail once there are no remaining rules that match.
323 const char *v4_cmd[] = {
324 IP_PATH,
325 "-4",
326 "rule",
327 "del",
328 "fwmark",
329 mark_str,
330 "table",
331 mark_str
332 };
333 while(!runCmd(ARRAY_SIZE(v4_cmd), v4_cmd)) {}
334
335 const char *v6_cmd[] = {
336 IP_PATH,
337 "-6",
338 "rule",
339 "del",
340 "fwmark",
341 mark_str,
342 "table",
343 mark_str
344 };
345 while(!runCmd(ARRAY_SIZE(v6_cmd), v6_cmd)) {}
346 }
347 // Add a route to the table to send all traffic to iface.
348 // We only need a default route because this table is only selected if a packet matches an
349 // IP rule that checks both the route and the mark.
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700350 const char *route_cmd[] = {
351 IP_PATH,
352 "route",
353 add ? "add" : "del",
354 "default",
355 "dev",
356 iface,
357 "table",
358 mark_str
359 };
360 ret = runCmd(ARRAY_SIZE(route_cmd), route_cmd);
Chad Brubaker797ec702014-02-06 13:38:41 -0800361 // The command might fail during delete if the iface is gone
362 if (add && ret) return ret;
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700363
Chad Brubaker797ec702014-02-06 13:38:41 -0800364 // As above for IPv6
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700365 const char *route6_cmd[] = {
366 IP_PATH,
367 "-6",
368 "route",
369 add ? "add" : "del",
370 "default",
371 "dev",
372 iface,
373 "table",
374 mark_str
375 };
376 ret = runCmd(ARRAY_SIZE(route6_cmd), route6_cmd);
Chad Brubaker797ec702014-02-06 13:38:41 -0800377 // The command might fail during delete if the iface is gone
378 if (add && ret) return ret;
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700379
Chad Brubaker797ec702014-02-06 13:38:41 -0800380 /* Best effort, because some kernels might not have the needed TCPMSS */
381 execIptables(V4V6,
382 "-t",
383 "mangle",
384 add ? "-A" : "-D",
385 LOCAL_MANGLE_POSTROUTING,
386 "-p", "tcp", "-o", iface, "--tcp-flags", "SYN,RST", "SYN",
387 "-j",
388 "TCPMSS",
389 "--clamp-mss-to-pmtu",
390 NULL);
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700391
Chad Brubaker797ec702014-02-06 13:38:41 -0800392 // Because the mark gets set after the intial routing decision the source IP address is that
393 // of the original out interface. The only way to change the source IP address to that of the
394 // VPN iface is using source NAT.
395 // TODO: Remove this when we get the mark set correctly before the first routing pass.
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700396 ret = execIptables(V4,
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700397 "-t",
398 "nat",
399 add ? "-A" : "-D",
400 LOCAL_NAT_POSTROUTING,
401 "-o",
402 iface,
403 "-m",
404 "mark",
405 "--mark",
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700406 mark_str,
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700407 "-j",
408 "MASQUERADE",
409 NULL);
410
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700411 if (ret) return ret;
412
Chad Brubaker797ec702014-02-06 13:38:41 -0800413 // Try and set up NAT for IPv6 as well. This was only added in Linux 3.7 so this may fail.
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700414 ret = execIptables(V6,
415 "-t",
416 "nat",
417 add ? "-A" : "-D",
418 LOCAL_NAT_POSTROUTING,
419 "-o",
420 iface,
421 "-m",
422 "mark",
423 "--mark",
424 mark_str,
425 "-j",
426 "MASQUERADE",
427 NULL);
428 if (ret) {
Chad Brubaker797ec702014-02-06 13:38:41 -0800429 // Without V6 NAT we can't do V6 over VPNs. If an IPv6 packet matches a VPN rule, then it
430 // will go out on the VPN interface, but without NAT, it will have the wrong source
431 // address. So reject all these packets.
432 // Due to rule application by the time the connection hits the output filter chain the
433 // routing pass based on the new mark has not yet happened. Reject in ip instead.
434 // TODO: Make the VPN code refuse to install IPv6 routes until we don't need IPv6 NAT.
435 const char *reject_cmd[] = {
436 IP_PATH,
437 "-6",
438 "route",
439 add ? "replace" : "del",
440 "unreachable",
441 "default",
442 "table",
443 mark_str
444 };
445 ret = runCmd(ARRAY_SIZE(reject_cmd), reject_cmd);
446 // The command might fail during delete if the iface is gone
447 if (add && ret) return ret;
448
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700449 }
Chad Brubaker797ec702014-02-06 13:38:41 -0800450 return 0;
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700451
452}
453
454int SecondaryTableController::addFwmarkRoute(const char* iface, const char *dest, int prefix) {
455 return setFwmarkRoute(iface, dest, prefix, true);
456}
457
458int SecondaryTableController::removeFwmarkRoute(const char* iface, const char *dest, int prefix) {
459 return setFwmarkRoute(iface, dest, prefix, true);
460}
461
462int SecondaryTableController::setFwmarkRoute(const char* iface, const char *dest, int prefix,
463 bool add) {
464 int tableIndex = findTableNumber(iface);
465 if (tableIndex == -1) {
466 errno = EINVAL;
467 return -1;
468 }
469 int mark = tableIndex + BASE_TABLE_NUMBER;
470 char mark_str[11] = {0};
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700471 char dest_str[44]; // enough to store an IPv6 address + 3 character bitmask
472
473 snprintf(mark_str, sizeof(mark_str), "%d", mark);
Chad Brubaker2251c0f2013-06-27 17:20:39 -0700474 snprintf(dest_str, sizeof(dest_str), "%s/%d", dest, prefix);
Chad Brubaker797ec702014-02-06 13:38:41 -0800475 const char *rule_cmd[] = {
476 IP_PATH,
477 getVersion(dest_str),
478 "rule",
479 add ? "add" : "del",
480 "prio",
481 RULE_PRIO,
482 "to",
483 dest_str,
484 "fwmark",
485 mark_str,
486 "table",
487 mark_str
488 };
489 return runCmd(ARRAY_SIZE(rule_cmd), rule_cmd);
Chad Brubaker7a6ce4b2013-06-06 21:42:53 -0700490}
Robert Greenwaltc4621772012-01-31 12:46:45 -0800491
Chad Brubaker8830b942013-06-12 10:51:55 -0700492int SecondaryTableController::addUidRule(const char *iface, int uid_start, int uid_end) {
493 return setUidRule(iface, uid_start, uid_end, true);
Chad Brubaker9a508892013-05-31 20:51:46 -0700494}
495
Chad Brubaker8830b942013-06-12 10:51:55 -0700496int SecondaryTableController::removeUidRule(const char *iface, int uid_start, int uid_end) {
497 return setUidRule(iface, uid_start, uid_end, false);
Chad Brubaker9a508892013-05-31 20:51:46 -0700498}
499
Chad Brubaker8830b942013-06-12 10:51:55 -0700500int SecondaryTableController::setUidRule(const char *iface, int uid_start, int uid_end, bool add) {
Chad Brubaker9a508892013-05-31 20:51:46 -0700501 int tableIndex = findTableNumber(iface);
502 if (tableIndex == -1) {
Chad Brubakerd2617932013-06-21 15:26:35 -0700503 errno = EINVAL;
Chad Brubaker9a508892013-05-31 20:51:46 -0700504 return -1;
505 }
Chad Brubakerd2617932013-06-21 15:26:35 -0700506 int mark = tableIndex + BASE_TABLE_NUMBER;
507 if (add) {
508 if (!mUidMarkMap->add(uid_start, uid_end, mark)) {
509 errno = EINVAL;
510 return -1;
511 }
512 } else {
513 if (!mUidMarkMap->remove(uid_start, uid_end, mark)) {
514 errno = EINVAL;
515 return -1;
516 }
517 }
Chad Brubaker8830b942013-06-12 10:51:55 -0700518 char uid_str[24] = {0};
519 snprintf(uid_str, sizeof(uid_str), "%d-%d", uid_start, uid_end);
Chad Brubaker797ec702014-02-06 13:38:41 -0800520 char mark_str[11] = {0};
521 snprintf(mark_str, sizeof(mark_str), "%d", mark);
Chad Brubaker9a508892013-05-31 20:51:46 -0700522 return execIptables(V4V6,
523 "-t",
524 "mangle",
525 add ? "-A" : "-D",
526 LOCAL_MANGLE_OUTPUT,
527 "-m",
528 "owner",
529 "--uid-owner",
Chad Brubaker8830b942013-06-12 10:51:55 -0700530 uid_str,
Chad Brubaker797ec702014-02-06 13:38:41 -0800531 "-j",
532 "MARK",
533 "--set-mark",
534 mark_str,
Chad Brubaker9a508892013-05-31 20:51:46 -0700535 NULL);
536}
537
Chad Brubaker4a946092013-07-10 12:08:08 -0700538int SecondaryTableController::addHostExemption(const char *host) {
539 return setHostExemption(host, true);
540}
541
542int SecondaryTableController::removeHostExemption(const char *host) {
543 return setHostExemption(host, false);
544}
545
546int SecondaryTableController::setHostExemption(const char *host, bool add) {
Chad Brubaker2349aa62013-07-15 15:28:59 -0700547 const char *cmd[] = {
548 IP_PATH,
549 getVersion(host),
550 "rule",
551 add ? "add" : "del",
552 "prio",
553 EXEMPT_PRIO,
554 "to",
555 host,
556 "table",
557 "main"
558 };
Chad Brubaker797ec702014-02-06 13:38:41 -0800559 return runCmd(ARRAY_SIZE(cmd), cmd);
Chad Brubaker4a946092013-07-10 12:08:08 -0700560}
561
Chad Brubakerda7df7c2013-07-11 12:05:39 -0700562void SecondaryTableController::getUidMark(SocketClient *cli, int uid) {
563 int mark = mUidMarkMap->getMark(uid);
564 char mark_str[11];
565 snprintf(mark_str, sizeof(mark_str), "%d", mark);
566 cli->sendMsg(ResponseCode::GetMarkResult, mark_str, false);
567}
568
569void SecondaryTableController::getProtectMark(SocketClient *cli) {
570 char protect_mark_str[11];
571 snprintf(protect_mark_str, sizeof(protect_mark_str), "%d", PROTECT_MARK);
572 cli->sendMsg(ResponseCode::GetMarkResult, protect_mark_str, false);
573}
574
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800575int SecondaryTableController::runCmd(int argc, const char **argv) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700576 int ret = 0;
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800577
578 ret = android_fork_execvp(argc, (char **)argv, NULL, false, false);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700579 return ret;
580}