Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / ntp / dist / lib / isc / unix / ifiter_ioctl.c
blob63c1611b76fe3bdef4573780679b49dcf62acef1
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.60.120.2 2009/01/18 23:47:41 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_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
49 #else
50 #define LIFREQ lifreq
51 #endif
52 #endif
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. */
59 isc_mem_t *mctx;
60 int mode;
61 int socket;
62 struct ifconf ifc;
63 void *buf; /* Buffer for sysctl data. */
64 unsigned int bufsize; /* Bytes allocated. */
65 unsigned int pos; /* Current offset in
66 SIOCGIFCONF data */
67 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
68 int socket6;
69 struct LIFCONF lifc;
70 void *buf6; /* Buffer for sysctl data. */
71 unsigned int bufsize6; /* Bytes allocated. */
72 unsigned int pos6; /* Current offset in
73 SIOCGLIFCONF data */
74 isc_result_t result6; /* Last result code. */
75 isc_boolean_t first6;
76 #endif
77 #ifdef HAVE_TRUCLUSTER
78 int clua_context; /* Cluster alias context */
79 isc_boolean_t clua_done;
80 struct sockaddr clua_sa;
81 #endif
82 #ifdef __linux
83 FILE * proc;
84 char entry[ISC_IF_INET6_SZ];
85 isc_result_t valid;
86 #endif
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>
94 #endif
97 /*%
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
104 #ifdef __linux
105 #ifndef IF_NAMESIZE
106 # ifdef IFNAMSIZ
107 # define IF_NAMESIZE IFNAMSIZ
108 # else
109 # define IF_NAMESIZE 16
110 # endif
111 #endif
112 #endif
114 static isc_result_t
115 getbuf4(isc_interfaceiter_t *iter) {
116 char strbuf[ISC_STRERRORSIZE];
118 iter->bufsize = IFCONF_BUFSIZE_INITIAL;
120 for (;;) {
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)
134 == -1) {
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,
140 ISC_MSG_GETIFCONFIG,
141 "get interface "
142 "configuration: %s"),
143 strbuf);
144 goto unexpected;
147 * EINVAL. Retry with a bigger buffer.
149 } else {
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
157 * retry.
159 if (iter->ifc.ifc_len + 2 * sizeof(struct ifreq)
160 < iter->bufsize)
161 break;
163 if (iter->bufsize >= IFCONF_BUFSIZE_MAX) {
164 UNEXPECTED_ERROR(__FILE__, __LINE__,
165 isc_msgcat_get(isc_msgcat,
166 ISC_MSGSET_IFITERIOCTL,
167 ISC_MSG_BUFFERMAX,
168 "get interface "
169 "configuration: "
170 "maximum buffer "
171 "size exceeded"));
172 goto unexpected;
174 isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
176 iter->bufsize *= 2;
178 return (ISC_R_SUCCESS);
180 unexpected:
181 isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
182 iter->buf = NULL;
183 return (ISC_R_UNEXPECTED);
186 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
187 static isc_result_t
188 getbuf6(isc_interfaceiter_t *iter) {
189 char strbuf[ISC_STRERRORSIZE];
190 isc_result_t result;
192 iter->bufsize6 = IFCONF_BUFSIZE_INITIAL;
194 for (;;) {
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;
202 #endif
203 #ifdef ISC_HAVE_LIFC_FLAGS
204 iter->lifc.lifc_flags = 0;
205 #endif
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)
214 == -1) {
215 #ifdef __hpux
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,
224 ISC_LOG_DEBUG(1),
225 isc_msgcat_get(isc_msgcat,
226 ISC_MSGSET_IFITERIOCTL,
227 ISC_MSG_GETIFCONFIG,
228 "get interface "
229 "configuration: %s"),
230 strbuf);
231 result = ISC_R_FAILURE;
232 goto cleanup;
234 #endif
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,
240 ISC_MSG_GETIFCONFIG,
241 "get interface "
242 "configuration: %s"),
243 strbuf);
244 result = ISC_R_UNEXPECTED;
245 goto cleanup;
248 * EINVAL. Retry with a bigger buffer.
250 } else {
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
258 * retry.
260 if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ)
261 < iter->bufsize6)
262 break;
264 if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) {
265 UNEXPECTED_ERROR(__FILE__, __LINE__,
266 isc_msgcat_get(isc_msgcat,
267 ISC_MSGSET_IFITERIOCTL,
268 ISC_MSG_BUFFERMAX,
269 "get interface "
270 "configuration: "
271 "maximum buffer "
272 "size exceeded"));
273 result = ISC_R_UNEXPECTED;
274 goto cleanup;
276 isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
278 iter->bufsize6 *= 2;
281 if (iter->lifc.lifc_len != 0)
282 iter->mode = 6;
283 return (ISC_R_SUCCESS);
285 cleanup:
286 isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
287 iter->buf6 = NULL;
288 return (result);
290 #endif
292 isc_result_t
293 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
294 isc_interfaceiter_t *iter;
295 isc_result_t result;
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));
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 result = iter->result6 = getbuf6(iter);
344 if (result != ISC_R_NOTIMPLEMENTED && result != ISC_R_SUCCESS)
345 goto ioctl6_failure;
347 #endif
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,
354 "making interface "
355 "scan socket: %s"),
356 strbuf);
357 result = ISC_R_UNEXPECTED;
358 goto socket_failure;
360 result = getbuf4(iter);
361 if (result != ISC_R_SUCCESS)
362 goto ioctl_failure;
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;
371 #endif
372 #ifdef __linux
373 iter->proc = fopen("/proc/net/if_inet6", "r");
374 iter->valid = ISC_R_FAILURE;
375 #endif
376 iter->result = ISC_R_FAILURE;
378 iter->magic = IFITER_MAGIC;
379 *iterp = iter;
380 return (ISC_R_SUCCESS);
382 ioctl_failure:
383 if (iter->buf != NULL)
384 isc_mem_put(mctx, iter->buf, iter->bufsize);
385 (void) close(iter->socket);
387 socket_failure:
388 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
389 if (iter->buf6 != NULL)
390 isc_mem_put(mctx, iter->buf6, iter->bufsize6);
391 ioctl6_failure:
392 if (iter->socket6 != -1)
393 (void) close(iter->socket6);
394 socket6_failure:
395 #endif
397 isc_mem_put(mctx, iter, sizeof(*iter));
398 return (result);
401 #ifdef HAVE_TRUCLUSTER
402 static void
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));
408 static isc_result_t
409 internal_current_clusteralias(isc_interfaceiter_t *iter) {
410 struct clua_info ci;
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);
422 #endif
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.
432 static isc_result_t
433 internal_current4(isc_interfaceiter_t *iter) {
434 struct ifreq *ifrp;
435 struct ifreq ifreq;
436 int family;
437 char strbuf[ISC_STRERRORSIZE];
438 #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
439 struct lifreq lifreq;
440 #else
441 char sabuf[256];
442 #endif
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) {
449 #ifdef __linux
450 return (linux_if_inet6_current(iter));
451 #else
452 return (ISC_R_NOMORE);
453 #endif
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)
466 #else
467 if (family != AF_INET)
468 #endif
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.
484 switch (family) {
485 case AF_INET:
486 if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
487 return (ISC_R_IGNORE);
488 break;
489 case AF_INET6:
490 if (memcmp(&iter->current.address.type.in6, &in6addr_any,
491 sizeof(in6addr_any)) == 0)
492 return (ISC_R_IGNORE);
493 break;
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;
521 #endif
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;
529 #ifdef IFF_MULTICAST
530 if ((ifreq.ifr_flags & IFF_MULTICAST) != 0)
531 iter->current.flags |= INTERFACE_F_MULTICAST;
532 #endif
534 if (family == AF_INET)
535 goto 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;
551 #else
552 isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf));
553 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
554 ISC_LOGMODULE_INTERFACE,
555 ISC_LOG_INFO,
556 isc_msgcat_get(isc_msgcat,
557 ISC_MSGSET_IFITERIOCTL,
558 ISC_MSG_GETIFCONFIG,
559 "prefix length for %s is unknown "
560 "(assume 128)"), sabuf);
561 prefixlen = 128;
562 #endif
565 * Netmask already zeroed.
567 iter->current.netmask.family = family;
568 for (i = 0; i < 16; i++) {
569 if (prefixlen > 8) {
570 bits = 0;
571 prefixlen -= 8;
572 } else {
573 bits = 8 - prefixlen;
574 prefixlen = 0;
576 iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff;
578 return (ISC_R_SUCCESS);
580 inet:
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)
594 < 0) {
595 isc__strerror(errno, strbuf, sizeof(strbuf));
596 UNEXPECTED_ERROR(__FILE__, __LINE__,
597 isc_msgcat_get(isc_msgcat,
598 ISC_MSGSET_IFITERIOCTL,
599 ISC_MSG_GETDESTADDR,
600 "%s: getting "
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);
608 #endif
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)
617 < 0) {
618 isc__strerror(errno, strbuf, sizeof(strbuf));
619 UNEXPECTED_ERROR(__FILE__, __LINE__,
620 isc_msgcat_get(isc_msgcat,
621 ISC_MSGSET_IFITERIOCTL,
622 ISC_MSG_GETBCSTADDR,
623 "%s: getting "
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,
647 ISC_MSG_GETNETMASK,
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)
658 static isc_result_t
659 internal_current6(isc_interfaceiter_t *iter) {
660 struct LIFREQ *ifrp;
661 struct LIFREQ lifreq;
662 int family;
663 char strbuf[ISC_STRERRORSIZE];
664 int fd;
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)
679 #else
680 if (family != AF_INET)
681 #endif
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);
695 * NTP local change
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.
706 switch (family) {
707 case AF_INET:
708 if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
709 return (ISC_R_IGNORE);
710 break;
711 case AF_INET6:
712 if (memcmp(&iter->current.address.type.in6, &in6addr_any,
713 sizeof(in6addr_any)) == 0)
714 return (ISC_R_IGNORE);
715 break;
719 * Get interface flags.
722 iter->current.flags = 0;
724 if (family == AF_INET6)
725 fd = iter->socket6;
726 else
727 fd = iter->socket;
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;
748 #endif
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;
757 #ifdef IFF_MULTICAST
758 if ((lifreq.lifr_flags & IFF_MULTICAST) != 0) {
759 iter->current.flags |= INTERFACE_F_MULTICAST;
761 #endif
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)
774 < 0) {
775 isc__strerror(errno, strbuf, sizeof(strbuf));
776 UNEXPECTED_ERROR(__FILE__, __LINE__,
777 isc_msgcat_get(isc_msgcat,
778 ISC_MSGSET_IFITERIOCTL,
779 ISC_MSG_GETDESTADDR,
780 "%s: getting "
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,
787 lifreq.lifr_name);
789 #endif
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)
799 < 0) {
800 isc__strerror(errno, strbuf, sizeof(strbuf));
801 UNEXPECTED_ERROR(__FILE__, __LINE__,
802 isc_msgcat_get(isc_msgcat,
803 ISC_MSGSET_IFITERIOCTL,
804 ISC_MSG_GETBCSTADDR,
805 "%s: getting "
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,
812 lifreq.lifr_name);
814 #endif /* SIOCGLIFBRDADDR */
817 * Get the network mask. Netmask already zeroed.
819 memset(&lifreq, 0, sizeof(lifreq));
820 memcpy(&lifreq, ifrp, sizeof(lifreq));
822 #ifdef lifr_addrlen
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) {
829 int i, bits;
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] =
836 (~0 << bits) & 0xff;
839 return (ISC_R_SUCCESS);
841 #endif
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,
853 ISC_MSG_GETNETMASK,
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);
863 #endif
865 static isc_result_t
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);
873 #endif
874 #ifdef HAVE_TRUCLUSTER
875 if (!iter->clua_done)
876 return(internal_current_clusteralias(iter));
877 #endif
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.
888 static isc_result_t
889 internal_next4(isc_interfaceiter_t *iter) {
890 #ifdef ISC_PLATFORM_HAVESALEN
891 struct ifreq *ifrp;
892 #endif
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;
901 else
902 #endif
903 iter->pos += sizeof(struct ifreq);
905 } else {
906 INSIST(iter->pos == (unsigned int) iter->ifc.ifc_len);
907 #ifdef __linux
908 return (linux_if_inet6_next(iter));
909 #else
910 return (ISC_R_NOMORE);
911 #endif
913 return (ISC_R_SUCCESS);
916 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
917 static isc_result_t
918 internal_next6(isc_interfaceiter_t *iter) {
919 #ifdef ISC_PLATFORM_HAVESALEN
920 struct LIFREQ *ifrp;
921 #endif
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;
933 else
934 #endif
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);
942 #endif
944 static isc_result_t
945 internal_next(isc_interfaceiter_t *iter) {
946 #ifdef HAVE_TRUCLUSTER
947 int clua_result;
948 #endif
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);
954 if (iter->first6) {
955 iter->first6 = ISC_FALSE;
956 return (ISC_R_SUCCESS);
959 #endif
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);
968 #endif
969 return (internal_next4(iter));
972 static void
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);
981 #endif
982 #ifdef __linux
983 if (iter->proc != NULL)
984 fclose(iter->proc);
985 #endif
988 static
989 void internal_first(isc_interfaceiter_t *iter) {
990 #ifdef HAVE_TRUCLUSTER
991 int clua_result;
992 #endif
993 iter->pos = 0;
994 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
995 iter->pos6 = 0;
996 if (iter->result6 == ISC_R_NOMORE)
997 iter->result6 = ISC_R_SUCCESS;
998 iter->first6 = ISC_TRUE;
999 #endif
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);
1005 #endif
1006 #ifdef __linux
1007 linux_if_inet6_first(iter);
1008 #endif