Merge commit '2e5574379e355feef79279ef6b2db0efe7c581e5' into honeycomb-release-to-dalvik-dev
This commit is contained in:
commit
f10a41b5a1
@ -347,35 +347,55 @@ str2number(const char *p)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Determine whether IPv6 connectivity is available. */
|
||||
/*
|
||||
* Connect a UDP socket to a given unicast address. This will cause no network
|
||||
* traffic, but will fail fast if the system has no or limited reachability to
|
||||
* the destination (e.g., no IPv4 address, no IPv6 default route, ...).
|
||||
*/
|
||||
static int
|
||||
_have_ipv6() {
|
||||
/*
|
||||
* Connect a UDP socket to an global unicast IPv6 address. This will
|
||||
* cause no network traffic, but will fail fast if the system has no or
|
||||
* limited IPv6 connectivity (e.g., only a link-local address).
|
||||
*/
|
||||
static const struct sockaddr_in6 sin6_test = {
|
||||
/* family, port, flow label */
|
||||
AF_INET6, 0, 0,
|
||||
/* 2000:: */
|
||||
{{{ 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}},
|
||||
/* scope ID */
|
||||
0};
|
||||
sockaddr_union addr_test;
|
||||
addr_test.in6 = sin6_test;
|
||||
int s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
||||
_test_connect(int pf, struct sockaddr *addr, size_t addrlen) {
|
||||
int s = socket(pf, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (s < 0)
|
||||
return 0;
|
||||
int ret;
|
||||
do {
|
||||
ret = connect(s, &addr_test.generic, sizeof(addr_test.in6));
|
||||
ret = connect(s, addr, addrlen);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
int have_ipv6 = (ret == 0);
|
||||
int success = (ret == 0);
|
||||
do {
|
||||
ret = close(s);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
return have_ipv6;
|
||||
return success;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following functions determine whether IPv4 or IPv6 connectivity is
|
||||
* available in order to implement AI_ADDRCONFIG.
|
||||
*
|
||||
* Strictly speaking, AI_ADDRCONFIG should not look at whether connectivity is
|
||||
* available, but whether addresses of the specified family are "configured
|
||||
* on the local system". However, bionic doesn't currently support getifaddrs,
|
||||
* so checking for connectivity is the next best thing.
|
||||
*/
|
||||
static int
|
||||
_have_ipv6() {
|
||||
static const struct sockaddr_in6 sin6_test = {
|
||||
.sin6_family = AF_INET6,
|
||||
.sin6_addr.s6_addr = { // 2000::
|
||||
0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
sockaddr_union addr = { .in6 = sin6_test };
|
||||
return _test_connect(PF_INET6, &addr.generic, sizeof(addr.in6));
|
||||
}
|
||||
|
||||
static int
|
||||
_have_ipv4() {
|
||||
static const struct sockaddr_in sin_test = {
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr.s_addr = __constant_htonl(0x08080808L) // 8.8.8.8
|
||||
};
|
||||
sockaddr_union addr = { .in = sin_test };
|
||||
return _test_connect(PF_INET, &addr.generic, sizeof(addr.in));
|
||||
}
|
||||
|
||||
// Returns 0 on success, else returns non-zero on error (in which case
|
||||
@ -1525,9 +1545,13 @@ _get_scope(const struct sockaddr *addr)
|
||||
#define IN6_IS_ADDR_6TO4(a) \
|
||||
(((a)->s6_addr[0] == 0x20) && ((a)->s6_addr[1] == 0x02))
|
||||
|
||||
/* 6bone testing address area (3ffe::/16), deprecated in RFC 3701. */
|
||||
#define IN6_IS_ADDR_6BONE(a) \
|
||||
(((a)->s6_addr[0] == 0x3f) && ((a)->s6_addr[1] == 0xfe))
|
||||
|
||||
/*
|
||||
* Get the label for a given IPv4/IPv6 address.
|
||||
* RFC 3484, section 2.1, plus Teredo added in with label 5.
|
||||
* RFC 3484, section 2.1, plus changes from draft-ietf-6man-rfc3484-revise-01.
|
||||
*/
|
||||
|
||||
/*ARGSUSED*/
|
||||
@ -1535,19 +1559,27 @@ static int
|
||||
_get_label(const struct sockaddr *addr)
|
||||
{
|
||||
if (addr->sa_family == AF_INET) {
|
||||
return 4;
|
||||
return 3;
|
||||
} else if (addr->sa_family == AF_INET6) {
|
||||
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
|
||||
if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) {
|
||||
return 0;
|
||||
} else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) {
|
||||
} else if (IN6_IS_ADDR_ULA(&addr6->sin6_addr)) {
|
||||
return 1;
|
||||
} else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) {
|
||||
return 3;
|
||||
} else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
|
||||
return 4;
|
||||
} else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) {
|
||||
return 5;
|
||||
} else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
|
||||
return 2;
|
||||
} else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) {
|
||||
return 10;
|
||||
} else if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr)) {
|
||||
return 11;
|
||||
} else if (IN6_IS_ADDR_6BONE(&addr6->sin6_addr)) {
|
||||
return 12;
|
||||
} else {
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
@ -1560,7 +1592,7 @@ _get_label(const struct sockaddr *addr)
|
||||
|
||||
/*
|
||||
* Get the precedence for a given IPv4/IPv6 address.
|
||||
* RFC 3484, section 2.1, plus Teredo added in with precedence 25.
|
||||
* RFC 3484, section 2.1, plus changes from draft-ietf-6man-rfc3484-revise-01.
|
||||
*/
|
||||
|
||||
/*ARGSUSED*/
|
||||
@ -1568,22 +1600,28 @@ static int
|
||||
_get_precedence(const struct sockaddr *addr)
|
||||
{
|
||||
if (addr->sa_family == AF_INET) {
|
||||
return 10;
|
||||
return 30;
|
||||
} else if (addr->sa_family == AF_INET6) {
|
||||
const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6 *)addr;
|
||||
if (IN6_IS_ADDR_LOOPBACK(&addr6->sin6_addr)) {
|
||||
return 60;
|
||||
} else if (IN6_IS_ADDR_ULA(&addr6->sin6_addr)) {
|
||||
return 50;
|
||||
} else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr)) {
|
||||
} else if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) {
|
||||
return 30;
|
||||
} else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
|
||||
return 20;
|
||||
} else if (IN6_IS_ADDR_TEREDO(&addr6->sin6_addr)) {
|
||||
return 25;
|
||||
} else if (IN6_IS_ADDR_6TO4(&addr6->sin6_addr)) {
|
||||
return 30;
|
||||
return 10;
|
||||
} else if (IN6_IS_ADDR_V4COMPAT(&addr6->sin6_addr) ||
|
||||
IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr) ||
|
||||
IN6_IS_ADDR_6BONE(&addr6->sin6_addr)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 40;
|
||||
}
|
||||
} else {
|
||||
return 5;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1867,17 +1905,27 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
|
||||
q.qclass = C_IN;
|
||||
q.answer = buf->buf;
|
||||
q.anslen = sizeof(buf->buf);
|
||||
/* If AI_ADDRCONFIG, lookup IPv6 only if we have connectivity */
|
||||
if (!(pai->ai_flags & AI_ADDRCONFIG) || _have_ipv6()) {
|
||||
int query_ipv6 = 1, query_ipv4 = 1;
|
||||
if (pai->ai_flags & AI_ADDRCONFIG) {
|
||||
query_ipv6 = _have_ipv6();
|
||||
query_ipv4 = _have_ipv4();
|
||||
}
|
||||
if (query_ipv6) {
|
||||
q.qtype = T_AAAA;
|
||||
q.next = &q2;
|
||||
q2.name = name;
|
||||
q2.qclass = C_IN;
|
||||
q2.qtype = T_A;
|
||||
q2.answer = buf2->buf;
|
||||
q2.anslen = sizeof(buf2->buf);
|
||||
} else {
|
||||
if (query_ipv4) {
|
||||
q.next = &q2;
|
||||
q2.name = name;
|
||||
q2.qclass = C_IN;
|
||||
q2.qtype = T_A;
|
||||
q2.answer = buf2->buf;
|
||||
q2.anslen = sizeof(buf2->buf);
|
||||
}
|
||||
} else if (query_ipv4) {
|
||||
q.qtype = T_A;
|
||||
} else {
|
||||
free(buf);
|
||||
free(buf2);
|
||||
return NS_NOTFOUND;
|
||||
}
|
||||
break;
|
||||
case AF_INET:
|
||||
|
Loading…
x
Reference in New Issue
Block a user