Index: include/netdb.h =================================================================== --- include/netdb.h (revision 290820) +++ 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 290820) +++ lib/libc/net/getaddrinfo.c (working copy) @@ -451,6 +451,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. @@ -1177,7 +1193,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]; @@ -1201,8 +1217,17 @@ return 0; 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; + } break; } @@ -1321,6 +1346,8 @@ char *fp_str; int translate = 0; #endif + struct in6_addr mapaddr; + int map_translate = 0; #ifdef FAITH /* @@ -1356,7 +1383,18 @@ translate = 1; } } + + if (translate == 1) + ; + else #endif + 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)); + map_translate = 1; + } ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + (afd->a_socklen)); @@ -1375,7 +1413,10 @@ memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen); else #endif - memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); + if (map_translate == 1) + memcpy(p + afd->a_off, &mapaddr, (size_t)afd->a_addrlen); + else + memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); return ai; } @@ -2191,7 +2232,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; @@ -2219,6 +2260,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; @@ -2275,9 +2323,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) @@ -2360,8 +2411,19 @@ hints.ai_protocol = 0; hints.ai_flags = AI_NUMERICHOST; error = getaddrinfo(addr, "0", &hints, &res0); - if (error) - goto again; + 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 /* XXX should check all items in the chain */ if (res0->ai_family == AF_INET6 && @@ -2468,6 +2530,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 */