PageRenderTime 98ms CodeModel.GetById 40ms app.highlight 50ms RepoModel.GetById 2ms app.codeStats 0ms

/contrib/ntp/libisc/ifiter_ioctl.c

https://bitbucket.org/freebsd/freebsd-head/
C | 1118 lines | 829 code | 115 blank | 174 comment | 195 complexity | e62477b724f349b4f147df4a71820867 MD5 | raw file
   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}