Merge "Remap existing EAI_SYSTEM to avoid relying on global errno variable"
diff --git a/bpf_progs/clatd.c b/bpf_progs/clatd.c
index b66591b..4c2953f 100644
--- a/bpf_progs/clatd.c
+++ b/bpf_progs/clatd.c
@@ -14,10 +14,40 @@
  * limitations under the License.
  */
 
+#include <linux/bpf.h>
+#include <linux/if.h>
+#include <linux/if_ether.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
 #include <linux/pkt_cls.h>
+#include <linux/swab.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <stdbool.h>
+#include <stdint.h>
+
 #include "bpf_helpers.h"
 #include "netdbpf/bpf_shared.h"
 
+// bionic/libc/kernel/uapi/linux/udp.h:
+//   struct __kernel_udphdr {
+// bionic/libc/kernel/tools/defaults.py:
+//   # We want to support both BSD and Linux member names in struct udphdr.
+//   "udphdr": "__kernel_udphdr",
+// so instead it just doesn't work... ugh.
+#define udphdr __kernel_udphdr
+
+// From kernel:include/net/ip.h
+#define IP_DF 0x4000  // Flag: "Don't Fragment"
+
+// Android only supports little endian architectures
+#define htons(x) (__builtin_constant_p(x) ? ___constant_swab16(x) : __builtin_bswap16(x))
+#define htonl(x) (__builtin_constant_p(x) ? ___constant_swab32(x) : __builtin_bswap32(x))
+#define ntohs(x) htons(x)
+#define ntohl(x) htonl(x)
+
 struct bpf_map_def SEC("maps") clat_ingress_map = {
         .type = BPF_MAP_TYPE_HASH,
         .key_size = sizeof(struct ClatIngressKey),
@@ -25,14 +55,130 @@
         .max_entries = 16,
 };
 
