Add dns_open_proxy for connecting to DnsProxyd

dns_open_proxy is a similar function to android_open_proxy.
dns_open_proxy returns fd of the connection.
libc will register dns_open_proxy in netdClientInitImpl.
libc calls dns_open_proxy in below function

-gethostbyname_internal
-android_getaddrinfo_proxy
-android_gethostbyaddrfornetcontext_proxy_internal

Test: build, dns works fine

Change-Id: Ic17f91866b85437b711648d24e72d2b4c82f1ad5
diff --git a/client/NetdClient.cpp b/client/NetdClient.cpp
index c4e7e2f..4497877 100644
--- a/client/NetdClient.cpp
+++ b/client/NetdClient.cpp
@@ -19,7 +19,9 @@
 #include <arpa/inet.h>
 #include <errno.h>
 #include <math.h>
+#include <stdlib.h>
 #include <sys/socket.h>
+#include <sys/un.h>
 #include <unistd.h>
 
 #include <atomic>
@@ -39,6 +41,7 @@
 typedef int (*ConnectFunctionType)(int, const sockaddr*, socklen_t);
 typedef int (*SocketFunctionType)(int, int, int);
 typedef unsigned (*NetIdForResolvFunctionType)(unsigned);
+typedef int (*DnsOpenProxyType)();
 
 // These variables are only modified at startup (when libc.so is loaded) and never afterwards, so
 // it's okay that they are read later at runtime without a lock.
@@ -144,12 +147,9 @@
     // Verify that we are allowed to use |netId|, by creating a socket and trying to have it marked
     // with the netId. Call libcSocket() directly; else the socket creation (via netdClientSocket())
     // might itself cause another check with the fwmark server, which would be wasteful.
-    int socketFd;
-    if (libcSocket) {
-        socketFd = libcSocket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-    } else {
-        socketFd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
-    }
+
+    const auto socketFunc = libcSocket ? libcSocket : socket;
+    int socketFd = socketFunc(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
     if (socketFd < 0) {
         return -errno;
     }
@@ -176,6 +176,36 @@
     return 0;
 }
 
+int dns_open_proxy() {
+    const char* cache_mode = getenv("ANDROID_DNS_MODE");
+    const bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
+    if (!use_proxy) {
+        return -1;
+    }
+
+    const auto socketFunc = libcSocket ? libcSocket : socket;
+    int s = socketFunc(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+    if (s == -1) {
+        return -1;
+    }
+    const int one = 1;
+    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+
+    static const struct sockaddr_un proxy_addr = {
+            .sun_family = AF_UNIX,
+            .sun_path = "/dev/socket/dnsproxyd",
+    };
+
+    const auto connectFunc = libcConnect ? libcConnect : connect;
+    if (TEMP_FAILURE_RETRY(
+                connectFunc(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
+        close(s);
+        return -1;
+    }
+
+    return s;
+}
+
 }  // namespace
 
 #define CHECK_SOCKET_IS_MARKABLE(sock)          \
@@ -214,6 +244,12 @@
     }
 }
 
+extern "C" void netdClientInitDnsOpenProxy(DnsOpenProxyType* function) {
+    if (function) {
+        *function = dns_open_proxy;
+    }
+}
+
 extern "C" int getNetworkForSocket(unsigned* netId, int socketFd) {
     if (!netId || socketFd < 0) {
         return -EBADF;