1 /* $NetBSD: discover.c,v 1.4 2014/07/12 12:09:37 spz Exp $ */ 2 /* discover.c 3 4 Find and identify the network interfaces. */ 5 6 /* 7 * Copyright (c) 2013-2014 by Internet Systems Consortium, Inc. ("ISC") 8 * Copyright (c) 2004-2009,2011 by Internet Systems Consortium, Inc. ("ISC") 9 * Copyright (c) 1995-2003 by Internet Software Consortium 10 * 11 * Permission to use, copy, modify, and distribute this software for any 12 * purpose with or without fee is hereby granted, provided that the above 13 * copyright notice and this permission notice appear in all copies. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 * 23 * Internet Systems Consortium, Inc. 24 * 950 Charter Street 25 * Redwood City, CA 94063 26 * <info@isc.org> 27 * https://www.isc.org/ 28 * 29 */ 30 31 #include <sys/cdefs.h> 32 __RCSID("$NetBSD: discover.c,v 1.4 2014/07/12 12:09:37 spz Exp $"); 33 34 #include "dhcpd.h" 35 36 #define BSD_COMP /* needed on Solaris for SIOCGLIFNUM */ 37 #include <sys/ioctl.h> 38 #include <errno.h> 39 40 #ifdef HAVE_NET_IF6_H 41 # include <net/if6.h> 42 #endif 43 44 struct interface_info *interfaces, *dummy_interfaces, *fallback_interface; 45 int interfaces_invalidated; 46 int quiet_interface_discovery; 47 u_int16_t local_port; 48 u_int16_t remote_port; 49 int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *); 50 int (*dhcp_interface_discovery_hook) (struct interface_info *); 51 isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *); 52 int (*dhcp_interface_shutdown_hook) (struct interface_info *); 53 54 struct in_addr limited_broadcast; 55 56 int local_family = AF_INET; 57 struct in_addr local_address; 58 59 void (*bootp_packet_handler) (struct interface_info *, 60 struct dhcp_packet *, unsigned, 61 unsigned int, 62 struct iaddr, struct hardware *); 63 64 #ifdef DHCPv6 65 void (*dhcpv6_packet_handler)(struct interface_info *, 66 const char *, int, 67 int, const struct iaddr *, 68 isc_boolean_t); 69 #endif /* DHCPv6 */ 70 71 72 omapi_object_type_t *dhcp_type_interface; 73 #if defined (TRACING) 74 trace_type_t *interface_trace; 75 trace_type_t *inpacket_trace; 76 trace_type_t *outpacket_trace; 77 #endif 78 struct interface_info **interface_vector; 79 int interface_count; 80 int interface_max; 81 82 OMAPI_OBJECT_ALLOC (interface, struct interface_info, dhcp_type_interface) 83 84 isc_result_t interface_setup () 85 { 86 isc_result_t status; 87 status = omapi_object_type_register (&dhcp_type_interface, 88 "interface", 89 dhcp_interface_set_value, 90 dhcp_interface_get_value, 91 dhcp_interface_destroy, 92 dhcp_interface_signal_handler, 93 dhcp_interface_stuff_values, 94 dhcp_interface_lookup, 95 dhcp_interface_create, 96 dhcp_interface_remove, 97 0, 0, 0, 98 sizeof (struct interface_info), 99 interface_initialize, RC_MISC); 100 if (status != ISC_R_SUCCESS) 101 log_fatal ("Can't register interface object type: %s", 102 isc_result_totext (status)); 103 104 return status; 105 } 106 107 #if defined (TRACING) 108 void interface_trace_setup () 109 { 110 interface_trace = trace_type_register ("interface", (void *)0, 111 trace_interface_input, 112 trace_interface_stop, MDL); 113 inpacket_trace = trace_type_register ("inpacket", (void *)0, 114 trace_inpacket_input, 115 trace_inpacket_stop, MDL); 116 outpacket_trace = trace_type_register ("outpacket", (void *)0, 117 trace_outpacket_input, 118 trace_outpacket_stop, MDL); 119 } 120 #endif 121 122 isc_result_t interface_initialize (omapi_object_t *ipo, 123 const char *file, int line) 124 { 125 struct interface_info *ip = (struct interface_info *)ipo; 126 ip -> rfdesc = ip -> wfdesc = -1; 127 return ISC_R_SUCCESS; 128 } 129 130 131 /* 132 * Scanning for Interfaces 133 * ----------------------- 134 * 135 * To find interfaces, we create an iterator that abstracts out most 136 * of the platform specifics. Use is fairly straightforward: 137 * 138 * - begin_iface_scan() starts the process. 139 * - Use next_iface() until it returns 0. 140 * - end_iface_scan() performs any necessary cleanup. 141 * 142 * We check for errors on each call to next_iface(), which returns a 143 * description of the error as a string if any occurs. 144 * 145 * We currently have code for Solaris and Linux. Other systems need 146 * to have code written. 147 * 148 * NOTE: the long-term goal is to use the interface code from BIND 9. 149 */ 150 151 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && defined(SIOCGLIFFLAGS) 152 153 /* HP/UX doesn't define struct lifconf, instead they define struct 154 * if_laddrconf. Similarly, 'struct lifreq' and 'struct lifaddrreq'. 155 */ 156 #ifdef ISC_PLATFORM_HAVEIF_LADDRCONF 157 # define lifc_len iflc_len 158 # define lifc_buf iflc_buf 159 # define lifc_req iflc_req 160 # define LIFCONF if_laddrconf 161 #else 162 # define ISC_HAVE_LIFC_FAMILY 1 163 # define ISC_HAVE_LIFC_FLAGS 1 164 # define LIFCONF lifconf 165 #endif 166 167 #ifdef ISC_PLATFORM_HAVEIF_LADDRREQ 168 # define lifr_addr iflr_addr 169 # define lifr_name iflr_name 170 # define lifr_dstaddr iflr_dstaddr 171 # define lifr_flags iflr_flags 172 # define sockaddr_storage sockaddr_ext 173 # define ss_family sa_family 174 # define LIFREQ if_laddrreq 175 #else 176 # define LIFREQ lifreq 177 #endif 178 179 #ifndef IF_NAMESIZE 180 # if defined(LIFNAMSIZ) 181 # define IF_NAMESIZE LIFNAMSIZ 182 # elif defined(IFNAMSIZ) 183 # define IF_NAMESIZE IFNAMSIZ 184 # else 185 # define IF_NAMESIZE 16 186 # endif 187 #endif 188 #elif !defined(__linux) && !defined(HAVE_IFADDRS_H) 189 # define SIOCGLIFCONF SIOCGIFCONF 190 # define SIOCGLIFFLAGS SIOCGIFFLAGS 191 # define LIFREQ ifreq 192 # define LIFCONF ifconf 193 # define lifr_name ifr_name 194 # define lifr_addr ifr_addr 195 # define lifr_flags ifr_flags 196 # define lifc_len ifc_len 197 # define lifc_buf ifc_buf 198 # define lifc_req ifc_req 199 #ifdef _AIX 200 # define ss_family __ss_family 201 #endif 202 #endif 203 204 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) 205 /* 206 * Solaris support 207 * --------------- 208 * 209 * The SIOCGLIFCONF ioctl() are the extension that you need to use 210 * on Solaris to get information about IPv6 addresses. 211 * 212 * Solaris' extended interface is documented in the if_tcp man page. 213 */ 214 215 /* 216 * Structure holding state about the scan. 217 */ 218 struct iface_conf_list { 219 int sock; /* file descriptor used to get information */ 220 int num; /* total number of interfaces */ 221 struct LIFCONF conf; /* structure used to get information */ 222 int next; /* next interface to retrieve when iterating */ 223 }; 224 225 /* 226 * Structure used to return information about a specific interface. 227 */ 228 struct iface_info { 229 char name[IF_NAMESIZE+1]; /* name of the interface, e.g. "bge0" */ 230 struct sockaddr_storage addr; /* address information */ 231 isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */ 232 }; 233 234 /* 235 * Start a scan of interfaces. 236 * 237 * The iface_conf_list structure maintains state for this process. 238 */ 239 static int 240 begin_iface_scan(struct iface_conf_list *ifaces) { 241 #ifdef ISC_PLATFORM_HAVELIFNUM 242 struct lifnum lifnum; 243 #else 244 int lifnum; 245 #endif 246 247 ifaces->sock = socket(local_family, SOCK_DGRAM, IPPROTO_UDP); 248 if (ifaces->sock < 0) { 249 log_error("Error creating socket to list interfaces; %m"); 250 return 0; 251 } 252 253 memset(&lifnum, 0, sizeof(lifnum)); 254 #ifdef ISC_PLATFORM_HAVELIFNUM 255 lifnum.lifn_family = AF_UNSPEC; 256 #endif 257 #ifdef SIOCGLIFNUM 258 if (ioctl(ifaces->sock, SIOCGLIFNUM, &lifnum) < 0) { 259 log_error("Error finding total number of interfaces; %m"); 260 close(ifaces->sock); 261 ifaces->sock = -1; 262 return 0; 263 } 264 265 #ifdef ISC_PLATFORM_HAVELIFNUM 266 ifaces->num = lifnum.lifn_count; 267 #else 268 ifaces->num = lifnum; 269 #endif 270 #else 271 ifaces->num = 64; 272 #endif /* SIOCGLIFNUM */ 273 274 memset(&ifaces->conf, 0, sizeof(ifaces->conf)); 275 #ifdef ISC_HAVE_LIFC_FAMILY 276 ifaces->conf.lifc_family = AF_UNSPEC; 277 #endif 278 ifaces->conf.lifc_len = ifaces->num * sizeof(struct LIFREQ); 279 ifaces->conf.lifc_buf = dmalloc(ifaces->conf.lifc_len, MDL); 280 if (ifaces->conf.lifc_buf == NULL) { 281 log_fatal("Out of memory getting interface list."); 282 } 283 284 if (ioctl(ifaces->sock, SIOCGLIFCONF, &ifaces->conf) < 0) { 285 log_error("Error getting interfaces configuration list; %m"); 286 dfree(ifaces->conf.lifc_buf, MDL); 287 close(ifaces->sock); 288 ifaces->sock = -1; 289 return 0; 290 } 291 292 ifaces->next = 0; 293 294 return 1; 295 } 296 297 /* 298 * Retrieve the next interface. 299 * 300 * Returns information in the info structure. 301 * Sets err to 1 if there is an error, otherwise 0. 302 */ 303 static int 304 next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { 305 struct LIFREQ *p; 306 struct LIFREQ tmp; 307 isc_boolean_t foundif; 308 #if defined(sun) || defined(__linux) 309 /* Pointer used to remove interface aliases. */ 310 char *s; 311 #endif 312 313 do { 314 foundif = ISC_FALSE; 315 316 if (ifaces->next >= ifaces->num) { 317 *err = 0; 318 return 0; 319 } 320 321 p = ifaces->conf.lifc_req; 322 p += ifaces->next; 323 324 if (strlen(p->lifr_name) >= sizeof(info->name)) { 325 *err = 1; 326 log_error("Interface name '%s' too long", p->lifr_name); 327 return 0; 328 } 329 330 /* Reject if interface address family does not match */ 331 if (p->lifr_addr.ss_family != local_family) { 332 ifaces->next++; 333 continue; 334 } 335 336 strcpy(info->name, p->lifr_name); 337 memset(&info->addr, 0, sizeof(info->addr)); 338 memcpy(&info->addr, &p->lifr_addr, sizeof(p->lifr_addr)); 339 340 #if defined(sun) || defined(__linux) 341 /* interface aliases look like "eth0:1" or "wlan1:3" */ 342 s = strchr(info->name, ':'); 343 if (s != NULL) { 344 *s = '\0'; 345 } 346 #endif /* defined(sun) || defined(__linux) */ 347 348 foundif = ISC_TRUE; 349 } while ((foundif == ISC_FALSE) || 350 (strncmp(info->name, "dummy", 5) == 0)); 351 352 memset(&tmp, 0, sizeof(tmp)); 353 strcpy(tmp.lifr_name, info->name); 354 if (ioctl(ifaces->sock, SIOCGLIFFLAGS, &tmp) < 0) { 355 log_error("Error getting interface flags for '%s'; %m", 356 p->lifr_name); 357 *err = 1; 358 return 0; 359 } 360 info->flags = tmp.lifr_flags; 361 362 ifaces->next++; 363 *err = 0; 364 return 1; 365 } 366 367 /* 368 * End scan of interfaces. 369 */ 370 static void 371 end_iface_scan(struct iface_conf_list *ifaces) { 372 dfree(ifaces->conf.lifc_buf, MDL); 373 close(ifaces->sock); 374 ifaces->sock = -1; 375 } 376 377 #elif __linux /* !HAVE_SIOCGLIFCONF */ 378 /* 379 * Linux support 380 * ------------- 381 * 382 * In Linux, we use the /proc pseudo-filesystem to get information 383 * about interfaces, along with selected ioctl() calls. 384 * 385 * Linux low level access is documented in the netdevice man page. 386 */ 387 388 /* 389 * Structure holding state about the scan. 390 */ 391 struct iface_conf_list { 392 int sock; /* file descriptor used to get information */ 393 FILE *fp; /* input from /proc/net/dev */ 394 #ifdef DHCPv6 395 FILE *fp6; /* input from /proc/net/if_inet6 */ 396 #endif 397 }; 398 399 /* 400 * Structure used to return information about a specific interface. 401 */ 402 struct iface_info { 403 char name[IFNAMSIZ]; /* name of the interface, e.g. "eth0" */ 404 struct sockaddr_storage addr; /* address information */ 405 isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */ 406 }; 407 408 /* 409 * Start a scan of interfaces. 410 * 411 * The iface_conf_list structure maintains state for this process. 412 */ 413 static int 414 begin_iface_scan(struct iface_conf_list *ifaces) { 415 char buf[256]; 416 int len; 417 int i; 418 419 ifaces->fp = fopen("/proc/net/dev", "r"); 420 if (ifaces->fp == NULL) { 421 log_error("Error opening '/proc/net/dev' to list interfaces"); 422 return 0; 423 } 424 425 /* 426 * The first 2 lines are header information, so read and ignore them. 427 */ 428 for (i=0; i<2; i++) { 429 if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) { 430 log_error("Error reading headers from '/proc/net/dev'"); 431 fclose(ifaces->fp); 432 ifaces->fp = NULL; 433 return 0; 434 } 435 len = strlen(buf); 436 if ((len <= 0) || (buf[len-1] != '\n')) { 437 log_error("Bad header line in '/proc/net/dev'"); 438 fclose(ifaces->fp); 439 ifaces->fp = NULL; 440 return 0; 441 } 442 } 443 444 ifaces->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 445 if (ifaces->sock < 0) { 446 log_error("Error creating socket to list interfaces; %m"); 447 fclose(ifaces->fp); 448 ifaces->fp = NULL; 449 return 0; 450 } 451 452 #ifdef DHCPv6 453 if (local_family == AF_INET6) { 454 ifaces->fp6 = fopen("/proc/net/if_inet6", "r"); 455 if (ifaces->fp6 == NULL) { 456 log_error("Error opening '/proc/net/if_inet6' to " 457 "list IPv6 interfaces; %m"); 458 close(ifaces->sock); 459 ifaces->sock = -1; 460 fclose(ifaces->fp); 461 ifaces->fp = NULL; 462 return 0; 463 } 464 } 465 #endif 466 467 return 1; 468 } 469 470 /* 471 * Read our IPv4 interfaces from /proc/net/dev. 472 * 473 * The file looks something like this: 474 * 475 * Inter-| Receive ... 476 * face |bytes packets errs drop fifo frame ... 477 * lo: 1580562 4207 0 0 0 0 ... 478 * eth0: 0 0 0 0 0 0 ... 479 * eth1:1801552440 37895 0 14 0 ... 480 * 481 * We only care about the interface name, which is at the start of 482 * each line. 483 * 484 * We use an ioctl() to get the address and flags for each interface. 485 */ 486 static int 487 next_iface4(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { 488 char buf[256]; 489 int len; 490 char *p; 491 char *name; 492 struct ifreq tmp; 493 494 /* 495 * Loop exits when we find an interface that has an address, or 496 * when we run out of interfaces. 497 */ 498 for (;;) { 499 do { 500 /* 501 * Read the next line in the file. 502 */ 503 if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) { 504 if (ferror(ifaces->fp)) { 505 *err = 1; 506 log_error("Error reading interface " 507 "information"); 508 } else { 509 *err = 0; 510 } 511 return 0; 512 } 513 514 /* 515 * Make sure the line is a nice, 516 * newline-terminated line. 517 */ 518 len = strlen(buf); 519 if ((len <= 0) || (buf[len-1] != '\n')) { 520 log_error("Bad line reading interface " 521 "information"); 522 *err = 1; 523 return 0; 524 } 525 526 /* 527 * Figure out our name. 528 */ 529 p = strrchr(buf, ':'); 530 if (p == NULL) { 531 log_error("Bad line reading interface " 532 "information (no colon)"); 533 *err = 1; 534 return 0; 535 } 536 *p = '\0'; 537 name = buf; 538 while (isspace(*name)) { 539 name++; 540 } 541 542 /* 543 * Copy our name into our interface structure. 544 */ 545 len = p - name; 546 if (len >= sizeof(info->name)) { 547 *err = 1; 548 log_error("Interface name '%s' too long", name); 549 return 0; 550 } 551 strcpy(info->name, name); 552 553 #ifdef ALIAS_NAMED_PERMUTED 554 /* interface aliases look like "eth0:1" or "wlan1:3" */ 555 s = strchr(info->name, ':'); 556 if (s != NULL) { 557 *s = '\0'; 558 } 559 #endif 560 561 #ifdef SKIP_DUMMY_INTERFACES 562 } while (strncmp(info->name, "dummy", 5) == 0); 563 #else 564 } while (0); 565 #endif 566 567 memset(&tmp, 0, sizeof(tmp)); 568 strcpy(tmp.ifr_name, name); 569 if (ioctl(ifaces->sock, SIOCGIFADDR, &tmp) < 0) { 570 if (errno == EADDRNOTAVAIL) { 571 continue; 572 } 573 log_error("Error getting interface address " 574 "for '%s'; %m", name); 575 *err = 1; 576 return 0; 577 } 578 memcpy(&info->addr, &tmp.ifr_addr, sizeof(tmp.ifr_addr)); 579 580 memset(&tmp, 0, sizeof(tmp)); 581 strcpy(tmp.ifr_name, name); 582 if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) { 583 log_error("Error getting interface flags for '%s'; %m", 584 name); 585 *err = 1; 586 return 0; 587 } 588 info->flags = tmp.ifr_flags; 589 590 *err = 0; 591 return 1; 592 } 593 } 594 595 #ifdef DHCPv6 596 /* 597 * Read our IPv6 interfaces from /proc/net/if_inet6. 598 * 599 * The file looks something like this: 600 * 601 * fe80000000000000025056fffec00008 05 40 20 80 vmnet8 602 * 00000000000000000000000000000001 01 80 10 80 lo 603 * fe80000000000000025056fffec00001 06 40 20 80 vmnet1 604 * 200108881936000202166ffffe497d9b 03 40 00 00 eth1 605 * fe8000000000000002166ffffe497d9b 03 40 20 80 eth1 606 * 607 * We get IPv6 address from the start, the interface name from the end, 608 * and ioctl() to get flags. 609 */ 610 static int 611 next_iface6(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { 612 char buf[256]; 613 int len; 614 char *p; 615 char *name; 616 int i; 617 struct sockaddr_in6 addr; 618 struct ifreq tmp; 619 620 do { 621 /* 622 * Read the next line in the file. 623 */ 624 if (fgets(buf, sizeof(buf), ifaces->fp6) == NULL) { 625 if (ferror(ifaces->fp6)) { 626 *err = 1; 627 log_error("Error reading IPv6 " 628 "interface information"); 629 } else { 630 *err = 0; 631 } 632 return 0; 633 } 634 635 /* 636 * Make sure the line is a nice, newline-terminated line. 637 */ 638 len = strlen(buf); 639 if ((len <= 0) || (buf[len-1] != '\n')) { 640 log_error("Bad line reading IPv6 " 641 "interface information"); 642 *err = 1; 643 return 0; 644 } 645 646 /* 647 * Figure out our name. 648 */ 649 buf[--len] = '\0'; 650 p = strrchr(buf, ' '); 651 if (p == NULL) { 652 log_error("Bad line reading IPv6 interface " 653 "information (no space)"); 654 *err = 1; 655 return 0; 656 } 657 name = p+1; 658 659 /* 660 * Copy our name into our interface structure. 661 */ 662 len = strlen(name); 663 if (len >= sizeof(info->name)) { 664 *err = 1; 665 log_error("IPv6 interface name '%s' too long", name); 666 return 0; 667 } 668 strcpy(info->name, name); 669 670 #ifdef SKIP_DUMMY_INTERFACES 671 } while (strncmp(info->name, "dummy", 5) == 0); 672 #else 673 } while (0); 674 #endif 675 676 /* 677 * Double-check we start with the IPv6 address. 678 */ 679 for (i=0; i<32; i++) { 680 if (!isxdigit(buf[i]) || isupper(buf[i])) { 681 *err = 1; 682 log_error("Bad line reading IPv6 interface address " 683 "for '%s'", name); 684 return 0; 685 } 686 } 687 688 /* 689 * Load our socket structure. 690 */ 691 memset(&addr, 0, sizeof(addr)); 692 addr.sin6_family = AF_INET6; 693 for (i=0; i<16; i++) { 694 unsigned char byte; 695 static const char hex[] = "0123456789abcdef"; 696 byte = ((index(hex, buf[i * 2]) - hex) << 4) | 697 (index(hex, buf[i * 2 + 1]) - hex); 698 addr.sin6_addr.s6_addr[i] = byte; 699 } 700 memcpy(&info->addr, &addr, sizeof(addr)); 701 702 /* 703 * Get our flags. 704 */ 705 memset(&tmp, 0, sizeof(tmp)); 706 strcpy(tmp.ifr_name, name); 707 if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) { 708 log_error("Error getting interface flags for '%s'; %m", name); 709 *err = 1; 710 return 0; 711 } 712 info->flags = tmp.ifr_flags; 713 714 *err = 0; 715 return 1; 716 } 717 #endif /* DHCPv6 */ 718 719 /* 720 * Retrieve the next interface. 721 * 722 * Returns information in the info structure. 723 * Sets err to 1 if there is an error, otherwise 0. 724 */ 725 static int 726 next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { 727 if (next_iface4(info, err, ifaces)) { 728 return 1; 729 } 730 #ifdef DHCPv6 731 if (!(*err)) { 732 if (local_family == AF_INET6) 733 return next_iface6(info, err, ifaces); 734 } 735 #endif 736 return 0; 737 } 738 739 /* 740 * End scan of interfaces. 741 */ 742 static void 743 end_iface_scan(struct iface_conf_list *ifaces) { 744 fclose(ifaces->fp); 745 ifaces->fp = NULL; 746 close(ifaces->sock); 747 ifaces->sock = -1; 748 #ifdef DHCPv6 749 if (local_family == AF_INET6) { 750 fclose(ifaces->fp6); 751 ifaces->fp6 = NULL; 752 } 753 #endif 754 } 755 #else 756 757 /* 758 * BSD support 759 * ----------- 760 * 761 * FreeBSD, NetBSD, OpenBSD, and OS X all have the getifaddrs() 762 * function. 763 * 764 * The getifaddrs() man page describes the use. 765 */ 766 767 #include <ifaddrs.h> 768 769 /* 770 * Structure holding state about the scan. 771 */ 772 struct iface_conf_list { 773 struct ifaddrs *head; /* beginning of the list */ 774 struct ifaddrs *next; /* current position in the list */ 775 }; 776 777 /* 778 * Structure used to return information about a specific interface. 779 */ 780 struct iface_info { 781 char name[IFNAMSIZ]; /* name of the interface, e.g. "bge0" */ 782 struct sockaddr_storage addr; /* address information */ 783 isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */ 784 }; 785 786 /* 787 * Start a scan of interfaces. 788 * 789 * The iface_conf_list structure maintains state for this process. 790 */ 791 static int 792 begin_iface_scan(struct iface_conf_list *ifaces) { 793 if (getifaddrs(&ifaces->head) != 0) { 794 log_error("Error getting interfaces; %m"); 795 return 0; 796 } 797 ifaces->next = ifaces->head; 798 return 1; 799 } 800 801 /* 802 * Retrieve the next interface. 803 * 804 * Returns information in the info structure. 805 * Sets err to 1 if there is an error, otherwise 0. 806 */ 807 static int 808 next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { 809 if (ifaces->next == NULL) { 810 *err = 0; 811 return 0; 812 } 813 if (strlen(ifaces->next->ifa_name) >= sizeof(info->name)) { 814 log_error("Interface name '%s' too long", 815 ifaces->next->ifa_name); 816 *err = 1; 817 return 0; 818 } 819 strcpy(info->name, ifaces->next->ifa_name); 820 memcpy(&info->addr, ifaces->next->ifa_addr, 821 ifaces->next->ifa_addr->sa_len); 822 info->flags = ifaces->next->ifa_flags; 823 ifaces->next = ifaces->next->ifa_next; 824 *err = 0; 825 return 1; 826 } 827 828 /* 829 * End scan of interfaces. 830 */ 831 static void 832 end_iface_scan(struct iface_conf_list *ifaces) { 833 freeifaddrs(ifaces->head); 834 ifaces->head = NULL; 835 ifaces->next = NULL; 836 } 837 #endif 838 839 /* XXX: perhaps create drealloc() rather than do it manually */ 840 static void 841 add_ipv4_addr_to_interface(struct interface_info *iface, 842 const struct in_addr *addr) { 843 /* 844 * We don't expect a lot of addresses per IPv4 interface, so 845 * we use 4, as our "chunk size" for collecting addresses. 846 */ 847 if (iface->addresses == NULL) { 848 iface->addresses = dmalloc(4 * sizeof(struct in_addr), MDL); 849 if (iface->addresses == NULL) { 850 log_fatal("Out of memory saving IPv4 address " 851 "on interface."); 852 } 853 iface->address_count = 0; 854 iface->address_max = 4; 855 } else if (iface->address_count >= iface->address_max) { 856 struct in_addr *tmp; 857 int new_max; 858 859 new_max = iface->address_max + 4; 860 tmp = dmalloc(new_max * sizeof(struct in_addr), MDL); 861 if (tmp == NULL) { 862 log_fatal("Out of memory saving IPv4 address " 863 "on interface."); 864 } 865 memcpy(tmp, 866 iface->addresses, 867 iface->address_max * sizeof(struct in_addr)); 868 dfree(iface->addresses, MDL); 869 iface->addresses = tmp; 870 iface->address_max = new_max; 871 } 872 iface->addresses[iface->address_count++] = *addr; 873 } 874 875 #ifdef DHCPv6 876 /* XXX: perhaps create drealloc() rather than do it manually */ 877 static void 878 add_ipv6_addr_to_interface(struct interface_info *iface, 879 const struct in6_addr *addr) { 880 /* 881 * Each IPv6 interface will have at least two IPv6 addresses, 882 * and likely quite a few more. So we use 8, as our "chunk size" for 883 * collecting addresses. 884 */ 885 if (iface->v6addresses == NULL) { 886 iface->v6addresses = dmalloc(8 * sizeof(struct in6_addr), MDL); 887 if (iface->v6addresses == NULL) { 888 log_fatal("Out of memory saving IPv6 address " 889 "on interface."); 890 } 891 iface->v6address_count = 0; 892 iface->v6address_max = 8; 893 } else if (iface->v6address_count >= iface->v6address_max) { 894 struct in6_addr *tmp; 895 int new_max; 896 897 new_max = iface->v6address_max + 8; 898 tmp = dmalloc(new_max * sizeof(struct in6_addr), MDL); 899 if (tmp == NULL) { 900 log_fatal("Out of memory saving IPv6 address " 901 "on interface."); 902 } 903 memcpy(tmp, 904 iface->v6addresses, 905 iface->v6address_max * sizeof(struct in6_addr)); 906 dfree(iface->v6addresses, MDL); 907 iface->v6addresses = tmp; 908 iface->v6address_max = new_max; 909 } 910 iface->v6addresses[iface->v6address_count++] = *addr; 911 } 912 #endif /* DHCPv6 */ 913 914 /* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces. 915 For each interface that's of type INET and not the loopback interface, 916 register that interface with the network I/O software, figure out what 917 subnet it's on, and add it to the list of interfaces. */ 918 919 void 920 discover_interfaces(int state) { 921 struct iface_conf_list ifaces; 922 struct iface_info info; 923 int err; 924 925 struct interface_info *tmp; 926 struct interface_info *last, *next; 927 928 #ifdef DHCPv6 929 char abuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; 930 #endif /* DHCPv6 */ 931 932 933 struct subnet *subnet; 934 int ir; 935 isc_result_t status; 936 int wifcount = 0; 937 938 static int setup_fallback = 0; 939 940 if (!begin_iface_scan(&ifaces)) { 941 log_fatal("Can't get list of interfaces."); 942 } 943 944 /* If we already have a list of interfaces, and we're running as 945 a DHCP server, the interfaces were requested. */ 946 if (interfaces && (state == DISCOVER_SERVER || 947 state == DISCOVER_RELAY || 948 state == DISCOVER_REQUESTED)) 949 ir = 0; 950 else if (state == DISCOVER_UNCONFIGURED) 951 ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC; 952 else 953 ir = INTERFACE_REQUESTED; 954 955 /* Cycle through the list of interfaces looking for IP addresses. */ 956 while (next_iface(&info, &err, &ifaces)) { 957 958 /* See if we've seen an interface that matches this one. */ 959 for (tmp = interfaces; tmp; tmp = tmp->next) { 960 if (!strcmp(tmp->name, info.name)) 961 break; 962 } 963 964 /* Skip non broadcast interfaces (plus loopback and 965 point-to-point in case an OS incorrectly marks them 966 as broadcast). Also skip down interfaces unless we're 967 trying to get a list of configurable interfaces. */ 968 if ((((local_family == AF_INET && 969 !(info.flags & IFF_BROADCAST)) || 970 #ifdef DHCPv6 971 (local_family == AF_INET6 && 972 !(info.flags & IFF_MULTICAST)) || 973 #endif 974 info.flags & IFF_LOOPBACK || 975 info.flags & IFF_POINTOPOINT) && !tmp) || 976 (!(info.flags & IFF_UP) && 977 state != DISCOVER_UNCONFIGURED)) 978 continue; 979 980 /* If there isn't already an interface by this name, 981 allocate one. */ 982 if (tmp == NULL) { 983 status = interface_allocate(&tmp, MDL); 984 if (status != ISC_R_SUCCESS) { 985 log_fatal("Error allocating interface %s: %s", 986 info.name, isc_result_totext(status)); 987 } 988 strcpy(tmp->name, info.name); 989 interface_snorf(tmp, ir); 990 interface_dereference(&tmp, MDL); 991 tmp = interfaces; /* XXX */ 992 } 993 994 if (dhcp_interface_discovery_hook) { 995 (*dhcp_interface_discovery_hook)(tmp); 996 } 997 998 if ((info.addr.ss_family == AF_INET) && 999 (local_family == AF_INET)) { 1000 struct sockaddr_in *a = (struct sockaddr_in*)&info.addr; 1001 struct iaddr addr; 1002 1003 /* We don't want the loopback interface. */ 1004 if (a->sin_addr.s_addr == htonl(INADDR_LOOPBACK) && 1005 ((tmp->flags & INTERFACE_AUTOMATIC) && 1006 state == DISCOVER_SERVER)) 1007 continue; 1008 1009 /* If the only address we have is 0.0.0.0, we 1010 shouldn't consider the interface configured. */ 1011 if (a->sin_addr.s_addr != htonl(INADDR_ANY)) 1012 tmp->configured = 1; 1013 1014 add_ipv4_addr_to_interface(tmp, &a->sin_addr); 1015 1016 /* invoke the setup hook */ 1017 addr.len = 4; 1018 memcpy(addr.iabuf, &a->sin_addr.s_addr, addr.len); 1019 if (dhcp_interface_setup_hook) { 1020 (*dhcp_interface_setup_hook)(tmp, &addr); 1021 } 1022 } 1023 #ifdef DHCPv6 1024 else if ((info.addr.ss_family == AF_INET6) && 1025 (local_family == AF_INET6)) { 1026 struct sockaddr_in6 *a = 1027 (struct sockaddr_in6*)&info.addr; 1028 struct iaddr addr; 1029 1030 /* We don't want the loopback interface. */ 1031 if (IN6_IS_ADDR_LOOPBACK(&a->sin6_addr) && 1032 ((tmp->flags & INTERFACE_AUTOMATIC) && 1033 state == DISCOVER_SERVER)) 1034 continue; 1035 1036 /* If the only address we have is 0.0.0.0, we 1037 shouldn't consider the interface configured. */ 1038 if (IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr)) 1039 tmp->configured = 1; 1040 1041 add_ipv6_addr_to_interface(tmp, &a->sin6_addr); 1042 1043 /* invoke the setup hook */ 1044 addr.len = 16; 1045 memcpy(addr.iabuf, &a->sin6_addr, addr.len); 1046 if (dhcp_interface_setup_hook) { 1047 (*dhcp_interface_setup_hook)(tmp, &addr); 1048 } 1049 } 1050 #endif /* DHCPv6 */ 1051 } 1052 1053 if (err) { 1054 log_fatal("Error getting interface information."); 1055 } 1056 1057 end_iface_scan(&ifaces); 1058 1059 1060 /* Mock-up an 'ifp' structure which is no longer used in the 1061 * new interface-sensing code, but is used in higher layers 1062 * (for example to sense fallback interfaces). 1063 */ 1064 for (tmp = interfaces ; tmp != NULL ; tmp = tmp->next) { 1065 if (tmp->ifp == NULL) { 1066 struct ifreq *tif; 1067 1068 tif = (struct ifreq *)dmalloc(sizeof(struct ifreq), 1069 MDL); 1070 if (tif == NULL) 1071 log_fatal("no space for ifp mockup."); 1072 strcpy(tif->ifr_name, tmp->name); 1073 tmp->ifp = tif; 1074 } 1075 } 1076 1077 1078 /* If we're just trying to get a list of interfaces that we might 1079 be able to configure, we can quit now. */ 1080 if (state == DISCOVER_UNCONFIGURED) { 1081 return; 1082 } 1083 1084 /* Weed out the interfaces that did not have IP addresses. */ 1085 tmp = last = next = NULL; 1086 if (interfaces) 1087 interface_reference (&tmp, interfaces, MDL); 1088 while (tmp) { 1089 if (next) 1090 interface_dereference (&next, MDL); 1091 if (tmp -> next) 1092 interface_reference (&next, tmp -> next, MDL); 1093 /* skip interfaces that are running already */ 1094 if (tmp -> flags & INTERFACE_RUNNING) { 1095 interface_dereference(&tmp, MDL); 1096 if(next) 1097 interface_reference(&tmp, next, MDL); 1098 continue; 1099 } 1100 if ((tmp -> flags & INTERFACE_AUTOMATIC) && 1101 state == DISCOVER_REQUESTED) 1102 tmp -> flags &= ~(INTERFACE_AUTOMATIC | 1103 INTERFACE_REQUESTED); 1104 1105 #ifdef DHCPv6 1106 if (!(tmp->flags & INTERFACE_REQUESTED)) { 1107 #else 1108 if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) { 1109 #endif /* DHCPv6 */ 1110 if ((tmp -> flags & INTERFACE_REQUESTED) != ir) 1111 log_fatal ("%s: not found", tmp -> name); 1112 if (!last) { 1113 if (interfaces) 1114 interface_dereference (&interfaces, 1115 MDL); 1116 if (next) 1117 interface_reference (&interfaces, next, MDL); 1118 } else { 1119 interface_dereference (&last -> next, MDL); 1120 if (next) 1121 interface_reference (&last -> next, 1122 next, MDL); 1123 } 1124 if (tmp -> next) 1125 interface_dereference (&tmp -> next, MDL); 1126 1127 /* Remember the interface in case we need to know 1128 about it later. */ 1129 if (dummy_interfaces) { 1130 interface_reference (&tmp -> next, 1131 dummy_interfaces, MDL); 1132 interface_dereference (&dummy_interfaces, MDL); 1133 } 1134 interface_reference (&dummy_interfaces, tmp, MDL); 1135 interface_dereference (&tmp, MDL); 1136 if (next) 1137 interface_reference (&tmp, next, MDL); 1138 continue; 1139 } 1140 last = tmp; 1141 1142 /* We must have a subnet declaration for each interface. */ 1143 if (!tmp->shared_network && (state == DISCOVER_SERVER)) { 1144 log_error("%s", ""); 1145 if (local_family == AF_INET) { 1146 log_error("No subnet declaration for %s (%s).", 1147 tmp->name, 1148 (tmp->addresses == NULL) ? 1149 "no IPv4 addresses" : 1150 inet_ntoa(tmp->addresses[0])); 1151 #ifdef DHCPv6 1152 } else { 1153 if (tmp->v6addresses != NULL) { 1154 inet_ntop(AF_INET6, 1155 &tmp->v6addresses[0], 1156 abuf, 1157 sizeof(abuf)); 1158 } else { 1159 strcpy(abuf, "no IPv6 addresses"); 1160 } 1161 log_error("No subnet6 declaration for %s (%s).", 1162 tmp->name, 1163 abuf); 1164 #endif /* DHCPv6 */ 1165 } 1166 if (supports_multiple_interfaces(tmp)) { 1167 log_error ("** Ignoring requests on %s. %s", 1168 tmp -> name, "If this is not what"); 1169 log_error (" you want, please write %s", 1170 #ifdef DHCPv6 1171 (local_family != AF_INET) ? 1172 "a subnet6 declaration" : 1173 #endif 1174 "a subnet declaration"); 1175 log_error (" in your dhcpd.conf file %s", 1176 "for the network segment"); 1177 log_error (" to %s %s %s", 1178 "which interface", 1179 tmp -> name, "is attached. **"); 1180 log_error ("%s", ""); 1181 goto next; 1182 } else { 1183 log_error ("You must write a %s", 1184 #ifdef DHCPv6 1185 (local_family != AF_INET) ? 1186 "subnet6 declaration for this" : 1187 #endif 1188 "subnet declaration for this"); 1189 log_error ("subnet. You cannot prevent %s", 1190 "the DHCP server"); 1191 log_error ("from listening on this subnet %s", 1192 "because your"); 1193 log_fatal ("operating system does not %s.", 1194 "support this capability"); 1195 } 1196 } 1197 1198 /* Find subnets that don't have valid interface 1199 addresses... */ 1200 for (subnet = (tmp -> shared_network 1201 ? tmp -> shared_network -> subnets 1202 : (struct subnet *)0); 1203 subnet; subnet = subnet -> next_sibling) { 1204 /* Set the interface address for this subnet 1205 to the first address we found. */ 1206 if (subnet->interface_address.len == 0) { 1207 if (tmp->address_count > 0) { 1208 subnet->interface_address.len = 4; 1209 memcpy(subnet->interface_address.iabuf, 1210 &tmp->addresses[0].s_addr, 4); 1211 } else if (tmp->v6address_count > 0) { 1212 subnet->interface_address.len = 16; 1213 memcpy(subnet->interface_address.iabuf, 1214 &tmp->v6addresses[0].s6_addr, 1215 16); 1216 } else { 1217 /* XXX: should be one */ 1218 log_error("%s missing an interface " 1219 "address", tmp->name); 1220 continue; 1221 } 1222 } 1223 } 1224 1225 /* Flag the index as not having been set, so that the 1226 interface registerer can set it or not as it chooses. */ 1227 tmp -> index = -1; 1228 1229 /* Register the interface... */ 1230 if (local_family == AF_INET) { 1231 if_register_receive(tmp); 1232 if_register_send(tmp); 1233 #ifdef DHCPv6 1234 } else { 1235 if ((state == DISCOVER_SERVER) || 1236 (state == DISCOVER_RELAY)) { 1237 if_register6(tmp, 1); 1238 } else { 1239 if_register_linklocal6(tmp); 1240 } 1241 #endif /* DHCPv6 */ 1242 } 1243 1244 interface_stash (tmp); 1245 wifcount++; 1246 #if defined (F_SETFD) 1247 if (fcntl (tmp -> rfdesc, F_SETFD, 1) < 0) 1248 log_error ("Can't set close-on-exec on %s: %m", 1249 tmp -> name); 1250 if (tmp -> rfdesc != tmp -> wfdesc) { 1251 if (fcntl (tmp -> wfdesc, F_SETFD, 1) < 0) 1252 log_error ("Can't set close-on-exec on %s: %m", 1253 tmp -> name); 1254 } 1255 #endif 1256 next: 1257 interface_dereference (&tmp, MDL); 1258 if (next) 1259 interface_reference (&tmp, next, MDL); 1260 } 1261 1262 /* 1263 * Now register all the remaining interfaces as protocols. 1264 * We register with omapi to allow for control of the interface, 1265 * we've already registered the fd or socket with the socket 1266 * manager as part of if_register_receive(). 1267 */ 1268 for (tmp = interfaces; tmp; tmp = tmp -> next) { 1269 /* not if it's been registered before */ 1270 if (tmp -> flags & INTERFACE_RUNNING) 1271 continue; 1272 if (tmp -> rfdesc == -1) 1273 continue; 1274 switch (local_family) { 1275 #ifdef DHCPv6 1276 case AF_INET6: 1277 status = omapi_register_io_object((omapi_object_t *)tmp, 1278 if_readsocket, 1279 0, got_one_v6, 0, 0); 1280 break; 1281 #endif /* DHCPv6 */ 1282 case AF_INET: 1283 default: 1284 status = omapi_register_io_object((omapi_object_t *)tmp, 1285 if_readsocket, 1286 0, got_one, 0, 0); 1287 break; 1288 } 1289 1290 if (status != ISC_R_SUCCESS) 1291 log_fatal ("Can't register I/O handle for %s: %s", 1292 tmp -> name, isc_result_totext (status)); 1293 1294 #if defined(DHCPv6) 1295 /* Only register the first interface for V6, since 1296 * servers and relays all use the same socket. 1297 * XXX: This has some messy side effects if we start 1298 * dynamically adding and removing interfaces, but 1299 * we're well beyond that point in terms of mess. 1300 */ 1301 if (((state == DISCOVER_SERVER) || (state == DISCOVER_RELAY)) && 1302 (local_family == AF_INET6)) 1303 break; 1304 #endif 1305 } /* for (tmp = interfaces; ... */ 1306 1307 if (state == DISCOVER_SERVER && wifcount == 0) { 1308 log_info ("%s", ""); 1309 log_fatal ("Not configured to listen on any interfaces!"); 1310 } 1311 1312 if ((local_family == AF_INET) && !setup_fallback) { 1313 setup_fallback = 1; 1314 maybe_setup_fallback(); 1315 } 1316 1317 #if defined (F_SETFD) 1318 if (fallback_interface) { 1319 if (fcntl (fallback_interface -> rfdesc, F_SETFD, 1) < 0) 1320 log_error ("Can't set close-on-exec on fallback: %m"); 1321 if (fallback_interface -> rfdesc != fallback_interface -> wfdesc) { 1322 if (fcntl (fallback_interface -> wfdesc, F_SETFD, 1) < 0) 1323 log_error ("Can't set close-on-exec on fallback: %m"); 1324 } 1325 } 1326 #endif /* F_SETFD */ 1327 } 1328 1329 int if_readsocket (h) 1330 omapi_object_t *h; 1331 { 1332 struct interface_info *ip; 1333 1334 if (h -> type != dhcp_type_interface) 1335 return -1; 1336 ip = (struct interface_info *)h; 1337 return ip -> rfdesc; 1338 } 1339 1340 int setup_fallback (struct interface_info **fp, const char *file, int line) 1341 { 1342 isc_result_t status; 1343 1344 status = interface_allocate (&fallback_interface, file, line); 1345 if (status != ISC_R_SUCCESS) 1346 log_fatal ("Error allocating fallback interface: %s", 1347 isc_result_totext (status)); 1348 strcpy (fallback_interface -> name, "fallback"); 1349 if (dhcp_interface_setup_hook) 1350 (*dhcp_interface_setup_hook) (fallback_interface, 1351 (struct iaddr *)0); 1352 status = interface_reference (fp, fallback_interface, file, line); 1353 1354 fallback_interface -> index = -1; 1355 interface_stash (fallback_interface); 1356 return status == ISC_R_SUCCESS; 1357 } 1358 1359 void reinitialize_interfaces () 1360 { 1361 struct interface_info *ip; 1362 1363 for (ip = interfaces; ip; ip = ip -> next) { 1364 if_reinitialize_receive (ip); 1365 if_reinitialize_send (ip); 1366 } 1367 1368 if (fallback_interface) 1369 if_reinitialize_send (fallback_interface); 1370 1371 interfaces_invalidated = 1; 1372 } 1373 1374 isc_result_t got_one (h) 1375 omapi_object_t *h; 1376 { 1377 struct sockaddr_in from; 1378 struct hardware hfrom; 1379 struct iaddr ifrom; 1380 int result; 1381 union { 1382 unsigned char packbuf [4095]; /* Packet input buffer. 1383 Must be as large as largest 1384 possible MTU. */ 1385 struct dhcp_packet packet; 1386 } u; 1387 struct interface_info *ip; 1388 1389 if (h -> type != dhcp_type_interface) 1390 return DHCP_R_INVALIDARG; 1391 ip = (struct interface_info *)h; 1392 1393 again: 1394 if ((result = 1395 receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) { 1396 log_error ("receive_packet failed on %s: %m", ip -> name); 1397 return ISC_R_UNEXPECTED; 1398 } 1399 if (result == 0) 1400 return ISC_R_UNEXPECTED; 1401 1402 /* 1403 * If we didn't at least get the fixed portion of the BOOTP 1404 * packet, drop the packet. 1405 * Previously we allowed packets with no sname or filename 1406 * as we were aware of at least one client that did. But 1407 * a bug caused short packets to not work and nobody has 1408 * complained, it seems rational to tighten up that 1409 * restriction. 1410 */ 1411 if (result < DHCP_FIXED_NON_UDP) 1412 return ISC_R_UNEXPECTED; 1413 1414 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO) 1415 { 1416 /* We retrieve the ifindex from the unused hfrom variable */ 1417 unsigned int ifindex; 1418 1419 memcpy(&ifindex, hfrom.hbuf, sizeof (ifindex)); 1420 1421 /* 1422 * Seek forward from the first interface to find the matching 1423 * source interface by interface index. 1424 */ 1425 ip = interfaces; 1426 while ((ip != NULL) && (if_nametoindex(ip->name) != ifindex)) 1427 ip = ip->next; 1428 if (ip == NULL) 1429 return ISC_R_NOTFOUND; 1430 } 1431 #endif 1432 1433 if (bootp_packet_handler) { 1434 ifrom.len = 4; 1435 memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len); 1436 1437 (*bootp_packet_handler) (ip, &u.packet, (unsigned)result, 1438 from.sin_port, ifrom, &hfrom); 1439 } 1440 1441 /* If there is buffered data, read again. This is for, e.g., 1442 bpf, which may return two packets at once. */ 1443 if (ip -> rbuf_offset != ip -> rbuf_len) 1444 goto again; 1445 return ISC_R_SUCCESS; 1446 } 1447 1448 #ifdef DHCPv6 1449 isc_result_t 1450 got_one_v6(omapi_object_t *h) { 1451 struct sockaddr_in6 from; 1452 struct in6_addr to; 1453 struct iaddr ifrom; 1454 int result; 1455 char buf[65536]; /* maximum size for a UDP packet is 65536 */ 1456 struct interface_info *ip; 1457 int is_unicast; 1458 unsigned int if_idx = 0; 1459 1460 if (h->type != dhcp_type_interface) { 1461 return DHCP_R_INVALIDARG; 1462 } 1463 ip = (struct interface_info *)h; 1464 1465 result = receive_packet6(ip, (unsigned char *)buf, sizeof(buf), 1466 &from, &to, &if_idx); 1467 if (result < 0) { 1468 log_error("receive_packet6() failed on %s: %m", ip->name); 1469 return ISC_R_UNEXPECTED; 1470 } 1471 1472 /* 0 is 'any' interface. */ 1473 if (if_idx == 0) 1474 return ISC_R_NOTFOUND; 1475 1476 if (dhcpv6_packet_handler != NULL) { 1477 /* 1478 * If a packet is not multicast, we assume it is unicast. 1479 */ 1480 if (IN6_IS_ADDR_MULTICAST(&to)) { 1481 is_unicast = ISC_FALSE; 1482 } else { 1483 is_unicast = ISC_TRUE; 1484 } 1485 1486 ifrom.len = 16; 1487 memcpy(ifrom.iabuf, &from.sin6_addr, ifrom.len); 1488 1489 /* Seek forward to find the matching source interface. */ 1490 ip = interfaces; 1491 while ((ip != NULL) && (if_nametoindex(ip->name) != if_idx)) 1492 ip = ip->next; 1493 1494 if (ip == NULL) 1495 return ISC_R_NOTFOUND; 1496 1497 (*dhcpv6_packet_handler)(ip, buf, 1498 result, from.sin6_port, 1499 &ifrom, is_unicast); 1500 } 1501 1502 return ISC_R_SUCCESS; 1503 } 1504 #endif /* DHCPv6 */ 1505 1506 isc_result_t dhcp_interface_set_value (omapi_object_t *h, 1507 omapi_object_t *id, 1508 omapi_data_string_t *name, 1509 omapi_typed_data_t *value) 1510 { 1511 struct interface_info *interface; 1512 isc_result_t status; 1513 1514 if (h -> type != dhcp_type_interface) 1515 return DHCP_R_INVALIDARG; 1516 interface = (struct interface_info *)h; 1517 1518 if (!omapi_ds_strcmp (name, "name")) { 1519 if ((value -> type == omapi_datatype_data || 1520 value -> type == omapi_datatype_string) && 1521 value -> u.buffer.len < sizeof interface -> name) { 1522 memcpy (interface -> name, 1523 value -> u.buffer.value, 1524 value -> u.buffer.len); 1525 interface -> name [value -> u.buffer.len] = 0; 1526 } else 1527 return DHCP_R_INVALIDARG; 1528 return ISC_R_SUCCESS; 1529 } 1530 1531 /* Try to find some inner object that can take the value. */ 1532 if (h -> inner && h -> inner -> type -> set_value) { 1533 status = ((*(h -> inner -> type -> set_value)) 1534 (h -> inner, id, name, value)); 1535 if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED) 1536 return status; 1537 } 1538 1539 return ISC_R_NOTFOUND; 1540 } 1541 1542 1543 isc_result_t dhcp_interface_get_value (omapi_object_t *h, 1544 omapi_object_t *id, 1545 omapi_data_string_t *name, 1546 omapi_value_t **value) 1547 { 1548 return ISC_R_NOTIMPLEMENTED; 1549 } 1550 1551 isc_result_t dhcp_interface_destroy (omapi_object_t *h, 1552 const char *file, int line) 1553 { 1554 struct interface_info *interface; 1555 1556 if (h -> type != dhcp_type_interface) 1557 return DHCP_R_INVALIDARG; 1558 interface = (struct interface_info *)h; 1559 1560 if (interface -> ifp) { 1561 dfree (interface -> ifp, file, line); 1562 interface -> ifp = 0; 1563 } 1564 if (interface -> next) 1565 interface_dereference (&interface -> next, file, line); 1566 if (interface -> rbuf) { 1567 dfree (interface -> rbuf, file, line); 1568 interface -> rbuf = (unsigned char *)0; 1569 } 1570 if (interface -> client) 1571 interface -> client = (struct client_state *)0; 1572 1573 if (interface -> shared_network) 1574 omapi_object_dereference ((void *) 1575 &interface -> shared_network, MDL); 1576 1577 return ISC_R_SUCCESS; 1578 } 1579 1580 isc_result_t dhcp_interface_signal_handler (omapi_object_t *h, 1581 const char *name, va_list ap) 1582 { 1583 struct interface_info *ip, *interface; 1584 isc_result_t status; 1585 1586 if (h -> type != dhcp_type_interface) 1587 return DHCP_R_INVALIDARG; 1588 interface = (struct interface_info *)h; 1589 1590 /* If it's an update signal, see if the interface is dead right 1591 now, or isn't known at all, and if that's the case, revive it. */ 1592 if (!strcmp (name, "update")) { 1593 for (ip = dummy_interfaces; ip; ip = ip -> next) 1594 if (ip == interface) 1595 break; 1596 if (ip && dhcp_interface_startup_hook) 1597 return (*dhcp_interface_startup_hook) (ip); 1598 1599 for (ip = interfaces; ip; ip = ip -> next) 1600 if (ip == interface) 1601 break; 1602 if (!ip && dhcp_interface_startup_hook) 1603 return (*dhcp_interface_startup_hook) (ip); 1604 } 1605 1606 /* Try to find some inner object that can take the value. */ 1607 if (h -> inner && h -> inner -> type -> signal_handler) { 1608 status = ((*(h -> inner -> type -> signal_handler)) 1609 (h -> inner, name, ap)); 1610 if (status == ISC_R_SUCCESS) 1611 return status; 1612 } 1613 return ISC_R_NOTFOUND; 1614 } 1615 1616 isc_result_t dhcp_interface_stuff_values (omapi_object_t *c, 1617 omapi_object_t *id, 1618 omapi_object_t *h) 1619 { 1620 struct interface_info *interface; 1621 isc_result_t status; 1622 1623 if (h -> type != dhcp_type_interface) 1624 return DHCP_R_INVALIDARG; 1625 interface = (struct interface_info *)h; 1626 1627 /* Write out all the values. */ 1628 1629 status = omapi_connection_put_name (c, "state"); 1630 if (status != ISC_R_SUCCESS) 1631 return status; 1632 if ((interface->flags & INTERFACE_REQUESTED) != 0) 1633 status = omapi_connection_put_string (c, "up"); 1634 else 1635 status = omapi_connection_put_string (c, "down"); 1636 if (status != ISC_R_SUCCESS) 1637 return status; 1638 1639 /* Write out the inner object, if any. */ 1640 if (h -> inner && h -> inner -> type -> stuff_values) { 1641 status = ((*(h -> inner -> type -> stuff_values)) 1642 (c, id, h -> inner)); 1643 if (status == ISC_R_SUCCESS) 1644 return status; 1645 } 1646 1647 return ISC_R_SUCCESS; 1648 } 1649 1650 isc_result_t dhcp_interface_lookup (omapi_object_t **ip, 1651 omapi_object_t *id, 1652 omapi_object_t *ref) 1653 { 1654 omapi_value_t *tv = (omapi_value_t *)0; 1655 isc_result_t status; 1656 struct interface_info *interface; 1657 1658 if (!ref) 1659 return DHCP_R_NOKEYS; 1660 1661 /* First see if we were sent a handle. */ 1662 status = omapi_get_value_str (ref, id, "handle", &tv); 1663 if (status == ISC_R_SUCCESS) { 1664 status = omapi_handle_td_lookup (ip, tv -> value); 1665 1666 omapi_value_dereference (&tv, MDL); 1667 if (status != ISC_R_SUCCESS) 1668 return status; 1669 1670 /* Don't return the object if the type is wrong. */ 1671 if ((*ip) -> type != dhcp_type_interface) { 1672 omapi_object_dereference (ip, MDL); 1673 return DHCP_R_INVALIDARG; 1674 } 1675 } 1676 1677 /* Now look for an interface name. */ 1678 status = omapi_get_value_str (ref, id, "name", &tv); 1679 if (status == ISC_R_SUCCESS) { 1680 char *s; 1681 unsigned len; 1682 for (interface = interfaces; interface; 1683 interface = interface -> next) { 1684 s = memchr (interface -> name, 0, IFNAMSIZ); 1685 if (s) 1686 len = s - &interface -> name [0]; 1687 else 1688 len = IFNAMSIZ; 1689 if ((tv -> value -> u.buffer.len == len && 1690 !memcmp (interface -> name, 1691 (char *)tv -> value -> u.buffer.value, 1692 len))) 1693 break; 1694 } 1695 if (!interface) { 1696 for (interface = dummy_interfaces; 1697 interface; interface = interface -> next) { 1698 s = memchr (interface -> name, 0, IFNAMSIZ); 1699 if (s) 1700 len = s - &interface -> name [0]; 1701 else 1702 len = IFNAMSIZ; 1703 if ((tv -> value -> u.buffer.len == len && 1704 !memcmp (interface -> name, 1705 (char *) 1706 tv -> value -> u.buffer.value, 1707 len))) 1708 break; 1709 } 1710 } 1711 1712 omapi_value_dereference (&tv, MDL); 1713 if (*ip && *ip != (omapi_object_t *)interface) { 1714 omapi_object_dereference (ip, MDL); 1715 return DHCP_R_KEYCONFLICT; 1716 } else if (!interface) { 1717 if (*ip) 1718 omapi_object_dereference (ip, MDL); 1719 return ISC_R_NOTFOUND; 1720 } else if (!*ip) 1721 omapi_object_reference (ip, 1722 (omapi_object_t *)interface, 1723 MDL); 1724 } 1725 1726 /* If we get to here without finding an interface, no valid key was 1727 specified. */ 1728 if (!*ip) 1729 return DHCP_R_NOKEYS; 1730 return ISC_R_SUCCESS; 1731 } 1732 1733 /* actually just go discover the interface */ 1734 isc_result_t dhcp_interface_create (omapi_object_t **lp, 1735 omapi_object_t *id) 1736 { 1737 struct interface_info *hp; 1738 isc_result_t status; 1739 1740 hp = (struct interface_info *)0; 1741 status = interface_allocate (&hp, MDL); 1742 if (status != ISC_R_SUCCESS) 1743 return status; 1744 hp -> flags = INTERFACE_REQUESTED; 1745 status = interface_reference ((struct interface_info **)lp, hp, MDL); 1746 interface_dereference (&hp, MDL); 1747 return status; 1748 } 1749 1750 isc_result_t dhcp_interface_remove (omapi_object_t *lp, 1751 omapi_object_t *id) 1752 { 1753 struct interface_info *interface, *ip, *last; 1754 1755 interface = (struct interface_info *)lp; 1756 1757 /* remove from interfaces */ 1758 last = 0; 1759 for (ip = interfaces; ip; ip = ip -> next) { 1760 if (ip == interface) { 1761 if (last) { 1762 interface_dereference (&last -> next, MDL); 1763 if (ip -> next) 1764 interface_reference (&last -> next, 1765 ip -> next, MDL); 1766 } else { 1767 interface_dereference (&interfaces, MDL); 1768 if (ip -> next) 1769 interface_reference (&interfaces, 1770 ip -> next, MDL); 1771 } 1772 if (ip -> next) 1773 interface_dereference (&ip -> next, MDL); 1774 break; 1775 } 1776 last = ip; 1777 } 1778 if (!ip) 1779 return ISC_R_NOTFOUND; 1780 1781 /* add the interface to the dummy_interface list */ 1782 if (dummy_interfaces) { 1783 interface_reference (&interface -> next, 1784 dummy_interfaces, MDL); 1785 interface_dereference (&dummy_interfaces, MDL); 1786 } 1787 interface_reference (&dummy_interfaces, interface, MDL); 1788 1789 /* do a DHCPRELEASE */ 1790 if (dhcp_interface_shutdown_hook) 1791 (*dhcp_interface_shutdown_hook) (interface); 1792 1793 /* remove the io object */ 1794 omapi_unregister_io_object ((omapi_object_t *)interface); 1795 1796 switch(local_family) { 1797 #ifdef DHCPv6 1798 case AF_INET6: 1799 if_deregister6(interface); 1800 break; 1801 #endif /* DHCPv6 */ 1802 case AF_INET: 1803 default: 1804 if_deregister_send(interface); 1805 if_deregister_receive(interface); 1806 break; 1807 } 1808 1809 return ISC_R_SUCCESS; 1810 } 1811 1812 void interface_stash (struct interface_info *tptr) 1813 { 1814 struct interface_info **vec; 1815 int delta; 1816 1817 /* If the registerer didn't assign an index, assign one now. */ 1818 if (tptr -> index == -1) { 1819 tptr -> index = interface_count++; 1820 while (tptr -> index < interface_max && 1821 interface_vector [tptr -> index]) 1822 tptr -> index = interface_count++; 1823 } 1824 1825 if (interface_max <= tptr -> index) { 1826 delta = tptr -> index - interface_max + 10; 1827 vec = dmalloc ((interface_max + delta) * 1828 sizeof (struct interface_info *), MDL); 1829 if (!vec) 1830 return; 1831 memset (&vec [interface_max], 0, 1832 (sizeof (struct interface_info *)) * delta); 1833 interface_max += delta; 1834 if (interface_vector) { 1835 memcpy (vec, interface_vector, 1836 (interface_count * 1837 sizeof (struct interface_info *))); 1838 dfree (interface_vector, MDL); 1839 } 1840 interface_vector = vec; 1841 } 1842 interface_reference (&interface_vector [tptr -> index], tptr, MDL); 1843 if (tptr -> index >= interface_count) 1844 interface_count = tptr -> index + 1; 1845 #if defined (TRACING) 1846 trace_interface_register (interface_trace, tptr); 1847 #endif 1848 } 1849 1850 void interface_snorf (struct interface_info *tmp, int ir) 1851 { 1852 tmp -> circuit_id = (u_int8_t *)tmp -> name; 1853 tmp -> circuit_id_len = strlen (tmp -> name); 1854 tmp -> remote_id = 0; 1855 tmp -> remote_id_len = 0; 1856 tmp -> flags = ir; 1857 if (interfaces) { 1858 interface_reference (&tmp -> next, 1859 interfaces, MDL); 1860 interface_dereference (&interfaces, MDL); 1861 } 1862 interface_reference (&interfaces, tmp, MDL); 1863 } 1864