[uClibc-cvs] svn commit: trunk/uClibc/libc/inet

andersen at uclibc.org andersen at uclibc.org
Thu Apr 28 20:29:59 UTC 2005


Author: andersen
Date: 2005-04-28 14:29:58 -0600 (Thu, 28 Apr 2005)
New Revision: 10200

Log:
Fix it so uClibc returns multiple ips via h_addr_list,
This fix, based on this patch
	http://bugs.uclibc.org/view.php?id=104
makes it so uClibc fills out round robin dns lists for
applications such as nslookup:

Before:

	$ nslookup google.com
	Server:     mace.codepoet.org
	Address:    10.10.10.1

	Name:       google.com
	Address:    216.239.39.99

After:
	$ nslookup google.com
	Server:     mace.codepoet.org
	Address:    10.10.10.1

	Name:       google.com
	Addresses:  216.239.57.99, 216.239.37.99, 216.239.39.99



Modified:
   trunk/uClibc/libc/inet/resolv.c


Changeset:
Modified: trunk/uClibc/libc/inet/resolv.c
===================================================================
--- trunk/uClibc/libc/inet/resolv.c	2005-04-28 18:57:25 UTC (rev 10199)
+++ trunk/uClibc/libc/inet/resolv.c	2005-04-28 20:29:58 UTC (rev 10200)
@@ -216,6 +216,9 @@
 	int rdlength;
 	unsigned char * rdata;
 	int rdoffset;
+	char* buf;
+	size_t buflen;
+	size_t add_count;
 };
 
 enum etc_hosts_action {
@@ -669,6 +672,8 @@
 	fd_set fds;
 	struct resolv_header h;
 	struct resolv_question q;
+	struct resolv_answer ma;
+	int first_answer = 1;
 	int retries = 0;
 	unsigned char * packet = malloc(PACKETSZ);
 	char *dns, *lookup = malloc(MAXDNAME);
@@ -831,21 +836,56 @@
 		}
 		DPRINTF("Decoding answer at pos %d\n", pos);
 
-		for (j=0;j<h.ancount;j++)
+		first_answer = 1;
+		for (j=0;j<h.ancount;j++,pos += i)
 		{
-		    i = __decode_answer(packet, pos, a);
+		    i = __decode_answer(packet, pos, &ma);
 
 		    if (i<0) {
 			DPRINTF("failed decode %d\n", i);
 			goto again;
 		    }
-		    /* For all but T_SIG, accept first answer */
-		    if (a->atype != T_SIG)
-			break;
 
-		    DPRINTF("skipping T_SIG %d\n", i);
-		    free(a->dotted);
-		    pos += i;
+		    if ( first_answer )
+		    {
+			ma.buf = a->buf;
+			ma.buflen = a->buflen;
+			ma.add_count = a->add_count;
+			memcpy(a, &ma, sizeof(ma));
+			if (a->atype != T_SIG && (0 == a->buf || (type != T_A && type != T_AAAA)))
+			{
+			    break;
+			}
+			if (a->atype != type)
+			{
+			    free(a->dotted);
+			    continue;
+			}
+			a->add_count = h.ancount - j - 1;
+			if ((a->rdlength + sizeof(struct in_addr*)) * a->add_count > a->buflen)
+			{
+			    break;
+			}
+			a->add_count = 0;
+			first_answer = 0;
+		    }
+		    else
+		    {
+			free(ma.dotted);
+			if (ma.atype != type)
+			{
+			    continue;
+			}
+			if (a->rdlength != ma.rdlength)
+			{
+			    free(a->dotted);
+			    DPRINTF("Answer address len(%u) differs from original(%u)\n",
+				    ma.rdlength, a->rdlength);
+			    goto again;
+			}
+			memcpy(a->buf + (a->add_count * ma.rdlength), ma.rdata, ma.rdlength);
+			++a->add_count;
+		    }
 		}
 
 		DPRINTF("Answer name = |%s|\n", a->dotted);
@@ -1397,10 +1437,8 @@
 	struct in6_addr	*in6=NULL;
 	struct in6_addr	**addr_list6=NULL;
 #endif /* __UCLIBC_HAS_IPV6__ */
