4 * Copyright (C) 2004, 2007-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2001 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: interfaceiter.c,v 1.15 2009/01/18 23:48:14 tbox Exp */
23 * Note that this code will need to be revisited to support IPv6 Interfaces.
24 * For now we just iterate through IPv4 interfaces.
30 #include <sys/types.h>
36 #include <isc/interfaceiter.h>
38 #include <isc/result.h>
39 #include <isc/string.h>
40 #include <isc/strerror.h>
41 #include <isc/types.h>
44 void InitSockets(void);
46 /* Common utility functions */
49 * Extract the network address part from a "struct sockaddr".
51 * The address family is given explicitly
52 * instead of using src->sa_family, because the latter does not work
53 * for copying a network mask obtained by SIOCGIFNETMASK (it does
54 * not have a valid address family).
58 #define IFITER_MAGIC 0x49464954U /* IFIT. */
59 #define VALID_IFITER(t) ((t) != NULL && (t)->magic == IFITER_MAGIC)
61 struct isc_interfaceiter
{
62 unsigned int magic
; /* Magic number. */
65 INTERFACE_INFO IFData
; /* Current Interface Info */
66 int numIF
; /* Current Interface count */
67 int v4IF
; /* Number of IPv4 Interfaces */
68 INTERFACE_INFO
*buf4
; /* Buffer for WSAIoctl data. */
69 unsigned int buf4size
; /* Bytes allocated. */
70 INTERFACE_INFO
*pos4
; /* Current offset in IF List */
71 SOCKET_ADDRESS_LIST
*buf6
;
72 unsigned int buf6size
; /* Bytes allocated. */
74 isc_interface_t current
; /* Current interface data. */
75 isc_result_t result
; /* Last result code. */
80 * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces.
81 * We assume no sane system will have more than than 1K of IP addresses on
82 * all of its adapters.
84 #define IFCONF_SIZE_INITIAL 16
85 #define IFCONF_SIZE_INCREMENT 64
86 #define IFCONF_SIZE_MAX 1040
89 get_addr(unsigned int family
, isc_netaddr_t
*dst
, struct sockaddr
*src
) {
94 &((struct sockaddr_in
*) src
)->sin_addr
,
95 sizeof(struct in_addr
));
98 memcpy(&dst
->type
.in6
,
99 &((struct sockaddr_in6
*) src
)->sin6_addr
,
100 sizeof(struct in6_addr
));
101 dst
->zone
= ((struct sockaddr_in6
*) src
)->sin6_scope_id
;
110 isc_interfaceiter_create(isc_mem_t
*mctx
, isc_interfaceiter_t
**iterp
) {
111 char strbuf
[ISC_STRERRORSIZE
];
112 isc_interfaceiter_t
*iter
;
115 unsigned long bytesReturned
= 0;
117 REQUIRE(mctx
!= NULL
);
118 REQUIRE(iterp
!= NULL
);
119 REQUIRE(*iterp
== NULL
);
121 iter
= isc_mem_get(mctx
, sizeof(*iter
));
123 return (ISC_R_NOMEMORY
);
134 iter
->result
= ISC_R_FAILURE
;
139 * Create an unbound datagram socket to do the
140 * SIO_GET_INTERFACE_LIST WSAIoctl on.
142 if ((iter
->socket
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
143 error
= WSAGetLastError();
144 if (error
== WSAEAFNOSUPPORT
)
146 isc__strerror(error
, strbuf
, sizeof(strbuf
));
147 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
148 "making interface scan socket: %s",
150 result
= ISC_R_UNEXPECTED
;
155 * Get the interface configuration, allocating more memory if
158 iter
->buf4size
= IFCONF_SIZE_INITIAL
*sizeof(INTERFACE_INFO
);
161 iter
->buf4
= isc_mem_get(mctx
, iter
->buf4size
);
162 if (iter
->buf4
== NULL
) {
163 result
= ISC_R_NOMEMORY
;
167 if (WSAIoctl(iter
->socket
, SIO_GET_INTERFACE_LIST
,
168 0, 0, iter
->buf4
, iter
->buf4size
,
169 &bytesReturned
, 0, 0) == SOCKET_ERROR
)
171 error
= WSAGetLastError();
172 if (error
!= WSAEFAULT
&& error
!= WSAENOBUFS
) {
174 isc__strerror(error
, strbuf
, sizeof(strbuf
));
175 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
176 "get interface configuration: %s",
178 result
= ISC_R_UNEXPECTED
;
182 * EINVAL. Retry with a bigger buffer.
186 * The WSAIoctl succeeded.
187 * If the number of the returned bytes is the same
188 * as the buffer size, we will grow it just in
191 if (bytesReturned
> 0 &&
192 (bytesReturned
< iter
->buf4size
))
195 if (iter
->buf4size
>= IFCONF_SIZE_MAX
*sizeof(INTERFACE_INFO
)) {
196 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
197 "get interface configuration: "
198 "maximum buffer size exceeded");
199 result
= ISC_R_UNEXPECTED
;
202 isc_mem_put(mctx
, iter
->buf4
, iter
->buf4size
);
204 iter
->buf4size
+= IFCONF_SIZE_INCREMENT
*
205 sizeof(INTERFACE_INFO
);
209 * A newly created iterator has an undefined position
210 * until isc_interfaceiter_first() is called.
212 iter
->v4IF
= bytesReturned
/sizeof(INTERFACE_INFO
);
214 /* We don't need the socket any more, so close it */
215 closesocket(iter
->socket
);
219 * Create an unbound datagram socket to do the
220 * SIO_ADDRESS_LIST_QUERY WSAIoctl on.
222 if ((iter
->socket
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
223 error
= WSAGetLastError();
224 if (error
== WSAEAFNOSUPPORT
)
226 isc__strerror(error
, strbuf
, sizeof(strbuf
));
227 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
228 "making interface scan socket: %s",
230 result
= ISC_R_UNEXPECTED
;
235 * Get the interface configuration, allocating more memory if
238 iter
->buf6size
= sizeof(SOCKET_ADDRESS_LIST
) +
239 IFCONF_SIZE_INITIAL
*sizeof(SOCKET_ADDRESS
);
242 iter
->buf6
= isc_mem_get(mctx
, iter
->buf6size
);
243 if (iter
->buf6
== NULL
) {
244 result
= ISC_R_NOMEMORY
;
248 if (WSAIoctl(iter
->socket
, SIO_ADDRESS_LIST_QUERY
,
249 0, 0, iter
->buf6
, iter
->buf6size
,
250 &bytesReturned
, 0, 0) == SOCKET_ERROR
)
252 error
= WSAGetLastError();
253 if (error
!= WSAEFAULT
&& error
!= WSAENOBUFS
) {
255 isc__strerror(error
, strbuf
, sizeof(strbuf
));
256 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
257 "sio address list query: %s",
259 result
= ISC_R_UNEXPECTED
;
263 * EINVAL. Retry with a bigger buffer.
268 if (iter
->buf6size
>= IFCONF_SIZE_MAX
*sizeof(SOCKET_ADDRESS
)) {
269 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
270 "get interface configuration: "
271 "maximum buffer size exceeded");
272 result
= ISC_R_UNEXPECTED
;
275 isc_mem_put(mctx
, iter
->buf6
, iter
->buf6size
);
277 iter
->buf6size
+= IFCONF_SIZE_INCREMENT
*
278 sizeof(SOCKET_ADDRESS
);
281 closesocket(iter
->socket
);
284 iter
->magic
= IFITER_MAGIC
;
286 return (ISC_R_SUCCESS
);
289 isc_mem_put(mctx
, iter
->buf6
, iter
->buf6size
);
292 if (iter
->buf4
!= NULL
)
293 isc_mem_put(mctx
, iter
->buf4
, iter
->buf4size
);
296 if (iter
->socket
>= 0)
297 (void) closesocket(iter
->socket
);
300 isc_mem_put(mctx
, iter
, sizeof(*iter
));
305 * Get information about the current interface to iter->current.
306 * If successful, return ISC_R_SUCCESS.
307 * If the interface has an unsupported address family, or if
308 * some operation on it fails, return ISC_R_IGNORE to make
309 * the higher-level iterator code ignore it.
313 internal_current(isc_interfaceiter_t
*iter
) {
314 BOOL ifNamed
= FALSE
;
317 REQUIRE(VALID_IFITER(iter
));
318 REQUIRE(iter
->numIF
>= 0);
320 memset(&iter
->current
, 0, sizeof(iter
->current
));
321 iter
->current
.af
= AF_INET
;
323 get_addr(AF_INET
, &iter
->current
.address
,
324 (struct sockaddr
*)&(iter
->IFData
.iiAddress
));
327 * Get interface flags.
330 iter
->current
.flags
= 0;
331 flags
= iter
->IFData
.iiFlags
;
333 if ((flags
& IFF_UP
) != 0)
334 iter
->current
.flags
|= INTERFACE_F_UP
;
336 if ((flags
& IFF_POINTTOPOINT
) != 0) {
337 iter
->current
.flags
|= INTERFACE_F_POINTTOPOINT
;
338 sprintf(iter
->current
.name
, "PPP Interface %d", iter
->numIF
);
342 if ((flags
& IFF_LOOPBACK
) != 0) {
343 iter
->current
.flags
|= INTERFACE_F_LOOPBACK
;
344 sprintf(iter
->current
.name
, "Loopback Interface %d",
350 * If the interface is point-to-point, get the destination address.
352 if ((iter
->current
.flags
& INTERFACE_F_POINTTOPOINT
) != 0) {
353 get_addr(AF_INET
, &iter
->current
.dstaddress
,
354 (struct sockaddr
*)&(iter
->IFData
.iiBroadcastAddress
));
357 if (ifNamed
== FALSE
)
358 sprintf(iter
->current
.name
,
359 "TCP/IP Interface %d", iter
->numIF
);
362 * Get the network mask.
364 get_addr(AF_INET
, &iter
->current
.netmask
,
365 (struct sockaddr
*)&(iter
->IFData
.iiNetmask
));
367 return (ISC_R_SUCCESS
);
371 internal_current6(isc_interfaceiter_t
*iter
) {
372 BOOL ifNamed
= FALSE
;
375 REQUIRE(VALID_IFITER(iter
));
376 REQUIRE(iter
->pos6
>= 0);
377 REQUIRE(iter
->buf6
!= 0);
379 memset(&iter
->current
, 0, sizeof(iter
->current
));
380 iter
->current
.af
= AF_INET6
;
382 get_addr(AF_INET6
, &iter
->current
.address
,
383 iter
->buf6
->Address
[iter
->pos6
].lpSockaddr
);
386 * Get interface flags.
389 iter
->current
.flags
= INTERFACE_F_UP
;
391 if (ifNamed
== FALSE
)
392 sprintf(iter
->current
.name
,
393 "TCP/IPv6 Interface %d", iter
->pos6
+ 1);
395 for (i
= 0; i
< 16; i
++)
396 iter
->current
.netmask
.type
.in6
.s6_addr
[i
] = 0xff;
397 iter
->current
.netmask
.family
= AF_INET6
;
398 return (ISC_R_SUCCESS
);
402 * Step the iterator to the next interface. Unlike
403 * isc_interfaceiter_next(), this may leave the iterator
404 * positioned on an interface that will ultimately
405 * be ignored. Return ISC_R_NOMORE if there are no more
406 * interfaces, otherwise ISC_R_SUCCESS.
409 internal_next(isc_interfaceiter_t
*iter
) {
410 if (iter
->numIF
>= iter
->v4IF
)
411 return (ISC_R_NOMORE
);
414 * The first one needs to be set up to point to the last
415 * Element of the array. Go to the end and back up
416 * Microsoft's implementation is peculiar for returning
417 * the list in reverse order
420 if (iter
->numIF
== 0)
421 iter
->pos4
= (INTERFACE_INFO
*)(iter
->buf4
+ (iter
->v4IF
));
424 if (&(iter
->pos4
) < &(iter
->buf4
))
425 return (ISC_R_NOMORE
);
427 memset(&(iter
->IFData
), 0, sizeof(INTERFACE_INFO
));
428 memcpy(&(iter
->IFData
), iter
->pos4
, sizeof(INTERFACE_INFO
));
431 return (ISC_R_SUCCESS
);
435 internal_next6(isc_interfaceiter_t
*iter
) {
437 return (ISC_R_NOMORE
);
439 return (ISC_R_SUCCESS
);
443 isc_interfaceiter_current(isc_interfaceiter_t
*iter
,
444 isc_interface_t
*ifdata
) {
445 REQUIRE(iter
->result
== ISC_R_SUCCESS
);
446 memcpy(ifdata
, &iter
->current
, sizeof(*ifdata
));
447 return (ISC_R_SUCCESS
);
451 isc_interfaceiter_first(isc_interfaceiter_t
*iter
) {
453 REQUIRE(VALID_IFITER(iter
));
455 if (iter
->buf6
!= NULL
)
456 iter
->pos6
= iter
->buf6
->iAddressCount
;
457 iter
->result
= ISC_R_SUCCESS
;
458 return (isc_interfaceiter_next(iter
));
462 isc_interfaceiter_next(isc_interfaceiter_t
*iter
) {
465 REQUIRE(VALID_IFITER(iter
));
466 REQUIRE(iter
->result
== ISC_R_SUCCESS
);
469 result
= internal_next(iter
);
470 if (result
== ISC_R_NOMORE
) {
471 result
= internal_next6(iter
);
472 if (result
!= ISC_R_SUCCESS
)
474 result
= internal_current6(iter
);
475 if (result
!= ISC_R_IGNORE
)
477 } else if (result
!= ISC_R_SUCCESS
)
479 result
= internal_current(iter
);
480 if (result
!= ISC_R_IGNORE
)
483 iter
->result
= result
;
488 isc_interfaceiter_destroy(isc_interfaceiter_t
**iterp
) {
489 isc_interfaceiter_t
*iter
;
490 REQUIRE(iterp
!= NULL
);
492 REQUIRE(VALID_IFITER(iter
));
494 if (iter
->buf4
!= NULL
)
495 isc_mem_put(iter
->mctx
, iter
->buf4
, iter
->buf4size
);
496 if (iter
->buf6
!= NULL
)
497 isc_mem_put(iter
->mctx
, iter
->buf6
, iter
->buf6size
);
500 isc_mem_put(iter
->mctx
, iter
, sizeof(*iter
));