1 /* $NetBSD: ifiter_ioctl.c,v 1.5 2014/12/10 04:38:01 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004-2009, 2014 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_flags iflr_flags 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 55 struct 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 112 static isc_result_t 113 getbuf4(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) 185 static isc_result_t 186 getbuf6(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 290 isc_result_t 291 isc_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 400 static void 401 get_inaddr(isc_netaddr_t *dst, struct in_addr *src) { 402 dst->family = AF_INET; 403 memmove(&dst->type.in, src, sizeof(struct in_addr)); 404 } 405 406 static isc_result_t 407 internal_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 430 static isc_result_t 431 internal_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 memmove(&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 memmove(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 (family == AF_INET) 525 goto inet; 526 527 #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR) 528 memset(&lifreq, 0, sizeof(lifreq)); 529 memmove(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name)); 530 memmove(&lifreq.lifr_addr, &iter->current.address.type.in6, 531 sizeof(iter->current.address.type.in6)); 532 533 if (ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) { 534 isc__strerror(errno, strbuf, sizeof(strbuf)); 535 UNEXPECTED_ERROR(__FILE__, __LINE__, 536 "%s: getting interface address: %s", 537 ifreq.ifr_name, strbuf); 538 return (ISC_R_IGNORE); 539 } 540 prefixlen = lifreq.lifr_addrlen; 541 #else 542 isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf)); 543 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, 544 ISC_LOGMODULE_INTERFACE, 545 ISC_LOG_INFO, 546 isc_msgcat_get(isc_msgcat, 547 ISC_MSGSET_IFITERIOCTL, 548 ISC_MSG_GETIFCONFIG, 549 "prefix length for %s is unknown " 550 "(assume 128)"), sabuf); 551 prefixlen = 128; 552 #endif 553 554 /* 555 * Netmask already zeroed. 556 */ 557 iter->current.netmask.family = family; 558 for (i = 0; i < 16; i++) { 559 if (prefixlen > 8) { 560 bits = 0; 561 prefixlen -= 8; 562 } else { 563 bits = 8 - prefixlen; 564 prefixlen = 0; 565 } 566 iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff; 567 } 568 return (ISC_R_SUCCESS); 569 570 inet: 571 if (family != AF_INET) 572 return (ISC_R_IGNORE); 573 #ifdef IFF_POINTOPOINT 574 /* 575 * If the interface is point-to-point, get the destination address. 576 */ 577 if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) { 578 /* 579 * Ignore the HP/UX warning about "integer overflow during 580 * conversion. It comes from its own macro definition, 581 * and is really hard to shut up. 582 */ 583 if (ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq) 584 < 0) { 585 isc__strerror(errno, strbuf, sizeof(strbuf)); 586 UNEXPECTED_ERROR(__FILE__, __LINE__, 587 isc_msgcat_get(isc_msgcat, 588 ISC_MSGSET_IFITERIOCTL, 589 ISC_MSG_GETDESTADDR, 590 "%s: getting " 591 "destination address: %s"), 592 ifreq.ifr_name, strbuf); 593 return (ISC_R_IGNORE); 594 } 595 get_addr(family, &iter->current.dstaddress, 596 (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name); 597 } 598 #endif 599 600 /* 601 * Get the network mask. 602 */ 603 memset(&ifreq, 0, sizeof(ifreq)); 604 memmove(&ifreq, ifrp, sizeof(ifreq)); 605 /* 606 * Ignore the HP/UX warning about "integer overflow during 607 * conversion. It comes from its own macro definition, 608 * and is really hard to shut up. 609 */ 610 if (ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) { 611 isc__strerror(errno, strbuf, sizeof(strbuf)); 612 UNEXPECTED_ERROR(__FILE__, __LINE__, 613 isc_msgcat_get(isc_msgcat, 614 ISC_MSGSET_IFITERIOCTL, 615 ISC_MSG_GETNETMASK, 616 "%s: getting netmask: %s"), 617 ifreq.ifr_name, strbuf); 618 return (ISC_R_IGNORE); 619 } 620 get_addr(family, &iter->current.netmask, 621 (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name); 622 return (ISC_R_SUCCESS); 623 } 624 625 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 626 static isc_result_t 627 internal_current6(isc_interfaceiter_t *iter) { 628 struct LIFREQ *ifrp; 629 struct LIFREQ lifreq; 630 int family; 631 char strbuf[ISC_STRERRORSIZE]; 632 int fd; 633 634 REQUIRE(VALID_IFITER(iter)); 635 if (iter->result6 != ISC_R_SUCCESS) 636 return (iter->result6); 637 REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len); 638 639 ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6); 640 641 memset(&lifreq, 0, sizeof(lifreq)); 642 memmove(&lifreq, ifrp, sizeof(lifreq)); 643 644 family = lifreq.lifr_addr.ss_family; 645 #ifdef ISC_PLATFORM_HAVEIPV6 646 if (family != AF_INET && family != AF_INET6) 647 #else 648 if (family != AF_INET) 649 #endif 650 return (ISC_R_IGNORE); 651 652 memset(&iter->current, 0, sizeof(iter->current)); 653 iter->current.af = family; 654 655 INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name)); 656 memset(iter->current.name, 0, sizeof(iter->current.name)); 657 memmove(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name)); 658 659 get_addr(family, &iter->current.address, 660 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name); 661 662 /* 663 * If the interface does not have a address ignore it. 664 */ 665 switch (family) { 666 case AF_INET: 667 if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY)) 668 return (ISC_R_IGNORE); 669 break; 670 case AF_INET6: 671 if (memcmp(&iter->current.address.type.in6, &in6addr_any, 672 sizeof(in6addr_any)) == 0) 673 return (ISC_R_IGNORE); 674 break; 675 } 676 677 /* 678 * Get interface flags. 679 */ 680 681 iter->current.flags = 0; 682 683 if (family == AF_INET6) 684 fd = iter->socket6; 685 else 686 fd = iter->socket; 687 688 /* 689 * Ignore the HP/UX warning about "integer overflow during 690 * conversion. It comes from its own macro definition, 691 * and is really hard to shut up. 692 */ 693 if (ioctl(fd, SIOCGLIFFLAGS, (char *) &lifreq) < 0) { 694 isc__strerror(errno, strbuf, sizeof(strbuf)); 695 UNEXPECTED_ERROR(__FILE__, __LINE__, 696 "%s: getting interface flags: %s", 697 lifreq.lifr_name, strbuf); 698 return (ISC_R_IGNORE); 699 } 700 701 if ((lifreq.lifr_flags & IFF_UP) != 0) 702 iter->current.flags |= INTERFACE_F_UP; 703 704 #ifdef IFF_POINTOPOINT 705 if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0) 706 iter->current.flags |= INTERFACE_F_POINTTOPOINT; 707 #endif 708 709 if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0) 710 iter->current.flags |= INTERFACE_F_LOOPBACK; 711 712 #ifdef IFF_POINTOPOINT 713 /* 714 * If the interface is point-to-point, get the destination address. 715 */ 716 if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) { 717 /* 718 * Ignore the HP/UX warning about "integer overflow during 719 * conversion. It comes from its own macro definition, 720 * and is really hard to shut up. 721 */ 722 if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq) 723 < 0) { 724 isc__strerror(errno, strbuf, sizeof(strbuf)); 725 UNEXPECTED_ERROR(__FILE__, __LINE__, 726 isc_msgcat_get(isc_msgcat, 727 ISC_MSGSET_IFITERIOCTL, 728 ISC_MSG_GETDESTADDR, 729 "%s: getting " 730 "destination address: %s"), 731 lifreq.lifr_name, strbuf); 732 return (ISC_R_IGNORE); 733 } 734 get_addr(family, &iter->current.dstaddress, 735 (struct sockaddr *)&lifreq.lifr_dstaddr, 736 lifreq.lifr_name); 737 } 738 #endif 739 740 /* 741 * Get the network mask. Netmask already zeroed. 742 */ 743 memset(&lifreq, 0, sizeof(lifreq)); 744 memmove(&lifreq, ifrp, sizeof(lifreq)); 745 746 #ifdef lifr_addrlen 747 /* 748 * Special case: if the system provides lifr_addrlen member, the 749 * netmask of an IPv6 address can be derived from the length, since 750 * an IPv6 address always has a contiguous mask. 751 */ 752 if (family == AF_INET6) { 753 int i, bits; 754 755 iter->current.netmask.family = family; 756 for (i = 0; i < lifreq.lifr_addrlen; i += 8) { 757 bits = lifreq.lifr_addrlen - i; 758 bits = (bits < 8) ? (8 - bits) : 0; 759 iter->current.netmask.type.in6.s6_addr[i / 8] = 760 (~0 << bits) & 0xff; 761 } 762 763 return (ISC_R_SUCCESS); 764 } 765 #endif 766 767 /* 768 * Ignore the HP/UX warning about "integer overflow during 769 * conversion. It comes from its own macro definition, 770 * and is really hard to shut up. 771 */ 772 if (ioctl(fd, SIOCGLIFNETMASK, (char *)&lifreq) < 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_GETNETMASK, 778 "%s: getting netmask: %s"), 779 lifreq.lifr_name, strbuf); 780 return (ISC_R_IGNORE); 781 } 782 get_addr(family, &iter->current.netmask, 783 (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name); 784 785 return (ISC_R_SUCCESS); 786 } 787 #endif 788 789 static isc_result_t 790 internal_current(isc_interfaceiter_t *iter) { 791 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 792 if (iter->mode == 6) { 793 iter->result6 = internal_current6(iter); 794 if (iter->result6 != ISC_R_NOMORE) 795 return (iter->result6); 796 } 797 #endif 798 #ifdef HAVE_TRUCLUSTER 799 if (!iter->clua_done) 800 return(internal_current_clusteralias(iter)); 801 #endif 802 return (internal_current4(iter)); 803 } 804 805 /* 806 * Step the iterator to the next interface. Unlike 807 * isc_interfaceiter_next(), this may leave the iterator 808 * positioned on an interface that will ultimately 809 * be ignored. Return ISC_R_NOMORE if there are no more 810 * interfaces, otherwise ISC_R_SUCCESS. 811 */ 812 static isc_result_t 813 internal_next4(isc_interfaceiter_t *iter) { 814 #ifdef ISC_PLATFORM_HAVESALEN 815 struct ifreq *ifrp; 816 #endif 817 818 if (iter->pos < (unsigned int) iter->ifc.ifc_len) { 819 #ifdef ISC_PLATFORM_HAVESALEN 820 ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos); 821 822 if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr)) 823 iter->pos += sizeof(ifrp->ifr_name) + 824 ifrp->ifr_addr.sa_len; 825 else 826 #endif 827 iter->pos += sizeof(struct ifreq); 828 829 } else { 830 INSIST(iter->pos == (unsigned int) iter->ifc.ifc_len); 831 #ifdef __linux 832 return (linux_if_inet6_next(iter)); 833 #else 834 return (ISC_R_NOMORE); 835 #endif 836 } 837 return (ISC_R_SUCCESS); 838 } 839 840 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 841 static isc_result_t 842 internal_next6(isc_interfaceiter_t *iter) { 843 #ifdef ISC_PLATFORM_HAVESALEN 844 struct LIFREQ *ifrp; 845 #endif 846 847 if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE) 848 return (iter->result6); 849 850 REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len); 851 852 #ifdef ISC_PLATFORM_HAVESALEN 853 ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6); 854 855 if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr)) 856 iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len; 857 else 858 #endif 859 iter->pos6 += sizeof(struct LIFREQ); 860 861 if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len) 862 return (ISC_R_NOMORE); 863 864 return (ISC_R_SUCCESS); 865 } 866 #endif 867 868 static isc_result_t 869 internal_next(isc_interfaceiter_t *iter) { 870 #ifdef HAVE_TRUCLUSTER 871 int clua_result; 872 #endif 873 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 874 if (iter->mode == 6) { 875 iter->result6 = internal_next6(iter); 876 if (iter->result6 != ISC_R_NOMORE) 877 return (iter->result6); 878 if (iter->first6) { 879 iter->first6 = ISC_FALSE; 880 return (ISC_R_SUCCESS); 881 } 882 } 883 #endif 884 #ifdef HAVE_TRUCLUSTER 885 if (!iter->clua_done) { 886 clua_result = clua_getaliasaddress(&iter->clua_sa, 887 &iter->clua_context); 888 if (clua_result != CLUA_SUCCESS) 889 iter->clua_done = ISC_TRUE; 890 return (ISC_R_SUCCESS); 891 } 892 #endif 893 return (internal_next4(iter)); 894 } 895 896 static void 897 internal_destroy(isc_interfaceiter_t *iter) { 898 (void) close(iter->socket); 899 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 900 if (iter->socket6 != -1) 901 (void) close(iter->socket6); 902 if (iter->buf6 != NULL) { 903 isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6); 904 } 905 #endif 906 #ifdef __linux 907 if (iter->proc != NULL) 908 fclose(iter->proc); 909 #endif 910 } 911 912 static 913 void internal_first(isc_interfaceiter_t *iter) { 914 #ifdef HAVE_TRUCLUSTER 915 int clua_result; 916 #endif 917 iter->pos = 0; 918 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR) 919 iter->pos6 = 0; 920 if (iter->result6 == ISC_R_NOMORE) 921 iter->result6 = ISC_R_SUCCESS; 922 iter->first6 = ISC_TRUE; 923 #endif 924 #ifdef HAVE_TRUCLUSTER 925 iter->clua_context = 0; 926 clua_result = clua_getaliasaddress(&iter->clua_sa, 927 &iter->clua_context); 928 iter->clua_done = ISC_TF(clua_result != CLUA_SUCCESS); 929 #endif 930 #ifdef __linux 931 linux_if_inet6_first(iter); 932 #endif 933 } 934