+static inline __always_inline int nat64(struct __sk_buff* skb, bool is_ethernet) {
+    const int l2_header_size = is_ethernet ? sizeof(struct ethhdr) : 0;
+    void* data = (void*)(long)skb->data;
+    const void* data_end = (void*)(long)skb->data_end;
+    const struct ethhdr* const eth = is_ethernet ? data : NULL;  // used iff is_ethernet
+    const struct ipv6hdr* const ip6 = is_ethernet ? (void*)(eth + 1) : data;
+    const struct tcphdr* const tcp = (void*)(ip6 + 1);
+    const struct udphdr* const udp = (void*)(ip6 + 1);
+
+    // Must be meta-ethernet IPv6 frame
+    if (skb->protocol != htons(ETH_P_IPV6)) return TC_ACT_OK;
+
+    // Must have (ethernet and) ipv6 header
+    if (data + l2_header_size + sizeof(*ip6) > data_end) return TC_ACT_OK;
+
+    // Ethertype - if present - must be IPv6
+    if (is_ethernet && (eth->h_proto != htons(ETH_P_IPV6))) return TC_ACT_OK;
+
+    // IP version must be 6
+    if (ip6->version != 6) return TC_ACT_OK;
+
+    // Maximum IPv6 payload length that can be translated to IPv4
+    if (ntohs(ip6->payload_len) > 0xFFFF - sizeof(struct iphdr)) return TC_ACT_OK;
+
+    switch (ip6->nexthdr) {
+        case IPPROTO_TCP:  // If TCP, must have 20 byte minimal TCP header
+            if (tcp + 1 > (struct tcphdr*)data_end) return TC_ACT_OK;
+            break;
+
+        case IPPROTO_UDP:  // If UDP, must have 8 byte minimal UDP header
+            if (udp + 1 > (struct udphdr*)data_end) return TC_ACT_OK;
+            break;
+
+        default:  // do not know how to handle anything else
+            return TC_ACT_OK;
+    }
+
+    struct ClatIngressKey k = {
+            .iif = skb->ifindex,
+            .pfx96.in6_u.u6_addr32 =
+                    {
+                            ip6->saddr.in6_u.u6_addr32[0],
+                            ip6->saddr.in6_u.u6_addr32[1],
+                            ip6->saddr.in6_u.u6_addr32[2],
+                    },
+            .local6 = ip6->daddr,
+    };
+
+    struct ClatIngressValue* v = bpf_map_lookup_elem(&clat_ingress_map, &k);
+
+    if (!v) return TC_ACT_OK;
+
+    struct ethhdr eth2;  // used iff is_ethernet
+    if (is_ethernet) {
+        eth2 = *eth;                     // Copy over the ethernet header (src/dst mac)
+        eth2.h_proto = htons(ETH_P_IP);  // But replace the ethertype
+    }
+
+    struct iphdr ip = {
+            .version = 4,                                                      // u4
+            .ihl = sizeof(struct iphdr) / sizeof(__u32),                       // u4
+            .tos = (ip6->priority << 4) + (ip6->flow_lbl[0] >> 4),             // u8
+            .tot_len = htons(ntohs(ip6->payload_len) + sizeof(struct iphdr)),  // u16
+            .id = 0,                                                           // u16
+            .frag_off = htons(IP_DF),                                          // u16
+            .ttl = ip6->hop_limit,                                             // u8
+            .protocol = ip6->nexthdr,                                          // u8
+            .check = 0,                                                        // u16
+            .saddr = ip6->saddr.in6_u.u6_addr32[3],                            // u32
+            .daddr = v->local4.s_addr,                                         // u32
+    };
+
+    // Calculate the IPv4 one's complement checksum of the IPv4 header.
+    __u32 sum = 0;
+    for (int i = 0; i < sizeof(ip) / sizeof(__u16); ++i) {
+        sum += ((__u16*)&ip)[i];
+    }
+    // Note that sum is guaranteed to be non-zero by virtue of ip.version == 4
+    sum = (sum & 0xFFFF) + (sum >> 16);  // collapse u32 into range 1 .. 0x1FFFE
+    sum = (sum & 0xFFFF) + (sum >> 16);  // collapse any potential carry into u16
+    ip.check = (__u16)~sum;              // sum cannot be zero, so this is never 0xFFFF
+
+    // Note that there is no L4 checksum update: we are relying on the checksum neutrality
+    // of the ipv6 address chosen by netd's ClatdController.
+
+    // Packet mutations begin - point of no return.
+    if (bpf_skb_change_proto(skb, htons(ETH_P_IP), 0)) return TC_ACT_SHOT;
+
+    // bpf_skb_change_proto() invalidates all pointers - reload them.
+    data = (void*)(long)skb->data;
+    data_end = (void*)(long)skb->data_end;
+
+    // I cannot think of any valid way for this error condition to trigger, however I do
+    // believe the explicit check is required to keep the in kernel ebpf verifier happy.
+    if (data + l2_header_size + sizeof(struct iphdr) > data_end) return TC_ACT_SHOT;
+
+    if (is_ethernet) {
+        struct ethhdr* new_eth = data;
+
+        // Copy over the updated ethernet header
+        *new_eth = eth2;
+
+        // Copy over the new ipv4 header.
+        *(struct iphdr*)(new_eth + 1) = ip;
+    } else {
+        // Copy over the new ipv4 header without an ethernet header.
+        *(struct iphdr*)data = ip;
+    }
+
+    // Redirect, possibly back to same interface, so tcpdump sees packet twice.
+    if (v->oif) return bpf_redirect(v->oif, BPF_F_INGRESS);
+
+    // Just let it through, tcpdump will not see IPv4 packet.
+    return TC_ACT_OK;
+}
+
 SEC("schedcls/ingress/clat_ether")
 int sched_cls_ingress_clat_ether(struct __sk_buff* skb) {
-    return TC_ACT_OK;
+    return nat64(skb, true);
 }
 
 SEC("schedcls/ingress/clat_rawip")
 int sched_cls_ingress_clat_rawip(struct __sk_buff* skb) {
-    return TC_ACT_OK;
+    return nat64(skb, false);
 }
 
 char _license[] SEC("license") = "Apache 2.0";
