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