Browse Source

Merge remote-tracking branch 'evolvis/dns-things'

Waldemar Brodkorb 2 years ago
parent
commit
0894e879f0
4 changed files with 70 additions and 137 deletions
  1. 1 1
      libc/inet/Makefile.in
  2. 0 8
      libc/inet/decoded.c
  3. 0 8
      libc/inet/encoded.c
  4. 69 120
      libc/inet/resolv.c

+ 1 - 1
libc/inet/Makefile.in

@@ -26,7 +26,7 @@ CSRC-$(V4_OR_V6) += \
 	inet_lnaof.c inet_netof.c
 # multi source resolv.c
 CSRC-$(V4_OR_V6) += \
-	encodeh.c decodeh.c encoded.c decoded.c \
+	encodeh.c decodeh.c \
 	encodeq.c encodea.c \
 	read_etc_hosts_r.c \
 	dnslookup.c opennameservers.c closenameservers.c \

+ 0 - 8
libc/inet/decoded.c

@@ -1,8 +0,0 @@
-/*
- * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
- *
- * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
- */
-
-#define L_decoded
-#include RESOLVER

+ 0 - 8
libc/inet/encoded.c

@@ -1,8 +0,0 @@
-/*
- * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
- *
- * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
- */
-
-#define L_encoded
-#include RESOLVER

+ 69 - 120
libc/inet/resolv.c

@@ -11,6 +11,7 @@
 /*
  * Portions Copyright (c) 1985, 1993
  *    The Regents of the University of California.  All rights reserved.
+ * Portions Copyright © 2021 mirabilos <m@mirbsd.org>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -395,14 +396,6 @@ extern int __dns_lookup(const char *name,
 		int type,
 		unsigned char **outpacket,
 		struct resolv_answer *a) attribute_hidden;
-extern int __encode_dotted(const char *dotted,
-		unsigned char *dest,
-		int maxlen) attribute_hidden;
-extern int __decode_dotted(const unsigned char *packet,
-		int offset,
-		int packet_len,
-		char *dest,
-		int dest_len) attribute_hidden;
 extern int __encode_header(struct resolv_header *h,
 		unsigned char *dest,
 		int maxlen) attribute_hidden;
@@ -416,6 +409,13 @@ extern int __encode_answer(struct resolv_answer *a,
 		int maxlen) attribute_hidden;
 extern void __open_nameservers(void) attribute_hidden;
 extern void __close_nameservers(void) attribute_hidden;
+extern int __hnbad(const char *dotted) attribute_hidden;
+
+#define __encode_dotted(dotted,dest,maxlen) \
+	dn_comp((dotted), (dest), (maxlen), NULL, NULL)
+#define __decode_dotted(packet,offset,packet_len,dest,dest_len) \
+	dn_expand((packet), (packet) + (packet_len), (packet) + (offset), \
+	    (dest), (dest_len))
 
 /*
  * Theory of operation.
@@ -552,116 +552,6 @@ void __decode_header(unsigned char *data,
 #endif /* L_decodeh */
 
 
