1135446Strhodes/* 2193149Sdougb * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2001, 2002 Internet Software Consortium. 4135446Strhodes * 5193149Sdougb * Permission to use, copy, modify, and/or 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 18234010Sdougb/* $Id: getaddresses.c,v 1.22 2007/06/19 23:47:16 tbox Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes#include <string.h> 24135446Strhodes 25135446Strhodes#include <isc/net.h> 26135446Strhodes#include <isc/netaddr.h> 27135446Strhodes#include <isc/netdb.h> 28135446Strhodes#include <isc/netscope.h> 29135446Strhodes#include <isc/result.h> 30135446Strhodes#include <isc/sockaddr.h> 31135446Strhodes#include <isc/util.h> 32135446Strhodes 33135446Strhodes#include <bind9/getaddresses.h> 34135446Strhodes 35135446Strhodes#ifdef HAVE_ADDRINFO 36135446Strhodes#ifdef HAVE_GETADDRINFO 37135446Strhodes#ifdef HAVE_GAISTRERROR 38135446Strhodes#define USE_GETADDRINFO 39135446Strhodes#endif 40135446Strhodes#endif 41135446Strhodes#endif 42135446Strhodes 43135446Strhodes#ifndef USE_GETADDRINFO 44135446Strhodes#ifndef ISC_PLATFORM_NONSTDHERRNO 45135446Strhodesextern int h_errno; 46135446Strhodes#endif 47135446Strhodes#endif 48135446Strhodes 49135446Strhodesisc_result_t 50135446Strhodesbind9_getaddresses(const char *hostname, in_port_t port, 51135446Strhodes isc_sockaddr_t *addrs, int addrsize, int *addrcount) 52135446Strhodes{ 53135446Strhodes struct in_addr in4; 54135446Strhodes struct in6_addr in6; 55135446Strhodes isc_boolean_t have_ipv4, have_ipv6; 56135446Strhodes int i; 57135446Strhodes 58135446Strhodes#ifdef USE_GETADDRINFO 59135446Strhodes struct addrinfo *ai = NULL, *tmpai, hints; 60135446Strhodes int result; 61135446Strhodes#else 62135446Strhodes struct hostent *he; 63135446Strhodes#endif 64135446Strhodes 65135446Strhodes REQUIRE(hostname != NULL); 66135446Strhodes REQUIRE(addrs != NULL); 67135446Strhodes REQUIRE(addrcount != NULL); 68135446Strhodes REQUIRE(addrsize > 0); 69135446Strhodes 70153816Sdougb have_ipv4 = ISC_TF((isc_net_probeipv4() == ISC_R_SUCCESS)); 71153816Sdougb have_ipv6 = ISC_TF((isc_net_probeipv6() == ISC_R_SUCCESS)); 72135446Strhodes 73135446Strhodes /* 74135446Strhodes * Try IPv4, then IPv6. In order to handle the extended format 75135446Strhodes * for IPv6 scoped addresses (address%scope_ID), we'll use a local 76135446Strhodes * working buffer of 128 bytes. The length is an ad-hoc value, but 77135446Strhodes * should be enough for this purpose; the buffer can contain a string 78135446Strhodes * of at least 80 bytes for scope_ID in addition to any IPv6 numeric 79135446Strhodes * addresses (up to 46 bytes), the delimiter character and the 80135446Strhodes * terminating NULL character. 81135446Strhodes */ 82135446Strhodes if (inet_pton(AF_INET, hostname, &in4) == 1) { 83135446Strhodes if (have_ipv4) 84135446Strhodes isc_sockaddr_fromin(&addrs[0], &in4, port); 85135446Strhodes else 86135446Strhodes isc_sockaddr_v6fromin(&addrs[0], &in4, port); 87135446Strhodes *addrcount = 1; 88135446Strhodes return (ISC_R_SUCCESS); 89143731Sdougb } else if (strlen(hostname) <= 127U) { 90135446Strhodes char tmpbuf[128], *d; 91135446Strhodes isc_uint32_t zone = 0; 92135446Strhodes 93135446Strhodes strcpy(tmpbuf, hostname); 94135446Strhodes d = strchr(tmpbuf, '%'); 95135446Strhodes if (d != NULL) 96135446Strhodes *d = '\0'; 97135446Strhodes 98135446Strhodes if (inet_pton(AF_INET6, tmpbuf, &in6) == 1) { 99135446Strhodes isc_netaddr_t na; 100135446Strhodes 101135446Strhodes if (!have_ipv6) 102135446Strhodes return (ISC_R_FAMILYNOSUPPORT); 103135446Strhodes 104135446Strhodes if (d != NULL) { 105135446Strhodes#ifdef ISC_PLATFORM_HAVESCOPEID 106135446Strhodes isc_result_t result; 107135446Strhodes 108135446Strhodes result = isc_netscope_pton(AF_INET6, d + 1, 109135446Strhodes &in6, &zone); 110135446Strhodes 111135446Strhodes if (result != ISC_R_SUCCESS) 112135446Strhodes return (result); 113135446Strhodes#else 114135446Strhodes /* 115135446Strhodes * The extended format is specified while the 116135446Strhodes * system does not provide the ability to use 117135446Strhodes * it. Throw an explicit error instead of 118135446Strhodes * ignoring the specified value. 119135446Strhodes */ 120135446Strhodes return (ISC_R_BADADDRESSFORM); 121135446Strhodes#endif 122135446Strhodes } 123135446Strhodes 124135446Strhodes isc_netaddr_fromin6(&na, &in6); 125135446Strhodes isc_netaddr_setzone(&na, zone); 126135446Strhodes isc_sockaddr_fromnetaddr(&addrs[0], 127135446Strhodes (const isc_netaddr_t *)&na, 128135446Strhodes port); 129135446Strhodes 130135446Strhodes *addrcount = 1; 131135446Strhodes return (ISC_R_SUCCESS); 132135446Strhodes 133135446Strhodes } 134135446Strhodes } 135135446Strhodes#ifdef USE_GETADDRINFO 136135446Strhodes memset(&hints, 0, sizeof(hints)); 137135446Strhodes if (!have_ipv6) 138135446Strhodes hints.ai_family = PF_INET; 139135446Strhodes else if (!have_ipv4) 140135446Strhodes hints.ai_family = PF_INET6; 141135446Strhodes else { 142135446Strhodes hints.ai_family = PF_UNSPEC; 143135446Strhodes#ifdef AI_ADDRCONFIG 144135446Strhodes hints.ai_flags = AI_ADDRCONFIG; 145135446Strhodes#endif 146135446Strhodes } 147135446Strhodes hints.ai_socktype = SOCK_STREAM; 148135446Strhodes#ifdef AI_ADDRCONFIG 149135446Strhodes again: 150135446Strhodes#endif 151135446Strhodes result = getaddrinfo(hostname, NULL, &hints, &ai); 152135446Strhodes switch (result) { 153135446Strhodes case 0: 154135446Strhodes break; 155135446Strhodes case EAI_NONAME: 156135446Strhodes#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) 157135446Strhodes case EAI_NODATA: 158135446Strhodes#endif 159135446Strhodes return (ISC_R_NOTFOUND); 160135446Strhodes#ifdef AI_ADDRCONFIG 161135446Strhodes case EAI_BADFLAGS: 162135446Strhodes if ((hints.ai_flags & AI_ADDRCONFIG) != 0) { 163135446Strhodes hints.ai_flags &= ~AI_ADDRCONFIG; 164135446Strhodes goto again; 165135446Strhodes } 166135446Strhodes#endif 167135446Strhodes default: 168135446Strhodes return (ISC_R_FAILURE); 169135446Strhodes } 170135446Strhodes for (tmpai = ai, i = 0; 171135446Strhodes tmpai != NULL && i < addrsize; 172135446Strhodes tmpai = tmpai->ai_next) 173135446Strhodes { 174135446Strhodes if (tmpai->ai_family != AF_INET && 175135446Strhodes tmpai->ai_family != AF_INET6) 176135446Strhodes continue; 177135446Strhodes if (tmpai->ai_family == AF_INET) { 178135446Strhodes struct sockaddr_in *sin; 179135446Strhodes sin = (struct sockaddr_in *)tmpai->ai_addr; 180135446Strhodes isc_sockaddr_fromin(&addrs[i], &sin->sin_addr, port); 181135446Strhodes } else { 182135446Strhodes struct sockaddr_in6 *sin6; 183135446Strhodes sin6 = (struct sockaddr_in6 *)tmpai->ai_addr; 184135446Strhodes isc_sockaddr_fromin6(&addrs[i], &sin6->sin6_addr, 185135446Strhodes port); 186135446Strhodes } 187135446Strhodes i++; 188135446Strhodes 189135446Strhodes } 190135446Strhodes freeaddrinfo(ai); 191135446Strhodes *addrcount = i; 192135446Strhodes#else 193135446Strhodes he = gethostbyname(hostname); 194135446Strhodes if (he == NULL) { 195135446Strhodes switch (h_errno) { 196135446Strhodes case HOST_NOT_FOUND: 197135446Strhodes#ifdef NO_DATA 198135446Strhodes case NO_DATA: 199135446Strhodes#endif 200135446Strhodes#if defined(NO_ADDRESS) && (!defined(NO_DATA) || (NO_DATA != NO_ADDRESS)) 201135446Strhodes case NO_ADDRESS: 202135446Strhodes#endif 203135446Strhodes return (ISC_R_NOTFOUND); 204135446Strhodes default: 205135446Strhodes return (ISC_R_FAILURE); 206135446Strhodes } 207135446Strhodes } 208135446Strhodes if (he->h_addrtype != AF_INET && he->h_addrtype != AF_INET6) 209135446Strhodes return (ISC_R_NOTFOUND); 210135446Strhodes for (i = 0; i < addrsize; i++) { 211135446Strhodes if (he->h_addrtype == AF_INET) { 212135446Strhodes struct in_addr *inp; 213135446Strhodes inp = (struct in_addr *)(he->h_addr_list[i]); 214135446Strhodes if (inp == NULL) 215135446Strhodes break; 216135446Strhodes isc_sockaddr_fromin(&addrs[i], inp, port); 217135446Strhodes } else { 218135446Strhodes struct in6_addr *in6p; 219135446Strhodes in6p = (struct in6_addr *)(he->h_addr_list[i]); 220135446Strhodes if (in6p == NULL) 221135446Strhodes break; 222135446Strhodes isc_sockaddr_fromin6(&addrs[i], in6p, port); 223135446Strhodes } 224135446Strhodes } 225135446Strhodes *addrcount = i; 226135446Strhodes#endif 227135446Strhodes if (*addrcount == 0) 228135446Strhodes return (ISC_R_NOTFOUND); 229135446Strhodes else 230135446Strhodes return (ISC_R_SUCCESS); 231135446Strhodes} 232