getaddresses.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005, 2007, 2014, 2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 2001, 2002  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id: getaddresses.c,v 1.22 2007/06/19 23:47:16 tbox Exp $ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 #include <string.h>
00024 
00025 #include <isc/net.h>
00026 #include <isc/netaddr.h>
00027 #include <isc/netdb.h>
00028 #include <isc/netscope.h>
00029 #include <isc/result.h>
00030 #include <isc/sockaddr.h>
00031 #include <isc/util.h>
00032 
00033 #include <bind9/getaddresses.h>
00034 
00035 #ifdef HAVE_ADDRINFO
00036 #ifdef HAVE_GETADDRINFO
00037 #ifdef HAVE_GAISTRERROR
00038 #define USE_GETADDRINFO
00039 #endif
00040 #endif
00041 #endif
00042 
00043 #ifndef USE_GETADDRINFO
00044 #ifndef ISC_PLATFORM_NONSTDHERRNO
00045 extern int h_errno;
00046 #endif
00047 #endif
00048 
00049 isc_result_t
00050 bind9_getaddresses(const char *hostname, in_port_t port,
00051                    isc_sockaddr_t *addrs, int addrsize, int *addrcount)
00052 {
00053         struct in_addr in4;
00054         struct in6_addr in6;
00055         isc_boolean_t have_ipv4, have_ipv6;
00056         int i;
00057 
00058 #ifdef USE_GETADDRINFO
00059         struct addrinfo *ai = NULL, *tmpai, hints;
00060         int result;
00061 #else
00062         struct hostent *he;
00063 #endif
00064 
00065         REQUIRE(hostname != NULL);
00066         REQUIRE(addrs != NULL);
00067         REQUIRE(addrcount != NULL);
00068         REQUIRE(addrsize > 0);
00069 
00070         have_ipv4 = ISC_TF((isc_net_probeipv4() == ISC_R_SUCCESS));
00071         have_ipv6 = ISC_TF((isc_net_probeipv6() == ISC_R_SUCCESS));
00072 
00073         /*
00074          * Try IPv4, then IPv6.  In order to handle the extended format
00075          * for IPv6 scoped addresses (address%scope_ID), we'll use a local
00076          * working buffer of 128 bytes.  The length is an ad-hoc value, but
00077          * should be enough for this purpose; the buffer can contain a string
00078          * of at least 80 bytes for scope_ID in addition to any IPv6 numeric
00079          * addresses (up to 46 bytes), the delimiter character and the
00080          * terminating NULL character.
00081          */
00082         if (inet_pton(AF_INET, hostname, &in4) == 1) {
00083                 if (have_ipv4)
00084                         isc_sockaddr_fromin(&addrs[0], &in4, port);
00085                 else
00086                         isc_sockaddr_v6fromin(&addrs[0], &in4, port);
00087                 *addrcount = 1;
00088                 return (ISC_R_SUCCESS);
00089         } else if (strlen(hostname) <= 127U) {
00090                 char tmpbuf[128], *d;
00091                 isc_uint32_t zone = 0;
00092 
00093                 strcpy(tmpbuf, hostname);
00094                 d = strchr(tmpbuf, '%');
00095                 if (d != NULL)
00096                         *d = '\0';
00097 
00098                 if (inet_pton(AF_INET6, tmpbuf, &in6) == 1) {
00099                         isc_netaddr_t na;
00100 
00101                         if (!have_ipv6)
00102                                 return (ISC_R_FAMILYNOSUPPORT);
00103 
00104                         if (d != NULL) {
00105 #ifdef ISC_PLATFORM_HAVESCOPEID
00106                                 isc_result_t iresult;
00107 
00108                                 iresult = isc_netscope_pton(AF_INET6, d + 1,
00109                                                             &in6, &zone);
00110 
00111                                 if (iresult != ISC_R_SUCCESS)
00112                                         return (iresult);
00113 #else
00114                                 /*
00115                                  * The extended format is specified while the
00116                                  * system does not provide the ability to use
00117                                  * it.  Throw an explicit error instead of
00118                                  * ignoring the specified value.
00119                                  */
00120                                 return (ISC_R_BADADDRESSFORM);
00121 #endif
00122                         }
00123 
00124                         isc_netaddr_fromin6(&na, &in6);
00125                         isc_netaddr_setzone(&na, zone);
00126                         isc_sockaddr_fromnetaddr(&addrs[0],
00127                                                  (const isc_netaddr_t *)&na,
00128                                                  port);
00129 
00130                         *addrcount = 1;
00131                         return (ISC_R_SUCCESS);
00132                 }
00133         }
00134 #ifdef USE_GETADDRINFO
00135         memset(&hints, 0, sizeof(hints));
00136         if (!have_ipv6)
00137                 hints.ai_family = PF_INET;
00138         else if (!have_ipv4)
00139                 hints.ai_family = PF_INET6;
00140         else {
00141                 hints.ai_family = PF_UNSPEC;
00142 #ifdef AI_ADDRCONFIG
00143                 hints.ai_flags = AI_ADDRCONFIG;
00144 #endif
00145         }
00146         hints.ai_socktype = SOCK_STREAM;
00147 #ifdef AI_ADDRCONFIG
00148  again:
00149 #endif
00150         result = getaddrinfo(hostname, NULL, &hints, &ai);
00151         switch (result) {
00152         case 0:
00153                 break;
00154         case EAI_NONAME:
00155 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
00156         case EAI_NODATA:
00157 #endif
00158                 return (ISC_R_NOTFOUND);
00159 #ifdef AI_ADDRCONFIG
00160         case EAI_BADFLAGS:
00161                 if ((hints.ai_flags & AI_ADDRCONFIG) != 0) {
00162                         hints.ai_flags &= ~AI_ADDRCONFIG;
00163                         goto again;
00164                 }
00165 #endif
00166         default:
00167                 return (ISC_R_FAILURE);
00168         }
00169         for (tmpai = ai, i = 0;
00170              tmpai != NULL && i < addrsize;
00171              tmpai = tmpai->ai_next)
00172         {
00173                 if (tmpai->ai_family != AF_INET &&
00174                     tmpai->ai_family != AF_INET6)
00175                         continue;
00176                 if (tmpai->ai_family == AF_INET) {
00177                         struct sockaddr_in *sin;
00178                         sin = (struct sockaddr_in *)tmpai->ai_addr;
00179                         isc_sockaddr_fromin(&addrs[i], &sin->sin_addr, port);
00180                 } else {
00181                         struct sockaddr_in6 *sin6;
00182                         sin6 = (struct sockaddr_in6 *)tmpai->ai_addr;
00183                         isc_sockaddr_fromin6(&addrs[i], &sin6->sin6_addr,
00184                                              port);
00185                 }
00186                 i++;
00187 
00188         }
00189         freeaddrinfo(ai);
00190         *addrcount = i;
00191 #else
00192         he = gethostbyname(hostname);
00193         if (he == NULL) {
00194                 switch (h_errno) {
00195                 case HOST_NOT_FOUND:
00196 #ifdef NO_DATA
00197                 case NO_DATA:
00198 #endif
00199 #if defined(NO_ADDRESS) && (!defined(NO_DATA) || (NO_DATA != NO_ADDRESS))
00200                 case NO_ADDRESS:
00201 #endif
00202                         return (ISC_R_NOTFOUND);
00203                 default:
00204                         return (ISC_R_FAILURE);
00205                 }
00206         }
00207         if (he->h_addrtype != AF_INET && he->h_addrtype != AF_INET6)
00208                 return (ISC_R_NOTFOUND);
00209         for (i = 0; i < addrsize; i++) {
00210                 if (he->h_addrtype == AF_INET) {
00211                         struct in_addr *inp;
00212                         inp = (struct in_addr *)(he->h_addr_list[i]);
00213                         if (inp == NULL)
00214                                 break;
00215                         isc_sockaddr_fromin(&addrs[i], inp, port);
00216                 } else {
00217                         struct in6_addr *in6p;
00218                         in6p = (struct in6_addr *)(he->h_addr_list[i]);
00219                         if (in6p == NULL)
00220                                 break;
00221                         isc_sockaddr_fromin6(&addrs[i], in6p, port);
00222                 }
00223         }
00224         *addrcount = i;
00225 #endif
00226         if (*addrcount == 0)
00227                 return (ISC_R_NOTFOUND);
00228         else
00229                 return (ISC_R_SUCCESS);
00230 }

Generated on Tue Apr 28 17:40:55 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha