1 /* 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> 33 #include <logwrap/logwrap.h> 34 35 #include "ResponseCode.h" 36 #include "NetdConstants.h" 37 #include "SecondaryTableController.h" 38 39 const char* SecondaryTableController::LOCAL_MANGLE_OUTPUT = "st_mangle_OUTPUT"; 40 const char* SecondaryTableController::LOCAL_MANGLE_EXEMPT = "st_mangle_EXEMPT"; 41 const char* SecondaryTableController::LOCAL_MANGLE_IFACE_FORMAT = "st_mangle_%s_OUTPUT"; 42 const char* SecondaryTableController::LOCAL_NAT_POSTROUTING = "st_nat_POSTROUTING"; 43 const char* SecondaryTableController::LOCAL_FILTER_OUTPUT = "st_filter_OUTPUT"; 44 45 SecondaryTableController::SecondaryTableController(UidMarkMap *map) : mUidMarkMap(map) { 46 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 54 SecondaryTableController::~SecondaryTableController() { 55 } 56 57 int SecondaryTableController::setupIptablesHooks() { 58 int res = execIptables(V4V6, 59 "-t", 60 "mangle", 61 "-F", 62 LOCAL_MANGLE_OUTPUT, 63 NULL); 64 res |= execIptables(V4V6, 65 "-t", 66 "mangle", 67 "-F", 68 LOCAL_MANGLE_EXEMPT, 69 NULL); 70 // rule for skipping anything marked with the PROTECT_MARK 71 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 86 // protect the legacy VPN daemons from routes. 87 // TODO: Remove this when legacy VPN's are removed. 88 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; 101 } 102 103 int SecondaryTableController::findTableNumber(const char *iface) { 104 int i; 105 for (i = 0; i < INTERFACES_TRACKED; i++) { 106 // compare through the final null, hence +1 107 if (strncmp(iface, mInterfaceTable[i], IFNAMSIZ + 1) == 0) { 108 return i; 109 } 110 } 111 return -1; 112 } 113 114 int SecondaryTableController::addRoute(SocketClient *cli, char *iface, char *dest, int prefix, 115 char *gateway) { 116 int tableIndex = findTableNumber(iface); 117 if (tableIndex == -1) { 118 tableIndex = findTableNumber(""); // look for an empty slot 119 if (tableIndex == -1) { 120 ALOGE("Max number of NATed interfaces reached"); 121 errno = ENODEV; 122 cli->sendMsg(ResponseCode::OperationFailed, "Max number NATed", true); 123 return -1; 124 } 125 strncpy(mInterfaceTable[tableIndex], iface, IFNAMSIZ); 126 // Ensure null termination even if truncation happened 127 mInterfaceTable[tableIndex][IFNAMSIZ] = 0; 128 } 129 130 return modifyRoute(cli, ADD, iface, dest, prefix, gateway, tableIndex); 131 } 132 133 int SecondaryTableController::modifyRoute(SocketClient *cli, const char *action, char *iface, 134 char *dest, int prefix, char *gateway, int tableIndex) { 135 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); 142 143 if (strcmp("::", gateway) == 0) { 144 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); 155 } else { 156 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); 169 } 170 171 if (ret) { 172 ALOGE("ip route %s failed: %s route %s %s/%d via %s dev %s table %d", action, 173 IP_PATH, action, dest, prefix, gateway, iface, tableIndex+BASE_TABLE_NUMBER); 174 errno = ENODEV; 175 cli->sendMsg(ResponseCode::OperationFailed, "ip route modification failed", true); 176 return -1; 177 } 178 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 } 187 modifyRuleCount(tableIndex, action); 188 cli->sendMsg(ResponseCode::CommandOkay, "Route modified", false); 189 return 0; 190 } 191 192 void 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 203 int 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 213 const char *SecondaryTableController::getVersion(const char *addr) { 214 if (strchr(addr, ':') != NULL) { 215 return "-6"; 216 } else { 217 return "-4"; 218 } 219 } 220 221 IptablesTarget SecondaryTableController::getIptablesTarget(const char *addr) { 222 if (strchr(addr, ':') != NULL) { 223 return V6; 224 } else { 225 return V4; 226 } 227 } 228 229 int SecondaryTableController::removeRoute(SocketClient *cli, char *iface, char *dest, int prefix, 230 char *gateway) { 231 int tableIndex = findTableNumber(iface); 232 if (tableIndex == -1) { 233 ALOGE("Interface not found"); 234 errno = ENODEV; 235 cli->sendMsg(ResponseCode::OperationFailed, "Interface not found", true); 236 return -1; 237 } 238 239 return modifyRoute(cli, DEL, iface, dest, prefix, gateway, tableIndex); 240 } 241 242 int SecondaryTableController::modifyFromRule(int tableIndex, const char *action, 243 const char *addr) { 244 char tableIndex_str[11]; 245 246 if (verifyTableIndex(tableIndex)) { 247 return -1; 248 } 249 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)) { 263 return -1; 264 } 265 266 modifyRuleCount(tableIndex, action); 267 return 0; 268 } 269 270 int SecondaryTableController::modifyLocalRoute(int tableIndex, const char *action, 271 const char *iface, const char *addr) { 272 char tableIndex_str[11]; 273 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 280 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); 294 } 295 int SecondaryTableController::addFwmarkRule(const char *iface) { 296 return setFwmarkRule(iface, true); 297 } 298 299 int SecondaryTableController::removeFwmarkRule(const char *iface) { 300 return setFwmarkRule(iface, false); 301 } 302 303 int SecondaryTableController::setFwmarkRule(const char *iface, bool add) { 304 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 } 316 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[] = { 341 IP_PATH, 342 "rule", 343 add ? "add" : "del", 344 "prio", 345 RULE_PRIO, 346 "fwmark", 347 mark_str, 348 "table", 349 mark_str 350 }; 351 ret = runCmd(ARRAY_SIZE(fwmark_cmd), fwmark_cmd); 352 if (ret) return ret; 353 354 //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", 373 "prio", 374 RULE_PRIO, 375 "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 455 //set up the needed source IP rewriting 456 //NOTE: Without ipv6 NAT in the kernel <3.7 only support V4 NAT 457 ret = execIptables(V4, 458 "-t", 459 "nat", 460 add ? "-A" : "-D", 461 LOCAL_NAT_POSTROUTING, 462 "-o", 463 iface, 464 "-m", 465 "mark", 466 "--mark", 467 mark_str, 468 "-j", 469 "MASQUERADE", 470 NULL); 471 472 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 508 int SecondaryTableController::addFwmarkRoute(const char* iface, const char *dest, int prefix) { 509 return setFwmarkRoute(iface, dest, prefix, true); 510 } 511 512 int SecondaryTableController::removeFwmarkRoute(const char* iface, const char *dest, int prefix) { 513 return setFwmarkRoute(iface, dest, prefix, true); 514 } 515 516 int 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); 543 } 544 545 int SecondaryTableController::addUidRule(const char *iface, int uid_start, int uid_end) { 546 return setUidRule(iface, uid_start, uid_end, true); 547 } 548 549 int SecondaryTableController::removeUidRule(const char *iface, int uid_start, int uid_end) { 550 return setUidRule(iface, uid_start, uid_end, false); 551 } 552 553 int SecondaryTableController::setUidRule(const char *iface, int uid_start, int uid_end, bool add) { 554 int tableIndex = findTableNumber(iface); 555 if (tableIndex == -1) { 556 errno = EINVAL; 557 return -1; 558 } 559 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 } 571 char uid_str[24] = {0}; 572 char chain_str[IFNAMSIZ + 18]; 573 snprintf(uid_str, sizeof(uid_str), "%d-%d", uid_start, uid_end); 574 snprintf(chain_str, sizeof(chain_str), LOCAL_MANGLE_IFACE_FORMAT, iface); 575 return execIptables(V4V6, 576 "-t", 577 "mangle", 578 add ? "-A" : "-D", 579 LOCAL_MANGLE_OUTPUT, 580 "-m", 581 "owner", 582 "--uid-owner", 583 uid_str, 584 "-g", 585 chain_str, 586 NULL); 587 } 588 589 int SecondaryTableController::addHostExemption(const char *host) { 590 return setHostExemption(host, true); 591 } 592 593 int SecondaryTableController::removeHostExemption(const char *host) { 594 return setHostExemption(host, false); 595 } 596 597 int 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); 601 int ret = execIptables(target, 602 "-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); 613 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; 627 } 628 629 void 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 636 void 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 642 int SecondaryTableController::runCmd(int argc, const char **argv) { 643 int ret = 0; 644 645 ret = android_fork_execvp(argc, (char **)argv, NULL, false, false); 646 return ret; 647 } 648