From 2f443e27e5988131d8b57bec58ee15f9227e0899 Mon Sep 17 00:00:00 2001 From: Robert Mustacchi Date: Thu, 14 Aug 2014 21:58:20 +0000 Subject: [PATCH] 5096 getaddrinfo doesn't properly handle AI_ADDRCONFIG | AI_V4MAPPED Reviewed by: Dan McDonald Reviewed by: Jason King Approved by: Richard Lowe --- usr/src/head/netdb.h | 5 ++++- usr/src/lib/libnsl/nss/getipnodeby.c | 26 +++++++++++++++++++++++++- usr/src/lib/libsocket/inet/getaddrinfo.c | 13 ++++++++++++- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/usr/src/head/netdb.h b/usr/src/head/netdb.h index b26c26d40b..8d8a6a8b80 100644 --- a/usr/src/head/netdb.h +++ b/usr/src/head/netdb.h @@ -123,7 +123,10 @@ struct addrinfo { struct addrinfo *ai_next; /* next structure in linked list */ }; - +/* + * The flag 0x8000 is currently reserved for private use between libnsl and + * libsocket. See lib/libsocket/inet/getaddrinfo.c for more information. + */ /* addrinfo flags */ #define AI_PASSIVE 0x0008 /* intended for bind() + listen() */ #define AI_CANONNAME 0x0010 /* return canonical version of host */ diff --git a/usr/src/lib/libnsl/nss/getipnodeby.c b/usr/src/lib/libnsl/nss/getipnodeby.c index 112b54ec5a..f84b641157 100644 --- a/usr/src/lib/libnsl/nss/getipnodeby.c +++ b/usr/src/lib/libnsl/nss/getipnodeby.c @@ -73,6 +73,8 @@ * IPNODE_LOOKUPIPNODES getipnodebyname() needs to lookup the name in ipnodes. * IPNODE_LOOKUPHOSTS getipnodebyname() needs to lookup the name in hosts. * IPNODE_ISLITERAL The name supplied is a literal address string. + * IPNODE_UNMAP The user doesn't want v4 mapped addresses if no IPv6 + * interfaces are plumbed on the system. */ #define IPNODE_WANTIPV6 0x00000001u #define IPNODE_WANTIPV4 0x00000002u @@ -80,9 +82,16 @@ #define IPNODE_LOOKUPIPNODES 0x00000008u #define IPNODE_LOOKUPHOSTS 0x00000010u #define IPNODE_LITERAL 0x00000020u +#define IPNODE_UNMAP 0x00000040u #define IPNODE_IPV4 (IPNODE_WANTIPV4 | IPNODE_IPV4IFNOIPV6) /* + * The private flag between libsocket and libnsl. See + * lib/libsocket/inet/getaddrinfo.c for more information. + */ +#define AI_ADDRINFO 0x8000 + +/* * The default set of bits corresponding to a getipnodebyname() flags * argument of AI_DEFAULT. */ @@ -162,6 +171,10 @@ getipnodebyname_processflags(const char *name, int af, int flags) } else if (flags & AI_ALL) { ipnode_bits &= ~IPNODE_IPV4IFNOIPV6; } + if ((flags & AI_ADDRCONFIG) && !ipv6configured && + (flags & AI_ADDRINFO)) { + ipnode_bits |= IPNODE_UNMAP; + } } else { ipnode_bits &= ~IPNODE_IPV4; } @@ -343,7 +356,18 @@ getipnodebyname(const char *name, int af, int flags, int *error_num) else if (!(ipnode_bits & IPNODE_WANTIPV6)) hp = __filter_addresses(AF_INET6, buf6->result); - if (hp == NULL) + /* + * We've been asked to unmap v4 addresses. This + * situation implies IPNODE_WANTIPV4 and + * !IPNODE_WANTIPV6. + */ + if (hp != NULL && (ipnode_bits & IPNODE_UNMAP)) { + /* + * Just set hp to a new value, cleanup: will + * free the old one + */ + hp = __mappedtov4(hp, error_num); + } else if (hp == NULL) *error_num = NO_ADDRESS; } diff --git a/usr/src/lib/libsocket/inet/getaddrinfo.c b/usr/src/lib/libsocket/inet/getaddrinfo.c index ec72a9974e..99b769e41e 100644 --- a/usr/src/lib/libsocket/inet/getaddrinfo.c +++ b/usr/src/lib/libsocket/inet/getaddrinfo.c @@ -69,6 +69,17 @@ const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; #define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST \ | AI_ADDRCONFIG | AI_NUMERICSERV | AI_V4MAPPED | AI_ALL) #define ANY 0 + +/* + * This is a private, undocumented, flag that getaddrinfo() uses for + * getipnodebyname(). In the case of AI_ADDRCONFIG && AI_V4MAPPED, if there are + * no IPv6 addresses, getaddrinfo() should return non-IPv4 mapped addresses. On + * the flip side, getipnodebyname() is defined by RFC 2553 to explicitly do so. + * Therefore this private flag indicates to getaddrinfo that we shouldn't do + * this. + */ +#define AI_ADDRINFO 0x8000 + /* function prototypes for used by getaddrinfo() routine */ static int get_addr(int family, const char *hostname, struct addrinfo *aip, struct addrinfo *cur, ushort_t port, int version); @@ -602,7 +613,7 @@ get_addr(int family, const char *hostname, struct addrinfo *aip, struct /* if hostname argument is literal, name service doesn't get called */ if (family == PF_UNSPEC) { hp = getipnodebyname(_hostname, AF_INET6, AI_ALL | - aip->ai_flags | AI_V4MAPPED, &errnum); + aip->ai_flags | AI_V4MAPPED | AI_ADDRINFO, &errnum); } else { hp = getipnodebyname(_hostname, family, aip->ai_flags, &errnum); } -- 2.11.4.GIT