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