Move NatController startup to iptables-restore.

This makes NatController startup much faster. Before:
02-03 14:09:19.199   485   485 I Netd    : Setting up NatController hooks: 223.4ms

After:
02-03 14:28:09.407   488   488 I Netd    : Setting up NatController hooks: 13.8ms

Also, fail if MSS rewriting is not supported. It's much easier
to diagnose a failure than a performance problem.

Test: unit tests continue to pass
Test: bullhead builds, boots, wifi tethering works
Fix: 17629786
Bug: 34873832
Change-Id: I0ef498ecbbb82a2672c279056d189d026e13100a
diff --git a/server/NatController.cpp b/server/NatController.cpp
index cda8f5f..85a7ee1 100644
--- a/server/NatController.cpp
+++ b/server/NatController.cpp
@@ -28,13 +28,17 @@
 #include <cutils/properties.h>
 
 #define LOG_TAG "NatController"
+#include <android-base/stringprintf.h>
 #include <cutils/log.h>
 #include <logwrap/logwrap.h>
 
+#include "NetdConstants.h"
 #include "NatController.h"
 #include "NetdConstants.h"
 #include "RouteController.h"
 
+using android::base::StringPrintf;
+
 const char* NatController::LOCAL_FORWARD = "natctrl_FORWARD";
 const char* NatController::LOCAL_MANGLE_FORWARD = "natctrl_mangle_FORWARD";
 const char* NatController::LOCAL_NAT_POSTROUTING = "natctrl_nat_POSTROUTING";
@@ -42,6 +46,7 @@
 const char* NatController::LOCAL_TETHER_COUNTERS_CHAIN = "natctrl_tether_counters";
 
 auto NatController::execFunction = android_fork_execvp;
+auto NatController::iptablesRestoreFunction = execIptablesRestore;
 
 NatController::NatController() {
 }
@@ -85,60 +90,61 @@
         return res;
     }
 
-    struct CommandsAndArgs defaultCommands[] = {
-        /*
-         * This is for tethering counters.
-         * This chain is reached via --goto, and then RETURNS.
-         */
-        {{IPTABLES_PATH, "-w", "-F", LOCAL_TETHER_COUNTERS_CHAIN,}, 0},
-        {{IP6TABLES_PATH, "-w", "-F", LOCAL_TETHER_COUNTERS_CHAIN,}, 0},
-        {{IPTABLES_PATH, "-w", "-X", LOCAL_TETHER_COUNTERS_CHAIN,}, 0},
-        {{IP6TABLES_PATH, "-w", "-X", LOCAL_TETHER_COUNTERS_CHAIN,}, 0},
-        {{IPTABLES_PATH, "-w", "-N", LOCAL_TETHER_COUNTERS_CHAIN,}, 1},
-        {{IP6TABLES_PATH, "-w", "-N", LOCAL_TETHER_COUNTERS_CHAIN,}, 1},
+    // Used to limit downstream mss to the upstream pmtu so we don't end up fragmenting every large
+    // packet tethered devices send. This is IPv4-only, because in IPv6 we send the MTU in the RA.
+    // This is no longer optional and tethering will fail to start if it fails.
+    std::string mssRewriteCommand = StringPrintf(
+        "*mangle\n"
+        "-A %s -p tcp --tcp-flags SYN SYN -j TCPMSS --clamp-mss-to-pmtu\n"
+        "COMMIT\n", LOCAL_MANGLE_FORWARD);
 
-        /*
-         * Second chain is used to limit downstream mss to the upstream pmtu
-         * so we don't end up fragmenting every large packet tethered devices
-         * send.  Note this feature requires kernel support with flag
-         * CONFIG_NETFILTER_XT_TARGET_TCPMSS=y, which not all builds will have,
-         * so the final rule is allowed to fail.
-         * Bug 17629786 asks to make the failure more obvious, or even fatal
-         * so that all builds eventually gain the performance improvement.
-         */
-        {{IPTABLES_PATH, "-w", "-t", "mangle", "-A", LOCAL_MANGLE_FORWARD, "-p", "tcp",
-                "--tcp-flags", "SYN", "SYN", "-j", "TCPMSS", "--clamp-mss-to-pmtu"}, 0},
-    };
-    for (unsigned int cmdNum = 0; cmdNum < ARRAY_SIZE(defaultCommands); cmdNum++) {
-        if (runCmd(ARRAY_SIZE(defaultCommands[cmdNum].cmd), defaultCommands[cmdNum].cmd) &&
-            defaultCommands[cmdNum].checkRes) {
-                return -1;
-        }
+    // This is for tethering counters. This chain is reached via --goto, and then RETURNS.
+    std::string defaultCommands = StringPrintf(
+        "*filter\n"
+        ":%s -\n"
+        "COMMIT\n", LOCAL_TETHER_COUNTERS_CHAIN);
+
+    res = iptablesRestoreFunction(V4, mssRewriteCommand);
+    if (res < 0) {
+        return res;
     }
+
+    res = iptablesRestoreFunction(V4V6, defaultCommands);
+    if (res < 0) {
+        return res;
+    }
+
     ifacePairList.clear();
 
     return 0;
 }
 
 int NatController::setDefaults() {
-    /*
-     * The following only works because:
-     *  - the defaultsCommands[].cmd array is padded with NULL, and
-     *  - the 1st argc of runCmd() will just be the max for the CommandsAndArgs[].cmd, and
-     *  - internally it will be memcopied to an array and terminated with a NULL.
-     */
-    struct CommandsAndArgs defaultCommands[] = {
-        {{IPTABLES_PATH, "-w", "-F", LOCAL_FORWARD,}, 1},
-        {{IP6TABLES_PATH, "-w", "-F", LOCAL_FORWARD,}, 1},
-        {{IPTABLES_PATH, "-w", "-A", LOCAL_FORWARD, "-j", "DROP"}, 1},
-        {{IPTABLES_PATH, "-w", "-t", "nat", "-F", LOCAL_NAT_POSTROUTING}, 1},
-        {{IP6TABLES_PATH, "-w", "-t", "raw", "-F", LOCAL_RAW_PREROUTING}, 1},
-    };
-    for (unsigned int cmdNum = 0; cmdNum < ARRAY_SIZE(defaultCommands); cmdNum++) {
-        if (runCmd(ARRAY_SIZE(defaultCommands[cmdNum].cmd), defaultCommands[cmdNum].cmd) &&
-            defaultCommands[cmdNum].checkRes) {
-                return -1;
-        }
+    std::string v4Cmd = StringPrintf(
+        "*filter\n"
+        ":%s -\n"
+        "-A %s -j DROP\n"
+        "COMMIT\n"
+        "*nat\n"
+        ":%s -\n"
+        "COMMIT\n", LOCAL_FORWARD, LOCAL_FORWARD, LOCAL_NAT_POSTROUTING);
+
+    std::string v6Cmd = StringPrintf(
+        "*filter\n"
+        ":%s -\n"
+        "COMMIT\n"
+        "*raw\n"
+        ":%s -\n"
+        "COMMIT\n", LOCAL_FORWARD, LOCAL_RAW_PREROUTING);
+
+    int res = iptablesRestoreFunction(V4, v4Cmd);
+    if (res < 0) {
+        return res;
+    }
+
+    res = iptablesRestoreFunction(V6, v6Cmd);
+    if (res < 0) {
+        return res;
     }
 
     natCount = 0;