diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2009-08-03 22:36:31 -0700 |
---|---|---|
committer | Lorenzo Colitti <lorenzo@google.com> | 2009-08-04 13:17:03 -0700 |
commit | 3d8f4ada56cc4965c8d2cbaa16d1bc0f75492c07 (patch) | |
tree | 3b2398f9b0687e271280a165cc3040b2c364dd85 | |
parent | 8b09aa39c3ab7bf17384082728001550c072e8c7 (diff) | |
download | bionic-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.
-rw-r--r-- | libc/netbsd/net/getaddrinfo.c | 50 |
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; |