1132451Sroberto/* 2182007Sroberto * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") 3182007Sroberto * Copyright (C) 1999-2003 Internet Software Consortium. 4132451Sroberto * 5132451Sroberto * Permission to use, copy, modify, and distribute this software for any 6132451Sroberto * purpose with or without fee is hereby granted, provided that the above 7132451Sroberto * copyright notice and this permission notice appear in all copies. 8132451Sroberto * 9182007Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10182007Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11182007Sroberto * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12182007Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13182007Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14182007Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15182007Sroberto * PERFORMANCE OF THIS SOFTWARE. 16132451Sroberto */ 17132451Sroberto 18182007Sroberto/* $Id: ifiter_ioctl.c,v 1.19.2.5.2.14 2004/06/22 04:40:23 marka Exp $ */ 19132451Sroberto 20132451Sroberto/* 21132451Sroberto * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl. 22132451Sroberto * See netintro(4). 23132451Sroberto */ 24132451Sroberto 25132451Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 26132451Sroberto#ifdef ISC_PLATFORM_HAVEIF_LADDRCONF 27132451Sroberto#define lifc_len iflc_len 28132451Sroberto#define lifc_buf iflc_buf 29132451Sroberto#define lifc_req iflc_req 30132451Sroberto#define LIFCONF if_laddrconf 31132451Sroberto#else 32132451Sroberto#define ISC_HAVE_LIFC_FAMILY 1 33132451Sroberto#define ISC_HAVE_LIFC_FLAGS 1 34132451Sroberto#define LIFCONF lifconf 35132451Sroberto#endif 36132451Sroberto 37132451Sroberto#ifdef ISC_PLATFORM_HAVEIF_LADDRREQ 38132451Sroberto#define lifr_addr iflr_addr 39132451Sroberto#define lifr_name iflr_name 40132451Sroberto#define lifr_dstaddr iflr_dstaddr 41132451Sroberto#define lifr_broadaddr iflr_broadaddr 42132451Sroberto#define lifr_flags iflr_flags 43182007Sroberto#define lifr_index iflr_index 44132451Sroberto#define ss_family sa_family 45132451Sroberto#define LIFREQ if_laddrreq 46132451Sroberto#else 47132451Sroberto#define LIFREQ lifreq 48132451Sroberto#endif 49132451Sroberto#endif 50132451Sroberto 51132451Sroberto#define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'T') 52132451Sroberto#define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC) 53132451Sroberto 54182007Sroberto#define ISC_IF_INET6_SZ \ 55182007Sroberto sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n") 56182007Sroberto 57132451Srobertostruct isc_interfaceiter { 58132451Sroberto unsigned int magic; /* Magic number. */ 59132451Sroberto isc_mem_t *mctx; 60182007Sroberto int mode; 61132451Sroberto int socket; 62132451Sroberto struct ifconf ifc; 63182007Sroberto void *buf; /* Buffer for sysctl data. */ 64182007Sroberto unsigned int bufsize; /* Bytes allocated. */ 65182007Sroberto unsigned int pos; /* Current offset in 66182007Sroberto SIOCGIFCONF data */ 67132451Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 68182007Sroberto int socket6; 69132451Sroberto struct LIFCONF lifc; 70182007Sroberto void *buf6; /* Buffer for sysctl data. */ 71182007Sroberto unsigned int bufsize6; /* Bytes allocated. */ 72182007Sroberto unsigned int pos6; /* Current offset in 73182007Sroberto SIOCGLIFCONF data */ 74182007Sroberto isc_result_t result6; /* Last result code. */ 75182007Sroberto isc_boolean_t first6; 76132451Sroberto#endif 77132451Sroberto#ifdef HAVE_TRUCLUSTER 78132451Sroberto int clua_context; /* Cluster alias context */ 79182007Sroberto isc_boolean_t clua_done; 80182007Sroberto struct sockaddr clua_sa; 81132451Sroberto#endif 82182007Sroberto#ifdef __linux 83182007Sroberto FILE * proc; 84182007Sroberto char entry[ISC_IF_INET6_SZ]; 85182007Sroberto isc_result_t valid; 86182007Sroberto isc_boolean_t first; 87182007Sroberto#endif 88132451Sroberto isc_interface_t current; /* Current interface data. */ 89132451Sroberto isc_result_t result; /* Last result code. */ 90132451Sroberto}; 91132451Sroberto 92132451Sroberto#ifdef HAVE_TRUCLUSTER 93132451Sroberto#include <clua/clua.h> 94132451Sroberto#include <sys/socket.h> 95132451Sroberto#endif 96132451Sroberto 97132451Sroberto 98132451Sroberto/* 99132451Sroberto * Size of buffer for SIOCGLIFCONF, in bytes. We assume no sane system 100132451Sroberto * will have more than a megabyte of interface configuration data. 101132451Sroberto */ 102132451Sroberto#define IFCONF_BUFSIZE_INITIAL 4096 103132451Sroberto#define IFCONF_BUFSIZE_MAX 1048576 104132451Sroberto 105182007Sroberto#ifdef __linux 106182007Sroberto#ifndef IF_NAMESIZE 107182007Sroberto# ifdef IFNAMSIZ 108182007Sroberto# define IF_NAMESIZE IFNAMSIZ 109182007Sroberto# else 110182007Sroberto# define IF_NAMESIZE 16 111182007Sroberto# endif 112182007Sroberto#endif 113182007Sroberto#endif 114182007Sroberto 115132451Srobertostatic isc_result_t 116132451Srobertogetbuf4(isc_interfaceiter_t *iter) { 117132451Sroberto char strbuf[ISC_STRERRORSIZE]; 118132451Sroberto 119132451Sroberto iter->bufsize = IFCONF_BUFSIZE_INITIAL; 120132451Sroberto 121132451Sroberto for (;;) { 122132451Sroberto iter->buf = isc_mem_get(iter->mctx, iter->bufsize); 123132451Sroberto if (iter->buf == NULL) 124132451Sroberto return (ISC_R_NOMEMORY); 125132451Sroberto 126132451Sroberto memset(&iter->ifc.ifc_len, 0, sizeof(iter->ifc.ifc_len)); 127132451Sroberto iter->ifc.ifc_len = iter->bufsize; 128132451Sroberto iter->ifc.ifc_buf = iter->buf; 129132451Sroberto /* 130132451Sroberto * Ignore the HP/UX warning about "integer overflow during 131132451Sroberto * conversion". It comes from its own macro definition, 132132451Sroberto * and is really hard to shut up. 133132451Sroberto */ 134132451Sroberto if (ioctl(iter->socket, SIOCGIFCONF, (char *)&iter->ifc) 135132451Sroberto == -1) { 136132451Sroberto if (errno != EINVAL) { 137132451Sroberto isc__strerror(errno, strbuf, sizeof(strbuf)); 138132451Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 139132451Sroberto isc_msgcat_get(isc_msgcat, 140132451Sroberto ISC_MSGSET_IFITERIOCTL, 141132451Sroberto ISC_MSG_GETIFCONFIG, 142132451Sroberto "get interface " 143132451Sroberto "configuration: %s"), 144132451Sroberto strbuf); 145132451Sroberto goto unexpected; 146132451Sroberto } 147132451Sroberto /* 148132451Sroberto * EINVAL. Retry with a bigger buffer. 149132451Sroberto */ 150132451Sroberto } else { 151132451Sroberto /* 152132451Sroberto * The ioctl succeeded. 153132451Sroberto * Some OS's just return what will fit rather 154132451Sroberto * than set EINVAL if the buffer is too small 155132451Sroberto * to fit all the interfaces in. If 156132451Sroberto * ifc.lifc_len is too near to the end of the 157132451Sroberto * buffer we will grow it just in case and 158132451Sroberto * retry. 159132451Sroberto */ 160132451Sroberto if (iter->ifc.ifc_len + 2 * sizeof(struct ifreq) 161132451Sroberto < iter->bufsize) 162132451Sroberto break; 163132451Sroberto } 164132451Sroberto if (iter->bufsize >= IFCONF_BUFSIZE_MAX) { 165132451Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 166132451Sroberto isc_msgcat_get(isc_msgcat, 167132451Sroberto ISC_MSGSET_IFITERIOCTL, 168132451Sroberto ISC_MSG_BUFFERMAX, 169132451Sroberto "get interface " 170132451Sroberto "configuration: " 171132451Sroberto "maximum buffer " 172132451Sroberto "size exceeded")); 173132451Sroberto goto unexpected; 174132451Sroberto } 175132451Sroberto isc_mem_put(iter->mctx, iter->buf, iter->bufsize); 176132451Sroberto 177132451Sroberto iter->bufsize *= 2; 178132451Sroberto } 179132451Sroberto return (ISC_R_SUCCESS); 180132451Sroberto 181132451Sroberto unexpected: 182132451Sroberto isc_mem_put(iter->mctx, iter->buf, iter->bufsize); 183132451Sroberto iter->buf = NULL; 184132451Sroberto return (ISC_R_UNEXPECTED); 185132451Sroberto} 186132451Sroberto 187182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 188132451Srobertostatic isc_result_t 189132451Srobertogetbuf6(isc_interfaceiter_t *iter) { 190132451Sroberto char strbuf[ISC_STRERRORSIZE]; 191132451Sroberto isc_result_t result; 192132451Sroberto 193182007Sroberto iter->bufsize6 = IFCONF_BUFSIZE_INITIAL; 194132451Sroberto 195132451Sroberto for (;;) { 196182007Sroberto iter->buf6 = isc_mem_get(iter->mctx, iter->bufsize6); 197182007Sroberto if (iter->buf6 == NULL) 198132451Sroberto return (ISC_R_NOMEMORY); 199132451Sroberto 200182007Sroberto memset(&iter->lifc, 0, sizeof(iter->lifc)); 201132451Sroberto#ifdef ISC_HAVE_LIFC_FAMILY 202182007Sroberto iter->lifc.lifc_family = AF_INET6; 203132451Sroberto#endif 204132451Sroberto#ifdef ISC_HAVE_LIFC_FLAGS 205132451Sroberto iter->lifc.lifc_flags = 0; 206132451Sroberto#endif 207182007Sroberto iter->lifc.lifc_len = iter->bufsize6; 208182007Sroberto iter->lifc.lifc_buf = iter->buf6; 209132451Sroberto /* 210132451Sroberto * Ignore the HP/UX warning about "integer overflow during 211132451Sroberto * conversion". It comes from its own macro definition, 212132451Sroberto * and is really hard to shut up. 213132451Sroberto */ 214182007Sroberto if (ioctl(iter->socket6, SIOCGLIFCONF, (char *)&iter->lifc) 215132451Sroberto == -1) { 216132451Sroberto#ifdef __hpux 217132451Sroberto /* 218132451Sroberto * IPv6 interface scanning is not available on all 219132451Sroberto * kernels w/ IPv6 sockets. 220132451Sroberto */ 221132451Sroberto if (errno == ENOENT) { 222132451Sroberto isc__strerror(errno, strbuf, sizeof(strbuf)); 223132451Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 224132451Sroberto isc_msgcat_get(isc_msgcat, 225132451Sroberto ISC_MSGSET_IFITERIOCTL, 226132451Sroberto ISC_MSG_GETIFCONFIG, 227132451Sroberto "get interface " 228132451Sroberto "configuration: %s"), 229132451Sroberto strbuf); 230132451Sroberto result = ISC_R_FAILURE; 231132451Sroberto goto cleanup; 232132451Sroberto } 233132451Sroberto#endif 234132451Sroberto if (errno != EINVAL) { 235132451Sroberto isc__strerror(errno, strbuf, sizeof(strbuf)); 236132451Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 237132451Sroberto isc_msgcat_get(isc_msgcat, 238132451Sroberto ISC_MSGSET_IFITERIOCTL, 239132451Sroberto ISC_MSG_GETIFCONFIG, 240132451Sroberto "get interface " 241132451Sroberto "configuration: %s"), 242132451Sroberto strbuf); 243132451Sroberto result = ISC_R_UNEXPECTED; 244132451Sroberto goto cleanup; 245132451Sroberto } 246132451Sroberto /* 247132451Sroberto * EINVAL. Retry with a bigger buffer. 248132451Sroberto */ 249132451Sroberto } else { 250132451Sroberto /* 251132451Sroberto * The ioctl succeeded. 252132451Sroberto * Some OS's just return what will fit rather 253132451Sroberto * than set EINVAL if the buffer is too small 254132451Sroberto * to fit all the interfaces in. If 255132451Sroberto * ifc.ifc_len is too near to the end of the 256132451Sroberto * buffer we will grow it just in case and 257132451Sroberto * retry. 258132451Sroberto */ 259132451Sroberto if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ) 260182007Sroberto < iter->bufsize6) 261132451Sroberto break; 262132451Sroberto } 263182007Sroberto if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) { 264132451Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 265132451Sroberto isc_msgcat_get(isc_msgcat, 266132451Sroberto ISC_MSGSET_IFITERIOCTL, 267132451Sroberto ISC_MSG_BUFFERMAX, 268132451Sroberto "get interface " 269132451Sroberto "configuration: " 270132451Sroberto "maximum buffer " 271132451Sroberto "size exceeded")); 272132451Sroberto result = ISC_R_UNEXPECTED; 273132451Sroberto goto cleanup; 274132451Sroberto } 275182007Sroberto isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6); 276132451Sroberto 277182007Sroberto iter->bufsize6 *= 2; 278132451Sroberto } 279132451Sroberto 280182007Sroberto if (iter->lifc.lifc_len != 0) 281182007Sroberto iter->mode = 6; 282132451Sroberto return (ISC_R_SUCCESS); 283132451Sroberto 284132451Sroberto cleanup: 285182007Sroberto isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6); 286182007Sroberto iter->buf6 = NULL; 287132451Sroberto return (result); 288182007Sroberto} 289132451Sroberto#endif 290132451Sroberto 291132451Srobertoisc_result_t 292132451Srobertoisc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) { 293132451Sroberto isc_interfaceiter_t *iter; 294132451Sroberto isc_result_t result; 295132451Sroberto char strbuf[ISC_STRERRORSIZE]; 296132451Sroberto 297132451Sroberto REQUIRE(iterp != NULL); 298132451Sroberto REQUIRE(*iterp == NULL); 299132451Sroberto 300132451Sroberto iter = isc_mem_get(mctx, sizeof(*iter)); 301132451Sroberto if (iter == NULL) 302132451Sroberto return (ISC_R_NOMEMORY); 303132451Sroberto 304132451Sroberto iter->mctx = mctx; 305182007Sroberto iter->mode = 4; 306132451Sroberto iter->buf = NULL; 307182007Sroberto iter->pos = (unsigned int) -1; 308182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 309182007Sroberto iter->buf6 = NULL; 310182007Sroberto iter->pos6 = (unsigned int) -1; 311182007Sroberto iter->result6 = ISC_R_NOMORE; 312182007Sroberto iter->socket6 = -1; 313182007Sroberto iter->first6 = ISC_FALSE; 314182007Sroberto#endif 315132451Sroberto 316132451Sroberto /* 317182007Sroberto * Get the interface configuration, allocating more memory if 318182007Sroberto * necessary. 319132451Sroberto */ 320182007Sroberto 321182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 322182007Sroberto result = isc_net_probeipv6(); 323182007Sroberto if (result == ISC_R_SUCCESS) { 324182007Sroberto /* 325182007Sroberto * Create an unbound datagram socket to do the SIOCGLIFCONF 326182007Sroberto * ioctl on. HP/UX requires an AF_INET6 socket for 327182007Sroberto * SIOCGLIFCONF to get IPv6 addresses. 328182007Sroberto */ 329182007Sroberto if ((iter->socket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 330182007Sroberto isc__strerror(errno, strbuf, sizeof(strbuf)); 331182007Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 332182007Sroberto isc_msgcat_get(isc_msgcat, 333182007Sroberto ISC_MSGSET_IFITERIOCTL, 334182007Sroberto ISC_MSG_MAKESCANSOCKET, 335182007Sroberto "making interface " 336182007Sroberto "scan socket: %s"), 337182007Sroberto strbuf); 338182007Sroberto result = ISC_R_UNEXPECTED; 339182007Sroberto goto socket6_failure; 340182007Sroberto } 341182007Sroberto iter->result6 = getbuf6(iter); 342182007Sroberto if (iter->result6 != ISC_R_NOTIMPLEMENTED && 343182007Sroberto iter->result6 != ISC_R_SUCCESS) 344182007Sroberto goto ioctl6_failure; 345182007Sroberto } 346182007Sroberto#endif 347132451Sroberto if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 348132451Sroberto isc__strerror(errno, strbuf, sizeof(strbuf)); 349132451Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 350132451Sroberto isc_msgcat_get(isc_msgcat, 351132451Sroberto ISC_MSGSET_IFITERIOCTL, 352132451Sroberto ISC_MSG_MAKESCANSOCKET, 353132451Sroberto "making interface " 354132451Sroberto "scan socket: %s"), 355132451Sroberto strbuf); 356132451Sroberto result = ISC_R_UNEXPECTED; 357132451Sroberto goto socket_failure; 358132451Sroberto } 359182007Sroberto result = getbuf4(iter); 360132451Sroberto if (result != ISC_R_SUCCESS) 361132451Sroberto goto ioctl_failure; 362132451Sroberto 363132451Sroberto /* 364132451Sroberto * A newly created iterator has an undefined position 365132451Sroberto * until isc_interfaceiter_first() is called. 366132451Sroberto */ 367132451Sroberto#ifdef HAVE_TRUCLUSTER 368132451Sroberto iter->clua_context = -1; 369182007Sroberto iter->clua_done = ISC_TRUE; 370132451Sroberto#endif 371182007Sroberto#ifdef __linux 372182007Sroberto iter->proc = fopen("/proc/net/if_inet6", "r"); 373182007Sroberto iter->valid = ISC_R_FAILURE; 374182007Sroberto iter->first = ISC_FALSE; 375182007Sroberto#endif 376132451Sroberto iter->result = ISC_R_FAILURE; 377132451Sroberto 378132451Sroberto iter->magic = IFITER_MAGIC; 379132451Sroberto *iterp = iter; 380132451Sroberto return (ISC_R_SUCCESS); 381132451Sroberto 382132451Sroberto ioctl_failure: 383132451Sroberto if (iter->buf != NULL) 384132451Sroberto isc_mem_put(mctx, iter->buf, iter->bufsize); 385132451Sroberto (void) close(iter->socket); 386132451Sroberto 387132451Sroberto socket_failure: 388182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 389182007Sroberto if (iter->buf6 != NULL) 390182007Sroberto isc_mem_put(mctx, iter->buf6, iter->bufsize6); 391182007Sroberto ioctl6_failure: 392182007Sroberto if (iter->socket6 != -1) 393182007Sroberto (void) close(iter->socket6); 394182007Sroberto socket6_failure: 395182007Sroberto#endif 396182007Sroberto 397132451Sroberto isc_mem_put(mctx, iter, sizeof(*iter)); 398132451Sroberto return (result); 399132451Sroberto} 400132451Sroberto 401132451Sroberto#ifdef HAVE_TRUCLUSTER 402132451Srobertostatic void 403132451Srobertoget_inaddr(isc_netaddr_t *dst, struct in_addr *src) { 404132451Sroberto dst->family = AF_INET; 405132451Sroberto memcpy(&dst->type.in, src, sizeof(struct in_addr)); 406132451Sroberto} 407132451Sroberto 408132451Srobertostatic isc_result_t 409132451Srobertointernal_current_clusteralias(isc_interfaceiter_t *iter) { 410132451Sroberto struct clua_info ci; 411182007Sroberto if (clua_getaliasinfo(&iter->clua_sa, &ci) != CLUA_SUCCESS) 412182007Sroberto return (ISC_R_IGNORE); 413182007Sroberto memset(&iter->current, 0, sizeof(iter->current)); 414182007Sroberto iter->current.af = iter->clua_sa.sa_family; 415182007Sroberto memset(iter->current.name, 0, sizeof(iter->current.name)); 416182007Sroberto sprintf(iter->current.name, "clua%d", ci.aliasid); 417182007Sroberto iter->current.flags = INTERFACE_F_UP; 418182007Sroberto get_inaddr(&iter->current.address, &ci.addr); 419182007Sroberto get_inaddr(&iter->current.netmask, &ci.netmask); 420182007Sroberto return (ISC_R_SUCCESS); 421182007Sroberto} 422182007Sroberto#endif 423182007Sroberto 424182007Sroberto#ifdef __linux 425182007Srobertostatic isc_result_t 426182007Srobertolinux_if_inet6_next(isc_interfaceiter_t *iter) { 427182007Sroberto if (iter->proc != NULL && 428182007Sroberto fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL) 429182007Sroberto iter->valid = ISC_R_SUCCESS; 430182007Sroberto else 431182007Sroberto iter->valid = ISC_R_NOMORE; 432182007Sroberto return (iter->valid); 433182007Sroberto} 434182007Sroberto 435182007Srobertostatic void 436182007Srobertolinux_if_inet6_first(isc_interfaceiter_t *iter) { 437182007Sroberto if (iter->proc != NULL) { 438182007Sroberto rewind(iter->proc); 439182007Sroberto (void)linux_if_inet6_next(iter); 440182007Sroberto } else 441182007Sroberto iter->valid = ISC_R_NOMORE; 442182007Sroberto iter->first = ISC_FALSE; 443182007Sroberto} 444182007Sroberto 445182007Srobertostatic isc_result_t 446182007Srobertolinux_if_inet6_current(isc_interfaceiter_t *iter) { 447182007Sroberto char address[33]; 448182007Sroberto char name[IF_NAMESIZE+1]; 449182007Sroberto char strbuf[ISC_STRERRORSIZE]; 450182007Sroberto struct in6_addr addr6; 451182007Sroberto struct ifreq ifreq; 452182007Sroberto int ifindex, prefix, scope, flags; 453182007Sroberto int res; 454182007Sroberto unsigned int i; 455182007Sroberto 456182007Sroberto if (iter->valid != ISC_R_SUCCESS) 457182007Sroberto return (iter->valid); 458182007Sroberto if (iter->proc == NULL) { 459182007Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 460182007Sroberto "/proc/net/if_inet6:iter->proc == NULL"); 461182007Sroberto return (ISC_R_FAILURE); 462132451Sroberto } 463182007Sroberto 464182007Sroberto /* 465182007Sroberto * Format for /proc/net/if_inet6: 466182007Sroberto * (see iface_proc_info() in net/ipv6/addrconf.c) 467182007Sroberto * <addr6:32> <ifindex:2> <prefix:2> <scope:2> <flags:2> <name:8> 468182007Sroberto */ 469182007Sroberto res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n", 470182007Sroberto address, &ifindex, &prefix, &scope, &flags, name); 471182007Sroberto if (res != 6) { 472182007Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 473182007Sroberto "/proc/net/if_inet6:sscanf() -> %d (expected 6)", 474182007Sroberto res); 475182007Sroberto return (ISC_R_FAILURE); 476182007Sroberto } 477182007Sroberto if (strlen(address) != 32) { 478182007Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 479182007Sroberto "/proc/net/if_inet6:strlen(%s) != 32", address); 480182007Sroberto return (ISC_R_FAILURE); 481182007Sroberto } 482182007Sroberto for (i = 0; i < 16; i++) { 483182007Sroberto unsigned char byte; 484182007Sroberto static const char hex[] = "0123456789abcdef"; 485182007Sroberto byte = ((index(hex, address[i * 2]) - hex) << 4) | 486182007Sroberto (index(hex, address[i * 2 + 1]) - hex); 487182007Sroberto addr6.s6_addr[i] = byte; 488182007Sroberto } 489182007Sroberto iter->current.af = AF_INET6; 490182007Sroberto /* iter->current.ifindex = ifindex; */ 491182007Sroberto iter->current.flags = 0; 492182007Sroberto 493182007Sroberto memset(&ifreq, 0, sizeof(ifreq)); 494182007Sroberto INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name)); 495182007Sroberto strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name)); 496182007Sroberto 497182007Sroberto if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) { 498182007Sroberto isc__strerror(errno, strbuf, sizeof(strbuf)); 499182007Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 500182007Sroberto "%s: getting interface flags: %s", 501182007Sroberto ifreq.ifr_name, strbuf); 502182007Sroberto return (ISC_R_IGNORE); 503182007Sroberto } 504182007Sroberto 505182007Sroberto if ((ifreq.ifr_flags & IFF_UP) != 0) 506182007Sroberto iter->current.flags |= INTERFACE_F_UP; 507182007Sroberto#ifdef IFF_POINTOPOINT 508182007Sroberto if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0) 509182007Sroberto iter->current.flags |= INTERFACE_F_POINTTOPOINT; 510182007Sroberto#endif 511182007Sroberto if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0) 512182007Sroberto iter->current.flags |= INTERFACE_F_LOOPBACK; 513182007Sroberto if ((ifreq.ifr_flags & IFF_BROADCAST) != 0) 514182007Sroberto iter->current.flags |= INTERFACE_F_BROADCAST; 515182007Sroberto#ifdef IFF_MULTICAST 516182007Sroberto if ((ifreq.ifr_flags & IFF_MULTICAST) != 0) 517182007Sroberto iter->current.flags |= INTERFACE_F_MULTICAST; 518182007Sroberto#endif 519182007Sroberto 520182007Sroberto /* 521182007Sroberto * enable_multicast_if() requires scopeid for setsockopt, 522182007Sroberto * so associate address with their corresponding ifindex. 523182007Sroberto */ 524182007Sroberto isc_netaddr_fromin6(&iter->current.address, &addr6); 525182007Sroberto isc_netaddr_setzone(&iter->current.address, (isc_uint32_t)ifindex); 526182007Sroberto 527182007Sroberto for (i = 0; i < 16; i++) { 528182007Sroberto if (prefix > 8) { 529182007Sroberto addr6.s6_addr[i] = 0xff; 530182007Sroberto prefix -= 8; 531182007Sroberto } else { 532182007Sroberto addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff; 533182007Sroberto prefix = 0; 534182007Sroberto } 535182007Sroberto } 536182007Sroberto isc_netaddr_fromin6(&iter->current.netmask, &addr6); 537182007Sroberto strncpy(iter->current.name, name, sizeof(iter->current.name)); 538182007Sroberto return (ISC_R_SUCCESS); 539132451Sroberto} 540132451Sroberto#endif 541132451Sroberto 542132451Sroberto/* 543132451Sroberto * Get information about the current interface to iter->current. 544132451Sroberto * If successful, return ISC_R_SUCCESS. 545132451Sroberto * If the interface has an unsupported address family, or if 546132451Sroberto * some operation on it fails, return ISC_R_IGNORE to make 547132451Sroberto * the higher-level iterator code ignore it. 548132451Sroberto */ 549132451Sroberto 550132451Srobertostatic isc_result_t 551132451Srobertointernal_current4(isc_interfaceiter_t *iter) { 552132451Sroberto struct ifreq *ifrp; 553132451Sroberto struct ifreq ifreq; 554132451Sroberto int family; 555132451Sroberto char strbuf[ISC_STRERRORSIZE]; 556182007Sroberto#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR) 557182007Sroberto struct lifreq lifreq; 558182007Sroberto#else 559182007Sroberto char sabuf[256]; 560132451Sroberto#endif 561182007Sroberto int i, bits, prefixlen; 562182007Sroberto#ifdef __linux 563182007Sroberto isc_result_t result; 564182007Sroberto#endif 565132451Sroberto 566132451Sroberto REQUIRE(VALID_IFITER(iter)); 567132451Sroberto REQUIRE (iter->pos < (unsigned int) iter->ifc.ifc_len); 568132451Sroberto 569182007Sroberto#ifdef __linux 570182007Sroberto result = linux_if_inet6_current(iter); 571182007Sroberto if (result != ISC_R_NOMORE) 572182007Sroberto return (result); 573182007Sroberto iter->first = ISC_TRUE; 574182007Sroberto#endif 575182007Sroberto 576132451Sroberto ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos); 577132451Sroberto 578132451Sroberto memset(&ifreq, 0, sizeof(ifreq)); 579132451Sroberto memcpy(&ifreq, ifrp, sizeof(ifreq)); 580132451Sroberto 581132451Sroberto family = ifreq.ifr_addr.sa_family; 582182007Sroberto#if defined(ISC_PLATFORM_HAVEIPV6) 583132451Sroberto if (family != AF_INET && family != AF_INET6) 584132451Sroberto#else 585132451Sroberto if (family != AF_INET) 586132451Sroberto#endif 587132451Sroberto return (ISC_R_IGNORE); 588132451Sroberto 589132451Sroberto memset(&iter->current, 0, sizeof(iter->current)); 590132451Sroberto iter->current.af = family; 591132451Sroberto 592132451Sroberto INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name)); 593132451Sroberto memset(iter->current.name, 0, sizeof(iter->current.name)); 594132451Sroberto memcpy(iter->current.name, ifreq.ifr_name, sizeof(ifreq.ifr_name)); 595132451Sroberto 596132451Sroberto get_addr(family, &iter->current.address, 597182007Sroberto (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name); 598132451Sroberto 599132451Sroberto /* 600132451Sroberto * If the interface does not have a address ignore it. 601132451Sroberto */ 602132451Sroberto switch (family) { 603132451Sroberto case AF_INET: 604132451Sroberto if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY)) 605132451Sroberto return (ISC_R_IGNORE); 606132451Sroberto break; 607182007Sroberto#ifdef ISC_PLATFORM_HAVEIPV6 608132451Sroberto case AF_INET6: 609132451Sroberto if (memcmp(&iter->current.address.type.in6, &in6addr_any, 610132451Sroberto sizeof(in6addr_any)) == 0) 611132451Sroberto return (ISC_R_IGNORE); 612132451Sroberto break; 613182007Sroberto#endif 614132451Sroberto } 615132451Sroberto 616132451Sroberto /* 617132451Sroberto * Get interface flags. 618132451Sroberto */ 619132451Sroberto 620132451Sroberto iter->current.flags = 0; 621132451Sroberto 622132451Sroberto /* 623132451Sroberto * Ignore the HP/UX warning about "integer overflow during 624132451Sroberto * conversion. It comes from its own macro definition, 625132451Sroberto * and is really hard to shut up. 626132451Sroberto */ 627132451Sroberto if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) { 628132451Sroberto isc__strerror(errno, strbuf, sizeof(strbuf)); 629132451Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 630132451Sroberto "%s: getting interface flags: %s", 631132451Sroberto ifreq.ifr_name, strbuf); 632132451Sroberto return (ISC_R_IGNORE); 633132451Sroberto } 634132451Sroberto 635132451Sroberto if ((ifreq.ifr_flags & IFF_UP) != 0) 636132451Sroberto iter->current.flags |= INTERFACE_F_UP; 637132451Sroberto 638182007Sroberto#ifdef IFF_POINTOPOINT 639132451Sroberto if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0) 640132451Sroberto iter->current.flags |= INTERFACE_F_POINTTOPOINT; 641182007Sroberto#endif 642132451Sroberto 643132451Sroberto if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0) 644132451Sroberto iter->current.flags |= INTERFACE_F_LOOPBACK; 645132451Sroberto 646132451Sroberto if ((ifreq.ifr_flags & IFF_BROADCAST) != 0) { 647132451Sroberto iter->current.flags |= INTERFACE_F_BROADCAST; 648132451Sroberto } 649132451Sroberto 650132451Sroberto#ifdef IFF_MULTICAST 651132451Sroberto if ((ifreq.ifr_flags & IFF_MULTICAST) != 0) { 652132451Sroberto iter->current.flags |= INTERFACE_F_MULTICAST; 653132451Sroberto } 654132451Sroberto#endif 655132451Sroberto 656182007Sroberto if (family == AF_INET) 657132451Sroberto goto inet; 658132451Sroberto 659182007Sroberto#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR) 660182007Sroberto memset(&lifreq, 0, sizeof(lifreq)); 661182007Sroberto memcpy(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name)); 662182007Sroberto memcpy(&lifreq.lifr_addr, &iter->current.address.type.in6, 663132451Sroberto sizeof(iter->current.address.type.in6)); 664132451Sroberto 665182007Sroberto if (ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) { 666132451Sroberto isc__strerror(errno, strbuf, sizeof(strbuf)); 667132451Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 668132451Sroberto "%s: getting interface address: %s", 669132451Sroberto ifreq.ifr_name, strbuf); 670132451Sroberto return (ISC_R_IGNORE); 671132451Sroberto } 672182007Sroberto prefixlen = lifreq.lifr_addrlen; 673182007Sroberto#else 674182007Sroberto isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf)); 675182007Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 676182007Sroberto isc_msgcat_get(isc_msgcat, 677182007Sroberto ISC_MSGSET_IFITERIOCTL, 678182007Sroberto ISC_MSG_GETIFCONFIG, 679182007Sroberto "prefix length for %s is unknown " 680182007Sroberto "(assume 128)"), sabuf); 681182007Sroberto prefixlen = 128; 682182007Sroberto#endif 683132451Sroberto 684132451Sroberto /* 685132451Sroberto * Netmask already zeroed. 686132451Sroberto */ 687132451Sroberto iter->current.netmask.family = family; 688132451Sroberto for (i = 0; i < 16; i++) { 689182007Sroberto if (prefixlen > 8) { 690132451Sroberto bits = 0; 691182007Sroberto prefixlen -= 8; 692132451Sroberto } else { 693182007Sroberto bits = 8 - prefixlen; 694182007Sroberto prefixlen = 0; 695132451Sroberto } 696132451Sroberto iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff; 697132451Sroberto } 698132451Sroberto return (ISC_R_SUCCESS); 699132451Sroberto 700132451Sroberto inet: 701132451Sroberto if (family != AF_INET) 702132451Sroberto return (ISC_R_IGNORE); 703182007Sroberto#ifdef IFF_POINTOPOINT 704132451Sroberto /* 705132451Sroberto * If the interface is point-to-point, get the destination address. 706132451Sroberto */ 707132451Sroberto if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) { 708132451Sroberto /* 709132451Sroberto * Ignore the HP/UX warning about "integer overflow during 710132451Sroberto * conversion. It comes from its own macro definition, 711132451Sroberto * and is really hard to shut up. 712132451Sroberto */ 713132451Sroberto if (ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq) 714132451Sroberto < 0) { 715132451Sroberto isc__strerror(errno, strbuf, sizeof(strbuf)); 716132451Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 717132451Sroberto isc_msgcat_get(isc_msgcat, 718132451Sroberto ISC_MSGSET_IFITERIOCTL, 719132451Sroberto ISC_MSG_GETDESTADDR, 720132451Sroberto "%s: getting " 721132451Sroberto "destination address: %s"), 722132451Sroberto ifreq.ifr_name, strbuf); 723132451Sroberto return (ISC_R_IGNORE); 724132451Sroberto } 725132451Sroberto get_addr(family, &iter->current.dstaddress, 726182007Sroberto (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name); 727132451Sroberto } 728182007Sroberto#endif 729132451Sroberto if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) { 730132451Sroberto /* 731132451Sroberto * Ignore the HP/UX warning about "integer overflow during 732132451Sroberto * conversion. It comes from its own macro definition, 733132451Sroberto * and is really hard to shut up. 734132451Sroberto */ 735132451Sroberto if (ioctl(iter->socket, SIOCGIFBRDADDR, (char *)&ifreq) 736132451Sroberto < 0) { 737132451Sroberto isc__strerror(errno, strbuf, sizeof(strbuf)); 738132451Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 739132451Sroberto isc_msgcat_get(isc_msgcat, 740132451Sroberto ISC_MSGSET_IFITERIOCTL, 741132451Sroberto ISC_MSG_GETDESTADDR, 742132451Sroberto "%s: getting " 743132451Sroberto "broadcast address: %s"), 744132451Sroberto ifreq.ifr_name, strbuf); 745132451Sroberto return (ISC_R_IGNORE); 746132451Sroberto } 747132451Sroberto get_addr(family, &iter->current.broadcast, 748182007Sroberto (struct sockaddr *)&ifreq.ifr_broadaddr, ifreq.ifr_name); 749132451Sroberto } 750182007Sroberto 751132451Sroberto /* 752132451Sroberto * Get the network mask. 753132451Sroberto */ 754132451Sroberto memset(&ifreq, 0, sizeof(ifreq)); 755132451Sroberto memcpy(&ifreq, ifrp, sizeof(ifreq)); 756132451Sroberto /* 757132451Sroberto * Ignore the HP/UX warning about "integer overflow during 758132451Sroberto * conversion. It comes from its own macro definition, 759132451Sroberto * and is really hard to shut up. 760132451Sroberto */ 761182007Sroberto if (ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) { 762132451Sroberto isc__strerror(errno, strbuf, sizeof(strbuf)); 763132451Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 764132451Sroberto isc_msgcat_get(isc_msgcat, 765132451Sroberto ISC_MSGSET_IFITERIOCTL, 766132451Sroberto ISC_MSG_GETNETMASK, 767132451Sroberto "%s: getting netmask: %s"), 768132451Sroberto ifreq.ifr_name, strbuf); 769132451Sroberto return (ISC_R_IGNORE); 770132451Sroberto } 771132451Sroberto get_addr(family, &iter->current.netmask, 772182007Sroberto (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name); 773132451Sroberto return (ISC_R_SUCCESS); 774132451Sroberto} 775132451Sroberto 776182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 777132451Srobertostatic isc_result_t 778132451Srobertointernal_current6(isc_interfaceiter_t *iter) { 779132451Sroberto struct LIFREQ *ifrp; 780132451Sroberto struct LIFREQ lifreq; 781132451Sroberto int family; 782132451Sroberto char strbuf[ISC_STRERRORSIZE]; 783182007Sroberto int fd; 784132451Sroberto 785132451Sroberto REQUIRE(VALID_IFITER(iter)); 786182007Sroberto if (iter->result6 != ISC_R_SUCCESS) 787182007Sroberto return (iter->result6); 788182007Sroberto REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len); 789132451Sroberto 790182007Sroberto ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6); 791132451Sroberto 792132451Sroberto memset(&lifreq, 0, sizeof(lifreq)); 793132451Sroberto memcpy(&lifreq, ifrp, sizeof(lifreq)); 794132451Sroberto 795132451Sroberto family = lifreq.lifr_addr.ss_family; 796132451Sroberto#ifdef ISC_PLATFORM_HAVEIPV6 797132451Sroberto if (family != AF_INET && family != AF_INET6) 798132451Sroberto#else 799132451Sroberto if (family != AF_INET) 800132451Sroberto#endif 801132451Sroberto return (ISC_R_IGNORE); 802132451Sroberto 803132451Sroberto memset(&iter->current, 0, sizeof(iter->current)); 804132451Sroberto iter->current.af = family; 805132451Sroberto 806132451Sroberto INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name)); 807132451Sroberto memset(iter->current.name, 0, sizeof(iter->current.name)); 808132451Sroberto memcpy(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name)); 809132451Sroberto 810132451Sroberto get_addr(family, &iter->current.address, 811182007Sroberto (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name); 812132451Sroberto 813132451Sroberto /* 814132451Sroberto * If the interface does not have a address ignore it. 815132451Sroberto */ 816132451Sroberto switch (family) { 817132451Sroberto case AF_INET: 818132451Sroberto if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY)) 819132451Sroberto return (ISC_R_IGNORE); 820132451Sroberto break; 821182007Sroberto#ifdef ISC_PLATFORM_HAVEIPV6 822132451Sroberto case AF_INET6: 823132451Sroberto if (memcmp(&iter->current.address.type.in6, &in6addr_any, 824132451Sroberto sizeof(in6addr_any)) == 0) 825132451Sroberto return (ISC_R_IGNORE); 826132451Sroberto break; 827182007Sroberto#endif 828132451Sroberto } 829132451Sroberto 830132451Sroberto /* 831132451Sroberto * Get interface flags. 832132451Sroberto */ 833132451Sroberto 834132451Sroberto iter->current.flags = 0; 835132451Sroberto 836182007Sroberto if (family == AF_INET6) 837182007Sroberto fd = iter->socket6; 838182007Sroberto else 839182007Sroberto fd = iter->socket; 840182007Sroberto 841132451Sroberto /* 842132451Sroberto * Ignore the HP/UX warning about "integer overflow during 843132451Sroberto * conversion. It comes from its own macro definition, 844132451Sroberto * and is really hard to shut up. 845132451Sroberto */ 846182007Sroberto if (ioctl(fd, SIOCGLIFFLAGS, (char *) &lifreq) < 0) { 847182007Sroberto isc__strerror(errno, strbuf, sizeof(strbuf)); 848182007Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 849132451Sroberto "%s: getting interface flags: %s", 850132451Sroberto lifreq.lifr_name, strbuf); 851182007Sroberto return (ISC_R_IGNORE); 852132451Sroberto } 853132451Sroberto 854132451Sroberto if ((lifreq.lifr_flags & IFF_UP) != 0) 855132451Sroberto iter->current.flags |= INTERFACE_F_UP; 856132451Sroberto 857182007Sroberto#ifdef IFF_POINTOPOINT 858132451Sroberto if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0) 859132451Sroberto iter->current.flags |= INTERFACE_F_POINTTOPOINT; 860182007Sroberto#endif 861132451Sroberto 862132451Sroberto if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0) 863132451Sroberto iter->current.flags |= INTERFACE_F_LOOPBACK; 864132451Sroberto 865182007Sroberto if ((lifreq.lifr_flags & IFF_BROADCAST) != 0) { 866182007Sroberto iter->current.flags |= INTERFACE_F_BROADCAST; 867182007Sroberto } 868132451Sroberto 869132451Sroberto#ifdef IFF_MULTICAST 870132451Sroberto if ((lifreq.lifr_flags & IFF_MULTICAST) != 0) { 871132451Sroberto iter->current.flags |= INTERFACE_F_MULTICAST; 872132451Sroberto } 873132451Sroberto#endif 874132451Sroberto 875182007Sroberto#ifdef IFF_POINTOPOINT 876132451Sroberto /* 877132451Sroberto * If the interface is point-to-point, get the destination address. 878132451Sroberto */ 879132451Sroberto if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) { 880132451Sroberto /* 881132451Sroberto * Ignore the HP/UX warning about "interger overflow during 882132451Sroberto * conversion. It comes from its own macro definition, 883132451Sroberto * and is really hard to shut up. 884132451Sroberto */ 885182007Sroberto if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq) 886132451Sroberto < 0) { 887132451Sroberto isc__strerror(errno, strbuf, sizeof(strbuf)); 888132451Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 889132451Sroberto isc_msgcat_get(isc_msgcat, 890132451Sroberto ISC_MSGSET_IFITERIOCTL, 891132451Sroberto ISC_MSG_GETDESTADDR, 892132451Sroberto "%s: getting " 893132451Sroberto "destination address: %s"), 894132451Sroberto lifreq.lifr_name, strbuf); 895132451Sroberto return (ISC_R_IGNORE); 896132451Sroberto } 897132451Sroberto get_addr(family, &iter->current.dstaddress, 898182007Sroberto (struct sockaddr *)&lifreq.lifr_dstaddr, 899182007Sroberto lifreq.lifr_name); 900132451Sroberto } 901182007Sroberto#endif 902132451Sroberto 903182007Sroberto#ifdef SIOCGLIFBRDADDR 904182007Sroberto if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) { 905132451Sroberto /* 906132451Sroberto * Ignore the HP/UX warning about "integer overflow during 907132451Sroberto * conversion. It comes from its own macro definition, 908132451Sroberto * and is really hard to shut up. 909132451Sroberto */ 910182007Sroberto if (ioctl(iter->socket, SIOCGLIFBRDADDR, (char *)&lifreq) 911132451Sroberto < 0) { 912132451Sroberto isc__strerror(errno, strbuf, sizeof(strbuf)); 913132451Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 914132451Sroberto isc_msgcat_get(isc_msgcat, 915132451Sroberto ISC_MSGSET_IFITERIOCTL, 916182007Sroberto ISC_MSG_GETDESTADDR, 917182007Sroberto "%s: getting " 918182007Sroberto "broadcast address: %s"), 919132451Sroberto lifreq.lifr_name, strbuf); 920132451Sroberto return (ISC_R_IGNORE); 921132451Sroberto } 922182007Sroberto get_addr(family, &iter->current.broadcast, 923182007Sroberto (struct sockaddr *)&lifreq.lifr_broadaddr, 924182007Sroberto lifreq.lifr_name); 925182007Sroberto } 926182007Sroberto#endif /* SIOCGLIFBRDADDR */ 927182007Sroberto 928182007Sroberto /* 929182007Sroberto * Get the network mask. Netmask already zeroed. 930182007Sroberto */ 931182007Sroberto memset(&lifreq, 0, sizeof(lifreq)); 932182007Sroberto memcpy(&lifreq, ifrp, sizeof(lifreq)); 933182007Sroberto 934132451Sroberto#ifdef lifr_addrlen 935182007Sroberto /* 936182007Sroberto * Special case: if the system provides lifr_addrlen member, the 937182007Sroberto * netmask of an IPv6 address can be derived from the length, since 938182007Sroberto * an IPv6 address always has a contiguous mask. 939182007Sroberto */ 940182007Sroberto if (family == AF_INET6) { 941132451Sroberto int i, bits; 942132451Sroberto 943132451Sroberto iter->current.netmask.family = family; 944132451Sroberto for (i = 0; i < lifreq.lifr_addrlen; i += 8) { 945132451Sroberto bits = lifreq.lifr_addrlen - i; 946132451Sroberto bits = (bits < 8) ? (8 - bits) : 0; 947132451Sroberto iter->current.netmask.type.in6.s6_addr[i / 8] = 948132451Sroberto (~0 << bits) & 0xff; 949132451Sroberto } 950182007Sroberto 951182007Sroberto return (ISC_R_SUCCESS); 952182007Sroberto } 953132451Sroberto#endif 954182007Sroberto 955182007Sroberto /* 956182007Sroberto * Ignore the HP/UX warning about "integer overflow during 957182007Sroberto * conversion. It comes from its own macro definition, 958182007Sroberto * and is really hard to shut up. 959182007Sroberto */ 960182007Sroberto if (ioctl(fd, SIOCGLIFNETMASK, (char *)&lifreq) < 0) { 961182007Sroberto isc__strerror(errno, strbuf, sizeof(strbuf)); 962182007Sroberto UNEXPECTED_ERROR(__FILE__, __LINE__, 963182007Sroberto isc_msgcat_get(isc_msgcat, 964182007Sroberto ISC_MSGSET_IFITERIOCTL, 965182007Sroberto ISC_MSG_GETNETMASK, 966182007Sroberto "%s: getting netmask: %s"), 967182007Sroberto lifreq.lifr_name, strbuf); 968182007Sroberto return (ISC_R_IGNORE); 969132451Sroberto } 970182007Sroberto get_addr(family, &iter->current.netmask, 971182007Sroberto (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name); 972132451Sroberto 973132451Sroberto return (ISC_R_SUCCESS); 974182007Sroberto} 975132451Sroberto#endif 976132451Sroberto 977132451Srobertostatic isc_result_t 978132451Srobertointernal_current(isc_interfaceiter_t *iter) { 979182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 980182007Sroberto if (iter->mode == 6) { 981182007Sroberto iter->result6 = internal_current6(iter); 982182007Sroberto if (iter->result6 != ISC_R_NOMORE) 983182007Sroberto return (iter->result6); 984182007Sroberto } 985182007Sroberto#endif 986182007Sroberto#ifdef HAVE_TRUCLUSTER 987182007Sroberto if (!iter->clua_done) 988182007Sroberto return(internal_current_clusteralias(iter)); 989182007Sroberto#endif 990132451Sroberto return (internal_current4(iter)); 991132451Sroberto} 992132451Sroberto 993132451Sroberto/* 994132451Sroberto * Step the iterator to the next interface. Unlike 995132451Sroberto * isc_interfaceiter_next(), this may leave the iterator 996132451Sroberto * positioned on an interface that will ultimately 997132451Sroberto * be ignored. Return ISC_R_NOMORE if there are no more 998132451Sroberto * interfaces, otherwise ISC_R_SUCCESS. 999132451Sroberto */ 1000132451Srobertostatic isc_result_t 1001132451Srobertointernal_next4(isc_interfaceiter_t *iter) { 1002132451Sroberto struct ifreq *ifrp; 1003132451Sroberto 1004132451Sroberto REQUIRE (iter->pos < (unsigned int) iter->ifc.ifc_len); 1005132451Sroberto 1006182007Sroberto#ifdef __linux 1007182007Sroberto if (linux_if_inet6_next(iter) == ISC_R_SUCCESS) 1008132451Sroberto return (ISC_R_SUCCESS); 1009182007Sroberto if (!iter->first) 1010182007Sroberto return (ISC_R_SUCCESS); 1011132451Sroberto#endif 1012132451Sroberto ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos); 1013132451Sroberto 1014132451Sroberto#ifdef ISC_PLATFORM_HAVESALEN 1015132451Sroberto if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr)) 1016132451Sroberto iter->pos += sizeof(ifrp->ifr_name) + ifrp->ifr_addr.sa_len; 1017132451Sroberto else 1018132451Sroberto#endif 1019132451Sroberto iter->pos += sizeof(*ifrp); 1020132451Sroberto 1021132451Sroberto if (iter->pos >= (unsigned int) iter->ifc.ifc_len) 1022132451Sroberto return (ISC_R_NOMORE); 1023132451Sroberto 1024132451Sroberto return (ISC_R_SUCCESS); 1025132451Sroberto} 1026132451Sroberto 1027182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 1028132451Srobertostatic isc_result_t 1029132451Srobertointernal_next6(isc_interfaceiter_t *iter) { 1030132451Sroberto struct LIFREQ *ifrp; 1031182007Sroberto 1032182007Sroberto if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE) 1033182007Sroberto return (iter->result6); 1034132451Sroberto 1035182007Sroberto REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len); 1036132451Sroberto 1037182007Sroberto ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6); 1038132451Sroberto 1039132451Sroberto#ifdef ISC_PLATFORM_HAVESALEN 1040132451Sroberto if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr)) 1041182007Sroberto iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len; 1042132451Sroberto else 1043132451Sroberto#endif 1044182007Sroberto iter->pos6 += sizeof(*ifrp); 1045132451Sroberto 1046182007Sroberto if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len) 1047132451Sroberto return (ISC_R_NOMORE); 1048132451Sroberto 1049132451Sroberto return (ISC_R_SUCCESS); 1050182007Sroberto} 1051132451Sroberto#endif 1052132451Sroberto 1053132451Srobertostatic isc_result_t 1054132451Srobertointernal_next(isc_interfaceiter_t *iter) { 1055182007Sroberto#ifdef HAVE_TRUCLUSTER 1056182007Sroberto int clua_result; 1057182007Sroberto#endif 1058182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 1059182007Sroberto if (iter->mode == 6) { 1060182007Sroberto iter->result6 = internal_next6(iter); 1061182007Sroberto if (iter->result6 != ISC_R_NOMORE) 1062182007Sroberto return (iter->result6); 1063182007Sroberto if (iter->first6) { 1064182007Sroberto iter->first6 = ISC_FALSE; 1065182007Sroberto return (ISC_R_SUCCESS); 1066182007Sroberto } 1067182007Sroberto } 1068182007Sroberto#endif 1069182007Sroberto#ifdef HAVE_TRUCLUSTER 1070182007Sroberto if (!iter->clua_done) { 1071182007Sroberto clua_result = clua_getaliasaddress(&iter->clua_sa, 1072182007Sroberto &iter->clua_context); 1073182007Sroberto if (clua_result != CLUA_SUCCESS) 1074182007Sroberto iter->clua_done = ISC_TRUE; 1075182007Sroberto return (ISC_R_SUCCESS); 1076182007Sroberto } 1077182007Sroberto#endif 1078132451Sroberto return (internal_next4(iter)); 1079132451Sroberto} 1080132451Sroberto 1081132451Srobertostatic void 1082132451Srobertointernal_destroy(isc_interfaceiter_t *iter) { 1083132451Sroberto (void) close(iter->socket); 1084182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 1085182007Sroberto if (iter->socket6 != -1) 1086182007Sroberto (void) close(iter->socket6); 1087182007Sroberto if (iter->buf6 != NULL) { 1088182007Sroberto isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6); 1089182007Sroberto } 1090182007Sroberto#endif 1091182007Sroberto#ifdef __linux 1092182007Sroberto if (iter->proc != NULL) 1093182007Sroberto fclose(iter->proc); 1094182007Sroberto#endif 1095132451Sroberto} 1096182007Sroberto 1097182007Srobertostatic 1098182007Srobertovoid internal_first(isc_interfaceiter_t *iter) { 1099182007Sroberto#ifdef HAVE_TRUCLUSTER 1100182007Sroberto int clua_result; 1101182007Sroberto#endif 1102182007Sroberto iter->pos = 0; 1103182007Sroberto#if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 1104182007Sroberto iter->pos6 = 0; 1105182007Sroberto if (iter->result6 == ISC_R_NOMORE) 1106182007Sroberto iter->result6 = ISC_R_SUCCESS; 1107182007Sroberto iter->first6 = ISC_TRUE; 1108182007Sroberto#endif 1109182007Sroberto#ifdef HAVE_TRUCLUSTER 1110182007Sroberto iter->clua_context = 0; 1111182007Sroberto clua_result = clua_getaliasaddress(&iter->clua_sa, 1112182007Sroberto &iter->clua_context); 1113182007Sroberto iter->clua_done = ISC_TF(clua_result != CLUA_SUCCESS); 1114182007Sroberto#endif 1115182007Sroberto#ifdef __linux 1116182007Sroberto linux_if_inet6_first(iter); 1117182007Sroberto#endif 1118182007Sroberto} 1119