Add netd support for marked packet forwarding

Add binds in netd for setting up fwmark rules to be used with the per
uid marking to do per uid routing.

Change-Id: Id4f315dd1aec73f074e233c2e3f70eb24b4c537a
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 7ffb725..8346945 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -104,6 +104,7 @@
 
 static const char* NAT_POSTROUTING[] = {
         NatController::LOCAL_NAT_POSTROUTING,
+        SecondaryTableController::LOCAL_NAT_POSTROUTING,
         NULL,
 };
 
@@ -262,9 +263,36 @@
 
         //     0       1       2        3          4           5     6      7
         // interface route add/remove iface default/secondary dest prefix gateway
+        // interface route  fwmark  add/remove   iface
         // interface route    uid   add/remove   iface        uid
         if (!strcmp(argv[1], "route")) {
             int prefix_length = 0;
+            if (!strcmp(argv[2], "fwmark")) {
+                if (argc < 5) {
+                    cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+                    return 0;
+                }
+                if (!strcmp(argv[3], "add")) {
+                    if (!sSecondaryTableCtrl->addFwmarkRule(argv[4])) {
+                        cli->sendMsg(ResponseCode::CommandOkay, "Fwmark rule successfully added",
+                                false);
+                    } else {
+                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to add fwmark rule",
+                                true);
+                    }
+                } else if (!strcmp(argv[3], "remove")) {
+                    if (!sSecondaryTableCtrl->removeFwmarkRule(argv[4])) {
+                        cli->sendMsg(ResponseCode::CommandOkay, "Fwmark rule successfully removed",
+                                false);
+                    } else {
+                        cli->sendMsg(ResponseCode::OperationFailed, "Failed to remove fwmark rule",
+                                true);
+                    }
+                } else {
+                    cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown fwmark cmd", false);
+                }
+                return 0;
+            }
             if (!strcmp(argv[2], "uid")) {
                 if (argc < 6) {
                     cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
diff --git a/SecondaryTableController.cpp b/SecondaryTableController.cpp
index 4b10f62..3841083 100644
--- a/SecondaryTableController.cpp
+++ b/SecondaryTableController.cpp
@@ -37,6 +37,7 @@
 #include "SecondaryTableController.h"
 
 const char* SecondaryTableController::LOCAL_MANGLE_OUTPUT = "st_mangle_OUTPUT";
+const char* SecondaryTableController::LOCAL_NAT_POSTROUTING = "st_nat_POSTROUTING";
 
 SecondaryTableController::SecondaryTableController() {
     int i;
@@ -234,6 +235,60 @@
 
     return runCmd(ARRAY_SIZE(cmd), cmd);
 }
+int SecondaryTableController::addFwmarkRule(const char *iface) {
+    return setFwmarkRule(iface, true);
+}
+
+int SecondaryTableController::removeFwmarkRule(const char *iface) {
+    return setFwmarkRule(iface, false);
+}
+
+int SecondaryTableController::setFwmarkRule(const char *iface, bool add) {
+    char tableIndex_str[11];
+    int tableIndex = findTableNumber(iface);
+    if (tableIndex == -1) {
+        tableIndex = findTableNumber(""); // look for an empty slot
+        if (tableIndex == -1) {
+            ALOGE("Max number of NATed interfaces reached");
+            errno = ENODEV;
+            return -1;
+        }
+        strncpy(mInterfaceTable[tableIndex], iface, IFNAMSIZ);
+        // Ensure null termination even if truncation happened
+        mInterfaceTable[tableIndex][IFNAMSIZ] = 0;
+    }
+    snprintf(tableIndex_str, sizeof(tableIndex_str), "%d", tableIndex +
+            BASE_TABLE_NUMBER);
+    const char *cmd[] = {
+        IP_PATH,
+        "rule",
+        add ? "add" : "del",
+        "fwmark",
+        tableIndex_str,
+        "table",
+        tableIndex_str
+    };
+    int ret = runCmd(ARRAY_SIZE(cmd), cmd);
+    if (ret) return ret;
+
+    //set up the needed source IP rewriting
+    //NOTE: Without ipv6 NAT in the kernel <3.7 only support V4 NAT
+    return execIptables(V4,
+            "-t",
+            "nat",
+            add ? "-A" : "-D",
+            LOCAL_NAT_POSTROUTING,
+            "-o",
+            iface,
+            "-m",
+            "mark",
+            "--mark",
+            tableIndex_str,
+            "-j",
+            "MASQUERADE",
+            NULL);
+
+}
 
 int SecondaryTableController::addUidRule(const char *iface, const char *uid) {
     return setUidRule(iface, uid, true);
diff --git a/SecondaryTableController.h b/SecondaryTableController.h
index 27344e4..d29198d 100644
--- a/SecondaryTableController.h
+++ b/SecondaryTableController.h
@@ -42,12 +42,16 @@
     int modifyLocalRoute(int tableIndex, const char *action, const char *iface, const char *addr);
     int addUidRule(const char *iface, const char *uid);
     int removeUidRule(const char *iface, const char *uid);
+    int addFwmarkRule(const char *iface);
+    int removeFwmarkRule(const char *iface);
 
     static const char* LOCAL_MANGLE_OUTPUT;
+    static const char* LOCAL_NAT_POSTROUTING;
 
 
 private:
     int setUidRule(const char* iface, const char *uid, bool add);
+    int setFwmarkRule(const char *iface, bool add);
     int modifyRoute(SocketClient *cli, const char *action, char *iface, char *dest, int prefix,
             char *gateway, int tableIndex);