NatController.cpp revision 11b4e9b26fe7b878992162afb39f5a8acfd143ed
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 179ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include <stdlib.h> 189ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include <errno.h> 199ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include <sys/socket.h> 209ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include <sys/stat.h> 219ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include <fcntl.h> 229ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include <netinet/in.h> 239ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include <arpa/inet.h> 24ff2c0d8c13457e43f0d4bf06d3177271aac104c1Olivier Bailly#include <string.h> 25ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau#include <cutils/properties.h> 269ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 279ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#define LOG_TAG "NatController" 289ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include <cutils/log.h> 299ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 309ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat#include "NatController.h" 319ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 329ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehatextern "C" int logwrap(int argc, const char **argv, int background); 339ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 349ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehatstatic char IPTABLES_PATH[] = "/system/bin/iptables"; 359ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 369ff78fb7da7158f5bd7c86d89a842691820259cfSan MehatNatController::NatController() { 371caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt natCount = 0; 389ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat} 399ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 409ff78fb7da7158f5bd7c86d89a842691820259cfSan MehatNatController::~NatController() { 419ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat} 429ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 439ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehatint NatController::runIptablesCmd(const char *cmd) { 4411b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall char *buffer; 4511b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall size_t len = strnlen(cmd, 255); 4611b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall int res; 479ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 4811b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall if (len == 255) { 4911b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall LOGE("iptables command too long"); 5011b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall errno = E2BIG; 5111b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall return -1; 529ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat } 539ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 5411b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall asprintf(&buffer, "%s %s", IPTABLES_PATH, cmd); 5511b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall res = system(buffer); 5611b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall free(buffer); 5711b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall return res; 589ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat} 599ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 609ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehatint NatController::setDefaults() { 619ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 629ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat if (runIptablesCmd("-P INPUT ACCEPT")) 639ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat return -1; 649ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat if (runIptablesCmd("-P OUTPUT ACCEPT")) 659ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat return -1; 669ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat if (runIptablesCmd("-P FORWARD DROP")) 679ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat return -1; 689ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat if (runIptablesCmd("-F FORWARD")) 699ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat return -1; 709ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat if (runIptablesCmd("-t nat -F")) 719ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat return -1; 729ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat return 0; 739ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat} 749ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 759ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehatbool NatController::interfaceExists(const char *iface) { 76b5ff9b277f256df84caf3d798ccc83b4740a1d31Paul Eastham // XXX: Implement this 779ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat return true; 789ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat} 799ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 801caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwaltint NatController::doNatCommands(const char *intIface, const char *extIface, bool add) { 819ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat char cmd[255]; 829ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 83ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau char bootmode[PROPERTY_VALUE_MAX] = {0}; 84ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau property_get("ro.bootmode", bootmode, "unknown"); 85ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau if (0 != strcmp("bp-tools", bootmode)) { 86ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0 87ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau if (add == false) { 88ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau if (natCount <= 1) { 89ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau int ret = setDefaults(); 90ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau if (ret == 0) { 91ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau natCount=0; 92ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau } 93ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau return ret; 94210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt } 95210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt } 96210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt } 97210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt 989ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat if (!interfaceExists(intIface) || !interfaceExists (extIface)) { 999ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat LOGE("Invalid interface specified"); 1009ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat errno = ENODEV; 1019ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat return -1; 1029ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat } 1039ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 1049ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat snprintf(cmd, sizeof(cmd), 1051caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT", 1061caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt (add ? "A" : "D"), 1079ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat extIface, intIface); 1089ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat if (runIptablesCmd(cmd)) { 1099ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat return -1; 1109ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat } 1119ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 112ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt snprintf(cmd, sizeof(cmd), 113ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt "-%s FORWARD -i %s -o %s -m state --state INVALID -j DROP", 114ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt (add ? "A" : "D"), 115ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt intIface, extIface); 116ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt if (runIptablesCmd(cmd)) { 117ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt snprintf(cmd, sizeof(cmd), 118ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT", 119ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt (!add ? "A" : "D"), 120ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt extIface, intIface); 1216e4d5db1b11f808bb4bdcc8dd45a7158c6c88515Robert Greenwalt runIptablesCmd(cmd); 122ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt return -1; 123ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt } 124ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt 1251caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt snprintf(cmd, sizeof(cmd), "-%s FORWARD -i %s -o %s -j ACCEPT", (add ? "A" : "D"), 1261caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt intIface, extIface); 1279ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat if (runIptablesCmd(cmd)) { 128210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt // unwind what's been done, but don't care about success - what more could we do? 129210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt snprintf(cmd, sizeof(cmd), 130ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt "-%s FORWARD -i %s -o %s -m state --state INVALID -j DROP", 131ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt (!add ? "A" : "D"), 132ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt intIface, extIface); 133ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt runIptablesCmd(cmd); 134ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt 135ddb9f6eb8d8c35f46c1e3da68f375b85903e85c9Robert Greenwalt snprintf(cmd, sizeof(cmd), 136210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT", 137210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt (!add ? "A" : "D"), 138210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt extIface, intIface); 1396e4d5db1b11f808bb4bdcc8dd45a7158c6c88515Robert Greenwalt runIptablesCmd(cmd); 1409ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat return -1; 1419ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat } 1429ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 143210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt // add this if we are the first added nat 1441caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt if (add && natCount == 0) { 1451caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt snprintf(cmd, sizeof(cmd), "-t nat -A POSTROUTING -o %s -j MASQUERADE", extIface); 1461caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt if (runIptablesCmd(cmd)) { 147ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau if (0 != strcmp("bp-tools", bootmode)) { 148ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau // unwind what's been done, but don't care about success - what more could we do? 149ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau setDefaults();; 150ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau } 1511caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt return -1; 1521caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt } 1539ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat } 1549ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 155210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt if (add) { 156210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt natCount++; 157210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt } else { 158210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt natCount--; 159210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt } 1609ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat return 0; 1619ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat} 1629ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat 1631caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwaltint NatController::enableNat(const char *intIface, const char *extIface) { 1641caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt return doNatCommands(intIface, extIface, true); 1651caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt} 1661caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt 1679ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehatint NatController::disableNat(const char *intIface, const char *extIface) { 168210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt return doNatCommands(intIface, extIface, false); 1699ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat} 170