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
55struct 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 */
113int
114isc_ioctl(int fildes, int req, char *arg);
115
116int
117isc_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
131static isc_result_t
132getbuf4(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)
204static isc_result_t
205getbuf6(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
309isc_result_t
310isc_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
419static void
420get_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
425static isc_result_t
426internal_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
449static isc_result_t
450internal_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)
681static isc_result_t
682internal_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
888static isc_result_t
889internal_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 */
911static isc_result_t
912internal_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)
940static isc_result_t
941internal_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
967static isc_result_t
968internal_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
995static void
996internal_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
1011static
1012void 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