• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
32 extern "C" int logwrap(int argc, const char **argv, int background);
33 
34 static char IPTABLES_PATH[] = "/system/bin/iptables";
35 
NatController()36 NatController::NatController() {
37     natCount = 0;
38 }
39 
~NatController()40 NatController::~NatController() {
41 }
42 
runIptablesCmd(const char * cmd)43 int 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 
setDefaults()60 int 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 
interfaceExists(const char * iface)75 bool 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.
doNatCommands(const char * intIface,const char * extIface,bool add)82 int 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 
enableNat(const char * intIface,const char * extIface)168 int NatController::enableNat(const char *intIface, const char *extIface) {
169     return doNatCommands(intIface, extIface, true);
170 }
171 
disableNat(const char * intIface,const char * extIface)172 int NatController::disableNat(const char *intIface, const char *extIface) {
173     return doNatCommands(intIface, extIface, false);
174 }
175