From 95d611c31690707350d26a990b5674253bc8dca5 Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Wed, 7 Nov 2001 22:02:57 +0000 Subject: Patch from Jari Korva 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 ;) --- libc/inet/resolv.c | 344 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 300 insertions(+), 44 deletions(-) (limited to 'libc/inet/resolv.c') diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c index aef1f7935..fea9a0c56 100644 --- a/libc/inet/resolv.c +++ b/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 + * 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] = ∈ - 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] = ∈ + + 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] = ∈ + 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] = ∈ - 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 -- cgit v1.2.3