1118e757roberto/*
2d54cfbdroberto * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
37a6072eroberto * Copyright (C) 1999-2003  Internet Software Consortium.
4118e757roberto *
5d54cfbdroberto * Permission to use, copy, modify, and/or distribute this software for any
6118e757roberto * purpose with or without fee is hereby granted, provided that the above
7118e757roberto * copyright notice and this permission notice appear in all copies.
8118e757roberto *
97a6072eroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
107a6072eroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
117a6072eroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
127a6072eroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
137a6072eroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
147a6072eroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
157a6072eroberto * PERFORMANCE OF THIS SOFTWARE.
16118e757roberto */
17118e757roberto
18047f369cy/* $Id: ifiter_ioctl.c,v 1.62 2009/01/18 23:48:14 tbox Exp $ */
19118e757roberto
20d54cfbdroberto/*! \file
21d54cfbdroberto * \brief
22118e757roberto * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl.
23118e757roberto * See netintro(4).
24118e757roberto */
25118e757roberto
26118e757roberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
27118e757roberto#ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
28118e757roberto#define lifc_len iflc_len
29118e757roberto#define lifc_buf iflc_buf
30118e757roberto#define lifc_req iflc_req
31118e757roberto#define LIFCONF if_laddrconf
32118e757roberto#else
33118e757roberto#define ISC_HAVE_LIFC_FAMILY 1
34118e757roberto#define ISC_HAVE_LIFC_FLAGS 1
35118e757roberto#define LIFCONF lifconf
36118e757roberto#endif
37118e757roberto
38118e757roberto#ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
39118e757roberto#define lifr_addr iflr_addr
40118e757roberto#define lifr_name iflr_name
41118e757roberto#define lifr_dstaddr iflr_dstaddr
42118e757roberto#define lifr_broadaddr iflr_broadaddr
43118e757roberto#define lifr_flags iflr_flags
447a6072eroberto#define lifr_index iflr_index
45118e757roberto#define ss_family sa_family
46118e757roberto#define LIFREQ if_laddrreq
47118e757roberto#else
48118e757roberto#define LIFREQ lifreq
49118e757roberto#endif
50118e757roberto#endif
51118e757roberto
52118e757roberto#define IFITER_MAGIC		ISC_MAGIC('I', 'F', 'I', 'T')
53118e757roberto#define VALID_IFITER(t)		ISC_MAGIC_VALID(t, IFITER_MAGIC)
54118e757roberto
55118e757robertostruct isc_interfaceiter {
56118e757roberto	unsigned int		magic;		/* Magic number. */
57118e757roberto	isc_mem_t		*mctx;
58118e757roberto	int			mode;
597a6072eroberto	int			socket;
60118e757roberto	struct ifconf 		ifc;
617a6072eroberto	void			*buf;		/* Buffer for sysctl data. */
627a6072eroberto	unsigned int		bufsize;	/* Bytes allocated. */
637a6072eroberto	unsigned int		pos;		/* Current offset in
647a6072eroberto						   SIOCGIFCONF data */
65118e757roberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
667a6072eroberto	int			socket6;
67118e757roberto	struct LIFCONF 		lifc;
687a6072eroberto	void			*buf6;		/* Buffer for sysctl data. */
697a6072eroberto	unsigned int		bufsize6;	/* Bytes allocated. */
707a6072eroberto	unsigned int		pos6;		/* Current offset in
717a6072eroberto						   SIOCGLIFCONF data */
727a6072eroberto	isc_result_t		result6;	/* Last result code. */
737a6072eroberto	isc_boolean_t		first6;
74118e757roberto#endif
75118e757roberto#ifdef HAVE_TRUCLUSTER
76118e757roberto	int			clua_context;	/* Cluster alias context */
777a6072eroberto	isc_boolean_t		clua_done;
787a6072eroberto	struct sockaddr		clua_sa;
797a6072eroberto#endif
807a6072eroberto#ifdef	__linux
817a6072eroberto	FILE *			proc;
827a6072eroberto	char			entry[ISC_IF_INET6_SZ];
837a6072eroberto	isc_result_t		valid;
84118e757roberto#endif
85118e757roberto	isc_interface_t		current;	/* Current interface data. */
86118e757roberto	isc_result_t		result;		/* Last result code. */
87118e757roberto};
88118e757roberto
89118e757roberto#ifdef HAVE_TRUCLUSTER
90118e757roberto#include <clua/clua.h>
91118e757roberto#include <sys/socket.h>
92118e757roberto#endif
93118e757roberto
94118e757roberto
95d54cfbdroberto/*%
96118e757roberto * Size of buffer for SIOCGLIFCONF, in bytes.  We assume no sane system
97118e757roberto * will have more than a megabyte of interface configuration data.
98118e757roberto */
99118e757roberto#define IFCONF_BUFSIZE_INITIAL	4096
100118e757roberto#define IFCONF_BUFSIZE_MAX	1048576
101118e757roberto
1027a6072eroberto#ifdef __linux
1037a6072eroberto#ifndef IF_NAMESIZE
1047a6072eroberto# ifdef IFNAMSIZ
105d54cfbdroberto#  define IF_NAMESIZE  IFNAMSIZ
1067a6072eroberto# else
1077a6072eroberto#  define IF_NAMESIZE 16
1087a6072eroberto# endif
1097a6072eroberto#endif
1107a6072eroberto#endif
1117a6072eroberto
112f63afe2cy/* Silence a warning when this file is #included */
113f63afe2cyint
114f63afe2cyisc_ioctl(int fildes, int req, char *arg);
115f63afe2cy
116047f369cyint
117047f369cyisc_ioctl(int fildes, int req, char *arg) {
118047f369cy	int trys;
119047f369cy	int ret;
120047f369cy
121047f369cy	for (trys = 0; trys < 3; trys++) {
122047f369cy		if ((ret = ioctl(fildes, req, arg)) < 0) {
123047f369cy			if (errno == EINTR)
124047f369cy				continue;
125047f369cy		}
126047f369cy		break;
127047f369cy	}
128047f369cy	return (ret);
129047f369cy}
130047f369cy
131118e757robertostatic isc_result_t
132118e757robertogetbuf4(isc_interfaceiter_t *iter) {
133118e757roberto	char strbuf[ISC_STRERRORSIZE];
134118e757roberto
135118e757roberto	iter->bufsize = IFCONF_BUFSIZE_INITIAL;
136118e757roberto
137118e757roberto	for (;;) {
138118e757roberto		iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
139118e757roberto		if (iter->buf == NULL)
140118e757roberto			return (ISC_R_NOMEMORY);
141118e757roberto
142118e757roberto		memset(&iter->ifc.ifc_len, 0, sizeof(iter->ifc.ifc_len));
143118e757roberto		iter->ifc.ifc_len = iter->bufsize;
144118e757roberto		iter->ifc.ifc_buf = iter->buf;
145118e757roberto		/*
146118e757roberto		 * Ignore the HP/UX warning about "integer overflow during
147118e757roberto		 * conversion".  It comes from its own macro definition,
148118e757roberto		 * and is really hard to shut up.
149118e757roberto		 */
150047f369cy		if (isc_ioctl(iter->socket, SIOCGIFCONF, (char *)&iter->ifc)
151118e757roberto		    == -1) {
152118e757roberto			if (errno != EINVAL) {
153118e757roberto				isc__strerror(errno, strbuf, sizeof(strbuf));
154118e757roberto				UNEXPECTED_ERROR(__FILE__, __LINE__,
155118e757roberto						 isc_msgcat_get(isc_msgcat,
156118e757roberto							ISC_MSGSET_IFITERIOCTL,
157118e757roberto							ISC_MSG_GETIFCONFIG,
158118e757roberto							"get interface "
159118e757roberto							"configuration: %s"),
160118e757roberto						 strbuf);
161118e757roberto				goto unexpected;
162118e757roberto			}
163118e757roberto			/*
164118e757roberto			 * EINVAL.  Retry with a bigger buffer.
165118e757roberto			 */
166118e757roberto		} else {
167118e757roberto			/*
168118e757roberto			 * The ioctl succeeded.
169118e757roberto			 * Some OS's just return what will fit rather
170118e757roberto			 * than set EINVAL if the buffer is too small
171118e757roberto			 * to fit all the interfaces in.  If
172118e757roberto			 * ifc.lifc_len is too near to the end of the
173118e757roberto			 * buffer we will grow it just in case and
174118e757roberto			 * retry.
175118e757roberto			 */
176118e757roberto			if (iter->ifc.ifc_len + 2 * sizeof(struct ifreq)
177118e757roberto			    < iter->bufsize)
178118e757roberto				break;
179118e757roberto		}
180118e757roberto		if (iter->bufsize >= IFCONF_BUFSIZE_MAX) {
181118e757roberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
182118e757roberto					 isc_msgcat_get(isc_msgcat,
183118e757roberto							ISC_MSGSET_IFITERIOCTL,
184118e757roberto							ISC_MSG_BUFFERMAX,
185118e757roberto							"get interface "
186118e757roberto							"configuration: "
187118e757roberto							"maximum buffer "
188118e757roberto							"size exceeded"));
189118e757roberto			goto unexpected;
190118e757roberto		}
191118e757roberto		isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
192118e757roberto
193118e757roberto		iter->bufsize *= 2;
194118e757roberto	}
195118e757roberto	return (ISC_R_SUCCESS);
196118e757roberto
197118e757roberto unexpected:
198118e757roberto	isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
199118e757roberto	iter->buf = NULL;
200118e757roberto	return (ISC_R_UNEXPECTED);
201118e757roberto}
202118e757roberto
2037a6072eroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
204118e757robertostatic isc_result_t
205118e757robertogetbuf6(isc_interfaceiter_t *iter) {
206118e757roberto	char strbuf[ISC_STRERRORSIZE];
207118e757roberto	isc_result_t result;
208118e757roberto
2097a6072eroberto	iter->bufsize6 = IFCONF_BUFSIZE_INITIAL;
210118e757roberto
211118e757roberto	for (;;) {
2127a6072eroberto		iter->buf6 = isc_mem_get(iter->mctx, iter->bufsize6);
2137a6072eroberto		if (iter->buf6 == NULL)
214118e757roberto			return (ISC_R_NOMEMORY);
215118e757roberto
2167a6072eroberto		memset(&iter->lifc, 0, sizeof(iter->lifc));
217118e757roberto#ifdef ISC_HAVE_LIFC_FAMILY
2187a6072eroberto		iter->lifc.lifc_family = AF_INET6;
219118e757roberto#endif
220118e757roberto#ifdef ISC_HAVE_LIFC_FLAGS
221118e757roberto		iter->lifc.lifc_flags = 0;
222118e757roberto#endif
2237a6072eroberto		iter->lifc.lifc_len = iter->bufsize6;
2247a6072eroberto		iter->lifc.lifc_buf = iter->buf6;
225118e757roberto		/*
226118e757roberto		 * Ignore the HP/UX warning about "integer overflow during
227118e757roberto		 * conversion".  It comes from its own macro definition,
228118e757roberto		 * and is really hard to shut up.
229118e757roberto		 */
230047f369cy		if (isc_ioctl(iter->socket6, SIOCGLIFCONF, (char *)&iter->lifc)
231118e757roberto		    == -1) {
232118e757roberto#ifdef __hpux
233118e757roberto			/*
234118e757roberto			 * IPv6 interface scanning is not available on all
235118e757roberto			 * kernels w/ IPv6 sockets.
236118e757roberto			 */
237118e757roberto			if (errno == ENOENT) {
238118e757roberto				isc__strerror(errno, strbuf, sizeof(strbuf));
239d54cfbdroberto				isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
240d54cfbdroberto					      ISC_LOGMODULE_INTERFACE,
241d54cfbdroberto					      ISC_LOG_DEBUG(1),
242d54cfbdroberto					      isc_msgcat_get(isc_msgcat,
243118e757roberto							ISC_MSGSET_IFITERIOCTL,
244118e757roberto							ISC_MSG_GETIFCONFIG,
245118e757roberto							"get interface "
246118e757roberto							"configuration: %s"),
247d54cfbdroberto					       strbuf);
248118e757roberto				result = ISC_R_FAILURE;
249118e757roberto				goto cleanup;
250118e757roberto			}
251118e757roberto#endif
252118e757roberto			if (errno != EINVAL) {
253118e757roberto				isc__strerror(errno, strbuf, sizeof(strbuf));
254118e757roberto				UNEXPECTED_ERROR(__FILE__, __LINE__,
255118e757roberto						 isc_msgcat_get(isc_msgcat,
256118e757roberto							ISC_MSGSET_IFITERIOCTL,
257118e757roberto							ISC_MSG_GETIFCONFIG,
258118e757roberto							"get interface "
259118e757roberto							"configuration: %s"),
260118e757roberto						 strbuf);
261118e757roberto				result = ISC_R_UNEXPECTED;
262118e757roberto				goto cleanup;
263118e757roberto			}
264118e757roberto			/*
265118e757roberto			 * EINVAL.  Retry with a bigger buffer.
266118e757roberto			 */
267118e757roberto		} else {
268118e757roberto			/*
269118e757roberto			 * The ioctl succeeded.
270118e757roberto			 * Some OS's just return what will fit rather
271118e757roberto			 * than set EINVAL if the buffer is too small
272118e757roberto			 * to fit all the interfaces in.  If
273118e757roberto			 * ifc.ifc_len is too near to the end of the
274118e757roberto			 * buffer we will grow it just in case and
275118e757roberto			 * retry.
276118e757roberto			 */
277118e757roberto			if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ)
2787a6072eroberto			    < iter->bufsize6)
279118e757roberto				break;
280118e757roberto		}
2817a6072eroberto		if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) {
282118e757roberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
283118e757roberto					 isc_msgcat_get(isc_msgcat,
284118e757roberto							ISC_MSGSET_IFITERIOCTL,
285118e757roberto							ISC_MSG_BUFFERMAX,
286118e757roberto							"get interface "
287118e757roberto							"configuration: "
288118e757roberto							"maximum buffer "
289118e757roberto							"size exceeded"));
290118e757roberto			result = ISC_R_UNEXPECTED;
291118e757roberto			goto cleanup;
292118e757roberto		}
2937a6072eroberto		isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
294118e757roberto
2957a6072eroberto		iter->bufsize6 *= 2;
296118e757roberto	}
297118e757roberto
2987a6072eroberto	if (iter->lifc.lifc_len != 0)
2997a6072eroberto		iter->mode = 6;
300118e757roberto	return (ISC_R_SUCCESS);
301118e757roberto
302118e757roberto cleanup:
3037a6072eroberto	isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
3047a6072eroberto	iter->buf6 = NULL;
305118e757roberto	return (result);
306118e757roberto}
3077a6072eroberto#endif
308118e757roberto
309118e757robertoisc_result_t
310118e757robertoisc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
311118e757roberto	isc_interfaceiter_t *iter;
312118e757roberto	isc_result_t result;
313118e757roberto	char strbuf[ISC_STRERRORSIZE];
314118e757roberto
315d54cfbdroberto	REQUIRE(mctx != NULL);
316118e757roberto	REQUIRE(iterp != NULL);
317118e757roberto	REQUIRE(*iterp == NULL);
318118e757roberto
319118e757roberto	iter = isc_mem_get(mctx, sizeof(*iter));
320118e757roberto	if (iter == NULL)
321118e757roberto		return (ISC_R_NOMEMORY);
322118e757roberto
323118e757roberto	iter->mctx = mctx;
3247a6072eroberto	iter->mode = 4;
325118e757roberto	iter->buf = NULL;
3267a6072eroberto	iter->pos = (unsigned int) -1;
3277a6072eroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
3287a6072eroberto	iter->buf6 = NULL;
3297a6072eroberto	iter->pos6 = (unsigned int) -1;
3307a6072eroberto	iter->result6 = ISC_R_NOMORE;
3317a6072eroberto	iter->socket6 = -1;
3327a6072eroberto	iter->first6 = ISC_FALSE;
3337a6072eroberto#endif
334118e757roberto
335118e757roberto	/*
3367a6072eroberto	 * Get the interface configuration, allocating more memory if
3377a6072eroberto	 * necessary.
338118e757roberto	 */
3397a6072eroberto
3407a6072eroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
3417a6072eroberto	result = isc_net_probeipv6();
3427a6072eroberto	if (result == ISC_R_SUCCESS) {
3437a6072eroberto		/*
3447a6072eroberto		 * Create an unbound datagram socket to do the SIOCGLIFCONF
3457a6072eroberto		 * ioctl on.  HP/UX requires an AF_INET6 socket for
3467a6072eroberto		 * SIOCGLIFCONF to get IPv6 addresses.
3477a6072eroberto		 */
3487a6072eroberto		if ((iter->socket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
3497a6072eroberto			isc__strerror(errno, strbuf, sizeof(strbuf));
3507a6072eroberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
3517a6072eroberto					 isc_msgcat_get(isc_msgcat,
3527a6072eroberto							ISC_MSGSET_IFITERIOCTL,
3537a6072eroberto							ISC_MSG_MAKESCANSOCKET,
3547a6072eroberto							"making interface "
3557a6072eroberto							"scan socket: %s"),
3567a6072eroberto					 strbuf);
3577a6072eroberto			result = ISC_R_UNEXPECTED;
3587a6072eroberto			goto socket6_failure;
3597a6072eroberto		}
360d54cfbdroberto		result = iter->result6 = getbuf6(iter);
361d54cfbdroberto		if (result != ISC_R_NOTIMPLEMENTED && result != ISC_R_SUCCESS)
3627a6072eroberto			goto ioctl6_failure;
3637a6072eroberto	}
3647a6072eroberto#endif
365118e757roberto	if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
366118e757roberto		isc__strerror(errno, strbuf, sizeof(strbuf));
367118e757roberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
368118e757roberto				 isc_msgcat_get(isc_msgcat,
369118e757roberto						ISC_MSGSET_IFITERIOCTL,
370118e757roberto						ISC_MSG_MAKESCANSOCKET,
371118e757roberto						"making interface "
372118e757roberto						"scan socket: %s"),
373118e757roberto				 strbuf);
374118e757roberto		result = ISC_R_UNEXPECTED;
375118e757roberto		goto socket_failure;
376118e757roberto	}
3777a6072eroberto	result = getbuf4(iter);
378118e757roberto	if (result != ISC_R_SUCCESS)
379118e757roberto		goto ioctl_failure;
380118e757roberto
381118e757roberto	/*
382118e757roberto	 * A newly created iterator has an undefined position
383118e757roberto	 * until isc_interfaceiter_first() is called.
384118e757roberto	 */
385118e757roberto#ifdef HAVE_TRUCLUSTER
386118e757roberto	iter->clua_context = -1;
3877a6072eroberto	iter->clua_done = ISC_TRUE;
3887a6072eroberto#endif
3897a6072eroberto#ifdef __linux
3907a6072eroberto	iter->proc = fopen("/proc/net/if_inet6", "r");
3917a6072eroberto	iter->valid = ISC_R_FAILURE;
392118e757roberto#endif
393118e757roberto	iter->result = ISC_R_FAILURE;
394118e757roberto
395118e757roberto	iter->magic = IFITER_MAGIC;
396118e757roberto	*iterp = iter;
397118e757roberto	return (ISC_R_SUCCESS);
398118e757roberto
399118e757roberto ioctl_failure:
400118e757roberto	if (iter->buf != NULL)
401118e757roberto		isc_mem_put(mctx, iter->buf, iter->bufsize);
402118e757roberto	(void) close(iter->socket);
403118e757roberto
404118e757roberto socket_failure:
4057a6072eroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
4067a6072eroberto	if (iter->buf6 != NULL)
4077a6072eroberto		isc_mem_put(mctx, iter->buf6, iter->bufsize6);
4087a6072eroberto  ioctl6_failure:
4097a6072eroberto	if (iter->socket6 != -1)
4107a6072eroberto		(void) close(iter->socket6);
4117a6072eroberto  socket6_failure:
4127a6072eroberto#endif
413d54cfbdroberto
414118e757roberto	isc_mem_put(mctx, iter, sizeof(*iter));
415118e757roberto	return (result);
416118e757roberto}
417118e757roberto
418118e757roberto#ifdef HAVE_TRUCLUSTER
419118e757robertostatic void
420118e757robertoget_inaddr(isc_netaddr_t *dst, struct in_addr *src) {
421118e757roberto	dst->family = AF_INET;
422118e757roberto	memcpy(&dst->type.in, src, sizeof(struct in_addr));
423118e757roberto}
424118e757roberto
425118e757robertostatic isc_result_t
426118e757robertointernal_current_clusteralias(isc_interfaceiter_t *iter) {
427118e757roberto	struct clua_info ci;
4287a6072eroberto	if (clua_getaliasinfo(&iter->clua_sa, &ci) != CLUA_SUCCESS)
4297a6072eroberto		return (ISC_R_IGNORE);
4307a6072eroberto	memset(&iter->current, 0, sizeof(iter->current));
4317a6072eroberto	iter->current.af = iter->clua_sa.sa_family;
4327a6072eroberto	memset(iter->current.name, 0, sizeof(iter->current.name));
4337a6072eroberto	sprintf(iter->current.name, "clua%d", ci.aliasid);
4347a6072eroberto	iter->current.flags = INTERFACE_F_UP;
4357a6072eroberto	get_inaddr(&iter->current.address, &ci.addr);
4367a6072eroberto	get_inaddr(&iter->current.netmask, &ci.netmask);
4377a6072eroberto	return (ISC_R_SUCCESS);
4387a6072eroberto}
4397a6072eroberto#endif
4407a6072eroberto
441118e757roberto/*
442118e757roberto * Get information about the current interface to iter->current.
443118e757roberto * If successful, return ISC_R_SUCCESS.
444118e757roberto * If the interface has an unsupported address family, or if
445118e757roberto * some operation on it fails, return ISC_R_IGNORE to make
446118e757roberto * the higher-level iterator code ignore it.
447118e757roberto */
448118e757roberto
449118e757robertostatic isc_result_t
450118e757robertointernal_current4(isc_interfaceiter_t *iter) {
451118e757roberto	struct ifreq *ifrp;
452118e757roberto	struct ifreq ifreq;
453118e757roberto	int family;
454118e757roberto	char strbuf[ISC_STRERRORSIZE];
4557a6072eroberto#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
4567a6072eroberto	struct lifreq lifreq;
4577a6072eroberto#else
4587a6072eroberto	char sabuf[256];
4597a6072eroberto#endif
4607a6072eroberto	int i, bits, prefixlen;
461118e757roberto
462118e757roberto	REQUIRE(VALID_IFITER(iter));
463118e757roberto
464d54cfbdroberto	if (iter->ifc.ifc_len == 0 ||
465d54cfbdroberto	    iter->pos == (unsigned int)iter->ifc.ifc_len) {
4667a6072eroberto#ifdef __linux
467d54cfbdroberto		return (linux_if_inet6_current(iter));
468d54cfbdroberto#else
469d54cfbdroberto		return (ISC_R_NOMORE);
4707a6072eroberto#endif
471d54cfbdroberto	}
472d54cfbdroberto
473d54cfbdroberto	INSIST( iter->pos < (unsigned int) iter->ifc.ifc_len);
4747a6072eroberto
475047f369cy	ifrp = (void *)((char *) iter->ifc.ifc_req + iter->pos);
476118e757roberto
477118e757roberto	memset(&ifreq, 0, sizeof(ifreq));
478118e757roberto	memcpy(&ifreq, ifrp, sizeof(ifreq));
479118e757roberto
480118e757roberto	family = ifreq.ifr_addr.sa_family;
4817a6072eroberto#if defined(ISC_PLATFORM_HAVEIPV6)
482118e757roberto	if (family != AF_INET && family != AF_INET6)
483118e757roberto#else
484118e757roberto	if (family != AF_INET)
485118e757roberto#endif
486118e757roberto		return (ISC_R_IGNORE);
487118e757roberto
488118e757roberto	memset(&iter->current, 0, sizeof(iter->current));
489118e757roberto	iter->current.af = family;
490118e757roberto
491118e757roberto	INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
492118e757roberto	memset(iter->current.name, 0, sizeof(iter->current.name));
493118e757roberto	memcpy(iter->current.name, ifreq.ifr_name, sizeof(ifreq.ifr_name));
494118e757roberto
495118e757roberto	get_addr(family, &iter->current.address,
4967a6072eroberto		 (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name);
497118e757roberto
498118e757roberto	/*
499118e757roberto	 * If the interface does not have a address ignore it.
500118e757roberto	 */
501118e757roberto	switch (family) {
502118e757roberto	case AF_INET:
503118e757roberto		if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
504118e757roberto			return (ISC_R_IGNORE);
505118e757roberto		break;
506118e757roberto	case AF_INET6:
507118e757roberto		if (memcmp(&iter->current.address.type.in6, &in6addr_any,
508118e757roberto			   sizeof(in6addr_any)) == 0)
509118e757roberto			return (ISC_R_IGNORE);
510118e757roberto		break;
511118e757roberto	}
512118e757roberto
513118e757roberto	/*
514118e757roberto	 * Get interface flags.
515118e757roberto	 */
516118e757roberto
517118e757roberto	iter->current.flags = 0;
518118e757roberto
519118e757roberto	/*
520118e757roberto	 * Ignore the HP/UX warning about "integer overflow during
521118e757roberto	 * conversion.  It comes from its own macro definition,
522118e757roberto	 * and is really hard to shut up.
523118e757roberto	 */
524047f369cy	if (isc_ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
525118e757roberto		isc__strerror(errno, strbuf, sizeof(strbuf));
526118e757roberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
527118e757roberto				 "%s: getting interface flags: %s",
528118e757roberto				 ifreq.ifr_name, strbuf);
529118e757roberto		return (ISC_R_IGNORE);
530118e757roberto	}
531118e757roberto
532118e757roberto	if ((ifreq.ifr_flags & IFF_UP) != 0)
533118e757roberto		iter->current.flags |= INTERFACE_F_UP;
534118e757roberto
5357a6072eroberto#ifdef IFF_POINTOPOINT
536118e757roberto	if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
537118e757roberto		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
5387a6072eroberto#endif
539118e757roberto
540118e757roberto	if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
541118e757roberto		iter->current.flags |= INTERFACE_F_LOOPBACK;
542118e757roberto
543d54cfbdroberto	if ((ifreq.ifr_flags & IFF_BROADCAST) != 0)
544118e757roberto		iter->current.flags |= INTERFACE_F_BROADCAST;
545118e757roberto
546118e757roberto#ifdef IFF_MULTICAST
547d54cfbdroberto	if ((ifreq.ifr_flags & IFF_MULTICAST) != 0)
548118e757roberto		iter->current.flags |= INTERFACE_F_MULTICAST;
549118e757roberto#endif
550118e757roberto
5517a6072eroberto	if (family == AF_INET)
552118e757roberto		goto inet;
553118e757roberto
5547a6072eroberto#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
5557a6072eroberto	memset(&lifreq, 0, sizeof(lifreq));
5567a6072eroberto	memcpy(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name));
5577a6072eroberto	memcpy(&lifreq.lifr_addr, &iter->current.address.type.in6,
558118e757roberto	       sizeof(iter->current.address.type.in6));
559118e757roberto
560047f369cy	if (isc_ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) {
561118e757roberto		isc__strerror(errno, strbuf, sizeof(strbuf));
562118e757roberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
563118e757roberto				 "%s: getting interface address: %s",
564118e757roberto				 ifreq.ifr_name, strbuf);
565118e757roberto		return (ISC_R_IGNORE);
566118e757roberto	}
5677a6072eroberto	prefixlen = lifreq.lifr_addrlen;
5687a6072eroberto#else
5697a6072eroberto	isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf));
570d54cfbdroberto	isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
571d54cfbdroberto		      ISC_LOGMODULE_INTERFACE,
572d54cfbdroberto		      ISC_LOG_INFO,
5737a6072eroberto		      isc_msgcat_get(isc_msgcat,
5747a6072eroberto				     ISC_MSGSET_IFITERIOCTL,
5757a6072eroberto				     ISC_MSG_GETIFCONFIG,
5767a6072eroberto				     "prefix length for %s is unknown "
5777a6072eroberto				     "(assume 128)"), sabuf);
5787a6072eroberto	prefixlen = 128;
5797a6072eroberto#endif
580118e757roberto
581118e757roberto	/*
582118e757roberto	 * Netmask already zeroed.
583118e757roberto	 */
584118e757roberto	iter->current.netmask.family = family;
585118e757roberto	for (i = 0; i < 16; i++) {
5867a6072eroberto		if (prefixlen > 8) {
587118e757roberto			bits = 0;
5887a6072eroberto			prefixlen -= 8;
589118e757roberto		} else {
5907a6072eroberto			bits = 8 - prefixlen;
5917a6072eroberto			prefixlen = 0;
592118e757roberto		}
593118e757roberto		iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff;
594118e757roberto	}
595f63afe2cy#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
596f63afe2cy	iter->current.ifindex = if_nametoindex(iter->current.name);
597f63afe2cy#endif
598118e757roberto	return (ISC_R_SUCCESS);
599118e757roberto
600118e757roberto inet:
601118e757roberto	if (family != AF_INET)
602118e757roberto		return (ISC_R_IGNORE);
6037a6072eroberto#ifdef IFF_POINTOPOINT
604118e757roberto	/*
605118e757roberto	 * If the interface is point-to-point, get the destination address.
606118e757roberto	 */
607118e757roberto	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
608118e757roberto		/*
609118e757roberto		 * Ignore the HP/UX warning about "integer overflow during
610118e757roberto		 * conversion.  It comes from its own macro definition,
611118e757roberto		 * and is really hard to shut up.
612118e757roberto		 */
613047f369cy		if (isc_ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq)
614118e757roberto		    < 0) {
615118e757roberto			isc__strerror(errno, strbuf, sizeof(strbuf));
616118e757roberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
617118e757roberto				isc_msgcat_get(isc_msgcat,
618118e757roberto					       ISC_MSGSET_IFITERIOCTL,
619118e757roberto					       ISC_MSG_GETDESTADDR,
620118e757roberto					       "%s: getting "
621118e757roberto					       "destination address: %s"),
622118e757roberto					 ifreq.ifr_name, strbuf);
623118e757roberto			return (ISC_R_IGNORE);
624118e757roberto		}
625118e757roberto		get_addr(family, &iter->current.dstaddress,
6267a6072eroberto			 (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name);
627118e757roberto	}
6287a6072eroberto#endif
629d54cfbdroberto
630118e757roberto	if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
631118e757roberto		/*
632118e757roberto		 * Ignore the HP/UX warning about "integer overflow during
633118e757roberto		 * conversion.  It comes from its own macro definition,
634118e757roberto		 * and is really hard to shut up.
635118e757roberto		 */
636047f369cy		if (isc_ioctl(iter->socket, SIOCGIFBRDADDR, (char *)&ifreq)
637118e757roberto		    < 0) {
638118e757roberto			isc__strerror(errno, strbuf, sizeof(strbuf));
639118e757roberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
640118e757roberto				isc_msgcat_get(isc_msgcat,
641118e757roberto					       ISC_MSGSET_IFITERIOCTL,
642d54cfbdroberto					       ISC_MSG_GETBCSTADDR,
643118e757roberto					       "%s: getting "
644118e757roberto					       "broadcast address: %s"),
645118e757roberto					 ifreq.ifr_name, strbuf);
646118e757roberto			return (ISC_R_IGNORE);
647118e757roberto		}
648118e757roberto		get_addr(family, &iter->current.broadcast,
6497a6072eroberto			 (struct sockaddr *)&ifreq.ifr_broadaddr, ifreq.ifr_name);
650118e757roberto	}
6517a6072eroberto
652118e757roberto	/*
653118e757roberto	 * Get the network mask.
654118e757roberto	 */
655118e757roberto	memset(&ifreq, 0, sizeof(ifreq));
656118e757roberto	memcpy(&ifreq, ifrp, sizeof(ifreq));
657118e757roberto	/*
658118e757roberto	 * Ignore the HP/UX warning about "integer overflow during
659118e757roberto	 * conversion.  It comes from its own macro definition,
660118e757roberto	 * and is really hard to shut up.
661118e757roberto	 */
662047f369cy	if (isc_ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
663118e757roberto		isc__strerror(errno, strbuf, sizeof(strbuf));
664118e757roberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
665118e757roberto			isc_msgcat_get(isc_msgcat,
666118e757roberto				       ISC_MSGSET_IFITERIOCTL,
667118e757roberto				       ISC_MSG_GETNETMASK,
668118e757roberto				       "%s: getting netmask: %s"),
669118e757roberto				       ifreq.ifr_name, strbuf);
670118e757roberto		return (ISC_R_IGNORE);
671118e757roberto	}
672118e757roberto	get_addr(family, &iter->current.netmask,
6737a6072eroberto		 (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name);
674f63afe2cy#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
675f63afe2cy	iter->current.ifindex = if_nametoindex(iter->current.name);
676f63afe2cy#endif
677118e757roberto	return (ISC_R_SUCCESS);
678118e757roberto}
679118e757roberto
6807a6072eroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
681118e757robertostatic isc_result_t
682118e757robertointernal_current6(isc_interfaceiter_t *iter) {
683118e757roberto	struct LIFREQ *ifrp;
684118e757roberto	struct LIFREQ lifreq;
685118e757roberto	int family;
686118e757roberto	char strbuf[ISC_STRERRORSIZE];
6877a6072eroberto	int fd;
688118e757roberto
689118e757roberto	REQUIRE(VALID_IFITER(iter));
6907a6072eroberto	if (iter->result6 != ISC_R_SUCCESS)
6917a6072eroberto		return (iter->result6);
6927a6072eroberto	REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
693118e757roberto
694047f369cy	ifrp = (void *)((char *)iter->lifc.lifc_req + iter->pos6);
695118e757roberto
696118e757roberto	memset(&lifreq, 0, sizeof(lifreq));
697118e757roberto	memcpy(&lifreq, ifrp, sizeof(lifreq));
698118e757roberto
699118e757roberto	family = lifreq.lifr_addr.ss_family;
700118e757roberto#ifdef ISC_PLATFORM_HAVEIPV6
701118e757roberto	if (family != AF_INET && family != AF_INET6)
702118e757roberto#else
703118e757roberto	if (family != AF_INET)
704118e757roberto#endif
705118e757roberto		return (ISC_R_IGNORE);
706118e757roberto
707118e757roberto	memset(&iter->current, 0, sizeof(iter->current));
708118e757roberto	iter->current.af = family;
709118e757roberto
710118e757roberto	INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name));
711118e757roberto	memset(iter->current.name, 0, sizeof(iter->current.name));
712118e757roberto	memcpy(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name));
713118e757roberto
714118e757roberto	get_addr(family, &iter->current.address,
7157a6072eroberto		 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
716118e757roberto
717d54cfbdroberto	if (isc_netaddr_islinklocal(&iter->current.address))
718d54cfbdroberto		isc_netaddr_setzone(&iter->current.address,
719d54cfbdroberto				    (isc_uint32_t)lifreq.lifr_index);
720d54cfbdroberto
721118e757roberto	/*
722118e757roberto	 * If the interface does not have a address ignore it.
723118e757roberto	 */
724118e757roberto	switch (family) {
725118e757roberto	case AF_INET:
726118e757roberto		if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
727118e757roberto			return (ISC_R_IGNORE);
728118e757roberto		break;
729118e757roberto	case AF_INET6:
730118e757roberto		if (memcmp(&iter->current.address.type.in6, &in6addr_any,
731118e757roberto			   sizeof(in6addr_any)) == 0)
732118e757roberto			return (ISC_R_IGNORE);
733118e757roberto		break;
734118e757roberto	}
735118e757roberto
736118e757roberto	/*
737118e757roberto	 * Get interface flags.
738118e757roberto	 */
739118e757roberto
740118e757roberto	iter->current.flags = 0;
741118e757roberto
7427a6072eroberto	if (family == AF_INET6)
7437a6072eroberto		fd = iter->socket6;
7447a6072eroberto	else
7457a6072eroberto		fd = iter->socket;
7467a6072eroberto
747118e757roberto	/*
748118e757roberto	 * Ignore the HP/UX warning about "integer overflow during
749118e757roberto	 * conversion.  It comes from its own macro definition,
750118e757roberto	 * and is really hard to shut up.
751118e757roberto	 */
752047f369cy	if (isc_ioctl(fd, SIOCGLIFFLAGS, (char *) &lifreq) < 0) {
7537a6072eroberto		isc__strerror(errno, strbuf, sizeof(strbuf));
7547a6072eroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
755118e757roberto				 "%s: getting interface flags: %s",
756118e757roberto				 lifreq.lifr_name, strbuf);
7577a6072eroberto		return (ISC_R_IGNORE);
758118e757roberto	}
759118e757roberto
760118e757roberto	if ((lifreq.lifr_flags & IFF_UP) != 0)
761118e757roberto		iter->current.flags |= INTERFACE_F_UP;
762118e757roberto
7637a6072eroberto#ifdef IFF_POINTOPOINT
764118e757roberto	if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0)
765118e757roberto		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
7667a6072eroberto#endif
767118e757roberto
768118e757roberto	if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0)
769118e757roberto		iter->current.flags |= INTERFACE_F_LOOPBACK;
770118e757roberto
7717a6072eroberto	if ((lifreq.lifr_flags & IFF_BROADCAST) != 0) {
7727a6072eroberto		iter->current.flags |= INTERFACE_F_BROADCAST;
7737a6072eroberto	}
774118e757roberto
775118e757roberto#ifdef IFF_MULTICAST
776118e757roberto	if ((lifreq.lifr_flags & IFF_MULTICAST) != 0) {
777118e757roberto		iter->current.flags |= INTERFACE_F_MULTICAST;
778118e757roberto	}
779118e757roberto#endif
780118e757roberto
7817a6072eroberto#ifdef IFF_POINTOPOINT
782118e757roberto	/*
783118e757roberto	 * If the interface is point-to-point, get the destination address.
784118e757roberto	 */
785118e757roberto	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
786118e757roberto		/*
787d54cfbdroberto		 * Ignore the HP/UX warning about "integer overflow during
788118e757roberto		 * conversion.  It comes from its own macro definition,
789118e757roberto		 * and is really hard to shut up.
790118e757roberto		 */
791047f369cy		if (isc_ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq)
792118e757roberto		    < 0) {
793118e757roberto			isc__strerror(errno, strbuf, sizeof(strbuf));
794118e757roberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
795118e757roberto				isc_msgcat_get(isc_msgcat,
796118e757roberto					       ISC_MSGSET_IFITERIOCTL,
797118e757roberto					       ISC_MSG_GETDESTADDR,
798118e757roberto					       "%s: getting "
799118e757roberto					       "destination address: %s"),
800118e757roberto					 lifreq.lifr_name, strbuf);
801118e757roberto			return (ISC_R_IGNORE);
802118e757roberto		}
803118e757roberto		get_addr(family, &iter->current.dstaddress,
8047a6072eroberto			 (struct sockaddr *)&lifreq.lifr_dstaddr,
8057a6072eroberto			 lifreq.lifr_name);
806118e757roberto	}
8077a6072eroberto#endif
808118e757roberto
8097a6072eroberto#ifdef SIOCGLIFBRDADDR
8107a6072eroberto	if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
811118e757roberto		/*
812118e757roberto		 * Ignore the HP/UX warning about "integer overflow during
813118e757roberto		 * conversion.  It comes from its own macro definition,
814118e757roberto		 * and is really hard to shut up.
815118e757roberto		 */
816047f369cy		if (isc_ioctl(iter->socket, SIOCGLIFBRDADDR, (char *)&lifreq)
817118e757roberto		    < 0) {
818118e757roberto			isc__strerror(errno, strbuf, sizeof(strbuf));
819118e757roberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
820118e757roberto				isc_msgcat_get(isc_msgcat,
821118e757roberto					       ISC_MSGSET_IFITERIOCTL,
822d54cfbdroberto					       ISC_MSG_GETBCSTADDR,
8237a6072eroberto					       "%s: getting "
8247a6072eroberto					       "broadcast address: %s"),
825118e757roberto					 lifreq.lifr_name, strbuf);
826118e757roberto			return (ISC_R_IGNORE);
827118e757roberto		}
8287a6072eroberto		get_addr(family, &iter->current.broadcast,
8297a6072eroberto			 (struct sockaddr *)&lifreq.lifr_broadaddr,
8307a6072eroberto			 lifreq.lifr_name);
8317a6072eroberto	}
8327a6072eroberto#endif	/* SIOCGLIFBRDADDR */
8337a6072eroberto
8347a6072eroberto	/*
8357a6072eroberto	 * Get the network mask.  Netmask already zeroed.
8367a6072eroberto	 */
8377a6072eroberto	memset(&lifreq, 0, sizeof(lifreq));
8387a6072eroberto	memcpy(&lifreq, ifrp, sizeof(lifreq));
8397a6072eroberto
840118e757roberto#ifdef lifr_addrlen
8417a6072eroberto	/*
8427a6072eroberto	 * Special case: if the system provides lifr_addrlen member, the
8437a6072eroberto	 * netmask of an IPv6 address can be derived from the length, since
8447a6072eroberto	 * an IPv6 address always has a contiguous mask.
8457a6072eroberto	 */
8467a6072eroberto	if (family == AF_INET6) {
847118e757roberto		int i, bits;
848118e757roberto
849118e757roberto		iter->current.netmask.family = family;
850118e757roberto		for (i = 0; i < lifreq.lifr_addrlen; i += 8) {
851118e757roberto			bits = lifreq.lifr_addrlen - i;
852118e757roberto			bits = (bits < 8) ? (8 - bits) : 0;
853118e757roberto			iter->current.netmask.type.in6.s6_addr[i / 8] =
854118e757roberto				(~0 << bits) & 0xff;
855118e757roberto		}
856f63afe2cy#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
857f63afe2cy		iter->current.ifindex = if_nametoindex(iter->current.name);
858f63afe2cy#endif
8597a6072eroberto		return (ISC_R_SUCCESS);
860118e757roberto	}
8617a6072eroberto#endif
8627a6072eroberto
8637a6072eroberto	/*
8647a6072eroberto	 * Ignore the HP/UX warning about "integer overflow during
8657a6072eroberto	 * conversion.  It comes from its own macro definition,
8667a6072eroberto	 * and is really hard to shut up.
8677a6072eroberto	 */
868047f369cy	if (isc_ioctl(fd, SIOCGLIFNETMASK, (char *)&lifreq) < 0) {
8697a6072eroberto		isc__strerror(errno, strbuf, sizeof(strbuf));
8707a6072eroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
8717a6072eroberto				 isc_msgcat_get(isc_msgcat,
8727a6072eroberto						ISC_MSGSET_IFITERIOCTL,
8737a6072eroberto						ISC_MSG_GETNETMASK,
8747a6072eroberto						"%s: getting netmask: %s"),
8757a6072eroberto				 lifreq.lifr_name, strbuf);
8767a6072eroberto		return (ISC_R_IGNORE);
877118e757roberto	}
8787a6072eroberto	get_addr(family, &iter->current.netmask,
8797a6072eroberto		 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
880118e757roberto
881f63afe2cy#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
882f63afe2cy	iter->current.ifindex = if_nametoindex(iter->current.name);
883f63afe2cy#endif
884118e757roberto	return (ISC_R_SUCCESS);
885118e757roberto}
8867a6072eroberto#endif
887118e757roberto
888118e757robertostatic isc_result_t
889118e757robertointernal_current(isc_interfaceiter_t *iter) {
8907a6072eroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
8917a6072eroberto	if (iter->mode == 6) {
8927a6072eroberto		iter->result6 = internal_current6(iter);
8937a6072eroberto		if (iter->result6 != ISC_R_NOMORE)
8947a6072eroberto			return (iter->result6);
8957a6072eroberto	}
8967a6072eroberto#endif
8977a6072eroberto#ifdef HAVE_TRUCLUSTER
8987a6072eroberto	if (!iter->clua_done)
8997a6072eroberto		return(internal_current_clusteralias(iter));
9007a6072eroberto#endif
901118e757roberto	return (internal_current4(iter));
902118e757roberto}
903118e757roberto
904118e757roberto/*
905118e757roberto * Step the iterator to the next interface.  Unlike
906118e757roberto * isc_interfaceiter_next(), this may leave the iterator
907118e757roberto * positioned on an interface that will ultimately
908118e757roberto * be ignored.  Return ISC_R_NOMORE if there are no more
909118e757roberto * interfaces, otherwise ISC_R_SUCCESS.
910118e757roberto */
911118e757robertostatic isc_result_t
912118e757robertointernal_next4(isc_interfaceiter_t *iter) {
913d54cfbdroberto#ifdef ISC_PLATFORM_HAVESALEN
914118e757roberto	struct ifreq *ifrp;
915118e757roberto#endif
916118e757roberto
917d54cfbdroberto	if (iter->pos < (unsigned int) iter->ifc.ifc_len) {
918118e757roberto#ifdef ISC_PLATFORM_HAVESALEN
919d54cfbdroberto		ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
920d54cfbdroberto
921d54cfbdroberto		if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
922d54cfbdroberto			iter->pos += sizeof(ifrp->ifr_name) +
923d54cfbdroberto				     ifrp->ifr_addr.sa_len;
924d54cfbdroberto		else
925118e757roberto#endif
926d54cfbdroberto			iter->pos += sizeof(struct ifreq);
927118e757roberto
928d54cfbdroberto	} else {
929d54cfbdroberto		INSIST(iter->pos == (unsigned int) iter->ifc.ifc_len);
930d54cfbdroberto#ifdef __linux
931d54cfbdroberto		return (linux_if_inet6_next(iter));
932d54cfbdroberto#else
933118e757roberto		return (ISC_R_NOMORE);
934d54cfbdroberto#endif
935d54cfbdroberto	}
936118e757roberto	return (ISC_R_SUCCESS);
937118e757roberto}
938118e757roberto
9397a6072eroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
940118e757robertostatic isc_result_t
941118e757robertointernal_next6(isc_interfaceiter_t *iter) {
942d54cfbdroberto#ifdef ISC_PLATFORM_HAVESALEN
943118e757roberto	struct LIFREQ *ifrp;
944d54cfbdroberto#endif
945d54cfbdroberto
9467a6072eroberto	if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE)
9477a6072eroberto		return (iter->result6);
948118e757roberto
9497a6072eroberto	REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
950118e757roberto
951d54cfbdroberto#ifdef ISC_PLATFORM_HAVESALEN
9527a6072eroberto	ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
953118e757roberto
954118e757roberto	if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr))
9557a6072eroberto		iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len;
956118e757roberto	else
957118e757roberto#endif
958d54cfbdroberto		iter->pos6 += sizeof(struct LIFREQ);
959118e757roberto
9607a6072eroberto	if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len)
961118e757roberto		return (ISC_R_NOMORE);
962118e757roberto
963118e757roberto	return (ISC_R_SUCCESS);
964118e757roberto}
9657a6072eroberto#endif
966118e757roberto
967118e757robertostatic isc_result_t
968118e757robertointernal_next(isc_interfaceiter_t *iter) {
9697a6072eroberto#ifdef HAVE_TRUCLUSTER
9707a6072eroberto	int clua_result;
9717a6072eroberto#endif
9727a6072eroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
9737a6072eroberto	if (iter->mode == 6) {
9747a6072eroberto		iter->result6 = internal_next6(iter);
9757a6072eroberto		if (iter->result6 != ISC_R_NOMORE)
9767a6072eroberto			return (iter->result6);
9777a6072eroberto		if (iter->first6) {
9787a6072eroberto			iter->first6 = ISC_FALSE;
9797a6072eroberto			return (ISC_R_SUCCESS);
9807a6072eroberto		}
9817a6072eroberto	}
9827a6072eroberto#endif
9837a6072eroberto#ifdef HAVE_TRUCLUSTER
9847a6072eroberto	if (!iter->clua_done) {
9857a6072eroberto		clua_result = clua_getaliasaddress(&iter->clua_sa,
9867a6072eroberto						   &iter->clua_context);
9877a6072eroberto		if (clua_result != CLUA_SUCCESS)
9887a6072eroberto			iter->clua_done = ISC_TRUE;
9897a6072eroberto		return (ISC_R_SUCCESS);
9907a6072eroberto	}
9917a6072eroberto#endif
992118e757roberto	return (internal_next4(iter));
993118e757roberto}
994118e757roberto
995118e757robertostatic void
996118e757robertointernal_destroy(isc_interfaceiter_t *iter) {
997118e757roberto	(void) close(iter->socket);
9987a6072eroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
9997a6072eroberto	if (iter->socket6 != -1)
10007a6072eroberto		(void) close(iter->socket6);
10017a6072eroberto	if (iter->buf6 != NULL) {
10027a6072eroberto		isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
10037a6072eroberto	}
10047a6072eroberto#endif
10057a6072eroberto#ifdef __linux
10067a6072eroberto	if (iter->proc != NULL)
10077a6072eroberto		fclose(iter->proc);
10087a6072eroberto#endif
10097a6072eroberto}
10107a6072eroberto
10117a6072erobertostatic
10127a6072erobertovoid internal_first(isc_interfaceiter_t *iter) {
10137a6072eroberto#ifdef HAVE_TRUCLUSTER
10147a6072eroberto	int clua_result;
10157a6072eroberto#endif
10167a6072eroberto	iter->pos = 0;
10177a6072eroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
10187a6072eroberto	iter->pos6 = 0;
10197a6072eroberto	if (iter->result6 == ISC_R_NOMORE)
10207a6072eroberto		iter->result6 = ISC_R_SUCCESS;
10217a6072eroberto	iter->first6 = ISC_TRUE;
10227a6072eroberto#endif
10237a6072eroberto#ifdef HAVE_TRUCLUSTER
10247a6072eroberto	iter->clua_context = 0;
10257a6072eroberto	clua_result = clua_getaliasaddress(&iter->clua_sa,
10267a6072eroberto					   &iter->clua_context);
10277a6072eroberto	iter->clua_done = ISC_TF(clua_result != CLUA_SUCCESS);
10287a6072eroberto#endif
10297a6072eroberto#ifdef __linux
10307a6072eroberto	linux_if_inet6_first(iter);
10317a6072eroberto#endif
1032118e757roberto}
1033