git: 8538c69d84ff - main - Revert "libc/resolv: Reimplement the sortlist parser"

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Mon, 29 Jun 2026 15:54:27 UTC
The branch main has been updated by des:

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

commit 8538c69d84ff2ee4462d09ac21a69e8c907116f1
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2026-06-29 15:53:59 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2026-06-29 15:53:59 +0000

    Revert "libc/resolv: Reimplement the sortlist parser"
    
    This reverts commit 507ab02d751b4aaa7f35f30882299e9908448e53.
---
 lib/libc/resolv/Makefile.inc |   1 -
 lib/libc/resolv/res_init.c   | 232 ++++++++++++++++++++-----------------------
 share/man/man5/resolver.5    |  33 +++---
 3 files changed, 123 insertions(+), 143 deletions(-)

diff --git a/lib/libc/resolv/Makefile.inc b/lib/libc/resolv/Makefile.inc
index ecb0c2462b08..be900e942435 100644
--- a/lib/libc/resolv/Makefile.inc
+++ b/lib/libc/resolv/Makefile.inc
@@ -7,5 +7,4 @@ SRCS+=	herror.c h_errno.c mtctxres.c res_comp.c res_data.c res_debug.c \
 
 SYM_MAPS+= ${LIBC_SRCTOP}/resolv/Symbol.map
 
-CFLAGS+=-I${LIBC_SRCTOP}/net
 CFLAGS+=-I${SRCTOP}/lib/libmd
diff --git a/lib/libc/resolv/res_init.c b/lib/libc/resolv/res_init.c
index a0cd381d0f0f..c61b247b5199 100644
--- a/lib/libc/resolv/res_init.c
+++ b/lib/libc/resolv/res_init.c
@@ -95,7 +95,6 @@
 /* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
 #include <resolv.h>
 
-#include "res_config.h"
 #include "res_private.h"
 
 static void res_readconf(res_state, const char *, int);
@@ -105,8 +104,10 @@ static int res_setnsaddr(res_state, int, const char *, const char *);
 static void res_setoptions(res_state, const char *, const char *);
 
 #ifdef RESOLVSORT
-static int res_setsortlist(res_state, int, const char *, const char *);
-#endif /* RESOLVSORT */
+static const char sort_mask[] = "/&";
+#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
+static u_int32_t net_mask(struct in_addr);
+#endif
 
 #define res_space(ch)							\
 	isspace((unsigned char)(ch))
@@ -284,7 +285,8 @@ res_readconf(res_state statp, const char *resconf, int maxns)
 	size_t sz = 0;
 	int nserv = 0;
 #ifdef RESOLVSORT
-	int nsort = 0;
+	int n, nsort = 0;
+	char *net;
 #endif
 
 	if ((fp = fopen(resconf, "re")) == NULL)
@@ -355,28 +357,101 @@ res_readconf(res_state statp, const char *resconf, int maxns)
 			continue;
 		}
 #ifdef RESOLVSORT