diff --git a/client/Android.bp b/client/Android.bp
index 4c27117..25b4f9d 100644
--- a/client/Android.bp
+++ b/client/Android.bp
@@ -25,7 +25,7 @@
     export_header_lib_headers: ["libnetd_client_headers"],
     include_dirs: [
         "system/netd/resolv",
-        "system/netd/include",
+        "system/netd/libnetdutils/include",
     ],
     defaults: ["netd_defaults"],
     product_variables: {
diff --git a/client/NetdClient.cpp b/client/NetdClient.cpp
index 195c45d..bc8d3fc 100644
--- a/client/NetdClient.cpp
+++ b/client/NetdClient.cpp
@@ -32,12 +32,13 @@
 #include "Fwmark.h"
 #include "FwmarkClient.h"
 #include "FwmarkCommand.h"
-#include "Stopwatch.h"
+#include "netdutils/Stopwatch.h"
 #include "netid_client.h"
 
 #include "android-base/unique_fd.h"
 
 using android::base::unique_fd;
+using android::netdutils::Stopwatch;
 
 namespace {
 
diff --git a/libnetdutils/Android.bp b/libnetdutils/Android.bp
index a1cbbbb..b3fcfc7 100644
--- a/libnetdutils/Android.bp
+++ b/libnetdutils/Android.bp
@@ -39,6 +39,7 @@
         "SliceTest.cpp",
         "StatusTest.cpp",
         "SyscallsTest.cpp",
+        "ThreadUtilTest.cpp",
     ],
     defaults: ["netd_defaults"],
     test_suites: ["device-tests"],
diff --git a/libnetdutils/ThreadUtilTest.cpp b/libnetdutils/ThreadUtilTest.cpp
new file mode 100644
index 0000000..2fe63b7
--- /dev/null
+++ b/libnetdutils/ThreadUtilTest.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "netdutils/ThreadUtil.h"
+
+namespace android {
+namespace netdutils {
+
+namespace {
+
+class NoopRun {
+  public:
+    NoopRun() { instanceNum++; }
+    ~NoopRun() { instanceNum--; }
+
+    void run() {}
+
+    static bool waitForAllReleased(int timeoutMs) {
+        constexpr int intervalMs = 20;
+        int limit = timeoutMs / intervalMs;
+        for (int i = 1; i < limit; i++) {
+            if (instanceNum == 0) {
+                return true;
+            }
+            usleep(intervalMs * 1000);
+        }
+        return false;
+    }
+
+    // To track how many instances are alive.
+    static std::atomic<int> instanceNum;
+};
+
+std::atomic<int> NoopRun::instanceNum;
+
+}  // namespace
+
+TEST(ThreadUtilTest, objectReleased) {
+    NoopRun::instanceNum = 0;
+    NoopRun* obj = new NoopRun();
+    EXPECT_EQ(1, NoopRun::instanceNum);
+    threadLaunch(obj);
+
+    // Wait for the object released along with the thread exited.
+    EXPECT_TRUE(NoopRun::waitForAllReleased(1000));
+    EXPECT_EQ(0, NoopRun::instanceNum);
+}
+
+}  // namespace netdutils
+}  // namespace android
diff --git a/server/ResponseCode.h b/libnetdutils/include/netdutils/ResponseCode.h
similarity index 94%
rename from server/ResponseCode.h
rename to libnetdutils/include/netdutils/ResponseCode.h
index b02fe29..5703ce8 100644
--- a/server/ResponseCode.h
+++ b/libnetdutils/include/netdutils/ResponseCode.h
@@ -14,8 +14,11 @@
  * limitations under the License.
  */
 
-#ifndef _RESPONSECODE_H
-#define _RESPONSECODE_H
+#ifndef NETDUTILS_RESPONSECODE_H
+#define NETDUTILS_RESPONSECODE_H
+
+namespace android {
+namespace netdutils {
 
 class ResponseCode {
     // Keep in sync with
@@ -80,4 +83,8 @@
     static const int RouteChange                    = 616;
     static const int StrictCleartext                = 617;
 };
-#endif
+
+}  // namespace netdutils
+}  // namespace android
+
+#endif  // NETDUTILS_RESPONSECODE_H
diff --git a/include/Stopwatch.h b/libnetdutils/include/netdutils/Stopwatch.h
similarity index 82%
rename from include/Stopwatch.h
rename to libnetdutils/include/netdutils/Stopwatch.h
index 31a921c..18e2050 100644
--- a/include/Stopwatch.h
+++ b/libnetdutils/include/netdutils/Stopwatch.h
@@ -14,16 +14,23 @@
  * limitations under the License.
  */
 
-#ifndef NETD_INCLUDE_STOPWATCH_H
-#define NETD_INCLUDE_STOPWATCH_H
+#ifndef NETDUTILS_STOPWATCH_H
+#define NETDUTILS_STOPWATCH_H
 
 #include <chrono>
 
+namespace android {
+namespace netdutils {
+
 class Stopwatch {
+  private:
+    using clock = std::chrono::steady_clock;
+    using time_point = std::chrono::time_point<clock>;
+
   public:
     Stopwatch() : mStart(clock::now()) {}
 
-    virtual ~Stopwatch() {};
+    virtual ~Stopwatch() = default;
 
     float timeTaken() const { return getElapsed(clock::now()); }
 
@@ -43,8 +50,6 @@
     }
 
   private:
-    typedef std::chrono::steady_clock clock;
-    typedef std::chrono::time_point<clock> time_point;
     time_point mStart;
 
     float getElapsed(const time_point& now) const {
@@ -56,4 +61,7 @@
     }
 };
 
-#endif  // NETD_INCLUDE_STOPWATCH_H
+}  // namespace netdutils
+}  // namespace android
+
+#endif  // NETDUTILS_STOPWATCH_H
diff --git a/server/thread_util.h b/libnetdutils/include/netdutils/ThreadUtil.h
similarity index 78%
rename from server/thread_util.h
rename to libnetdutils/include/netdutils/ThreadUtil.h
index 895ec57..2ef97ef 100644
--- a/server/thread_util.h
+++ b/libnetdutils/include/netdutils/ThreadUtil.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef NETD_SERVER_THREAD_UTIL_H
-#define NETD_SERVER_THREAD_UTIL_H
+#ifndef NETDUTILS_THREADUTIL_H
+#define NETDUTILS_THREADUTIL_H
 
 #include <pthread.h>
 #include <memory>
