Snap for 5704971 from cfc15dd03578051f88a40d94dcb42b2597614a1f to qt-release

Change-Id: I275627be5b536b5ba4b034b5ed4407135a29dd72
diff --git a/server/ClatdController.cpp b/server/ClatdController.cpp
index d82198b..5a5566b 100644
--- a/server/ClatdController.cpp
+++ b/server/ClatdController.cpp
@@ -36,6 +36,7 @@
 
 #include "android-base/properties.h"
 #include "android-base/scopeguard.h"
+#include "android-base/stringprintf.h"
 #include "android-base/unique_fd.h"
 #include "bpf/BpfMap.h"
 #include "netdbpf/bpf_shared.h"
@@ -59,6 +60,7 @@
 static const in_addr kV4Addr = {inet_addr(kV4AddrString)};
 static const int kV4AddrLen = 29;
 
+using android::base::StringPrintf;
 using android::base::unique_fd;
 using android::bpf::BpfMap;
 using android::netdutils::DumpWriter;
@@ -312,6 +314,18 @@
     // success
 }
 
+void ClatdController::maybeSetIptablesDropRule(bool add, const char* pfx96Str, const char* v6Str) {
+    if (mClatEbpfMode == ClatEbpfDisabled) return;
+
+    std::string cmd = StringPrintf(
+            "*raw\n"
+            "%s %s -s %s/96 -d %s -j DROP\n"
+            "COMMIT\n",
+            (add ? "-A" : "-D"), LOCAL_RAW_PREROUTING, pfx96Str, v6Str);
+
+    iptablesRestoreFunction(V6, cmd);
+}
+
 void ClatdController::maybeStopBpf(const ClatdTracker& tracker) {
     if (mClatEbpfMode == ClatEbpfDisabled) return;
 
@@ -502,14 +516,17 @@
         return -res;
     }
 
-    // 11. actually perform vfork/dup2/execve
+    // 11. If necessary, add the drop rule for iptables.
+    maybeSetIptablesDropRule(true, tracker.pfx96String, tracker.v6Str);
+
+    // 12. actually perform vfork/dup2/execve
     res = posix_spawn(&tracker.pid, kClatdPath, &fa, &attr, (char* const*)args, nullptr);
     if (res) {
         ALOGE("posix_spawn failed (%s)", strerror(res));
         return -res;
     }
 
-    // 12. configure eBPF offload - if possible
+    // 13. configure eBPF offload - if possible
     maybeStartBpf(tracker);
 
     mClatdTrackers[interface] = tracker;
@@ -534,6 +551,8 @@
 
     kill(tracker->pid, SIGTERM);
     waitpid(tracker->pid, nullptr, 0);
+
+    maybeSetIptablesDropRule(false, tracker->pfx96String, tracker->v6Str);
     mClatdTrackers.erase(interface);
 
     ALOGD("clatd on %s stopped", interface.c_str());
@@ -593,6 +612,7 @@
 }
 
 auto ClatdController::isIpv4AddressFreeFunc = isIpv4AddressFree;
+auto ClatdController::iptablesRestoreFunction = execIptablesRestore;
 
 }  // namespace net
 }  // namespace android
diff --git a/server/ClatdController.h b/server/ClatdController.h
index a00f713..8648f17 100644
--- a/server/ClatdController.h
+++ b/server/ClatdController.h
@@ -52,6 +52,8 @@
 
     void dump(netdutils::DumpWriter& dw) EXCLUDES(mutex);
 
+    static constexpr const char LOCAL_RAW_PREROUTING[] = "clat_raw_PREROUTING";
+
   private:
     struct ClatdTracker {
         pid_t pid = -1;
@@ -91,17 +93,25 @@
         ClatEbpfEnabled,   // >=4.9 kernel && >=Q api shipping level -- must work
     };
     eClatEbpfMode mClatEbpfMode GUARDED_BY(mutex);
+    eClatEbpfMode getEbpfMode() EXCLUDES(mutex) {
+        std::lock_guard guard(mutex);
+        return mClatEbpfMode;
+    }
+
     base::unique_fd mNetlinkFd GUARDED_BY(mutex);
     bpf::BpfMap<ClatIngressKey, ClatIngressValue> mClatIngressMap GUARDED_BY(mutex);
 
     void maybeStartBpf(const ClatdTracker& tracker) REQUIRES(mutex);
     void maybeStopBpf(const ClatdTracker& tracker) REQUIRES(mutex);
