OSDN Git Service

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