@@ -23,34 +23,36 @@
 #include <android-base/logging.h>
 
 namespace android {
-namespace net {
+namespace netdutils {
 
 struct scoped_pthread_attr {
     scoped_pthread_attr() { pthread_attr_init(&attr); }
     ~scoped_pthread_attr() { pthread_attr_destroy(&attr); }
 
-    int detach() {
-        return -pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-    }
+    int detach() { return -pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); }
 
     pthread_attr_t attr;
 };
 
-template<typename T>
+template <typename T>
 inline void* runAndDelete(void* obj) {
     std::unique_ptr<T> handler(reinterpret_cast<T*>(obj));
     handler->run();
     return nullptr;
 }
 
-template<typename T>
+template <typename T>
 inline int threadLaunch(T* obj) {
-    if (obj == nullptr) { return -EINVAL;}
+    if (obj == nullptr) {
+        return -EINVAL;
+    }
 
     scoped_pthread_attr scoped_attr;
 
     int rval = scoped_attr.detach();
-    if (rval != 0) { return rval; }
+    if (rval != 0) {
+        return rval;
+    }
 
     pthread_t thread;
     rval = pthread_create(&thread, &scoped_attr.attr, &runAndDelete<T>, obj);
@@ -62,7 +64,7 @@
     return rval;
 }
 
-}  // namespace net
+}  // namespace netdutils
 }  // namespace android
 
-#endif  // NETD_SERVER_THREAD_UTIL_H
+#endif  // NETDUTILS_THREADUTIL_H
diff --git a/resolv/Android.bp b/resolv/Android.bp
index 7aad96d..65d2f0b 100644
--- a/resolv/Android.bp
+++ b/resolv/Android.bp
@@ -83,7 +83,6 @@
         "libbinder_ndk",
         "libstatslog",
     ],
