1258945Sroberto/*
2258945Sroberto * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
3258945Sroberto * Copyright (C) 1999-2003  Internet Software Consortium.
4258945Sroberto *
5258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any
6258945Sroberto * purpose with or without fee is hereby granted, provided that the above
7258945Sroberto * copyright notice and this permission notice appear in all copies.
8258945Sroberto *
9258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11258945Sroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15258945Sroberto * PERFORMANCE OF THIS SOFTWARE.
16258945Sroberto */
17258945Sroberto
18280849Scy/* $Id: ifiter_ioctl.c,v 1.62 2009/01/18 23:48:14 tbox Exp $ */
19258945Sroberto
20258945Sroberto/*! \file
21258945Sroberto * \brief
22258945Sroberto * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl.
23258945Sroberto * See netintro(4).
24258945Sroberto */
25258945Sroberto
26258945Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
27258945Sroberto#ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
28258945Sroberto#define lifc_len iflc_len
29258945Sroberto#define lifc_buf iflc_buf
30258945Sroberto#define lifc_req iflc_req
31258945Sroberto#define LIFCONF if_laddrconf
32258945Sroberto#else
33258945Sroberto#define ISC_HAVE_LIFC_FAMILY 1
34258945Sroberto#define ISC_HAVE_LIFC_FLAGS 1
35258945Sroberto#define LIFCONF lifconf
36258945Sroberto#endif
37258945Sroberto
38258945Sroberto#ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
39258945Sroberto#define lifr_addr iflr_addr
40258945Sroberto#define lifr_name iflr_name
41258945Sroberto#define lifr_dstaddr iflr_dstaddr
42258945Sroberto#define lifr_broadaddr iflr_broadaddr
43258945Sroberto#define lifr_flags iflr_flags
44258945Sroberto#define lifr_index iflr_index
45258945Sroberto#define ss_family sa_family
46258945Sroberto#define LIFREQ if_laddrreq
47258945Sroberto#else
48258945Sroberto#define LIFREQ lifreq
49258945Sroberto#endif
50258945Sroberto#endif
51258945Sroberto
52258945Sroberto#define IFITER_MAGIC		ISC_MAGIC('I', 'F', 'I', 'T')
53258945Sroberto#define VALID_IFITER(t)		ISC_MAGIC_VALID(t, IFITER_MAGIC)
54258945Sroberto
55258945Srobertostruct isc_interfaceiter {
56258945Sroberto	unsigned int		magic;		/* Magic number. */
57258945Sroberto	isc_mem_t		*mctx;
58258945Sroberto	int			mode;
59258945Sroberto	int			socket;
60258945Sroberto	struct ifconf 		ifc;
61258945Sroberto	void			*buf;		/* Buffer for sysctl data. */
62258945Sroberto	unsigned int		bufsize;	/* Bytes allocated. */
63258945Sroberto	unsigned int		pos;		/* Current offset in
64258945Sroberto						   SIOCGIFCONF data */
65258945Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
66258945Sroberto	int			socket6;
67258945Sroberto	struct LIFCONF 		lifc;
68258945Sroberto	void			*buf6;		/* Buffer for sysctl data. */
69258945Sroberto	unsigned int		bufsize6;	/* Bytes allocated. */
70258945Sroberto	unsigned int		pos6;		/* Current offset in
71258945Sroberto						   SIOCGLIFCONF data */
72258945Sroberto	isc_result_t		result6;	/* Last result code. */
73258945Sroberto	isc_boolean_t		first6;
74258945Sroberto#endif
75258945Sroberto#ifdef HAVE_TRUCLUSTER
76258945Sroberto	int			clua_context;	/* Cluster alias context */
77258945Sroberto	isc_boolean_t		clua_done;
78258945Sroberto	struct sockaddr		clua_sa;
79258945Sroberto#endif
80258945Sroberto#ifdef	__linux
81258945Sroberto	FILE *			proc;
82258945Sroberto	char			entry[ISC_IF_INET6_SZ];
83258945Sroberto	isc_result_t		valid;
84258945Sroberto#endif
85258945Sroberto	isc_interface_t		current;	/* Current interface data. */
86258945Sroberto	isc_result_t		result;		/* Last result code. */
87258945Sroberto};
88258945Sroberto
89258945Sroberto#ifdef HAVE_TRUCLUSTER
90258945Sroberto#include <clua/clua.h>
91258945Sroberto#include <sys/socket.h>
92258945Sroberto#endif
93258945Sroberto
94258945Sroberto
95258945Sroberto/*%
96258945Sroberto * Size of buffer for SIOCGLIFCONF, in bytes.  We assume no sane system
97258945Sroberto * will have more than a megabyte of interface configuration data.
98258945Sroberto */
99258945Sroberto#define IFCONF_BUFSIZE_INITIAL	4096
100258945Sroberto#define IFCONF_BUFSIZE_MAX	1048576
101258945Sroberto
102258945Sroberto#ifdef __linux
103258945Sroberto#ifndef IF_NAMESIZE
104258945Sroberto# ifdef IFNAMSIZ
105258945Sroberto#  define IF_NAMESIZE  IFNAMSIZ
106258945Sroberto# else
107258945Sroberto#  define IF_NAMESIZE 16
108258945Sroberto# endif
109258945Sroberto#endif
110258945Sroberto#endif
111258945Sroberto
112282408Scy/* Silence a warning when this file is #included */
113280849Scyint
114282408Scyisc_ioctl(int fildes, int req, char *arg);
115282408Scy
116282408Scyint
117280849Scyisc_ioctl(int fildes, int req, char *arg) {
118280849Scy	int trys;
119280849Scy	int ret;
120280849Scy
121280849Scy	for (trys = 0; trys < 3; trys++) {
122280849Scy		if ((ret = ioctl(fildes, req, arg)) < 0) {
123280849Scy			if (errno == EINTR)
124280849Scy				continue;
125280849Scy		}
126280849Scy		break;
127280849Scy	}
128280849Scy	return (ret);
129280849Scy}
130280849Scy
131258945Srobertostatic isc_result_t
132258945Srobertogetbuf4(isc_interfaceiter_t *iter) {
133258945Sroberto	char strbuf[ISC_STRERRORSIZE];
134258945Sroberto
135258945Sroberto	iter->bufsize = IFCONF_BUFSIZE_INITIAL;
136258945Sroberto
137258945Sroberto	for (;;) {
138258945Sroberto		iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
139258945Sroberto		if (iter->buf == NULL)
140258945Sroberto			return (ISC_R_NOMEMORY);
141258945Sroberto
142258945Sroberto		memset(&iter->ifc.ifc_len, 0, sizeof(iter->ifc.ifc_len));
143258945Sroberto		iter->ifc.ifc_len = iter->bufsize;
144258945Sroberto		iter->ifc.ifc_buf = iter->buf;
145258945Sroberto		/*
146258945Sroberto		 * Ignore the HP/UX warning about "integer overflow during
147258945Sroberto		 * conversion".  It comes from its own macro definition,
148258945Sroberto		 * and is really hard to shut up.
149258945Sroberto		 */
150280849Scy		if (isc_ioctl(iter->socket, SIOCGIFCONF, (char *)&iter->ifc)
151258945Sroberto		    == -1) {
152258945Sroberto			if (errno != EINVAL) {
153258945Sroberto				isc__strerror(errno, strbuf, sizeof(strbuf));
154258945Sroberto				UNEXPECTED_ERROR(__FILE__, __LINE__,
155258945Sroberto						 isc_msgcat_get(isc_msgcat,
156258945Sroberto							ISC_MSGSET_IFITERIOCTL,
157258945Sroberto							ISC_MSG_GETIFCONFIG,
158258945Sroberto							"get interface "
159258945Sroberto							"configuration: %s"),
160258945Sroberto						 strbuf);
161258945Sroberto				goto unexpected;
162258945Sroberto			}
163258945Sroberto			/*
164258945Sroberto			 * EINVAL.  Retry with a bigger buffer.
165258945Sroberto			 */
166258945Sroberto		} else {
167258945Sroberto			/*
168258945Sroberto			 * The ioctl succeeded.
169258945Sroberto			 * Some OS's just return what will fit rather
170258945Sroberto			 * than set EINVAL if the buffer is too small
171258945Sroberto			 * to fit all the interfaces in.  If
172258945Sroberto			 * ifc.lifc_len is too near to the end of the
173258945Sroberto			 * buffer we will grow it just in case and
174258945Sroberto			 * retry.
175258945Sroberto			 */
176258945Sroberto			if (iter->ifc.ifc_len + 2 * sizeof(struct ifreq)
177258945Sroberto			    < iter->bufsize)
178258945Sroberto				break;
179258945Sroberto		}
180258945Sroberto		if (iter->bufsize >= IFCONF_BUFSIZE_MAX) {
181258945Sroberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
182258945Sroberto					 isc_msgcat_get(isc_msgcat,
183258945Sroberto							ISC_MSGSET_IFITERIOCTL,
184258945Sroberto							ISC_MSG_BUFFERMAX,
185258945Sroberto							"get interface "
186258945Sroberto							"configuration: "
187258945Sroberto							"maximum buffer "
188258945Sroberto							"size exceeded"));
189258945Sroberto			goto unexpected;
190258945Sroberto		}
191258945Sroberto		isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
192258945Sroberto
193258945Sroberto		iter->bufsize *= 2;
194258945Sroberto	}
195258945Sroberto	return (ISC_R_SUCCESS);
196258945Sroberto
197258945Sroberto unexpected:
198258945Sroberto	isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
199258945Sroberto	iter->buf = NULL;
200258945Sroberto	return (ISC_R_UNEXPECTED);
201258945Sroberto}
202258945Sroberto
203258945Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
204258945Srobertostatic isc_result_t
205258945Srobertogetbuf6(isc_interfaceiter_t *iter) {
206258945Sroberto	char strbuf[ISC_STRERRORSIZE];
207258945Sroberto	isc_result_t result;
208258945Sroberto
209258945Sroberto	iter->bufsize6 = IFCONF_BUFSIZE_INITIAL;
210258945Sroberto
211258945Sroberto	for (;;) {
212258945Sroberto		iter->buf6 = isc_mem_get(iter->mctx, iter->bufsize6);
213258945Sroberto		if (iter->buf6 == NULL)
214258945Sroberto			return (ISC_R_NOMEMORY);
215258945Sroberto
216258945Sroberto		memset(&iter->lifc, 0, sizeof(iter->lifc));
217258945Sroberto#ifdef ISC_HAVE_LIFC_FAMILY
218258945Sroberto		iter->lifc.lifc_family = AF_INET6;
219258945Sroberto#endif
220258945Sroberto#ifdef ISC_HAVE_LIFC_FLAGS
221258945Sroberto		iter->lifc.lifc_flags = 0;
222258945Sroberto#endif
223258945Sroberto		iter->lifc.lifc_len = iter->bufsize6;
224258945Sroberto		iter->lifc.lifc_buf = iter->buf6;
225258945Sroberto		/*
226258945Sroberto		 * Ignore the HP/UX warning about "integer overflow during
227258945Sroberto		 * conversion".  It comes from its own macro definition,
228258945Sroberto		 * and is really hard to shut up.
229258945Sroberto		 */
230280849Scy		if (isc_ioctl(iter->socket6, SIOCGLIFCONF, (char *)&iter->lifc)
231258945Sroberto		    == -1) {
232258945Sroberto#ifdef __hpux
233258945Sroberto			/*
234258945Sroberto			 * IPv6 interface scanning is not available on all
235258945Sroberto			 * kernels w/ IPv6 sockets.
236258945Sroberto			 */
237258945Sroberto			if (errno == ENOENT) {
238258945Sroberto				isc__strerror(errno, strbuf, sizeof(strbuf));
239258945Sroberto				isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
240258945Sroberto					      ISC_LOGMODULE_INTERFACE,
241258945Sroberto					      ISC_LOG_DEBUG(1),
242258945Sroberto					      isc_msgcat_get(isc_msgcat,
243258945Sroberto							ISC_MSGSET_IFITERIOCTL,
244258945Sroberto							ISC_MSG_GETIFCONFIG,
245258945Sroberto							"get interface "
246258945Sroberto							"configuration: %s"),
247258945Sroberto					       strbuf);
248258945Sroberto				result = ISC_R_FAILURE;
249258945Sroberto				goto cleanup;
250258945Sroberto			}
251258945Sroberto#endif
252258945Sroberto			if (errno != EINVAL) {
253258945Sroberto				isc__strerror(errno, strbuf, sizeof(strbuf));
254258945Sroberto				UNEXPECTED_ERROR(__FILE__, __LINE__,
255258945Sroberto						 isc_msgcat_get(isc_msgcat,
256258945Sroberto							ISC_MSGSET_IFITERIOCTL,
257258945Sroberto							ISC_MSG_GETIFCONFIG,
258258945Sroberto							"get interface "
259258945Sroberto							"configuration: %s"),
260258945Sroberto						 strbuf);
261258945Sroberto				result = ISC_R_UNEXPECTED;
262258945Sroberto				goto cleanup;
263258945Sroberto			}
264258945Sroberto			/*
265258945Sroberto			 * EINVAL.  Retry with a bigger buffer.
266258945Sroberto			 */
267258945Sroberto		} else {
268258945Sroberto			/*
269258945Sroberto			 * The ioctl succeeded.
270258945Sroberto			 * Some OS's just return what will fit rather
271258945Sroberto			 * than set EINVAL if the buffer is too small
272258945Sroberto			 * to fit all the interfaces in.  If
273258945Sroberto			 * ifc.ifc_len is too near to the end of the
274258945Sroberto			 * buffer we will grow it just in case and
275258945Sroberto			 * retry.
276258945Sroberto			 */
277258945Sroberto			if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ)
278258945Sroberto			    < iter->bufsize6)
279258945Sroberto				break;
280258945Sroberto		}
281258945Sroberto		if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) {
282258945Sroberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
283258945Sroberto					 isc_msgcat_get(isc_msgcat,
284258945Sroberto							ISC_MSGSET_IFITERIOCTL,
285258945Sroberto							ISC_MSG_BUFFERMAX,
286258945Sroberto							"get interface "
287258945Sroberto							"configuration: "
288258945Sroberto							"maximum buffer "
289258945Sroberto							"size exceeded"));
290258945Sroberto			result = ISC_R_UNEXPECTED;
291258945Sroberto			goto cleanup;
292258945Sroberto		}
293258945Sroberto		isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
294258945Sroberto
295258945Sroberto		iter->bufsize6 *= 2;
296258945Sroberto	}
297258945Sroberto
298258945Sroberto	if (iter->lifc.lifc_len != 0)
299258945Sroberto		iter->mode = 6;
300258945Sroberto	return (ISC_R_SUCCESS);
301258945Sroberto
302258945Sroberto cleanup:
303258945Sroberto	isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
304258945Sroberto	iter->buf6 = NULL;
305258945Sroberto	return (result);
306258945Sroberto}
307258945Sroberto#endif
308258945Sroberto
309258945Srobertoisc_result_t
310258945Srobertoisc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
311258945Sroberto	isc_interfaceiter_t *iter;
312258945Sroberto	isc_result_t result;
313258945Sroberto	char strbuf[ISC_STRERRORSIZE];
314258945Sroberto
315258945Sroberto	REQUIRE(mctx != NULL);
316258945Sroberto	REQUIRE(iterp != NULL);
317258945Sroberto	REQUIRE(*iterp == NULL);
318258945Sroberto
319258945Sroberto	iter = isc_mem_get(mctx, sizeof(*iter));
320258945Sroberto	if (iter == NULL)
321258945Sroberto		return (ISC_R_NOMEMORY);
322258945Sroberto
323258945Sroberto	iter->mctx = mctx;
324258945Sroberto	iter->mode = 4;
325258945Sroberto	iter->buf = NULL;
326258945Sroberto	iter->pos = (unsigned int) -1;
327258945Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
328258945Sroberto	iter->buf6 = NULL;
329258945Sroberto	iter->pos6 = (unsigned int) -1;
330258945Sroberto	iter->result6 = ISC_R_NOMORE;
331258945Sroberto	iter->socket6 = -1;
332258945Sroberto	iter->first6 = ISC_FALSE;
333258945Sroberto#endif
334258945Sroberto
335258945Sroberto	/*
336258945Sroberto	 * Get the interface configuration, allocating more memory if
337258945Sroberto	 * necessary.
338258945Sroberto	 */
339258945Sroberto
340258945Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
341258945Sroberto	result = isc_net_probeipv6();
342258945Sroberto	if (result == ISC_R_SUCCESS) {
343258945Sroberto		/*
344258945Sroberto		 * Create an unbound datagram socket to do the SIOCGLIFCONF
345258945Sroberto		 * ioctl on.  HP/UX requires an AF_INET6 socket for
346258945Sroberto		 * SIOCGLIFCONF to get IPv6 addresses.
347258945Sroberto		 */
348258945Sroberto		if ((iter->socket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
349258945Sroberto			isc__strerror(errno, strbuf, sizeof(strbuf));
350258945Sroberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
351258945Sroberto					 isc_msgcat_get(isc_msgcat,
352258945Sroberto							ISC_MSGSET_IFITERIOCTL,
353258945Sroberto							ISC_MSG_MAKESCANSOCKET,
354258945Sroberto							"making interface "
355258945Sroberto							"scan socket: %s"),
356258945Sroberto					 strbuf);
357258945Sroberto			result = ISC_R_UNEXPECTED;
358258945Sroberto			goto socket6_failure;
359258945Sroberto		}
360258945Sroberto		result = iter->result6 = getbuf6(iter);
361258945Sroberto		if (result != ISC_R_NOTIMPLEMENTED && result != ISC_R_SUCCESS)
362258945Sroberto			goto ioctl6_failure;
363258945Sroberto	}
364258945Sroberto#endif
365258945Sroberto	if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
366258945Sroberto		isc__strerror(errno, strbuf, sizeof(strbuf));
367258945Sroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
368258945Sroberto				 isc_msgcat_get(isc_msgcat,
369258945Sroberto						ISC_MSGSET_IFITERIOCTL,
370258945Sroberto						ISC_MSG_MAKESCANSOCKET,
371258945Sroberto						"making interface "
372258945Sroberto						"scan socket: %s"),
373258945Sroberto				 strbuf);
374258945Sroberto		result = ISC_R_UNEXPECTED;
375258945Sroberto		goto socket_failure;
376258945Sroberto	}
377258945Sroberto	result = getbuf4(iter);
378258945Sroberto	if (result != ISC_R_SUCCESS)
379258945Sroberto		goto ioctl_failure;
380258945Sroberto
381258945Sroberto	/*
382258945Sroberto	 * A newly created iterator has an undefined position
383258945Sroberto	 * until isc_interfaceiter_first() is called.
384258945Sroberto	 */
385258945Sroberto#ifdef HAVE_TRUCLUSTER
386258945Sroberto	iter->clua_context = -1;
387258945Sroberto	iter->clua_done = ISC_TRUE;
388258945Sroberto#endif
389258945Sroberto#ifdef __linux
390258945Sroberto	iter->proc = fopen("/proc/net/if_inet6", "r");
391258945Sroberto	iter->valid = ISC_R_FAILURE;
392258945Sroberto#endif
393258945Sroberto	iter->result = ISC_R_FAILURE;
394258945Sroberto
395258945Sroberto	iter->magic = IFITER_MAGIC;
396258945Sroberto	*iterp = iter;
397258945Sroberto	return (ISC_R_SUCCESS);
398258945Sroberto
399258945Sroberto ioctl_failure:
400258945Sroberto	if (iter->buf != NULL)
401258945Sroberto		isc_mem_put(mctx, iter->buf, iter->bufsize);
402258945Sroberto	(void) close(iter->socket);
403258945Sroberto
404258945Sroberto socket_failure:
405258945Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
406258945Sroberto	if (iter->buf6 != NULL)
407258945Sroberto		isc_mem_put(mctx, iter->buf6, iter->bufsize6);
408258945Sroberto  ioctl6_failure:
409258945Sroberto	if (iter->socket6 != -1)
410258945Sroberto		(void) close(iter->socket6);
411258945Sroberto  socket6_failure:
412258945Sroberto#endif
413258945Sroberto
414258945Sroberto	isc_mem_put(mctx, iter, sizeof(*iter));
415258945Sroberto	return (result);
416258945Sroberto}
417258945Sroberto
418258945Sroberto#ifdef HAVE_TRUCLUSTER
419258945Srobertostatic void
420258945Srobertoget_inaddr(isc_netaddr_t *dst, struct in_addr *src) {
421258945Sroberto	dst->family = AF_INET;
422258945Sroberto	memcpy(&dst->type.in, src, sizeof(struct in_addr));
423258945Sroberto}
424258945Sroberto
425258945Srobertostatic isc_result_t
426258945Srobertointernal_current_clusteralias(isc_interfaceiter_t *iter) {
427258945Sroberto	struct clua_info ci;
428258945Sroberto	if (clua_getaliasinfo(&iter->clua_sa, &ci) != CLUA_SUCCESS)
429258945Sroberto		return (ISC_R_IGNORE);
430258945Sroberto	memset(&iter->current, 0, sizeof(iter->current));
431258945Sroberto	iter->current.af = iter->clua_sa.sa_family;
432258945Sroberto	memset(iter->current.name, 0, sizeof(iter->current.name));
433258945Sroberto	sprintf(iter->current.name, "clua%d", ci.aliasid);
434258945Sroberto	iter->current.flags = INTERFACE_F_UP;
435258945Sroberto	get_inaddr(&iter->current.address, &ci.addr);
436258945Sroberto	get_inaddr(&iter->current.netmask, &ci.netmask);
437258945Sroberto	return (ISC_R_SUCCESS);
438258945Sroberto}
439258945Sroberto#endif
440258945Sroberto
441258945Sroberto/*
442258945Sroberto * Get information about the current interface to iter->current.
443258945Sroberto * If successful, return ISC_R_SUCCESS.
444258945Sroberto * If the interface has an unsupported address family, or if
445258945Sroberto * some operation on it fails, return ISC_R_IGNORE to make
446258945Sroberto * the higher-level iterator code ignore it.
447258945Sroberto */
448258945Sroberto
449258945Srobertostatic isc_result_t
450258945Srobertointernal_current4(isc_interfaceiter_t *iter) {
451258945Sroberto	struct ifreq *ifrp;
452258945Sroberto	struct ifreq ifreq;
453258945Sroberto	int family;
454258945Sroberto	char strbuf[ISC_STRERRORSIZE];
455258945Sroberto#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
456258945Sroberto	struct lifreq lifreq;
457258945Sroberto#else
458258945Sroberto	char sabuf[256];
459258945Sroberto#endif
460258945Sroberto	int i, bits, prefixlen;
461258945Sroberto
462258945Sroberto	REQUIRE(VALID_IFITER(iter));
463258945Sroberto
464258945Sroberto	if (iter->ifc.ifc_len == 0 ||
465258945Sroberto	    iter->pos == (unsigned int)iter->ifc.ifc_len) {
466258945Sroberto#ifdef __linux
467258945Sroberto		return (linux_if_inet6_current(iter));
468258945Sroberto#else
469258945Sroberto		return (ISC_R_NOMORE);
470258945Sroberto#endif
471258945Sroberto	}
472258945Sroberto
473258945Sroberto	INSIST( iter->pos < (unsigned int) iter->ifc.ifc_len);
474258945Sroberto
475280849Scy	ifrp = (void *)((char *) iter->ifc.ifc_req + iter->pos);
476258945Sroberto
477258945Sroberto	memset(&ifreq, 0, sizeof(ifreq));
478258945Sroberto	memcpy(&ifreq, ifrp, sizeof(ifreq));
479258945Sroberto
480258945Sroberto	family = ifreq.ifr_addr.sa_family;
481258945Sroberto#if defined(ISC_PLATFORM_HAVEIPV6)
482258945Sroberto	if (family != AF_INET && family != AF_INET6)
483258945Sroberto#else
484258945Sroberto	if (family != AF_INET)
485258945Sroberto#endif
486258945Sroberto		return (ISC_R_IGNORE);
487258945Sroberto
488258945Sroberto	memset(&iter->current, 0, sizeof(iter->current));
489258945Sroberto	iter->current.af = family;
490258945Sroberto
491258945Sroberto	INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
492258945Sroberto	memset(iter->current.name, 0, sizeof(iter->current.name));
493258945Sroberto	memcpy(iter->current.name, ifreq.ifr_name, sizeof(ifreq.ifr_name));
494258945Sroberto
495258945Sroberto	get_addr(family, &iter->current.address,
496258945Sroberto		 (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name);
497258945Sroberto
498258945Sroberto	/*
499258945Sroberto	 * If the interface does not have a address ignore it.
500258945Sroberto	 */
501258945Sroberto	switch (family) {
502258945Sroberto	case AF_INET:
503258945Sroberto		if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
504258945Sroberto			return (ISC_R_IGNORE);
505258945Sroberto		break;
506258945Sroberto	case AF_INET6:
507258945Sroberto		if (memcmp(&iter->current.address.type.in6, &in6addr_any,
508258945Sroberto			   sizeof(in6addr_any)) == 0)
509258945Sroberto			return (ISC_R_IGNORE);
510258945Sroberto		break;
511258945Sroberto	}
512258945Sroberto
513258945Sroberto	/*
514258945Sroberto	 * Get interface flags.
515258945Sroberto	 */
516258945Sroberto
517258945Sroberto	iter->current.flags = 0;
518258945Sroberto
519258945Sroberto	/*
520258945Sroberto	 * Ignore the HP/UX warning about "integer overflow during
521258945Sroberto	 * conversion.  It comes from its own macro definition,
522258945Sroberto	 * and is really hard to shut up.
523258945Sroberto	 */
524280849Scy	if (isc_ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
525258945Sroberto		isc__strerror(errno, strbuf, sizeof(strbuf));
526258945Sroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
527258945Sroberto				 "%s: getting interface flags: %s",
528258945Sroberto				 ifreq.ifr_name, strbuf);
529258945Sroberto		return (ISC_R_IGNORE);
530258945Sroberto	}
531258945Sroberto
532258945Sroberto	if ((ifreq.ifr_flags & IFF_UP) != 0)
533258945Sroberto		iter->current.flags |= INTERFACE_F_UP;
534258945Sroberto
535258945Sroberto#ifdef IFF_POINTOPOINT
536258945Sroberto	if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
537258945Sroberto		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
538258945Sroberto#endif
539258945Sroberto
540258945Sroberto	if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
541258945Sroberto		iter->current.flags |= INTERFACE_F_LOOPBACK;
542258945Sroberto
543258945Sroberto	if ((ifreq.ifr_flags & IFF_BROADCAST) != 0)
544258945Sroberto		iter->current.flags |= INTERFACE_F_BROADCAST;
545258945Sroberto
546258945Sroberto#ifdef IFF_MULTICAST
547258945Sroberto	if ((ifreq.ifr_flags & IFF_MULTICAST) != 0)
548258945Sroberto		iter->current.flags |= INTERFACE_F_MULTICAST;
549258945Sroberto#endif
550258945Sroberto
551258945Sroberto	if (family == AF_INET)
552258945Sroberto		goto inet;
553258945Sroberto
554258945Sroberto#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
555258945Sroberto	memset(&lifreq, 0, sizeof(lifreq));
556258945Sroberto	memcpy(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name));
557258945Sroberto	memcpy(&lifreq.lifr_addr, &iter->current.address.type.in6,
558258945Sroberto	       sizeof(iter->current.address.type.in6));
559258945Sroberto
560280849Scy	if (isc_ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) {
561258945Sroberto		isc__strerror(errno, strbuf, sizeof(strbuf));
562258945Sroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
563258945Sroberto				 "%s: getting interface address: %s",
564258945Sroberto				 ifreq.ifr_name, strbuf);
565258945Sroberto		return (ISC_R_IGNORE);
566258945Sroberto	}
567258945Sroberto	prefixlen = lifreq.lifr_addrlen;
568258945Sroberto#else
569258945Sroberto	isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf));
570258945Sroberto	isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
571258945Sroberto		      ISC_LOGMODULE_INTERFACE,
572258945Sroberto		      ISC_LOG_INFO,
573258945Sroberto		      isc_msgcat_get(isc_msgcat,
574258945Sroberto				     ISC_MSGSET_IFITERIOCTL,
575258945Sroberto				     ISC_MSG_GETIFCONFIG,
576258945Sroberto				     "prefix length for %s is unknown "
577258945Sroberto				     "(assume 128)"), sabuf);
578258945Sroberto	prefixlen = 128;
579258945Sroberto#endif
580258945Sroberto
581258945Sroberto	/*
582258945Sroberto	 * Netmask already zeroed.
583258945Sroberto	 */
584258945Sroberto	iter->current.netmask.family = family;
585258945Sroberto	for (i = 0; i < 16; i++) {
586258945Sroberto		if (prefixlen > 8) {
587258945Sroberto			bits = 0;
588258945Sroberto			prefixlen -= 8;
589258945Sroberto		} else {
590258945Sroberto			bits = 8 - prefixlen;
591258945Sroberto			prefixlen = 0;
592258945Sroberto		}
593258945Sroberto		iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff;
594258945Sroberto	}
595282408Scy#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
596282408Scy	iter->current.ifindex = if_nametoindex(iter->current.name);
597282408Scy#endif
598258945Sroberto	return (ISC_R_SUCCESS);
599258945Sroberto
600258945Sroberto inet:
601258945Sroberto	if (family != AF_INET)
602258945Sroberto		return (ISC_R_IGNORE);
603258945Sroberto#ifdef IFF_POINTOPOINT
604258945Sroberto	/*
605258945Sroberto	 * If the interface is point-to-point, get the destination address.
606258945Sroberto	 */
607258945Sroberto	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
608258945Sroberto		/*
609258945Sroberto		 * Ignore the HP/UX warning about "integer overflow during
610258945Sroberto		 * conversion.  It comes from its own macro definition,
611258945Sroberto		 * and is really hard to shut up.
612258945Sroberto		 */
613280849Scy		if (isc_ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq)
614258945Sroberto		    < 0) {
615258945Sroberto			isc__strerror(errno, strbuf, sizeof(strbuf));
616258945Sroberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
617258945Sroberto				isc_msgcat_get(isc_msgcat,
618258945Sroberto					       ISC_MSGSET_IFITERIOCTL,
619258945Sroberto					       ISC_MSG_GETDESTADDR,
620258945Sroberto					       "%s: getting "
621258945Sroberto					       "destination address: %s"),
622258945Sroberto					 ifreq.ifr_name, strbuf);
623258945Sroberto			return (ISC_R_IGNORE);
624258945Sroberto		}
625258945Sroberto		get_addr(family, &iter->current.dstaddress,
626258945Sroberto			 (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name);
627258945Sroberto	}
628258945Sroberto#endif
629258945Sroberto
630258945Sroberto	if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
631258945Sroberto		/*
632258945Sroberto		 * Ignore the HP/UX warning about "integer overflow during
633258945Sroberto		 * conversion.  It comes from its own macro definition,
634258945Sroberto		 * and is really hard to shut up.
635258945Sroberto		 */
636280849Scy		if (isc_ioctl(iter->socket, SIOCGIFBRDADDR, (char *)&ifreq)
637258945Sroberto		    < 0) {
638258945Sroberto			isc__strerror(errno, strbuf, sizeof(strbuf));
639258945Sroberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
640258945Sroberto				isc_msgcat_get(isc_msgcat,
641258945Sroberto					       ISC_MSGSET_IFITERIOCTL,
642258945Sroberto					       ISC_MSG_GETBCSTADDR,
643258945Sroberto					       "%s: getting "
644258945Sroberto					       "broadcast address: %s"),
645258945Sroberto					 ifreq.ifr_name, strbuf);
646258945Sroberto			return (ISC_R_IGNORE);
647258945Sroberto		}
648258945Sroberto		get_addr(family, &iter->current.broadcast,
649258945Sroberto			 (struct sockaddr *)&ifreq.ifr_broadaddr, ifreq.ifr_name);
650258945Sroberto	}
651258945Sroberto
652258945Sroberto	/*
653258945Sroberto	 * Get the network mask.
654258945Sroberto	 */
655258945Sroberto	memset(&ifreq, 0, sizeof(ifreq));
656258945Sroberto	memcpy(&ifreq, ifrp, sizeof(ifreq));
657258945Sroberto	/*
658258945Sroberto	 * Ignore the HP/UX warning about "integer overflow during
659258945Sroberto	 * conversion.  It comes from its own macro definition,
660258945Sroberto	 * and is really hard to shut up.
661258945Sroberto	 */
662280849Scy	if (isc_ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
663258945Sroberto		isc__strerror(errno, strbuf, sizeof(strbuf));
664258945Sroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
665258945Sroberto			isc_msgcat_get(isc_msgcat,
666258945Sroberto				       ISC_MSGSET_IFITERIOCTL,
667258945Sroberto				       ISC_MSG_GETNETMASK,
668258945Sroberto				       "%s: getting netmask: %s"),
669258945Sroberto				       ifreq.ifr_name, strbuf);
670258945Sroberto		return (ISC_R_IGNORE);
671258945Sroberto	}
672258945Sroberto	get_addr(family, &iter->current.netmask,
673258945Sroberto		 (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name);
674282408Scy#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
675282408Scy	iter->current.ifindex = if_nametoindex(iter->current.name);
676282408Scy#endif
677258945Sroberto	return (ISC_R_SUCCESS);
678258945Sroberto}
679258945Sroberto
680258945Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
681258945Srobertostatic isc_result_t
682258945Srobertointernal_current6(isc_interfaceiter_t *iter) {
683258945Sroberto	struct LIFREQ *ifrp;
684258945Sroberto	struct LIFREQ lifreq;
685258945Sroberto	int family;
686258945Sroberto	char strbuf[ISC_STRERRORSIZE];
687258945Sroberto	int fd;
688258945Sroberto
689258945Sroberto	REQUIRE(VALID_IFITER(iter));
690258945Sroberto	if (iter->result6 != ISC_R_SUCCESS)
691258945Sroberto		return (iter->result6);
692258945Sroberto	REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
693258945Sroberto
694280849Scy	ifrp = (void *)((char *)iter->lifc.lifc_req + iter->pos6);
695258945Sroberto
696258945Sroberto	memset(&lifreq, 0, sizeof(lifreq));
697258945Sroberto	memcpy(&lifreq, ifrp, sizeof(lifreq));
698258945Sroberto
699258945Sroberto	family = lifreq.lifr_addr.ss_family;
700258945Sroberto#ifdef ISC_PLATFORM_HAVEIPV6
701258945Sroberto	if (family != AF_INET && family != AF_INET6)
702258945Sroberto#else
703258945Sroberto	if (family != AF_INET)
704258945Sroberto#endif
705258945Sroberto		return (ISC_R_IGNORE);
706258945Sroberto
707258945Sroberto	memset(&iter->current, 0, sizeof(iter->current));
708258945Sroberto	iter->current.af = family;
709258945Sroberto
710258945Sroberto	INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name));
711258945Sroberto	memset(iter->current.name, 0, sizeof(iter->current.name));
712258945Sroberto	memcpy(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name));
713258945Sroberto
714258945Sroberto	get_addr(family, &iter->current.address,
715258945Sroberto		 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
716258945Sroberto
717258945Sroberto	if (isc_netaddr_islinklocal(&iter->current.address))
718258945Sroberto		isc_netaddr_setzone(&iter->current.address,
719258945Sroberto				    (isc_uint32_t)lifreq.lifr_index);
720258945Sroberto
721258945Sroberto	/*
722258945Sroberto	 * If the interface does not have a address ignore it.
723258945Sroberto	 */
724258945Sroberto	switch (family) {
725258945Sroberto	case AF_INET:
726258945Sroberto		if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
727258945Sroberto			return (ISC_R_IGNORE);
728258945Sroberto		break;
729258945Sroberto	case AF_INET6:
730258945Sroberto		if (memcmp(&iter->current.address.type.in6, &in6addr_any,
731258945Sroberto			   sizeof(in6addr_any)) == 0)
732258945Sroberto			return (ISC_R_IGNORE);
733258945Sroberto		break;
734258945Sroberto	}
735258945Sroberto
736258945Sroberto	/*
737258945Sroberto	 * Get interface flags.
738258945Sroberto	 */
739258945Sroberto
740258945Sroberto	iter->current.flags = 0;
741258945Sroberto
742258945Sroberto	if (family == AF_INET6)
743258945Sroberto		fd = iter->socket6;
744258945Sroberto	else
745258945Sroberto		fd = iter->socket;
746258945Sroberto
747258945Sroberto	/*
748258945Sroberto	 * Ignore the HP/UX warning about "integer overflow during
749258945Sroberto	 * conversion.  It comes from its own macro definition,
750258945Sroberto	 * and is really hard to shut up.
751258945Sroberto	 */
752280849Scy	if (isc_ioctl(fd, SIOCGLIFFLAGS, (char *) &lifreq) < 0) {
753258945Sroberto		isc__strerror(errno, strbuf, sizeof(strbuf));
754258945Sroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
755258945Sroberto				 "%s: getting interface flags: %s",
756258945Sroberto				 lifreq.lifr_name, strbuf);
757258945Sroberto		return (ISC_R_IGNORE);
758258945Sroberto	}
759258945Sroberto
760258945Sroberto	if ((lifreq.lifr_flags & IFF_UP) != 0)
761258945Sroberto		iter->current.flags |= INTERFACE_F_UP;
762258945Sroberto
763258945Sroberto#ifdef IFF_POINTOPOINT
764258945Sroberto	if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0)
765258945Sroberto		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
766258945Sroberto#endif
767258945Sroberto
768258945Sroberto	if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0)
769258945Sroberto		iter->current.flags |= INTERFACE_F_LOOPBACK;
770258945Sroberto
771258945Sroberto	if ((lifreq.lifr_flags & IFF_BROADCAST) != 0) {
772258945Sroberto		iter->current.flags |= INTERFACE_F_BROADCAST;
773258945Sroberto	}
774258945Sroberto
775258945Sroberto#ifdef IFF_MULTICAST
776258945Sroberto	if ((lifreq.lifr_flags & IFF_MULTICAST) != 0) {
777258945Sroberto		iter->current.flags |= INTERFACE_F_MULTICAST;
778258945Sroberto	}
779258945Sroberto#endif
780258945Sroberto
781258945Sroberto#ifdef IFF_POINTOPOINT
782258945Sroberto	/*
783258945Sroberto	 * If the interface is point-to-point, get the destination address.
784258945Sroberto	 */
785258945Sroberto	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
786258945Sroberto		/*
787258945Sroberto		 * Ignore the HP/UX warning about "integer overflow during
788258945Sroberto		 * conversion.  It comes from its own macro definition,
789258945Sroberto		 * and is really hard to shut up.
790258945Sroberto		 */
791280849Scy		if (isc_ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq)
792258945Sroberto		    < 0) {
793258945Sroberto			isc__strerror(errno, strbuf, sizeof(strbuf));
794258945Sroberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
795258945Sroberto				isc_msgcat_get(isc_msgcat,
796258945Sroberto					       ISC_MSGSET_IFITERIOCTL,
797258945Sroberto					       ISC_MSG_GETDESTADDR,
798258945Sroberto					       "%s: getting "
799258945Sroberto					       "destination address: %s"),
800258945Sroberto					 lifreq.lifr_name, strbuf);
801258945Sroberto			return (ISC_R_IGNORE);
802258945Sroberto		}
803258945Sroberto		get_addr(family, &iter->current.dstaddress,
804258945Sroberto			 (struct sockaddr *)&lifreq.lifr_dstaddr,
805258945Sroberto			 lifreq.lifr_name);
806258945Sroberto	}
807258945Sroberto#endif
808258945Sroberto
809258945Sroberto#ifdef SIOCGLIFBRDADDR
810258945Sroberto	if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
811258945Sroberto		/*
812258945Sroberto		 * Ignore the HP/UX warning about "integer overflow during
813258945Sroberto		 * conversion.  It comes from its own macro definition,
814258945Sroberto		 * and is really hard to shut up.
815258945Sroberto		 */
816280849Scy		if (isc_ioctl(iter->socket, SIOCGLIFBRDADDR, (char *)&lifreq)
817258945Sroberto		    < 0) {
818258945Sroberto			isc__strerror(errno, strbuf, sizeof(strbuf));
819258945Sroberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
820258945Sroberto				isc_msgcat_get(isc_msgcat,
821258945Sroberto					       ISC_MSGSET_IFITERIOCTL,
822258945Sroberto					       ISC_MSG_GETBCSTADDR,
823258945Sroberto					       "%s: getting "
824258945Sroberto					       "broadcast address: %s"),
825258945Sroberto					 lifreq.lifr_name, strbuf);
826258945Sroberto			return (ISC_R_IGNORE);
827258945Sroberto		}
828258945Sroberto		get_addr(family, &iter->current.broadcast,
829258945Sroberto			 (struct sockaddr *)&lifreq.lifr_broadaddr,
830258945Sroberto			 lifreq.lifr_name);
831258945Sroberto	}
832258945Sroberto#endif	/* SIOCGLIFBRDADDR */
833258945Sroberto
834258945Sroberto	/*
835258945Sroberto	 * Get the network mask.  Netmask already zeroed.
836258945Sroberto	 */
837258945Sroberto	memset(&lifreq, 0, sizeof(lifreq));
838258945Sroberto	memcpy(&lifreq, ifrp, sizeof(lifreq));
839258945Sroberto
840258945Sroberto#ifdef lifr_addrlen
841258945Sroberto	/*
842258945Sroberto	 * Special case: if the system provides lifr_addrlen member, the
843258945Sroberto	 * netmask of an IPv6 address can be derived from the length, since
844258945Sroberto	 * an IPv6 address always has a contiguous mask.
845258945Sroberto	 */
846258945Sroberto	if (family == AF_INET6) {
847258945Sroberto		int i, bits;
848258945Sroberto
849258945Sroberto		iter->current.netmask.family = family;
850258945Sroberto		for (i = 0; i < lifreq.lifr_addrlen; i += 8) {
851258945Sroberto			bits = lifreq.lifr_addrlen - i;
852258945Sroberto			bits = (bits < 8) ? (8 - bits) : 0;
853258945Sroberto			iter->current.netmask.type.in6.s6_addr[i / 8] =
854258945Sroberto				(~0 << bits) & 0xff;
855258945Sroberto		}
856282408Scy#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
857282408Scy		iter->current.ifindex = if_nametoindex(iter->current.name);
858282408Scy#endif
859258945Sroberto		return (ISC_R_SUCCESS);
860258945Sroberto	}
861258945Sroberto#endif
862258945Sroberto
863258945Sroberto	/*
864258945Sroberto	 * Ignore the HP/UX warning about "integer overflow during
865258945Sroberto	 * conversion.  It comes from its own macro definition,
866258945Sroberto	 * and is really hard to shut up.
867258945Sroberto	 */
868280849Scy	if (isc_ioctl(fd, SIOCGLIFNETMASK, (char *)&lifreq) < 0) {
869258945Sroberto		isc__strerror(errno, strbuf, sizeof(strbuf));
870258945Sroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
871258945Sroberto				 isc_msgcat_get(isc_msgcat,
872258945Sroberto						ISC_MSGSET_IFITERIOCTL,
873258945Sroberto						ISC_MSG_GETNETMASK,
874258945Sroberto						"%s: getting netmask: %s"),
875258945Sroberto				 lifreq.lifr_name, strbuf);
876258945Sroberto		return (ISC_R_IGNORE);
877258945Sroberto	}
878258945Sroberto	get_addr(family, &iter->current.netmask,
879258945Sroberto		 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
880258945Sroberto
881282408Scy#ifdef ISC_PLATFORM_HAVEIFNAMETOINDEX
882282408Scy	iter->current.ifindex = if_nametoindex(iter->current.name);
883282408Scy#endif
884258945Sroberto	return (ISC_R_SUCCESS);
885258945Sroberto}
886258945Sroberto#endif
887258945Sroberto
888258945Srobertostatic isc_result_t
889258945Srobertointernal_current(isc_interfaceiter_t *iter) {
890258945Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
891258945Sroberto	if (iter->mode == 6) {
892258945Sroberto		iter->result6 = internal_current6(iter);
893258945Sroberto		if (iter->result6 != ISC_R_NOMORE)
894258945Sroberto			return (iter->result6);
895258945Sroberto	}
896258945Sroberto#endif
897258945Sroberto#ifdef HAVE_TRUCLUSTER
898258945Sroberto	if (!iter->clua_done)
899258945Sroberto		return(internal_current_clusteralias(iter));
900258945Sroberto#endif
901258945Sroberto	return (internal_current4(iter));
902258945Sroberto}
903258945Sroberto
904258945Sroberto/*
905258945Sroberto * Step the iterator to the next interface.  Unlike
906258945Sroberto * isc_interfaceiter_next(), this may leave the iterator
907258945Sroberto * positioned on an interface that will ultimately
908258945Sroberto * be ignored.  Return ISC_R_NOMORE if there are no more
909258945Sroberto * interfaces, otherwise ISC_R_SUCCESS.
910258945Sroberto */
911258945Srobertostatic isc_result_t
912258945Srobertointernal_next4(isc_interfaceiter_t *iter) {
913258945Sroberto#ifdef ISC_PLATFORM_HAVESALEN
914258945Sroberto	struct ifreq *ifrp;
915258945Sroberto#endif
916258945Sroberto
917258945Sroberto	if (iter->pos < (unsigned int) iter->ifc.ifc_len) {
918258945Sroberto#ifdef ISC_PLATFORM_HAVESALEN
919258945Sroberto		ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
920258945Sroberto
921258945Sroberto		if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
922258945Sroberto			iter->pos += sizeof(ifrp->ifr_name) +
923258945Sroberto				     ifrp->ifr_addr.sa_len;
924258945Sroberto		else
925258945Sroberto#endif
926258945Sroberto			iter->pos += sizeof(struct ifreq);
927258945Sroberto
928258945Sroberto	} else {
929258945Sroberto		INSIST(iter->pos == (unsigned int) iter->ifc.ifc_len);
930258945Sroberto#ifdef __linux
931258945Sroberto		return (linux_if_inet6_next(iter));
932258945Sroberto#else
933258945Sroberto		return (ISC_R_NOMORE);
934258945Sroberto#endif
935258945Sroberto	}
936258945Sroberto	return (ISC_R_SUCCESS);
937258945Sroberto}
938258945Sroberto
939258945Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
940258945Srobertostatic isc_result_t
941258945Srobertointernal_next6(isc_interfaceiter_t *iter) {
942258945Sroberto#ifdef ISC_PLATFORM_HAVESALEN
943258945Sroberto	struct LIFREQ *ifrp;
944258945Sroberto#endif
945258945Sroberto
946258945Sroberto	if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE)
947258945Sroberto		return (iter->result6);
948258945Sroberto
949258945Sroberto	REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
950258945Sroberto
951258945Sroberto#ifdef ISC_PLATFORM_HAVESALEN
952258945Sroberto	ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
953258945Sroberto
954258945Sroberto	if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr))
955258945Sroberto		iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len;
956258945Sroberto	else
957258945Sroberto#endif
958258945Sroberto		iter->pos6 += sizeof(struct LIFREQ);
959258945Sroberto
960258945Sroberto	if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len)
961258945Sroberto		return (ISC_R_NOMORE);
962258945Sroberto
963258945Sroberto	return (ISC_R_SUCCESS);
964258945Sroberto}
965258945Sroberto#endif
966258945Sroberto
967258945Srobertostatic isc_result_t
968258945Srobertointernal_next(isc_interfaceiter_t *iter) {
969258945Sroberto#ifdef HAVE_TRUCLUSTER
970258945Sroberto	int clua_result;
971258945Sroberto#endif
972258945Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
973258945Sroberto	if (iter->mode == 6) {
974258945Sroberto		iter->result6 = internal_next6(iter);
975258945Sroberto		if (iter->result6 != ISC_R_NOMORE)
976258945Sroberto			return (iter->result6);
977258945Sroberto		if (iter->first6) {
978258945Sroberto			iter->first6 = ISC_FALSE;
979258945Sroberto			return (ISC_R_SUCCESS);
980258945Sroberto		}
981258945Sroberto	}
982258945Sroberto#endif
983258945Sroberto#ifdef HAVE_TRUCLUSTER
984258945Sroberto	if (!iter->clua_done) {
985258945Sroberto		clua_result = clua_getaliasaddress(&iter->clua_sa,
986258945Sroberto						   &iter->clua_context);
987258945Sroberto		if (clua_result != CLUA_SUCCESS)
988258945Sroberto			iter->clua_done = ISC_TRUE;
989258945Sroberto		return (ISC_R_SUCCESS);
990258945Sroberto	}
991258945Sroberto#endif
992258945Sroberto	return (internal_next4(iter));
993258945Sroberto}
994258945Sroberto
995258945Srobertostatic void
996258945Srobertointernal_destroy(isc_interfaceiter_t *iter) {
997258945Sroberto	(void) close(iter->socket);
998258945Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
999258945Sroberto	if (iter->socket6 != -1)
1000258945Sroberto		(void) close(iter->socket6);
1001258945Sroberto	if (iter->buf6 != NULL) {
1002258945Sroberto		isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
1003258945Sroberto	}
1004258945Sroberto#endif
1005258945Sroberto#ifdef __linux
1006258945Sroberto	if (iter->proc != NULL)
1007258945Sroberto		fclose(iter->proc);
1008258945Sroberto#endif
1009258945Sroberto}
1010258945Sroberto
1011258945Srobertostatic
1012258945Srobertovoid internal_first(isc_interfaceiter_t *iter) {
1013258945Sroberto#ifdef HAVE_TRUCLUSTER
1014258945Sroberto	int clua_result;
1015258945Sroberto#endif
1016258945Sroberto	iter->pos = 0;
1017258945Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1018258945Sroberto	iter->pos6 = 0;
1019258945Sroberto	if (iter->result6 == ISC_R_NOMORE)
1020258945Sroberto		iter->result6 = ISC_R_SUCCESS;
1021258945Sroberto	iter->first6 = ISC_TRUE;
1022258945Sroberto#endif
1023258945Sroberto#ifdef HAVE_TRUCLUSTER
1024258945Sroberto	iter->clua_context = 0;
1025258945Sroberto	clua_result = clua_getaliasaddress(&iter->clua_sa,
1026258945Sroberto					   &iter->clua_context);
1027258945Sroberto	iter->clua_done = ISC_TF(clua_result != CLUA_SUCCESS);
1028258945Sroberto#endif
1029258945Sroberto#ifdef __linux
1030258945Sroberto	linux_if_inet6_first(iter);
1031258945Sroberto#endif
1032258945Sroberto}
1033