Merge "Solve compiler warning related to string size"
diff --git a/bpf_progs/offload.c b/bpf_progs/offload.c
index 9b475b1..7d33e46 100644
--- a/bpf_progs/offload.c
+++ b/bpf_progs/offload.c
@@ -146,8 +146,9 @@
     return do_forward(skb, true);
 }
 
-SEC("schedcls/ingress/tether_rawip")
-int sched_cls_ingress_tether_rawip(struct __sk_buff* skb) {
+DEFINE_BPF_PROG_KVER("schedcls/ingress/tether_rawip", AID_ROOT, AID_ROOT,
+                     sched_cls_ingress_tether_rawip, KVER(4, 14, 0))
+(struct __sk_buff* skb) {
     return do_forward(skb, false);
 }
 
diff --git a/server/Android.bp b/server/Android.bp
index 3f0373e..b21b070 100644
--- a/server/Android.bp
+++ b/server/Android.bp
@@ -25,6 +25,7 @@
         "InterfaceController.cpp",
         "NetlinkCommands.cpp",
         "NetlinkListener.cpp",
+        "SockDiag.cpp",
         "XfrmController.cpp",
         "TrafficController.cpp",
     ],
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index 0b87715..baea57d 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -35,12 +35,14 @@
 #include <net/if.h>
 #include <netdb.h>
 #include <netinet/in.h>
+#include <netinet/tcp.h>
 #include <openssl/base64.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 
 #include <android-base/file.h>
 #include <android-base/macros.h>
+#include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android/multinetwork.h>
@@ -58,6 +60,7 @@
 #include "NetdClient.h"
 #include "NetdConstants.h"
 #include "NetworkController.h"
+#include "SockDiag.h"
 #include "TestUnsolService.h"
 #include "XfrmController.h"
 #include "android/net/INetd.h"
@@ -84,6 +87,7 @@
 using android::String16;
 using android::String8;
 using android::base::Join;
+using android::base::make_scope_guard;
 using android::base::ReadFileToString;
 using android::base::StartsWith;
 using android::base::StringPrintf;
@@ -93,10 +97,12 @@
 using android::net::InterfaceConfigurationParcel;
 using android::net::InterfaceController;
 using android::net::MarkMaskParcel;
+using android::net::SockDiag;
 using android::net::TetherOffloadRuleParcel;
 using android::net::TetherStatsParcel;
 using android::net::TunInterface;
 using android::net::UidRangeParcel;
+using android::netdutils::IPAddress;
 using android::netdutils::ScopedAddrinfo;
 using android::netdutils::sSyscalls;
 using android::netdutils::Stopwatch;
@@ -105,6 +111,7 @@
 static const char* IP_RULE_V6 = "-6";
 static const int TEST_NETID1 = 65501;
 static const int TEST_NETID2 = 65502;
+static const char* DNSMASQ = "dnsmasq";
 
 // Use maximum reserved appId for applications to avoid conflict with existing
 // uids.