-		/* read result sort order */
 		if (res_match(line, eow, "sortlist")) {
+			struct in_addr a;
+			struct in6_addr a6;
+			int m, i;
+			u_char *u;
+			struct __res_state_ext *ext = statp->_u._ext.ext;
+
+			cp = line + sizeof("sortlist") - 1;
 			while (nsort < MAXRESOLVSORT) {
-				cp = eow;
-				while (cp < eol && res_space(*cp))
+				while (*cp == ' ' || *cp == '\t')
 					cp++;
-				if (cp == eol)
+				if (*cp == '\0' || *cp == '\n' || *cp == ';')
 					break;
-				eow = cp;
-				while (eow < eol && !res_space(*eow))
-					eow++;
-				if (res_setsortlist(statp, nsort, cp, eow))
+				net = cp;
+				while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
+				    isascii(*cp) && !isspace((unsigned char)*cp))
+					cp++;
+				n = *cp;
+				*cp = 0;
+				if (inet_aton(net, &a)) {
+					statp->sort_list[nsort].addr = a;
+					if (ISSORTMASK(n)) {
+						*cp++ = n;
+						net = cp;
+						while (*cp && *cp != ';' &&
+						    isascii(*cp) &&
+						    !isspace((unsigned char)*cp))
+							cp++;
+						n = *cp;
+						*cp = 0;
+						if (inet_aton(net, &a)) {
+							statp->sort_list[nsort].mask = a.s_addr;
+						} else {
+							statp->sort_list[nsort].mask =
+							    net_mask(statp->sort_list[nsort].addr);
+						}
+					} else {
+						statp->sort_list[nsort].mask =
+						    net_mask(statp->sort_list[nsort].addr);
+					}
+					ext->sort_list[nsort].af = AF_INET;
+					ext->sort_list[nsort].addr.ina =
+					    statp->sort_list[nsort].addr;
+					ext->sort_list[nsort].mask.ina.s_addr =
+					    statp->sort_list[nsort].mask;
 					nsort++;
+				}
+				else if (inet_pton(AF_INET6, net, &a6) == 1) {
+
+					ext->sort_list[nsort].af = AF_INET6;
+					ext->sort_list[nsort].addr.in6a = a6;
+					u = (u_char *)&ext->sort_list[nsort].mask.in6a;
+					*cp++ = n;
+					net = cp;
+					while (*cp && *cp != ';' &&
+					    isascii(*cp) && !isspace(*cp))
+						cp++;
+					m = n;
+					n = *cp;
+					*cp = 0;
+					switch (m) {
+					case '/':
+						m = atoi(net);
+						break;
+					case '&':
+						if (inet_pton(AF_INET6, net, u) == 1) {
+							m = -1;
+							break;
+						}
+						/*FALLTHROUGH*/
+					default:
+						m = sizeof(struct in6_addr) * CHAR_BIT;
+						break;
+					}
+					if (m >= 0) {
+						for (i = 0; i < sizeof(struct in6_addr); i++) {
+							if (m <= 0) {
+								*u = 0;
+							} else {
+								m -= CHAR_BIT;
+								*u = (u_char)~0;
+								if (m < 0)
+									*u <<= -m;
+							}
+							u++;
+						}
+					}
+					statp->sort_list[nsort].addr.s_addr =
+					    (u_int32_t)0xffffffff;
+					statp->sort_list[nsort].mask =
+					    (u_int32_t)0xffffffff;
+					nsort++;
+				}
+				*cp = n;
 			}
-#ifdef DEBUG
-			while (cp < eol && res_space(*cp))
-				cp++;
-			if (cp < eol) {
-				printf(";; sortlist overflow: %.*s\n",
-				    (int)(eol - cp), cp);
-			}
-#endif
 			continue;
 		}
 #endif /* RESOLVSORT */
@@ -576,108 +651,6 @@ res_setnsaddr(res_state statp, int i, const char *str, const char *end)
 	return (ret);
 }
 
-#ifdef RESOLVSORT
-/*%
- * Set the sort order.  Assumes no leading or trailing space.
- */
-int
-res_setsortlist(res_state statp, int i, const char *str, const char *end)
-{
-	struct __res_state_ext *ext = statp->_u._ext.ext;
-	char addr[48], mask[48], *dst, *numend;
-	_Static_assert(sizeof(addr) > INET6_ADDRSTRLEN,
-	    "address buffer too small for AF_INET6");
-	_Static_assert(sizeof(addr) > INET_ADDRSTRLEN,
-	    "address buffer too small for AF_INET");
-	_Static_assert(sizeof(mask) > INET6_ADDRSTRLEN,
-	    "mask buffer too small for AF_INET6");
-	_Static_assert(sizeof(mask) > INET_ADDRSTRLEN,
-	    "mask buffer too small for AF_INET");
-	struct in_addr a;
-	struct in6_addr a6;
-	uint8_t *u;
-	long num;
-
-	/* copy the address */
-	dst = addr;
-	while (str < end && !res_space(*str) && *str != '/') {
-		*dst++ = *str++;
-		if (dst == addr + sizeof(addr))
-			return (0);
-	}
-	*dst = '\0';
-
-	/* copy the mask, if there is one */
-	dst = mask;
-	if (str < end) {
-		if (*str++ != '/')
-			return (0);
-		if (end - str >= sizeof(mask))
-			return (0);
-		memcpy(mask, str, end - str);
-		dst += end - str;
-	}
-	*dst = '\0';
-
-	/* IPv4 case */
-	if (inet_pton(AF_INET, addr, &a) == 1) {
-		statp->sort_list[i].addr = a;
-		if (mask[0] != '\0') {
-			if ((num = strtol(mask, &numend, 10)) < 0 ||
-			    num > 32 || *numend != '\0')
-				return (0);
-		} else {
-			if (IN_CLASSA(ntohl(a.s_addr)))
-				num = 8;
-			else if (IN_CLASSB(ntohl(a.s_addr)))
-				num = 16;
-			else
-				num = 24;
-		}
-		statp->sort_list[i].mask =
-		    htonl(0xffffffffU << (32 - num));
-		ext->sort_list[i].af = AF_INET;
-		ext->sort_list[i].addr.ina =
-		    statp->sort_list[i].addr;
-		ext->sort_list[i].mask.ina.s_addr =
-		    statp->sort_list[i].mask;
-#ifdef DEBUG
-		inet_ntop(AF_INET, &a, addr, sizeof(addr));
-		printf(";; sortlist %s/%ld\n", addr, num);
-#endif
-		return (1);
-	}
-
-	/* IPv6 case */
-	if (inet_pton(AF_INET6, addr, &a6) == 1) {
-		statp->sort_list[i].addr.s_addr = INADDR_NONE;
-		statp->sort_list[i].mask = INADDR_NONE;
-		ext->sort_list[i].af = AF_INET6;
-		ext->sort_list[i].addr.in6a = a6;
-		if (mask[0]) {
-			/* prefix length */
-			if ((num = strtol(mask, &numend, 10)) < 0 ||
-			    num > 128 || *numend != '\0')
-				return (0);
-		} else {
-			num = 64;
-		}
-#ifdef DEBUG
-		inet_ntop(AF_INET6, &a6, addr, sizeof(addr));
-		printf(";; sortlist %s/%ld\n", addr, num);
-#endif
-		a6 = (struct in6_addr)IN6ADDR_ANY_INIT;
-		for (u = a6.s6_addr8; num > 0; num -= 8)
-			*u++ = num > 8 ? 0xffU : 0xffU << (8 - num);
-		ext->sort_list[i].mask.in6a = a6;
-		return (1);
-	}
-
-	/* invalid */
-	return (0);
-}
-#endif /* RESOLVSORT */
-
 /*%
  * Split the string up into words and interpret them as resolver options.
  */
