Browse Source

Bart Visscher <magick@Linux-Fan.com> has added some missing IPV6 support, and
added several additional reentrant networking functions such that iptables now
runs with IPV6 support.

Eric Andersen 22 years ago
parent
commit
54d956c541
6 changed files with 1601 additions and 307 deletions
  1. 4 3
      libc/inet/Makefile
  2. 62 0
      libc/inet/gai_strerror.c
  3. 863 0
      libc/inet/getaddrinfo.c
  4. 74 24
      libc/inet/getservice.c
  5. 40 0
      libc/inet/if_nametoindex.c
  6. 558 280
      libc/inet/resolv.c

+ 4 - 3
libc/inet/Makefile

@@ -41,8 +41,9 @@ MOBJ2=encodeh.o decodeh.o encoded.o decoded.o lengthd.o encodeq.o \
 	formquery.o dnslookup.o resolveaddress.o resolvemailbox.o \
 	opennameservers.o closenameservers.o resolvename.o gethostbyname.o\
 	res_init.o res_query.o gethostbyaddr.o \
-	get_hosts_byname.o get_hosts_byaddr.o read_etc_hosts.o \
-	gethostbyname2.o getnameinfo.o gethostent.o sethostent.o endhostent.o 
+	read_etc_hosts_r.o get_hosts_byname_r.o get_hosts_byaddr_r.o \
+	gethostbyname2.o getnameinfo.o gethostent.o sethostent.o endhostent.o \
+	gethostbyname_r.o gethostbyname2_r.o gethostbyaddr_r.o
 
 MSRC3=socketcalls.c
 MOBJ3= accept.o bind.o connect.o getpeername.o getsockname.o getsockopt.o \
@@ -50,7 +51,7 @@ MOBJ3= accept.o bind.o connect.o getpeername.o getsockname.o getsockopt.o \
 	setsockopt.o shutdown.o socket.o socketpair.o 
 
 CSRC =getservice.c getproto.c hostid.c getnetent.c getnetbynm.c getnetbyad.c \
-	inet_net.c ntop.c herror.c
+	inet_net.c ntop.c herror.c if_nametoindex.c gai_strerror.c getaddrinfo.c 
 
 COBJS=$(patsubst %.c,%.o, $(CSRC))
 

+ 62 - 0
libc/inet/gai_strerror.c

