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