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