Clean up DNS proxying.
authorElliott Hughes <enh@google.com>
Wed, 10 Dec 2014 22:56:46 +0000 (14:56 -0800)
committerElliott Hughes <enh@google.com>
Thu, 11 Dec 2014 01:14:02 +0000 (17:14 -0800)
Remove code duplication and fall back to trying directly if the proxy
isn't available. With this, tests still work if netd is dead (perhaps
because you've run "adb shell stop", or because you're running on the host).

Bug: 18547878
Change-Id: Ia4a9aa18b1fc79e09735107246989fa7fc6c8455

libc/dns/gethnamaddr.c
libc/dns/include/resolv_netid.h
libc/dns/net/getaddrinfo.c
libc/dns/net/getnameinfo.c

index 0bd838e86249223e2b033a2e0d7eae324ddc14db..736858ff2ae06c620b769562d3092fc86e600d8a 100644 (file)
@@ -69,6 +69,7 @@
 #include <errno.h>
 #include <netdb.h>
 #include <stdarg.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <strings.h>
 #include <syslog.h>
@@ -532,30 +533,32 @@ android_gethostbynamefornet(const char *name, int af, unsigned netid, unsigned m
        return hp;
 }
 
+__LIBC_HIDDEN__ FILE* android_open_proxy() {
+       const char* cache_mode = getenv("ANDROID_DNS_MODE");
+       bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
+       if (!use_proxy) {
+               return NULL;
+       }
 
-static FILE* android_open_proxy()
-{
-       int sock;
-       const int one = 1;
-       struct sockaddr_un proxy_addr;
-
-       sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
-       if (sock < 0) {
+       int s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+       if (s == -1) {
                return NULL;
        }
 
-       setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+       const int one = 1;
+       setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+
+       struct sockaddr_un proxy_addr;
        memset(&proxy_addr, 0, sizeof(proxy_addr));
        proxy_addr.sun_family = AF_UNIX;
        strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd", sizeof(proxy_addr.sun_path));
-       if (TEMP_FAILURE_RETRY(connect(sock,
-                       (const struct sockaddr*) &proxy_addr,
-                       sizeof(proxy_addr))) != 0) {
-               close(sock);
+
+       if (TEMP_FAILURE_RETRY(connect(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
+               close(s);
                return NULL;
        }
 
-       return fdopen(sock, "r+");
+       return fdopen(s, "r+");
 }
 
 static struct hostent *
@@ -565,8 +568,8 @@ android_read_hostent(FILE* proxy)
        char buf[4];
        if (fread(buf, 1, sizeof(buf), proxy) != sizeof(buf)) return NULL;
 
-       /* This is reading serialized data from system/netd/server/DnsProxyListener.cpp
-        * and changes here need to be matched there */
+       // This is reading serialized data from system/netd/server/DnsProxyListener.cpp
+       // and changes here need to be matched there.
        int result_code = strtol(buf, NULL, 10);
        if (result_code != DnsProxyQueryResult) {
                fread(&size, 1, sizeof(size), proxy);
@@ -748,80 +751,39 @@ gethostbyname_internal_real(const char *name, int af, res_state res)
 static struct hostent *
 gethostbyname_internal(const char *name, int af, res_state res, unsigned netid, unsigned mark)
 {
-       const char *cache_mode = getenv("ANDROID_DNS_MODE");
-       FILE* proxy = NULL;
-       struct hostent *result = NULL;
-
-       if (cache_mode != NULL && strcmp(cache_mode, "local") == 0) {
+       FILE* proxy = android_open_proxy();
+       if (proxy == NULL) {
+               // Either we're not supposed to be using the proxy or the proxy is unavailable.
                res_setnetid(res, netid);
                res_setmark(res, mark);
                return gethostbyname_internal_real(name, af, res);
        }
 
-       proxy = android_open_proxy();
-       if (proxy == NULL) goto exit;
-
        netid = __netdClientDispatch.netIdForResolv(netid);
 
-       /* This is writing to system/netd/server/DnsProxyListener.cpp and changes
-        * here need to be matched there */
+       // This is writing to system/netd/server/DnsProxyListener.cpp and changes
+       // here need to be matched there.
        if (fprintf(proxy, "gethostbyname %u %s %d",
                        netid,
                        name == NULL ? "^" : name,
                        af) < 0) {
-               goto exit;
-       }
-
-       if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
-               goto exit;
-       }
-
-       result = android_read_hostent(proxy);
-
-exit:
-       if (proxy != NULL) {
                fclose(proxy);
-       }
-       return result;
-}
-
-
-struct hostent *
-android_gethostbyaddrfornet_proxy(const void *addr,
-    socklen_t len, int af, unsigned netid)
-{
-       struct hostent *result = NULL;
-       FILE* proxy = android_open_proxy();
-
-       if (proxy == NULL) goto exit;
-
-       char buf[INET6_ADDRSTRLEN];  //big enough for IPv4 and IPv6
-       const char * addrStr = inet_ntop(af, addr, buf, sizeof(buf));
-       if (addrStr == NULL) goto exit;
-
-       netid = __netdClientDispatch.netIdForResolv(netid);
-
-       if (fprintf(proxy, "gethostbyaddr %s %d %d %u",
-                       addrStr, len, af, netid) < 0) {
-               goto exit;
+               return NULL;
        }
 
        if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
-               goto exit;
-       }
-
-       result = android_read_hostent(proxy);
-exit:
-       if (proxy != NULL) {
                fclose(proxy);
+               return NULL;
        }
+
+       struct hostent* result = android_read_hostent(proxy);
+       fclose(proxy);
        return result;
 }
 
-struct hostent *
-android_gethostbyaddrfornet_real(const void *addr,
-    socklen_t len, int af, unsigned netid, unsigned mark)
-{
+
+static struct hostent *
+android_gethostbyaddrfornet_real(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark) {
        const u_char *uaddr = (const u_char *)addr;
        socklen_t size;
        struct hostent *hp;
@@ -874,16 +836,43 @@ android_gethostbyaddrfornet_real(const void *addr,
        return hp;
 }
 
+__LIBC_HIDDEN__ struct hostent*
+android_gethostbyaddrfornet_proxy(const void* addr, socklen_t len, int af, unsigned netid, unsigned mark) {
+       FILE* proxy = android_open_proxy();
+       if (proxy == NULL) {
+               // Either we're not supposed to be using the proxy or the proxy is unavailable.
+               return android_gethostbyaddrfornet_real(addr,len, af, netid, mark);
+       }
+
+       char buf[INET6_ADDRSTRLEN];  //big enough for IPv4 and IPv6
+       const char * addrStr = inet_ntop(af, addr, buf, sizeof(buf));
+       if (addrStr == NULL) {
+               fclose(proxy);
+               return NULL;
+       }
+
+       netid = __netdClientDispatch.netIdForResolv(netid);
+
+       if (fprintf(proxy, "gethostbyaddr %s %d %d %u",
+                       addrStr, len, af, netid) < 0) {
+               fclose(proxy);
+               return NULL;
+       }
+
+       if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
+               fclose(proxy);
+               return NULL;
+       }
+
+       struct hostent *result = android_read_hostent(proxy);
+       fclose(proxy);
+       return result;
+}
+
 struct hostent *
 android_gethostbyaddrfornet(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark)
 {
-       const char *cache_mode = getenv("ANDROID_DNS_MODE");
-
-       if (cache_mode == NULL || strcmp(cache_mode, "local") != 0) {
-               return android_gethostbyaddrfornet_proxy(addr, len, af, netid);
-       } else {
-               return android_gethostbyaddrfornet_real(addr,len, af, netid, mark);
-       }
+       return android_gethostbyaddrfornet_proxy(addr, len, af, netid, mark);
 }
 
 struct hostent *
index e5521b809b82765e4207c496438c26019b114ee9..1d0f8691c8c0890d7b15b8a1c5e891e0fbf349ce 100644 (file)
@@ -34,6 +34,7 @@
  */
 #include <sys/cdefs.h>
 #include <netinet/in.h>
+#include <stdio.h>
 
 /*
  * Passing NETID_UNSET as the netId causes system/netd/server/DnsProxyListener.cpp to
@@ -68,9 +69,9 @@ extern void _resolv_flush_cache_for_net(unsigned netid) __used_in_netd;
 extern void _resolv_delete_cache_for_net(unsigned netid) __used_in_netd;
 
 /* Internal use only. */
-struct hostent *android_gethostbyaddrfornet_proxy(const void *, socklen_t, int , unsigned);
-int android_getnameinfofornet(const struct sockaddr *, socklen_t, char *, size_t, char *, size_t,
-                int, unsigned, unsigned);
+struct hostent *android_gethostbyaddrfornet_proxy(const void *, socklen_t, int , unsigned, unsigned) __LIBC_HIDDEN__;
+int android_getnameinfofornet(const struct sockaddr *, socklen_t, char *, size_t, char *, size_t, int, unsigned, unsigned) __LIBC_HIDDEN__;
+FILE* android_open_proxy(void) __LIBC_HIDDEN__;
 
 /* delete the cache associated with a certain network */
 extern void _resolv_delete_cache_for_net(unsigned netid);
index 1ebd222fe3a798d600d1b79efd686bcefb782c50..f0d522a02f1afcc148186605238474c35f672c7f 100644 (file)
@@ -423,10 +423,6 @@ android_getaddrinfo_proxy(
     const char *hostname, const char *servname,
     const struct addrinfo *hints, struct addrinfo **res, unsigned netid)
 {
-       int sock;
-       const int one = 1;
-       struct sockaddr_un proxy_addr;
-       FILE* proxy = NULL;
        int success = 0;
 
        // Clear this at start, as we use its non-NULLness later (in the
@@ -442,36 +438,14 @@ android_getaddrinfo_proxy(
                return EAI_NODATA;
        }
 
-       sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
-       if (sock < 0) {
-               return EAI_NODATA;
-       }
-
-       setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
-       memset(&proxy_addr, 0, sizeof(proxy_addr));
-       proxy_addr.sun_family = AF_UNIX;
-       strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd",
-               sizeof(proxy_addr.sun_path));
-       if (TEMP_FAILURE_RETRY(connect(sock,
-                                      (const struct sockaddr*) &proxy_addr,
-                                      sizeof(proxy_addr))) != 0) {
-               close(sock);
-               return EAI_NODATA;
+       FILE* proxy = android_open_proxy();
+       if (proxy == NULL) {
+               return EAI_SYSTEM;
        }
 
        netid = __netdClientDispatch.netIdForResolv(netid);
 
        // Send the request.
-       proxy = fdopen(sock, "r+");
-       if (proxy == NULL) {
-               // Failed to map sock to FILE*. Check errno for the cause.
-               // @sonymobile.com saw failures in automated testing, but
-               // couldn't reproduce it for debugging.
-               // Fail with EAI_SYSTEM and let callers handle the failure.
-               close(sock);
-               return EAI_SYSTEM;
-       }
-
        if (fprintf(proxy, "getaddrinfo %s %s %d %d %d %d %u",
                    hostname == NULL ? "^" : hostname,
                    servname == NULL ? "^" : servname,
@@ -618,7 +592,6 @@ android_getaddrinfofornet(const char *hostname, const char *servname,
        struct addrinfo ai0;
        struct addrinfo *pai;
        const struct explore *ex;
-       const char* cache_mode = getenv("ANDROID_DNS_MODE");
 
        /* hostname is allowed to be NULL */
        /* servname is allowed to be NULL */
@@ -753,13 +726,12 @@ android_getaddrinfofornet(const char *hostname, const char *servname,
        if (pai->ai_flags & AI_NUMERICHOST)
                ERR(EAI_NONAME);
 
-        /*
-         * BEGIN ANDROID CHANGES; proxying to the cache
-         */
-       if (cache_mode == NULL || strcmp(cache_mode, "local") != 0) {
-               // we're not the proxy - pass the request to them
-               return android_getaddrinfo_proxy(hostname, servname, hints, res, netid);
+#if defined(__ANDROID__)
+       int gai_error = android_getaddrinfo_proxy(hostname, servname, hints, res, netid);
+       if (gai_error != EAI_SYSTEM) {
+               return gai_error;
        }
+#endif
 
        /*
         * hostname as alphabetical name.
index b9c0280ddf000a7490276c58ef35f6c68e305428..893e982d1820c51f943c67bc34f273f28dfe1823 100644 (file)
@@ -303,7 +303,7 @@ getnameinfo_inet(const struct sockaddr* sa, socklen_t salen,
                        break;
                }
        } else {
-               hp = android_gethostbyaddrfornet_proxy(addr, afd->a_addrlen, afd->a_af, netid);
+               hp = android_gethostbyaddrfornet_proxy(addr, afd->a_addrlen, afd->a_af, netid, mark);
                if (hp) {
 #if 0
                        /*