Merge "Replace scary buffer handling in addalias() with std::vector"
diff --git a/include/netid_client.h b/include/netid_client.h
index 23b16fd..4279f89 100644
--- a/include/netid_client.h
+++ b/include/netid_client.h
@@ -18,7 +18,7 @@
 #define NETD_CLIENT_NETID_H
 
 /*
- * Passing NETID_UNSET as the netId causes system/netd/server/DnsProxyListener.cpp to
+ * Passing NETID_UNSET as the netId causes system/netd/resolv/DnsProxyListener.cpp to
  * fill in the appropriate default netId for the query.
  */
 #define NETID_UNSET 0u
diff --git a/libnetdutils/include/netdutils/InternetAddresses.h b/libnetdutils/include/netdutils/InternetAddresses.h
index 95c60eb..07a6e90 100644
--- a/libnetdutils/include/netdutils/InternetAddresses.h
+++ b/libnetdutils/include/netdutils/InternetAddresses.h
@@ -203,6 +203,8 @@
 
     constexpr sa_family_t family() const noexcept { return mData.family; }
     IPAddress ip() const noexcept { return IPAddress(mData); }
+    in_addr addr4() const noexcept { return mData.ip.v4; }
+    in6_addr addr6() const noexcept { return mData.ip.v6; }
     constexpr int length() const noexcept { return mData.cidrlen; }
 
     bool isUninitialized() const noexcept;
diff --git a/resolv/Android.bp b/resolv/Android.bp
index ccea41f..ab333f4 100644
--- a/resolv/Android.bp
+++ b/resolv/Android.bp
@@ -20,6 +20,7 @@
         "res_send.cpp",
         "res_state.cpp",
         "res_stats.cpp",
+        "DnsProxyListener.cpp",
         "DnsTlsDispatcher.cpp",
         "DnsTlsQueryMap.cpp",
         "DnsTlsTransport.cpp",
@@ -35,13 +36,21 @@
     static_libs: [
         "libbase",
         "libcrypto",
+        "libcutils",
         "liblog",
         "libnetdutils",
         "libssl",
+        "libsysutils",
         "netd_event_listener_interface-ndk_platform",
     ],
     shared_libs: [
         "libbinder_ndk",
+        "libstatslog",
+    ],
+    // TODO: Get rid of these include paths used in DnsProxyListener.
+    include_dirs: [
+        "system/netd/include",
+        "system/netd/server",
     ],
     export_include_dirs: ["include"],
     // TODO: pie in the sky: make this code clang-tidy clean
diff --git a/server/DnsProxyListener.cpp b/resolv/DnsProxyListener.cpp
similarity index 91%
rename from server/DnsProxyListener.cpp
rename to resolv/DnsProxyListener.cpp
index 822a840..18006f1 100644
--- a/server/DnsProxyListener.cpp
+++ b/resolv/DnsProxyListener.cpp
@@ -19,21 +19,19 @@
 #include <errno.h>
 #include <linux/if.h>
 #include <math.h>
+#include <net/if.h>
 #include <netdb.h>
 #include <netinet/in.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/socket.h>
 #include <sys/types.h>
-#include <string.h>
-#include <pthread.h>
-#include <net/if.h>
 
 #define LOG_TAG "DnsProxyListener"
 #define DBG 0
 #define VDBG 0
 
 #include <algorithm>
-#include <chrono>
 #include <list>
 #include <vector>
 
@@ -42,29 +40,37 @@
 #include <log/log.h>
 #include <netdutils/OperationLimiter.h>
 #include <netdutils/Slice.h>
+#include <private/android_filesystem_config.h>  // AID_SYSTEM
 #include <resolv.h>
 #include <statslog.h>
 #include <sysutils/SocketClient.h>
-#include <utils/String16.h>
 
-#include <binder/IServiceManager.h>
-
-#include "Controllers.h"
-#include "DnsProxyListener.h"
-#include "Fwmark.h"
-#include "NetdClient.h"
-#include "NetdConstants.h"
-#include "NetworkController.h"
+// TODO: Considering moving ResponseCode.h Stopwatch.h thread_util.h to libnetdutils.
+#include "NetdClient.h"  // NETID_USE_LOCAL_NAMESERVERS
 #include "ResponseCode.h"
 #include "Stopwatch.h"