@@ -0,0 +1,62 @@
+/* Copyright (C) 1997, 2001 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Philip Blundell <pjb27@cam.ac.uk>, 1997.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#define _GNU_SOURCE
+#define __FORCE_GLIBC
+#include <features.h>
+#include <stdio.h>
+#include <netdb.h>
+
+#define N_(x) x
+#define _(x) x
+static struct
+  {
+    int code;
+    const char *msg;
+  }
+values[] =
+  {
+    { EAI_ADDRFAMILY, N_("Address family for hostname not supported") },
+    { EAI_AGAIN, N_("Temporary failure in name resolution") },
+    { EAI_BADFLAGS, N_("Bad value for ai_flags") },
+    { EAI_FAIL, N_("Non-recoverable failure in name resolution") },
+    { EAI_FAMILY, N_("ai_family not supported") },
+    { EAI_MEMORY, N_("Memory allocation failure") },
+    { EAI_NODATA, N_("No address associated with hostname") },
+    { EAI_NONAME, N_("Name or service not known") },
+    { EAI_SERVICE, N_("Servname not supported for ai_socktype") },
+    { EAI_SOCKTYPE, N_("ai_socktype not supported") },
+    { EAI_SYSTEM, N_("System error") },
+    { EAI_INPROGRESS, N_("Processing request in progress") },
+    { EAI_CANCELED, N_("Request canceled") },
+    { EAI_NOTCANCELED, N_("Request not canceled") },
+    { EAI_ALLDONE, N_("All requests done") },
+    { EAI_INTR, N_("Interrupted by a signal") }
+  };
+
+const char *
+gai_strerror (int code)
+{
+    size_t i;
+    for (i = 0; i < sizeof (values) / sizeof (values[0]); ++i)
+	if (values[i].code == code)
+	    return _(values[i].msg);
+
+    return _("Unknown error");
+}

+ 863 - 0
libc/inet/getaddrinfo.c

@@ -0,0 +1,863 @@
+/* $USAGI: getaddrinfo.c,v 1.16 2001/10/04 09:52:03 sekiya Exp $ */
+
+/* The Inner Net License, Version 2.00
+
+  The author(s) grant permission for redistribution and use in source and
+binary forms, with or without modification, of the software and documentation
+provided that the following conditions are met:
+
+0. If you receive a version of the software that is specifically labelled
+   as not being for redistribution (check the version message and/or README),
+   you are not permitted to redistribute that version of the software in any
+   way or form.
+1. All terms of the all other applicable copyrights and licenses must be
+   followed.
+2. Redistributions of source code must retain the authors' copyright
+   notice(s), this list of conditions, and the following disclaimer.
+3. Redistributions in binary form must reproduce the authors' copyright
+   notice(s), this list of conditions, and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+4. All advertising materials mentioning features or use of this software
+   must display the following acknowledgement with the name(s) of the
+   authors as specified in the copyright notice(s) substituted where
+   indicated:
+
+	This product includes software developed by <name(s)>, The Inner
+	Net, and other contributors.
+
+5. Neither the name(s) of the author(s) nor the names of its contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  If these license terms cause you a real problem, contact the author.  */
+
+/* This software is Copyright 1996 by Craig Metz, All Rights Reserved.  */
+
+#define _GNU_SOURCE
+#define __FORCE_GLIBC
+#include <features.h>
+#include <assert.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/utsname.h>
+#include <net/if.h>
+
+#define GAIH_OKIFUNSPEC 0x0100
+#define GAIH_EAI        ~(GAIH_OKIFUNSPEC)
+
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX  108
+#endif
+
+struct gaih_service
+{
+    const char *name;
+    int num;
+};
+
+struct gaih_servtuple
+{
+    struct gaih_servtuple *next;
+    int socktype;
+    int protocol;
+    int port;
+};
+
+static const struct gaih_servtuple nullserv;
+
+struct gaih_addrtuple
+{
+    struct gaih_addrtuple *next;
+    int family;
+    char addr[16];
+    uint32_t scopeid;
+};
+
+struct gaih_typeproto
+{
+    int socktype;
+    int protocol;
+    char name[4];
+    int protoflag;
+};
+
+/* Values for `protoflag'.  */
+#define GAI_PROTO_NOSERVICE	1
+#define GAI_PROTO_PROTOANY	2
+
+static const struct gaih_typeproto gaih_inet_typeproto[] =
+{
+    { 0, 0, "", 0 },
+    { SOCK_STREAM, IPPROTO_TCP, "tcp", 0 },
+    { SOCK_DGRAM, IPPROTO_UDP, "udp", 0 },
+    { SOCK_RAW, 0, "raw", GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE },
+    { 0, 0, "", 0 }
+};
+
+struct gaih
+{
+    int family;
+    int (*gaih)(const char *name, const struct gaih_service *service,
+		const struct addrinfo *req, struct addrinfo **pai);
+};
+
+#if PF_UNSPEC == 0
+static const struct addrinfo default_hints;
+#else
+static const struct addrinfo default_hints =
+{ 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
+#endif
+
+
+static int addrconfig (sa_family_t af)
+{
+    int s;
+    int ret;
+    int saved_errno = errno;
+    s = socket(af, SOCK_DGRAM, 0);
+    if (s < 0)
+	ret = (errno == EMFILE) ? 1 : 0;
+    else
+    {
+	close(s);
+	ret = 1;
+    }
+    __set_errno (saved_errno);
+    return ret;
+}
+
+#if 0
+/* Using Unix sockets this way is a security risk.  */
+static int
+gaih_local (const char *name, const struct gaih_service *service,
+	    const struct addrinfo *req, struct addrinfo **pai)
+{
+    struct utsname utsname;
+
+    if ((name != NULL) && (req->ai_flags & AI_NUMERICHOST))
+	return GAIH_OKIFUNSPEC | -EAI_NONAME;
+
+    if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
+	if (uname (&utsname) < 0)
+	    return -EAI_SYSTEM;
+
+    if (name != NULL)
+    {
+	if (strcmp(name, "localhost") &&
+	    strcmp(name, "local") &&
+	    strcmp(name, "unix") &&
+	    strcmp(name, utsname.nodename))
+	    return GAIH_OKIFUNSPEC | -EAI_NONAME;
+    }
+
+    if (req->ai_protocol || req->ai_socktype)
+    {
+	const struct gaih_typeproto *tp = gaih_inet_typeproto + 1;
+
+	while (tp->name[0]
+	       && ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0
+		   || (req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
+		   || (req->ai_protocol != 0
+		       && !(tp->protoflag & GAI_PROTO_PROTOANY)
+		       && req->ai_protocol != tp->protocol)))
+	    ++tp;
+
+	if (! tp->name[0])
+	{
+	    if (req->ai_socktype)
+		return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
+	    else
+		return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
+	}
+    }
+
+    *pai = malloc (sizeof (struct addrinfo) + sizeof (struct sockaddr_un)
+		   + ((req->ai_flags & AI_CANONNAME)
+		      ? (strlen(utsname.nodename) + 1): 0));
+    if (*pai == NULL)
+	return -EAI_MEMORY;
+
+    (*pai)->ai_next = NULL;
+    (*pai)->ai_flags = req->ai_flags;
+    (*pai)->ai_family = AF_LOCAL;
+    (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
+    (*pai)->ai_protocol = req->ai_protocol;
+    (*pai)->ai_addrlen = sizeof (struct sockaddr_un);
+    (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo);
+
+#if SALEN
+    ((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
+	sizeof (struct sockaddr_un);
+#endif /* SALEN */
+
+    ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
+    memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
+
+    if (service)
+    {
+	struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
+
+	if (strchr (service->name, '/') != NULL)
+	{
+	    if (strlen (service->name) >= sizeof (sunp->sun_path))
+		return GAIH_OKIFUNSPEC | -EAI_SERVICE;
+
+	    strcpy (sunp->sun_path, service->name);
+	}
+	else
+	{
+	    if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
+		sizeof (sunp->sun_path))
+		return GAIH_OKIFUNSPEC | -EAI_SERVICE;
+
+	    __stpcpy (__stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
+	}
+    }
+    else
+    {
+	/* This is a dangerous use of the interface since there is a time
+	   window between the test for the file and the actual creation
+	   (done by the caller) in which a file with the same name could
+	   be created.  */
+	char *buf = ((struct sockaddr_un *) (*pai)->ai_addr)->sun_path;
+
+	if (__builtin_expect (__path_search (buf, L_tmpnam, NULL, NULL, 0),
+			      0) != 0
+	    || __builtin_expect (__gen_tempname (buf, __GT_NOCREATE), 0) != 0)
+	    return -EAI_SYSTEM;
+    }
+
+    if (req->ai_flags & AI_CANONNAME)
+	(*pai)->ai_canonname = strcpy ((char *) *pai + sizeof (struct addrinfo)
+				       + sizeof (struct sockaddr_un),
+				       utsname.nodename);
+    else
+	(*pai)->ai_canonname = NULL;
+    return 0;
+}
+#endif	/* 0 */
+
+static int
+gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
+		const struct addrinfo *req, struct gaih_servtuple *st)
+{
+    struct servent *s;
+    size_t tmpbuflen = 1024;
+    struct servent ts;
+    char *tmpbuf;
+    int r;
+
+    do
+    {
+	tmpbuf = alloca (tmpbuflen);
+
+	r = getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
+			     &s);
+	if (r != 0 || s == NULL)
+	{
+	    if (r == ERANGE)
+		tmpbuflen *= 2;
+	    else
+		return GAIH_OKIFUNSPEC | -EAI_SERVICE;
+	}
+    }
+    while (r);
+
+    st->next = NULL;
+    st->socktype = tp->socktype;
+    st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
+		    ? req->ai_protocol : tp->protocol);
+    st->port = s->s_port;
+
+    return 0;
+}
+
+#define gethosts(_family, _type)					\
+{									\
+    int i, herrno;							\
+    size_t tmpbuflen;							\
+    struct hostent th;							\
+    char *tmpbuf;							\
+    tmpbuflen = 512;							\
+    no_data = 0;							\
+    do {								\
+	tmpbuflen *= 2;							\
+	tmpbuf = alloca (tmpbuflen);					\
+	rc = gethostbyname2_r (name, _family, &th, tmpbuf,		\
+			       tmpbuflen, &h, &herrno);			\
+    } while (rc == ERANGE && herrno == NETDB_INTERNAL);			\
+    if (rc != 0)							\
+    {									\
+	if (herrno == NETDB_INTERNAL)					\
+	{								\
+	    __set_h_errno (herrno);					\
+		return -EAI_SYSTEM;					\
+	}								\
+	if (herrno == TRY_AGAIN)					\
+	    no_data = EAI_AGAIN;					\
+	else								\
+	    no_data = herrno == NO_DATA;				\
+    }									\
+    else if (h != NULL)							\
+    {									\
+	for (i = 0; h->h_addr_list[i]; i++)				\
+	{								\
+	    if (*pat == NULL) {						\
+		*pat = alloca (sizeof(struct gaih_addrtuple));		\
+		    (*pat)->scopeid = 0;				\
+	    }								\
+	    (*pat)->next = NULL;					\
+		(*pat)->family = _family;				\
+		memcpy ((*pat)->addr, h->h_addr_list[i],		\
+			sizeof(_type));					\
+		pat = &((*pat)->next);					\
+	}								\
+    }									\
+}
+
+static int
+gaih_inet (const char *name, const struct gaih_service *service,
+	   const struct addrinfo *req, struct addrinfo **pai)
+{
+    const struct gaih_typeproto *tp = gaih_inet_typeproto;
+    struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;
+    struct gaih_addrtuple *at = NULL;
+    int rc;
+    int v4mapped = (req->ai_family == PF_UNSPEC || req->ai_family == PF_INET6) &&
+	(req->ai_flags & AI_V4MAPPED);
+
+    if (req->ai_protocol || req->ai_socktype)
+    {
+	++tp;
+
+	while (tp->name[0]
+	       && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)
+		   || (req->ai_protocol != 0
+		       && !(tp->protoflag & GAI_PROTO_PROTOANY)
+		       && req->ai_protocol != tp->protocol)))
+	    ++tp;
+
+	if (! tp->name[0])
+	{
+	    if (req->ai_socktype)
+		return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
+	    else
+		return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
+	}
+    }
+
+    if (service != NULL)
+    {
+	if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
+	    return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
+
+	if (service->num < 0)
+	{
+	    if (tp->name[0])
+	    {
+		st = (struct gaih_servtuple *)
+		    alloca (sizeof (struct gaih_servtuple));
+
+		if ((rc = gaih_inet_serv (service->name, tp, req, st)))
+		    return rc;
+	    }
+	    else
+	    {
+		struct gaih_servtuple **pst = &st;
+		for (tp++; tp->name[0]; tp++)
+		{
+		    struct gaih_servtuple *newp;
+
+		    if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)
+			continue;
+
+		    if (req->ai_socktype != 0
+			&& req->ai_socktype != tp->socktype)
+			continue;
+		    if (req->ai_protocol != 0
+			&& !(tp->protoflag & GAI_PROTO_PROTOANY)
+			&& req->ai_protocol != tp->protocol)
+			continue;
+
+		    newp = (struct gaih_servtuple *)
+			alloca (sizeof (struct gaih_servtuple));
+
+		    if ((rc = gaih_inet_serv (service->name, tp, req, newp)))
+		    {
+			if (rc & GAIH_OKIFUNSPEC)
+			    continue;
+			return rc;
+		    }
+
+		    *pst = newp;
+		    pst = &(newp->next);
+		}
+		if (st == (struct gaih_servtuple *) &nullserv)
+		    return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
+	    }
+	}
+	else
+	{
+	    st = alloca (sizeof (struct gaih_servtuple));
+	    st->next = NULL;
+	    st->socktype = tp->socktype;
+	    st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
+			    ? req->ai_protocol : tp->protocol);
+	    st->port = htons (service->num);
+	}
+    }
+    else if (req->ai_socktype || req->ai_protocol)
+    {
+	st = alloca (sizeof (struct gaih_servtuple));
+	st->next = NULL;
+	st->socktype = tp->socktype;
+	st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)
+			? req->ai_protocol : tp->protocol);
+	st->port = 0;
+    }
+    else
+    {
+	/* 
+	 * Neither socket type nor protocol is set.  Return all socket types
+	 * we know about.
+	 */
+	struct gaih_servtuple **lastp = &st;
+	for (++tp; tp->name[0]; ++tp)
+	{
+	    struct gaih_servtuple *newp;
+
+	    newp = alloca (sizeof (struct gaih_servtuple));
+	    newp->next = NULL;
+	    newp->socktype = tp->socktype;
+	    newp->protocol = tp->protocol;
+	    newp->port = 0;
+
+	    *lastp = newp;
+	    lastp = &newp->next;
+	}
+    }
+
+    if (name != NULL)
+    {
+	at = alloca (sizeof (struct gaih_addrtuple));
+
+	at->family = AF_UNSPEC;
+	at->scopeid = 0;
+	at->next = NULL;
+
+	if (inet_pton (AF_INET, name, at->addr) > 0)
+	{
+	    if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET || v4mapped)
+		at->family = AF_INET;
+	    else
+		return -EAI_FAMILY;
+	}
+
+#if __UCLIBC_HAS_IPV6__
+	if (at->family == AF_UNSPEC)
+	{
+	    char *namebuf = strdupa (name);
+	    char *scope_delim;
+
+	    scope_delim = strchr (namebuf, SCOPE_DELIMITER);
+	    if (scope_delim != NULL)
+		*scope_delim = '\0';
+
+	    if (inet_pton (AF_INET6, namebuf, at->addr) > 0)
+	    {
+		if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+		    at->family = AF_INET6;
+		else
+		    return -EAI_FAMILY;
+
+		if (scope_delim != NULL)
+		{
+		    int try_numericscope = 0;
+		    if (IN6_IS_ADDR_LINKLOCAL (at->addr)
+			|| IN6_IS_ADDR_MC_LINKLOCAL (at->addr))
+		    {
+			at->scopeid = if_nametoindex (scope_delim + 1);
+			if (at->scopeid == 0)
+			    try_numericscope = 1;
+		    }
+		    else
+			try_numericscope = 1;
+
+		    if (try_numericscope != 0)
+		    {
+			char *end;
+			assert (sizeof (uint32_t) <= sizeof (unsigned long));
+			at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,
+							  10);
+			if (*end != '\0')
+			    return GAIH_OKIFUNSPEC | -EAI_NONAME;
+		    }
+		}
+	    }
+	}
+#endif
+
+	if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
+	{
+	    struct hostent *h;
+	    struct gaih_addrtuple **pat = &at;
+	    int no_data = 0;
+	    int no_inet6_data;
+
+	    /*
+	     * If we are looking for both IPv4 and IPv6 address we don't want
+	     * the lookup functions to automatically promote IPv4 addresses to
+	     * IPv6 addresses.
+	     */
+
+#if __UCLIBC_HAS_IPV6__
+	    if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
+		gethosts (AF_INET6, struct in6_addr);
+#endif
+	    no_inet6_data = no_data;
+
+	    if (req->ai_family == AF_INET ||
+		(!v4mapped && req->ai_family == AF_UNSPEC) ||
+		(v4mapped && (no_inet6_data != 0 || (req->ai_flags & AI_ALL))))
+		gethosts (AF_INET, struct in_addr);
+
+	    if (no_data != 0 && no_inet6_data != 0)
+	    {
+		/* If both requests timed out report this. */
+		if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)
+		    return -EAI_AGAIN;
+
+		/*
+		 * We made requests but they turned out no data.
+		 * The name is known, though.
+		 */
+		return (GAIH_OKIFUNSPEC | -EAI_AGAIN);
+	    }
+	}
+
+	if (at->family == AF_UNSPEC)
+	    return (GAIH_OKIFUNSPEC | -EAI_NONAME);
+    }
+    else
+    {
+	struct gaih_addrtuple *atr;
+	atr = at = alloca (sizeof (struct gaih_addrtuple));
+	memset (at, '\0', sizeof (struct gaih_addrtuple));
+
+	if (req->ai_family == 0)
+	{
+	    at->next = alloca (sizeof (struct gaih_addrtuple));
+	    memset (at->next, '\0', sizeof (struct gaih_addrtuple));
+	}
+
+#if __UCLIBC_HAS_IPV6__
+	if (req->ai_family == 0 || req->ai_family == AF_INET6)
+	{
+	    at->family = AF_INET6;
+	    if ((req->ai_flags & AI_PASSIVE) == 0)
+		memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));
+	    atr = at->next;
+	}
+#endif
+
+	if (req->ai_family == 0 || req->ai_family == AF_INET)
+	{
+	    atr->family = AF_INET;
+	    if ((req->ai_flags & AI_PASSIVE) == 0)
+		*(uint32_t *) atr->addr = htonl (INADDR_LOOPBACK);
+	}
+    }
+
+    if (pai == NULL)
+	return 0;
+
+    {
+	const char *c = NULL;
+	struct gaih_servtuple *st2;
+	struct gaih_addrtuple *at2 = at;
+	size_t socklen, namelen;
+	sa_family_t family;
+
+	/*
+	 * buffer is the size of an unformatted IPv6 address in
+	 * printable format.
+	 */
+	char buffer[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
+
+	while (at2 != NULL)
+	{
+	    if (req->ai_flags & AI_CANONNAME)
+	    {
+		struct hostent *h = NULL;
+
+		int herrno;
+		struct hostent th;
+		size_t tmpbuflen = 512;
+		char *tmpbuf;
+
+		do
+		{
+		    tmpbuflen *= 2;
+		    tmpbuf = alloca (tmpbuflen);
+
+		    if (tmpbuf == NULL)
+			return -EAI_MEMORY;
+
+		    rc = gethostbyaddr_r (at2->addr,
+					  ((at2->family == AF_INET6)
+					   ? sizeof(struct in6_addr)
+					   : sizeof(struct in_addr)),
+					  at2->family, &th, tmpbuf, tmpbuflen,
+					  &h, &herrno);
+
+		}
+		while (rc == errno && herrno == NETDB_INTERNAL);
+
+		if (rc != 0 && herrno == NETDB_INTERNAL)
+		{
+		    __set_h_errno (herrno);
+		    return -EAI_SYSTEM;
+		}
+
+		if (h == NULL)
+		    c = inet_ntop (at2->family, at2->addr, buffer, sizeof(buffer));
+		else
+		    c = h->h_name;
+
+		if (c == NULL)
+		    return GAIH_OKIFUNSPEC | -EAI_NONAME;
+
+		namelen = strlen (c) + 1;
+	    }
+	    else
+		namelen = 0;
+
+#if __UCLIBC_HAS_IPV6__
+	    if (at2->family == AF_INET6 || v4mapped)
+	    {
+		family = AF_INET6;
+		socklen = sizeof (struct sockaddr_in6);
+	    }
+	    else
+#endif
+	    {
+		family = AF_INET;
+		socklen = sizeof (struct sockaddr_in);
+	    }
+
+	    for (st2 = st; st2 != NULL; st2 = st2->next)
+	    {
+		*pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
+		if (*pai == NULL)
+		    return -EAI_MEMORY;
+
+		(*pai)->ai_flags = req->ai_flags;
+		(*pai)->ai_family = family;
+		(*pai)->ai_socktype = st2->socktype;
+		(*pai)->ai_protocol = st2->protocol;
+		(*pai)->ai_addrlen = socklen;
+		(*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
+#if SALEN
+		(*pai)->ai_addr->sa_len = socklen;
+#endif /* SALEN */
+		(*pai)->ai_addr->sa_family = family;
+
+#if __UCLIBC_HAS_IPV6__
+		if (family == AF_INET6)
+		{
+		    struct sockaddr_in6 *sin6p =
+			(struct sockaddr_in6 *) (*pai)->ai_addr;
+
+		    sin6p->sin6_flowinfo = 0;
+		    if (at2->family == AF_INET6)
+		    {
+			memcpy (&sin6p->sin6_addr,
+				at2->addr, sizeof (struct in6_addr));
+		    }
+		    else
+		    {
+			sin6p->sin6_addr.s6_addr32[0] = 0;
+			sin6p->sin6_addr.s6_addr32[1] = 0;
+			sin6p->sin6_addr.s6_addr32[2] = htonl(0x0000ffff);
+			memcpy(&sin6p->sin6_addr.s6_addr32[3], 
+			       at2->addr, sizeof (sin6p->sin6_addr.s6_addr32[3]));
+		    }
+		    sin6p->sin6_port = st2->port;
+		    sin6p->sin6_scope_id = at2->scopeid;
+		}
+		else
+#endif
+		{
+		    struct sockaddr_in *sinp =
+			(struct sockaddr_in *) (*pai)->ai_addr;
+
+		    memcpy (&sinp->sin_addr,
+			    at2->addr, sizeof (struct in_addr));
+		    sinp->sin_port = st2->port;
+		    memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
+		}
+
+		if (c)
+		{
+		    (*pai)->ai_canonname = ((void *) (*pai) +
+					    sizeof (struct addrinfo) + socklen);
+		    strcpy ((*pai)->ai_canonname, c);
+		}
+		else
+		    (*pai)->ai_canonname = NULL;
+
+		(*pai)->ai_next = NULL;
+		pai = &((*pai)->ai_next);
+	    }
+
+	    at2 = at2->next;
+	}
+    }
+    return 0;
+}
+
+static struct gaih gaih[] =
+{
+#if __UCLIBC_HAS_IPV6__
+    { PF_INET6, gaih_inet },
+#endif
+    { PF_INET, gaih_inet },
+#if 0
+    { PF_LOCAL, gaih_local },
+#endif
+    { PF_UNSPEC, NULL }
+};
+
+int
+getaddrinfo (const char *name, const char *service,
+	     const struct addrinfo *hints, struct addrinfo **pai)
+{
+    int i = 0, j = 0, last_i = 0;
+    struct addrinfo *p = NULL, **end;
+    struct gaih *g = gaih, *pg = NULL;
+    struct gaih_service gaih_service, *pservice;
+
+    if (name != NULL && name[0] == '*' && name[1] == 0)
+	name = NULL;
+
+    if (service != NULL && service[0] == '*' && service[1] == 0)
+	service = NULL;
+
+    if (name == NULL && service == NULL)
+	return EAI_NONAME;
+
+    if (hints == NULL)
+	hints = &default_hints;
+
+    if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|
+			    AI_ADDRCONFIG|AI_V4MAPPED|AI_ALL))
+	return EAI_BADFLAGS;
+
+    if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
+	return EAI_BADFLAGS;
+
+    if (service && service[0])
+    {
+	char *c;
+	gaih_service.name = service;
+	gaih_service.num = strtoul (gaih_service.name, &c, 10);
+	if (*c)
+	    gaih_service.num = -1;
+	else
+	    /*
+	     * Can't specify a numerical socket unless a protocol
+	     * family was given.
+	     */
+	    if (hints->ai_socktype == 0 && hints->ai_protocol == 0)
+		return EAI_SERVICE;
+	pservice = &gaih_service;
+    }
+    else
+	pservice = NULL;
+
+    if (pai)
+	end = &p;
+    else
+	end = NULL;
+
+    while (g->gaih)
+    {
+	if (hints->ai_family == g->family || hints->ai_family == AF_UNSPEC)
+	{
+	    if ((hints->ai_flags & AI_ADDRCONFIG) && !addrconfig(g->family))
+		continue;
+	    j++;
+	    if (pg == NULL || pg->gaih != g->gaih)
+	    {
+		pg = g;
+		i = g->gaih (name, pservice, hints, end);
+		if (i != 0)
+		{
+		    last_i = i;
+
+		    if (hints->ai_family == AF_UNSPEC && (i & GAIH_OKIFUNSPEC))
+			continue;
+
+		    if (p)
+			freeaddrinfo (p);
+
+		    return -(i & GAIH_EAI);
+		}
+		if (end)
+		    while(*end) end = &((*end)->ai_next);
+	    }
+	}
+	++g;
+    }
+
+    if (j == 0)
+	return EAI_FAMILY;
+
+    if (p)
+    {
+	*pai = p;
+	return 0;
+    }
+
+    if (pai == NULL && last_i == 0)
+	return 0;
+
+    if (p)
+	freeaddrinfo (p);
+
+    return last_i ? -(last_i & GAIH_EAI) : EAI_NONAME;
+}
+
+void
+freeaddrinfo (struct addrinfo *ai)
+{
+    struct addrinfo *p;
+
+    while (ai != NULL)
+    {
+	p = ai;
+	ai = ai->ai_next;
+	free (p);
+    }
+}

