1/* 2 * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 2001, 2002 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: getaddresses.c,v 1.22 2007/06/19 23:47:16 tbox Exp $ */ 19 20/*! \file */ 21 22#include <config.h> 23#include <string.h> 24 25#include <isc/net.h> 26#include <isc/netaddr.h> 27#include <isc/netdb.h> 28#include <isc/netscope.h> 29#include <isc/result.h> 30#include <isc/sockaddr.h> 31#include <isc/util.h> 32 33#include <bind9/getaddresses.h> 34 35#ifdef HAVE_ADDRINFO 36#ifdef HAVE_GETADDRINFO 37#ifdef HAVE_GAISTRERROR 38#define USE_GETADDRINFO 39#endif 40#endif 41#endif 42 43#ifndef USE_GETADDRINFO 44#ifndef ISC_PLATFORM_NONSTDHERRNO 45extern int h_errno; 46#endif 47#endif 48 49isc_result_t 50bind9_getaddresses(const char *hostname, in_port_t port, 51 isc_sockaddr_t *addrs, int addrsize, int *addrcount) 52{ 53 struct in_addr in4; 54 struct in6_addr in6; 55 isc_boolean_t have_ipv4, have_ipv6; 56 int i; 57 58#ifdef USE_GETADDRINFO 59 struct addrinfo *ai = NULL, *tmpai, hints; 60 int result; 61#else 62 struct hostent *he; 63#endif 64 65 REQUIRE(hostname != NULL); 66 REQUIRE(addrs != NULL); 67 REQUIRE(addrcount != NULL); 68 REQUIRE(addrsize > 0); 69 70 have_ipv4 = ISC_TF((isc_net_probeipv4() == ISC_R_SUCCESS)); 71 have_ipv6 = ISC_TF((isc_net_probeipv6() == ISC_R_SUCCESS)); 72 73 /* 74 * Try IPv4, then IPv6. In order to handle the extended format 75 * for IPv6 scoped addresses (address%scope_ID), we'll use a local 76 * working buffer of 128 bytes. The length is an ad-hoc value, but 77 * should be enough for this purpose; the buffer can contain a string 78 * of at least 80 bytes for scope_ID in addition to any IPv6 numeric 79 * addresses (up to 46 bytes), the delimiter character and the 80 * terminating NULL character. 81 */ 82 if (inet_pton(AF_INET, hostname, &in4) == 1) { 83 if (have_ipv4) 84 isc_sockaddr_fromin(&addrs[0], &in4, port); 85 else 86 isc_sockaddr_v6fromin(&addrs[0], &in4, port); 87 *addrcount = 1; 88 return (ISC_R_SUCCESS); 89 } else if (strlen(hostname) <= 127U) { 90 char tmpbuf[128], *d; 91 isc_uint32_t zone = 0; 92 93 strcpy(tmpbuf, hostname); 94 d = strchr(tmpbuf, '%'); 95 if (d != NULL) 96 *d = '\0'; 97 98 if (inet_pton(AF_INET6, tmpbuf, &in6) == 1) { 99 isc_netaddr_t na; 100 101 if (!have_ipv6) 102 return (ISC_R_FAMILYNOSUPPORT); 103 104 if (d != NULL) { 105#ifdef ISC_PLATFORM_HAVESCOPEID 106 isc_result_t result; 107 108 result = isc_netscope_pton(AF_INET6, d + 1, 109 &in6, &zone); 110 111 if (result != ISC_R_SUCCESS) 112 return (result); 113#else 114 /* 115 * The extended format is specified while the 116 * system does not provide the ability to use 117 * it. Throw an explicit error instead of 118 * ignoring the specified value. 119 */ 120 return (ISC_R_BADADDRESSFORM); 121#endif 122 } 123 124 isc_netaddr_fromin6(&na, &in6); 125 isc_netaddr_setzone(&na, zone); 126 isc_sockaddr_fromnetaddr(&addrs[0], 127 (const isc_netaddr_t *)&na, 128 port); 129 130 *addrcount = 1; 131 return (ISC_R_SUCCESS); 132 133 } 134 } 135#ifdef USE_GETADDRINFO 136 memset(&hints, 0, sizeof(hints)); 137 if (!have_ipv6) 138 hints.ai_family = PF_INET; 139 else if (!have_ipv4) 140 hints.ai_family = PF_INET6; 141 else { 142 hints.ai_family = PF_UNSPEC; 143#ifdef AI_ADDRCONFIG 144 hints.ai_flags = AI_ADDRCONFIG; 145#endif 146 } 147 hints.ai_socktype = SOCK_STREAM; 148#ifdef AI_ADDRCONFIG 149 again: 150#endif 151 result = getaddrinfo(hostname, NULL, &hints, &ai); 152 switch (result) { 153 case 0: 154 break; 155 case EAI_NONAME: 156#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) 157 case EAI_NODATA: 158#endif 159 return (ISC_R_NOTFOUND); 160#ifdef AI_ADDRCONFIG 161 case EAI_BADFLAGS: 162 if ((hints.ai_flags & AI_ADDRCONFIG) != 0) { 163 hints.ai_flags &= ~AI_ADDRCONFIG; 164 goto again; 165 } 166#endif 167 default: 168 return (ISC_R_FAILURE); 169 } 170 for (tmpai = ai, i = 0; 171 tmpai != NULL && i < addrsize; 172 tmpai = tmpai->ai_next) 173 { 174 if (tmpai->ai_family != AF_INET && 175 tmpai->ai_family != AF_INET6) 176 continue; 177 if (tmpai->ai_family == AF_INET) { 178 struct sockaddr_in *sin; 179 sin = (struct sockaddr_in *)tmpai->ai_addr; 180 isc_sockaddr_fromin(&addrs[i], &sin->sin_addr, port); 181 } else { 182 struct sockaddr_in6 *sin6; 183 sin6 = (struct sockaddr_in6 *)tmpai->ai_addr; 184 isc_sockaddr_fromin6(&addrs[i], &sin6->sin6_addr, 185 port); 186 } 187 i++; 188 189 } 190 freeaddrinfo(ai); 191 *addrcount = i; 192#else 193 he = gethostbyname(hostname); 194 if (he == NULL) { 195 switch (h_errno) { 196 case HOST_NOT_FOUND: 197#ifdef NO_DATA 198 case NO_DATA: 199#endif 200#if defined(NO_ADDRESS) && (!defined(NO_DATA) || (NO_DATA != NO_ADDRESS)) 201 case NO_ADDRESS: 202#endif 203 return (ISC_R_NOTFOUND); 204 default: 205 return (ISC_R_FAILURE); 206 } 207 } 208 if (he->h_addrtype != AF_INET && he->h_addrtype != AF_INET6) 209 return (ISC_R_NOTFOUND); 210 for (i = 0; i < addrsize; i++) { 211 if (he->h_addrtype == AF_INET) { 212 struct in_addr *inp; 213 inp = (struct in_addr *)(he->h_addr_list[i]); 214 if (inp == NULL) 215 break; 216 isc_sockaddr_fromin(&addrs[i], inp, port); 217 } else { 218 struct in6_addr *in6p; 219 in6p = (struct in6_addr *)(he->h_addr_list[i]); 220 if (in6p == NULL) 221 break; 222 isc_sockaddr_fromin6(&addrs[i], in6p, port); 223 } 224 } 225 *addrcount = i; 226#endif 227 if (*addrcount == 0) 228 return (ISC_R_NOTFOUND); 229 else 230 return (ISC_R_SUCCESS); 231} 232