-#include "android/net/metrics/INetdEventListener.h"
+#include "netd_resolv/DnsProxyListener.h"
+#include "netd_resolv/ResolverEventReporter.h"
+#include "netd_resolv/stats.h"  // RCODE_TIMEOUT
+#include "netdutils/InternetAddresses.h"
 #include "thread_util.h"
 
-#include <netd_resolv/resolv_stub.h>
-
-using android::String16;
+using aidl::android::net::metrics::INetdEventListener;
 using android::base::StringPrintf;
-using android::net::metrics::INetdEventListener;
+
+static android::net::DnsProxyListener gDnsProxyListener;
+
+bool resolv_init(const dnsproxylistener_callbacks& callbacks) {
+    if (!gDnsProxyListener.setCallbacks(callbacks)) {
+        ALOGE("Unable to set callbacks to DnsProxyListener");
+        return false;
+    }
+    if (gDnsProxyListener.startListener()) {
+        ALOGE("Unable to start DnsProxyListener (%s)", strerror(errno));
+        return false;
+    }
+    return true;
+}
 
 namespace android {
 namespace net {
@@ -124,7 +130,7 @@
 
 inline bool queryingViaTls(unsigned dns_netid) {
     ExternalPrivateDnsStatus privateDnsStatus = {PrivateDnsMode::OFF, 0, {}};
-    RESOLV_STUB.resolv_get_private_dns_status_for_net(dns_netid, &privateDnsStatus);
+    resolv_get_private_dns_status_for_net(dns_netid, &privateDnsStatus);
     switch (static_cast<PrivateDnsMode>(privateDnsStatus.mode)) {
         case PrivateDnsMode::OPPORTUNISTIC:
             for (int i = 0; i < privateDnsStatus.numServers; i++) {
@@ -149,7 +155,7 @@
 
     for (const char* const permission :
          {CONNECTIVITY_USE_RESTRICTED_NETWORKS, NETWORK_BYPASS_PRIVATE_DNS}) {
-        if (checkCallingPermission(String16(permission))) {
+        if (gDnsProxyListener.mCallbacks.check_calling_permission(permission)) {
             return true;
         }
     }
@@ -297,7 +303,7 @@
     android::util::stats_write(android::util::NETWORK_DNS_EVENT_REPORTED, eventType, returnCode,
                                latencyUs);
 
-    const auto listener = gCtls->eventReporter.getNetdEventListener();
+    const std::shared_ptr<INetdEventListener> listener = ResolverEventReporter::getListener();
     if (!listener) return;
     const int latencyMs = latencyUs / 1000;
     listener->onDnsEvent(netContext.dns_netid, eventType, returnCode, latencyMs, query_name,
@@ -470,14 +476,30 @@
     return true;
 }
 
+bool getDns64Prefix(unsigned netId, netdutils::IPPrefix* prefix) {
+    in6_addr v6addr{};
+    uint8_t prefixLen = 0;
+    if (!gDnsProxyListener.mCallbacks.get_dns64_prefix(netId, &v6addr, &prefixLen)) {
+        return false;
+    }
+    const netdutils::IPAddress ipv6(v6addr);
+    *prefix = netdutils::IPPrefix(ipv6, static_cast<int>(prefixLen));
+    return true;
+}
+
 }  // namespace
 
-DnsProxyListener::DnsProxyListener(const NetworkController* netCtrl)
-    : FrameworkListener(SOCKET_NAME), mNetCtrl(netCtrl) {
-    registerCmd(new GetAddrInfoCmd(this));
-    registerCmd(new GetHostByAddrCmd(this));
-    registerCmd(new GetHostByNameCmd(this));
-    registerCmd(new ResNSendCommand(this));
+bool DnsProxyListener::setCallbacks(const dnsproxylistener_callbacks& callbacks) {
+    mCallbacks = callbacks;
+    return mCallbacks.check_calling_permission && mCallbacks.get_network_context &&
+           mCallbacks.get_dns64_prefix;
+}
+
+DnsProxyListener::DnsProxyListener() : FrameworkListener(SOCKET_NAME) {
+    registerCmd(new GetAddrInfoCmd());
+    registerCmd(new GetHostByAddrCmd());
+    registerCmd(new GetHostByNameCmd());
+    registerCmd(new ResNSendCommand());
 }
 
 DnsProxyListener::GetAddrInfoHandler::GetAddrInfoHandler(SocketClient* c, char* host, char* service,
@@ -578,7 +600,7 @@
     }
 
     netdutils::IPPrefix prefix{};
-    if (net::gCtls->resolverCtrl.getPrefix64(mNetContext.dns_netid, &prefix)) {
+    if (!getDns64Prefix(mNetContext.dns_netid, &prefix)) {
         return;
     }
 
@@ -589,8 +611,7 @@
             mHints->ai_family = AF_INET;
             // Don't need to do freeaddrinfo(res) before starting new DNS lookup because previous
             // DNS lookup is failed with error EAI_NODATA.
-            *rv = RESOLV_STUB.android_getaddrinfofornetcontext(mHost, mService, mHints,
-                                                               &mNetContext, res);
+            *rv = android_getaddrinfofornetcontext(mHost, mService, mHints, &mNetContext, res);
             queryLimiter.finish(uid);
             if (*rv) {
                 *rv = EAI_NODATA;  // return original error code
@@ -629,8 +650,7 @@
     const uid_t uid = mClient->getUid();
     int32_t rv = 0;
     if (queryLimiter.start(uid)) {
-        rv = RESOLV_STUB.android_getaddrinfofornetcontext(mHost, mService, mHints, &mNetContext,
-                                                          &result);
+        rv = android_getaddrinfofornetcontext(mHost, mService, mHints, &mNetContext, &result);
         queryLimiter.finish(uid);
     } else {
         // Note that this error code is currently not passed down to the client.
@@ -682,10 +702,7 @@
 
 }  // namespace
 
-DnsProxyListener::GetAddrInfoCmd::GetAddrInfoCmd(DnsProxyListener* dnsProxyListener) :
-    NetdCommand("getaddrinfo"),
-    mDnsProxyListener(dnsProxyListener) {
-}
+DnsProxyListener::GetAddrInfoCmd::GetAddrInfoCmd() : FrameworkCommand("getaddrinfo") {}
 
 int DnsProxyListener::GetAddrInfoCmd::runCommand(SocketClient *cli,
                                             int argc, char **argv) {
@@ -724,7 +741,8 @@
     const uid_t uid = cli->getUid();
 
     android_net_context netcontext;
-    mDnsProxyListener->mNetCtrl->getNetworkContext(netId, uid, &netcontext);
+    gDnsProxyListener.mCallbacks.get_network_context(netId, uid, &netcontext);
+
     if (useLocalNameservers) {
         netcontext.flags |= NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS;
     }
@@ -756,8 +774,7 @@
 /*******************************************************
  *                  ResNSendCommand                  *
  *******************************************************/
-DnsProxyListener::ResNSendCommand::ResNSendCommand(DnsProxyListener* dnsProxyListener)
-    : NetdCommand("resnsend"), mDnsProxyListener(dnsProxyListener) {}
+DnsProxyListener::ResNSendCommand::ResNSendCommand() : FrameworkCommand("resnsend") {}
 
 int DnsProxyListener::ResNSendCommand::runCommand(SocketClient* cli, int argc, char** argv) {
     if (DBG) logArguments(argc, argv);
@@ -784,7 +801,7 @@
     }
 
     android_net_context netcontext;
-    mDnsProxyListener->mNetCtrl->getNetworkContext(netId, uid, &netcontext);
+    gDnsProxyListener.mCallbacks.get_network_context(netId, uid, &netcontext);
     if (checkAndClearUseLocalNameserversFlag(&netId)) {
         netcontext.flags |= NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS;
     }
@@ -841,9 +858,8 @@
     std::vector<uint8_t> ansBuf(MAXPACKET, 0);
     int arcode, nsendAns = -1;
     if (queryLimiter.start(uid)) {
-        nsendAns = RESOLV_STUB.resolv_res_nsend(&mNetContext, msg.data(), msgLen, ansBuf.data(),
-                                                MAXPACKET, &arcode,
-                                                static_cast<ResNsendFlags>(mFlags));
+        nsendAns = resolv_res_nsend(&mNetContext, msg.data(), msgLen, ansBuf.data(), MAXPACKET,
+                                    &arcode, static_cast<ResNsendFlags>(mFlags));
         queryLimiter.finish(uid);
     } else {
         ALOGW("resnsend: from UID %d, max concurrent queries reached", uid);
@@ -886,10 +902,7 @@
 /*******************************************************
  *                  GetHostByName                      *
  *******************************************************/
-DnsProxyListener::GetHostByNameCmd::GetHostByNameCmd(DnsProxyListener* dnsProxyListener) :
-      NetdCommand("gethostbyname"),
-      mDnsProxyListener(dnsProxyListener) {
-}
+DnsProxyListener::GetHostByNameCmd::GetHostByNameCmd() : FrameworkCommand("gethostbyname") {}
 
 int DnsProxyListener::GetHostByNameCmd::runCommand(SocketClient *cli,
                                             int argc, char **argv) {
@@ -917,7 +930,8 @@
     }
 
     android_net_context netcontext;
-    mDnsProxyListener->mNetCtrl->getNetworkContext(netId, uid, &netcontext);
+    gDnsProxyListener.mCallbacks.get_network_context(netId, uid, &netcontext);
+
     if (useLocalNameservers) {
         netcontext.flags |= NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS;
     }
@@ -937,7 +951,6 @@
 }
 
 void DnsProxyListener::GetHostByNameHandler::doDns64Synthesis(int32_t* rv, struct hostent** hpp) {
-    netdutils::IPPrefix prefix{};
     // Don't have to consider family AF_UNSPEC case because gethostbyname{, 2} only supports
     // family AF_INET or AF_INET6.
     const bool ipv6WantedButNoData = (mAf == AF_INET6 && *rv == EAI_NODATA);
@@ -946,14 +959,15 @@
         return;
     }
 
-    if (net::gCtls->resolverCtrl.getPrefix64(mNetContext.dns_netid, &prefix)) {
+    netdutils::IPPrefix prefix{};
+    if (!getDns64Prefix(mNetContext.dns_netid, &prefix)) {
         return;
     }
 
     // If caller wants IPv6 answers but no data, try to query IPv4 answers for synthesis
     const uid_t uid = mClient->getUid();
     if (queryLimiter.start(uid)) {
-        *rv = RESOLV_STUB.android_gethostbynamefornetcontext(mName, AF_INET, &mNetContext, hpp);
+        *rv = android_gethostbynamefornetcontext(mName, AF_INET, &mNetContext, hpp);
         queryLimiter.finish(uid);
         if (*rv) {
             *rv = EAI_NODATA;  // return original error code
@@ -982,7 +996,7 @@
     hostent* hp = nullptr;
     int32_t rv = 0;
     if (queryLimiter.start(uid)) {
-        rv = RESOLV_STUB.android_gethostbynamefornetcontext(mName, mAf, &mNetContext, &hp);
+        rv = android_gethostbynamefornetcontext(mName, mAf, &mNetContext, &hp);
         queryLimiter.finish(uid);
     } else {
         rv = EAI_MEMORY;
@@ -1023,10 +1037,7 @@
 /*******************************************************
  *                  GetHostByAddr                      *
  *******************************************************/
-DnsProxyListener::GetHostByAddrCmd::GetHostByAddrCmd(const DnsProxyListener* dnsProxyListener) :
-        NetdCommand("gethostbyaddr"),
-        mDnsProxyListener(dnsProxyListener) {
-}
+DnsProxyListener::GetHostByAddrCmd::GetHostByAddrCmd() : FrameworkCommand("gethostbyaddr") {}
 
 int DnsProxyListener::GetHostByAddrCmd::runCommand(SocketClient *cli,
                                             int argc, char **argv) {
@@ -1062,7 +1073,8 @@
     }
 
     android_net_context netcontext;
-    mDnsProxyListener->mNetCtrl->getNetworkContext(netId, uid, &netcontext);
+    gDnsProxyListener.mCallbacks.get_network_context(netId, uid, &netcontext);
+
     if (useLocalNameservers) {
         netcontext.flags |= NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS;
     }
@@ -1092,7 +1104,7 @@
     }
 
     netdutils::IPPrefix prefix{};
-    if (net::gCtls->resolverCtrl.getPrefix64(mNetContext.dns_netid, &prefix)) {
+    if (!getDns64Prefix(mNetContext.dns_netid, &prefix)) {
         return;
     }
 
@@ -1114,8 +1126,7 @@
     if (queryLimiter.start(uid)) {
         // Remove NAT64 prefix and do reverse DNS query
         struct in_addr v4addr = {.s_addr = v6addr.s6_addr32[3]};
-        RESOLV_STUB.android_gethostbyaddrfornetcontext(&v4addr, sizeof(v4addr), AF_INET,
-                                                       &mNetContext, hpp);
+        android_gethostbyaddrfornetcontext(&v4addr, sizeof(v4addr), AF_INET, &mNetContext, hpp);
         queryLimiter.finish(uid);
         if (*hpp) {
             // Replace IPv4 address with original queried IPv6 address in place. The space has
@@ -1142,8 +1153,8 @@
     hostent* hp = nullptr;
     int32_t rv = 0;
     if (queryLimiter.start(uid)) {
-        rv = RESOLV_STUB.android_gethostbyaddrfornetcontext(mAddress, mAddressLen, mAddressFamily,
-                                                            &mNetContext, &hp);
+        rv = android_gethostbyaddrfornetcontext(mAddress, mAddressLen, mAddressFamily,
+                                                &mNetContext, &hp);
         queryLimiter.finish(uid);
     } else {
         rv = EAI_MEMORY;
diff --git a/server/DnsProxyListener.h b/resolv/include/netd_resolv/DnsProxyListener.h
similarity index 79%
rename from server/DnsProxyListener.h
rename to resolv/include/netd_resolv/DnsProxyListener.h
index e34f82e..ef9a3da 100644
--- a/server/DnsProxyListener.h
+++ b/resolv/include/netd_resolv/DnsProxyListener.h
@@ -17,35 +17,32 @@
 #ifndef _DNSPROXYLISTENER_H__
 #define _DNSPROXYLISTENER_H__
 
-#include <binder/IServiceManager.h>
+#include <sysutils/FrameworkCommand.h>
 #include <sysutils/FrameworkListener.h>
 
-#include "NetdCommand.h"
-#include "netd_resolv/resolv.h"  // android_net_context
+#include "resolv.h"  // android_net_context
 
 namespace android {
 namespace net {
 
-class NetworkController;
-
 class DnsProxyListener : public FrameworkListener {
   public:
-    explicit DnsProxyListener(const NetworkController* netCtrl);
+    DnsProxyListener();
     virtual ~DnsProxyListener() {}
 
+    bool setCallbacks(const dnsproxylistener_callbacks& callbacks);
+
     static constexpr const char* SOCKET_NAME = "dnsproxyd";
 
-  private:
-    const NetworkController *mNetCtrl;
+    // TODO: Considering putting this callbacks structure in its own file.
+    dnsproxylistener_callbacks mCallbacks{};
 
-    class GetAddrInfoCmd : public NetdCommand {
+  private:
+    class GetAddrInfoCmd : public FrameworkCommand {
       public:
-        explicit GetAddrInfoCmd(DnsProxyListener* dnsProxyListener);
+        GetAddrInfoCmd();
         virtual ~GetAddrInfoCmd() {}
         int runCommand(SocketClient* c, int argc, char** argv) override;
-
-      private:
-        DnsProxyListener* mDnsProxyListener;
     };
 
     /* ------ getaddrinfo ------*/
@@ -69,14 +66,11 @@
     };
 
     /* ------ gethostbyname ------*/
-    class GetHostByNameCmd : public NetdCommand {
+    class GetHostByNameCmd : public FrameworkCommand {
       public:
-        explicit GetHostByNameCmd(DnsProxyListener* dnsProxyListener);
+        GetHostByNameCmd();
         virtual ~GetHostByNameCmd() {}
         int runCommand(SocketClient* c, int argc, char** argv) override;
-
-      private:
-        DnsProxyListener* mDnsProxyListener;
     };
 
     class GetHostByNameHandler {
@@ -97,14 +91,11 @@
     };
 
     /* ------ gethostbyaddr ------*/
-    class GetHostByAddrCmd : public NetdCommand {
+    class GetHostByAddrCmd : public FrameworkCommand {
       public:
-        explicit GetHostByAddrCmd(const DnsProxyListener* dnsProxyListener);
+        GetHostByAddrCmd();
         virtual ~GetHostByAddrCmd() {}
         int runCommand(SocketClient* c, int argc, char** argv) override;
-
-      private:
-        const DnsProxyListener* mDnsProxyListener;
     };
 
     class GetHostByAddrHandler {
@@ -126,14 +117,11 @@
     };
 
     /* ------ resnsend ------*/
-    class ResNSendCommand : public NetdCommand {
+    class ResNSendCommand : public FrameworkCommand {
       public:
-        explicit ResNSendCommand(DnsProxyListener* dnsProxyListener);
+        ResNSendCommand();
         ~ResNSendCommand() override {}
         int runCommand(SocketClient* c, int argc, char** argv) override;
-
-      private:
-        DnsProxyListener* mDnsProxyListener;
     };
 
     class ResNSendHandler {
diff --git a/resolv/include/netd_resolv/resolv.h b/resolv/include/netd_resolv/resolv.h
index 4f43107..dde600d 100644
--- a/resolv/include/netd_resolv/resolv.h
+++ b/resolv/include/netd_resolv/resolv.h
@@ -45,7 +45,7 @@
 } sockaddr_union;
 
 /*
- * Passing NETID_UNSET as the netId causes system/netd/server/DnsProxyListener.cpp to
+ * Passing NETID_UNSET as the netId causes system/netd/resolv/DnsProxyListener.cpp to
  * fill in the appropriate default netId for the query.
  */
 #define NETID_UNSET 0u
@@ -101,9 +101,31 @@
     } serverStatus[MAXNS];
 };
 
+/*
+ * Some of functions (e.g. checkCallingPermission()) require the dependency on libbinder.so,
+ * but we can't include the library since it's not stable. Move the functions to netd and use
+ * these function pointers pointing to them.
+ */
+typedef void (*get_network_context_callback)(unsigned netid, uid_t uid,
+                                             android_net_context* netcontext);
+
+// TODO: investigate having the resolver check permissions itself, either by adding support to
+// libbinder_ndk or by converting IPermissionController into a stable AIDL interface.
+typedef bool (*check_calling_permission_callback)(const char* permission);
+
+// TODO: Remove the callback.
 typedef void (*private_dns_validated_callback)(unsigned netid, const char* server,
                                                const char* hostname, bool success);
 
+// TODO: Remove the callback after moving NAT64 prefix discovery out of netd to libnetd_resolv.
+typedef bool (*get_dns64_prefix_callback)(unsigned netid, in6_addr* prefix, uint8_t* prefix_len);
+
+struct dnsproxylistener_callbacks {
+    check_calling_permission_callback check_calling_permission;
+    get_network_context_callback get_network_context;
+    get_dns64_prefix_callback get_dns64_prefix;
+};
+
 LIBNETD_RESOLV_PUBLIC int android_gethostbyaddrfornetcontext(const void*, socklen_t, int,
                                                              const android_net_context*, hostent**);
 LIBNETD_RESOLV_PUBLIC int android_gethostbynamefornetcontext(const char*, int,
@@ -136,10 +158,14 @@
                                                                  ExternalPrivateDnsStatus* status);
 
 // Register callback to listen whether private DNS validated
+// TODO: Remove it. Use ResolverEventReporter instead.
 LIBNETD_RESOLV_PUBLIC void resolv_register_private_dns_callback(
         private_dns_validated_callback callback);
 
 // Delete the cache associated with a certain network
 LIBNETD_RESOLV_PUBLIC void resolv_delete_cache_for_net(unsigned netid);
 
+// Set callbacks to DnsProxyListener, and bring it up.
+LIBNETD_RESOLV_PUBLIC bool resolv_init(const dnsproxylistener_callbacks& callbacks);
+
 #endif  // NETD_RESOLV_RESOLV_H
diff --git a/resolv/include/netd_resolv/resolv_stub.h b/resolv/include/netd_resolv/resolv_stub.h
index b4364ba..9e09b44 100644
--- a/resolv/include/netd_resolv/resolv_stub.h
+++ b/resolv/include/netd_resolv/resolv_stub.h
@@ -63,6 +63,8 @@
 
     bool (*resolv_has_nameservers)(unsigned netid);
 
+    bool (*resolv_init)(const dnsproxylistener_callbacks& callbacks);
+
     void (*resolv_register_private_dns_callback)(private_dns_validated_callback callback);
 
     int (*resolv_res_nsend)(const android_net_context* netContext, const u_char* msg, int msgLen,
diff --git a/resolv/libnetd_resolv.map.txt b/resolv/libnetd_resolv.map.txt
index 175e3d8..336a7a9 100644
--- a/resolv/libnetd_resolv.map.txt
+++ b/resolv/libnetd_resolv.map.txt
@@ -30,6 +30,7 @@
     resolv_delete_private_dns_for_net;
     resolv_get_private_dns_status_for_net;
     resolv_has_nameservers;
+    resolv_init;
     resolv_register_private_dns_callback;
     resolv_res_nsend;
     resolv_set_nameservers_for_net;
diff --git a/server/Android.bp b/server/Android.bp
index b375cfc..18d7c5f 100644
--- a/server/Android.bp
+++ b/server/Android.bp
@@ -124,7 +124,6 @@
         "libpcap",
         "libqtaguid",
         "libselinux",
-        "libstatslog",
         "libsysutils",
         "libutils",
         "netd_aidl_interface-cpp",
@@ -139,7 +138,6 @@
     srcs: [
         "ClatdController.cpp",
         "CommandListener.cpp",
-        "DnsProxyListener.cpp",
         "DummyNetwork.cpp",
         "DumpWriter.cpp",
         "EventReporter.cpp",
diff --git a/server/EventReporter.h b/server/EventReporter.h
index d4dc93d..7dfa659 100644
--- a/server/EventReporter.h
+++ b/server/EventReporter.h
@@ -37,7 +37,7 @@
     // std::atomic<android::net::metrics::INetdEventListener> and deleting the mutex.
     //
     // Alternatively, if this locking causes a performance penalty, have each single-threaded
-    // caller (DnsProxyListener, FwmarkServer) keep their own per-thread copy of NetdEventListener
+    // caller (FwmarkServer) keep their own per-thread copy of NetdEventListener
     // and remove mNetdEventListener entirely.
     android::sp<android::net::metrics::INetdEventListener> mNetdEventListener;
     std::mutex mutex;
diff --git a/server/ResolvStub.cpp b/server/ResolvStub.cpp
index dafd58f..774b651 100644
--- a/server/ResolvStub.cpp
+++ b/server/ResolvStub.cpp
@@ -84,6 +84,7 @@
     RESOLV_STUB_LOAD_SYMBOL(resolv_delete_private_dns_for_net);
     RESOLV_STUB_LOAD_SYMBOL(resolv_get_private_dns_status_for_net);
     RESOLV_STUB_LOAD_SYMBOL(resolv_has_nameservers);
+    RESOLV_STUB_LOAD_SYMBOL(resolv_init);
     RESOLV_STUB_LOAD_SYMBOL(resolv_register_private_dns_callback);
     RESOLV_STUB_LOAD_SYMBOL(resolv_res_nsend);
     RESOLV_STUB_LOAD_SYMBOL(resolv_set_nameservers_for_net);
diff --git a/server/ResolverController.cpp b/server/ResolverController.cpp
index 39a0b83..c746f26 100644
--- a/server/ResolverController.cpp
+++ b/server/ResolverController.cpp
@@ -108,6 +108,24 @@
     }
 }
 
+void getNetworkContextCallback(uint32_t netId, uint32_t uid, android_net_context* netcontext) {
+    net::gCtls->netCtrl.getNetworkContext(netId, uid, netcontext);
+}
+
+bool getDns64PrefixCallback(unsigned netId, in6_addr* v6addr, uint8_t* prefix_len) {
+    netdutils::IPPrefix prefix{};
+    if (net::gCtls->resolverCtrl.getPrefix64(netId, &prefix) != 0) {
+        return false;
+    }
+    *v6addr = prefix.addr6();
+    *prefix_len = prefix.length();
+    return true;
+}
+
+bool checkCallingPermissionCallback(const char* permission) {
+    return checkCallingPermission(String16(permission));
+}
+
 bool allIPv6Only(const std::vector<std::string>& servers) {
     for (const auto& server : servers) {
         if (server.find(':') == std::string::npos) return false;
@@ -356,6 +374,15 @@
                                           args.prefixLength);
 }
 
+bool ResolverController::initResolver() {
+    dnsproxylistener_callbacks callbacks = {
+            .get_network_context = &getNetworkContextCallback,
+            .get_dns64_prefix = &getDns64PrefixCallback,
+            .check_calling_permission = &checkCallingPermissionCallback,
+    };
+    return RESOLV_STUB.resolv_init(callbacks);
+}
+
 void ResolverController::dump(DumpWriter& dw, unsigned netId) {
     // No lock needed since Bionic's resolver locks all accessed data structures internally.
     using android::net::ResolverStats;
diff --git a/server/ResolverController.h b/server/ResolverController.h
index bcb82db..4a104ed 100644
--- a/server/ResolverController.h
+++ b/server/ResolverController.h
@@ -64,6 +64,8 @@
 
     void sendNat64PrefixEvent(const net::Dns64Configuration::Nat64PrefixInfo& args);
 
+    bool initResolver();
+
     void dump(DumpWriter& dw, unsigned netId);
 
   private:
diff --git a/server/main.cpp b/server/main.cpp
index 51ce7ea..fd0856e 100644
--- a/server/main.cpp
+++ b/server/main.cpp
@@ -39,7 +39,6 @@
 
 #include "CommandListener.h"
 #include "Controllers.h"
-#include "DnsProxyListener.h"
 #include "FwmarkServer.h"
 #include "MDnsSdListener.h"
 #include "NFLogListener.h"
@@ -58,7 +57,6 @@
 using android::ProcessState;
 using android::defaultServiceManager;
 using android::net::CommandListener;
-using android::net::DnsProxyListener;
 using android::net::FwmarkServer;
 using android::net::NetdHwService;
 using android::net::NetdNativeService;
@@ -67,6 +65,7 @@
 using android::net::makeNFLogListener;
 
 const char* const PID_FILE_PATH = "/data/misc/net/netd_pid";
+constexpr const char DNSPROXYLISTENER_SOCKET_NAME[] = "dnsproxyd";
 
 std::mutex android::net::gBigNetdLock;
 
@@ -83,7 +82,7 @@
     // FrameworkListener does this on initialization as well, but we only initialize these
     // components after having initialized other subsystems that can fork.
     for (const auto& sock : { CommandListener::SOCKET_NAME,
-                              DnsProxyListener::SOCKET_NAME,
+                              DNSPROXYLISTENER_SOCKET_NAME,
                               FwmarkServer::SOCKET_NAME,
                               MDnsSdListener::SOCKET_NAME }) {
         setCloseOnExec(sock);
@@ -132,10 +131,11 @@
 
     // Set local DNS mode, to prevent bionic from proxying
     // back to this service, recursively.
+    // TODO: Check if we could remove it since resolver cache no loger
+    // checks this environment variable after aosp/838050.
     setenv("ANDROID_DNS_MODE", "local", 1);
-    DnsProxyListener dpl(&gCtls->netCtrl);
-    if (dpl.startListener()) {
-        ALOGE("Unable to start DnsProxyListener (%s)", strerror(errno));
+    if (!gCtls->resolverCtrl.initResolver()) {
+        ALOGE("Unable to init resolver");
         exit(1);
     }