-#ifdef L_encoded
-
-/* Encode a dotted string into nameserver transport-level encoding.
-   This routine is fairly dumb, and doesn't attempt to compress
-   the data */
-int __encode_dotted(const char *dotted, unsigned char *dest, int maxlen)
-{
-	unsigned used = 0;
-
-	while (dotted && *dotted) {
-		char *c = strchr(dotted, '.');
-		int l = c ? c - dotted : strlen(dotted);
-
-		/* two consecutive dots are not valid */
-		if (l == 0)
-			return -1;
-
-		if (l >= (maxlen - used - 1))
-			return -1;
-
-		dest[used++] = l;
-		memcpy(dest + used, dotted, l);
-		used += l;
-
-		if (!c)
-			break;
-		dotted = c + 1;
-	}
-
-	if (maxlen < 1)
-		return -1;
-
-	dest[used++] = 0;
-
-	return used;
-}
-#endif /* L_encoded */
-
-
-#ifdef L_decoded
-
-/* Decode a dotted string from nameserver transport-level encoding.
-   This routine understands compressed data. */
-int __decode_dotted(const unsigned char *packet,
-		int offset,
-		int packet_len,
-		char *dest,
-		int dest_len)
-{
-	unsigned b;
-	bool measure = 1;
-	unsigned total = 0;
-	unsigned used = 0;
-	unsigned maxiter = 256;
-
-	if (!packet)
-		return -1;
-
-	dest[0] = '\0';
-	while (--maxiter) {
-		if (offset >= packet_len)
-			return -1;
-		b = packet[offset++];
-		if (b == 0)
-			break;
-
-		if (measure)
-			total++;
-
-		if ((b & 0xc0) == 0xc0) {
-			if (offset >= packet_len)
-				return -1;
-			if (measure)
-				total++;
-			/* compressed item, redirect */
-			offset = ((b & 0x3f) << 8) | packet[offset];
-			measure = 0;
-			continue;
-		}
-
-		if (used + b + 1 >= dest_len)
-			return -1;
-		if (offset + b >= packet_len)
-			return -1;
-		memcpy(dest + used, packet + offset, b);
-		offset += b;
-		used += b;
-
-		if (measure)
-			total += b;
-
-		if (packet[offset] != 0)
-			dest[used++] = '.';
-		else
-			dest[used++] = '\0';
-	}
-	if (!maxiter)
-		return -1;
-
-	/* The null byte must be counted too */
-	if (measure)
-		total++;
-
-	DPRINTF("Total decode len = %d\n", total);
-
-	return total;
-}
-#endif /* L_decoded */
-
-
 #ifdef L_encodeq
 
 int __encode_question(const struct resolv_question *q,
@@ -1204,6 +1094,7 @@ int __dns_lookup(const char *name,
 	bool ends_with_dot;
 	bool contains_dot;
 	sockaddr46_t sa;
+	int num_answers;
 
 	fd = -1;
 	lookup = NULL;
@@ -1446,6 +1337,7 @@ int __dns_lookup(const char *name,
 			goto fail1;
 		}
 		pos = HFIXEDSZ;
+		/*XXX TODO: check that question matches query (and qdcount==1?) */
 		for (j = 0; j < h.qdcount; j++) {
 			DPRINTF("Skipping question %d at %d\n", j, pos);
 			i = __length_question(packet + pos, packet_len - pos);
@@ -1460,6 +1352,7 @@ int __dns_lookup(const char *name,
 		DPRINTF("Decoding answer at pos %d\n", pos);
 
 		first_answer = 1;
+		num_answers = 0;
 		a->dotted = NULL;
 		for (j = 0; j < h.ancount; j++) {
 			i = __decode_answer(packet, pos, packet_len, &ma);
@@ -1467,12 +1360,15 @@ int __dns_lookup(const char *name,
 				DPRINTF("failed decode %d\n", i);
 				/* If the message was truncated but we have
 				 * decoded some answers, pretend it's OK */
-				if (j && h.tc)
+				if (num_answers && h.tc)
 					break;
 				goto try_next_server;
 			}
 			pos += i;
 
+			if (__hnbad(ma.dotted))
+				break;
+			++num_answers;
 			if (first_answer) {
 				ma.buf = a->buf;
 				ma.buflen = a->buflen;
@@ -1502,6 +1398,10 @@ int __dns_lookup(const char *name,
 				++a->add_count;
 			}
 		}
+		if (!num_answers) {
+			h_errno = NO_RECOVERY;
+			goto fail1;
+		}
 
 		/* Success! */
 		DPRINTF("Answer name = |%s|\n", a->dotted);
@@ -2468,7 +2368,7 @@ int gethostbyaddr_r(const void *addr, socklen_t addrlen,
 		/* Decode CNAME into buf, feed it to __dns_lookup() again */
 		i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
 		free(packet);
-		if (i < 0) {
+		if (i < 0 || __hnbad(buf)) {
 			*h_errnop = NO_RECOVERY;
 			return -1;
 		}
@@ -2477,6 +2377,10 @@ int gethostbyaddr_r(const void *addr, socklen_t addrlen,
 	if (a.atype == T_PTR) {	/* ADDRESS */
 		i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
 		free(packet);
+		if (__hnbad(buf)) {
+			*h_errnop = NO_RECOVERY;
+			return -1;
+		}
 		result_buf->h_name = buf;
 		result_buf->h_addrtype = type;
 		result_buf->h_length = addrlen;
@@ -3041,6 +2945,51 @@ int ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
 }
 libc_hidden_def(ns_name_pton)
 
+/*
+ * __hnbad(dotted)
+ *	Check whether a name is valid enough for DNS. The rules, as
+ *	laid down by glibc, are:
+ *	- printable input string
+ *	- converts to label notation
+ *	- each label only contains [0-9a-zA-Z_-], up to 63 octets
+ *	- first label doesn’t begin with ‘-’
+ *	This both is weaker than Unix hostnames (e.g. it allows
+ *	underscores and leading/trailing hyphen-minus) and stronger
+ *	than general (e.g. a leading “*.” is valid sometimes), take care.
+ * return:
+ *	0 if the name is ok
+ */
+int __hnbad(const char *dotted)
+{
+	unsigned char c, n, *cp;
+	unsigned char buf[NS_MAXCDNAME];
+
+	cp = (unsigned char *)dotted;
+	while ((c = *cp++))
+		if (c < 0x21 || c > 0x7E)
+			return (1);
+	if (ns_name_pton(dotted, buf, sizeof(buf)) < 0)
+		return (2);
+	if (buf[0] > 0 && buf[1] == '-')
+		return (3);
+	cp = buf;
+	while ((n = *cp++)) {
+		if (n > 63)
+			return (4);
+		while (n--) {
+			c = *cp++;
+			if (c < '-' ||
+			    (c > '-' && c < '0') ||
+			    (c > '9' && c < 'A') ||
+			    (c > 'Z' && c < '_') ||
+			    (c > '_' && c < 'a') ||
+			    c > 'z')
+				return (5);
+		}
+	}
+	return (0);
+}
+
 /*
  * ns_name_unpack(msg, eom, src, dst, dstsiz)
  *      Unpack a domain name from a message, source may be compressed.