Drop packets to the clat address.

These packets are not needed for 464xlat to function because
clatd reads packets from packet sockets, which run before
iptables, and the TC action also happens before packet sockets.

Their existence complicates data usage accounting, and in
certain situations results in applications receiving duplicate
UDP packets.

Bug: 65674744
Bug: 136193260
Test: atest netd_unit_test

Merged-In: I26bd8a1e7a54dbac86971b4e62f88f46ae5466f1
Change-Id: Iab2a64d8a8a380a2448170c9af5109b969527861
(cherry picked from commit cbb2447617d77bc8982945ebc2876a166559b585)
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"