-	char					*cp;
-	char					**alias;
-	int						aliases, i;
-	int		ret=HOST_NOT_FOUND;
+	char *cp, **alias;
+	int aliases, i, ret=HOST_NOT_FOUND;
 
 	if (buflen < sizeof(char *)*(ALIAS_DIM))
 		return ERANGE;
@@ -1619,7 +1657,8 @@
 			    struct hostent ** result,
 			    int * h_errnop)
 {
-	return(__read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME, result_buf, buf, buflen, result, h_errnop));
+	return(__read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME,
+		    result_buf, buf, buflen, result, h_errnop));
 }
 #endif
 
@@ -1706,7 +1745,8 @@
 			if (!(flags & NI_NUMERICHOST)) {
 #ifdef __UCLIBC_HAS_IPV6__
 				if (sa->sa_family == AF_INET6)
-					h = gethostbyaddr ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr),
+					h = gethostbyaddr ((const void *)
+						&(((const struct sockaddr_in6 *) sa)->sin6_addr),
 						sizeof(struct in6_addr), AF_INET6);
 				else
 #endif /* __UCLIBC_HAS_IPV6__ */
@@ -1745,7 +1785,7 @@
 						c = inet_ntop (AF_INET6,
 							(const void *) &sin6p->sin6_addr, host, hostlen);
 #if 0
-/* Does scope id need to be supported? */
+						/* Does scope id need to be supported? */
 						uint32_t scopeid;
 						scopeid = sin6p->sin6_scope_id;
 						if (scopeid != 0) {
@@ -1768,7 +1808,7 @@
 									scopelen = strlen (scopebuf);
 							} else {
 								++ni_numericscope;
-                            }
+							}
 
 							if (ni_numericscope)
 								scopelen = 1 + snprintf (scopeptr,
@@ -1784,8 +1824,8 @@
 #endif
 					} else
 #endif /* __UCLIBC_HAS_IPV6__ */
