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