1 /*
2 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 /* $Id: ifiter_ioctl.c,v 1.62 2009/01/18 23:48:14 tbox Exp $ */
19
20 /*! \file
21 * \brief
22 * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl.
23 * See netintro(4).
24 */
25
26 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
27 #ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
28 #define lifc_len iflc_len
29 #define lifc_buf iflc_buf
30 #define lifc_req iflc_req
31 #define LIFCONF if_laddrconf
32 #else
33 #define ISC_HAVE_LIFC_FAMILY 1
34 #define ISC_HAVE_LIFC_FLAGS 1
35 #define LIFCONF lifconf
36 #endif
37
38 #ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
39 #define lifr_addr iflr_addr
40 #define lifr_name iflr_name
41 #define lifr_dstaddr iflr_dstaddr
42 #define lifr_broadaddr iflr_broadaddr
43 #define lifr_flags iflr_flags
44 #define lifr_index iflr_index
45 #define ss_family sa_family
46 #define LIFREQ if_laddrreq
47 #else
48 #define LIFREQ lifreq
49 #endif
50 #endif
51
52 #define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'T')
53 #define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)
54
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. */
87 };
88
89 #ifdef HAVE_TRUCLUSTER
90 #include <clua/clua.h>
91 #include <sys/socket.h>
92 #endif
93
94
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.
98 */
99 #define IFCONF_BUFSIZE_INITIAL 4096
100 #define IFCONF_BUFSIZE_MAX 1048576
101
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
111
112 /* Silence a warning when this file is #included */
113 int
114 isc_ioctl(int fildes, int req, char *arg);
115
116 int
isc_ioctl(int fildes,int req,char * arg)117 isc_ioctl(int fildes, int req, char *arg) {
118 int trys;
119 int ret;
120
121 for (trys = 0; trys < 3; trys++) {
122 if ((ret = ioctl(fildes, req, arg)) < 0) {
123 if (errno == EINTR)
124 continue;
125 }
126 break;
127 }
128 return (ret);
129 }
130
131 static isc_result_t
getbuf4(isc_interfaceiter_t * iter)132 getbuf4(isc_interfaceiter_t *iter) {
133 char strbuf[ISC_STRERRORSIZE];
134
135 iter->bufsize = IFCONF_BUFSIZE_INITIAL;
136
137 for (;;) {
138 iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
139 if (iter->buf == NULL)
140 return (ISC_R_NOMEMORY);
141
142 memset(&iter->ifc.ifc_len, 0, sizeof(iter->ifc.ifc_len));
143 iter->ifc.ifc_len = iter->bufsize;
144 iter->ifc.ifc_buf = iter->buf;
145 /*
146 * Ignore the HP/UX warning about "integer overflow during
147 * conversion". It comes from its own macro definition,
148 * and is really hard to shut up.
149 */
150 if (isc_ioctl(iter->socket, SIOCGIFCONF, (char *)&iter->ifc)
151 == -1) {
152 if (errno != EINVAL) {
153 isc__strerror(errno, strbuf, sizeof(strbuf));
154 UNEXPECTED_ERROR(__FILE__, __LINE__,
155 isc_msgcat_get(isc_msgcat,
156 ISC_MSGSET_IFITERIOCTL,
157 ISC_MSG_GETIFCONFIG,
158 "get interface "
159 "configuration: %s"),
160 strbuf);
161 goto unexpected;
162 }
163 /*
164 * EINVAL. Retry with a bigger buffer.
165 */
166 } else {
167 /*
168 * The ioctl succeeded.
169 * Some OS's just return what will fit rather
170 * than set EINVAL if the buffer is too small
171 * to fit all the interfaces in. If
172 * ifc.lifc_len is too near to the end of the
173 * buffer we will grow it just in case and
174 * retry.
175 */
176 if (iter->ifc.ifc_len + 2 * sizeof(struct ifreq)
177 < iter->bufsize)
178 break;
179 }
180 if (iter->bufsize >= IFCONF_BUFSIZE_MAX) {
181 UNEXPECTED_ERROR(__FILE__, __LINE__,
182 isc_msgcat_get(isc_msgcat,
183 ISC_MSGSET_IFITERIOCTL,
184 ISC_MSG_BUFFERMAX,
185 "get interface "
186 "configuration: "
187 "maximum buffer "
188 "size exceeded"));
189 goto unexpected;
190 }
191 isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
192
193 iter->bufsize *= 2;
194 }
195 return (ISC_R_SUCCESS);
196
197 unexpected:
198 isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
199 iter->buf = NULL;
200 return (ISC_R_UNEXPECTED);
201 }
202
203 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
204 static isc_result_t
getbuf6(isc_interfaceiter_t * iter)205 getbuf6(isc_interfaceiter_t *iter) {
206 char strbuf[ISC_STRERRORSIZE];
207 isc_result_t result;
208
209 iter->bufsize6 = IFCONF_BUFSIZE_INITIAL;
210
211 for (;;) {
212 iter->buf6 = isc_mem_get(iter->mctx, iter->bufsize6);
213 if (iter->buf6 == NULL)
214 return (ISC_R_NOMEMORY);
215
216 memset(&iter->lifc, 0, sizeof(iter->lifc));
217 #ifdef ISC_HAVE_LIFC_FAMILY
218 iter->lifc.lifc_family = AF_INET6;
219 #endif
220 #ifdef ISC_HAVE_LIFC_FLAGS
221 iter->lifc.lifc_flags = 0;
222 #endif
223 iter->lifc.lifc_len = iter->bufsize6;
224 iter->lifc.lifc_buf = iter->buf6;
225 /*
226 * Ignore the HP/UX warning about "integer overflow during
227 * conversion". It comes from its own macro definition,
228 * and is really hard to shut up.
229 */
230 if (isc_ioctl(iter->socket6, SIOCGLIFCONF, (char *)&iter->lifc)
231 == -1) {
232 #ifdef __hpux
233 /*
234 * IPv6 interface scanning is not available on all
235 * kernels w/ IPv6 sockets.
236 */
237 if (errno == ENOENT) {
238 isc__strerror(errno, strbuf, sizeof(strbuf));
239 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
240 ISC_LOGMODULE_INTERFACE,
241 ISC_LOG_DEBUG(1),
242 isc_msgcat_get(isc_msgcat,
243 ISC_MSGSET_IFITERIOCTL,
244 ISC_MSG_GETIFCONFIG,
245 "get interface "
246 "configuration: %s"),
247 strbuf);
248 result = ISC_R_FAILURE;
249 goto cleanup;
250 }
251 #endif
252 if (errno != EINVAL) {
253 isc__strerror(errno, strbuf, sizeof(strbuf));
254 UNEXPECTED_ERROR(__FILE__, __LINE__,
255 isc_msgcat_get(isc_msgcat,
256 ISC_MSGSET_IFITERIOCTL,
257 ISC_MSG_GETIFCONFIG,
258 "get interface "
259 "configuration: %s"),
260 strbuf);
261 result = ISC_R_UNEXPECTED;
262 goto cleanup;
263 }
264 /*
265 * EINVAL. Retry with a bigger buffer.
266 */
267 } else {
268 /*
269 * The ioctl succeeded.
270 * Some OS's just return what will fit rather
271 * than set EINVAL if the buffer is too small
272 * to fit all the interfaces in. If
273 * ifc.ifc_len is too near to the end of the
274 * buffer we will grow it just in case and
275 * retry.
276 */
277 if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ)
278 < iter->bufsize6)
279 break;
280 }
281 if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) {
282 UNEXPECTED_ERROR(__FILE__, __LINE__,
283 isc_msgcat_get(isc_msgcat,
284 ISC_MSGSET_IFITERIOCTL,
285 ISC_MSG_BUFFERMAX,
286 "get interface "
287 "configuration: "
288 "maximum buffer "
289 "size exceeded"));
290 result = ISC_R_UNEXPECTED;
291 goto cleanup;
292 }
293 isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
294
295 iter->bufsize6 *= 2;
296 }
297
298 if (iter->lifc.lifc_len != 0)
299 iter->mode = 6;
300 return (ISC_R_SUCCESS);
301
302 cleanup:
303 isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
304 iter->buf6 = NULL;
305 return (result);
306 }
307 #endif
308
309 isc_result_t
isc_interfaceiter_create(isc_mem_t * mctx,isc_interfaceiter_t ** iterp)310 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
311 isc_interfaceiter_t *iter;
312 isc_result_t result;
313 char strbuf[ISC_STRERRORSIZE];
314
315 REQUIRE(mctx != NULL);
316 REQUIRE(iterp != NULL);
317 REQUIRE(*iterp == NULL);
318
319 iter = isc_mem_get(mctx, sizeof(*iter));
320 if (iter == NULL)
321 return (ISC_R_NOMEMORY);
322
323 iter->mctx = mctx;
324 iter->mode = 4;
325 iter->buf = NULL;
326 iter->pos = (unsigned int) -1;
327 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
328 iter->buf6 = NULL;
329 iter->pos6 = (unsigned int) -1;
330 iter->result6 = ISC_R_NOMORE;
331 iter->socket6 = -1;
332 iter->first6 = ISC_FALSE;
333 #endif
334
335 /*
336 * Get the interface configuration, allocating more memory if
337 * necessary.
338 */
339
340 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
341 result = isc_net_probeipv6();
342 if (result == ISC_R_SUCCESS) {
343 /*
344 * Create an unbound datagram socket to do the SIOCGLIFCONF
345 * ioctl on. HP/UX requires an AF_INET6 socket for
346 * SIOCGLIFCONF to get IPv6 addresses.
347 */
348 if ((iter->socket6 = socket(AF_INET6, 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 socket6_failure;
359 }
360 result = iter->result6 = getbuf6(iter);
361 if (result != ISC_R_NOTIMPLEMENTED && result != ISC_R_SUCCESS)
362 goto ioctl6_failure;
363 }
364 #endif
365 if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
366 isc__strerror(errno, strbuf, sizeof(strbuf));
367 UNEXPECTED_ERROR(__FILE__, __LINE__,
368 isc_msgcat_get(isc_msgcat,
369 ISC_MSGSET_IFITERIOCTL,
370 ISC_MSG_MAKESCANSOCKET,
371 "making interface "
372 "scan socket: %s"),
373 strbuf);
374 result = ISC_R_UNEXPECTED;
375 goto socket_failure;
376 }
377 result = getbuf4(iter);
378 if (result != ISC_R_SUCCESS)
379 goto ioctl_failure;
380
381 /*
382 * A newly created iterator has an undefined position
383 * until isc_interfaceiter_first() is called.
384 */
385 #ifdef HAVE_TRUCLUSTER
386 iter->clua_context = -1;
387 iter->clua_done = ISC_TRUE;
388 #endif
389 #ifdef __linux
390 iter->proc = fopen("/proc/net/if_inet6", "r");
391 iter->valid = ISC_R_FAILURE;
392 #endif
393 iter->result = ISC_R_FAILURE;
394
395 iter->magic = IFITER_MAGIC;
396 *iterp = iter;
397 return (ISC_R_SUCCESS);
398
399 ioctl_failure:
400 if (iter->buf != NULL)
401 isc_mem_put(mctx, iter->buf, iter->bufsize);
402 (void) close(iter->socket);
403
404 socket_failure:
405 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
406 if (iter->buf6 != NULL)
407 isc_mem_put(mctx, iter->buf6, iter->bufsize6);
408 ioctl6_failure:
409 if (iter->socket6 != -1)
410 (void) close(iter->socket6);
411 socket6_failure:
412 #endif
413
414 isc_mem_put(mctx, iter, sizeof(*iter));
415 return (result);
416 }
417
418 #ifdef HAVE_TRUCLUSTER
419 static void
get_inaddr(isc_netaddr_t * dst,struct in_addr * src)420 get_inaddr(isc_netaddr_t *dst, struct in_addr *src) {
421 dst->family = AF_INET;
422 memcpy(&dst->type.in, src, sizeof(struct in_addr));
423 }
424
425 static isc_result_t
internal_current_clusteralias(isc_interfaceiter_t * iter)426 internal_current_clusteralias(isc_interfaceiter_t *iter) {
427 struct clua_info ci;
428 if (clua_getaliasinfo(&iter->clua_sa, &ci) != CLUA_SUCCESS)
429 return (ISC_R_IGNORE);
430 memset(&iter->current, 0, sizeof(iter->current));
431 iter->current.af = iter->clua_sa.sa_family;
432 memset(iter->current.name, 0, sizeof(iter->current.name));
433 sprintf(iter->current.name, "clua%d", ci.aliasid);
434 iter->current.flags = INTERFACE_F_UP;
435 get_inaddr(&iter->current.address, &ci.addr);
436 get_inaddr(&iter->current.netmask, &ci.netmask);
437 return (ISC_R_SUCCESS);
438 }
439 #endif
440
441 /*
442 * Get information about the current interface to iter->current.
443 * If successful, return ISC_R_SUCCESS.
444 * If the interface has an unsupported address family, or if
445 * some operation on it fails, return ISC_R_IGNORE to make
446 * the higher-level iterator code ignore it.
447 */
448
449 static isc_result_t
internal_current4(isc_interfaceiter_t * iter)450 internal_current4(isc_interfaceiter_t *iter) {
451 struct ifreq *ifrp;
452 struct ifreq ifreq;
453 int family;
454 char strbuf[ISC_STRERRORSIZE];
455 #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
456 struct lifreq lifreq;
457 #else
458 char sabuf[256];
459 #endif
460 int i, bits, prefixlen;
461
462 REQUIRE(VALID_IFITER(iter));
463
464 if (iter->ifc.ifc_len == 0 ||
465 iter->pos == (unsigned int)iter->ifc.ifc_len) {
466 #ifdef __linux
467 return (linux_if_inet6_current(iter));
468 #else
469 return (ISC_R_NOMORE);
470 #endif
471 }
472
473 INSIST( iter->pos < (unsigned int) iter->ifc.ifc_len);
474
475 ifrp = (void *)((char *) iter->ifc.ifc_req + iter->pos);
476
477 memset(&ifreq, 0, sizeof(ifreq));
478 memcpy(&ifreq, ifrp, sizeof(ifreq));
479
480 family = ifreq.ifr_addr.sa_family;
481 #if defined(ISC_PLATFORM_HAVEIPV6)
482 if (family != AF_INET && family != AF_INET6)
483 #else
484 if (family != AF_INET)
485 #endif
486 return (ISC_R_IGNORE);
487
488 memset(&iter->current, 0, sizeof(iter->current));
489 iter->current.af = family;
490
491 INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
492 memset(iter->current.name, 0, sizeof(iter->current.name));
493 memcpy(iter->current.name, ifreq.ifr_name, sizeof(ifreq.ifr_name));
494
495 get_addr(family, &iter->current.address,
496 (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name);
497
498 /*
499 * If the interface does not have a address ignore it.
500 */
501 switch (family) {
502 case AF_INET:
503 if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
504 return (ISC_R_IGNORE);
505 break;
506 case AF_INET6:
507 if (memcmp(&iter->current.address.type.in6, &in6addr_any,
508 sizeof(in6addr_any)) == 0)
509 return (ISC_R_IGNORE);
510 break;
511 }
512
513 /*
514 * Get interface flags.
515 */
516
517 iter->current.flags = 0;
518
519 /*
520 * Ignore the HP/UX warning about "integer overflow during
521 * conversion. It comes from its own macro definition,
522 * and is really hard to shut up.
523 */
524 if (isc_ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
525 isc__strerror(errno, strbuf, sizeof(strbuf));
526 UNEXPECTED_ERROR(__FILE__, __LINE__,
527 "%s: getting interface flags: %s",
528 ifreq.ifr_name, strbuf);
529 return (ISC_R_IGNORE);
530 }
531
532 if ((ifreq.ifr_flags & IFF_UP) != 0)
533 iter->current.flags |= INTERFACE_F_UP;
534
535 #ifdef IFF_POINTOPOINT
536 if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
537 iter->current.flags |= INTERFACE_F_POINTTOPOINT;
538 #endif
539
540 if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
541 iter->current.flags |= INTERFACE_F_LOOPBACK;
542
543 if ((ifreq.ifr_flags & IFF_BROADCAST) != 0)
544 iter->current.flags |= INTERFACE_F_BROADCAST;
545
546 #ifdef IFF_MULTICAST
547 if ((ifreq.ifr_flags & IFF_MULTICAST) != 0)
548 iter->current.flags |= INTERFACE_F_MULTICAST;
549 #endif
550
551 if (family == AF_INET)
552 goto inet;
553
554 #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
555 memset(&lifreq, 0, sizeof(lifreq));
556 memcpy(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name));
557 memcpy(&lifreq.lifr_addr, &iter->current.address.type.in6,
558 sizeof(iter->current.address.type.in6));
559
560 if (isc_ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) {
561 isc__strerror(errno, strbuf, sizeof(strbuf));
562 UNEXPECTED_ERROR(__FILE__, __LINE__,
563 "%s: getting interface address: %s",
564 ifreq.ifr_name, strbuf);
565 return (ISC_R_IGNORE);
566 }
567 prefixlen = lifreq.lifr_addrlen;
568 #else
569 isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf));
570 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
571 ISC_LOGMODULE_INTERFACE,
572 ISC_LOG_INFO,
573 isc_msgcat_get(isc_msgcat,
574 ISC_MSGSET_IFITERIOCTL,
575 ISC_MSG_GETIFCONFIG,
576 "prefix length for %s is unknown "
577 "(assume 128)"), sabuf);
578 prefixlen = 128;
579 #endif
580
581 /*
582 * Netmask already zeroed.
583 */
584 iter->current.netmask.family = family;
585 for (i = 0; i < 16; i++) {
586 if (prefixlen > 8) {
587 bits = 0;
588 prefixlen -= 8;
589 } else {
590 bits = 8 - prefixlen;
591 prefixlen = 0;
592 }
593 iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff;
594 }
595 #ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
596 iter->current.ifindex = if_nametoindex(iter->current.name);
597 #endif
598 return (ISC_R_SUCCESS);
599
600 inet:
601 if (family != AF_INET)
602 return (ISC_R_IGNORE);
603 #ifdef IFF_POINTOPOINT
604 /*
605 * If the interface is point-to-point, get the destination address.
606 */
607 if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
608 /*
609 * Ignore the HP/UX warning about "integer overflow during
610 * conversion. It comes from its own macro definition,
611 * and is really hard to shut up.
612 */
613 if (isc_ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq)
614 < 0) {
615 isc__strerror(errno, strbuf, sizeof(strbuf));
616 UNEXPECTED_ERROR(__FILE__, __LINE__,
617 isc_msgcat_get(isc_msgcat,
618 ISC_MSGSET_IFITERIOCTL,
619 ISC_MSG_GETDESTADDR,
620 "%s: getting "
621 "destination address: %s"),
622 ifreq.ifr_name, strbuf);
623 return (ISC_R_IGNORE);
624 }
625 get_addr(family, &iter->current.dstaddress,
626 (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name);
627 }
628 #endif
629
630 if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
631 /*
632 * Ignore the HP/UX warning about "integer overflow during
633 * conversion. It comes from its own macro definition,
634 * and is really hard to shut up.
635 */
636 if (isc_ioctl(iter->socket, SIOCGIFBRDADDR, (char *)&ifreq)
637 < 0) {
638 isc__strerror(errno, strbuf, sizeof(strbuf));
639 UNEXPECTED_ERROR(__FILE__, __LINE__,
640 isc_msgcat_get(isc_msgcat,
641 ISC_MSGSET_IFITERIOCTL,
642 ISC_MSG_GETBCSTADDR,
643 "%s: getting "
644 "broadcast address: %s"),
645 ifreq.ifr_name, strbuf);
646 return (ISC_R_IGNORE);
647 }
648 get_addr(family, &iter->current.broadcast,
649 (struct sockaddr *)&ifreq.ifr_broadaddr, ifreq.ifr_name);
650 }
651
652 /*
653 * Get the network mask.
654 */
655 memset(&ifreq, 0, sizeof(ifreq));
656 memcpy(&ifreq, ifrp, sizeof(ifreq));
657 /*
658 * Ignore the HP/UX warning about "integer overflow during
659 * conversion. It comes from its own macro definition,
660 * and is really hard to shut up.
661 */
662 if (isc_ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
663 isc__strerror(errno, strbuf, sizeof(strbuf));
664 UNEXPECTED_ERROR(__FILE__, __LINE__,
665 isc_msgcat_get(isc_msgcat,
666 ISC_MSGSET_IFITERIOCTL,
667 ISC_MSG_GETNETMASK,
668 "%s: getting netmask: %s"),
669 ifreq.ifr_name, strbuf);
670 return (ISC_R_IGNORE);
671 }
672 get_addr(family, &iter->current.netmask,
673 (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name);
674 #ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
675 iter->current.ifindex = if_nametoindex(iter->current.name);
676 #endif
677 return (ISC_R_SUCCESS);
678 }
679
680 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
681 static isc_result_t
internal_current6(isc_interfaceiter_t * iter)682 internal_current6(isc_interfaceiter_t *iter) {
683 struct LIFREQ *ifrp;
684 struct LIFREQ lifreq;
685 int family;
686 char strbuf[ISC_STRERRORSIZE];
687 int fd;
688
689 REQUIRE(VALID_IFITER(iter));
690 if (iter->result6 != ISC_R_SUCCESS)
691 return (iter->result6);
692 REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
693
694 ifrp = (void *)((char *)iter->lifc.lifc_req + iter->pos6);
695
696 memset(&lifreq, 0, sizeof(lifreq));
697 memcpy(&lifreq, ifrp, sizeof(lifreq));
698
699 family = lifreq.lifr_addr.ss_family;
700 #ifdef ISC_PLATFORM_HAVEIPV6
701 if (family != AF_INET && family != AF_INET6)
702 #else
703 if (family != AF_INET)
704 #endif
705 return (ISC_R_IGNORE);
706
707 memset(&iter->current, 0, sizeof(iter->current));
708 iter->current.af = family;
709
710 INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name));
711 memset(iter->current.name, 0, sizeof(iter->current.name));
712 memcpy(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name));
713
714 get_addr(family, &iter->current.address,
715 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
716
717 if (isc_netaddr_islinklocal(&iter->current.address))
718 isc_netaddr_setzone(&iter->current.address,
719 (isc_uint32_t)lifreq.lifr_index);
720
721 /*
722 * If the interface does not have a address ignore it.
723 */
724 switch (family) {
725 case AF_INET:
726 if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
727 return (ISC_R_IGNORE);
728 break;
729 case AF_INET6:
730 if (memcmp(&iter->current.address.type.in6, &in6addr_any,
731 sizeof(in6addr_any)) == 0)
732 return (ISC_R_IGNORE);
733 break;
734 }
735
736 /*
737 * Get interface flags.
738 */
739
740 iter->current.flags = 0;
741
742 if (family == AF_INET6)
743 fd = iter->socket6;
744 else
745 fd = iter->socket;
746
747 /*
748 * Ignore the HP/UX warning about "integer overflow during
749 * conversion. It comes from its own macro definition,
750 * and is really hard to shut up.
751 */
752 if (isc_ioctl(fd, SIOCGLIFFLAGS, (char *) &lifreq) < 0) {
753 isc__strerror(errno, strbuf, sizeof(strbuf));
754 UNEXPECTED_ERROR(__FILE__, __LINE__,
755 "%s: getting interface flags: %s",
756 lifreq.lifr_name, strbuf);
757 return (ISC_R_IGNORE);
758 }
759
760 if ((lifreq.lifr_flags & IFF_UP) != 0)
761 iter->current.flags |= INTERFACE_F_UP;
762
763 #ifdef IFF_POINTOPOINT
764 if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0)
765 iter->current.flags |= INTERFACE_F_POINTTOPOINT;
766 #endif
767
768 if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0)
769 iter->current.flags |= INTERFACE_F_LOOPBACK;
770
771 if ((lifreq.lifr_flags & IFF_BROADCAST) != 0) {
772 iter->current.flags |= INTERFACE_F_BROADCAST;
773 }
774
775 #ifdef IFF_MULTICAST
776 if ((lifreq.lifr_flags & IFF_MULTICAST) != 0) {
777 iter->current.flags |= INTERFACE_F_MULTICAST;
778 }
779 #endif
780
781 #ifdef IFF_POINTOPOINT
782 /*
783 * If the interface is point-to-point, get the destination address.
784 */
785 if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
786 /*
787 * Ignore the HP/UX warning about "integer overflow during
788 * conversion. It comes from its own macro definition,
789 * and is really hard to shut up.
790 */
791 if (isc_ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq)
792 < 0) {
793 isc__strerror(errno, strbuf, sizeof(strbuf));
794 UNEXPECTED_ERROR(__FILE__, __LINE__,
795 isc_msgcat_get(isc_msgcat,
796 ISC_MSGSET_IFITERIOCTL,
797 ISC_MSG_GETDESTADDR,
798 "%s: getting "
799 "destination address: %s"),
800 lifreq.lifr_name, strbuf);
801 return (ISC_R_IGNORE);
802 }
803 get_addr(family, &iter->current.dstaddress,
804 (struct sockaddr *)&lifreq.lifr_dstaddr,
805 lifreq.lifr_name);
806 }
807 #endif
808
809 #ifdef SIOCGLIFBRDADDR
810 if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
811 /*
812 * Ignore the HP/UX warning about "integer overflow during
813 * conversion. It comes from its own macro definition,
814 * and is really hard to shut up.
815 */
816 if (isc_ioctl(iter->socket, SIOCGLIFBRDADDR, (char *)&lifreq)
817 < 0) {
818 isc__strerror(errno, strbuf, sizeof(strbuf));
819 UNEXPECTED_ERROR(__FILE__, __LINE__,
820 isc_msgcat_get(isc_msgcat,
821 ISC_MSGSET_IFITERIOCTL,
822 ISC_MSG_GETBCSTADDR,
823 "%s: getting "
824 "broadcast address: %s"),
825 lifreq.lifr_name, strbuf);
826 return (ISC_R_IGNORE);
827 }
828 get_addr(family, &iter->current.broadcast,
829 (struct sockaddr *)&lifreq.lifr_broadaddr,
830 lifreq.lifr_name);
831 }
832 #endif /* SIOCGLIFBRDADDR */
833
834 /*
835 * Get the network mask. Netmask already zeroed.
836 */
837 memset(&lifreq, 0, sizeof(lifreq));
838 memcpy(&lifreq, ifrp, sizeof(lifreq));
839
840 #ifdef lifr_addrlen
841 /*
842 * Special case: if the system provides lifr_addrlen member, the
843 * netmask of an IPv6 address can be derived from the length, since
844 * an IPv6 address always has a contiguous mask.
845 */
846 if (family == AF_INET6) {
847 int i, bits;
848
849 iter->current.netmask.family = family;
850 for (i = 0; i < lifreq.lifr_addrlen; i += 8) {
851 bits = lifreq.lifr_addrlen - i;
852 bits = (bits < 8) ? (8 - bits) : 0;
853 iter->current.netmask.type.in6.s6_addr[i / 8] =
854 (~0 << bits) & 0xff;
855 }
856 #ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
857 iter->current.ifindex = if_nametoindex(iter->current.name);
858 #endif
859 return (ISC_R_SUCCESS);
860 }
861 #endif
862
863 /*
864 * Ignore the HP/UX warning about "integer overflow during
865 * conversion. It comes from its own macro definition,
866 * and is really hard to shut up.
867 */
868 if (isc_ioctl(fd, SIOCGLIFNETMASK, (char *)&lifreq) < 0) {
869 isc__strerror(errno, strbuf, sizeof(strbuf));
870 UNEXPECTED_ERROR(__FILE__, __LINE__,
871 isc_msgcat_get(isc_msgcat,
872 ISC_MSGSET_IFITERIOCTL,
873 ISC_MSG_GETNETMASK,
874 "%s: getting netmask: %s"),
875 lifreq.lifr_name, strbuf);
876 return (ISC_R_IGNORE);
877 }
878 get_addr(family, &iter->current.netmask,
879 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
880
881 #ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
882 iter->current.ifindex = if_nametoindex(iter->current.name);
883 #endif
884 return (ISC_R_SUCCESS);
885 }
886 #endif
887
888 static isc_result_t
internal_current(isc_interfaceiter_t * iter)889 internal_current(isc_interfaceiter_t *iter) {
890 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
891 if (iter->mode == 6) {
892 iter->result6 = internal_current6(iter);
893 if (iter->result6 != ISC_R_NOMORE)
894 return (iter->result6);
895 }
896 #endif
897 #ifdef HAVE_TRUCLUSTER
898 if (!iter->clua_done)
899 return(internal_current_clusteralias(iter));
900 #endif
901 return (internal_current4(iter));
902 }
903
904 /*
905 * Step the iterator to the next interface. Unlike
906 * isc_interfaceiter_next(), this may leave the iterator
907 * positioned on an interface that will ultimately
908 * be ignored. Return ISC_R_NOMORE if there are no more
909 * interfaces, otherwise ISC_R_SUCCESS.
910 */
911 static isc_result_t
internal_next4(isc_interfaceiter_t * iter)912 internal_next4(isc_interfaceiter_t *iter) {
913 #ifdef ISC_PLATFORM_HAVESALEN
914 struct ifreq *ifrp;
915 #endif
916
917 if (iter->pos < (unsigned int) iter->ifc.ifc_len) {
918 #ifdef ISC_PLATFORM_HAVESALEN
919 ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
920
921 if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
922 iter->pos += sizeof(ifrp->ifr_name) +
923 ifrp->ifr_addr.sa_len;
924 else
925 #endif
926 iter->pos += sizeof(struct ifreq);
927
928 } else {
929 INSIST(iter->pos == (unsigned int) iter->ifc.ifc_len);
930 #ifdef __linux
931 return (linux_if_inet6_next(iter));
932 #else
933 return (ISC_R_NOMORE);
934 #endif
935 }
936 return (ISC_R_SUCCESS);
937 }
938
939 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
940 static isc_result_t
internal_next6(isc_interfaceiter_t * iter)941 internal_next6(isc_interfaceiter_t *iter) {
942 #ifdef ISC_PLATFORM_HAVESALEN
943 struct LIFREQ *ifrp;
944 #endif
945
946 if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE)
947 return (iter->result6);
948
949 REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
950
951 #ifdef ISC_PLATFORM_HAVESALEN
952 ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
953
954 if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr))
955 iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len;
956 else
957 #endif
958 iter->pos6 += sizeof(struct LIFREQ);
959
960 if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len)
961 return (ISC_R_NOMORE);
962
963 return (ISC_R_SUCCESS);
964 }
965 #endif
966
967 static isc_result_t
internal_next(isc_interfaceiter_t * iter)968 internal_next(isc_interfaceiter_t *iter) {
969 #ifdef HAVE_TRUCLUSTER
970 int clua_result;
971 #endif
972 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
973 if (iter->mode == 6) {
974 iter->result6 = internal_next6(iter);
975 if (iter->result6 != ISC_R_NOMORE)
976 return (iter->result6);
977 if (iter->first6) {
978 iter->first6 = ISC_FALSE;
979 return (ISC_R_SUCCESS);
980 }
981 }
982 #endif
983 #ifdef HAVE_TRUCLUSTER
984 if (!iter->clua_done) {
985 clua_result = clua_getaliasaddress(&iter->clua_sa,
986 &iter->clua_context);
987 if (clua_result != CLUA_SUCCESS)
988 iter->clua_done = ISC_TRUE;
989 return (ISC_R_SUCCESS);
990 }
991 #endif
992 return (internal_next4(iter));
993 }
994
995 static void
internal_destroy(isc_interfaceiter_t * iter)996 internal_destroy(isc_interfaceiter_t *iter) {
997 (void) close(iter->socket);
998 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
999 if (iter->socket6 != -1)
1000 (void) close(iter->socket6);
1001 if (iter->buf6 != NULL) {
1002 isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
1003 }
1004 #endif
1005 #ifdef __linux
1006 if (iter->proc != NULL)
1007 fclose(iter->proc);
1008 #endif
1009 }
1010
1011 static
internal_first(isc_interfaceiter_t * iter)1012 void internal_first(isc_interfaceiter_t *iter) {
1013 #ifdef HAVE_TRUCLUSTER
1014 int clua_result;
1015 #endif
1016 iter->pos = 0;
1017 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1018 iter->pos6 = 0;
1019 if (iter->result6 == ISC_R_NOMORE)
1020 iter->result6 = ISC_R_SUCCESS;
1021 iter->first6 = ISC_TRUE;
1022 #endif
1023 #ifdef HAVE_TRUCLUSTER
1024 iter->clua_context = 0;
1025 clua_result = clua_getaliasaddress(&iter->clua_sa,
1026 &iter->clua_context);
1027 iter->clua_done = ISC_TF(clua_result != CLUA_SUCCESS);
1028 #endif
1029 #ifdef __linux
1030 linux_if_inet6_first(iter);
1031 #endif
1032 }
1033