1 /* $NetBSD: ifiter_ioctl.c,v 1.3 2006/06/11 19:34:10 kardel Exp $ */
4 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and 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: ifiter_ioctl.c,v 1.19.2.5.2.14 2004/06/22 04:40:23 marka Exp */
23 * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl.
27 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
28 #ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
29 #define lifc_len iflc_len
30 #define lifc_buf iflc_buf
31 #define lifc_req iflc_req
32 #define LIFCONF if_laddrconf
34 #define ISC_HAVE_LIFC_FAMILY 1
35 #define ISC_HAVE_LIFC_FLAGS 1
36 #define LIFCONF lifconf
39 #ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
40 #define lifr_addr iflr_addr
41 #define lifr_name iflr_name
42 #define lifr_dstaddr iflr_dstaddr
43 #define lifr_broadaddr iflr_broadaddr
44 #define lifr_flags iflr_flags
45 #define lifr_index iflr_index
46 #define ss_family sa_family
47 #define LIFREQ if_laddrreq
53 #define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'T')
54 #define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)
56 #define ISC_IF_INET6_SZ \
57 sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n")
59 struct isc_interfaceiter
{
60 unsigned int magic
; /* Magic number. */
65 void *buf
; /* Buffer for sysctl data. */
66 unsigned int bufsize
; /* Bytes allocated. */
67 unsigned int pos
; /* Current offset in
69 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
72 void *buf6
; /* Buffer for sysctl data. */
73 unsigned int bufsize6
; /* Bytes allocated. */
74 unsigned int pos6
; /* Current offset in
76 isc_result_t result6
; /* Last result code. */
79 #ifdef HAVE_TRUCLUSTER
80 int clua_context
; /* Cluster alias context */
81 isc_boolean_t clua_done
;
82 struct sockaddr clua_sa
;
86 char entry
[ISC_IF_INET6_SZ
];
90 isc_interface_t current
; /* Current interface data. */
91 isc_result_t result
; /* Last result code. */
94 #ifdef HAVE_TRUCLUSTER
95 #include <clua/clua.h>
96 #include <sys/socket.h>
101 * Size of buffer for SIOCGLIFCONF, in bytes. We assume no sane system
102 * will have more than a megabyte of interface configuration data.
104 #define IFCONF_BUFSIZE_INITIAL 4096
105 #define IFCONF_BUFSIZE_MAX 1048576
110 # define IF_NAMESIZE IFNAMSIZ
112 # define IF_NAMESIZE 16
118 getbuf4(isc_interfaceiter_t
*iter
) {
119 char strbuf
[ISC_STRERRORSIZE
];
121 iter
->bufsize
= IFCONF_BUFSIZE_INITIAL
;
124 iter
->buf
= isc_mem_get(iter
->mctx
, iter
->bufsize
);
125 if (iter
->buf
== NULL
)
126 return (ISC_R_NOMEMORY
);
128 memset(&iter
->ifc
.ifc_len
, 0, sizeof(iter
->ifc
.ifc_len
));
129 iter
->ifc
.ifc_len
= iter
->bufsize
;
130 iter
->ifc
.ifc_buf
= iter
->buf
;
132 * Ignore the HP/UX warning about "integer overflow during
133 * conversion". It comes from its own macro definition,
134 * and is really hard to shut up.
136 if (ioctl(iter
->socket
, SIOCGIFCONF
, (char *)&iter
->ifc
)
138 if (errno
!= EINVAL
) {
139 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
140 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
141 isc_msgcat_get(isc_msgcat
,
142 ISC_MSGSET_IFITERIOCTL
,
145 "configuration: %s"),
150 * EINVAL. Retry with a bigger buffer.
154 * The ioctl succeeded.
155 * Some OS's just return what will fit rather
156 * than set EINVAL if the buffer is too small
157 * to fit all the interfaces in. If
158 * ifc.lifc_len is too near to the end of the
159 * buffer we will grow it just in case and
162 if (iter
->ifc
.ifc_len
+ 2 * sizeof(struct ifreq
)
166 if (iter
->bufsize
>= IFCONF_BUFSIZE_MAX
) {
167 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
168 isc_msgcat_get(isc_msgcat
,
169 ISC_MSGSET_IFITERIOCTL
,
177 isc_mem_put(iter
->mctx
, iter
->buf
, iter
->bufsize
);
181 return (ISC_R_SUCCESS
);
184 isc_mem_put(iter
->mctx
, iter
->buf
, iter
->bufsize
);
186 return (ISC_R_UNEXPECTED
);
189 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
191 getbuf6(isc_interfaceiter_t
*iter
) {
192 char strbuf
[ISC_STRERRORSIZE
];
195 iter
->bufsize6
= IFCONF_BUFSIZE_INITIAL
;
198 iter
->buf6
= isc_mem_get(iter
->mctx
, iter
->bufsize6
);
199 if (iter
->buf6
== NULL
)
200 return (ISC_R_NOMEMORY
);
202 memset(&iter
->lifc
, 0, sizeof(iter
->lifc
));
203 #ifdef ISC_HAVE_LIFC_FAMILY
204 iter
->lifc
.lifc_family
= AF_INET6
;
206 #ifdef ISC_HAVE_LIFC_FLAGS
207 iter
->lifc
.lifc_flags
= 0;
209 iter
->lifc
.lifc_len
= iter
->bufsize6
;
210 iter
->lifc
.lifc_buf
= iter
->buf6
;
212 * Ignore the HP/UX warning about "integer overflow during
213 * conversion". It comes from its own macro definition,
214 * and is really hard to shut up.
216 if (ioctl(iter
->socket6
, SIOCGLIFCONF
, (char *)&iter
->lifc
)
220 * IPv6 interface scanning is not available on all
221 * kernels w/ IPv6 sockets.
223 if (errno
== ENOENT
) {
224 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
225 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
226 isc_msgcat_get(isc_msgcat
,
227 ISC_MSGSET_IFITERIOCTL
,
230 "configuration: %s"),
232 result
= ISC_R_FAILURE
;
236 if (errno
!= EINVAL
) {
237 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
238 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
239 isc_msgcat_get(isc_msgcat
,
240 ISC_MSGSET_IFITERIOCTL
,
243 "configuration: %s"),
245 result
= ISC_R_UNEXPECTED
;
249 * EINVAL. Retry with a bigger buffer.
253 * The ioctl succeeded.
254 * Some OS's just return what will fit rather
255 * than set EINVAL if the buffer is too small
256 * to fit all the interfaces in. If
257 * ifc.ifc_len is too near to the end of the
258 * buffer we will grow it just in case and
261 if (iter
->lifc
.lifc_len
+ 2 * sizeof(struct LIFREQ
)
265 if (iter
->bufsize6
>= IFCONF_BUFSIZE_MAX
) {
266 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
267 isc_msgcat_get(isc_msgcat
,
268 ISC_MSGSET_IFITERIOCTL
,
274 result
= ISC_R_UNEXPECTED
;
277 isc_mem_put(iter
->mctx
, iter
->buf6
, iter
->bufsize6
);
282 if (iter
->lifc
.lifc_len
!= 0)
284 return (ISC_R_SUCCESS
);
287 isc_mem_put(iter
->mctx
, iter
->buf6
, iter
->bufsize6
);
294 isc_interfaceiter_create(isc_mem_t
*mctx
, isc_interfaceiter_t
**iterp
) {
295 isc_interfaceiter_t
*iter
;
297 char strbuf
[ISC_STRERRORSIZE
];
299 REQUIRE(iterp
!= NULL
);
300 REQUIRE(*iterp
== NULL
);
302 iter
= isc_mem_get(mctx
, sizeof(*iter
));
304 return (ISC_R_NOMEMORY
);
309 iter
->pos
= (unsigned int) -1;
310 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
312 iter
->pos6
= (unsigned int) -1;
313 iter
->result6
= ISC_R_NOMORE
;
315 iter
->first6
= ISC_FALSE
;
319 * Get the interface configuration, allocating more memory if
323 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
324 result
= isc_net_probeipv6();
325 if (result
== ISC_R_SUCCESS
) {
327 * Create an unbound datagram socket to do the SIOCGLIFCONF
328 * ioctl on. HP/UX requires an AF_INET6 socket for
329 * SIOCGLIFCONF to get IPv6 addresses.
331 if ((iter
->socket6
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
332 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
333 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
334 isc_msgcat_get(isc_msgcat
,
335 ISC_MSGSET_IFITERIOCTL
,
336 ISC_MSG_MAKESCANSOCKET
,
340 result
= ISC_R_UNEXPECTED
;
341 goto socket6_failure
;
343 iter
->result6
= getbuf6(iter
);
344 if (iter
->result6
!= ISC_R_NOTIMPLEMENTED
&&
345 iter
->result6
!= ISC_R_SUCCESS
)
349 if ((iter
->socket
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
350 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
351 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
352 isc_msgcat_get(isc_msgcat
,
353 ISC_MSGSET_IFITERIOCTL
,
354 ISC_MSG_MAKESCANSOCKET
,
358 result
= ISC_R_UNEXPECTED
;
361 result
= getbuf4(iter
);
362 if (result
!= ISC_R_SUCCESS
)
366 * A newly created iterator has an undefined position
367 * until isc_interfaceiter_first() is called.
369 #ifdef HAVE_TRUCLUSTER
370 iter
->clua_context
= -1;
371 iter
->clua_done
= ISC_TRUE
;
374 iter
->proc
= fopen("/proc/net/if_inet6", "r");
375 iter
->valid
= ISC_R_FAILURE
;
376 iter
->first
= ISC_FALSE
;
378 iter
->result
= ISC_R_FAILURE
;
380 iter
->magic
= IFITER_MAGIC
;
382 return (ISC_R_SUCCESS
);
385 if (iter
->buf
!= NULL
)
386 isc_mem_put(mctx
, iter
->buf
, iter
->bufsize
);
387 (void) close(iter
->socket
);
390 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
391 if (iter
->buf6
!= NULL
)
392 isc_mem_put(mctx
, iter
->buf6
, iter
->bufsize6
);
394 if (iter
->socket6
!= -1)
395 (void) close(iter
->socket6
);
399 isc_mem_put(mctx
, iter
, sizeof(*iter
));
403 #ifdef HAVE_TRUCLUSTER
405 get_inaddr(isc_netaddr_t
*dst
, struct in_addr
*src
) {
406 dst
->family
= AF_INET
;
407 memcpy(&dst
->type
.in
, src
, sizeof(struct in_addr
));
411 internal_current_clusteralias(isc_interfaceiter_t
*iter
) {
413 if (clua_getaliasinfo(&iter
->clua_sa
, &ci
) != CLUA_SUCCESS
)
414 return (ISC_R_IGNORE
);
415 memset(&iter
->current
, 0, sizeof(iter
->current
));
416 iter
->current
.af
= iter
->clua_sa
.sa_family
;
417 memset(iter
->current
.name
, 0, sizeof(iter
->current
.name
));
418 sprintf(iter
->current
.name
, "clua%d", ci
.aliasid
);
419 iter
->current
.flags
= INTERFACE_F_UP
;
420 get_inaddr(&iter
->current
.address
, &ci
.addr
);
421 get_inaddr(&iter
->current
.netmask
, &ci
.netmask
);
422 return (ISC_R_SUCCESS
);
428 linux_if_inet6_next(isc_interfaceiter_t
*iter
) {
429 if (iter
->proc
!= NULL
&&
430 fgets(iter
->entry
, sizeof(iter
->entry
), iter
->proc
) != NULL
)
431 iter
->valid
= ISC_R_SUCCESS
;
433 iter
->valid
= ISC_R_NOMORE
;
434 return (iter
->valid
);
438 linux_if_inet6_first(isc_interfaceiter_t
*iter
) {
439 if (iter
->proc
!= NULL
) {
441 (void)linux_if_inet6_next(iter
);
443 iter
->valid
= ISC_R_NOMORE
;
444 iter
->first
= ISC_FALSE
;
448 linux_if_inet6_current(isc_interfaceiter_t
*iter
) {
450 char name
[IF_NAMESIZE
+1];
451 char strbuf
[ISC_STRERRORSIZE
];
452 struct in6_addr addr6
;
454 int ifindex
, prefix
, scope
, flags
;
458 if (iter
->valid
!= ISC_R_SUCCESS
)
459 return (iter
->valid
);
460 if (iter
->proc
== NULL
) {
461 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
462 "/proc/net/if_inet6:iter->proc == NULL");
463 return (ISC_R_FAILURE
);
467 * Format for /proc/net/if_inet6:
468 * (see iface_proc_info() in net/ipv6/addrconf.c)
469 * <addr6:32> <ifindex:2> <prefix:2> <scope:2> <flags:2> <name:8>
471 res
= sscanf(iter
->entry
, "%32[a-f0-9] %x %x %x %x %16s\n",
472 address
, &ifindex
, &prefix
, &scope
, &flags
, name
);
474 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
475 "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
477 return (ISC_R_FAILURE
);
479 if (strlen(address
) != 32) {
480 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
481 "/proc/net/if_inet6:strlen(%s) != 32", address
);
482 return (ISC_R_FAILURE
);
484 for (i
= 0; i
< 16; i
++) {
486 static const char hex
[] = "0123456789abcdef";
487 byte
= ((index(hex
, address
[i
* 2]) - hex
) << 4) |
488 (index(hex
, address
[i
* 2 + 1]) - hex
);
489 addr6
.s6_addr
[i
] = byte
;
491 iter
->current
.af
= AF_INET6
;
492 /* iter->current.ifindex = ifindex; */
493 iter
->current
.flags
= 0;
495 memset(&ifreq
, 0, sizeof(ifreq
));
496 INSIST(sizeof(ifreq
.ifr_name
) <= sizeof(iter
->current
.name
));
497 strncpy(ifreq
.ifr_name
, name
, sizeof(ifreq
.ifr_name
));
499 if (ioctl(iter
->socket
, SIOCGIFFLAGS
, (char *) &ifreq
) < 0) {
500 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
501 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
502 "%s: getting interface flags: %s",
503 ifreq
.ifr_name
, strbuf
);
504 return (ISC_R_IGNORE
);
507 if ((ifreq
.ifr_flags
& IFF_UP
) != 0)
508 iter
->current
.flags
|= INTERFACE_F_UP
;
509 #ifdef IFF_POINTOPOINT
510 if ((ifreq
.ifr_flags
& IFF_POINTOPOINT
) != 0)
511 iter
->current
.flags
|= INTERFACE_F_POINTTOPOINT
;
513 if ((ifreq
.ifr_flags
& IFF_LOOPBACK
) != 0)
514 iter
->current
.flags
|= INTERFACE_F_LOOPBACK
;
515 if ((ifreq
.ifr_flags
& IFF_BROADCAST
) != 0)
516 iter
->current
.flags
|= INTERFACE_F_BROADCAST
;
518 if ((ifreq
.ifr_flags
& IFF_MULTICAST
) != 0)
519 iter
->current
.flags
|= INTERFACE_F_MULTICAST
;
523 * enable_multicast_if() requires scopeid for setsockopt,
524 * so associate address with their corresponding ifindex.
526 isc_netaddr_fromin6(&iter
->current
.address
, &addr6
);
527 isc_netaddr_setzone(&iter
->current
.address
, (isc_uint32_t
)ifindex
);
529 for (i
= 0; i
< 16; i
++) {
531 addr6
.s6_addr
[i
] = 0xff;
534 addr6
.s6_addr
[i
] = (0xff << (8 - prefix
)) & 0xff;
538 isc_netaddr_fromin6(&iter
->current
.netmask
, &addr6
);
539 strncpy(iter
->current
.name
, name
, sizeof(iter
->current
.name
));
540 return (ISC_R_SUCCESS
);
545 * Get information about the current interface to iter->current.
546 * If successful, return ISC_R_SUCCESS.
547 * If the interface has an unsupported address family, or if
548 * some operation on it fails, return ISC_R_IGNORE to make
549 * the higher-level iterator code ignore it.
553 internal_current4(isc_interfaceiter_t
*iter
) {
557 char strbuf
[ISC_STRERRORSIZE
];
558 #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
559 struct lifreq lifreq
;
563 int i
, bits
, prefixlen
;
568 REQUIRE(VALID_IFITER(iter
));
569 REQUIRE (iter
->pos
< (unsigned int) iter
->ifc
.ifc_len
);
572 result
= linux_if_inet6_current(iter
);
573 if (result
!= ISC_R_NOMORE
)
575 iter
->first
= ISC_TRUE
;
578 ifrp
= (struct ifreq
*)((char *) iter
->ifc
.ifc_req
+ iter
->pos
);
580 memset(&ifreq
, 0, sizeof(ifreq
));
581 memcpy(&ifreq
, ifrp
, sizeof(ifreq
));
583 family
= ifreq
.ifr_addr
.sa_family
;
584 #if defined(ISC_PLATFORM_HAVEIPV6)
585 if (family
!= AF_INET
&& family
!= AF_INET6
)
587 if (family
!= AF_INET
)
589 return (ISC_R_IGNORE
);
591 memset(&iter
->current
, 0, sizeof(iter
->current
));
592 iter
->current
.af
= family
;
594 INSIST(sizeof(ifreq
.ifr_name
) <= sizeof(iter
->current
.name
));
595 memset(iter
->current
.name
, 0, sizeof(iter
->current
.name
));
596 memcpy(iter
->current
.name
, ifreq
.ifr_name
, sizeof(ifreq
.ifr_name
));
598 get_addr(family
, &iter
->current
.address
,
599 (struct sockaddr
*)&ifrp
->ifr_addr
, ifreq
.ifr_name
);
602 * If the interface does not have a address ignore it.
606 if (iter
->current
.address
.type
.in
.s_addr
== htonl(INADDR_ANY
))
607 return (ISC_R_IGNORE
);
609 #ifdef ISC_PLATFORM_HAVEIPV6
611 if (memcmp(&iter
->current
.address
.type
.in6
, &in6addr_any
,
612 sizeof(in6addr_any
)) == 0)
613 return (ISC_R_IGNORE
);
619 * Get interface flags.
622 iter
->current
.flags
= 0;
625 * Ignore the HP/UX warning about "integer overflow during
626 * conversion. It comes from its own macro definition,
627 * and is really hard to shut up.
629 if (ioctl(iter
->socket
, SIOCGIFFLAGS
, (char *) &ifreq
) < 0) {
630 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
631 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
632 "%s: getting interface flags: %s",
633 ifreq
.ifr_name
, strbuf
);
634 return (ISC_R_IGNORE
);
637 if ((ifreq
.ifr_flags
& IFF_UP
) != 0)
638 iter
->current
.flags
|= INTERFACE_F_UP
;
640 #ifdef IFF_POINTOPOINT
641 if ((ifreq
.ifr_flags
& IFF_POINTOPOINT
) != 0)
642 iter
->current
.flags
|= INTERFACE_F_POINTTOPOINT
;
645 if ((ifreq
.ifr_flags
& IFF_LOOPBACK
) != 0)
646 iter
->current
.flags
|= INTERFACE_F_LOOPBACK
;
648 if ((ifreq
.ifr_flags
& IFF_BROADCAST
) != 0) {
649 iter
->current
.flags
|= INTERFACE_F_BROADCAST
;
653 if ((ifreq
.ifr_flags
& IFF_MULTICAST
) != 0) {
654 iter
->current
.flags
|= INTERFACE_F_MULTICAST
;
658 if (family
== AF_INET
)
661 #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
662 memset(&lifreq
, 0, sizeof(lifreq
));
663 memcpy(lifreq
.lifr_name
, iter
->current
.name
, sizeof(lifreq
.lifr_name
));
664 memcpy(&lifreq
.lifr_addr
, &iter
->current
.address
.type
.in6
,
665 sizeof(iter
->current
.address
.type
.in6
));
667 if (ioctl(iter
->socket
, SIOCGLIFADDR
, &lifreq
) < 0) {
668 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
669 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
670 "%s: getting interface address: %s",
671 ifreq
.ifr_name
, strbuf
);
672 return (ISC_R_IGNORE
);
674 prefixlen
= lifreq
.lifr_addrlen
;
676 isc_netaddr_format(&iter
->current
.address
, sabuf
, sizeof(sabuf
));
677 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
678 isc_msgcat_get(isc_msgcat
,
679 ISC_MSGSET_IFITERIOCTL
,
681 "prefix length for %s is unknown "
682 "(assume 128)"), sabuf
);
687 * Netmask already zeroed.
689 iter
->current
.netmask
.family
= family
;
690 for (i
= 0; i
< 16; i
++) {
695 bits
= 8 - prefixlen
;
698 iter
->current
.netmask
.type
.in6
.s6_addr
[i
] = (~0 << bits
) & 0xff;
700 return (ISC_R_SUCCESS
);
703 if (family
!= AF_INET
)
704 return (ISC_R_IGNORE
);
705 #ifdef IFF_POINTOPOINT
707 * If the interface is point-to-point, get the destination address.
709 if ((iter
->current
.flags
& INTERFACE_F_POINTTOPOINT
) != 0) {
711 * Ignore the HP/UX warning about "integer overflow during
712 * conversion. It comes from its own macro definition,
713 * and is really hard to shut up.
715 if (ioctl(iter
->socket
, SIOCGIFDSTADDR
, (char *)&ifreq
)
717 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
718 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
719 isc_msgcat_get(isc_msgcat
,
720 ISC_MSGSET_IFITERIOCTL
,
723 "destination address: %s"),
724 ifreq
.ifr_name
, strbuf
);
725 return (ISC_R_IGNORE
);
727 get_addr(family
, &iter
->current
.dstaddress
,
728 (struct sockaddr
*)&ifreq
.ifr_dstaddr
, ifreq
.ifr_name
);
731 if ((iter
->current
.flags
& INTERFACE_F_BROADCAST
) != 0) {
733 * Ignore the HP/UX warning about "integer overflow during
734 * conversion. It comes from its own macro definition,
735 * and is really hard to shut up.
737 if (ioctl(iter
->socket
, SIOCGIFBRDADDR
, (char *)&ifreq
)
739 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
740 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
741 isc_msgcat_get(isc_msgcat
,
742 ISC_MSGSET_IFITERIOCTL
,
745 "broadcast address: %s"),
746 ifreq
.ifr_name
, strbuf
);
747 return (ISC_R_IGNORE
);
749 get_addr(family
, &iter
->current
.broadcast
,
750 (struct sockaddr
*)&ifreq
.ifr_broadaddr
, ifreq
.ifr_name
);
754 * Get the network mask.
756 memset(&ifreq
, 0, sizeof(ifreq
));
757 memcpy(&ifreq
, ifrp
, sizeof(ifreq
));
759 * Ignore the HP/UX warning about "integer overflow during
760 * conversion. It comes from its own macro definition,
761 * and is really hard to shut up.
763 if (ioctl(iter
->socket
, SIOCGIFNETMASK
, (char *)&ifreq
) < 0) {
764 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
765 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
766 isc_msgcat_get(isc_msgcat
,
767 ISC_MSGSET_IFITERIOCTL
,
769 "%s: getting netmask: %s"),
770 ifreq
.ifr_name
, strbuf
);
771 return (ISC_R_IGNORE
);
773 get_addr(family
, &iter
->current
.netmask
,
774 (struct sockaddr
*)&ifreq
.ifr_addr
, ifreq
.ifr_name
);
775 return (ISC_R_SUCCESS
);
778 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
780 internal_current6(isc_interfaceiter_t
*iter
) {
782 struct LIFREQ lifreq
;
784 char strbuf
[ISC_STRERRORSIZE
];
787 REQUIRE(VALID_IFITER(iter
));
788 if (iter
->result6
!= ISC_R_SUCCESS
)
789 return (iter
->result6
);
790 REQUIRE(iter
->pos6
< (unsigned int) iter
->lifc
.lifc_len
);
792 ifrp
= (struct LIFREQ
*)((char *) iter
->lifc
.lifc_req
+ iter
->pos6
);
794 memset(&lifreq
, 0, sizeof(lifreq
));
795 memcpy(&lifreq
, ifrp
, sizeof(lifreq
));
797 family
= lifreq
.lifr_addr
.ss_family
;
798 #ifdef ISC_PLATFORM_HAVEIPV6
799 if (family
!= AF_INET
&& family
!= AF_INET6
)
801 if (family
!= AF_INET
)
803 return (ISC_R_IGNORE
);
805 memset(&iter
->current
, 0, sizeof(iter
->current
));
806 iter
->current
.af
= family
;
808 INSIST(sizeof(lifreq
.lifr_name
) <= sizeof(iter
->current
.name
));
809 memset(iter
->current
.name
, 0, sizeof(iter
->current
.name
));
810 memcpy(iter
->current
.name
, lifreq
.lifr_name
, sizeof(lifreq
.lifr_name
));
812 get_addr(family
, &iter
->current
.address
,
813 (struct sockaddr
*)&lifreq
.lifr_addr
, lifreq
.lifr_name
);
816 * If the interface does not have a address ignore it.
820 if (iter
->current
.address
.type
.in
.s_addr
== htonl(INADDR_ANY
))
821 return (ISC_R_IGNORE
);
823 #ifdef ISC_PLATFORM_HAVEIPV6
825 if (memcmp(&iter
->current
.address
.type
.in6
, &in6addr_any
,
826 sizeof(in6addr_any
)) == 0)
827 return (ISC_R_IGNORE
);
833 * Get interface flags.
836 iter
->current
.flags
= 0;
838 if (family
== AF_INET6
)
844 * Ignore the HP/UX warning about "integer overflow during
845 * conversion. It comes from its own macro definition,
846 * and is really hard to shut up.
848 if (ioctl(fd
, SIOCGLIFFLAGS
, (char *) &lifreq
) < 0) {
849 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
850 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
851 "%s: getting interface flags: %s",
852 lifreq
.lifr_name
, strbuf
);
853 return (ISC_R_IGNORE
);
856 if ((lifreq
.lifr_flags
& IFF_UP
) != 0)
857 iter
->current
.flags
|= INTERFACE_F_UP
;
859 #ifdef IFF_POINTOPOINT
860 if ((lifreq
.lifr_flags
& IFF_POINTOPOINT
) != 0)
861 iter
->current
.flags
|= INTERFACE_F_POINTTOPOINT
;
864 if ((lifreq
.lifr_flags
& IFF_LOOPBACK
) != 0)
865 iter
->current
.flags
|= INTERFACE_F_LOOPBACK
;
867 if ((lifreq
.lifr_flags
& IFF_BROADCAST
) != 0) {
868 iter
->current
.flags
|= INTERFACE_F_BROADCAST
;
872 if ((lifreq
.lifr_flags
& IFF_MULTICAST
) != 0) {
873 iter
->current
.flags
|= INTERFACE_F_MULTICAST
;
877 #ifdef IFF_POINTOPOINT
879 * If the interface is point-to-point, get the destination address.
881 if ((iter
->current
.flags
& INTERFACE_F_POINTTOPOINT
) != 0) {
883 * Ignore the HP/UX warning about "interger overflow during
884 * conversion. It comes from its own macro definition,
885 * and is really hard to shut up.
887 if (ioctl(fd
, SIOCGLIFDSTADDR
, (char *)&lifreq
)
889 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
890 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
891 isc_msgcat_get(isc_msgcat
,
892 ISC_MSGSET_IFITERIOCTL
,
895 "destination address: %s"),
896 lifreq
.lifr_name
, strbuf
);
897 return (ISC_R_IGNORE
);
899 get_addr(family
, &iter
->current
.dstaddress
,
900 (struct sockaddr
*)&lifreq
.lifr_dstaddr
,
905 #ifdef SIOCGLIFBRDADDR
906 if ((iter
->current
.flags
& INTERFACE_F_BROADCAST
) != 0) {
908 * Ignore the HP/UX warning about "integer overflow during
909 * conversion. It comes from its own macro definition,
910 * and is really hard to shut up.
912 if (ioctl(iter
->socket
, SIOCGLIFBRDADDR
, (char *)&lifreq
)
914 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
915 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
916 isc_msgcat_get(isc_msgcat
,
917 ISC_MSGSET_IFITERIOCTL
,
920 "broadcast address: %s"),
921 lifreq
.lifr_name
, strbuf
);
922 return (ISC_R_IGNORE
);
924 get_addr(family
, &iter
->current
.broadcast
,
925 (struct sockaddr
*)&lifreq
.lifr_broadaddr
,
928 #endif /* SIOCGLIFBRDADDR */
931 * Get the network mask. Netmask already zeroed.
933 memset(&lifreq
, 0, sizeof(lifreq
));
934 memcpy(&lifreq
, ifrp
, sizeof(lifreq
));
938 * Special case: if the system provides lifr_addrlen member, the
939 * netmask of an IPv6 address can be derived from the length, since
940 * an IPv6 address always has a contiguous mask.
942 if (family
== AF_INET6
) {
945 iter
->current
.netmask
.family
= family
;
946 for (i
= 0; i
< lifreq
.lifr_addrlen
; i
+= 8) {
947 bits
= lifreq
.lifr_addrlen
- i
;
948 bits
= (bits
< 8) ? (8 - bits
) : 0;
949 iter
->current
.netmask
.type
.in6
.s6_addr
[i
/ 8] =
953 return (ISC_R_SUCCESS
);
958 * Ignore the HP/UX warning about "integer overflow during
959 * conversion. It comes from its own macro definition,
960 * and is really hard to shut up.
962 if (ioctl(fd
, SIOCGLIFNETMASK
, (char *)&lifreq
) < 0) {
963 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
964 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
965 isc_msgcat_get(isc_msgcat
,
966 ISC_MSGSET_IFITERIOCTL
,
968 "%s: getting netmask: %s"),
969 lifreq
.lifr_name
, strbuf
);
970 return (ISC_R_IGNORE
);
972 get_addr(family
, &iter
->current
.netmask
,
973 (struct sockaddr
*)&lifreq
.lifr_addr
, lifreq
.lifr_name
);
975 return (ISC_R_SUCCESS
);
980 internal_current(isc_interfaceiter_t
*iter
) {
981 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
982 if (iter
->mode
== 6) {
983 iter
->result6
= internal_current6(iter
);
984 if (iter
->result6
!= ISC_R_NOMORE
)
985 return (iter
->result6
);
988 #ifdef HAVE_TRUCLUSTER
989 if (!iter
->clua_done
)
990 return(internal_current_clusteralias(iter
));
992 return (internal_current4(iter
));
996 * Step the iterator to the next interface. Unlike
997 * isc_interfaceiter_next(), this may leave the iterator
998 * positioned on an interface that will ultimately
999 * be ignored. Return ISC_R_NOMORE if there are no more
1000 * interfaces, otherwise ISC_R_SUCCESS.
1003 internal_next4(isc_interfaceiter_t
*iter
) {
1006 REQUIRE (iter
->pos
< (unsigned int) iter
->ifc
.ifc_len
);
1009 if (linux_if_inet6_next(iter
) == ISC_R_SUCCESS
)
1010 return (ISC_R_SUCCESS
);
1012 return (ISC_R_SUCCESS
);
1014 ifrp
= (struct ifreq
*)((char *) iter
->ifc
.ifc_req
+ iter
->pos
);
1016 #ifdef ISC_PLATFORM_HAVESALEN
1017 if (ifrp
->ifr_addr
.sa_len
> sizeof(struct sockaddr
))
1018 iter
->pos
+= sizeof(ifrp
->ifr_name
) + ifrp
->ifr_addr
.sa_len
;
1021 iter
->pos
+= sizeof(*ifrp
);
1023 if (iter
->pos
>= (unsigned int) iter
->ifc
.ifc_len
)
1024 return (ISC_R_NOMORE
);
1026 return (ISC_R_SUCCESS
);
1029 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1031 internal_next6(isc_interfaceiter_t
*iter
) {
1032 struct LIFREQ
*ifrp
;
1034 if (iter
->result6
!= ISC_R_SUCCESS
&& iter
->result6
!= ISC_R_IGNORE
)
1035 return (iter
->result6
);
1037 REQUIRE(iter
->pos6
< (unsigned int) iter
->lifc
.lifc_len
);
1039 ifrp
= (struct LIFREQ
*)((char *) iter
->lifc
.lifc_req
+ iter
->pos6
);
1041 #ifdef ISC_PLATFORM_HAVESALEN
1042 if (ifrp
->lifr_addr
.sa_len
> sizeof(struct sockaddr
))
1043 iter
->pos6
+= sizeof(ifrp
->lifr_name
) + ifrp
->lifr_addr
.sa_len
;
1046 iter
->pos6
+= sizeof(*ifrp
);
1048 if (iter
->pos6
>= (unsigned int) iter
->lifc
.lifc_len
)
1049 return (ISC_R_NOMORE
);
1051 return (ISC_R_SUCCESS
);
1056 internal_next(isc_interfaceiter_t
*iter
) {
1057 #ifdef HAVE_TRUCLUSTER
1060 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1061 if (iter
->mode
== 6) {
1062 iter
->result6
= internal_next6(iter
);
1063 if (iter
->result6
!= ISC_R_NOMORE
)
1064 return (iter
->result6
);
1066 iter
->first6
= ISC_FALSE
;
1067 return (ISC_R_SUCCESS
);
1071 #ifdef HAVE_TRUCLUSTER
1072 if (!iter
->clua_done
) {
1073 clua_result
= clua_getaliasaddress(&iter
->clua_sa
,
1074 &iter
->clua_context
);
1075 if (clua_result
!= CLUA_SUCCESS
)
1076 iter
->clua_done
= ISC_TRUE
;
1077 return (ISC_R_SUCCESS
);
1080 return (internal_next4(iter
));
1084 internal_destroy(isc_interfaceiter_t
*iter
) {
1085 (void) close(iter
->socket
);
1086 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1087 if (iter
->socket6
!= -1)
1088 (void) close(iter
->socket6
);
1089 if (iter
->buf6
!= NULL
) {
1090 isc_mem_put(iter
->mctx
, iter
->buf6
, iter
->bufsize6
);
1094 if (iter
->proc
!= NULL
)
1100 void internal_first(isc_interfaceiter_t
*iter
) {
1101 #ifdef HAVE_TRUCLUSTER
1105 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1107 if (iter
->result6
== ISC_R_NOMORE
)
1108 iter
->result6
= ISC_R_SUCCESS
;
1109 iter
->first6
= ISC_TRUE
;
1111 #ifdef HAVE_TRUCLUSTER
1112 iter
->clua_context
= 0;
1113 clua_result
= clua_getaliasaddress(&iter
->clua_sa
,
1114 &iter
->clua_context
);
1115 iter
->clua_done
= ISC_TF(clua_result
!= CLUA_SUCCESS
);
1118 linux_if_inet6_first(iter
);