2 * Copyright (C) 2004, 2007-2009 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2001 Internet Software Consortium.
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.
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.
18 /* $Id: interfaceiter.c,v 1.15 2009/01/18 23:48:14 tbox Exp $ */
21 * Note that this code will need to be revisited to support IPv6 Interfaces.
22 * For now we just iterate through IPv4 interfaces.
28 #include <sys/types.h>
34 #include <isc/interfaceiter.h>
36 #include <isc/result.h>
37 #include <isc/string.h>
38 #include <isc/strerror.h>
39 #include <isc/types.h>
42 void InitSockets(void);
44 /* Common utility functions */
47 * Extract the network address part from a "struct sockaddr".
49 * The address family is given explicitly
50 * instead of using src->sa_family, because the latter does not work
51 * for copying a network mask obtained by SIOCGIFNETMASK (it does
52 * not have a valid address family).
56 #define IFITER_MAGIC 0x49464954U /* IFIT. */
57 #define VALID_IFITER(t) ((t) != NULL && (t)->magic == IFITER_MAGIC)
59 struct isc_interfaceiter {
60 unsigned int magic; /* Magic number. */
63 INTERFACE_INFO IFData; /* Current Interface Info */
64 int numIF; /* Current Interface count */
65 int v4IF; /* Number of IPv4 Interfaces */
66 INTERFACE_INFO *buf4; /* Buffer for WSAIoctl data. */
67 unsigned int buf4size; /* Bytes allocated. */
68 INTERFACE_INFO *pos4; /* Current offset in IF List */
69 SOCKET_ADDRESS_LIST *buf6;
70 unsigned int buf6size; /* Bytes allocated. */
72 isc_interface_t current; /* Current interface data. */
73 isc_result_t result; /* Last result code. */
78 * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces.
79 * We assume no sane system will have more than than 1K of IP addresses on
80 * all of its adapters.
82 #define IFCONF_SIZE_INITIAL 16
83 #define IFCONF_SIZE_INCREMENT 64
84 #define IFCONF_SIZE_MAX 1040
87 get_addr(unsigned int family, isc_netaddr_t *dst, struct sockaddr *src) {
92 &((struct sockaddr_in *) src)->sin_addr,
93 sizeof(struct in_addr));
96 memcpy(&dst->type.in6,
97 &((struct sockaddr_in6 *) src)->sin6_addr,
98 sizeof(struct in6_addr));
99 dst->zone = ((struct sockaddr_in6 *) src)->sin6_scope_id;
108 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
109 char strbuf[ISC_STRERRORSIZE];
110 isc_interfaceiter_t *iter;
113 unsigned long bytesReturned = 0;
115 REQUIRE(mctx != NULL);
116 REQUIRE(iterp != NULL);
117 REQUIRE(*iterp == NULL);
119 iter = isc_mem_get(mctx, sizeof(*iter));
121 return (ISC_R_NOMEMORY);
132 iter->result = ISC_R_FAILURE;
137 * Create an unbound datagram socket to do the
138 * SIO_GET_INTERFACE_LIST WSAIoctl on.
140 if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
141 error = WSAGetLastError();
142 if (error == WSAEAFNOSUPPORT)
144 isc__strerror(error, strbuf, sizeof(strbuf));
145 UNEXPECTED_ERROR(__FILE__, __LINE__,
146 "making interface scan socket: %s",
148 result = ISC_R_UNEXPECTED;
153 * Get the interface configuration, allocating more memory if
156 iter->buf4size = IFCONF_SIZE_INITIAL*sizeof(INTERFACE_INFO);
159 iter->buf4 = isc_mem_get(mctx, iter->buf4size);
160 if (iter->buf4 == NULL) {
161 result = ISC_R_NOMEMORY;
165 if (WSAIoctl(iter->socket, SIO_GET_INTERFACE_LIST,
166 0, 0, iter->buf4, iter->buf4size,
167 &bytesReturned, 0, 0) == SOCKET_ERROR)
169 error = WSAGetLastError();
170 if (error != WSAEFAULT && error != WSAENOBUFS) {
172 isc__strerror(error, strbuf, sizeof(strbuf));
173 UNEXPECTED_ERROR(__FILE__, __LINE__,
174 "get interface configuration: %s",
176 result = ISC_R_UNEXPECTED;
180 * EINVAL. Retry with a bigger buffer.
184 * The WSAIoctl succeeded.
185 * If the number of the returned bytes is the same
186 * as the buffer size, we will grow it just in
189 if (bytesReturned > 0 &&
190 (bytesReturned < iter->buf4size))
193 if (iter->buf4size >= IFCONF_SIZE_MAX*sizeof(INTERFACE_INFO)) {
194 UNEXPECTED_ERROR(__FILE__, __LINE__,
195 "get interface configuration: "
196 "maximum buffer size exceeded");
197 result = ISC_R_UNEXPECTED;
200 isc_mem_put(mctx, iter->buf4, iter->buf4size);
202 iter->buf4size += IFCONF_SIZE_INCREMENT *
203 sizeof(INTERFACE_INFO);
207 * A newly created iterator has an undefined position
208 * until isc_interfaceiter_first() is called.
210 iter->v4IF = bytesReturned/sizeof(INTERFACE_INFO);
212 /* We don't need the socket any more, so close it */
213 closesocket(iter->socket);
217 * Create an unbound datagram socket to do the
218 * SIO_ADDRESS_LIST_QUERY WSAIoctl on.
220 if ((iter->socket = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
221 error = WSAGetLastError();
222 if (error == WSAEAFNOSUPPORT)
224 isc__strerror(error, strbuf, sizeof(strbuf));
225 UNEXPECTED_ERROR(__FILE__, __LINE__,
226 "making interface scan socket: %s",
228 result = ISC_R_UNEXPECTED;
233 * Get the interface configuration, allocating more memory if
236 iter->buf6size = sizeof(SOCKET_ADDRESS_LIST) +
237 IFCONF_SIZE_INITIAL*sizeof(SOCKET_ADDRESS);
240 iter->buf6 = isc_mem_get(mctx, iter->buf6size);
241 if (iter->buf6 == NULL) {
242 result = ISC_R_NOMEMORY;
246 if (WSAIoctl(iter->socket, SIO_ADDRESS_LIST_QUERY,
247 0, 0, iter->buf6, iter->buf6size,
248 &bytesReturned, 0, 0) == SOCKET_ERROR)
250 error = WSAGetLastError();
251 if (error != WSAEFAULT && error != WSAENOBUFS) {
253 isc__strerror(error, strbuf, sizeof(strbuf));
254 UNEXPECTED_ERROR(__FILE__, __LINE__,
255 "sio address list query: %s",
257 result = ISC_R_UNEXPECTED;
261 * EINVAL. Retry with a bigger buffer.
266 if (iter->buf6size >= IFCONF_SIZE_MAX*sizeof(SOCKET_ADDRESS)) {
267 UNEXPECTED_ERROR(__FILE__, __LINE__,
268 "get interface configuration: "
269 "maximum buffer size exceeded");
270 result = ISC_R_UNEXPECTED;
273 isc_mem_put(mctx, iter->buf6, iter->buf6size);
275 iter->buf6size += IFCONF_SIZE_INCREMENT *
276 sizeof(SOCKET_ADDRESS);
279 closesocket(iter->socket);
282 iter->magic = IFITER_MAGIC;
284 return (ISC_R_SUCCESS);
287 isc_mem_put(mctx, iter->buf6, iter->buf6size);
290 if (iter->buf4 != NULL)
291 isc_mem_put(mctx, iter->buf4, iter->buf4size);
294 if (iter->socket >= 0)
295 (void) closesocket(iter->socket);
298 isc_mem_put(mctx, iter, sizeof(*iter));
303 * Get information about the current interface to iter->current.
304 * If successful, return ISC_R_SUCCESS.
305 * If the interface has an unsupported address family, or if
306 * some operation on it fails, return ISC_R_IGNORE to make
307 * the higher-level iterator code ignore it.
311 internal_current(isc_interfaceiter_t *iter) {
312 BOOL ifNamed = FALSE;
315 REQUIRE(VALID_IFITER(iter));
316 REQUIRE(iter->numIF >= 0);
318 memset(&iter->current, 0, sizeof(iter->current));
319 iter->current.af = AF_INET;
321 get_addr(AF_INET, &iter->current.address,
322 (struct sockaddr *)&(iter->IFData.iiAddress));
325 * Get interface flags.
328 iter->current.flags = 0;
329 flags = iter->IFData.iiFlags;
331 if ((flags & IFF_UP) != 0)
332 iter->current.flags |= INTERFACE_F_UP;
334 if ((flags & IFF_POINTTOPOINT) != 0) {
335 iter->current.flags |= INTERFACE_F_POINTTOPOINT;
336 sprintf(iter->current.name, "PPP Interface %d", iter->numIF);
340 if ((flags & IFF_LOOPBACK) != 0) {
341 iter->current.flags |= INTERFACE_F_LOOPBACK;
342 sprintf(iter->current.name, "Loopback Interface %d",
348 * If the interface is point-to-point, get the destination address.
350 if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
351 get_addr(AF_INET, &iter->current.dstaddress,
352 (struct sockaddr *)&(iter->IFData.iiBroadcastAddress));
355 if (ifNamed == FALSE)
356 sprintf(iter->current.name,
357 "TCP/IP Interface %d", iter->numIF);
360 * Get the network mask.
362 get_addr(AF_INET, &iter->current.netmask,
363 (struct sockaddr *)&(iter->IFData.iiNetmask));
365 return (ISC_R_SUCCESS);
369 internal_current6(isc_interfaceiter_t *iter) {
370 BOOL ifNamed = FALSE;
373 REQUIRE(VALID_IFITER(iter));
374 REQUIRE(iter->pos6 >= 0);
375 REQUIRE(iter->buf6 != 0);
377 memset(&iter->current, 0, sizeof(iter->current));
378 iter->current.af = AF_INET6;
380 get_addr(AF_INET6, &iter->current.address,
381 iter->buf6->Address[iter->pos6].lpSockaddr);
384 * Get interface flags.
387 iter->current.flags = INTERFACE_F_UP;
389 if (ifNamed == FALSE)
390 sprintf(iter->current.name,
391 "TCP/IPv6 Interface %d", iter->pos6 + 1);
393 for (i = 0; i< 16; i++)
394 iter->current.netmask.type.in6.s6_addr[i] = 0xff;
395 iter->current.netmask.family = AF_INET6;
396 return (ISC_R_SUCCESS);
400 * Step the iterator to the next interface. Unlike
401 * isc_interfaceiter_next(), this may leave the iterator
402 * positioned on an interface that will ultimately
403 * be ignored. Return ISC_R_NOMORE if there are no more
404 * interfaces, otherwise ISC_R_SUCCESS.
407 internal_next(isc_interfaceiter_t *iter) {
408 if (iter->numIF >= iter->v4IF)
409 return (ISC_R_NOMORE);
412 * The first one needs to be set up to point to the last
413 * Element of the array. Go to the end and back up
414 * Microsoft's implementation is peculiar for returning
415 * the list in reverse order
418 if (iter->numIF == 0)
419 iter->pos4 = (INTERFACE_INFO *)(iter->buf4 + (iter->v4IF));
422 if (&(iter->pos4) < &(iter->buf4))
423 return (ISC_R_NOMORE);
425 memset(&(iter->IFData), 0, sizeof(INTERFACE_INFO));
426 memcpy(&(iter->IFData), iter->pos4, sizeof(INTERFACE_INFO));
429 return (ISC_R_SUCCESS);
433 internal_next6(isc_interfaceiter_t *iter) {
435 return (ISC_R_NOMORE);
437 return (ISC_R_SUCCESS);
441 isc_interfaceiter_current(isc_interfaceiter_t *iter,
442 isc_interface_t *ifdata) {
443 REQUIRE(iter->result == ISC_R_SUCCESS);
444 memcpy(ifdata, &iter->current, sizeof(*ifdata));
445 return (ISC_R_SUCCESS);
449 isc_interfaceiter_first(isc_interfaceiter_t *iter) {
451 REQUIRE(VALID_IFITER(iter));
453 if (iter->buf6 != NULL)
454 iter->pos6 = iter->buf6->iAddressCount;
455 iter->result = ISC_R_SUCCESS;
456 return (isc_interfaceiter_next(iter));
460 isc_interfaceiter_next(isc_interfaceiter_t *iter) {
463 REQUIRE(VALID_IFITER(iter));
464 REQUIRE(iter->result == ISC_R_SUCCESS);
467 result = internal_next(iter);
468 if (result == ISC_R_NOMORE) {
469 result = internal_next6(iter);
470 if (result != ISC_R_SUCCESS)
472 result = internal_current6(iter);
473 if (result != ISC_R_IGNORE)
475 } else if (result != ISC_R_SUCCESS)
477 result = internal_current(iter);
478 if (result != ISC_R_IGNORE)
481 iter->result = result;
486 isc_interfaceiter_destroy(isc_interfaceiter_t **iterp) {
487 isc_interfaceiter_t *iter;
488 REQUIRE(iterp != NULL);
490 REQUIRE(VALID_IFITER(iter));
492 if (iter->buf4 != NULL)
493 isc_mem_put(iter->mctx, iter->buf4, iter->buf4size);
494 if (iter->buf6 != NULL)
495 isc_mem_put(iter->mctx, iter->buf6, iter->buf6size);
498 isc_mem_put(iter->mctx, iter, sizeof(*iter));