Home | History | Annotate | Download | only in netd
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <stdlib.h>
     18 #include <errno.h>
     19 #include <sys/socket.h>
     20 #include <sys/stat.h>
     21 #include <fcntl.h>
     22 #include <netinet/in.h>
     23 #include <arpa/inet.h>
     24 
     25 #define LOG_TAG "NatController"
     26 #include <cutils/log.h>
     27 
     28 #include "NatController.h"
     29 
     30 extern "C" int logwrap(int argc, const char **argv, int background);
     31 
     32 static char IPTABLES_PATH[] = "/system/bin/iptables";
     33 
     34 NatController::NatController() {
     35     natCount = 0;
     36 }
     37 
     38 NatController::~NatController() {
     39 }
     40 
     41 int NatController::runIptablesCmd(const char *cmd) {
     42     char buffer[255];
     43 
     44     strncpy(buffer, cmd, sizeof(buffer)-1);
     45 
     46     const char *args[16];
     47     char *next = buffer;
     48     char *tmp;
     49 
     50     args[0] = IPTABLES_PATH;
     51     args[1] = "--verbose";
     52     int i = 2;
     53 
     54     while ((tmp = strsep(&next, " "))) {
     55         args[i++] = tmp;
     56         if (i == 16) {
     57             LOGE("iptables argument overflow");
     58             errno = E2BIG;
     59             return -1;
     60         }
     61     }
     62     args[i] = NULL;
     63 
     64     return logwrap(i, args, 0);
     65 }
     66 
     67 int NatController::setDefaults() {
     68 
     69     if (runIptablesCmd("-P INPUT ACCEPT"))
     70         return -1;
     71     if (runIptablesCmd("-F INPUT"))
     72         return -1;
     73     if (runIptablesCmd("-P OUTPUT ACCEPT"))
     74         return -1;
     75     if (runIptablesCmd("-F OUTPUT"))
     76         return -1;
     77     if (runIptablesCmd("-P FORWARD DROP"))
     78         return -1;
     79     if (runIptablesCmd("-F FORWARD"))
     80         return -1;
     81     if (runIptablesCmd("-t nat -F"))
     82         return -1;
     83     return 0;
     84 }
     85 
     86 bool NatController::interfaceExists(const char *iface) {
     87     // XXX: STOPSHIP - Implement this
     88     return true;
     89 }
     90 
     91 int NatController::doNatCommands(const char *intIface, const char *extIface, bool add) {
     92     char cmd[255];
     93 
     94     // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
     95     if (add == false) {
     96         if (natCount <= 1) {
     97             int ret = setDefaults();
     98             if (ret == 0) {
     99                 natCount=0;
    100             }
    101             return ret;
    102         }
    103     }
    104 
    105     if (!interfaceExists(intIface) || !interfaceExists (extIface)) {
    106         LOGE("Invalid interface specified");
    107         errno = ENODEV;
    108         return -1;
    109     }
    110 
    111     snprintf(cmd, sizeof(cmd),
    112              "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
    113              (add ? "A" : "D"),
    114              extIface, intIface);
    115     if (runIptablesCmd(cmd)) {
    116         return -1;
    117     }
    118 
    119     snprintf(cmd, sizeof(cmd), "-%s FORWARD -i %s -o %s -j ACCEPT", (add ? "A" : "D"),
    120             intIface, extIface);
    121     if (runIptablesCmd(cmd)) {
    122         // unwind what's been done, but don't care about success - what more could we do?
    123         snprintf(cmd, sizeof(cmd),
    124                  "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
    125                  (!add ? "A" : "D"),
    126                  extIface, intIface);
    127         return -1;
    128     }
    129 
    130     // add this if we are the first added nat
    131     if (add && natCount == 0) {
    132         snprintf(cmd, sizeof(cmd), "-t nat -A POSTROUTING -o %s -j MASQUERADE", extIface);
    133         if (runIptablesCmd(cmd)) {
    134             // unwind what's been done, but don't care about success - what more could we do?
    135             setDefaults();;
    136             return -1;
    137         }
    138     }
    139 
    140     if (add) {
    141         natCount++;
    142     } else {
    143         natCount--;
    144     }
    145     return 0;
    146 }
    147 
    148 int NatController::enableNat(const char *intIface, const char *extIface) {
    149     return doNatCommands(intIface, extIface, true);
    150 }
    151 
    152 int NatController::disableNat(const char *intIface, const char *extIface) {
    153     return doNatCommands(intIface, extIface, false);
    154 }
    155