Browse Source

Patch from Jari Korva <jpkorva@iki.fi>
I found some support in uClibc for IPv6 but I needed some more...
Enclosed
is the patch containing following modifications:

- getnameinfo port from lates glibc
- IPv6 support for gethostbyaddr()
- IPv6 support for get_hosts_byname and read_etc_hosts (among other
things this fixed a bug in gethostbyname2 in a case when user asked for
an IPv6 but got a v4 address if it was present in /etc/hosts)
- defined ip6addr_any and in6addr_loopback (though the place where I
defined these isn't correct, I guess)

What is still missing:

- getaddrinfo (this could be ported also from glibc but it won't be as
easy as porting getnameinfo, I guess)

I have tested the patch using enclosed test program and boa web server.
Seems to work ;)

Eric Andersen 23 years ago
parent
commit
95d611c316
1 changed files with 300 additions and 44 deletions
  1. 300 44
      libc/inet/resolv.c

+ 300 - 44
libc/inet/resolv.c

@@ -36,6 +36,11 @@
  *   partial IPv6 support (i.e. gethostbyname2() and resolve_address2()
  *   functions added), IPv6 nameservers are also supported.
  *
+ * 6-Oct-2001 Jari Korva <jari.korva@iki.fi>
+ *   more IPv6 support (IPv6 support for gethostbyaddr();
+ *   address family parameter and improved IPv6 support for get_hosts_byname
+ *   and read_etc_hosts; getnameinfo() port from glibc; defined
+ *   defined ip6addr_any and in6addr_loopback)
  */
 
 #define __FORCE_GLIBC__
@@ -100,9 +105,9 @@ extern int nameservers;
 extern char * nameserver[MAX_SERVERS];
 extern int searchdomains;
 extern char * searchdomain[MAX_SEARCH];
-extern struct hostent * get_hosts_byname(const char * name);
+extern struct hostent * get_hosts_byname(const char * name, int type);
 extern struct hostent * get_hosts_byaddr(const char * addr, int len, int type);
