Преглед на файлове

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 години
родител
ревизия
54d956c541
променени са 6 файла, в които са добавени 1601 реда и са изтрити 307 реда
  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