+ 74 - 24
libc/inet/getservice.c

@@ -62,13 +62,13 @@
 #include <stdlib.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <errno.h>
 
 #define	MAXALIASES	35
 
 static FILE *servf = NULL;
-static char line[BUFSIZ+1];
 static struct servent serv;
-static char *serv_aliases[MAXALIASES];
+static char buf[BUFSIZ+1 + sizeof(char *)*MAXALIASES];
 static int serv_stayopen;
 
 void setservent(int f)
@@ -90,22 +90,67 @@ void endservent(void)
 }
 
 struct servent * getservent(void)
+{
+	struct servent *result;
+	getservent_r(&serv, buf, sizeof(buf), &result);
+	return result;
+}
+
+
+struct servent *getservbyname(const char *name, const char *proto)
+{
+	struct servent *result;
+	getservbyname_r(name, proto, &serv, buf, sizeof(buf), &result);
+	return result;
+}
+
+
+struct servent * getservbyport(int port, const char *proto)
+{
+	struct servent *result;
+	getservbyport_r(port, proto, &serv, buf, sizeof(buf), &result);
+	return result;
+}
+
+int getservent_r(struct servent * result_buf,
+		 char * buf, size_t buflen,
+		 struct servent ** result)
 {
 	char *p;
 	register char *cp, **q;
+	char **serv_aliases;
+	char *line;
+
+	*result=NULL;
+
+	if (buflen < sizeof(*serv_aliases)*MAXALIASES) {
+		errno=ERANGE;
+		return errno;
+	}
+	serv_aliases=(char **)buf;
+	buf+=sizeof(*serv_aliases)*MAXALIASES;
+	buflen-=sizeof(*serv_aliases)*MAXALIASES;
+	
+	if (buflen < BUFSIZ+1) {
+		errno=ERANGE;
+		return errno;
+	}
+	line=buf;
+	buf+=BUFSIZ+1;
+	buflen-=BUFSIZ+1;
 
 	if (servf == NULL && (servf = fopen(_PATH_SERVICES, "r" )) == NULL)
-		return (NULL);
+		return errno;
 again:
 	if ((p = fgets(line, BUFSIZ, servf)) == NULL)
-		return (NULL);
+		return TRY_AGAIN;
 	if (*p == '#')
 		goto again;
 	cp = strpbrk(p, "#\n");
 	if (cp == NULL)
 		goto again;
 	*cp = '\0';
-	serv.s_name = p;
+	result_buf->s_name = p;
 	p = strpbrk(p, " \t");
 	if (p == NULL)
 		goto again;
@@ -116,9 +161,9 @@ again:
 	if (cp == NULL)
 		goto again;
 	*cp++ = '\0';
-	serv.s_port = htons((u_short)atoi(p));
-	serv.s_proto = cp;
-	q = serv.s_aliases = serv_aliases;
+	result_buf->s_port = htons((u_short)atoi(p));
+	result_buf->s_proto = cp;
+	q = result_buf->s_aliases = serv_aliases;
 	cp = strpbrk(cp, " \t");
 	if (cp != NULL)
 		*cp++ = '\0';
@@ -134,45 +179,50 @@ again:
 			*cp++ = '\0';
 	}
 	*q = NULL;
