Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ntp / libisc / ifiter_ioctl.c
blob02c5f085de73b616ab94885efdc9b1a1bd2c2680
1 /* $NetBSD: ifiter_ioctl.c,v 1.3 2006/06/11 19:34:10 kardel Exp $ */
3 /*
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.
24 * See netintro(4).
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
33 #else
34 #define ISC_HAVE_LIFC_FAMILY 1
35 #define ISC_HAVE_LIFC_FLAGS 1
36 #define LIFCONF lifconf
37 #endif
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
48 #else
49 #define LIFREQ lifreq
50 #endif
51 #endif
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. */
61 isc_mem_t *mctx;
62 int mode;
63 int socket;
64 struct ifconf ifc;
65 void *buf; /* Buffer for sysctl data. */
66 unsigned int bufsize; /* Bytes allocated. */
67 unsigned int pos; /* Current offset in
68 SIOCGIFCONF data */
69 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
70 int socket6;
71 struct LIFCONF lifc;
72 void *buf6; /* Buffer for sysctl data. */
73 unsigned int bufsize6; /* Bytes allocated. */
74 unsigned int pos6; /* Current offset in
75 SIOCGLIFCONF data */
76 isc_result_t result6; /* Last result code. */
77 isc_boolean_t first6;
78 #endif
79 #ifdef HAVE_TRUCLUSTER
80 int clua_context; /* Cluster alias context */
81 isc_boolean_t clua_done;
82 struct sockaddr clua_sa;
83 #endif
84 #ifdef __linux
85 FILE * proc;
86 char entry[ISC_IF_INET6_SZ];
87 isc_result_t valid;
88 isc_boolean_t first;
89 #endif
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>
97 #endif
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
107 #ifdef __linux
108 #ifndef IF_NAMESIZE
109 # ifdef IFNAMSIZ
110 # define IF_NAMESIZE IFNAMSIZ
111 # else
112 # define IF_NAMESIZE 16
113 # endif
114 #endif
115 #endif
117 static isc_result_t
118 getbuf4(isc_interfaceiter_t *iter) {
119 char strbuf[ISC_STRERRORSIZE];
121 iter->bufsize = IFCONF_BUFSIZE_INITIAL;
123 for (;;) {
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)
137 == -1) {
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,
143 ISC_MSG_GETIFCONFIG,
144 "get interface "
145 "configuration: %s"),
146 strbuf);
147 goto unexpected;
150 * EINVAL. Retry with a bigger buffer.
152 } else {
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
160 * retry.
162 if (iter->ifc.ifc_len + 2 * sizeof(struct ifreq)
163 < iter->bufsize)
164 break;
166 if (iter->bufsize >= IFCONF_BUFSIZE_MAX) {
167 UNEXPECTED_ERROR(__FILE__, __LINE__,
168 isc_msgcat_get(isc_msgcat,
169 ISC_MSGSET_IFITERIOCTL,
170 ISC_MSG_BUFFERMAX,
171 "get interface "
172 "configuration: "
173 "maximum buffer "
174 "size exceeded"));
175 goto unexpected;
177 isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
179 iter->bufsize *= 2;
181 return (ISC_R_SUCCESS);
183 unexpected:
184 isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
185 iter->buf = NULL;
186 return (ISC_R_UNEXPECTED);
189 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
190 static isc_result_t
191 getbuf6(isc_interfaceiter_t *iter) {
192 char strbuf[ISC_STRERRORSIZE];
193 isc_result_t result;
195 iter->bufsize6 = IFCONF_BUFSIZE_INITIAL;
197 for (;;) {
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;
205 #endif
206 #ifdef ISC_HAVE_LIFC_FLAGS
207 iter->lifc.lifc_flags = 0;
208 #endif
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)
217 == -1) {
218 #ifdef __hpux
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,
228 ISC_MSG_GETIFCONFIG,
229 "get interface "
230 "configuration: %s"),
231 strbuf);
232 result = ISC_R_FAILURE;
233 goto cleanup;
235 #endif
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,
241 ISC_MSG_GETIFCONFIG,
242 "get interface "
243 "configuration: %s"),
244 strbuf);
245 result = ISC_R_UNEXPECTED;
246 goto cleanup;
249 * EINVAL. Retry with a bigger buffer.
251 } else {
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
259 * retry.
261 if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ)
262 < iter->bufsize6)
263 break;
265 if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) {
266 UNEXPECTED_ERROR(__FILE__, __LINE__,
267 isc_msgcat_get(isc_msgcat,
268 ISC_MSGSET_IFITERIOCTL,
269 ISC_MSG_BUFFERMAX,
270 "get interface "
271 "configuration: "
272 "maximum buffer "
273 "size exceeded"));
274 result = ISC_R_UNEXPECTED;
275 goto cleanup;
277 isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
279 iter->bufsize6 *= 2;
282 if (iter->lifc.lifc_len != 0)
283 iter->mode = 6;
284 return (ISC_R_SUCCESS);
286 cleanup:
287 isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
288 iter->buf6 = NULL;
289 return (result);
291 #endif
293 isc_result_t
294 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
295 isc_interfaceiter_t *iter;
296 isc_result_t result;
297 char strbuf[ISC_STRERRORSIZE];
299 REQUIRE(iterp != NULL);
300 REQUIRE(*iterp == NULL);
302 iter = isc_mem_get(mctx, sizeof(*iter));
303 if (iter == NULL)
304 return (ISC_R_NOMEMORY);
306 iter->mctx = mctx;
307 iter->mode = 4;
308 iter->buf = NULL;
309 iter->pos = (unsigned int) -1;
310 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
311 iter->buf6 = NULL;
312 iter->pos6 = (unsigned int) -1;
313 iter->result6 = ISC_R_NOMORE;
314 iter->socket6 = -1;
315 iter->first6 = ISC_FALSE;
316 #endif
319 * Get the interface configuration, allocating more memory if
320 * necessary.
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,
337 "making interface "
338 "scan socket: %s"),
339 strbuf);
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)
346 goto ioctl6_failure;
348 #endif
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,
355 "making interface "
356 "scan socket: %s"),
357 strbuf);
358 result = ISC_R_UNEXPECTED;
359 goto socket_failure;
361 result = getbuf4(iter);
362 if (result != ISC_R_SUCCESS)
363 goto ioctl_failure;
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;
372 #endif
373 #ifdef __linux
374 iter->proc = fopen("/proc/net/if_inet6", "r");
375 iter->valid = ISC_R_FAILURE;
376 iter->first = ISC_FALSE;
377 #endif
378 iter->result = ISC_R_FAILURE;
380 iter->magic = IFITER_MAGIC;
381 *iterp = iter;
382 return (ISC_R_SUCCESS);
384 ioctl_failure:
385 if (iter->buf != NULL)
386 isc_mem_put(mctx, iter->buf, iter->bufsize);
387 (void) close(iter->socket);
389 socket_failure:
390 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
391 if (iter->buf6 != NULL)
392 isc_mem_put(mctx, iter->buf6, iter->bufsize6);
393 ioctl6_failure:
394 if (iter->socket6 != -1)
395 (void) close(iter->socket6);
396 socket6_failure:
397 #endif
399 isc_mem_put(mctx, iter, sizeof(*iter));
400 return (result);
403 #ifdef HAVE_TRUCLUSTER
404 static void
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));
410 static isc_result_t
411 internal_current_clusteralias(isc_interfaceiter_t *iter) {
412 struct clua_info ci;
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);
424 #endif
426 #ifdef __linux
427 static isc_result_t
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;
432 else
433 iter->valid = ISC_R_NOMORE;
434 return (iter->valid);
437 static void
438 linux_if_inet6_first(isc_interfaceiter_t *iter) {
439 if (iter->proc != NULL) {
440 rewind(iter->proc);
441 (void)linux_if_inet6_next(iter);
442 } else
443 iter->valid = ISC_R_NOMORE;
444 iter->first = ISC_FALSE;
447 static isc_result_t
448 linux_if_inet6_current(isc_interfaceiter_t *iter) {
449 char address[33];
450 char name[IF_NAMESIZE+1];
451 char strbuf[ISC_STRERRORSIZE];
452 struct in6_addr addr6;
453 struct ifreq ifreq;
454 int ifindex, prefix, scope, flags;
455 int res;
456 unsigned int i;
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);
473 if (res != 6) {
474 UNEXPECTED_ERROR(__FILE__, __LINE__,
475 "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
476 res);
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++) {
485 unsigned char byte;
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;
512 #endif
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;
517 #ifdef IFF_MULTICAST
518 if ((ifreq.ifr_flags & IFF_MULTICAST) != 0)
519 iter->current.flags |= INTERFACE_F_MULTICAST;
520 #endif
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++) {
530 if (prefix > 8) {
531 addr6.s6_addr[i] = 0xff;
532 prefix -= 8;
533 } else {
534 addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
535 prefix = 0;
538 isc_netaddr_fromin6(&iter->current.netmask, &addr6);
539 strncpy(iter->current.name, name, sizeof(iter->current.name));
540 return (ISC_R_SUCCESS);
542 #endif
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.
552 static isc_result_t
553 internal_current4(isc_interfaceiter_t *iter) {
554 struct ifreq *ifrp;
555 struct ifreq ifreq;
556 int family;
557 char strbuf[ISC_STRERRORSIZE];
558 #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
559 struct lifreq lifreq;
560 #else
561 char sabuf[256];
562 #endif
563 int i, bits, prefixlen;
564 #ifdef __linux
565 isc_result_t result;
566 #endif
568 REQUIRE(VALID_IFITER(iter));
569 REQUIRE (iter->pos < (unsigned int) iter->ifc.ifc_len);
571 #ifdef __linux
572 result = linux_if_inet6_current(iter);
573 if (result != ISC_R_NOMORE)
574 return (result);
575 iter->first = ISC_TRUE;
576 #endif
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)
586 #else
587 if (family != AF_INET)
588 #endif
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.
604 switch (family) {
605 case AF_INET:
606 if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
607 return (ISC_R_IGNORE);
608 break;
609 #ifdef ISC_PLATFORM_HAVEIPV6
610 case AF_INET6:
611 if (memcmp(&iter->current.address.type.in6, &in6addr_any,
612 sizeof(in6addr_any)) == 0)
613 return (ISC_R_IGNORE);
614 break;
615 #endif
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;
643 #endif
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;
652 #ifdef IFF_MULTICAST
653 if ((ifreq.ifr_flags & IFF_MULTICAST) != 0) {
654 iter->current.flags |= INTERFACE_F_MULTICAST;
656 #endif
658 if (family == AF_INET)
659 goto 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;
675 #else
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,
680 ISC_MSG_GETIFCONFIG,
681 "prefix length for %s is unknown "
682 "(assume 128)"), sabuf);
683 prefixlen = 128;
684 #endif
687 * Netmask already zeroed.
689 iter->current.netmask.family = family;
690 for (i = 0; i < 16; i++) {
691 if (prefixlen > 8) {
692 bits = 0;
693 prefixlen -= 8;
694 } else {
695 bits = 8 - prefixlen;
696 prefixlen = 0;
698 iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff;
700 return (ISC_R_SUCCESS);
702 inet:
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)
716 < 0) {
717 isc__strerror(errno, strbuf, sizeof(strbuf));
718 UNEXPECTED_ERROR(__FILE__, __LINE__,
719 isc_msgcat_get(isc_msgcat,
720 ISC_MSGSET_IFITERIOCTL,
721 ISC_MSG_GETDESTADDR,
722 "%s: getting "
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);
730 #endif
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)
738 < 0) {
739 isc__strerror(errno, strbuf, sizeof(strbuf));
740 UNEXPECTED_ERROR(__FILE__, __LINE__,
741 isc_msgcat_get(isc_msgcat,
742 ISC_MSGSET_IFITERIOCTL,
743 ISC_MSG_GETDESTADDR,
744 "%s: getting "
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,
768 ISC_MSG_GETNETMASK,
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)
779 static isc_result_t
780 internal_current6(isc_interfaceiter_t *iter) {
781 struct LIFREQ *ifrp;
782 struct LIFREQ lifreq;
783 int family;
784 char strbuf[ISC_STRERRORSIZE];
785 int fd;
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)
800 #else
801 if (family != AF_INET)
802 #endif
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.
818 switch (family) {
819 case AF_INET:
820 if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
821 return (ISC_R_IGNORE);
822 break;
823 #ifdef ISC_PLATFORM_HAVEIPV6
824 case AF_INET6:
825 if (memcmp(&iter->current.address.type.in6, &in6addr_any,
826 sizeof(in6addr_any)) == 0)
827 return (ISC_R_IGNORE);
828 break;
829 #endif
833 * Get interface flags.
836 iter->current.flags = 0;
838 if (family == AF_INET6)
839 fd = iter->socket6;
840 else
841 fd = iter->socket;
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;
862 #endif
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;
871 #ifdef IFF_MULTICAST
872 if ((lifreq.lifr_flags & IFF_MULTICAST) != 0) {
873 iter->current.flags |= INTERFACE_F_MULTICAST;
875 #endif
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)
888 < 0) {
889 isc__strerror(errno, strbuf, sizeof(strbuf));
890 UNEXPECTED_ERROR(__FILE__, __LINE__,
891 isc_msgcat_get(isc_msgcat,
892 ISC_MSGSET_IFITERIOCTL,
893 ISC_MSG_GETDESTADDR,
894 "%s: getting "
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,
901 lifreq.lifr_name);
903 #endif
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)
913 < 0) {
914 isc__strerror(errno, strbuf, sizeof(strbuf));
915 UNEXPECTED_ERROR(__FILE__, __LINE__,
916 isc_msgcat_get(isc_msgcat,
917 ISC_MSGSET_IFITERIOCTL,
918 ISC_MSG_GETDESTADDR,
919 "%s: getting "
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,
926 lifreq.lifr_name);
928 #endif /* SIOCGLIFBRDADDR */
931 * Get the network mask. Netmask already zeroed.
933 memset(&lifreq, 0, sizeof(lifreq));
934 memcpy(&lifreq, ifrp, sizeof(lifreq));
936 #ifdef lifr_addrlen
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) {
943 int i, bits;
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] =
950 (~0 << bits) & 0xff;
953 return (ISC_R_SUCCESS);
955 #endif
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,
967 ISC_MSG_GETNETMASK,
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);
977 #endif
979 static isc_result_t
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);
987 #endif
988 #ifdef HAVE_TRUCLUSTER
989 if (!iter->clua_done)
990 return(internal_current_clusteralias(iter));
991 #endif
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.
1002 static isc_result_t
1003 internal_next4(isc_interfaceiter_t *iter) {
1004 struct ifreq *ifrp;
1006 REQUIRE (iter->pos < (unsigned int) iter->ifc.ifc_len);
1008 #ifdef __linux
1009 if (linux_if_inet6_next(iter) == ISC_R_SUCCESS)
1010 return (ISC_R_SUCCESS);
1011 if (!iter->first)
1012 return (ISC_R_SUCCESS);
1013 #endif
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;
1019 else
1020 #endif
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)
1030 static isc_result_t
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;
1044 else
1045 #endif
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);
1053 #endif
1055 static isc_result_t
1056 internal_next(isc_interfaceiter_t *iter) {
1057 #ifdef HAVE_TRUCLUSTER
1058 int clua_result;
1059 #endif
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);
1065 if (iter->first6) {
1066 iter->first6 = ISC_FALSE;
1067 return (ISC_R_SUCCESS);
1070 #endif
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);
1079 #endif
1080 return (internal_next4(iter));
1083 static void
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);
1092 #endif
1093 #ifdef __linux
1094 if (iter->proc != NULL)
1095 fclose(iter->proc);
1096 #endif
1099 static
1100 void internal_first(isc_interfaceiter_t *iter) {
1101 #ifdef HAVE_TRUCLUSTER
1102 int clua_result;
1103 #endif
1104 iter->pos = 0;
1105 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1106 iter->pos6 = 0;
1107 if (iter->result6 == ISC_R_NOMORE)
1108 iter->result6 = ISC_R_SUCCESS;
1109 iter->first6 = ISC_TRUE;
1110 #endif
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);
1116 #endif
1117 #ifdef __linux
1118 linux_if_inet6_first(iter);
1119 #endif