@@ -817,6 +790,21 @@ res_setoptions(res_state statp, const char *options, const char *source)
 	}
 }
 
+#ifdef RESOLVSORT
+/* XXX - should really support CIDR which means explicit masks always. */
+static u_int32_t
+net_mask(struct in_addr in)		/*!< XXX - should really use system's version of this  */
+{
+	u_int32_t i = ntohl(in.s_addr);
+
+	if (IN_CLASSA(i))
+		return (htonl(IN_CLASSA_NET));
+	else if (IN_CLASSB(i))
+		return (htonl(IN_CLASSB_NET));
+	return (htonl(IN_CLASSC_NET));
+}
+#endif
+
 void
 freebsd15_res_rndinit(res_state statp)
 {
diff --git a/share/man/man5/resolver.5 b/share/man/man5/resolver.5
index 135e56287b5f..8af69fd2dac7 100644
--- a/share/man/man5/resolver.5
+++ b/share/man/man5/resolver.5
@@ -100,27 +100,20 @@ for one of the domains.
 .Pp
 The search list is currently limited to six domains
 with a total of 256 characters.
-.It Cm sortlist Ar addr1 Ns Oo Li / Ns Ar plen1 Oc Op addr2 Ns Oo Li / Ns Ar plen2 Oc ...
-Sort order for query results in the form of a list of
-.Ar addr Ns Li / Ns Ar plen
-entries, for instance:
-.Bd -literal
-sortlist 198.51.100.0/24 203.0.113.0/24 2001:db8::/32
-.Ed
-.Pp
-If the prefix length is omitted, it defaults to historical class-based
-addressing for IPv4 and to 64 for IPv6.
-.Pp
-Query results that match one of the sort list entries are sorted
-accordingly and ahead of query results that don't.
-If multiple results match a single sort list entry, the order is
-unspecified.
+.It Sy sortlist
+Sortlist allows addresses returned by the resolver to be sorted.
+A sortlist is specified by IP address netmask pairs.
+If the netmask is not specified,
+it defaults to the historical Class A/B/C netmask of the net;
+this usage is deprecated.
+The IP address
+and network pairs are separated by slashes.
+Up to 10 pairs may
+be specified.
+E.g.,
 .Pp
-If multiple
-.Cm sortlist
-lines are encountered, entries are appended to the list in the order
-in which they were encountered, up to a maximum of ten.
-.It Cm options
+.Dl "sortlist 10.9.1.0/255.255.240.0 10.9.0.0/255.255.0.0"
+.It Cm options Ar option1 Op Ar option2 ...
 Options allows certain internal resolver variables to be modified.
 The following options are supported:
 .Bl -tag -width indent