blob: dd5316a59a681e9c0e8f7a067c851f288867dccf [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"
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050035#include "NetworkController.h"
Robert Greenwaltfc97b822011-11-02 16:48:36 -070036#include "SecondaryTableController.h"
Robert Greenwaltc4621772012-01-31 12:46:45 -080037#include "NetdConstants.h"
San Mehat9ff78fb2010-01-19 12:59:15 -080038
Jeff Sharkey8e188ed2012-07-12 18:32:03 -070039const char* NatController::LOCAL_FORWARD = "natctrl_FORWARD";
40const char* NatController::LOCAL_NAT_POSTROUTING = "natctrl_nat_POSTROUTING";
JP Abgrallbaeccc42013-06-25 09:44:10 -070041const char* NatController::LOCAL_TETHER_COUNTERS_CHAIN = "natctrl_tether_counters";
Jeff Sharkey8e188ed2012-07-12 18:32:03 -070042
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -050043NatController::NatController(SecondaryTableController *table_ctrl, NetworkController* net_ctrl) :
44 mSecondaryTableCtrl(table_ctrl), mNetCtrl(net_ctrl) {
San Mehat9ff78fb2010-01-19 12:59:15 -080045}
46
47NatController::~NatController() {
48}
49
JP Abgrall4ae80de2013-03-14 20:06:20 -070050struct CommandsAndArgs {
51 /* The array size doesn't really matter as the compiler will barf if too many initializers are specified. */
52 const char *cmd[32];
53 bool checkRes;
54};
55
Rom Lemarchand001f0a42013-01-31 12:41:03 -080056int NatController::runCmd(int argc, const char **argv) {
JP Abgrall11b4e9b2011-08-11 15:34:49 -070057 int res;
San Mehat9ff78fb2010-01-19 12:59:15 -080058
Rom Lemarchand001f0a42013-01-31 12:41:03 -080059 res = android_fork_execvp(argc, (char **)argv, NULL, false, false);
JP Abgrallbaeccc42013-06-25 09:44:10 -070060
61#if !LOG_NDEBUG
62 std::string full_cmd = argv[0];
63 argc--; argv++;
64 /*
65 * HACK: Sometimes runCmd() is called with a ridcously large value (32)
66 * and it works because the argv[] contains a NULL after the last
67 * true argv. So here we use the NULL argv[] to terminate when the argc
68 * is horribly wrong, and argc for the normal cases.
69 */
70 for (; argc && argv[0]; argc--, argv++) {
71 full_cmd += " ";
72 full_cmd += argv[0];
73 }
74 ALOGV("runCmd(%s) res=%d", full_cmd.c_str(), res);
75#endif
JP Abgrall11b4e9b2011-08-11 15:34:49 -070076 return res;
San Mehat9ff78fb2010-01-19 12:59:15 -080077}
78
JP Abgrall0031cea2012-04-17 16:38:23 -070079int NatController::setupIptablesHooks() {
JP Abgrallbaeccc42013-06-25 09:44:10 -070080 int res;
81 res = setDefaults();
82 if (res < 0) {
83 return res;
84 }
85
86 struct CommandsAndArgs defaultCommands[] = {
87 /*
88 * Chain for tethering counters.
89 * This chain is reached via --goto, and then RETURNS.
90 */
91 {{IPTABLES_PATH, "-F", LOCAL_TETHER_COUNTERS_CHAIN,}, 0},
92 {{IPTABLES_PATH, "-X", LOCAL_TETHER_COUNTERS_CHAIN,}, 0},
93 {{IPTABLES_PATH, "-N", LOCAL_TETHER_COUNTERS_CHAIN,}, 1},
94 };
95 for (unsigned int cmdNum = 0; cmdNum < ARRAY_SIZE(defaultCommands); cmdNum++) {
96 if (runCmd(ARRAY_SIZE(defaultCommands[cmdNum].cmd), defaultCommands[cmdNum].cmd) &&
97 defaultCommands[cmdNum].checkRes) {
98 return -1;
99 }
100 }
101
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) {
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500142 unsigned netId = mNetCtrl->getNetworkId(extIface);
JP Abgrall4ae80de2013-03-14 20:06:20 -0700143 int ret = 0;
144
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500145 for (int i = 0; i < addrCount; i++) {
146 if (add) {
147 ret |= mSecondaryTableCtrl->modifyFromRule(netId, ADD, argv[5+i]);
148 ret |= mSecondaryTableCtrl->modifyLocalRoute(netId, ADD, intIface, argv[5+i]);
149 } else {
150 ret |= mSecondaryTableCtrl->modifyLocalRoute(netId, DEL, intIface, argv[5+i]);
151 ret |= mSecondaryTableCtrl->modifyFromRule(netId, DEL, argv[5+i]);
JP Abgrall4ae80de2013-03-14 20:06:20 -0700152 }
JP Abgrall4ae80de2013-03-14 20:06:20 -0700153 }
Szymon Jakubczaka0efaec2014-02-14 17:09:43 -0500154 const char *cmd[] = {
155 IP_PATH,
156 "route",
157 "flush",
158 "cache"
159 };
160 runCmd(ARRAY_SIZE(cmd), cmd);
JP Abgrall4ae80de2013-03-14 20:06:20 -0700161 return ret;
162}
163
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700164// 0 1 2 3 4 5
165// nat enable intface extface addrcnt nated-ipaddr/prelength
166int NatController::enableNat(const int argc, char **argv) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700167 int i;
168 int addrCount = atoi(argv[4]);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700169 const char *intIface = argv[2];
170 const char *extIface = argv[3];
171 int tableNumber;
San Mehat9ff78fb2010-01-19 12:59:15 -0800172
JP Abgrallbaeccc42013-06-25 09:44:10 -0700173 ALOGV("enableNat(intIface=<%s>, extIface=<%s>)",intIface, extIface);
174
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700175 if (!checkInterface(intIface) || !checkInterface(extIface)) {
Steve Block5ea0c052012-01-06 19:18:11 +0000176 ALOGE("Invalid interface specified");
San Mehat9ff78fb2010-01-19 12:59:15 -0800177 errno = ENODEV;
178 return -1;
179 }
180
JP Abgrallbaeccc42013-06-25 09:44:10 -0700181 /* Bug: b/9565268. "enableNat wlan0 wlan0". For now we fail until java-land is fixed */
182 if (!strcmp(intIface, extIface)) {
183 ALOGE("Duplicate interface specified: %s %s", intIface, extIface);
184 errno = EINVAL;
185 return -1;
186 }
187
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700188 if (argc < 5 + addrCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000189 ALOGE("Missing Argument");
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700190 errno = EINVAL;
191 return -1;
192 }
JP Abgrall659692a2013-03-14 20:07:17 -0700193 if (routesOp(true, intIface, extIface, argv, addrCount)) {
194 ALOGE("Error setting route rules");
195 routesOp(false, intIface, extIface, argv, addrCount);
196 errno = ENODEV;
197 return -1;
198 }
199
200 // add this if we are the first added nat
201 if (natCount == 0) {
202 const char *cmd[] = {
203 IPTABLES_PATH,
204 "-t",
205 "nat",
206 "-A",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700207 LOCAL_NAT_POSTROUTING,
JP Abgrall659692a2013-03-14 20:07:17 -0700208 "-o",
209 extIface,
210 "-j",
211 "MASQUERADE"
212 };
213 if (runCmd(ARRAY_SIZE(cmd), cmd)) {
214 ALOGE("Error seting postroute rule: iface=%s", extIface);
215 // unwind what's been done, but don't care about success - what more could we do?
216 routesOp(false, intIface, extIface, argv, addrCount);
217 setDefaults();
218 return -1;
219 }
220 }
221
222
223 if (setForwardRules(true, intIface, extIface) != 0) {
Steve Block5ea0c052012-01-06 19:18:11 +0000224 ALOGE("Error setting forward rules");
JP Abgrall4ae80de2013-03-14 20:06:20 -0700225 routesOp(false, intIface, extIface, argv, addrCount);
JP Abgrall659692a2013-03-14 20:07:17 -0700226 if (natCount == 0) {
227 setDefaults();
228 }
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700229 errno = ENODEV;
230 return -1;
231 }
232
JP Abgrall0031cea2012-04-17 16:38:23 -0700233 /* Always make sure the drop rule is at the end */
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800234 const char *cmd1[] = {
235 IPTABLES_PATH,
236 "-D",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700237 LOCAL_FORWARD,
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800238 "-j",
239 "DROP"
240 };
241 runCmd(ARRAY_SIZE(cmd1), cmd1);
242 const char *cmd2[] = {
243 IPTABLES_PATH,
244 "-A",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700245 LOCAL_FORWARD,
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800246 "-j",
247 "DROP"
248 };
249 runCmd(ARRAY_SIZE(cmd2), cmd2);
JP Abgrall0031cea2012-04-17 16:38:23 -0700250
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700251 natCount++;
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700252 return 0;
253}
254
JP Abgrallbaeccc42013-06-25 09:44:10 -0700255int NatController::setTetherCountingRules(bool add, const char *intIface, const char *extIface) {
256
257 /* We only ever add tethering quota rules so that they stick. */
258 if (!add) {
259 return 0;
260 }
261 char *quota_name, *proc_path;
262 int quota_fd;
263 asprintf(&quota_name, "%s_%s", intIface, extIface);
264
265 asprintf(&proc_path, "/proc/net/xt_quota/%s", quota_name);
266 quota_fd = open(proc_path, O_RDONLY);
267 if (quota_fd >= 0) {
268 /* quota for iface pair already exists */
269 free(proc_path);
270 free(quota_name);
271 return 0;
272 }
273 close(quota_fd);
274 free(proc_path);
275
276 const char *cmd2b[] = {
277 IPTABLES_PATH,
278 "-A",
279 LOCAL_TETHER_COUNTERS_CHAIN,
280 "-i",
281 intIface,
282 "-o",
283 extIface,
284 "-m",
285 "quota2",
286 "--name",
287 quota_name,
288 "--grow",
289 "-j",
290 "RETURN"
291 };
292
293 if (runCmd(ARRAY_SIZE(cmd2b), cmd2b) && add) {
294 free(quota_name);
295 return -1;
296 }
297 free(quota_name);
298
299 asprintf(&quota_name, "%s_%s", extIface, intIface);
300 asprintf(&proc_path, "/proc/net/xt_quota/%s", quota_name);
301 quota_fd = open(proc_path, O_RDONLY);
302 if (quota_fd >= 0) {
303 /* quota for iface pair already exists */
304 free(proc_path);
305 free(quota_name);
306 return 0;
307 }
308 close(quota_fd);
309 free(proc_path);
310
311 const char *cmd3b[] = {
312 IPTABLES_PATH,
313 "-A",
314 LOCAL_TETHER_COUNTERS_CHAIN,
315 "-i",
316 extIface,
317 "-o",
318 intIface,
319 "-m",
320 "quota2",
321 "--name",
322 quota_name,
323 "--grow",
324 "-j",
325 "RETURN"
326 };
327
328 if (runCmd(ARRAY_SIZE(cmd3b), cmd3b) && add) {
329 // unwind what's been done, but don't care about success - what more could we do?
330 free(quota_name);
331 return -1;
332 }
333 free(quota_name);
334 return 0;
335}
336
337int NatController::setForwardRules(bool add, const char *intIface, const char *extIface) {
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800338 const char *cmd1[] = {
339 IPTABLES_PATH,
340 add ? "-A" : "-D",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700341 LOCAL_FORWARD,
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800342 "-i",
343 extIface,
344 "-o",
345 intIface,
346 "-m",
347 "state",
348 "--state",
349 "ESTABLISHED,RELATED",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700350 "-g",
351 LOCAL_TETHER_COUNTERS_CHAIN
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800352 };
353 int rc = 0;
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700354
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800355 if (runCmd(ARRAY_SIZE(cmd1), cmd1) && add) {
San Mehat9ff78fb2010-01-19 12:59:15 -0800356 return -1;
357 }
358
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800359 const char *cmd2[] = {
360 IPTABLES_PATH,
361 add ? "-A" : "-D",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700362 LOCAL_FORWARD,
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800363 "-i",
364 intIface,
365 "-o",
366 extIface,
367 "-m",
368 "state",
369 "--state",
370 "INVALID",
371 "-j",
372 "DROP"
373 };
374
375 const char *cmd3[] = {
376 IPTABLES_PATH,
377 add ? "-A" : "-D",
JP Abgrallbaeccc42013-06-25 09:44:10 -0700378 LOCAL_FORWARD,
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800379 "-i",
380 intIface,
381 "-o",
382 extIface,
JP Abgrallbaeccc42013-06-25 09:44:10 -0700383 "-g",
384 LOCAL_TETHER_COUNTERS_CHAIN
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800385 };
386
387 if (runCmd(ARRAY_SIZE(cmd2), cmd2) && add) {
Robert Greenwaltf7bf29c2011-11-01 22:07:28 -0700388 // bail on error, but only if adding
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800389 rc = -1;
390 goto err_invalid_drop;
Robert Greenwaltddb9f6e2011-08-02 13:00:11 -0700391 }
392
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800393 if (runCmd(ARRAY_SIZE(cmd3), cmd3) && add) {
Robert Greenwalt210b9772010-03-25 14:54:45 -0700394 // unwind what's been done, but don't care about success - what more could we do?
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800395 rc = -1;
396 goto err_return;
San Mehat9ff78fb2010-01-19 12:59:15 -0800397 }
JP Abgrall0031cea2012-04-17 16:38:23 -0700398
JP Abgrallbaeccc42013-06-25 09:44:10 -0700399 if (setTetherCountingRules(add, intIface, extIface) && add) {
400 rc = -1;
401 goto err_return;
402 }
403
San Mehat9ff78fb2010-01-19 12:59:15 -0800404 return 0;
Rom Lemarchand001f0a42013-01-31 12:41:03 -0800405
406err_return:
407 cmd2[1] = "-D";
408 runCmd(ARRAY_SIZE(cmd2), cmd2);
409err_invalid_drop:
410 cmd1[1] = "-D";
411 runCmd(ARRAY_SIZE(cmd1), cmd1);
412 return rc;
San Mehat9ff78fb2010-01-19 12:59:15 -0800413}
414
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700415// nat disable intface extface
416// 0 1 2 3 4 5
417// nat enable intface extface addrcnt nated-ipaddr/prelength
418int NatController::disableNat(const int argc, char **argv) {
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700419 int i;
420 int addrCount = atoi(argv[4]);
421 const char *intIface = argv[2];
422 const char *extIface = argv[3];
423 int tableNumber;
Robert Greenwalt1caafe62010-03-24 15:43:00 -0700424
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700425 if (!checkInterface(intIface) || !checkInterface(extIface)) {
Steve Block5ea0c052012-01-06 19:18:11 +0000426 ALOGE("Invalid interface specified");
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700427 errno = ENODEV;
428 return -1;
429 }
430
431 if (argc < 5 + addrCount) {
Steve Block5ea0c052012-01-06 19:18:11 +0000432 ALOGE("Missing Argument");
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700433 errno = EINVAL;
434 return -1;
435 }
436
437 setForwardRules(false, intIface, extIface);
JP Abgrall4ae80de2013-03-14 20:06:20 -0700438 routesOp(false, intIface, extIface, argv, addrCount);
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700439 if (--natCount <= 0) {
Kazuhiro Ondo4ab46852012-01-12 16:15:06 -0600440 // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
441 setDefaults();
Robert Greenwaltfc97b822011-11-02 16:48:36 -0700442 }
443 return 0;
San Mehat9ff78fb2010-01-19 12:59:15 -0800444}