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