diff options
Diffstat (limited to 'libc/inet/resolv.c')
| -rw-r--r-- | libc/inet/resolv.c | 416 | 
1 files changed, 197 insertions, 219 deletions
diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c index e377c3883..c6807aae1 100644 --- a/libc/inet/resolv.c +++ b/libc/inet/resolv.c @@ -151,6 +151,7 @@  #include <netdb.h>  #include <ctype.h>  #include <stdbool.h> +#include <time.h>  #include <arpa/nameser.h>  #include <sys/utsname.h>  #include <sys/un.h> @@ -219,6 +220,13 @@  /* libc_hidden_proto(__ctype_b) */  #endif +#if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__ +#define IF_HAS_BOTH(...) __VA_ARGS__ +#else +#define IF_HAS_BOTH(...) +#endif + +  extern int __libc_getdomainname(char *name, size_t len);  libc_hidden_proto(__libc_getdomainname) @@ -919,13 +927,22 @@ static char *skip_and_NUL_space(char *p)  /* Must be called under __resolv_lock. */  void attribute_hidden __open_nameservers(void)  { +	static uint8_t last_time; +  	char szBuffer[MAXLEN_searchdomain];  	FILE *fp;  	int i;  	sockaddr46_t sa; -	//if (!__res_sync && last_time_was_long_ago) -	//	__close_nameservers(); /* force config reread */ +	if (!__res_sync) { +		/* Provide for periodic reread of /etc/resolv.conf */ +		/* cur_time "ticks" every 256 seconds */ +		uint8_t cur_time = ((unsigned)time(NULL)) >> 8; +		if (last_time != cur_time) { +			last_time = cur_time; +			__close_nameservers(); /* force config reread */ +		} +	}  	if (__nameservers)  		goto sync; @@ -1290,14 +1307,18 @@ int attribute_hidden __dns_lookup(const char *name, int type,  			h_errno = HOST_NOT_FOUND;  			goto fail1;  		} -		if (h.rcode != 0) /* error */ -			goto try_next_sdomain; -		/* code below won't work correctly with h.ancount == 0, so... */ +		/* Insert other non-fatal errors here, which do not warrant +		 * switching to next nameserver */ + +		/* Strange error, assuming this nameserver is feeling bad */ +		if (h.rcode != 0) +			goto try_next_server; + +		/* Code below won't work correctly with h.ancount == 0, so... */  		if (h.ancount <= 0) {  			h_errno = NO_DATA; /* is this correct code? */  			goto fail1;  		} -  		pos = HFIXEDSZ;  		for (j = 0; j < h.qdcount; j++) {  			DPRINTF("Skipping question %d at %d\n", j, pos); @@ -1313,11 +1334,11 @@ int attribute_hidden __dns_lookup(const char *name, int type,  			i = __decode_answer(packet, pos, len, &ma);  			if (i < 0) {  				DPRINTF("failed decode %d\n", i); -				/* if the message was truncated and we have +				/* If the message was truncated but we have  				 * decoded some answers, pretend it's OK */  				if (j && h.tc)  					break; -				goto try_next_sdomain; +				goto try_next_server;  			}  			pos += i; @@ -1345,14 +1366,14 @@ int attribute_hidden __dns_lookup(const char *name, int type,  					free(a->dotted);  					DPRINTF("Answer address len(%u) differs from original(%u)\n",  							ma.rdlength, a->rdlength); -					goto try_next_sdomain; +					goto try_next_server;  				}  				memcpy(a->buf + (a->add_count * ma.rdlength), ma.rdata, ma.rdlength);  				++a->add_count;  			}  		} -		/* success! */ +		/* Success! */  		DPRINTF("Answer name = |%s|\n", a->dotted);  		DPRINTF("Answer type = |%d|\n", a->atype);  		if (fd != -1) @@ -1364,20 +1385,8 @@ int attribute_hidden __dns_lookup(const char *name, int type,  		free(lookup);  		return len; -//TODO: audit whether *any* "goto try_next_sdomain" is actually correct: -//trying next search domain makes sense only if we got NXDOMAIN! -//why we do it in other cases too? - try_next_sdomain: -		/* if there are searchdomains, try them */ -		if (!ends_with_dot) { -			if (variant < sdomains - 1) { -				/* next search */ -				variant++; -				continue; -			} -		}   try_next_server: -		/* if there are other nameservers, try them */ +		/* Try next nameserver */  		local_ns_num++;  		variant = -1;  	} while (retries_left > 0); @@ -1415,53 +1424,40 @@ int attribute_hidden __read_etc_hosts_r(  		struct hostent ** result,  		int * h_errnop)  { -	struct in_addr *in = NULL;  	struct in_addr **addr_list = NULL; -#ifdef __UCLIBC_HAS_IPV6__ -	struct in6_addr *in6 = NULL; -	struct in6_addr **addr_list6 = NULL; -#endif /* __UCLIBC_HAS_IPV6__ */ +	struct in_addr *in = NULL;  	char *cp, **alias;  	int aliases, i, ret = HOST_NOT_FOUND; -	/* make sure user char * is aligned */ +	*h_errnop = NETDB_INTERNAL; + +	/* make sure pointer is aligned */  	i = ALIGN_BUFFER_OFFSET(buf);  	buf += i;  	buflen -= i; - +	/* Layout in buf: +	 * char *alias[ALIAS_DIM]; +	 * struct in[6]_addr* addr_list[2]; +	 * struct in[6]_addr* in; +	 * char line_buffer[80+]; +	 */ +#define in6 ((struct in6_addr *)in)  	alias = (char **)buf;  	buf += sizeof(char **) * ALIAS_DIM;  	buflen -= sizeof(char **) * ALIAS_DIM;  	if ((ssize_t)buflen < 0)  		return ERANGE; -  	if (action != GETHOSTENT) { -#ifdef __UCLIBC_HAS_IPV6__ -		char *p = buf; -		size_t len = buflen; -#endif -		*h_errnop = NETDB_INTERNAL; +		addr_list = (struct in_addr**)buf; +		buf += sizeof(*addr_list) * 2; +		buflen -= sizeof(*addr_list) * 2;  		in = (struct in_addr*)buf; +#ifndef __UCLIBC_HAS_IPV6__  		buf += sizeof(*in);  		buflen -= sizeof(*in); -		addr_list = (struct in_addr **)buf; -		buf += sizeof(*addr_list) * 2; -		buflen -= sizeof(*addr_list) * 2; -		if ((ssize_t)buflen < 0) -			return ERANGE; -#ifdef __UCLIBC_HAS_IPV6__ -		in6 = (struct in6_addr*)p; -		p += sizeof(*in6); -		len -= sizeof(*in6); -		addr_list6 = (struct in6_addr**)p; -		p += sizeof(*addr_list6) * 2; -		len -= sizeof(*addr_list6) * 2; -		if ((ssize_t)len < 0) -			return ERANGE; -		if (len < buflen) { -			buflen = len; -			buf = p; -		} +#else +		buf += sizeof(*in6); +		buflen -= sizeof(*in6);  #endif  		if ((ssize_t)buflen < 80)  			return ERANGE; @@ -1472,12 +1468,12 @@ int attribute_hidden __read_etc_hosts_r(  			return errno;  		}  	} +	addr_list[0] = in; +	addr_list[1] = NULL;  	*h_errnop = HOST_NOT_FOUND;  	while (fgets(buf, buflen, fp)) { -		cp = strchr(buf, '#'); -		if (cp) -			*cp = '\0'; +		*strchrnul(buf, '#') = '\0';  		DPRINTF("Looking at: %s\n", buf);  		aliases = 0; @@ -1487,7 +1483,7 @@ int attribute_hidden __read_etc_hosts_r(  				*cp++ = '\0';  			if (!*cp)  				break; -			if (aliases < (2+MAX_ALIASES)) +			if (aliases < (2 + MAX_ALIASES))  				alias[aliases++] = cp;  			while (*cp && !isspace(*cp))  				cp++; @@ -1508,32 +1504,31 @@ int attribute_hidden __read_etc_hosts_r(  			/* GET_HOSTS_BYNAME */  			for (i = 1; i < aliases; i++)  				if (strcasecmp(name, alias[i]) == 0) -					break; -			if (i >= aliases) -				continue; +					goto found; +			continue; + found: ;  		} -		if (type == AF_INET && inet_pton(AF_INET, alias[0], in) > 0) { +		if (0) /* nothing */; +#ifdef __UCLIBC_HAS_IPV4__ +		else if (type == AF_INET && inet_pton(AF_INET, alias[0], in) > 0) {  			DPRINTF("Found INET\n"); -			addr_list[0] = in; -			addr_list[1] = NULL; -			result_buf->h_name = alias[1];  			result_buf->h_addrtype = AF_INET;  			result_buf->h_length = sizeof(*in); +			result_buf->h_name = alias[1];  			result_buf->h_addr_list = (char**) addr_list;  			result_buf->h_aliases = alias + 2;  			*result = result_buf;  			ret = NETDB_SUCCESS;  		} +#endif  #ifdef __UCLIBC_HAS_IPV6__  		else if (type == AF_INET6 && inet_pton(AF_INET6, alias[0], in6) > 0) {  			DPRINTF("Found INET6\n"); -			addr_list6[0] = in6; -			addr_list6[1] = NULL; -			result_buf->h_name = alias[1];  			result_buf->h_addrtype = AF_INET6;  			result_buf->h_length = sizeof(*in6); -			result_buf->h_addr_list = (char**) addr_list6; +			result_buf->h_name = alias[1]; +			result_buf->h_addr_list = (char**) addr_list;  			result_buf->h_aliases = alias + 2;  			*result = result_buf;  			ret = NETDB_SUCCESS; @@ -1557,6 +1552,7 @@ int attribute_hidden __read_etc_hosts_r(  	if (action != GETHOSTENT)  		fclose(fp);  	return ret; +#undef in6  }  #endif @@ -1587,19 +1583,21 @@ int attribute_hidden __get_hosts_byaddr_r(const char * addr, int len, int type,  	char	ipaddr[INET_ADDRSTRLEN];  #else  	char	ipaddr[INET6_ADDRSTRLEN]; -#endif /* __UCLIBC_HAS_IPV6__ */ +#endif  	switch (type) { +#ifdef __UCLIBC_HAS_IPV4__  		case AF_INET:  			if (len != sizeof(struct in_addr))  				return 0;  			break; +#endif  #ifdef __UCLIBC_HAS_IPV6__  		case AF_INET6:  			if (len != sizeof(struct in6_addr))  				return 0;  			break; -#endif /* __UCLIBC_HAS_IPV6__ */ +#endif  		default:  			return 0;  	} @@ -1627,24 +1625,23 @@ int getnameinfo(const struct sockaddr *sa, socklen_t addrlen, char *host,  		return EAI_BADFLAGS;  	if (sa == NULL || addrlen < sizeof(sa_family_t)) -		goto BAD_FAM; +		return EAI_FAMILY;  	ok = sa->sa_family;  	if (ok == AF_LOCAL) /* valid */;  #ifdef __UCLIBC_HAS_IPV4__  	else if (ok == AF_INET) {  		if (addrlen < sizeof(struct sockaddr_in)) -			goto BAD_FAM; +			return EAI_FAMILY;  	}  #endif  #ifdef __UCLIBC_HAS_IPV6__  	else if (ok == AF_INET6) {  		if (addrlen < sizeof(struct sockaddr_in6)) -			goto BAD_FAM; +			return EAI_FAMILY;  	} -#endif /* __UCLIBC_HAS_IPV6__ */ +#endif  	else -BAD_FAM:  		return EAI_FAMILY;  	ok = 0; @@ -1813,6 +1810,8 @@ libc_hidden_def(getnameinfo)  #ifdef L_gethostbyname_r +//Does this function assume IPv4? If yes, +//what happens in IPv6-only build?  /* Bug 671 says:   * "uClibc resolver's gethostbyname does not return the requested name @@ -1892,23 +1891,23 @@ int gethostbyname_r(const char * name,  	i = strlen(name) + 1;  	if ((ssize_t)buflen <= i)  		return ERANGE; -	strcpy(buf, name); +	memcpy(buf, name, i); /* paranoia: name might change */  	alias0 = buf;  	buf += i;  	buflen -= i; -  	/* make sure pointer is aligned */  	i = ALIGN_BUFFER_OFFSET(buf);  	buf += i;  	buflen -= i; - +	/* Layout in buf: +	 * char *alias[2]; +	 * struct in_addr* addr_list[NN+1]; +	 * struct in_addr* in[NN]; +	 */  	alias = (char **)buf;  	buf += sizeof(alias[0]) * 2;  	buflen -= sizeof(alias[0]) * 2; -  	addr_list = (struct in_addr **)buf; - -	/* do not use *buf or buflen before this verification! */  	/* buflen may be < 0, must do signed compare */  	if ((ssize_t)buflen < 256)  		return ERANGE; @@ -1946,18 +1945,16 @@ int gethostbyname_r(const char * name,  	}  	/* talk to DNS servers */ -	{ -		a.buf = buf; -		/* take into account that at least one address will be there, -		 * we'll need space of one in_addr + two addr_list[] elems */ -		a.buflen = buflen - ((sizeof(addr_list[0]) * 2 + sizeof(struct in_addr))); -		a.add_count = 0; -		i = __dns_lookup(name, T_A, &packet, &a); -		if (i < 0) { -			*h_errnop = HOST_NOT_FOUND; -			DPRINTF("__dns_lookup returned < 0\n"); -			return TRY_AGAIN; -		} +	a.buf = buf; +	/* take into account that at least one address will be there, +	 * we'll need space of one in_addr + two addr_list[] elems */ +	a.buflen = buflen - ((sizeof(addr_list[0]) * 2 + sizeof(struct in_addr))); +	a.add_count = 0; +	i = __dns_lookup(name, T_A, &packet, &a); +	if (i < 0) { +		*h_errnop = HOST_NOT_FOUND; +		DPRINTF("__dns_lookup returned < 0\n"); +		return TRY_AGAIN;  	}  	if (a.atype == T_A) { /* ADDRESS */ @@ -2093,7 +2090,11 @@ int gethostbyname2_r(const char *name,  	i = ALIGN_BUFFER_OFFSET(buf);  	buf += i;  	buflen -= i; - +	/* Layout in buf: +	 * struct in6_addr* in; +	 * struct in6_addr* addr_list[2]; +	 * char scratch_buf[256]; +	 */  	in = (struct in6_addr*)buf;  	buf += sizeof(*in);  	buflen -= sizeof(*in); @@ -2105,6 +2106,7 @@ int gethostbyname2_r(const char *name,  	addr_list[0] = in;  	addr_list[1] = NULL;  	strncpy(buf, name, buflen); +	buf[buflen] = '\0';  	/* maybe it is already an address? */  	if (inet_pton(AF_INET6, name, in)) { @@ -2112,6 +2114,7 @@ int gethostbyname2_r(const char *name,  		result_buf->h_addrtype = AF_INET6;  		result_buf->h_length = sizeof(*in);  		result_buf->h_addr_list = (char **) addr_list; +		//result_buf->h_aliases = ???  		*result = result_buf;  		*h_errnop = NETDB_SUCCESS;  		return NETDB_SUCCESS; @@ -2129,48 +2132,46 @@ int gethostbyname2_r(const char *name,  // TODO: why it's so different from gethostbyname_r (IPv4 case)?  	memset(&a, '\0', sizeof(a));  	for (;;) { +// Hmm why we memset(a) to zeros only once?  		i = __dns_lookup(buf, T_AAAA, &packet, &a); -  		if (i < 0) {  			*h_errnop = HOST_NOT_FOUND;  			return TRY_AGAIN;  		} -  		strncpy(buf, a.dotted, buflen);  		free(a.dotted); -		if (a.atype == T_CNAME) {		/* CNAME */ -			DPRINTF("Got a CNAME in gethostbyname()\n"); -			i = __decode_dotted(packet, a.rdoffset, buf, buflen); -			free(packet); +		if (a.atype != T_CNAME) +			break; -			if (i < 0) { -				*h_errnop = NO_RECOVERY; -				return -1; -			} -			if (++nest > MAX_RECURSE) { -				*h_errnop = NO_RECOVERY; -				return -1; -			} -			continue; +		DPRINTF("Got a CNAME in gethostbyname()\n"); +		if (++nest > MAX_RECURSE) { +			*h_errnop = NO_RECOVERY; +			return -1;  		} -		if (a.atype == T_AAAA) {	/* ADDRESS */ -			memcpy(in, a.rdata, sizeof(*in)); -			result_buf->h_name = buf; -			result_buf->h_addrtype = AF_INET6; -			result_buf->h_length = sizeof(*in); -			result_buf->h_addr_list = (char **) addr_list; -			free(packet); -			break; +		i = __decode_dotted(packet, a.rdoffset, buf, buflen); +		free(packet); +		if (i < 0) { +			*h_errnop = NO_RECOVERY; +			return -1;  		} +	} +	if (a.atype == T_AAAA) {	/* ADDRESS */ +		memcpy(in, a.rdata, sizeof(*in)); +		result_buf->h_name = buf; +		result_buf->h_addrtype = AF_INET6; +		result_buf->h_length = sizeof(*in); +		result_buf->h_addr_list = (char **) addr_list; +		//result_buf->h_aliases = ???  		free(packet); -		*h_errnop = HOST_NOT_FOUND; -		return TRY_AGAIN; +		*result = result_buf; +		*h_errnop = NETDB_SUCCESS; +		return NETDB_SUCCESS;  	} +	free(packet); +	*h_errnop = HOST_NOT_FOUND; +	return TRY_AGAIN; -	*result = result_buf; -	*h_errnop = NETDB_SUCCESS; -	return NETDB_SUCCESS;  #endif /* __UCLIBC_HAS_IPV6__ */  }  libc_hidden_def(gethostbyname2_r) @@ -2179,7 +2180,7 @@ libc_hidden_def(gethostbyname2_r)  #ifdef L_gethostbyaddr_r -int gethostbyaddr_r(const void *addr, socklen_t len, int type, +int gethostbyaddr_r(const void *addr, socklen_t addrlen, int type,  					 struct hostent * result_buf,  					 char * buf, size_t buflen,  					 struct hostent ** result, @@ -2188,12 +2189,6 @@ int gethostbyaddr_r(const void *addr, socklen_t len, int type,  {  	struct in_addr *in;  	struct in_addr **addr_list; -#ifdef __UCLIBC_HAS_IPV6__ -	char *qp; -	size_t plen; -	struct in6_addr	*in6; -	struct in6_addr	**addr_list6; -#endif /* __UCLIBC_HAS_IPV6__ */  	char **alias;  	unsigned char *packet;  	struct resolv_answer a; @@ -2204,25 +2199,25 @@ int gethostbyaddr_r(const void *addr, socklen_t len, int type,  	if (!addr)  		return EINVAL; -	memset(&a, '\0', sizeof(a)); -  	switch (type) { +#ifdef __UCLIBC_HAS_IPV4__  		case AF_INET: -			if (len != sizeof(struct in_addr)) +			if (addrlen != sizeof(struct in_addr))  				return EINVAL;  			break; +#endif  #ifdef __UCLIBC_HAS_IPV6__  		case AF_INET6: -			if (len != sizeof(struct in6_addr)) +			if (addrlen != sizeof(struct in6_addr))  				return EINVAL;  			break; -#endif /* __UCLIBC_HAS_IPV6__ */ +#endif  		default:  			return EINVAL;  	}  	/* do /etc/hosts first */ -	i = __get_hosts_byaddr_r(addr, len, type, result_buf, +	i = __get_hosts_byaddr_r(addr, addrlen, type, result_buf,  				buf, buflen, result, h_errnop);  	if (i == 0)  		return i; @@ -2240,68 +2235,59 @@ int gethostbyaddr_r(const void *addr, socklen_t len, int type,  	i = ALIGN_BUFFER_OFFSET(buf);  	buf += i;  	buflen -= i; - -#ifdef __UCLIBC_HAS_IPV6__ -	qp = buf; -	plen = buflen; -#endif -	in = (struct in_addr*)buf; -	buf += sizeof(*in); -	buflen -= sizeof(*in); -	addr_list = (struct in_addr**)buf; -	buf += sizeof(*addr_list) * 2; -	buflen -= sizeof(*addr_list) * 2; +	/* Layout in buf: +	 * char *alias[ALIAS_DIM]; +	 * struct in[6]_addr* addr_list[2]; +	 * struct in[6]_addr* in; +	 * char scratch_buffer[256+]; +	 */ +#define in6 ((struct in6_addr *)in)  	alias = (char **)buf;  	buf += sizeof(*alias) * ALIAS_DIM;  	buflen -= sizeof(*alias) * ALIAS_DIM; -	if ((ssize_t)buflen < 0) -		return ERANGE; -#ifdef __UCLIBC_HAS_IPV6__ -	in6 = (struct in6_addr*)qp; -	qp += sizeof(*in6); -	plen -= sizeof(*in6); -	addr_list6 = (struct in6_addr**)qp; -	qp += sizeof(*addr_list6) * 2; -	plen -= sizeof(*addr_list6) * 2; -	if ((ssize_t)plen < 0) -		return ERANGE; -	if (plen < buflen) { -		buflen = plen; -		buf = qp; -	} +	addr_list = (struct in_addr**)buf; +	buf += sizeof(*addr_list) * 2; +	buflen -= sizeof(*addr_list) * 2; +	in = (struct in_addr*)buf; +#ifndef __UCLIBC_HAS_IPV6__ +	buf += sizeof(*in); +	buflen -= sizeof(*in); +#else +	buf += sizeof(*in6); +	buflen -= sizeof(*in6);  #endif -	if (buflen < 256) +	if ((ssize_t)buflen < 256)  		return ERANGE; +	alias[0] = buf; +	alias[1] = NULL; +	addr_list[0] = in; +	addr_list[1] = NULL; +	memcpy(&in, addr, addrlen); -	if (type == AF_INET) { -		unsigned char *tmp_addr = (unsigned char *)addr; - -		memcpy(&in->s_addr, addr, len); -		addr_list[0] = in; +	if (0) /* nothing */; +#ifdef __UCLIBC_HAS_IPV4__ +	else IF_HAS_BOTH(if (type == AF_INET)) { +		unsigned char *tp = (unsigned char *)addr;  		sprintf(buf, "%u.%u.%u.%u.in-addr.arpa", -				tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0]); +				tp[3], tp[2], tp[1], tp[0]);  	} +#endif  #ifdef __UCLIBC_HAS_IPV6__  	else { -		memcpy(in6->s6_addr, addr, len); -		addr_list6[0] = in6; -		qp = buf; -		for (i = len - 1; i >= 0; i--) { -			qp += sprintf(qp, "%x.%x.", -					in6->s6_addr[i] & 0xf, -					(in6->s6_addr[i] >> 4) & 0xf); -		} -		strcpy(qp, "ip6.arpa"); +		char *dst = buf; +		unsigned char *tp = (unsigned char *)addr + addrlen - 1; +		do { +			dst += sprintf(dst, "%x.%x.", tp[i] & 0xf, tp[i] >> 4); +			tp--; +		} while (tp >= (unsigned char *)addr); +		strcpy(dst, "ip6.arpa");  	}  #endif -	addr_list[1] = NULL; - -	alias[0] = buf; -	alias[1] = NULL; +	memset(&a, '\0', sizeof(a));  	for (;;) { +// Hmm why we memset(a) to zeros only once?  		i = __dns_lookup(buf, T_PTR, &packet, &a); -  		if (i < 0) {  			*h_errnop = HOST_NOT_FOUND;  			return TRY_AGAIN; @@ -2309,48 +2295,40 @@ int gethostbyaddr_r(const void *addr, socklen_t len, int type,  		strncpy(buf, a.dotted, buflen);  		free(a.dotted); +		if (a.atype != T_CNAME) +			break; -		if (a.atype == T_CNAME) { /* CNAME */ -			DPRINTF("Got a CNAME in gethostbyaddr()\n"); -			i = __decode_dotted(packet, a.rdoffset, buf, buflen); -			free(packet); - -			if (i < 0) { -				*h_errnop = NO_RECOVERY; -				return -1; -			} -			if (++nest > MAX_RECURSE) { -				*h_errnop = NO_RECOVERY; -				return -1; -			} -			continue; +		DPRINTF("Got a CNAME in gethostbyaddr()\n"); +		if (++nest > MAX_RECURSE) { +			*h_errnop = NO_RECOVERY; +			return -1;  		} - -		if (a.atype == T_PTR) {	/* ADDRESS */ -			i = __decode_dotted(packet, a.rdoffset, buf, buflen); -			free(packet); - -			result_buf->h_name = buf; -			result_buf->h_addrtype = type; -			if (type == AF_INET) -				result_buf->h_length = sizeof(*in); -#ifdef __UCLIBC_HAS_IPV6__ -			else -				result_buf->h_length = sizeof(*in6); -#endif -			result_buf->h_addr_list = (char **) addr_list; -			result_buf->h_aliases = alias; -			break; +		/* Decode CNAME into buf, feed it to __dns_lookup() again */ +		i = __decode_dotted(packet, a.rdoffset, buf, buflen); +		free(packet); +		if (i < 0) { +			*h_errnop = NO_RECOVERY; +			return -1;  		} +	} +	if (a.atype == T_PTR) {	/* ADDRESS */ +		i = __decode_dotted(packet, a.rdoffset, buf, buflen);  		free(packet); -		*h_errnop = NO_ADDRESS; -		return TRY_AGAIN; +		result_buf->h_name = buf; +		result_buf->h_addrtype = type; +		result_buf->h_length = addrlen; +		result_buf->h_addr_list = (char **) addr_list; +		result_buf->h_aliases = alias; +		*result = result_buf; +		*h_errnop = NETDB_SUCCESS; +		return NETDB_SUCCESS;  	} -	*result = result_buf; -	*h_errnop = NETDB_SUCCESS; -	return NETDB_SUCCESS; +	free(packet); +	*h_errnop = NO_ADDRESS; +	return TRY_AGAIN; +#undef in6  }  libc_hidden_def(gethostbyaddr_r)  #endif @@ -2605,7 +2583,7 @@ int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)  			__set_errno(EMSGSIZE);  			return -1;  		} -		for ((void)NULL; n > 0; n--) { +		for (; n > 0; n--) {  			c = *cp++;  			if (special(c)) {  				if (dn + 1 >= eom) {  | 