-	return (&serv);
+	*result=result_buf;
+	return 0;
 }
 
-
-struct servent *getservbyname(const char *name, const char *proto)
+int getservbyname_r(const char *name, const char *proto,
+			    struct servent * result_buf,
+			    char * buf, size_t buflen,
+			    struct servent ** result)
 {
-	register struct servent *p;
 	register char **cp;
+	int ret;
 
 	setservent(serv_stayopen);
-	while ((p = getservent()) != NULL) {
-		if (strcmp(name, p->s_name) == 0)
+	while (!(ret=getservent_r(result_buf, buf, buflen, result))) {
+		if (strcmp(name, result_buf->s_name) == 0)
 			goto gotname;
-		for (cp = p->s_aliases; *cp; cp++)
+		for (cp = result_buf->s_aliases; *cp; cp++)
 			if (strcmp(name, *cp) == 0)
 				goto gotname;
 		continue;
 gotname:
-		if (proto == 0 || strcmp(p->s_proto, proto) == 0)
+		if (proto == 0 || strcmp(result_buf->s_proto, proto) == 0)
 			break;
 	}
 	if (!serv_stayopen)
 		endservent();
-	return (p);
+	return *result?0:ret;
 }
 
-
-struct servent * getservbyport(int port, const char *proto)
+int getservbyport_r(int port, const char *proto,
+			    struct servent * result_buf,
+			    char * buf, size_t buflen,
+			    struct servent ** result)
 {
-	register struct servent *p;
+	int ret;
 
 	setservent(serv_stayopen);
-	while ((p = getservent()) != NULL) {
-		if (p->s_port != port)
+	while (!(ret=getservent_r(result_buf, buf, buflen, result))) {
+		if (result_buf->s_port != port)
 			continue;
-		if (proto == 0 || strcmp(p->s_proto, proto) == 0)
+		if (proto == 0 || strcmp(result_buf->s_proto, proto) == 0)
 			break;
 	}
 	if (!serv_stayopen)
 		endservent();
-	return (p);
+	return *result?0:ret;
 }

+ 40 - 0
libc/inet/if_nametoindex.c

@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
+ *                     The Silver Hammer Group, Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ */
+#define __FORCE_GLIBC
+#include <features.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+unsigned int if_nametoindex(const char* blub) {
+	struct ifreq ifr;
+	int fd;
+	char *tmp;
+	int len=sizeof(ifr.ifr_name);
+
+#ifdef __UCLIBC_HAS_IPV6__
+	fd=socket(AF_INET6,SOCK_DGRAM,0);
+	if (fd<0)
+#endif /* __UCLIBC_HAS_IPV6__ */
+		fd=socket(AF_INET,SOCK_DGRAM,0);
+
+	for (tmp=ifr.ifr_name; len>0; --len) {
+		if ((*tmp++ = *blub++)==0) break;
+	}
+
+	if (ioctl(fd,SIOCGIFINDEX,&ifr)==0) {
+		close(fd);
+		return ifr.ifr_ifindex;
+	}
+	close(fd);
+	return 0;
+}

+ 558 - 280
libc/inet/resolv.c

@@ -118,10 +118,23 @@ 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, int type);
-extern struct hostent * get_hosts_byaddr(const char * addr, int len, int type);
+extern int get_hosts_byname_r(const char * name, int type,
+			      struct hostent * result_buf,
+			      char * buf, size_t buflen,
+			      struct hostent ** result,
+			      int * h_errnop);
+extern int get_hosts_byaddr_r(const char * addr, int len, int type,
+			      struct hostent * result_buf,
+			      char * buf, size_t buflen,
+			      struct hostent ** result,
+			      int * h_errnop);
 extern void __open_etc_hosts(FILE **fp);
