1129198Scognet/*
2129198Scognet * Copyright (C) 2004-2009, 2014  Internet Systems Consortium, Inc. ("ISC")
3139735Simp * Copyright (C) 1999-2003  Internet Software Consortium.
4129198Scognet *
5129198Scognet * Permission to use, copy, modify, and/or distribute this software for any
6129198Scognet * purpose with or without fee is hereby granted, provided that the above
7129198Scognet * copyright notice and this permission notice appear in all copies.
8129198Scognet *
9129198Scognet * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10129198Scognet * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11129198Scognet * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12129198Scognet * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13129198Scognet * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14129198Scognet * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15129198Scognet * PERFORMANCE OF THIS SOFTWARE.
16129198Scognet */
17129198Scognet
18129198Scognet/* $Id: ifiter_ioctl.c,v 1.62 2009/01/18 23:48:14 tbox Exp $ */
19129198Scognet
20129198Scognet/*! \file
21129198Scognet * \brief
22129198Scognet * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl.
23129198Scognet * See netintro(4).
24129198Scognet */
25129198Scognet
26129198Scognet#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
27129198Scognet#ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
28129198Scognet#define lifc_len iflc_len
29129198Scognet#define lifc_buf iflc_buf
30129198Scognet#define lifc_req iflc_req
31129198Scognet#define LIFCONF if_laddrconf
32129198Scognet#else
33129198Scognet#define ISC_HAVE_LIFC_FAMILY 1
34236991Simp#define ISC_HAVE_LIFC_FLAGS 1
35129198Scognet#define LIFCONF lifconf
36129198Scognet#endif
37129198Scognet
38129198Scognet#ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
39129198Scognet#define lifr_addr iflr_addr
40129198Scognet#define lifr_name iflr_name
41129198Scognet#define lifr_dstaddr iflr_dstaddr
42129198Scognet#define lifr_flags iflr_flags
43129198Scognet#define ss_family sa_family
44129198Scognet#define LIFREQ if_laddrreq
45129198Scognet#else
46129198Scognet#define LIFREQ lifreq
47129198Scognet#endif
48129198Scognet#endif
49129198Scognet
50129198Scognet#define IFITER_MAGIC		ISC_MAGIC('I', 'F', 'I', 'T')
51129198Scognet#define VALID_IFITER(t)		ISC_MAGIC_VALID(t, IFITER_MAGIC)
52129198Scognet
53248361Sandrewstruct isc_interfaceiter {
54129198Scognet	unsigned int		magic;		/* Magic number. */
55129198Scognet	isc_mem_t		*mctx;
56129198Scognet	int			mode;
57129198Scognet	int			socket;
58129198Scognet	struct ifconf 		ifc;
59129198Scognet	void			*buf;		/* Buffer for sysctl data. */
60129198Scognet	unsigned int		bufsize;	/* Bytes allocated. */
61129198Scognet	unsigned int		pos;		/* Current offset in
62248361Sandrew						   SIOCGIFCONF data */
63129198Scognet#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
64129198Scognet	int			socket6;
65129198Scognet	struct LIFCONF 		lifc;
66129198Scognet	void			*buf6;		/* Buffer for sysctl data. */
67248361Sandrew	unsigned int		bufsize6;	/* Bytes allocated. */
68129198Scognet	unsigned int		pos6;		/* Current offset in
69129198Scognet						   SIOCGLIFCONF data */
70129198Scognet	isc_result_t		result6;	/* Last result code. */
71129198Scognet	isc_boolean_t		first6;
72129198Scognet#endif
73129198Scognet#ifdef HAVE_TRUCLUSTER
74129198Scognet	int			clua_context;	/* Cluster alias context */
75129198Scognet	isc_boolean_t		clua_done;
76129198Scognet	struct sockaddr		clua_sa;
77129198Scognet#endif
78129198Scognet#ifdef	__linux
79129198Scognet	FILE *			proc;
80129198Scognet	char			entry[ISC_IF_INET6_SZ];
81129198Scognet	isc_result_t		valid;
82129198Scognet#endif
83129198Scognet	isc_interface_t		current;	/* Current interface data. */
84129198Scognet	isc_result_t		result;		/* Last result code. */
85129198Scognet};
86129198Scognet
87129198Scognet#ifdef HAVE_TRUCLUSTER
88129198Scognet#include <clua/clua.h>
89129198Scognet#include <sys/socket.h>
90129198Scognet#endif
91129198Scognet
92246001Sian
93129198Scognet/*%
94129198Scognet * Size of buffer for SIOCGLIFCONF, in bytes.  We assume no sane system
95248361Sandrew * will have more than a megabyte of interface configuration data.
96129198Scognet */
97129198Scognet#define IFCONF_BUFSIZE_INITIAL	4096
98129198Scognet#define IFCONF_BUFSIZE_MAX	1048576
99129198Scognet
100129198Scognet#ifdef __linux
101129198Scognet#ifndef IF_NAMESIZE
102129198Scognet# ifdef IFNAMSIZ
103129198Scognet#  define IF_NAMESIZE  IFNAMSIZ
104129198Scognet# else
105129198Scognet#  define IF_NAMESIZE 16
106129198Scognet# endif
107129198Scognet#endif
108129198Scognet#endif
109129198Scognet
110129198Scognetstatic isc_result_t
111129198Scognetgetbuf4(isc_interfaceiter_t *iter) {
112129198Scognet	char strbuf[ISC_STRERRORSIZE];
113129198Scognet
114246001Sian	iter->bufsize = IFCONF_BUFSIZE_INITIAL;
115246001Sian
116129198Scognet	for (;;) {
117246001Sian		iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
118129198Scognet		if (iter->buf == NULL)
119129198Scognet			return (ISC_R_NOMEMORY);
120248361Sandrew
121129198Scognet		memset(&iter->ifc.ifc_len, 0, sizeof(iter->ifc.ifc_len));
122129198Scognet		iter->ifc.ifc_len = iter->bufsize;
123129198Scognet		iter->ifc.ifc_buf = iter->buf;
124129198Scognet		/*
125129198Scognet		 * Ignore the HP/UX warning about "integer overflow during
126129198Scognet		 * conversion".  It comes from its own macro definition,
127129198Scognet		 * and is really hard to shut up.
128129198Scognet		 */
129129198Scognet		if (ioctl(iter->socket, SIOCGIFCONF, (char *)&iter->ifc)
130129198Scognet		    == -1) {
131129198Scognet			if (errno != EINVAL) {
132129198Scognet				isc__strerror(errno, strbuf, sizeof(strbuf));
133129198Scognet				UNEXPECTED_ERROR(__FILE__, __LINE__,
134129198Scognet						 isc_msgcat_get(isc_msgcat,
135129198Scognet							ISC_MSGSET_IFITERIOCTL,
136129198Scognet							ISC_MSG_GETIFCONFIG,
137129198Scognet							"get interface "
138246001Sian							"configuration: %s"),
139129198Scognet						 strbuf);
140129198Scognet				goto unexpected;
141248361Sandrew			}
142129198Scognet			/*
143129198Scognet			 * EINVAL.  Retry with a bigger buffer.
144129198Scognet			 */
145129198Scognet		} else {
146129198Scognet			/*
147129198Scognet			 * The ioctl succeeded.
148129198Scognet			 * Some OS's just return what will fit rather
149129198Scognet			 * than set EINVAL if the buffer is too small
150129198Scognet			 * to fit all the interfaces in.  If
151129198Scognet			 * ifc.lifc_len is too near to the end of the
152129198Scognet			 * buffer we will grow it just in case and
153129198Scognet			 * retry.
154129198Scognet			 */
155129198Scognet			if (iter->ifc.ifc_len + 2 * sizeof(struct ifreq)
156246001Sian			    < iter->bufsize)
157129198Scognet				break;
158129198Scognet		}
159248361Sandrew		if (iter->bufsize >= IFCONF_BUFSIZE_MAX) {
160129198Scognet			UNEXPECTED_ERROR(__FILE__, __LINE__,
161129198Scognet					 isc_msgcat_get(isc_msgcat,
162129198Scognet							ISC_MSGSET_IFITERIOCTL,
163129198Scognet							ISC_MSG_BUFFERMAX,
164129198Scognet							"get interface "
165129198Scognet							"configuration: "
166129198Scognet							"maximum buffer "
167129198Scognet							"size exceeded"));
168129198Scognet			goto unexpected;
169129198Scognet		}
170129198Scognet		isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
171129198Scognet
172129198Scognet		iter->bufsize *= 2;
173129198Scognet	}
174129198Scognet	return (ISC_R_SUCCESS);
175129198Scognet
176129198Scognet unexpected:
177129198Scognet	isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
178246001Sian	iter->buf = NULL;
179129198Scognet	return (ISC_R_UNEXPECTED);
180129198Scognet}
181248361Sandrew
182129198Scognet#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
183129198Scognetstatic isc_result_t
184129198Scognetgetbuf6(isc_interfaceiter_t *iter) {
185129198Scognet	char strbuf[ISC_STRERRORSIZE];
186129198Scognet	isc_result_t result;
187129198Scognet
188129198Scognet	iter->bufsize6 = IFCONF_BUFSIZE_INITIAL;
189129198Scognet
190129198Scognet	for (;;) {
191129198Scognet		iter->buf6 = isc_mem_get(iter->mctx, iter->bufsize6);
192129198Scognet		if (iter->buf6 == NULL)
193129198Scognet			return (ISC_R_NOMEMORY);
194129198Scognet
195129198Scognet		memset(&iter->lifc, 0, sizeof(iter->lifc));
196129198Scognet#ifdef ISC_HAVE_LIFC_FAMILY
197246001Sian		iter->lifc.lifc_family = AF_INET6;
198129198Scognet#endif
199129198Scognet#ifdef ISC_HAVE_LIFC_FLAGS
200248361Sandrew		iter->lifc.lifc_flags = 0;
201129198Scognet#endif
202129198Scognet		iter->lifc.lifc_len = iter->bufsize6;
203129198Scognet		iter->lifc.lifc_buf = iter->buf6;
204129198Scognet		/*
205129198Scognet		 * Ignore the HP/UX warning about "integer overflow during
206129198Scognet		 * conversion".  It comes from its own macro definition,
207129198Scognet		 * and is really hard to shut up.
208129198Scognet		 */
209129198Scognet		if (ioctl(iter->socket6, SIOCGLIFCONF, (char *)&iter->lifc)
210129198Scognet		    == -1) {
211129198Scognet#ifdef __hpux
212269796Sian			/*
213129198Scognet			 * IPv6 interface scanning is not available on all
214129198Scognet			 * kernels w/ IPv6 sockets.
215129198Scognet			 */
216129198Scognet			if (errno == ENOENT) {
217129198Scognet				isc__strerror(errno, strbuf, sizeof(strbuf));
218129198Scognet				isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
219129198Scognet					      ISC_LOGMODULE_INTERFACE,
220246001Sian					      ISC_LOG_DEBUG(1),
221246001Sian					      isc_msgcat_get(isc_msgcat,
222129198Scognet							ISC_MSGSET_IFITERIOCTL,
223246001Sian							ISC_MSG_GETIFCONFIG,
224129198Scognet							"get interface "
225129198Scognet							"configuration: %s"),
226269796Sian					       strbuf);
227248361Sandrew				result = ISC_R_FAILURE;
228129198Scognet				goto cleanup;
229129198Scognet			}
230129198Scognet#endif
231129198Scognet			if (errno != EINVAL) {
232129198Scognet				isc__strerror(errno, strbuf, sizeof(strbuf));
233129198Scognet				UNEXPECTED_ERROR(__FILE__, __LINE__,
234129198Scognet						 isc_msgcat_get(isc_msgcat,
235129198Scognet							ISC_MSGSET_IFITERIOCTL,
236129198Scognet							ISC_MSG_GETIFCONFIG,
237129198Scognet							"get interface "
238129198Scognet							"configuration: %s"),
239129198Scognet						 strbuf);
240129198Scognet				result = ISC_R_UNEXPECTED;
241129198Scognet				goto cleanup;
242129198Scognet			}
243129198Scognet			/*
244129198Scognet			 * EINVAL.  Retry with a bigger buffer.
245129198Scognet			 */
246129198Scognet		} else {
247129198Scognet			/*
248129198Scognet			 * The ioctl succeeded.
249129198Scognet			 * Some OS's just return what will fit rather
250129198Scognet			 * than set EINVAL if the buffer is too small
251129198Scognet			 * to fit all the interfaces in.  If
252129198Scognet			 * ifc.ifc_len is too near to the end of the
253129198Scognet			 * buffer we will grow it just in case and
254129198Scognet			 * retry.
255248361Sandrew			 */
256129198Scognet			if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ)
257129198Scognet			    < iter->bufsize6)
258129198Scognet				break;
259129198Scognet		}
260129198Scognet		if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) {
261129198Scognet			UNEXPECTED_ERROR(__FILE__, __LINE__,
262129198Scognet					 isc_msgcat_get(isc_msgcat,
263129198Scognet							ISC_MSGSET_IFITERIOCTL,
264129198Scognet							ISC_MSG_BUFFERMAX,
265236991Simp							"get interface "
266129198Scognet							"configuration: "
267129198Scognet							"maximum buffer "
268129198Scognet							"size exceeded"));
269129198Scognet			result = ISC_R_UNEXPECTED;
270129198Scognet			goto cleanup;
271129198Scognet		}
272129198Scognet		isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
273129198Scognet
274129198Scognet		iter->bufsize6 *= 2;
275129198Scognet	}
276129198Scognet
277	if (iter->lifc.lifc_len != 0)
278		iter->mode = 6;
279	return (ISC_R_SUCCESS);
280
281 cleanup:
282	isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
283	iter->buf6 = NULL;
284	return (result);
285}
286#endif
287
288isc_result_t
289isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
290	isc_interfaceiter_t *iter;
291	isc_result_t result;
292	char strbuf[ISC_STRERRORSIZE];
293
294	REQUIRE(mctx != NULL);
295	REQUIRE(iterp != NULL);
296	REQUIRE(*iterp == NULL);
297
298	iter = isc_mem_get(mctx, sizeof(*iter));
299	if (iter == NULL)
300		return (ISC_R_NOMEMORY);
301
302	iter->mctx = mctx;
303	iter->mode = 4;
304	iter->buf = NULL;
305	iter->pos = (unsigned int) -1;
306#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
307	iter->buf6 = NULL;
308	iter->pos6 = (unsigned int) -1;
309	iter->result6 = ISC_R_NOMORE;
310	iter->socket6 = -1;
311	iter->first6 = ISC_FALSE;
312#endif
313
314	/*
315	 * Get the interface configuration, allocating more memory if
316	 * necessary.
317	 */
318
319#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
320	result = isc_net_probeipv6();
321	if (result == ISC_R_SUCCESS) {
322		/*
323		 * Create an unbound datagram socket to do the SIOCGLIFCONF
324		 * ioctl on.  HP/UX requires an AF_INET6 socket for
325		 * SIOCGLIFCONF to get IPv6 addresses.
326		 */
327		if ((iter->socket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
328			isc__strerror(errno, strbuf, sizeof(strbuf));
329			UNEXPECTED_ERROR(__FILE__, __LINE__,
330					 isc_msgcat_get(isc_msgcat,
331							ISC_MSGSET_IFITERIOCTL,
332							ISC_MSG_MAKESCANSOCKET,
333							"making interface "
334							"scan socket: %s"),
335					 strbuf);
336			result = ISC_R_UNEXPECTED;
337			goto socket6_failure;
338		}
339		result = iter->result6 = getbuf6(iter);
340		if (result != ISC_R_NOTIMPLEMENTED && result != ISC_R_SUCCESS)
341			goto ioctl6_failure;
342	}
343#endif
344	if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
345		isc__strerror(errno, strbuf, sizeof(strbuf));
346		UNEXPECTED_ERROR(__FILE__, __LINE__,
347				 isc_msgcat_get(isc_msgcat,
348						ISC_MSGSET_IFITERIOCTL,
349						ISC_MSG_MAKESCANSOCKET,
350						"making interface "
351						"scan socket: %s"),
352				 strbuf);
353		result = ISC_R_UNEXPECTED;
354		goto socket_failure;
355	}
356	result = getbuf4(iter);
357	if (result != ISC_R_SUCCESS)
358		goto ioctl_failure;
359
360	/*
361	 * A newly created iterator has an undefined position
362	 * until isc_interfaceiter_first() is called.
363	 */
364#ifdef HAVE_TRUCLUSTER
365	iter->clua_context = -1;
366	iter->clua_done = ISC_TRUE;
367#endif
368#ifdef __linux
369	iter->proc = fopen("/proc/net/if_inet6", "r");
370	iter->valid = ISC_R_FAILURE;
371#endif
372	iter->result = ISC_R_FAILURE;
373
374	iter->magic = IFITER_MAGIC;
375	*iterp = iter;
376	return (ISC_R_SUCCESS);
377
378 ioctl_failure:
379	if (iter->buf != NULL)
380		isc_mem_put(mctx, iter->buf, iter->bufsize);
381	(void) close(iter->socket);
382
383 socket_failure:
384#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
385	if (iter->buf6 != NULL)
386		isc_mem_put(mctx, iter->buf6, iter->bufsize6);
387  ioctl6_failure:
388	if (iter->socket6 != -1)
389		(void) close(iter->socket6);
390  socket6_failure:
391#endif
392
393	isc_mem_put(mctx, iter, sizeof(*iter));
394	return (result);
395}
396
397#ifdef HAVE_TRUCLUSTER
398static void
399get_inaddr(isc_netaddr_t *dst, struct in_addr *src) {
400	dst->family = AF_INET;
401	memmove(&dst->type.in, src, sizeof(struct in_addr));
402}
403
404static isc_result_t
405internal_current_clusteralias(isc_interfaceiter_t *iter) {
406	struct clua_info ci;
407	if (clua_getaliasinfo(&iter->clua_sa, &ci) != CLUA_SUCCESS)
408		return (ISC_R_IGNORE);
409	memset(&iter->current, 0, sizeof(iter->current));
410	iter->current.af = iter->clua_sa.sa_family;
411	memset(iter->current.name, 0, sizeof(iter->current.name));
412	sprintf(iter->current.name, "clua%d", ci.aliasid);
413	iter->current.flags = INTERFACE_F_UP;
414	get_inaddr(&iter->current.address, &ci.addr);
415	get_inaddr(&iter->current.netmask, &ci.netmask);
416	return (ISC_R_SUCCESS);
417}
418#endif
419
420/*
421 * Get information about the current interface to iter->current.
422 * If successful, return ISC_R_SUCCESS.
423 * If the interface has an unsupported address family, or if
424 * some operation on it fails, return ISC_R_IGNORE to make
425 * the higher-level iterator code ignore it.
426 */
427
428static isc_result_t
429internal_current4(isc_interfaceiter_t *iter) {
430	struct ifreq *ifrp;
431	struct ifreq ifreq;
432	int family;
433	char strbuf[ISC_STRERRORSIZE];
434#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
435	struct lifreq lifreq;
436#else
437	char sabuf[256];
438#endif
439	int i, bits, prefixlen;
440
441	REQUIRE(VALID_IFITER(iter));
442
443	if (iter->ifc.ifc_len == 0 ||
444	    iter->pos == (unsigned int)iter->ifc.ifc_len) {
445#ifdef __linux
446		return (linux_if_inet6_current(iter));
447#else
448		return (ISC_R_NOMORE);
449#endif
450	}
451
452	INSIST( iter->pos < (unsigned int) iter->ifc.ifc_len);
453
454	ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
455
456	memset(&ifreq, 0, sizeof(ifreq));
457	memmove(&ifreq, ifrp, sizeof(ifreq));
458
459	family = ifreq.ifr_addr.sa_family;
460#if defined(ISC_PLATFORM_HAVEIPV6)
461	if (family != AF_INET && family != AF_INET6)
462#else
463	if (family != AF_INET)
464#endif
465		return (ISC_R_IGNORE);
466
467	memset(&iter->current, 0, sizeof(iter->current));
468	iter->current.af = family;
469
470	INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
471	memset(iter->current.name, 0, sizeof(iter->current.name));
472	memmove(iter->current.name, ifreq.ifr_name, sizeof(ifreq.ifr_name));
473
474	get_addr(family, &iter->current.address,
475		 (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name);
476
477	/*
478	 * If the interface does not have a address ignore it.
479	 */
480	switch (family) {
481	case AF_INET:
482		if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
483			return (ISC_R_IGNORE);
484		break;
485	case AF_INET6:
486		if (memcmp(&iter->current.address.type.in6, &in6addr_any,
487			   sizeof(in6addr_any)) == 0)
488			return (ISC_R_IGNORE);
489		break;
490	}
491
492	/*
493	 * Get interface flags.
494	 */
495
496	iter->current.flags = 0;
497
498	/*
499	 * Ignore the HP/UX warning about "integer overflow during
500	 * conversion.  It comes from its own macro definition,
501	 * and is really hard to shut up.
502	 */
503	if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
504		isc__strerror(errno, strbuf, sizeof(strbuf));
505		UNEXPECTED_ERROR(__FILE__, __LINE__,
506				 "%s: getting interface flags: %s",
507				 ifreq.ifr_name, strbuf);
508		return (ISC_R_IGNORE);
509	}
510
511	if ((ifreq.ifr_flags & IFF_UP) != 0)
512		iter->current.flags |= INTERFACE_F_UP;
513
514#ifdef IFF_POINTOPOINT
515	if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
516		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
517#endif
518
519	if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
520		iter->current.flags |= INTERFACE_F_LOOPBACK;
521
522	if (family == AF_INET)
523		goto inet;
524
525#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
526	memset(&lifreq, 0, sizeof(lifreq));
527	memmove(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name));
528	memmove(&lifreq.lifr_addr, &iter->current.address.type.in6,
529	       sizeof(iter->current.address.type.in6));
530
531	if (ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) {
532		isc__strerror(errno, strbuf, sizeof(strbuf));
533		UNEXPECTED_ERROR(__FILE__, __LINE__,
534				 "%s: getting interface address: %s",
535				 ifreq.ifr_name, strbuf);
536		return (ISC_R_IGNORE);
537	}
538	prefixlen = lifreq.lifr_addrlen;
539#else
540	isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf));
541	isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
542		      ISC_LOGMODULE_INTERFACE,
543		      ISC_LOG_INFO,
544		      isc_msgcat_get(isc_msgcat,
545				     ISC_MSGSET_IFITERIOCTL,
546				     ISC_MSG_GETIFCONFIG,
547				     "prefix length for %s is unknown "
548				     "(assume 128)"), sabuf);
549	prefixlen = 128;
550#endif
551
552	/*
553	 * Netmask already zeroed.
554	 */
555	iter->current.netmask.family = family;
556	for (i = 0; i < 16; i++) {
557		if (prefixlen > 8) {
558			bits = 0;
559			prefixlen -= 8;
560		} else {
561			bits = 8 - prefixlen;
562			prefixlen = 0;
563		}
564		iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff;
565	}
566	return (ISC_R_SUCCESS);
567
568 inet:
569	if (family != AF_INET)
570		return (ISC_R_IGNORE);
571#ifdef IFF_POINTOPOINT
572	/*
573	 * If the interface is point-to-point, get the destination address.
574	 */
575	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
576		/*
577		 * Ignore the HP/UX warning about "integer overflow during
578		 * conversion.  It comes from its own macro definition,
579		 * and is really hard to shut up.
580		 */
581		if (ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq)
582		    < 0) {
583			isc__strerror(errno, strbuf, sizeof(strbuf));
584			UNEXPECTED_ERROR(__FILE__, __LINE__,
585				isc_msgcat_get(isc_msgcat,
586					       ISC_MSGSET_IFITERIOCTL,
587					       ISC_MSG_GETDESTADDR,
588					       "%s: getting "
589					       "destination address: %s"),
590					 ifreq.ifr_name, strbuf);
591			return (ISC_R_IGNORE);
592		}
593		get_addr(family, &iter->current.dstaddress,
594			 (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name);
595	}
596#endif
597
598	/*
599	 * Get the network mask.
600	 */
601	memset(&ifreq, 0, sizeof(ifreq));
602	memmove(&ifreq, ifrp, sizeof(ifreq));
603	/*
604	 * Ignore the HP/UX warning about "integer overflow during
605	 * conversion.  It comes from its own macro definition,
606	 * and is really hard to shut up.
607	 */
608	if (ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
609		isc__strerror(errno, strbuf, sizeof(strbuf));
610		UNEXPECTED_ERROR(__FILE__, __LINE__,
611			isc_msgcat_get(isc_msgcat,
612				       ISC_MSGSET_IFITERIOCTL,
613				       ISC_MSG_GETNETMASK,
614				       "%s: getting netmask: %s"),
615				       ifreq.ifr_name, strbuf);
616		return (ISC_R_IGNORE);
617	}
618	get_addr(family, &iter->current.netmask,
619		 (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name);
620	return (ISC_R_SUCCESS);
621}
622
623#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
624static isc_result_t
625internal_current6(isc_interfaceiter_t *iter) {
626	struct LIFREQ *ifrp;
627	struct LIFREQ lifreq;
628	int family;
629	char strbuf[ISC_STRERRORSIZE];
630	int fd;
631
632	REQUIRE(VALID_IFITER(iter));
633	if (iter->result6 != ISC_R_SUCCESS)
634		return (iter->result6);
635	REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
636
637	ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
638
639	memset(&lifreq, 0, sizeof(lifreq));
640	memmove(&lifreq, ifrp, sizeof(lifreq));
641
642	family = lifreq.lifr_addr.ss_family;
643#ifdef ISC_PLATFORM_HAVEIPV6
644	if (family != AF_INET && family != AF_INET6)
645#else
646	if (family != AF_INET)
647#endif
648		return (ISC_R_IGNORE);
649
650	memset(&iter->current, 0, sizeof(iter->current));
651	iter->current.af = family;
652
653	INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name));
654	memset(iter->current.name, 0, sizeof(iter->current.name));
655	memmove(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name));
656
657	get_addr(family, &iter->current.address,
658		 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
659
660	/*
661	 * If the interface does not have a address ignore it.
662	 */
663	switch (family) {
664	case AF_INET:
665		if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
666			return (ISC_R_IGNORE);
667		break;
668	case AF_INET6:
669		if (memcmp(&iter->current.address.type.in6, &in6addr_any,
670			   sizeof(in6addr_any)) == 0)
671			return (ISC_R_IGNORE);
672		break;
673	}
674
675	/*
676	 * Get interface flags.
677	 */
678
679	iter->current.flags = 0;
680
681	if (family == AF_INET6)
682		fd = iter->socket6;
683	else
684		fd = iter->socket;
685
686	/*
687	 * Ignore the HP/UX warning about "integer overflow during
688	 * conversion.  It comes from its own macro definition,
689	 * and is really hard to shut up.
690	 */
691	if (ioctl(fd, SIOCGLIFFLAGS, (char *) &lifreq) < 0) {
692		isc__strerror(errno, strbuf, sizeof(strbuf));
693		UNEXPECTED_ERROR(__FILE__, __LINE__,
694				 "%s: getting interface flags: %s",
695				 lifreq.lifr_name, strbuf);
696		return (ISC_R_IGNORE);
697	}
698
699	if ((lifreq.lifr_flags & IFF_UP) != 0)
700		iter->current.flags |= INTERFACE_F_UP;
701
702#ifdef IFF_POINTOPOINT
703	if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0)
704		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
705#endif
706
707	if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0)
708		iter->current.flags |= INTERFACE_F_LOOPBACK;
709
710#ifdef IFF_POINTOPOINT
711	/*
712	 * If the interface is point-to-point, get the destination address.
713	 */
714	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
715		/*
716		 * Ignore the HP/UX warning about "integer overflow during
717		 * conversion.  It comes from its own macro definition,
718		 * and is really hard to shut up.
719		 */
720		if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq)
721		    < 0) {
722			isc__strerror(errno, strbuf, sizeof(strbuf));
723			UNEXPECTED_ERROR(__FILE__, __LINE__,
724				isc_msgcat_get(isc_msgcat,
725					       ISC_MSGSET_IFITERIOCTL,
726					       ISC_MSG_GETDESTADDR,
727					       "%s: getting "
728					       "destination address: %s"),
729					 lifreq.lifr_name, strbuf);
730			return (ISC_R_IGNORE);
731		}
732		get_addr(family, &iter->current.dstaddress,
733			 (struct sockaddr *)&lifreq.lifr_dstaddr,
734			 lifreq.lifr_name);
735	}
736#endif
737
738	/*
739	 * Get the network mask.  Netmask already zeroed.
740	 */
741	memset(&lifreq, 0, sizeof(lifreq));
742	memmove(&lifreq, ifrp, sizeof(lifreq));
743
744#ifdef lifr_addrlen
745	/*
746	 * Special case: if the system provides lifr_addrlen member, the
747	 * netmask of an IPv6 address can be derived from the length, since
748	 * an IPv6 address always has a contiguous mask.
749	 */
750	if (family == AF_INET6) {
751		int i, bits;
752
753		iter->current.netmask.family = family;
754		for (i = 0; i < lifreq.lifr_addrlen; i += 8) {
755			bits = lifreq.lifr_addrlen - i;
756			bits = (bits < 8) ? (8 - bits) : 0;
757			iter->current.netmask.type.in6.s6_addr[i / 8] =
758				(~0 << bits) & 0xff;
759		}
760
761		return (ISC_R_SUCCESS);
762	}
763#endif
764
765	/*
766	 * Ignore the HP/UX warning about "integer overflow during
767	 * conversion.  It comes from its own macro definition,
768	 * and is really hard to shut up.
769	 */
770	if (ioctl(fd, SIOCGLIFNETMASK, (char *)&lifreq) < 0) {
771		isc__strerror(errno, strbuf, sizeof(strbuf));
772		UNEXPECTED_ERROR(__FILE__, __LINE__,
773				 isc_msgcat_get(isc_msgcat,
774						ISC_MSGSET_IFITERIOCTL,
775						ISC_MSG_GETNETMASK,
776						"%s: getting netmask: %s"),
777				 lifreq.lifr_name, strbuf);
778		return (ISC_R_IGNORE);
779	}
780	get_addr(family, &iter->current.netmask,
781		 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
782
783	return (ISC_R_SUCCESS);
784}
785#endif
786
787static isc_result_t
788internal_current(isc_interfaceiter_t *iter) {
789#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
790	if (iter->mode == 6) {
791		iter->result6 = internal_current6(iter);
792		if (iter->result6 != ISC_R_NOMORE)
793			return (iter->result6);
794	}
795#endif
796#ifdef HAVE_TRUCLUSTER
797	if (!iter->clua_done)
798		return(internal_current_clusteralias(iter));
799#endif
800	return (internal_current4(iter));
801}
802
803/*
804 * Step the iterator to the next interface.  Unlike
805 * isc_interfaceiter_next(), this may leave the iterator
806 * positioned on an interface that will ultimately
807 * be ignored.  Return ISC_R_NOMORE if there are no more
808 * interfaces, otherwise ISC_R_SUCCESS.
809 */
810static isc_result_t
811internal_next4(isc_interfaceiter_t *iter) {
812#ifdef ISC_PLATFORM_HAVESALEN
813	struct ifreq *ifrp;
814#endif
815
816	if (iter->pos < (unsigned int) iter->ifc.ifc_len) {
817#ifdef ISC_PLATFORM_HAVESALEN
818		ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
819
820		if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
821			iter->pos += sizeof(ifrp->ifr_name) +
822				     ifrp->ifr_addr.sa_len;
823		else
824#endif
825			iter->pos += sizeof(struct ifreq);
826
827	} else {
828		INSIST(iter->pos == (unsigned int) iter->ifc.ifc_len);
829#ifdef __linux
830		return (linux_if_inet6_next(iter));
831#else
832		return (ISC_R_NOMORE);
833#endif
834	}
835	return (ISC_R_SUCCESS);
836}
837
838#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
839static isc_result_t
840internal_next6(isc_interfaceiter_t *iter) {
841#ifdef ISC_PLATFORM_HAVESALEN
842	struct LIFREQ *ifrp;
843#endif
844
845	if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE)
846		return (iter->result6);
847
848	REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
849
850#ifdef ISC_PLATFORM_HAVESALEN
851	ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
852
853	if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr))
854		iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len;
855	else
856#endif
857		iter->pos6 += sizeof(struct LIFREQ);
858
859	if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len)
860		return (ISC_R_NOMORE);
861
862	return (ISC_R_SUCCESS);
863}
864#endif
865
866static isc_result_t
867internal_next(isc_interfaceiter_t *iter) {
868#ifdef HAVE_TRUCLUSTER
869	int clua_result;
870#endif
871#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
872	if (iter->mode == 6) {
873		iter->result6 = internal_next6(iter);
874		if (iter->result6 != ISC_R_NOMORE)
875			return (iter->result6);
876		if (iter->first6) {
877			iter->first6 = ISC_FALSE;
878			return (ISC_R_SUCCESS);
879		}
880	}
881#endif
882#ifdef HAVE_TRUCLUSTER
883	if (!iter->clua_done) {
884		clua_result = clua_getaliasaddress(&iter->clua_sa,
885						   &iter->clua_context);
886		if (clua_result != CLUA_SUCCESS)
887			iter->clua_done = ISC_TRUE;
888		return (ISC_R_SUCCESS);
889	}
890#endif
891	return (internal_next4(iter));
892}
893
894static void
895internal_destroy(isc_interfaceiter_t *iter) {
896	(void) close(iter->socket);
897#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
898	if (iter->socket6 != -1)
899		(void) close(iter->socket6);
900	if (iter->buf6 != NULL) {
901		isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
902	}
903#endif
904#ifdef __linux
905	if (iter->proc != NULL)
906		fclose(iter->proc);
907#endif
908}
909
910static
911void internal_first(isc_interfaceiter_t *iter) {
912#ifdef HAVE_TRUCLUSTER
913	int clua_result;
914#endif
915	iter->pos = 0;
916#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
917	iter->pos6 = 0;
918	if (iter->result6 == ISC_R_NOMORE)
919		iter->result6 = ISC_R_SUCCESS;
920	iter->first6 = ISC_TRUE;
921#endif
922#ifdef HAVE_TRUCLUSTER
923	iter->clua_context = 0;
924	clua_result = clua_getaliasaddress(&iter->clua_sa,
925					   &iter->clua_context);
926	iter->clua_done = ISC_TF(clua_result != CLUA_SUCCESS);
927#endif
928#ifdef __linux
929	linux_if_inet6_first(iter);
930#endif
931}
932