• 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 // #define LOG_NDEBUG 0
18 
19 #include <stdlib.h>
20 #include <errno.h>
21 #include <sys/socket.h>
22 #include <sys/stat.h>
23 #include <sys/wait.h>
24 #include <fcntl.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <string.h>
28 #include <cutils/properties.h>
29 
30 #define LOG_TAG "NatController"
31 #include <cutils/log.h>
32 #include <logwrap/logwrap.h>
33 
34 #include "NatController.h"
35 #include "SecondaryTableController.h"
36 #include "NetdConstants.h"
37 
38 const char* NatController::LOCAL_FORWARD = "natctrl_FORWARD";
39 const char* NatController::LOCAL_NAT_POSTROUTING = "natctrl_nat_POSTROUTING";
40 
NatController(SecondaryTableController * ctrl)41 NatController::NatController(SecondaryTableController *ctrl) {
42     secondaryTableCtrl = ctrl;
43 }
44 
~NatController()45 NatController::~NatController() {
46 }
47 
48 struct CommandsAndArgs {
49     /* The array size doesn't really matter as the compiler will barf if too many initializers are specified. */
50     const char *cmd[32];
51     bool checkRes;
52 };
53 
runCmd(int argc,const char ** argv)54 int NatController::runCmd(int argc, const char **argv) {
55     int res;
56 
57     res = android_fork_execvp(argc, (char **)argv, NULL, false, false);
58     ALOGV("runCmd() res=%d", res);
59     return res;
60 }
61 
setupIptablesHooks()62 int NatController::setupIptablesHooks() {
63     setDefaults();
64     return 0;
65 }
66 
setDefaults()67 int NatController::setDefaults() {
68     struct CommandsAndArgs defaultCommands[] = {
69         {{IPTABLES_PATH, "-F", "natctrl_FORWARD",}, 1},
70         {{IPTABLES_PATH, "-A", "natctrl_FORWARD", "-j", "DROP"}, 1},
71         {{IPTABLES_PATH, "-t", "nat", "-F", "natctrl_nat_POSTROUTING"}, 1},
72         {{IP_PATH, "rule", "flush"}, 0},
73         {{IP_PATH, "-6", "rule", "flush"}, 0},
74         {{IP_PATH, "rule", "add", "from", "all", "lookup", "default", "prio", "32767"}, 0},
75         {{IP_PATH, "rule", "add", "from", "all", "lookup", "main", "prio", "32766"}, 0},
76         {{IP_PATH, "-6", "rule", "add", "from", "all", "lookup", "default", "prio", "32767"}, 0},
77         {{IP_PATH, "-6", "rule", "add", "from", "all", "lookup", "main", "prio", "32766"}, 0},
78         {{IP_PATH, "route", "flush", "cache"}, 0},
79     };
80     for (unsigned int cmdNum = 0; cmdNum < ARRAY_SIZE(defaultCommands); cmdNum++) {
81         if (runCmd(ARRAY_SIZE(defaultCommands[cmdNum].cmd), defaultCommands[cmdNum].cmd) &&
82             defaultCommands[cmdNum].checkRes) {
83                 return -1;
84         }
85     }
86 
87     natCount = 0;
88 
89     return 0;
90 }
91 
checkInterface(const char * iface)92 bool NatController::checkInterface(const char *iface) {
93     if (strlen(iface) > IFNAMSIZ) return false;
94     return true;
95 }
96 
routesOp(bool add,const char * intIface,const char * extIface,char ** argv,int addrCount)97 int NatController::routesOp(bool add, const char *intIface, const char *extIface, char **argv, int addrCount) {
98     int tableNumber = secondaryTableCtrl->findTableNumber(extIface);
99     int ret = 0;
100 
101     if (tableNumber != -1) {
102         for (int i = 0; i < addrCount; i++) {
103             if (add) {
104                 ret |= secondaryTableCtrl->modifyFromRule(tableNumber, ADD, argv[5+i]);
105                 ret |= secondaryTableCtrl->modifyLocalRoute(tableNumber, ADD, intIface, argv[5+i]);
106             } else {
107                 ret |= secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
108                 ret |= secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
109             }
110         }
111         const char *cmd[] = {
112                 IP_PATH,
113                 "route",
114                 "flush",
115                 "cache"
116         };
117         runCmd(ARRAY_SIZE(cmd), cmd);
118     }
119     return ret;
120 }
121 
122 //  0    1       2       3       4            5
123 // nat enable intface extface addrcnt nated-ipaddr/prelength
enableNat(const int argc,char ** argv)124 int NatController::enableNat(const int argc, char **argv) {
125     int i;
126     int addrCount = atoi(argv[4]);
127     const char *intIface = argv[2];
128     const char *extIface = argv[3];
129     int tableNumber;
130 
131     if (!checkInterface(intIface) || !checkInterface(extIface)) {
132         ALOGE("Invalid interface specified");
133         errno = ENODEV;
134         return -1;
135     }
136 
137     if (argc < 5 + addrCount) {
138         ALOGE("Missing Argument");
139         errno = EINVAL;
140         return -1;
141     }
142     if (routesOp(true, intIface, extIface, argv, addrCount)) {
143         ALOGE("Error setting route rules");
144         routesOp(false, intIface, extIface, argv, addrCount);
145         errno = ENODEV;
146         return -1;
147     }
148 
149     // add this if we are the first added nat
150     if (natCount == 0) {
151         const char *cmd[] = {
152                 IPTABLES_PATH,
153                 "-t",
154                 "nat",
155                 "-A",
156                 "natctrl_nat_POSTROUTING",
157                 "-o",
158                 extIface,
159                 "-j",
160                 "MASQUERADE"
161         };
162         if (runCmd(ARRAY_SIZE(cmd), cmd)) {
163             ALOGE("Error seting postroute rule: iface=%s", extIface);
164             // unwind what's been done, but don't care about success - what more could we do?
165             routesOp(false, intIface, extIface, argv, addrCount);
166             setDefaults();
167             return -1;
168         }
169     }
170 
171 
172     if (setForwardRules(true, intIface, extIface) != 0) {
173         ALOGE("Error setting forward rules");
174         routesOp(false, intIface, extIface, argv, addrCount);
175         if (natCount == 0) {
176             setDefaults();
177         }
178         errno = ENODEV;
179         return -1;
180     }
181 
182     /* Always make sure the drop rule is at the end */
183     const char *cmd1[] = {
184             IPTABLES_PATH,
185             "-D",
186             "natctrl_FORWARD",
187             "-j",
188             "DROP"
189     };
190     runCmd(ARRAY_SIZE(cmd1), cmd1);
191     const char *cmd2[] = {
192             IPTABLES_PATH,
193             "-A",
194             "natctrl_FORWARD",
195             "-j",
196             "DROP"
197     };
198     runCmd(ARRAY_SIZE(cmd2), cmd2);
199 
200     natCount++;
201     return 0;
202 }
203 
setForwardRules(bool add,const char * intIface,const char * extIface)204 int NatController::setForwardRules(bool add, const char *intIface, const char * extIface) {
205     const char *cmd1[] = {
206             IPTABLES_PATH,
207             add ? "-A" : "-D",
208             "natctrl_FORWARD",
209             "-i",
210             extIface,
211             "-o",
212             intIface,
213             "-m",
214             "state",
215             "--state",
216             "ESTABLISHED,RELATED",
217             "-j",
218             "RETURN"
219     };
220     int rc = 0;
221 
222     if (runCmd(ARRAY_SIZE(cmd1), cmd1) && add) {
223         return -1;
224     }
225 
226     const char *cmd2[] = {
227             IPTABLES_PATH,
228             add ? "-A" : "-D",
229             "natctrl_FORWARD",
230             "-i",
231             intIface,
232             "-o",
233             extIface,
234             "-m",
235             "state",
236             "--state",
237             "INVALID",
238             "-j",
239             "DROP"
240     };
241 
242     const char *cmd3[] = {
243             IPTABLES_PATH,
244             add ? "-A" : "-D",
245             "natctrl_FORWARD",
246             "-i",
247             intIface,
248             "-o",
249             extIface,
250             "-j",
251             "RETURN"
252     };
253 
254     if (runCmd(ARRAY_SIZE(cmd2), cmd2) && add) {
255         // bail on error, but only if adding
256         rc = -1;
257         goto err_invalid_drop;
258     }
259 
260     if (runCmd(ARRAY_SIZE(cmd3), cmd3) && add) {
261         // unwind what's been done, but don't care about success - what more could we do?
262         rc = -1;
263         goto err_return;
264     }
265 
266     return 0;
267 
268 err_return:
269     cmd2[1] = "-D";
270     runCmd(ARRAY_SIZE(cmd2), cmd2);
271 err_invalid_drop:
272     cmd1[1] = "-D";
273     runCmd(ARRAY_SIZE(cmd1), cmd1);
274     return rc;
275 }
276 
277 // nat disable intface extface
278 //  0    1       2       3       4            5
279 // nat enable intface extface addrcnt nated-ipaddr/prelength
disableNat(const int argc,char ** argv)280 int NatController::disableNat(const int argc, char **argv) {
281     int i;
282     int addrCount = atoi(argv[4]);
283     const char *intIface = argv[2];
284     const char *extIface = argv[3];
285     int tableNumber;
286 
287     if (!checkInterface(intIface) || !checkInterface(extIface)) {
288         ALOGE("Invalid interface specified");
289         errno = ENODEV;
290         return -1;
291     }
292 
293     if (argc < 5 + addrCount) {
294         ALOGE("Missing Argument");
295         errno = EINVAL;
296         return -1;
297     }
298 
299     setForwardRules(false, intIface, extIface);
300     routesOp(false, intIface, extIface, argv, addrCount);
301     if (--natCount <= 0) {
302         // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
303         setDefaults();
304     }
305     return 0;
306 }
307