NatController.cpp revision f7bf29c8a37d65e132a4dceb7c5a4200ed5c3d79
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 32extern "C" int logwrap(int argc, const char **argv, int background); 33 34static char IPTABLES_PATH[] = "/system/bin/iptables"; 35 36NatController::NatController() { 37 natCount = 0; 38} 39 40NatController::~NatController() { 41} 42 43int NatController::runIptablesCmd(const char *cmd) { 44 char *buffer; 45 size_t len = strnlen(cmd, 255); 46 int res; 47 48 if (len == 255) { 49 LOGE("iptables command too long"); 50 errno = E2BIG; 51 return -1; 52 } 53 54 asprintf(&buffer, "%s %s", IPTABLES_PATH, cmd); 55 res = system(buffer); 56 free(buffer); 57 return res; 58} 59 60int NatController::setDefaults() { 61 62 if (runIptablesCmd("-P INPUT ACCEPT")) 63 return -1; 64 if (runIptablesCmd("-P OUTPUT ACCEPT")) 65 return -1; 66 if (runIptablesCmd("-P FORWARD DROP")) 67 return -1; 68 if (runIptablesCmd("-F FORWARD")) 69 return -1; 70 if (runIptablesCmd("-t nat -F")) 71 return -1; 72 return 0; 73} 74 75bool NatController::interfaceExists(const char *iface) { 76 // XXX: Implement this 77 return true; 78} 79 80// when un-doing NAT, we should report errors, but also try to do as much cleanup 81// as we can - don't short circuit on error. 82int NatController::doNatCommands(const char *intIface, const char *extIface, bool add) { 83 char cmd[255]; 84 85 char bootmode[PROPERTY_VALUE_MAX] = {0}; 86 property_get("ro.bootmode", bootmode, "unknown"); 87 if (0 != strcmp("bp-tools", bootmode)) { 88 // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0 89 if (add == false) { 90 if (natCount <= 1) { 91 int ret = setDefaults(); 92 if (ret == 0) { 93 natCount=0; 94 } 95 LOGE("setDefaults returned %d", ret); 96 return ret; 97 } 98 } 99 } 100 101 if (!interfaceExists(intIface) || !interfaceExists (extIface)) { 102 LOGE("Invalid interface specified"); 103 errno = ENODEV; 104 return -1; 105 } 106 107 snprintf(cmd, sizeof(cmd), 108 "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT", 109 (add ? "A" : "D"), 110 extIface, intIface); 111 if (runIptablesCmd(cmd) && add) { 112 // only bail out if we are adding, not removing nat rules 113 return -1; 114 } 115 116 snprintf(cmd, sizeof(cmd), 117 "-%s FORWARD -i %s -o %s -m state --state INVALID -j DROP", 118 (add ? "A" : "D"), 119 intIface, extIface); 120 if (runIptablesCmd(cmd) && add) { 121 // bail on error, but only if adding 122 snprintf(cmd, sizeof(cmd), 123 "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT", 124 (!add ? "A" : "D"), 125 extIface, intIface); 126 runIptablesCmd(cmd); 127 return -1; 128 } 129 130 snprintf(cmd, sizeof(cmd), "-%s FORWARD -i %s -o %s -j ACCEPT", (add ? "A" : "D"), 131 intIface, extIface); 132 if (runIptablesCmd(cmd) && add) { 133 // unwind what's been done, but don't care about success - what more could we do? 134 snprintf(cmd, sizeof(cmd), 135 "-%s FORWARD -i %s -o %s -m state --state INVALID -j DROP", 136 (!add ? "A" : "D"), 137 intIface, extIface); 138 runIptablesCmd(cmd); 139 140 snprintf(cmd, sizeof(cmd), 141 "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT", 142 (!add ? "A" : "D"), 143 extIface, intIface); 144 runIptablesCmd(cmd); 145 return -1; 146 } 147 148 // add this if we are the first added nat 149 if (add && natCount == 0) { 150 snprintf(cmd, sizeof(cmd), "-t nat -A POSTROUTING -o %s -j MASQUERADE", extIface); 151 if (runIptablesCmd(cmd)) { 152 if (0 != strcmp("bp-tools", bootmode)) { 153 // unwind what's been done, but don't care about success - what more could we do? 154 setDefaults();; 155 } 156 return -1; 157 } 158 } 159 160 if (add) { 161 natCount++; 162 } else { 163 natCount--; 164 } 165 return 0; 166} 167 168int NatController::enableNat(const char *intIface, const char *extIface) { 169 return doNatCommands(intIface, extIface, true); 170} 171 172int NatController::disableNat(const char *intIface, const char *extIface) { 173 return doNatCommands(intIface, extIface, false); 174} 175