-extern struct hostent * read_etc_hosts(FILE *fp, const char * name, int type, enum etc_hosts_action action);
+extern int read_etc_hosts_r(FILE *fp, const char * name, int type,
+			    enum etc_hosts_action action,
+			    struct hostent * result_buf,
+			    char * buf, size_t buflen,
+			    struct hostent ** result,
+			    int * h_errnop);
 extern int resolve_address(const char * address, int nscount, 
 	char ** nsip, struct in_addr * in);
 extern int resolve_mailbox(const char * address, int nscount, 
@@ -982,75 +995,14 @@ const char *resolve_name(const char *name, int mailbox)
 struct hostent *gethostbyname(const char *name)
 {
 	static struct hostent h;
-	static char namebuf[256];
-	static struct in_addr in;
-	static struct in_addr *addr_list[2];
+	static char buf[sizeof(struct in_addr) +
+			sizeof(struct in_addr *)*2 +
+			256/*namebuffer*/ + 32/* margin */];
 	struct hostent *hp;
-	unsigned char *packet;
-	struct resolv_answer a;
-	int i;
-	int nest = 0;
 
-	open_nameservers();
-
-	if (!name)
-		return 0;
-
-	if ((hp = get_hosts_byname(name, AF_INET))) /* do /etc/hosts first */
-		return(hp);
-
-	memset(&h, 0, sizeof(h));
-
-	addr_list[0] = &in;
-	addr_list[1] = 0;
-	
-	strncpy(namebuf, name, sizeof(namebuf));
-
-	/* First check if this is already an address */
-	if (inet_aton(name, &in)) {
-	    h.h_name = namebuf;
-	    h.h_addrtype = AF_INET;
-	    h.h_length = sizeof(in);
-	    h.h_addr_list = (char **) addr_list;
-	    return &h;
-	}
-
-	for (;;) {
-
-		i = dns_lookup(namebuf, 1, nameservers, nameserver, &packet, &a);
-
-		if (i < 0)
-			return 0;
-
-		strncpy(namebuf, a.dotted, sizeof(namebuf));
-		free(a.dotted);
+	gethostbyname_r(name, &h, buf, sizeof(buf), &hp, &h_errno);
 
-
-		if (a.atype == T_CNAME) {		/* CNAME */
-			DPRINTF("Got a CNAME in gethostbyname()\n");
-			i = decode_dotted(packet, a.rdoffset, namebuf, sizeof(namebuf));
-			free(packet);
-
-			if (i < 0)
-				return 0;
-			if (++nest > MAX_RECURSE)
-				return 0;
-			continue;
-		} else if (a.atype == T_A) {	/* ADDRESS */
-			memcpy(&in, a.rdata, sizeof(in));
-			h.h_name = namebuf;
-			h.h_addrtype = AF_INET;
-			h.h_length = sizeof(in);
-			h.h_addr_list = (char **) addr_list;
-			free(packet);
-			break;
-		} else {
-			free(packet);
-			return 0;
-		}
-	}
-
-	return &h;
+	return hp;
 }
 #endif
 
@@ -1070,81 +1022,14 @@ struct hostent *gethostbyname2(const char *name, int family)
 	return family == AF_INET ? gethostbyname(name) : (struct hostent*)0;
 #else /* __UCLIBC_HAS_IPV6__ */
 	static struct hostent h;
-	static char namebuf[256];
-	static struct in6_addr in;
-	static struct in6_addr *addr_list[2];
+	static char buf[sizeof(struct in6_addr) +
+			sizeof(struct in6_addr *)*2 +
+			256/*namebuffer*/ + 32/* margin */];
 	struct hostent *hp;
-	unsigned char *packet;
-	struct resolv_answer a;
-	int i;
-	int nest = 0;
-
-	if (family == AF_INET)
-		return gethostbyname(name);
-		
-	if (family != AF_INET6)
-		return NULL;
-		
-	open_nameservers();
 
-	if (!name)
-		return 0;
-
-	if ((hp = get_hosts_byname(name, family))) /* do /etc/hosts first */
-		return(hp);
+	gethostbyname_r(name, &h, buf, sizeof(buf), &hp, &h_errno);
 
-	memset(&h, 0, sizeof(h));
-
-	addr_list[0] = &in;
-	addr_list[1] = 0;
-	
-	strncpy(namebuf, name, sizeof(namebuf));
-
-	/* First check if this is already an address */
-	if (inet_pton(AF_INET6, name, &in)) {
-	    h.h_name = namebuf;
-	    h.h_addrtype = AF_INET6;
-	    h.h_length = sizeof(in);
-	    h.h_addr_list = (char **) addr_list;
-	    return &h;
-	}
-
-	for (;;) {
-
-		i = dns_lookup(namebuf, T_AAAA, nameservers, nameserver, &packet, &a);
-
-		if (i < 0)
-			return 0;
-
-		strncpy(namebuf, a.dotted, sizeof(namebuf));
-		free(a.dotted);
-
-
-		if (a.atype == T_CNAME) {		/* CNAME */
-			DPRINTF("Got a CNAME in gethostbyname()\n");
-			i = decode_dotted(packet, a.rdoffset, namebuf, sizeof(namebuf));
-			free(packet);
-
-			if (i < 0)
-				return 0;
-			if (++nest > MAX_RECURSE)
-				return 0;
-			continue;
-		} else if (a.atype == T_AAAA) {	/* ADDRESS */
-			memcpy(&in, a.rdata, sizeof(in));
-			h.h_name = namebuf;
-			h.h_addrtype = AF_INET6;
-			h.h_length = sizeof(in);
-			h.h_addr_list = (char **) addr_list;
-			free(packet);
-			break;
-		} else {
-			free(packet);
-			return 0;
-		}
-	}
-
-	return &h;
+	return hp;
 #endif /* __UCLIBC_HAS_IPV6__ */
 }
 #endif
