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