xref: /minix3/external/bsd/bind/dist/lib/isc/win32/interfaceiter.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: interfaceiter.c,v 1.6 2014/12/10 04:38:01 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2004, 2007-2009, 2013, 2014  Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek  * Copyright (C) 1999-2001  Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek  *
7*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek  *
11*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek  * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek  */
19*00b67f09SDavid van Moolenbroek 
20*00b67f09SDavid van Moolenbroek /* Id: interfaceiter.c,v 1.15 2009/01/18 23:48:14 tbox Exp  */
21*00b67f09SDavid van Moolenbroek 
22*00b67f09SDavid van Moolenbroek /*
23*00b67f09SDavid van Moolenbroek  * Note that this code will need to be revisited to support IPv6 Interfaces.
24*00b67f09SDavid van Moolenbroek  * For now we just iterate through IPv4 interfaces.
25*00b67f09SDavid van Moolenbroek  */
26*00b67f09SDavid van Moolenbroek 
27*00b67f09SDavid van Moolenbroek #include <config.h>
28*00b67f09SDavid van Moolenbroek #include <winsock2.h>
29*00b67f09SDavid van Moolenbroek #include <ws2tcpip.h>
30*00b67f09SDavid van Moolenbroek #include <sys/types.h>
31*00b67f09SDavid van Moolenbroek 
32*00b67f09SDavid van Moolenbroek #include <stdio.h>
33*00b67f09SDavid van Moolenbroek #include <stdlib.h>
34*00b67f09SDavid van Moolenbroek #include <errno.h>
35*00b67f09SDavid van Moolenbroek 
36*00b67f09SDavid van Moolenbroek #include <isc/interfaceiter.h>
37*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
38*00b67f09SDavid van Moolenbroek #include <isc/result.h>
39*00b67f09SDavid van Moolenbroek #include <isc/string.h>
40*00b67f09SDavid van Moolenbroek #include <isc/strerror.h>
41*00b67f09SDavid van Moolenbroek #include <isc/types.h>
42*00b67f09SDavid van Moolenbroek #include <isc/util.h>
43*00b67f09SDavid van Moolenbroek 
44*00b67f09SDavid van Moolenbroek void InitSockets(void);
45*00b67f09SDavid van Moolenbroek 
46*00b67f09SDavid van Moolenbroek /* Common utility functions */
47*00b67f09SDavid van Moolenbroek 
48*00b67f09SDavid van Moolenbroek /*
49*00b67f09SDavid van Moolenbroek  * Extract the network address part from a "struct sockaddr".
50*00b67f09SDavid van Moolenbroek  *
51*00b67f09SDavid van Moolenbroek  * The address family is given explicitly
52*00b67f09SDavid van Moolenbroek  * instead of using src->sa_family, because the latter does not work
53*00b67f09SDavid van Moolenbroek  * for copying a network mask obtained by SIOCGIFNETMASK (it does
54*00b67f09SDavid van Moolenbroek  * not have a valid address family).
55*00b67f09SDavid van Moolenbroek  */
56*00b67f09SDavid van Moolenbroek 
57*00b67f09SDavid van Moolenbroek 
58*00b67f09SDavid van Moolenbroek #define IFITER_MAGIC		0x49464954U	/* IFIT. */
59*00b67f09SDavid van Moolenbroek #define VALID_IFITER(t)		((t) != NULL && (t)->magic == IFITER_MAGIC)
60*00b67f09SDavid van Moolenbroek 
61*00b67f09SDavid van Moolenbroek struct isc_interfaceiter {
62*00b67f09SDavid van Moolenbroek 	unsigned int		magic;		/* Magic number. */
63*00b67f09SDavid van Moolenbroek 	isc_mem_t		*mctx;
64*00b67f09SDavid van Moolenbroek 	SOCKET			socket;
65*00b67f09SDavid van Moolenbroek 	INTERFACE_INFO		IFData;		/* Current Interface Info */
66*00b67f09SDavid van Moolenbroek 	int			numIF;		/* Current Interface count */
67*00b67f09SDavid van Moolenbroek 	int			v4IF;		/* Number of IPv4 Interfaces */
68*00b67f09SDavid van Moolenbroek 	INTERFACE_INFO		*buf4;		/* Buffer for WSAIoctl data. */
69*00b67f09SDavid van Moolenbroek 	unsigned int		buf4size;	/* Bytes allocated. */
70*00b67f09SDavid van Moolenbroek 	INTERFACE_INFO		*pos4;		/* Current offset in IF List */
71*00b67f09SDavid van Moolenbroek 	SOCKET_ADDRESS_LIST	*buf6;
72*00b67f09SDavid van Moolenbroek 	unsigned int		buf6size;	/* Bytes allocated. */
73*00b67f09SDavid van Moolenbroek 	unsigned int		pos6;
74*00b67f09SDavid van Moolenbroek 	isc_interface_t		current;	/* Current interface data. */
75*00b67f09SDavid van Moolenbroek 	isc_result_t		result;		/* Last result code. */
76*00b67f09SDavid van Moolenbroek };
77*00b67f09SDavid van Moolenbroek 
78*00b67f09SDavid van Moolenbroek 
79*00b67f09SDavid van Moolenbroek /*
80*00b67f09SDavid van Moolenbroek  * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces.
81*00b67f09SDavid van Moolenbroek  * We assume no sane system will have more than than 1K of IP addresses on
82*00b67f09SDavid van Moolenbroek  * all of its adapters.
83*00b67f09SDavid van Moolenbroek  */
84*00b67f09SDavid van Moolenbroek #define IFCONF_SIZE_INITIAL	  16
85*00b67f09SDavid van Moolenbroek #define IFCONF_SIZE_INCREMENT	  64
86*00b67f09SDavid van Moolenbroek #define IFCONF_SIZE_MAX		1040
87*00b67f09SDavid van Moolenbroek 
88*00b67f09SDavid van Moolenbroek static void
get_addr(unsigned int family,isc_netaddr_t * dst,struct sockaddr * src)89*00b67f09SDavid van Moolenbroek get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src) {
90*00b67f09SDavid van Moolenbroek 	dst->family = family;
91*00b67f09SDavid van Moolenbroek 	switch (family) {
92*00b67f09SDavid van Moolenbroek 	case AF_INET:
93*00b67f09SDavid van Moolenbroek 		memmove(&dst->type.in,
94*00b67f09SDavid van Moolenbroek 			&((struct sockaddr_in *) src)->sin_addr,
95*00b67f09SDavid van Moolenbroek 			sizeof(struct in_addr));
96*00b67f09SDavid van Moolenbroek 		break;
97*00b67f09SDavid van Moolenbroek 	case	AF_INET6:
98*00b67f09SDavid van Moolenbroek 		memmove(&dst->type.in6,
99*00b67f09SDavid van Moolenbroek 			&((struct sockaddr_in6 *) src)->sin6_addr,
100*00b67f09SDavid van Moolenbroek 			sizeof(struct in6_addr));
101*00b67f09SDavid van Moolenbroek 		dst->zone = ((struct sockaddr_in6 *) src)->sin6_scope_id;
102*00b67f09SDavid van Moolenbroek 		break;
103*00b67f09SDavid van Moolenbroek 	default:
104*00b67f09SDavid van Moolenbroek 		INSIST(0);
105*00b67f09SDavid van Moolenbroek 		break;
106*00b67f09SDavid van Moolenbroek 	}
107*00b67f09SDavid van Moolenbroek }
108*00b67f09SDavid van Moolenbroek 
109*00b67f09SDavid van Moolenbroek isc_result_t
isc_interfaceiter_create(isc_mem_t * mctx,isc_interfaceiter_t ** iterp)110*00b67f09SDavid van Moolenbroek isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
111*00b67f09SDavid van Moolenbroek 	char strbuf[ISC_STRERRORSIZE];
112*00b67f09SDavid van Moolenbroek 	isc_interfaceiter_t *iter;
113*00b67f09SDavid van Moolenbroek 	isc_result_t result;
114*00b67f09SDavid van Moolenbroek 	int error;
115*00b67f09SDavid van Moolenbroek 	unsigned long bytesReturned = 0;
116*00b67f09SDavid van Moolenbroek 
117*00b67f09SDavid van Moolenbroek 	REQUIRE(mctx != NULL);
118*00b67f09SDavid van Moolenbroek 	REQUIRE(iterp != NULL);
119*00b67f09SDavid van Moolenbroek 	REQUIRE(*iterp == NULL);
120*00b67f09SDavid van Moolenbroek 
121*00b67f09SDavid van Moolenbroek 	iter = isc_mem_get(mctx, sizeof(*iter));
122*00b67f09SDavid van Moolenbroek 	if (iter == NULL)
123*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
124*00b67f09SDavid van Moolenbroek 
125*00b67f09SDavid van Moolenbroek 	InitSockets();
126*00b67f09SDavid van Moolenbroek 
127*00b67f09SDavid van Moolenbroek 	iter->mctx = mctx;
128*00b67f09SDavid van Moolenbroek 	iter->buf4 = NULL;
129*00b67f09SDavid van Moolenbroek 	iter->buf6 = NULL;
130*00b67f09SDavid van Moolenbroek 	iter->pos4 = NULL;
131*00b67f09SDavid van Moolenbroek 	iter->pos6 = 0;
132*00b67f09SDavid van Moolenbroek 	iter->buf6size = 0;
133*00b67f09SDavid van Moolenbroek 	iter->buf4size = 0;
134*00b67f09SDavid van Moolenbroek 	iter->result = ISC_R_FAILURE;
135*00b67f09SDavid van Moolenbroek 	iter->numIF = 0;
136*00b67f09SDavid van Moolenbroek 	iter->v4IF = 0;
137*00b67f09SDavid van Moolenbroek 
138*00b67f09SDavid van Moolenbroek 	/*
139*00b67f09SDavid van Moolenbroek 	 * Create an unbound datagram socket to do the
140*00b67f09SDavid van Moolenbroek 	 * SIO_GET_INTERFACE_LIST WSAIoctl on.
141*00b67f09SDavid van Moolenbroek 	 */
142*00b67f09SDavid van Moolenbroek 	iter->socket = socket(AF_INET, SOCK_DGRAM, 0);
143*00b67f09SDavid van Moolenbroek 	if (iter->socket == INVALID_SOCKET) {
144*00b67f09SDavid van Moolenbroek 		error = WSAGetLastError();
145*00b67f09SDavid van Moolenbroek 		if (error == WSAEAFNOSUPPORT)
146*00b67f09SDavid van Moolenbroek 			goto inet6_only;
147*00b67f09SDavid van Moolenbroek 		isc__strerror(error, strbuf, sizeof(strbuf));
148*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__,
149*00b67f09SDavid van Moolenbroek 				"making interface scan socket: %s",
150*00b67f09SDavid van Moolenbroek 				strbuf);
151*00b67f09SDavid van Moolenbroek 		result = ISC_R_UNEXPECTED;
152*00b67f09SDavid van Moolenbroek 		goto socket_failure;
153*00b67f09SDavid van Moolenbroek 	}
154*00b67f09SDavid van Moolenbroek 
155*00b67f09SDavid van Moolenbroek 	/*
156*00b67f09SDavid van Moolenbroek 	 * Get the interface configuration, allocating more memory if
157*00b67f09SDavid van Moolenbroek 	 * necessary.
158*00b67f09SDavid van Moolenbroek 	 */
159*00b67f09SDavid van Moolenbroek 	iter->buf4size = IFCONF_SIZE_INITIAL*sizeof(INTERFACE_INFO);
160*00b67f09SDavid van Moolenbroek 
161*00b67f09SDavid van Moolenbroek 	for (;;) {
162*00b67f09SDavid van Moolenbroek 		iter->buf4 = isc_mem_get(mctx, iter->buf4size);
163*00b67f09SDavid van Moolenbroek 		if (iter->buf4 == NULL) {
164*00b67f09SDavid van Moolenbroek 			result = ISC_R_NOMEMORY;
165*00b67f09SDavid van Moolenbroek 			goto alloc_failure;
166*00b67f09SDavid van Moolenbroek 		}
167*00b67f09SDavid van Moolenbroek 
168*00b67f09SDavid van Moolenbroek 		if (WSAIoctl(iter->socket, SIO_GET_INTERFACE_LIST,
169*00b67f09SDavid van Moolenbroek 			     0, 0, iter->buf4, iter->buf4size,
170*00b67f09SDavid van Moolenbroek 			     &bytesReturned, 0, 0) == SOCKET_ERROR)
171*00b67f09SDavid van Moolenbroek 		{
172*00b67f09SDavid van Moolenbroek 			error = WSAGetLastError();
173*00b67f09SDavid van Moolenbroek 			if (error != WSAEFAULT && error != WSAENOBUFS) {
174*00b67f09SDavid van Moolenbroek 				errno = error;
175*00b67f09SDavid van Moolenbroek 				isc__strerror(error, strbuf, sizeof(strbuf));
176*00b67f09SDavid van Moolenbroek 				UNEXPECTED_ERROR(__FILE__, __LINE__,
177*00b67f09SDavid van Moolenbroek 						"get interface configuration: %s",
178*00b67f09SDavid van Moolenbroek 						strbuf);
179*00b67f09SDavid van Moolenbroek 				result = ISC_R_UNEXPECTED;
180*00b67f09SDavid van Moolenbroek 				goto ioctl_failure;
181*00b67f09SDavid van Moolenbroek 			}
182*00b67f09SDavid van Moolenbroek 			/*
183*00b67f09SDavid van Moolenbroek 			 * EINVAL.  Retry with a bigger buffer.
184*00b67f09SDavid van Moolenbroek 			 */
185*00b67f09SDavid van Moolenbroek 		} else {
186*00b67f09SDavid van Moolenbroek 			/*
187*00b67f09SDavid van Moolenbroek 			 * The WSAIoctl succeeded.
188*00b67f09SDavid van Moolenbroek 			 * If the number of the returned bytes is the same
189*00b67f09SDavid van Moolenbroek 			 * as the buffer size, we will grow it just in
190*00b67f09SDavid van Moolenbroek 			 * case and retry.
191*00b67f09SDavid van Moolenbroek 			 */
192*00b67f09SDavid van Moolenbroek 			if (bytesReturned > 0 &&
193*00b67f09SDavid van Moolenbroek 			    (bytesReturned < iter->buf4size))
194*00b67f09SDavid van Moolenbroek 				break;
195*00b67f09SDavid van Moolenbroek 		}
196*00b67f09SDavid van Moolenbroek 		if (iter->buf4size >= IFCONF_SIZE_MAX*sizeof(INTERFACE_INFO)) {
197*00b67f09SDavid van Moolenbroek 			UNEXPECTED_ERROR(__FILE__, __LINE__,
198*00b67f09SDavid van Moolenbroek 					 "get interface configuration: "
199*00b67f09SDavid van Moolenbroek 					 "maximum buffer size exceeded");
200*00b67f09SDavid van Moolenbroek 			result = ISC_R_UNEXPECTED;
201*00b67f09SDavid van Moolenbroek 			goto ioctl_failure;
202*00b67f09SDavid van Moolenbroek 		}
203*00b67f09SDavid van Moolenbroek 		isc_mem_put(mctx, iter->buf4, iter->buf4size);
204*00b67f09SDavid van Moolenbroek 
205*00b67f09SDavid van Moolenbroek 		iter->buf4size += IFCONF_SIZE_INCREMENT *
206*00b67f09SDavid van Moolenbroek 			sizeof(INTERFACE_INFO);
207*00b67f09SDavid van Moolenbroek 	}
208*00b67f09SDavid van Moolenbroek 
209*00b67f09SDavid van Moolenbroek 	/*
210*00b67f09SDavid van Moolenbroek 	 * A newly created iterator has an undefined position
211*00b67f09SDavid van Moolenbroek 	 * until isc_interfaceiter_first() is called.
212*00b67f09SDavid van Moolenbroek 	 */
213*00b67f09SDavid van Moolenbroek 	iter->v4IF = bytesReturned/sizeof(INTERFACE_INFO);
214*00b67f09SDavid van Moolenbroek 
215*00b67f09SDavid van Moolenbroek 	/* We don't need the socket any more, so close it */
216*00b67f09SDavid van Moolenbroek 	closesocket(iter->socket);
217*00b67f09SDavid van Moolenbroek 
218*00b67f09SDavid van Moolenbroek  inet6_only:
219*00b67f09SDavid van Moolenbroek 	/*
220*00b67f09SDavid van Moolenbroek 	 * Create an unbound datagram socket to do the
221*00b67f09SDavid van Moolenbroek 	 * SIO_ADDRESS_LIST_QUERY WSAIoctl on.
222*00b67f09SDavid van Moolenbroek 	 */
223*00b67f09SDavid van Moolenbroek 	iter->socket = socket(AF_INET6, SOCK_DGRAM, 0);
224*00b67f09SDavid van Moolenbroek 	if (iter->socket == INVALID_SOCKET) {
225*00b67f09SDavid van Moolenbroek 		error = WSAGetLastError();
226*00b67f09SDavid van Moolenbroek 		if (error == WSAEAFNOSUPPORT)
227*00b67f09SDavid van Moolenbroek 			goto inet_only;
228*00b67f09SDavid van Moolenbroek 		isc__strerror(error, strbuf, sizeof(strbuf));
229*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__,
230*00b67f09SDavid van Moolenbroek 				"making interface scan socket: %s",
231*00b67f09SDavid van Moolenbroek 				strbuf);
232*00b67f09SDavid van Moolenbroek 		result = ISC_R_UNEXPECTED;
233*00b67f09SDavid van Moolenbroek 		goto ioctl_failure;
234*00b67f09SDavid van Moolenbroek 	}
235*00b67f09SDavid van Moolenbroek 
236*00b67f09SDavid van Moolenbroek 	/*
237*00b67f09SDavid van Moolenbroek 	 * Get the interface configuration, allocating more memory if
238*00b67f09SDavid van Moolenbroek 	 * necessary.
239*00b67f09SDavid van Moolenbroek 	 */
240*00b67f09SDavid van Moolenbroek 	iter->buf6size = sizeof(SOCKET_ADDRESS_LIST) +
241*00b67f09SDavid van Moolenbroek 			 IFCONF_SIZE_INITIAL*sizeof(SOCKET_ADDRESS);
242*00b67f09SDavid van Moolenbroek 
243*00b67f09SDavid van Moolenbroek 	for (;;) {
244*00b67f09SDavid van Moolenbroek 		iter->buf6 = isc_mem_get(mctx, iter->buf6size);
245*00b67f09SDavid van Moolenbroek 		if (iter->buf6 == NULL) {
246*00b67f09SDavid van Moolenbroek 			result = ISC_R_NOMEMORY;
247*00b67f09SDavid van Moolenbroek 			goto ioctl_failure;
248*00b67f09SDavid van Moolenbroek 		}
249*00b67f09SDavid van Moolenbroek 
250*00b67f09SDavid van Moolenbroek 		if (WSAIoctl(iter->socket, SIO_ADDRESS_LIST_QUERY,
251*00b67f09SDavid van Moolenbroek 			     0, 0, iter->buf6, iter->buf6size,
252*00b67f09SDavid van Moolenbroek 			     &bytesReturned, 0, 0) == SOCKET_ERROR)
253*00b67f09SDavid van Moolenbroek 		{
254*00b67f09SDavid van Moolenbroek 			error = WSAGetLastError();
255*00b67f09SDavid van Moolenbroek 			if (error != WSAEFAULT && error != WSAENOBUFS) {
256*00b67f09SDavid van Moolenbroek 				errno = error;
257*00b67f09SDavid van Moolenbroek 				isc__strerror(error, strbuf, sizeof(strbuf));
258*00b67f09SDavid van Moolenbroek 				UNEXPECTED_ERROR(__FILE__, __LINE__,
259*00b67f09SDavid van Moolenbroek 						 "sio address list query: %s",
260*00b67f09SDavid van Moolenbroek 						 strbuf);
261*00b67f09SDavid van Moolenbroek 				result = ISC_R_UNEXPECTED;
262*00b67f09SDavid van Moolenbroek 				goto ioctl6_failure;
263*00b67f09SDavid van Moolenbroek 			}
264*00b67f09SDavid van Moolenbroek 			/*
265*00b67f09SDavid van Moolenbroek 			 * EINVAL.  Retry with a bigger buffer.
266*00b67f09SDavid van Moolenbroek 			 */
267*00b67f09SDavid van Moolenbroek 		} else
268*00b67f09SDavid van Moolenbroek 			break;
269*00b67f09SDavid van Moolenbroek 
270*00b67f09SDavid van Moolenbroek 		if (iter->buf6size >= IFCONF_SIZE_MAX*sizeof(SOCKET_ADDRESS)) {
271*00b67f09SDavid van Moolenbroek 			UNEXPECTED_ERROR(__FILE__, __LINE__,
272*00b67f09SDavid van Moolenbroek 					 "get interface configuration: "
273*00b67f09SDavid van Moolenbroek 					 "maximum buffer size exceeded");
274*00b67f09SDavid van Moolenbroek 			result = ISC_R_UNEXPECTED;
275*00b67f09SDavid van Moolenbroek 			goto ioctl6_failure;
276*00b67f09SDavid van Moolenbroek 		}
277*00b67f09SDavid van Moolenbroek 		isc_mem_put(mctx, iter->buf6, iter->buf6size);
278*00b67f09SDavid van Moolenbroek 
279*00b67f09SDavid van Moolenbroek 		iter->buf6size += IFCONF_SIZE_INCREMENT *
280*00b67f09SDavid van Moolenbroek 			sizeof(SOCKET_ADDRESS);
281*00b67f09SDavid van Moolenbroek 	}
282*00b67f09SDavid van Moolenbroek 
283*00b67f09SDavid van Moolenbroek 	closesocket(iter->socket);
284*00b67f09SDavid van Moolenbroek 
285*00b67f09SDavid van Moolenbroek  inet_only:
286*00b67f09SDavid van Moolenbroek 	iter->magic = IFITER_MAGIC;
287*00b67f09SDavid van Moolenbroek 	*iterp = iter;
288*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
289*00b67f09SDavid van Moolenbroek 
290*00b67f09SDavid van Moolenbroek  ioctl6_failure:
291*00b67f09SDavid van Moolenbroek 	isc_mem_put(mctx, iter->buf6, iter->buf6size);
292*00b67f09SDavid van Moolenbroek 
293*00b67f09SDavid van Moolenbroek  ioctl_failure:
294*00b67f09SDavid van Moolenbroek 	if (iter->buf4 != NULL)
295*00b67f09SDavid van Moolenbroek 		isc_mem_put(mctx, iter->buf4, iter->buf4size);
296*00b67f09SDavid van Moolenbroek 
297*00b67f09SDavid van Moolenbroek  alloc_failure:
298*00b67f09SDavid van Moolenbroek 	if (iter->socket != INVALID_SOCKET)
299*00b67f09SDavid van Moolenbroek 		(void) closesocket(iter->socket);
300*00b67f09SDavid van Moolenbroek 
301*00b67f09SDavid van Moolenbroek  socket_failure:
302*00b67f09SDavid van Moolenbroek 	isc_mem_put(mctx, iter, sizeof(*iter));
303*00b67f09SDavid van Moolenbroek 	return (result);
304*00b67f09SDavid van Moolenbroek }
305*00b67f09SDavid van Moolenbroek 
306*00b67f09SDavid van Moolenbroek /*
307*00b67f09SDavid van Moolenbroek  * Get information about the current interface to iter->current.
308*00b67f09SDavid van Moolenbroek  * If successful, return ISC_R_SUCCESS.
309*00b67f09SDavid van Moolenbroek  * If the interface has an unsupported address family, or if
310*00b67f09SDavid van Moolenbroek  * some operation on it fails, return ISC_R_IGNORE to make
311*00b67f09SDavid van Moolenbroek  * the higher-level iterator code ignore it.
312*00b67f09SDavid van Moolenbroek  */
313*00b67f09SDavid van Moolenbroek 
314*00b67f09SDavid van Moolenbroek static isc_result_t
internal_current(isc_interfaceiter_t * iter)315*00b67f09SDavid van Moolenbroek internal_current(isc_interfaceiter_t *iter) {
316*00b67f09SDavid van Moolenbroek 	BOOL ifNamed = FALSE;
317*00b67f09SDavid van Moolenbroek 	unsigned long flags;
318*00b67f09SDavid van Moolenbroek 
319*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_IFITER(iter));
320*00b67f09SDavid van Moolenbroek 	REQUIRE(iter->numIF >= 0);
321*00b67f09SDavid van Moolenbroek 
322*00b67f09SDavid van Moolenbroek 	memset(&iter->current, 0, sizeof(iter->current));
323*00b67f09SDavid van Moolenbroek 	iter->current.af = AF_INET;
324*00b67f09SDavid van Moolenbroek 
325*00b67f09SDavid van Moolenbroek 	get_addr(AF_INET, &iter->current.address,
326*00b67f09SDavid van Moolenbroek 		 (struct sockaddr *)&(iter->IFData.iiAddress));
327*00b67f09SDavid van Moolenbroek 
328*00b67f09SDavid van Moolenbroek 	/*
329*00b67f09SDavid van Moolenbroek 	 * Get interface flags.
330*00b67f09SDavid van Moolenbroek 	 */
331*00b67f09SDavid van Moolenbroek 
332*00b67f09SDavid van Moolenbroek 	iter->current.flags = 0;
333*00b67f09SDavid van Moolenbroek 	flags = iter->IFData.iiFlags;
334*00b67f09SDavid van Moolenbroek 
335*00b67f09SDavid van Moolenbroek 	if ((flags & IFF_UP) != 0)
336*00b67f09SDavid van Moolenbroek 		iter->current.flags |= INTERFACE_F_UP;
337*00b67f09SDavid van Moolenbroek 
338*00b67f09SDavid van Moolenbroek 	if ((flags & IFF_POINTTOPOINT) != 0) {
339*00b67f09SDavid van Moolenbroek 		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
340*00b67f09SDavid van Moolenbroek 		sprintf(iter->current.name, "PPP Interface %d", iter->numIF);
341*00b67f09SDavid van Moolenbroek 		ifNamed = TRUE;
342*00b67f09SDavid van Moolenbroek 	}
343*00b67f09SDavid van Moolenbroek 
344*00b67f09SDavid van Moolenbroek 	if ((flags & IFF_LOOPBACK) != 0) {
345*00b67f09SDavid van Moolenbroek 		iter->current.flags |= INTERFACE_F_LOOPBACK;
346*00b67f09SDavid van Moolenbroek 		sprintf(iter->current.name, "Loopback Interface %d",
347*00b67f09SDavid van Moolenbroek 			iter->numIF);
348*00b67f09SDavid van Moolenbroek 		ifNamed = TRUE;
349*00b67f09SDavid van Moolenbroek 	}
350*00b67f09SDavid van Moolenbroek 
351*00b67f09SDavid van Moolenbroek 	/*
352*00b67f09SDavid van Moolenbroek 	 * If the interface is point-to-point, get the destination address.
353*00b67f09SDavid van Moolenbroek 	 */
354*00b67f09SDavid van Moolenbroek 	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
355*00b67f09SDavid van Moolenbroek 		get_addr(AF_INET, &iter->current.dstaddress,
356*00b67f09SDavid van Moolenbroek 		(struct sockaddr *)&(iter->IFData.iiBroadcastAddress));
357*00b67f09SDavid van Moolenbroek 	}
358*00b67f09SDavid van Moolenbroek 
359*00b67f09SDavid van Moolenbroek 	if (ifNamed == FALSE)
360*00b67f09SDavid van Moolenbroek 		sprintf(iter->current.name,
361*00b67f09SDavid van Moolenbroek 			"TCP/IP Interface %d", iter->numIF);
362*00b67f09SDavid van Moolenbroek 
363*00b67f09SDavid van Moolenbroek 	/*
364*00b67f09SDavid van Moolenbroek 	 * Get the network mask.
365*00b67f09SDavid van Moolenbroek 	 */
366*00b67f09SDavid van Moolenbroek 	get_addr(AF_INET, &iter->current.netmask,
367*00b67f09SDavid van Moolenbroek 		 (struct sockaddr *)&(iter->IFData.iiNetmask));
368*00b67f09SDavid van Moolenbroek 
369*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
370*00b67f09SDavid van Moolenbroek }
371*00b67f09SDavid van Moolenbroek 
372*00b67f09SDavid van Moolenbroek static isc_result_t
internal_current6(isc_interfaceiter_t * iter)373*00b67f09SDavid van Moolenbroek internal_current6(isc_interfaceiter_t *iter) {
374*00b67f09SDavid van Moolenbroek 	BOOL ifNamed = FALSE;
375*00b67f09SDavid van Moolenbroek 	int i;
376*00b67f09SDavid van Moolenbroek 
377*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_IFITER(iter));
378*00b67f09SDavid van Moolenbroek 	REQUIRE(iter->pos6 >= 0);
379*00b67f09SDavid van Moolenbroek 	REQUIRE(iter->buf6 != 0);
380*00b67f09SDavid van Moolenbroek 
381*00b67f09SDavid van Moolenbroek 	memset(&iter->current, 0, sizeof(iter->current));
382*00b67f09SDavid van Moolenbroek 	iter->current.af = AF_INET6;
383*00b67f09SDavid van Moolenbroek 
384*00b67f09SDavid van Moolenbroek 	get_addr(AF_INET6, &iter->current.address,
385*00b67f09SDavid van Moolenbroek 		 iter->buf6->Address[iter->pos6].lpSockaddr);
386*00b67f09SDavid van Moolenbroek 
387*00b67f09SDavid van Moolenbroek 	/*
388*00b67f09SDavid van Moolenbroek 	 * Get interface flags.
389*00b67f09SDavid van Moolenbroek 	 */
390*00b67f09SDavid van Moolenbroek 
391*00b67f09SDavid van Moolenbroek 	iter->current.flags = INTERFACE_F_UP;
392*00b67f09SDavid van Moolenbroek 
393*00b67f09SDavid van Moolenbroek 	if (ifNamed == FALSE)
394*00b67f09SDavid van Moolenbroek 		sprintf(iter->current.name,
395*00b67f09SDavid van Moolenbroek 			"TCP/IPv6 Interface %d", iter->pos6 + 1);
396*00b67f09SDavid van Moolenbroek 
397*00b67f09SDavid van Moolenbroek 	for (i = 0; i< 16; i++)
398*00b67f09SDavid van Moolenbroek 		iter->current.netmask.type.in6.s6_addr[i] = 0xff;
399*00b67f09SDavid van Moolenbroek 	iter->current.netmask.family = AF_INET6;
400*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
401*00b67f09SDavid van Moolenbroek }
402*00b67f09SDavid van Moolenbroek 
403*00b67f09SDavid van Moolenbroek /*
404*00b67f09SDavid van Moolenbroek  * Step the iterator to the next interface.  Unlike
405*00b67f09SDavid van Moolenbroek  * isc_interfaceiter_next(), this may leave the iterator
406*00b67f09SDavid van Moolenbroek  * positioned on an interface that will ultimately
407*00b67f09SDavid van Moolenbroek  * be ignored.  Return ISC_R_NOMORE if there are no more
408*00b67f09SDavid van Moolenbroek  * interfaces, otherwise ISC_R_SUCCESS.
409*00b67f09SDavid van Moolenbroek  */
410*00b67f09SDavid van Moolenbroek static isc_result_t
internal_next(isc_interfaceiter_t * iter)411*00b67f09SDavid van Moolenbroek internal_next(isc_interfaceiter_t *iter) {
412*00b67f09SDavid van Moolenbroek 	if (iter->numIF >= iter->v4IF)
413*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMORE);
414*00b67f09SDavid van Moolenbroek 
415*00b67f09SDavid van Moolenbroek 	/*
416*00b67f09SDavid van Moolenbroek 	 * The first one needs to be set up to point to the last
417*00b67f09SDavid van Moolenbroek 	 * Element of the array.  Go to the end and back up
418*00b67f09SDavid van Moolenbroek 	 * Microsoft's implementation is peculiar for returning
419*00b67f09SDavid van Moolenbroek 	 * the list in reverse order
420*00b67f09SDavid van Moolenbroek 	 */
421*00b67f09SDavid van Moolenbroek 
422*00b67f09SDavid van Moolenbroek 	if (iter->numIF == 0)
423*00b67f09SDavid van Moolenbroek 		iter->pos4 = (INTERFACE_INFO *)(iter->buf4 + (iter->v4IF));
424*00b67f09SDavid van Moolenbroek 
425*00b67f09SDavid van Moolenbroek 	iter->pos4--;
426*00b67f09SDavid van Moolenbroek 	if (&(iter->pos4) < &(iter->buf4))
427*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMORE);
428*00b67f09SDavid van Moolenbroek 
429*00b67f09SDavid van Moolenbroek 	memset(&(iter->IFData), 0, sizeof(INTERFACE_INFO));
430*00b67f09SDavid van Moolenbroek 	memmove(&(iter->IFData), iter->pos4, sizeof(INTERFACE_INFO));
431*00b67f09SDavid van Moolenbroek 	iter->numIF++;
432*00b67f09SDavid van Moolenbroek 
433*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
434*00b67f09SDavid van Moolenbroek }
435*00b67f09SDavid van Moolenbroek 
436*00b67f09SDavid van Moolenbroek static isc_result_t
internal_next6(isc_interfaceiter_t * iter)437*00b67f09SDavid van Moolenbroek internal_next6(isc_interfaceiter_t *iter) {
438*00b67f09SDavid van Moolenbroek 	if (iter->pos6 == 0)
439*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMORE);
440*00b67f09SDavid van Moolenbroek 	iter->pos6--;
441*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
442*00b67f09SDavid van Moolenbroek }
443*00b67f09SDavid van Moolenbroek 
444*00b67f09SDavid van Moolenbroek isc_result_t
isc_interfaceiter_current(isc_interfaceiter_t * iter,isc_interface_t * ifdata)445*00b67f09SDavid van Moolenbroek isc_interfaceiter_current(isc_interfaceiter_t *iter,
446*00b67f09SDavid van Moolenbroek 			  isc_interface_t *ifdata) {
447*00b67f09SDavid van Moolenbroek 	REQUIRE(iter->result == ISC_R_SUCCESS);
448*00b67f09SDavid van Moolenbroek 	memmove(ifdata, &iter->current, sizeof(*ifdata));
449*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
450*00b67f09SDavid van Moolenbroek }
451*00b67f09SDavid van Moolenbroek 
452*00b67f09SDavid van Moolenbroek isc_result_t
isc_interfaceiter_first(isc_interfaceiter_t * iter)453*00b67f09SDavid van Moolenbroek isc_interfaceiter_first(isc_interfaceiter_t *iter) {
454*00b67f09SDavid van Moolenbroek 
455*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_IFITER(iter));
456*00b67f09SDavid van Moolenbroek 
457*00b67f09SDavid van Moolenbroek 	if (iter->buf6 != NULL)
458*00b67f09SDavid van Moolenbroek 		iter->pos6 = iter->buf6->iAddressCount;
459*00b67f09SDavid van Moolenbroek 	iter->result = ISC_R_SUCCESS;
460*00b67f09SDavid van Moolenbroek 	return (isc_interfaceiter_next(iter));
461*00b67f09SDavid van Moolenbroek }
462*00b67f09SDavid van Moolenbroek 
463*00b67f09SDavid van Moolenbroek isc_result_t
isc_interfaceiter_next(isc_interfaceiter_t * iter)464*00b67f09SDavid van Moolenbroek isc_interfaceiter_next(isc_interfaceiter_t *iter) {
465*00b67f09SDavid van Moolenbroek 	isc_result_t result;
466*00b67f09SDavid van Moolenbroek 
467*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_IFITER(iter));
468*00b67f09SDavid van Moolenbroek 	REQUIRE(iter->result == ISC_R_SUCCESS);
469*00b67f09SDavid van Moolenbroek 
470*00b67f09SDavid van Moolenbroek 	for (;;) {
471*00b67f09SDavid van Moolenbroek 		result = internal_next(iter);
472*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_NOMORE) {
473*00b67f09SDavid van Moolenbroek 			result = internal_next6(iter);
474*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_SUCCESS)
475*00b67f09SDavid van Moolenbroek 				break;
476*00b67f09SDavid van Moolenbroek 			result = internal_current6(iter);
477*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_IGNORE)
478*00b67f09SDavid van Moolenbroek 				break;
479*00b67f09SDavid van Moolenbroek 		} else if (result != ISC_R_SUCCESS)
480*00b67f09SDavid van Moolenbroek 			break;
481*00b67f09SDavid van Moolenbroek 		result = internal_current(iter);
482*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_IGNORE)
483*00b67f09SDavid van Moolenbroek 			break;
484*00b67f09SDavid van Moolenbroek 	}
485*00b67f09SDavid van Moolenbroek 	iter->result = result;
486*00b67f09SDavid van Moolenbroek 	return (result);
487*00b67f09SDavid van Moolenbroek }
488*00b67f09SDavid van Moolenbroek 
489*00b67f09SDavid van Moolenbroek void
isc_interfaceiter_destroy(isc_interfaceiter_t ** iterp)490*00b67f09SDavid van Moolenbroek isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) {
491*00b67f09SDavid van Moolenbroek 	isc_interfaceiter_t *iter;
492*00b67f09SDavid van Moolenbroek 	REQUIRE(iterp != NULL);
493*00b67f09SDavid van Moolenbroek 	iter = *iterp;
494*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_IFITER(iter));
495*00b67f09SDavid van Moolenbroek 
496*00b67f09SDavid van Moolenbroek 	if (iter->buf4 != NULL)
497*00b67f09SDavid van Moolenbroek 		isc_mem_put(iter->mctx, iter->buf4, iter->buf4size);
498*00b67f09SDavid van Moolenbroek 	if (iter->buf6 != NULL)
499*00b67f09SDavid van Moolenbroek 		isc_mem_put(iter->mctx, iter->buf6, iter->buf6size);
500*00b67f09SDavid van Moolenbroek 
501*00b67f09SDavid van Moolenbroek 	iter->magic = 0;
502*00b67f09SDavid van Moolenbroek 	isc_mem_put(iter->mctx, iter, sizeof(*iter));
503*00b67f09SDavid van Moolenbroek 	*iterp = NULL;
504*00b67f09SDavid van Moolenbroek }
505