OSDN Git Service

Fix bug in NATing code.
[android-x86/system-netd.git] / NatController.cpp
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
25 #define LOG_TAG "NatController"
26 #include <cutils/log.h>
27
28 #include "NatController.h"
29
30 extern "C" int logwrap(int argc, const char **argv, int background);
31
32 static char IPTABLES_PATH[] = "/system/bin/iptables";
33
34 NatController::NatController() {
35     natCount = 0;
36 }
37
38 NatController::~NatController() {
39 }
40
41 int NatController::runIptablesCmd(const char *cmd) {
42     char buffer[255];
43
44     strncpy(buffer, cmd, sizeof(buffer)-1);
45
46     const char *args[16];
47     char *next = buffer;
48     char *tmp;
49
50     args[0] = IPTABLES_PATH;
51     args[1] = "--verbose";
52     int i = 2;
53
54     while ((tmp = strsep(&next, " "))) {
55         args[i++] = tmp;
56         if (i == 16) {
57             LOGE("iptables argument overflow");
58             errno = E2BIG;
59             return -1;
60         }
61     }
62     args[i] = NULL;
63
64     return logwrap(i, args, 0);
65 }
66
67 int NatController::setDefaults() {
68
69     if (runIptablesCmd("-P INPUT ACCEPT"))
70         return -1;
71     if (runIptablesCmd("-F INPUT"))
72         return -1;
73     if (runIptablesCmd("-P OUTPUT ACCEPT"))
74         return -1;
75     if (runIptablesCmd("-F OUTPUT"))
76         return -1;
77     if (runIptablesCmd("-P FORWARD DROP"))
78         return -1;
79     if (runIptablesCmd("-F FORWARD"))
80         return -1;
81     if (runIptablesCmd("-t nat -F"))
82         return -1;
83     return 0;
84 }
85
86 bool NatController::interfaceExists(const char *iface) {
87     // XXX: STOPSHIP - Implement this
88     return true;
89 }
90
91 int NatController::doNatCommands(const char *intIface, const char *extIface, bool add) {
92     char cmd[255];
93
94     // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
95     if (add == false) {
96         if (natCount <= 1) {
97             int ret = setDefaults();
98             if (ret == 0) {
99                 natCount=0;
100             }
101             return ret;
102         }
103     }
104
105     if (!interfaceExists(intIface) || !interfaceExists (extIface)) {
106         LOGE("Invalid interface specified");
107         errno = ENODEV;
108         return -1;
109     }
110
111     snprintf(cmd, sizeof(cmd),
112              "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
113              (add ? "A" : "D"),
114              extIface, intIface);
115     if (runIptablesCmd(cmd)) {
116         return -1;
117     }
118
119     snprintf(cmd, sizeof(cmd), "-%s FORWARD -i %s -o %s -j ACCEPT", (add ? "A" : "D"),
120             intIface, extIface);
121     if (runIptablesCmd(cmd)) {
122         // unwind what's been done, but don't care about success - what more could we do?
123         snprintf(cmd, sizeof(cmd),
124                  "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
125                  (!add ? "A" : "D"),
126                  extIface, intIface);
127         return -1;
128     }
129
130     // add this if we are the first added nat
131     if (add && natCount == 0) {
132         snprintf(cmd, sizeof(cmd), "-t nat -A POSTROUTING -o %s -j MASQUERADE", extIface);
133         if (runIptablesCmd(cmd)) {
134             // unwind what's been done, but don't care about success - what more could we do?
135             setDefaults();;
136             return -1;
137         }
138     }
139
140     if (add) {
141         natCount++;
142     } else {
143         natCount--;
144     }
145     return 0;
146 }
147
148 int NatController::enableNat(const char *intIface, const char *extIface) {
149     return doNatCommands(intIface, extIface, true);
150 }
151
152 int NatController::disableNat(const char *intIface, const char *extIface) {
153     return doNatCommands(intIface, extIface, false);
154 }