1/* 2 * Copyright (c) 1999 - 2008, 2011, 2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * bootpd.c 25 * - BOOTP/DHCP server main 26 * - see RFC951, RFC2131, RFC2132 for details on the BOOTP protocol, 27 * BOOTP extensions/DHCP options, and the DHCP protocol 28 */ 29 30/* 31 * Modification History 32 * 01/22/86 Croft created. 33 * 34 * 03/19/86 Lougheed Converted to run under 4.3 BSD inetd. 35 * 36 * 09/06/88 King Added NeXT interrim support. 37 * 38 * 02/23/98 Dieter Siegmund (dieter@apple.com) 39 * - complete overhaul 40 * - added specialized Mac NC support 41 * - removed the NeXT "Sexy Net Init" code that performed 42 * a proprietary form of dynamic BOOTP, since this 43 * functionality is replaced by DHCP 44 * - added ability to respond to requests originating from 45 * a specific set of interfaces 46 * - added rfc2132 option handling 47 * 48 * June 5, 1998 Dieter Siegmund (dieter@apple.com) 49 * - do lookups using netinfo calls directly to be able to read/write 50 * entries and get subnet-specific bindings 51 * 52 * Oct 19, 1998 Dieter Siegmund (dieter@apple.com) 53 * - provide domain name servers for this server if not explicitly 54 * configured otherwise 55 * Mar 29, 1999 Dieter Siegmund (dieter@apple.com) 56 * - added code to do ethernet lookups with or without leading zeroes 57 * April 27, 2000 Dieter Siegmund (dieter@apple.com) 58 * - added netinfo host caching to avoid denial of service 59 * attacks and handle any valid format for the ethernet address 60 * i.e. leading zeroes, capitalization, etc. 61 * - eliminated practice of supplying a default bootfile 62 * - eliminated ability to read host entries from a file 63 */ 64 65#include <unistd.h> 66#include <stdlib.h> 67#include <sys/stat.h> 68#include <sys/socket.h> 69#include <sys/ioctl.h> 70#include <sys/file.h> 71#include <sys/time.h> 72#include <sys/types.h> 73#include <net/if.h> 74#include <netinet/in.h> 75#include <netinet/in_systm.h> 76#include <netinet/ip.h> 77#include <netinet/udp.h> 78#include <netinet/bootp.h> 79#include <netinet/if_ether.h> 80#include <net/if_arp.h> 81#include <mach/boolean.h> 82#include <signal.h> 83#include <stdio.h> 84#include <stdarg.h> 85#include <string.h> 86#include <errno.h> 87#include <ctype.h> 88#include <netdb.h> 89#include <syslog.h> 90#include <arpa/inet.h> 91#include <arpa/nameser.h> 92#include <sys/uio.h> 93#include <resolv.h> 94#include <CoreFoundation/CFString.h> 95#include <CoreFoundation/CFNumber.h> 96#include <CoreFoundation/CFArray.h> 97#include <CoreFoundation/CFDictionary.h> 98#include <SystemConfiguration/SCValidation.h> 99 100#include "arp.h" 101#include "netinfo.h" 102#include "interfaces.h" 103#include "inetroute.h" 104#include "subnets.h" 105#include "dhcp_options.h" 106#include "DNSNameList.h" 107#include "rfc_options.h" 108#include "macNC.h" 109#include "bsdpd.h" 110#include "NICache.h" 111#include "host_identifier.h" 112#include "dhcpd.h" 113#include "bootpd.h" 114#include "bsdp.h" 115#include "bootp_transmit.h" 116#include "util.h" 117#include "cfutil.h" 118#include "bootpd-plist.h" 119#include "bootpdfile.h" 120#include "bootplookup.h" 121 122#define CFGPROP_DHCP_IGNORE_CLIENT_IDENTIFIER "dhcp_ignore_client_identifier" 123#define CFGPROP_DETECT_OTHER_DHCP_SERVER "detect_other_dhcp_server" 124#define CFGPROP_BOOTP_ENABLED "bootp_enabled" 125#define CFGPROP_DHCP_ENABLED "dhcp_enabled" 126#if !TARGET_OS_EMBEDDED 127#define CFGPROP_OLD_NETBOOT_ENABLED "old_netboot_enabled" 128#define CFGPROP_NETBOOT_ENABLED "netboot_enabled" 129#define CFGPROP_USE_OPEN_DIRECTORY "use_open_directory" 130#endif /* !TARGET_OS_EMBEDDED */ 131#define CFGPROP_RELAY_ENABLED "relay_enabled" 132#define CFGPROP_ALLOW "allow" 133#define CFGPROP_DENY "deny" 134#define CFGPROP_REPLY_THRESHOLD_SECONDS "reply_threshold_seconds" 135#define CFGPROP_RELAY_IP_LIST "relay_ip_list" 136#define CFGPROP_USE_SERVER_CONFIG_FOR_DHCP_OPTIONS "use_server_config_for_dhcp_options" 137 138/* 139 * On some platforms the root filesystem is mounted read-only; 140 * make sure that the plist points to a user-writeable location. 141 */ 142#if TARGET_OS_EMBEDDED 143#define BOOTPD_PLIST_ROOT "/Library/Preferences/SystemConfiguration" 144#else 145#define BOOTPD_PLIST_ROOT "/etc" 146#endif /* TARGET_OS_EMBEDDED */ 147#define BOOTPD_PLIST_PATH BOOTPD_PLIST_ROOT "/bootpd.plist" 148 149/* local defines */ 150#define MAXIDLE (5*60) /* we hang around for five minutes */ 151#define SERVICE_BOOTP 0x00000001 152#define SERVICE_DHCP 0x00000002 153#define SERVICE_OLD_NETBOOT 0x00000004 154#define SERVICE_NETBOOT 0x00000008 155#define SERVICE_RELAY 0x00000010 156 157/* global variables: */ 158char boot_tftp_dir[128] = "/private/tftpboot"; 159int bootp_socket = -1; 160int debug = 0; 161bool detect_other_dhcp_server = FALSE; 162bool dhcp_ignore_client_identifier = FALSE; 163int quiet = 0; 164uint32_t reply_threshold_seconds = 0; 165unsigned short server_priority = BSDP_PRIORITY_BASE; 166char * testing_control = ""; 167char server_name[MAXHOSTNAMELEN + 1]; 168SubnetListRef subnets; 169/* 170 * transmit_buffer is cast to some struct types containing short fields; 171 * force it to be aligned as much as an int 172 */ 173static int transmit_buffer_aligned[512]; 174char * transmit_buffer = (char *)transmit_buffer_aligned; 175 176#if ! TARGET_OS_EMBEDDED 177bool use_open_directory = TRUE; 178#endif /* ! TARGET_OS_EMBEDDED */ 179int verbose = 0; 180 181/* local types */ 182 183/* local variables */ 184static boolean_t S_bootfile_noexist_reply = TRUE; 185static boolean_t S_do_bootp; 186#if !TARGET_OS_EMBEDDED 187static boolean_t S_do_netboot; 188static boolean_t S_do_old_netboot; 189#endif /* !TARGET_OS_EMBEDDED */ 190static boolean_t S_do_dhcp; 191static boolean_t S_do_relay; 192static struct in_addr * S_dns_servers = NULL; 193static int S_dns_servers_count = 0; 194static char * S_domain_name = NULL; 195static uint8_t * S_domain_search = NULL; 196static int S_domain_search_size = 0; 197static ptrlist_t S_if_list; 198static interface_list_t * S_interfaces; 199static inetroute_list_t * S_inetroutes = NULL; 200static u_short S_ipport_client = IPPORT_BOOTPC; 201static u_short S_ipport_server = IPPORT_BOOTPS; 202static struct timeval S_lastmsgtime; 203/* ALIGN: S_rxpkt is aligned to at least sizeof(uint32_t) bytes */ 204static uint32_t S_rxpkt[2048/(sizeof(uint32_t))];/* receive packet buffer */ 205static boolean_t S_sighup = TRUE; /* fake the 1st sighup */ 206static u_int32_t S_which_services = 0; 207static struct ether_addr * S_allow = NULL; 208static int S_allow_count = 0; 209static struct ether_addr * S_deny = NULL; 210static int S_deny_count = 0; 211static int S_persist = 0; 212static struct in_addr * S_relay_ip_list = NULL; 213static int S_relay_ip_list_count = 0; 214static int S_max_hops = 4; 215static boolean_t S_use_server_config_for_dhcp_options = TRUE; 216 217 218void 219my_log(int priority, const char *message, ...) 220{ 221 va_list ap; 222 223 if (priority == LOG_DEBUG) { 224 if (verbose == FALSE) 225 return; 226 priority = LOG_NOTICE; 227 } 228 else if (priority == LOG_INFO) { 229 priority = LOG_NOTICE; 230 } 231 if (quiet && (priority > LOG_ERR)) { 232 return; 233 } 234 va_start(ap, message); 235 vsyslog(priority, message, ap); 236 va_end(ap); 237 return; 238} 239 240/* forward function declarations */ 241static int issock(int fd); 242static void on_alarm(int sigraised); 243static void on_sighup(int sigraised); 244static void bootp_request(request_t * request); 245static void S_server_loop(); 246 247#define PID_FILE "/var/run/bootpd.pid" 248static void 249writepid(void) 250{ 251 FILE *fp; 252 253 fp = fopen(PID_FILE, "w"); 254 if (fp != NULL) { 255 fprintf(fp, "%d\n", getpid()); 256 (void) fclose(fp); 257 } 258} 259 260/* 261 * Function: background 262 * 263 * Purpose: 264 * Daemon-ize ourselves. 265 */ 266static void 267background() 268{ 269 if (fork()) 270 exit(0); 271 { 272 int s; 273 for (s = 0; s < 10; s++) 274 (void) close(s); 275 } 276 (void) open("/", O_RDONLY); 277 (void) dup2(0, 1); 278 (void) dup2(0, 2); 279 { 280 int tt = open("/dev/tty", O_RDWR); 281 if (tt > 0) { 282 ioctl(tt, TIOCNOTTY, 0); 283 close(tt); 284 } 285 } 286} 287 288static void 289S_get_dns() 290{ 291 int domain_search_count = 0; 292 int i; 293 294 res_init(); /* figure out the default dns servers */ 295 296 S_domain_name = NULL; 297 if (S_dns_servers) { 298 free(S_dns_servers); 299 S_dns_servers = NULL; 300 } 301 if (S_domain_search != NULL) { 302 free(S_domain_search); 303 S_domain_search = NULL; 304 } 305 S_domain_search_size = 0; 306 S_dns_servers_count = 0; 307 308 /* create the DNS server address list */ 309 if (_res.nscount != 0) { 310 S_dns_servers = (struct in_addr *)malloc(sizeof(*S_dns_servers) * _res.nscount); 311 for (i = 0; i < _res.nscount; i++) { 312 in_addr_t s_addr = _res.nsaddr_list[i].sin_addr.s_addr; 313 314 /* exclude 0.0.0.0, 255.255.255.255, and 127/8 */ 315 if (s_addr == 0 316 || s_addr == INADDR_BROADCAST 317 || (((ntohl(s_addr) & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) 318 == IN_LOOPBACKNET)) { 319 continue; 320 } 321 S_dns_servers[S_dns_servers_count++].s_addr = s_addr; 322 if (debug) { 323 if (S_dns_servers_count == 1) { 324 printf("DNS servers:"); 325 } 326 printf(" %s", 327 inet_ntoa(S_dns_servers[S_dns_servers_count - 1])); 328 } 329 } 330 if (S_dns_servers_count == 0) { 331 free(S_dns_servers); 332 S_dns_servers = NULL; 333 } 334 else if (debug) { 335 printf("\n"); 336 } 337 } 338 if (S_dns_servers_count != 0) { 339 if (_res.defdname[0] && strcmp(_res.defdname, "local") != 0) { 340 S_domain_name = _res.defdname; 341 if (debug) 342 printf("DNS domain: %s\n", S_domain_name); 343 } 344 /* create the DNS search list */ 345 for (i = 0; i < MAXDNSRCH; i++) { 346 if (_res.dnsrch[i] == NULL) { 347 break; 348 } 349 domain_search_count++; 350 if (debug) { 351 if (i == 0) { 352 printf("DNS search:"); 353 } 354 printf(" %s", _res.dnsrch[i]); 355 } 356 } 357 if (domain_search_count != 0) { 358 if (debug) { 359 printf("\n"); 360 } 361 S_domain_search 362 = DNSNameListBufferCreate((const char * *)_res.dnsrch, 363 domain_search_count, 364 NULL, &S_domain_search_size); 365 } 366 } 367 return; 368} 369 370/* 371 * Function: S_string_in_list 372 * 373 * Purpose: 374 * Given a List object, return boolean whether the C string is 375 * in the list. 376 */ 377static boolean_t 378S_string_in_list(ptrlist_t * list, const char * str) 379{ 380 int i; 381 382 for (i = 0; i < ptrlist_count(list); i++) { 383 char * lstr = (char *)ptrlist_element(list, i); 384 if (strcmp(str, lstr) == 0) 385 return (TRUE); 386 } 387 return (FALSE); 388} 389 390/* 391 * Function: S_log_interfaces 392 * 393 * Purpose: 394 * Log which interfaces we will respond on. 395 */ 396void 397S_log_interfaces() 398{ 399 int i; 400 int count = 0; 401 402 for (i = 0; i < S_interfaces->count; i++) { 403 interface_t * if_p = S_interfaces->list + i; 404 405 if ((ptrlist_count(&S_if_list) == 0 406 || S_string_in_list(&S_if_list, if_name(if_p))) 407 && if_inet_valid(if_p) && !(if_flags(if_p) & IFF_LOOPBACK)) { 408 int i; 409 inet_addrinfo_t * info; 410 char ip[32]; 411 412 for (i = 0; i < if_inet_count(if_p); i++) { 413 info = if_inet_addr_at(if_p, i); 414 strcpy(ip, inet_ntoa(info->addr)); 415 my_log(LOG_INFO, "interface %s: ip %s mask %s", 416 if_name(if_p), ip, inet_ntoa(info->mask)); 417 } 418 count++; 419 } 420 } 421 if (count == 0) { 422 my_log(LOG_INFO, "no available interfaces"); 423 if (S_persist == 0) { 424 exit(2); 425 } 426 } 427 return; 428} 429 430/* 431 * Function: S_get_interfaces 432 * 433 * Purpose: 434 * Get the list of interfaces we will use. 435 */ 436void 437S_get_interfaces() 438{ 439 interface_list_t * new_list; 440 441 new_list = ifl_init(); 442 if (new_list == NULL) { 443 my_log(LOG_INFO, "interface list initialization failed"); 444 exit(1); 445 } 446 ifl_free(&S_interfaces); 447 S_interfaces = new_list; 448 return; 449} 450 451/* 452 * Function: S_get_network_routes 453 * 454 * Purpose: 455 * Get the list of network routes. 456 */ 457void 458S_get_network_routes() 459{ 460 inetroute_list_t * new_list; 461 462 new_list = inetroute_list_init(); 463 if (new_list == NULL) { 464 my_log(LOG_INFO, "can't get inetroutes list"); 465 exit(1); 466 } 467 468 inetroute_list_free(&S_inetroutes); 469 S_inetroutes = new_list; 470 if (debug) 471 inetroute_list_print(S_inetroutes); 472} 473 474static void 475S_service_enable(CFTypeRef prop, u_int32_t which) 476{ 477 int i; 478 CFStringRef ifname_cf = NULL; 479 int count; 480 481 if (prop == NULL) { 482 return; 483 } 484 if (isA_CFBoolean(prop) != NULL) { 485 if (CFEqual(prop, kCFBooleanTrue)) { 486 S_which_services |= which; 487 } 488 return; 489 } 490 if (isA_CFString(prop) != NULL) { 491 count = 1; 492 ifname_cf = prop; 493 } 494 else if (isA_CFArray(prop) != NULL) { 495 count = CFArrayGetCount(prop); 496 if (count == 0) { 497 S_which_services |= which; 498 return; 499 } 500 } 501 else { 502 /* invalid type */ 503 return; 504 } 505 for (i = 0; i < count; i++) { 506 interface_t * if_p; 507 char ifname[IFNAMSIZ + 1]; 508 509 if (i != 0 || ifname_cf == NULL) { 510 ifname_cf = CFArrayGetValueAtIndex(prop, i); 511 if (isA_CFString(ifname_cf) == NULL) { 512 continue; 513 } 514 } 515 if (CFStringGetCString(ifname_cf, ifname, sizeof(ifname), 516 kCFStringEncodingASCII) 517 == FALSE) { 518 continue; 519 } 520 if (*ifname == '\0') { 521 continue; 522 } 523 if_p = ifl_find_name(S_interfaces, ifname); 524 if (if_p == NULL) { 525 continue; 526 } 527 if_p->user_defined |= which; 528 } 529 return; 530} 531 532#if !TARGET_OS_EMBEDDED 533static void 534S_service_disable(u_int32_t service) 535{ 536 int i; 537 538 S_which_services &= ~service; 539 540 for (i = 0; i < S_interfaces->count; i++) { 541 interface_t * if_p = S_interfaces->list + i; 542 if_p->user_defined &= ~service; 543 } 544 return; 545} 546 547static boolean_t 548S_service_is_enabled(u_int32_t service) 549{ 550 int i; 551 552 if (S_which_services & service) 553 return (TRUE); 554 555 for (i = 0; i < S_interfaces->count; i++) { 556 interface_t * if_p = S_interfaces->list + i; 557 if (if_p->user_defined & service) 558 return (TRUE); 559 } 560 return (FALSE); 561} 562 563static void 564S_disable_netboot() 565{ 566 S_do_netboot = FALSE; 567 S_do_old_netboot = FALSE; 568 S_service_disable(SERVICE_NETBOOT | SERVICE_OLD_NETBOOT); 569 return; 570} 571#endif /* !TARGET_OS_EMBEDDED */ 572 573typedef int (*qsort_compare_func_t)(const void *, const void *); 574 575static struct ether_addr * 576S_make_ether_list(CFArrayRef array, int * count_p) 577{ 578 int array_count = CFArrayGetCount(array); 579 int count = 0; 580 int i; 581 struct ether_addr * list; 582 583 list = (struct ether_addr *)malloc(sizeof(*list) * array_count); 584 for (i = 0; i < array_count; i++) { 585 struct ether_addr * eaddr; 586 CFStringRef str = CFArrayGetValueAtIndex(array, i); 587 char val[64]; 588 589 if (isA_CFString(str) == NULL) { 590 continue; 591 } 592 if (CFStringGetCString(str, val, sizeof(val), kCFStringEncodingASCII) 593 == FALSE) { 594 continue; 595 } 596 if (strlen(val) < 2) { 597 continue; 598 } 599 /* ignore ethernet hardware type, if present */ 600 if (strncmp(val, "1,", 2) == 0) { 601 eaddr = ether_aton(val + 2); 602 } 603 else { 604 eaddr = ether_aton((char *)val); 605 } 606 if (eaddr == NULL) { 607 continue; 608 } 609 list[count++] = *eaddr; 610 } 611 if (count == 0) { 612 free(list); 613 list = NULL; 614 } 615 else { 616 qsort(list, count, sizeof(*list), (qsort_compare_func_t)ether_cmp); 617 } 618 *count_p = count; 619 return (list); 620} 621 622static boolean_t 623S_ok_to_respond(int hwtype, void * hwaddr, int hwlen) 624{ 625 struct ether_addr * search; 626 boolean_t respond = TRUE; 627 628 if (hwlen != ETHER_ADDR_LEN) { 629 return (TRUE); 630 } 631 if (S_deny != NULL) { 632 search = bsearch(hwaddr, S_deny, S_deny_count, sizeof(*S_deny), 633 (qsort_compare_func_t)ether_cmp); 634 if (search != NULL) { 635 my_log(LOG_DEBUG, "%s is in deny list, ignoring", 636 ether_ntoa(hwaddr)); 637 respond = FALSE; 638 } 639 } 640 if (respond == TRUE && S_allow != NULL) { 641 search = bsearch(hwaddr, S_allow, S_allow_count, sizeof(*S_allow), 642 (qsort_compare_func_t)ether_cmp); 643 if (search == NULL) { 644 my_log(LOG_DEBUG, "%s is not in the allow list, ignoring", 645 ether_ntoa(hwaddr)); 646 respond = FALSE; 647 } 648 } 649 return (respond); 650} 651 652static void 653S_refresh_allow_deny(CFDictionaryRef plist) 654{ 655 CFArrayRef prop; 656 657 if (S_allow != NULL) { 658 free(S_allow); 659 S_allow = NULL; 660 } 661 if (S_deny != NULL) { 662 free(S_deny); 663 S_deny = NULL; 664 } 665 S_allow_count = 0; 666 S_deny_count = 0; 667 668 if (plist == NULL) { 669 return; 670 } 671 672 /* allow */ 673 prop = CFDictionaryGetValue(plist, CFSTR(CFGPROP_ALLOW)); 674 if (isA_CFArray(prop) != NULL && CFArrayGetCount(prop) > 0) { 675 S_allow = S_make_ether_list(prop, &S_allow_count); 676 } 677 /* deny */ 678 prop = CFDictionaryGetValue(plist, CFSTR(CFGPROP_DENY)); 679 if (isA_CFArray(prop) != NULL && CFArrayGetCount(prop) > 0) { 680 S_deny = S_make_ether_list(prop, &S_deny_count); 681 } 682 return; 683} 684 685static boolean_t 686S_str_to_ip(const char * ip_str, struct in_addr * ret_ip) 687{ 688 if (inet_aton(ip_str, ret_ip) == 0 689 || ret_ip->s_addr == 0 690 || ret_ip->s_addr == INADDR_BROADCAST) { 691 return (FALSE); 692 } 693 return (TRUE); 694} 695 696static void 697S_relay_ip_list_clear(void) 698{ 699 if (S_relay_ip_list != NULL) { 700 free(S_relay_ip_list); 701 S_relay_ip_list = NULL; 702 S_relay_ip_list_count = 0; 703 } 704 return; 705} 706 707static void 708S_relay_ip_list_add(struct in_addr relay_ip) 709{ 710 if (S_relay_ip_list == NULL) { 711 S_relay_ip_list 712 = (struct in_addr *)malloc(sizeof(struct in_addr *)); 713 S_relay_ip_list[0] = relay_ip; 714 S_relay_ip_list_count = 1; 715 } 716 else { 717 S_relay_ip_list_count++; 718 S_relay_ip_list = (struct in_addr *) 719 realloc(S_relay_ip_list, 720 sizeof(struct in_addr *) * S_relay_ip_list_count); 721 S_relay_ip_list[S_relay_ip_list_count - 1] = relay_ip; 722 } 723 return; 724} 725 726static void 727S_update_relay_ip_list(CFArrayRef list) 728{ 729 int count; 730 int i; 731 732 count = CFArrayGetCount(list); 733 S_relay_ip_list_clear(); 734 for (i = 0; i < count; i++) { 735 struct in_addr relay_ip; 736 CFStringRef str = CFArrayGetValueAtIndex(list, i); 737 738 if (isA_CFString(str) == NULL) { 739 continue; 740 } 741 if (my_CFStringToIPAddress(str, &relay_ip) == FALSE) { 742 my_log(LOG_NOTICE, "Invalid relay server ip address"); 743 continue; 744 } 745 if (relay_ip.s_addr == 0 || relay_ip.s_addr == INADDR_BROADCAST) { 746 my_log(LOG_NOTICE, 747 "Invalid relay server ip address %s", 748 inet_ntoa(relay_ip)); 749 continue; 750 } 751 if (ifl_find_ip(S_interfaces, relay_ip) != NULL) { 752 my_log(LOG_NOTICE, 753 "Relay server ip address %s specifies this host", 754 inet_ntoa(relay_ip)); 755 continue; 756 } 757 S_relay_ip_list_add(relay_ip); 758 } 759 return; 760} 761 762__private_extern__ void 763set_number_from_plist(CFDictionaryRef plist, CFStringRef prop_name_cf, 764 const char * prop_name, uint32_t * val_p) 765{ 766 CFTypeRef prop; 767 768 if (plist == NULL) { 769 return; 770 } 771 prop = CFDictionaryGetValue(plist, prop_name_cf); 772 if (prop != NULL 773 && my_CFTypeToNumber(prop, val_p) == FALSE) { 774 my_log(LOG_INFO, "Invalid '%s' property", prop_name); 775 } 776 return; 777} 778 779static boolean_t 780S_get_plist_boolean(CFDictionaryRef plist, CFStringRef prop_name_cf, 781 const char * prop_name, boolean_t def_value) 782{ 783 boolean_t ret; 784 785 ret = def_value; 786 if (plist != NULL) { 787 CFBooleanRef prop = CFDictionaryGetValue(plist, prop_name_cf); 788 uint32_t val; 789 790 if (prop != NULL) { 791 if (my_CFTypeToNumber(prop, &val) == FALSE) { 792 my_log(LOG_NOTICE, "Invalid '%s' property", 793 prop_name); 794 } 795 else { 796 ret = (val != 0); 797 } 798 } 799 } 800 return (ret); 801} 802 803static void 804S_update_services() 805{ 806 uint32_t num; 807 CFDictionaryRef plist = NULL; 808 CFTypeRef prop; 809 810 plist = my_CFPropertyListCreateFromFile(BOOTPD_PLIST_PATH); 811 if (plist != NULL) { 812 if (isA_CFDictionary(plist) == NULL) { 813 CFRelease(plist); 814 plist = NULL; 815 } 816 } 817 S_which_services = 0; 818 819 if (plist != NULL) { 820 /* BOOTP */ 821 S_service_enable(CFDictionaryGetValue(plist, 822 CFSTR(CFGPROP_BOOTP_ENABLED)), 823 SERVICE_BOOTP); 824 825 /* DHCP */ 826 S_service_enable(CFDictionaryGetValue(plist, 827 CFSTR(CFGPROP_DHCP_ENABLED)), 828 SERVICE_DHCP); 829#if !TARGET_OS_EMBEDDED 830 /* NetBoot (2.0) */ 831 S_service_enable(CFDictionaryGetValue(plist, 832 CFSTR(CFGPROP_NETBOOT_ENABLED)), 833 SERVICE_NETBOOT); 834 835 /* NetBoot (old, pre 2.0) */ 836 S_service_enable(CFDictionaryGetValue(plist, 837 CFSTR(CFGPROP_OLD_NETBOOT_ENABLED)), 838 SERVICE_OLD_NETBOOT); 839#endif /* !TARGET_OS_EMBEDDED */ 840 /* Relay */ 841 S_service_enable(CFDictionaryGetValue(plist, 842 CFSTR(CFGPROP_RELAY_ENABLED)), 843 SERVICE_RELAY); 844 prop = CFDictionaryGetValue(plist, CFSTR(CFGPROP_RELAY_IP_LIST)); 845 if (isA_CFArray(prop) != NULL) { 846 S_update_relay_ip_list(prop); 847 } 848 } 849 /* allow/deny list */ 850 S_refresh_allow_deny(plist); 851 852 /* reply threshold */ 853 reply_threshold_seconds = 0; 854 set_number_from_plist(plist, CFSTR(CFGPROP_REPLY_THRESHOLD_SECONDS), 855 CFGPROP_REPLY_THRESHOLD_SECONDS, 856 &reply_threshold_seconds); 857 858 /* detect other DHCP server */ 859 detect_other_dhcp_server = FALSE; 860 num = 0; 861 set_number_from_plist(plist, CFSTR(CFGPROP_DETECT_OTHER_DHCP_SERVER), 862 CFGPROP_DETECT_OTHER_DHCP_SERVER, 863 &num); 864 if (num != 0) { 865 detect_other_dhcp_server = TRUE; 866 } 867 868 /* ignore the DHCP client identifier */ 869 dhcp_ignore_client_identifier = FALSE; 870 num = 0; 871 set_number_from_plist(plist, CFSTR(CFGPROP_DHCP_IGNORE_CLIENT_IDENTIFIER), 872 CFGPROP_DHCP_IGNORE_CLIENT_IDENTIFIER, 873 &num); 874 if (num != 0) { 875 dhcp_ignore_client_identifier = TRUE; 876 } 877#if !TARGET_OS_EMBEDDED 878 /* use open directory [for bootpent queries] */ 879 use_open_directory = TRUE; 880 num = 1; 881 set_number_from_plist(plist, CFSTR(CFGPROP_USE_OPEN_DIRECTORY), 882 CFGPROP_USE_OPEN_DIRECTORY, 883 &num); 884 if (num == 0) { 885 use_open_directory = FALSE; 886 } 887#endif /* !TARGET_OS_EMBEDDED */ 888 889 /* check whether to supply our own configuration for missing dhcp options */ 890 S_use_server_config_for_dhcp_options 891 = S_get_plist_boolean(plist, 892 CFSTR(CFGPROP_USE_SERVER_CONFIG_FOR_DHCP_OPTIONS), 893 CFGPROP_USE_SERVER_CONFIG_FOR_DHCP_OPTIONS, 894 TRUE); 895 896 /* get the new list of subnets */ 897 SubnetListFree(&subnets); 898 if (plist != NULL) { 899 prop = CFDictionaryGetValue(plist, BOOTPD_PLIST_SUBNETS); 900 if (isA_CFArray(prop) != NULL) { 901 subnets = SubnetListCreateWithArray(prop); 902 if (subnets != NULL) { 903 if (debug) { 904 SubnetListPrint(subnets); 905 } 906 } 907 } 908 } 909 910 dhcp_init(); 911#if !TARGET_OS_EMBEDDED 912 if (S_do_netboot || S_do_old_netboot 913 || S_service_is_enabled(SERVICE_NETBOOT | SERVICE_OLD_NETBOOT)) { 914 if (bsdp_init(plist) == FALSE) { 915 my_log(LOG_INFO, "bootpd: NetBoot service turned off"); 916 S_disable_netboot(); 917 } 918 } 919#endif /* !TARGET_OS_EMBEDDED */ 920 if (plist != NULL) { 921 CFRelease(plist); 922 } 923 return; 924} 925 926static __inline__ boolean_t 927bootp_enabled(interface_t * if_p) 928{ 929 u_int32_t which = (S_which_services | if_p->user_defined); 930 931 return (S_do_bootp || (which & SERVICE_BOOTP) != 0); 932} 933 934static __inline__ boolean_t 935dhcp_enabled(interface_t * if_p) 936{ 937 u_int32_t which = (S_which_services | if_p->user_defined); 938 939 return (S_do_dhcp || (which & SERVICE_DHCP) != 0); 940} 941 942#if !TARGET_OS_EMBEDDED 943static __inline__ boolean_t 944netboot_enabled(interface_t * if_p) 945{ 946 u_int32_t which = (S_which_services | if_p->user_defined); 947 948 return (S_do_netboot || (which & SERVICE_NETBOOT) != 0); 949} 950 951static __inline__ boolean_t 952old_netboot_enabled(interface_t * if_p) 953{ 954 u_int32_t which = (S_which_services | if_p->user_defined); 955 956 return (S_do_old_netboot || (which & SERVICE_OLD_NETBOOT) != 0); 957} 958#endif /* !TARGET_OS_EMBEDDED */ 959 960static __inline__ boolean_t 961relay_enabled(interface_t * if_p) 962{ 963 u_int32_t which = (S_which_services | if_p->user_defined); 964 965 return (S_do_relay || (which & SERVICE_RELAY) != 0); 966} 967 968void 969usage() 970{ 971 fprintf(stderr, "usage: bootpd <options>\n" 972 "<options> are:\n" 973 "[ -a ] support anonymous binding for BOOTP clients\n" 974 "[ -D ] be a DHCP server\n" 975 "[ -B ] don't service BOOTP requests\n" 976 "[ -b ] bootfile must exist or we don't respond\n" 977 "[ -d ] debug mode, stay in foreground, extra printf's\n" 978 "[ -I ] disable re-initialization on IP address changes\n" 979 "[ -i <interface> [ -i <interface> ... ] ]\n" 980#if !TARGET_OS_EMBEDDED 981 "[ -m ] be an old NetBoot (1.0) server\n" 982#endif /* !TARGET_OS_EMBEDDED */ 983 "[ -n <domain> [ -n <domain> [...] ] ]\n" 984#if !TARGET_OS_EMBEDDED 985 "[ -N ] be a NetBoot 2.0 server\n" 986#endif /* !TARGET_OS_EMBEDDED */ 987 "[ -q ] be quiet as possible\n" 988 "[ -r <server ip> [ -o <max hops> ] ] relay packets to server, " 989 "optionally set the hop count (default is 4 hops)\n" 990 "[ -v ] verbose mode, extra information\n" 991 ); 992 exit(1); 993} 994 995static void 996S_add_ip_change_notifications(); 997 998int 999main(int argc, char * argv[]) 1000{ 1001 int ch; 1002 boolean_t ip_change_notifications = TRUE; 1003 int logopt = LOG_CONS; 1004 struct in_addr relay_ip = { 0 }; 1005 1006 debug = 0; /* no debugging ie. go into the background */ 1007 verbose = 0; /* don't print extra information */ 1008 1009 ptrlist_init(&S_if_list); 1010 1011 S_get_interfaces(); 1012 1013 while ((ch = getopt(argc, argv, "aBbc:DdhHi:I" 1014#if !TARGET_OS_EMBEDDED 1015 "mN" 1016#endif /* !TARGET_OS_EMBEDDED */ 1017 "o:Pp:qr:St:v")) != EOF) { 1018 switch ((char)ch) { 1019 case 'a': 1020 /* was: enable anonymous binding for BOOTP clients */ 1021 break; 1022 case 'B': 1023 break; 1024 case 'S': 1025 S_do_bootp = TRUE; 1026 break; 1027 case 'b': 1028 S_bootfile_noexist_reply = FALSE; 1029 /* reply only if bootfile exists */ 1030 break; 1031 case 'c': /* was: cache check interval - seconds */ 1032 break; 1033 case 'D': /* answer DHCP requests as a DHCP server */ 1034 S_do_dhcp = TRUE; 1035 break; 1036 case 'd': /* stay in the foreground, extra printf's */ 1037 debug = 1; 1038 break; 1039 case 'h': 1040 case 'H': 1041 usage(); 1042 exit(1); 1043 break; 1044 case 'I': 1045 ip_change_notifications = FALSE; 1046 break; 1047 case 'i': /* user specified interface(s) to use */ 1048 if (S_string_in_list(&S_if_list, optarg) == FALSE) { 1049 ptrlist_add(&S_if_list, optarg); 1050 } 1051 else { 1052 my_log(LOG_INFO, "interface %s already specified", 1053 optarg); 1054 } 1055 break; 1056#if !TARGET_OS_EMBEDDED 1057 case 'm': 1058 S_do_old_netboot = TRUE; 1059 S_do_dhcp = TRUE; 1060 break; 1061 case 'N': 1062 S_do_netboot = TRUE; 1063 break; 1064#endif /* !TARGET_OS_EMBEDDED */ 1065 case 'o': { 1066 int h; 1067 h = atoi(optarg); 1068 if (h > 16 || h < 1) { 1069 printf("max hops value %s must be in the range 1..16\n", 1070 optarg); 1071 exit(1); 1072 } 1073 S_max_hops = h; 1074 break; 1075 } 1076 case 'P': 1077 S_persist = 1; 1078 break; 1079 case 'p': 1080 server_priority = strtoul(optarg, NULL, 0); 1081 printf("Priority set to %d\n", server_priority); 1082 break; 1083 case 'q': 1084 quiet = 1; 1085 break; 1086 case 'r': 1087 S_do_relay = 1; 1088 if (S_str_to_ip(optarg, &relay_ip) == FALSE) { 1089 printf("Invalid relay server ip address %s\n", optarg); 1090 exit(1); 1091 } 1092 if (ifl_find_ip(S_interfaces, relay_ip) != NULL) { 1093 printf("Relay server ip address %s specifies this host\n", 1094 optarg); 1095 exit(1); 1096 } 1097 S_relay_ip_list_add(relay_ip); 1098 break; 1099 case 't': 1100 testing_control = optarg; 1101 break; 1102 case 'v': /* extra info to syslog */ 1103 verbose++; 1104 break; 1105 default: 1106 break; 1107 } 1108 } 1109 if (!issock(0)) { /* started by user */ 1110 struct sockaddr_in Sin = { sizeof(Sin), AF_INET }; 1111 int i; 1112 1113 if (!debug) 1114 background(); 1115 1116 if ((bootp_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 1117 my_log(LOG_INFO, "socket call failed"); 1118 exit(1); 1119 } 1120 Sin.sin_port = htons(S_ipport_server); 1121 Sin.sin_addr.s_addr = htonl(INADDR_ANY); 1122 i = 0; 1123 while (bind(bootp_socket, (struct sockaddr *)&Sin, sizeof(Sin)) < 0) { 1124 my_log(LOG_INFO, "bind call failed: %s", strerror(errno)); 1125 if (errno != EADDRINUSE) 1126 exit(1); 1127 i++; 1128 if (i == 10) { 1129 my_log(LOG_INFO, "exiting"); 1130 exit(1); 1131 } 1132 sleep(10); 1133 } 1134 } 1135 else { /* started by inetd */ 1136 bootp_socket = 0; 1137 gettimeofday(&S_lastmsgtime, 0); 1138 if (S_persist == 0) { 1139 signal(SIGALRM, on_alarm); 1140 alarm(15); 1141 } 1142 } 1143 1144 writepid(); 1145 1146 if (debug) 1147 logopt = LOG_PERROR; 1148 1149 (void) openlog("bootpd", logopt | LOG_PID, LOG_DAEMON); 1150 1151 SubnetListLogErrors(LOG_NOTICE); 1152 1153 my_log(LOG_DEBUG, "server starting"); 1154 1155 { 1156 int opt = 1; 1157 1158#if defined(IP_RECVIF) 1159 if (setsockopt(bootp_socket, IPPROTO_IP, IP_RECVIF, (caddr_t)&opt, 1160 sizeof(opt)) < 0) { 1161 my_log(LOG_INFO, "setsockopt(IP_RECVIF) failed: %s", 1162 strerror(errno)); 1163 exit(1); 1164 } 1165#endif 1166 1167 if (setsockopt(bootp_socket, SOL_SOCKET, SO_BROADCAST, (caddr_t)&opt, 1168 sizeof(opt)) < 0) { 1169 my_log(LOG_INFO, "setsockopt(SO_BROADCAST) failed"); 1170 exit(1); 1171 } 1172 if (setsockopt(bootp_socket, IPPROTO_IP, IP_RECVDSTADDR, (caddr_t)&opt, 1173 sizeof(opt)) < 0) { 1174 my_log(LOG_INFO, "setsockopt(IPPROTO_IP, IP_RECVDSTADDR) failed"); 1175 exit(1); 1176 } 1177 if (setsockopt(bootp_socket, SOL_SOCKET, SO_REUSEADDR, (caddr_t)&opt, 1178 sizeof(opt)) < 0) { 1179 my_log(LOG_INFO, "setsockopt(SO_REUSEADDR) failed"); 1180 exit(1); 1181 } 1182 } 1183 1184 /* install our sighup handler */ 1185 signal(SIGHUP, on_sighup); 1186 1187 if (ip_change_notifications) { 1188 S_add_ip_change_notifications(); 1189 } 1190 S_server_loop(); 1191 exit (0); 1192} 1193 1194/* 1195 * Function: subnetAddressAndMask 1196 * 1197 * Purpose: 1198 * Given the gateway address field from the request and the 1199 * interface the packet was received on, determine the subnet 1200 * address and mask. 1201 * Note: 1202 * This currently does not support "super-netting", in which 1203 * more than one proper subnet shares the same physical subnet. 1204 */ 1205boolean_t 1206subnetAddressAndMask(struct in_addr giaddr, interface_t * if_p, 1207 struct in_addr * addr, struct in_addr * mask) 1208{ 1209 /* gateway specified, find a subnet description on the same subnet */ 1210 if (giaddr.s_addr) { 1211 SubnetRef subnet; 1212 1213 /* find a subnet entry on the same subnet as the gateway */ 1214 if (subnets == NULL) { 1215 return (FALSE); 1216 } 1217 subnet = SubnetListGetSubnetForAddress(subnets, giaddr, FALSE); 1218 if (subnet == NULL) { 1219 return (FALSE); 1220 } 1221 *addr = giaddr; 1222 *mask = SubnetGetMask(subnet); 1223 } 1224 else { 1225 *addr = if_inet_netaddr(if_p); 1226 *mask = if_inet_netmask(if_p); 1227 } 1228 return (TRUE); 1229} 1230 1231/* 1232 * Function: issock 1233 * 1234 * Purpose: 1235 * Determine if a descriptor belongs to a socket or not 1236 */ 1237static int 1238issock(fd) 1239 int fd; 1240{ 1241 struct stat st; 1242 1243 if (fstat(fd, &st) < 0) { 1244 return (0); 1245 } 1246 /* 1247 * SunOS returns S_IFIFO for sockets, while 4.3 returns 0 and 1248 * does not even have an S_IFIFO mode. Since there is confusion 1249 * about what the mode is, we check for what it is not instead of 1250 * what it is. 1251 */ 1252 switch (st.st_mode & S_IFMT) { 1253 case S_IFCHR: 1254 case S_IFREG: 1255 case S_IFLNK: 1256 case S_IFDIR: 1257 case S_IFBLK: 1258 return (0); 1259 default: 1260 return (1); 1261 } 1262} 1263 1264 1265/* 1266 * Function: on_sighup 1267 * 1268 * Purpose: 1269 * If we get a sighup, re-read the subnet descriptions. 1270 */ 1271static void 1272on_sighup(int sigraised) 1273{ 1274 if (sigraised == SIGHUP) 1275 S_sighup = TRUE; 1276 return; 1277} 1278 1279/* 1280 * Function: on_alarm 1281 * 1282 * Purpose: 1283 * If we were started by inetd, we kill ourselves during periods of 1284 * inactivity. If we've been idle for MAXIDLE, exit. 1285 */ 1286static void 1287on_alarm(int sigraised) 1288{ 1289 struct timeval tv; 1290 1291 gettimeofday(&tv, 0); 1292 1293 if ((tv.tv_sec - S_lastmsgtime.tv_sec) >= MAXIDLE) 1294 exit(0); 1295 alarm(15); 1296 return; 1297} 1298 1299/* 1300 * Function: bootp_add_bootfile 1301 * 1302 * Purpose: 1303 * Verify that the specified bootfile exists, and add it to the given 1304 * packet. Handle <bootfile>.<hostname> to allow a specific host to 1305 * get its own version of the bootfile. 1306 */ 1307boolean_t 1308bootp_add_bootfile(const char * request_file, const char * hostname, 1309 const char * bootfile, 1310 char * reply_file, int reply_file_size) 1311{ 1312 boolean_t dothost = FALSE; /* file.host was found */ 1313 char file[PATH_MAX]; 1314 int len; 1315 char path[PATH_MAX]; 1316 1317 if (request_file && request_file[0]) 1318 strcpy(file, request_file); 1319 else if (bootfile && bootfile[0]) 1320 strcpy(file, bootfile); 1321 else { 1322 my_log(LOG_DEBUG, "no replyfile", path); 1323 return (TRUE); 1324 } 1325 1326 if (file[0] == '/') /* if absolute pathname */ 1327 strcpy(path, file); 1328 else { 1329 strcpy(path, boot_tftp_dir); 1330 strcat(path, "/"); 1331 strcat(path, file); 1332 } 1333 1334 /* see if file exists with a ".host" suffix */ 1335 if (hostname) { 1336 int n; 1337 1338 n = strlen(path); 1339 strcat(path, "."); 1340 strcat(path, hostname); 1341 if (access(path, R_OK) >= 0) 1342 dothost = TRUE; 1343 else 1344 path[n] = 0; /* try it without the suffix */ 1345 } 1346 1347 if (dothost == FALSE) { 1348 if (access(path, R_OK) < 0) { 1349 if (S_bootfile_noexist_reply == FALSE) { 1350 my_log(LOG_INFO, 1351 "boot file %s* missing - not replying", path); 1352 return (FALSE); 1353 } 1354 my_log(LOG_DEBUG, "boot file %s* missing", path); 1355 } 1356 } 1357 len = strlen(path); 1358 if (len >= reply_file_size) { 1359 my_log(LOG_DEBUG, "boot file name too long %d >= %d", 1360 len, reply_file_size); 1361 return (TRUE); 1362 } 1363 my_log(LOG_DEBUG, "replyfile %s", path); 1364 strcpy(reply_file, path); 1365 return (TRUE); 1366} 1367 1368#define NIPROP_IP_ADDRESS "ip_address" 1369 1370/* 1371 * Function: ip_address_reachable 1372 * 1373 * Purpose: 1374 * Determine whether the given ip address is directly reachable from 1375 * the given interface or gateway. 1376 * 1377 * Directly reachable means without using a router ie. share the same wire. 1378 */ 1379boolean_t 1380ip_address_reachable(struct in_addr ip, struct in_addr giaddr, 1381 interface_t * if_p) 1382{ 1383 int i; 1384 1385 if (giaddr.s_addr) { /* gateway'd */ 1386 /* find a subnet entry on the same subnet as the gateway */ 1387 if (subnets == NULL) { 1388 return (FALSE); 1389 } 1390 return (SubnetListAreAddressesOnSameSupernet(subnets, ip, giaddr)); 1391 } 1392 1393 for (i = 0; i < S_inetroutes->count; i++) { 1394 inetroute_t * inr_p = S_inetroutes->list + i; 1395 1396 if (inr_p->mask.s_addr != 0 1397 && inr_p->gateway.link.sdl_family == AF_LINK 1398 && (ifl_find_link(S_interfaces, inr_p->gateway.link.sdl_index) 1399 == if_p)) { 1400 /* reachable? */ 1401 if (in_subnet(inr_p->dest, inr_p->mask, ip)) 1402 return (TRUE); 1403 } 1404 } 1405 return (FALSE); 1406} 1407 1408boolean_t 1409subnet_match(void * arg, struct in_addr iaddr) 1410{ 1411 subnet_match_args_t * s = (subnet_match_args_t *)arg; 1412 1413 if (iaddr.s_addr == 0) { 1414 /* make sure we never vend 0.0.0.0 */ 1415 return (FALSE); 1416 } 1417 /* the binding may be invalid for this subnet, but it has one */ 1418 s->has_binding = TRUE; 1419 if (iaddr.s_addr == s->ciaddr.s_addr 1420 || ip_address_reachable(iaddr, s->giaddr, s->if_p)) { 1421 return (TRUE); 1422 } 1423 return (FALSE); 1424} 1425 1426/* 1427 * Function: bootp_request 1428 * 1429 * Purpose: 1430 * Process BOOTREQUEST packet. 1431 * 1432 */ 1433static void 1434bootp_request(request_t * request) 1435{ 1436 char * bootfile = NULL; 1437 char * hostname = NULL; 1438 struct in_addr iaddr; 1439 struct bootp rp; 1440 struct bootp * rq = (struct bootp *)request->pkt; 1441 u_int16_t secs; 1442 1443 if (request->pkt_length < sizeof(struct bootp)) 1444 return; 1445 1446 secs = (u_int16_t)ntohs(rq->bp_secs); 1447 if (secs < reply_threshold_seconds) { 1448 if (debug) { 1449 printf("rq->bp_secs %d < threshold %d\n", 1450 secs, reply_threshold_seconds); 1451 } 1452 return; 1453 } 1454 1455 rp = *rq; /* copy request into reply */ 1456 rp.bp_op = BOOTREPLY; 1457 1458 if (rq->bp_ciaddr.s_addr == 0) { /* client doesn't specify ip */ 1459 subnet_match_args_t match; 1460 1461 bzero(&match, sizeof(match)); 1462 match.if_p = request->if_p; 1463 match.giaddr = rq->bp_giaddr; 1464 if (bootp_getbyhw_file(rq->bp_htype, rq->bp_chaddr, rq->bp_hlen, 1465 subnet_match, &match, &iaddr, 1466 &hostname, &bootfile) == FALSE) { 1467#if !TARGET_OS_EMBEDDED 1468 if (use_open_directory == FALSE 1469 || bootp_getbyhw_ds(rq->bp_htype, rq->bp_chaddr, rq->bp_hlen, 1470 subnet_match, &match, &iaddr, 1471 &hostname, &bootfile) == FALSE) { 1472 return; 1473 } 1474#else /* TARGET_OS_EMBEDDED */ 1475 return; 1476#endif /* TARGET_OS_EMBEDDED */ 1477 } 1478 rp.bp_yiaddr = iaddr; 1479 } 1480 else { /* client specified ip address */ 1481 iaddr = rq->bp_ciaddr; 1482 if (bootp_getbyip_file(iaddr, &hostname, &bootfile) == FALSE) { 1483#if !TARGET_OS_EMBEDDED 1484 if (use_open_directory == FALSE 1485 || bootp_getbyip_ds(iaddr, &hostname, &bootfile) == FALSE) { 1486 return; 1487 } 1488#else /* TARGET_OS_EMBEDDED */ 1489 return; 1490#endif /* TARGET_OS_EMBEDDED */ 1491 } 1492 } 1493 rq->bp_file[sizeof(rq->bp_file) - 1] = '\0'; 1494 my_log(LOG_INFO,"BOOTP request [%s]: %s requested file '%s'", 1495 if_name(request->if_p), 1496 hostname ? hostname : inet_ntoa(iaddr), 1497 rq->bp_file); 1498 if (bootp_add_bootfile((const char *)rq->bp_file, hostname, bootfile, 1499 (char *)rp.bp_file, 1500 sizeof(rp.bp_file)) == FALSE) 1501 /* client specified a bootfile but it did not exist */ 1502 goto no_reply; 1503 1504 if (bcmp(rq->bp_vend, rfc_magic, sizeof(rfc_magic)) == 0) { 1505 /* insert the usual set of options/extensions if possible */ 1506 dhcpoa_t options; 1507 1508 dhcpoa_init(&options, rp.bp_vend + sizeof(rfc_magic), 1509 sizeof(rp.bp_vend) - sizeof(rfc_magic)); 1510 1511 add_subnet_options(hostname, iaddr, 1512 request->if_p, &options, NULL, 0); 1513 my_log(LOG_DEBUG, "added vendor extensions"); 1514 if (dhcpoa_add(&options, dhcptag_end_e, 0, NULL) 1515 != dhcpoa_success_e) { 1516 my_log(LOG_INFO, "couldn't add end tag"); 1517 } 1518 else 1519 bcopy(rfc_magic, rp.bp_vend, sizeof(rfc_magic)); 1520 } /* if RFC magic number */ 1521 1522 rp.bp_siaddr = if_inet_addr(request->if_p); 1523 strcpy((char *)rp.bp_sname, server_name); 1524 if (sendreply(request->if_p, &rp, sizeof(rp), FALSE, NULL)) { 1525 my_log(LOG_INFO, "reply sent %s %s pktsize %d", 1526 hostname, inet_ntoa(iaddr), sizeof(rp)); 1527 } 1528 1529 no_reply: 1530 if (hostname != NULL) 1531 free(hostname); 1532 if (bootfile != NULL) 1533 free(bootfile); 1534 return; 1535} 1536 1537 1538/* 1539 * Function: sendreply 1540 * 1541 * Purpose: 1542 * Send a reply packet to the client. 1543 */ 1544boolean_t 1545sendreply(interface_t * if_p, struct bootp * bp, int n, 1546 boolean_t broadcast, struct in_addr * dest_p) 1547{ 1548 struct in_addr dst; 1549 u_short dest_port = S_ipport_client; 1550 void * hwaddr = NULL; 1551 u_short src_port = S_ipport_server; 1552 1553 /* 1554 * If the client IP address is specified, use that 1555 * else if gateway IP address is specified, use that 1556 * else make a temporary arp cache entry for the client's NEW 1557 * IP/hardware address and use that. 1558 */ 1559 if (bp->bp_ciaddr.s_addr) { 1560 dst = bp->bp_ciaddr; 1561 my_log(LOG_DEBUG, "reply ciaddr %s", inet_ntoa(dst)); 1562 } 1563 else if (bp->bp_giaddr.s_addr) { 1564 dst = bp->bp_giaddr; 1565 dest_port = S_ipport_server; 1566 src_port = S_ipport_client; 1567 my_log(LOG_DEBUG, "reply giaddr %s", inet_ntoa(dst)); 1568 if (broadcast) /* tell the gateway to broadcast */ 1569 bp->bp_unused = htons(ntohs(bp->bp_unused | DHCP_FLAGS_BROADCAST)); 1570 } 1571 else { /* local net request */ 1572 if (broadcast || (ntohs(bp->bp_unused) & DHCP_FLAGS_BROADCAST)) { 1573 my_log(LOG_DEBUG, "replying using broadcast IP address"); 1574 dst.s_addr = htonl(INADDR_BROADCAST); 1575 } 1576 else { 1577 if (dest_p) 1578 dst = *dest_p; 1579 else 1580 dst = bp->bp_yiaddr; 1581 hwaddr = bp->bp_chaddr; 1582 } 1583 my_log(LOG_DEBUG, "replying to %s", inet_ntoa(dst)); 1584 } 1585 if (bootp_transmit(bootp_socket, transmit_buffer, if_name(if_p), 1586 if_link_arptype(if_p), 1587 hwaddr, 1588 bp->bp_hlen, 1589 dst, if_inet_addr(if_p), 1590 dest_port, src_port, 1591 bp, n) < 0) { 1592 my_log(LOG_INFO, "transmit failed, %m"); 1593 return (FALSE); 1594 } 1595 if (debug && verbose) { 1596 printf("\n=================== Server Reply ====" 1597 "=================\n"); 1598 dhcp_packet_print((struct dhcp *)bp, n); 1599 } 1600 return (TRUE); 1601} 1602 1603/* 1604 * Function: add_subnet_options 1605 * 1606 * Purpose: 1607 * Given a list of tags, retrieve them from the subnet entry and 1608 * insert them into the message options. 1609 */ 1610int 1611add_subnet_options(char * hostname, 1612 struct in_addr iaddr, interface_t * if_p, 1613 dhcpoa_t * options, const uint8_t * tags, int n) 1614{ 1615 inet_addrinfo_t * info = if_inet_addr_at(if_p, 0); 1616 static const uint8_t default_tags[] = { 1617 dhcptag_subnet_mask_e, 1618 dhcptag_router_e, 1619 dhcptag_domain_name_server_e, 1620 dhcptag_domain_name_e, 1621 dhcptag_host_name_e, 1622 }; 1623#define N_DEFAULT_TAGS (sizeof(default_tags) / sizeof(default_tags[0])) 1624 int number_before = dhcpoa_count(options); 1625 int i; 1626 SubnetRef subnet = NULL; 1627 1628 if (subnets != NULL) { 1629 /* try to find exact match */ 1630 subnet = SubnetListGetSubnetForAddress(subnets, iaddr, TRUE); 1631 if (subnet == NULL) { 1632 /* settle for inexact match */ 1633 subnet = SubnetListGetSubnetForAddress(subnets, iaddr, FALSE); 1634 } 1635 } 1636 if (tags == NULL) { 1637 tags = default_tags; 1638 n = N_DEFAULT_TAGS; 1639 } 1640 1641 for (i = 0; i < n; i++ ) { 1642 bool handled = FALSE; 1643 1644 switch (tags[i]) { 1645 case dhcptag_end_e: 1646 case dhcptag_pad_e: 1647 case dhcptag_requested_ip_address_e: 1648 case dhcptag_lease_time_e: 1649 case dhcptag_option_overload_e: 1650 case dhcptag_dhcp_message_type_e: 1651 case dhcptag_server_identifier_e: 1652 case dhcptag_parameter_request_list_e: 1653 case dhcptag_message_e: 1654 case dhcptag_max_dhcp_message_size_e: 1655 case dhcptag_renewal_t1_time_value_e: 1656 case dhcptag_rebinding_t2_time_value_e: 1657 case dhcptag_client_identifier_e: 1658 continue; /* ignore these */ 1659 default: 1660 break; 1661 } 1662 if (tags[i] == dhcptag_host_name_e) { 1663 if (hostname) { 1664 if (dhcpoa_add(options, dhcptag_host_name_e, 1665 strlen(hostname), hostname) 1666 != dhcpoa_success_e) { 1667 my_log(LOG_INFO, "couldn't add hostname: %s", 1668 dhcpoa_err(options)); 1669 } 1670 } 1671 handled = TRUE; 1672 } 1673 else if (subnet != NULL) { 1674 const char * opt; 1675 int opt_length; 1676 1677 opt = SubnetGetOptionPtrAndLength(subnet, tags[i], &opt_length); 1678 if (opt != NULL) { 1679 handled = TRUE; 1680 if (dhcpoa_add(options, tags[i], opt_length, opt) 1681 != dhcpoa_success_e) { 1682 my_log(LOG_INFO, "couldn't add option %d: %s", 1683 tags[i], dhcpoa_err(options)); 1684 } 1685 } 1686 } 1687 if (handled == FALSE && S_use_server_config_for_dhcp_options) { 1688 /* try to use defaults if no explicit configuration */ 1689 struct in_addr * def_route; 1690 1691 switch (tags[i]) { 1692 case dhcptag_subnet_mask_e: { 1693 if (ifl_find_subnet(S_interfaces, iaddr) != if_p) 1694 continue; 1695 if (dhcpoa_add(options, dhcptag_subnet_mask_e, 1696 sizeof(info->mask), &info->mask) 1697 != dhcpoa_success_e) { 1698 my_log(LOG_INFO, "couldn't add subnet_mask: %s", 1699 dhcpoa_err(options)); 1700 continue; 1701 } 1702 my_log(LOG_DEBUG, "subnet mask %s derived from %s", 1703 inet_ntoa(info->mask), if_name(if_p)); 1704 break; 1705 } 1706 case dhcptag_router_e: 1707 def_route = inetroute_default(S_inetroutes); 1708 if (def_route == NULL 1709 || in_subnet(info->netaddr, info->mask, 1710 *def_route) == FALSE 1711 || in_subnet(info->netaddr, info->mask, 1712 iaddr) == FALSE) 1713 /* don't respond if default route not on same subnet */ 1714 continue; 1715 if (dhcpoa_add(options, dhcptag_router_e, sizeof(*def_route), 1716 def_route) != dhcpoa_success_e) { 1717 my_log(LOG_INFO, "couldn't add router: %s", 1718 dhcpoa_err(options)); 1719 continue; 1720 } 1721 my_log(LOG_DEBUG, "default route added as router"); 1722 break; 1723 case dhcptag_domain_name_server_e: 1724 if (S_dns_servers_count == 0) 1725 continue; 1726 if (dhcpoa_add(options, dhcptag_domain_name_server_e, 1727 S_dns_servers_count * sizeof(*S_dns_servers), 1728 S_dns_servers) != dhcpoa_success_e) { 1729 my_log(LOG_INFO, "couldn't add dns servers: %s", 1730 dhcpoa_err(options)); 1731 continue; 1732 } 1733 if (verbose) 1734 my_log(LOG_DEBUG, "default dns servers added"); 1735 break; 1736 case dhcptag_domain_name_e: 1737 if (S_domain_name) { 1738 if (dhcpoa_add(options, dhcptag_domain_name_e, 1739 strlen(S_domain_name), S_domain_name) 1740 != dhcpoa_success_e) { 1741 my_log(LOG_INFO, "couldn't add domain name: %s", 1742 dhcpoa_err(options)); 1743 continue; 1744 } 1745 if (verbose) 1746 my_log(LOG_DEBUG, "default domain name added"); 1747 } 1748 break; 1749 case dhcptag_domain_search_e: 1750 if (S_domain_search) { 1751 if (dhcpoa_add(options, dhcptag_domain_search_e, 1752 S_domain_search_size, S_domain_search) 1753 != dhcpoa_success_e) { 1754 my_log(LOG_INFO, "couldn't add domain search: %s", 1755 dhcpoa_err(options)); 1756 continue; 1757 } 1758 if (verbose) 1759 my_log(LOG_DEBUG, "domain search added"); 1760 } 1761 break; 1762 default: 1763 break; 1764 } 1765 } 1766 } 1767 return (dhcpoa_count(options) - number_before); 1768} 1769 1770/** 1771 ** Server Main Loop 1772 **/ 1773static char control[512]; 1774static struct iovec iov; 1775static struct msghdr msg; 1776 1777static void 1778S_init_msg() 1779{ 1780 msg.msg_name = 0; 1781 msg.msg_namelen = 0; 1782 msg.msg_iov = &iov; 1783 msg.msg_iovlen = 1; 1784 msg.msg_control = control; 1785 msg.msg_controllen = sizeof(control); 1786 msg.msg_flags = 0; 1787 iov.iov_base = (caddr_t)S_rxpkt; 1788 iov.iov_len = sizeof(S_rxpkt); 1789 return; 1790} 1791 1792static void 1793S_relay_packet(struct bootp * bp, int n, interface_t * if_p) 1794{ 1795 boolean_t clear_giaddr = FALSE; 1796 int i; 1797 boolean_t printed = FALSE; 1798 u_int16_t secs; 1799 1800 if (n < sizeof(struct bootp)) 1801 return; 1802 1803 switch (bp->bp_op) { 1804 case BOOTREQUEST: 1805 if (bp->bp_hops >= S_max_hops) 1806 return; 1807 secs = (u_int16_t)ntohs(bp->bp_secs); 1808 if (secs < reply_threshold_seconds) { 1809 /* don't bother yet */ 1810 break; 1811 } 1812 if (bp->bp_giaddr.s_addr == 0) { 1813 /* fill it in with our interface address */ 1814 bp->bp_giaddr = if_inet_addr(if_p); 1815 clear_giaddr = TRUE; 1816 } 1817 bp->bp_hops++; 1818 for (i = 0; i < S_relay_ip_list_count; i++) { 1819 struct in_addr relay = S_relay_ip_list[i]; 1820 if (relay.s_addr == if_inet_broadcast(if_p).s_addr) { 1821 continue; /* don't rebroadcast */ 1822 } 1823 if (debug && verbose && printed == FALSE) { 1824 printed = TRUE; 1825 printf("\n=================== Relayed Request ====" 1826 "=================\n"); 1827 dhcp_packet_print((struct dhcp *)bp, n); 1828 } 1829 1830 if (bootp_transmit(bootp_socket, transmit_buffer, if_name(if_p), 1831 bp->bp_htype, NULL, 0, 1832 relay, if_inet_addr(if_p), 1833 S_ipport_server, S_ipport_client, 1834 bp, n) < 0) { 1835 my_log(LOG_INFO, "send to %s failed, %m", inet_ntoa(relay)); 1836 } 1837 else { 1838 my_log(LOG_INFO, 1839 "Relayed Request [%s] to %s", if_name(if_p), 1840 inet_ntoa(relay)); 1841 } 1842 } 1843 if (clear_giaddr) { 1844 bp->bp_giaddr.s_addr = 0; 1845 } 1846 bp->bp_hops--; 1847 break; 1848 case BOOTREPLY: { 1849 interface_t * if_p; 1850 struct in_addr dst; 1851 1852 if (bp->bp_giaddr.s_addr == 0) { 1853 break; 1854 } 1855 if_p = ifl_find_ip(S_interfaces, bp->bp_giaddr); 1856 if (if_p == NULL) { /* we aren't the gateway - discard */ 1857 break; 1858 } 1859 1860 if ((ntohs(bp->bp_unused) & DHCP_FLAGS_BROADCAST)) { 1861 my_log(LOG_DEBUG, "replying using broadcast IP address"); 1862 dst.s_addr = htonl(INADDR_BROADCAST); 1863 } 1864 else { 1865 dst = bp->bp_yiaddr; 1866 } 1867 if (debug && verbose) { 1868 if (debug) { 1869 printf("\n=================== Relayed Reply ====" 1870 "=================\n"); 1871 dhcp_packet_print((struct dhcp *)bp, n); 1872 } 1873 } 1874 if (bootp_transmit(bootp_socket, transmit_buffer, if_name(if_p), 1875 bp->bp_htype, bp->bp_chaddr, bp->bp_hlen, 1876 dst, if_inet_addr(if_p), 1877 S_ipport_client, S_ipport_server, 1878 bp, n) < 0) { 1879 my_log(LOG_INFO, "send %s failed, %m", inet_ntoa(dst)); 1880 } 1881 else { 1882 my_log(LOG_INFO, 1883 "Relayed Response [%s] to %s", if_name(if_p), 1884 inet_ntoa(dst)); 1885 } 1886 break; 1887 } 1888 1889 default: 1890 break; 1891 } 1892 return; 1893} 1894 1895static void 1896S_dispatch_packet(struct bootp * bp, int n, interface_t * if_p, 1897 struct in_addr * dstaddr_p) 1898{ 1899#if !TARGET_OS_EMBEDDED 1900 boolean_t bsdp_pkt = FALSE; 1901#endif /* !TARGET_OS_EMBEDDED */ 1902 boolean_t dhcp_pkt = FALSE; 1903 dhcp_msgtype_t dhcp_msgtype = dhcp_msgtype_none_e; 1904 1905 switch (bp->bp_op) { 1906 case BOOTREQUEST: { 1907 boolean_t handled = FALSE; 1908 dhcpol_t options; 1909 request_t request; 1910 1911 request.if_p = if_p; 1912 request.pkt = (struct dhcp *)bp; 1913 request.pkt_length = n; 1914 request.options_p = NULL; 1915 request.dstaddr_p = dstaddr_p; 1916 request.time_in_p = &S_lastmsgtime; 1917 1918 dhcpol_init(&options); 1919 1920 /* get the packet options, check for dhcp */ 1921 if (dhcpol_parse_packet(&options, (struct dhcp *)bp, n, NULL)) { 1922 request.options_p = &options; 1923 dhcp_pkt = is_dhcp_packet(&options, &dhcp_msgtype); 1924 } 1925 1926 if (debug && verbose) { 1927 printf("\n---------------- Client Request --------------------\n"); 1928 dhcp_packet_print((struct dhcp *)bp, n); 1929 } 1930 1931 if (bp->bp_sname[0] != '\0' 1932 && strcmp((char *)bp->bp_sname, server_name) != 0) 1933 goto request_done; 1934 1935 if (bp->bp_siaddr.s_addr != 0 1936 && ntohl(bp->bp_siaddr.s_addr) != ntohl(if_inet_addr(if_p).s_addr)) 1937 goto request_done; 1938 1939 if (dhcp_pkt) { /* this is a DHCP packet */ 1940#if !TARGET_OS_EMBEDDED 1941 if (netboot_enabled(if_p) || old_netboot_enabled(if_p)) { 1942 char arch[256]; 1943 bsdp_version_t client_version; 1944 boolean_t is_old_netboot = FALSE; 1945 char sysid[256]; 1946 dhcpol_t rq_vsopt; /* is_bsdp_packet() initializes */ 1947 1948 bsdp_pkt = is_bsdp_packet(request.options_p, arch, sysid, 1949 &rq_vsopt, &client_version, 1950 &is_old_netboot); 1951 if (bsdp_pkt) { 1952 if (is_old_netboot == TRUE 1953 && old_netboot_enabled(if_p) == FALSE) { 1954 /* ignore it */ 1955 } 1956 else { 1957 bsdp_request(&request, dhcp_msgtype, 1958 arch, sysid, &rq_vsopt, client_version, 1959 is_old_netboot); 1960 } 1961 } 1962 else { 1963 bsdp_dhcp_request(&request, dhcp_msgtype); 1964 } 1965 dhcpol_free(&rq_vsopt); 1966 } 1967#endif /* !TARGET_OS_EMBEDDED */ 1968 if (dhcp_enabled(if_p) 1969#if !TARGET_OS_EMBEDDED 1970 || old_netboot_enabled(if_p) 1971#endif /* !TARGET_OS_EMBEDDED */ 1972 ) { 1973 handled = TRUE; 1974 dhcp_request(&request, dhcp_msgtype, dhcp_enabled(if_p)); 1975 } 1976 } 1977#if !TARGET_OS_EMBEDDED 1978 if (handled == FALSE && old_netboot_enabled(if_p)) { 1979 handled = old_netboot_request(&request); 1980 } 1981#endif /* !TARGET_OS_EMBEDDED */ 1982 if (handled == FALSE && bootp_enabled(if_p)) { 1983 bootp_request(&request); 1984 } 1985 request_done: 1986 dhcpol_free(&options); 1987 break; 1988 } 1989 1990 case BOOTREPLY: 1991 break; 1992 1993 default: 1994 break; 1995 } 1996 1997 if (S_relay_ip_list != NULL && relay_enabled(if_p)) { 1998 /* ALIGN: S_rxpkt is aligned to uint32, cast safe */ 1999 S_relay_packet((struct bootp *)(void *)S_rxpkt, n, if_p); 2000 } 2001 2002 if (verbose) { 2003 struct timeval now; 2004 struct timeval result; 2005 2006 gettimeofday(&now, 0); 2007 timeval_subtract(now, S_lastmsgtime, &result); 2008 my_log(LOG_INFO, "service time %d.%06d seconds", 2009 result.tv_sec, result.tv_usec); 2010 } 2011 return; 2012} 2013 2014static void * 2015S_parse_control(int level, int type, int * len) 2016{ 2017 struct cmsghdr * cmsg; 2018 2019 *len = 0; 2020 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 2021 if (cmsg->cmsg_level == level 2022 && cmsg->cmsg_type == type) { 2023 if (cmsg->cmsg_len < sizeof(*cmsg)) 2024 return (NULL); 2025 *len = cmsg->cmsg_len - sizeof(*cmsg); 2026 return (CMSG_DATA(cmsg)); 2027 } 2028 } 2029 return (NULL); 2030} 2031 2032#if defined(IP_RECVIF) 2033static interface_t * 2034S_which_interface() 2035{ 2036 struct sockaddr_dl *dl_p; 2037 char ifname[IFNAMSIZ + 1]; 2038 interface_t * if_p = NULL; 2039 int len = 0; 2040 2041 dl_p = (struct sockaddr_dl *)S_parse_control(IPPROTO_IP, IP_RECVIF, &len); 2042 if (dl_p == NULL || len == 0 || dl_p->sdl_nlen >= sizeof(ifname)) { 2043 return (NULL); 2044 } 2045 2046 bcopy(dl_p->sdl_data, ifname, dl_p->sdl_nlen); 2047 ifname[dl_p->sdl_nlen] = '\0'; 2048 if_p = ifl_find_name(S_interfaces, ifname); 2049 if (if_p == NULL) { 2050 if (verbose) 2051 my_log(LOG_DEBUG, "unknown interface %s", ifname); 2052 return (NULL); 2053 } 2054 if (if_inet_valid(if_p) == FALSE) 2055 return (NULL); 2056 if (ptrlist_count(&S_if_list) > 0 2057 && S_string_in_list(&S_if_list, ifname) == FALSE) { 2058 if (verbose) 2059 my_log(LOG_DEBUG, "ignoring request on %s", ifname); 2060 return (NULL); 2061 } 2062 return (if_p); 2063} 2064#endif 2065 2066static struct in_addr * 2067S_which_dstaddr() 2068{ 2069 void * data; 2070 int len = 0; 2071 2072 data = S_parse_control(IPPROTO_IP, IP_RECVDSTADDR, &len); 2073 if (data && len == sizeof(struct in_addr)) 2074 return ((struct in_addr *)data); 2075 return (NULL); 2076} 2077 2078/* 2079 * Function: S_server_loop 2080 * 2081 * Purpose: 2082 * This is the main loop that dispatches a request according to 2083 * whether it is BOOTP, DHCP, or NetBoot. 2084 */ 2085static void 2086S_server_loop() 2087{ 2088 struct in_addr * dstaddr_p = NULL; 2089 struct sockaddr_in from = { sizeof(from), AF_INET }; 2090 interface_t * if_p = NULL; 2091 int mask; 2092 int n; 2093 /* ALIGN: S_rxpkt is aligned to uint32, hence cast safe */ 2094 struct dhcp * request = (struct dhcp *)(void *)S_rxpkt; 2095 2096 for (;;) { 2097 S_init_msg(); 2098 msg.msg_name = (caddr_t)&from; 2099 msg.msg_namelen = sizeof(from); 2100 n = recvmsg(bootp_socket, &msg, 0); 2101 if (n < 0) { 2102 my_log(LOG_DEBUG, "recvmsg failed, %m"); 2103 errno = 0; 2104 continue; 2105 } 2106 if (S_sighup) { 2107 bootp_readtab(NULL); 2108 2109 if (gethostname(server_name, sizeof(server_name) - 1)) { 2110 server_name[0] = '\0'; 2111 my_log(LOG_INFO, "gethostname() failed, %m"); 2112 } 2113 else { 2114 my_log(LOG_INFO, "server name %s", server_name); 2115 } 2116 2117 S_get_interfaces(); 2118 S_log_interfaces(); 2119 S_get_network_routes(); 2120 S_update_services(); 2121 S_get_dns(); 2122 S_sighup = FALSE; 2123 } 2124 2125 if (n < sizeof(struct dhcp)) { 2126 continue; 2127 } 2128 if (request->dp_hlen > sizeof(request->dp_chaddr)) { 2129 continue; 2130 } 2131 if (S_ok_to_respond(request->dp_htype, request->dp_chaddr, 2132 request->dp_hlen) == FALSE) { 2133 continue; 2134 } 2135 dstaddr_p = S_which_dstaddr(); 2136 if (debug) { 2137 if (dstaddr_p == NULL) 2138 printf("no destination address\n"); 2139 else 2140 printf("destination address %s\n", inet_ntoa(*dstaddr_p)); 2141 } 2142 2143#if defined(IP_RECVIF) 2144 if_p = S_which_interface(); 2145 if (if_p == NULL) { 2146 continue; 2147 } 2148#else 2149 if_p = if_first_broadcast_inet(S_interfaces); 2150#endif 2151 2152 gettimeofday(&S_lastmsgtime, 0); 2153 mask = sigblock(sigmask(SIGALRM)); 2154 /* ALIGN: S_rxpkt is aligned, cast ok. */ 2155 S_dispatch_packet((struct bootp *)(void *)S_rxpkt, n, if_p, dstaddr_p); 2156 sigsetmask(mask); 2157 } 2158 return; 2159} 2160 2161#include <SystemConfiguration/SystemConfiguration.h> 2162#include <SystemConfiguration/SCDynamicStorePrivate.h> 2163static SCDynamicStoreRef store; 2164static void 2165S_add_ip_change_notifications() 2166{ 2167 CFStringRef key; 2168 CFMutableArrayRef patterns; 2169 2170 store = SCDynamicStoreCreate(NULL, 2171 CFSTR("com.apple.network.bootpd"), 2172 NULL, 2173 NULL); 2174 if (store == NULL) { 2175 return; 2176 } 2177 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, 2178 kSCDynamicStoreDomainState, 2179 kSCCompAnyRegex, 2180 kSCEntNetIPv4); 2181 patterns = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks); 2182 CFArrayAppendValue(patterns, key); 2183 CFRelease(key); 2184 SCDynamicStoreSetNotificationKeys(store, NULL, patterns); 2185 CFRelease(patterns); 2186 SCDynamicStoreNotifySignal(store, getpid(), SIGHUP); 2187 return; 2188} 2189