2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
28 #include <cutils/properties.h>
30 #define LOG_TAG "NatController"
31 #include <cutils/log.h>
32 #include <logwrap/logwrap.h>
34 #include "NatController.h"
35 #include "SecondaryTableController.h"
36 #include "NetdConstants.h"
38 const char* NatController::LOCAL_FORWARD = "natctrl_FORWARD";
39 const char* NatController::LOCAL_NAT_POSTROUTING = "natctrl_nat_POSTROUTING";
40 const char* NatController::LOCAL_TETHER_COUNTERS_CHAIN = "natctrl_tether_counters";
42 NatController::NatController(SecondaryTableController *ctrl) {
43 secondaryTableCtrl = ctrl;
46 NatController::~NatController() {
49 struct CommandsAndArgs {
50 /* The array size doesn't really matter as the compiler will barf if too many initializers are specified. */
55 int NatController::runCmd(int argc, const char **argv) {
58 res = android_fork_execvp(argc, (char **)argv, NULL, false, false);
61 std::string full_cmd = argv[0];
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.
69 for (; argc && argv[0]; argc--, argv++) {
73 ALOGV("runCmd(%s) res=%d", full_cmd.c_str(), res);
78 int NatController::setupIptablesHooks() {
85 struct CommandsAndArgs defaultCommands[] = {
87 * Chain for tethering counters.
88 * This chain is reached via --goto, and then RETURNS.
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},
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) {
104 int NatController::setDefaults() {
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.
111 struct CommandsAndArgs defaultCommands[] = {
112 {{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},
115 {{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},
123 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) {
135 bool NatController::checkInterface(const char *iface) {
136 if (strlen(iface) > IFNAMSIZ) return false;
140 int NatController::routesOp(bool add, const char *intIface, const char *extIface, char **argv, int addrCount) {
141 int tableNumber = secondaryTableCtrl->findTableNumber(extIface);
144 if (tableNumber != -1) {
145 for (int i = 0; i < addrCount; i++) {
147 ret |= secondaryTableCtrl->modifyFromRule(tableNumber, ADD, argv[5+i]);
148 ret |= secondaryTableCtrl->modifyLocalRoute(tableNumber, ADD, intIface, argv[5+i]);
150 ret |= secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
151 ret |= secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
154 const char *cmd[] = {
160 runCmd(ARRAY_SIZE(cmd), cmd);
166 // nat enable intface extface addrcnt nated-ipaddr/prelength
167 int NatController::enableNat(const int argc, char **argv) {
169 int addrCount = atoi(argv[4]);
170 const char *intIface = argv[2];
171 const char *extIface = argv[3];
174 ALOGV("enableNat(intIface=<%s>, extIface=<%s>)",intIface, extIface);
176 if (!checkInterface(intIface) || !checkInterface(extIface)) {
177 ALOGE("Invalid interface specified");
182 /* 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);
189 if (argc < 5 + addrCount) {
190 ALOGE("Missing Argument");
194 if (routesOp(true, intIface, extIface, argv, addrCount)) {
195 ALOGE("Error setting route rules");
196 routesOp(false, intIface, extIface, argv, addrCount);
201 // add this if we are the first added nat
203 const char *cmd[] = {
208 LOCAL_NAT_POSTROUTING,
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);
224 if (setForwardRules(true, intIface, extIface) != 0) {
225 ALOGE("Error setting forward rules");
226 routesOp(false, intIface, extIface, argv, addrCount);
234 /* Always make sure the drop rule is at the end */
235 const char *cmd1[] = {
242 runCmd(ARRAY_SIZE(cmd1), cmd1);
243 const char *cmd2[] = {
250 runCmd(ARRAY_SIZE(cmd2), cmd2);
256 int NatController::setTetherCountingRules(bool add, const char *intIface, const char *extIface) {
258 /* We only ever add tethering quota rules so that they stick. */
262 char *quota_name, *proc_path;
264 asprintf("a_name, "%s_%s", intIface, extIface);
266 asprintf(&proc_path, "/proc/net/xt_quota/%s", quota_name);
267 quota_fd = open(proc_path, O_RDONLY);
269 /* quota for iface pair already exists */
277 const char *cmd2b[] = {
280 LOCAL_TETHER_COUNTERS_CHAIN,
294 if (runCmd(ARRAY_SIZE(cmd2b), cmd2b) && add) {
300 asprintf("a_name, "%s_%s", extIface, intIface);
301 asprintf(&proc_path, "/proc/net/xt_quota/%s", quota_name);
302 quota_fd = open(proc_path, O_RDONLY);
304 /* quota for iface pair already exists */
312 const char *cmd3b[] = {
315 LOCAL_TETHER_COUNTERS_CHAIN,
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?
338 int NatController::setForwardRules(bool add, const char *intIface, const char *extIface) {
339 const char *cmd1[] = {
350 "ESTABLISHED,RELATED",
352 LOCAL_TETHER_COUNTERS_CHAIN
356 if (runCmd(ARRAY_SIZE(cmd1), cmd1) && add) {
360 const char *cmd2[] = {
376 const char *cmd3[] = {
385 LOCAL_TETHER_COUNTERS_CHAIN
388 if (runCmd(ARRAY_SIZE(cmd2), cmd2) && add) {
389 // bail on error, but only if adding
391 goto err_invalid_drop;
394 if (runCmd(ARRAY_SIZE(cmd3), cmd3) && add) {
395 // unwind what's been done, but don't care about success - what more could we do?
400 if (setTetherCountingRules(add, intIface, extIface) && add) {
409 runCmd(ARRAY_SIZE(cmd2), cmd2);
412 runCmd(ARRAY_SIZE(cmd1), cmd1);
416 // nat disable intface extface
418 // nat enable intface extface addrcnt nated-ipaddr/prelength
419 int NatController::disableNat(const int argc, char **argv) {
421 int addrCount = atoi(argv[4]);
422 const char *intIface = argv[2];
423 const char *extIface = argv[3];
426 if (!checkInterface(intIface) || !checkInterface(extIface)) {
427 ALOGE("Invalid interface specified");
432 if (argc < 5 + addrCount) {
433 ALOGE("Missing Argument");
438 setForwardRules(false, intIface, extIface);
439 routesOp(false, intIface, extIface, argv, addrCount);
440 if (--natCount <= 0) {
441 // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0