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