1132451Sroberto/*
2182007Sroberto * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3182007Sroberto * Copyright (C) 1999-2003  Internet Software Consortium.
4132451Sroberto *
5132451Sroberto * Permission to use, copy, modify, and distribute this software for any
6132451Sroberto * purpose with or without fee is hereby granted, provided that the above
7132451Sroberto * copyright notice and this permission notice appear in all copies.
8132451Sroberto *
9182007Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10182007Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11182007Sroberto * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12182007Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13182007Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14182007Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15182007Sroberto * PERFORMANCE OF THIS SOFTWARE.
16132451Sroberto */
17132451Sroberto
18182007Sroberto/* $Id: ifiter_ioctl.c,v 1.19.2.5.2.14 2004/06/22 04:40:23 marka Exp $ */
19132451Sroberto
20132451Sroberto/*
21132451Sroberto * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl.
22132451Sroberto * See netintro(4).
23132451Sroberto */
24132451Sroberto
25132451Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
26132451Sroberto#ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
27132451Sroberto#define lifc_len iflc_len
28132451Sroberto#define lifc_buf iflc_buf
29132451Sroberto#define lifc_req iflc_req
30132451Sroberto#define LIFCONF if_laddrconf
31132451Sroberto#else
32132451Sroberto#define ISC_HAVE_LIFC_FAMILY 1
33132451Sroberto#define ISC_HAVE_LIFC_FLAGS 1
34132451Sroberto#define LIFCONF lifconf
35132451Sroberto#endif
36132451Sroberto
37132451Sroberto#ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
38132451Sroberto#define lifr_addr iflr_addr
39132451Sroberto#define lifr_name iflr_name
40132451Sroberto#define lifr_dstaddr iflr_dstaddr
41132451Sroberto#define lifr_broadaddr iflr_broadaddr
42132451Sroberto#define lifr_flags iflr_flags
43182007Sroberto#define lifr_index iflr_index
44132451Sroberto#define ss_family sa_family
45132451Sroberto#define LIFREQ if_laddrreq
46132451Sroberto#else
47132451Sroberto#define LIFREQ lifreq
48132451Sroberto#endif
49132451Sroberto#endif
50132451Sroberto
51132451Sroberto#define IFITER_MAGIC		ISC_MAGIC('I', 'F', 'I', 'T')
52132451Sroberto#define VALID_IFITER(t)		ISC_MAGIC_VALID(t, IFITER_MAGIC)
53132451Sroberto
54182007Sroberto#define ISC_IF_INET6_SZ \
55182007Sroberto    sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n")
56182007Sroberto
57132451Srobertostruct isc_interfaceiter {
58132451Sroberto	unsigned int		magic;		/* Magic number. */
59132451Sroberto	isc_mem_t		*mctx;
60182007Sroberto	int			mode;
61132451Sroberto	int			socket;
62132451Sroberto	struct ifconf 		ifc;
63182007Sroberto	void			*buf;		/* Buffer for sysctl data. */
64182007Sroberto	unsigned int		bufsize;	/* Bytes allocated. */
65182007Sroberto	unsigned int		pos;		/* Current offset in
66182007Sroberto						   SIOCGIFCONF data */
67132451Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
68182007Sroberto	int			socket6;
69132451Sroberto	struct LIFCONF 		lifc;
70182007Sroberto	void			*buf6;		/* Buffer for sysctl data. */
71182007Sroberto	unsigned int		bufsize6;	/* Bytes allocated. */
72182007Sroberto	unsigned int		pos6;		/* Current offset in
73182007Sroberto						   SIOCGLIFCONF data */
74182007Sroberto	isc_result_t		result6;	/* Last result code. */
75182007Sroberto	isc_boolean_t		first6;
76132451Sroberto#endif
77132451Sroberto#ifdef HAVE_TRUCLUSTER
78132451Sroberto	int			clua_context;	/* Cluster alias context */
79182007Sroberto	isc_boolean_t		clua_done;
80182007Sroberto	struct sockaddr		clua_sa;
81132451Sroberto#endif
82182007Sroberto#ifdef	__linux
83182007Sroberto	FILE *			proc;
84182007Sroberto	char			entry[ISC_IF_INET6_SZ];
85182007Sroberto	isc_result_t		valid;
86182007Sroberto	isc_boolean_t		first;
87182007Sroberto#endif
88132451Sroberto	isc_interface_t		current;	/* Current interface data. */
89132451Sroberto	isc_result_t		result;		/* Last result code. */
90132451Sroberto};
91132451Sroberto
92132451Sroberto#ifdef HAVE_TRUCLUSTER
93132451Sroberto#include <clua/clua.h>
94132451Sroberto#include <sys/socket.h>
95132451Sroberto#endif
96132451Sroberto
97132451Sroberto
98132451Sroberto/*
99132451Sroberto * Size of buffer for SIOCGLIFCONF, in bytes.  We assume no sane system
100132451Sroberto * will have more than a megabyte of interface configuration data.
101132451Sroberto */
102132451Sroberto#define IFCONF_BUFSIZE_INITIAL	4096
103132451Sroberto#define IFCONF_BUFSIZE_MAX	1048576
104132451Sroberto
105182007Sroberto#ifdef __linux
106182007Sroberto#ifndef IF_NAMESIZE
107182007Sroberto# ifdef IFNAMSIZ
108182007Sroberto#  define IF_NAMESIZE  IFNAMSIZ
109182007Sroberto# else
110182007Sroberto#  define IF_NAMESIZE 16
111182007Sroberto# endif
112182007Sroberto#endif
113182007Sroberto#endif
114182007Sroberto
115132451Srobertostatic isc_result_t
116132451Srobertogetbuf4(isc_interfaceiter_t *iter) {
117132451Sroberto	char strbuf[ISC_STRERRORSIZE];
118132451Sroberto
119132451Sroberto	iter->bufsize = IFCONF_BUFSIZE_INITIAL;
120132451Sroberto
121132451Sroberto	for (;;) {
122132451Sroberto		iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
123132451Sroberto		if (iter->buf == NULL)
124132451Sroberto			return (ISC_R_NOMEMORY);
125132451Sroberto
126132451Sroberto		memset(&iter->ifc.ifc_len, 0, sizeof(iter->ifc.ifc_len));
127132451Sroberto		iter->ifc.ifc_len = iter->bufsize;
128132451Sroberto		iter->ifc.ifc_buf = iter->buf;
129132451Sroberto		/*
130132451Sroberto		 * Ignore the HP/UX warning about "integer overflow during
131132451Sroberto		 * conversion".  It comes from its own macro definition,
132132451Sroberto		 * and is really hard to shut up.
133132451Sroberto		 */
134132451Sroberto		if (ioctl(iter->socket, SIOCGIFCONF, (char *)&iter->ifc)
135132451Sroberto		    == -1) {
136132451Sroberto			if (errno != EINVAL) {
137132451Sroberto				isc__strerror(errno, strbuf, sizeof(strbuf));
138132451Sroberto				UNEXPECTED_ERROR(__FILE__, __LINE__,
139132451Sroberto						 isc_msgcat_get(isc_msgcat,
140132451Sroberto							ISC_MSGSET_IFITERIOCTL,
141132451Sroberto							ISC_MSG_GETIFCONFIG,
142132451Sroberto							"get interface "
143132451Sroberto							"configuration: %s"),
144132451Sroberto						 strbuf);
145132451Sroberto				goto unexpected;
146132451Sroberto			}
147132451Sroberto			/*
148132451Sroberto			 * EINVAL.  Retry with a bigger buffer.
149132451Sroberto			 */
150132451Sroberto		} else {
151132451Sroberto			/*
152132451Sroberto			 * The ioctl succeeded.
153132451Sroberto			 * Some OS's just return what will fit rather
154132451Sroberto			 * than set EINVAL if the buffer is too small
155132451Sroberto			 * to fit all the interfaces in.  If
156132451Sroberto			 * ifc.lifc_len is too near to the end of the
157132451Sroberto			 * buffer we will grow it just in case and
158132451Sroberto			 * retry.
159132451Sroberto			 */
160132451Sroberto			if (iter->ifc.ifc_len + 2 * sizeof(struct ifreq)
161132451Sroberto			    < iter->bufsize)
162132451Sroberto				break;
163132451Sroberto		}
164132451Sroberto		if (iter->bufsize >= IFCONF_BUFSIZE_MAX) {
165132451Sroberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
166132451Sroberto					 isc_msgcat_get(isc_msgcat,
167132451Sroberto							ISC_MSGSET_IFITERIOCTL,
168132451Sroberto							ISC_MSG_BUFFERMAX,
169132451Sroberto							"get interface "
170132451Sroberto							"configuration: "
171132451Sroberto							"maximum buffer "
172132451Sroberto							"size exceeded"));
173132451Sroberto			goto unexpected;
174132451Sroberto		}
175132451Sroberto		isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
176132451Sroberto
177132451Sroberto		iter->bufsize *= 2;
178132451Sroberto	}
179132451Sroberto	return (ISC_R_SUCCESS);
180132451Sroberto
181132451Sroberto unexpected:
182132451Sroberto	isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
183132451Sroberto	iter->buf = NULL;
184132451Sroberto	return (ISC_R_UNEXPECTED);
185132451Sroberto}
186132451Sroberto
187182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
188132451Srobertostatic isc_result_t
189132451Srobertogetbuf6(isc_interfaceiter_t *iter) {
190132451Sroberto	char strbuf[ISC_STRERRORSIZE];
191132451Sroberto	isc_result_t result;
192132451Sroberto
193182007Sroberto	iter->bufsize6 = IFCONF_BUFSIZE_INITIAL;
194132451Sroberto
195132451Sroberto	for (;;) {
196182007Sroberto		iter->buf6 = isc_mem_get(iter->mctx, iter->bufsize6);
197182007Sroberto		if (iter->buf6 == NULL)
198132451Sroberto			return (ISC_R_NOMEMORY);
199132451Sroberto
200182007Sroberto		memset(&iter->lifc, 0, sizeof(iter->lifc));
201132451Sroberto#ifdef ISC_HAVE_LIFC_FAMILY
202182007Sroberto		iter->lifc.lifc_family = AF_INET6;
203132451Sroberto#endif
204132451Sroberto#ifdef ISC_HAVE_LIFC_FLAGS
205132451Sroberto		iter->lifc.lifc_flags = 0;
206132451Sroberto#endif
207182007Sroberto		iter->lifc.lifc_len = iter->bufsize6;
208182007Sroberto		iter->lifc.lifc_buf = iter->buf6;
209132451Sroberto		/*
210132451Sroberto		 * Ignore the HP/UX warning about "integer overflow during
211132451Sroberto		 * conversion".  It comes from its own macro definition,
212132451Sroberto		 * and is really hard to shut up.
213132451Sroberto		 */
214182007Sroberto		if (ioctl(iter->socket6, SIOCGLIFCONF, (char *)&iter->lifc)
215132451Sroberto		    == -1) {
216132451Sroberto#ifdef __hpux
217132451Sroberto			/*
218132451Sroberto			 * IPv6 interface scanning is not available on all
219132451Sroberto			 * kernels w/ IPv6 sockets.
220132451Sroberto			 */
221132451Sroberto			if (errno == ENOENT) {
222132451Sroberto				isc__strerror(errno, strbuf, sizeof(strbuf));
223132451Sroberto				UNEXPECTED_ERROR(__FILE__, __LINE__,
224132451Sroberto						 isc_msgcat_get(isc_msgcat,
225132451Sroberto							ISC_MSGSET_IFITERIOCTL,
226132451Sroberto							ISC_MSG_GETIFCONFIG,
227132451Sroberto							"get interface "
228132451Sroberto							"configuration: %s"),
229132451Sroberto						 strbuf);
230132451Sroberto				result = ISC_R_FAILURE;
231132451Sroberto				goto cleanup;
232132451Sroberto			}
233132451Sroberto#endif
234132451Sroberto			if (errno != EINVAL) {
235132451Sroberto				isc__strerror(errno, strbuf, sizeof(strbuf));
236132451Sroberto				UNEXPECTED_ERROR(__FILE__, __LINE__,
237132451Sroberto						 isc_msgcat_get(isc_msgcat,
238132451Sroberto							ISC_MSGSET_IFITERIOCTL,
239132451Sroberto							ISC_MSG_GETIFCONFIG,
240132451Sroberto							"get interface "
241132451Sroberto							"configuration: %s"),
242132451Sroberto						 strbuf);
243132451Sroberto				result = ISC_R_UNEXPECTED;
244132451Sroberto				goto cleanup;
245132451Sroberto			}
246132451Sroberto			/*
247132451Sroberto			 * EINVAL.  Retry with a bigger buffer.
248132451Sroberto			 */
249132451Sroberto		} else {
250132451Sroberto			/*
251132451Sroberto			 * The ioctl succeeded.
252132451Sroberto			 * Some OS's just return what will fit rather
253132451Sroberto			 * than set EINVAL if the buffer is too small
254132451Sroberto			 * to fit all the interfaces in.  If
255132451Sroberto			 * ifc.ifc_len is too near to the end of the
256132451Sroberto			 * buffer we will grow it just in case and
257132451Sroberto			 * retry.
258132451Sroberto			 */
259132451Sroberto			if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ)
260182007Sroberto			    < iter->bufsize6)
261132451Sroberto				break;
262132451Sroberto		}
263182007Sroberto		if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) {
264132451Sroberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
265132451Sroberto					 isc_msgcat_get(isc_msgcat,
266132451Sroberto							ISC_MSGSET_IFITERIOCTL,
267132451Sroberto							ISC_MSG_BUFFERMAX,
268132451Sroberto							"get interface "
269132451Sroberto							"configuration: "
270132451Sroberto							"maximum buffer "
271132451Sroberto							"size exceeded"));
272132451Sroberto			result = ISC_R_UNEXPECTED;
273132451Sroberto			goto cleanup;
274132451Sroberto		}
275182007Sroberto		isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
276132451Sroberto
277182007Sroberto		iter->bufsize6 *= 2;
278132451Sroberto	}
279132451Sroberto
280182007Sroberto	if (iter->lifc.lifc_len != 0)
281182007Sroberto		iter->mode = 6;
282132451Sroberto	return (ISC_R_SUCCESS);
283132451Sroberto
284132451Sroberto cleanup:
285182007Sroberto	isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
286182007Sroberto	iter->buf6 = NULL;
287132451Sroberto	return (result);
288182007Sroberto}
289132451Sroberto#endif
290132451Sroberto
291132451Srobertoisc_result_t
292132451Srobertoisc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
293132451Sroberto	isc_interfaceiter_t *iter;
294132451Sroberto	isc_result_t result;
295132451Sroberto	char strbuf[ISC_STRERRORSIZE];
296132451Sroberto
297132451Sroberto	REQUIRE(iterp != NULL);
298132451Sroberto	REQUIRE(*iterp == NULL);
299132451Sroberto
300132451Sroberto	iter = isc_mem_get(mctx, sizeof(*iter));
301132451Sroberto	if (iter == NULL)
302132451Sroberto		return (ISC_R_NOMEMORY);
303132451Sroberto
304132451Sroberto	iter->mctx = mctx;
305182007Sroberto	iter->mode = 4;
306132451Sroberto	iter->buf = NULL;
307182007Sroberto	iter->pos = (unsigned int) -1;
308182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
309182007Sroberto	iter->buf6 = NULL;
310182007Sroberto	iter->pos6 = (unsigned int) -1;
311182007Sroberto	iter->result6 = ISC_R_NOMORE;
312182007Sroberto	iter->socket6 = -1;
313182007Sroberto	iter->first6 = ISC_FALSE;
314182007Sroberto#endif
315132451Sroberto
316132451Sroberto	/*
317182007Sroberto	 * Get the interface configuration, allocating more memory if
318182007Sroberto	 * necessary.
319132451Sroberto	 */
320182007Sroberto
321182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
322182007Sroberto	result = isc_net_probeipv6();
323182007Sroberto	if (result == ISC_R_SUCCESS) {
324182007Sroberto		/*
325182007Sroberto		 * Create an unbound datagram socket to do the SIOCGLIFCONF
326182007Sroberto		 * ioctl on.  HP/UX requires an AF_INET6 socket for
327182007Sroberto		 * SIOCGLIFCONF to get IPv6 addresses.
328182007Sroberto		 */
329182007Sroberto		if ((iter->socket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
330182007Sroberto			isc__strerror(errno, strbuf, sizeof(strbuf));
331182007Sroberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
332182007Sroberto					 isc_msgcat_get(isc_msgcat,
333182007Sroberto							ISC_MSGSET_IFITERIOCTL,
334182007Sroberto							ISC_MSG_MAKESCANSOCKET,
335182007Sroberto							"making interface "
336182007Sroberto							"scan socket: %s"),
337182007Sroberto					 strbuf);
338182007Sroberto			result = ISC_R_UNEXPECTED;
339182007Sroberto			goto socket6_failure;
340182007Sroberto		}
341182007Sroberto		iter->result6 = getbuf6(iter);
342182007Sroberto		if (iter->result6 != ISC_R_NOTIMPLEMENTED &&
343182007Sroberto		    iter->result6 != ISC_R_SUCCESS)
344182007Sroberto			goto ioctl6_failure;
345182007Sroberto	}
346182007Sroberto#endif
347132451Sroberto	if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
348132451Sroberto		isc__strerror(errno, strbuf, sizeof(strbuf));
349132451Sroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
350132451Sroberto				 isc_msgcat_get(isc_msgcat,
351132451Sroberto						ISC_MSGSET_IFITERIOCTL,
352132451Sroberto						ISC_MSG_MAKESCANSOCKET,
353132451Sroberto						"making interface "
354132451Sroberto						"scan socket: %s"),
355132451Sroberto				 strbuf);
356132451Sroberto		result = ISC_R_UNEXPECTED;
357132451Sroberto		goto socket_failure;
358132451Sroberto	}
359182007Sroberto	result = getbuf4(iter);
360132451Sroberto	if (result != ISC_R_SUCCESS)
361132451Sroberto		goto ioctl_failure;
362132451Sroberto
363132451Sroberto	/*
364132451Sroberto	 * A newly created iterator has an undefined position
365132451Sroberto	 * until isc_interfaceiter_first() is called.
366132451Sroberto	 */
367132451Sroberto#ifdef HAVE_TRUCLUSTER
368132451Sroberto	iter->clua_context = -1;
369182007Sroberto	iter->clua_done = ISC_TRUE;
370132451Sroberto#endif
371182007Sroberto#ifdef __linux
372182007Sroberto	iter->proc = fopen("/proc/net/if_inet6", "r");
373182007Sroberto	iter->valid = ISC_R_FAILURE;
374182007Sroberto	iter->first = ISC_FALSE;
375182007Sroberto#endif
376132451Sroberto	iter->result = ISC_R_FAILURE;
377132451Sroberto
378132451Sroberto	iter->magic = IFITER_MAGIC;
379132451Sroberto	*iterp = iter;
380132451Sroberto	return (ISC_R_SUCCESS);
381132451Sroberto
382132451Sroberto ioctl_failure:
383132451Sroberto	if (iter->buf != NULL)
384132451Sroberto		isc_mem_put(mctx, iter->buf, iter->bufsize);
385132451Sroberto	(void) close(iter->socket);
386132451Sroberto
387132451Sroberto socket_failure:
388182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
389182007Sroberto	if (iter->buf6 != NULL)
390182007Sroberto		isc_mem_put(mctx, iter->buf6, iter->bufsize6);
391182007Sroberto  ioctl6_failure:
392182007Sroberto	if (iter->socket6 != -1)
393182007Sroberto		(void) close(iter->socket6);
394182007Sroberto  socket6_failure:
395182007Sroberto#endif
396182007Sroberto
397132451Sroberto	isc_mem_put(mctx, iter, sizeof(*iter));
398132451Sroberto	return (result);
399132451Sroberto}
400132451Sroberto
401132451Sroberto#ifdef HAVE_TRUCLUSTER
402132451Srobertostatic void
403132451Srobertoget_inaddr(isc_netaddr_t *dst, struct in_addr *src) {
404132451Sroberto	dst->family = AF_INET;
405132451Sroberto	memcpy(&dst->type.in, src, sizeof(struct in_addr));
406132451Sroberto}
407132451Sroberto
408132451Srobertostatic isc_result_t
409132451Srobertointernal_current_clusteralias(isc_interfaceiter_t *iter) {
410132451Sroberto	struct clua_info ci;
411182007Sroberto	if (clua_getaliasinfo(&iter->clua_sa, &ci) != CLUA_SUCCESS)
412182007Sroberto		return (ISC_R_IGNORE);
413182007Sroberto	memset(&iter->current, 0, sizeof(iter->current));
414182007Sroberto	iter->current.af = iter->clua_sa.sa_family;
415182007Sroberto	memset(iter->current.name, 0, sizeof(iter->current.name));
416182007Sroberto	sprintf(iter->current.name, "clua%d", ci.aliasid);
417182007Sroberto	iter->current.flags = INTERFACE_F_UP;
418182007Sroberto	get_inaddr(&iter->current.address, &ci.addr);
419182007Sroberto	get_inaddr(&iter->current.netmask, &ci.netmask);
420182007Sroberto	return (ISC_R_SUCCESS);
421182007Sroberto}
422182007Sroberto#endif
423182007Sroberto
424182007Sroberto#ifdef __linux
425182007Srobertostatic isc_result_t
426182007Srobertolinux_if_inet6_next(isc_interfaceiter_t *iter) {
427182007Sroberto	if (iter->proc != NULL &&
428182007Sroberto	    fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL)
429182007Sroberto		iter->valid = ISC_R_SUCCESS;
430182007Sroberto	else
431182007Sroberto		iter->valid = ISC_R_NOMORE;
432182007Sroberto	return (iter->valid);
433182007Sroberto}
434182007Sroberto
435182007Srobertostatic void
436182007Srobertolinux_if_inet6_first(isc_interfaceiter_t *iter) {
437182007Sroberto	if (iter->proc != NULL) {
438182007Sroberto		rewind(iter->proc);
439182007Sroberto		(void)linux_if_inet6_next(iter);
440182007Sroberto	} else
441182007Sroberto		iter->valid = ISC_R_NOMORE;
442182007Sroberto	iter->first = ISC_FALSE;
443182007Sroberto}
444182007Sroberto
445182007Srobertostatic isc_result_t
446182007Srobertolinux_if_inet6_current(isc_interfaceiter_t *iter) {
447182007Sroberto	char address[33];
448182007Sroberto	char name[IF_NAMESIZE+1];
449182007Sroberto	char strbuf[ISC_STRERRORSIZE];
450182007Sroberto	struct in6_addr addr6;
451182007Sroberto	struct ifreq ifreq;
452182007Sroberto	int ifindex, prefix, scope, flags;
453182007Sroberto	int res;
454182007Sroberto	unsigned int i;
455182007Sroberto
456182007Sroberto	if (iter->valid != ISC_R_SUCCESS)
457182007Sroberto		return (iter->valid);
458182007Sroberto	if (iter->proc == NULL) {
459182007Sroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
460182007Sroberto			      "/proc/net/if_inet6:iter->proc == NULL");
461182007Sroberto		return (ISC_R_FAILURE);
462132451Sroberto	}
463182007Sroberto
464182007Sroberto	/*
465182007Sroberto	 * Format for /proc/net/if_inet6:
466182007Sroberto	 * (see iface_proc_info() in net/ipv6/addrconf.c)
467182007Sroberto	 * <addr6:32> <ifindex:2> <prefix:2> <scope:2> <flags:2> <name:8>
468182007Sroberto	 */
469182007Sroberto	res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n",
470182007Sroberto		     address, &ifindex, &prefix, &scope, &flags, name);
471182007Sroberto	if (res != 6) {
472182007Sroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
473182007Sroberto			      "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
474182007Sroberto			      res);
475182007Sroberto		return (ISC_R_FAILURE);
476182007Sroberto	}
477182007Sroberto	if (strlen(address) != 32) {
478182007Sroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
479182007Sroberto			      "/proc/net/if_inet6:strlen(%s) != 32", address);
480182007Sroberto		return (ISC_R_FAILURE);
481182007Sroberto	}
482182007Sroberto	for (i = 0; i < 16; i++) {
483182007Sroberto		unsigned char byte;
484182007Sroberto		static const char hex[] = "0123456789abcdef";
485182007Sroberto		byte = ((index(hex, address[i * 2]) - hex) << 4) |
486182007Sroberto		       (index(hex, address[i * 2 + 1]) - hex);
487182007Sroberto		addr6.s6_addr[i] = byte;
488182007Sroberto	}
489182007Sroberto	iter->current.af = AF_INET6;
490182007Sroberto	/* iter->current.ifindex = ifindex; */
491182007Sroberto	iter->current.flags = 0;
492182007Sroberto
493182007Sroberto	memset(&ifreq, 0, sizeof(ifreq));
494182007Sroberto	INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
495182007Sroberto	strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
496182007Sroberto
497182007Sroberto	if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
498182007Sroberto		isc__strerror(errno, strbuf, sizeof(strbuf));
499182007Sroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
500182007Sroberto				 "%s: getting interface flags: %s",
501182007Sroberto				 ifreq.ifr_name, strbuf);
502182007Sroberto		return (ISC_R_IGNORE);
503182007Sroberto	}
504182007Sroberto
505182007Sroberto	if ((ifreq.ifr_flags & IFF_UP) != 0)
506182007Sroberto		iter->current.flags |= INTERFACE_F_UP;
507182007Sroberto#ifdef IFF_POINTOPOINT
508182007Sroberto	if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
509182007Sroberto		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
510182007Sroberto#endif
511182007Sroberto	if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
512182007Sroberto		iter->current.flags |= INTERFACE_F_LOOPBACK;
513182007Sroberto	if ((ifreq.ifr_flags & IFF_BROADCAST) != 0)
514182007Sroberto		iter->current.flags |= INTERFACE_F_BROADCAST;
515182007Sroberto#ifdef IFF_MULTICAST
516182007Sroberto	if ((ifreq.ifr_flags & IFF_MULTICAST) != 0)
517182007Sroberto		iter->current.flags |= INTERFACE_F_MULTICAST;
518182007Sroberto#endif
519182007Sroberto
520182007Sroberto	/*
521182007Sroberto	 * enable_multicast_if() requires scopeid for setsockopt,
522182007Sroberto	 * so associate address with their corresponding ifindex.
523182007Sroberto	 */
524182007Sroberto	isc_netaddr_fromin6(&iter->current.address, &addr6);
525182007Sroberto	isc_netaddr_setzone(&iter->current.address, (isc_uint32_t)ifindex);
526182007Sroberto
527182007Sroberto	for (i = 0; i < 16; i++) {
528182007Sroberto		if (prefix > 8) {
529182007Sroberto			addr6.s6_addr[i] = 0xff;
530182007Sroberto			prefix -= 8;
531182007Sroberto		} else {
532182007Sroberto			addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
533182007Sroberto			prefix = 0;
534182007Sroberto		}
535182007Sroberto	}
536182007Sroberto	isc_netaddr_fromin6(&iter->current.netmask, &addr6);
537182007Sroberto	strncpy(iter->current.name, name, sizeof(iter->current.name));
538182007Sroberto	return (ISC_R_SUCCESS);
539132451Sroberto}
540132451Sroberto#endif
541132451Sroberto
542132451Sroberto/*
543132451Sroberto * Get information about the current interface to iter->current.
544132451Sroberto * If successful, return ISC_R_SUCCESS.
545132451Sroberto * If the interface has an unsupported address family, or if
546132451Sroberto * some operation on it fails, return ISC_R_IGNORE to make
547132451Sroberto * the higher-level iterator code ignore it.
548132451Sroberto */
549132451Sroberto
550132451Srobertostatic isc_result_t
551132451Srobertointernal_current4(isc_interfaceiter_t *iter) {
552132451Sroberto	struct ifreq *ifrp;
553132451Sroberto	struct ifreq ifreq;
554132451Sroberto	int family;
555132451Sroberto	char strbuf[ISC_STRERRORSIZE];
556182007Sroberto#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
557182007Sroberto	struct lifreq lifreq;
558182007Sroberto#else
559182007Sroberto	char sabuf[256];
560132451Sroberto#endif
561182007Sroberto	int i, bits, prefixlen;
562182007Sroberto#ifdef __linux
563182007Sroberto	isc_result_t result;
564182007Sroberto#endif
565132451Sroberto
566132451Sroberto	REQUIRE(VALID_IFITER(iter));
567132451Sroberto	REQUIRE (iter->pos < (unsigned int) iter->ifc.ifc_len);
568132451Sroberto
569182007Sroberto#ifdef __linux
570182007Sroberto	result = linux_if_inet6_current(iter);
571182007Sroberto	if (result != ISC_R_NOMORE)
572182007Sroberto		return (result);
573182007Sroberto	iter->first = ISC_TRUE;
574182007Sroberto#endif
575182007Sroberto
576132451Sroberto	ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
577132451Sroberto
578132451Sroberto	memset(&ifreq, 0, sizeof(ifreq));
579132451Sroberto	memcpy(&ifreq, ifrp, sizeof(ifreq));
580132451Sroberto
581132451Sroberto	family = ifreq.ifr_addr.sa_family;
582182007Sroberto#if defined(ISC_PLATFORM_HAVEIPV6)
583132451Sroberto	if (family != AF_INET && family != AF_INET6)
584132451Sroberto#else
585132451Sroberto	if (family != AF_INET)
586132451Sroberto#endif
587132451Sroberto		return (ISC_R_IGNORE);
588132451Sroberto
589132451Sroberto	memset(&iter->current, 0, sizeof(iter->current));
590132451Sroberto	iter->current.af = family;
591132451Sroberto
592132451Sroberto	INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
593132451Sroberto	memset(iter->current.name, 0, sizeof(iter->current.name));
594132451Sroberto	memcpy(iter->current.name, ifreq.ifr_name, sizeof(ifreq.ifr_name));
595132451Sroberto
596132451Sroberto	get_addr(family, &iter->current.address,
597182007Sroberto		 (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name);
598132451Sroberto
599132451Sroberto	/*
600132451Sroberto	 * If the interface does not have a address ignore it.
601132451Sroberto	 */
602132451Sroberto	switch (family) {
603132451Sroberto	case AF_INET:
604132451Sroberto		if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
605132451Sroberto			return (ISC_R_IGNORE);
606132451Sroberto		break;
607182007Sroberto#ifdef ISC_PLATFORM_HAVEIPV6
608132451Sroberto	case AF_INET6:
609132451Sroberto		if (memcmp(&iter->current.address.type.in6, &in6addr_any,
610132451Sroberto			   sizeof(in6addr_any)) == 0)
611132451Sroberto			return (ISC_R_IGNORE);
612132451Sroberto		break;
613182007Sroberto#endif
614132451Sroberto	}
615132451Sroberto
616132451Sroberto	/*
617132451Sroberto	 * Get interface flags.
618132451Sroberto	 */
619132451Sroberto
620132451Sroberto	iter->current.flags = 0;
621132451Sroberto
622132451Sroberto	/*
623132451Sroberto	 * Ignore the HP/UX warning about "integer overflow during
624132451Sroberto	 * conversion.  It comes from its own macro definition,
625132451Sroberto	 * and is really hard to shut up.
626132451Sroberto	 */
627132451Sroberto	if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
628132451Sroberto		isc__strerror(errno, strbuf, sizeof(strbuf));
629132451Sroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
630132451Sroberto				 "%s: getting interface flags: %s",
631132451Sroberto				 ifreq.ifr_name, strbuf);
632132451Sroberto		return (ISC_R_IGNORE);
633132451Sroberto	}
634132451Sroberto
635132451Sroberto	if ((ifreq.ifr_flags & IFF_UP) != 0)
636132451Sroberto		iter->current.flags |= INTERFACE_F_UP;
637132451Sroberto
638182007Sroberto#ifdef IFF_POINTOPOINT
639132451Sroberto	if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
640132451Sroberto		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
641182007Sroberto#endif
642132451Sroberto
643132451Sroberto	if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
644132451Sroberto		iter->current.flags |= INTERFACE_F_LOOPBACK;
645132451Sroberto
646132451Sroberto	if ((ifreq.ifr_flags & IFF_BROADCAST) != 0) {
647132451Sroberto		iter->current.flags |= INTERFACE_F_BROADCAST;
648132451Sroberto	}
649132451Sroberto
650132451Sroberto#ifdef IFF_MULTICAST
651132451Sroberto	if ((ifreq.ifr_flags & IFF_MULTICAST) != 0) {
652132451Sroberto		iter->current.flags |= INTERFACE_F_MULTICAST;
653132451Sroberto	}
654132451Sroberto#endif
655132451Sroberto
656182007Sroberto	if (family == AF_INET)
657132451Sroberto		goto inet;
658132451Sroberto
659182007Sroberto#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
660182007Sroberto	memset(&lifreq, 0, sizeof(lifreq));
661182007Sroberto	memcpy(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name));
662182007Sroberto	memcpy(&lifreq.lifr_addr, &iter->current.address.type.in6,
663132451Sroberto	       sizeof(iter->current.address.type.in6));
664132451Sroberto
665182007Sroberto	if (ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) {
666132451Sroberto		isc__strerror(errno, strbuf, sizeof(strbuf));
667132451Sroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
668132451Sroberto				 "%s: getting interface address: %s",
669132451Sroberto				 ifreq.ifr_name, strbuf);
670132451Sroberto		return (ISC_R_IGNORE);
671132451Sroberto	}
672182007Sroberto	prefixlen = lifreq.lifr_addrlen;
673182007Sroberto#else
674182007Sroberto	isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf));
675182007Sroberto	UNEXPECTED_ERROR(__FILE__, __LINE__,
676182007Sroberto		      isc_msgcat_get(isc_msgcat,
677182007Sroberto				     ISC_MSGSET_IFITERIOCTL,
678182007Sroberto				     ISC_MSG_GETIFCONFIG,
679182007Sroberto				     "prefix length for %s is unknown "
680182007Sroberto				     "(assume 128)"), sabuf);
681182007Sroberto	prefixlen = 128;
682182007Sroberto#endif
683132451Sroberto
684132451Sroberto	/*
685132451Sroberto	 * Netmask already zeroed.
686132451Sroberto	 */
687132451Sroberto	iter->current.netmask.family = family;
688132451Sroberto	for (i = 0; i < 16; i++) {
689182007Sroberto		if (prefixlen > 8) {
690132451Sroberto			bits = 0;
691182007Sroberto			prefixlen -= 8;
692132451Sroberto		} else {
693182007Sroberto			bits = 8 - prefixlen;
694182007Sroberto			prefixlen = 0;
695132451Sroberto		}
696132451Sroberto		iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff;
697132451Sroberto	}
698132451Sroberto	return (ISC_R_SUCCESS);
699132451Sroberto
700132451Sroberto inet:
701132451Sroberto	if (family != AF_INET)
702132451Sroberto		return (ISC_R_IGNORE);
703182007Sroberto#ifdef IFF_POINTOPOINT
704132451Sroberto	/*
705132451Sroberto	 * If the interface is point-to-point, get the destination address.
706132451Sroberto	 */
707132451Sroberto	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
708132451Sroberto		/*
709132451Sroberto		 * Ignore the HP/UX warning about "integer overflow during
710132451Sroberto		 * conversion.  It comes from its own macro definition,
711132451Sroberto		 * and is really hard to shut up.
712132451Sroberto		 */
713132451Sroberto		if (ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq)
714132451Sroberto		    < 0) {
715132451Sroberto			isc__strerror(errno, strbuf, sizeof(strbuf));
716132451Sroberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
717132451Sroberto				isc_msgcat_get(isc_msgcat,
718132451Sroberto					       ISC_MSGSET_IFITERIOCTL,
719132451Sroberto					       ISC_MSG_GETDESTADDR,
720132451Sroberto					       "%s: getting "
721132451Sroberto					       "destination address: %s"),
722132451Sroberto					 ifreq.ifr_name, strbuf);
723132451Sroberto			return (ISC_R_IGNORE);
724132451Sroberto		}
725132451Sroberto		get_addr(family, &iter->current.dstaddress,
726182007Sroberto			 (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name);
727132451Sroberto	}
728182007Sroberto#endif
729132451Sroberto	if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
730132451Sroberto		/*
731132451Sroberto		 * Ignore the HP/UX warning about "integer overflow during
732132451Sroberto		 * conversion.  It comes from its own macro definition,
733132451Sroberto		 * and is really hard to shut up.
734132451Sroberto		 */
735132451Sroberto		if (ioctl(iter->socket, SIOCGIFBRDADDR, (char *)&ifreq)
736132451Sroberto		    < 0) {
737132451Sroberto			isc__strerror(errno, strbuf, sizeof(strbuf));
738132451Sroberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
739132451Sroberto				isc_msgcat_get(isc_msgcat,
740132451Sroberto					       ISC_MSGSET_IFITERIOCTL,
741132451Sroberto					       ISC_MSG_GETDESTADDR,
742132451Sroberto					       "%s: getting "
743132451Sroberto					       "broadcast address: %s"),
744132451Sroberto					 ifreq.ifr_name, strbuf);
745132451Sroberto			return (ISC_R_IGNORE);
746132451Sroberto		}
747132451Sroberto		get_addr(family, &iter->current.broadcast,
748182007Sroberto			 (struct sockaddr *)&ifreq.ifr_broadaddr, ifreq.ifr_name);
749132451Sroberto	}
750182007Sroberto
751132451Sroberto	/*
752132451Sroberto	 * Get the network mask.
753132451Sroberto	 */
754132451Sroberto	memset(&ifreq, 0, sizeof(ifreq));
755132451Sroberto	memcpy(&ifreq, ifrp, sizeof(ifreq));
756132451Sroberto	/*
757132451Sroberto	 * Ignore the HP/UX warning about "integer overflow during
758132451Sroberto	 * conversion.  It comes from its own macro definition,
759132451Sroberto	 * and is really hard to shut up.
760132451Sroberto	 */
761182007Sroberto	if (ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
762132451Sroberto		isc__strerror(errno, strbuf, sizeof(strbuf));
763132451Sroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
764132451Sroberto			isc_msgcat_get(isc_msgcat,
765132451Sroberto				       ISC_MSGSET_IFITERIOCTL,
766132451Sroberto				       ISC_MSG_GETNETMASK,
767132451Sroberto				       "%s: getting netmask: %s"),
768132451Sroberto				       ifreq.ifr_name, strbuf);
769132451Sroberto		return (ISC_R_IGNORE);
770132451Sroberto	}
771132451Sroberto	get_addr(family, &iter->current.netmask,
772182007Sroberto		 (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name);
773132451Sroberto	return (ISC_R_SUCCESS);
774132451Sroberto}
775132451Sroberto
776182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
777132451Srobertostatic isc_result_t
778132451Srobertointernal_current6(isc_interfaceiter_t *iter) {
779132451Sroberto	struct LIFREQ *ifrp;
780132451Sroberto	struct LIFREQ lifreq;
781132451Sroberto	int family;
782132451Sroberto	char strbuf[ISC_STRERRORSIZE];
783182007Sroberto	int fd;
784132451Sroberto
785132451Sroberto	REQUIRE(VALID_IFITER(iter));
786182007Sroberto	if (iter->result6 != ISC_R_SUCCESS)
787182007Sroberto		return (iter->result6);
788182007Sroberto	REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
789132451Sroberto
790182007Sroberto	ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
791132451Sroberto
792132451Sroberto	memset(&lifreq, 0, sizeof(lifreq));
793132451Sroberto	memcpy(&lifreq, ifrp, sizeof(lifreq));
794132451Sroberto
795132451Sroberto	family = lifreq.lifr_addr.ss_family;
796132451Sroberto#ifdef ISC_PLATFORM_HAVEIPV6
797132451Sroberto	if (family != AF_INET && family != AF_INET6)
798132451Sroberto#else
799132451Sroberto	if (family != AF_INET)
800132451Sroberto#endif
801132451Sroberto		return (ISC_R_IGNORE);
802132451Sroberto
803132451Sroberto	memset(&iter->current, 0, sizeof(iter->current));
804132451Sroberto	iter->current.af = family;
805132451Sroberto
806132451Sroberto	INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name));
807132451Sroberto	memset(iter->current.name, 0, sizeof(iter->current.name));
808132451Sroberto	memcpy(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name));
809132451Sroberto
810132451Sroberto	get_addr(family, &iter->current.address,
811182007Sroberto		 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
812132451Sroberto
813132451Sroberto	/*
814132451Sroberto	 * If the interface does not have a address ignore it.
815132451Sroberto	 */
816132451Sroberto	switch (family) {
817132451Sroberto	case AF_INET:
818132451Sroberto		if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
819132451Sroberto			return (ISC_R_IGNORE);
820132451Sroberto		break;
821182007Sroberto#ifdef ISC_PLATFORM_HAVEIPV6
822132451Sroberto	case AF_INET6:
823132451Sroberto		if (memcmp(&iter->current.address.type.in6, &in6addr_any,
824132451Sroberto			   sizeof(in6addr_any)) == 0)
825132451Sroberto			return (ISC_R_IGNORE);
826132451Sroberto		break;
827182007Sroberto#endif
828132451Sroberto	}
829132451Sroberto
830132451Sroberto	/*
831132451Sroberto	 * Get interface flags.
832132451Sroberto	 */
833132451Sroberto
834132451Sroberto	iter->current.flags = 0;
835132451Sroberto
836182007Sroberto	if (family == AF_INET6)
837182007Sroberto		fd = iter->socket6;
838182007Sroberto	else
839182007Sroberto		fd = iter->socket;
840182007Sroberto
841132451Sroberto	/*
842132451Sroberto	 * Ignore the HP/UX warning about "integer overflow during
843132451Sroberto	 * conversion.  It comes from its own macro definition,
844132451Sroberto	 * and is really hard to shut up.
845132451Sroberto	 */
846182007Sroberto	if (ioctl(fd, SIOCGLIFFLAGS, (char *) &lifreq) < 0) {
847182007Sroberto		isc__strerror(errno, strbuf, sizeof(strbuf));
848182007Sroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
849132451Sroberto				 "%s: getting interface flags: %s",
850132451Sroberto				 lifreq.lifr_name, strbuf);
851182007Sroberto		return (ISC_R_IGNORE);
852132451Sroberto	}
853132451Sroberto
854132451Sroberto	if ((lifreq.lifr_flags & IFF_UP) != 0)
855132451Sroberto		iter->current.flags |= INTERFACE_F_UP;
856132451Sroberto
857182007Sroberto#ifdef IFF_POINTOPOINT
858132451Sroberto	if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0)
859132451Sroberto		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
860182007Sroberto#endif
861132451Sroberto
862132451Sroberto	if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0)
863132451Sroberto		iter->current.flags |= INTERFACE_F_LOOPBACK;
864132451Sroberto
865182007Sroberto	if ((lifreq.lifr_flags & IFF_BROADCAST) != 0) {
866182007Sroberto		iter->current.flags |= INTERFACE_F_BROADCAST;
867182007Sroberto	}
868132451Sroberto
869132451Sroberto#ifdef IFF_MULTICAST
870132451Sroberto	if ((lifreq.lifr_flags & IFF_MULTICAST) != 0) {
871132451Sroberto		iter->current.flags |= INTERFACE_F_MULTICAST;
872132451Sroberto	}
873132451Sroberto#endif
874132451Sroberto
875182007Sroberto#ifdef IFF_POINTOPOINT
876132451Sroberto	/*
877132451Sroberto	 * If the interface is point-to-point, get the destination address.
878132451Sroberto	 */
879132451Sroberto	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
880132451Sroberto		/*
881132451Sroberto		 * Ignore the HP/UX warning about "interger overflow during
882132451Sroberto		 * conversion.  It comes from its own macro definition,
883132451Sroberto		 * and is really hard to shut up.
884132451Sroberto		 */
885182007Sroberto		if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq)
886132451Sroberto		    < 0) {
887132451Sroberto			isc__strerror(errno, strbuf, sizeof(strbuf));
888132451Sroberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
889132451Sroberto				isc_msgcat_get(isc_msgcat,
890132451Sroberto					       ISC_MSGSET_IFITERIOCTL,
891132451Sroberto					       ISC_MSG_GETDESTADDR,
892132451Sroberto					       "%s: getting "
893132451Sroberto					       "destination address: %s"),
894132451Sroberto					 lifreq.lifr_name, strbuf);
895132451Sroberto			return (ISC_R_IGNORE);
896132451Sroberto		}
897132451Sroberto		get_addr(family, &iter->current.dstaddress,
898182007Sroberto			 (struct sockaddr *)&lifreq.lifr_dstaddr,
899182007Sroberto			 lifreq.lifr_name);
900132451Sroberto	}
901182007Sroberto#endif
902132451Sroberto
903182007Sroberto#ifdef SIOCGLIFBRDADDR
904182007Sroberto	if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
905132451Sroberto		/*
906132451Sroberto		 * Ignore the HP/UX warning about "integer overflow during
907132451Sroberto		 * conversion.  It comes from its own macro definition,
908132451Sroberto		 * and is really hard to shut up.
909132451Sroberto		 */
910182007Sroberto		if (ioctl(iter->socket, SIOCGLIFBRDADDR, (char *)&lifreq)
911132451Sroberto		    < 0) {
912132451Sroberto			isc__strerror(errno, strbuf, sizeof(strbuf));
913132451Sroberto			UNEXPECTED_ERROR(__FILE__, __LINE__,
914132451Sroberto				isc_msgcat_get(isc_msgcat,
915132451Sroberto					       ISC_MSGSET_IFITERIOCTL,
916182007Sroberto					       ISC_MSG_GETDESTADDR,
917182007Sroberto					       "%s: getting "
918182007Sroberto					       "broadcast address: %s"),
919132451Sroberto					 lifreq.lifr_name, strbuf);
920132451Sroberto			return (ISC_R_IGNORE);
921132451Sroberto		}
922182007Sroberto		get_addr(family, &iter->current.broadcast,
923182007Sroberto			 (struct sockaddr *)&lifreq.lifr_broadaddr,
924182007Sroberto			 lifreq.lifr_name);
925182007Sroberto	}
926182007Sroberto#endif	/* SIOCGLIFBRDADDR */
927182007Sroberto
928182007Sroberto	/*
929182007Sroberto	 * Get the network mask.  Netmask already zeroed.
930182007Sroberto	 */
931182007Sroberto	memset(&lifreq, 0, sizeof(lifreq));
932182007Sroberto	memcpy(&lifreq, ifrp, sizeof(lifreq));
933182007Sroberto
934132451Sroberto#ifdef lifr_addrlen
935182007Sroberto	/*
936182007Sroberto	 * Special case: if the system provides lifr_addrlen member, the
937182007Sroberto	 * netmask of an IPv6 address can be derived from the length, since
938182007Sroberto	 * an IPv6 address always has a contiguous mask.
939182007Sroberto	 */
940182007Sroberto	if (family == AF_INET6) {
941132451Sroberto		int i, bits;
942132451Sroberto
943132451Sroberto		iter->current.netmask.family = family;
944132451Sroberto		for (i = 0; i < lifreq.lifr_addrlen; i += 8) {
945132451Sroberto			bits = lifreq.lifr_addrlen - i;
946132451Sroberto			bits = (bits < 8) ? (8 - bits) : 0;
947132451Sroberto			iter->current.netmask.type.in6.s6_addr[i / 8] =
948132451Sroberto				(~0 << bits) & 0xff;
949132451Sroberto		}
950182007Sroberto
951182007Sroberto		return (ISC_R_SUCCESS);
952182007Sroberto	}
953132451Sroberto#endif
954182007Sroberto
955182007Sroberto	/*
956182007Sroberto	 * Ignore the HP/UX warning about "integer overflow during
957182007Sroberto	 * conversion.  It comes from its own macro definition,
958182007Sroberto	 * and is really hard to shut up.
959182007Sroberto	 */
960182007Sroberto	if (ioctl(fd, SIOCGLIFNETMASK, (char *)&lifreq) < 0) {
961182007Sroberto		isc__strerror(errno, strbuf, sizeof(strbuf));
962182007Sroberto		UNEXPECTED_ERROR(__FILE__, __LINE__,
963182007Sroberto				 isc_msgcat_get(isc_msgcat,
964182007Sroberto						ISC_MSGSET_IFITERIOCTL,
965182007Sroberto						ISC_MSG_GETNETMASK,
966182007Sroberto						"%s: getting netmask: %s"),
967182007Sroberto				 lifreq.lifr_name, strbuf);
968182007Sroberto		return (ISC_R_IGNORE);
969132451Sroberto	}
970182007Sroberto	get_addr(family, &iter->current.netmask,
971182007Sroberto		 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
972132451Sroberto
973132451Sroberto	return (ISC_R_SUCCESS);
974182007Sroberto}
975132451Sroberto#endif
976132451Sroberto
977132451Srobertostatic isc_result_t
978132451Srobertointernal_current(isc_interfaceiter_t *iter) {
979182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
980182007Sroberto	if (iter->mode == 6) {
981182007Sroberto		iter->result6 = internal_current6(iter);
982182007Sroberto		if (iter->result6 != ISC_R_NOMORE)
983182007Sroberto			return (iter->result6);
984182007Sroberto	}
985182007Sroberto#endif
986182007Sroberto#ifdef HAVE_TRUCLUSTER
987182007Sroberto	if (!iter->clua_done)
988182007Sroberto		return(internal_current_clusteralias(iter));
989182007Sroberto#endif
990132451Sroberto	return (internal_current4(iter));
991132451Sroberto}
992132451Sroberto
993132451Sroberto/*
994132451Sroberto * Step the iterator to the next interface.  Unlike
995132451Sroberto * isc_interfaceiter_next(), this may leave the iterator
996132451Sroberto * positioned on an interface that will ultimately
997132451Sroberto * be ignored.  Return ISC_R_NOMORE if there are no more
998132451Sroberto * interfaces, otherwise ISC_R_SUCCESS.
999132451Sroberto */
1000132451Srobertostatic isc_result_t
1001132451Srobertointernal_next4(isc_interfaceiter_t *iter) {
1002132451Sroberto	struct ifreq *ifrp;
1003132451Sroberto
1004132451Sroberto	REQUIRE (iter->pos < (unsigned int) iter->ifc.ifc_len);
1005132451Sroberto
1006182007Sroberto#ifdef __linux
1007182007Sroberto	if (linux_if_inet6_next(iter) == ISC_R_SUCCESS)
1008132451Sroberto		return (ISC_R_SUCCESS);
1009182007Sroberto	if (!iter->first)
1010182007Sroberto		return (ISC_R_SUCCESS);
1011132451Sroberto#endif
1012132451Sroberto	ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
1013132451Sroberto
1014132451Sroberto#ifdef ISC_PLATFORM_HAVESALEN
1015132451Sroberto	if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
1016132451Sroberto		iter->pos += sizeof(ifrp->ifr_name) + ifrp->ifr_addr.sa_len;
1017132451Sroberto	else
1018132451Sroberto#endif
1019132451Sroberto		iter->pos += sizeof(*ifrp);
1020132451Sroberto
1021132451Sroberto	if (iter->pos >= (unsigned int) iter->ifc.ifc_len)
1022132451Sroberto		return (ISC_R_NOMORE);
1023132451Sroberto
1024132451Sroberto	return (ISC_R_SUCCESS);
1025132451Sroberto}
1026132451Sroberto
1027182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1028132451Srobertostatic isc_result_t
1029132451Srobertointernal_next6(isc_interfaceiter_t *iter) {
1030132451Sroberto	struct LIFREQ *ifrp;
1031182007Sroberto
1032182007Sroberto	if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE)
1033182007Sroberto		return (iter->result6);
1034132451Sroberto
1035182007Sroberto	REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
1036132451Sroberto
1037182007Sroberto	ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
1038132451Sroberto
1039132451Sroberto#ifdef ISC_PLATFORM_HAVESALEN
1040132451Sroberto	if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr))
1041182007Sroberto		iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len;
1042132451Sroberto	else
1043132451Sroberto#endif
1044182007Sroberto		iter->pos6 += sizeof(*ifrp);
1045132451Sroberto
1046182007Sroberto	if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len)
1047132451Sroberto		return (ISC_R_NOMORE);
1048132451Sroberto
1049132451Sroberto	return (ISC_R_SUCCESS);
1050182007Sroberto}
1051132451Sroberto#endif
1052132451Sroberto
1053132451Srobertostatic isc_result_t
1054132451Srobertointernal_next(isc_interfaceiter_t *iter) {
1055182007Sroberto#ifdef HAVE_TRUCLUSTER
1056182007Sroberto	int clua_result;
1057182007Sroberto#endif
1058182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1059182007Sroberto	if (iter->mode == 6) {
1060182007Sroberto		iter->result6 = internal_next6(iter);
1061182007Sroberto		if (iter->result6 != ISC_R_NOMORE)
1062182007Sroberto			return (iter->result6);
1063182007Sroberto		if (iter->first6) {
1064182007Sroberto			iter->first6 = ISC_FALSE;
1065182007Sroberto			return (ISC_R_SUCCESS);
1066182007Sroberto		}
1067182007Sroberto	}
1068182007Sroberto#endif
1069182007Sroberto#ifdef HAVE_TRUCLUSTER
1070182007Sroberto	if (!iter->clua_done) {
1071182007Sroberto		clua_result = clua_getaliasaddress(&iter->clua_sa,
1072182007Sroberto						   &iter->clua_context);
1073182007Sroberto		if (clua_result != CLUA_SUCCESS)
1074182007Sroberto			iter->clua_done = ISC_TRUE;
1075182007Sroberto		return (ISC_R_SUCCESS);
1076182007Sroberto	}
1077182007Sroberto#endif
1078132451Sroberto	return (internal_next4(iter));
1079132451Sroberto}
1080132451Sroberto
1081132451Srobertostatic void
1082132451Srobertointernal_destroy(isc_interfaceiter_t *iter) {
1083132451Sroberto	(void) close(iter->socket);
1084182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1085182007Sroberto	if (iter->socket6 != -1)
1086182007Sroberto		(void) close(iter->socket6);
1087182007Sroberto	if (iter->buf6 != NULL) {
1088182007Sroberto		isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
1089182007Sroberto	}
1090182007Sroberto#endif
1091182007Sroberto#ifdef __linux
1092182007Sroberto	if (iter->proc != NULL)
1093182007Sroberto		fclose(iter->proc);
1094182007Sroberto#endif
1095132451Sroberto}
1096182007Sroberto
1097182007Srobertostatic
1098182007Srobertovoid internal_first(isc_interfaceiter_t *iter) {
1099182007Sroberto#ifdef HAVE_TRUCLUSTER
1100182007Sroberto	int clua_result;
1101182007Sroberto#endif
1102182007Sroberto	iter->pos = 0;
1103182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1104182007Sroberto	iter->pos6 = 0;
1105182007Sroberto	if (iter->result6 == ISC_R_NOMORE)
1106182007Sroberto		iter->result6 = ISC_R_SUCCESS;
1107182007Sroberto	iter->first6 = ISC_TRUE;
1108182007Sroberto#endif
1109182007Sroberto#ifdef HAVE_TRUCLUSTER
1110182007Sroberto	iter->clua_context = 0;
1111182007Sroberto	clua_result = clua_getaliasaddress(&iter->clua_sa,
1112182007Sroberto					   &iter->clua_context);
1113182007Sroberto	iter->clua_done = ISC_TF(clua_result != CLUA_SUCCESS);
1114182007Sroberto#endif
1115182007Sroberto#ifdef __linux
1116182007Sroberto	linux_if_inet6_first(iter);
1117182007Sroberto#endif
1118182007Sroberto}
1119