@@ -1212,120 +1097,23 @@ int res_query(const char *dname, int class, int type,
 struct hostent *gethostbyaddr (const void *addr, socklen_t len, int type)
 {
 	static struct hostent h;
-	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];
+	static char buf[
+#ifndef __UCLIBC_HAS_IPV6__
+		sizeof(struct in_addr) + sizeof(struct in_addr *)*2 +
+#else
+		sizeof(struct in6_addr) + sizeof(struct in6_addr *)*2 +
 #endif /* __UCLIBC_HAS_IPV6__ */
+		256/*namebuffer*/ + 32/* margin */];
 	struct hostent *hp;
-	unsigned char *packet;
-	struct resolv_answer a;
-	int i;
-	int nest = 0;
 
-	if (!addr)
-		return 0;
+	gethostbyaddr_r(addr, len, type, &h, buf, sizeof(buf), &hp, &h_errno);
         
-    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);
-
-	open_nameservers();
-
-	memset(&h, 0, sizeof(h));
-
-	if(type == AF_INET) {
-		unsigned char *tmp_addr = (unsigned char *)addr;
-
-		memcpy(&in.s_addr, addr, len);
-
-		addr_list[0] = &in;
-
-		sprintf(namebuf, "%u.%u.%u.%u.in-addr.arpa",
-			tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0]);
-#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 (;;) {
-
-		i = dns_lookup(namebuf, T_PTR, nameservers, nameserver, &packet, &a);
-
-		if (i < 0)
-			return 0;
-
-		strncpy(namebuf, a.dotted, sizeof(namebuf));
-		free(a.dotted);
-
-		if (a.atype == T_CNAME) {		/* CNAME */
-			DPRINTF("Got a CNAME in gethostbyaddr()\n");
-			i = decode_dotted(packet, a.rdoffset, namebuf, sizeof(namebuf));
-			free(packet);
-
-			if (i < 0)
-				return 0;
-			if (++nest > MAX_RECURSE)
-				return 0;
-			continue;
-		} else if (a.atype == T_PTR) {	/* ADDRESS */
-			i = decode_dotted(packet, a.rdoffset, namebuf, sizeof(namebuf));
-			free(packet);
-
-			h.h_name = namebuf;
-			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 {
-			free(packet);
-			return 0;
-		}
-	}
-
-	return &h;
+	return hp;
 }
 #endif
 
 
-#ifdef L_read_etc_hosts
+#ifdef L_read_etc_hosts_r
 
 void __open_etc_hosts(FILE **fp)
 {
@@ -1335,34 +1123,79 @@ void __open_etc_hosts(FILE **fp)
 	return;
 }
 
