Index: include/netdb.h =================================================================== --- include/netdb.h (revision 292012) +++ include/netdb.h (working copy) @@ -179,7 +179,7 @@ /* valid flags for addrinfo (not a standard def, apps should not use it) */ #define AI_MASK \ (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_NUMERICSERV | \ - AI_ADDRCONFIG) + AI_ADDRCONFIG | AI_ALL | AI_V4MAPPED) #define AI_ALL 0x00000100 /* IPv6 and IPv4-mapped (with AI_V4MAPPED) */ #define AI_V4MAPPED_CFG 0x00000200 /* accept IPv4-mapped if kernel supports */ Index: lib/libc/net/getaddrinfo.c =================================================================== --- lib/libc/net/getaddrinfo.c (revision 292129) +++ lib/libc/net/getaddrinfo.c (working copy) @@ -470,6 +470,22 @@ } /* + * RFC 3493: AI_ALL and AI_V4MAPPED are effective only against + * AF_INET6 query. They need to be ignored if specified in other + * occassions. + */ + switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) { + case AI_V4MAPPED: + case AI_ALL | AI_V4MAPPED: + if (pai->ai_family != AF_INET6) + pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); + break; + case AI_ALL: + pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); + break; + } + + /* * check for special cases. (1) numeric servname is disallowed if * socktype/protocol are left unspecified. (2) servname is disallowed * for raw and other inet{,6} sockets. @@ -861,6 +877,17 @@ if ((s = _socket(ai.ai_family, ai.ai_socktype | SOCK_CLOEXEC, ai.ai_protocol)) < 0) return; /* give up */ + if (ai.ai_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai.ai_addr; + int off = 0, ret; + + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + ret = _setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + (char *)&off, sizeof(off)); + if (ret < 0) + goto cleanup; + } + } if (_connect(s, ai.ai_addr, ai.ai_addrlen) < 0) goto cleanup; srclen = ai.ai_addrlen; @@ -1199,7 +1226,7 @@ const char *servname, struct addrinfo **res, const char *canonname) { const struct afd *afd; - struct addrinfo *ai; + struct addrinfo *ai, ai0; int error; char pton[PTON_MAX], path[PATH_MAX], *p; @@ -1236,8 +1263,17 @@ p = pton; break; default: - if (inet_pton(afd->a_af, hostname, pton) != 1) - return 0; + if (inet_pton(afd->a_af, hostname, pton) != 1) { + if (pai->ai_family != AF_INET6 || + (pai->ai_flags & AI_V4MAPPED) != AI_V4MAPPED) + return 0; + if (inet_aton(hostname, (struct in_addr *)pton) != 1) + return 0; + afd = &afdl[N_INET]; + ai0 = *pai; + ai0.ai_family = AF_INET; + pai = &ai0; + } p = pton; break; } @@ -1354,7 +1390,16 @@ { char *p; struct addrinfo *ai; + struct in6_addr mapaddr; + if (afd->a_af == AF_INET && (pai->ai_flags & AI_V4MAPPED) != 0) { + afd = &afdl[N_INET6]; + memset(&mapaddr.s6_addr[0], 0, 10); + memset(&mapaddr.s6_addr[10], 0xff, 2); + memcpy(&mapaddr.s6_addr[12], addr, sizeof(struct in_addr)); + addr = (char *)&mapaddr; + } + ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + (afd->a_socklen)); if (ai == NULL) @@ -2192,7 +2237,7 @@ static int _dns_getaddrinfo(void *rv, void *cb_data, va_list ap) { - struct addrinfo *ai; + struct addrinfo *ai, ai0; querybuf *buf, *buf2; const char *hostname; const struct addrinfo *pai; @@ -2222,6 +2267,13 @@ return NS_NOTFOUND; } + if (pai->ai_family == AF_INET6 && + (pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED) { + ai0 = *pai; + ai0.ai_family = AF_UNSPEC; + pai = &ai0; + } + switch (pai->ai_family) { case AF_UNSPEC: q.name = hostname; @@ -2277,9 +2329,12 @@ cur = cur->ai_next; } } - ai = getanswer(buf, q.n, q.name, q.qtype, pai, res); - if (ai) - cur->ai_next = ai; + if (!ai || pai->ai_family != AF_UNSPEC || + (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) != AI_V4MAPPED) { + ai = getanswer(buf, q.n, q.name, q.qtype, pai, res); + if (ai) + cur->ai_next = ai; + } free(buf); free(buf2); if (sentinel.ai_next == NULL) @@ -2362,6 +2417,17 @@ hints.ai_protocol = 0; hints.ai_flags = AI_NUMERICHOST; error = getaddrinfo(addr, "0", &hints, &res0); + if (error) { + /* + * XXX: Both IPv6 address and IPv4-mapped IPv6 address + * are returned without specifying AI_ALL. + */ + if (pai->ai_family != AF_INET6 || + (pai->ai_flags & AI_V4MAPPED) != AI_V4MAPPED) + goto again; + hints.ai_flags |= AI_V4MAPPED; + error = getaddrinfo(addr, "0", &hints, &res0); + } if (error) goto again; #ifdef FILTER_V4MAPPED @@ -2470,6 +2536,13 @@ hints = *pai; hints.ai_flags = AI_NUMERICHOST; error = getaddrinfo(addr, NULL, &hints, &res0); + if (error) { + if (pai->ai_family == AF_INET6 && + (pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED) { + hints.ai_flags |= AI_V4MAPPED; + error = getaddrinfo(addr, NULL, &hints, &res0); + } + } if (error == 0) { for (res = res0; res; res = res->ai_next) { /* cover it up */