19ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat/*
29ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat * Copyright (C) 2008 The Android Open Source Project
39ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat *
49ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat * Licensed under the Apache License, Version 2.0 (the "License");
59ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat * you may not use this file except in compliance with the License.
69ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat * You may obtain a copy of the License at
79ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat *
89ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat *      http://www.apache.org/licenses/LICENSE-2.0
99ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat *
109ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat * Unless required by applicable law or agreed to in writing, software
119ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat * distributed under the License is distributed on an "AS IS" BASIS,
129ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat * See the License for the specific language governing permissions and
149ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat * limitations under the License.
159ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat */
169ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
17baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall#define LOG_NDEBUG 0
180031cead820149e2fe3ccb3cc2fe05758a3cb5c2JP Abgrall
199ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include <stdlib.h>
209ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include <errno.h>
219ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include <sys/socket.h>
229ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include <sys/stat.h>
23001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand#include <sys/wait.h>
249ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include <fcntl.h>
259ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include <netinet/in.h>
269ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include <arpa/inet.h>
27ff2c0d8c13457e43f0d4bf06d3177271aac104c1Olivier Bailly#include <string.h>
28ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau#include <cutils/properties.h>
299ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
309ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#define LOG_TAG "NatController"
319ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include <cutils/log.h>
32001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand#include <logwrap/logwrap.h>
339ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
349ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include "NatController.h"
35fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt#include "SecondaryTableController.h"
36c462177bd58e3bf0ac4f618934dae060569e3e0bRobert Greenwalt#include "NetdConstants.h"
379ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
388e188ed5c989ddcc07f0f5e9839493c22d17e7b6Jeff Sharkeyconst char* NatController::LOCAL_FORWARD = "natctrl_FORWARD";
398e188ed5c989ddcc07f0f5e9839493c22d17e7b6Jeff Sharkeyconst char* NatController::LOCAL_NAT_POSTROUTING = "natctrl_nat_POSTROUTING";
40baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrallconst char* NatController::LOCAL_TETHER_COUNTERS_CHAIN = "natctrl_tether_counters";
418e188ed5c989ddcc07f0f5e9839493c22d17e7b6Jeff Sharkey
42fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert GreenwaltNatController::NatController(SecondaryTableController *ctrl) {
43fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    secondaryTableCtrl = ctrl;
449ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat}
459ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
469ff78fb7da7158f5bd7c86d89a842691820259cfSan MehatNatController::~NatController() {
479ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat}
489ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
494ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrallstruct CommandsAndArgs {
504ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall    /* The array size doesn't really matter as the compiler will barf if too many initializers are specified. */
514ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall    const char *cmd[32];
524ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall    bool checkRes;
534ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall};
544ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall
55001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchandint NatController::runCmd(int argc, const char **argv) {
5611b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    int res;
579ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
58001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand    res = android_fork_execvp(argc, (char **)argv, NULL, false, false);
59baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall
60baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall#if !LOG_NDEBUG
61baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    std::string full_cmd = argv[0];
62baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    argc--; argv++;
63baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    /*
64baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall     * HACK: Sometimes runCmd() is called with a ridcously large value (32)
65baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall     * and it works because the argv[] contains a NULL after the last
66baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall     * true argv. So here we use the NULL argv[] to terminate when the argc
67baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall     * is horribly wrong, and argc for the normal cases.
68baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall     */
69baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    for (; argc && argv[0]; argc--, argv++) {
70baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        full_cmd += " ";
71baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        full_cmd += argv[0];
72baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    }
73baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    ALOGV("runCmd(%s) res=%d", full_cmd.c_str(), res);
74baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall#endif
7511b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    return res;
769ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat}
779ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
780031cead820149e2fe3ccb3cc2fe05758a3cb5c2JP Abgrallint NatController::setupIptablesHooks() {
79baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    int res;
80baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    res = setDefaults();
81baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    if (res < 0) {
82baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        return res;
83baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    }
84baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall
85baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    struct CommandsAndArgs defaultCommands[] = {
86baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        /*
87baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall         * Chain for tethering counters.
88baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall         * This chain is reached via --goto, and then RETURNS.
89baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall         */
90baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        {{IPTABLES_PATH, "-F", LOCAL_TETHER_COUNTERS_CHAIN,}, 0},
91baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        {{IPTABLES_PATH, "-X", LOCAL_TETHER_COUNTERS_CHAIN,}, 0},
92baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        {{IPTABLES_PATH, "-N", LOCAL_TETHER_COUNTERS_CHAIN,}, 1},
93baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    };
94baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    for (unsigned int cmdNum = 0; cmdNum < ARRAY_SIZE(defaultCommands); cmdNum++) {
95baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        if (runCmd(ARRAY_SIZE(defaultCommands[cmdNum].cmd), defaultCommands[cmdNum].cmd) &&
96baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            defaultCommands[cmdNum].checkRes) {
97baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall                return -1;
98baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        }
99baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    }
100baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall
1010031cead820149e2fe3ccb3cc2fe05758a3cb5c2JP Abgrall    return 0;
1020031cead820149e2fe3ccb3cc2fe05758a3cb5c2JP Abgrall}
1030031cead820149e2fe3ccb3cc2fe05758a3cb5c2JP Abgrall
1040031cead820149e2fe3ccb3cc2fe05758a3cb5c2JP Abgrallint NatController::setDefaults() {
105baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    /*
106baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall     * The following only works because:
107baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall     *  - the defaultsCommands[].cmd array is padded with NULL, and
108baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall     *  - the 1st argc of runCmd() will just be the max for the CommandsAndArgs[].cmd, and
109baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall     *  - internally it will be memcopied to an array and terminated with a NULL.
110baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall     */
1114ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall    struct CommandsAndArgs defaultCommands[] = {
112baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        {{IPTABLES_PATH, "-F", LOCAL_FORWARD,}, 1},
113baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        {{IPTABLES_PATH, "-A", LOCAL_FORWARD, "-j", "DROP"}, 1},
114baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        {{IPTABLES_PATH, "-t", "nat", "-F", LOCAL_NAT_POSTROUTING}, 1},
1154ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall        {{IP_PATH, "rule", "flush"}, 0},
1164ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall        {{IP_PATH, "-6", "rule", "flush"}, 0},
1174ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall        {{IP_PATH, "rule", "add", "from", "all", "lookup", "default", "prio", "32767"}, 0},
1184ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall        {{IP_PATH, "rule", "add", "from", "all", "lookup", "main", "prio", "32766"}, 0},
1194ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall        {{IP_PATH, "-6", "rule", "add", "from", "all", "lookup", "default", "prio", "32767"}, 0},
1204ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall        {{IP_PATH, "-6", "rule", "add", "from", "all", "lookup", "main", "prio", "32766"}, 0},
1214ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall        {{IP_PATH, "route", "flush", "cache"}, 0},
122001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand    };
1234ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall    for (unsigned int cmdNum = 0; cmdNum < ARRAY_SIZE(defaultCommands); cmdNum++) {
1244ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall        if (runCmd(ARRAY_SIZE(defaultCommands[cmdNum].cmd), defaultCommands[cmdNum].cmd) &&
1254ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall            defaultCommands[cmdNum].checkRes) {
1264ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall                return -1;
1274ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall        }
1284ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall    }
129fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt
130fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    natCount = 0;
1314ab468577647d1ee73810b89d2287eaa5546fecbKazuhiro Ondo
1329ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    return 0;
1339ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat}
1349ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
135fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwaltbool NatController::checkInterface(const char *iface) {
136d14fd4f83ffeea4ad1cd559a41f775f6814565ccJaime A Lopez-Sollano    if (strlen(iface) > IFNAMSIZ) return false;
1379ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    return true;
1389ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat}
1399ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
1404ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrallint NatController::routesOp(bool add, const char *intIface, const char *extIface, char **argv, int addrCount) {
1414ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall    int tableNumber = secondaryTableCtrl->findTableNumber(extIface);
1424ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall    int ret = 0;
1434ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall
1444ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall    if (tableNumber != -1) {
1454ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall        for (int i = 0; i < addrCount; i++) {
1464ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall            if (add) {
1474ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall                ret |= secondaryTableCtrl->modifyFromRule(tableNumber, ADD, argv[5+i]);
1484ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall                ret |= secondaryTableCtrl->modifyLocalRoute(tableNumber, ADD, intIface, argv[5+i]);
1494ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall            } else {
1504ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall                ret |= secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
1514ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall                ret |= secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
1524ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall            }
1534ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall        }
1544ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall        const char *cmd[] = {
1554ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall                IP_PATH,
1564ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall                "route",
1574ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall                "flush",
1584ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall                "cache"
1594ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall        };
1604ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall        runCmd(ARRAY_SIZE(cmd), cmd);
1614ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall    }
1624ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall    return ret;
1634ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall}
1644ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall
165fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt//  0    1       2       3       4            5
166fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt// nat enable intface extface addrcnt nated-ipaddr/prelength
167fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwaltint NatController::enableNat(const int argc, char **argv) {
168fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    int i;
169fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    int addrCount = atoi(argv[4]);
170fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    const char *intIface = argv[2];
171fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    const char *extIface = argv[3];
172fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    int tableNumber;
173fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt
174baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    ALOGV("enableNat(intIface=<%s>, extIface=<%s>)",intIface, extIface);
175baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall
176fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    if (!checkInterface(intIface) || !checkInterface(extIface)) {
1775ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Invalid interface specified");
178fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt        errno = ENODEV;
179fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt        return -1;
180fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    }
1819ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
182baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    /* Bug: b/9565268. "enableNat wlan0 wlan0". For now we fail until java-land is fixed */
183baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    if (!strcmp(intIface, extIface)) {
184baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        ALOGE("Duplicate interface specified: %s %s", intIface, extIface);
185baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        errno = EINVAL;
186baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        return -1;
187baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    }
188baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall
189fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    if (argc < 5 + addrCount) {
1905ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Missing Argument");
191fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt        errno = EINVAL;
192fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt        return -1;
193fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    }
194659692a56cca02822a43b792baba2632d39eb739JP Abgrall    if (routesOp(true, intIface, extIface, argv, addrCount)) {
195659692a56cca02822a43b792baba2632d39eb739JP Abgrall        ALOGE("Error setting route rules");
1964ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall        routesOp(false, intIface, extIface, argv, addrCount);
1979ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        errno = ENODEV;
1989ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        return -1;
1999ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    }
2009ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
201fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    // add this if we are the first added nat
202659692a56cca02822a43b792baba2632d39eb739JP Abgrall    if (natCount == 0) {
203001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand        const char *cmd[] = {
204001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand                IPTABLES_PATH,
205001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand                "-t",
206001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand                "nat",
207001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand                "-A",
208baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall                LOCAL_NAT_POSTROUTING,
209001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand                "-o",
210001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand                extIface,
211001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand                "-j",
212001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand                "MASQUERADE"
213001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand        };
214001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand        if (runCmd(ARRAY_SIZE(cmd), cmd)) {
215001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            ALOGE("Error seting postroute rule: iface=%s", extIface);
216fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt            // unwind what's been done, but don't care about success - what more could we do?
2174ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall            routesOp(false, intIface, extIface, argv, addrCount);
218fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt            setDefaults();
219fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt            return -1;
220fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt        }
221fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    }
222fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt
223659692a56cca02822a43b792baba2632d39eb739JP Abgrall
224659692a56cca02822a43b792baba2632d39eb739JP Abgrall    if (setForwardRules(true, intIface, extIface) != 0) {
225659692a56cca02822a43b792baba2632d39eb739JP Abgrall        ALOGE("Error setting forward rules");
226659692a56cca02822a43b792baba2632d39eb739JP Abgrall        routesOp(false, intIface, extIface, argv, addrCount);
227659692a56cca02822a43b792baba2632d39eb739JP Abgrall        if (natCount == 0) {
228659692a56cca02822a43b792baba2632d39eb739JP Abgrall            setDefaults();
229659692a56cca02822a43b792baba2632d39eb739JP Abgrall        }
230659692a56cca02822a43b792baba2632d39eb739JP Abgrall        errno = ENODEV;
231659692a56cca02822a43b792baba2632d39eb739JP Abgrall        return -1;
232659692a56cca02822a43b792baba2632d39eb739JP Abgrall    }
233659692a56cca02822a43b792baba2632d39eb739JP Abgrall
234659692a56cca02822a43b792baba2632d39eb739JP Abgrall    /* Always make sure the drop rule is at the end */
235659692a56cca02822a43b792baba2632d39eb739JP Abgrall    const char *cmd1[] = {
236659692a56cca02822a43b792baba2632d39eb739JP Abgrall            IPTABLES_PATH,
237659692a56cca02822a43b792baba2632d39eb739JP Abgrall            "-D",
238baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            LOCAL_FORWARD,
239659692a56cca02822a43b792baba2632d39eb739JP Abgrall            "-j",
240659692a56cca02822a43b792baba2632d39eb739JP Abgrall            "DROP"
241659692a56cca02822a43b792baba2632d39eb739JP Abgrall    };
242659692a56cca02822a43b792baba2632d39eb739JP Abgrall    runCmd(ARRAY_SIZE(cmd1), cmd1);
243659692a56cca02822a43b792baba2632d39eb739JP Abgrall    const char *cmd2[] = {
244659692a56cca02822a43b792baba2632d39eb739JP Abgrall            IPTABLES_PATH,
245659692a56cca02822a43b792baba2632d39eb739JP Abgrall            "-A",
246baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            LOCAL_FORWARD,
247659692a56cca02822a43b792baba2632d39eb739JP Abgrall            "-j",
248659692a56cca02822a43b792baba2632d39eb739JP Abgrall            "DROP"
249659692a56cca02822a43b792baba2632d39eb739JP Abgrall    };
250659692a56cca02822a43b792baba2632d39eb739JP Abgrall    runCmd(ARRAY_SIZE(cmd2), cmd2);
251659692a56cca02822a43b792baba2632d39eb739JP Abgrall
252659692a56cca02822a43b792baba2632d39eb739JP Abgrall    natCount++;
253fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    return 0;
254fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt}
255fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt
256baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrallint NatController::setTetherCountingRules(bool add, const char *intIface, const char *extIface) {
257baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall
258baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    /* We only ever add tethering quota rules so that they stick. */
259baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    if (!add) {
260baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        return 0;
261baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    }
262baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    char *quota_name, *proc_path;
263baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    int quota_fd;
264baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    asprintf(&quota_name, "%s_%s", intIface, extIface);
265baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall
266baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    asprintf(&proc_path, "/proc/net/xt_quota/%s", quota_name);
267baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    quota_fd = open(proc_path, O_RDONLY);
268baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    if (quota_fd >= 0) {
269baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        /* quota for iface pair already exists */
270baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        free(proc_path);
271baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        free(quota_name);
272baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        return 0;
273baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    }
274baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    close(quota_fd);
275baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    free(proc_path);
276baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall
277baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    const char *cmd2b[] = {
278baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            IPTABLES_PATH,
279baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "-A",
280baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            LOCAL_TETHER_COUNTERS_CHAIN,
281baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "-i",
282baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            intIface,
283baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "-o",
284baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            extIface,
285baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "-m",
286baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "quota2",
287baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "--name",
288baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            quota_name,
289baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "--grow",
290baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "-j",
291baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall          "RETURN"
292baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    };
293baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall
294baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    if (runCmd(ARRAY_SIZE(cmd2b), cmd2b) && add) {
295baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        free(quota_name);
296baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        return -1;
297baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    }
298baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    free(quota_name);
299baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall
300baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    asprintf(&quota_name, "%s_%s", extIface, intIface);
301baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    asprintf(&proc_path, "/proc/net/xt_quota/%s", quota_name);
302baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    quota_fd = open(proc_path, O_RDONLY);
303baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    if (quota_fd >= 0) {
304baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        /* quota for iface pair already exists */
305baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        free(proc_path);
306baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        free(quota_name);
307baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        return 0;
308baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    }
309baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    close(quota_fd);
310baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    free(proc_path);
311baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall
312baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    const char *cmd3b[] = {
313baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            IPTABLES_PATH,
314baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "-A",
315baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            LOCAL_TETHER_COUNTERS_CHAIN,
316baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "-i",
317baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            extIface,
318baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "-o",
319baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            intIface,
320baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "-m",
321baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "quota2",
322baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "--name",
323baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            quota_name,
324baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "--grow",
325baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "-j",
326baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "RETURN"
327baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    };
328baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall
329baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    if (runCmd(ARRAY_SIZE(cmd3b), cmd3b) && add) {
330baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        // unwind what's been done, but don't care about success - what more could we do?
331baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        free(quota_name);
332baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        return -1;
333baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    }
334baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    free(quota_name);
335baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    return 0;
336baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall}
337baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall
338baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrallint NatController::setForwardRules(bool add, const char *intIface, const char *extIface) {
339001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand    const char *cmd1[] = {
340001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            IPTABLES_PATH,
341001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            add ? "-A" : "-D",
342baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            LOCAL_FORWARD,
343001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            "-i",
344001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            extIface,
345001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            "-o",
346001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            intIface,
347001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            "-m",
348001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            "state",
349001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            "--state",
350001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            "ESTABLISHED,RELATED",
351baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "-g",
352baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            LOCAL_TETHER_COUNTERS_CHAIN
353001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand    };
354001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand    int rc = 0;
355001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand
356001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand    if (runCmd(ARRAY_SIZE(cmd1), cmd1) && add) {
3579ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        return -1;
3589ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    }
3599ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
360001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand    const char *cmd2[] = {
361001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            IPTABLES_PATH,
362001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            add ? "-A" : "-D",
363baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            LOCAL_FORWARD,
364001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            "-i",
365001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            intIface,
366001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            "-o",
367001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            extIface,
368001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            "-m",
369001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            "state",
370001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            "--state",
371001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            "INVALID",
372001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            "-j",
373001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            "DROP"
374001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand    };
375001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand
376001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand    const char *cmd3[] = {
377001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            IPTABLES_PATH,
378001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            add ? "-A" : "-D",
379baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            LOCAL_FORWARD,
380001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            "-i",
381001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            intIface,
382001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            "-o",
383001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand            extIface,
384baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            "-g",
385baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall            LOCAL_TETHER_COUNTERS_CHAIN
386001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand    };
387001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand
388001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand    if (runCmd(ARRAY_SIZE(cmd2), cmd2) && add) {
389f7bf29c8a37d65e132a4dceb7c5a4200ed5c3d79Robert Greenwalt        // bail on error, but only if adding
390001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand        rc = -1;
391001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand        goto err_invalid_drop;
392ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt    }
393ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt
394001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand    if (runCmd(ARRAY_SIZE(cmd3), cmd3) && add) {
395210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt        // unwind what's been done, but don't care about success - what more could we do?
396001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand        rc = -1;
397001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand        goto err_return;
3989ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    }
3990031cead820149e2fe3ccb3cc2fe05758a3cb5c2JP Abgrall
400baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    if (setTetherCountingRules(add, intIface, extIface) && add) {
401baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        rc = -1;
402baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall        goto err_return;
403baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall    }
404baeccc455b293c2c83dbe6463f56b741177bd612JP Abgrall
405fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    return 0;
406001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand
407001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchanderr_return:
408001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand    cmd2[1] = "-D";
409001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand    runCmd(ARRAY_SIZE(cmd2), cmd2);
410001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchanderr_invalid_drop:
411001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand    cmd1[1] = "-D";
412001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand    runCmd(ARRAY_SIZE(cmd1), cmd1);
413001f0a436e9fe0353dccd98ee34b91095d9ed1a1Rom Lemarchand    return rc;
414fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt}
4159ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
416fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt// nat disable intface extface
417fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt//  0    1       2       3       4            5
418fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt// nat enable intface extface addrcnt nated-ipaddr/prelength
419fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwaltint NatController::disableNat(const int argc, char **argv) {
420fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    int i;
421fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    int addrCount = atoi(argv[4]);
422fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    const char *intIface = argv[2];
423fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    const char *extIface = argv[3];
424fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    int tableNumber;
425fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt
426fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    if (!checkInterface(intIface) || !checkInterface(extIface)) {
4275ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Invalid interface specified");
428fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt        errno = ENODEV;
429fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt        return -1;
4309ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    }
4319ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
432fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    if (argc < 5 + addrCount) {
4335ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Missing Argument");
434fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt        errno = EINVAL;
435fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt        return -1;
436210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt    }
4379ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
438fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    setForwardRules(false, intIface, extIface);
4394ae80dea9cbf1fe1b33037aeb5feb04daeba8ee0JP Abgrall    routesOp(false, intIface, extIface, argv, addrCount);
440fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    if (--natCount <= 0) {
4414ab468577647d1ee73810b89d2287eaa5546fecbKazuhiro Ondo        // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
4424ab468577647d1ee73810b89d2287eaa5546fecbKazuhiro Ondo        setDefaults();
443fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    }
444fc97b82e02979f246d56a4bfd60e4aab8686d3f6Robert Greenwalt    return 0;
4459ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat}
446