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 33 extern "C" int system_nosh(const char *command); 34 35 static char IPTABLES_PATH[] = "/system/bin/iptables"; 36 static char IP_PATH[] = "/system/bin/ip"; 37 38 NatController::NatController(SecondaryTableController *ctrl) { 39 secondaryTableCtrl = ctrl; 40 setDefaults(); 41 } 42 43 NatController::~NatController() { 44 } 45 46 int 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_nosh(buffer); 59 free(buffer); 60 return res; 61 } 62 63 int 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, "-6 rule flush"); 78 runCmd(IP_PATH, "rule add from all lookup default prio 32767"); 79 runCmd(IP_PATH, "rule add from all lookup main prio 32766"); 80 runCmd(IP_PATH, "-6 rule add from all lookup default prio 32767"); 81 runCmd(IP_PATH, "-6 rule add from all lookup main prio 32766"); 82 runCmd(IP_PATH, "route flush cache"); 83 84 natCount = 0; 85 return 0; 86 } 87 88 bool NatController::checkInterface(const char *iface) { 89 if (strlen(iface) > MAX_IFACE_LENGTH) return false; 90 return true; 91 } 92 93 const char *NatController::getVersion(const char *addr) { 94 if (strchr(addr, ':') != NULL) { 95 return "-6"; 96 } else { 97 return "-4"; 98 } 99 } 100 101 // 0 1 2 3 4 5 102 // nat enable intface extface addrcnt nated-ipaddr/prelength 103 int NatController::enableNat(const int argc, char **argv) { 104 char cmd[255]; 105 int i; 106 int addrCount = atoi(argv[4]); 107 int ret = 0; 108 const char *intIface = argv[2]; 109 const char *extIface = argv[3]; 110 int tableNumber; 111 112 if (!checkInterface(intIface) || !checkInterface(extIface)) { 113 LOGE("Invalid interface specified"); 114 errno = ENODEV; 115 return -1; 116 } 117 118 if (argc < 5 + addrCount) { 119 LOGE("Missing Argument"); 120 errno = EINVAL; 121 return -1; 122 } 123 124 tableNumber = secondaryTableCtrl->findTableNumber(extIface); 125 if (tableNumber != -1) { 126 for(i = 0; i < addrCount && ret == 0; i++) { 127 snprintf(cmd, sizeof(cmd), "%s rule add from %s table %d", getVersion(argv[5+i]), 128 argv[5+i], tableNumber + BASE_TABLE_NUMBER); 129 ret |= runCmd(IP_PATH, cmd); 130 if (ret) LOGE("IP rule %s got %d", cmd, ret); 131 132 snprintf(cmd, sizeof(cmd), "route add %s dev %s table %d", argv[5+i], intIface, 133 tableNumber + BASE_TABLE_NUMBER); 134 ret |= runCmd(IP_PATH, cmd); 135 if (ret) LOGE("IP route %s got %d", cmd, ret); 136 } 137 runCmd(IP_PATH, "route flush cache"); 138 } 139 140 if (ret != 0 || setForwardRules(true, intIface, extIface) != 0) { 141 if (tableNumber != -1) { 142 for (i = 0; i < addrCount; i++) { 143 snprintf(cmd, sizeof(cmd), "route del %s dev %s table %d", argv[5+i], intIface, 144 tableNumber + BASE_TABLE_NUMBER); 145 runCmd(IP_PATH, cmd); 146 147 snprintf(cmd, sizeof(cmd), "%s rule del from %s table %d", getVersion(argv[5+i]), 148 argv[5+i], tableNumber + BASE_TABLE_NUMBER); 149 runCmd(IP_PATH, cmd); 150 } 151 runCmd(IP_PATH, "route flush cache"); 152 } 153 LOGE("Error setting forward rules"); 154 errno = ENODEV; 155 return -1; 156 } 157 158 natCount++; 159 // add this if we are the first added nat 160 if (natCount == 1) { 161 snprintf(cmd, sizeof(cmd), "-t nat -A POSTROUTING -o %s -j MASQUERADE", extIface); 162 if (runCmd(IPTABLES_PATH, cmd)) { 163 LOGE("Error seting postroute rule: %s", cmd); 164 // unwind what's been done, but don't care about success - what more could we do? 165 for (i = 0; i < addrCount; i++) { 166 snprintf(cmd, sizeof(cmd), "route del %s dev %s table %d", argv[5+i], intIface, 167 tableNumber + BASE_TABLE_NUMBER); 168 runCmd(IP_PATH, cmd); 169 } 170 setDefaults(); 171 return -1; 172 } 173 } 174 175 return 0; 176 } 177 178 int NatController::setForwardRules(bool add, const char *intIface, const char * extIface) { 179 char cmd[255]; 180 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 if (runCmd(IPTABLES_PATH, cmd) && add) { 186 return -1; 187 } 188 189 snprintf(cmd, sizeof(cmd), 190 "-%s FORWARD -i %s -o %s -m state --state INVALID -j DROP", 191 (add ? "A" : "D"), 192 intIface, extIface); 193 if (runCmd(IPTABLES_PATH, cmd) && add) { 194 // bail on error, but only if adding 195 snprintf(cmd, sizeof(cmd), 196 "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT", 197 (!add ? "A" : "D"), 198 extIface, intIface); 199 runCmd(IPTABLES_PATH, cmd); 200 return -1; 201 } 202 203 snprintf(cmd, sizeof(cmd), "-%s FORWARD -i %s -o %s -j ACCEPT", (add ? "A" : "D"), 204 intIface, extIface); 205 if (runCmd(IPTABLES_PATH, cmd) && add) { 206 // unwind what's been done, but don't care about success - what more could we do? 207 snprintf(cmd, sizeof(cmd), 208 "-%s FORWARD -i %s -o %s -m state --state INVALID -j DROP", 209 (!add ? "A" : "D"), 210 intIface, extIface); 211 runCmd(IPTABLES_PATH, cmd); 212 213 snprintf(cmd, sizeof(cmd), 214 "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT", 215 (!add ? "A" : "D"), 216 extIface, intIface); 217 runCmd(IPTABLES_PATH, cmd); 218 return -1; 219 } 220 return 0; 221 } 222 223 // nat disable intface extface 224 // 0 1 2 3 4 5 225 // nat enable intface extface addrcnt nated-ipaddr/prelength 226 int NatController::disableNat(const int argc, char **argv) { 227 char cmd[255]; 228 int i; 229 int addrCount = atoi(argv[4]); 230 const char *intIface = argv[2]; 231 const char *extIface = argv[3]; 232 int tableNumber; 233 234 if (!checkInterface(intIface) || !checkInterface(extIface)) { 235 LOGE("Invalid interface specified"); 236 errno = ENODEV; 237 return -1; 238 } 239 240 if (argc < 5 + addrCount) { 241 LOGE("Missing Argument"); 242 errno = EINVAL; 243 return -1; 244 } 245 246 setForwardRules(false, intIface, extIface); 247 248 tableNumber = secondaryTableCtrl->findTableNumber(extIface); 249 if (tableNumber != -1) { 250 for (i = 0; i < addrCount; i++) { 251 snprintf(cmd, sizeof(cmd), "route del %s dev %s table %d", argv[5+i], intIface, 252 tableNumber + BASE_TABLE_NUMBER); 253 // if the interface has gone down these will be gone already and give errors 254 // ignore them. 255 runCmd(IP_PATH, cmd); 256 257 snprintf(cmd, sizeof(cmd), "%s rule del from %s table %d", getVersion(argv[5+i]), 258 argv[5+i], tableNumber + BASE_TABLE_NUMBER); 259 runCmd(IP_PATH, cmd); 260 } 261 262 runCmd(IP_PATH, "route flush cache"); 263 } 264 265 if (--natCount <= 0) { 266 char bootmode[PROPERTY_VALUE_MAX] = {0}; 267 property_get("ro.bootmode", bootmode, "unknown"); 268 if (0 != strcmp("bp-tools", bootmode)) { 269 // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0 270 setDefaults(); 271 } 272 natCount = 0; 273 } 274 return 0; 275 } 276