NatController.cpp revision ac208608c9e10ef199fdd11c38a31675ee9290c0
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) {
449ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    char buffer[255];
459ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
469ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    strncpy(buffer, cmd, sizeof(buffer)-1);
479ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
489ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    const char *args[16];
499ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    char *next = buffer;
509ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    char *tmp;
519ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
529ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    args[0] = IPTABLES_PATH;
539ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    args[1] = "--verbose";
549ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    int i = 2;
559ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
569ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    while ((tmp = strsep(&next, " "))) {
579ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        args[i++] = tmp;
589ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        if (i == 16) {
599ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat            LOGE("iptables argument overflow");
609ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat            errno = E2BIG;
619ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat            return -1;
629ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        }
639ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    }
649ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    args[i] = NULL;
659ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
669ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    return logwrap(i, args, 0);
679ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat}
689ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
699ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehatint NatController::setDefaults() {
709ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
719ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    if (runIptablesCmd("-P INPUT ACCEPT"))
729ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        return -1;
739ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    if (runIptablesCmd("-F INPUT"))
749ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        return -1;
759ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    if (runIptablesCmd("-P OUTPUT ACCEPT"))
769ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        return -1;
779ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    if (runIptablesCmd("-F OUTPUT"))
789ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        return -1;
799ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    if (runIptablesCmd("-P FORWARD DROP"))
809ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        return -1;
819ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    if (runIptablesCmd("-F FORWARD"))
829ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        return -1;
839ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    if (runIptablesCmd("-t nat -F"))
849ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        return -1;
859ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    return 0;
869ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat}
879ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
889ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehatbool NatController::interfaceExists(const char *iface) {
89b5ff9b277f256df84caf3d798ccc83b4740a1d31Paul Eastham    // XXX: Implement this
909ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    return true;
919ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat}
929ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
931caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwaltint NatController::doNatCommands(const char *intIface, const char *extIface, bool add) {
949ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    char cmd[255];
959ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
96ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau    char bootmode[PROPERTY_VALUE_MAX] = {0};
97ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau    property_get("ro.bootmode", bootmode, "unknown");
98ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau    if (0 != strcmp("bp-tools", bootmode)) {
99ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau        // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
100ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau        if (add == false) {
101ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau            if (natCount <= 1) {
102ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau                int ret = setDefaults();
103ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau                if (ret == 0) {
104ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau                    natCount=0;
105ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau                }
106ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau                return ret;
107210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt            }
108210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt        }
109210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt    }
110210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt
1119ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    if (!interfaceExists(intIface) || !interfaceExists (extIface)) {
1129ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        LOGE("Invalid interface specified");
1139ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        errno = ENODEV;
1149ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        return -1;
1159ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    }
1169ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
1179ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    snprintf(cmd, sizeof(cmd),
1181caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt             "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
1191caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt             (add ? "A" : "D"),
1209ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat             extIface, intIface);
1219ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    if (runIptablesCmd(cmd)) {
1229ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        return -1;
1239ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    }
1249ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
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),
130210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt                 "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
131210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt                 (!add ? "A" : "D"),
132210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt                 extIface, intIface);
1339ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat        return -1;
1349ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    }
1359ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
136210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt    // add this if we are the first added nat
1371caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt    if (add && natCount == 0) {
1381caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt        snprintf(cmd, sizeof(cmd), "-t nat -A POSTROUTING -o %s -j MASQUERADE", extIface);
1391caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt        if (runIptablesCmd(cmd)) {
140ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau            if (0 != strcmp("bp-tools", bootmode)) {
141ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau                // unwind what's been done, but don't care about success - what more could we do?
142ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau                setDefaults();;
143ac208608c9e10ef199fdd11c38a31675ee9290c0John Michelau            }
1441caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt            return -1;
1451caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt        }
1469ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    }
1479ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
148210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt    if (add) {
149210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt        natCount++;
150210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt    } else {
151210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt        natCount--;
152210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt    }
1539ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat    return 0;
1549ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat}
1559ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat
1561caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwaltint NatController::enableNat(const char *intIface, const char *extIface) {
1571caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt    return doNatCommands(intIface, extIface, true);
1581caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt}
1591caafe66a6b927fa5d8eb4c59ec9eb48b0b1b075Robert Greenwalt
1609ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehatint NatController::disableNat(const char *intIface, const char *extIface) {
161210b97745e14830cdb1f29ee1109e6e516f4e6f6Robert Greenwalt    return doNatCommands(intIface, extIface, false);
1629ff78fb7da7158f5bd7c86d89a842691820259cfSan Mehat}
163