blob: 90335c239e9d7f3e03c51e07c3482d56d48b6570 [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 }
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700100 ifacePairList.clear();
JP Abgrallbaeccc42013-06-25 09:44:10 -0700101
JP Abgrall0031cea2012-04-17 16:38:23 -0700102 return 0;
103}
104
105int NatController::setDefaults() {
JP Abgrallbaeccc42013-06-25 09:44:10 -0700106 /*
107 * The following only works because:
108 * - the defaultsCommands[].cmd array is padded with NULL, and
109 * - the 1st argc of runCmd() will just be the max for the CommandsAndArgs[].cmd, and
110 * - internally it will be memcopied to an array and terminated with a NULL.
111 */
JP Abgrall4ae80de2013-03-14 20:06:20 -0700112 struct CommandsAndArgs defaultCommands[] = {
JP Abgrallbaeccc42013-06-25 09:44:10 -0700113 {{IPTABLES_PATH, "-F", LOCAL_FORWARD,}, 1},
114 {{IPTABLES_PATH, "-A", LOCAL_FORWARD, "-j", "DROP"}, 1},
115 {{IPTABLES_PATH, "-t", "nat", "-F", LOCAL_NAT_POSTROUTING}, 1},
JP Abgrall4ae80de2013-03-14 20:06:20 -0700116 {{IP_PATH, "rule", "flush"}, 0},
117 {{IP_PATH, "-6", "rule", "flush"}, 0},
118 {{IP_PATH, "rule", "add", "from", "all", "lookup", "default", "prio", "32767"}, 0},
119 {{IP_PATH, "rule", "add", "from", "all", "lookup", "main", "prio", "32766"}, 0},
120 {{IP_PATH, "-6", "rule", "add", "from", "all", "lookup", "default", "prio", "32767"}, 0},
121 {{IP_PATH, "-6", "rule", "add", "from", "all", "lookup", "main", "prio", "32766"}, 0},
122 {{IP_PATH, "route", "flush", "cache"}, 0},
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800123 };
JP Abgrall4ae80de2013-03-14 20:06:20 -0700124 for (unsigned int cmdNum = 0; cmdNum < ARRAY_SIZE(defaultCommands); cmdNum++) {
125 if (runCmd(ARRAY_SIZE(defaultCommands[cmdNum].cmd), defaultCommands[cmdNum].cmd) &&
126 defaultCommands[cmdNum].checkRes) {
127 return -1;
128 }
129 }
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700130
131 natCount = 0;
Kazuhiro Ondo4ab46852012-01-12 16:15:06 -0600132
San Mehat9ff78fb2010-01-19 12:59:15 -0800133 return 0;
134}
135
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700136bool NatController::checkInterface(const char *iface) {
Jaime A Lopez-Sollanod14fd4f2012-01-11 16:29:28 -0800137 if (strlen(iface) > IFNAMSIZ) return false;
San Mehat9ff78fb2010-01-19 12:59:15 -0800138 return true;
139}
140
JP Abgrall4ae80de2013-03-14 20:06:20 -0700141int NatController::routesOp(bool add, const char *intIface, const char *extIface, char **argv, int addrCount) {
142 int tableNumber = secondaryTableCtrl->findTableNumber(extIface);
143 int ret = 0;
144
145 if (tableNumber != -1) {
146 for (int i = 0; i < addrCount; i++) {
147 if (add) {
148 ret |= secondaryTableCtrl->modifyFromRule(tableNumber, ADD, argv[5+i]);
149 ret |= secondaryTableCtrl->modifyLocalRoute(tableNumber, ADD, intIface, argv[5+i]);
150 } else {
151 ret |= secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
152 ret |= secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
153 }
154 }
155 const char *cmd[] = {
156 IP_PATH,
157 "route",
158 "flush",
159 "cache"
160 };
161 runCmd(ARRAY_SIZE(cmd), cmd);
162 }
163 return ret;
164}
165
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700166// 0 1 2 3 4 5
167// nat enable intface extface addrcnt nated-ipaddr/prelength
168int NatController::enableNat(const int argc, char **argv) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700169 int i;
170 int addrCount = atoi(argv[4]);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700171 const char *intIface = argv[2];
172 const char *extIface = argv[3];
173 int tableNumber;
San Mehat9ff78fb2010-01-19 12:59:15 -0800174
JP Abgrallbaeccc42013-06-25 09:44:10 -0700175 ALOGV("enableNat(intIface=<%s>, extIface=<%s>)",intIface, extIface);
176
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700177 if (!checkInterface(intIface) || !checkInterface(extIface)) {
Steve Block5ea0c052012-01-06 19:18:11 +0000178 ALOGE("Invalid interface specified");
San Mehat9ff78fb2010-01-19 12:59:15 -0800179 errno = ENODEV;
180 return -1;
181 }
182
JP Abgrallbaeccc42013-06-25 09:44:10 -0700183 /* Bug: b/9565268. "enableNat wlan0 wlan0". For now we fail until java-land is fixed */
184 if (!strcmp(intIface, extIface)) {
185 ALOGE("Duplicate interface specified: %s %s", intIface, extIface);
186 errno = EINVAL;
187 return -1;
188 }
189
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700190 if (argc < 5 + addrCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000191 ALOGE("Missing Argument");
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700192 errno = EINVAL;
193 return -1;
194 }
JP Abgrall659692a2013-03-14 20:07:17 -0700195 if (routesOp(true, intIface, extIface, argv, addrCount)) {
196 ALOGE("Error setting route rules");
197 routesOp(false, intIface, extIface, argv, addrCount);
198 errno = ENODEV;
199 return -1;
200 }
201
202 // add this if we are the first added nat
203 if (natCount == 0) {
204 const char *cmd[] = {
205 IPTABLES_PATH,
206 "-t",
207 "nat",
208 "-A",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700209 LOCAL_NAT_POSTROUTING,
JP Abgrall659692a2013-03-14 20:07:17 -0700210 "-o",
211 extIface,
212 "-j",
213 "MASQUERADE"
214 };
215 if (runCmd(ARRAY_SIZE(cmd), cmd)) {
216 ALOGE("Error seting postroute rule: iface=%s", extIface);
217 // unwind what's been done, but don't care about success - what more could we do?
218 routesOp(false, intIface, extIface, argv, addrCount);
219 setDefaults();
220 return -1;
221 }
222 }
223
224
225 if (setForwardRules(true, intIface, extIface) != 0) {
Steve Block5ea0c052012-01-06 19:18:11 +0000226 ALOGE("Error setting forward rules");
JP Abgrall4ae80de2013-03-14 20:06:20 -0700227 routesOp(false, intIface, extIface, argv, addrCount);
JP Abgrall659692a2013-03-14 20:07:17 -0700228 if (natCount == 0) {
229 setDefaults();
230 }
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700231 errno = ENODEV;
232 return -1;
233 }
234
JP Abgrall0031cea2012-04-17 16:38:23 -0700235 /* Always make sure the drop rule is at the end */
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800236 const char *cmd1[] = {
237 IPTABLES_PATH,
238 "-D",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700239 LOCAL_FORWARD,
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800240 "-j",
241 "DROP"
242 };
243 runCmd(ARRAY_SIZE(cmd1), cmd1);
244 const char *cmd2[] = {
245 IPTABLES_PATH,
246 "-A",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700247 LOCAL_FORWARD,
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800248 "-j",
249 "DROP"
250 };
251 runCmd(ARRAY_SIZE(cmd2), cmd2);
JP Abgrall0031cea2012-04-17 16:38:23 -0700252
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700253 natCount++;
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700254 return 0;
255}
256
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700257bool NatController::checkTetherCountingRuleExist(const char *pair_name) {
258 std::list<std::string>::iterator it;
259
260 for (it = ifacePairList.begin(); it != ifacePairList.end(); it++) {
261 if (*it == pair_name) {
262 /* We already have this counter */
263 return true;
264 }
265 }
266 return false;
267}
268
JP Abgrallbaeccc42013-06-25 09:44:10 -0700269int NatController::setTetherCountingRules(bool add, const char *intIface, const char *extIface) {
270
271 /* We only ever add tethering quota rules so that they stick. */
272 if (!add) {
273 return 0;
274 }
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700275 char *pair_name, *proc_path;
JP Abgrallbaeccc42013-06-25 09:44:10 -0700276 int quota_fd;
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700277 asprintf(&pair_name, "%s_%s", intIface, extIface);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700278
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700279 if (checkTetherCountingRuleExist(pair_name)) {
280 free(pair_name);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700281 return 0;
282 }
JP Abgrallbaeccc42013-06-25 09:44:10 -0700283 const char *cmd2b[] = {
284 IPTABLES_PATH,
285 "-A",
286 LOCAL_TETHER_COUNTERS_CHAIN,
287 "-i",
288 intIface,
289 "-o",
290 extIface,
JP Abgrallbaeccc42013-06-25 09:44:10 -0700291 "-j",
292 "RETURN"
293 };
294
295 if (runCmd(ARRAY_SIZE(cmd2b), cmd2b) && add) {
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700296 free(pair_name);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700297 return -1;
298 }
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700299 ifacePairList.push_front(pair_name);
300 free(pair_name);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700301
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700302 asprintf(&pair_name, "%s_%s", extIface, intIface);
303 if (checkTetherCountingRuleExist(pair_name)) {
304 free(pair_name);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700305 return 0;
306 }
JP Abgrallbaeccc42013-06-25 09:44:10 -0700307
308 const char *cmd3b[] = {
309 IPTABLES_PATH,
310 "-A",
311 LOCAL_TETHER_COUNTERS_CHAIN,
312 "-i",
313 extIface,
314 "-o",
315 intIface,
JP Abgrallbaeccc42013-06-25 09:44:10 -0700316 "-j",
317 "RETURN"
318 };
319
320 if (runCmd(ARRAY_SIZE(cmd3b), cmd3b) && add) {
321 // unwind what's been done, but don't care about success - what more could we do?
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700322 free(pair_name);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700323 return -1;
324 }
JP Abgrallf3cc83f2013-09-11 20:01:59 -0700325 ifacePairList.push_front(pair_name);
326 free(pair_name);
JP Abgrallbaeccc42013-06-25 09:44:10 -0700327 return 0;
328}
329
330int NatController::setForwardRules(bool add, const char *intIface, const char *extIface) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800331 const char *cmd1[] = {
332 IPTABLES_PATH,
333 add ? "-A" : "-D",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700334 LOCAL_FORWARD,
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800335 "-i",
336 extIface,
337 "-o",
338 intIface,
339 "-m",
340 "state",
341 "--state",
342 "ESTABLISHED,RELATED",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700343 "-g",
344 LOCAL_TETHER_COUNTERS_CHAIN
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800345 };
346 int rc = 0;
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700347
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800348 if (runCmd(ARRAY_SIZE(cmd1), cmd1) && add) {
San Mehat9ff78fb2010-01-19 12:59:15 -0800349 return -1;
350 }
351
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800352 const char *cmd2[] = {
353 IPTABLES_PATH,
354 add ? "-A" : "-D",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700355 LOCAL_FORWARD,
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800356 "-i",
357 intIface,
358 "-o",
359 extIface,
360 "-m",
361 "state",
362 "--state",
363 "INVALID",
364 "-j",
365 "DROP"
366 };
367
368 const char *cmd3[] = {
369 IPTABLES_PATH,
370 add ? "-A" : "-D",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700371 LOCAL_FORWARD,
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800372 "-i",
373 intIface,
374 "-o",
375 extIface,
JP Abgrallbaeccc42013-06-25 09:44:10 -0700376 "-g",
377 LOCAL_TETHER_COUNTERS_CHAIN
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800378 };
379
380 if (runCmd(ARRAY_SIZE(cmd2), cmd2) && add) {
Robert Greenwaltf7bf29c2011-11-01 22:07:28 -0700381 // bail on error, but only if adding
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800382 rc = -1;
383 goto err_invalid_drop;
Robert Greenwaltddb9f6e2011-08-02 13:00:11 -0700384 }
385
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800386 if (runCmd(ARRAY_SIZE(cmd3), cmd3) && add) {
Robert Greenwalt210b9772010-03-25 14:54:45 -0700387 // unwind what's been done, but don't care about success - what more could we do?
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800388 rc = -1;
389 goto err_return;
San Mehat9ff78fb2010-01-19 12:59:15 -0800390 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700391
JP Abgrallbaeccc42013-06-25 09:44:10 -0700392 if (setTetherCountingRules(add, intIface, extIface) && add) {
393 rc = -1;
394 goto err_return;
395 }
396
San Mehat9ff78fb2010-01-19 12:59:15 -0800397 return 0;
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800398
399err_return:
400 cmd2[1] = "-D";
401 runCmd(ARRAY_SIZE(cmd2), cmd2);
402err_invalid_drop:
403 cmd1[1] = "-D";
404 runCmd(ARRAY_SIZE(cmd1), cmd1);
405 return rc;
San Mehat9ff78fb2010-01-19 12:59:15 -0800406}
407
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700408// nat disable intface extface
409// 0 1 2 3 4 5
410// nat enable intface extface addrcnt nated-ipaddr/prelength
411int NatController::disableNat(const int argc, char **argv) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700412 int i;
413 int addrCount = atoi(argv[4]);
414 const char *intIface = argv[2];
415 const char *extIface = argv[3];
416 int tableNumber;
Robert Greenwalt1caafe62010-03-24 15:43:00 -0700417
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700418 if (!checkInterface(intIface) || !checkInterface(extIface)) {
Steve Block5ea0c052012-01-06 19:18:11 +0000419 ALOGE("Invalid interface specified");
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700420 errno = ENODEV;
421 return -1;
422 }
423
424 if (argc < 5 + addrCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000425 ALOGE("Missing Argument");
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700426 errno = EINVAL;
427 return -1;
428 }
429
430 setForwardRules(false, intIface, extIface);
JP Abgrall4ae80de2013-03-14 20:06:20 -0700431 routesOp(false, intIface, extIface, argv, addrCount);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700432 if (--natCount <= 0) {
Kazuhiro Ondo4ab46852012-01-12 16:15:06 -0600433 // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
434 setDefaults();
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700435 }
436 return 0;
San Mehat9ff78fb2010-01-19 12:59:15 -0800437}