Subject: support "no-check-names" in resolv.conf(5)?
To: None <tech-userlevel@netbsd.org>
From: Matthias Drochner <M.Drochner@fz-juelich.de>
List: tech-userlevel
Date: 12/19/2006 18:34:10
This is a multipart MIME message.

--==_Exmh_22061319897680
Content-Type: text/plain; charset=us-ascii


NetBSD is stricter than other OSes about checking the
result of DNS queries for non-allowed characters.
While this is formally correct, one might want to be more
liberal here to work around interoperability problems.
(see PR misc/35254 for an example case)

Now the resolver lib in newer versions of BIND supports
an option "no-check-names" to switch off the strict
checks. The parsing code in libc/resolv/res_init.c does
already set the flag, just the nss glue code in libc/net
does not recognize it. This is trivially fixed by pulling
in some lines from dist/bind -- patches appended.
(The manpage needs more updates, but this is a seperate
issue.)

best regards
Matthias



--==_Exmh_22061319897680
Content-Type: text/plain ; name="res.txt"; charset=us-ascii
Content-Description: res.txt
Content-Disposition: attachment; filename="res.txt"

Index: lib/libc/net/getaddrinfo.c
===================================================================
RCS file: /cvsroot/src/lib/libc/net/getaddrinfo.c,v
retrieving revision 1.87
diff -u -p -r1.87 getaddrinfo.c
--- lib/libc/net/getaddrinfo.c	15 Oct 2006 16:14:46 -0000	1.87
+++ lib/libc/net/getaddrinfo.c	19 Dec 2006 16:54:36 -0000
@@ -211,7 +211,7 @@ static int ip6_str2scopeid(char *, struc
 #endif
 
 static struct addrinfo *getanswer(const querybuf *, int, const char *, int,
-	const struct addrinfo *);
+	const struct addrinfo *, res_state);
 static void aisort(struct addrinfo *s, res_state res);
 static int _dns_getaddrinfo(void *, void *, va_list);
 static void _sethtent(FILE **);
@@ -1032,9 +1032,15 @@ ip6_str2scopeid(char *scope, struct sock
 static const char AskedForGot[] =
 	"gethostby*.getanswer: asked for \"%s\", got \"%s\"";
 
+/* from bind/irs/dns_p.h */
+#define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \
+                               (ok)(nm) != 0)
+#define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok)
+#define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok)
+
 static struct addrinfo *
 getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
