RouteController.cpp revision a10ac3214f6a582b7fdb66acc43c702731e53d81
1/* 2 * Copyright (C) 2014 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 "RouteController.h" 18 19#include "Fwmark.h" 20#include "NetdConstants.h" 21 22#include <logwrap/logwrap.h> 23#include <net/if.h> 24 25namespace { 26 27const uint32_t RULE_PRIORITY_PER_NETWORK_EXPLICIT = 300; 28const uint32_t RULE_PRIORITY_PER_NETWORK_OIF = 400; 29const uint32_t RULE_PRIORITY_PER_NETWORK_NORMAL = 700; 30 31const bool FWMARK_USE_NET_ID = true; 32const bool FWMARK_USE_EXPLICIT = true; 33const bool FWMARK_USE_PROTECT = true; 34 35uint32_t getRouteTableForInterface(const char* interface) { 36 uint32_t index = if_nametoindex(interface); 37 return index ? index + RouteController::ROUTE_TABLE_OFFSET_FROM_INDEX : 0; 38} 39 40bool runIpRuleCommand(const char* action, uint32_t priority, uint32_t table, 41 uint32_t fwmark, uint32_t mask, const char* oif) { 42 43 char priorityString[UINT32_STRLEN]; 44 char tableString[UINT32_STRLEN]; 45 snprintf(priorityString, sizeof(priorityString), "%u", priority); 46 snprintf(tableString, sizeof(tableString), "%u", table); 47 48 char fwmarkString[sizeof("0x12345678/0x12345678")]; 49 snprintf(fwmarkString, sizeof(fwmarkString), "0x%x/0x%x", fwmark, mask); 50 51 const char* version[] = {"-4", "-6"}; 52 for (size_t i = 0; i < ARRAY_SIZE(version); ++i) { 53 int argc = 0; 54 const char* argv[16]; 55 56 argv[argc++] = IP_PATH; 57 argv[argc++] = version[i]; 58 argv[argc++] = "rule"; 59 argv[argc++] = action; 60 argv[argc++] = "priority"; 61 argv[argc++] = priorityString; 62 argv[argc++] = "table"; 63 argv[argc++] = tableString; 64 if (mask) { 65 argv[argc++] = "fwmark"; 66 argv[argc++] = fwmarkString; 67 } 68 if (oif) { 69 argv[argc++] = "oif"; 70 argv[argc++] = oif; 71 } 72 if (android_fork_execvp(argc, const_cast<char**>(argv), NULL, false, false)) { 73 return false; 74 } 75 } 76 77 return true; 78} 79 80bool modifyNetwork(unsigned netId, const char* interface, Permission permission, bool add) { 81 uint32_t table = getRouteTableForInterface(interface); 82 if (!table) { 83 return false; 84 } 85 86 const char* action = add ? ADD : DEL; 87 88 // A rule to route traffic based on an explicitly chosen network. 89 // 90 // Supports apps that use the multinetwork APIs to restrict their traffic to a network. 91 // 92 // We don't really need to check the permission bits of the fwmark here, as they would've been 93 // checked at the time the netId was set into the fwmark, but we do so to be consistent. 94 uint32_t fwmark = getFwmark(netId, FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission); 95 uint32_t mask = getFwmarkMask(FWMARK_USE_NET_ID, FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, 96 permission); 97 if (!runIpRuleCommand(action, RULE_PRIORITY_PER_NETWORK_EXPLICIT, table, fwmark, mask, NULL)) { 98 return false; 99 } 100 101 // A rule to route traffic based on a chosen outgoing interface. 102 // 103 // Supports apps that use SO_BINDTODEVICE or IP_PKTINFO options and the kernel that already 104 // knows the outgoing interface (typically for link-local communications). 105 fwmark = getFwmark(0, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission); 106 mask = getFwmark(!FWMARK_USE_NET_ID, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission); 107 if (!runIpRuleCommand(action, RULE_PRIORITY_PER_NETWORK_OIF, table, fwmark, mask, interface)) { 108 return false; 109 } 110 111 // A rule to route traffic based on the chosen network. 112 // 113 // This is for sockets that have not explicitly requested a particular network, but have been 114 // bound to one when they called connect(). This ensures that sockets connected on a particular 115 // network stay on that network even if the default network changes. 116 fwmark = getFwmark(netId, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission); 117 mask = getFwmarkMask(FWMARK_USE_NET_ID, !FWMARK_USE_EXPLICIT, !FWMARK_USE_PROTECT, permission); 118 if (!runIpRuleCommand(action, RULE_PRIORITY_PER_NETWORK_NORMAL, table, fwmark, mask, NULL)) { 119 return false; 120 } 121 122 // An iptables rule to mark incoming packets on a network with the netId of the network. 123 // 124 // This is so that the kernel can: 125 // + Use the right fwmark for (and thus correctly route) replies (e.g.: TCP RST, ICMP errors, 126 // ping replies). 127 // + Mark sockets that accept connections from this interface so that the connection stays on 128 // the same interface. 129 action = add ? "-A" : "-D"; 130 char markString[UINT32_HEX_STRLEN]; 131 snprintf(markString, sizeof(markString), "0x%x", netId); 132 if (execIptables(V4V6, "-t", "mangle", action, "INPUT", "-i", interface, "-j", "MARK", 133 "--set-mark", markString, NULL)) { 134 return false; 135 } 136 137 return true; 138} 139 140} // namespace 141 142bool RouteController::createNetwork(unsigned netId, const char* interface, Permission permission) { 143 return modifyNetwork(netId, interface, permission, true); 144} 145 146bool RouteController::destroyNetwork(unsigned netId, const char* interface, Permission permission) { 147 return modifyNetwork(netId, interface, permission, false); 148} 149