OSDN Git Service

Merge "Fix idletimer iptable rules."
[android-x86/system-netd.git] / NatController.cpp
index 28f1fe2..e44a29b 100644 (file)
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+// #define LOG_NDEBUG 0
+
 #include <stdlib.h>
 #include <errno.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <string.h>
+#include <cutils/properties.h>
 
 #define LOG_TAG "NatController"
 #include <cutils/log.h>
 
 #include "NatController.h"
+#include "SecondaryTableController.h"
+#include "NetdConstants.h"
 
-extern "C" int logwrap(int argc, const char **argv, int background);
+extern "C" int system_nosh(const char *command);
 
-static char IPTABLES_PATH[] = "/system/bin/iptables";
+const char* NatController::LOCAL_FORWARD = "natctrl_FORWARD";
+const char* NatController::LOCAL_NAT_POSTROUTING = "natctrl_nat_POSTROUTING";
 
-NatController::NatController() {
-    natCount = 0;
+NatController::NatController(SecondaryTableController *ctrl) {
+    secondaryTableCtrl = ctrl;
 }
 
 NatController::~NatController() {
 }
 
-int NatController::runIptablesCmd(const char *cmd) {
-    char buffer[255];
-
-    strncpy(buffer, cmd, sizeof(buffer)-1);
-
-    const char *args[16];
-    char *next = buffer;
-    char *tmp;
-
-    args[0] = IPTABLES_PATH;
-    args[1] = "--verbose";
-    int i = 2;
+int NatController::runCmd(const char *path, const char *cmd) {
+    char *buffer;
+    size_t len = strnlen(cmd, 255);
+    int res;
 
-    while ((tmp = strsep(&next, " "))) {
-        args[i++] = tmp;
-        if (i == 16) {
-            LOGE("iptables argument overflow");
-            errno = E2BIG;
-            return -1;
-        }
+    if (len == 255) {
+        ALOGE("command too long");
+        errno = E2BIG;
+        return -1;
     }
-    args[i] = NULL;
 
-    return logwrap(i, args, 0);
+    asprintf(&buffer, "%s %s", path, cmd);
+    res = system_nosh(buffer);
+    ALOGV("runCmd() buffer='%s' res=%d", buffer, res);
+    free(buffer);
+    return res;
 }
 
-int NatController::setDefaults() {
+int NatController::setupIptablesHooks() {
+    setDefaults();
+    return 0;
+}
 
-    if (runIptablesCmd("-P INPUT ACCEPT"))
-        return -1;
-    if (runIptablesCmd("-F INPUT"))
-        return -1;
-    if (runIptablesCmd("-P OUTPUT ACCEPT"))
-        return -1;
-    if (runIptablesCmd("-F OUTPUT"))
-        return -1;
-    if (runIptablesCmd("-P FORWARD DROP"))
-        return -1;
-    if (runIptablesCmd("-F FORWARD"))
+int NatController::setDefaults() {
+    if (runCmd(IPTABLES_PATH, "-F natctrl_FORWARD"))
         return -1;
-    if (runIptablesCmd("-t nat -F"))
+    if (runCmd(IPTABLES_PATH, "-t nat -F natctrl_nat_POSTROUTING"))
         return -1;
+
+    runCmd(IP_PATH, "rule flush");
+    runCmd(IP_PATH, "-6 rule flush");
+    runCmd(IP_PATH, "rule add from all lookup default prio 32767");
+    runCmd(IP_PATH, "rule add from all lookup main prio 32766");
+    runCmd(IP_PATH, "-6 rule add from all lookup default prio 32767");
+    runCmd(IP_PATH, "-6 rule add from all lookup main prio 32766");
+    runCmd(IP_PATH, "route flush cache");
+
+    natCount = 0;
+
     return 0;
 }
 
-bool NatController::interfaceExists(const char *iface) {
-    // XXX: Implement this
+bool NatController::checkInterface(const char *iface) {
+    if (strlen(iface) > IFNAMSIZ) return false;
     return true;
 }
 
-int NatController::doNatCommands(const char *intIface, const char *extIface, bool add) {
+//  0    1       2       3       4            5
+// nat enable intface extface addrcnt nated-ipaddr/prelength
+int NatController::enableNat(const int argc, char **argv) {
     char cmd[255];
+    int i;
+    int addrCount = atoi(argv[4]);
+    int ret = 0;
+    const char *intIface = argv[2];
+    const char *extIface = argv[3];
+    int tableNumber;
 
-    // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
-    if (add == false) {
-        if (natCount <= 1) {
-            int ret = setDefaults();
-            if (ret == 0) {
-                natCount=0;
-            }
-            return ret;
+    if (!checkInterface(intIface) || !checkInterface(extIface)) {
+        ALOGE("Invalid interface specified");
+        errno = ENODEV;
+        return -1;
+    }
+
+    if (argc < 5 + addrCount) {
+        ALOGE("Missing Argument");
+        errno = EINVAL;
+        return -1;
+    }
+
+    tableNumber = secondaryTableCtrl->findTableNumber(extIface);
+    if (tableNumber != -1) {
+        for(i = 0; i < addrCount; i++) {
+            ret |= secondaryTableCtrl->modifyFromRule(tableNumber, ADD, argv[5+i]);
+
+            ret |= secondaryTableCtrl->modifyLocalRoute(tableNumber, ADD, intIface, argv[5+i]);
         }
+        runCmd(IP_PATH, "route flush cache");
     }
 
-    if (!interfaceExists(intIface) || !interfaceExists (extIface)) {
-        LOGE("Invalid interface specified");
+    if (ret != 0 || setForwardRules(true, intIface, extIface) != 0) {
+        if (tableNumber != -1) {
+            for (i = 0; i < addrCount; i++) {
+                secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
+
+                secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
+            }
+            runCmd(IP_PATH, "route flush cache");
+        }
+        ALOGE("Error setting forward rules");
         errno = ENODEV;
         return -1;
     }
 
+    /* Always make sure the drop rule is at the end */
+    snprintf(cmd, sizeof(cmd), "-D natctrl_FORWARD -j DROP");
+    runCmd(IPTABLES_PATH, cmd);
+    snprintf(cmd, sizeof(cmd), "-A natctrl_FORWARD -j DROP");
+    runCmd(IPTABLES_PATH, cmd);
+
+
+    natCount++;
+    // add this if we are the first added nat
+    if (natCount == 1) {
+        snprintf(cmd, sizeof(cmd), "-t nat -A natctrl_nat_POSTROUTING -o %s -j MASQUERADE", extIface);
+        if (runCmd(IPTABLES_PATH, cmd)) {
+            ALOGE("Error seting postroute rule: %s", cmd);
+            // unwind what's been done, but don't care about success - what more could we do?
+            for (i = 0; i < addrCount; i++) {
+                secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
+
+                secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
+            }
+            setDefaults();
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+int NatController::setForwardRules(bool add, const char *intIface, const char * extIface) {
+    char cmd[255];
+
     snprintf(cmd, sizeof(cmd),
-             "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
+             "-%s natctrl_FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j RETURN",
              (add ? "A" : "D"),
              extIface, intIface);
-    if (runIptablesCmd(cmd)) {
+    if (runCmd(IPTABLES_PATH, cmd) && add) {
+        return -1;
+    }
+
+    snprintf(cmd, sizeof(cmd),
+            "-%s natctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
+            (add ? "A" : "D"),
+            intIface, extIface);
+    if (runCmd(IPTABLES_PATH, cmd) && add) {
+        // bail on error, but only if adding
+        snprintf(cmd, sizeof(cmd),
+                "-%s natctrl_FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j RETURN",
+                (!add ? "A" : "D"),
+                extIface, intIface);
+        runCmd(IPTABLES_PATH, cmd);
         return -1;
     }
 
-    snprintf(cmd, sizeof(cmd), "-%s FORWARD -i %s -o %s -j ACCEPT", (add ? "A" : "D"),
+    snprintf(cmd, sizeof(cmd), "-%s natctrl_FORWARD -i %s -o %s -j RETURN", (add ? "A" : "D"),
             intIface, extIface);
-    if (runIptablesCmd(cmd)) {
+    if (runCmd(IPTABLES_PATH, cmd) && add) {
         // unwind what's been done, but don't care about success - what more could we do?
         snprintf(cmd, sizeof(cmd),
-                 "-%s FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT",
+                "-%s natctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
+                (!add ? "A" : "D"),
+                intIface, extIface);
+        runCmd(IPTABLES_PATH, cmd);
+
+        snprintf(cmd, sizeof(cmd),
+                 "-%s natctrl_FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j RETURN",
                  (!add ? "A" : "D"),
                  extIface, intIface);
+        runCmd(IPTABLES_PATH, cmd);
         return -1;
     }
 
-    // add this if we are the first added nat
-    if (add && natCount == 0) {
-        snprintf(cmd, sizeof(cmd), "-t nat -A POSTROUTING -o %s -j MASQUERADE", extIface);
-        if (runIptablesCmd(cmd)) {
-            // unwind what's been done, but don't care about success - what more could we do?
-            setDefaults();;
-            return -1;
-        }
+    return 0;
+}
+
+// nat disable intface extface
+//  0    1       2       3       4            5
+// nat enable intface extface addrcnt nated-ipaddr/prelength
+int NatController::disableNat(const int argc, char **argv) {
+    char cmd[255];
+    int i;
+    int addrCount = atoi(argv[4]);
+    const char *intIface = argv[2];
+    const char *extIface = argv[3];
+    int tableNumber;
+
+    if (!checkInterface(intIface) || !checkInterface(extIface)) {
+        ALOGE("Invalid interface specified");
+        errno = ENODEV;
+        return -1;
     }
 
-    if (add) {
-        natCount++;
-    } else {
-        natCount--;
+    if (argc < 5 + addrCount) {
+        ALOGE("Missing Argument");
+        errno = EINVAL;
+        return -1;
     }
-    return 0;
-}
 
-int NatController::enableNat(const char *intIface, const char *extIface) {
-    return doNatCommands(intIface, extIface, true);
-}
+    setForwardRules(false, intIface, extIface);
+
+    tableNumber = secondaryTableCtrl->findTableNumber(extIface);
+    if (tableNumber != -1) {
+        for (i = 0; i < addrCount; i++) {
+            secondaryTableCtrl->modifyLocalRoute(tableNumber, DEL, intIface, argv[5+i]);
+
+            secondaryTableCtrl->modifyFromRule(tableNumber, DEL, argv[5+i]);
+        }
 
-int NatController::disableNat(const char *intIface, const char *extIface) {
-    return doNatCommands(intIface, extIface, false);
+        runCmd(IP_PATH, "route flush cache");
+    }
+
+    if (--natCount <= 0) {
+        // handle decrement to 0 case (do reset to defaults) and erroneous dec below 0
+        setDefaults();
+    }
+    return 0;
 }