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.13.110.2 2009/01/18 23:47:41 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. */
73 unsigned int pos6
; /* buf6 index, counts down */
74 struct in6_addr loop__1
; /* ::1 node-scope localhost */
75 struct in6_addr loopfe80__1
; /* fe80::1 link-scope localhost */
76 isc_interface_t current
; /* Current interface data. */
77 isc_result_t result
; /* Last result code. */
82 * Size of buffer for SIO_GET_INTERFACE_LIST, in number of interfaces.
83 * We assume no sane system will have more than than 1K of IP addresses on
84 * all of its adapters.
86 #define IFCONF_SIZE_INITIAL 16
87 #define IFCONF_SIZE_INCREMENT 64
88 #define IFCONF_SIZE_MAX 1040
91 get_addr(unsigned int family
, isc_netaddr_t
*dst
, struct sockaddr
*src
) {
96 &((struct sockaddr_in
*) src
)->sin_addr
,
97 sizeof(struct in_addr
));
100 memcpy(&dst
->type
.in6
,
101 &((struct sockaddr_in6
*) src
)->sin6_addr
,
102 sizeof(struct in6_addr
));
103 dst
->zone
= ((struct sockaddr_in6
*) src
)->sin6_scope_id
;
112 * Windows always provides 255.255.255.255 as the the broadcast
113 * address. ntpd needs to know the broadcast address which will target
114 * only that network interface, not all. Reconstruct it from the
118 get_broadcastaddr(isc_netaddr_t
*bcastaddr
, isc_netaddr_t
*addr
, isc_netaddr_t
*netmask
) {
123 b
= (isc_uint32_t
*)&bcastaddr
->type
.in
;
124 a
= *(isc_uint32_t
*)&addr
->type
.in
;
125 n
= *(isc_uint32_t
*)&netmask
->type
.in
;
131 isc_interfaceiter_create(isc_mem_t
*mctx
, isc_interfaceiter_t
**iterp
) {
132 char strbuf
[ISC_STRERRORSIZE
];
133 isc_interfaceiter_t
*iter
;
136 unsigned long bytesReturned
= 0;
138 REQUIRE(mctx
!= NULL
);
139 REQUIRE(iterp
!= NULL
);
140 REQUIRE(*iterp
== NULL
);
142 iter
= isc_mem_get(mctx
, sizeof(*iter
));
144 return (ISC_R_NOMEMORY
);
155 iter
->result
= ISC_R_FAILURE
;
160 * Create an unbound datagram socket to do the
161 * SIO_GET_INTERFACE_LIST WSAIoctl on.
163 if ((iter
->socket
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
164 error
= WSAGetLastError();
165 if (error
== WSAEAFNOSUPPORT
)
167 isc__strerror(error
, strbuf
, sizeof(strbuf
));
168 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
169 "making interface scan socket: %s",
171 result
= ISC_R_UNEXPECTED
;
176 * Get the interface configuration, allocating more memory if
179 iter
->buf4size
= IFCONF_SIZE_INITIAL
*sizeof(INTERFACE_INFO
);
182 iter
->buf4
= isc_mem_get(mctx
, iter
->buf4size
);
183 if (iter
->buf4
== NULL
) {
184 result
= ISC_R_NOMEMORY
;
188 if (WSAIoctl(iter
->socket
, SIO_GET_INTERFACE_LIST
,
189 0, 0, iter
->buf4
, iter
->buf4size
,
190 &bytesReturned
, 0, 0) == SOCKET_ERROR
)
192 error
= WSAGetLastError();
193 if (error
!= WSAEFAULT
&& error
!= WSAENOBUFS
) {
195 isc__strerror(error
, strbuf
, sizeof(strbuf
));
196 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
197 "get interface configuration: %s",
199 result
= ISC_R_UNEXPECTED
;
203 * EINVAL. Retry with a bigger buffer.
207 * The WSAIoctl succeeded.
208 * If the number of the returned bytes is the same
209 * as the buffer size, we will grow it just in
212 if (bytesReturned
> 0 &&
213 (bytesReturned
< iter
->buf4size
))
216 if (iter
->buf4size
>= IFCONF_SIZE_MAX
*sizeof(INTERFACE_INFO
)) {
217 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
218 "get interface configuration: "
219 "maximum buffer size exceeded");
220 result
= ISC_R_UNEXPECTED
;
223 isc_mem_put(mctx
, iter
->buf4
, iter
->buf4size
);
225 iter
->buf4size
+= IFCONF_SIZE_INCREMENT
*
226 sizeof(INTERFACE_INFO
);
230 * A newly created iterator has an undefined position
231 * until isc_interfaceiter_first() is called.
233 iter
->v4IF
= bytesReturned
/sizeof(INTERFACE_INFO
);
235 /* We don't need the socket any more, so close it */
236 closesocket(iter
->socket
);
240 * Create an unbound datagram socket to do the
241 * SIO_ADDRESS_LIST_QUERY WSAIoctl on.
243 if ((iter
->socket
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
244 error
= WSAGetLastError();
245 if (error
== WSAEAFNOSUPPORT
)
247 isc__strerror(error
, strbuf
, sizeof(strbuf
));
248 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
249 "making interface scan socket: %s",
251 result
= ISC_R_UNEXPECTED
;
256 * Get the interface configuration, allocating more memory if
259 iter
->buf6size
= sizeof(SOCKET_ADDRESS_LIST
) +
260 IFCONF_SIZE_INITIAL
*sizeof(SOCKET_ADDRESS
);
263 iter
->buf6
= isc_mem_get(mctx
, iter
->buf6size
);
264 if (iter
->buf6
== NULL
) {
265 result
= ISC_R_NOMEMORY
;
269 if (WSAIoctl(iter
->socket
, SIO_ADDRESS_LIST_QUERY
,
270 0, 0, iter
->buf6
, iter
->buf6size
,
271 &bytesReturned
, 0, 0) == SOCKET_ERROR
)
273 error
= WSAGetLastError();
274 if (error
!= WSAEFAULT
&& error
!= WSAENOBUFS
) {
276 isc__strerror(error
, strbuf
, sizeof(strbuf
));
277 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
278 "sio address list query: %s",
280 result
= ISC_R_UNEXPECTED
;
284 * EINVAL. Retry with a bigger buffer.
289 if (iter
->buf6size
>= IFCONF_SIZE_MAX
*sizeof(SOCKET_ADDRESS
)) {
290 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
291 "get interface configuration: "
292 "maximum buffer size exceeded");
293 result
= ISC_R_UNEXPECTED
;
296 isc_mem_put(mctx
, iter
->buf6
, iter
->buf6size
);
298 iter
->buf6size
+= IFCONF_SIZE_INCREMENT
*
299 sizeof(SOCKET_ADDRESS
);
303 * initialize loop__1 to [::1] and loopfe80__1 to [fe80::1].
304 * used by internal_current6().
306 memset(&iter
->loop__1
, 0, sizeof(iter
->loop__1
));
307 memset(&iter
->loopfe80__1
, 0, sizeof(iter
->loopfe80__1
));
308 iter
->loop__1
.s6_addr
[15] = 1;
309 iter
->loopfe80__1
.s6_addr
[15] = 1;
310 iter
->loopfe80__1
.s6_addr
[0] = 0xfe;
311 iter
->loopfe80__1
.s6_addr
[1] = 0x80;
313 closesocket(iter
->socket
);
316 iter
->magic
= IFITER_MAGIC
;
318 return (ISC_R_SUCCESS
);
321 isc_mem_put(mctx
, iter
->buf6
, iter
->buf6size
);
324 if (iter
->buf4
!= NULL
)
325 isc_mem_put(mctx
, iter
->buf4
, iter
->buf4size
);
328 if (iter
->socket
>= 0)
329 (void) closesocket(iter
->socket
);
332 isc_mem_put(mctx
, iter
, sizeof(*iter
));
337 * Get information about the current interface to iter->current.
338 * If successful, return ISC_R_SUCCESS.
339 * If the interface has an unsupported address family, or if
340 * some operation on it fails, return ISC_R_IGNORE to make
341 * the higher-level iterator code ignore it.
345 internal_current(isc_interfaceiter_t
*iter
) {
346 BOOL ifNamed
= FALSE
;
349 REQUIRE(VALID_IFITER(iter
));
350 REQUIRE(iter
->numIF
>= 0);
352 memset(&iter
->current
, 0, sizeof(iter
->current
));
353 iter
->current
.af
= AF_INET
;
355 get_addr(AF_INET
, &iter
->current
.address
,
356 (struct sockaddr
*)&(iter
->IFData
.iiAddress
));
359 * Get interface flags.
362 iter
->current
.flags
= 0;
363 flags
= iter
->IFData
.iiFlags
;
365 if ((flags
& IFF_UP
) != 0)
366 iter
->current
.flags
|= INTERFACE_F_UP
;
368 if ((flags
& IFF_BROADCAST
) != 0)
369 iter
->current
.flags
|= INTERFACE_F_BROADCAST
;
371 if ((flags
& IFF_MULTICAST
) != 0)
372 iter
->current
.flags
|= INTERFACE_F_MULTICAST
;
374 if ((flags
& IFF_POINTTOPOINT
) != 0) {
375 iter
->current
.flags
|= INTERFACE_F_POINTTOPOINT
;
376 sprintf(iter
->current
.name
, "PPP %d", iter
->numIF
);
380 if ((flags
& IFF_LOOPBACK
) != 0) {
381 iter
->current
.flags
|= INTERFACE_F_LOOPBACK
;
382 sprintf(iter
->current
.name
, "v4loop %d",
388 * If the interface is point-to-point, get the destination address.
390 if ((iter
->current
.flags
& INTERFACE_F_POINTTOPOINT
) != 0) {
391 get_addr(AF_INET
, &iter
->current
.dstaddress
,
392 (struct sockaddr
*)&(iter
->IFData
.iiBroadcastAddress
));
396 * Get the network mask.
398 get_addr(AF_INET
, &iter
->current
.netmask
,
399 (struct sockaddr
*)&(iter
->IFData
.iiNetmask
));
402 * If the interface is broadcast, get the broadcast address,
403 * based on the unicast address and network mask.
405 if ((iter
->current
.flags
& INTERFACE_F_BROADCAST
) != 0)
406 get_broadcastaddr(&iter
->current
.broadcast
,
407 &iter
->current
.address
,
408 &iter
->current
.netmask
);
410 if (ifNamed
== FALSE
)
411 sprintf(iter
->current
.name
,
412 "IPv4 %d", iter
->numIF
);
414 return (ISC_R_SUCCESS
);
418 internal_current6(isc_interfaceiter_t
*iter
) {
419 BOOL ifNamed
= FALSE
;
420 struct sockaddr_in6
*psa6
;
424 REQUIRE(VALID_IFITER(iter
));
425 REQUIRE(iter
->pos6
>= 0);
426 REQUIRE(iter
->buf6
!= 0);
428 memset(&iter
->current
, 0, sizeof(iter
->current
));
429 iter
->current
.af
= AF_INET6
;
432 * synthesize localhost ::1 before returning the rest, if ::1
433 * is not on the list.
435 if (iter
->pos6
>= (unsigned)iter
->buf6
->iAddressCount
) {
436 localhostSeen
= FALSE
;
437 for (i
= 0; i
< iter
->buf6
->iAddressCount
; i
++) {
438 psa6
= (struct sockaddr_in6
*)
439 iter
->buf6
->Address
[i
].lpSockaddr
;
440 if (!memcmp(&iter
->loop__1
, &psa6
->sin6_addr
,
441 sizeof(iter
->loop__1
))) {
442 localhostSeen
= TRUE
;
447 iter
->pos6
= iter
->buf6
->iAddressCount
- 1;
450 if (iter
->pos6
< (unsigned)iter
->buf6
->iAddressCount
)
451 get_addr(AF_INET6
, &iter
->current
.address
,
452 iter
->buf6
->Address
[iter
->pos6
].lpSockaddr
);
454 iter
->current
.address
.family
= AF_INET6
;
455 memcpy(&iter
->current
.address
.type
.in6
, &iter
->loop__1
,
456 sizeof(iter
->current
.address
.type
.in6
));
460 * Get interface flags.
463 iter
->current
.flags
= INTERFACE_F_UP
| INTERFACE_F_MULTICAST
;
465 if (!memcmp(&iter
->current
.address
.type
.in6
, &iter
->loop__1
,
466 sizeof(iter
->current
.address
.type
.in6
)) ||
467 !memcmp(&iter
->current
.address
.type
.in6
, &iter
->loopfe80__1
,
468 sizeof(iter
->current
.address
.type
.in6
))) {
470 iter
->current
.flags
|= INTERFACE_F_LOOPBACK
;
471 sprintf(iter
->current
.name
, "v6loop %d",
472 iter
->buf6
->iAddressCount
- iter
->pos6
);
476 if (ifNamed
== FALSE
)
477 sprintf(iter
->current
.name
, "IPv6 %d",
478 iter
->buf6
->iAddressCount
- iter
->pos6
);
480 memset(iter
->current
.netmask
.type
.in6
.s6_addr
, 0xff,
481 sizeof(iter
->current
.netmask
.type
.in6
.s6_addr
));
482 iter
->current
.netmask
.family
= AF_INET6
;
483 return (ISC_R_SUCCESS
);
487 * Step the iterator to the next interface. Unlike
488 * isc_interfaceiter_next(), this may leave the iterator
489 * positioned on an interface that will ultimately
490 * be ignored. Return ISC_R_NOMORE if there are no more
491 * interfaces, otherwise ISC_R_SUCCESS.
494 internal_next(isc_interfaceiter_t
*iter
) {
495 if (iter
->numIF
>= iter
->v4IF
)
496 return (ISC_R_NOMORE
);
499 * The first one needs to be set up to point to the last
500 * Element of the array. Go to the end and back up
501 * Microsoft's implementation is peculiar for returning
502 * the list in reverse order
505 if (iter
->numIF
== 0)
506 iter
->pos4
= (INTERFACE_INFO
*)(iter
->buf4
+ (iter
->v4IF
));
509 if (&(iter
->pos4
) < &(iter
->buf4
))
510 return (ISC_R_NOMORE
);
512 memset(&(iter
->IFData
), 0, sizeof(INTERFACE_INFO
));
513 memcpy(&(iter
->IFData
), iter
->pos4
, sizeof(INTERFACE_INFO
));
516 return (ISC_R_SUCCESS
);
520 internal_next6(isc_interfaceiter_t
*iter
) {
522 return (ISC_R_NOMORE
);
524 return (ISC_R_SUCCESS
);
528 isc_interfaceiter_current(isc_interfaceiter_t
*iter
,
529 isc_interface_t
*ifdata
) {
530 REQUIRE(iter
->result
== ISC_R_SUCCESS
);
531 memcpy(ifdata
, &iter
->current
, sizeof(*ifdata
));
532 return (ISC_R_SUCCESS
);
536 isc_interfaceiter_first(isc_interfaceiter_t
*iter
) {
538 REQUIRE(VALID_IFITER(iter
));
541 * SIO_ADDRESS_LIST_QUERY (used to query IPv6 addresses)
542 * intentionally omits localhost addresses ::1 and ::fe80 in
543 * some cases. ntpd depends on enumerating ::1 to listen on
544 * it, and ntpq and ntpdc default to "localhost" as the target,
545 * so they will attempt to talk to [::1]:123 and fail. This
546 * means we need to synthesize ::1, which we will do first,
549 if (iter
->buf6
!= NULL
)
550 iter
->pos6
= iter
->buf6
->iAddressCount
+ 1;
552 iter
->result
= ISC_R_SUCCESS
;
553 return (isc_interfaceiter_next(iter
));
557 isc_interfaceiter_next(isc_interfaceiter_t
*iter
) {
560 REQUIRE(VALID_IFITER(iter
));
561 REQUIRE(iter
->result
== ISC_R_SUCCESS
);
564 result
= internal_next(iter
);
565 if (result
== ISC_R_NOMORE
) {
566 result
= internal_next6(iter
);
567 if (result
!= ISC_R_SUCCESS
)
569 result
= internal_current6(iter
);
570 if (result
!= ISC_R_IGNORE
)
572 } else if (result
!= ISC_R_SUCCESS
)
574 result
= internal_current(iter
);
575 if (result
!= ISC_R_IGNORE
)
578 iter
->result
= result
;
583 isc_interfaceiter_destroy(isc_interfaceiter_t
**iterp
) {
584 isc_interfaceiter_t
*iter
;
585 REQUIRE(iterp
!= NULL
);
587 REQUIRE(VALID_IFITER(iter
));
589 if (iter
->buf4
!= NULL
)
590 isc_mem_put(iter
->mctx
, iter
->buf4
, iter
->buf4size
);
591 if (iter
->buf6
!= NULL
)
592 isc_mem_put(iter
->mctx
, iter
->buf6
, iter
->buf6size
);
595 isc_mem_put(iter
->mctx
, iter
, sizeof(*iter
));