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