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