4 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 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: ifiter_ioctl.c,v 1.60.120.2 2009/01/18 23:47:41 tbox Exp */
24 * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl.
28 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
29 #ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
30 #define lifc_len iflc_len
31 #define lifc_buf iflc_buf
32 #define lifc_req iflc_req
33 #define LIFCONF if_laddrconf
35 #define ISC_HAVE_LIFC_FAMILY 1
36 #define ISC_HAVE_LIFC_FLAGS 1
37 #define LIFCONF lifconf
40 #ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
41 #define lifr_addr iflr_addr
42 #define lifr_name iflr_name
43 #define lifr_dstaddr iflr_dstaddr
44 #define lifr_broadaddr iflr_broadaddr
45 #define lifr_flags iflr_flags
46 #define lifr_index iflr_index
47 #define ss_family sa_family
48 #define LIFREQ if_laddrreq
54 #define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'T')
55 #define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)
57 struct isc_interfaceiter
{
58 unsigned int magic
; /* Magic number. */
63 void *buf
; /* Buffer for sysctl data. */
64 unsigned int bufsize
; /* Bytes allocated. */
65 unsigned int pos
; /* Current offset in
67 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
70 void *buf6
; /* Buffer for sysctl data. */
71 unsigned int bufsize6
; /* Bytes allocated. */
72 unsigned int pos6
; /* Current offset in
74 isc_result_t result6
; /* Last result code. */
77 #ifdef HAVE_TRUCLUSTER
78 int clua_context
; /* Cluster alias context */
79 isc_boolean_t clua_done
;
80 struct sockaddr clua_sa
;
84 char entry
[ISC_IF_INET6_SZ
];
87 isc_interface_t current
; /* Current interface data. */
88 isc_result_t result
; /* Last result code. */
91 #ifdef HAVE_TRUCLUSTER
92 #include <clua/clua.h>
93 #include <sys/socket.h>
98 * Size of buffer for SIOCGLIFCONF, in bytes. We assume no sane system
99 * will have more than a megabyte of interface configuration data.
101 #define IFCONF_BUFSIZE_INITIAL 4096
102 #define IFCONF_BUFSIZE_MAX 1048576
107 # define IF_NAMESIZE IFNAMSIZ
109 # define IF_NAMESIZE 16
115 getbuf4(isc_interfaceiter_t
*iter
) {
116 char strbuf
[ISC_STRERRORSIZE
];
118 iter
->bufsize
= IFCONF_BUFSIZE_INITIAL
;
121 iter
->buf
= isc_mem_get(iter
->mctx
, iter
->bufsize
);
122 if (iter
->buf
== NULL
)
123 return (ISC_R_NOMEMORY
);
125 memset(&iter
->ifc
.ifc_len
, 0, sizeof(iter
->ifc
.ifc_len
));
126 iter
->ifc
.ifc_len
= iter
->bufsize
;
127 iter
->ifc
.ifc_buf
= iter
->buf
;
129 * Ignore the HP/UX warning about "integer overflow during
130 * conversion". It comes from its own macro definition,
131 * and is really hard to shut up.
133 if (ioctl(iter
->socket
, SIOCGIFCONF
, (char *)&iter
->ifc
)
135 if (errno
!= EINVAL
) {
136 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
137 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
138 isc_msgcat_get(isc_msgcat
,
139 ISC_MSGSET_IFITERIOCTL
,
142 "configuration: %s"),
147 * EINVAL. Retry with a bigger buffer.
151 * The ioctl succeeded.
152 * Some OS's just return what will fit rather
153 * than set EINVAL if the buffer is too small
154 * to fit all the interfaces in. If
155 * ifc.lifc_len is too near to the end of the
156 * buffer we will grow it just in case and
159 if (iter
->ifc
.ifc_len
+ 2 * sizeof(struct ifreq
)
163 if (iter
->bufsize
>= IFCONF_BUFSIZE_MAX
) {
164 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
165 isc_msgcat_get(isc_msgcat
,
166 ISC_MSGSET_IFITERIOCTL
,
174 isc_mem_put(iter
->mctx
, iter
->buf
, iter
->bufsize
);
178 return (ISC_R_SUCCESS
);
181 isc_mem_put(iter
->mctx
, iter
->buf
, iter
->bufsize
);
183 return (ISC_R_UNEXPECTED
);
186 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
188 getbuf6(isc_interfaceiter_t
*iter
) {
189 char strbuf
[ISC_STRERRORSIZE
];
192 iter
->bufsize6
= IFCONF_BUFSIZE_INITIAL
;
195 iter
->buf6
= isc_mem_get(iter
->mctx
, iter
->bufsize6
);
196 if (iter
->buf6
== NULL
)
197 return (ISC_R_NOMEMORY
);
199 memset(&iter
->lifc
, 0, sizeof(iter
->lifc
));
200 #ifdef ISC_HAVE_LIFC_FAMILY
201 iter
->lifc
.lifc_family
= AF_INET6
;
203 #ifdef ISC_HAVE_LIFC_FLAGS
204 iter
->lifc
.lifc_flags
= 0;
206 iter
->lifc
.lifc_len
= iter
->bufsize6
;
207 iter
->lifc
.lifc_buf
= iter
->buf6
;
209 * Ignore the HP/UX warning about "integer overflow during
210 * conversion". It comes from its own macro definition,
211 * and is really hard to shut up.
213 if (ioctl(iter
->socket6
, SIOCGLIFCONF
, (char *)&iter
->lifc
)
217 * IPv6 interface scanning is not available on all
218 * kernels w/ IPv6 sockets.
220 if (errno
== ENOENT
) {
221 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
222 isc_log_write(isc_lctx
, ISC_LOGCATEGORY_GENERAL
,
223 ISC_LOGMODULE_INTERFACE
,
225 isc_msgcat_get(isc_msgcat
,
226 ISC_MSGSET_IFITERIOCTL
,
229 "configuration: %s"),
231 result
= ISC_R_FAILURE
;
235 if (errno
!= EINVAL
) {
236 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
237 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
238 isc_msgcat_get(isc_msgcat
,
239 ISC_MSGSET_IFITERIOCTL
,
242 "configuration: %s"),
244 result
= ISC_R_UNEXPECTED
;
248 * EINVAL. Retry with a bigger buffer.
252 * The ioctl succeeded.
253 * Some OS's just return what will fit rather
254 * than set EINVAL if the buffer is too small
255 * to fit all the interfaces in. If
256 * ifc.ifc_len is too near to the end of the
257 * buffer we will grow it just in case and
260 if (iter
->lifc
.lifc_len
+ 2 * sizeof(struct LIFREQ
)
264 if (iter
->bufsize6
>= IFCONF_BUFSIZE_MAX
) {
265 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
266 isc_msgcat_get(isc_msgcat
,
267 ISC_MSGSET_IFITERIOCTL
,
273 result
= ISC_R_UNEXPECTED
;
276 isc_mem_put(iter
->mctx
, iter
->buf6
, iter
->bufsize6
);
281 if (iter
->lifc
.lifc_len
!= 0)
283 return (ISC_R_SUCCESS
);
286 isc_mem_put(iter
->mctx
, iter
->buf6
, iter
->bufsize6
);
293 isc_interfaceiter_create(isc_mem_t
*mctx
, isc_interfaceiter_t
**iterp
) {
294 isc_interfaceiter_t
*iter
;
296 char strbuf
[ISC_STRERRORSIZE
];
298 REQUIRE(mctx
!= NULL
);
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 result
= iter
->result6
= getbuf6(iter
);
344 if (result
!= ISC_R_NOTIMPLEMENTED
&& result
!= ISC_R_SUCCESS
)
348 if ((iter
->socket
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) {
349 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
350 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
351 isc_msgcat_get(isc_msgcat
,
352 ISC_MSGSET_IFITERIOCTL
,
353 ISC_MSG_MAKESCANSOCKET
,
357 result
= ISC_R_UNEXPECTED
;
360 result
= getbuf4(iter
);
361 if (result
!= ISC_R_SUCCESS
)
365 * A newly created iterator has an undefined position
366 * until isc_interfaceiter_first() is called.
368 #ifdef HAVE_TRUCLUSTER
369 iter
->clua_context
= -1;
370 iter
->clua_done
= ISC_TRUE
;
373 iter
->proc
= fopen("/proc/net/if_inet6", "r");
374 iter
->valid
= ISC_R_FAILURE
;
376 iter
->result
= ISC_R_FAILURE
;
378 iter
->magic
= IFITER_MAGIC
;
380 return (ISC_R_SUCCESS
);
383 if (iter
->buf
!= NULL
)
384 isc_mem_put(mctx
, iter
->buf
, iter
->bufsize
);
385 (void) close(iter
->socket
);
388 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
389 if (iter
->buf6
!= NULL
)
390 isc_mem_put(mctx
, iter
->buf6
, iter
->bufsize6
);
392 if (iter
->socket6
!= -1)
393 (void) close(iter
->socket6
);
397 isc_mem_put(mctx
, iter
, sizeof(*iter
));
401 #ifdef HAVE_TRUCLUSTER
403 get_inaddr(isc_netaddr_t
*dst
, struct in_addr
*src
) {
404 dst
->family
= AF_INET
;
405 memcpy(&dst
->type
.in
, src
, sizeof(struct in_addr
));
409 internal_current_clusteralias(isc_interfaceiter_t
*iter
) {
411 if (clua_getaliasinfo(&iter
->clua_sa
, &ci
) != CLUA_SUCCESS
)
412 return (ISC_R_IGNORE
);
413 memset(&iter
->current
, 0, sizeof(iter
->current
));
414 iter
->current
.af
= iter
->clua_sa
.sa_family
;
415 memset(iter
->current
.name
, 0, sizeof(iter
->current
.name
));
416 sprintf(iter
->current
.name
, "clua%d", ci
.aliasid
);
417 iter
->current
.flags
= INTERFACE_F_UP
;
418 get_inaddr(&iter
->current
.address
, &ci
.addr
);
419 get_inaddr(&iter
->current
.netmask
, &ci
.netmask
);
420 return (ISC_R_SUCCESS
);
425 * Get information about the current interface to iter->current.
426 * If successful, return ISC_R_SUCCESS.
427 * If the interface has an unsupported address family, or if
428 * some operation on it fails, return ISC_R_IGNORE to make
429 * the higher-level iterator code ignore it.
433 internal_current4(isc_interfaceiter_t
*iter
) {
437 char strbuf
[ISC_STRERRORSIZE
];
438 #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
439 struct lifreq lifreq
;
443 int i
, bits
, prefixlen
;
445 REQUIRE(VALID_IFITER(iter
));
447 if (iter
->ifc
.ifc_len
== 0 ||
448 iter
->pos
== (unsigned int)iter
->ifc
.ifc_len
) {
450 return (linux_if_inet6_current(iter
));
452 return (ISC_R_NOMORE
);
456 INSIST( iter
->pos
< (unsigned int) iter
->ifc
.ifc_len
);
458 ifrp
= (struct ifreq
*)((char *) iter
->ifc
.ifc_req
+ iter
->pos
);
460 memset(&ifreq
, 0, sizeof(ifreq
));
461 memcpy(&ifreq
, ifrp
, sizeof(ifreq
));
463 family
= ifreq
.ifr_addr
.sa_family
;
464 #if defined(ISC_PLATFORM_HAVEIPV6)
465 if (family
!= AF_INET
&& family
!= AF_INET6
)
467 if (family
!= AF_INET
)
469 return (ISC_R_IGNORE
);
471 memset(&iter
->current
, 0, sizeof(iter
->current
));
472 iter
->current
.af
= family
;
474 INSIST(sizeof(ifreq
.ifr_name
) <= sizeof(iter
->current
.name
));
475 memset(iter
->current
.name
, 0, sizeof(iter
->current
.name
));
476 memcpy(iter
->current
.name
, ifreq
.ifr_name
, sizeof(ifreq
.ifr_name
));
478 get_addr(family
, &iter
->current
.address
,
479 (struct sockaddr
*)&ifrp
->ifr_addr
, ifreq
.ifr_name
);
482 * If the interface does not have a address ignore it.
486 if (iter
->current
.address
.type
.in
.s_addr
== htonl(INADDR_ANY
))
487 return (ISC_R_IGNORE
);
490 if (memcmp(&iter
->current
.address
.type
.in6
, &in6addr_any
,
491 sizeof(in6addr_any
)) == 0)
492 return (ISC_R_IGNORE
);
497 * Get interface flags.
500 iter
->current
.flags
= 0;
503 * Ignore the HP/UX warning about "integer overflow during
504 * conversion. It comes from its own macro definition,
505 * and is really hard to shut up.
507 if (ioctl(iter
->socket
, SIOCGIFFLAGS
, (char *) &ifreq
) < 0) {
508 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
509 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
510 "%s: getting interface flags: %s",
511 ifreq
.ifr_name
, strbuf
);
512 return (ISC_R_IGNORE
);
515 if ((ifreq
.ifr_flags
& IFF_UP
) != 0)
516 iter
->current
.flags
|= INTERFACE_F_UP
;
518 #ifdef IFF_POINTOPOINT
519 if ((ifreq
.ifr_flags
& IFF_POINTOPOINT
) != 0)
520 iter
->current
.flags
|= INTERFACE_F_POINTTOPOINT
;
523 if ((ifreq
.ifr_flags
& IFF_LOOPBACK
) != 0)
524 iter
->current
.flags
|= INTERFACE_F_LOOPBACK
;
526 if ((ifreq
.ifr_flags
& IFF_BROADCAST
) != 0)
527 iter
->current
.flags
|= INTERFACE_F_BROADCAST
;
530 if ((ifreq
.ifr_flags
& IFF_MULTICAST
) != 0)
531 iter
->current
.flags
|= INTERFACE_F_MULTICAST
;
534 if (family
== AF_INET
)
537 #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
538 memset(&lifreq
, 0, sizeof(lifreq
));
539 memcpy(lifreq
.lifr_name
, iter
->current
.name
, sizeof(lifreq
.lifr_name
));
540 memcpy(&lifreq
.lifr_addr
, &iter
->current
.address
.type
.in6
,
541 sizeof(iter
->current
.address
.type
.in6
));
543 if (ioctl(iter
->socket
, SIOCGLIFADDR
, &lifreq
) < 0) {
544 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
545 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
546 "%s: getting interface address: %s",
547 ifreq
.ifr_name
, strbuf
);
548 return (ISC_R_IGNORE
);
550 prefixlen
= lifreq
.lifr_addrlen
;
552 isc_netaddr_format(&iter
->current
.address
, sabuf
, sizeof(sabuf
));
553 isc_log_write(isc_lctx
, ISC_LOGCATEGORY_GENERAL
,
554 ISC_LOGMODULE_INTERFACE
,
556 isc_msgcat_get(isc_msgcat
,
557 ISC_MSGSET_IFITERIOCTL
,
559 "prefix length for %s is unknown "
560 "(assume 128)"), sabuf
);
565 * Netmask already zeroed.
567 iter
->current
.netmask
.family
= family
;
568 for (i
= 0; i
< 16; i
++) {
573 bits
= 8 - prefixlen
;
576 iter
->current
.netmask
.type
.in6
.s6_addr
[i
] = (~0 << bits
) & 0xff;
578 return (ISC_R_SUCCESS
);
581 if (family
!= AF_INET
)
582 return (ISC_R_IGNORE
);
583 #ifdef IFF_POINTOPOINT
585 * If the interface is point-to-point, get the destination address.
587 if ((iter
->current
.flags
& INTERFACE_F_POINTTOPOINT
) != 0) {
589 * Ignore the HP/UX warning about "integer overflow during
590 * conversion. It comes from its own macro definition,
591 * and is really hard to shut up.
593 if (ioctl(iter
->socket
, SIOCGIFDSTADDR
, (char *)&ifreq
)
595 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
596 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
597 isc_msgcat_get(isc_msgcat
,
598 ISC_MSGSET_IFITERIOCTL
,
601 "destination address: %s"),
602 ifreq
.ifr_name
, strbuf
);
603 return (ISC_R_IGNORE
);
605 get_addr(family
, &iter
->current
.dstaddress
,
606 (struct sockaddr
*)&ifreq
.ifr_dstaddr
, ifreq
.ifr_name
);
610 if ((iter
->current
.flags
& INTERFACE_F_BROADCAST
) != 0) {
612 * Ignore the HP/UX warning about "integer overflow during
613 * conversion. It comes from its own macro definition,
614 * and is really hard to shut up.
616 if (ioctl(iter
->socket
, SIOCGIFBRDADDR
, (char *)&ifreq
)
618 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
619 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
620 isc_msgcat_get(isc_msgcat
,
621 ISC_MSGSET_IFITERIOCTL
,
624 "broadcast address: %s"),
625 ifreq
.ifr_name
, strbuf
);
626 return (ISC_R_IGNORE
);
628 get_addr(family
, &iter
->current
.broadcast
,
629 (struct sockaddr
*)&ifreq
.ifr_broadaddr
, ifreq
.ifr_name
);
633 * Get the network mask.
635 memset(&ifreq
, 0, sizeof(ifreq
));
636 memcpy(&ifreq
, ifrp
, sizeof(ifreq
));
638 * Ignore the HP/UX warning about "integer overflow during
639 * conversion. It comes from its own macro definition,
640 * and is really hard to shut up.
642 if (ioctl(iter
->socket
, SIOCGIFNETMASK
, (char *)&ifreq
) < 0) {
643 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
644 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
645 isc_msgcat_get(isc_msgcat
,
646 ISC_MSGSET_IFITERIOCTL
,
648 "%s: getting netmask: %s"),
649 ifreq
.ifr_name
, strbuf
);
650 return (ISC_R_IGNORE
);
652 get_addr(family
, &iter
->current
.netmask
,
653 (struct sockaddr
*)&ifreq
.ifr_addr
, ifreq
.ifr_name
);
654 return (ISC_R_SUCCESS
);
657 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
659 internal_current6(isc_interfaceiter_t
*iter
) {
661 struct LIFREQ lifreq
;
663 char strbuf
[ISC_STRERRORSIZE
];
666 REQUIRE(VALID_IFITER(iter
));
667 if (iter
->result6
!= ISC_R_SUCCESS
)
668 return (iter
->result6
);
669 REQUIRE(iter
->pos6
< (unsigned int) iter
->lifc
.lifc_len
);
671 ifrp
= (struct LIFREQ
*)((char *) iter
->lifc
.lifc_req
+ iter
->pos6
);
673 memset(&lifreq
, 0, sizeof(lifreq
));
674 memcpy(&lifreq
, ifrp
, sizeof(lifreq
));
676 family
= lifreq
.lifr_addr
.ss_family
;
677 #ifdef ISC_PLATFORM_HAVEIPV6
678 if (family
!= AF_INET
&& family
!= AF_INET6
)
680 if (family
!= AF_INET
)
682 return (ISC_R_IGNORE
);
684 memset(&iter
->current
, 0, sizeof(iter
->current
));
685 iter
->current
.af
= family
;
687 INSIST(sizeof(lifreq
.lifr_name
) <= sizeof(iter
->current
.name
));
688 memset(iter
->current
.name
, 0, sizeof(iter
->current
.name
));
689 memcpy(iter
->current
.name
, lifreq
.lifr_name
, sizeof(lifreq
.lifr_name
));
691 get_addr(family
, &iter
->current
.address
,
692 (struct sockaddr
*)&lifreq
.lifr_addr
, lifreq
.lifr_name
);
696 * enable_multicast_if() requires scopeid for setsockopt,
697 * so associate address with their corresponding ifindex.
699 if (family
== AF_INET6
)
700 isc_netaddr_setzone(&iter
->current
.address
,
701 (isc_uint32_t
)lifreq
.lifr_index
);
704 * If the interface does not have a address ignore it.
708 if (iter
->current
.address
.type
.in
.s_addr
== htonl(INADDR_ANY
))
709 return (ISC_R_IGNORE
);
712 if (memcmp(&iter
->current
.address
.type
.in6
, &in6addr_any
,
713 sizeof(in6addr_any
)) == 0)
714 return (ISC_R_IGNORE
);
719 * Get interface flags.
722 iter
->current
.flags
= 0;
724 if (family
== AF_INET6
)
730 * Ignore the HP/UX warning about "integer overflow during
731 * conversion. It comes from its own macro definition,
732 * and is really hard to shut up.
734 if (ioctl(fd
, SIOCGLIFFLAGS
, (char *) &lifreq
) < 0) {
735 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
736 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
737 "%s: getting interface flags: %s",
738 lifreq
.lifr_name
, strbuf
);
739 return (ISC_R_IGNORE
);
742 if ((lifreq
.lifr_flags
& IFF_UP
) != 0)
743 iter
->current
.flags
|= INTERFACE_F_UP
;
745 #ifdef IFF_POINTOPOINT
746 if ((lifreq
.lifr_flags
& IFF_POINTOPOINT
) != 0)
747 iter
->current
.flags
|= INTERFACE_F_POINTTOPOINT
;
750 if ((lifreq
.lifr_flags
& IFF_LOOPBACK
) != 0)
751 iter
->current
.flags
|= INTERFACE_F_LOOPBACK
;
753 if ((lifreq
.lifr_flags
& IFF_BROADCAST
) != 0) {
754 iter
->current
.flags
|= INTERFACE_F_BROADCAST
;
758 if ((lifreq
.lifr_flags
& IFF_MULTICAST
) != 0) {
759 iter
->current
.flags
|= INTERFACE_F_MULTICAST
;
763 #ifdef IFF_POINTOPOINT
765 * If the interface is point-to-point, get the destination address.
767 if ((iter
->current
.flags
& INTERFACE_F_POINTTOPOINT
) != 0) {
769 * Ignore the HP/UX warning about "integer overflow during
770 * conversion. It comes from its own macro definition,
771 * and is really hard to shut up.
773 if (ioctl(fd
, SIOCGLIFDSTADDR
, (char *)&lifreq
)
775 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
776 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
777 isc_msgcat_get(isc_msgcat
,
778 ISC_MSGSET_IFITERIOCTL
,
781 "destination address: %s"),
782 lifreq
.lifr_name
, strbuf
);
783 return (ISC_R_IGNORE
);
785 get_addr(family
, &iter
->current
.dstaddress
,
786 (struct sockaddr
*)&lifreq
.lifr_dstaddr
,
791 #ifdef SIOCGLIFBRDADDR
792 if ((iter
->current
.flags
& INTERFACE_F_BROADCAST
) != 0) {
794 * Ignore the HP/UX warning about "integer overflow during
795 * conversion. It comes from its own macro definition,
796 * and is really hard to shut up.
798 if (ioctl(iter
->socket
, SIOCGLIFBRDADDR
, (char *)&lifreq
)
800 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
801 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
802 isc_msgcat_get(isc_msgcat
,
803 ISC_MSGSET_IFITERIOCTL
,
806 "broadcast address: %s"),
807 lifreq
.lifr_name
, strbuf
);
808 return (ISC_R_IGNORE
);
810 get_addr(family
, &iter
->current
.broadcast
,
811 (struct sockaddr
*)&lifreq
.lifr_broadaddr
,
814 #endif /* SIOCGLIFBRDADDR */
817 * Get the network mask. Netmask already zeroed.
819 memset(&lifreq
, 0, sizeof(lifreq
));
820 memcpy(&lifreq
, ifrp
, sizeof(lifreq
));
824 * Special case: if the system provides lifr_addrlen member, the
825 * netmask of an IPv6 address can be derived from the length, since
826 * an IPv6 address always has a contiguous mask.
828 if (family
== AF_INET6
) {
831 iter
->current
.netmask
.family
= family
;
832 for (i
= 0; i
< lifreq
.lifr_addrlen
; i
+= 8) {
833 bits
= lifreq
.lifr_addrlen
- i
;
834 bits
= (bits
< 8) ? (8 - bits
) : 0;
835 iter
->current
.netmask
.type
.in6
.s6_addr
[i
/ 8] =
839 return (ISC_R_SUCCESS
);
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
, SIOCGLIFNETMASK
, (char *)&lifreq
) < 0) {
849 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
850 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
851 isc_msgcat_get(isc_msgcat
,
852 ISC_MSGSET_IFITERIOCTL
,
854 "%s: getting netmask: %s"),
855 lifreq
.lifr_name
, strbuf
);
856 return (ISC_R_IGNORE
);
858 get_addr(family
, &iter
->current
.netmask
,
859 (struct sockaddr
*)&lifreq
.lifr_addr
, lifreq
.lifr_name
);
861 return (ISC_R_SUCCESS
);
866 internal_current(isc_interfaceiter_t
*iter
) {
867 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
868 if (iter
->mode
== 6) {
869 iter
->result6
= internal_current6(iter
);
870 if (iter
->result6
!= ISC_R_NOMORE
)
871 return (iter
->result6
);
874 #ifdef HAVE_TRUCLUSTER
875 if (!iter
->clua_done
)
876 return(internal_current_clusteralias(iter
));
878 return (internal_current4(iter
));
882 * Step the iterator to the next interface. Unlike
883 * isc_interfaceiter_next(), this may leave the iterator
884 * positioned on an interface that will ultimately
885 * be ignored. Return ISC_R_NOMORE if there are no more
886 * interfaces, otherwise ISC_R_SUCCESS.
889 internal_next4(isc_interfaceiter_t
*iter
) {
890 #ifdef ISC_PLATFORM_HAVESALEN
894 if (iter
->pos
< (unsigned int) iter
->ifc
.ifc_len
) {
895 #ifdef ISC_PLATFORM_HAVESALEN
896 ifrp
= (struct ifreq
*)((char *) iter
->ifc
.ifc_req
+ iter
->pos
);
898 if (ifrp
->ifr_addr
.sa_len
> sizeof(struct sockaddr
))
899 iter
->pos
+= sizeof(ifrp
->ifr_name
) +
900 ifrp
->ifr_addr
.sa_len
;
903 iter
->pos
+= sizeof(struct ifreq
);
906 INSIST(iter
->pos
== (unsigned int) iter
->ifc
.ifc_len
);
908 return (linux_if_inet6_next(iter
));
910 return (ISC_R_NOMORE
);
913 return (ISC_R_SUCCESS
);
916 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
918 internal_next6(isc_interfaceiter_t
*iter
) {
919 #ifdef ISC_PLATFORM_HAVESALEN
923 if (iter
->result6
!= ISC_R_SUCCESS
&& iter
->result6
!= ISC_R_IGNORE
)
924 return (iter
->result6
);
926 REQUIRE(iter
->pos6
< (unsigned int) iter
->lifc
.lifc_len
);
928 #ifdef ISC_PLATFORM_HAVESALEN
929 ifrp
= (struct LIFREQ
*)((char *) iter
->lifc
.lifc_req
+ iter
->pos6
);
931 if (ifrp
->lifr_addr
.sa_len
> sizeof(struct sockaddr
))
932 iter
->pos6
+= sizeof(ifrp
->lifr_name
) + ifrp
->lifr_addr
.sa_len
;
935 iter
->pos6
+= sizeof(struct LIFREQ
);
937 if (iter
->pos6
>= (unsigned int) iter
->lifc
.lifc_len
)
938 return (ISC_R_NOMORE
);
940 return (ISC_R_SUCCESS
);
945 internal_next(isc_interfaceiter_t
*iter
) {
946 #ifdef HAVE_TRUCLUSTER
949 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
950 if (iter
->mode
== 6) {
951 iter
->result6
= internal_next6(iter
);
952 if (iter
->result6
!= ISC_R_NOMORE
)
953 return (iter
->result6
);
955 iter
->first6
= ISC_FALSE
;
956 return (ISC_R_SUCCESS
);
960 #ifdef HAVE_TRUCLUSTER
961 if (!iter
->clua_done
) {
962 clua_result
= clua_getaliasaddress(&iter
->clua_sa
,
963 &iter
->clua_context
);
964 if (clua_result
!= CLUA_SUCCESS
)
965 iter
->clua_done
= ISC_TRUE
;
966 return (ISC_R_SUCCESS
);
969 return (internal_next4(iter
));
973 internal_destroy(isc_interfaceiter_t
*iter
) {
974 (void) close(iter
->socket
);
975 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
976 if (iter
->socket6
!= -1)
977 (void) close(iter
->socket6
);
978 if (iter
->buf6
!= NULL
) {
979 isc_mem_put(iter
->mctx
, iter
->buf6
, iter
->bufsize6
);
983 if (iter
->proc
!= NULL
)
989 void internal_first(isc_interfaceiter_t
*iter
) {
990 #ifdef HAVE_TRUCLUSTER
994 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
996 if (iter
->result6
== ISC_R_NOMORE
)
997 iter
->result6
= ISC_R_SUCCESS
;
998 iter
->first6
= ISC_TRUE
;
1000 #ifdef HAVE_TRUCLUSTER
1001 iter
->clua_context
= 0;
1002 clua_result
= clua_getaliasaddress(&iter
->clua_sa
,
1003 &iter
->clua_context
);
1004 iter
->clua_done
= ISC_TF(clua_result
!= CLUA_SUCCESS
);
1007 linux_if_inet6_first(iter
);