Try to fixup the mess of mdoc(7)/man(7) mixture as created by the merge.
[netbsd-mini2440.git] / external / bsd / bind / dist / lib / isc / unix / ifiter_ioctl.c
blob4d2b5af64d26897a839aa07683961579691bb68e
1 /* $NetBSD$ */
3 /*
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.62 2009/01/18 23:48:14 tbox Exp */
22 /*! \file
23 * \brief
24 * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl.
25 * See netintro(4).
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
34 #else
35 #define ISC_HAVE_LIFC_FAMILY 1
36 #define ISC_HAVE_LIFC_FLAGS 1
37 #define LIFCONF lifconf
38 #endif
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_flags iflr_flags
45 #define ss_family sa_family
46 #define LIFREQ if_laddrreq
47 #else
48 #define LIFREQ lifreq
49 #endif
50 #endif
52 #define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'T')
53 #define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)
55 struct isc_interfaceiter {
56 unsigned int magic; /* Magic number. */
57 isc_mem_t *mctx;
58 int mode;
59 int socket;
60 struct ifconf ifc;
61 void *buf; /* Buffer for sysctl data. */
62 unsigned int bufsize; /* Bytes allocated. */
63 unsigned int pos; /* Current offset in
64 SIOCGIFCONF data */
65 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
66 int socket6;
67 struct LIFCONF lifc;
68 void *buf6; /* Buffer for sysctl data. */
69 unsigned int bufsize6; /* Bytes allocated. */
70 unsigned int pos6; /* Current offset in
71 SIOCGLIFCONF data */
72 isc_result_t result6; /* Last result code. */
73 isc_boolean_t first6;
74 #endif
75 #ifdef HAVE_TRUCLUSTER
76 int clua_context; /* Cluster alias context */
77 isc_boolean_t clua_done;
78 struct sockaddr clua_sa;
79 #endif
80 #ifdef __linux
81 FILE * proc;
82 char entry[ISC_IF_INET6_SZ];
83 isc_result_t valid;
84 #endif
85 isc_interface_t current; /* Current interface data. */
86 isc_result_t result; /* Last result code. */
89 #ifdef HAVE_TRUCLUSTER
90 #include <clua/clua.h>
91 #include <sys/socket.h>
92 #endif
95 /*%
96 * Size of buffer for SIOCGLIFCONF, in bytes. We assume no sane system
97 * will have more than a megabyte of interface configuration data.
99 #define IFCONF_BUFSIZE_INITIAL 4096
100 #define IFCONF_BUFSIZE_MAX 1048576
102 #ifdef __linux
103 #ifndef IF_NAMESIZE
104 # ifdef IFNAMSIZ
105 # define IF_NAMESIZE IFNAMSIZ
106 # else
107 # define IF_NAMESIZE 16
108 # endif
109 #endif
110 #endif
112 static isc_result_t
113 getbuf4(isc_interfaceiter_t *iter) {
114 char strbuf[ISC_STRERRORSIZE];
116 iter->bufsize = IFCONF_BUFSIZE_INITIAL;
118 for (;;) {
119 iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
120 if (iter->buf == NULL)
121 return (ISC_R_NOMEMORY);
123 memset(&iter->ifc.ifc_len, 0, sizeof(iter->ifc.ifc_len));
124 iter->ifc.ifc_len = iter->bufsize;
125 iter->ifc.ifc_buf = iter->buf;
127 * Ignore the HP/UX warning about "integer overflow during
128 * conversion". It comes from its own macro definition,
129 * and is really hard to shut up.
131 if (ioctl(iter->socket, SIOCGIFCONF, (char *)&iter->ifc)
132 == -1) {
133 if (errno != EINVAL) {
134 isc__strerror(errno, strbuf, sizeof(strbuf));
135 UNEXPECTED_ERROR(__FILE__, __LINE__,
136 isc_msgcat_get(isc_msgcat,
137 ISC_MSGSET_IFITERIOCTL,
138 ISC_MSG_GETIFCONFIG,
139 "get interface "
140 "configuration: %s"),
141 strbuf);
142 goto unexpected;
145 * EINVAL. Retry with a bigger buffer.
147 } else {
149 * The ioctl succeeded.
150 * Some OS's just return what will fit rather
151 * than set EINVAL if the buffer is too small
152 * to fit all the interfaces in. If
153 * ifc.lifc_len is too near to the end of the
154 * buffer we will grow it just in case and
155 * retry.
157 if (iter->ifc.ifc_len + 2 * sizeof(struct ifreq)
158 < iter->bufsize)
159 break;
161 if (iter->bufsize >= IFCONF_BUFSIZE_MAX) {
162 UNEXPECTED_ERROR(__FILE__, __LINE__,
163 isc_msgcat_get(isc_msgcat,
164 ISC_MSGSET_IFITERIOCTL,
165 ISC_MSG_BUFFERMAX,
166 "get interface "
167 "configuration: "
168 "maximum buffer "
169 "size exceeded"));
170 goto unexpected;
172 isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
174 iter->bufsize *= 2;
176 return (ISC_R_SUCCESS);
178 unexpected:
179 isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
180 iter->buf = NULL;
181 return (ISC_R_UNEXPECTED);
184 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
185 static isc_result_t
186 getbuf6(isc_interfaceiter_t *iter) {
187 char strbuf[ISC_STRERRORSIZE];
188 isc_result_t result;
190 iter->bufsize6 = IFCONF_BUFSIZE_INITIAL;
192 for (;;) {
193 iter->buf6 = isc_mem_get(iter->mctx, iter->bufsize6);
194 if (iter->buf6 == NULL)
195 return (ISC_R_NOMEMORY);
197 memset(&iter->lifc, 0, sizeof(iter->lifc));
198 #ifdef ISC_HAVE_LIFC_FAMILY
199 iter->lifc.lifc_family = AF_INET6;
200 #endif
201 #ifdef ISC_HAVE_LIFC_FLAGS
202 iter->lifc.lifc_flags = 0;
203 #endif
204 iter->lifc.lifc_len = iter->bufsize6;
205 iter->lifc.lifc_buf = iter->buf6;
207 * Ignore the HP/UX warning about "integer overflow during
208 * conversion". It comes from its own macro definition,
209 * and is really hard to shut up.
211 if (ioctl(iter->socket6, SIOCGLIFCONF, (char *)&iter->lifc)
212 == -1) {
213 #ifdef __hpux
215 * IPv6 interface scanning is not available on all
216 * kernels w/ IPv6 sockets.
218 if (errno == ENOENT) {
219 isc__strerror(errno, strbuf, sizeof(strbuf));
220 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
221 ISC_LOGMODULE_INTERFACE,
222 ISC_LOG_DEBUG(1),
223 isc_msgcat_get(isc_msgcat,
224 ISC_MSGSET_IFITERIOCTL,
225 ISC_MSG_GETIFCONFIG,
226 "get interface "
227 "configuration: %s"),
228 strbuf);
229 result = ISC_R_FAILURE;
230 goto cleanup;
232 #endif
233 if (errno != EINVAL) {
234 isc__strerror(errno, strbuf, sizeof(strbuf));
235 UNEXPECTED_ERROR(__FILE__, __LINE__,
236 isc_msgcat_get(isc_msgcat,
237 ISC_MSGSET_IFITERIOCTL,
238 ISC_MSG_GETIFCONFIG,
239 "get interface "
240 "configuration: %s"),
241 strbuf);
242 result = ISC_R_UNEXPECTED;
243 goto cleanup;
246 * EINVAL. Retry with a bigger buffer.
248 } else {
250 * The ioctl succeeded.
251 * Some OS's just return what will fit rather
252 * than set EINVAL if the buffer is too small
253 * to fit all the interfaces in. If
254 * ifc.ifc_len is too near to the end of the
255 * buffer we will grow it just in case and
256 * retry.
258 if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ)
259 < iter->bufsize6)
260 break;
262 if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) {
263 UNEXPECTED_ERROR(__FILE__, __LINE__,
264 isc_msgcat_get(isc_msgcat,
265 ISC_MSGSET_IFITERIOCTL,
266 ISC_MSG_BUFFERMAX,
267 "get interface "
268 "configuration: "
269 "maximum buffer "
270 "size exceeded"));
271 result = ISC_R_UNEXPECTED;
272 goto cleanup;
274 isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
276 iter->bufsize6 *= 2;
279 if (iter->lifc.lifc_len != 0)
280 iter->mode = 6;
281 return (ISC_R_SUCCESS);
283 cleanup:
284 isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
285 iter->buf6 = NULL;
286 return (result);
288 #endif
290 isc_result_t
291 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
292 isc_interfaceiter_t *iter;
293 isc_result_t result;
294 char strbuf[ISC_STRERRORSIZE];
296 REQUIRE(mctx != NULL);
297 REQUIRE(iterp != NULL);
298 REQUIRE(*iterp == NULL);
300 iter = isc_mem_get(mctx, sizeof(*iter));
301 if (iter == NULL)
302 return (ISC_R_NOMEMORY);
304 iter->mctx = mctx;
305 iter->mode = 4;
306 iter->buf = NULL;
307 iter->pos = (unsigned int) -1;
308 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
309 iter->buf6 = NULL;
310 iter->pos6 = (unsigned int) -1;
311 iter->result6 = ISC_R_NOMORE;
312 iter->socket6 = -1;
313 iter->first6 = ISC_FALSE;
314 #endif
317 * Get the interface configuration, allocating more memory if
318 * necessary.
321 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
322 result = isc_net_probeipv6();
323 if (result == ISC_R_SUCCESS) {
325 * Create an unbound datagram socket to do the SIOCGLIFCONF
326 * ioctl on. HP/UX requires an AF_INET6 socket for
327 * SIOCGLIFCONF to get IPv6 addresses.
329 if ((iter->socket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
330 isc__strerror(errno, strbuf, sizeof(strbuf));
331 UNEXPECTED_ERROR(__FILE__, __LINE__,
332 isc_msgcat_get(isc_msgcat,
333 ISC_MSGSET_IFITERIOCTL,
334 ISC_MSG_MAKESCANSOCKET,
335 "making interface "
336 "scan socket: %s"),
337 strbuf);
338 result = ISC_R_UNEXPECTED;
339 goto socket6_failure;
341 result = iter->result6 = getbuf6(iter);
342 if (result != ISC_R_NOTIMPLEMENTED && result != ISC_R_SUCCESS)
343 goto ioctl6_failure;
345 #endif
346 if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
347 isc__strerror(errno, strbuf, sizeof(strbuf));
348 UNEXPECTED_ERROR(__FILE__, __LINE__,
349 isc_msgcat_get(isc_msgcat,
350 ISC_MSGSET_IFITERIOCTL,
351 ISC_MSG_MAKESCANSOCKET,
352 "making interface "
353 "scan socket: %s"),
354 strbuf);
355 result = ISC_R_UNEXPECTED;
356 goto socket_failure;
358 result = getbuf4(iter);
359 if (result != ISC_R_SUCCESS)
360 goto ioctl_failure;
363 * A newly created iterator has an undefined position
364 * until isc_interfaceiter_first() is called.
366 #ifdef HAVE_TRUCLUSTER
367 iter->clua_context = -1;
368 iter->clua_done = ISC_TRUE;
369 #endif
370 #ifdef __linux
371 iter->proc = fopen("/proc/net/if_inet6", "r");
372 iter->valid = ISC_R_FAILURE;
373 #endif
374 iter->result = ISC_R_FAILURE;
376 iter->magic = IFITER_MAGIC;
377 *iterp = iter;
378 return (ISC_R_SUCCESS);
380 ioctl_failure:
381 if (iter->buf != NULL)
382 isc_mem_put(mctx, iter->buf, iter->bufsize);
383 (void) close(iter->socket);
385 socket_failure:
386 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
387 if (iter->buf6 != NULL)
388 isc_mem_put(mctx, iter->buf6, iter->bufsize6);
389 ioctl6_failure:
390 if (iter->socket6 != -1)
391 (void) close(iter->socket6);
392 socket6_failure:
393 #endif
395 isc_mem_put(mctx, iter, sizeof(*iter));
396 return (result);
399 #ifdef HAVE_TRUCLUSTER
400 static void
401 get_inaddr(isc_netaddr_t *dst, struct in_addr *src) {
402 dst->family = AF_INET;
403 memcpy(&dst->type.in, src, sizeof(struct in_addr));
406 static isc_result_t
407 internal_current_clusteralias(isc_interfaceiter_t *iter) {
408 struct clua_info ci;
409 if (clua_getaliasinfo(&iter->clua_sa, &ci) != CLUA_SUCCESS)
410 return (ISC_R_IGNORE);
411 memset(&iter->current, 0, sizeof(iter->current));
412 iter->current.af = iter->clua_sa.sa_family;
413 memset(iter->current.name, 0, sizeof(iter->current.name));
414 sprintf(iter->current.name, "clua%d", ci.aliasid);
415 iter->current.flags = INTERFACE_F_UP;
416 get_inaddr(&iter->current.address, &ci.addr);
417 get_inaddr(&iter->current.netmask, &ci.netmask);
418 return (ISC_R_SUCCESS);
420 #endif
423 * Get information about the current interface to iter->current.
424 * If successful, return ISC_R_SUCCESS.
425 * If the interface has an unsupported address family, or if
426 * some operation on it fails, return ISC_R_IGNORE to make
427 * the higher-level iterator code ignore it.
430 static isc_result_t
431 internal_current4(isc_interfaceiter_t *iter) {
432 struct ifreq *ifrp;
433 struct ifreq ifreq;
434 int family;
435 char strbuf[ISC_STRERRORSIZE];
436 #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
437 struct lifreq lifreq;
438 #else
439 char sabuf[256];
440 #endif
441 int i, bits, prefixlen;
443 REQUIRE(VALID_IFITER(iter));
445 if (iter->ifc.ifc_len == 0 ||
446 iter->pos == (unsigned int)iter->ifc.ifc_len) {
447 #ifdef __linux
448 return (linux_if_inet6_current(iter));
449 #else
450 return (ISC_R_NOMORE);
451 #endif
454 INSIST( iter->pos < (unsigned int) iter->ifc.ifc_len);
456 ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
458 memset(&ifreq, 0, sizeof(ifreq));
459 memcpy(&ifreq, ifrp, sizeof(ifreq));
461 family = ifreq.ifr_addr.sa_family;
462 #if defined(ISC_PLATFORM_HAVEIPV6)
463 if (family != AF_INET && family != AF_INET6)
464 #else
465 if (family != AF_INET)
466 #endif
467 return (ISC_R_IGNORE);
469 memset(&iter->current, 0, sizeof(iter->current));
470 iter->current.af = family;
472 INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
473 memset(iter->current.name, 0, sizeof(iter->current.name));
474 memcpy(iter->current.name, ifreq.ifr_name, sizeof(ifreq.ifr_name));
476 get_addr(family, &iter->current.address,
477 (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name);
480 * If the interface does not have a address ignore it.
482 switch (family) {
483 case AF_INET:
484 if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
485 return (ISC_R_IGNORE);
486 break;
487 case AF_INET6:
488 if (memcmp(&iter->current.address.type.in6, &in6addr_any,
489 sizeof(in6addr_any)) == 0)
490 return (ISC_R_IGNORE);
491 break;
495 * Get interface flags.
498 iter->current.flags = 0;
501 * Ignore the HP/UX warning about "integer overflow during
502 * conversion. It comes from its own macro definition,
503 * and is really hard to shut up.
505 if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
506 isc__strerror(errno, strbuf, sizeof(strbuf));
507 UNEXPECTED_ERROR(__FILE__, __LINE__,
508 "%s: getting interface flags: %s",
509 ifreq.ifr_name, strbuf);
510 return (ISC_R_IGNORE);
513 if ((ifreq.ifr_flags & IFF_UP) != 0)
514 iter->current.flags |= INTERFACE_F_UP;
516 #ifdef IFF_POINTOPOINT
517 if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
518 iter->current.flags |= INTERFACE_F_POINTTOPOINT;
519 #endif
521 if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
522 iter->current.flags |= INTERFACE_F_LOOPBACK;
524 if (family == AF_INET)
525 goto inet;
527 #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
528 memset(&lifreq, 0, sizeof(lifreq));
529 memcpy(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name));
530 memcpy(&lifreq.lifr_addr, &iter->current.address.type.in6,
531 sizeof(iter->current.address.type.in6));
533 if (ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) {
534 isc__strerror(errno, strbuf, sizeof(strbuf));
535 UNEXPECTED_ERROR(__FILE__, __LINE__,
536 "%s: getting interface address: %s",
537 ifreq.ifr_name, strbuf);
538 return (ISC_R_IGNORE);
540 prefixlen = lifreq.lifr_addrlen;
541 #else
542 isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf));
543 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
544 ISC_LOGMODULE_INTERFACE,
545 ISC_LOG_INFO,
546 isc_msgcat_get(isc_msgcat,
547 ISC_MSGSET_IFITERIOCTL,
548 ISC_MSG_GETIFCONFIG,
549 "prefix length for %s is unknown "
550 "(assume 128)"), sabuf);
551 prefixlen = 128;
552 #endif
555 * Netmask already zeroed.
557 iter->current.netmask.family = family;
558 for (i = 0; i < 16; i++) {
559 if (prefixlen > 8) {
560 bits = 0;
561 prefixlen -= 8;
562 } else {
563 bits = 8 - prefixlen;
564 prefixlen = 0;
566 iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff;
568 return (ISC_R_SUCCESS);
570 inet:
571 if (family != AF_INET)
572 return (ISC_R_IGNORE);
573 #ifdef IFF_POINTOPOINT
575 * If the interface is point-to-point, get the destination address.
577 if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
579 * Ignore the HP/UX warning about "integer overflow during
580 * conversion. It comes from its own macro definition,
581 * and is really hard to shut up.
583 if (ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq)
584 < 0) {
585 isc__strerror(errno, strbuf, sizeof(strbuf));
586 UNEXPECTED_ERROR(__FILE__, __LINE__,
587 isc_msgcat_get(isc_msgcat,
588 ISC_MSGSET_IFITERIOCTL,
589 ISC_MSG_GETDESTADDR,
590 "%s: getting "
591 "destination address: %s"),
592 ifreq.ifr_name, strbuf);
593 return (ISC_R_IGNORE);
595 get_addr(family, &iter->current.dstaddress,
596 (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name);
598 #endif
601 * Get the network mask.
603 memset(&ifreq, 0, sizeof(ifreq));
604 memcpy(&ifreq, ifrp, sizeof(ifreq));
606 * Ignore the HP/UX warning about "integer overflow during
607 * conversion. It comes from its own macro definition,
608 * and is really hard to shut up.
610 if (ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
611 isc__strerror(errno, strbuf, sizeof(strbuf));
612 UNEXPECTED_ERROR(__FILE__, __LINE__,
613 isc_msgcat_get(isc_msgcat,
614 ISC_MSGSET_IFITERIOCTL,
615 ISC_MSG_GETNETMASK,
616 "%s: getting netmask: %s"),
617 ifreq.ifr_name, strbuf);
618 return (ISC_R_IGNORE);
620 get_addr(family, &iter->current.netmask,
621 (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name);
622 return (ISC_R_SUCCESS);
625 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
626 static isc_result_t
627 internal_current6(isc_interfaceiter_t *iter) {
628 struct LIFREQ *ifrp;
629 struct LIFREQ lifreq;
630 int family;
631 char strbuf[ISC_STRERRORSIZE];
632 int fd;
634 REQUIRE(VALID_IFITER(iter));
635 if (iter->result6 != ISC_R_SUCCESS)
636 return (iter->result6);
637 REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
639 ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
641 memset(&lifreq, 0, sizeof(lifreq));
642 memcpy(&lifreq, ifrp, sizeof(lifreq));
644 family = lifreq.lifr_addr.ss_family;
645 #ifdef ISC_PLATFORM_HAVEIPV6
646 if (family != AF_INET && family != AF_INET6)
647 #else
648 if (family != AF_INET)
649 #endif
650 return (ISC_R_IGNORE);
652 memset(&iter->current, 0, sizeof(iter->current));
653 iter->current.af = family;
655 INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name));
656 memset(iter->current.name, 0, sizeof(iter->current.name));
657 memcpy(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name));
659 get_addr(family, &iter->current.address,
660 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
663 * If the interface does not have a address ignore it.
665 switch (family) {
666 case AF_INET:
667 if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
668 return (ISC_R_IGNORE);
669 break;
670 case AF_INET6:
671 if (memcmp(&iter->current.address.type.in6, &in6addr_any,
672 sizeof(in6addr_any)) == 0)
673 return (ISC_R_IGNORE);
674 break;
678 * Get interface flags.
681 iter->current.flags = 0;
683 if (family == AF_INET6)
684 fd = iter->socket6;
685 else
686 fd = iter->socket;
689 * Ignore the HP/UX warning about "integer overflow during
690 * conversion. It comes from its own macro definition,
691 * and is really hard to shut up.
693 if (ioctl(fd, SIOCGLIFFLAGS, (char *) &lifreq) < 0) {
694 isc__strerror(errno, strbuf, sizeof(strbuf));
695 UNEXPECTED_ERROR(__FILE__, __LINE__,
696 "%s: getting interface flags: %s",
697 lifreq.lifr_name, strbuf);
698 return (ISC_R_IGNORE);
701 if ((lifreq.lifr_flags & IFF_UP) != 0)
702 iter->current.flags |= INTERFACE_F_UP;
704 #ifdef IFF_POINTOPOINT
705 if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0)
706 iter->current.flags |= INTERFACE_F_POINTTOPOINT;
707 #endif
709 if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0)
710 iter->current.flags |= INTERFACE_F_LOOPBACK;
712 #ifdef IFF_POINTOPOINT
714 * If the interface is point-to-point, get the destination address.
716 if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
718 * Ignore the HP/UX warning about "integer overflow during
719 * conversion. It comes from its own macro definition,
720 * and is really hard to shut up.
722 if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq)
723 < 0) {
724 isc__strerror(errno, strbuf, sizeof(strbuf));
725 UNEXPECTED_ERROR(__FILE__, __LINE__,
726 isc_msgcat_get(isc_msgcat,
727 ISC_MSGSET_IFITERIOCTL,
728 ISC_MSG_GETDESTADDR,
729 "%s: getting "
730 "destination address: %s"),
731 lifreq.lifr_name, strbuf);
732 return (ISC_R_IGNORE);
734 get_addr(family, &iter->current.dstaddress,
735 (struct sockaddr *)&lifreq.lifr_dstaddr,
736 lifreq.lifr_name);
738 #endif
741 * Get the network mask. Netmask already zeroed.
743 memset(&lifreq, 0, sizeof(lifreq));
744 memcpy(&lifreq, ifrp, sizeof(lifreq));
746 #ifdef lifr_addrlen
748 * Special case: if the system provides lifr_addrlen member, the
749 * netmask of an IPv6 address can be derived from the length, since
750 * an IPv6 address always has a contiguous mask.
752 if (family == AF_INET6) {
753 int i, bits;
755 iter->current.netmask.family = family;
756 for (i = 0; i < lifreq.lifr_addrlen; i += 8) {
757 bits = lifreq.lifr_addrlen - i;
758 bits = (bits < 8) ? (8 - bits) : 0;
759 iter->current.netmask.type.in6.s6_addr[i / 8] =
760 (~0 << bits) & 0xff;
763 return (ISC_R_SUCCESS);
765 #endif
768 * Ignore the HP/UX warning about "integer overflow during
769 * conversion. It comes from its own macro definition,
770 * and is really hard to shut up.
772 if (ioctl(fd, SIOCGLIFNETMASK, (char *)&lifreq) < 0) {
773 isc__strerror(errno, strbuf, sizeof(strbuf));
774 UNEXPECTED_ERROR(__FILE__, __LINE__,
775 isc_msgcat_get(isc_msgcat,
776 ISC_MSGSET_IFITERIOCTL,
777 ISC_MSG_GETNETMASK,
778 "%s: getting netmask: %s"),
779 lifreq.lifr_name, strbuf);
780 return (ISC_R_IGNORE);
782 get_addr(family, &iter->current.netmask,
783 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
785 return (ISC_R_SUCCESS);
787 #endif
789 static isc_result_t
790 internal_current(isc_interfaceiter_t *iter) {
791 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
792 if (iter->mode == 6) {
793 iter->result6 = internal_current6(iter);
794 if (iter->result6 != ISC_R_NOMORE)
795 return (iter->result6);
797 #endif
798 #ifdef HAVE_TRUCLUSTER
799 if (!iter->clua_done)
800 return(internal_current_clusteralias(iter));
801 #endif
802 return (internal_current4(iter));
806 * Step the iterator to the next interface. Unlike
807 * isc_interfaceiter_next(), this may leave the iterator
808 * positioned on an interface that will ultimately
809 * be ignored. Return ISC_R_NOMORE if there are no more
810 * interfaces, otherwise ISC_R_SUCCESS.
812 static isc_result_t
813 internal_next4(isc_interfaceiter_t *iter) {
814 #ifdef ISC_PLATFORM_HAVESALEN
815 struct ifreq *ifrp;
816 #endif
818 if (iter->pos < (unsigned int) iter->ifc.ifc_len) {
819 #ifdef ISC_PLATFORM_HAVESALEN
820 ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
822 if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
823 iter->pos += sizeof(ifrp->ifr_name) +
824 ifrp->ifr_addr.sa_len;
825 else
826 #endif
827 iter->pos += sizeof(struct ifreq);
829 } else {
830 INSIST(iter->pos == (unsigned int) iter->ifc.ifc_len);
831 #ifdef __linux
832 return (linux_if_inet6_next(iter));
833 #else
834 return (ISC_R_NOMORE);
835 #endif
837 return (ISC_R_SUCCESS);
840 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
841 static isc_result_t
842 internal_next6(isc_interfaceiter_t *iter) {
843 #ifdef ISC_PLATFORM_HAVESALEN
844 struct LIFREQ *ifrp;
845 #endif
847 if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE)
848 return (iter->result6);
850 REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
852 #ifdef ISC_PLATFORM_HAVESALEN
853 ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
855 if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr))
856 iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len;
857 else
858 #endif
859 iter->pos6 += sizeof(struct LIFREQ);
861 if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len)
862 return (ISC_R_NOMORE);
864 return (ISC_R_SUCCESS);
866 #endif
868 static isc_result_t
869 internal_next(isc_interfaceiter_t *iter) {
870 #ifdef HAVE_TRUCLUSTER
871 int clua_result;
872 #endif
873 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
874 if (iter->mode == 6) {
875 iter->result6 = internal_next6(iter);
876 if (iter->result6 != ISC_R_NOMORE)
877 return (iter->result6);
878 if (iter->first6) {
879 iter->first6 = ISC_FALSE;
880 return (ISC_R_SUCCESS);
883 #endif
884 #ifdef HAVE_TRUCLUSTER
885 if (!iter->clua_done) {
886 clua_result = clua_getaliasaddress(&iter->clua_sa,
887 &iter->clua_context);
888 if (clua_result != CLUA_SUCCESS)
889 iter->clua_done = ISC_TRUE;
890 return (ISC_R_SUCCESS);
892 #endif
893 return (internal_next4(iter));
896 static void
897 internal_destroy(isc_interfaceiter_t *iter) {
898 (void) close(iter->socket);
899 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
900 if (iter->socket6 != -1)
901 (void) close(iter->socket6);
902 if (iter->buf6 != NULL) {
903 isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
905 #endif
906 #ifdef __linux
907 if (iter->proc != NULL)
908 fclose(iter->proc);
909 #endif
912 static
913 void internal_first(isc_interfaceiter_t *iter) {
914 #ifdef HAVE_TRUCLUSTER
915 int clua_result;
916 #endif
917 iter->pos = 0;
918 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
919 iter->pos6 = 0;
920 if (iter->result6 == ISC_R_NOMORE)
921 iter->result6 = ISC_R_SUCCESS;
922 iter->first6 = ISC_TRUE;
923 #endif
924 #ifdef HAVE_TRUCLUSTER
925 iter->clua_context = 0;
926 clua_result = clua_getaliasaddress(&iter->clua_sa,
927 &iter->clua_context);
928 iter->clua_done = ISC_TF(clua_result != CLUA_SUCCESS);
929 #endif
930 #ifdef __linux
931 linux_if_inet6_first(iter);
932 #endif