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