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