-    const struct addrinfo *pai)
+    const struct addrinfo *pai, res_state res)
 {
 	struct addrinfo sentinel, *cur;
 	struct addrinfo ai;
@@ -1083,7 +1089,7 @@ getanswer(const querybuf *answer, int an
 		return (NULL);
 	}
 	n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
-	if ((n < 0) || !(*name_ok)(bp)) {
+	if ((n < 0) || !maybe_ok(res, bp, name_ok)) {
 		h_errno = NO_RECOVERY;
 		return (NULL);
 	}
@@ -1107,7 +1113,7 @@ getanswer(const querybuf *answer, int an
 	had_error = 0;
 	while (ancount-- > 0 && cp < eom && !had_error) {
 		n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
-		if ((n < 0) || !(*name_ok)(bp)) {
+		if ((n < 0) || !maybe_ok(res, bp, name_ok)) {
 			had_error++;
 			continue;
 		}
@@ -1126,7 +1132,7 @@ getanswer(const querybuf *answer, int an
 		if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
 		    type == T_CNAME) {
 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
-			if ((n < 0) || !(*name_ok)(tbuf)) {
+			if ((n < 0) || !maybe_ok(res, tbuf, name_ok)) {
 				had_error++;
 				continue;
 			}
@@ -1334,14 +1340,14 @@ _dns_getaddrinfo(void *rv, void	*cb_data
 		free(buf2);
 		return NS_NOTFOUND;
 	}
-	ai = getanswer(buf, q.n, q.name, q.qtype, pai);
+	ai = getanswer(buf, q.n, q.name, q.qtype, pai, res);
 	if (ai) {
 		cur->ai_next = ai;
 		while (cur && cur->ai_next)
 			cur = cur->ai_next;
 	}
 	if (q.next) {
-		ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai);
+		ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai, res);
 		if (ai)
 			cur->ai_next = ai;
 	}
Index: lib/libc/net/gethnamaddr.c
===================================================================
RCS file: /cvsroot/src/lib/libc/net/gethnamaddr.c,v
retrieving revision 1.71
diff -u -p -r1.71 gethnamaddr.c
--- lib/libc/net/gethnamaddr.c	15 Oct 2006 16:14:46 -0000	1.71
+++ lib/libc/net/gethnamaddr.c	19 Dec 2006 16:54:37 -0000
@@ -210,6 +210,12 @@ dprintf(const char *msg, res_state res, 
 		} \
 	} while (/*CONSTCOND*/0)
 
+/* from bind/irs/dns_p.h */
+#define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \
+                               (ok)(nm) != 0)
+#define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok)
+#define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok)
+
 static struct hostent *
 getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
     res_state res)
@@ -258,7 +264,7 @@ getanswer(const querybuf *answer, int an
 		return NULL;
 	}
 	n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
-	if ((n < 0) || !(*name_ok)(bp)) {
+	if ((n < 0) || !maybe_ok(res, bp, name_ok)) {
 		h_errno = NO_RECOVERY;
 		return NULL;
 	}
@@ -288,7 +294,7 @@ getanswer(const querybuf *answer, int an
 	had_error = 0;
 	while (ancount-- > 0 && cp < eom && !had_error) {
 		n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
-		if ((n < 0) || !(*name_ok)(bp)) {
+		if ((n < 0) || !maybe_ok(res, bp, name_ok)) {
 			had_error++;
 			continue;
 		}
@@ -311,7 +317,7 @@ getanswer(const querybuf *answer, int an
 			if (ap >= &host_aliases[MAXALIASES-1])
 				continue;
 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
-			if ((n < 0) || !(*name_ok)(tbuf)) {
+			if ((n < 0) || !maybe_ok(res, tbuf, name_ok)) {
 				had_error++;
 				continue;
 			}
@@ -341,7 +347,7 @@ getanswer(const querybuf *answer, int an
 		}
 		if (qtype == T_PTR && type == T_CNAME) {
 			n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
-			if (n < 0 || !res_dnok(tbuf)) {
+			if (n < 0 || !maybe_dnok(res, tbuf)) {
 				had_error++;
 				continue;
 			}
@@ -379,7 +385,7 @@ getanswer(const querybuf *answer, int an
 				continue;	/* XXX - had_error++ ? */
 			}
 			n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
-			if ((n < 0) || !res_hnok(bp)) {
+			if ((n < 0) || !maybe_hnok(res, bp)) {
 				had_error++;
 				break;
 			}
Index: lib/libc/net/getnetnamadr.c
===================================================================
RCS file: /cvsroot/src/lib/libc/net/getnetnamadr.c,v
retrieving revision 1.35
diff -u -p -r1.35 getnetnamadr.c
--- lib/libc/net/getnetnamadr.c	15 Oct 2006 16:14:46 -0000	1.35
+++ lib/libc/net/getnetnamadr.c	19 Dec 2006 16:54:38 -0000
@@ -104,7 +104,7 @@ static int   __ypcurrentlen;
 static	struct netent net_entry;
 static	char *net_aliases[MAXALIASES];
 
-static struct netent *getnetanswer(querybuf *, int, int);
+static struct netent *getnetanswer(querybuf *, int, int, res_state);
 int	_files_getnetbyaddr(void *, void *, va_list);
 int	_files_getnetbyname(void *, void *, va_list);
 int	_dns_getnetbyaddr(void *, void *, va_list);
@@ -115,8 +115,14 @@ int	_yp_getnetbyname(void *, void *, va_
 struct netent *_ypnetent(char *);
 #endif
 
+/* from bind/irs/dns_p.h */
+#define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \
+                               (ok)(nm) != 0)
+#define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok)
+#define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok)
+
 static struct netent *
-getnetanswer(querybuf *answer, int anslen, int net_i)
+getnetanswer(querybuf *answer, int anslen, int net_i, res_state res)
 {
 	HEADER *hp;
 	u_char *cp;
@@ -172,7 +178,7 @@ getnetanswer(querybuf *answer, int ansle
 	haveanswer = 0;
 	while (--ancount >= 0 && cp < eom) {
 		n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
-		if ((n < 0) || !res_dnok(bp))
+		if ((n < 0) || !maybe_dnok(res, bp))
 			break;
 		cp += n;
 		ans[0] = '\0';
@@ -183,7 +189,7 @@ getnetanswer(querybuf *answer, int ansle
 		GETSHORT(n, cp);
 		if (class == C_IN && type == T_PTR) {
 			n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
-			if ((n < 0) || !res_hnok(bp)) {
+			if ((n < 0) || !maybe_hnok(res, bp)) {
 				cp += n;
 				return NULL;
 			}
@@ -335,7 +341,7 @@ _dns_getnetbyaddr(void *rv, void *cb_dat
 		return NS_NOTFOUND;
 	}
 	__res_put_state(res);
-	np = getnetanswer(buf, anslen, BYADDR);
+	np = getnetanswer(buf, anslen, BYADDR, res);
 	free(buf);
 	if (np) {
 		/* maybe net should be unsigned? */
@@ -442,7 +448,7 @@ _dns_getnetbyname(void *rv, void *cb_dat
 		return NS_NOTFOUND;
 	}
 	__res_put_state(res);
-	np = getnetanswer(buf, anslen, BYNAME);
+	np = getnetanswer(buf, anslen, BYNAME, res);
 	free(buf);
 	*((struct netent **)rv) = np;
 	if (np == NULL) {
Index: share/man/man5/resolv.conf.5
===================================================================
RCS file: /cvsroot/src/share/man/man5/resolv.conf.5,v
retrieving revision 1.24
diff -u -p -r1.24 resolv.conf.5
--- share/man/man5/resolv.conf.5	25 Feb 2006 02:28:56 -0000	1.24
+++ share/man/man5/resolv.conf.5	19 Dec 2006 16:54:38 -0000
@@ -170,6 +170,11 @@ before an initial absolute query will be
 The default for n is 1, meaning that if there are any
 dots in a name, the name will be tried first as an absolute
 name before any search list elements are appended to it.
+.It Sy no-check-names
+sets  RES_NOCHECKNAME in _res.options, which disables the
+modern BIND checking of  incoming  host  names  and  mail
+names for invalid characters such as underscore (_),
+non-ASCII, or control characters.
 .El
 .El
 .Pp

--==_Exmh_22061319897680--