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