-struct hostent * read_etc_hosts(FILE * fp, const char * name, int type, enum etc_hosts_action action)
+int read_etc_hosts_r(FILE * fp, const char * name, int type,
+		     enum etc_hosts_action action,
+		     struct hostent * result_buf,
+		     char * buf, size_t buflen,
+		     struct hostent ** result,
+		     int * h_errnop)
 {
-	static struct hostent	h;
-	static struct in_addr	in;
-	static struct in_addr	*addr_list[2];
+	struct in_addr	*in=NULL;
+	struct in_addr	**addr_list=NULL;
 #ifdef __UCLIBC_HAS_IPV6__
-	static struct in6_addr	in6;
-	static struct in6_addr	*addr_list6[2];
+	struct in6_addr	*in6=NULL;
+	struct in6_addr	**addr_list6=NULL;
 #endif /* __UCLIBC_HAS_IPV6__ */
-	static char				line[80];
 	char					*cp;
 #define		 MAX_ALIAS		5
 	char					*alias[MAX_ALIAS];
 	int						aliases, i;
+	int		ret=HOST_NOT_FOUND;
 
 	if (action!=GETHOSTENT) {
+#ifdef __UCLIBC_HAS_IPV6__
+		char *p=buf;
+		size_t len=buflen;
+#endif /* __UCLIBC_HAS_IPV6__ */
+		*h_errnop=NETDB_INTERNAL;
+		if (buflen < sizeof(*in))
+			return ERANGE;
+		in=(struct in_addr*)buf;
+		buf+=sizeof(*in);
+		buflen-=sizeof(*in);
+
+		if (buflen < sizeof(*addr_list)*2)
+			return ERANGE;
+		addr_list=(struct in_addr **)buf;
+		buf+=sizeof(*addr_list)*2;
+		buflen-=sizeof(*addr_list)*2;
+
+#ifdef __UCLIBC_HAS_IPV6__
+		if (len < sizeof(*in6))
+			return ERANGE;
+		in6=(struct in6_addr*)p;
+		p+=sizeof(*in6);
+		len-=sizeof(*in6);
+
+		if (len < sizeof(*addr_list6)*2)
+			return ERANGE;
+		addr_list6=(struct in6_addr**)p;
+		p+=sizeof(*addr_list6)*2;
+		len-=sizeof(*addr_list6)*2;
+
+		if (len < buflen) {
+			buflen=len;
+			buf=p;
+		}
+#endif /* __UCLIBC_HAS_IPV6__ */
+		if (buflen < 80)
+			return ERANGE;
+
 		__open_etc_hosts(&fp);
 		if (fp == NULL) {
-			return((struct hostent *)NULL);
+			result=NULL;
+			return errno;
 		}
 	}
 
-	while (fgets(line, sizeof(line), fp)) {
-		if ((cp = strchr(line, '#')))
+	*h_errnop=HOST_NOT_FOUND;
+	while (fgets(buf, buflen, fp)) {
+		if ((cp = strchr(buf, '#')))
 			*cp = '\0';
+		DPRINTF("Looking at: %s\n", buf);
 		aliases = 0;
 
-		cp = line;
+		cp = buf;
 		while (*cp) {
 			while (*cp && isspace(*cp))
 				*cp++ = '\0';
@@ -1392,35 +1225,43 @@ struct hostent * read_etc_hosts(FILE * fp, const char * name, int type, enum etc
 				continue;
 		}
 
-		if (type == AF_INET && inet_pton(AF_INET, alias[0], &in) > 0) {
-			addr_list[0] = &in;
+		if (type == AF_INET && inet_pton(AF_INET, alias[0], in) > 0) {
+			DPRINTF("Found INET\n");
+			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;
+			result_buf->h_name = alias[1];
+			result_buf->h_addrtype = AF_INET;
+			result_buf->h_length = sizeof(*in);
+			result_buf->h_addr_list = (char**) addr_list;
+			*result=result_buf;
+			ret=NETDB_SUCCESS;
 #ifdef __UCLIBC_HAS_IPV6__
-        } else if (type == AF_INET6 && inet_pton(AF_INET6, alias[0], &in6) > 0) {
-			addr_list6[0] = &in6;
+        } else if (type == AF_INET6 && inet_pton(AF_INET6, alias[0], in6) > 0) {
+			DPRINTF("Found INET6\n");
+			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;
+			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=result_buf;
+			ret=NETDB_SUCCESS;
 #endif /* __UCLIBC_HAS_IPV6__ */
 		} else {
+			DPRINTF("Error\n");
+			ret=TRY_AGAIN;
 			break; /* bad ip address */
         }
         
 		if (action!=GETHOSTENT) {
 			fclose(fp);
 		}
-		return(&h);
+		return ret;
 	}
 	if (action!=GETHOSTENT) {
 		fclose(fp);
 	}
-	return((struct hostent *) NULL);
+	return ret;
 }
 #endif
 
@@ -1451,6 +1292,14 @@ FILE * __gethostent_fp;
 
 struct hostent *gethostent (void)
 {
+    static struct hostent	h;
+    static char buf[
+#ifndef __UCLIBC_HAS_IPV6__
+	    sizeof(struct in_addr) + sizeof(struct in_addr *)*2 +
+#else
+	    sizeof(struct in6_addr) + sizeof(struct in6_addr *)*2 +
+#endif /* __UCLIBC_HAS_IPV6__ */
+	    80/*namebuffer*/ + 2/* margin */];
     struct hostent *host;
 
     if (__gethostent_fp == NULL) {
@@ -1460,7 +1309,8 @@ struct hostent *gethostent (void)
 	}
     }
 
-    host = read_etc_hosts(__gethostent_fp, NULL, AF_INET, GETHOSTENT);
+    read_etc_hosts_r(__gethostent_fp, NULL, AF_INET, GETHOSTENT, 
+		   &h, buf, sizeof(buf), &host, &h_errno);
     if (__stay_open==0) {
 	fclose(__gethostent_fp);
     }
@@ -1468,18 +1318,25 @@ struct hostent *gethostent (void)
 }
 #endif
 
-#ifdef L_get_hosts_byname
+#ifdef L_get_hosts_byname_r
 
-struct hostent * get_hosts_byname(const char * name, int type)
+int get_hosts_byname_r(const char * name, int type,
+			    struct hostent * result_buf,
+			    char * buf, size_t buflen,
+			    struct hostent ** result,
+			    int * h_errnop)
 {
-	return(read_etc_hosts(NULL, name, type, GET_HOSTS_BYNAME));
+	return(read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME, result_buf, buf, buflen, result, h_errnop));
 }
 #endif
 
+#ifdef L_get_hosts_byaddr_r
 
-#ifdef L_get_hosts_byaddr
-
-struct hostent * get_hosts_byaddr(const char * addr, int len, int type)
+int get_hosts_byaddr_r(const char * addr, int len, int type,
+			    struct hostent * result_buf,
+			    char * buf, size_t buflen,
+			    struct hostent ** result,
+			    int * h_errnop)
 {
 #ifndef __UCLIBC_HAS_IPV6__
 	char	ipaddr[INET_ADDRSTRLEN];
@@ -1504,7 +1361,7 @@ struct hostent * get_hosts_byaddr(const char * addr, int len, int type)
 
 	inet_ntop(type, addr, ipaddr, sizeof(ipaddr));
 
-	return(read_etc_hosts(NULL, ipaddr, type, GET_HOSTS_BYADDR));
+	return(read_etc_hosts_r(NULL, ipaddr, type, GET_HOSTS_BYADDR, result_buf, buf, buflen, result, h_errnop));
 }
 #endif
 
@@ -1700,3 +1557,424 @@ int getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
 	return 0;
 }
 #endif
