diff options
| -rw-r--r-- | libc/inet/Makefile.in | 2 | ||||
| -rw-r--r-- | libc/inet/decoded.c | 8 | ||||
| -rw-r--r-- | libc/inet/encoded.c | 8 | ||||
| -rw-r--r-- | libc/inet/resolv.c | 189 | 
4 files changed, 70 insertions, 137 deletions
| diff --git a/libc/inet/Makefile.in b/libc/inet/Makefile.in index 91c417cc2..5e43f2303 100644 --- a/libc/inet/Makefile.in +++ b/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 \ diff --git a/libc/inet/decoded.c b/libc/inet/decoded.c deleted file mode 100644 index 378cbfad7..000000000 --- a/libc/inet/decoded.c +++ /dev/null @@ -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 diff --git a/libc/inet/encoded.c b/libc/inet/encoded.c deleted file mode 100644 index 27f92becd..000000000 --- a/libc/inet/encoded.c +++ /dev/null @@ -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 diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c index ed2e0d2fa..8bbd7c7cd 100644 --- a/libc/inet/resolv.c +++ b/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; @@ -3042,6 +2946,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.   * return: | 
