NatController.cpp revision fc97b82e02979f246d56a4bfd60e4aab8686d3f6
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 <sys/socket.h> 20#include <sys/stat.h> 21#include <fcntl.h> 22#include <netinet/in.h> 23#include <arpa/inet.h> 24#include <string.h> 25#include <cutils/properties.h> 26 27#define LOG_TAG "NatController" 28#include <cutils/log.h> 29 30#include "NatController.h" 31#include "SecondaryTableController.h" 32 33extern "C" int logwrap(int argc, const char **argv, int background); 34 35static char IPTABLES_PATH[] = "/system/bin/iptables"; 36static char IP_PATH[] = "/system/bin/ip"; 37 38NatController::NatController(SecondaryTableController *ctrl) { 39 secondaryTableCtrl = ctrl; 40 setDefaults(); 41} 42 43NatController::~NatController() { 44} 45 46int NatController::runCmd(const char *path, const char *cmd) { 47 char *buffer; 48 size_t len = strnlen(cmd, 255); 49 int res; 50 51 if (len == 255) { 52 LOGE("command too long"); 53 errno = E2BIG; 54 return -1; 55 } 56 57 asprintf(&buffer, "%s %s", path, cmd); 58 res = system(buffer); 59 free(buffer); 60 return res; 61} 62 63int NatController::setDefaults() { 64 65 if (runCmd(IPTABLES_PATH, "-P INPUT ACCEPT")) 66 return -1; 67 if (runCmd(IPTABLES_PATH, "-P OUTPUT ACCEPT")) 68 return -1; 69 if (runCmd(IPTABLES_PATH, "-P FORWARD DROP")) 70 return -1; 71 if (runCmd(IPTABLES_PATH, "-F FORWARD")) 72 return -1; 73 if (runCmd(IPTABLES_PATH, "-t nat -F")) 74 return -1; 75 76 runCmd(IP_PATH, "rule flush"); 77 runCmd(IP_PATH, "rule add from all lookup default prio 32767"); 78 runCmd(IP_PATH, "rule add from all lookup main prio 32766"); 79 80 natCount = 0; 81 return 0; 82} 83 84bool NatController::checkInterface(const char *iface) { 85 if (strlen(iface) > MAX_IFACE_LENGTH) return false; 86 return true; 87} 88 89// 0 1 2 3 4 5 90// nat enable intface extface addrcnt nated-ipaddr/prelength 91int NatController::enableNat(const int argc, char **argv) { 92 char cmd[255]; 93 int i; 94 int addrCount = atoi(argv[4]); 95 int ret = 0; 96 const char *intIface = argv[2]; 97 const char *extIface = argv[3]; 98 int tableNumber; 99 100 if (!checkInterface(intIface) || !checkInterface(extIface)) { 101 LOGE("Invalid interface specified"); 102 errno = ENODEV; 103 return -1; 104 } 105 106 if (argc < 5 + addrCount) { 107 LOGE("Missing Argument"); 108 errno = EINVAL; 109 return -1; 110 } 111 112 tableNumber = secondaryTableCtrl->findTableNumber(extIface); 113 if (tableNumber != -1) { 114 for(i = 0; i < addrCount && ret == 0; i++) { 115 snprintf(cmd, sizeof(cmd), "rule add from %s table %d", argv[5+i], 116 tableNumber + BASE_TABLE_NUMBER); 117 ret |= runCmd(IP_PATH, cmd); 118 if (ret) LOGE("IP rule %s got %d", cmd, ret); 119 120 snprintf(cmd, sizeof(cmd), "route add %s dev %s table %d", argv[5+i], intIface, 121 tableNumber + BASE_TABLE_NUMBER); 122 ret |= runCmd(IP_PATH, cmd); 123 if (ret) LOGE("IP route %s got %d", cmd, ret); 124 } 125 } 126 127 if (ret != 0 || setForwardRules(true, intIface, extIface) != 0) { 128 if (tableNumber != -1) { 129 for (i = 0; i < addrCount; i++) { 130 snprintf(cmd, sizeof(cmd), "route del %s dev %s table %d", argv[5+i], intIface, 131 tableNumber + BASE_TABLE_NUMBER); 132 runCmd(IP_PATH, cmd); 133 134 snprintf(cmd, sizeof(cmd), "rule del from %s table %d", argv[5+i], 135 tableNumber + BASE_TABLE_NUMBER); 136 runCmd(IP_PATH, cmd); 137 } 138 } 139 LOGE("Error setting forward rules"); 140 errno = ENODEV; 141 return -1; 142 } 143 144 natCount++; 145 // add this if we are the first added nat 146 if (natCount == 1) { 147 snprintf(cmd, sizeof(cmd), "-t nat -A POSTROUTING -o %s -j MASQUERADE", extIface); 148 if (runCmd(IPTABLES_PATH, cmd)) { 149 LOGE("Error seting postroute rule: %s", cmd); 150 // unwind what's been done, but don't care about success - what more could we do? 151 for (i = 0; i < addrCount; i++) { 152 snprintf(cmd, sizeof(cmd), "route del %s dev %s table %d", argv[5+i], intIface, 153 tableNumber + BASE_TABLE_NUMBER); 154 runCmd(IP_PATH, cmd); 155 } 156 setDefaults(); 157 return -1; 158 } 159 } 160 161 return 0; 162} 163 164int NatController::setForwardRules(bool add, const char *intIface, const char * extIface) { 165 char cmd[255]; 166 167 snprintf(cmd, sizeof(cmd), 168 "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT", 169 (add ? "A" : "D"), 170 extIface, intIface); 171 if (runCmd(IPTABLES_PATH, cmd) && add) { 172 return -1; 173 } 174 175 snprintf(cmd, sizeof(cmd), 176 "-%s FORWARD -i %s -o %s -m state --state INVALID -j DROP", 177 (add ? "A" : "D"), 178 intIface, extIface); 179 if (runCmd(IPTABLES_PATH, cmd) && add) { 180 // bail on error, but only if adding 181 snprintf(cmd, sizeof(cmd), 182 "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT", 183 (!add ? "A" : "D"), 184 extIface, intIface); 185 runCmd(IPTABLES_PATH, cmd); 186 return -1; 187 } 188 189 snprintf(cmd, sizeof(cmd), "-%s FORWARD -i %s -o %s -j ACCEPT", (add ? "A" : "D"), 190 intIface, extIface); 191 if (runCmd(IPTABLES_PATH, cmd) && add) { 192 // unwind what's been done, but don't care about success - what more could we do? 193 snprintf(cmd, sizeof(cmd), 194 "-%s FORWARD -i %s -o %s -m state --state INVALID -j DROP", 195 (!add ? "A" : "D"), 196 intIface, extIface); 197 runCmd(IPTABLES_PATH, cmd); 198 199 snprintf(cmd, sizeof(cmd), 200 "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT", 201 (!add ? "A" : "D"), 202 extIface, intIface); 203 runCmd(IPTABLES_PATH, cmd); 204 return -1; 205 } 206 return 0; 207} 208 209// nat disable intface extface 210// 0 1 2 3 4 5 211// nat enable intface extface addrcnt nated-ipaddr/prelength 212int NatController::disableNat(const int argc, char **argv) { 213 char cmd[255]; 214 int i; 215 int addrCount = atoi(argv[4]); 216 const char *intIface = argv[2]; 217 const char *extIface = argv[3]; 218 int tableNumber; 219 220 if (!checkInterface(intIface) || !checkInterface(extIface)) { 221 LOGE("Invalid interface specified"); 222 errno = ENODEV; 223 return -1; 224 } 225 226 if (argc < 5 + addrCount) { 227 LOGE("Missing Argument"); 228 errno = EINVAL; 229 return -1; 230 } 231 232 setForwardRules(false, intIface, extIface); 233 234 tableNumber = secondaryTableCtrl->findTableNumber(extIface); 235 if (tableNumber != -1) { 236 for (i = 0; i < addrCount; i++) { 237 snprintf(cmd, sizeof(cmd), "route del %s dev %s table %d", argv[5+i], intIface, 238 tableNumber + BASE_TABLE_NUMBER); 239 // if the interface has gone down these will be gone already and give errors 240 // ignore them. 241 runCmd(IP_PATH, cmd); 242 } 243 } 244 245 if (--natCount <= 0) { 246 char bootmode[PROPERTY_VALUE_MAX] = {0}; 247 property_get("ro.bootmode", bootmode, "unknown"); 248 if (0 != strcmp("bp-tools", bootmode)) { 249 // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0 250 setDefaults(); 251 } 252 natCount = 0; 253 } 254 return 0; 255} 256