4 * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2001, 2002 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: getaddresses.c,v 1.22 2007/06/19 23:47:16 tbox Exp */
28 #include <isc/netaddr.h>
29 #include <isc/netdb.h>
30 #include <isc/netscope.h>
31 #include <isc/result.h>
32 #include <isc/sockaddr.h>
35 #include <bind9/getaddresses.h>
38 #ifdef HAVE_GETADDRINFO
39 #ifdef HAVE_GAISTRERROR
40 #define USE_GETADDRINFO
45 #ifndef USE_GETADDRINFO
46 #ifndef ISC_PLATFORM_NONSTDHERRNO
52 bind9_getaddresses(const char *hostname
, in_port_t port
,
53 isc_sockaddr_t
*addrs
, int addrsize
, int *addrcount
)
57 isc_boolean_t have_ipv4
, have_ipv6
;
60 #ifdef USE_GETADDRINFO
61 struct addrinfo
*ai
= NULL
, *tmpai
, hints
;
67 REQUIRE(hostname
!= NULL
);
68 REQUIRE(addrs
!= NULL
);
69 REQUIRE(addrcount
!= NULL
);
70 REQUIRE(addrsize
> 0);
72 have_ipv4
= ISC_TF((isc_net_probeipv4() == ISC_R_SUCCESS
));
73 have_ipv6
= ISC_TF((isc_net_probeipv6() == ISC_R_SUCCESS
));
76 * Try IPv4, then IPv6. In order to handle the extended format
77 * for IPv6 scoped addresses (address%scope_ID), we'll use a local
78 * working buffer of 128 bytes. The length is an ad-hoc value, but
79 * should be enough for this purpose; the buffer can contain a string
80 * of at least 80 bytes for scope_ID in addition to any IPv6 numeric
81 * addresses (up to 46 bytes), the delimiter character and the
82 * terminating NULL character.
84 if (inet_pton(AF_INET
, hostname
, &in4
) == 1) {
86 isc_sockaddr_fromin(&addrs
[0], &in4
, port
);
88 isc_sockaddr_v6fromin(&addrs
[0], &in4
, port
);
90 return (ISC_R_SUCCESS
);
91 } else if (strlen(hostname
) <= 127U) {
93 isc_uint32_t zone
= 0;
95 strcpy(tmpbuf
, hostname
);
96 d
= strchr(tmpbuf
, '%');
100 if (inet_pton(AF_INET6
, tmpbuf
, &in6
) == 1) {
104 return (ISC_R_FAMILYNOSUPPORT
);
107 #ifdef ISC_PLATFORM_HAVESCOPEID
110 result
= isc_netscope_pton(AF_INET6
, d
+ 1,
113 if (result
!= ISC_R_SUCCESS
)
117 * The extended format is specified while the
118 * system does not provide the ability to use
119 * it. Throw an explicit error instead of
120 * ignoring the specified value.
122 return (ISC_R_BADADDRESSFORM
);
126 isc_netaddr_fromin6(&na
, &in6
);
127 isc_netaddr_setzone(&na
, zone
);
128 isc_sockaddr_fromnetaddr(&addrs
[0],
129 (const isc_netaddr_t
*)&na
,
133 return (ISC_R_SUCCESS
);
137 #ifdef USE_GETADDRINFO
138 memset(&hints
, 0, sizeof(hints
));
140 hints
.ai_family
= PF_INET
;
142 hints
.ai_family
= PF_INET6
;
144 hints
.ai_family
= PF_UNSPEC
;
146 hints
.ai_flags
= AI_ADDRCONFIG
;
149 hints
.ai_socktype
= SOCK_STREAM
;
153 result
= getaddrinfo(hostname
, NULL
, &hints
, &ai
);
158 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
161 return (ISC_R_NOTFOUND
);
164 if ((hints
.ai_flags
& AI_ADDRCONFIG
) != 0) {
165 hints
.ai_flags
&= ~AI_ADDRCONFIG
;
170 return (ISC_R_FAILURE
);
172 for (tmpai
= ai
, i
= 0;
173 tmpai
!= NULL
&& i
< addrsize
;
174 tmpai
= tmpai
->ai_next
)
176 if (tmpai
->ai_family
!= AF_INET
&&
177 tmpai
->ai_family
!= AF_INET6
)
179 if (tmpai
->ai_family
== AF_INET
) {
180 struct sockaddr_in
*sin
;
181 sin
= (struct sockaddr_in
*)tmpai
->ai_addr
;
182 isc_sockaddr_fromin(&addrs
[i
], &sin
->sin_addr
, port
);
184 struct sockaddr_in6
*sin6
;
185 sin6
= (struct sockaddr_in6
*)tmpai
->ai_addr
;
186 isc_sockaddr_fromin6(&addrs
[i
], &sin6
->sin6_addr
,
195 he
= gethostbyname(hostname
);
202 #if defined(NO_ADDRESS) && (!defined(NO_DATA) || (NO_DATA != NO_ADDRESS))
205 return (ISC_R_NOTFOUND
);
207 return (ISC_R_FAILURE
);
210 if (he
->h_addrtype
!= AF_INET
&& he
->h_addrtype
!= AF_INET6
)
211 return (ISC_R_NOTFOUND
);
212 for (i
= 0; i
< addrsize
; i
++) {
213 if (he
->h_addrtype
== AF_INET
) {
215 inp
= (struct in_addr
*)(he
->h_addr_list
[i
]);
218 isc_sockaddr_fromin(&addrs
[i
], inp
, port
);
220 struct in6_addr
*in6p
;
221 in6p
= (struct in6_addr
*)(he
->h_addr_list
[i
]);
224 isc_sockaddr_fromin6(&addrs
[i
], in6p
, port
);
230 return (ISC_R_NOTFOUND
);
232 return (ISC_R_SUCCESS
);