-extern struct hostent * read_etc_hosts(const char * name, int ip);
+extern struct hostent * read_etc_hosts(const char * name, int type, int ip);
 extern int resolve_address(const char * address, int nscount, 
 	char ** nsip, struct in_addr * in);
 extern int resolve_mailbox(const char * address, int nscount, 
@@ -977,7 +982,7 @@ struct hostent *gethostbyname(const char *name)
 	if (!name)
 		return 0;
 
-	if ((hp = get_hosts_byname(name))) /* do /etc/hosts first */
+	if ((hp = get_hosts_byname(name, AF_INET))) /* do /etc/hosts first */
 		return(hp);
 
 	memset(&h, 0, sizeof(h));
@@ -1037,6 +1042,14 @@ struct hostent *gethostbyname(const char *name)
 
 #ifdef L_gethostbyname2
 
+#ifdef __UCLIBC_HAS_IPV6__
+/* TBD: Not the right place for defining these, I guess */
+const struct in6_addr in6addr_any =
+	{ { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } };
+const struct in6_addr in6addr_loopback =
+	{ { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } };                                    
+#endif /* __UCLIBC_HAS_IPV6__ */
+
 struct hostent *gethostbyname2(const char *name, int family)
 {
 #ifndef __UCLIBC_HAS_IPV6__
@@ -1063,7 +1076,7 @@ struct hostent *gethostbyname2(const char *name, int family)
 	if (!name)
 		return 0;
 
-	if ((hp = get_hosts_byname(name))) /* do /etc/hosts first */
+	if ((hp = get_hosts_byname(name, family))) /* do /etc/hosts first */
 		return(hp);
 
 	memset(&h, 0, sizeof(h));
@@ -1188,32 +1201,68 @@ struct hostent *gethostbyaddr (const void *addr, socklen_t len, int type)
 	static char namebuf[256];
 	static struct in_addr in;
 	static struct in_addr *addr_list[2];
+#ifdef __UCLIBC_HAS_IPV6__
+    char *qp;
+	static struct in6_addr	in6;
+	static struct in6_addr	*addr_list6[2];
+#endif /* __UCLIBC_HAS_IPV6__ */
 	struct hostent *hp;
 	unsigned char *packet;
 	struct resolv_answer a;
 	int i;
 	int nest = 0;
 
-	if (!addr || (len != sizeof(in)) || (type != AF_INET))
+	if (!addr)
 		return 0;
+        
+    switch (type) {
+	case AF_INET:
+		if (len != sizeof(struct in_addr))
+			return 0;
+		break;
+#ifdef __UCLIBC_HAS_IPV6__
+	case AF_INET6:
+		if (len != sizeof(struct in6_addr))
+			return 0;
+		break;
+#endif /* __UCLIBC_HAS_IPV6__ */
+	default:
+		return 0;
+	}
 
 	if ((hp = get_hosts_byaddr(addr, len, type))) /* do /etc/hosts first */
 		return(hp);
 
-	memcpy(&in.s_addr, addr, len);
-
 	open_nameservers();
 
 	memset(&h, 0, sizeof(h));
 
-	addr_list[0] = &in;
-	addr_list[1] = 0;
+	if(type == AF_INET) {
+		memcpy(&in.s_addr, addr, len);
 
-	sprintf(namebuf, "%d.%d.%d.%d.in-addr.arpa",
+		addr_list[0] = &in;
+
+		sprintf(namebuf, "%d.%d.%d.%d.in-addr.arpa",
 			(in.s_addr >> 24) & 0xff,
 			(in.s_addr >> 16) & 0xff,
 			(in.s_addr >> 8) & 0xff, 
 			(in.s_addr >> 0) & 0xff);
+#ifdef __UCLIBC_HAS_IPV6__
+	} else {
+		memcpy(&in6.s6_addr, addr, len);
+
+		addr_list6[0] = &in6;
+        qp = namebuf;
+
+		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.int");
+#endif /* __UCLIBC_HAS_IPV6__ */
+	}
+
+	addr_list[1] = 0;
 
 	for (;;) {
 
@@ -1240,8 +1289,16 @@ struct hostent *gethostbyaddr (const void *addr, socklen_t len, int type)
 			free(packet);
 
 			h.h_name = namebuf;
-			h.h_addrtype = AF_INET;
-			h.h_length = sizeof(in);
+			h.h_addrtype = type;
+
+			if(type == AF_INET) {
+				h.h_length = sizeof(in);
+#ifdef __UCLIBC_HAS_IPV6__
+			} else {
+				h.h_length = sizeof(in6);
+#endif /* __UCLIBC_HAS_IPV6__ */
+    		}
+
 			h.h_addr_list = (char **) addr_list;
 			break;
 		} else {
@@ -1257,7 +1314,7 @@ struct hostent *gethostbyaddr (const void *addr, socklen_t len, int type)
 
 #ifdef L_read_etc_hosts
 
-struct hostent * read_etc_hosts(const char * name, int ip)
+struct hostent * read_etc_hosts(const char * name, int type, int ip)
 {
 	static struct hostent	h;
 	static struct in_addr	in;
@@ -1308,31 +1365,26 @@ struct hostent * read_etc_hosts(const char * name, int ip)
 				continue;
 		}
 
-#ifndef __UCLIBC_HAS_IPV6__
-		if (inet_aton(alias[0], &in) == 0)
-			break; /* bad ip address */
-#else /* __UCLIBC_HAS_IPV6__ */
-		if (inet_aton(alias[0], &in) == 0) {
-			if (inet_pton(AF_INET6, alias[0], &in6) == 0) {
-				addr_list6[0] = &in6;
-				addr_list6[1] = 0;
-				h.h_name = alias[1];
-				h.h_addrtype = AF_INET6;
-				h.h_length = sizeof(in6);
-				h.h_addr_list = (char**) addr_list6;
-				fclose(fp);
-				return(&h);
-			} else
-				break; /* bad ip address */
-		}
+		if (type == AF_INET && inet_pton(AF_INET, alias[0], &in) > 0) {
+			addr_list[0] = &in;
+			addr_list[1] = 0;
+			h.h_name = alias[1];
+			h.h_addrtype = AF_INET;
+			h.h_length = sizeof(in);
+			h.h_addr_list = (char**) addr_list;
+#ifdef __UCLIBC_HAS_IPV6__
+        } else if (type == AF_INET6 && inet_pton(AF_INET6, alias[0], &in6) > 0) {
+			addr_list6[0] = &in6;
+			addr_list6[1] = 0;
+			h.h_name = alias[1];
+			h.h_addrtype = AF_INET6;
+			h.h_length = sizeof(in6);
+			h.h_addr_list = (char**) addr_list6;
 #endif /* __UCLIBC_HAS_IPV6__ */
-
-		addr_list[0] = &in;
-		addr_list[1] = 0;
-		h.h_name = alias[1];
-		h.h_addrtype = AF_INET;
-		h.h_length = sizeof(in);
-		h.h_addr_list = (char**) addr_list;
+		} else {
+			break; /* bad ip address */
+        }
+        
 		fclose(fp);
 		return(&h);
 	}
@@ -1344,9 +1396,9 @@ struct hostent * read_etc_hosts(const char * name, int ip)
 
 #ifdef L_get_hosts_byname
 
-struct hostent * get_hosts_byname(const char * name)
+struct hostent * get_hosts_byname(const char * name, int type)
 {
-	return(read_etc_hosts(name, 0));
+	return(read_etc_hosts(name, type, 0));
 }
 #endif
 
@@ -1355,14 +1407,218 @@ struct hostent * get_hosts_byname(const char * name)
 
 struct hostent * get_hosts_byaddr(const char * addr, int len, int type)
 {
-	char	ipaddr[20];
+#ifndef __UCLIBC_HAS_IPV6__
+	char	ipaddr[INET_ADDRSTRLEN];
+#else
+	char	ipaddr[INET6_ADDRSTRLEN];
+#endif /* __UCLIBC_HAS_IPV6__ */
 
-	if (type != AF_INET || len != sizeof(struct in_addr))
-		return((struct hostent *) NULL);
+    switch (type) {
+	case AF_INET:
+		if (len != sizeof(struct in_addr))
+			return 0;
+		break;
+#ifdef __UCLIBC_HAS_IPV6__
+	case AF_INET6:
+		if (len != sizeof(struct in6_addr))
+			return 0;
+		break;
+#endif /* __UCLIBC_HAS_IPV6__ */
+	default:
+		return 0;
+	}
+
+	inet_ntop(type, addr, ipaddr, sizeof(ipaddr));
 
-	strcpy(ipaddr, inet_ntoa(* (struct in_addr *) addr));
-	return(read_etc_hosts(ipaddr, 1));
+	return(read_etc_hosts(ipaddr, type, 1));
 }
 #endif
 
+#ifdef L_getnameinfo
 
+int getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
+	     socklen_t hostlen, char *serv, socklen_t servlen,
+	     unsigned int flags)
+{
+	int serrno = errno;
+	int ok = 0;
+	struct hostent *h = NULL;
+    char domain[256];
+    
+	if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM))
+		return EAI_BADFLAGS;
+
+	if (sa == NULL || addrlen < sizeof (sa_family_t))
+		return EAI_FAMILY;
+
+	switch (sa->sa_family) {
+	case AF_LOCAL:
+		break;
+	case AF_INET:
+		if (addrlen < sizeof (struct sockaddr_in))
+			return EAI_FAMILY;
+		break;
+#ifdef __UCLIBC_HAS_IPV6__
+	case AF_INET6:
+		if (addrlen < sizeof (struct sockaddr_in6))
+			return EAI_FAMILY;
+		break;
+#endif /* __UCLIBC_HAS_IPV6__ */
+	default:
+		return EAI_FAMILY;
+	}
+
+	if (host != NULL && hostlen > 0)
+		switch (sa->sa_family) {
+		case AF_INET:
+#ifdef __UCLIBC_HAS_IPV6__
+		case AF_INET6:
+#endif /* __UCLIBC_HAS_IPV6__ */
+			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),
+						sizeof(struct in6_addr), AF_INET6);
+				else
+#endif /* __UCLIBC_HAS_IPV6__ */
+                    h = gethostbyaddr ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
+					  sizeof(struct in_addr), AF_INET);
+
+				if (h) {
+					char *c;
+					if ((flags & NI_NOFQDN)
+					    && (getdomainname (domain, sizeof(domain)) == 0)
+					    && (c = strstr (h->h_name, domain))
+					    && (c != h->h_name) && (*(--c) == '.')) {
+						strncpy (host, h->h_name,
+							min(hostlen, (size_t) (c - h->h_name)));
+						host[min(hostlen - 1, (size_t) (c - h->h_name))] = '\0';
+						ok = 1;
+					} else {
+						strncpy (host, h->h_name, hostlen);
+						ok = 1;
+					}
+				 }
+			}
+
+			if (!ok) {
+				if (flags & NI_NAMEREQD) {
+					errno = serrno;
+					return EAI_NONAME;
+				} else {
+					const char *c;
+#ifdef __UCLIBC_HAS_IPV6__
+					if (sa->sa_family == AF_INET6) {
+						const struct sockaddr_in6 *sin6p;
+						uint32_t scopeid;
+
+						sin6p = (const struct sockaddr_in6 *) sa;
+
+						c = inet_ntop (AF_INET6,
+							(const void *) &sin6p->sin6_addr, host, hostlen);
+#if 0
+/* Does scope id need to be supported? */
+						scopeid = sin6p->sin6_scope_id;
+						if (scopeid != 0) {
+							/* Buffer is >= IFNAMSIZ+1.  */
+							char scopebuf[IFNAMSIZ + 1];
+							char *scopeptr;
+							int ni_numericscope = 0;
+							size_t real_hostlen = __strnlen (host, hostlen);
+							size_t scopelen = 0;
+
+							scopebuf[0] = SCOPE_DELIMITER;
+							scopebuf[1] = '\0';
+							scopeptr = &scopebuf[1];
+
+							if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
+							    || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr)) {
+								if (if_indextoname (scopeid, scopeptr) == NULL)
+									++ni_numericscope;
+								else
+									scopelen = strlen (scopebuf);
+							} else {
+								++ni_numericscope;
+                            }
+
+							if (ni_numericscope)
+								scopelen = 1 + snprintf (scopeptr,
+									(scopebuf
+									+ sizeof scopebuf
+									- scopeptr),
+									"%u", scopeid);
+
+							if (real_hostlen + scopelen + 1 > hostlen)
+								return EAI_SYSTEM;
+							memcpy (host + real_hostlen, scopebuf, scopelen + 1);
+						}
+#endif
+					} else
+#endif /* __UCLIBC_HAS_IPV6__ */
+						c = inet_ntop (AF_INET,
+							(const void *) &(((const struct sockaddr_in *) sa)->sin_addr),
+							host, hostlen);
+
+					if (c == NULL) {
+						errno = serrno;
+						return EAI_SYSTEM;
+					}
+				}
+				ok = 1;
+			}
+			break;
+
+		case AF_LOCAL:
+			if (!(flags & NI_NUMERICHOST)) {
+				struct utsname utsname;
+
+				if (!uname (&utsname)) {
+					strncpy (host, utsname.nodename, hostlen);
+					break;
+				};
+			};
+
+			if (flags & NI_NAMEREQD) {
+				errno = serrno;
+				return EAI_NONAME;
+			}
+
+			strncpy (host, "localhost", hostlen);
+			break;
+
+		default:
+			return EAI_FAMILY;
+	}
+
+	if (serv && (servlen > 0)) {
+		switch (sa->sa_family) {
+		case AF_INET:
+#ifdef __UCLIBC_HAS_IPV6__
+		case AF_INET6:
+#endif /* __UCLIBC_HAS_IPV6__ */
+			if (!(flags & NI_NUMERICSERV)) {
+				struct servent *s;
+				s = getservbyport (((const struct sockaddr_in *) sa)->sin_port,
+				      ((flags & NI_DGRAM) ? "udp" : "tcp"));
+				if (s) {
+					strncpy (serv, s->s_name, servlen);
+					break;
+				}
+			}
+			snprintf (serv, servlen, "%d",
+				ntohs (((const struct sockaddr_in *) sa)->sin_port));
+			break;
+
+		case AF_LOCAL:
+			strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
+			break;
+		}
+	}
+	if (host && (hostlen > 0))
+		host[hostlen-1] = 0;
+	if (serv && (servlen > 0))
+		serv[servlen-1] = 0;
+	errno = serrno;
+	return 0;
+}
+#endif