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