From owner-svn-src-stable-9@freebsd.org Fri Dec 25 11:33:10 2015 Return-Path: Delivered-To: svn-src-stable-9@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id B1C48A50F89; Fri, 25 Dec 2015 11:33:10 +0000 (UTC) (envelope-from ume@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 7200814BE; Fri, 25 Dec 2015 11:33:10 +0000 (UTC) (envelope-from ume@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id tBPBX90T061778; Fri, 25 Dec 2015 11:33:09 GMT (envelope-from ume@FreeBSD.org) Received: (from ume@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id tBPBX9Hk061775; Fri, 25 Dec 2015 11:33:09 GMT (envelope-from ume@FreeBSD.org) Message-Id: <201512251133.tBPBX9Hk061775@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ume set sender to ume@FreeBSD.org using -f From: Hajimu UMEMOTO Date: Fri, 25 Dec 2015 11:33:09 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org Subject: svn commit: r292724 - in stable/9: include lib/libc/net X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-9@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for only the 9-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 25 Dec 2015 11:33:10 -0000 Author: ume Date: Fri Dec 25 11:33:09 2015 New Revision: 292724 URL: https://svnweb.freebsd.org/changeset/base/292724 Log: MFC r292444, r292446: Add AI_V4MAPPED and AI_ALL support for getaddrinfo(3). PR: 198092 Modified: stable/9/include/netdb.h stable/9/lib/libc/net/getaddrinfo.3 stable/9/lib/libc/net/getaddrinfo.c Directory Properties: stable/9/include/ (props changed) stable/9/lib/libc/ (props changed) Modified: stable/9/include/netdb.h ============================================================================== --- stable/9/include/netdb.h Fri Dec 25 11:29:18 2015 (r292723) +++ stable/9/include/netdb.h Fri Dec 25 11:33:09 2015 (r292724) @@ -179,7 +179,7 @@ struct addrinfo { /* 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 */ Modified: stable/9/lib/libc/net/getaddrinfo.3 ============================================================================== --- stable/9/lib/libc/net/getaddrinfo.3 Fri Dec 25 11:29:18 2015 (r292723) +++ stable/9/lib/libc/net/getaddrinfo.3 Fri Dec 25 11:33:09 2015 (r292724) @@ -18,7 +18,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 14, 2013 +.Dd December 19, 2015 .Dt GETADDRINFO 3 .Os .Sh NAME @@ -126,11 +126,13 @@ field to which the parameter points shall be set to zero or be the bitwise-inclusive OR of one or more of the values .Dv AI_ADDRCONFIG , +.Dv AI_ALL , .Dv AI_CANONNAME , .Dv AI_NUMERICHOST , -.Dv AI_NUMERICSERV +.Dv AI_NUMERICSERV , +.Dv AI_PASSIVE and -.Dv AI_PASSIVE . +.Dv AI_V4MAPPED . .Bl -tag -width "AI_CANONNAMEXX" .It Dv AI_ADDRCONFIG If the @@ -139,6 +141,25 @@ bit is set, IPv4 addresses shall be retu an IPv4 address is configured on the local system, and IPv6 addresses shall be returned only if an IPv6 address is configured on the local system. +.It Dv AI_ALL +If the +.Dv AI_ALL +flag is used with the +.Dv AI_V4MAPPED +flag, then +.Fn getaddrinfo +shall return all matching IPv6 and IPv4 addresses. +.Pp +For example, when using the DNS, queries are made for both AAAA records and A records, and +.Fn getaddrinfo +returns the combined results of both queries. +Any IPv4 addresses found are returned as IPv4-mapped IPv6 addresses. +.Pp +The +.Dv AI_ALL +flag without the +.Dv AI_V4MAPPED +flag is ignored. .It Dv AI_CANONNAME If the .Dv AI_CANONNAME @@ -203,6 +224,25 @@ loopback address if is the null pointer and .Dv AI_PASSIVE is not set. +.It Dv AI_V4MAPPED +If the +.Dv AI_V4MAPPED +flag is specified along with an ai_family of +.Dv AF_INET6 , +then +.Fn getaddrinfo +shall return IPv4-mapped IPv6 addresses on finding no matching IPv6 addresses ( +.Fa ai_addrlen +shall be 16). +.Pp +For example, when using the DNS, if no AAAA records are found then a query is made for A records and any found are returned as IPv4-mapped IPv6 addresses. +.Pp +The +.Dv AI_V4MAPPED +flag shall be ignored unless +.Fa ai_family +equals +.Dv AF_INET6 . .El .El .Pp Modified: stable/9/lib/libc/net/getaddrinfo.c ============================================================================== --- stable/9/lib/libc/net/getaddrinfo.c Fri Dec 25 11:29:18 2015 (r292723) +++ stable/9/lib/libc/net/getaddrinfo.c Fri Dec 25 11:33:09 2015 (r292724) @@ -96,6 +96,7 @@ __FBSDID("$FreeBSD$"); #include #include #include "un-namespace.h" +#include "netdb_private.h" #include "libc_private.h" #ifdef NS_CACHING #include "nscache.h" @@ -450,6 +451,24 @@ getaddrinfo(const char *hostname, const } /* + * 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: +#ifdef INET6 + if (pai->ai_family != AF_INET6) + pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); + break; +#endif + 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. @@ -840,6 +859,16 @@ set_source(struct ai_order *aio, struct /* open a socket to get the source address for the given dst */ if ((s = _socket(ai.ai_family, ai.ai_socktype, ai.ai_protocol)) < 0) return; /* give up */ +#ifdef INET6 + if (ai.ai_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai.ai_addr; + int off = 0; + + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) + (void)_setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + (char *)&off, sizeof(off)); + } +#endif if (_connect(s, ai.ai_addr, ai.ai_addrlen) < 0) goto cleanup; srclen = ai.ai_addrlen; @@ -1175,7 +1204,7 @@ explore_numeric(const struct addrinfo *p 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]; @@ -1199,8 +1228,17 @@ explore_numeric(const struct addrinfo *p 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; } @@ -1319,6 +1357,9 @@ get_ai(const struct addrinfo *pai, const char *fp_str; int translate = 0; #endif +#ifdef INET6 + struct in6_addr mapaddr; +#endif #ifdef FAITH /* @@ -1356,6 +1397,14 @@ get_ai(const struct addrinfo *pai, const } #endif +#ifdef INET6 + if (afd->a_af == AF_INET && (pai->ai_flags & AI_V4MAPPED) != 0) { + afd = &afdl[N_INET6]; + _map_v4v6_address(addr, (char *)&mapaddr); + addr = (char *)&mapaddr; + } +#endif + ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) + (afd->a_socklen)); if (ai == NULL) @@ -2186,7 +2235,7 @@ addr4sort(struct addrinfo *sentinel, res 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; @@ -2216,6 +2265,13 @@ _dns_getaddrinfo(void *rv, void *cb_data 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; @@ -2271,9 +2327,12 @@ _dns_getaddrinfo(void *rv, void *cb_data 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) @@ -2355,6 +2414,9 @@ found: hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = 0; hints.ai_flags = AI_NUMERICHOST; + if (pai->ai_family == AF_INET6 && + (pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED) + hints.ai_flags |= AI_V4MAPPED; error = getaddrinfo(addr, "0", &hints, &res0); if (error) goto again; @@ -2382,6 +2444,20 @@ found: return res0; } +static struct addrinfo * +_getht(FILE **hostf, const char *name, const struct addrinfo *pai, + struct addrinfo *cur) +{ + struct addrinfo *p; + + while ((p = _gethtent(hostf, name, pai)) != NULL) { + cur->ai_next = p; + while (cur && cur->ai_next) + cur = cur->ai_next; + } + return (cur); +} + /*ARGSUSED*/ static int _files_getaddrinfo(void *rv, void *cb_data, va_list ap) @@ -2389,7 +2465,6 @@ _files_getaddrinfo(void *rv, void *cb_da const char *name; const struct addrinfo *pai; struct addrinfo sentinel, *cur; - struct addrinfo *p; FILE *hostf = NULL; name = va_arg(ap, char *); @@ -2399,11 +2474,19 @@ _files_getaddrinfo(void *rv, void *cb_da cur = &sentinel; _sethtent(&hostf); - while ((p = _gethtent(&hostf, name, pai)) != NULL) { - cur->ai_next = p; - while (cur && cur->ai_next) - cur = cur->ai_next; - } + if (pai->ai_family == AF_INET6 && + (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) == AI_V4MAPPED) { + struct addrinfo ai0 = *pai; + + ai0.ai_flags &= ~AI_V4MAPPED; + cur = _getht(&hostf, name, &ai0, cur); + if (sentinel.ai_next == NULL) { + _sethtent(&hostf); + ai0.ai_flags |= AI_V4MAPPED; + cur = _getht(&hostf, name, &ai0, cur); + } + } else + cur = _getht(&hostf, name, pai, cur); _endhtent(&hostf); *((struct addrinfo **)rv) = sentinel.ai_next; @@ -2463,6 +2546,9 @@ nextline: hints = *pai; hints.ai_flags = AI_NUMERICHOST; + 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) { @@ -2510,15 +2596,46 @@ _yp_getaddrinfo(void *rv, void *cb_data, memset(&sentinel, 0, sizeof(sentinel)); cur = &sentinel; + /* ipnodes.byname can hold both IPv4/v6 */ + r = yp_match(ypdomain, "ipnodes.byname", name, + (int)strlen(name), &ypbuf, &ypbuflen); + if (r == 0) { + ai = _yphostent(ypbuf, pai); + if (ai) { + cur->ai_next = ai; + while (cur && cur->ai_next) + cur = cur->ai_next; + } + free(ypbuf); + } + + if (ai != NULL) { + struct sockaddr_in6 *sin6; + + switch (ai->ai_family) { + case AF_INET: + goto done; + case AF_INET6: + sin6 = (struct sockaddr_in6 *)ai->ai_addr; + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) + goto done; + break; + } + } + /* hosts.byname is only for IPv4 (Solaris8) */ - if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) { + if (pai->ai_family == AF_UNSPEC || pai->ai_family == AF_INET || + ((pai->ai_family == AF_INET6 && + (pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED) && + (ai == NULL || (pai->ai_flags & AI_ALL) == AI_ALL))) { r = yp_match(ypdomain, "hosts.byname", name, (int)strlen(name), &ypbuf, &ypbuflen); if (r == 0) { struct addrinfo ai4; ai4 = *pai; - ai4.ai_family = AF_INET; + if (pai->ai_family == AF_UNSPEC) + ai4.ai_family = AF_INET; ai = _yphostent(ypbuf, &ai4); if (ai) { cur->ai_next = ai; @@ -2529,16 +2646,7 @@ _yp_getaddrinfo(void *rv, void *cb_data, } } - /* ipnodes.byname can hold both IPv4/v6 */ - r = yp_match(ypdomain, "ipnodes.byname", name, - (int)strlen(name), &ypbuf, &ypbuflen); - if (r == 0) { - ai = _yphostent(ypbuf, pai); - if (ai) - cur->ai_next = ai; - free(ypbuf); - } - +done: if (sentinel.ai_next == NULL) { RES_SET_H_ERRNO(__res_state(), HOST_NOT_FOUND); return NS_NOTFOUND;