--------------------- PatchSet 5348 Date: 2007/08/16 10:05:43 Author: amosjeffries Branch: squid3-ipv6 Tag: (none) Log: Non-IPv6 capable OS fixes. - Adds getnameinfo() from KAME - Hacks imported getaddrinfo() to use gethostbyname() (was doing gethostbyname_r repalcement hacks. nasty) - Updates configure.in to do proper function tests and include custom code only if needed. Squid now needs to use xgetaddrinfo(), xfreeaddrinfo(), xgai_strerror(), and xgetnameinfo() globally to pull the right overloaded version. Members: configure.in:1.63.2.35->1.63.2.36 lib/Makefile.am:1.12.4.9->1.12.4.10 lib/getaddrinfo.c:1.1.2.2->1.1.2.3 lib/getaddrinfo.h:1.1.2.2->1.1.2.3 lib/gethostbyname.c:1.1.2.1->1.1.2.2(DEAD) lib/getnameinfo.c:1.1->1.1.2.1 Index: squid3/configure.in =================================================================== RCS file: /cvsroot/squid-sf//squid3/configure.in,v retrieving revision 1.63.2.35 retrieving revision 1.63.2.36 diff -u -r1.63.2.35 -r1.63.2.36 --- squid3/configure.in 15 Aug 2007 05:16:38 -0000 1.63.2.35 +++ squid3/configure.in 16 Aug 2007 10:05:43 -0000 1.63.2.36 @@ -1,7 +1,7 @@ dnl Configuration input file for Squid dnl -dnl $Id: configure.in,v 1.63.2.35 2007/08/15 05:16:38 amosjeffries Exp $ +dnl $Id: configure.in,v 1.63.2.36 2007/08/16 10:05:43 amosjeffries Exp $ dnl dnl dnl @@ -11,7 +11,7 @@ AC_CONFIG_AUX_DIR(cfgaux) AC_CONFIG_SRCDIR([src/main.cc]) AM_INIT_AUTOMAKE([tar-ustar]) -AC_REVISION($Revision: 1.63.2.35 $)dnl +AC_REVISION($Revision: 1.63.2.36 $)dnl AC_PREFIX_DEFAULT(/usr/local/squid) AM_MAINTAINER_MODE @@ -220,12 +220,6 @@ fi fi -dnsl Search for OS support of IPNG functions -AC_SEARCH_LIBS(getaddrinfo, inet6, - AC_DEFINE(HAVE_GETADDRINFO,1,[define to 1 if you have the getaddrinfo function]), - AC_DEFINE(HAVE_GETADDRINFO,0,[define to 0 if you need teh getaddrinfo function]) -) - dnl Enable optional modules AC_ARG_ENABLE(dlmalloc, [ --enable-dlmalloc[=LIB] Compile & use the malloc package by Doug Lea], @@ -1822,12 +1816,18 @@ dnl Enable IPv6 support AC_MSG_CHECKING([whether to enable IPv6]) +dnl Search for OS support of IP Next Generation functions +AC_CHECK_FUNC(getaddrinfo,[ AC_MSG_RESULT([yes]) ],[ AC_LIBOBJ(getaddrinfo) ]) +AC_CHECK_FUNC(getnameinfo,[ AC_MSG_RESULT([yes]) ],[ AC_LIBOBJ(getnameinfo) ]) + +dnl Check for Windows XP option AC_ARG_WITH(ipv6-split-stack, [ --with-ipv6-split-stack Require IPv6 split-stack support (Requires IPv6 Support)], AC_DEFINE(USE_IPV6_SPLITSTACK, 1, [Enable support for Split-Stack IPv6 Implementations]) , AC_DEFINE(USE_IPV6_SPLITSTACK, 0, [No support for split-stack IPv6 Implementations]) ) +dnl Check for IPv6 Windows Vista option AC_ARG_WITH(ipv4-mapped, [ --with-ipv4-mapped Hybrid-Stack OS require Squid to do any v4-mapping (Requires IPv6 Support)], AC_DEFINE(IPV6_SPECIAL_V4MAPPING, 1, [Perform v4-mapping Internally]) , Index: squid3/lib/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid3/lib/Makefile.am,v retrieving revision 1.12.4.9 retrieving revision 1.12.4.10 diff -u -r1.12.4.9 -r1.12.4.10 --- squid3/lib/Makefile.am 15 Aug 2007 05:16:38 -0000 1.12.4.9 +++ squid3/lib/Makefile.am 16 Aug 2007 10:05:44 -0000 1.12.4.10 @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in # -# $Id: Makefile.am,v 1.12.4.9 2007/08/15 05:16:38 amosjeffries Exp $ +# $Id: Makefile.am,v 1.12.4.10 2007/08/16 10:05:44 amosjeffries Exp $ # DIST_SUBDIRS = libTrie @@ -62,8 +62,6 @@ MemPool.cc \ base64.c \ getfullhostname.c \ - getaddrinfo.c \ - gethostbyname.c \ hash.c \ heap.c \ html_quote.c \ Index: squid3/lib/getaddrinfo.c =================================================================== RCS file: /cvsroot/squid-sf//squid3/lib/Attic/getaddrinfo.c,v retrieving revision 1.1.2.2 retrieving revision 1.1.2.3 diff -u -r1.1.2.2 -r1.1.2.3 --- squid3/lib/getaddrinfo.c 15 Aug 2007 05:19:51 -0000 1.1.2.2 +++ squid3/lib/getaddrinfo.c 16 Aug 2007 10:05:44 -0000 1.1.2.3 @@ -7,13 +7,15 @@ * 15-Aug-2007 : Copied from fetchmail 6.3.8 * - added protection around libray headers * - * Squid CVS $Id: getaddrinfo.c,v 1.1.2.2 2007/08/15 05:19:51 amosjeffries Exp $ + * 16-Aug-2007 : Altered configure checks + * Un-hacked slightly to use system gethostbyname() + * + * Squid CVS $Id: getaddrinfo.c,v 1.1.2.3 2007/08/16 10:05:44 amosjeffries Exp $ * * Original License and code follows. */ #include "config.h" -#if !HAVE_GETADDRINFO /* * This file is part of libESMTP, a library for submission of RFC 2822 * formatted electronic mail messages using the SMTP protocol described @@ -39,11 +41,7 @@ /* An emulation of the RFC 2553 / Posix getaddrinfo resolver interface. */ -#if HAVE_CONFIG_H -#include -#endif - -// #ifndef HAVE_GETADDRINFO +#ifndef HAVE_GETADDRINFO /* Need to turn off Posix features in glibc to build this */ #undef _POSIX_C_SOURCE @@ -75,7 +73,10 @@ #include #endif +#ifndef HAVE_GETHOSTBYNAME #include "gethostbyname.h" +#endif + #include "getaddrinfo.h" static struct addrinfo * @@ -99,7 +100,7 @@ } int -getaddrinfo (const char *nodename, const char *servname, +xgetaddrinfo (const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { struct hostent *hp; @@ -108,10 +109,12 @@ int port; struct addrinfo hint, result; struct addrinfo *ai, *sai, *eai; - struct ghbnctx ghbnctx; char **addrs; int code; + if (servname == NULL && nodename == NULL) + return EAI_NONAME; + memset (&result, 0, sizeof result); /* default for hints */ @@ -122,9 +125,6 @@ hints = &hint; } - if (servname == NULL && nodename == NULL) - return EAI_NONAME; - if (servname == NULL) port = 0; else { @@ -190,29 +190,26 @@ return (*res == NULL) ? EAI_MEMORY : 0; } + h_errno = 0; errno = 0; - hp = gethostbyname_ctx (nodename, &ghbnctx); + hp = gethostbyname(nodename); if (hp == NULL) { - if (errno != 0) - { - free_ghbnctx (&ghbnctx); - return EAI_SYSTEM; - } - code = h_error_ctx (&ghbnctx); - switch (code) - { - case HOST_NOT_FOUND: code = EAI_NODATA; break; - case NO_DATA: code = EAI_NODATA; break; + if (errno != 0) { + return EAI_SYSTEM; + } + 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: code = EAI_NODATA; break; + case NO_ADDRESS: return EAI_NODATA; #endif - case NO_RECOVERY: code = EAI_FAIL; break; - case TRY_AGAIN: code = EAI_AGAIN; break; - default: code = EAI_FAIL; break; - } - free_ghbnctx (&ghbnctx); - return code; + 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. @@ -221,17 +218,15 @@ { case AF_INET: if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET)) - goto eai_family; + return EAI_FAMILY; break; -#ifdef USE_IPV6 +#if USE_IPV6 case AF_INET6: if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET6)) - goto eai_family; + return EAI_FAMILY; break; #endif default: - eai_family: - free_ghbnctx (&ghbnctx); return EAI_FAMILY; } @@ -254,7 +249,7 @@ *addrs, hp->h_length); addrlen = sizeof (struct sockaddr_in); break; -#ifdef USE_IPV6 +#if USE_IPV6 case AF_INET6: # if SIN6_LEN ((struct sockaddr_in6 *) &sa)->sin6_len = hp->h_length; @@ -273,7 +268,6 @@ ai = dup_addrinfo (&result, &sa, addrlen); if (ai == NULL) { - free_ghbnctx (&ghbnctx); freeaddrinfo (sai); return EAI_MEMORY; } @@ -286,7 +280,6 @@ if (sai == NULL) { - free_ghbnctx (&ghbnctx); return EAI_NODATA; } @@ -295,20 +288,18 @@ sai->ai_canonname = malloc (strlen (hp->h_name) + 1); if (sai->ai_canonname == NULL) { - free_ghbnctx (&ghbnctx); freeaddrinfo (sai); return EAI_MEMORY; } strcpy (sai->ai_canonname, hp->h_name); } - free_ghbnctx (&ghbnctx); *res = sai; return 0; } void -freeaddrinfo (struct addrinfo *ai) +xfreeaddrinfo (struct addrinfo *ai) { struct addrinfo *next; @@ -325,7 +316,7 @@ } const char * -gai_strerror (int ecode) +xgai_strerror (int ecode) { static const char *eai_descr[] = { Index: squid3/lib/getaddrinfo.h =================================================================== RCS file: /cvsroot/squid-sf//squid3/lib/Attic/getaddrinfo.h,v retrieving revision 1.1.2.2 retrieving revision 1.1.2.3 diff -u -r1.1.2.2 -r1.1.2.3 --- squid3/lib/getaddrinfo.h 15 Aug 2007 05:19:51 -0000 1.1.2.2 +++ squid3/lib/getaddrinfo.h 16 Aug 2007 10:05:44 -0000 1.1.2.3 @@ -10,16 +10,16 @@ * 15-Aug-2007 : Copied from fetchmail 6.3.8 * - added protection around libray headers * - * Squid CVS $Id: getaddrinfo.h,v 1.1.2.2 2007/08/15 05:19:51 amosjeffries Exp $ + * 16-Aug-2007 : Altered configure checks + * Un-hacked slightly to use system gethostbyname() + * + * Squid CVS $Id: getaddrinfo.h,v 1.1.2.3 2007/08/16 10:05:44 amosjeffries Exp $ * * Original License and code follows. */ #include "config.h" - /* DO NOT define anything if getaddrinfo is provided. */ -#if !HAVE_GETADDRINFO - /* * This file is part of libESMTP, a library for submission of RFC 2822 * formatted electronic mail messages using the SMTP protocol described @@ -42,10 +42,16 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Structure and prototypes aken from RFC 2553 */ +/* 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 -#include -// #ifndef HAVE_GETADDRINFO +#else /* !HAVE_GETADDRINFO */ struct addrinfo { @@ -79,14 +85,15 @@ #define EAI_OVERFLOW 12 /* argument buffer too small */ /* RFC 2553 / Posix resolver */ -int getaddrinfo (const char *nodename, const char *servname, +int xgetaddrinfo (const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res); /* Free addrinfo structure and associated storage */ -void freeaddrinfo (struct addrinfo *ai); +void xfreeaddrinfo (struct addrinfo *ai); /* Convert error return from getaddrinfo() to string */ -const char *gai_strerror (int code); +const char *xgai_strerror (int code); -#endif #endif /* HAVE_GETADDRINFO */ + +#endif --- squid3/lib/gethostbyname.c Fri Aug 17 00:21:01 2007 +++ /dev/null Fri Aug 17 00:21:01 2007 @@ -1,255 +0,0 @@ -/* - * 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 - * - * Squid CVS $Id: gethostbyname.c,v 1.1.2.1 2007/08/15 05:16:38 amosjeffries Exp $ - * - * Original License and code follows. - */ -#include "config.h" - -#if !HAVE_GETADDRINFO -/* - * This file is a ghastly hack because nobody can agree on - * gethostbyname_r()'s prototype. - * - * Copyright (C) 2001,2002 Brian Stafford - * - * 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 - */ - -#if HAVE_CONFIG_H -#include -#endif - -#define _SVID_SOURCE 1 /* Need this to get gethostbyname_r() */ - -#if HAVE_ASSERT_H -#include -#endif -#if HAVE_STDLIB_H -#include -#endif -#if HAVE_STRING_H -#include -#endif -#if HAVE_NETDB_H -#include -#endif -#if HAVE_ERRNO_H -#include -#endif - -#include "gethostbyname.h" - -#if HAVE_GETIPNODEBYNAME - -void -free_ghbnctx (struct ghbnctx *ctx) -{ - assert (ctx != NULL); - - if (ctx->hostent != NULL) - freehostent (ctx->hostent); -} - -struct hostent * -gethostbyname_ctx (const char *host, struct ghbnctx *ctx) -{ - assert (ctx != NULL); - - memset (ctx, 0, sizeof (struct ghbnctx)); - ctx->hostent = getipnodebyname (host, AF_UNSPEC, AI_ADDRCONFIG, &ctx->h_err); - return ctx->hostent; -} - -int -h_error_ctx (struct ghbnctx *ctx) -{ - assert (ctx != NULL); - - return ctx->h_err; -} - -#elif HAVE_GETHOSTBYNAME_R == 6 - -void -free_ghbnctx (struct ghbnctx *ctx) -{ - assert (ctx != NULL); - - if (ctx->hostbuf != NULL) - free (ctx->hostbuf); -} - -struct hostent * -gethostbyname_ctx (const char *host, struct ghbnctx *ctx) -{ - struct hostent *hp; - char *tmp; - int err; - - assert (ctx != NULL); - - memset (ctx, 0, sizeof (struct ghbnctx)); - ctx->hostbuf_len = 2048; - if ((ctx->hostbuf = (char *)malloc (ctx->hostbuf_len)) == NULL) - { - errno = ENOMEM; - return NULL; - } - while ((err = gethostbyname_r (host, - &ctx->hostent, ctx->hostbuf, ctx->hostbuf_len, - &hp, &ctx->h_err)) == ERANGE) - { - ctx->hostbuf_len += 1024; - if ((tmp = (char *)realloc (ctx->hostbuf, ctx->hostbuf_len)) == NULL) - { - errno = ENOMEM; - return NULL; - } - ctx->hostbuf = tmp; - } - if (err != 0) - { - errno = err; - return NULL; - } - return hp; -} - -int -h_error_ctx (struct ghbnctx *ctx) -{ - assert (ctx != NULL); - - return ctx->h_err; -} - -#elif HAVE_GETHOSTBYNAME_R == 5 - -void -free_ghbnctx (struct ghbnctx *ctx) -{ - assert (ctx != NULL); - - if (ctx->hostbuf != NULL) - free (ctx->hostbuf); -} - -struct hostent * -gethostbyname_ctx (const char *host, struct ghbnctx *ctx) -{ - struct hostent *hp; - char *tmp; - - assert (ctx != NULL); - - memset (ctx, 0, sizeof (struct ghbnctx)); - ctx->hostbuf_len = 2048; - if ((ctx->hostbuf = malloc (ctx->hostbuf_len)) == NULL) - { - errno = ENOMEM; - return NULL; - } - while ((hp = gethostbyname_r (host, &ctx->hostent, - ctx->hostbuf, ctx->hostbuf_len, - &ctx->h_err)) == NULL && errno == ERANGE) - { - ctx->hostbuf_len += 1024; - if ((tmp = realloc (ctx->hostbuf, ctx->hostbuf_len)) == NULL) - { - errno = ENOMEM; - return NULL; - } - ctx->hostbuf = tmp; - } - return hp; -} - -int -h_error_ctx (struct ghbnctx *ctx) -{ - assert (ctx != NULL); - - return ctx->h_err; -} - -#elif HAVE_GETHOSTBYNAME_R == 3 - -void -free_ghbnctx (struct ghbnctx *ctx) -{ - assert (ctx != NULL); - - /* FIXME: does this need to do anything? */ -} - -struct hostent * -gethostbyname_ctx (const char *host, struct ghbnctx *ctx) -{ - assert (ctx != NULL); - - if (!gethostbyname_r (host, &ctx->hostent, &ctx->hostent_data)) - { - ctx->h_err = h_errno; /* FIXME: is this correct? */ - return NULL; - } - return &ctx->hostent; -} - -int -h_error_ctx (struct ghbnctx *ctx) -{ - assert (ctx != NULL); - - return ctx->h_err; -} - -#else - -void -free_ghbnctx (struct ghbnctx *ctx __attribute__ ((unused))) -{ - assert (ctx != NULL); -} - -struct hostent * -gethostbyname_ctx (const char *host, struct ghbnctx *ctx) -{ - struct hostent *hp; - - hp = gethostbyname (host); - if (hp == NULL) - ctx->h_err = h_errno; - return hp; -} - -int -h_error_ctx (struct ghbnctx *ctx) -{ - assert (ctx != NULL); - - return ctx->h_err; -} - -#endif - -#endif /* HAVE_GETADDRINFO */ --- /dev/null Fri Aug 17 00:21:01 2007 +++ squid3/lib/getnameinfo.c Fri Aug 17 00:21:01 2007 @@ -0,0 +1,427 @@ +/* + * 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. + * + * Squid CVS $Id: getnameinfo.c,v 1.1.2.1 2007/08/16 10:05:44 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. + */ + +#ifdef HAVE_GETNAMEINFO + +#define xgetnameinfo getnameinfo + +#else + +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_SYS_SOCKET_H +#include +#endif +#if HAVE_NET_IF_H +#include +#endif +#if HAVE_NETINET_IN_H +#include +#endif +#if HAVE_ARPA_INET_H +#include +#endif +#if HAVE_ARPA_NAMESER_H +#include +#endif +#if HAVE_NETDB_H +#include +#endif +#if HAVE_RESOLV_H +#include +#endif +#if HAVE_STRING_H +#include +#endif +#if HAVE_STDDEF_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_INTTYPES_H +#include +#endif + +#include "getaddrinfo.h" + +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; +#ifdef HAVE_SOCKLEN_T + socklen_t salen; +#else + unsigned int salen; +#endif + 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]; + char numaddr[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; + strlcpy(serv, sp->s_name, servlen); + } else { + snprintf(numserv, sizeof(numserv), "%u", ntohs(port)); + if (strlen(numserv) + 1 > servlen) + return EAI_OVERFLOW; + strlcpy(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; + } + strlcpy(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: +#ifdef HAVE_INET_NTOP + if (inet_ntop(afd->a_af, addr, host, + hostlen) == NULL) + return EAI_SYSTEM; +#else + if (afd->a_af == AF_INET) + strlcpy(host, inet_ntoa(addr), hostlen); + else + return EAI_FAMILY; +#endif + 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 (inet_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; + strlcpy(host, numaddr, hostlen); + + if (((const struct sockaddr_in6 *)sa)->sin6_scope_id) { + char zonebuf[MAXHOSTNAMELEN]; + 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 */ + 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