blob: b2a0e64134ec4aa7cafcb62c24043134f1cb44a3 [file] [log] [blame]
San Mehat9ff78fb2010-01-19 12:59:15 -08001/*
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
JP Abgrallbaeccc42013-06-25 09:44:10 -070017#define LOG_NDEBUG 0
JP Abgrall0031cea2012-04-17 16:38:23 -070018
San Mehat9ff78fb2010-01-19 12:59:15 -080019#include <stdlib.h>
20#include <errno.h>
21#include <sys/socket.h>
22#include <sys/stat.h>
Rom Lemarchand001f0a42013-01-31 12:41:03 -080023#include <sys/wait.h>
San Mehat9ff78fb2010-01-19 12:59:15 -080024#include <fcntl.h>
25#include <netinet/in.h>
26#include <arpa/inet.h>
Olivier Baillyff2c0d82010-11-17 11:45:07 -080027#include <string.h>
John Michelauac208602011-05-27 22:07:20 -050028#include <cutils/properties.h>
San Mehat9ff78fb2010-01-19 12:59:15 -080029
30#define LOG_TAG "NatController"
31#include <cutils/log.h>
Rom Lemarchand001f0a42013-01-31 12:41:03 -080032#include <logwrap/logwrap.h>
San Mehat9ff78fb2010-01-19 12:59:15 -080033
34#include "NatController.h"
Robert Greenwaltfc97b822011-11-02 16:48:36 -070035#include "SecondaryTableController.h"
Robert Greenwaltc4621772012-01-31 12:46:45 -080036#include "NetdConstants.h"
San Mehat9ff78fb2010-01-19 12:59:15 -080037
Jeff Sharkey8e188ed2012-07-12 18:32:03 -070038const char* NatController::LOCAL_FORWARD = "natctrl_FORWARD";
39const char* NatController::LOCAL_NAT_POSTROUTING = "natctrl_nat_POSTROUTING";
JP Abgrallbaeccc42013-06-25 09:44:10 -070040const char* NatController::LOCAL_TETHER_COUNTERS_CHAIN = "natctrl_tether_counters";
Jeff Sharkey8e188ed2012-07-12 18:32:03 -070041
Robert Greenwaltfc97b822011-11-02 16:48:36 -070042NatController::NatController(SecondaryTableController *ctrl) {
43 secondaryTableCtrl = ctrl;
San Mehat9ff78fb2010-01-19 12:59:15 -080044}
45
46NatController::~NatController() {
47}
48
JP Abgrall4ae80de2013-03-14 20:06:20 -070049struct CommandsAndArgs {
50 /* The array size doesn't really matter as the compiler will barf if too many initializers are specified. */
51 const char *cmd[32];
52 bool checkRes;
53};
54
Rom Lemarchand001f0a42013-01-31 12:41:03 -080055int NatController::runCmd(int argc, const char **argv) {
JP Abgrall11b4e9b2011-08-11 15:34:49 -070056 int res;
San Mehat9ff78fb2010-01-19 12:59:15 -080057
Rom Lemarchand001f0a42013-01-31 12:41:03 -080058 res = android_fork_execvp(argc, (char **)argv, NULL, false, false);
JP Abgrallbaeccc42013-06-25 09:44:10 -070059
60#if !LOG_NDEBUG
61 std::string full_cmd = argv[0];
62 argc--; argv++;
63 /*
64 * HACK: Sometimes runCmd() is called with a ridcously large value (32)
65 * and it works because the argv[] contains a NULL after the last
66 * true argv. So here we use the NULL argv[] to terminate when the argc
67 * is horribly wrong, and argc for the normal cases.
68 */
69 for (; argc && argv[0]; argc--, argv++) {
70 full_cmd += " ";
71 full_cmd += argv[0];
72 }
73 ALOGV("runCmd(%s) res=%d", full_cmd.c_str(), res);
74#endif
JP Abgrall11b4e9b2011-08-11 15:34:49 -070075 return res;
San Mehat9ff78fb2010-01-19 12:59:15 -080076}
77
JP Abgrall0031cea2012-04-17 16:38:23 -070078int NatController::setupIptablesHooks() {
JP Abgrallbaeccc42013-06-25 09:44:10 -070079 int res;
80 res = setDefaults();
81 if (res < 0) {
82 return res;
83 }
84
85 struct CommandsAndArgs defaultCommands[] = {
86 /*
87 * Chain for tethering counters.
88 * This chain is reached via --goto, and then RETURNS.
89 */
90 {{IPTABLES_PATH, "-F", LOCAL_TETHER_COUNTERS_CHAIN,}, 0},
91 {{IPTABLES_PATH, "-X", LOCAL_TETHER_COUNTERS_CHAIN,}, 0},
92 {{IPTABLES_PATH, "-N", LOCAL_TETHER_COUNTERS_CHAIN,}, 1},
93 };
94 for (unsigned int cmdNum = 0; cmdNum < ARRAY_SIZE(defaultCommands); cmdNum++) {
95 if (runCmd(ARRAY_SIZE(defaultCommands[cmdNum].cmd), defaultCommands[cmdNum].cmd) &&
96 defaultCommands[cmdNum].checkRes) {
97 return -1;
98 }
99 }
100
JP Abgrall0031cea2012-04-17 16:38:23 -0700101 return 0;
102}
103
104int NatController::setDefaults() {
JP Abgrallbaeccc42013-06-25 09:44:10 -0700105 /*
106 * The following only works because:
107 * - the defaultsCommands[].cmd array is padded with NULL, and
108 * - the 1st argc of runCmd() will just be the max for the CommandsAndArgs[].cmd, and
109 * - internally it will be memcopied to an array and terminated with a NULL.
110 */
JP Abgrall4ae80de2013-03-14 20:06:20 -0700111 struct CommandsAndArgs defaultCommands[] = {
JP Abgrallbaeccc42013-06-25 09:44:10 -0700112 {{IPTABLES_PATH, "-F", LOCAL_FORWARD,}, 1},
113 {{IPTABLES_PATH, "-A", LOCAL_FORWARD, "-j", "DROP"}, 1},
114 {{IPTABLES_PATH, "-t", "nat", "-F", LOCAL_NAT_POSTROUTING}, 1},
JP Abgrall4ae80de2013-03-14 20:06:20 -0700115 {{IP_PATH, "rule", "flush"}, 0},
116 {{IP_PATH, "-6", "rule", "flush"}, 0},
117 {{IP_PATH, "rule", "add", "from", "all", "lookup", "default", "prio", "32767"}, 0},
118 {{IP_PATH, "rule", "add", "from", "all", "lookup", "main", "prio", "32766"}, 0},
119 {{IP_PATH, "-6", "rule", "add", "from", "all", "lookup", "default", "prio", "32767"}, 0},
120 {{IP_PATH, "-6", "rule", "add", "from", "all", "lookup", "main", "prio", "32766"}, 0},
121 {{IP_PATH, "route", "flush", "cache"}, 0},
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800122 };
JP Abgrall4ae80de2013-03-14 20:06:20 -0700123 for (unsigned int cmdNum = 0; cmdNum < ARRAY_SIZE(defaultCommands); cmdNum++) {
124 if (runCmd(ARRAY_SIZE(defaultCommands[cmdNum].cmd), defaultCommands[cmdNum].cmd) &&
125 defaultCommands[cmdNum].checkRes) {
126 return -1;
127 }
128 }
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700129
130 natCount = 0;
Kazuhiro Ondo4ab46852012-01-12 16:15:06 -0600131
San Mehat9ff78fb2010-01-19 12:59:15 -0800132 return 0;
133}
134
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700135bool NatController::checkInterface(const char *iface) {
Jaime A Lopez-Sollanod14fd4f2012-01-11 16:29:28 -0800136 if (strlen(iface) > IFNAMSIZ) return false;
San Mehat9ff78fb2010-01-19 12:59:15 -0800137 return true;
138}
139
JP Abgrall4ae80de2013-03-14 20:06:20 -0700140int NatController::routesOp(bool add, const char *intIface, const char *extIface, char **argv, int addrCount) {
141 int tableNumber = secondaryTableCtrl->findTableNumber(extIface);
142 int ret = 0;
143
144 if (tableNumber != -1) {
145 for (int i = 0; i < addrCount; i++) {
146 if (add) {
147 ret |= secondaryTableCtrl->modifyFromRule(tableNumber, ADD, argv[5+i]);
148 ret |= secondaryTableCtrl->modifyLocalRoute(tableNumber, ADD, intIface, argv[5+i]);
149 } else {
150 ret |= secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
151 ret |= secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
152 }
153 }
154 const char *cmd[] = {
155 IP_PATH,
156 "route",
157 "flush",
158 "cache"
159 };
160 runCmd(ARRAY_SIZE(cmd), cmd);
161 }
162 return ret;
163}
164
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700165// 0 1 2 3 4 5
166// nat enable intface extface addrcnt nated-ipaddr/prelength
167int NatController::enableNat(const int argc, char **argv) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700168 int i;
169 int addrCount = atoi(argv[4]);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700170 const char *intIface = argv[2];
171 const char *extIface = argv[3];
172 int tableNumber;
San Mehat9ff78fb2010-01-19 12:59:15 -0800173
JP Abgrallbaeccc42013-06-25 09:44:10 -0700174 ALOGV("enableNat(intIface=<%s>, extIface=<%s>)",intIface, extIface);
175
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700176 if (!checkInterface(intIface) || !checkInterface(extIface)) {
Steve Block5ea0c052012-01-06 19:18:11 +0000177 ALOGE("Invalid interface specified");
San Mehat9ff78fb2010-01-19 12:59:15 -0800178 errno = ENODEV;
179 return -1;
180 }
181
JP Abgrallbaeccc42013-06-25 09:44:10 -0700182 /* Bug: b/9565268. "enableNat wlan0 wlan0". For now we fail until java-land is fixed */
183 if (!strcmp(intIface, extIface)) {
184 ALOGE("Duplicate interface specified: %s %s", intIface, extIface);
185 errno = EINVAL;
186 return -1;
187 }
188
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700189 if (argc < 5 + addrCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000190 ALOGE("Missing Argument");
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700191 errno = EINVAL;
192 return -1;
193 }
JP Abgrall659692a2013-03-14 20:07:17 -0700194 if (routesOp(true, intIface, extIface, argv, addrCount)) {
195 ALOGE("Error setting route rules");
196 routesOp(false, intIface, extIface, argv, addrCount);
197 errno = ENODEV;
198 return -1;
199 }
200
201 // add this if we are the first added nat
202 if (natCount == 0) {
203 const char *cmd[] = {
204 IPTABLES_PATH,
205 "-t",
206 "nat",
207 "-A",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700208 LOCAL_NAT_POSTROUTING,
JP Abgrall659692a2013-03-14 20:07:17 -0700209 "-o",
210 extIface,
211 "-j",
212 "MASQUERADE"
213 };
214 if (runCmd(ARRAY_SIZE(cmd), cmd)) {
215 ALOGE("Error seting postroute rule: iface=%s", extIface);
216 // unwind what's been done, but don't care about success - what more could we do?
217 routesOp(false, intIface, extIface, argv, addrCount);
218 setDefaults();
219 return -1;
220 }
221 }
222
223
224 if (setForwardRules(true, intIface, extIface) != 0) {
Steve Block5ea0c052012-01-06 19:18:11 +0000225 ALOGE("Error setting forward rules");
JP Abgrall4ae80de2013-03-14 20:06:20 -0700226 routesOp(false, intIface, extIface, argv, addrCount);
JP Abgrall659692a2013-03-14 20:07:17 -0700227 if (natCount == 0) {
228 setDefaults();
229 }
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700230 errno = ENODEV;
231 return -1;
232 }
233
JP Abgrall0031cea2012-04-17 16:38:23 -0700234 /* Always make sure the drop rule is at the end */
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800235 const char *cmd1[] = {
236 IPTABLES_PATH,
237 "-D",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700238 LOCAL_FORWARD,
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800239 "-j",
240 "DROP"
241 };
242 runCmd(ARRAY_SIZE(cmd1), cmd1);
243 const char *cmd2[] = {
244 IPTABLES_PATH,
245 "-A",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700246 LOCAL_FORWARD,
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800247 "-j",
248 "DROP"
249 };
250 runCmd(ARRAY_SIZE(cmd2), cmd2);
JP Abgrall0031cea2012-04-17 16:38:23 -0700251
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700252 natCount++;
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700253 return 0;
254}
255
JP Abgrallbaeccc42013-06-25 09:44:10 -0700256int NatController::setTetherCountingRules(bool add, const char *intIface, const char *extIface) {
257
258 /* We only ever add tethering quota rules so that they stick. */
259 if (!add) {
260 return 0;
261 }
262 char *quota_name, *proc_path;
263 int quota_fd;
264 asprintf(&quota_name, "%s_%s", intIface, extIface);
265
266 asprintf(&proc_path, "/proc/net/xt_quota/%s", quota_name);
267 quota_fd = open(proc_path, O_RDONLY);
268 if (quota_fd >= 0) {
269 /* quota for iface pair already exists */
270 free(proc_path);
271 free(quota_name);
272 return 0;
273 }
274 close(quota_fd);
275 free(proc_path);
276
277 const char *cmd2b[] = {
278 IPTABLES_PATH,
279 "-A",
280 LOCAL_TETHER_COUNTERS_CHAIN,
281 "-i",
282 intIface,
283 "-o",
284 extIface,
285 "-m",
286 "quota2",
287 "--name",
288 quota_name,
289 "--grow",
290 "-j",
291 "RETURN"
292 };
293
294 if (runCmd(ARRAY_SIZE(cmd2b), cmd2b) && add) {
295 free(quota_name);
296 return -1;
297 }
298 free(quota_name);
299
300 asprintf(&quota_name, "%s_%s", extIface, intIface);
301 asprintf(&proc_path, "/proc/net/xt_quota/%s", quota_name);
302 quota_fd = open(proc_path, O_RDONLY);
303 if (quota_fd >= 0) {
304 /* quota for iface pair already exists */
305 free(proc_path);
306 free(quota_name);
307 return 0;
308 }
309 close(quota_fd);
310 free(proc_path);
311
312 const char *cmd3b[] = {
313 IPTABLES_PATH,
314 "-A",
315 LOCAL_TETHER_COUNTERS_CHAIN,
316 "-i",
317 extIface,
318 "-o",
319 intIface,
320 "-m",
321 "quota2",
322 "--name",
323 quota_name,
324 "--grow",
325 "-j",
326 "RETURN"
327 };
328
329 if (runCmd(ARRAY_SIZE(cmd3b), cmd3b) && add) {
330 // unwind what's been done, but don't care about success - what more could we do?
331 free(quota_name);
332 return -1;
333 }
334 free(quota_name);
335 return 0;
336}
337
338int NatController::setForwardRules(bool add, const char *intIface, const char *extIface) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800339 const char *cmd1[] = {
340 IPTABLES_PATH,
341 add ? "-A" : "-D",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700342 LOCAL_FORWARD,
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800343 "-i",
344 extIface,
345 "-o",
346 intIface,
347 "-m",
348 "state",
349 "--state",
350 "ESTABLISHED,RELATED",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700351 "-g",
352 LOCAL_TETHER_COUNTERS_CHAIN
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800353 };
354 int rc = 0;
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700355
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800356 if (runCmd(ARRAY_SIZE(cmd1), cmd1) && add) {
San Mehat9ff78fb2010-01-19 12:59:15 -0800357 return -1;
358 }
359
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800360 const char *cmd2[] = {
361 IPTABLES_PATH,
362 add ? "-A" : "-D",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700363 LOCAL_FORWARD,
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800364 "-i",
365 intIface,
366 "-o",
367 extIface,
368 "-m",
369 "state",
370 "--state",
371 "INVALID",
372 "-j",
373 "DROP"
374 };
375
376 const char *cmd3[] = {
377 IPTABLES_PATH,
378 add ? "-A" : "-D",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700379 LOCAL_FORWARD,
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800380 "-i",
381 intIface,
382 "-o",
383 extIface,
JP Abgrallbaeccc42013-06-25 09:44:10 -0700384 "-g",
385 LOCAL_TETHER_COUNTERS_CHAIN
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800386 };
387
388 if (runCmd(ARRAY_SIZE(cmd2), cmd2) && add) {
Robert Greenwaltf7bf29c2011-11-01 22:07:28 -0700389 // bail on error, but only if adding
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800390 rc = -1;
391 goto err_invalid_drop;
Robert Greenwaltddb9f6e2011-08-02 13:00:11 -0700392 }
393
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800394 if (runCmd(ARRAY_SIZE(cmd3), cmd3) && add) {
Robert Greenwalt210b9772010-03-25 14:54:45 -0700395 // unwind what's been done, but don't care about success - what more could we do?
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800396 rc = -1;
397 goto err_return;
San Mehat9ff78fb2010-01-19 12:59:15 -0800398 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700399
JP Abgrallbaeccc42013-06-25 09:44:10 -0700400 if (setTetherCountingRules(add, intIface, extIface) && add) {
401 rc = -1;
402 goto err_return;
403 }
404
San Mehat9ff78fb2010-01-19 12:59:15 -0800405 return 0;
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800406
407err_return:
408 cmd2[1] = "-D";
409 runCmd(ARRAY_SIZE(cmd2), cmd2);
410err_invalid_drop:
411 cmd1[1] = "-D";
412 runCmd(ARRAY_SIZE(cmd1), cmd1);
413 return rc;
San Mehat9ff78fb2010-01-19 12:59:15 -0800414}
415
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700416// nat disable intface extface
417// 0 1 2 3 4 5
418// nat enable intface extface addrcnt nated-ipaddr/prelength
419int NatController::disableNat(const int argc, char **argv) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700420 int i;
421 int addrCount = atoi(argv[4]);
422 const char *intIface = argv[2];
423 const char *extIface = argv[3];
424 int tableNumber;
Robert Greenwalt1caafe62010-03-24 15:43:00 -0700425
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700426 if (!checkInterface(intIface) || !checkInterface(extIface)) {
Steve Block5ea0c052012-01-06 19:18:11 +0000427 ALOGE("Invalid interface specified");
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700428 errno = ENODEV;
429 return -1;
430 }
431
432 if (argc < 5 + addrCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000433 ALOGE("Missing Argument");
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700434 errno = EINVAL;
435 return -1;
436 }
437
438 setForwardRules(false, intIface, extIface);
JP Abgrall4ae80de2013-03-14 20:06:20 -0700439 routesOp(false, intIface, extIface, argv, addrCount);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700440 if (--natCount <= 0) {
Kazuhiro Ondo4ab46852012-01-12 16:15:06 -0600441 // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
442 setDefaults();
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700443 }
444 return 0;
San Mehat9ff78fb2010-01-19 12:59:15 -0800445}