Add tests for interface add/remove binder API

Bug: 30298058
Change-Id: Ib16f02667cdae06688106bf064d17db693d60cd5
diff --git a/server/NetdConstants.h b/server/NetdConstants.h
index e3f533a..605362c 100644
--- a/server/NetdConstants.h
+++ b/server/NetdConstants.h
@@ -19,6 +19,8 @@
 
 #include <string>
 #include <list>
+#include <ifaddrs.h>
+#include <netdb.h>
 #include <stdarg.h>
 
 #include <chrono>
@@ -73,6 +75,28 @@
     std::chrono::time_point<std::chrono::steady_clock> mStart;
 };
 
+
+struct AddrinfoDeleter {
+    void operator()(struct addrinfo* p) const {
+        if (p != nullptr) {
+            freeaddrinfo(p);
+        }
+    }
+};
+
+typedef std::unique_ptr<struct addrinfo, struct AddrinfoDeleter> ScopedAddrinfo;
+
+
+struct IfaddrsDeleter {
+    void operator()(struct ifaddrs *p) const {
+        if (p != nullptr) {
+            freeifaddrs(p);
+        }
+    }
+};
+
+typedef std::unique_ptr<struct ifaddrs, struct IfaddrsDeleter> ScopedIfaddrs;
+
 namespace android {
 namespace net {
 
diff --git a/server/SockDiag.cpp b/server/SockDiag.cpp
index 41e92c2..e91c6d1 100644
--- a/server/SockDiag.cpp
+++ b/server/SockDiag.cpp
@@ -42,12 +42,6 @@
 
 namespace {
 
-struct AddrinfoDeleter {
-  void operator()(addrinfo *a) { if (a) freeaddrinfo(a); }
-};
-
-typedef std::unique_ptr<addrinfo, AddrinfoDeleter> ScopedAddrinfo;
-
 int checkError(int fd) {
     struct {
         nlmsghdr h;
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index 661680c..9909aef 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -25,6 +25,7 @@
 #include <vector>
 
 #include <fcntl.h>
+#include <ifaddrs.h>
 #include <netdb.h>
 #include <sys/socket.h>
 #include <sys/types.h>
@@ -32,6 +33,7 @@
 #include <linux/if.h>
 #include <linux/if_tun.h>
 
+#include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <cutils/multiuser.h>
@@ -73,6 +75,7 @@
     // Static because setting up the tun interface takes about 40ms.
     static void SetUpTestCase() {
         sTunFd = createTunInterface();
+        ASSERT_LE(sTunIfName.size(), static_cast<size_t>(IFNAMSIZ));
         ASSERT_NE(-1, sTunFd);
     }
 
@@ -87,11 +90,13 @@
 protected:
     sp<INetd> mNetd;
     static int sTunFd;
+    static std::string sTunIfName;
     static in6_addr sSrcAddr, sDstAddr;
     static char sSrcStr[], sDstStr[];
 };
 
 int BinderTest::sTunFd;
+std::string BinderTest::sTunIfName;
 in6_addr BinderTest::sSrcAddr;
 in6_addr BinderTest::sDstAddr;
 char BinderTest::sSrcStr[INET6_ADDRSTRLEN];
@@ -343,10 +348,11 @@
     }
 
     // Create a tun interface with a name based on our PID.
+    sTunIfName = StringPrintf("netdtest%u", getpid());
     struct ifreq ifr = {
         .ifr_ifru = { .ifru_flags = IFF_TUN },
     };
-    snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "netdtest%u", getpid());
+    snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", sTunIfName.c_str());
 
     int fd = open(TUN_DEV, O_RDWR | O_NONBLOCK | O_CLOEXEC);
     EXPECT_NE(-1, fd) << TUN_DEV << ": " << strerror(errno);
@@ -456,3 +462,158 @@
     close(serverSocket);
     close(acceptedSocket);
 }
+
+namespace {
+
+int netmaskToPrefixLength(const uint8_t *buf, size_t buflen) {
+    if (buf == nullptr) return -1;
+
+    int prefixLength = 0;
+    bool endOfContiguousBits = false;
+    for (unsigned int i = 0; i < buflen; i++) {
+        const uint8_t value = buf[i];
+
+        // Bad bit sequence: check for a contiguous set of bits from the high
+        // end by verifying that the inverted value + 1 is a power of 2
+        // (power of 2 iff. (v & (v - 1)) == 0).
+        const uint8_t inverse = ~value + 1;
+        if ((inverse & (inverse - 1)) != 0) return -1;
+
+        prefixLength += (value == 0) ? 0 : CHAR_BIT - ffs(value) + 1;
+
+        // Bogus netmask.
+        if (endOfContiguousBits && value != 0) return -1;
+
+        if (value != 0xff) endOfContiguousBits = true;
+    }
+
+    return prefixLength;
+}
+
+template<typename T>
+int netmaskToPrefixLength(const T *p) {
+    return netmaskToPrefixLength(reinterpret_cast<const uint8_t*>(p), sizeof(T));
+}
+
+
+static bool interfaceHasAddress(
+        const std::string &ifname, const char *addrString, int prefixLength) {
+    struct addrinfo *addrinfoList = nullptr;
+    ScopedAddrinfo addrinfoCleanup(addrinfoList);
+
+    const struct addrinfo hints = {
+        .ai_flags    = AI_NUMERICHOST,
+        .ai_family   = AF_UNSPEC,
+        .ai_socktype = SOCK_DGRAM,
+    };
+    if (getaddrinfo(addrString, nullptr, &hints, &addrinfoList) != 0 ||
+        addrinfoList == nullptr || addrinfoList->ai_addr == nullptr) {
+        return false;
+    }
+
+    struct ifaddrs *ifaddrsList = nullptr;
+    ScopedIfaddrs ifaddrsCleanup(ifaddrsList);
+
+    if (getifaddrs(&ifaddrsList) != 0) {
+        return false;
+    }
+
+    for (struct ifaddrs *addr = ifaddrsList; addr != nullptr; addr = addr->ifa_next) {
+        if (std::string(addr->ifa_name) != ifname ||
+            addr->ifa_addr == nullptr ||
+            addr->ifa_addr->sa_family != addrinfoList->ai_addr->sa_family) {
+            continue;
+        }
+
+        switch (addr->ifa_addr->sa_family) {
+        case AF_INET: {
+            auto *addr4 = reinterpret_cast<const struct sockaddr_in*>(addr->ifa_addr);
+            auto *want = reinterpret_cast<const struct sockaddr_in*>(addrinfoList->ai_addr);
+            if (memcmp(&addr4->sin_addr, &want->sin_addr, sizeof(want->sin_addr)) != 0) {
+                continue;
+            }
+
+            if (prefixLength < 0) return true;  // not checking prefix lengths
+
+            if (addr->ifa_netmask == nullptr) return false;
+            auto *nm = reinterpret_cast<const struct sockaddr_in*>(addr->ifa_netmask);
+            EXPECT_EQ(prefixLength, netmaskToPrefixLength(&nm->sin_addr));
+            return (prefixLength == netmaskToPrefixLength(&nm->sin_addr));
+        }
+        case AF_INET6: {
+            auto *addr6 = reinterpret_cast<const struct sockaddr_in6*>(addr->ifa_addr);
+            auto *want = reinterpret_cast<const struct sockaddr_in6*>(addrinfoList->ai_addr);
+            if (memcmp(&addr6->sin6_addr, &want->sin6_addr, sizeof(want->sin6_addr)) != 0) {
+                continue;
+            }
+
+            if (prefixLength < 0) return true;  // not checking prefix lengths
+
+            if (addr->ifa_netmask == nullptr) return false;
+            auto *nm = reinterpret_cast<const struct sockaddr_in6*>(addr->ifa_netmask);
+            EXPECT_EQ(prefixLength, netmaskToPrefixLength(&nm->sin6_addr));
+            return (prefixLength == netmaskToPrefixLength(&nm->sin6_addr));
+        }
+        default:
+            // Cannot happen because we have already screened for matching
+            // address families at the top of each iteration.
+            continue;
+        }
+    }
+
+    return false;
+}
+
+}  // namespace
+
+TEST_F(BinderTest, TestInterfaceAddRemoveAddress) {
+    static const struct TestData {
+        const char *addrString;
+        const int   prefixLength;
+        const bool  expectSuccess;
+    } kTestData[] = {
+        { "192.0.2.1", 24, true },
+        { "192.0.2.2", 25, true },
+        { "192.0.2.3", 32, true },
+        { "192.0.2.4", 33, false },
+        { "192.not.an.ip", 24, false },
+        { "2001:db8::1", 64, true },
+        { "2001:db8::2", 65, true },
+        { "2001:db8::3", 128, true },
+        { "2001:db8::4", 129, false },
+        { "foo:bar::bad", 64, false },
+    };
+
+    for (unsigned int i = 0; i < arraysize(kTestData); i++) {
+        const auto &td = kTestData[i];
+
+        // [1.a] Add the address.
+        binder::Status status = mNetd->interfaceAddAddress(
+                sTunIfName, td.addrString, td.prefixLength);
+        if (td.expectSuccess) {
+            EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+        } else {
+            ASSERT_EQ(binder::Status::EX_SERVICE_SPECIFIC, status.exceptionCode());
+            ASSERT_NE(0, status.serviceSpecificErrorCode());
+        }
+
+        // [1.b] Verify the addition meets the expectation.
+        if (td.expectSuccess) {
+            EXPECT_TRUE(interfaceHasAddress(sTunIfName, td.addrString, td.prefixLength));
+        } else {
+            EXPECT_FALSE(interfaceHasAddress(sTunIfName, td.addrString, -1));
+        }
+
+        // [2.a] Try to remove the address.  If it was not previously added, removing it fails.
+        status = mNetd->interfaceDelAddress(sTunIfName, td.addrString, td.prefixLength);
+        if (td.expectSuccess) {
+            EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+        } else {
+            ASSERT_EQ(binder::Status::EX_SERVICE_SPECIFIC, status.exceptionCode());
+            ASSERT_NE(0, status.serviceSpecificErrorCode());
+        }
+
+        // [2.b] No matter what, the address should not be present.
+        EXPECT_FALSE(interfaceHasAddress(sTunIfName, td.addrString, -1));
+    }
+}