git: c179937b986e - main - libc/getnameinfo: stop adding NI_NUMERICHOST where inappropriate

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Fri, 26 Jul 2024 11:04:35 UTC
The branch main has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=c179937b986ec3959d89bfeb8eed0a6f58a28649

commit c179937b986ec3959d89bfeb8eed0a6f58a28649
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2024-06-10 11:34:25 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2024-07-26 11:03:56 +0000

    libc/getnameinfo: stop adding NI_NUMERICHOST where inappropriate
    
    Checking the first nibble of the IPv6 address to be 0 and then
    excluding two well known cases (v4-mapped, loopback) leaves us with
    more cases where the first nibble could be 0, e.g., the RFC 6052,
    2.1 Well-Known Prefix 64:ff9b::/96.
    It is not practical to track them all and it is not clear what lead
    to this special casing originally, so remove them.
    
    While here also remove the IN6_IS_ADDR_LINKLOCAL() + NI_NUMERICHOST
    case as link-local address resolution does exist.
    
    We do leave the IN6_IS_ADDR_MULTICAST() case for now as I could
    not find any references to any official reverse lookups for these.
    
    Adding comments for more case (and some historic behaviour) in order
    to make it easier to follow the logic.
    
    PR:             279618
    Fixes:          6cb9418289f90
    MFC after:      6 weeks
    Reviewed by:    hrs
    Differential Revision: https://reviews.freebsd.org/D45547
---
 lib/libc/net/getnameinfo.c | 54 +++++++++++++++++++++++++++++++---------------
 1 file changed, 37 insertions(+), 17 deletions(-)

diff --git a/lib/libc/net/getnameinfo.c b/lib/libc/net/getnameinfo.c
index 7ab490abb67f..01bceaa98fce 100644
--- a/lib/libc/net/getnameinfo.c
+++ b/lib/libc/net/getnameinfo.c
@@ -229,24 +229,44 @@ getnameinfo_inet(const struct afd *afd,
 	case AF_INET6:
 	    {
 		const struct sockaddr_in6 *sin6;
+
 		sin6 = (const struct sockaddr_in6 *)sa;
-		switch (sin6->sin6_addr.s6_addr[0]) {
-		case 0x00:
-			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
-				;
-			else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
-				;
-			else
-				flags |= NI_NUMERICHOST;
-			break;
-		default:
-			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
-				flags |= NI_NUMERICHOST;
-			}
-			else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
-				flags |= NI_NUMERICHOST;
-			break;
-		}
+
+		/*
+		 * https://pubs.opengroup.org/onlinepubs/9699919799/functions/getnameinfo.html
+		 * "[IP6] [Option Start] If the socket address structure
+		 * contains an IPv4-mapped IPv6 address or an IPv4-compatible
+		 * IPv6 address, the implementation shall extract the embedded
+		 * IPv4 address and lookup the node name for that IPv4 address.
+		 * [Option End]"
+		 * => getipnodebyaddr() handles this case for us.
+		 * => in case of NI_NUMERICHOST being set, inet_ntop[6] will
+		 *    handle it too.
+		 *
+		 * "If the address is the IPv6 unspecified address ( "::" ),
+		 * a lookup shall not be performed and the behavior shall be
+		 * the same as when the node's name cannot be located."
+		 * => getipnodebyaddr() handles this case for us.
+		 * => in case of NI_NUMERICHOST being set,
+		 *    ip6_parsenumeric() -> inet_ntop[6] will handle it too.
+		 */
+
+		/*
+		 * We used to exclude link-local from lookups.
+		 * Even though calles in the resolver chain may not (yet)
+		 * properly deal with them, we no longer do as for link-local
+		 * there is a path to resolve these. See:
+		 * RFC 6303 4.5.  IPv6 Link-Local Addresses
+		 * RFC 6762 4.  Reverse Address Mapping
+		 *
+		 * XXX For IPv6 MC the only reference found was
+		 * https://www.ietf.org/archive/id/draft-michaelson-as112-ipv6-02.html
+		 * but there are also no "empty zone"s for x.0.f.f.ip6.arpa
+		 * in DNS servers.  Keep catching it here for now and
+		 * do not attempt name resolution but return the address string.
+		 */
+		if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
+			flags |= NI_NUMERICHOST;
 	    }
 		break;
 #endif