summaryrefslogtreecommitdiff
path: root/libc/inet
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2002-03-19 11:28:17 +0000
committerEric Andersen <andersen@codepoet.org>2002-03-19 11:28:17 +0000
commit54d956c541aa6ea5a8e39d3db8bb3d4f3c9f4bb2 (patch)
treeaadc83ae6ad21f6955b25ca5ab679e5c4d32304c /libc/inet
parent8c4fbefcd9afcd0f3a8776eb8309ee2ed91ba970 (diff)
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.
Diffstat (limited to 'libc/inet')
-rw-r--r--libc/inet/Makefile7
-rw-r--r--libc/inet/gai_strerror.c62
-rw-r--r--libc/inet/getaddrinfo.c863
-rw-r--r--libc/inet/getservice.c98
-rw-r--r--libc/inet/if_nametoindex.c40
-rw-r--r--libc/inet/resolv.c838
6 files changed, 1601 insertions, 307 deletions
diff --git a/libc/inet/Makefile b/libc/inet/Makefile
index 8f053f1f8..14c533be5 100644
--- a/libc/inet/Makefile
+++ b/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))
diff --git a/libc/inet/gai_strerror.c b/libc/inet/gai_strerror.c
new file mode 100644
index 000000000..56fb57684
--- /dev/null
+++ b/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");
+}
diff --git a/libc/inet/getaddrinfo.c b/libc/inet/getaddrinfo.c
new file mode 100644
index 000000000..6a068442a
--- /dev/null
+++ b/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);
+ }
+}
diff --git a/libc/inet/getservice.c b/libc/inet/getservice.c
index 5ba4d4a92..0625a46e1 100644
--- a/libc/inet/getservice.c
+++ b/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)
@@ -91,21 +91,66 @@ 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;
}
diff --git a/libc/inet/if_nametoindex.c b/libc/inet/if_nametoindex.c
new file mode 100644
index 000000000..40818aad9
--- /dev/null
+++ b/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;
+}
diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c
index cbf7b177b..ff2e918b7 100644
--- a/libc/inet/resolv.c
+++ b/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