1/*
2 * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: ifiter_ioctl.c,v 1.19.2.5.2.14 2004/06/22 04:40:23 marka Exp $ */
19
20/*
21 * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl.
22 * See netintro(4).
23 */
24
25#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
26#ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
27#define lifc_len iflc_len
28#define lifc_buf iflc_buf
29#define lifc_req iflc_req
30#define LIFCONF if_laddrconf
31#else
32#define ISC_HAVE_LIFC_FAMILY 1
33#define ISC_HAVE_LIFC_FLAGS 1
34#define LIFCONF lifconf
35#endif
36
37#ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
38#define lifr_addr iflr_addr
39#define lifr_name iflr_name
40#define lifr_dstaddr iflr_dstaddr
41#define lifr_broadaddr iflr_broadaddr
42#define lifr_flags iflr_flags
43#define lifr_index iflr_index
44#define ss_family sa_family
45#define LIFREQ if_laddrreq
46#else
47#define LIFREQ lifreq
48#endif
49#endif
50
51#define IFITER_MAGIC		ISC_MAGIC('I', 'F', 'I', 'T')
52#define VALID_IFITER(t)		ISC_MAGIC_VALID(t, IFITER_MAGIC)
53
54#define ISC_IF_INET6_SZ \
55    sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n")
56
57struct isc_interfaceiter {
58	unsigned int		magic;		/* Magic number. */
59	isc_mem_t		*mctx;
60	int			mode;
61	int			socket;
62	struct ifconf 		ifc;
63	void			*buf;		/* Buffer for sysctl data. */
64	unsigned int		bufsize;	/* Bytes allocated. */
65	unsigned int		pos;		/* Current offset in
66						   SIOCGIFCONF data */
67#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
68	int			socket6;
69	struct LIFCONF 		lifc;
70	void			*buf6;		/* Buffer for sysctl data. */
71	unsigned int		bufsize6;	/* Bytes allocated. */
72	unsigned int		pos6;		/* Current offset in
73						   SIOCGLIFCONF data */
74	isc_result_t		result6;	/* Last result code. */
75	isc_boolean_t		first6;
76#endif
77#ifdef HAVE_TRUCLUSTER
78	int			clua_context;	/* Cluster alias context */
79	isc_boolean_t		clua_done;
80	struct sockaddr		clua_sa;
81#endif
82#ifdef	__linux
83	FILE *			proc;
84	char			entry[ISC_IF_INET6_SZ];
85	isc_result_t		valid;
86	isc_boolean_t		first;
87#endif
88	isc_interface_t		current;	/* Current interface data. */
89	isc_result_t		result;		/* Last result code. */
90};
91
92#ifdef HAVE_TRUCLUSTER
93#include <clua/clua.h>
94#include <sys/socket.h>
95#endif
96
97
98/*
99 * Size of buffer for SIOCGLIFCONF, in bytes.  We assume no sane system
100 * will have more than a megabyte of interface configuration data.
101 */
102#define IFCONF_BUFSIZE_INITIAL	4096
103#define IFCONF_BUFSIZE_MAX	1048576
104
105#ifdef __linux
106#ifndef IF_NAMESIZE
107# ifdef IFNAMSIZ
108#  define IF_NAMESIZE  IFNAMSIZ
109# else
110#  define IF_NAMESIZE 16
111# endif
112#endif
113#endif
114
115static isc_result_t
116getbuf4(isc_interfaceiter_t *iter) {
117	char strbuf[ISC_STRERRORSIZE];
118
119	iter->bufsize = IFCONF_BUFSIZE_INITIAL;
120
121	for (;;) {
122		iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
123		if (iter->buf == NULL)
124			return (ISC_R_NOMEMORY);
125
126		memset(&iter->ifc.ifc_len, 0, sizeof(iter->ifc.ifc_len));
127		iter->ifc.ifc_len = iter->bufsize;
128		iter->ifc.ifc_buf = iter->buf;
129		/*
130		 * Ignore the HP/UX warning about "integer overflow during
131		 * conversion".  It comes from its own macro definition,
132		 * and is really hard to shut up.
133		 */
134		if (ioctl(iter->socket, SIOCGIFCONF, (char *)&iter->ifc)
135		    == -1) {
136			if (errno != EINVAL) {
137				isc__strerror(errno, strbuf, sizeof(strbuf));
138				UNEXPECTED_ERROR(__FILE__, __LINE__,
139						 isc_msgcat_get(isc_msgcat,
140							ISC_MSGSET_IFITERIOCTL,
141							ISC_MSG_GETIFCONFIG,
142							"get interface "
143							"configuration: %s"),
144						 strbuf);
145				goto unexpected;
146			}
147			/*
148			 * EINVAL.  Retry with a bigger buffer.
149			 */
150		} else {
151			/*
152			 * The ioctl succeeded.
153			 * Some OS's just return what will fit rather
154			 * than set EINVAL if the buffer is too small
155			 * to fit all the interfaces in.  If
156			 * ifc.lifc_len is too near to the end of the
157			 * buffer we will grow it just in case and
158			 * retry.
159			 */
160			if (iter->ifc.ifc_len + 2 * sizeof(struct ifreq)
161			    < iter->bufsize)
162				break;
163		}
164		if (iter->bufsize >= IFCONF_BUFSIZE_MAX) {
165			UNEXPECTED_ERROR(__FILE__, __LINE__,
166					 isc_msgcat_get(isc_msgcat,
167							ISC_MSGSET_IFITERIOCTL,
168							ISC_MSG_BUFFERMAX,
169							"get interface "
170							"configuration: "
171							"maximum buffer "
172							"size exceeded"));
173			goto unexpected;
174		}
175		isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
176
177		iter->bufsize *= 2;
178	}
179	return (ISC_R_SUCCESS);
180
181 unexpected:
182	isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
183	iter->buf = NULL;
184	return (ISC_R_UNEXPECTED);
185}
186
187#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
188static isc_result_t
189getbuf6(isc_interfaceiter_t *iter) {
190	char strbuf[ISC_STRERRORSIZE];
191	isc_result_t result;
192
193	iter->bufsize6 = IFCONF_BUFSIZE_INITIAL;
194
195	for (;;) {
196		iter->buf6 = isc_mem_get(iter->mctx, iter->bufsize6);
197		if (iter->buf6 == NULL)
198			return (ISC_R_NOMEMORY);
199
200		memset(&iter->lifc, 0, sizeof(iter->lifc));
201#ifdef ISC_HAVE_LIFC_FAMILY
202		iter->lifc.lifc_family = AF_INET6;
203#endif
204#ifdef ISC_HAVE_LIFC_FLAGS
205		iter->lifc.lifc_flags = 0;
206#endif
207		iter->lifc.lifc_len = iter->bufsize6;
208		iter->lifc.lifc_buf = iter->buf6;
209		/*
210		 * Ignore the HP/UX warning about "integer overflow during
211		 * conversion".  It comes from its own macro definition,
212		 * and is really hard to shut up.
213		 */
214		if (ioctl(iter->socket6, SIOCGLIFCONF, (char *)&iter->lifc)
215		    == -1) {
216#ifdef __hpux
217			/*
218			 * IPv6 interface scanning is not available on all
219			 * kernels w/ IPv6 sockets.
220			 */
221			if (errno == ENOENT) {
222				isc__strerror(errno, strbuf, sizeof(strbuf));
223				UNEXPECTED_ERROR(__FILE__, __LINE__,
224						 isc_msgcat_get(isc_msgcat,
225							ISC_MSGSET_IFITERIOCTL,
226							ISC_MSG_GETIFCONFIG,
227							"get interface "
228							"configuration: %s"),
229						 strbuf);
230				result = ISC_R_FAILURE;
231				goto cleanup;
232			}
233#endif
234			if (errno != EINVAL) {
235				isc__strerror(errno, strbuf, sizeof(strbuf));
236				UNEXPECTED_ERROR(__FILE__, __LINE__,
237						 isc_msgcat_get(isc_msgcat,
238							ISC_MSGSET_IFITERIOCTL,
239							ISC_MSG_GETIFCONFIG,
240							"get interface "
241							"configuration: %s"),
242						 strbuf);
243				result = ISC_R_UNEXPECTED;
244				goto cleanup;
245			}
246			/*
247			 * EINVAL.  Retry with a bigger buffer.
248			 */
249		} else {
250			/*
251			 * The ioctl succeeded.
252			 * Some OS's just return what will fit rather
253			 * than set EINVAL if the buffer is too small
254			 * to fit all the interfaces in.  If
255			 * ifc.ifc_len is too near to the end of the
256			 * buffer we will grow it just in case and
257			 * retry.
258			 */
259			if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ)
260			    < iter->bufsize6)
261				break;
262		}
263		if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) {
264			UNEXPECTED_ERROR(__FILE__, __LINE__,
265					 isc_msgcat_get(isc_msgcat,
266							ISC_MSGSET_IFITERIOCTL,
267							ISC_MSG_BUFFERMAX,
268							"get interface "
269							"configuration: "
270							"maximum buffer "
271							"size exceeded"));
272			result = ISC_R_UNEXPECTED;
273			goto cleanup;
274		}
275		isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
276
277		iter->bufsize6 *= 2;
278	}
279
280	if (iter->lifc.lifc_len != 0)
281		iter->mode = 6;
282	return (ISC_R_SUCCESS);
283
284 cleanup:
285	isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
286	iter->buf6 = NULL;
287	return (result);
288}
289#endif
290
291isc_result_t
292isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
293	isc_interfaceiter_t *iter;
294	isc_result_t result;
295	char strbuf[ISC_STRERRORSIZE];
296
297	REQUIRE(iterp != NULL);
298	REQUIRE(*iterp == NULL);
299
300	iter = isc_mem_get(mctx, sizeof(*iter));
301	if (iter == NULL)
302		return (ISC_R_NOMEMORY);
303
304	iter->mctx = mctx;
305	iter->mode = 4;
306	iter->buf = NULL;
307	iter->pos = (unsigned int) -1;
308#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
309	iter->buf6 = NULL;
310	iter->pos6 = (unsigned int) -1;
311	iter->result6 = ISC_R_NOMORE;
312	iter->socket6 = -1;
313	iter->first6 = ISC_FALSE;
314#endif
315
316	/*
317	 * Get the interface configuration, allocating more memory if
318	 * necessary.
319	 */
320
321#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
322	result = isc_net_probeipv6();
323	if (result == ISC_R_SUCCESS) {
324		/*
325		 * Create an unbound datagram socket to do the SIOCGLIFCONF
326		 * ioctl on.  HP/UX requires an AF_INET6 socket for
327		 * SIOCGLIFCONF to get IPv6 addresses.
328		 */
329		if ((iter->socket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
330			isc__strerror(errno, strbuf, sizeof(strbuf));
331			UNEXPECTED_ERROR(__FILE__, __LINE__,
332					 isc_msgcat_get(isc_msgcat,
333							ISC_MSGSET_IFITERIOCTL,
334							ISC_MSG_MAKESCANSOCKET,
335							"making interface "
336							"scan socket: %s"),
337					 strbuf);
338			result = ISC_R_UNEXPECTED;
339			goto socket6_failure;
340		}
341		iter->result6 = getbuf6(iter);
342		if (iter->result6 != ISC_R_NOTIMPLEMENTED &&
343		    iter->result6 != ISC_R_SUCCESS)
344			goto ioctl6_failure;
345	}
346#endif
347	if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
348		isc__strerror(errno, strbuf, sizeof(strbuf));
349		UNEXPECTED_ERROR(__FILE__, __LINE__,
350				 isc_msgcat_get(isc_msgcat,
351						ISC_MSGSET_IFITERIOCTL,
352						ISC_MSG_MAKESCANSOCKET,
353						"making interface "
354						"scan socket: %s"),
355				 strbuf);
356		result = ISC_R_UNEXPECTED;
357		goto socket_failure;
358	}
359	result = getbuf4(iter);
360	if (result != ISC_R_SUCCESS)
361		goto ioctl_failure;
362
363	/*
364	 * A newly created iterator has an undefined position
365	 * until isc_interfaceiter_first() is called.
366	 */
367#ifdef HAVE_TRUCLUSTER
368	iter->clua_context = -1;
369	iter->clua_done = ISC_TRUE;
370#endif
371#ifdef __linux
372	iter->proc = fopen("/proc/net/if_inet6", "r");
373	iter->valid = ISC_R_FAILURE;
374	iter->first = ISC_FALSE;
375#endif
376	iter->result = ISC_R_FAILURE;
377
378	iter->magic = IFITER_MAGIC;
379	*iterp = iter;
380	return (ISC_R_SUCCESS);
381
382 ioctl_failure:
383	if (iter->buf != NULL)
384		isc_mem_put(mctx, iter->buf, iter->bufsize);
385	(void) close(iter->socket);
386
387 socket_failure:
388#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
389	if (iter->buf6 != NULL)
390		isc_mem_put(mctx, iter->buf6, iter->bufsize6);
391  ioctl6_failure:
392	if (iter->socket6 != -1)
393		(void) close(iter->socket6);
394  socket6_failure:
395#endif
396
397	isc_mem_put(mctx, iter, sizeof(*iter));
398	return (result);
399}
400
401#ifdef HAVE_TRUCLUSTER
402static void
403get_inaddr(isc_netaddr_t *dst, struct in_addr *src) {
404	dst->family = AF_INET;
405	memcpy(&dst->type.in, src, sizeof(struct in_addr));
406}
407
408static isc_result_t
409internal_current_clusteralias(isc_interfaceiter_t *iter) {
410	struct clua_info ci;
411	if (clua_getaliasinfo(&iter->clua_sa, &ci) != CLUA_SUCCESS)
412		return (ISC_R_IGNORE);
413	memset(&iter->current, 0, sizeof(iter->current));
414	iter->current.af = iter->clua_sa.sa_family;
415	memset(iter->current.name, 0, sizeof(iter->current.name));
416	sprintf(iter->current.name, "clua%d", ci.aliasid);
417	iter->current.flags = INTERFACE_F_UP;
418	get_inaddr(&iter->current.address, &ci.addr);
419	get_inaddr(&iter->current.netmask, &ci.netmask);
420	return (ISC_R_SUCCESS);
421}
422#endif
423
424#ifdef __linux
425static isc_result_t
426linux_if_inet6_next(isc_interfaceiter_t *iter) {
427	if (iter->proc != NULL &&
428	    fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL)
429		iter->valid = ISC_R_SUCCESS;
430	else
431		iter->valid = ISC_R_NOMORE;
432	return (iter->valid);
433}
434
435static void
436linux_if_inet6_first(isc_interfaceiter_t *iter) {
437	if (iter->proc != NULL) {
438		rewind(iter->proc);
439		(void)linux_if_inet6_next(iter);
440	} else
441		iter->valid = ISC_R_NOMORE;
442	iter->first = ISC_FALSE;
443}
444
445static isc_result_t
446linux_if_inet6_current(isc_interfaceiter_t *iter) {
447	char address[33];
448	char name[IF_NAMESIZE+1];
449	char strbuf[ISC_STRERRORSIZE];
450	struct in6_addr addr6;
451	struct ifreq ifreq;
452	int ifindex, prefix, scope, flags;
453	int res;
454	unsigned int i;
455
456	if (iter->valid != ISC_R_SUCCESS)
457		return (iter->valid);
458	if (iter->proc == NULL) {
459		UNEXPECTED_ERROR(__FILE__, __LINE__,
460			      "/proc/net/if_inet6:iter->proc == NULL");
461		return (ISC_R_FAILURE);
462	}
463
464	/*
465	 * Format for /proc/net/if_inet6:
466	 * (see iface_proc_info() in net/ipv6/addrconf.c)
467	 * <addr6:32> <ifindex:2> <prefix:2> <scope:2> <flags:2> <name:8>
468	 */
469	res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n",
470		     address, &ifindex, &prefix, &scope, &flags, name);
471	if (res != 6) {
472		UNEXPECTED_ERROR(__FILE__, __LINE__,
473			      "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
474			      res);
475		return (ISC_R_FAILURE);
476	}
477	if (strlen(address) != 32) {
478		UNEXPECTED_ERROR(__FILE__, __LINE__,
479			      "/proc/net/if_inet6:strlen(%s) != 32", address);
480		return (ISC_R_FAILURE);
481	}
482	for (i = 0; i < 16; i++) {
483		unsigned char byte;
484		static const char hex[] = "0123456789abcdef";
485		byte = ((index(hex, address[i * 2]) - hex) << 4) |
486		       (index(hex, address[i * 2 + 1]) - hex);
487		addr6.s6_addr[i] = byte;
488	}
489	iter->current.af = AF_INET6;
490	/* iter->current.ifindex = ifindex; */
491	iter->current.flags = 0;
492
493	memset(&ifreq, 0, sizeof(ifreq));
494	INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
495	strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
496
497	if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
498		isc__strerror(errno, strbuf, sizeof(strbuf));
499		UNEXPECTED_ERROR(__FILE__, __LINE__,
500				 "%s: getting interface flags: %s",
501				 ifreq.ifr_name, strbuf);
502		return (ISC_R_IGNORE);
503	}
504
505	if ((ifreq.ifr_flags & IFF_UP) != 0)
506		iter->current.flags |= INTERFACE_F_UP;
507#ifdef IFF_POINTOPOINT
508	if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
509		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
510#endif
511	if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
512		iter->current.flags |= INTERFACE_F_LOOPBACK;
513	if ((ifreq.ifr_flags & IFF_BROADCAST) != 0)
514		iter->current.flags |= INTERFACE_F_BROADCAST;
515#ifdef IFF_MULTICAST
516	if ((ifreq.ifr_flags & IFF_MULTICAST) != 0)
517		iter->current.flags |= INTERFACE_F_MULTICAST;
518#endif
519
520	/*
521	 * enable_multicast_if() requires scopeid for setsockopt,
522	 * so associate address with their corresponding ifindex.
523	 */
524	isc_netaddr_fromin6(&iter->current.address, &addr6);
525	isc_netaddr_setzone(&iter->current.address, (isc_uint32_t)ifindex);
526
527	for (i = 0; i < 16; i++) {
528		if (prefix > 8) {
529			addr6.s6_addr[i] = 0xff;
530			prefix -= 8;
531		} else {
532			addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
533			prefix = 0;
534		}
535	}
536	isc_netaddr_fromin6(&iter->current.netmask, &addr6);
537	strncpy(iter->current.name, name, sizeof(iter->current.name));
538	return (ISC_R_SUCCESS);
539}
540#endif
541
542/*
543 * Get information about the current interface to iter->current.
544 * If successful, return ISC_R_SUCCESS.
545 * If the interface has an unsupported address family, or if
546 * some operation on it fails, return ISC_R_IGNORE to make
547 * the higher-level iterator code ignore it.
548 */
549
550static isc_result_t
551internal_current4(isc_interfaceiter_t *iter) {
552	struct ifreq *ifrp;
553	struct ifreq ifreq;
554	int family;
555	char strbuf[ISC_STRERRORSIZE];
556#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
557	struct lifreq lifreq;
558#else
559	char sabuf[256];
560#endif
561	int i, bits, prefixlen;
562#ifdef __linux
563	isc_result_t result;
564#endif
565
566	REQUIRE(VALID_IFITER(iter));
567	REQUIRE (iter->pos < (unsigned int) iter->ifc.ifc_len);
568
569#ifdef __linux
570	result = linux_if_inet6_current(iter);
571	if (result != ISC_R_NOMORE)
572		return (result);
573	iter->first = ISC_TRUE;
574#endif
575
576	ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
577
578	memset(&ifreq, 0, sizeof(ifreq));
579	memcpy(&ifreq, ifrp, sizeof(ifreq));
580
581	family = ifreq.ifr_addr.sa_family;
582#if defined(ISC_PLATFORM_HAVEIPV6)
583	if (family != AF_INET && family != AF_INET6)
584#else
585	if (family != AF_INET)
586#endif
587		return (ISC_R_IGNORE);
588
589	memset(&iter->current, 0, sizeof(iter->current));
590	iter->current.af = family;
591
592	INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
593	memset(iter->current.name, 0, sizeof(iter->current.name));
594	memcpy(iter->current.name, ifreq.ifr_name, sizeof(ifreq.ifr_name));
595
596	get_addr(family, &iter->current.address,
597		 (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name);
598
599	/*
600	 * If the interface does not have a address ignore it.
601	 */
602	switch (family) {
603	case AF_INET:
604		if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
605			return (ISC_R_IGNORE);
606		break;
607#ifdef ISC_PLATFORM_HAVEIPV6
608	case AF_INET6:
609		if (memcmp(&iter->current.address.type.in6, &in6addr_any,
610			   sizeof(in6addr_any)) == 0)
611			return (ISC_R_IGNORE);
612		break;
613#endif
614	}
615
616	/*
617	 * Get interface flags.
618	 */
619
620	iter->current.flags = 0;
621
622	/*
623	 * Ignore the HP/UX warning about "integer overflow during
624	 * conversion.  It comes from its own macro definition,
625	 * and is really hard to shut up.
626	 */
627	if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
628		isc__strerror(errno, strbuf, sizeof(strbuf));
629		UNEXPECTED_ERROR(__FILE__, __LINE__,
630				 "%s: getting interface flags: %s",
631				 ifreq.ifr_name, strbuf);
632		return (ISC_R_IGNORE);
633	}
634
635	if ((ifreq.ifr_flags & IFF_UP) != 0)
636		iter->current.flags |= INTERFACE_F_UP;
637
638#ifdef IFF_POINTOPOINT
639	if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
640		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
641#endif
642
643	if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
644		iter->current.flags |= INTERFACE_F_LOOPBACK;
645
646	if ((ifreq.ifr_flags & IFF_BROADCAST) != 0) {
647		iter->current.flags |= INTERFACE_F_BROADCAST;
648	}
649
650#ifdef IFF_MULTICAST
651	if ((ifreq.ifr_flags & IFF_MULTICAST) != 0) {
652		iter->current.flags |= INTERFACE_F_MULTICAST;
653	}
654#endif
655
656	if (family == AF_INET)
657		goto inet;
658
659#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
660	memset(&lifreq, 0, sizeof(lifreq));
661	memcpy(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name));
662	memcpy(&lifreq.lifr_addr, &iter->current.address.type.in6,
663	       sizeof(iter->current.address.type.in6));
664
665	if (ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) {
666		isc__strerror(errno, strbuf, sizeof(strbuf));
667		UNEXPECTED_ERROR(__FILE__, __LINE__,
668				 "%s: getting interface address: %s",
669				 ifreq.ifr_name, strbuf);
670		return (ISC_R_IGNORE);
671	}
672	prefixlen = lifreq.lifr_addrlen;
673#else
674	isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf));
675	UNEXPECTED_ERROR(__FILE__, __LINE__,
676		      isc_msgcat_get(isc_msgcat,
677				     ISC_MSGSET_IFITERIOCTL,
678				     ISC_MSG_GETIFCONFIG,
679				     "prefix length for %s is unknown "
680				     "(assume 128)"), sabuf);
681	prefixlen = 128;
682#endif
683
684	/*
685	 * Netmask already zeroed.
686	 */
687	iter->current.netmask.family = family;
688	for (i = 0; i < 16; i++) {
689		if (prefixlen > 8) {
690			bits = 0;
691			prefixlen -= 8;
692		} else {
693			bits = 8 - prefixlen;
694			prefixlen = 0;
695		}
696		iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff;
697	}
698	return (ISC_R_SUCCESS);
699
700 inet:
701	if (family != AF_INET)
702		return (ISC_R_IGNORE);
703#ifdef IFF_POINTOPOINT
704	/*
705	 * If the interface is point-to-point, get the destination address.
706	 */
707	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
708		/*
709		 * Ignore the HP/UX warning about "integer overflow during
710		 * conversion.  It comes from its own macro definition,
711		 * and is really hard to shut up.
712		 */
713		if (ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq)
714		    < 0) {
715			isc__strerror(errno, strbuf, sizeof(strbuf));
716			UNEXPECTED_ERROR(__FILE__, __LINE__,
717				isc_msgcat_get(isc_msgcat,
718					       ISC_MSGSET_IFITERIOCTL,
719					       ISC_MSG_GETDESTADDR,
720					       "%s: getting "
721					       "destination address: %s"),
722					 ifreq.ifr_name, strbuf);
723			return (ISC_R_IGNORE);
724		}
725		get_addr(family, &iter->current.dstaddress,
726			 (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name);
727	}
728#endif
729	if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
730		/*
731		 * Ignore the HP/UX warning about "integer overflow during
732		 * conversion.  It comes from its own macro definition,
733		 * and is really hard to shut up.
734		 */
735		if (ioctl(iter->socket, SIOCGIFBRDADDR, (char *)&ifreq)
736		    < 0) {
737			isc__strerror(errno, strbuf, sizeof(strbuf));
738			UNEXPECTED_ERROR(__FILE__, __LINE__,
739				isc_msgcat_get(isc_msgcat,
740					       ISC_MSGSET_IFITERIOCTL,
741					       ISC_MSG_GETDESTADDR,
742					       "%s: getting "
743					       "broadcast address: %s"),
744					 ifreq.ifr_name, strbuf);
745			return (ISC_R_IGNORE);
746		}
747		get_addr(family, &iter->current.broadcast,
748			 (struct sockaddr *)&ifreq.ifr_broadaddr, ifreq.ifr_name);
749	}
750
751	/*
752	 * Get the network mask.
753	 */
754	memset(&ifreq, 0, sizeof(ifreq));
755	memcpy(&ifreq, ifrp, sizeof(ifreq));
756	/*
757	 * Ignore the HP/UX warning about "integer overflow during
758	 * conversion.  It comes from its own macro definition,
759	 * and is really hard to shut up.
760	 */
761	if (ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
762		isc__strerror(errno, strbuf, sizeof(strbuf));
763		UNEXPECTED_ERROR(__FILE__, __LINE__,
764			isc_msgcat_get(isc_msgcat,
765				       ISC_MSGSET_IFITERIOCTL,
766				       ISC_MSG_GETNETMASK,
767				       "%s: getting netmask: %s"),
768				       ifreq.ifr_name, strbuf);
769		return (ISC_R_IGNORE);
770	}
771	get_addr(family, &iter->current.netmask,
772		 (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name);
773	return (ISC_R_SUCCESS);
774}
775
776#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
777static isc_result_t
778internal_current6(isc_interfaceiter_t *iter) {
779	struct LIFREQ *ifrp;
780	struct LIFREQ lifreq;
781	int family;
782	char strbuf[ISC_STRERRORSIZE];
783	int fd;
784
785	REQUIRE(VALID_IFITER(iter));
786	if (iter->result6 != ISC_R_SUCCESS)
787		return (iter->result6);
788	REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
789
790	ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
791
792	memset(&lifreq, 0, sizeof(lifreq));
793	memcpy(&lifreq, ifrp, sizeof(lifreq));
794
795	family = lifreq.lifr_addr.ss_family;
796#ifdef ISC_PLATFORM_HAVEIPV6
797	if (family != AF_INET && family != AF_INET6)
798#else
799	if (family != AF_INET)
800#endif
801		return (ISC_R_IGNORE);
802
803	memset(&iter->current, 0, sizeof(iter->current));
804	iter->current.af = family;
805
806	INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name));
807	memset(iter->current.name, 0, sizeof(iter->current.name));
808	memcpy(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name));
809
810	get_addr(family, &iter->current.address,
811		 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
812
813	/*
814	 * If the interface does not have a address ignore it.
815	 */
816	switch (family) {
817	case AF_INET:
818		if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
819			return (ISC_R_IGNORE);
820		break;
821#ifdef ISC_PLATFORM_HAVEIPV6
822	case AF_INET6:
823		if (memcmp(&iter->current.address.type.in6, &in6addr_any,
824			   sizeof(in6addr_any)) == 0)
825			return (ISC_R_IGNORE);
826		break;
827#endif
828	}
829
830	/*
831	 * Get interface flags.
832	 */
833
834	iter->current.flags = 0;
835
836	if (family == AF_INET6)
837		fd = iter->socket6;
838	else
839		fd = iter->socket;
840
841	/*
842	 * Ignore the HP/UX warning about "integer overflow during
843	 * conversion.  It comes from its own macro definition,
844	 * and is really hard to shut up.
845	 */
846	if (ioctl(fd, SIOCGLIFFLAGS, (char *) &lifreq) < 0) {
847		isc__strerror(errno, strbuf, sizeof(strbuf));
848		UNEXPECTED_ERROR(__FILE__, __LINE__,
849				 "%s: getting interface flags: %s",
850				 lifreq.lifr_name, strbuf);
851		return (ISC_R_IGNORE);
852	}
853
854	if ((lifreq.lifr_flags & IFF_UP) != 0)
855		iter->current.flags |= INTERFACE_F_UP;
856
857#ifdef IFF_POINTOPOINT
858	if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0)
859		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
860#endif
861
862	if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0)
863		iter->current.flags |= INTERFACE_F_LOOPBACK;
864
865	if ((lifreq.lifr_flags & IFF_BROADCAST) != 0) {
866		iter->current.flags |= INTERFACE_F_BROADCAST;
867	}
868
869#ifdef IFF_MULTICAST
870	if ((lifreq.lifr_flags & IFF_MULTICAST) != 0) {
871		iter->current.flags |= INTERFACE_F_MULTICAST;
872	}
873#endif
874
875#ifdef IFF_POINTOPOINT
876	/*
877	 * If the interface is point-to-point, get the destination address.
878	 */
879	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
880		/*
881		 * Ignore the HP/UX warning about "interger overflow during
882		 * conversion.  It comes from its own macro definition,
883		 * and is really hard to shut up.
884		 */
885		if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq)
886		    < 0) {
887			isc__strerror(errno, strbuf, sizeof(strbuf));
888			UNEXPECTED_ERROR(__FILE__, __LINE__,
889				isc_msgcat_get(isc_msgcat,
890					       ISC_MSGSET_IFITERIOCTL,
891					       ISC_MSG_GETDESTADDR,
892					       "%s: getting "
893					       "destination address: %s"),
894					 lifreq.lifr_name, strbuf);
895			return (ISC_R_IGNORE);
896		}
897		get_addr(family, &iter->current.dstaddress,
898			 (struct sockaddr *)&lifreq.lifr_dstaddr,
899			 lifreq.lifr_name);
900	}
901#endif
902
903#ifdef SIOCGLIFBRDADDR
904	if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
905		/*
906		 * Ignore the HP/UX warning about "integer overflow during
907		 * conversion.  It comes from its own macro definition,
908		 * and is really hard to shut up.
909		 */
910		if (ioctl(iter->socket, SIOCGLIFBRDADDR, (char *)&lifreq)
911		    < 0) {
912			isc__strerror(errno, strbuf, sizeof(strbuf));
913			UNEXPECTED_ERROR(__FILE__, __LINE__,
914				isc_msgcat_get(isc_msgcat,
915					       ISC_MSGSET_IFITERIOCTL,
916					       ISC_MSG_GETDESTADDR,
917					       "%s: getting "
918					       "broadcast address: %s"),
919					 lifreq.lifr_name, strbuf);
920			return (ISC_R_IGNORE);
921		}
922		get_addr(family, &iter->current.broadcast,
923			 (struct sockaddr *)&lifreq.lifr_broadaddr,
924			 lifreq.lifr_name);
925	}
926#endif	/* SIOCGLIFBRDADDR */
927
928	/*
929	 * Get the network mask.  Netmask already zeroed.
930	 */
931	memset(&lifreq, 0, sizeof(lifreq));
932	memcpy(&lifreq, ifrp, sizeof(lifreq));
933
934#ifdef lifr_addrlen
935	/*
936	 * Special case: if the system provides lifr_addrlen member, the
937	 * netmask of an IPv6 address can be derived from the length, since
938	 * an IPv6 address always has a contiguous mask.
939	 */
940	if (family == AF_INET6) {
941		int i, bits;
942
943		iter->current.netmask.family = family;
944		for (i = 0; i < lifreq.lifr_addrlen; i += 8) {
945			bits = lifreq.lifr_addrlen - i;
946			bits = (bits < 8) ? (8 - bits) : 0;
947			iter->current.netmask.type.in6.s6_addr[i / 8] =
948				(~0 << bits) & 0xff;
949		}
950
951		return (ISC_R_SUCCESS);
952	}
953#endif
954
955	/*
956	 * Ignore the HP/UX warning about "integer overflow during
957	 * conversion.  It comes from its own macro definition,
958	 * and is really hard to shut up.
959	 */
960	if (ioctl(fd, SIOCGLIFNETMASK, (char *)&lifreq) < 0) {
961		isc__strerror(errno, strbuf, sizeof(strbuf));
962		UNEXPECTED_ERROR(__FILE__, __LINE__,
963				 isc_msgcat_get(isc_msgcat,
964						ISC_MSGSET_IFITERIOCTL,
965						ISC_MSG_GETNETMASK,
966						"%s: getting netmask: %s"),
967				 lifreq.lifr_name, strbuf);
968		return (ISC_R_IGNORE);
969	}
970	get_addr(family, &iter->current.netmask,
971		 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
972
973	return (ISC_R_SUCCESS);
974}
975#endif
976
977static isc_result_t
978internal_current(isc_interfaceiter_t *iter) {
979#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
980	if (iter->mode == 6) {
981		iter->result6 = internal_current6(iter);
982		if (iter->result6 != ISC_R_NOMORE)
983			return (iter->result6);
984	}
985#endif
986#ifdef HAVE_TRUCLUSTER
987	if (!iter->clua_done)
988		return(internal_current_clusteralias(iter));
989#endif
990	return (internal_current4(iter));
991}
992
993/*
994 * Step the iterator to the next interface.  Unlike
995 * isc_interfaceiter_next(), this may leave the iterator
996 * positioned on an interface that will ultimately
997 * be ignored.  Return ISC_R_NOMORE if there are no more
998 * interfaces, otherwise ISC_R_SUCCESS.
999 */
1000static isc_result_t
1001internal_next4(isc_interfaceiter_t *iter) {
1002	struct ifreq *ifrp;
1003
1004	REQUIRE (iter->pos < (unsigned int) iter->ifc.ifc_len);
1005
1006#ifdef __linux
1007	if (linux_if_inet6_next(iter) == ISC_R_SUCCESS)
1008		return (ISC_R_SUCCESS);
1009	if (!iter->first)
1010		return (ISC_R_SUCCESS);
1011#endif
1012	ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
1013
1014#ifdef ISC_PLATFORM_HAVESALEN
1015	if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
1016		iter->pos += sizeof(ifrp->ifr_name) + ifrp->ifr_addr.sa_len;
1017	else
1018#endif
1019		iter->pos += sizeof(*ifrp);
1020
1021	if (iter->pos >= (unsigned int) iter->ifc.ifc_len)
1022		return (ISC_R_NOMORE);
1023
1024	return (ISC_R_SUCCESS);
1025}
1026
1027#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1028static isc_result_t
1029internal_next6(isc_interfaceiter_t *iter) {
1030	struct LIFREQ *ifrp;
1031
1032	if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE)
1033		return (iter->result6);
1034
1035	REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
1036
1037	ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
1038
1039#ifdef ISC_PLATFORM_HAVESALEN
1040	if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr))
1041		iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len;
1042	else
1043#endif
1044		iter->pos6 += sizeof(*ifrp);
1045
1046	if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len)
1047		return (ISC_R_NOMORE);
1048
1049	return (ISC_R_SUCCESS);
1050}
1051#endif
1052
1053static isc_result_t
1054internal_next(isc_interfaceiter_t *iter) {
1055#ifdef HAVE_TRUCLUSTER
1056	int clua_result;
1057#endif
1058#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1059	if (iter->mode == 6) {
1060		iter->result6 = internal_next6(iter);
1061		if (iter->result6 != ISC_R_NOMORE)
1062			return (iter->result6);
1063		if (iter->first6) {
1064			iter->first6 = ISC_FALSE;
1065			return (ISC_R_SUCCESS);
1066		}
1067	}
1068#endif
1069#ifdef HAVE_TRUCLUSTER
1070	if (!iter->clua_done) {
1071		clua_result = clua_getaliasaddress(&iter->clua_sa,
1072						   &iter->clua_context);
1073		if (clua_result != CLUA_SUCCESS)
1074			iter->clua_done = ISC_TRUE;
1075		return (ISC_R_SUCCESS);
1076	}
1077#endif
1078	return (internal_next4(iter));
1079}
1080
1081static void
1082internal_destroy(isc_interfaceiter_t *iter) {
1083	(void) close(iter->socket);
1084#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1085	if (iter->socket6 != -1)
1086		(void) close(iter->socket6);
1087	if (iter->buf6 != NULL) {
1088		isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
1089	}
1090#endif
1091#ifdef __linux
1092	if (iter->proc != NULL)
1093		fclose(iter->proc);
1094#endif
1095}
1096
1097static
1098void internal_first(isc_interfaceiter_t *iter) {
1099#ifdef HAVE_TRUCLUSTER
1100	int clua_result;
1101#endif
1102	iter->pos = 0;
1103#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1104	iter->pos6 = 0;
1105	if (iter->result6 == ISC_R_NOMORE)
1106		iter->result6 = ISC_R_SUCCESS;
1107	iter->first6 = ISC_TRUE;
1108#endif
1109#ifdef HAVE_TRUCLUSTER
1110	iter->clua_context = 0;
1111	clua_result = clua_getaliasaddress(&iter->clua_sa,
1112					   &iter->clua_context);
1113	iter->clua_done = ISC_TF(clua_result != CLUA_SUCCESS);
1114#endif
1115#ifdef __linux
1116	linux_if_inet6_first(iter);
1117#endif
1118}
1119