OSDN Git Service

am b7aeeb6c: am 500e77d5: am 3c20787d: Increase the valid name of the iface to IFNAMSIZ
[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 #include <cutils/properties.h>
26
27 #define LOG_TAG "NatController"
28 #include <cutils/log.h>
29
30 #include "NatController.h"
31 #include "SecondaryTableController.h"
32 #include "oem_iptables_hook.h"
33 #include "NetdConstants.h"
34
35 extern "C" int system_nosh(const char *command);
36
37 NatController::NatController(SecondaryTableController *ctrl) {
38     secondaryTableCtrl = ctrl;
39     setDefaults();
40 }
41
42 NatController::~NatController() {
43 }
44
45 int NatController::runCmd(const char *path, const char *cmd) {
46     char *buffer;
47     size_t len = strnlen(cmd, 255);
48     int res;
49
50     if (len == 255) {
51         ALOGE("command too long");
52         errno = E2BIG;
53         return -1;
54     }
55
56     asprintf(&buffer, "%s %s", path, cmd);
57     res = system_nosh(buffer);
58     free(buffer);
59     return res;
60 }
61
62 int NatController::setDefaults() {
63
64     if (runCmd(IPTABLES_PATH, "-P INPUT ACCEPT"))
65         return -1;
66     if (runCmd(IPTABLES_PATH, "-P OUTPUT ACCEPT"))
67         return -1;
68     if (runCmd(IPTABLES_PATH, "-P FORWARD DROP"))
69         return -1;
70     if (runCmd(IPTABLES_PATH, "-F FORWARD"))
71         return -1;
72     if (runCmd(IPTABLES_PATH, "-t nat -F"))
73         return -1;
74
75     runCmd(IP_PATH, "rule flush");
76     runCmd(IP_PATH, "-6 rule flush");
77     runCmd(IP_PATH, "rule add from all lookup default prio 32767");
78     runCmd(IP_PATH, "rule add from all lookup main prio 32766");
79     runCmd(IP_PATH, "-6 rule add from all lookup default prio 32767");
80     runCmd(IP_PATH, "-6 rule add from all lookup main prio 32766");
81     runCmd(IP_PATH, "route flush cache");
82
83     natCount = 0;
84
85     setupOemIptablesHook();
86     return 0;
87 }
88
89 bool NatController::checkInterface(const char *iface) {
90     if (strlen(iface) > IFNAMSIZ) return false;
91     return true;
92 }
93
94 //  0    1       2       3       4            5
95 // nat enable intface extface addrcnt nated-ipaddr/prelength
96 int NatController::enableNat(const int argc, char **argv) {
97     char cmd[255];
98     int i;
99     int addrCount = atoi(argv[4]);
100     int ret = 0;
101     const char *intIface = argv[2];
102     const char *extIface = argv[3];
103     int tableNumber;
104
105     if (!checkInterface(intIface) || !checkInterface(extIface)) {
106         ALOGE("Invalid interface specified");
107         errno = ENODEV;
108         return -1;
109     }
110
111     if (argc < 5 + addrCount) {
112         ALOGE("Missing Argument");
113         errno = EINVAL;
114         return -1;
115     }
116
117     tableNumber = secondaryTableCtrl->findTableNumber(extIface);
118     if (tableNumber != -1) {
119         for(i = 0; i < addrCount; i++) {
120             ret |= secondaryTableCtrl->modifyFromRule(tableNumber, ADD, argv[5+i]);
121
122             ret |= secondaryTableCtrl->modifyLocalRoute(tableNumber, ADD, intIface, argv[5+i]);
123         }
124         runCmd(IP_PATH, "route flush cache");
125     }
126
127     if (ret != 0 || setForwardRules(true, intIface, extIface) != 0) {
128         if (tableNumber != -1) {
129             for (i = 0; i < addrCount; i++) {
130                 secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
131
132                 secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
133             }
134             runCmd(IP_PATH, "route flush cache");
135         }
136         ALOGE("Error setting forward rules");
137         errno = ENODEV;
138         return -1;
139     }
140
141     natCount++;
142     // add this if we are the first added nat
143     if (natCount == 1) {
144         snprintf(cmd, sizeof(cmd), "-t nat -A POSTROUTING -o %s -j MASQUERADE", extIface);
145         if (runCmd(IPTABLES_PATH, cmd)) {
146             ALOGE("Error seting postroute rule: %s", cmd);
147             // unwind what's been done, but don't care about success - what more could we do?
148             for (i = 0; i < addrCount; i++) {
149                 secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
150
151                 secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
152             }
153             setDefaults();
154             return -1;
155         }
156     }
157
158     return 0;
159 }
160
161 int NatController::setForwardRules(bool add, const char *intIface, const char * extIface) {
162     char cmd[255];
163
164     snprintf(cmd, sizeof(cmd),
165              "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
166              (add ? "A" : "D"),
167              extIface, intIface);
168     if (runCmd(IPTABLES_PATH, cmd) && add) {
169         return -1;
170     }
171
172     snprintf(cmd, sizeof(cmd),
173             "-%s FORWARD -i %s -o %s -m state --state INVALID -j DROP",
174             (add ? "A" : "D"),
175             intIface, extIface);
176     if (runCmd(IPTABLES_PATH, cmd) && add) {
177         // bail on error, but only if adding
178         snprintf(cmd, sizeof(cmd),
179                 "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
180                 (!add ? "A" : "D"),
181                 extIface, intIface);
182         runCmd(IPTABLES_PATH, cmd);
183         return -1;
184     }
185
186     snprintf(cmd, sizeof(cmd), "-%s FORWARD -i %s -o %s -j ACCEPT", (add ? "A" : "D"),
187             intIface, extIface);
188     if (runCmd(IPTABLES_PATH, cmd) && add) {
189         // unwind what's been done, but don't care about success - what more could we do?
190         snprintf(cmd, sizeof(cmd),
191                 "-%s FORWARD -i %s -o %s -m state --state INVALID -j DROP",
192                 (!add ? "A" : "D"),
193                 intIface, extIface);
194         runCmd(IPTABLES_PATH, cmd);
195
196         snprintf(cmd, sizeof(cmd),
197                  "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
198                  (!add ? "A" : "D"),
199                  extIface, intIface);
200         runCmd(IPTABLES_PATH, cmd);
201         return -1;
202     }
203     return 0;
204 }
205
206 // nat disable intface extface
207 //  0    1       2       3       4            5
208 // nat enable intface extface addrcnt nated-ipaddr/prelength
209 int NatController::disableNat(const int argc, char **argv) {
210     char cmd[255];
211     int i;
212     int addrCount = atoi(argv[4]);
213     const char *intIface = argv[2];
214     const char *extIface = argv[3];
215     int tableNumber;
216
217     if (!checkInterface(intIface) || !checkInterface(extIface)) {
218         ALOGE("Invalid interface specified");
219         errno = ENODEV;
220         return -1;
221     }
222
223     if (argc < 5 + addrCount) {
224         ALOGE("Missing Argument");
225         errno = EINVAL;
226         return -1;
227     }
228
229     setForwardRules(false, intIface, extIface);
230
231     tableNumber = secondaryTableCtrl->findTableNumber(extIface);
232     if (tableNumber != -1) {
233         for (i = 0; i < addrCount; i++) {
234             secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
235
236             secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
237         }
238
239         runCmd(IP_PATH, "route flush cache");
240     }
241
242     if (--natCount <= 0) {
243         // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
244         setDefaults();
245     }
246     return 0;
247 }