summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2001-11-07 22:02:57 +0000
committerEric Andersen <andersen@codepoet.org>2001-11-07 22:02:57 +0000
commit95d611c31690707350d26a990b5674253bc8dca5 (patch)
tree3a8a57c7efbd37d670ec4bb66190130f57a8a5a6 /libc
parentec59f7c2621e30eb776253e82e620db43c136001 (diff)
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 ;)
Diffstat (limited to 'libc')
-rw-r--r--libc/inet/resolv.c344
1 files changed, 300 insertions, 44 deletions
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 <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