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