summaryrefslogtreecommitdiffstats
path: root/libc/netbsd
diff options
context:
space:
mode:
authorLorenzo Colitti <lorenzo@google.com>2009-08-03 22:36:31 -0700
committerLorenzo Colitti <lorenzo@google.com>2009-08-04 13:17:03 -0700
commit3d8f4ada56cc4965c8d2cbaa16d1bc0f75492c07 (patch)
tree3b2398f9b0687e271280a165cc3040b2c364dd85 /libc/netbsd
parent8b09aa39c3ab7bf17384082728001550c072e8c7 (diff)
downloadbionic-3d8f4ada56cc4965c8d2cbaa16d1bc0f75492c07.zip
bionic-3d8f4ada56cc4965c8d2cbaa16d1bc0f75492c07.tar.gz
bionic-3d8f4ada56cc4965c8d2cbaa16d1bc0f75492c07.tar.bz2
Don't request IPv6 addresses if AI_ADDRCONFIG is specified and the system has no IPv6 connectivity.
Diffstat (limited to 'libc/netbsd')
-rw-r--r--libc/netbsd/net/getaddrinfo.c50
1 files changed, 42 insertions, 8 deletions
diff --git a/libc/netbsd/net/getaddrinfo.c b/libc/netbsd/net/getaddrinfo.c
index f2189fb..1233cb8 100644
--- a/libc/netbsd/net/getaddrinfo.c
+++ b/libc/netbsd/net/getaddrinfo.c
@@ -335,6 +335,36 @@ str2number(const char *p)
return -1;
}
+/* Determine whether IPv6 connectivity is available. */
+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};
+ static const struct sockaddr *sa_test = (struct sockaddr *) &sin6_test;
+ int s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (s < 0)
+ return 0;
+ int ret;
+ do {
+ ret = connect(s, sa_test, sizeof(sin6_test));
+ } while (ret < 0 && errno == EINTR);
+ int have_ipv6 = (ret == 0);
+ do {
+ ret = close(s);
+ } while (ret < 0 && errno == EINTR);
+ return have_ipv6;
+}
+
int
getaddrinfo(const char *hostname, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
@@ -1274,7 +1304,6 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
name = va_arg(ap, char *);
pai = va_arg(ap, const struct addrinfo *);
-
//fprintf(stderr, "_dns_getaddrinfo() name = '%s'\n", name);
memset(&q, 0, sizeof(q));
@@ -1299,15 +1328,20 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
/* prefer IPv6 */
q.name = name;
q.qclass = C_IN;
- q.qtype = T_AAAA;
q.answer = buf->buf;
q.anslen = sizeof(buf->buf);
- q.next = &q2;
- q2.name = name;
- q2.qclass = C_IN;
- q2.qtype = T_A;
- q2.answer = buf2->buf;
- q2.anslen = sizeof(buf2->buf);
+ /* If AI_ADDRCONFIG, lookup IPv6 only if we have connectivity */
+ if (!(pai->ai_flags & AI_ADDRCONFIG) || _have_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 {
+ q.qtype = T_A;
+ }
break;
case AF_INET:
q.name = name;