2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
25 #include <cutils/properties.h>
27 #define LOG_TAG "NatController"
28 #include <cutils/log.h>
30 #include "NatController.h"
31 #include "SecondaryTableController.h"
33 extern "C" int system_nosh(const char *command);
35 static char IPTABLES_PATH[] = "/system/bin/iptables";
36 static char IP_PATH[] = "/system/bin/ip";
38 NatController::NatController(SecondaryTableController *ctrl) {
39 secondaryTableCtrl = ctrl;
43 NatController::~NatController() {
46 int NatController::runCmd(const char *path, const char *cmd) {
48 size_t len = strnlen(cmd, 255);
52 ALOGE("command too long");
57 asprintf(&buffer, "%s %s", path, cmd);
58 res = system_nosh(buffer);
63 int NatController::setDefaults() {
65 if (runCmd(IPTABLES_PATH, "-P INPUT ACCEPT"))
67 if (runCmd(IPTABLES_PATH, "-P OUTPUT ACCEPT"))
69 if (runCmd(IPTABLES_PATH, "-P FORWARD DROP"))
71 if (runCmd(IPTABLES_PATH, "-F FORWARD"))
73 if (runCmd(IPTABLES_PATH, "-t nat -F"))
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");
88 bool NatController::checkInterface(const char *iface) {
89 if (strlen(iface) > MAX_IFACE_LENGTH) return false;
93 const char *NatController::getVersion(const char *addr) {
94 if (strchr(addr, ':') != NULL) {
102 // nat enable intface extface addrcnt nated-ipaddr/prelength
103 int NatController::enableNat(const int argc, char **argv) {
106 int addrCount = atoi(argv[4]);
108 const char *intIface = argv[2];
109 const char *extIface = argv[3];
112 if (!checkInterface(intIface) || !checkInterface(extIface)) {
113 ALOGE("Invalid interface specified");
118 if (argc < 5 + addrCount) {
119 ALOGE("Missing Argument");
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) ALOGE("IP rule %s got %d", cmd, ret);
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) ALOGE("IP route %s got %d", cmd, ret);
137 runCmd(IP_PATH, "route flush cache");
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);
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);
151 runCmd(IP_PATH, "route flush cache");
153 ALOGE("Error setting forward rules");
159 // add this if we are the first added nat
161 snprintf(cmd, sizeof(cmd), "-t nat -A POSTROUTING -o %s -j MASQUERADE", extIface);
162 if (runCmd(IPTABLES_PATH, cmd)) {
163 ALOGE("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);
178 int NatController::setForwardRules(bool add, const char *intIface, const char * extIface) {
181 snprintf(cmd, sizeof(cmd),
182 "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
185 if (runCmd(IPTABLES_PATH, cmd) && add) {
189 snprintf(cmd, sizeof(cmd),
190 "-%s FORWARD -i %s -o %s -m state --state INVALID -j DROP",
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",
199 runCmd(IPTABLES_PATH, cmd);
203 snprintf(cmd, sizeof(cmd), "-%s FORWARD -i %s -o %s -j ACCEPT", (add ? "A" : "D"),
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",
211 runCmd(IPTABLES_PATH, cmd);
213 snprintf(cmd, sizeof(cmd),
214 "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
217 runCmd(IPTABLES_PATH, cmd);
223 // nat disable intface extface
225 // nat enable intface extface addrcnt nated-ipaddr/prelength
226 int NatController::disableNat(const int argc, char **argv) {
229 int addrCount = atoi(argv[4]);
230 const char *intIface = argv[2];
231 const char *extIface = argv[3];
234 if (!checkInterface(intIface) || !checkInterface(extIface)) {
235 ALOGE("Invalid interface specified");
240 if (argc < 5 + addrCount) {
241 ALOGE("Missing Argument");
246 setForwardRules(false, intIface, extIface);
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
255 runCmd(IP_PATH, cmd);
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);
262 runCmd(IP_PATH, "route flush cache");
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