am 0ec85334
: Merge "DNS proxy: the start. proxies getaddrinfo calls."
* commit '0ec85334ff375a2b7823f322e083d4a0ea24c289': DNS proxy: the start. proxies getaddrinfo calls.
This commit is contained in:
commit
ff24286911
1 changed files with 184 additions and 0 deletions
|
@ -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>
|
||||
|
@ -391,6 +394,180 @@ _have_ipv4() {
|
|||
return _test_connect(PF_INET, &addr.generic, sizeof(addr.in));
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
@ -537,6 +714,13 @@ getaddrinfo(const char *hostname, const char *servname,
|
|||
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
|
||||
|
|
Loading…
Reference in a new issue