+    void maybeSetIptablesDropRule(bool add, const char* pfx96Str, const char* v6Str)
+            REQUIRES(mutex);
 
     // For testing.
     friend class ClatdControllerTest;
 
     static bool (*isIpv4AddressFreeFunc)(in_addr_t);
     static bool isIpv4AddressFree(in_addr_t addr);
+    static int (*iptablesRestoreFunction)(IptablesTarget target, const std::string& commands);
 };
 
 }  // namespace net
diff --git a/server/ClatdControllerTest.cpp b/server/ClatdControllerTest.cpp
index a4a271a..e90dd1a 100644
--- a/server/ClatdControllerTest.cpp
+++ b/server/ClatdControllerTest.cpp
@@ -31,6 +31,8 @@
 }
 
 #include "ClatdController.h"
+#include "IptablesBaseTest.h"
+#include "NetworkController.h"
 #include "tun_interface.h"
 
 static const char kIPv4LocalAddr[] = "192.0.0.4";
@@ -57,11 +59,21 @@
     return (ntohl(addr) & 0xff) == 10;
 }
 
-class ClatdControllerTest : public ::testing::Test {
+class ClatdControllerTest : public IptablesBaseTest {
   public:
+    ClatdControllerTest() : mClatdCtrl(nullptr) {
+        ClatdController::iptablesRestoreFunction = fakeExecIptablesRestore;
+    }
+
     void SetUp() { resetIpv4AddressFreeFunc(); }
 
   protected:
+    ClatdController mClatdCtrl;
+    bool isEbpfDisabled() { return mClatdCtrl.getEbpfMode() == ClatdController::ClatEbpfDisabled; }
+    void maybeSetIptablesDropRule(bool a, const char* b, const char* c) {
+        std::lock_guard guard(mClatdCtrl.mutex);
+        return mClatdCtrl.maybeSetIptablesDropRule(a, b, c);
+    }
     void setIpv4AddressFreeFunc(bool (*func)(in_addr_t)) {
         ClatdController::isIpv4AddressFreeFunc = func;
     }
@@ -175,5 +187,27 @@
     EXPECT_GE(3210000, onebits);
 }
 
+TEST_F(ClatdControllerTest, AddRemoveIptablesRule) {
+    if (isEbpfDisabled()) return;
+
+    ExpectedIptablesCommands expected = {
+            {V6,
+             "*raw\n"
+             "-A clat_raw_PREROUTING -s 64:ff9b::/96 -d 2001:db8::1:2:3:4 -j DROP\n"
+             "COMMIT\n"},
+    };
+    maybeSetIptablesDropRule(true, "64:ff9b::", "2001:db8::1:2:3:4");
+    expectIptablesRestoreCommands(expected);
+
+    expected = {
+            {V6,
+             "*raw\n"
+             "-D clat_raw_PREROUTING -s 64:ff9b::/96 -d 2001:db8::a:b:c:d -j DROP\n"
+             "COMMIT\n"},
+    };
+    maybeSetIptablesDropRule(false, "64:ff9b::", "2001:db8::a:b:c:d");
+    expectIptablesRestoreCommands(expected);
+}
+
 }  // namespace net
 }  // namespace android
diff --git a/server/Controllers.cpp b/server/Controllers.cpp
index 01eae77..c941a80 100644
--- a/server/Controllers.cpp
+++ b/server/Controllers.cpp
@@ -73,6 +73,7 @@
 };
 
 static const std::vector<const char*> RAW_PREROUTING = {
+        ClatdController::LOCAL_RAW_PREROUTING,
         BandwidthController::LOCAL_RAW_PREROUTING,
         IdletimerController::LOCAL_RAW_PREROUTING,
         TetherController::LOCAL_RAW_PREROUTING,
diff --git a/server/ControllersTest.cpp b/server/ControllersTest.cpp
index cc8b1aa..ebaa38f 100644
--- a/server/ControllersTest.cpp
+++ b/server/ControllersTest.cpp
@@ -96,6 +96,8 @@
              "*raw\n"
              ":PREROUTING -\n"
              "-F PREROUTING\n"
+             ":clat_raw_PREROUTING -\n"
+             "-A PREROUTING -j clat_raw_PREROUTING\n"
              ":bw_raw_PREROUTING -\n"
              "-A PREROUTING -j bw_raw_PREROUTING\n"
              ":idletimer_raw_PREROUTING -\n"