-    // TODO: Get rid of these include paths used in DnsProxyListener.
     include_dirs: [
         "system/netd/include",
         "system/netd/server",
diff --git a/resolv/DnsProxyListener.cpp b/resolv/DnsProxyListener.cpp
index c11e869..18e05cc 100644
--- a/resolv/DnsProxyListener.cpp
+++ b/resolv/DnsProxyListener.cpp
@@ -38,30 +38,32 @@
 #include <android-base/stringprintf.h>
 #include <android/multinetwork.h>  // ResNsendFlags
 #include <cutils/misc.h>           // FIRST_APPLICATION_UID
+#include <netdutils/InternetAddresses.h>
 #include <netdutils/OperationLimiter.h>
+#include <netdutils/ResponseCode.h>
 #include <netdutils/Slice.h>
+#include <netdutils/Stopwatch.h>
+#include <netdutils/ThreadUtil.h>
 #include <private/android_filesystem_config.h>  // AID_SYSTEM
 #include <resolv.h>
 #include <statslog.h>
 #include <sysutils/SocketClient.h>
 
-// TODO: Considering moving ResponseCode.h Stopwatch.h thread_util.h to libnetdutils.
 #include "DnsResolver.h"
 #include "NetdClient.h"  // NETID_USE_LOCAL_NAMESERVERS
 #include "NetdPermissions.h"
 #include "ResolverEventReporter.h"
-#include "ResponseCode.h"
-#include "Stopwatch.h"
 #include "netd_resolv/stats.h"  // RCODE_TIMEOUT
-#include "netdutils/InternetAddresses.h"
 #include "resolv_private.h"
-#include "thread_util.h"
 
 using aidl::android::net::metrics::INetdEventListener;
 
 namespace android {
-namespace net {
 
+using netdutils::ResponseCode;
+using netdutils::Stopwatch;
+
+namespace net {
 namespace {
 
 // Limits the number of outstanding DNS queries by client UID.
@@ -83,7 +85,7 @@
 void tryThreadOrError(SocketClient* cli, T* handler) {
     cli->incRef();
 
-    const int rval = threadLaunch(handler);
+    const int rval = netdutils::threadLaunch(handler);
     if (rval == 0) {
         // SocketClient decRef() happens in the handler's run() method.
         return;
diff --git a/resolv/DnsResolver.cpp b/resolv/DnsResolver.cpp
index 703d6bf..0093d8c 100644
--- a/resolv/DnsResolver.cpp
+++ b/resolv/DnsResolver.cpp
@@ -27,7 +27,7 @@
 bool resolv_init(const ResolverNetdCallbacks& callbacks) {
     android::base::InitLogging(/*argv=*/nullptr);
     android::base::SetDefaultTag("libnetd_resolv");
-    LOG(INFO) << __func__ << "Initializing resolver";
+    LOG(INFO) << __func__ << ": Initializing resolver";
     const std::string logSeverityStr =
             android::base::GetProperty("persist.sys.nw_dns_resolver_log", "WARNING");
     android::base::SetMinimumLogSeverity(logSeverityStrToEnum(logSeverityStr));
@@ -61,16 +61,16 @@
 
 bool DnsResolver::start() {
     if (!verifyCallbacks()) {
-        LOG(ERROR) << __func__ << "Callback verification failed";
+        LOG(ERROR) << __func__ << ": Callback verification failed";
         return false;
     }
     if (mDnsProxyListener.startListener()) {
-        PLOG(ERROR) << __func__ << "Unable to start DnsProxyListener";
+        PLOG(ERROR) << __func__ << ": Unable to start DnsProxyListener";
         return false;
     }
     binder_status_t ret;
     if ((ret = DnsResolverService::start()) != STATUS_OK) {
-        LOG(ERROR) << __func__ << "Unable to start DnsResolverService: " << ret;
+        LOG(ERROR) << __func__ << ": Unable to start DnsResolverService: " << ret;
         return false;
     }
     return true;
diff --git a/resolv/dnsresolver_binder_test.cpp b/resolv/dnsresolver_binder_test.cpp
index 701a97c..39a0e6a 100644
--- a/resolv/dnsresolver_binder_test.cpp
+++ b/resolv/dnsresolver_binder_test.cpp
@@ -27,13 +27,13 @@
 #include <gmock/gmock-matchers.h>
 #include <gtest/gtest.h>
 #include <netdb.h>
+#include <netdutils/Stopwatch.h>
 
 #include "tests/BaseTestMetricsListener.h"
 #include "tests/TestMetrics.h"
 
 #include "NetdConstants.h"  // SHA256_SIZE
 #include "ResolverStats.h"
-#include "Stopwatch.h"
 #include "dns_responder.h"
 #include "dns_responder_client.h"
 
@@ -49,6 +49,7 @@
 using android::net::ResolverStats;
 using android::net::metrics::INetdEventListener;
 using android::net::metrics::TestOnDnsEvent;
+using android::netdutils::Stopwatch;
 
 // TODO: make this dynamic and stop depending on implementation details.
 // Sync from TEST_NETID in dns_responder_client.cpp as resolver_test.cpp does.
@@ -278,4 +279,4 @@
 
     EXPECT_THAT(res_servers, testing::UnorderedElementsAreArray(servers));
     EXPECT_THAT(res_domains, testing::UnorderedElementsAreArray(domains));
-}
\ No newline at end of file
+}
diff --git a/resolv/res_debug.cpp b/resolv/res_debug.cpp
index 16ede43..2ea5d87 100644
--- a/resolv/res_debug.cpp
+++ b/resolv/res_debug.cpp
@@ -96,7 +96,6 @@
  */
 
 #define LOG_TAG "res_debug"
-#define DBG 0
 
 #include <sys/param.h>
 #include <sys/socket.h>
@@ -118,6 +117,14 @@
 
 #include "resolv_private.h"
 
+// Default to disabling verbose logging unless overridden by Android.bp
+// for debuggable builds.
+//
+// NOTE: Verbose resolver logs could contain PII -- do NOT enable in production builds
+#ifndef RESOLV_ALLOW_VERBOSE_LOGGING
+#define RESOLV_ALLOW_VERBOSE_LOGGING 0
+#endif
+
 struct res_sym {
     int number;            /* Identifying number, like T_MX */
     const char* name;      /* Its symbolic name, like "MX" */
@@ -502,12 +509,12 @@
 android::base::LogSeverity logSeverityStrToEnum(const std::string& logSeverityStr) {
     android::base::LogSeverity logSeverityEnum;
 
-    if (logSeverityStr == "DEBUG") {
+    if (logSeverityStr == "VERBOSE") {
         // *** enable verbose logging only when DBG is set. It prints sensitive data ***
-        if (DBG)
-            logSeverityEnum = android::base::VERBOSE;
-        else
-            logSeverityEnum = android::base::DEBUG;
+        logSeverityEnum =
+                RESOLV_ALLOW_VERBOSE_LOGGING ? android::base::VERBOSE : android::base::DEBUG;
+    } else if (logSeverityStr == "DEBUG") {
+        logSeverityEnum = android::base::DEBUG;
     } else if (logSeverityStr == "INFO") {
         logSeverityEnum = android::base::INFO;
     } else if (logSeverityStr == "WARNING") {
diff --git a/resolv/resolver_test.cpp b/resolv/resolver_test.cpp
index 7f30dad..ad6a951 100644
--- a/resolv/resolver_test.cpp
+++ b/resolv/resolver_test.cpp
@@ -39,6 +39,7 @@
 #include <android-base/stringprintf.h>
 #include <android/multinetwork.h>  // ResNsendFlags
 #include <cutils/sockets.h>
+#include <gmock/gmock-matchers.h>
 #include <gtest/gtest.h>
 #include <openssl/base64.h>
 #include <private/android_filesystem_config.h>
@@ -85,28 +86,6 @@
 }
 }  // namespace
 
-// Emulates the behavior of UnorderedElementsAreArray, which currently cannot be used.
-// TODO: Use UnorderedElementsAreArray, which depends on being able to compile libgmock_host,
-// if that is not possible, improve this hacky algorithm, which is O(n**2)
-template <class A, class B>
-bool UnorderedCompareArray(const A& a, const B& b) {
-    if (a.size() != b.size()) return false;
-    for (const auto& a_elem : a) {
-        size_t a_count = 0;
-        for (const auto& a_elem2 : a) {
-            if (a_elem == a_elem2) {
-                ++a_count;
-            }
-        }
-        size_t b_count = 0;
-        for (const auto& b_elem : b) {
-            if (a_elem == b_elem) ++b_count;
-        }
-        if (a_count != b_count) return false;
-    }
-    return true;
-}
-
 class ResolverTest : public ::testing::Test {
   protected:
     struct DnsRecord {
@@ -576,8 +555,8 @@
               res_params.base_timeout_msec);
     EXPECT_EQ(servers.size(), res_stats.size());
 
-    EXPECT_TRUE(UnorderedCompareArray(res_servers, servers));
-    EXPECT_TRUE(UnorderedCompareArray(res_domains, domains));
+    EXPECT_THAT(res_servers, testing::UnorderedElementsAreArray(servers));
+    EXPECT_THAT(res_domains, testing::UnorderedElementsAreArray(domains));
 
     ASSERT_NO_FATAL_FAILURE(mDnsClient.ShutdownDNSServers(&dns));
 }
diff --git a/server/CommandListener.cpp b/server/CommandListener.cpp
index d0fc875..5819a93 100644
--- a/server/CommandListener.cpp
+++ b/server/CommandListener.cpp
@@ -33,6 +33,7 @@
 
 #include <log/log.h>
 #include <netd_resolv/params.h>
+#include <netdutils/ResponseCode.h>
 #include <netdutils/Status.h>
 #include <netdutils/StatusOr.h>
 #include <netutils/ifc.h>
@@ -45,7 +46,6 @@
 #include "IdletimerController.h"
 #include "InterfaceController.h"
 #include "NetdConstants.h"
-#include "ResponseCode.h"
 #include "RouteController.h"
 #include "UidRanges.h"
 #include "netid_client.h"
@@ -54,8 +54,10 @@
 #include <vector>
 
 namespace android {
-namespace net {
 
+using netdutils::ResponseCode;
+
+namespace net {
 namespace {
 
 const unsigned NUM_OEM_IDS = NetworkController::MAX_OEM_ID - NetworkController::MIN_OEM_ID + 1;
diff --git a/server/Controllers.cpp b/server/Controllers.cpp
index 5cf4e06..c3b549f 100644
--- a/server/Controllers.cpp
+++ b/server/Controllers.cpp
@@ -18,8 +18,9 @@
 #include <set>
 #include <string>
 
-#include <android-base/strings.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <netdutils/Stopwatch.h>
 
 #define LOG_TAG "Netd"
 #include <log/log.h>
@@ -28,15 +29,15 @@
 #include "IdletimerController.h"
 #include "NetworkController.h"
 #include "RouteController.h"
-#include "Stopwatch.h"
-#include "oem_iptables_hook.h"
 #include "XfrmController.h"
+#include "oem_iptables_hook.h"
 
 namespace android {
 namespace net {
 
-using android::base::StringPrintf;
 using android::base::StringAppendF;
+using android::base::StringPrintf;
+using android::netdutils::Stopwatch;
 
 auto Controllers::execIptablesRestore  = ::execIptablesRestore;
 auto Controllers::execIptablesRestoreWithOutput = ::execIptablesRestoreWithOutput;
diff --git a/server/IptablesRestoreControllerTest.cpp b/server/IptablesRestoreControllerTest.cpp
index e34f644..d01d7ce 100644
--- a/server/IptablesRestoreControllerTest.cpp
+++ b/server/IptablesRestoreControllerTest.cpp
@@ -24,14 +24,14 @@
 #include <gtest/gtest.h>
 
 #define LOG_TAG "IptablesRestoreControllerTest"
-#include <log/log.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <log/log.h>
 #include <netdutils/MockSyscalls.h>
+#include <netdutils/Stopwatch.h>
 
 #include "IptablesRestoreController.h"
 #include "NetdConstants.h"
-#include "Stopwatch.h"
 #include "bpf/BpfUtils.h"
 
 #define XT_LOCK_NAME "/system/etc/xtables.lock"
@@ -41,6 +41,7 @@
 using android::base::Join;
 using android::base::StringPrintf;
 using android::netdutils::ScopedMockSyscalls;
+using android::netdutils::Stopwatch;
 using testing::Return;
 using testing::StrictMock;
 
diff --git a/server/MDnsSdListener.cpp b/server/MDnsSdListener.cpp
index 83726c3..e8eddcc 100644
--- a/server/MDnsSdListener.cpp
+++ b/server/MDnsSdListener.cpp
@@ -36,11 +36,10 @@
 
 #include <cutils/properties.h>
 #include <log/log.h>
+#include <netdutils/ResponseCode.h>
+#include <netdutils/ThreadUtil.h>
 #include <sysutils/SocketClient.h>
 
-#include "ResponseCode.h"
-#include "thread_util.h"
-
 #define MDNS_SERVICE_NAME "mdnsd"
 #define MDNS_SERVICE_STATUS "init.svc.mdnsd"
 
@@ -48,6 +47,8 @@
 
 constexpr char RESCAN[] = "1";
 
+using android::netdutils::ResponseCode;
+
 MDnsSdListener::MDnsSdListener() : FrameworkListener(SOCKET_NAME, true) {
     Monitor *m = new Monitor();
     registerCmd(new Handler(m, this));
@@ -526,7 +527,7 @@
     mPollSize = 10;
     socketpair(AF_LOCAL, SOCK_STREAM, 0, mCtrlSocketPair);
 
-    const int rval = ::android::net::threadLaunch(this);
+    const int rval = ::android::netdutils::threadLaunch(this);
     if (rval != 0) {
         ALOGW("Error spawning monitor thread: %s (%d)", strerror(-rval), -rval);
     }
diff --git a/server/NetlinkHandler.cpp b/server/NetlinkHandler.cpp
index 6e9a1e0..0354fca 100644
--- a/server/NetlinkHandler.cpp
+++ b/server/NetlinkHandler.cpp
@@ -31,7 +31,6 @@
 #include "Controllers.h"
 #include "NetlinkHandler.h"
 #include "NetlinkManager.h"
-#include "ResponseCode.h"
 #include "SockDiag.h"
 
 #include <charconv>
diff --git a/server/SockDiag.cpp b/server/SockDiag.cpp
index 5caf347..33c523a 100644
--- a/server/SockDiag.cpp
+++ b/server/SockDiag.cpp
@@ -30,13 +30,11 @@
 
 #include <android-base/strings.h>
 #include <log/log.h>
+#include <netdutils/Stopwatch.h>
 
 #include "NetdConstants.h"
 #include "Permission.h"
 #include "SockDiag.h"
-#include "Stopwatch.h"
-
-#include <chrono>
 
 #ifndef SOCK_DESTROY
 #define SOCK_DESTROY 21
@@ -45,8 +43,10 @@
 #define INET_DIAG_BC_MARK_COND 10
 
 namespace android {
-namespace net {
 
+using netdutils::Stopwatch;
+
+namespace net {
 namespace {
 
 int checkError(int fd) {
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index c684a1a..0c5b6bf 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -45,11 +45,10 @@
 
 #include "Controllers.h"
 #include "Fwmark.h"
-#include "NetdConstants.h"
-#include "Permission.h"
 #include "InterfaceController.h"
+#include "NetdConstants.h"
 #include "NetworkController.h"
-#include "ResponseCode.h"
+#include "Permission.h"
 #include "TetherController.h"
 
 namespace android {
diff --git a/server/XfrmController.cpp b/server/XfrmController.cpp
index b7f6649..a57b492 100644
--- a/server/XfrmController.cpp
+++ b/server/XfrmController.cpp
@@ -59,7 +59,6 @@
 #include "NetdConstants.h"
 #include "NetlinkCommands.h"
 #include "Permission.h"
-#include "ResponseCode.h"
 #include "XfrmController.h"
 #include "android-base/stringprintf.h"
 #include "android-base/strings.h"
diff --git a/server/XfrmControllerTest.cpp b/server/XfrmControllerTest.cpp
index 8f09ca8..36af67a 100644
--- a/server/XfrmControllerTest.cpp
+++ b/server/XfrmControllerTest.cpp
@@ -47,7 +47,6 @@
 #include "NetdConstants.h"
 #include "NetlinkCommands.h"
 #include "Permission.h"
-#include "Stopwatch.h"
 #include "XfrmController.h"
 #include "android/net/INetd.h"
 #include "binder/IServiceManager.h"
diff --git a/server/main.cpp b/server/main.cpp
index a60622b..9d38ed2 100644
--- a/server/main.cpp
+++ b/server/main.cpp
@@ -35,6 +35,7 @@
 #include <android-base/properties.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
+#include <netdutils/Stopwatch.h>
 
 #include "CommandListener.h"
 #include "Controllers.h"
@@ -46,7 +47,6 @@
 #include "NetdNativeService.h"
 #include "NetlinkManager.h"
 #include "Process.h"
-#include "Stopwatch.h"
 
 #include "netd_resolv/resolv.h"
 #include "netd_resolv/resolv_stub.h"
@@ -63,6 +63,7 @@
 using android::net::NetdNativeService;
 using android::net::NetlinkManager;
 using android::net::NFLogListener;
+using android::netdutils::Stopwatch;
 
 const char* const PID_FILE_PATH = "/data/misc/net/netd_pid";
 constexpr const char DNSPROXYLISTENER_SOCKET_NAME[] = "dnsproxyd";
diff --git a/tests/benchmarks/connect_benchmark.cpp b/tests/benchmarks/connect_benchmark.cpp
index c8d3797..e08fb01 100644
--- a/tests/benchmarks/connect_benchmark.cpp
+++ b/tests/benchmarks/connect_benchmark.cpp
@@ -70,13 +70,14 @@
 #include <android-base/stringprintf.h>
 #include <benchmark/benchmark.h>
 #include <log/log.h>
+#include <netdutils/Stopwatch.h>
 #include <utils/StrongPointer.h>
 
 #include "FwmarkClient.h"
 #include "SockDiag.h"
-#include "Stopwatch.h"
 
 using android::base::StringPrintf;
+using android::netdutils::Stopwatch;
 
 static int bindAndListen(int s) {
     sockaddr_in6 sin6 = { .sin6_family = AF_INET6 };
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index c656e1c..682e1b3 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -53,11 +53,11 @@
 
 #include "InterfaceController.h"
 #include "NetdConstants.h"
-#include "Stopwatch.h"
 #include "TestUnsolService.h"
 #include "XfrmController.h"
 #include "android/net/INetd.h"
 #include "binder/IServiceManager.h"
+#include "netdutils/Stopwatch.h"
 #include "netdutils/Syscalls.h"
 #include "tun_interface.h"
 
@@ -89,6 +89,7 @@
 using android::net::TunInterface;
 using android::net::UidRangeParcel;
 using android::netdutils::sSyscalls;
+using android::netdutils::Stopwatch;
 
 static const char* IP_RULE_V4 = "-4";
 static const char* IP_RULE_V6 = "-6";
diff --git a/tests/tun_interface.cpp b/tests/tun_interface.cpp
index 3d62fb0..65f1528 100644
--- a/tests/tun_interface.cpp
+++ b/tests/tun_interface.cpp
@@ -145,7 +145,7 @@
         in_addr ip4;
         in6_addr ip6;
     } ip;
-    if (addr.find(":") != std::string::npos) {
+    if (addr.find(':') != std::string::npos) {
         family = AF_INET6;
         inet_pton(AF_INET6, addr.c_str(), &ip.ip6);
         addrlen = sizeof(ip.ip6);