@@ -2076,8 +2083,6 @@
 
 TEST_F(BinderTest, TetherStartStopStatus) {
     std::vector<std::string> noDhcpRange = {};
-    static const char dnsdName[] = "dnsmasq";
-
     for (bool usingLegacyDnsProxy : {true, false}) {
         android::net::TetherConfigParcel config;
         config.usingLegacyDnsProxy = usingLegacyDnsProxy;
@@ -2086,9 +2091,9 @@
         EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
         SCOPED_TRACE(StringPrintf("usingLegacyDnsProxy: %d", usingLegacyDnsProxy));
         if (usingLegacyDnsProxy == true) {
-            expectProcessExists(dnsdName);
+            expectProcessExists(DNSMASQ);
         } else {
-            expectProcessDoesNotExist(dnsdName);
+            expectProcessDoesNotExist(DNSMASQ);
         }
 
         bool tetherEnabled;
@@ -2098,7 +2103,7 @@
 
         status = mNetd->tetherStop();
         EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
-        expectProcessDoesNotExist(dnsdName);
+        expectProcessDoesNotExist(DNSMASQ);
 
         status = mNetd->tetherIsEnabled(&tetherEnabled);
         EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
@@ -2143,6 +2148,135 @@
 
 namespace {
 
+std::vector<IPAddress> findDnsSockets(SockDiag* sd, unsigned numExpected) {
+    std::vector<IPAddress> listenAddrs;
+
+    // Callback lambda that finds all IPv4 sockets with source port 53.
+    auto findDnsSockets = [&](uint8_t /* proto */, const inet_diag_msg* msg) {
+        // Always return false, which means do not destroy this socket.
+        if (msg->id.idiag_sport != htons(53)) return false;
+        IPAddress addr(*(in_addr*)msg->id.idiag_src);
+        listenAddrs.push_back(addr);
+        return false;
+    };
+
+    // There is no way to know if dnsmasq has finished processing the update_interfaces command and
+    // opened listening sockets. So, just spin a few times and return the first list of sockets
+    // that is at least numExpected long.
+    // Pick a relatively large timeout to avoid flaky tests. Testing suggests that 5 attempts are
+    // sufficient for the test to pass 500 times in a row on crosshatch-eng.  Pick 10 to be safe.
+    constexpr int kMaxAttempts = 10;
+    constexpr int kSleepMs = 100;
+    for (int i = 0; i < kMaxAttempts; i++) {
+        listenAddrs.clear();
+        EXPECT_EQ(0, sd->sendDumpRequest(IPPROTO_TCP, AF_INET, 1 << TCP_LISTEN))
+                << "Failed to dump sockets, attempt " << i << " of " << kMaxAttempts;
+        sd->readDiagMsg(IPPROTO_TCP, findDnsSockets);
+        if (listenAddrs.size() >= numExpected) {
+            break;
+        }
+        usleep(kSleepMs * 1000);
+    }
+
+    return listenAddrs;
+}
+
+}  // namespace
+
+// Checks that when starting dnsmasq on an interface that no longer exists, it doesn't attempt to
+// start on other interfaces instead.
+TEST_F(BinderTest, TetherDeletedInterface) {
+    // Do this first so we don't need to clean up anything else if it fails.
+    SockDiag sd;
+    ASSERT_TRUE(sd.open()) << "Failed to open SOCK_DIAG socket";
+
+    // Create our own TunInterfaces (so we can delete them without affecting other tests), and add
+    // IP addresses to them. They must be IPv4 because tethering an interface disables and
+    // re-enables IPv6 on the interface, which clears all addresses.
+    TunInterface tun1, tun2;
+    ASSERT_EQ(0, tun1.init());
+    ASSERT_EQ(0, tun2.init());
+
+    // Clean up. It is safe to call TunInterface::destroy multiple times.
+    auto guard = android::base::make_scope_guard([&] {
+        tun1.destroy();
+        tun2.destroy();
+        mNetd->tetherStop();
+        mNetd->tetherInterfaceRemove(tun1.name());
+        mNetd->tetherInterfaceRemove(tun2.name());
+    });
+
+    IPAddress addr1, addr2;
+    ASSERT_TRUE(IPAddress::forString("192.0.2.1", &addr1));
+    ASSERT_TRUE(IPAddress::forString("192.0.2.2", &addr2));
+    EXPECT_EQ(0, tun1.addAddress(addr1.toString(), 32));
+    EXPECT_EQ(0, tun2.addAddress(addr2.toString(), 32));
+
+    // Stop tethering.
+    binder::Status status = mNetd->tetherStop();
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+
+    // Start dnsmasq on an interface that doesn't exist.
+    // First, tether our tun interface...
+    status = mNetd->tetherInterfaceAdd(tun1.name());
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+    expectTetherInterfaceConfigureForIPv6Router(tun1.name());
+
+    // ... then delete it...
+    tun1.destroy();
+
+    // ... then start dnsmasq.
+    android::net::TetherConfigParcel config;
+    config.usingLegacyDnsProxy = true;
+    config.dhcpRanges = {};
+    status = mNetd->tetherStartWithConfiguration(config);
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+
+    // Wait for dnsmasq to start.
+    expectProcessExists(DNSMASQ);
+
+    // Make sure that netd thinks the interface is tethered (even though it doesn't exist).
+    std::vector<std::string> ifList;
+    status = mNetd->tetherInterfaceList(&ifList);
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+    ASSERT_EQ(1U, ifList.size());
+    EXPECT_EQ(tun1.name(), ifList[0]);
+
+    // Give dnsmasq some time to start up.
+    usleep(200 * 1000);
+
+    // Check that dnsmasq is not listening on any IP addresses. It shouldn't, because it was only
+    // told to run on tun1, and tun1 does not exist. Ensure it stays running and doesn't listen on
+    // any IP addresses.
+    std::vector<IPAddress> listenAddrs = findDnsSockets(&sd, 0);
+    EXPECT_EQ(0U, listenAddrs.size()) << "Unexpectedly found IPv4 socket(s) listening on port 53";
+
+    // Now add an interface to dnsmasq and check that we can see the sockets. This confirms that
+    // findDnsSockets is actually able to see sockets when they exist.
+    status = mNetd->tetherInterfaceAdd(tun2.name());
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+
+    in_addr loopback = {htonl(INADDR_LOOPBACK)};
+    listenAddrs = findDnsSockets(&sd, 2);
+    EXPECT_EQ(2U, listenAddrs.size()) << "Expected exactly 2 IPv4 sockets listening on port 53";
+    EXPECT_EQ(1, std::count(listenAddrs.begin(), listenAddrs.end(), addr2));
+    EXPECT_EQ(1, std::count(listenAddrs.begin(), listenAddrs.end(), IPAddress(loopback)));
+
+    // Clean up.
+    status = mNetd->tetherStop();
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+
+    expectProcessDoesNotExist(DNSMASQ);
+
+    status = mNetd->tetherInterfaceRemove(tun1.name());
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+
+    status = mNetd->tetherInterfaceRemove(tun2.name());
+    EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+}
+
+namespace {
+
 constexpr char FIREWALL_INPUT[] = "fw_INPUT";
 constexpr char FIREWALL_OUTPUT[] = "fw_OUTPUT";
 constexpr char FIREWALL_FORWARD[] = "fw_FORWARD";