xref: /freebsd-src/contrib/ntp/libntp/lib/isc/win32/interfaceiter.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
1*a466cc55SCy Schubert /*
2*a466cc55SCy Schubert  * Copyright (C) 2004, 2007-2009  Internet Systems Consortium, Inc. ("ISC")
3*a466cc55SCy Schubert  * Copyright (C) 1999-2001  Internet Software Consortium.
4*a466cc55SCy Schubert  *
5*a466cc55SCy Schubert  * Permission to use, copy, modify, and/or distribute this software for any
6*a466cc55SCy Schubert  * purpose with or without fee is hereby granted, provided that the above
7*a466cc55SCy Schubert  * copyright notice and this permission notice appear in all copies.
8*a466cc55SCy Schubert  *
9*a466cc55SCy Schubert  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10*a466cc55SCy Schubert  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11*a466cc55SCy Schubert  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12*a466cc55SCy Schubert  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13*a466cc55SCy Schubert  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14*a466cc55SCy Schubert  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15*a466cc55SCy Schubert  * PERFORMANCE OF THIS SOFTWARE.
16*a466cc55SCy Schubert  */
17*a466cc55SCy Schubert 
18*a466cc55SCy Schubert /* $Id: interfaceiter.c,v 1.15 2009/01/18 23:48:14 tbox Exp $ */
19*a466cc55SCy Schubert 
20*a466cc55SCy Schubert #include <config.h>
21*a466cc55SCy Schubert 
22*a466cc55SCy Schubert #include <stdio.h>
23*a466cc55SCy Schubert #include <stdlib.h>
24*a466cc55SCy Schubert #include <errno.h>
25*a466cc55SCy Schubert #include <sys/types.h>
26*a466cc55SCy Schubert #include <winsock2.h>
27*a466cc55SCy Schubert #include <ws2tcpip.h>
28*a466cc55SCy Schubert #include <gaa_compat.h>
29*a466cc55SCy Schubert 
30*a466cc55SCy Schubert #include <isc/interfaceiter.h>
31*a466cc55SCy Schubert #include <isc/mem.h>
32*a466cc55SCy Schubert #include <isc/result.h>
33*a466cc55SCy Schubert #include <isc/string.h>
34*a466cc55SCy Schubert #include <isc/strerror.h>
35*a466cc55SCy Schubert #include <isc/types.h>
36*a466cc55SCy Schubert #include <isc/util.h>
37*a466cc55SCy Schubert #include <isc/win32os.h>
38*a466cc55SCy Schubert 
39*a466cc55SCy Schubert void InitSockets(void);
40*a466cc55SCy Schubert 
41*a466cc55SCy Schubert 
42*a466cc55SCy Schubert #define IFITER_MAGIC		0x49464954U	/* IFIT. */
43*a466cc55SCy Schubert #define VALID_IFITER(t)		((t) != NULL && (t)->magic == IFITER_MAGIC)
44*a466cc55SCy Schubert 
45*a466cc55SCy Schubert struct isc_interfaceiter {
46*a466cc55SCy Schubert 	unsigned int		magic;		/* Magic number. */
47*a466cc55SCy Schubert 	/* common fields */
48*a466cc55SCy Schubert 	isc_mem_t		*mctx;
49*a466cc55SCy Schubert 	isc_interface_t		current;	/* Current interface data. */
50*a466cc55SCy Schubert 	isc_result_t		result;		/* Last result code. */
51*a466cc55SCy Schubert 	/* fields used if GetAdaptersAddresses is available at runtime */
52*a466cc55SCy Schubert 	IP_ADAPTER_ADDRESSES *	ipaa;		/* GAA() result buffer */
53*a466cc55SCy Schubert 	ULONG			ipaasize;	/* Bytes allocated */
54*a466cc55SCy Schubert 	IP_ADAPTER_ADDRESSES *	ipaaCur;	/* enumeration position */
55*a466cc55SCy Schubert 	IP_ADAPTER_UNICAST_ADDRESS *ipuaCur;	/* enumeration subposition */
56*a466cc55SCy Schubert 	/* fields used for the older address enumeration ioctls */
57*a466cc55SCy Schubert 	SOCKET			socket;
58*a466cc55SCy Schubert 	INTERFACE_INFO		IFData;		/* Current Interface Info */
59*a466cc55SCy Schubert 	int			numIF;		/* Current Interface count */
60*a466cc55SCy Schubert 	int			v4IF;		/* Number of IPv4 Interfaces */
61*a466cc55SCy Schubert 	INTERFACE_INFO		*buf4;		/* Buffer for WSAIoctl data. */
62*a466cc55SCy Schubert 	unsigned int		buf4size;	/* Bytes allocated. */
63*a466cc55SCy Schubert 	INTERFACE_INFO		*pos4;		/* Current offset in IF List */
64*a466cc55SCy Schubert 	SOCKET_ADDRESS_LIST	*buf6;
65*a466cc55SCy Schubert 	unsigned int		buf6size;	/* Bytes allocated. */
66*a466cc55SCy Schubert 	unsigned int		pos6;		/* buf6 index, counts down */
67*a466cc55SCy Schubert 	struct in6_addr		loop__1;	/* ::1 node-scope localhost */
68*a466cc55SCy Schubert 	struct in6_addr		loopfe80__1;	/* fe80::1 link-scope localhost */
69*a466cc55SCy Schubert };
70*a466cc55SCy Schubert 
71*a466cc55SCy Schubert typedef ULONG (WINAPI *PGETADAPTERSADDRESSES)(
72*a466cc55SCy Schubert     ULONG Family,
73*a466cc55SCy Schubert     ULONG Flags,
74*a466cc55SCy Schubert     PVOID Reserved,
75*a466cc55SCy Schubert     PIP_ADAPTER_ADDRESSES AdapterAddresses,
76*a466cc55SCy Schubert     PULONG SizePointer
77*a466cc55SCy Schubert );
78*a466cc55SCy Schubert 
79*a466cc55SCy Schubert static	isc_boolean_t		use_GAA;
80*a466cc55SCy Schubert static	isc_boolean_t		use_GAA_determined;
81*a466cc55SCy Schubert static	HMODULE			hmod_iphlpapi;
82*a466cc55SCy Schubert static	PGETADAPTERSADDRESSES	pGAA;
83*a466cc55SCy Schubert 
84*a466cc55SCy Schubert 
85*a466cc55SCy Schubert /*
86*a466cc55SCy Schubert  * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces.
87*a466cc55SCy Schubert  * We assume no sane system will have more than than 1K of IP addresses on
88*a466cc55SCy Schubert  * all of its adapters.
89*a466cc55SCy Schubert  */
90*a466cc55SCy Schubert #define IFCONF_SIZE_INITIAL	  16
91*a466cc55SCy Schubert #define IFCONF_SIZE_INCREMENT	  64
92*a466cc55SCy Schubert #define IFCONF_SIZE_MAX		1040
93*a466cc55SCy Schubert 
94*a466cc55SCy Schubert 
95*a466cc55SCy Schubert /* Common utility functions */
96*a466cc55SCy Schubert 
97*a466cc55SCy Schubert /*
98*a466cc55SCy Schubert  * Windows always provides 255.255.255.255 as the the broadcast
99*a466cc55SCy Schubert  * address.  ntpd needs to know the broadcast address which will target
100*a466cc55SCy Schubert  * only that network interface, not all.  Reconstruct it from the
101*a466cc55SCy Schubert  * address and mask.
102*a466cc55SCy Schubert  */
103*a466cc55SCy Schubert static void
get_broadcastaddr(isc_netaddr_t * bcastaddr,isc_netaddr_t * addr,isc_netaddr_t * netmask)104*a466cc55SCy Schubert get_broadcastaddr(isc_netaddr_t *bcastaddr, isc_netaddr_t *addr, isc_netaddr_t *netmask) {
105*a466cc55SCy Schubert 
106*a466cc55SCy Schubert 	isc_uint32_t *	b;
107*a466cc55SCy Schubert 	isc_uint32_t	a, n;
108*a466cc55SCy Schubert 
109*a466cc55SCy Schubert 	b = (isc_uint32_t *)&bcastaddr->type.in;
110*a466cc55SCy Schubert 	a = *(isc_uint32_t *)&addr->type.in;
111*a466cc55SCy Schubert 	n = *(isc_uint32_t *)&netmask->type.in;
112*a466cc55SCy Schubert 
113*a466cc55SCy Schubert 	*b = a | ~n;
114*a466cc55SCy Schubert }
115*a466cc55SCy Schubert 
116*a466cc55SCy Schubert isc_result_t
isc_interfaceiter_create(isc_mem_t * mctx,isc_interfaceiter_t ** iterp)117*a466cc55SCy Schubert isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
118*a466cc55SCy Schubert 	char strbuf[ISC_STRERRORSIZE];
119*a466cc55SCy Schubert 	isc_interfaceiter_t *iter;
120*a466cc55SCy Schubert 	isc_result_t result;
121*a466cc55SCy Schubert 	unsigned int major;
122*a466cc55SCy Schubert 	unsigned int minor;
123*a466cc55SCy Schubert 	unsigned int spmajor;
124*a466cc55SCy Schubert 	ULONG err;
125*a466cc55SCy Schubert 	int tries;
126*a466cc55SCy Schubert 	int error;
127*a466cc55SCy Schubert 	unsigned long bytesReturned = 0;
128*a466cc55SCy Schubert 
129*a466cc55SCy Schubert 	REQUIRE(mctx != NULL);
130*a466cc55SCy Schubert 	REQUIRE(iterp != NULL);
131*a466cc55SCy Schubert 	REQUIRE(*iterp == NULL);
132*a466cc55SCy Schubert 
133*a466cc55SCy Schubert 	iter = isc_mem_get(mctx, sizeof(*iter));
134*a466cc55SCy Schubert 	if (iter == NULL)
135*a466cc55SCy Schubert 		return (ISC_R_NOMEMORY);
136*a466cc55SCy Schubert 
137*a466cc55SCy Schubert 	InitSockets();
138*a466cc55SCy Schubert 
139*a466cc55SCy Schubert 	iter->mctx = mctx;
140*a466cc55SCy Schubert 	iter->ipaa = NULL;
141*a466cc55SCy Schubert 	iter->buf4 = NULL;
142*a466cc55SCy Schubert 	iter->buf6 = NULL;
143*a466cc55SCy Schubert 	iter->pos4 = NULL;
144*a466cc55SCy Schubert 	iter->ipaaCur = NULL;
145*a466cc55SCy Schubert 	iter->ipuaCur = NULL;
146*a466cc55SCy Schubert 	iter->ipaasize = 0;
147*a466cc55SCy Schubert 	iter->pos6 = 0;
148*a466cc55SCy Schubert 	iter->buf6size = 0;
149*a466cc55SCy Schubert 	iter->buf4size = 0;
150*a466cc55SCy Schubert 	iter->result = ISC_R_FAILURE;
151*a466cc55SCy Schubert 	iter->numIF = 0;
152*a466cc55SCy Schubert 	iter->v4IF = 0;
153*a466cc55SCy Schubert 
154*a466cc55SCy Schubert 	/*
155*a466cc55SCy Schubert 	 * Use GetAdaptersAddresses in preference to ioctls when running
156*a466cc55SCy Schubert 	 * on Windows XP SP1 or later.  Earlier GetAdaptersAddresses do
157*a466cc55SCy Schubert 	 * not appear to provide enough information to associate unicast
158*a466cc55SCy Schubert 	 * addresses with their prefixes.
159*a466cc55SCy Schubert 	 */
160*a466cc55SCy Schubert 	if (!use_GAA_determined) {
161*a466cc55SCy Schubert 		major = isc_win32os_majorversion();
162*a466cc55SCy Schubert 		minor = isc_win32os_minorversion();
163*a466cc55SCy Schubert 		spmajor = isc_win32os_servicepackmajor();
164*a466cc55SCy Schubert 		if (major > 5 || (5 == major &&
165*a466cc55SCy Schubert 		    (minor > 1 || (1 == minor && spmajor >= 1)))) {
166*a466cc55SCy Schubert 			if (NULL == hmod_iphlpapi)
167*a466cc55SCy Schubert 				hmod_iphlpapi = LoadLibrary("iphlpapi");
168*a466cc55SCy Schubert 			if (NULL != hmod_iphlpapi)
169*a466cc55SCy Schubert 				pGAA = (PGETADAPTERSADDRESSES)
170*a466cc55SCy Schubert 				    GetProcAddress(
171*a466cc55SCy Schubert 					hmod_iphlpapi,
172*a466cc55SCy Schubert 					"GetAdaptersAddresses");
173*a466cc55SCy Schubert 			if (NULL != pGAA)
174*a466cc55SCy Schubert 				use_GAA = ISC_TRUE;
175*a466cc55SCy Schubert 		}
176*a466cc55SCy Schubert 		use_GAA_determined = ISC_TRUE;
177*a466cc55SCy Schubert 	}
178*a466cc55SCy Schubert 
179*a466cc55SCy Schubert 	if (!use_GAA)
180*a466cc55SCy Schubert 		goto use_ioctls;
181*a466cc55SCy Schubert 
182*a466cc55SCy Schubert 	iter->ipaasize = 16 * 1024;
183*a466cc55SCy Schubert 
184*a466cc55SCy Schubert 	for (tries = 0; tries < 5; tries++) {
185*a466cc55SCy Schubert 		iter->ipaa = isc_mem_reallocate(mctx, iter->ipaa,
186*a466cc55SCy Schubert 						 iter->ipaasize);
187*a466cc55SCy Schubert 		if (NULL == iter->ipaa) {
188*a466cc55SCy Schubert 			result = ISC_R_NOMEMORY;
189*a466cc55SCy Schubert 			goto put_iter;
190*a466cc55SCy Schubert 		}
191*a466cc55SCy Schubert 		err = (*pGAA)(
192*a466cc55SCy Schubert 			AF_UNSPEC,
193*a466cc55SCy Schubert 			GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST,
194*a466cc55SCy Schubert 			NULL,
195*a466cc55SCy Schubert 			iter->ipaa,
196*a466cc55SCy Schubert 			&iter->ipaasize);
197*a466cc55SCy Schubert 		if (NO_ERROR == err || ERROR_BUFFER_OVERFLOW != err)
198*a466cc55SCy Schubert 			break;
199*a466cc55SCy Schubert 	}
200*a466cc55SCy Schubert 
201*a466cc55SCy Schubert 	if (NO_ERROR != err) {
202*a466cc55SCy Schubert 		isc__strerror(err, strbuf, sizeof(strbuf));
203*a466cc55SCy Schubert 		UNEXPECTED_ERROR(__FILE__, __LINE__,
204*a466cc55SCy Schubert 				"GetAdaptersAddresses: %s",
205*a466cc55SCy Schubert 				strbuf);
206*a466cc55SCy Schubert 		result = ISC_R_UNEXPECTED;
207*a466cc55SCy Schubert 		goto gaa_failure;
208*a466cc55SCy Schubert 	}
209*a466cc55SCy Schubert 
210*a466cc55SCy Schubert 	iter->ipaaCur = iter->ipaa;
211*a466cc55SCy Schubert 	goto success;
212*a466cc55SCy Schubert 
213*a466cc55SCy Schubert  use_ioctls:
214*a466cc55SCy Schubert 	/*
215*a466cc55SCy Schubert 	 * Create an unbound datagram socket to do the
216*a466cc55SCy Schubert 	 * SIO_GET_INTERFACE_LIST WSAIoctl on.
217*a466cc55SCy Schubert 	 */
218*a466cc55SCy Schubert 	if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
219*a466cc55SCy Schubert 		error = WSAGetLastError();
220*a466cc55SCy Schubert 		if (error == WSAEAFNOSUPPORT)
221*a466cc55SCy Schubert 			goto inet6_only;
222*a466cc55SCy Schubert 		isc__strerror(error, strbuf, sizeof(strbuf));
223*a466cc55SCy Schubert 		UNEXPECTED_ERROR(__FILE__, __LINE__,
224*a466cc55SCy Schubert 				"making interface scan socket: %s",
225*a466cc55SCy Schubert 				strbuf);
226*a466cc55SCy Schubert 		result = ISC_R_UNEXPECTED;
227*a466cc55SCy Schubert 		goto put_iter;
228*a466cc55SCy Schubert 	}
229*a466cc55SCy Schubert 
230*a466cc55SCy Schubert 	/*
231*a466cc55SCy Schubert 	 * Get the interface configuration, allocating more memory if
232*a466cc55SCy Schubert 	 * necessary.
233*a466cc55SCy Schubert 	 */
234*a466cc55SCy Schubert 	iter->buf4size = IFCONF_SIZE_INITIAL*sizeof(INTERFACE_INFO);
235*a466cc55SCy Schubert 
236*a466cc55SCy Schubert 	for (;;) {
237*a466cc55SCy Schubert 		iter->buf4 = isc_mem_get(mctx, iter->buf4size);
238*a466cc55SCy Schubert 		if (iter->buf4 == NULL) {
239*a466cc55SCy Schubert 			result = ISC_R_NOMEMORY;
240*a466cc55SCy Schubert 			goto alloc_failure;
241*a466cc55SCy Schubert 		}
242*a466cc55SCy Schubert 
243*a466cc55SCy Schubert 		if (WSAIoctl(iter->socket, SIO_GET_INTERFACE_LIST,
244*a466cc55SCy Schubert 			     0, 0, iter->buf4, iter->buf4size,
245*a466cc55SCy Schubert 			     &bytesReturned, 0, 0) == SOCKET_ERROR)
246*a466cc55SCy Schubert 		{
247*a466cc55SCy Schubert 			error = WSAGetLastError();
248*a466cc55SCy Schubert 			if (error != WSAEFAULT && error != WSAENOBUFS) {
249*a466cc55SCy Schubert 				errno = error;
250*a466cc55SCy Schubert 				isc__strerror(error, strbuf, sizeof(strbuf));
251*a466cc55SCy Schubert 				UNEXPECTED_ERROR(__FILE__, __LINE__,
252*a466cc55SCy Schubert 						"get interface configuration: %s",
253*a466cc55SCy Schubert 						strbuf);
254*a466cc55SCy Schubert 				result = ISC_R_UNEXPECTED;
255*a466cc55SCy Schubert 				goto ioctl_failure;
256*a466cc55SCy Schubert 			}
257*a466cc55SCy Schubert 			/*
258*a466cc55SCy Schubert 			 * EINVAL.  Retry with a bigger buffer.
259*a466cc55SCy Schubert 			 */
260*a466cc55SCy Schubert 		} else {
261*a466cc55SCy Schubert 			/*
262*a466cc55SCy Schubert 			 * The WSAIoctl succeeded.
263*a466cc55SCy Schubert 			 * If the number of the returned bytes is the same
264*a466cc55SCy Schubert 			 * as the buffer size, we will grow it just in
265*a466cc55SCy Schubert 			 * case and retry.
266*a466cc55SCy Schubert 			 */
267*a466cc55SCy Schubert 			if (bytesReturned > 0 &&
268*a466cc55SCy Schubert 			    (bytesReturned < iter->buf4size))
269*a466cc55SCy Schubert 				break;
270*a466cc55SCy Schubert 		}
271*a466cc55SCy Schubert 		if (iter->buf4size >= IFCONF_SIZE_MAX*sizeof(INTERFACE_INFO)) {
272*a466cc55SCy Schubert 			UNEXPECTED_ERROR(__FILE__, __LINE__,
273*a466cc55SCy Schubert 					 "get interface configuration: "
274*a466cc55SCy Schubert 					 "maximum buffer size exceeded");
275*a466cc55SCy Schubert 			result = ISC_R_UNEXPECTED;
276*a466cc55SCy Schubert 			goto ioctl_failure;
277*a466cc55SCy Schubert 		}
278*a466cc55SCy Schubert 		isc_mem_put(mctx, iter->buf4, iter->buf4size);
279*a466cc55SCy Schubert 
280*a466cc55SCy Schubert 		iter->buf4size += IFCONF_SIZE_INCREMENT *
281*a466cc55SCy Schubert 			sizeof(INTERFACE_INFO);
282*a466cc55SCy Schubert 	}
283*a466cc55SCy Schubert 
284*a466cc55SCy Schubert 	/*
285*a466cc55SCy Schubert 	 * A newly created iterator has an undefined position
286*a466cc55SCy Schubert 	 * until isc_interfaceiter_first() is called.
287*a466cc55SCy Schubert 	 */
288*a466cc55SCy Schubert 	iter->v4IF = bytesReturned/sizeof(INTERFACE_INFO);
289*a466cc55SCy Schubert 
290*a466cc55SCy Schubert 	/* We don't need the socket any more, so close it */
291*a466cc55SCy Schubert 	closesocket(iter->socket);
292*a466cc55SCy Schubert 
293*a466cc55SCy Schubert  inet6_only:
294*a466cc55SCy Schubert 	/*
295*a466cc55SCy Schubert 	 * Create an unbound datagram socket to do the
296*a466cc55SCy Schubert 	 * SIO_ADDRESS_LIST_QUERY WSAIoctl on.
297*a466cc55SCy Schubert 	 */
298*a466cc55SCy Schubert 	if ((iter->socket = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
299*a466cc55SCy Schubert 		error = WSAGetLastError();
300*a466cc55SCy Schubert 		if (error == WSAEAFNOSUPPORT)
301*a466cc55SCy Schubert 			goto success;
302*a466cc55SCy Schubert 		isc__strerror(error, strbuf, sizeof(strbuf));
303*a466cc55SCy Schubert 		UNEXPECTED_ERROR(__FILE__, __LINE__,
304*a466cc55SCy Schubert 				"making interface scan socket: %s",
305*a466cc55SCy Schubert 				strbuf);
306*a466cc55SCy Schubert 		result = ISC_R_UNEXPECTED;
307*a466cc55SCy Schubert 		goto put_iter;
308*a466cc55SCy Schubert 	}
309*a466cc55SCy Schubert 
310*a466cc55SCy Schubert 	/*
311*a466cc55SCy Schubert 	 * Get the interface configuration, allocating more memory if
312*a466cc55SCy Schubert 	 * necessary.
313*a466cc55SCy Schubert 	 */
314*a466cc55SCy Schubert 	iter->buf6size = sizeof(SOCKET_ADDRESS_LIST) +
315*a466cc55SCy Schubert 			 IFCONF_SIZE_INITIAL*sizeof(SOCKET_ADDRESS);
316*a466cc55SCy Schubert 
317*a466cc55SCy Schubert 	for (;;) {
318*a466cc55SCy Schubert 		iter->buf6 = isc_mem_get(mctx, iter->buf6size);
319*a466cc55SCy Schubert 		if (iter->buf6 == NULL) {
320*a466cc55SCy Schubert 			result = ISC_R_NOMEMORY;
321*a466cc55SCy Schubert 			goto ioctl_failure;
322*a466cc55SCy Schubert 		}
323*a466cc55SCy Schubert 
324*a466cc55SCy Schubert 		if (WSAIoctl(iter->socket, SIO_ADDRESS_LIST_QUERY,
325*a466cc55SCy Schubert 			     0, 0, iter->buf6, iter->buf6size,
326*a466cc55SCy Schubert 			     &bytesReturned, 0, 0) == SOCKET_ERROR)
327*a466cc55SCy Schubert 		{
328*a466cc55SCy Schubert 			error = WSAGetLastError();
329*a466cc55SCy Schubert 			if (error != WSAEFAULT && error != WSAENOBUFS) {
330*a466cc55SCy Schubert 				errno = error;
331*a466cc55SCy Schubert 				isc__strerror(error, strbuf, sizeof(strbuf));
332*a466cc55SCy Schubert 				UNEXPECTED_ERROR(__FILE__, __LINE__,
333*a466cc55SCy Schubert 						 "sio address list query: %s",
334*a466cc55SCy Schubert 						 strbuf);
335*a466cc55SCy Schubert 				result = ISC_R_UNEXPECTED;
336*a466cc55SCy Schubert 				goto ioctl6_failure;
337*a466cc55SCy Schubert 			}
338*a466cc55SCy Schubert 			/*
339*a466cc55SCy Schubert 			 * EINVAL.  Retry with a bigger buffer.
340*a466cc55SCy Schubert 			 */
341*a466cc55SCy Schubert 		} else
342*a466cc55SCy Schubert 			break;
343*a466cc55SCy Schubert 
344*a466cc55SCy Schubert 		if (iter->buf6size >= IFCONF_SIZE_MAX*sizeof(SOCKET_ADDRESS)) {
345*a466cc55SCy Schubert 			UNEXPECTED_ERROR(__FILE__, __LINE__,
346*a466cc55SCy Schubert 					 "get interface configuration: "
347*a466cc55SCy Schubert 					 "maximum buffer size exceeded");
348*a466cc55SCy Schubert 			result = ISC_R_UNEXPECTED;
349*a466cc55SCy Schubert 			goto ioctl6_failure;
350*a466cc55SCy Schubert 		}
351*a466cc55SCy Schubert 		isc_mem_put(mctx, iter->buf6, iter->buf6size);
352*a466cc55SCy Schubert 
353*a466cc55SCy Schubert 		iter->buf6size += IFCONF_SIZE_INCREMENT *
354*a466cc55SCy Schubert 			sizeof(SOCKET_ADDRESS);
355*a466cc55SCy Schubert 	}
356*a466cc55SCy Schubert 
357*a466cc55SCy Schubert 	/*
358*a466cc55SCy Schubert 	 * initialize loop__1 to [::1] and loopfe80__1 to [fe80::1].
359*a466cc55SCy Schubert 	 * used by internal_current6().
360*a466cc55SCy Schubert 	 */
361*a466cc55SCy Schubert 	memset(&iter->loop__1, 0, sizeof(iter->loop__1));
362*a466cc55SCy Schubert 	memset(&iter->loopfe80__1, 0, sizeof(iter->loopfe80__1));
363*a466cc55SCy Schubert 	iter->loop__1.s6_addr[15] = 1;
364*a466cc55SCy Schubert 	iter->loopfe80__1.s6_addr[15] = 1;
365*a466cc55SCy Schubert 	iter->loopfe80__1.s6_addr[0] = 0xfe;
366*a466cc55SCy Schubert 	iter->loopfe80__1.s6_addr[1] = 0x80;
367*a466cc55SCy Schubert 
368*a466cc55SCy Schubert 	closesocket(iter->socket);
369*a466cc55SCy Schubert 
370*a466cc55SCy Schubert  success:
371*a466cc55SCy Schubert 	iter->magic = IFITER_MAGIC;
372*a466cc55SCy Schubert 	*iterp = iter;
373*a466cc55SCy Schubert 	return (ISC_R_SUCCESS);
374*a466cc55SCy Schubert 
375*a466cc55SCy Schubert  gaa_failure:
376*a466cc55SCy Schubert 	isc_mem_put(mctx, iter->ipaa, iter->ipaasize);
377*a466cc55SCy Schubert 	goto put_iter;
378*a466cc55SCy Schubert 
379*a466cc55SCy Schubert  ioctl6_failure:
380*a466cc55SCy Schubert 	isc_mem_put(mctx, iter->buf6, iter->buf6size);
381*a466cc55SCy Schubert 
382*a466cc55SCy Schubert  ioctl_failure:
383*a466cc55SCy Schubert 	if (iter->buf4 != NULL)
384*a466cc55SCy Schubert 		isc_mem_put(mctx, iter->buf4, iter->buf4size);
385*a466cc55SCy Schubert 
386*a466cc55SCy Schubert  alloc_failure:
387*a466cc55SCy Schubert 	if (iter->socket >= 0)
388*a466cc55SCy Schubert 		(void) closesocket(iter->socket);
389*a466cc55SCy Schubert 
390*a466cc55SCy Schubert  put_iter:
391*a466cc55SCy Schubert 	isc_mem_put(mctx, iter, sizeof(*iter));
392*a466cc55SCy Schubert 	return (result);
393*a466cc55SCy Schubert }
394*a466cc55SCy Schubert 
395*a466cc55SCy Schubert static unsigned char
GAA_find_prefix(isc_interfaceiter_t * iter)396*a466cc55SCy Schubert GAA_find_prefix(isc_interfaceiter_t *iter) {
397*a466cc55SCy Schubert 	IP_ADAPTER_PREFIX *	ipap;
398*a466cc55SCy Schubert 	IP_ADAPTER_PREFIX *	ipap_match;
399*a466cc55SCy Schubert 	int			match_len;
400*a466cc55SCy Schubert 	int			max_len;
401*a466cc55SCy Schubert 	isc_netaddr_t		target;
402*a466cc55SCy Schubert 	u_short			af;
403*a466cc55SCy Schubert 	isc_netaddr_t		pfx;
404*a466cc55SCy Schubert 	int			pfx_len;
405*a466cc55SCy Schubert 	size_t			nbytes;
406*a466cc55SCy Schubert 	unsigned char		nbits;
407*a466cc55SCy Schubert 	unsigned char *		pbits;
408*a466cc55SCy Schubert 	unsigned int		octets;
409*a466cc55SCy Schubert 
410*a466cc55SCy Schubert 	match_len = 0;
411*a466cc55SCy Schubert 	ipap_match = NULL;
412*a466cc55SCy Schubert 	isc_netaddr_fromsockaddr(&target,
413*a466cc55SCy Schubert 	    (isc_sockaddr_t *)iter->ipuaCur->Address.lpSockaddr);
414*a466cc55SCy Schubert 	af = (u_short)target.family;
415*a466cc55SCy Schubert 	INSIST(AF_INET == af || AF_INET6 == af);
416*a466cc55SCy Schubert 	max_len = (AF_INET6 == af) ? 128 : 32;
417*a466cc55SCy Schubert 	iter->current.netmask.family = af;
418*a466cc55SCy Schubert 	for (ipap = iter->ipaaCur->FirstPrefix;
419*a466cc55SCy Schubert 	     ipap != NULL;
420*a466cc55SCy Schubert 	     ipap = ipap->Next) {
421*a466cc55SCy Schubert 		if (ipap->Address.lpSockaddr->sa_family != af)
422*a466cc55SCy Schubert 			continue;
423*a466cc55SCy Schubert 		isc_netaddr_fromsockaddr(&pfx,
424*a466cc55SCy Schubert 		    (isc_sockaddr_t *)ipap->Address.lpSockaddr);
425*a466cc55SCy Schubert 		pfx_len = ipap->PrefixLength;
426*a466cc55SCy Schubert 		INSIST(0 <= pfx_len && pfx_len <= max_len);
427*a466cc55SCy Schubert 		if (pfx_len > match_len && pfx_len < max_len &&
428*a466cc55SCy Schubert 		    isc_netaddr_eqprefix(&target, &pfx, pfx_len)) {
429*a466cc55SCy Schubert 			ipap_match = ipap;
430*a466cc55SCy Schubert 			match_len = pfx_len;
431*a466cc55SCy Schubert 		}
432*a466cc55SCy Schubert 	}
433*a466cc55SCy Schubert 	if (NULL == ipap_match) {
434*a466cc55SCy Schubert 		/* presume all-ones mask */
435*a466cc55SCy Schubert 		if (AF_INET6 == af)
436*a466cc55SCy Schubert 			octets = sizeof(iter->current.netmask.type.in6);
437*a466cc55SCy Schubert 		else
438*a466cc55SCy Schubert 			octets = sizeof(iter->current.netmask.type.in);
439*a466cc55SCy Schubert 		memset(&iter->current.netmask.type, 0xFF, octets);
440*a466cc55SCy Schubert 		return (8 * (unsigned char)octets);
441*a466cc55SCy Schubert 	}
442*a466cc55SCy Schubert 	nbytes = match_len / 8;
443*a466cc55SCy Schubert 	nbits = match_len % 8;
444*a466cc55SCy Schubert 	memset(&iter->current.netmask.type.in6, 0xFF, nbytes);
445*a466cc55SCy Schubert 	pbits = (void *)&iter->current.netmask.type.in6;
446*a466cc55SCy Schubert 	pbits += nbytes;
447*a466cc55SCy Schubert 	*pbits |= 0xFF << (8 - nbits);
448*a466cc55SCy Schubert 	return ((unsigned char)match_len);
449*a466cc55SCy Schubert }
450*a466cc55SCy Schubert 
451*a466cc55SCy Schubert static isc_result_t
internal_current_GAA(isc_interfaceiter_t * iter)452*a466cc55SCy Schubert internal_current_GAA(isc_interfaceiter_t *iter) {
453*a466cc55SCy Schubert 	IP_ADAPTER_ADDRESSES *adap;
454*a466cc55SCy Schubert 	IP_ADAPTER_UNICAST_ADDRESS *addr;
455*a466cc55SCy Schubert 	unsigned char prefix_len;
456*a466cc55SCy Schubert 
457*a466cc55SCy Schubert 	REQUIRE(iter->ipaaCur != NULL);
458*a466cc55SCy Schubert 	REQUIRE(iter->ipuaCur != NULL);
459*a466cc55SCy Schubert 	adap = iter->ipaaCur;
460*a466cc55SCy Schubert 	addr = iter->ipuaCur;
461*a466cc55SCy Schubert 	if (IpDadStatePreferred != addr->DadState)
462*a466cc55SCy Schubert 		return (ISC_R_IGNORE);
463*a466cc55SCy Schubert 	memset(&iter->current, 0, sizeof(iter->current));
464*a466cc55SCy Schubert 	iter->current.af = addr->Address.lpSockaddr->sa_family;
465*a466cc55SCy Schubert 	isc_netaddr_fromsockaddr(&iter->current.address,
466*a466cc55SCy Schubert 	    (isc_sockaddr_t *)addr->Address.lpSockaddr);
467*a466cc55SCy Schubert 	if (AF_INET6 == iter->current.af)
468*a466cc55SCy Schubert 		iter->current.ifindex = adap->Ipv6IfIndex;
469*a466cc55SCy Schubert 	iter->current.name[0] = '\0';
470*a466cc55SCy Schubert 	WideCharToMultiByte(
471*a466cc55SCy Schubert 		CP_ACP,
472*a466cc55SCy Schubert 		0,
473*a466cc55SCy Schubert 		adap->FriendlyName,
474*a466cc55SCy Schubert 		-1,
475*a466cc55SCy Schubert 		iter->current.name,
476*a466cc55SCy Schubert 		sizeof(iter->current.name),
477*a466cc55SCy Schubert 		NULL,
478*a466cc55SCy Schubert 		NULL);
479*a466cc55SCy Schubert 	iter->current.name[sizeof(iter->current.name) - 1] = '\0';
480*a466cc55SCy Schubert 	if (IfOperStatusUp == adap->OperStatus)
481*a466cc55SCy Schubert 		iter->current.flags |= INTERFACE_F_UP;
482*a466cc55SCy Schubert 	if (IF_TYPE_PPP == adap->IfType)
483*a466cc55SCy Schubert 		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
484*a466cc55SCy Schubert 	else if (IF_TYPE_SOFTWARE_LOOPBACK == adap->IfType)
485*a466cc55SCy Schubert 		iter->current.flags |= INTERFACE_F_LOOPBACK;
486*a466cc55SCy Schubert 	if ((IP_ADAPTER_NO_MULTICAST & adap->Flags) == 0)
487*a466cc55SCy Schubert 		iter->current.flags |= INTERFACE_F_MULTICAST;
488*a466cc55SCy Schubert 	if (IpSuffixOriginRandom == addr->SuffixOrigin)
489*a466cc55SCy Schubert 		iter->current.flags |= INTERFACE_F_PRIVACY;
490*a466cc55SCy Schubert 
491*a466cc55SCy Schubert 	prefix_len = GAA_find_prefix(iter);
492*a466cc55SCy Schubert 	/* I'm failing to see a broadcast flag via GAA */
493*a466cc55SCy Schubert 	if (AF_INET == iter->current.af && prefix_len < 32 &&
494*a466cc55SCy Schubert 	    (INTERFACE_F_LOOPBACK & iter->current.flags) == 0) {
495*a466cc55SCy Schubert 		iter->current.flags |= INTERFACE_F_BROADCAST;
496*a466cc55SCy Schubert 		get_broadcastaddr(&iter->current.broadcast,
497*a466cc55SCy Schubert 				  &iter->current.address,
498*a466cc55SCy Schubert 				  &iter->current.netmask);
499*a466cc55SCy Schubert 	}
500*a466cc55SCy Schubert 	return (ISC_R_SUCCESS);
501*a466cc55SCy Schubert }
502*a466cc55SCy Schubert 
503*a466cc55SCy Schubert /*
504*a466cc55SCy Schubert  * Get information about the current interface to iter->current.
505*a466cc55SCy Schubert  * If successful, return ISC_R_SUCCESS.
506*a466cc55SCy Schubert  * If the interface has an unsupported address family, or if
507*a466cc55SCy Schubert  * some operation on it fails, return ISC_R_IGNORE to make
508*a466cc55SCy Schubert  * the higher-level iterator code ignore it.
509*a466cc55SCy Schubert  */
510*a466cc55SCy Schubert 
511*a466cc55SCy Schubert static isc_result_t
internal_current(isc_interfaceiter_t * iter)512*a466cc55SCy Schubert internal_current(isc_interfaceiter_t *iter) {
513*a466cc55SCy Schubert 	BOOL ifNamed = FALSE;
514*a466cc55SCy Schubert 	unsigned long flags;
515*a466cc55SCy Schubert 
516*a466cc55SCy Schubert 	REQUIRE(VALID_IFITER(iter));
517*a466cc55SCy Schubert 	REQUIRE(iter->numIF >= 0);
518*a466cc55SCy Schubert 
519*a466cc55SCy Schubert 	memset(&iter->current, 0, sizeof(iter->current));
520*a466cc55SCy Schubert 	iter->current.af = AF_INET;
521*a466cc55SCy Schubert 
522*a466cc55SCy Schubert 	isc_netaddr_fromsockaddr(&iter->current.address,
523*a466cc55SCy Schubert 	    (isc_sockaddr_t *)&(iter->IFData.iiAddress));
524*a466cc55SCy Schubert 
525*a466cc55SCy Schubert 	/*
526*a466cc55SCy Schubert 	 * Get interface flags.
527*a466cc55SCy Schubert 	 */
528*a466cc55SCy Schubert 
529*a466cc55SCy Schubert 	iter->current.flags = 0;
530*a466cc55SCy Schubert 	flags = iter->IFData.iiFlags;
531*a466cc55SCy Schubert 
532*a466cc55SCy Schubert 	if ((flags & IFF_UP) != 0)
533*a466cc55SCy Schubert 		iter->current.flags |= INTERFACE_F_UP;
534*a466cc55SCy Schubert 
535*a466cc55SCy Schubert 	if ((flags & IFF_BROADCAST) != 0)
536*a466cc55SCy Schubert 		iter->current.flags |= INTERFACE_F_BROADCAST;
537*a466cc55SCy Schubert 
538*a466cc55SCy Schubert 	if ((flags & IFF_MULTICAST) != 0)
539*a466cc55SCy Schubert 		iter->current.flags |= INTERFACE_F_MULTICAST;
540*a466cc55SCy Schubert 
541*a466cc55SCy Schubert 	if ((flags & IFF_POINTTOPOINT) != 0) {
542*a466cc55SCy Schubert 		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
543*a466cc55SCy Schubert 		snprintf(iter->current.name, sizeof(iter->current.name),
544*a466cc55SCy Schubert 			 "PPP %d", iter->numIF);
545*a466cc55SCy Schubert 		ifNamed = TRUE;
546*a466cc55SCy Schubert 	}
547*a466cc55SCy Schubert 
548*a466cc55SCy Schubert 	if ((flags & IFF_LOOPBACK) != 0) {
549*a466cc55SCy Schubert 		iter->current.flags |= INTERFACE_F_LOOPBACK;
550*a466cc55SCy Schubert 		snprintf(iter->current.name, sizeof(iter->current.name),
551*a466cc55SCy Schubert 			"v4loop %d", iter->numIF);
552*a466cc55SCy Schubert 		ifNamed = TRUE;
553*a466cc55SCy Schubert 	}
554*a466cc55SCy Schubert 
555*a466cc55SCy Schubert 	/*
556*a466cc55SCy Schubert 	 * If the interface is point-to-point, get the destination address.
557*a466cc55SCy Schubert 	 */
558*a466cc55SCy Schubert 	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0)
559*a466cc55SCy Schubert 		isc_netaddr_fromsockaddr(&iter->current.dstaddress,
560*a466cc55SCy Schubert 		    (isc_sockaddr_t *)&(iter->IFData.iiBroadcastAddress));
561*a466cc55SCy Schubert 
562*a466cc55SCy Schubert 	/*
563*a466cc55SCy Schubert 	 * Get the network mask.
564*a466cc55SCy Schubert 	 */
565*a466cc55SCy Schubert 	isc_netaddr_fromsockaddr(&iter->current.netmask,
566*a466cc55SCy Schubert 	    (isc_sockaddr_t *)&(iter->IFData.iiNetmask));
567*a466cc55SCy Schubert 
568*a466cc55SCy Schubert 	/*
569*a466cc55SCy Schubert 	 * If the interface is broadcast, get the broadcast address,
570*a466cc55SCy Schubert 	 * based on the unicast address and network mask.
571*a466cc55SCy Schubert 	 */
572*a466cc55SCy Schubert 	if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0)
573*a466cc55SCy Schubert 		get_broadcastaddr(&iter->current.broadcast,
574*a466cc55SCy Schubert 				  &iter->current.address,
575*a466cc55SCy Schubert 				  &iter->current.netmask);
576*a466cc55SCy Schubert 
577*a466cc55SCy Schubert 	if (ifNamed == FALSE)
578*a466cc55SCy Schubert 		snprintf(iter->current.name, sizeof(iter->current.name),
579*a466cc55SCy Schubert 			"IPv4 %d", iter->numIF);
580*a466cc55SCy Schubert 
581*a466cc55SCy Schubert 	return (ISC_R_SUCCESS);
582*a466cc55SCy Schubert }
583*a466cc55SCy Schubert 
584*a466cc55SCy Schubert static isc_result_t
internal_current6(isc_interfaceiter_t * iter)585*a466cc55SCy Schubert internal_current6(isc_interfaceiter_t *iter) {
586*a466cc55SCy Schubert 	BOOL ifNamed = FALSE;
587*a466cc55SCy Schubert 	struct sockaddr_in6 *psa6;
588*a466cc55SCy Schubert 	BOOL localhostSeen;
589*a466cc55SCy Schubert 	int i;
590*a466cc55SCy Schubert 
591*a466cc55SCy Schubert 	REQUIRE(VALID_IFITER(iter));
592*a466cc55SCy Schubert 	REQUIRE(iter->pos6 >= 0);
593*a466cc55SCy Schubert 	REQUIRE(iter->buf6 != 0);
594*a466cc55SCy Schubert 
595*a466cc55SCy Schubert 	memset(&iter->current, 0, sizeof(iter->current));
596*a466cc55SCy Schubert 	iter->current.af = AF_INET6;
597*a466cc55SCy Schubert 
598*a466cc55SCy Schubert 	/*
599*a466cc55SCy Schubert 	 * synthesize localhost ::1 before returning the rest, if ::1
600*a466cc55SCy Schubert 	 * is not on the list.
601*a466cc55SCy Schubert 	 */
602*a466cc55SCy Schubert 	if (iter->pos6 >= (unsigned)iter->buf6->iAddressCount) {
603*a466cc55SCy Schubert 		localhostSeen = FALSE;
604*a466cc55SCy Schubert 		for (i = 0; i < iter->buf6->iAddressCount; i++) {
605*a466cc55SCy Schubert 			psa6 = (struct sockaddr_in6 *)
606*a466cc55SCy Schubert 			       iter->buf6->Address[i].lpSockaddr;
607*a466cc55SCy Schubert 			if (!memcmp(&iter->loop__1, &psa6->sin6_addr,
608*a466cc55SCy Schubert 				    sizeof(iter->loop__1))) {
609*a466cc55SCy Schubert 				localhostSeen = TRUE;
610*a466cc55SCy Schubert 				break;
611*a466cc55SCy Schubert 			}
612*a466cc55SCy Schubert 		}
613*a466cc55SCy Schubert 		if (localhostSeen)
614*a466cc55SCy Schubert 			iter->pos6 = iter->buf6->iAddressCount - 1;
615*a466cc55SCy Schubert 	}
616*a466cc55SCy Schubert 
617*a466cc55SCy Schubert 	if (iter->pos6 < (unsigned)iter->buf6->iAddressCount) {
618*a466cc55SCy Schubert 		isc_netaddr_fromsockaddr(&iter->current.address,
619*a466cc55SCy Schubert 		    (isc_sockaddr_t *)iter->buf6->Address[iter->pos6].lpSockaddr);
620*a466cc55SCy Schubert 	} else {
621*a466cc55SCy Schubert 		iter->current.address.family = AF_INET6;
622*a466cc55SCy Schubert 		memcpy(&iter->current.address.type.in6, &iter->loop__1,
623*a466cc55SCy Schubert 		       sizeof(iter->current.address.type.in6));
624*a466cc55SCy Schubert 	}
625*a466cc55SCy Schubert 
626*a466cc55SCy Schubert 	/*
627*a466cc55SCy Schubert 	 * Get interface flags.
628*a466cc55SCy Schubert 	 */
629*a466cc55SCy Schubert 
630*a466cc55SCy Schubert 	iter->current.flags = INTERFACE_F_UP | INTERFACE_F_MULTICAST;
631*a466cc55SCy Schubert 
632*a466cc55SCy Schubert 	if (!memcmp(&iter->current.address.type.in6, &iter->loop__1,
633*a466cc55SCy Schubert 		    sizeof(iter->current.address.type.in6)) ||
634*a466cc55SCy Schubert 	    !memcmp(&iter->current.address.type.in6, &iter->loopfe80__1,
635*a466cc55SCy Schubert 	            sizeof(iter->current.address.type.in6))) {
636*a466cc55SCy Schubert 
637*a466cc55SCy Schubert 		iter->current.flags |= INTERFACE_F_LOOPBACK;
638*a466cc55SCy Schubert 		snprintf(iter->current.name, sizeof(iter->current.name),
639*a466cc55SCy Schubert 			 "v6loop %d",
640*a466cc55SCy Schubert 			 iter->buf6->iAddressCount - iter->pos6);
641*a466cc55SCy Schubert 		ifNamed = TRUE;
642*a466cc55SCy Schubert 	}
643*a466cc55SCy Schubert 
644*a466cc55SCy Schubert 	if (ifNamed == FALSE)
645*a466cc55SCy Schubert 		snprintf(iter->current.name, sizeof(iter->current.name),
646*a466cc55SCy Schubert 			 "IPv6 %d",
647*a466cc55SCy Schubert 			 iter->buf6->iAddressCount - iter->pos6);
648*a466cc55SCy Schubert 
649*a466cc55SCy Schubert 	memset(iter->current.netmask.type.in6.s6_addr, 0xff,
650*a466cc55SCy Schubert 	       sizeof(iter->current.netmask.type.in6.s6_addr));
651*a466cc55SCy Schubert 	iter->current.netmask.family = AF_INET6;
652*a466cc55SCy Schubert 	return (ISC_R_SUCCESS);
653*a466cc55SCy Schubert }
654*a466cc55SCy Schubert 
655*a466cc55SCy Schubert static isc_result_t
internal_next_GAA(isc_interfaceiter_t * iter)656*a466cc55SCy Schubert internal_next_GAA(isc_interfaceiter_t *iter) {
657*a466cc55SCy Schubert 	REQUIRE(use_GAA);
658*a466cc55SCy Schubert 	if (NULL == iter->ipaaCur)
659*a466cc55SCy Schubert 		return (ISC_R_NOMORE);
660*a466cc55SCy Schubert 	if (NULL == iter->ipuaCur)
661*a466cc55SCy Schubert 		iter->ipuaCur = iter->ipaaCur->FirstUnicastAddress;
662*a466cc55SCy Schubert 	else
663*a466cc55SCy Schubert 		iter->ipuaCur = iter->ipuaCur->Next;
664*a466cc55SCy Schubert 	while (NULL == iter->ipuaCur) {
665*a466cc55SCy Schubert 		iter->ipaaCur = iter->ipaaCur->Next;
666*a466cc55SCy Schubert 		if (NULL == iter->ipaaCur)
667*a466cc55SCy Schubert 			return (ISC_R_NOMORE);
668*a466cc55SCy Schubert 		iter->ipuaCur = iter->ipaaCur->FirstUnicastAddress;
669*a466cc55SCy Schubert 	}
670*a466cc55SCy Schubert 	return (ISC_R_SUCCESS);
671*a466cc55SCy Schubert }
672*a466cc55SCy Schubert 
673*a466cc55SCy Schubert /*
674*a466cc55SCy Schubert  * Step the iterator to the next interface.  Unlike
675*a466cc55SCy Schubert  * isc_interfaceiter_next(), this may leave the iterator
676*a466cc55SCy Schubert  * positioned on an interface that will ultimately
677*a466cc55SCy Schubert  * be ignored.  Return ISC_R_NOMORE if there are no more
678*a466cc55SCy Schubert  * interfaces, otherwise ISC_R_SUCCESS.
679*a466cc55SCy Schubert  */
680*a466cc55SCy Schubert static isc_result_t
internal_next(isc_interfaceiter_t * iter)681*a466cc55SCy Schubert internal_next(isc_interfaceiter_t *iter) {
682*a466cc55SCy Schubert 	if (iter->numIF >= iter->v4IF)
683*a466cc55SCy Schubert 		return (ISC_R_NOMORE);
684*a466cc55SCy Schubert 
685*a466cc55SCy Schubert 	/*
686*a466cc55SCy Schubert 	 * The first one needs to be set up to point to the last
687*a466cc55SCy Schubert 	 * Element of the array.  Go to the end and back up
688*a466cc55SCy Schubert 	 * Microsoft's implementation is peculiar for returning
689*a466cc55SCy Schubert 	 * the list in reverse order
690*a466cc55SCy Schubert 	 */
691*a466cc55SCy Schubert 
692*a466cc55SCy Schubert 	if (iter->numIF == 0)
693*a466cc55SCy Schubert 		iter->pos4 = (INTERFACE_INFO *)(iter->buf4 + (iter->v4IF));
694*a466cc55SCy Schubert 
695*a466cc55SCy Schubert 	iter->pos4--;
696*a466cc55SCy Schubert 	if (&(iter->pos4) < &(iter->buf4))
697*a466cc55SCy Schubert 		return (ISC_R_NOMORE);
698*a466cc55SCy Schubert 
699*a466cc55SCy Schubert 	memset(&(iter->IFData), 0, sizeof(INTERFACE_INFO));
700*a466cc55SCy Schubert 	memcpy(&(iter->IFData), iter->pos4, sizeof(INTERFACE_INFO));
701*a466cc55SCy Schubert 	iter->numIF++;
702*a466cc55SCy Schubert 
703*a466cc55SCy Schubert 	return (ISC_R_SUCCESS);
704*a466cc55SCy Schubert }
705*a466cc55SCy Schubert 
706*a466cc55SCy Schubert static isc_result_t
internal_next6(isc_interfaceiter_t * iter)707*a466cc55SCy Schubert internal_next6(isc_interfaceiter_t *iter) {
708*a466cc55SCy Schubert 	if (iter->pos6 == 0)
709*a466cc55SCy Schubert 		return (ISC_R_NOMORE);
710*a466cc55SCy Schubert 	iter->pos6--;
711*a466cc55SCy Schubert 	return (ISC_R_SUCCESS);
712*a466cc55SCy Schubert }
713*a466cc55SCy Schubert 
714*a466cc55SCy Schubert isc_result_t
isc_interfaceiter_current(isc_interfaceiter_t * iter,isc_interface_t * ifdata)715*a466cc55SCy Schubert isc_interfaceiter_current(isc_interfaceiter_t *iter,
716*a466cc55SCy Schubert 			  isc_interface_t *ifdata) {
717*a466cc55SCy Schubert 	REQUIRE(iter->result == ISC_R_SUCCESS);
718*a466cc55SCy Schubert 	memcpy(ifdata, &iter->current, sizeof(*ifdata));
719*a466cc55SCy Schubert 	return (ISC_R_SUCCESS);
720*a466cc55SCy Schubert }
721*a466cc55SCy Schubert 
722*a466cc55SCy Schubert isc_result_t
isc_interfaceiter_first(isc_interfaceiter_t * iter)723*a466cc55SCy Schubert isc_interfaceiter_first(isc_interfaceiter_t *iter) {
724*a466cc55SCy Schubert 	REQUIRE(VALID_IFITER(iter));
725*a466cc55SCy Schubert 	REQUIRE(use_GAA_determined);
726*a466cc55SCy Schubert 	/*
727*a466cc55SCy Schubert 	 * SIO_ADDRESS_LIST_QUERY (used to query IPv6 addresses)
728*a466cc55SCy Schubert 	 * intentionally omits localhost addresses [::1] and [::fe80] in
729*a466cc55SCy Schubert 	 * some cases.  ntpd depends on enumerating [::1] to listen on
730*a466cc55SCy Schubert 	 * it, and ntpq and ntpdc default to "localhost" as the target,
731*a466cc55SCy Schubert 	 * so they will attempt to talk to [::1]:123 and fail. This
732*a466cc55SCy Schubert 	 * means we need to synthesize ::1, which we will do first,
733*a466cc55SCy Schubert 	 * hence iAddressCount + 1.  internal_next6() will decrement
734*a466cc55SCy Schubert 	 * it before the first use as an index, and internal_current6()
735*a466cc55SCy Schubert 	 * will treat pos6 == iAddressCount as a sign to synthesize
736*a466cc55SCy Schubert 	 * [::1] if needed.
737*a466cc55SCy Schubert 	 */
738*a466cc55SCy Schubert 	if (!use_GAA && iter->buf6 != NULL)
739*a466cc55SCy Schubert 		iter->pos6 = iter->buf6->iAddressCount + 1;
740*a466cc55SCy Schubert 	iter->result = ISC_R_SUCCESS;
741*a466cc55SCy Schubert 	return (isc_interfaceiter_next(iter));
742*a466cc55SCy Schubert }
743*a466cc55SCy Schubert 
744*a466cc55SCy Schubert isc_result_t
isc_interfaceiter_next(isc_interfaceiter_t * iter)745*a466cc55SCy Schubert isc_interfaceiter_next(isc_interfaceiter_t *iter) {
746*a466cc55SCy Schubert 	isc_result_t result;
747*a466cc55SCy Schubert 
748*a466cc55SCy Schubert 	REQUIRE(VALID_IFITER(iter));
749*a466cc55SCy Schubert 	REQUIRE(iter->result == ISC_R_SUCCESS);
750*a466cc55SCy Schubert 	REQUIRE(use_GAA_determined);
751*a466cc55SCy Schubert 
752*a466cc55SCy Schubert 	if (use_GAA) {
753*a466cc55SCy Schubert 		do {
754*a466cc55SCy Schubert 			result = internal_next_GAA(iter);
755*a466cc55SCy Schubert 			if (ISC_R_NOMORE == result)
756*a466cc55SCy Schubert 				goto set_result;
757*a466cc55SCy Schubert 			result = internal_current_GAA(iter);
758*a466cc55SCy Schubert 		} while (ISC_R_IGNORE == result);
759*a466cc55SCy Schubert 		goto set_result;
760*a466cc55SCy Schubert 	}
761*a466cc55SCy Schubert 
762*a466cc55SCy Schubert 	for (;;) {
763*a466cc55SCy Schubert 		result = internal_next(iter);
764*a466cc55SCy Schubert 		if (result == ISC_R_NOMORE) {
765*a466cc55SCy Schubert 			result = internal_next6(iter);
766*a466cc55SCy Schubert 			if (result != ISC_R_SUCCESS)
767*a466cc55SCy Schubert 				break;
768*a466cc55SCy Schubert 			result = internal_current6(iter);
769*a466cc55SCy Schubert 			if (result != ISC_R_IGNORE)
770*a466cc55SCy Schubert 				break;
771*a466cc55SCy Schubert 		} else if (result != ISC_R_SUCCESS)
772*a466cc55SCy Schubert 			break;
773*a466cc55SCy Schubert 		result = internal_current(iter);
774*a466cc55SCy Schubert 		if (result != ISC_R_IGNORE)
775*a466cc55SCy Schubert 			break;
776*a466cc55SCy Schubert 	}
777*a466cc55SCy Schubert  set_result:
778*a466cc55SCy Schubert 	iter->result = result;
779*a466cc55SCy Schubert 	return (result);
780*a466cc55SCy Schubert }
781*a466cc55SCy Schubert 
782*a466cc55SCy Schubert void
isc_interfaceiter_destroy(isc_interfaceiter_t ** iterp)783*a466cc55SCy Schubert isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) {
784*a466cc55SCy Schubert 	isc_interfaceiter_t *iter;
785*a466cc55SCy Schubert 
786*a466cc55SCy Schubert 	REQUIRE(iterp != NULL);
787*a466cc55SCy Schubert 	iter = *iterp;
788*a466cc55SCy Schubert 	REQUIRE(VALID_IFITER(iter));
789*a466cc55SCy Schubert 	REQUIRE(use_GAA_determined);
790*a466cc55SCy Schubert 
791*a466cc55SCy Schubert 	if (use_GAA) {
792*a466cc55SCy Schubert 		REQUIRE(NULL == iter->buf4);
793*a466cc55SCy Schubert 		REQUIRE(NULL == iter->buf4);
794*a466cc55SCy Schubert 		if (iter->ipaa != NULL)
795*a466cc55SCy Schubert 			isc_mem_put(iter->mctx, iter->ipaa, iter->ipaasize);
796*a466cc55SCy Schubert 	} else {
797*a466cc55SCy Schubert 		REQUIRE(NULL == iter->ipaa);
798*a466cc55SCy Schubert 		if (iter->buf4 != NULL)
799*a466cc55SCy Schubert 			isc_mem_put(iter->mctx, iter->buf4, iter->buf4size);
800*a466cc55SCy Schubert 		if (iter->buf6 != NULL)
801*a466cc55SCy Schubert 			isc_mem_put(iter->mctx, iter->buf6, iter->buf6size);
802*a466cc55SCy Schubert 	}
803*a466cc55SCy Schubert 
804*a466cc55SCy Schubert 	iter->magic = 0;
805*a466cc55SCy Schubert 	isc_mem_put(iter->mctx, iter, sizeof(*iter));
806*a466cc55SCy Schubert 	*iterp = NULL;
807*a466cc55SCy Schubert }
808