Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 25 Dec 2015 11:17:21 +0000 (UTC)
From:      Hajimu UMEMOTO <ume@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r292722 - in stable/10: include lib/libc/net
Message-ID:  <201512251117.tBPBHLHo055811@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ume
Date: Fri Dec 25 11:17:21 2015
New Revision: 292722
URL: https://svnweb.freebsd.org/changeset/base/292722

Log:
  Add AI_V4MAPPED and AI_ALL support for getaddrinfo(3).
  
  PR:		198092

Modified:
  stable/10/include/netdb.h
  stable/10/lib/libc/net/getaddrinfo.3
  stable/10/lib/libc/net/getaddrinfo.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/include/netdb.h
==============================================================================
--- stable/10/include/netdb.h	Fri Dec 25 10:55:39 2015	(r292721)
+++ stable/10/include/netdb.h	Fri Dec 25 11:17:21 2015	(r292722)
@@ -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/10/lib/libc/net/getaddrinfo.3
==============================================================================
--- stable/10/lib/libc/net/getaddrinfo.3	Fri Dec 25 10:55:39 2015	(r292721)
+++ stable/10/lib/libc/net/getaddrinfo.3	Fri Dec 25 11:17:21 2015	(r292722)
@@ -18,7 +18,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd October 5, 2015
+.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/10/lib/libc/net/getaddrinfo.c
==============================================================================
--- stable/10/lib/libc/net/getaddrinfo.c	Fri Dec 25 10:55:39 2015	(r292721)
+++ stable/10/lib/libc/net/getaddrinfo.c	Fri Dec 25 11:17:21 2015	(r292722)
@@ -96,6 +96,7 @@ __FBSDID("$FreeBSD$");
 #include <stdarg.h>
 #include <nsswitch.h>
 #include "un-namespace.h"
+#include "netdb_private.h"
 #include "libc_private.h"
 #ifdef NS_CACHING
 #include "nscache.h"
@@ -451,6 +452,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.
@@ -842,6 +861,16 @@ set_source(struct ai_order *aio, struct 
 	if ((s = _socket(ai.ai_family, ai.ai_socktype | SOCK_CLOEXEC,
 	    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;
@@ -1177,7 +1206,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];
 
@@ -1201,8 +1230,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;
 	}
 
@@ -1321,6 +1359,9 @@ get_ai(const struct addrinfo *pai, const
 	char *fp_str;
 	int translate = 0;
 #endif
+#ifdef INET6
+	struct in6_addr mapaddr;
+#endif
 
 #ifdef FAITH
 	/*
@@ -1358,6 +1399,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)
@@ -2191,7 +2240,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;
@@ -2221,6 +2270,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;
@@ -2276,9 +2332,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)
@@ -2360,6 +2419,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;
@@ -2387,6 +2449,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)
@@ -2394,7 +2470,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 *);
@@ -2404,11 +2479,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;
@@ -2468,6 +2551,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) {
@@ -2515,15 +2601,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;
@@ -2534,16 +2651,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;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201512251117.tBPBHLHo055811>