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("a_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("a_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