Merge "DNS proxy: the start. proxies getaddrinfo calls."
diff --git a/libc/netbsd/net/getaddrinfo.c b/libc/netbsd/net/getaddrinfo.c
index e7564c4..4fa92b7 100644
--- a/libc/netbsd/net/getaddrinfo.c
+++ b/libc/netbsd/net/getaddrinfo.c
@@ -77,10 +77,13 @@
* friends.
*/
+#include <fcntl.h>
#include <sys/cdefs.h>
#include <sys/types.h>
+#include <sys/stat.h>
#include <sys/param.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -371,6 +374,180 @@
return have_ipv6;
}
+// Returns 0 on success, else returns non-zero on error (in which case
+// getaddrinfo should continue as normal)
+static int
+android_getaddrinfo_proxy(
+ const char *hostname, const char *servname,
+ const struct addrinfo *hints, struct addrinfo **res)
+{
+ int sock;
+ const int one = 1;
+ struct sockaddr_un proxy_addr;
+ const char* cache_mode = getenv("ANDROID_DNS_MODE");
+ FILE* proxy = NULL;
+ int success = 0;
+
+ // Clear this at start, as we use its non-NULLness later (in the
+ // error path) to decide if we have to free up any memory we
+ // allocated in the process (before failing).
+ *res = NULL;
+
+ if (cache_mode != NULL && strcmp(cache_mode, "local") == 0) {
+ // Don't use the proxy in local mode. This is used by the
+ // proxy itself.
+ return -1;
+ }
+
+ // Bogus things we can't serialize. Don't use the proxy.
+ if ((hostname != NULL &&
+ strcspn(hostname, " \n\r\t^'\"") != strlen(hostname)) ||
+ (servname != NULL &&
+ strcspn(servname, " \n\r\t^'\"") != strlen(servname))) {
+ return -1;
+ }
+
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0) {
+ return -1;
+ }
+
+ 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 -1;
+ }
+
+ // Send the request.
+ proxy = fdopen(sock, "r+");
+ if (fprintf(proxy, "getaddrinfo %s %s %d %d %d %d",
+ hostname == NULL ? "^" : hostname,
+ servname == NULL ? "^" : servname,
+ hints == NULL ? -1 : hints->ai_flags,
+ hints == NULL ? -1 : hints->ai_family,
+ hints == NULL ? -1 : hints->ai_socktype,
+ hints == NULL ? -1 : hints->ai_protocol) < 0) {
+ goto exit;
+ }
+ // literal NULL byte at end, required by FrameworkListener
+ if (fputc(0, proxy) == EOF ||
+ fflush(proxy) != 0) {
+ goto exit;
+ }
+
+ int remote_rv;
+ if (fread(&remote_rv, sizeof(int), 1, proxy) != 1) {
+ goto exit;
+ }
+
+ if (remote_rv != 0) {
+ goto exit;
+ }
+
+ struct addrinfo* ai = NULL;
+ struct addrinfo** nextres = res;
+ while (1) {
+ uint32_t addrinfo_len;
+ if (fread(&addrinfo_len, sizeof(addrinfo_len),
+ 1, proxy) != 1) {
+ break;
+ }
+ addrinfo_len = ntohl(addrinfo_len);
+ if (addrinfo_len == 0) {
+ success = 1;
+ break;
+ }
+
+ if (addrinfo_len < sizeof(struct addrinfo)) {
+ break;
+ }
+ struct addrinfo* ai = calloc(1, addrinfo_len +
+ sizeof(struct sockaddr_storage));
+ if (ai == NULL) {
+ break;
+ }
+
+ if (fread(ai, addrinfo_len, 1, proxy) != 1) {
+ // Error; fall through.
+ break;
+ }
+
+ // Zero out the pointer fields we copied which aren't
+ // valid in this address space.
+ ai->ai_addr = NULL;
+ ai->ai_canonname = NULL;
+ ai->ai_next = NULL;
+
+ // struct sockaddr
+ uint32_t addr_len;
+ if (fread(&addr_len, sizeof(addr_len), 1, proxy) != 1) {
+ break;
+ }
+ addr_len = ntohl(addr_len);
+ if (addr_len != 0) {
+ if (addr_len > sizeof(struct sockaddr_storage)) {
+ // Bogus; too big.
+ break;
+ }
+ struct sockaddr* addr = (struct sockaddr*)(ai + 1);
+ if (fread(addr, addr_len, 1, proxy) != 1) {
+ break;
+ }
+ ai->ai_addr = addr;
+ }
+
+ // cannonname
+ uint32_t name_len;
+ if (fread(&name_len, sizeof(name_len), 1, proxy) != 1) {
+ break;
+ }
+ if (name_len != 0) {
+ ai->ai_canonname = (char*) malloc(name_len);
+ if (fread(ai->ai_canonname, name_len, 1, proxy) != 1) {
+ break;
+ }
+ if (ai->ai_canonname[name_len - 1] != '\0') {
+ // The proxy should be returning this
+ // NULL-terminated.
+ break;
+ }
+ }
+
+ *nextres = ai;
+ nextres = &ai->ai_next;
+ ai = NULL;
+ }
+
+ if (ai != NULL) {
+ // Clean up partially-built addrinfo that we never ended up
+ // attaching to the response.
+ freeaddrinfo(ai);
+ }
+exit:
+ if (proxy != NULL) {
+ fclose(proxy);
+ }
+
+ if (success) {
+ return 0;
+ }
+
+ // Proxy failed; fall through to local
+ // resolver case. But first clean up any
+ // memory we might've allocated.
+ if (*res) {
+ freeaddrinfo(*res);
+ *res = NULL;
+ }
+ return -1;
+}
+
int
getaddrinfo(const char *hostname, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
@@ -517,6 +694,13 @@
if (pai->ai_flags & AI_NUMERICHOST)
ERR(EAI_NONAME);
+ /*
+ * BEGIN ANDROID CHANGES; proxying to the cache
+ */
+ if (android_getaddrinfo_proxy(hostname, servname, hints, res) == 0) {
+ return 0;
+ }
+
/*
* hostname as alphabetical name.
* we would like to prefer AF_INET6 than AF_INET, so we'll make a