1/* dhcpd.c 2 3 DHCP Server Daemon. */ 4 5/* 6 * Copyright (c) 2004-2005 by Internet Systems Consortium, Inc. ("ISC") 7 * Copyright (c) 1996-2003 by Internet Software Consortium 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 * 21 * Internet Systems Consortium, Inc. 22 * 950 Charter Street 23 * Redwood City, CA 94063 24 * <info@isc.org> 25 * http://www.isc.org/ 26 * 27 * This software has been written for Internet Systems Consortium 28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. 29 * To learn more about Internet Systems Consortium, see 30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises, 31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see 32 * ``http://www.nominum.com''. 33 */ 34 35#ifndef lint 36static char ocopyright[] = 37"$Id: dhcpd.c,v 1.6 2005/08/11 17:13:30 drochner Exp $ Copyright 2004-2005 Internet Systems Consortium."; 38#endif 39 40 static char copyright[] = 41"Copyright 2004-2005 Internet Systems Consortium."; 42static char arr [] = "All rights reserved."; 43static char message [] = "Internet Systems Consortium DHCP Server"; 44static char url [] = "For info, please visit http://www.isc.org/sw/dhcp/"; 45 46#include "dhcpd.h" 47#include "version.h" 48#include <omapip/omapip_p.h> 49 50static void usage PROTO ((void)); 51 52struct iaddr server_identifier; 53int server_identifier_matched; 54 55#if defined (NSUPDATE) 56 57/* This stuff is always executed to figure the default values for certain 58 ddns variables. */ 59 60char std_nsupdate [] = " \n\ 61option server.ddns-hostname = \n\ 62 pick (option fqdn.hostname, option host-name); \n\ 63option server.ddns-domainname = config-option domain-name; \n\ 64option server.ddns-ttl = encode-int(lease-time / 2, 32); \n\ 65option server.ddns-rev-domainname = \"in-addr.arpa.\";"; 66 67/* This is the old-style name service updater that is executed 68 whenever a lease is committed. It does not follow the DHCP-DNS 69 draft at all. */ 70 71char old_nsupdate [] = " \n\ 72on commit { \n\ 73 if (not static and \n\ 74 ((config-option server.ddns-updates = null) or \n\ 75 (config-option server.ddns-updates != 0))) { \n\ 76 set new-ddns-fwd-name = \n\ 77 concat (pick (config-option server.ddns-hostname, \n\ 78 option host-name), \".\", \n\ 79 pick (config-option server.ddns-domainname, \n\ 80 config-option domain-name)); \n\ 81 if (defined (ddns-fwd-name) and ddns-fwd-name != new-ddns-fwd-name) { \n\ 82 switch (ns-update (delete (IN, A, ddns-fwd-name, leased-address))) { \n\ 83 case NOERROR: \n\ 84 unset ddns-fwd-name; \n\ 85 on expiry or release { \n\ 86 } \n\ 87 } \n\ 88 } \n\ 89 \n\ 90 if (not defined (ddns-fwd-name)) { \n\ 91 set ddns-fwd-name = new-ddns-fwd-name; \n\ 92 if defined (ddns-fwd-name) { \n\ 93 switch (ns-update (not exists (IN, A, ddns-fwd-name, null), \n\ 94 add (IN, A, ddns-fwd-name, leased-address, \n\ 95 lease-time / 2))) { \n\ 96 default: \n\ 97 unset ddns-fwd-name; \n\ 98 break; \n\ 99 \n\ 100 case NOERROR: \n\ 101 set ddns-rev-name = \n\ 102 concat (binary-to-ascii (10, 8, \".\", \n\ 103 reverse (1, \n\ 104 leased-address)), \".\", \n\ 105 pick (config-option server.ddns-rev-domainname, \n\ 106 \"in-addr.arpa.\")); \n\ 107 switch (ns-update (delete (IN, PTR, ddns-rev-name, null), \n\ 108 add (IN, PTR, ddns-rev-name, ddns-fwd-name, \n\ 109 lease-time / 2))) \n\ 110 { \n\ 111 default: \n\ 112 unset ddns-rev-name; \n\ 113 on release or expiry { \n\ 114 switch (ns-update (delete (IN, A, ddns-fwd-name, \n\ 115 leased-address))) { \n\ 116 case NOERROR: \n\ 117 unset ddns-fwd-name; \n\ 118 break; \n\ 119 } \n\ 120 on release or expiry; \n\ 121 } \n\ 122 break; \n\ 123 \n\ 124 case NOERROR: \n\ 125 on release or expiry { \n\ 126 switch (ns-update (delete (IN, PTR, ddns-rev-name, null))) {\n\ 127 case NOERROR: \n\ 128 unset ddns-rev-name; \n\ 129 break; \n\ 130 } \n\ 131 switch (ns-update (delete (IN, A, ddns-fwd-name, \n\ 132 leased-address))) { \n\ 133 case NOERROR: \n\ 134 unset ddns-fwd-name; \n\ 135 break; \n\ 136 } \n\ 137 on release or expiry; \n\ 138 } \n\ 139 } \n\ 140 } \n\ 141 } \n\ 142 } \n\ 143 unset new-ddns-fwd-name; \n\ 144 } \n\ 145}"; 146 147int ddns_update_style; 148#endif /* NSUPDATE */ 149 150const char *path_dhcpd_conf = _PATH_DHCPD_CONF; 151const char *path_dhcpd_db = _PATH_DHCPD_DB; 152const char *path_dhcpd_pid = _PATH_DHCPD_PID; 153 154int dhcp_max_agent_option_packet_length = DHCP_MTU_MAX; 155 156static omapi_auth_key_t *omapi_key = (omapi_auth_key_t *)0; 157int omapi_port; 158 159#if defined (TRACING) 160trace_type_t *trace_srandom; 161#endif 162 163static isc_result_t verify_addr (omapi_object_t *l, omapi_addr_t *addr) { 164 return ISC_R_SUCCESS; 165} 166 167static isc_result_t verify_auth (omapi_object_t *p, omapi_auth_key_t *a) { 168 if (a != omapi_key) 169 return ISC_R_INVALIDKEY; 170 return ISC_R_SUCCESS; 171} 172 173static void omapi_listener_start (void *foo) 174{ 175 omapi_object_t *listener; 176 isc_result_t result; 177 178 listener = (omapi_object_t *)0; 179 result = omapi_generic_new (&listener, MDL); 180 if (result != ISC_R_SUCCESS) 181 log_fatal ("Can't allocate new generic object: %s", 182 isc_result_totext (result)); 183 result = omapi_protocol_listen (listener, 184 (unsigned)omapi_port, 1); 185 if (result == ISC_R_SUCCESS && omapi_key) 186 result = omapi_protocol_configure_security 187 (listener, verify_addr, verify_auth); 188 if (result != ISC_R_SUCCESS) { 189 log_error ("Can't start OMAPI protocol: %s", 190 isc_result_totext (result)); 191 add_timeout (cur_time + 5, omapi_listener_start, 0, 0, 0); 192 } 193 omapi_object_dereference (&listener, MDL); 194} 195 196int main (argc, argv, envp) 197 int argc; 198 char **argv, **envp; 199{ 200 int i, status; 201 struct servent *ent; 202 char *s; 203 int cftest = 0; 204 int lftest = 0; 205#ifndef DEBUG 206 int pidfilewritten = 0; 207 int pid; 208 char pbuf [20]; 209 int daemon = 1; 210#endif 211 int quiet = 0; 212 char *server = (char *)0; 213 isc_result_t result; 214 unsigned seed; 215 struct interface_info *ip; 216 struct parse *parse; 217 int lose; 218 int no_dhcpd_conf = 0; 219 int no_dhcpd_db = 0; 220 int no_dhcpd_pid = 0; 221#if defined (TRACING) 222 char *traceinfile = (char *)0; 223 char *traceoutfile = (char *)0; 224#endif 225 226 /* Make sure we have stdin, stdout and stderr. */ 227 status = open ("/dev/null", O_RDWR); 228 if (status == 0) 229 status = open ("/dev/null", O_RDWR); 230 if (status == 1) { 231 status = open ("/dev/null", O_RDWR); 232 log_perror = 0; /* No sense logging to /dev/null. */ 233 } else if (status != -1) 234 close (status); 235 236 /* Set up the client classification system. */ 237 classification_setup (); 238 239 /* Initialize the omapi system. */ 240 result = omapi_init (); 241 if (result != ISC_R_SUCCESS) 242 log_fatal ("Can't initialize OMAPI: %s", 243 isc_result_totext (result)); 244 245 /* Set up the OMAPI wrappers for common objects. */ 246 dhcp_db_objects_setup (); 247 /* Set up the OMAPI wrappers for various server database internal 248 objects. */ 249 dhcp_common_objects_setup (); 250 251 /* Initially, log errors to stderr as well as to syslogd. */ 252#ifdef SYSLOG_4_2 253 openlog ("dhcpd", LOG_NDELAY); 254 log_priority = DHCPD_LOG_FACILITY; 255#else 256 openlog ("dhcpd", LOG_NDELAY, DHCPD_LOG_FACILITY); 257#endif 258 259 for (i = 1; i < argc; i++) { 260 if (!strcmp (argv [i], "-p")) { 261 if (++i == argc) 262 usage (); 263 for (s = argv [i]; *s; s++) 264 if (!isdigit ((unsigned char)*s)) 265 log_fatal ("%s: not a valid UDP port", 266 argv [i]); 267 status = atoi (argv [i]); 268 if (status < 1 || status > 65535) 269 log_fatal ("%s: not a valid UDP port", 270 argv [i]); 271 local_port = htons (status); 272 log_debug ("binding to user-specified port %d", 273 ntohs (local_port)); 274 } else if (!strcmp (argv [i], "-f")) { 275#ifndef DEBUG 276 daemon = 0; 277#endif 278 } else if (!strcmp (argv [i], "-d")) { 279#ifndef DEBUG 280 daemon = 0; 281#endif 282 log_perror = -1; 283 } else if (!strcmp (argv [i], "-s")) { 284 if (++i == argc) 285 usage (); 286 server = argv [i]; 287 } else if (!strcmp (argv [i], "-cf")) { 288 if (++i == argc) 289 usage (); 290 path_dhcpd_conf = argv [i]; 291 no_dhcpd_conf = 1; 292 } else if (!strcmp (argv [i], "-lf")) { 293 if (++i == argc) 294 usage (); 295 path_dhcpd_db = argv [i]; 296 no_dhcpd_db = 1; 297 } else if (!strcmp (argv [i], "-pf")) { 298 if (++i == argc) 299 usage (); 300 path_dhcpd_pid = argv [i]; 301 no_dhcpd_pid = 1; 302 } else if (!strcmp (argv [i], "-t")) { 303 /* test configurations only */ 304#ifndef DEBUG 305 daemon = 0; 306#endif 307 cftest = 1; 308 log_perror = -1; 309 } else if (!strcmp (argv [i], "-T")) { 310 /* test configurations and lease file only */ 311#ifndef DEBUG 312 daemon = 0; 313#endif 314 cftest = 1; 315 lftest = 1; 316 log_perror = -1; 317 } else if (!strcmp (argv [i], "-q")) { 318 quiet = 1; 319 quiet_interface_discovery = 1; 320 } else if (!strcmp (argv [i], "--version")) { 321 log_info ("isc-dhcpd-%s", DHCP_VERSION); 322 exit (0); 323#if defined (TRACING) 324 } else if (!strcmp (argv [i], "-tf")) { 325 if (++i == argc) 326 usage (); 327 traceoutfile = argv [i]; 328 } else if (!strcmp (argv [i], "-play")) { 329 if (++i == argc) 330 usage (); 331 traceinfile = argv [i]; 332 trace_replay_init (); 333#endif /* TRACING */ 334 } else if (argv [i][0] == '-') { 335 usage (); 336 } else { 337 struct interface_info *tmp = 338 (struct interface_info *)0; 339 result = interface_allocate (&tmp, MDL); 340 if (result != ISC_R_SUCCESS) 341 log_fatal ("Insufficient memory to %s %s: %s", 342 "record interface", argv [i], 343 isc_result_totext (result)); 344 strcpy (tmp -> name, argv [i]); 345 if (interfaces) { 346 interface_reference (&tmp -> next, 347 interfaces, MDL); 348 interface_dereference (&interfaces, MDL); 349 } 350 interface_reference (&interfaces, tmp, MDL); 351 tmp -> flags = INTERFACE_REQUESTED; 352 } 353 } 354 355 if (!no_dhcpd_conf && (s = getenv ("PATH_DHCPD_CONF"))) { 356 path_dhcpd_conf = s; 357 } 358 if (!no_dhcpd_db && (s = getenv ("PATH_DHCPD_DB"))) { 359 path_dhcpd_db = s; 360 } 361 if (!no_dhcpd_pid && (s = getenv ("PATH_DHCPD_PID"))) { 362 path_dhcpd_pid = s; 363 } 364 365 if (!quiet) { 366 log_info ("%s %s", message, DHCP_VERSION); 367 log_info (copyright); 368 log_info (arr); 369 log_info (url); 370 } else { 371 quiet = 0; 372 log_perror = 0; 373 } 374 375#if defined (TRACING) 376 trace_init (set_time, MDL); 377 if (traceoutfile) { 378 result = trace_begin (traceoutfile, MDL); 379 if (result != ISC_R_SUCCESS) 380 log_fatal ("Unable to begin trace: %s", 381 isc_result_totext (result)); 382 } 383 interface_trace_setup (); 384 parse_trace_setup (); 385 trace_srandom = trace_type_register ("random-seed", (void *)0, 386 trace_seed_input, 387 trace_seed_stop, MDL); 388#endif 389 390 /* Default to the DHCP/BOOTP port. */ 391 if (!local_port) 392 { 393 if ((s = getenv ("DHCPD_PORT"))) { 394 local_port = htons (atoi (s)); 395 log_debug ("binding to environment-specified port %d", 396 ntohs (local_port)); 397 } else { 398 ent = getservbyname ("dhcp", "udp"); 399 if (!ent) 400 local_port = htons (67); 401 else 402 local_port = ent -> s_port; 403#ifndef __CYGWIN32__ /* XXX */ 404 endservent (); 405#endif 406 } 407 } 408 409 remote_port = htons (ntohs (local_port) + 1); 410 411 if (server) { 412 if (!inet_aton (server, &limited_broadcast)) { 413 struct hostent *he; 414 he = gethostbyname (server); 415 if (he) { 416 memcpy (&limited_broadcast, 417 he -> h_addr_list [0], 418 sizeof limited_broadcast); 419 } else 420 limited_broadcast.s_addr = INADDR_BROADCAST; 421 } 422 } else { 423 limited_broadcast.s_addr = INADDR_BROADCAST; 424 } 425 426 /* Get the current time... */ 427 GET_TIME (&cur_time); 428 429 /* Set up the initial dhcp option universe. */ 430 initialize_common_option_spaces (); 431 initialize_server_option_spaces (); 432 433 /* Add the ddns update style enumeration prior to parsing. */ 434 add_enumeration (&ddns_styles); 435 add_enumeration (&syslog_enum); 436 437 if (!group_allocate (&root_group, MDL)) 438 log_fatal ("Can't allocate root group!"); 439 root_group -> authoritative = 0; 440 441 /* Set up various hooks. */ 442 dhcp_interface_setup_hook = dhcpd_interface_setup_hook; 443 bootp_packet_handler = do_packet; 444 445#if defined (NSUPDATE) 446 /* Set up the standard name service updater routine. */ 447 parse = (struct parse *)0; 448 status = new_parse (&parse, -1, 449 std_nsupdate, (sizeof std_nsupdate) - 1, 450 "standard name service update routine", 0); 451 if (status != ISC_R_SUCCESS) 452 log_fatal ("can't begin parsing name service updater!"); 453 454 lose = 0; 455 if (!(parse_executable_statements 456 (&root_group -> statements, parse, &lose, context_any))) { 457 end_parse (&parse); 458 log_fatal ("can't parse standard name service updater!"); 459 } 460 end_parse (&parse); 461#endif 462 463 /* Initialize icmp support... */ 464 if (!cftest && !lftest) 465 icmp_startup (1, lease_pinged); 466 467#if defined (TRACING) 468 if (traceinfile) { 469 if (!no_dhcpd_db) { 470 log_error ("%s", ""); 471 log_error ("** You must specify a lease file with -lf."); 472 log_error (" Dhcpd will not overwrite your default"); 473 log_fatal (" lease file when playing back a trace. **"); 474 } 475 trace_file_replay (traceinfile); 476 477#if defined (DEBUG_MEMORY_LEAKAGE) && \ 478 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) 479 free_everything (); 480 omapi_print_dmalloc_usage_by_caller (); 481#endif 482 483 exit (0); 484 } 485#endif 486 487 /* Read the dhcpd.conf file... */ 488 if (readconf () != ISC_R_SUCCESS) 489 log_fatal ("Configuration file errors encountered -- exiting"); 490 491 postconf_initialization (quiet); 492 493 /* test option should cause an early exit */ 494 if (cftest && !lftest) 495 exit(0); 496 497 group_write_hook = group_writer; 498 499 /* Start up the database... */ 500 db_startup (lftest); 501 502 if (lftest) 503 exit (0); 504 505 /* Discover all the network interfaces and initialize them. */ 506 discover_interfaces (DISCOVER_SERVER); 507 508 /* Make up a seed for the random number generator from current 509 time plus the sum of the last four bytes of each 510 interface's hardware address interpreted as an integer. 511 Not much entropy, but we're booting, so we're not likely to 512 find anything better. */ 513 seed = 0; 514 for (ip = interfaces; ip; ip = ip -> next) { 515 int junk; 516 memcpy (&junk, 517 &ip -> hw_address.hbuf [ip -> hw_address.hlen - 518 sizeof seed], sizeof seed); 519 seed += junk; 520 } 521 srandom (seed + cur_time); 522#if defined (TRACING) 523 trace_seed_stash (trace_srandom, seed + cur_time); 524#endif 525 postdb_startup (); 526 527#ifndef DEBUG 528 if (daemon) { 529 /* First part of becoming a daemon... */ 530 if ((pid = fork ()) < 0) 531 log_fatal ("Can't fork daemon: %m"); 532 else if (pid) 533 exit (0); 534 } 535 536 /* Read previous pid file. */ 537 if ((i = open (path_dhcpd_pid, O_RDONLY)) >= 0) { 538 status = read (i, pbuf, (sizeof pbuf) - 1); 539 close (i); 540 if (status > 0) { 541 pbuf [status] = 0; 542 pid = atoi (pbuf); 543 544 /* If the previous server process is not still running, 545 write a new pid file immediately. */ 546 if (pid && (pid == getpid() || kill (pid, 0) < 0)) { 547 unlink (path_dhcpd_pid); 548 if ((i = open (path_dhcpd_pid, 549 O_WRONLY | O_CREAT, 0644)) >= 0) { 550 sprintf (pbuf, "%d\n", (int)getpid ()); 551 write (i, pbuf, strlen (pbuf)); 552 close (i); 553 pidfilewritten = 1; 554 } 555 } else 556 log_fatal ("There's already a DHCP server running."); 557 } 558 } 559 560 /* If we were requested to log to stdout on the command line, 561 keep doing so; otherwise, stop. */ 562 if (log_perror == -1) 563 log_perror = 1; 564 else 565 log_perror = 0; 566 567 if (daemon) { 568 /* Become session leader and get pid... */ 569 close (0); 570 close (1); 571 close (2); 572 pid = setsid (); 573 } 574 575 /* If we didn't write the pid file earlier because we found a 576 process running the logged pid, but we made it to here, 577 meaning nothing is listening on the bootp port, then write 578 the pid file out - what's in it now is bogus anyway. */ 579 if (!pidfilewritten) { 580 unlink (path_dhcpd_pid); 581 if ((i = open (path_dhcpd_pid, 582 O_WRONLY | O_CREAT, 0644)) >= 0) { 583 sprintf (pbuf, "%d\n", (int)getpid ()); 584 write (i, pbuf, strlen (pbuf)); 585 close (i); 586 pidfilewritten = 1; 587 } 588 } 589#endif /* !DEBUG */ 590 591#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ 592 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) 593 dmalloc_cutoff_generation = dmalloc_generation; 594 dmalloc_longterm = dmalloc_outstanding; 595 dmalloc_outstanding = 0; 596#endif 597 598#if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY) 599 dump_rc_history (); 600#endif 601 602 omapi_set_int_value ((omapi_object_t *)dhcp_control_object, 603 (omapi_object_t *)0, "state", server_running); 604 605 /* Receive packets and dispatch them... */ 606 dispatch (); 607 608 /* Not reached */ 609 return 0; 610} 611 612void postconf_initialization (int quiet) 613{ 614 struct option_state *options = (struct option_state *)0; 615 struct data_string db; 616 struct option_cache *oc; 617 char *s; 618 isc_result_t result; 619 struct parse *parse; 620 int tmp; 621 622 /* Now try to get the lease file name. */ 623 option_state_allocate (&options, MDL); 624 625 execute_statements_in_scope ((struct binding_value **)0, 626 (struct packet *)0, 627 (struct lease *)0, 628 (struct client_state *)0, 629 (struct option_state *)0, 630 options, &global_scope, 631 root_group, 632 (struct group *)0); 633 memset (&db, 0, sizeof db); 634 oc = lookup_option (&server_universe, options, SV_LEASE_FILE_NAME); 635 if (oc && 636 evaluate_option_cache (&db, (struct packet *)0, 637 (struct lease *)0, (struct client_state *)0, 638 options, (struct option_state *)0, 639 &global_scope, oc, MDL)) { 640 s = dmalloc (db.len + 1, MDL); 641 if (!s) 642 log_fatal ("no memory for lease db filename."); 643 memcpy (s, db.data, db.len); 644 s [db.len] = 0; 645 data_string_forget (&db, MDL); 646 path_dhcpd_db = s; 647 } 648 649 oc = lookup_option (&server_universe, options, SV_PID_FILE_NAME); 650 if (oc && 651 evaluate_option_cache (&db, (struct packet *)0, 652 (struct lease *)0, (struct client_state *)0, 653 options, (struct option_state *)0, 654 &global_scope, oc, MDL)) { 655 s = dmalloc (db.len + 1, MDL); 656 if (!s) 657 log_fatal ("no memory for lease db filename."); 658 memcpy (s, db.data, db.len); 659 s [db.len] = 0; 660 data_string_forget (&db, MDL); 661 path_dhcpd_pid = s; 662 } 663 664 omapi_port = -1; 665 oc = lookup_option (&server_universe, options, SV_OMAPI_PORT); 666 if (oc && 667 evaluate_option_cache (&db, (struct packet *)0, 668 (struct lease *)0, (struct client_state *)0, 669 options, (struct option_state *)0, 670 &global_scope, oc, MDL)) { 671 if (db.len == 2) { 672 omapi_port = getUShort (db.data); 673 } else 674 log_fatal ("invalid omapi port data length"); 675 data_string_forget (&db, MDL); 676 } 677 678 oc = lookup_option (&server_universe, options, SV_OMAPI_KEY); 679 if (oc && 680 evaluate_option_cache (&db, (struct packet *)0, 681 (struct lease *)0, (struct client_state *)0, 682 options, 683 (struct option_state *)0, 684 &global_scope, oc, MDL)) { 685 s = dmalloc (db.len + 1, MDL); 686 if (!s) 687 log_fatal ("no memory for OMAPI key filename."); 688 memcpy (s, db.data, db.len); 689 s [db.len] = 0; 690 data_string_forget (&db, MDL); 691 result = omapi_auth_key_lookup_name (&omapi_key, s); 692 dfree (s, MDL); 693 if (result != ISC_R_SUCCESS) 694 log_fatal ("OMAPI key %s: %s", 695 s, isc_result_totext (result)); 696 } 697 698 oc = lookup_option (&server_universe, options, SV_LOCAL_PORT); 699 if (oc && 700 evaluate_option_cache (&db, (struct packet *)0, 701 (struct lease *)0, (struct client_state *)0, 702 options, 703 (struct option_state *)0, 704 &global_scope, oc, MDL)) { 705 if (db.len == 2) { 706 local_port = htons (getUShort (db.data)); 707 } else 708 log_fatal ("invalid local port data length"); 709 data_string_forget (&db, MDL); 710 } 711 712 oc = lookup_option (&server_universe, options, SV_REMOTE_PORT); 713 if (oc && 714 evaluate_option_cache (&db, (struct packet *)0, 715 (struct lease *)0, (struct client_state *)0, 716 options, (struct option_state *)0, 717 &global_scope, oc, MDL)) { 718 if (db.len == 2) { 719 remote_port = htons (getUShort (db.data)); 720 } else 721 log_fatal ("invalid remote port data length"); 722 data_string_forget (&db, MDL); 723 } 724 725 oc = lookup_option (&server_universe, options, 726 SV_LIMITED_BROADCAST_ADDRESS); 727 if (oc && 728 evaluate_option_cache (&db, (struct packet *)0, 729 (struct lease *)0, (struct client_state *)0, 730 options, (struct option_state *)0, 731 &global_scope, oc, MDL)) { 732 if (db.len == 4) { 733 memcpy (&limited_broadcast, db.data, 4); 734 } else 735 log_fatal ("invalid remote port data length"); 736 data_string_forget (&db, MDL); 737 } 738 739 oc = lookup_option (&server_universe, options, 740 SV_LOCAL_ADDRESS); 741 if (oc && 742 evaluate_option_cache (&db, (struct packet *)0, 743 (struct lease *)0, (struct client_state *)0, 744 options, (struct option_state *)0, 745 &global_scope, oc, MDL)) { 746 if (db.len == 4) { 747 memcpy (&local_address, db.data, 4); 748 } else 749 log_fatal ("invalid remote port data length"); 750 data_string_forget (&db, MDL); 751 } 752 753 oc = lookup_option (&server_universe, options, SV_DDNS_UPDATE_STYLE); 754 if (oc) { 755 if (evaluate_option_cache (&db, (struct packet *)0, 756 (struct lease *)0, 757 (struct client_state *)0, 758 options, 759 (struct option_state *)0, 760 &global_scope, oc, MDL)) { 761 if (db.len == 1) { 762 ddns_update_style = db.data [0]; 763 } else 764 log_fatal ("invalid dns update type"); 765 data_string_forget (&db, MDL); 766 } 767 } else { 768 log_info ("%s", ""); 769 log_error ("** You must add a global ddns-update-style %s%s.", 770 "statement to ", path_dhcpd_conf); 771 log_error (" To get the same behaviour as in 3.0b2pl11 %s", 772 "and previous"); 773 log_error (" versions, add a line that says \"%s\"", 774 "ddns-update-style ad-hoc;"); 775 log_fatal (" Please read the dhcpd.conf manual page %s", 776 "for more information. **"); 777 } 778 779 oc = lookup_option (&server_universe, options, SV_LOG_FACILITY); 780 if (oc) { 781 if (evaluate_option_cache (&db, (struct packet *)0, 782 (struct lease *)0, 783 (struct client_state *)0, 784 options, 785 (struct option_state *)0, 786 &global_scope, oc, MDL)) { 787 if (db.len == 1) { 788 closelog (); 789#ifdef SYSLOG_4_2 790 openlog ("dhcpd", LOG_NDELAY); 791 log_priority = db.data [0]; 792#else 793 openlog ("dhcpd", 794 LOG_NDELAY, db.data [0]); 795#endif 796 /* Log the startup banner into the new 797 log file. */ 798 if (!quiet) { 799 /* Don't log to stderr twice. */ 800 tmp = log_perror; 801 log_perror = 0; 802 log_info ("%s %s", 803 message, DHCP_VERSION); 804 log_info (copyright); 805 log_info (arr); 806 log_info (url); 807 log_perror = tmp; 808 } 809 } else 810 log_fatal ("invalid log facility"); 811 data_string_forget (&db, MDL); 812 } 813 } 814 815 /* Don't need the options anymore. */ 816 option_state_dereference (&options, MDL); 817 818#if defined (NSUPDATE) 819 /* If old-style ddns updates have been requested, parse the 820 old-style ddns updater. */ 821 if (ddns_update_style == 1) { 822 struct executable_statement **e, *s; 823 824 if (root_group -> statements) { 825 s = (struct executable_statement *)0; 826 if (!executable_statement_allocate (&s, MDL)) 827 log_fatal ("no memory for ddns updater"); 828 executable_statement_reference 829 (&s -> next, root_group -> statements, MDL); 830 executable_statement_dereference 831 (&root_group -> statements, MDL); 832 executable_statement_reference 833 (&root_group -> statements, s, MDL); 834 s -> op = statements_statement; 835 e = &s -> data.statements; 836 executable_statement_dereference (&s, MDL); 837 } else { 838 e = &root_group -> statements; 839 } 840 841 /* Set up the standard name service updater routine. */ 842 parse = (struct parse *)0; 843 result = new_parse (&parse, -1, 844 old_nsupdate, (sizeof old_nsupdate) - 1, 845 "old name service update routine", 0); 846 if (result != ISC_R_SUCCESS) 847 log_fatal ("can't begin parsing old ddns updater!"); 848 849 tmp = 0; 850 if (!(parse_executable_statements (e, parse, 851 &tmp, context_any))) { 852 end_parse (&parse); 853 log_fatal ("can't parse standard ddns updater!"); 854 } 855 end_parse (&parse); 856 } 857#endif 858} 859 860void postdb_startup (void) 861{ 862 /* Initialize the omapi listener state. */ 863 if (omapi_port != -1) { 864 omapi_listener_start (0); 865 } 866 867#if defined (FAILOVER_PROTOCOL) 868 /* Initialize the failover listener state. */ 869 dhcp_failover_startup (); 870#endif 871} 872 873/* Print usage message. */ 874 875static void usage () 876{ 877 log_info ("%s %s", message, DHCP_VERSION); 878 log_info (copyright); 879 log_info (arr); 880 881 log_fatal ("Usage: dhcpd [-p <UDP port #>] [-d] [-f]%s%s%s%s", 882 "\n [-cf config-file] [-lf lease-file]", 883#if defined (TRACING) 884 "\n [-tf trace-output-file]", 885 "\n [-play trace-input-file]", 886#else 887 "", "", 888#endif /* TRACING */ 889 "\n [-t] [-T] [-s server] [if0 [...ifN]]"); 890} 891 892void lease_pinged (from, packet, length) 893 struct iaddr from; 894 u_int8_t *packet; 895 int length; 896{ 897 struct lease *lp; 898 899 /* Don't try to look up a pinged lease if we aren't trying to 900 ping one - otherwise somebody could easily make us churn by 901 just forging repeated ICMP EchoReply packets for us to look 902 up. */ 903 if (!outstanding_pings) 904 return; 905 906 lp = (struct lease *)0; 907 if (!find_lease_by_ip_addr (&lp, from, MDL)) { 908 log_debug ("unexpected ICMP Echo Reply from %s", 909 piaddr (from)); 910 return; 911 } 912 913 if (!lp -> state) { 914#if defined (FAILOVER_PROTOCOL) 915 if (!lp -> pool || 916 !lp -> pool -> failover_peer) 917#endif 918 log_debug ("ICMP Echo Reply for %s late or spurious.", 919 piaddr (from)); 920 goto out; 921 } 922 923 if (lp -> ends > cur_time) { 924 log_debug ("ICMP Echo reply while lease %s valid.", 925 piaddr (from)); 926 } 927 928 /* At this point it looks like we pinged a lease and got a 929 response, which shouldn't have happened. */ 930 data_string_forget (&lp -> state -> parameter_request_list, MDL); 931 free_lease_state (lp -> state, MDL); 932 lp -> state = (struct lease_state *)0; 933 934 abandon_lease (lp, "pinged before offer"); 935 cancel_timeout (lease_ping_timeout, lp); 936 --outstanding_pings; 937 out: 938 lease_dereference (&lp, MDL); 939} 940 941void lease_ping_timeout (vlp) 942 void *vlp; 943{ 944 struct lease *lp = vlp; 945 946#if defined (DEBUG_MEMORY_LEAKAGE) 947 unsigned long previous_outstanding = dmalloc_outstanding; 948#endif 949 950 --outstanding_pings; 951 dhcp_reply (lp); 952 953#if defined (DEBUG_MEMORY_LEAKAGE) 954 log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term", 955 dmalloc_generation, 956 dmalloc_outstanding - previous_outstanding, 957 dmalloc_outstanding, dmalloc_longterm); 958#endif 959#if defined (DEBUG_MEMORY_LEAKAGE) 960 dmalloc_dump_outstanding (); 961#endif 962} 963 964int dhcpd_interface_setup_hook (struct interface_info *ip, struct iaddr *ia) 965{ 966 struct subnet *subnet; 967 struct shared_network *share; 968 isc_result_t status; 969 970 /* Special case for fallback network - not sure why this is 971 necessary. */ 972 if (!ia) { 973 const char *fnn = "fallback-net"; 974 status = shared_network_allocate (&ip -> shared_network, MDL); 975 if (status != ISC_R_SUCCESS) 976 log_fatal ("No memory for shared subnet: %s", 977 isc_result_totext (status)); 978 ip -> shared_network -> name = dmalloc (strlen (fnn) + 1, MDL); 979 strcpy (ip -> shared_network -> name, fnn); 980 return 1; 981 } 982 983 /* If there's a registered subnet for this address, 984 connect it together... */ 985 subnet = (struct subnet *)0; 986 if (find_subnet (&subnet, *ia, MDL)) { 987 /* If this interface has multiple aliases on the same 988 subnet, ignore all but the first we encounter. */ 989 if (!subnet -> interface) { 990 interface_reference (&subnet -> interface, ip, MDL); 991 subnet -> interface_address = *ia; 992 } else if (subnet -> interface != ip) { 993 log_error ("Multiple interfaces match the %s: %s %s", 994 "same subnet", 995 subnet -> interface -> name, ip -> name); 996 } 997 share = subnet -> shared_network; 998 if (ip -> shared_network && 999 ip -> shared_network != share) { 1000 log_fatal ("Interface %s matches multiple shared %s", 1001 ip -> name, "networks"); 1002 } else { 1003 if (!ip -> shared_network) 1004 shared_network_reference 1005 (&ip -> shared_network, share, MDL); 1006 } 1007 1008 if (!share -> interface) { 1009 interface_reference (&share -> interface, ip, MDL); 1010 } else if (share -> interface != ip) { 1011 log_error ("Multiple interfaces match the %s: %s %s", 1012 "same shared network", 1013 share -> interface -> name, ip -> name); 1014 } 1015 subnet_dereference (&subnet, MDL); 1016 } 1017 return 1; 1018} 1019 1020static TIME shutdown_time; 1021static int omapi_connection_count; 1022enum dhcp_shutdown_state shutdown_state; 1023 1024isc_result_t dhcp_io_shutdown (omapi_object_t *obj, void *foo) 1025{ 1026 /* Shut down all listeners. */ 1027 if (shutdown_state == shutdown_listeners && 1028 obj -> type == omapi_type_listener && 1029 obj -> inner && 1030 obj -> inner -> type == omapi_type_protocol_listener) { 1031 omapi_listener_destroy (obj, MDL); 1032 return ISC_R_SUCCESS; 1033 } 1034 1035 /* Shut down all existing omapi connections. */ 1036 if (obj -> type == omapi_type_connection && 1037 obj -> inner && 1038 obj -> inner -> type == omapi_type_protocol) { 1039 if (shutdown_state == shutdown_drop_omapi_connections) { 1040 omapi_disconnect (obj, 1); 1041 } 1042 omapi_connection_count++; 1043 if (shutdown_state == shutdown_omapi_connections) { 1044 omapi_disconnect (obj, 0); 1045 return ISC_R_SUCCESS; 1046 } 1047 } 1048 1049 /* Shutdown all DHCP interfaces. */ 1050 if (obj -> type == dhcp_type_interface && 1051 shutdown_state == shutdown_dhcp) { 1052 dhcp_interface_remove (obj, (omapi_object_t *)0); 1053 return ISC_R_SUCCESS; 1054 } 1055 return ISC_R_SUCCESS; 1056} 1057 1058static isc_result_t dhcp_io_shutdown_countdown (void *vlp) 1059{ 1060 dhcp_failover_state_t *state; 1061#if defined (FAILOVER_PROTOCOL) 1062 int failover_connection_count = 0; 1063#endif 1064 1065 oncemore: 1066 if (shutdown_state == shutdown_listeners || 1067 shutdown_state == shutdown_omapi_connections || 1068 shutdown_state == shutdown_drop_omapi_connections || 1069 shutdown_state == shutdown_dhcp) { 1070 omapi_connection_count = 0; 1071 omapi_io_state_foreach (dhcp_io_shutdown, 0); 1072 } 1073 1074 if ((shutdown_state == shutdown_listeners || 1075 shutdown_state == shutdown_omapi_connections || 1076 shutdown_state == shutdown_drop_omapi_connections) && 1077 omapi_connection_count == 0) { 1078 shutdown_state = shutdown_dhcp; 1079 shutdown_time = cur_time; 1080 goto oncemore; 1081 } else if (shutdown_state == shutdown_listeners && 1082 cur_time - shutdown_time > 4) { 1083 shutdown_state = shutdown_omapi_connections; 1084 shutdown_time = cur_time; 1085 } else if (shutdown_state == shutdown_omapi_connections && 1086 cur_time - shutdown_time > 4) { 1087 shutdown_state = shutdown_drop_omapi_connections; 1088 shutdown_time = cur_time; 1089 } else if (shutdown_state == shutdown_drop_omapi_connections && 1090 cur_time - shutdown_time > 4) { 1091 shutdown_state = shutdown_dhcp; 1092 shutdown_time = cur_time; 1093 goto oncemore; 1094 } else if (shutdown_state == shutdown_dhcp && 1095 cur_time - shutdown_time > 4) { 1096 shutdown_state = shutdown_done; 1097 shutdown_time = cur_time; 1098 } 1099 1100#if defined (FAILOVER_PROTOCOL) 1101 /* Set all failover peers into the shutdown state. */ 1102 if (shutdown_state == shutdown_dhcp) { 1103 for (state = failover_states; state; state = state -> next) { 1104 if (state -> me.state == normal) { 1105 dhcp_failover_set_state (state, shut_down); 1106 failover_connection_count++; 1107 } 1108 if (state -> me.state == shut_down && 1109 state -> partner.state != partner_down) 1110 failover_connection_count++; 1111 } 1112 } 1113 1114 if (shutdown_state == shutdown_done) { 1115 for (state = failover_states; state; state = state -> next) { 1116 if (state -> me.state == shut_down) { 1117 if (state -> link_to_peer) 1118 dhcp_failover_link_dereference (&state -> link_to_peer, 1119 MDL); 1120 dhcp_failover_set_state (state, recover); 1121 } 1122 } 1123#if defined (DEBUG_MEMORY_LEAKAGE) && \ 1124 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) 1125 free_everything (); 1126 omapi_print_dmalloc_usage_by_caller (); 1127#endif 1128 exit (0); 1129 } 1130#else 1131 if (shutdown_state == shutdown_done) { 1132#if defined (DEBUG_MEMORY_LEAKAGE) && \ 1133 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) 1134 free_everything (); 1135 omapi_print_dmalloc_usage_by_caller (); 1136#endif 1137 exit (0); 1138 } 1139#endif 1140 if (shutdown_state == shutdown_dhcp && 1141 !failover_connection_count) { 1142 shutdown_state = shutdown_done; 1143 shutdown_time = cur_time; 1144 goto oncemore; 1145 } 1146 add_timeout (cur_time + 1, 1147 (void (*)(void *))dhcp_io_shutdown_countdown, 0, 0, 0); 1148 return ISC_R_SUCCESS; 1149} 1150 1151isc_result_t dhcp_set_control_state (control_object_state_t oldstate, 1152 control_object_state_t newstate) 1153{ 1154 if (newstate == server_shutdown) { 1155 shutdown_time = cur_time; 1156 shutdown_state = shutdown_listeners; 1157 dhcp_io_shutdown_countdown (0); 1158 return ISC_R_SUCCESS; 1159 } 1160 return ISC_R_INVALIDARG; 1161} 1162