getaddresses.c revision 135446
1135446Strhodes/* 2135446Strhodes * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2001, 2002 Internet Software Consortium. 4135446Strhodes * 5135446Strhodes * Permission to use, copy, modify, and distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18135446Strhodes/* $Id: getaddresses.c,v 1.13.126.5 2004/05/15 03:46:12 jinmei Exp $ */ 19135446Strhodes 20135446Strhodes#include <config.h> 21135446Strhodes#include <string.h> 22135446Strhodes 23135446Strhodes#include <isc/net.h> 24135446Strhodes#include <isc/netaddr.h> 25135446Strhodes#include <isc/netdb.h> 26135446Strhodes#include <isc/netscope.h> 27135446Strhodes#include <isc/result.h> 28135446Strhodes#include <isc/sockaddr.h> 29135446Strhodes#include <isc/util.h> 30135446Strhodes 31135446Strhodes#include <bind9/getaddresses.h> 32135446Strhodes 33135446Strhodes#ifdef HAVE_ADDRINFO 34135446Strhodes#ifdef HAVE_GETADDRINFO 35135446Strhodes#ifdef HAVE_GAISTRERROR 36135446Strhodes#define USE_GETADDRINFO 37135446Strhodes#endif 38135446Strhodes#endif 39135446Strhodes#endif 40135446Strhodes 41135446Strhodes#ifndef USE_GETADDRINFO 42135446Strhodes#ifndef ISC_PLATFORM_NONSTDHERRNO 43135446Strhodesextern int h_errno; 44135446Strhodes#endif 45135446Strhodes#endif 46135446Strhodes 47135446Strhodesisc_result_t 48135446Strhodesbind9_getaddresses(const char *hostname, in_port_t port, 49135446Strhodes isc_sockaddr_t *addrs, int addrsize, int *addrcount) 50135446Strhodes{ 51135446Strhodes struct in_addr in4; 52135446Strhodes struct in6_addr in6; 53135446Strhodes isc_boolean_t have_ipv4, have_ipv6; 54135446Strhodes int i; 55135446Strhodes 56135446Strhodes#ifdef USE_GETADDRINFO 57135446Strhodes struct addrinfo *ai = NULL, *tmpai, hints; 58135446Strhodes int result; 59135446Strhodes#else 60135446Strhodes struct hostent *he; 61135446Strhodes#endif 62135446Strhodes 63135446Strhodes REQUIRE(hostname != NULL); 64135446Strhodes REQUIRE(addrs != NULL); 65135446Strhodes REQUIRE(addrcount != NULL); 66135446Strhodes REQUIRE(addrsize > 0); 67135446Strhodes 68135446Strhodes have_ipv4 = (isc_net_probeipv4() == ISC_R_SUCCESS); 69135446Strhodes have_ipv6 = (isc_net_probeipv6() == ISC_R_SUCCESS); 70135446Strhodes 71135446Strhodes /* 72135446Strhodes * Try IPv4, then IPv6. In order to handle the extended format 73135446Strhodes * for IPv6 scoped addresses (address%scope_ID), we'll use a local 74135446Strhodes * working buffer of 128 bytes. The length is an ad-hoc value, but 75135446Strhodes * should be enough for this purpose; the buffer can contain a string 76135446Strhodes * of at least 80 bytes for scope_ID in addition to any IPv6 numeric 77135446Strhodes * addresses (up to 46 bytes), the delimiter character and the 78135446Strhodes * terminating NULL character. 79135446Strhodes */ 80135446Strhodes if (inet_pton(AF_INET, hostname, &in4) == 1) { 81135446Strhodes if (have_ipv4) 82135446Strhodes isc_sockaddr_fromin(&addrs[0], &in4, port); 83135446Strhodes else 84135446Strhodes isc_sockaddr_v6fromin(&addrs[0], &in4, port); 85135446Strhodes *addrcount = 1; 86135446Strhodes return (ISC_R_SUCCESS); 87135446Strhodes } else if (strlen(hostname) <= 127) { 88135446Strhodes char tmpbuf[128], *d; 89135446Strhodes isc_uint32_t zone = 0; 90135446Strhodes 91135446Strhodes strcpy(tmpbuf, hostname); 92135446Strhodes d = strchr(tmpbuf, '%'); 93135446Strhodes if (d != NULL) 94135446Strhodes *d = '\0'; 95135446Strhodes 96135446Strhodes if (inet_pton(AF_INET6, tmpbuf, &in6) == 1) { 97135446Strhodes isc_netaddr_t na; 98135446Strhodes 99135446Strhodes if (!have_ipv6) 100135446Strhodes return (ISC_R_FAMILYNOSUPPORT); 101135446Strhodes 102135446Strhodes if (d != NULL) { 103135446Strhodes#ifdef ISC_PLATFORM_HAVESCOPEID 104135446Strhodes isc_result_t result; 105135446Strhodes 106135446Strhodes result = isc_netscope_pton(AF_INET6, d + 1, 107135446Strhodes &in6, &zone); 108135446Strhodes 109135446Strhodes if (result != ISC_R_SUCCESS) 110135446Strhodes return (result); 111135446Strhodes#else 112135446Strhodes /* 113135446Strhodes * The extended format is specified while the 114135446Strhodes * system does not provide the ability to use 115135446Strhodes * it. Throw an explicit error instead of 116135446Strhodes * ignoring the specified value. 117135446Strhodes */ 118135446Strhodes return (ISC_R_BADADDRESSFORM); 119135446Strhodes#endif 120135446Strhodes } 121135446Strhodes 122135446Strhodes isc_netaddr_fromin6(&na, &in6); 123135446Strhodes isc_netaddr_setzone(&na, zone); 124135446Strhodes isc_sockaddr_fromnetaddr(&addrs[0], 125135446Strhodes (const isc_netaddr_t *)&na, 126135446Strhodes port); 127135446Strhodes 128135446Strhodes *addrcount = 1; 129135446Strhodes return (ISC_R_SUCCESS); 130135446Strhodes 131135446Strhodes } 132135446Strhodes } 133135446Strhodes#ifdef USE_GETADDRINFO 134135446Strhodes memset(&hints, 0, sizeof(hints)); 135135446Strhodes if (!have_ipv6) 136135446Strhodes hints.ai_family = PF_INET; 137135446Strhodes else if (!have_ipv4) 138135446Strhodes hints.ai_family = PF_INET6; 139135446Strhodes else { 140135446Strhodes hints.ai_family = PF_UNSPEC; 141135446Strhodes#ifdef AI_ADDRCONFIG 142135446Strhodes hints.ai_flags = AI_ADDRCONFIG; 143135446Strhodes#endif 144135446Strhodes } 145135446Strhodes hints.ai_socktype = SOCK_STREAM; 146135446Strhodes#ifdef AI_ADDRCONFIG 147135446Strhodes again: 148135446Strhodes#endif 149135446Strhodes result = getaddrinfo(hostname, NULL, &hints, &ai); 150135446Strhodes switch (result) { 151135446Strhodes case 0: 152135446Strhodes break; 153135446Strhodes case EAI_NONAME: 154135446Strhodes#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) 155135446Strhodes case EAI_NODATA: 156135446Strhodes#endif 157135446Strhodes return (ISC_R_NOTFOUND); 158135446Strhodes#ifdef AI_ADDRCONFIG 159135446Strhodes case EAI_BADFLAGS: 160135446Strhodes if ((hints.ai_flags & AI_ADDRCONFIG) != 0) { 161135446Strhodes hints.ai_flags &= ~AI_ADDRCONFIG; 162135446Strhodes goto again; 163135446Strhodes } 164135446Strhodes#endif 165135446Strhodes default: 166135446Strhodes return (ISC_R_FAILURE); 167135446Strhodes } 168135446Strhodes for (tmpai = ai, i = 0; 169135446Strhodes tmpai != NULL && i < addrsize; 170135446Strhodes tmpai = tmpai->ai_next) 171135446Strhodes { 172135446Strhodes if (tmpai->ai_family != AF_INET && 173135446Strhodes tmpai->ai_family != AF_INET6) 174135446Strhodes continue; 175135446Strhodes if (tmpai->ai_family == AF_INET) { 176135446Strhodes struct sockaddr_in *sin; 177135446Strhodes sin = (struct sockaddr_in *)tmpai->ai_addr; 178135446Strhodes isc_sockaddr_fromin(&addrs[i], &sin->sin_addr, port); 179135446Strhodes } else { 180135446Strhodes struct sockaddr_in6 *sin6; 181135446Strhodes sin6 = (struct sockaddr_in6 *)tmpai->ai_addr; 182135446Strhodes isc_sockaddr_fromin6(&addrs[i], &sin6->sin6_addr, 183135446Strhodes port); 184135446Strhodes } 185135446Strhodes i++; 186135446Strhodes 187135446Strhodes } 188135446Strhodes freeaddrinfo(ai); 189135446Strhodes *addrcount = i; 190135446Strhodes#else 191135446Strhodes he = gethostbyname(hostname); 192135446Strhodes if (he == NULL) { 193135446Strhodes switch (h_errno) { 194135446Strhodes case HOST_NOT_FOUND: 195135446Strhodes#ifdef NO_DATA 196135446Strhodes case NO_DATA: 197135446Strhodes#endif 198135446Strhodes#if defined(NO_ADDRESS) && (!defined(NO_DATA) || (NO_DATA != NO_ADDRESS)) 199135446Strhodes case NO_ADDRESS: 200135446Strhodes#endif 201135446Strhodes return (ISC_R_NOTFOUND); 202135446Strhodes default: 203135446Strhodes return (ISC_R_FAILURE); 204135446Strhodes } 205135446Strhodes } 206135446Strhodes if (he->h_addrtype != AF_INET && he->h_addrtype != AF_INET6) 207135446Strhodes return (ISC_R_NOTFOUND); 208135446Strhodes for (i = 0; i < addrsize; i++) { 209135446Strhodes if (he->h_addrtype == AF_INET) { 210135446Strhodes struct in_addr *inp; 211135446Strhodes inp = (struct in_addr *)(he->h_addr_list[i]); 212135446Strhodes if (inp == NULL) 213135446Strhodes break; 214135446Strhodes isc_sockaddr_fromin(&addrs[i], inp, port); 215135446Strhodes } else { 216135446Strhodes struct in6_addr *in6p; 217135446Strhodes in6p = (struct in6_addr *)(he->h_addr_list[i]); 218135446Strhodes if (in6p == NULL) 219135446Strhodes break; 220135446Strhodes isc_sockaddr_fromin6(&addrs[i], in6p, port); 221135446Strhodes } 222135446Strhodes } 223135446Strhodes *addrcount = i; 224135446Strhodes#endif 225135446Strhodes if (*addrcount == 0) 226135446Strhodes return (ISC_R_NOTFOUND); 227135446Strhodes else 228135446Strhodes return (ISC_R_SUCCESS); 229135446Strhodes} 230