+
+
+#ifdef L_gethostbyname_r
+
+int gethostbyname_r(const char * name,
+			    struct hostent * result_buf,
+			    char * buf, size_t buflen,
+			    struct hostent ** result,
+			    int * h_errnop)
+{
+	struct in_addr *in;
+	struct in_addr **addr_list;
+	unsigned char *packet;
+	struct resolv_answer a;
+	int i;
+	int nest = 0;
+
+	open_nameservers();
+
+	*result=NULL;
+	if (!name)
+		return EINVAL;
+
+	/* do /etc/hosts first */
+	if ((i=get_hosts_byname_r(name, AF_INET, result_buf,
+				  buf, buflen, result, h_errnop))==0)
+		return i;
+	switch (*h_errnop) {
+		case HOST_NOT_FOUND:
+		case NO_ADDRESS:
+			break;
+		default:
+			return i;
+	}
+
+	DPRINTF("Nothing found in /etc/hosts\n");
+
+	*h_errnop = NETDB_INTERNAL;
+	if (buflen < sizeof(*in))
+		return ERANGE;
+	in=(struct in_addr*)buf;
+	buf+=sizeof(*in);
+	buflen-=sizeof(*in);
+
+	if (buflen < sizeof(*addr_list)*2)
+		return ERANGE;
+	addr_list=(struct in_addr**)buf;
+	buf+=sizeof(*addr_list)*2;
+	buflen-=sizeof(*addr_list)*2;
+
+	addr_list[0] = in;
+	addr_list[1] = 0;
+	
+	if (buflen<256)
+		return ERANGE;
+	strncpy(buf, name, buflen);
+
+	/* First check if this is already an address */
+	if (inet_aton(name, 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;
+	    *h_errnop = NETDB_SUCCESS;
+	    return NETDB_SUCCESS;
+	}
+
+	for (;;) {
+
+		i = dns_lookup(buf, T_A, nameservers, nameserver, &packet, &a);
+
+		if (i < 0) {
+			*h_errnop = HOST_NOT_FOUND;
+			DPRINTF("dns_lookup\n");
+			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 (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;
+			free(packet);
+			break;
+		} else {
+			free(packet);
+			*h_errnop=HOST_NOT_FOUND;
+			return TRY_AGAIN;
+		}
+	}
+
+	*result=result_buf;
+	return NETDB_SUCCESS;
+}
+#endif
+
+#ifdef L_gethostbyname2_r
+
+#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__ */
+
+int gethostbyname2_r(const char *name, int family,
+			    struct hostent * result_buf,
+			    char * buf, size_t buflen,
+			    struct hostent ** result,
+			    int * h_errnop)
+{
+#ifndef __UCLIBC_HAS_IPV6__
+	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;
+	unsigned char *packet;
+	struct resolv_answer a;
+	int i;
+	int nest = 0;
+
+	if (family == AF_INET)
+		return gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop);
+		
+	if (family != AF_INET6)
+		return EINVAL;
+		
+	open_nameservers();
+
+	*result=NULL;
+	if (!name)
+		return EINVAL;
+
+	/* do /etc/hosts first */
+	if ((i=get_hosts_byname_r(name, family, result_buf,
+				  buf, buflen, result, h_errnop))==0)
+		return i;
+	switch (*h_errnop) {
+		case HOST_NOT_FOUND:
+		case NO_ADDRESS:
+			break;
+		default:
+			return i;
+	}
+
+	DPRINTF("Nothing found in /etc/hosts\n");
+
+	*h_errnop = NETDB_INTERNAL;
+	if (buflen < sizeof(*in))
+		return ERANGE;
+	in=(struct in6_addr*)buf;
+	buf+=sizeof(*in);
+	buflen-=sizeof(*in);
+
+	if (buflen < sizeof(*addr_list)*2)
+		return ERANGE;
+	addr_list=(struct in6_addr**)buf;
+	buf+=sizeof(*addr_list)*2;
+	buflen-=sizeof(*addr_list)*2;
+
+	addr_list[0] = in;
+	addr_list[1] = 0;
+	
+	if (buflen<256)
+		return ERANGE;
+	strncpy(buf, name, buflen);
+
+	/* First check if this is already an address */
+	if (inet_pton(AF_INET6, name, 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;
+	    *h_errnop = NETDB_SUCCESS;
+	    return NETDB_SUCCESS;
+	}
+
+	for (;;) {
+
+		i = dns_lookup(buf, T_AAAA, nameservers, nameserver, &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 (i < 0) {
+				*h_errnop = NO_RECOVERY;
+				return -1;
+			}
+			if (++nest > MAX_RECURSE) {
+				*h_errnop = NO_RECOVERY;
+				return -1;
+			}
+			continue;
+		} else 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;
+		} else {
+			free(packet);
+			*h_errnop=HOST_NOT_FOUND;
+			return TRY_AGAIN;
+		}
+	}
+
+	*result=result_buf;
+	return NETDB_SUCCESS;
+#endif /* __UCLIBC_HAS_IPV6__ */
+}
+#endif
+
+#ifdef L_gethostbyaddr_r
+int gethostbyaddr_r (const void *addr, socklen_t len, int type,
+			    struct hostent * result_buf,
+			    char * buf, size_t buflen,
+			    struct hostent ** result,
+			    int * h_errnop)
+
+{
+	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__ */
+	unsigned char *packet;
+	struct resolv_answer a;
+	int i;
+	int nest = 0;
+
+	*result=NULL;
+	if (!addr)
+		return EINVAL;
+        
+	switch (type) {
+		case AF_INET:
+			if (len != sizeof(struct in_addr))
+				return EINVAL;
+			break;
+#ifdef __UCLIBC_HAS_IPV6__
+		case AF_INET6:
+			if (len != sizeof(struct in6_addr))
+				return EINVAL;
+			break;
+#endif /* __UCLIBC_HAS_IPV6__ */
+		default:
+			return EINVAL;
+	}
+
+	/* do /etc/hosts first */
+	if ((i=get_hosts_byaddr_r(addr, len, type, result_buf,
+				  buf, buflen, result, h_errnop))==0)
+		return i;
+	switch (*h_errnop) {
+		case HOST_NOT_FOUND:
+		case NO_ADDRESS:
+			break;
+		default:
+			return i;
+	}
+
+	open_nameservers();
+
+#ifdef __UCLIBC_HAS_IPV6__
+	qp=buf;
+	plen=buflen;
+#endif /* __UCLIBC_HAS_IPV6__ */
+
+	*h_errnop = NETDB_INTERNAL;
+	if (buflen < sizeof(*in))
+		return ERANGE;
+	in=(struct in_addr*)buf;
+	buf+=sizeof(*in);
+	buflen-=sizeof(*in);
+
+	if (buflen < sizeof(*addr_list)*2)
+		return ERANGE;
+	addr_list=(struct in_addr**)buf;
+	buf+=sizeof(*addr_list)*2;
+	buflen-=sizeof(*addr_list)*2;
+
+#ifdef __UCLIBC_HAS_IPV6__
+	if (plen < sizeof(*in6))
+		return ERANGE;
+	in6=(struct in6_addr*)qp;
+	qp+=sizeof(*in6);
+	plen-=sizeof(*in6);
+
+	if (plen < sizeof(*addr_list6)*2)
+		return ERANGE;
+	addr_list6=(struct in6_addr**)qp;
+	qp+=sizeof(*addr_list6)*2;
+	plen-=sizeof(*addr_list6)*2;
+
+	if (len < buflen) {
+		buflen=len;
+		buf=qp;
+	}
+#endif /* __UCLIBC_HAS_IPV6__ */
+
+	if (buflen<256)
+		return ERANGE;
+
+	if(type == AF_INET) {
+		unsigned char *tmp_addr = (unsigned char *)addr;
+
+		memcpy(&in->s_addr, addr, len);
+
+		addr_list[0] = in;
+
+		sprintf(buf, "%u.%u.%u.%u.in-addr.arpa",
+			tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0]);
+#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.int");
+#endif /* __UCLIBC_HAS_IPV6__ */
+	}
+
+	addr_list[1] = 0;
+
+	for (;;) {
+
+		i = dns_lookup(buf, T_PTR, nameservers, nameserver, &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 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;
+		} else 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 /* __UCLIBC_HAS_IPV6__ */
+    		}
+
+			result_buf->h_addr_list = (char **) addr_list;
+			break;
+		} else {
+			free(packet);
+			*h_errnop = NO_ADDRESS;
+			return TRY_AGAIN;
+		}
+	}
+
+	*result=result_buf;
+	return NETDB_SUCCESS;
+}
+#endif