-						c = inet_ntop (AF_INET,
-							(const void *) &(((const struct sockaddr_in *) sa)->sin_addr),
+						c = inet_ntop (AF_INET, (const void *)
+							&(((const struct sockaddr_in *) sa)->sin_addr),
 							host, hostlen);
 
 					if (c == NULL) {
@@ -1867,7 +1907,6 @@
 	unsigned char *packet;
 	struct resolv_answer a;
 	int i;
-	int nest = 0;
 	int __nameserversXX;
 	char ** __nameserverXX;
 
@@ -1882,7 +1921,7 @@
 		__set_errno(0);			/* to check for missing /etc/hosts. */
 
 		if ((i=__get_hosts_byname_r(name, AF_INET, result_buf,
-									buf, buflen, result, h_errnop))==0)
+				buf, buflen, result, h_errnop))==0)
 			return i;
 		switch (*h_errnop) {
 			case HOST_NOT_FOUND:
@@ -1944,54 +1983,61 @@
 
 	for (;;) {
 
-	BIGLOCK;
-	__nameserversXX=__nameservers;
-	__nameserverXX=__nameserver;
-	BIGUNLOCK;
-		i = __dns_lookup(buf, T_A, __nameserversXX, __nameserverXX, &packet, &a);
+	    BIGLOCK;
+	    __nameserversXX=__nameservers;
+	    __nameserverXX=__nameserver;
+	    BIGUNLOCK;
+	    a.buf = buf;
+	    a.buflen = buflen;
+	    a.add_count = 0;
+	    i = __dns_lookup(name, T_A, __nameserversXX, __nameserverXX, &packet, &a);
 
-		if (i < 0) {
-			*h_errnop = HOST_NOT_FOUND;
-			DPRINTF("__dns_lookup\n");
-			return TRY_AGAIN;
-		}
+	    if (i < 0) {
+		*h_errnop = HOST_NOT_FOUND;
+		DPRINTF("__dns_lookup\n");
+		return TRY_AGAIN;
+	    }
 
-		strncpy(buf, a.dotted, buflen);
+	    if ((a.rdlength + sizeof(struct in_addr*)) * a.add_count + 256 > buflen)
+	    {
 		free(a.dotted);
+		free(packet);
+		*h_errnop = NETDB_INTERNAL;
+		DPRINTF("buffer to small(multiple addresses)\n");
+		return ERANGE;
+	    }
+	    else if(a.add_count > 0)
+	    {
+		memmove(buf - sizeof(struct in_addr*)*2, buf, a.add_count * a.rdlength);
+		addr_list = (struct in_addr**)(buf + a.add_count * a.rdlength);
+		addr_list[0] = in;
+		for (i = a.add_count-1; i>=0; --i)
+		    addr_list[i+1] = (struct in_addr*)(buf - sizeof(struct in_addr*)*2 + a.rdlength * i);
+		addr_list[a.add_count + 1] = 0;
+		buflen -= (((char*)&(addr_list[a.add_count + 2])) - buf);
+		buf = (char*)&addr_list[a.add_count + 2];
+	    }
 
-		if (a.atype == T_CNAME) {		/* CNAME */
-			DPRINTF("Got a CNAME in gethostbyname()\n");
-			i = __decode_dotted(packet, a.rdoffset, buf, buflen);
-			free(packet);
+	    strncpy(buf, a.dotted, buflen);
+	    free(a.dotted);
 
-			if (i < 0) {
-				*h_errnop = NO_RECOVERY;
-				DPRINTF("__decode_dotted\n");
-				return -1;
-			}
-			if (++nest > MAX_RECURSE) {
-				*h_errnop = NO_RECOVERY;
-				DPRINTF("recursion\n");
-				return -1;
-			}
-			continue;
-		} else if (a.atype == T_A) {	/* ADDRESS */
-			memcpy(in, a.rdata, sizeof(*in));
-			result_buf->h_name = buf;
-			result_buf->h_addrtype = AF_INET;
-			result_buf->h_length = sizeof(*in);
-			result_buf->h_addr_list = (char **) addr_list;
+	    if (a.atype == T_A) { /* ADDRESS */
+		memcpy(in, a.rdata, sizeof(*in));
+		result_buf->h_name = buf;
+		result_buf->h_addrtype = AF_INET;
+		result_buf->h_length = sizeof(*in);
+		result_buf->h_addr_list = (char **) addr_list;
 #ifdef __UCLIBC_MJN3_ONLY__
 #warning TODO -- generate the full list
 #endif
-			result_buf->h_aliases = alias; /* TODO: generate the full list */
-			free(packet);
-			break;
-		} else {
-			free(packet);
-			*h_errnop=HOST_NOT_FOUND;
-			return TRY_AGAIN;
-		}
+		result_buf->h_aliases = alias; /* TODO: generate the full list */
+		free(packet);
+		break;
+	    } else {
+		free(packet);
+		*h_errnop=HOST_NOT_FOUND;
+		return TRY_AGAIN;
+	    }
 	}
 
 	*result=result_buf;
@@ -2009,7 +2055,8 @@
 			    int * h_errnop)
 {
 #ifndef __UCLIBC_HAS_IPV6__
-	return family == AF_INET ? gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop) : HOST_NOT_FOUND;
+	return family == (AF_INET)? gethostbyname_r(name, result_buf,
+		buf, buflen, result, h_errnop) : HOST_NOT_FOUND;
 #else /* __UCLIBC_HAS_IPV6__ */
 	struct in6_addr *in;
 	struct in6_addr **addr_list;
@@ -2037,7 +2084,7 @@
 		__set_errno(0);			/* to check for missing /etc/hosts. */
 
 		if ((i=__get_hosts_byname_r(name, AF_INET, result_buf,
-									buf, buflen, result, h_errnop))==0)
+				buf, buflen, result, h_errnop))==0)
 			return i;
 		switch (*h_errnop) {
 			case HOST_NOT_FOUND:
@@ -2087,6 +2134,8 @@
 	    return NETDB_SUCCESS;
 	}
 
+	memset((char *) &a, '\0', sizeof(a));
+
 	for (;;) {
 	BIGLOCK;
 	__nameserversXX=__nameservers;
@@ -2166,6 +2215,8 @@
 	if (!addr)
 		return EINVAL;
 
+	memset((char *) &a, '\0', sizeof(a));
+
 	switch (type) {
 		case AF_INET:
 			if (len != sizeof(struct in_addr))




More information about the uClibc-cvs mailing list