GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/bind/lib/bind9/getaddresses.c Lines: 0 63 0.0 %
Date: 2016-12-06 Branches: 0 42 0.0 %

Line Branch Exec Source
1
/*
2
 * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
3
 * Copyright (C) 2001, 2002  Internet Software Consortium.
4
 *
5
 * Permission to use, copy, modify, and 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
/* $ISC: getaddresses.c,v 1.15.18.5 2005/10/14 01:28:24 marka 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
45
extern int h_errno;
46
#endif
47
#endif
48
49
isc_result_t
50
bind9_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
		strlcpy(tmpbuf, hostname, sizeof(tmpbuf));
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
}