]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Import alternate RFC 3495 library functions from squid3-ipv6 branch.
authoramosjeffries <>
Fri, 14 Dec 2007 12:03:25 +0000 (12:03 +0000)
committeramosjeffries <>
Fri, 14 Dec 2007 12:03:25 +0000 (12:03 +0000)
Some OS do not provide RFC 3495 libraries (socket extensions for IPv6).
While these OS are expected to be built with --disable-ipv6 they still need
squid to provide the library methods for IP-neutral code use of IPv4.

TODO: This patch does not contain the autotools configure options to cause
 these functions to be built. That will come in the later IPv6-enabling patch

include/getaddrinfo.h [new file with mode: 0644]
include/getnameinfo.h [new file with mode: 0644]
include/inet_ntop.h [new file with mode: 0644]
include/inet_pton.h [new file with mode: 0644]
lib/getaddrinfo.c [new file with mode: 0644]
lib/getnameinfo.c [new file with mode: 0644]
lib/inet_ntop.c [new file with mode: 0644]
lib/inet_pton.c [new file with mode: 0644]

diff --git a/include/getaddrinfo.h b/include/getaddrinfo.h
new file mode 100644 (file)
index 0000000..d5ac51a
--- /dev/null
@@ -0,0 +1,115 @@
+#ifndef _getaddrinfo_h
+#define _getaddrinfo_h
+
+/*
+ *  Shamelessly duplicated from the fetchmail public sources
+ *  for use by the Squid Project under GNU Public License.
+ *
+ * Update/Maintenance History:
+ *
+ *    15-Aug-2007 : Copied from fetchmail 6.3.8
+ *                     - added protection around libray headers
+ *
+ *    16-Aug-2007 : Altered configure checks
+ *                  Un-hacked slightly to use system gethostbyname()
+ *
+ * Squid CVS $Id: getaddrinfo.h,v 1.1 2007/12/14 05:03:25 amosjeffries Exp $
+ *
+ *  Original License and code follows.
+ */
+
+#include "config.h"
+
+/*
+ *  This file is part of libESMTP, a library for submission of RFC 2822
+ *  formatted electronic mail messages using the SMTP protocol described
+ *  in RFC 2821.
+ *
+ *  Copyright (C) 2001,2002  Brian Stafford  <brian@stafford.uklinux.net>
+ *
+ *  This 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.
+ *
+ *  This 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 this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* Structure and prototypes taken from RFC 2553 */
+
+#ifdef HAVE_GETADDRINFO
+
+    /* These functions are provided by the OS */
+#define xgetaddrinfo   getaddrinfo
+#define xfreeaddrinfo  freeaddrinfo
+#define xgai_strerror  gai_strerror
+
+#else /* !HAVE_GETADDRINFO */
+
+/* SG 23/09/2007:
+   On Windows the following definitions are already available, may be that
+   this could be needed on some other platform */
+#if 0
+struct addrinfo
+  {
+    int ai_flags;              /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */
+    int ai_family;             /* PF_xxx */
+    int ai_socktype;           /* SOCK_xxx */
+    int ai_protocol;           /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+    size_t ai_addrlen;         /* length of ai_addr */
+    char *ai_canonname;                /* canonical name for nodename */
+    struct sockaddr *ai_addr;  /* binary address */
+    struct addrinfo *ai_next;  /* next structure in linked list */
+  };
+
+/* Supposed to be defined in <netdb.h> */
+#define AI_PASSIVE     1       /* Socket address is intended for `bind'.  */
+#define AI_CANONNAME   2       /* Request for canonical name.  */
+#define AI_NUMERICHOST 4       /* Don't use name resolution.  */
+
+/* Supposed to be defined in <netdb.h> */
+#define EAI_ADDRFAMILY 1   /* address family for nodename not supported */
+#define EAI_AGAIN      2   /* temporary failure in name resolution */
+#define EAI_BADFLAGS   3   /* invalid value for ai_flags */
+#define EAI_FAIL       4   /* non-recoverable failure in name resolution */
+#define EAI_FAMILY     5   /* ai_family not supported */
+#define EAI_MEMORY     6   /* memory allocation failure */
+#define EAI_NODATA     7   /* no address associated with nodename */
+#define EAI_NONAME     8   /* nodename nor servname provided, or not known */
+#define EAI_SERVICE    9   /* servname not supported for ai_socktype */
+#define EAI_SOCKTYPE   10  /* ai_socktype not supported */
+#endif
+#ifndef EAI_SYSTEM
+/* Not defined on mingw32. */
+#define EAI_SYSTEM     11  /* System error returned in `errno'.  */
+#endif
+#ifndef EAI_OVERFLOW
+/* Not defined on mingw32. */
+#define EAI_OVERFLOW   12 /* Argument buffer overflow.  */
+#endif
+
+#ifndef IN_EXPERIMENTAL
+#define IN_EXPERIMENTAL(a)  \
+     ((((long int) (a)) & 0xf0000000) == 0xf0000000)
+#endif
+
+/* RFC 2553 / Posix resolver */
+SQUIDCEXTERN int xgetaddrinfo (const char *nodename, const char *servname,
+                const struct addrinfo *hints, struct addrinfo **res);
+
+/* Free addrinfo structure and associated storage */
+SQUIDCEXTERN void xfreeaddrinfo (struct addrinfo *ai);
+
+/* Convert error return from getaddrinfo() to string */
+SQUIDCEXTERN const char *xgai_strerror (int code);
+
+#endif /* HAVE_GETADDRINFO */
+
+#endif
diff --git a/include/getnameinfo.h b/include/getnameinfo.h
new file mode 100644 (file)
index 0000000..71a386e
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _getnameinfo_h
+#define _getnameinfo_h
+/*
+ * Reconstructed from KAME getnameinfo.c (in lib/)
+ *
+ * $Id: getnameinfo.h,v 1.1 2007/12/14 05:03:25 amosjeffries Exp $
+ */
+
+#include "config.h"
+
+#ifdef HAVE_GETNAMEINFO
+
+    /* These functions are provided by the OS */
+#define xgetnameinfo   getnameinfo
+
+#else /* !HAVE_GETNAMEINFO */
+
+/* RFC 2553 / Posix resolver */
+SQUIDCEXTERN int xgetnameinfo(const struct sockaddr *sa,
+        socklen_t salen,
+        char *host,
+        size_t hostlen,
+        char *serv,
+        size_t servlen,
+        int flags );
+
+
+#endif /* HAVE_GETNAMEINFO */
+
+#endif
diff --git a/include/inet_ntop.h b/include/inet_ntop.h
new file mode 100644 (file)
index 0000000..9bad7c6
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _INC_INET_NTOP_H
+#define _INC_INET_NTOP_H
+
+#if HAVE_INET_NTOP
+
+/* Use the system provided version where possible */
+#define xinet_ntop inet_ntop
+
+#else
+
+/* char *
+ * inet_ntop(af, src, dst, size)
+ *      convert a network format address to presentation format.
+ * return:
+ *      pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ *      Paul Vixie, 1996.
+ */
+SQUIDCEXTERN const char * xinet_ntop(int af, const void *src, char *dst, size_t size);
+
+#endif
+
+#endif /* _INC_INET_NTOP_H */
diff --git a/include/inet_pton.h b/include/inet_pton.h
new file mode 100644 (file)
index 0000000..1f538d6
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef _INC_INET_PTON_H
+#define _INC_INET_PTON_H
+
+#if HAVE_INET_PTON
+
+/* Use the system provided version where possible */
+#define xinet_pton inet_pton
+
+#else
+
+/* int
+ * inet_pton(af, src, dst)
+ *      convert from presentation format (which usually means ASCII printable)
+ *      to network format (which is usually some kind of binary format).
+ * return:
+ *      1 if the address was valid for the specified address family
+ *      0 if the address wasn't valid (`dst' is untouched in this case)
+ *      -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ *      Paul Vixie, 1996.
+ */
+SQUIDCEXTERN int xinet_pton(int af, const char *src, void *dst);
+
+#endif
+
+#endif /* _INC_INET_NTOP_H */
diff --git a/lib/getaddrinfo.c b/lib/getaddrinfo.c
new file mode 100644 (file)
index 0000000..05f7165
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ *  Shamelessly duplicated from the fetchmail public sources
+ *  for use by the Squid Project under GNU Public License.
+ *
+ * Update/Maintenance History:
+ *
+ *    15-Aug-2007 : Copied from fetchmail 6.3.8
+ *                     - added protection around libray headers
+ *
+ *    16-Aug-2007 : Altered configure checks
+ *                  Un-hacked slightly to use system gethostbyname()
+ *
+ *    06-Oct-2007 : Various fixes to allow the build on MinGW
+ *
+ * Squid CVS $Id: getaddrinfo.c,v 1.1 2007/12/14 05:03:26 amosjeffries Exp $
+ *
+ *  Original License and code follows.
+ */
+#include "config.h"
+
+/*
+ *  This file is part of libESMTP, a library for submission of RFC 2822
+ *  formatted electronic mail messages using the SMTP protocol described
+ *  in RFC 2821.
+ *
+ *  Copyright (C) 2001,2002  Brian Stafford  <brian@stafford.uklinux.net>
+ *
+ *  This 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.
+ *
+ *  This 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 this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* An emulation of the RFC 2553 / Posix getaddrinfo resolver interface.
+ */
+
+#ifndef HAVE_GETADDRINFO
+
+/* Need to turn off Posix features in glibc to build this */
+#undef _POSIX_C_SOURCE
+#undef _XOPEN_SOURCE
+
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+#if HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef _SQUID_MSWIN_
+#undef IN_ADDR
+#include <ws2tcpip.h>
+#endif
+
+#include "getaddrinfo.h"
+
+static struct addrinfo *
+dup_addrinfo (struct addrinfo *info, void *addr, size_t addrlen)
+{
+  struct addrinfo *ret;
+
+  ret = malloc (sizeof (struct addrinfo));
+  if (ret == NULL)
+    return NULL;
+  memcpy (ret, info, sizeof (struct addrinfo));
+  ret->ai_addr = malloc (addrlen);
+  if (ret->ai_addr == NULL)
+    {
+      free (ret);
+      return NULL;
+    }
+  memcpy (ret->ai_addr, addr, addrlen);
+  ret->ai_addrlen = addrlen;
+  return ret;
+}
+
+int
+xgetaddrinfo (const char *nodename, const char *servname,
+            const struct addrinfo *hints, struct addrinfo **res)
+{
+  struct hostent *hp;
+  struct servent *servent;
+  const char *socktype;
+  int port;
+  struct addrinfo hint, result;
+  struct addrinfo *ai, *sai, *eai;
+  char **addrs;
+
+  if (servname == NULL && nodename == NULL)
+    return EAI_NONAME;
+
+  memset (&result, 0, sizeof result);
+
+  /* default for hints */
+  if (hints == NULL)
+    {
+      memset (&hint, 0, sizeof hint);
+      hint.ai_family = PF_UNSPEC;
+      hints = &hint;
+    }
+
+  if (servname == NULL)
+    port = 0;
+  else {
+    /* check for tcp or udp sockets only */
+    if (hints->ai_socktype == SOCK_STREAM)
+      socktype = "tcp";
+    else if (hints->ai_socktype == SOCK_DGRAM)
+      socktype = "udp";
+    else
+      return EAI_SERVICE;
+    result.ai_socktype = hints->ai_socktype;
+
+    /* Note: maintain port in host byte order to make debugging easier */
+    if (isdigit (*servname))
+      port = strtol (servname, NULL, 10);
+    else if ((servent = getservbyname (servname, socktype)) != NULL)
+      port = ntohs (servent->s_port);
+    else
+      return EAI_NONAME;
+  }
+
+  /* if nodename == NULL refer to the local host for a client or any
+     for a server */
+  if (nodename == NULL)
+    {
+      struct sockaddr_in sin;
+
+      /* check protocol family is PF_UNSPEC or PF_INET - could try harder
+         for IPv6 but that's more code than I'm prepared to write */
+      if (hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET)
+       result.ai_family = AF_INET;
+      else
+       return EAI_FAMILY;
+
+      sin.sin_family = result.ai_family;
+      sin.sin_port = htons (port);
+      if (hints->ai_flags & AI_PASSIVE)
+        sin.sin_addr.s_addr = htonl (INADDR_ANY);
+      else
+        sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+      /* Duplicate result and addr and return */
+      *res = dup_addrinfo (&result, &sin, sizeof sin);
+      return (*res == NULL) ? EAI_MEMORY : 0;
+    }
+
+  /* If AI_NUMERIC is specified, use inet_addr to translate numbers and
+     dots notation. */
+  if (hints->ai_flags & AI_NUMERICHOST)
+    {
+      struct sockaddr_in sin;
+
+      /* check protocol family is PF_UNSPEC or PF_INET */
+      if (hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET)
+       result.ai_family = AF_INET;
+      else
+       return EAI_FAMILY;
+
+      sin.sin_family = result.ai_family;
+      sin.sin_port = htons (port);
+      sin.sin_addr.s_addr = inet_addr (nodename);
+      /* Duplicate result and addr and return */
+      *res = dup_addrinfo (&result, &sin, sizeof sin);
+      return (*res == NULL) ? EAI_MEMORY : 0;
+    }
+
+  h_errno = 0;
+  errno = 0;
+  hp = gethostbyname(nodename);
+  if (hp == NULL)
+    {
+#ifdef EAI_SYSTEM
+      if (errno != 0) {
+        return EAI_SYSTEM;
+      }
+#endif
+      switch (h_errno)
+        {
+        case HOST_NOT_FOUND: return EAI_NODATA;
+        case NO_DATA:        return EAI_NODATA;
+#if defined(NO_ADDRESS) && NO_ADDRESS != NO_DATA
+        case NO_ADDRESS:     return EAI_NODATA;
+#endif
+        case NO_RECOVERY:    return EAI_FAIL;
+        case TRY_AGAIN:      return EAI_AGAIN;
+        default:             return EAI_FAIL;
+        }
+      return EAI_FAIL;
+    }
+
+  /* Check that the address family is acceptable.
+   */
+  switch (hp->h_addrtype)
+    {
+    case AF_INET:
+      if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET))
+        return EAI_FAMILY;
+      break;
+#if USE_IPV6
+    case AF_INET6:
+      if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET6))
+        return EAI_FAMILY;
+      break;
+#endif
+    default:
+      return EAI_FAMILY;
+    }
+
+  /* For each element pointed to by hp, create an element in the
+     result linked list. */
+  sai = eai = NULL;
+  for (addrs = hp->h_addr_list; *addrs != NULL; addrs++)
+    {
+      struct sockaddr sa;
+      size_t addrlen;
+
+      if (hp->h_length < 1)
+        continue;
+      sa.sa_family = hp->h_addrtype;
+      switch (hp->h_addrtype)
+        {
+        case AF_INET:
+         ((struct sockaddr_in *) &sa)->sin_port = htons (port);
+         memcpy (&((struct sockaddr_in *) &sa)->sin_addr,
+                 *addrs, hp->h_length);
+          addrlen = sizeof (struct sockaddr_in);
+          break;
+#if USE_IPV6
+        case AF_INET6:
+#if SIN6_LEN
+         ((struct sockaddr_in6 *) &sa)->sin6_len = hp->h_length;
+#endif
+         ((struct sockaddr_in6 *) &sa)->sin6_port = htons (port);
+         memcpy (&((struct sockaddr_in6 *) &sa)->sin6_addr,
+                 *addrs, hp->h_length);
+          addrlen = sizeof (struct sockaddr_in6);
+          break;
+#endif
+        default:
+          continue;
+        }
+
+      result.ai_family = hp->h_addrtype;
+      ai = dup_addrinfo (&result, &sa, addrlen);
+      if (ai == NULL)
+        {
+          xfreeaddrinfo (sai);
+          return EAI_MEMORY;
+        }
+      if (sai == NULL)
+       sai = ai;
+      else
+       eai->ai_next = ai;
+      eai = ai;
+    }
+
+  if (sai == NULL)
+    {
+      return EAI_NODATA;
+    }
+  
+  if (hints->ai_flags & AI_CANONNAME) 
+    {
+      sai->ai_canonname = malloc (strlen (hp->h_name) + 1);
+      if (sai->ai_canonname == NULL)
+        {
+          xfreeaddrinfo (sai);
+          return EAI_MEMORY;
+        }
+      strcpy (sai->ai_canonname, hp->h_name);
+    }
+
+  *res = sai;
+  return 0;
+}
+
+void
+xfreeaddrinfo (struct addrinfo *ai)
+{
+  struct addrinfo *next;
+
+  while (ai != NULL)
+    {
+      next = ai->ai_next;
+      if (ai->ai_canonname != NULL)
+        free (ai->ai_canonname);
+      if (ai->ai_addr != NULL)
+        free (ai->ai_addr);
+      free (ai);
+      ai = next;
+    }
+}
+
+const char *
+xgai_strerror (int ecode)
+{
+  static const char *eai_descr[] =
+    {
+      "no error",
+      "address family for nodename not supported",     /* EAI_ADDRFAMILY */
+      "temporary failure in name resolution",          /* EAI_AGAIN */
+      "invalid value for ai_flags",                    /* EAI_BADFLAGS */
+      "non-recoverable failure in name resolution",    /* EAI_FAIL */
+      "ai_family not supported",                       /* EAI_FAMILY */
+      "memory allocation failure",                     /* EAI_MEMORY */
+      "no address associated with nodename",           /* EAI_NODATA */
+      "nodename nor servname provided, or not known",  /* EAI_NONAME */
+      "servname not supported for ai_socktype",                /* EAI_SERVICE */
+      "ai_socktype not supported",                     /* EAI_SOCKTYPE */
+      "system error returned in errno",                        /* EAI_SYSTEM */
+      "argument buffer overflow",                      /* EAI_OVERFLOW */
+    };
+
+  if (ecode < 0 || ecode > (int) (sizeof eai_descr/ sizeof eai_descr[0]))
+    return "unknown error";
+  return eai_descr[ecode];
+}
+
+#endif /* HAVE_GETADDRINFO */
diff --git a/lib/getnameinfo.c b/lib/getnameinfo.c
new file mode 100644 (file)
index 0000000..d17c053
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ *  Shamelessly duplicated from the fetchmail public sources
+ *  for use by the Squid Project under GNU Public License.
+ *
+ * Update/Maintenance History:
+ *
+ *    16-Aug-2007 : Copied from fetchmail 6.3.8
+ *                      - added protection around libray headers
+ *                      - added use of alternative name xgetnameinfo
+ *                        to split from any OS-provided.
+ *
+ *    06-Oct-2007 : Various fixes to allow the build on MinGW
+ *                      - use srtncpy instead of strlcpy
+ *                      - use xinet_ntop instead of inet_ntop
+ *                      - use SQUIDHOSTNAMELEN instead of MAXHOSTNAMELEN
+ *
+ * Squid CVS $Id: getnameinfo.c,v 1.1 2007/12/14 05:03:26 amosjeffries Exp $
+ *
+ *  Original License and code follows.
+ */
+#include "config.h"
+
+/*     KAME: getnameinfo.c,v 1.72 2005/01/13 04:12:03 itojun Exp       */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project 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 THE PROJECT 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 PROJECT 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.
+ */
+
+/*
+ * Issues to be discussed:
+ * - RFC2553 says that we should raise error on short buffer.  X/Open says
+ *   we need to truncate the result.  We obey RFC2553 (and X/Open should be
+ *   modified).  ipngwg rough consensus seems to follow RFC2553.  RFC3493 says
+ *   nothing about it, but defines a new error code EAI_OVERFLOW which seems
+ *   to be intended the code for this case.
+ * - What is "local" in NI_NOFQDN?  (see comments in the code)
+ * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other.
+ * - (KAME extension) always attach textual scopeid (fe80::1%lo0), if
+ *   sin6_scope_id is filled - standardization status?
+ * - what should we do if we should do getservbyport("sctp")?
+ */
+
+/*
+ * Considerations about thread-safeness
+ *   The code in this file is thread-safe, and so the thread-safeness of
+ *   getnameinfo() depends on the property of backend functions.
+ *     - getservbyport() is not thread safe for most systems we are targeting.
+ *     - getipnodebyaddr() is thread safe.  However, many resolver libraries
+ *       used in the function are not thread safe.
+ *     - gethostbyaddr() is usually not thread safe.
+ */
+
+#ifndef HAVE_GETNAMEINFO
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#if HAVE_RESOLV_H
+#include <resolv.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+#if HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#ifdef _SQUID_MSWIN_
+#undef IN_ADDR
+#include <ws2tcpip.h>
+#endif
+
+#include "getaddrinfo.h"
+
+#if !HAVE_INET_NTOP
+#include "inet_ntop.h"
+#endif
+
+static const struct afd {
+       int a_af;
+       int a_addrlen;
+       int a_socklen;
+       int a_off;
+       int a_portoff;
+} afdl [] = {
+#ifdef INET6
+       {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
+        offsetof(struct sockaddr_in6, sin6_addr),
+        offsetof(struct sockaddr_in6, sin6_port)},
+#endif
+       {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
+        offsetof(struct sockaddr_in, sin_addr),
+        offsetof(struct sockaddr_in, sin_port)},
+       {0, 0, 0, 0, 0},
+};
+
+#ifdef INET6
+static int ip6_parsenumeric __P((const struct sockaddr *, const char *, char *,
+                                size_t, int));
+static int ip6_sa2str __P((const struct sockaddr_in6 *, char *, size_t, int));
+#endif
+
+int
+xgetnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
+       const struct sockaddr *sa;
+       socklen_t salen;
+       char *host;
+       size_t hostlen;
+       char *serv;
+       size_t servlen;
+       int flags;
+{
+       const struct afd *afd;
+       struct servent *sp;
+       struct hostent *hp;
+       u_short port;
+       int family, i;
+       const char *addr;
+       u_int32_t v4a;
+       int h_error;
+       char numserv[512];
+
+       if (sa == NULL)
+               return EAI_FAIL;
+
+#ifdef HAVE_SA_LEN     /*XXX*/
+       if (sa->sa_len != salen)
+               return EAI_FAIL;
+#endif
+
+       family = sa->sa_family;
+       for (i = 0; afdl[i].a_af; i++)
+               if (afdl[i].a_af == family) {
+                       afd = &afdl[i];
+                       goto found;
+               }
+       return EAI_FAMILY;
+
+ found:
+       if (salen != afd->a_socklen)
+               return EAI_FAIL;
+
+       /* network byte order */
+       memcpy(&port, (const char *)sa + afd->a_portoff, sizeof(port));
+       addr = (const char *)sa + afd->a_off;
+
+       if (serv == NULL || servlen == 0) {
+               /*
+                * do nothing in this case.
+                * in case you are wondering if "&&" is more correct than
+                * "||" here: RFC3493 says that serv == NULL OR servlen == 0
+                * means that the caller does not want the result.
+                */
+       } else {
+               if (flags & NI_NUMERICSERV)
+                       sp = NULL;
+               else {
+                       sp = getservbyport(port,
+                               (flags & NI_DGRAM) ? "udp" : "tcp");
+               }
+               if (sp) {
+                       if (strlen(sp->s_name) + 1 > servlen)
+                               return EAI_OVERFLOW;
+                       strncpy(serv, sp->s_name, servlen);
+               } else {
+                       snprintf(numserv, sizeof(numserv), "%u", ntohs(port));
+                       if (strlen(numserv) + 1 > servlen)
+                               return EAI_OVERFLOW;
+                       strncpy(serv, numserv, servlen);
+               }
+       }
+
+       switch (sa->sa_family) {
+       case AF_INET:
+               v4a = (u_int32_t)
+                   ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr);
+               if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
+                       flags |= NI_NUMERICHOST;
+               v4a >>= IN_CLASSA_NSHIFT;
+               if (v4a == 0)
+                       flags |= NI_NUMERICHOST;
+               break;
+#ifdef INET6
+       case AF_INET6:
+           {
+               const struct sockaddr_in6 *sin6;
+               sin6 = (const struct sockaddr_in6 *)sa;
+               switch (sin6->sin6_addr.s6_addr[0]) {
+               case 0x00:
+                       if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
+                               ;
+                       else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
+                               ;
+                       else
+                               flags |= NI_NUMERICHOST;
+                       break;
+               default:
+                       if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+                               flags |= NI_NUMERICHOST;
+                       else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
+                               flags |= NI_NUMERICHOST;
+                       break;
+               }
+           }
+               break;
+#endif
+       }
+       if (host == NULL || hostlen == 0) {
+               /*
+                * do nothing in this case.
+                * in case you are wondering if "&&" is more correct than
+                * "||" here: RFC3493 says that host == NULL or hostlen == 0
+                * means that the caller does not want the result.
+                */
+       } else if (flags & NI_NUMERICHOST) {
+               /* NUMERICHOST and NAMEREQD conflicts with each other */
+               if (flags & NI_NAMEREQD)
+                       return EAI_NONAME;
+
+               goto numeric;
+       } else {
+#ifdef USE_GETIPNODEBY
+               hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
+#else
+               hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
+#ifdef HAVE_H_ERRNO
+               h_error = h_errno;
+#else
+               h_error = EINVAL;
+#endif
+#endif
+
+               if (hp) {
+#if 0
+                       if (flags & NI_NOFQDN) {
+                               /*
+                                * According to RFC3493 section 6.2, NI_NOFQDN
+                                * means "node name portion of the FQDN shall
+                                * be returned for local hosts."  The following
+                                * code tries to implement it by returning the
+                                * first label (the part before the first
+                                * period) of the FQDN.  However, it is not
+                                * clear if this always makes sense, since the
+                                * given address may be outside of "local
+                                * hosts."  Due to the unclear description, we
+                                * disable the code in this implementation.
+                                */
+                               char *p;
+                               p = strchr(hp->h_name, '.');
+                               if (p)
+                                       *p = '\0';
+                       }
+#endif
+                       if (strlen(hp->h_name) + 1 > hostlen) {
+#ifdef USE_GETIPNODEBY
+                               freehostent(hp);
+#endif
+                               return EAI_OVERFLOW;
+                       }
+                       strncpy(host, hp->h_name, hostlen);
+#ifdef USE_GETIPNODEBY
+                       freehostent(hp);
+#endif
+               } else {
+                       if (flags & NI_NAMEREQD)
+                               return EAI_NONAME;
+
+                 numeric:
+                       switch(afd->a_af) {
+#ifdef INET6
+                       case AF_INET6:
+                       {
+                               int error;
+
+                               if ((error = ip6_parsenumeric(sa, addr, host,
+                                                             hostlen,
+                                                             flags)) != 0)
+                                       return(error);
+                               break;
+                       }
+#endif
+                       default:
+                               if (xinet_ntop(afd->a_af, addr, host,
+                                   hostlen) == NULL)
+                                       return EAI_SYSTEM;
+                               break;
+                       }
+               }
+       }
+       return(0);
+}
+
+#ifdef INET6
+static int
+ip6_parsenumeric(sa, addr, host, hostlen, flags)
+       const struct sockaddr *sa;
+       const char *addr;
+       char *host;
+       size_t hostlen;
+       int flags;
+{
+       int numaddrlen;
+       char numaddr[512];
+
+       if (xinet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) == NULL)
+               return EAI_SYSTEM;
+
+       numaddrlen = strlen(numaddr);
+       if (numaddrlen + 1 > hostlen) /* don't forget terminator */
+               return EAI_OVERFLOW;
+       strncpy(host, numaddr, hostlen);
+
+       if (((const struct sockaddr_in6 *)sa)->sin6_scope_id) {
+               char zonebuf[SQUIDHOSTNAMELEN];
+               int zonelen;
+
+               zonelen = ip6_sa2str(
+                   (const struct sockaddr_in6 *)(const void *)sa,
+                   zonebuf, sizeof(zonebuf), flags);
+               if (zonelen < 0)
+                       return EAI_OVERFLOW;
+               if (zonelen + 1 + numaddrlen + 1 > hostlen)
+                       return EAI_OVERFLOW;
+
+               /* construct <numeric-addr><delim><zoneid> */
+               memcpy(host + numaddrlen + 1, zonebuf,
+                   (size_t)zonelen);
+               host[numaddrlen] = SCOPE_DELIMITER;
+               host[numaddrlen + 1 + zonelen] = '\0';
+       }
+
+       return 0;
+}
+
+/* ARGSUSED */
+static int
+ip6_sa2str(sa6, buf, bufsiz, flags)
+       const struct sockaddr_in6 *sa6;
+       char *buf;
+       size_t bufsiz;
+       int flags;
+{
+       unsigned int ifindex;
+       const struct in6_addr *a6;
+       int n;
+
+       ifindex = (unsigned int)sa6->sin6_scope_id;
+       a6 = &sa6->sin6_addr;
+
+#ifdef NI_NUMERICSCOPE
+       if ((flags & NI_NUMERICSCOPE) != 0) {
+               n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
+               if (n < 0 || n >= bufsiz)
+                       return -1;
+               else
+                       return n;
+       }
+#endif
+
+       /* if_indextoname() does not take buffer size.  not a good api... */
+       if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) ||
+            IN6_IS_ADDR_MC_NODELOCAL(a6)) && bufsiz >= IF_NAMESIZE) {
+               char *p = if_indextoname(ifindex, buf);
+               if (p)
+                       return (strlen(p));
+       }
+
+       /* last resort */
+       n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
+       if (n < 0 || n >= bufsiz)
+               return -1;
+       else
+               return n;
+}
+#endif /* INET6 */
+#endif
diff --git a/lib/inet_ntop.c b/lib/inet_ntop.c
new file mode 100644 (file)
index 0000000..e780286
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ *  Shamelessly duplicated from the bind9 public sources
+ *  for use by the Squid Project under ISC written permission
+ *  included "as found" below.
+ *
+ * Update/Maintenance History:
+ *
+ *    24-Sep-2007 : Copied from bind 9.3.3
+ *                     - Added protection around libray headers
+ *                     - Altered configure checks
+ *                     - Un-hacked slightly to use system gethostbyname()
+ *
+ *    06-Oct-2007 : Various fixes to allow the build on MinGW
+ *
+ *    28-Oct-2007: drop some dead code. now tested working without.
+ *
+ * Squid CVS $Id: inet_ntop.c,v 1.1 2007/12/14 05:03:26 amosjeffries Exp $
+ *
+ *  Original License and code follows.
+ */
+
+#include "config.h"
+
+#ifndef HAVE_INET_NTOP
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "inet_ntop.c,v 1.1.2.1.8.2 2005/11/03 23:08:40 marka Exp";
+#endif /* LIBC_SCCS and not lint */
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef SPRINTF_CHAR
+# define SPRINTF(x) strlen(sprintf/**/x)
+#else
+# define SPRINTF(x) ((size_t)sprintf x)
+#endif
+
+#if ! defined(NS_INADDRSZ)
+#define NS_INADDRSZ      4
+#endif
+#if ! defined(NS_IN6ADDRSZ)
+#define NS_IN6ADDRSZ    16
+#endif
+#if ! defined(NS_INT16SZ)
+#define NS_INT16SZ      2
+#endif
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static const char *inet_ntop4 (const u_char *src, char *dst, size_t size);
+static const char *inet_ntop6 (const u_char *src, char *dst, size_t size);
+
+/* char *
+ * inet_ntop(af, src, dst, size)
+ *     convert a network format address to presentation format.
+ * return:
+ *     pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ *     Paul Vixie, 1996.
+ */
+const char *
+xinet_ntop(af, src, dst, size)
+       int af;
+       const void *src;
+       char *dst;
+       size_t size;
+{
+       switch (af) {
+       case AF_INET:
+               return (inet_ntop4(src, dst, size));
+       case AF_INET6:
+               return (inet_ntop6(src, dst, size));
+       default:
+               errno = EAFNOSUPPORT;
+               return (NULL);
+       }
+       /* NOTREACHED */
+}
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ *     format an IPv4 address
+ * return:
+ *     `dst' (as a const)
+ * notes:
+ *     (1) uses no statics
+ *     (2) takes a u_char* not an in_addr as input
+ * author:
+ *     Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(src, dst, size)
+       const u_char *src;
+       char *dst;
+       size_t size;
+{
+       static const char fmt[] = "%u.%u.%u.%u";
+       char tmp[sizeof "255.255.255.255"];
+
+       if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size) {
+               errno = ENOSPC;
+               return (NULL);
+       }
+       strcpy(dst, tmp);
+       return (dst);
+}
+
+/* const char *
+ * inet_ntop6(src, dst, size)
+ *     convert IPv6 binary address into presentation (printable) format
+ * author:
+ *     Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop6(src, dst, size)
+       const u_char *src;
+       char *dst;
+       size_t size;
+{
+       /*
+        * Note that int32_t and int16_t need only be "at least" large enough
+        * to contain a value of the specified size.  On some systems, like
+        * Crays, there is no such thing as an integer variable with 16 bits.
+        * Keep this in mind if you think this function should have been coded
+        * to use pointer overlays.  All the world's not a VAX.
+        */
+       char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+       struct { int base, len; } best, cur;
+       u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
+       int i;
+
+       /*
+        * Preprocess:
+        *      Copy the input (bytewise) array into a wordwise array.
+        *      Find the longest run of 0x00's in src[] for :: shorthanding.
+        */
+       memset(words, '\0', sizeof words);
+       for (i = 0; i < NS_IN6ADDRSZ; i++)
+               words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+       best.base = -1;
+       best.len = 0;
+       cur.base = -1;
+       cur.len = 0;
+       for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+               if (words[i] == 0) {
+                       if (cur.base == -1)
+                               cur.base = i, cur.len = 1;
+                       else
+                               cur.len++;
+               } else {
+                       if (cur.base != -1) {
+                               if (best.base == -1 || cur.len > best.len)
+                                       best = cur;
+                               cur.base = -1;
+                       }
+               }
+       }
+       if (cur.base != -1) {
+               if (best.base == -1 || cur.len > best.len)
+                       best = cur;
+       }
+       if (best.base != -1 && best.len < 2)
+               best.base = -1;
+
+       /*
+        * Format the result.
+        */
+       tp = tmp;
+       for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+               /* Are we inside the best run of 0x00's? */
+               if (best.base != -1 && i >= best.base &&
+                   i < (best.base + best.len)) {
+                       if (i == best.base)
+                               *tp++ = ':';
+                       continue;
+               }
+               /* Are we following an initial run of 0x00s or any real hex? */
+               if (i != 0)
+                       *tp++ = ':';
+               /* Is this address an encapsulated IPv4? */
+               if (i == 6 && best.base == 0 && (best.len == 6 ||
+                   (best.len == 7 && words[7] != 0x0001) ||
+                   (best.len == 5 && words[5] == 0xffff))) {
+                       if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
+                               return (NULL);
+                       tp += strlen(tp);
+                       break;
+               }
+               tp += SPRINTF((tp, "%x", words[i]));
+       }
+       /* Was it a trailing run of 0x00's? */
+       if (best.base != -1 && (best.base + best.len) ==
+           (NS_IN6ADDRSZ / NS_INT16SZ))
+               *tp++ = ':';
+       *tp++ = '\0';
+
+       /*
+        * Check for overflow, copy, and we're done.
+        */
+       if ((size_t)(tp - tmp) > size) {
+               errno = ENOSPC;
+               return (NULL);
+       }
+       strcpy(dst, tmp);
+       return (dst);
+}
+
+#endif /* HAVE_INET_NTOP */
diff --git a/lib/inet_pton.c b/lib/inet_pton.c
new file mode 100644 (file)
index 0000000..dbdad40
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ *  Shamelessly duplicated from the bind9 public sources
+ *  for use by the Squid Project under ISC written permission
+ *  included "as found" below.
+ *
+ * Update/Maintenance History:
+ *
+ *    24-Sep-2007 : Copied from bind 9.3.3
+ *                      - Added protection around libray headers
+ *                      - Altered configure checks to import
+ *
+ *    06-Oct-2007 : Various fixes to allow the build on MinGW
+ *
+ *    28-Oct-2007: drop some dead code. now tested working without.
+ *
+ * Squid CVS $Id: inet_pton.c,v 1.1 2007/12/14 05:03:26 amosjeffries Exp $
+ *
+ *  Original License and code follows.
+ */
+
+#include "config.h"
+
+#ifndef HAVE_INET_PTON 
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "inet_pton.c,v 1.2.206.2 2005/07/28 07:43:18 marka Exp";
+#endif /* LIBC_SCCS and not lint */
+
+#if HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#if ! defined(NS_INADDRSZ)
+#define NS_INADDRSZ      4
+#endif
+#if ! defined(NS_IN6ADDRSZ)
+#define NS_IN6ADDRSZ    16
+#endif
+#if ! defined(NS_INT16SZ)
+#define NS_INT16SZ      2
+#endif
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int     inet_pton4 (const char *src, u_char *dst);
+static int     inet_pton6 (const char *src, u_char *dst);
+
+/* int
+ * inet_pton(af, src, dst)
+ *     convert from presentation format (which usually means ASCII printable)
+ *     to network format (which is usually some kind of binary format).
+ * return:
+ *     1 if the address was valid for the specified address family
+ *     0 if the address wasn't valid (`dst' is untouched in this case)
+ *     -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ *     Paul Vixie, 1996.
+ */
+int
+xinet_pton(af, src, dst)
+       int af;
+       const char *src;
+       void *dst;
+{
+       switch (af) {
+       case AF_INET:
+               return (inet_pton4(src, dst));
+       case AF_INET6:
+               return (inet_pton6(src, dst));
+       default:
+               errno = EAFNOSUPPORT;
+               return (-1);
+       }
+       /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ *     like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ *     1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ *     does not touch `dst' unless it's returning 1.
+ * author:
+ *     Paul Vixie, 1996.
+ */
+static int
+inet_pton4(src, dst)
+       const char *src;
+       u_char *dst;
+{
+       static const char digits[] = "0123456789";
+       int saw_digit, octets, ch;
+       u_char tmp[NS_INADDRSZ], *tp;
+
+       saw_digit = 0;
+       octets = 0;
+       *(tp = tmp) = 0;
+       while ((ch = *src++) != '\0') {
+               const char *pch;
+
+               if ((pch = strchr(digits, ch)) != NULL) {
+                       u_int new = *tp * 10 + (pch - digits);
+
+                       if (saw_digit && *tp == 0)
+                               return (0);
+                       if (new > 255)
+                               return (0);
+                       *tp = new;
+                       if (!saw_digit) {
+                               if (++octets > 4)
+                                       return (0);
+                               saw_digit = 1;
+                       }
+               } else if (ch == '.' && saw_digit) {
+                       if (octets == 4)
+                               return (0);
+                       *++tp = 0;
+                       saw_digit = 0;
+               } else
+                       return (0);
+       }
+       if (octets < 4)
+               return (0);
+       memcpy(dst, tmp, NS_INADDRSZ);
+       return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ *     convert presentation level address to network order binary form.
+ * return:
+ *     1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ *     (1) does not touch `dst' unless it's returning 1.
+ *     (2) :: in a full address is silently ignored.
+ * credit:
+ *     inspired by Mark Andrews.
+ * author:
+ *     Paul Vixie, 1996.
+ */
+static int
+inet_pton6(src, dst)
+       const char *src;
+       u_char *dst;
+{
+       static const char xdigits_l[] = "0123456789abcdef",
+                         xdigits_u[] = "0123456789ABCDEF";
+       u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+       const char *xdigits, *curtok;
+       int ch, seen_xdigits;
+       u_int val;
+
+       memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+       endp = tp + NS_IN6ADDRSZ;
+       colonp = NULL;
+       /* Leading :: requires some special handling. */
+       if (*src == ':')
+               if (*++src != ':')
+                       return (0);
+       curtok = src;
+       seen_xdigits = 0;
+       val = 0;
+       while ((ch = *src++) != '\0') {
+               const char *pch;
+
+               if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+                       pch = strchr((xdigits = xdigits_u), ch);
+               if (pch != NULL) {
+                       val <<= 4;
+                       val |= (pch - xdigits);
+                       if (++seen_xdigits > 4)
+                               return (0);
+                       continue;
+               }
+               if (ch == ':') {
+                       curtok = src;
+                       if (!seen_xdigits) {
+                               if (colonp)
+                                       return (0);
+                               colonp = tp;
+                               continue;
+                       } else if (*src == '\0') {
+                               return (0);
+                       }
+                       if (tp + NS_INT16SZ > endp)
+                               return (0);
+                       *tp++ = (u_char) (val >> 8) & 0xff;
+                       *tp++ = (u_char) val & 0xff;
+                       seen_xdigits = 0;
+                       val = 0;
+                       continue;
+               }
+               if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+                   inet_pton4(curtok, tp) > 0) {
+                       tp += NS_INADDRSZ;
+                       seen_xdigits = 0;
+                       break;  /* '\0' was seen by inet_pton4(). */
+               }
+               return (0);
+       }
+       if (seen_xdigits) {
+               if (tp + NS_INT16SZ > endp)
+                       return (0);
+               *tp++ = (u_char) (val >> 8) & 0xff;
+               *tp++ = (u_char) val & 0xff;
+       }
+       if (colonp != NULL) {
+               /*
+                * Since some memmove()'s erroneously fail to handle
+                * overlapping regions, we'll do the shift by hand.
+                */
+               const int n = tp - colonp;
+               int i;
+
+               if (tp == endp)
+                       return (0);
+               for (i = 1; i <= n; i++) {
+                       endp[- i] = colonp[n - i];
+                       colonp[n - i] = 0;
+               }
+               tp = endp;
+       }
+       if (tp != endp)
+               return (0);
+       memcpy(dst, tmp, NS_IN6ADDRSZ);
+       return (1);
+}
+
+#endif /* HAVE_INET_PTON */