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