Annotation of embedaddon/dhcp/server/dhcpd.c, revision 1.1
1.1 ! misho 1: /* dhcpd.c
! 2:
! 3: DHCP Server Daemon. */
! 4:
! 5: /*
! 6: * Copyright (c) 2004-2011 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: * https://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: * ``https://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: static const char copyright[] =
! 36: "Copyright 2004-2011 Internet Systems Consortium.";
! 37: static const char arr [] = "All rights reserved.";
! 38: static const char message [] = "Internet Systems Consortium DHCP Server";
! 39: static const char url [] =
! 40: "For info, please visit https://www.isc.org/software/dhcp/";
! 41:
! 42: #include "dhcpd.h"
! 43: #include <omapip/omapip_p.h>
! 44: #include <syslog.h>
! 45: #include <errno.h>
! 46: #include <limits.h>
! 47: #include <sys/types.h>
! 48: #include <sys/time.h>
! 49: #include <signal.h>
! 50:
! 51: #if defined (PARANOIA)
! 52: # include <sys/types.h>
! 53: # include <unistd.h>
! 54: # include <pwd.h>
! 55: /* get around the ISC declaration of group */
! 56: # define group real_group
! 57: # include <grp.h>
! 58: # undef group
! 59: #endif /* PARANOIA */
! 60:
! 61: static void usage(void);
! 62:
! 63: struct iaddr server_identifier;
! 64: int server_identifier_matched;
! 65:
! 66: #if defined (NSUPDATE)
! 67:
! 68: /* This stuff is always executed to figure the default values for certain
! 69: ddns variables. */
! 70:
! 71: char std_nsupdate [] = " \n\
! 72: option server.ddns-hostname = \n\
! 73: pick (option fqdn.hostname, option host-name); \n\
! 74: option server.ddns-domainname = config-option domain-name; \n\
! 75: option server.ddns-ttl = encode-int(lease-time / 2, 32); \n\
! 76: option server.ddns-rev-domainname = \"in-addr.arpa.\";";
! 77:
! 78: /* This is the old-style name service updater that is executed
! 79: whenever a lease is committed. It does not follow the DHCP-DNS
! 80: draft at all. */
! 81:
! 82: char old_nsupdate [] = " \n\
! 83: on commit { \n\
! 84: if (not static and \n\
! 85: ((config-option server.ddns-updates = null) or \n\
! 86: (config-option server.ddns-updates != 0))) { \n\
! 87: set new-ddns-fwd-name = \n\
! 88: concat (pick (config-option server.ddns-hostname, \n\
! 89: option host-name), \".\", \n\
! 90: pick (config-option server.ddns-domainname, \n\
! 91: config-option domain-name)); \n\
! 92: if (defined (ddns-fwd-name) and ddns-fwd-name != new-ddns-fwd-name) { \n\
! 93: switch (ns-update (delete (IN, A, ddns-fwd-name, leased-address))) { \n\
! 94: case NOERROR: \n\
! 95: unset ddns-fwd-name; \n\
! 96: on expiry or release { \n\
! 97: } \n\
! 98: } \n\
! 99: } \n\
! 100: \n\
! 101: if (not defined (ddns-fwd-name)) { \n\
! 102: set ddns-fwd-name = new-ddns-fwd-name; \n\
! 103: if defined (ddns-fwd-name) { \n\
! 104: switch (ns-update (not exists (IN, A, ddns-fwd-name, null), \n\
! 105: add (IN, A, ddns-fwd-name, leased-address, \n\
! 106: lease-time / 2))) { \n\
! 107: default: \n\
! 108: unset ddns-fwd-name; \n\
! 109: break; \n\
! 110: \n\
! 111: case NOERROR: \n\
! 112: set ddns-rev-name = \n\
! 113: concat (binary-to-ascii (10, 8, \".\", \n\
! 114: reverse (1, \n\
! 115: leased-address)), \".\", \n\
! 116: pick (config-option server.ddns-rev-domainname, \n\
! 117: \"in-addr.arpa.\")); \n\
! 118: switch (ns-update (delete (IN, PTR, ddns-rev-name, null), \n\
! 119: add (IN, PTR, ddns-rev-name, ddns-fwd-name, \n\
! 120: lease-time / 2))) \n\
! 121: { \n\
! 122: default: \n\
! 123: unset ddns-rev-name; \n\
! 124: on release or expiry { \n\
! 125: switch (ns-update (delete (IN, A, ddns-fwd-name, \n\
! 126: leased-address))) { \n\
! 127: case NOERROR: \n\
! 128: unset ddns-fwd-name; \n\
! 129: break; \n\
! 130: } \n\
! 131: on release or expiry; \n\
! 132: } \n\
! 133: break; \n\
! 134: \n\
! 135: case NOERROR: \n\
! 136: on release or expiry { \n\
! 137: switch (ns-update (delete (IN, PTR, ddns-rev-name, null))) {\n\
! 138: case NOERROR: \n\
! 139: unset ddns-rev-name; \n\
! 140: break; \n\
! 141: } \n\
! 142: switch (ns-update (delete (IN, A, ddns-fwd-name, \n\
! 143: leased-address))) { \n\
! 144: case NOERROR: \n\
! 145: unset ddns-fwd-name; \n\
! 146: break; \n\
! 147: } \n\
! 148: on release or expiry; \n\
! 149: } \n\
! 150: } \n\
! 151: } \n\
! 152: } \n\
! 153: } \n\
! 154: unset new-ddns-fwd-name; \n\
! 155: } \n\
! 156: }";
! 157:
! 158: int ddns_update_style;
! 159: #endif /* NSUPDATE */
! 160:
! 161: const char *path_dhcpd_conf = _PATH_DHCPD_CONF;
! 162: const char *path_dhcpd_db = _PATH_DHCPD_DB;
! 163: const char *path_dhcpd_pid = _PATH_DHCPD_PID;
! 164: /* False (default) => we write and use a pid file */
! 165: isc_boolean_t no_pid_file = ISC_FALSE;
! 166:
! 167: int dhcp_max_agent_option_packet_length = DHCP_MTU_MAX;
! 168:
! 169: static omapi_auth_key_t *omapi_key = (omapi_auth_key_t *)0;
! 170: int omapi_port;
! 171:
! 172: #if defined (TRACING)
! 173: trace_type_t *trace_srandom;
! 174: #endif
! 175:
! 176: static isc_result_t verify_addr (omapi_object_t *l, omapi_addr_t *addr) {
! 177: return ISC_R_SUCCESS;
! 178: }
! 179:
! 180: static isc_result_t verify_auth (omapi_object_t *p, omapi_auth_key_t *a) {
! 181: if (a != omapi_key)
! 182: return ISC_R_INVALIDKEY;
! 183: return ISC_R_SUCCESS;
! 184: }
! 185:
! 186: static void omapi_listener_start (void *foo)
! 187: {
! 188: omapi_object_t *listener;
! 189: isc_result_t result;
! 190: struct timeval tv;
! 191:
! 192: listener = (omapi_object_t *)0;
! 193: result = omapi_generic_new (&listener, MDL);
! 194: if (result != ISC_R_SUCCESS)
! 195: log_fatal ("Can't allocate new generic object: %s",
! 196: isc_result_totext (result));
! 197: result = omapi_protocol_listen (listener,
! 198: (unsigned)omapi_port, 1);
! 199: if (result == ISC_R_SUCCESS && omapi_key)
! 200: result = omapi_protocol_configure_security
! 201: (listener, verify_addr, verify_auth);
! 202: if (result != ISC_R_SUCCESS) {
! 203: log_error ("Can't start OMAPI protocol: %s",
! 204: isc_result_totext (result));
! 205: tv.tv_sec = cur_tv.tv_sec + 5;
! 206: tv.tv_usec = cur_tv.tv_usec;
! 207: add_timeout (&tv, omapi_listener_start, 0, 0, 0);
! 208: }
! 209: omapi_object_dereference (&listener, MDL);
! 210: }
! 211:
! 212: #if defined (PARANOIA)
! 213: /* to be used in one of two possible scenarios */
! 214: static void setup_chroot (char *chroot_dir) {
! 215: if (geteuid())
! 216: log_fatal ("you must be root to use chroot");
! 217:
! 218: if (chroot(chroot_dir)) {
! 219: log_fatal ("chroot(\"%s\"): %m", chroot_dir);
! 220: }
! 221: if (chdir ("/")) {
! 222: /* probably permission denied */
! 223: log_fatal ("chdir(\"/\"): %m");
! 224: }
! 225: }
! 226: #endif /* PARANOIA */
! 227:
! 228: #ifndef UNIT_TEST
! 229: int
! 230: main(int argc, char **argv) {
! 231: int fd;
! 232: int i, status;
! 233: struct servent *ent;
! 234: char *s;
! 235: int cftest = 0;
! 236: int lftest = 0;
! 237: #ifndef DEBUG
! 238: int pid;
! 239: char pbuf [20];
! 240: int daemon = 1;
! 241: #endif
! 242: int quiet = 0;
! 243: char *server = (char *)0;
! 244: isc_result_t result;
! 245: unsigned seed;
! 246: struct interface_info *ip;
! 247: struct parse *parse;
! 248: int lose;
! 249: int no_dhcpd_conf = 0;
! 250: int no_dhcpd_db = 0;
! 251: int no_dhcpd_pid = 0;
! 252: #ifdef DHCPv6
! 253: int local_family_set = 0;
! 254: #endif /* DHCPv6 */
! 255: #if defined (TRACING)
! 256: char *traceinfile = (char *)0;
! 257: char *traceoutfile = (char *)0;
! 258: #endif
! 259:
! 260: #if defined (PARANOIA)
! 261: char *set_user = 0;
! 262: char *set_group = 0;
! 263: char *set_chroot = 0;
! 264:
! 265: uid_t set_uid = 0;
! 266: gid_t set_gid = 0;
! 267: #endif /* PARANOIA */
! 268:
! 269: /* Make sure that file descriptors 0 (stdin), 1, (stdout), and
! 270: 2 (stderr) are open. To do this, we assume that when we
! 271: open a file the lowest available file descriptor is used. */
! 272: fd = open("/dev/null", O_RDWR);
! 273: if (fd == 0)
! 274: fd = open("/dev/null", O_RDWR);
! 275: if (fd == 1)
! 276: fd = open("/dev/null", O_RDWR);
! 277: if (fd == 2)
! 278: log_perror = 0; /* No sense logging to /dev/null. */
! 279: else if (fd != -1)
! 280: close(fd);
! 281:
! 282: /* Set up the client classification system. */
! 283: classification_setup ();
! 284:
! 285: /*
! 286: * Set up the signal handlers, currently we only
! 287: * have one to ignore sigpipe.
! 288: */
! 289: if (dhcp_handle_signal(SIGPIPE, SIG_IGN) != ISC_R_SUCCESS) {
! 290: log_fatal("Can't set up signal handler");
! 291: }
! 292:
! 293: /* Initialize the omapi system. */
! 294: result = omapi_init ();
! 295: if (result != ISC_R_SUCCESS)
! 296: log_fatal ("Can't initialize OMAPI: %s",
! 297: isc_result_totext (result));
! 298:
! 299: /* Set up the OMAPI wrappers for common objects. */
! 300: dhcp_db_objects_setup ();
! 301: /* Set up the OMAPI wrappers for various server database internal
! 302: objects. */
! 303: dhcp_common_objects_setup ();
! 304:
! 305: /* Initially, log errors to stderr as well as to syslogd. */
! 306: openlog ("dhcpd", LOG_NDELAY, DHCPD_LOG_FACILITY);
! 307:
! 308: for (i = 1; i < argc; i++) {
! 309: if (!strcmp (argv [i], "-p")) {
! 310: if (++i == argc)
! 311: usage ();
! 312: local_port = validate_port (argv [i]);
! 313: log_debug ("binding to user-specified port %d",
! 314: ntohs (local_port));
! 315: } else if (!strcmp (argv [i], "-f")) {
! 316: #ifndef DEBUG
! 317: daemon = 0;
! 318: #endif
! 319: } else if (!strcmp (argv [i], "-d")) {
! 320: #ifndef DEBUG
! 321: daemon = 0;
! 322: #endif
! 323: log_perror = -1;
! 324: } else if (!strcmp (argv [i], "-s")) {
! 325: if (++i == argc)
! 326: usage ();
! 327: server = argv [i];
! 328: #if defined (PARANOIA)
! 329: } else if (!strcmp (argv [i], "-user")) {
! 330: if (++i == argc)
! 331: usage ();
! 332: set_user = argv [i];
! 333: } else if (!strcmp (argv [i], "-group")) {
! 334: if (++i == argc)
! 335: usage ();
! 336: set_group = argv [i];
! 337: } else if (!strcmp (argv [i], "-chroot")) {
! 338: if (++i == argc)
! 339: usage ();
! 340: set_chroot = argv [i];
! 341: #endif /* PARANOIA */
! 342: } else if (!strcmp (argv [i], "-cf")) {
! 343: if (++i == argc)
! 344: usage ();
! 345: path_dhcpd_conf = argv [i];
! 346: no_dhcpd_conf = 1;
! 347: } else if (!strcmp (argv [i], "-lf")) {
! 348: if (++i == argc)
! 349: usage ();
! 350: path_dhcpd_db = argv [i];
! 351: no_dhcpd_db = 1;
! 352: } else if (!strcmp (argv [i], "-pf")) {
! 353: if (++i == argc)
! 354: usage ();
! 355: path_dhcpd_pid = argv [i];
! 356: no_dhcpd_pid = 1;
! 357: } else if (!strcmp(argv[i], "--no-pid")) {
! 358: no_pid_file = ISC_TRUE;
! 359: } else if (!strcmp (argv [i], "-t")) {
! 360: /* test configurations only */
! 361: #ifndef DEBUG
! 362: daemon = 0;
! 363: #endif
! 364: cftest = 1;
! 365: log_perror = -1;
! 366: } else if (!strcmp (argv [i], "-T")) {
! 367: /* test configurations and lease file only */
! 368: #ifndef DEBUG
! 369: daemon = 0;
! 370: #endif
! 371: cftest = 1;
! 372: lftest = 1;
! 373: log_perror = -1;
! 374: } else if (!strcmp (argv [i], "-q")) {
! 375: quiet = 1;
! 376: quiet_interface_discovery = 1;
! 377: #ifdef DHCPv6
! 378: } else if (!strcmp(argv[i], "-4")) {
! 379: if (local_family_set && (local_family != AF_INET)) {
! 380: log_fatal("Server cannot run in both IPv4 and "
! 381: "IPv6 mode at the same time.");
! 382: }
! 383: local_family = AF_INET;
! 384: local_family_set = 1;
! 385: } else if (!strcmp(argv[i], "-6")) {
! 386: if (local_family_set && (local_family != AF_INET6)) {
! 387: log_fatal("Server cannot run in both IPv4 and "
! 388: "IPv6 mode at the same time.");
! 389: }
! 390: local_family = AF_INET6;
! 391: local_family_set = 1;
! 392: #endif /* DHCPv6 */
! 393: } else if (!strcmp (argv [i], "--version")) {
! 394: log_info("isc-dhcpd-%s", PACKAGE_VERSION);
! 395: exit (0);
! 396: #if defined (TRACING)
! 397: } else if (!strcmp (argv [i], "-tf")) {
! 398: if (++i == argc)
! 399: usage ();
! 400: traceoutfile = argv [i];
! 401: } else if (!strcmp (argv [i], "-play")) {
! 402: if (++i == argc)
! 403: usage ();
! 404: traceinfile = argv [i];
! 405: trace_replay_init ();
! 406: #endif /* TRACING */
! 407: } else if (argv [i][0] == '-') {
! 408: usage ();
! 409: } else {
! 410: struct interface_info *tmp =
! 411: (struct interface_info *)0;
! 412: if (strlen(argv[i]) >= sizeof(tmp->name))
! 413: log_fatal("%s: interface name too long "
! 414: "(is %ld)",
! 415: argv[i], (long)strlen(argv[i]));
! 416: result = interface_allocate (&tmp, MDL);
! 417: if (result != ISC_R_SUCCESS)
! 418: log_fatal ("Insufficient memory to %s %s: %s",
! 419: "record interface", argv [i],
! 420: isc_result_totext (result));
! 421: strcpy (tmp -> name, argv [i]);
! 422: if (interfaces) {
! 423: interface_reference (&tmp -> next,
! 424: interfaces, MDL);
! 425: interface_dereference (&interfaces, MDL);
! 426: }
! 427: interface_reference (&interfaces, tmp, MDL);
! 428: tmp -> flags = INTERFACE_REQUESTED;
! 429: }
! 430: }
! 431:
! 432: if (!no_dhcpd_conf && (s = getenv ("PATH_DHCPD_CONF"))) {
! 433: path_dhcpd_conf = s;
! 434: }
! 435:
! 436: #ifdef DHCPv6
! 437: if (local_family == AF_INET6) {
! 438: /* DHCPv6: override DHCPv4 lease and pid filenames */
! 439: if (!no_dhcpd_db) {
! 440: if ((s = getenv ("PATH_DHCPD6_DB")))
! 441: path_dhcpd_db = s;
! 442: else
! 443: path_dhcpd_db = _PATH_DHCPD6_DB;
! 444: }
! 445: if (!no_dhcpd_pid) {
! 446: if ((s = getenv ("PATH_DHCPD6_PID")))
! 447: path_dhcpd_pid = s;
! 448: else
! 449: path_dhcpd_pid = _PATH_DHCPD6_PID;
! 450: }
! 451: } else
! 452: #else /* !DHCPv6 */
! 453: {
! 454: if (!no_dhcpd_db && (s = getenv ("PATH_DHCPD_DB"))) {
! 455: path_dhcpd_db = s;
! 456: }
! 457: if (!no_dhcpd_pid && (s = getenv ("PATH_DHCPD_PID"))) {
! 458: path_dhcpd_pid = s;
! 459: }
! 460: }
! 461: #endif /* DHCPv6 */
! 462:
! 463: /*
! 464: * convert relative path names to absolute, for files that need
! 465: * to be reopened after chdir() has been called
! 466: */
! 467: if (path_dhcpd_db[0] != '/') {
! 468: char *path = dmalloc(PATH_MAX, MDL);
! 469: if (path == NULL)
! 470: log_fatal("No memory for filename\n");
! 471: path_dhcpd_db = realpath(path_dhcpd_db, path);
! 472: if (path_dhcpd_db == NULL)
! 473: log_fatal("%s: %s", path, strerror(errno));
! 474: }
! 475:
! 476: if (!quiet) {
! 477: log_info("%s %s", message, PACKAGE_VERSION);
! 478: log_info (copyright);
! 479: log_info (arr);
! 480: log_info (url);
! 481: } else {
! 482: quiet = 0;
! 483: log_perror = 0;
! 484: }
! 485:
! 486: #if defined (TRACING)
! 487: trace_init (set_time, MDL);
! 488: if (traceoutfile) {
! 489: result = trace_begin (traceoutfile, MDL);
! 490: if (result != ISC_R_SUCCESS)
! 491: log_fatal ("Unable to begin trace: %s",
! 492: isc_result_totext (result));
! 493: }
! 494: interface_trace_setup ();
! 495: parse_trace_setup ();
! 496: trace_srandom = trace_type_register ("random-seed", (void *)0,
! 497: trace_seed_input,
! 498: trace_seed_stop, MDL);
! 499: #endif
! 500:
! 501: #if defined (PARANOIA)
! 502: /* get user and group info if those options were given */
! 503: if (set_user) {
! 504: struct passwd *tmp_pwd;
! 505:
! 506: if (geteuid())
! 507: log_fatal ("you must be root to set user");
! 508:
! 509: if (!(tmp_pwd = getpwnam(set_user)))
! 510: log_fatal ("no such user: %s", set_user);
! 511:
! 512: set_uid = tmp_pwd->pw_uid;
! 513:
! 514: /* use the user's group as the default gid */
! 515: if (!set_group)
! 516: set_gid = tmp_pwd->pw_gid;
! 517: }
! 518:
! 519: if (set_group) {
! 520: /* get around the ISC declaration of group */
! 521: #define group real_group
! 522: struct group *tmp_grp;
! 523:
! 524: if (geteuid())
! 525: log_fatal ("you must be root to set group");
! 526:
! 527: if (!(tmp_grp = getgrnam(set_group)))
! 528: log_fatal ("no such group: %s", set_group);
! 529:
! 530: set_gid = tmp_grp->gr_gid;
! 531: #undef group
! 532: }
! 533:
! 534: # if defined (EARLY_CHROOT)
! 535: if (set_chroot) setup_chroot (set_chroot);
! 536: # endif /* EARLY_CHROOT */
! 537: #endif /* PARANOIA */
! 538:
! 539: /* Default to the DHCP/BOOTP port. */
! 540: if (!local_port)
! 541: {
! 542: if ((s = getenv ("DHCPD_PORT"))) {
! 543: local_port = validate_port (s);
! 544: log_debug ("binding to environment-specified port %d",
! 545: ntohs (local_port));
! 546: } else {
! 547: if (local_family == AF_INET) {
! 548: ent = getservbyname("dhcp", "udp");
! 549: if (ent == NULL) {
! 550: local_port = htons(67);
! 551: } else {
! 552: local_port = ent->s_port;
! 553: }
! 554: } else {
! 555: /* INSIST(local_family == AF_INET6); */
! 556: ent = getservbyname("dhcpv6-server", "udp");
! 557: if (ent == NULL) {
! 558: local_port = htons(547);
! 559: } else {
! 560: local_port = ent->s_port;
! 561: }
! 562: }
! 563: #ifndef __CYGWIN32__ /* XXX */
! 564: endservent ();
! 565: #endif
! 566: }
! 567: }
! 568:
! 569: if (local_family == AF_INET) {
! 570: remote_port = htons(ntohs(local_port) + 1);
! 571: } else {
! 572: /* INSIST(local_family == AF_INET6); */
! 573: ent = getservbyname("dhcpv6-client", "udp");
! 574: if (ent == NULL) {
! 575: remote_port = htons(546);
! 576: } else {
! 577: remote_port = ent->s_port;
! 578: }
! 579: }
! 580:
! 581: if (server) {
! 582: if (local_family != AF_INET) {
! 583: log_fatal("You can only specify address to send "
! 584: "replies to when running an IPv4 server.");
! 585: }
! 586: if (!inet_aton (server, &limited_broadcast)) {
! 587: struct hostent *he;
! 588: he = gethostbyname (server);
! 589: if (he) {
! 590: memcpy (&limited_broadcast,
! 591: he -> h_addr_list [0],
! 592: sizeof limited_broadcast);
! 593: } else
! 594: limited_broadcast.s_addr = INADDR_BROADCAST;
! 595: }
! 596: } else {
! 597: limited_broadcast.s_addr = INADDR_BROADCAST;
! 598: }
! 599:
! 600: /* Get the current time... */
! 601: gettimeofday(&cur_tv, NULL);
! 602:
! 603: /* Set up the initial dhcp option universe. */
! 604: initialize_common_option_spaces ();
! 605: initialize_server_option_spaces ();
! 606:
! 607: /* Add the ddns update style enumeration prior to parsing. */
! 608: add_enumeration (&ddns_styles);
! 609: add_enumeration (&syslog_enum);
! 610:
! 611: if (!group_allocate (&root_group, MDL))
! 612: log_fatal ("Can't allocate root group!");
! 613: root_group -> authoritative = 0;
! 614:
! 615: /* Set up various hooks. */
! 616: dhcp_interface_setup_hook = dhcpd_interface_setup_hook;
! 617: bootp_packet_handler = do_packet;
! 618: #ifdef DHCPv6
! 619: dhcpv6_packet_handler = do_packet6;
! 620: #endif /* DHCPv6 */
! 621:
! 622: #if defined (NSUPDATE)
! 623: /* Set up the standard name service updater routine. */
! 624: parse = NULL;
! 625: status = new_parse(&parse, -1, std_nsupdate, sizeof(std_nsupdate) - 1,
! 626: "standard name service update routine", 0);
! 627: if (status != ISC_R_SUCCESS)
! 628: log_fatal ("can't begin parsing name service updater!");
! 629:
! 630: if (parse != NULL) {
! 631: lose = 0;
! 632: if (!(parse_executable_statements(&root_group->statements,
! 633: parse, &lose, context_any))) {
! 634: end_parse(&parse);
! 635: log_fatal("can't parse standard name service updater!");
! 636: }
! 637: end_parse(&parse);
! 638: }
! 639: #endif
! 640:
! 641: /* Initialize icmp support... */
! 642: if (!cftest && !lftest)
! 643: icmp_startup (1, lease_pinged);
! 644:
! 645: #if defined (TRACING)
! 646: if (traceinfile) {
! 647: if (!no_dhcpd_db) {
! 648: log_error ("%s", "");
! 649: log_error ("** You must specify a lease file with -lf.");
! 650: log_error (" Dhcpd will not overwrite your default");
! 651: log_fatal (" lease file when playing back a trace. **");
! 652: }
! 653: trace_file_replay (traceinfile);
! 654:
! 655: #if defined (DEBUG_MEMORY_LEAKAGE) && \
! 656: defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
! 657: free_everything ();
! 658: omapi_print_dmalloc_usage_by_caller ();
! 659: #endif
! 660:
! 661: exit (0);
! 662: }
! 663: #endif
! 664:
! 665: #ifdef DHCPv6
! 666: /* set up DHCPv6 hashes */
! 667: if (!ia_new_hash(&ia_na_active, DEFAULT_HASH_SIZE, MDL)) {
! 668: log_fatal("Out of memory creating hash for active IA_NA.");
! 669: }
! 670: if (!ia_new_hash(&ia_ta_active, DEFAULT_HASH_SIZE, MDL)) {
! 671: log_fatal("Out of memory creating hash for active IA_TA.");
! 672: }
! 673: if (!ia_new_hash(&ia_pd_active, DEFAULT_HASH_SIZE, MDL)) {
! 674: log_fatal("Out of memory creating hash for active IA_PD.");
! 675: }
! 676: #endif /* DHCPv6 */
! 677:
! 678: /* Read the dhcpd.conf file... */
! 679: if (readconf () != ISC_R_SUCCESS)
! 680: log_fatal ("Configuration file errors encountered -- exiting");
! 681:
! 682: postconf_initialization (quiet);
! 683:
! 684: #if defined (PARANOIA) && !defined (EARLY_CHROOT)
! 685: if (set_chroot) setup_chroot (set_chroot);
! 686: #endif /* PARANOIA && !EARLY_CHROOT */
! 687:
! 688: /* test option should cause an early exit */
! 689: if (cftest && !lftest)
! 690: exit(0);
! 691:
! 692: group_write_hook = group_writer;
! 693:
! 694: /* Start up the database... */
! 695: db_startup (lftest);
! 696:
! 697: if (lftest)
! 698: exit (0);
! 699:
! 700: /* Discover all the network interfaces and initialize them. */
! 701: discover_interfaces(DISCOVER_SERVER);
! 702:
! 703: #ifdef DHCPv6
! 704: /*
! 705: * Remove addresses from our pools that we should not issue
! 706: * to clients.
! 707: *
! 708: * We currently have no support for this in IPv4. It is not
! 709: * as important in IPv4, as making pools with ranges that
! 710: * leave out interfaces and hosts is fairly straightforward
! 711: * using range notation, but not so handy with CIDR notation.
! 712: */
! 713: if (local_family == AF_INET6) {
! 714: mark_hosts_unavailable();
! 715: mark_phosts_unavailable();
! 716: mark_interfaces_unavailable();
! 717: }
! 718: #endif /* DHCPv6 */
! 719:
! 720:
! 721: /* Make up a seed for the random number generator from current
! 722: time plus the sum of the last four bytes of each
! 723: interface's hardware address interpreted as an integer.
! 724: Not much entropy, but we're booting, so we're not likely to
! 725: find anything better. */
! 726: seed = 0;
! 727: for (ip = interfaces; ip; ip = ip -> next) {
! 728: int junk;
! 729: memcpy (&junk,
! 730: &ip -> hw_address.hbuf [ip -> hw_address.hlen -
! 731: sizeof seed], sizeof seed);
! 732: seed += junk;
! 733: }
! 734: srandom (seed + cur_time);
! 735: #if defined (TRACING)
! 736: trace_seed_stash (trace_srandom, seed + cur_time);
! 737: #endif
! 738: postdb_startup ();
! 739:
! 740: #ifdef DHCPv6
! 741: /*
! 742: * Set server DHCPv6 identifier.
! 743: * See dhcpv6.c for discussion of setting DUID.
! 744: */
! 745: if (set_server_duid_from_option() == ISC_R_SUCCESS) {
! 746: write_server_duid();
! 747: } else {
! 748: if (!server_duid_isset()) {
! 749: if (generate_new_server_duid() != ISC_R_SUCCESS) {
! 750: log_fatal("Unable to set server identifier.");
! 751: }
! 752: write_server_duid();
! 753: }
! 754: }
! 755: #endif /* DHCPv6 */
! 756:
! 757: #ifndef DEBUG
! 758: if (daemon) {
! 759: /* First part of becoming a daemon... */
! 760: if ((pid = fork ()) < 0)
! 761: log_fatal ("Can't fork daemon: %m");
! 762: else if (pid)
! 763: exit (0);
! 764: }
! 765:
! 766: #if defined (PARANOIA)
! 767: /* change uid to the specified one */
! 768:
! 769: if (set_gid) {
! 770: if (setgroups (0, (void *)0))
! 771: log_fatal ("setgroups: %m");
! 772: if (setgid (set_gid))
! 773: log_fatal ("setgid(%d): %m", (int) set_gid);
! 774: }
! 775:
! 776: if (set_uid) {
! 777: if (setuid (set_uid))
! 778: log_fatal ("setuid(%d): %m", (int) set_uid);
! 779: }
! 780: #endif /* PARANOIA */
! 781:
! 782: /*
! 783: * Deal with pid files. If the user told us
! 784: * not to write a file we don't read one either
! 785: */
! 786: if (no_pid_file == ISC_FALSE) {
! 787: /*Read previous pid file. */
! 788: if ((i = open (path_dhcpd_pid, O_RDONLY)) >= 0) {
! 789: status = read(i, pbuf, (sizeof pbuf) - 1);
! 790: close (i);
! 791: if (status > 0) {
! 792: pbuf[status] = 0;
! 793: pid = atoi(pbuf);
! 794:
! 795: /*
! 796: * If there was a previous server process and
! 797: * it is still running, abort
! 798: */
! 799: if (!pid ||
! 800: (pid != getpid() && kill(pid, 0) == 0))
! 801: log_fatal("There's already a "
! 802: "DHCP server running.");
! 803: }
! 804: }
! 805:
! 806: /* Write new pid file. */
! 807: i = open(path_dhcpd_pid, O_WRONLY|O_CREAT|O_TRUNC, 0644);
! 808: if (i >= 0) {
! 809: sprintf(pbuf, "%d\n", (int) getpid());
! 810: IGNORE_RET (write(i, pbuf, strlen(pbuf)));
! 811: close(i);
! 812: } else {
! 813: log_error("Can't create PID file %s: %m.",
! 814: path_dhcpd_pid);
! 815: }
! 816: }
! 817:
! 818: /* If we were requested to log to stdout on the command line,
! 819: keep doing so; otherwise, stop. */
! 820: if (log_perror == -1)
! 821: log_perror = 1;
! 822: else
! 823: log_perror = 0;
! 824:
! 825: if (daemon) {
! 826: /* Become session leader and get pid... */
! 827: pid = setsid();
! 828:
! 829: /* Close standard I/O descriptors. */
! 830: close(0);
! 831: close(1);
! 832: close(2);
! 833:
! 834: /* Reopen them on /dev/null. */
! 835: open("/dev/null", O_RDWR);
! 836: open("/dev/null", O_RDWR);
! 837: open("/dev/null", O_RDWR);
! 838: log_perror = 0; /* No sense logging to /dev/null. */
! 839:
! 840: IGNORE_RET (chdir("/"));
! 841: }
! 842: #endif /* !DEBUG */
! 843:
! 844: #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
! 845: defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
! 846: dmalloc_cutoff_generation = dmalloc_generation;
! 847: dmalloc_longterm = dmalloc_outstanding;
! 848: dmalloc_outstanding = 0;
! 849: #endif
! 850:
! 851: omapi_set_int_value ((omapi_object_t *)dhcp_control_object,
! 852: (omapi_object_t *)0, "state", server_running);
! 853:
! 854: register_eventhandler(&rw_queue_empty,commit_leases_readerdry);
! 855:
! 856: /* Receive packets and dispatch them... */
! 857: dispatch ();
! 858:
! 859: /* Not reached */
! 860: return 0;
! 861: }
! 862: #endif /* !UNIT_TEST */
! 863:
! 864: void postconf_initialization (int quiet)
! 865: {
! 866: struct option_state *options = (struct option_state *)0;
! 867: struct data_string db;
! 868: struct option_cache *oc;
! 869: char *s;
! 870: isc_result_t result;
! 871: struct parse *parse;
! 872: int tmp;
! 873:
! 874: /* Now try to get the lease file name. */
! 875: option_state_allocate (&options, MDL);
! 876:
! 877: execute_statements_in_scope ((struct binding_value **)0,
! 878: (struct packet *)0,
! 879: (struct lease *)0,
! 880: (struct client_state *)0,
! 881: (struct option_state *)0,
! 882: options, &global_scope,
! 883: root_group,
! 884: (struct group *)0);
! 885: memset (&db, 0, sizeof db);
! 886: oc = lookup_option (&server_universe, options, SV_LEASE_FILE_NAME);
! 887: if (oc &&
! 888: evaluate_option_cache (&db, (struct packet *)0,
! 889: (struct lease *)0, (struct client_state *)0,
! 890: options, (struct option_state *)0,
! 891: &global_scope, oc, MDL)) {
! 892: s = dmalloc (db.len + 1, MDL);
! 893: if (!s)
! 894: log_fatal ("no memory for lease db filename.");
! 895: memcpy (s, db.data, db.len);
! 896: s [db.len] = 0;
! 897: data_string_forget (&db, MDL);
! 898: path_dhcpd_db = s;
! 899: }
! 900:
! 901: oc = lookup_option (&server_universe, options, SV_PID_FILE_NAME);
! 902: if (oc &&
! 903: evaluate_option_cache (&db, (struct packet *)0,
! 904: (struct lease *)0, (struct client_state *)0,
! 905: options, (struct option_state *)0,
! 906: &global_scope, oc, MDL)) {
! 907: s = dmalloc (db.len + 1, MDL);
! 908: if (!s)
! 909: log_fatal ("no memory for pid filename.");
! 910: memcpy (s, db.data, db.len);
! 911: s [db.len] = 0;
! 912: data_string_forget (&db, MDL);
! 913: path_dhcpd_pid = s;
! 914: }
! 915:
! 916: #ifdef DHCPv6
! 917: if (local_family == AF_INET6) {
! 918: /*
! 919: * Override lease file name with dhcpv6 lease file name,
! 920: * if it was set; then, do the same with the pid file name
! 921: */
! 922: oc = lookup_option(&server_universe, options,
! 923: SV_DHCPV6_LEASE_FILE_NAME);
! 924: if (oc &&
! 925: evaluate_option_cache(&db, NULL, NULL, NULL,
! 926: options, NULL, &global_scope,
! 927: oc, MDL)) {
! 928: s = dmalloc (db.len + 1, MDL);
! 929: if (!s)
! 930: log_fatal ("no memory for lease db filename.");
! 931: memcpy (s, db.data, db.len);
! 932: s [db.len] = 0;
! 933: data_string_forget (&db, MDL);
! 934: path_dhcpd_db = s;
! 935: }
! 936:
! 937: oc = lookup_option(&server_universe, options,
! 938: SV_DHCPV6_PID_FILE_NAME);
! 939: if (oc &&
! 940: evaluate_option_cache(&db, NULL, NULL, NULL,
! 941: options, NULL, &global_scope,
! 942: oc, MDL)) {
! 943: s = dmalloc (db.len + 1, MDL);
! 944: if (!s)
! 945: log_fatal ("no memory for pid filename.");
! 946: memcpy (s, db.data, db.len);
! 947: s [db.len] = 0;
! 948: data_string_forget (&db, MDL);
! 949: path_dhcpd_pid = s;
! 950: }
! 951: }
! 952: #endif /* DHCPv6 */
! 953:
! 954: omapi_port = -1;
! 955: oc = lookup_option (&server_universe, options, SV_OMAPI_PORT);
! 956: if (oc &&
! 957: evaluate_option_cache (&db, (struct packet *)0,
! 958: (struct lease *)0, (struct client_state *)0,
! 959: options, (struct option_state *)0,
! 960: &global_scope, oc, MDL)) {
! 961: if (db.len == 2) {
! 962: omapi_port = getUShort (db.data);
! 963: } else
! 964: log_fatal ("invalid omapi port data length");
! 965: data_string_forget (&db, MDL);
! 966: }
! 967:
! 968: oc = lookup_option (&server_universe, options, SV_OMAPI_KEY);
! 969: if (oc &&
! 970: evaluate_option_cache (&db, (struct packet *)0,
! 971: (struct lease *)0, (struct client_state *)0,
! 972: options,
! 973: (struct option_state *)0,
! 974: &global_scope, oc, MDL)) {
! 975: s = dmalloc (db.len + 1, MDL);
! 976: if (!s)
! 977: log_fatal ("no memory for OMAPI key filename.");
! 978: memcpy (s, db.data, db.len);
! 979: s [db.len] = 0;
! 980: data_string_forget (&db, MDL);
! 981: result = omapi_auth_key_lookup_name (&omapi_key, s);
! 982: dfree (s, MDL);
! 983: if (result != ISC_R_SUCCESS)
! 984: log_fatal ("OMAPI key %s: %s",
! 985: s, isc_result_totext (result));
! 986: }
! 987:
! 988: oc = lookup_option (&server_universe, options, SV_LOCAL_PORT);
! 989: if (oc &&
! 990: evaluate_option_cache (&db, (struct packet *)0,
! 991: (struct lease *)0, (struct client_state *)0,
! 992: options,
! 993: (struct option_state *)0,
! 994: &global_scope, oc, MDL)) {
! 995: if (db.len == 2) {
! 996: local_port = htons (getUShort (db.data));
! 997: } else
! 998: log_fatal ("invalid local port data length");
! 999: data_string_forget (&db, MDL);
! 1000: }
! 1001:
! 1002: oc = lookup_option (&server_universe, options, SV_REMOTE_PORT);
! 1003: if (oc &&
! 1004: evaluate_option_cache (&db, (struct packet *)0,
! 1005: (struct lease *)0, (struct client_state *)0,
! 1006: options, (struct option_state *)0,
! 1007: &global_scope, oc, MDL)) {
! 1008: if (db.len == 2) {
! 1009: remote_port = htons (getUShort (db.data));
! 1010: } else
! 1011: log_fatal ("invalid remote port data length");
! 1012: data_string_forget (&db, MDL);
! 1013: }
! 1014:
! 1015: oc = lookup_option (&server_universe, options,
! 1016: SV_LIMITED_BROADCAST_ADDRESS);
! 1017: if (oc &&
! 1018: evaluate_option_cache (&db, (struct packet *)0,
! 1019: (struct lease *)0, (struct client_state *)0,
! 1020: options, (struct option_state *)0,
! 1021: &global_scope, oc, MDL)) {
! 1022: if (db.len == 4) {
! 1023: memcpy (&limited_broadcast, db.data, 4);
! 1024: } else
! 1025: log_fatal ("invalid broadcast address data length");
! 1026: data_string_forget (&db, MDL);
! 1027: }
! 1028:
! 1029: oc = lookup_option (&server_universe, options,
! 1030: SV_LOCAL_ADDRESS);
! 1031: if (oc &&
! 1032: evaluate_option_cache (&db, (struct packet *)0,
! 1033: (struct lease *)0, (struct client_state *)0,
! 1034: options, (struct option_state *)0,
! 1035: &global_scope, oc, MDL)) {
! 1036: if (db.len == 4) {
! 1037: memcpy (&local_address, db.data, 4);
! 1038: } else
! 1039: log_fatal ("invalid local address data length");
! 1040: data_string_forget (&db, MDL);
! 1041: }
! 1042:
! 1043: oc = lookup_option (&server_universe, options, SV_DDNS_UPDATE_STYLE);
! 1044: if (oc) {
! 1045: if (evaluate_option_cache (&db, (struct packet *)0,
! 1046: (struct lease *)0,
! 1047: (struct client_state *)0,
! 1048: options,
! 1049: (struct option_state *)0,
! 1050: &global_scope, oc, MDL)) {
! 1051: if (db.len == 1) {
! 1052: ddns_update_style = db.data [0];
! 1053: } else
! 1054: log_fatal ("invalid dns update type");
! 1055: data_string_forget (&db, MDL);
! 1056: }
! 1057: } else {
! 1058: ddns_update_style = DDNS_UPDATE_STYLE_NONE;
! 1059: }
! 1060:
! 1061: oc = lookup_option (&server_universe, options, SV_LOG_FACILITY);
! 1062: if (oc) {
! 1063: if (evaluate_option_cache (&db, (struct packet *)0,
! 1064: (struct lease *)0,
! 1065: (struct client_state *)0,
! 1066: options,
! 1067: (struct option_state *)0,
! 1068: &global_scope, oc, MDL)) {
! 1069: if (db.len == 1) {
! 1070: closelog ();
! 1071: openlog ("dhcpd", LOG_NDELAY, db.data[0]);
! 1072: /* Log the startup banner into the new
! 1073: log file. */
! 1074: if (!quiet) {
! 1075: /* Don't log to stderr twice. */
! 1076: tmp = log_perror;
! 1077: log_perror = 0;
! 1078: log_info("%s %s",
! 1079: message, PACKAGE_VERSION);
! 1080: log_info (copyright);
! 1081: log_info (arr);
! 1082: log_info (url);
! 1083: log_perror = tmp;
! 1084: }
! 1085: } else
! 1086: log_fatal ("invalid log facility");
! 1087: data_string_forget (&db, MDL);
! 1088: }
! 1089: }
! 1090:
! 1091: oc = lookup_option(&server_universe, options, SV_DELAYED_ACK);
! 1092: if (oc &&
! 1093: evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
! 1094: &global_scope, oc, MDL)) {
! 1095: if (db.len == 2) {
! 1096: max_outstanding_acks = htons(getUShort(db.data));
! 1097: } else {
! 1098: log_fatal("invalid max delayed ACK count ");
! 1099: }
! 1100: data_string_forget(&db, MDL);
! 1101: }
! 1102:
! 1103: oc = lookup_option(&server_universe, options, SV_MAX_ACK_DELAY);
! 1104: if (oc &&
! 1105: evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
! 1106: &global_scope, oc, MDL)) {
! 1107: u_int32_t timeval;
! 1108:
! 1109: if (db.len != 4)
! 1110: log_fatal("invalid max ack delay configuration");
! 1111:
! 1112: timeval = getULong(db.data);
! 1113: max_ack_delay_secs = timeval / 1000000;
! 1114: max_ack_delay_usecs = timeval % 1000000;
! 1115:
! 1116: data_string_forget(&db, MDL);
! 1117: }
! 1118:
! 1119: /* Don't need the options anymore. */
! 1120: option_state_dereference (&options, MDL);
! 1121:
! 1122: #if defined (NSUPDATE)
! 1123: /* If old-style ddns updates have been requested, parse the
! 1124: old-style ddns updater. */
! 1125: if (ddns_update_style == 1) {
! 1126: struct executable_statement **e, *s;
! 1127:
! 1128: if (root_group -> statements) {
! 1129: s = (struct executable_statement *)0;
! 1130: if (!executable_statement_allocate (&s, MDL))
! 1131: log_fatal ("no memory for ddns updater");
! 1132: executable_statement_reference
! 1133: (&s -> next, root_group -> statements, MDL);
! 1134: executable_statement_dereference
! 1135: (&root_group -> statements, MDL);
! 1136: executable_statement_reference
! 1137: (&root_group -> statements, s, MDL);
! 1138: s -> op = statements_statement;
! 1139: e = &s -> data.statements;
! 1140: executable_statement_dereference (&s, MDL);
! 1141: } else {
! 1142: e = &root_group -> statements;
! 1143: }
! 1144:
! 1145: /* Set up the standard name service updater routine. */
! 1146: parse = NULL;
! 1147: result = new_parse(&parse, -1, old_nsupdate,
! 1148: sizeof(old_nsupdate) - 1,
! 1149: "old name service update routine", 0);
! 1150: if (result != ISC_R_SUCCESS)
! 1151: log_fatal ("can't begin parsing old ddns updater!");
! 1152:
! 1153: if (parse != NULL) {
! 1154: tmp = 0;
! 1155: if (!(parse_executable_statements(e, parse, &tmp,
! 1156: context_any))) {
! 1157: end_parse(&parse);
! 1158: log_fatal("can't parse standard ddns updater!");
! 1159: }
! 1160: }
! 1161: end_parse(&parse);
! 1162: }
! 1163: #endif
! 1164: }
! 1165:
! 1166: void postdb_startup (void)
! 1167: {
! 1168: /* Initialize the omapi listener state. */
! 1169: if (omapi_port != -1) {
! 1170: omapi_listener_start (0);
! 1171: }
! 1172:
! 1173: #if defined (FAILOVER_PROTOCOL)
! 1174: /* Initialize the failover listener state. */
! 1175: dhcp_failover_startup ();
! 1176: #endif
! 1177:
! 1178: /*
! 1179: * Begin our lease timeout background task.
! 1180: */
! 1181: schedule_all_ipv6_lease_timeouts();
! 1182: }
! 1183:
! 1184: /* Print usage message. */
! 1185:
! 1186: static void
! 1187: usage(void) {
! 1188: log_info("%s %s", message, PACKAGE_VERSION);
! 1189: log_info(copyright);
! 1190: log_info(arr);
! 1191:
! 1192: log_fatal("Usage: dhcpd [-p <UDP port #>] [-f] [-d] [-q] [-t|-T]\n"
! 1193: #ifdef DHCPv6
! 1194: " [-4|-6] [-cf config-file] [-lf lease-file]\n"
! 1195: #else /* !DHCPv6 */
! 1196: " [-cf config-file] [-lf lease-file]\n"
! 1197: #endif /* DHCPv6 */
! 1198: #if defined (PARANOIA)
! 1199: /* meld into the following string */
! 1200: " [-user user] [-group group] [-chroot dir]\n"
! 1201: #endif /* PARANOIA */
! 1202: #if defined (TRACING)
! 1203: " [-tf trace-output-file]\n"
! 1204: " [-play trace-input-file]\n"
! 1205: #endif /* TRACING */
! 1206: " [-pf pid-file] [--no-pid] [-s server]\n"
! 1207: " [if0 [...ifN]]");
! 1208: }
! 1209:
! 1210: void lease_pinged (from, packet, length)
! 1211: struct iaddr from;
! 1212: u_int8_t *packet;
! 1213: int length;
! 1214: {
! 1215: struct lease *lp;
! 1216:
! 1217: /* Don't try to look up a pinged lease if we aren't trying to
! 1218: ping one - otherwise somebody could easily make us churn by
! 1219: just forging repeated ICMP EchoReply packets for us to look
! 1220: up. */
! 1221: if (!outstanding_pings)
! 1222: return;
! 1223:
! 1224: lp = (struct lease *)0;
! 1225: if (!find_lease_by_ip_addr (&lp, from, MDL)) {
! 1226: log_debug ("unexpected ICMP Echo Reply from %s",
! 1227: piaddr (from));
! 1228: return;
! 1229: }
! 1230:
! 1231: if (!lp -> state) {
! 1232: #if defined (FAILOVER_PROTOCOL)
! 1233: if (!lp -> pool ||
! 1234: !lp -> pool -> failover_peer)
! 1235: #endif
! 1236: log_debug ("ICMP Echo Reply for %s late or spurious.",
! 1237: piaddr (from));
! 1238: goto out;
! 1239: }
! 1240:
! 1241: if (lp -> ends > cur_time) {
! 1242: log_debug ("ICMP Echo reply while lease %s valid.",
! 1243: piaddr (from));
! 1244: }
! 1245:
! 1246: /* At this point it looks like we pinged a lease and got a
! 1247: response, which shouldn't have happened. */
! 1248: data_string_forget (&lp -> state -> parameter_request_list, MDL);
! 1249: free_lease_state (lp -> state, MDL);
! 1250: lp -> state = (struct lease_state *)0;
! 1251:
! 1252: abandon_lease (lp, "pinged before offer");
! 1253: cancel_timeout (lease_ping_timeout, lp);
! 1254: --outstanding_pings;
! 1255: out:
! 1256: lease_dereference (&lp, MDL);
! 1257: }
! 1258:
! 1259: void lease_ping_timeout (vlp)
! 1260: void *vlp;
! 1261: {
! 1262: struct lease *lp = vlp;
! 1263:
! 1264: #if defined (DEBUG_MEMORY_LEAKAGE)
! 1265: unsigned long previous_outstanding = dmalloc_outstanding;
! 1266: #endif
! 1267:
! 1268: --outstanding_pings;
! 1269: dhcp_reply (lp);
! 1270:
! 1271: #if defined (DEBUG_MEMORY_LEAKAGE)
! 1272: log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
! 1273: dmalloc_generation,
! 1274: dmalloc_outstanding - previous_outstanding,
! 1275: dmalloc_outstanding, dmalloc_longterm);
! 1276: #endif
! 1277: #if defined (DEBUG_MEMORY_LEAKAGE)
! 1278: dmalloc_dump_outstanding ();
! 1279: #endif
! 1280: }
! 1281:
! 1282: int dhcpd_interface_setup_hook (struct interface_info *ip, struct iaddr *ia)
! 1283: {
! 1284: struct subnet *subnet;
! 1285: struct shared_network *share;
! 1286: isc_result_t status;
! 1287:
! 1288: /* Special case for fallback network - not sure why this is
! 1289: necessary. */
! 1290: if (!ia) {
! 1291: const char *fnn = "fallback-net";
! 1292: status = shared_network_allocate (&ip -> shared_network, MDL);
! 1293: if (status != ISC_R_SUCCESS)
! 1294: log_fatal ("No memory for shared subnet: %s",
! 1295: isc_result_totext (status));
! 1296: ip -> shared_network -> name = dmalloc (strlen (fnn) + 1, MDL);
! 1297: strcpy (ip -> shared_network -> name, fnn);
! 1298: return 1;
! 1299: }
! 1300:
! 1301: /* If there's a registered subnet for this address,
! 1302: connect it together... */
! 1303: subnet = (struct subnet *)0;
! 1304: if (find_subnet (&subnet, *ia, MDL)) {
! 1305: /* If this interface has multiple aliases on the same
! 1306: subnet, ignore all but the first we encounter. */
! 1307: if (!subnet -> interface) {
! 1308: interface_reference (&subnet -> interface, ip, MDL);
! 1309: subnet -> interface_address = *ia;
! 1310: } else if (subnet -> interface != ip) {
! 1311: log_error ("Multiple interfaces match the %s: %s %s",
! 1312: "same subnet",
! 1313: subnet -> interface -> name, ip -> name);
! 1314: }
! 1315: share = subnet -> shared_network;
! 1316: if (ip -> shared_network &&
! 1317: ip -> shared_network != share) {
! 1318: log_fatal ("Interface %s matches multiple shared %s",
! 1319: ip -> name, "networks");
! 1320: } else {
! 1321: if (!ip -> shared_network)
! 1322: shared_network_reference
! 1323: (&ip -> shared_network, share, MDL);
! 1324: }
! 1325:
! 1326: if (!share -> interface) {
! 1327: interface_reference (&share -> interface, ip, MDL);
! 1328: } else if (share -> interface != ip) {
! 1329: log_error ("Multiple interfaces match the %s: %s %s",
! 1330: "same shared network",
! 1331: share -> interface -> name, ip -> name);
! 1332: }
! 1333: subnet_dereference (&subnet, MDL);
! 1334: }
! 1335: return 1;
! 1336: }
! 1337:
! 1338: static TIME shutdown_time;
! 1339: static int omapi_connection_count;
! 1340: enum dhcp_shutdown_state shutdown_state;
! 1341:
! 1342: isc_result_t dhcp_io_shutdown (omapi_object_t *obj, void *foo)
! 1343: {
! 1344: /* Shut down all listeners. */
! 1345: if (shutdown_state == shutdown_listeners &&
! 1346: obj -> type == omapi_type_listener &&
! 1347: obj -> inner &&
! 1348: obj -> inner -> type == omapi_type_protocol_listener) {
! 1349: omapi_listener_destroy (obj, MDL);
! 1350: return ISC_R_SUCCESS;
! 1351: }
! 1352:
! 1353: /* Shut down all existing omapi connections. */
! 1354: if (obj -> type == omapi_type_connection &&
! 1355: obj -> inner &&
! 1356: obj -> inner -> type == omapi_type_protocol) {
! 1357: if (shutdown_state == shutdown_drop_omapi_connections) {
! 1358: omapi_disconnect (obj, 1);
! 1359: }
! 1360: omapi_connection_count++;
! 1361: if (shutdown_state == shutdown_omapi_connections) {
! 1362: omapi_disconnect (obj, 0);
! 1363: return ISC_R_SUCCESS;
! 1364: }
! 1365: }
! 1366:
! 1367: /* Shutdown all DHCP interfaces. */
! 1368: if (obj -> type == dhcp_type_interface &&
! 1369: shutdown_state == shutdown_dhcp) {
! 1370: dhcp_interface_remove (obj, (omapi_object_t *)0);
! 1371: return ISC_R_SUCCESS;
! 1372: }
! 1373: return ISC_R_SUCCESS;
! 1374: }
! 1375:
! 1376: static isc_result_t dhcp_io_shutdown_countdown (void *vlp)
! 1377: {
! 1378: #if defined (FAILOVER_PROTOCOL)
! 1379: dhcp_failover_state_t *state;
! 1380: int failover_connection_count = 0;
! 1381: #endif
! 1382: struct timeval tv;
! 1383:
! 1384: oncemore:
! 1385: if (shutdown_state == shutdown_listeners ||
! 1386: shutdown_state == shutdown_omapi_connections ||
! 1387: shutdown_state == shutdown_drop_omapi_connections ||
! 1388: shutdown_state == shutdown_dhcp) {
! 1389: omapi_connection_count = 0;
! 1390: omapi_io_state_foreach (dhcp_io_shutdown, 0);
! 1391: }
! 1392:
! 1393: if ((shutdown_state == shutdown_listeners ||
! 1394: shutdown_state == shutdown_omapi_connections ||
! 1395: shutdown_state == shutdown_drop_omapi_connections) &&
! 1396: omapi_connection_count == 0) {
! 1397: shutdown_state = shutdown_dhcp;
! 1398: shutdown_time = cur_time;
! 1399: goto oncemore;
! 1400: } else if (shutdown_state == shutdown_listeners &&
! 1401: cur_time - shutdown_time > 4) {
! 1402: shutdown_state = shutdown_omapi_connections;
! 1403: shutdown_time = cur_time;
! 1404: } else if (shutdown_state == shutdown_omapi_connections &&
! 1405: cur_time - shutdown_time > 4) {
! 1406: shutdown_state = shutdown_drop_omapi_connections;
! 1407: shutdown_time = cur_time;
! 1408: } else if (shutdown_state == shutdown_drop_omapi_connections &&
! 1409: cur_time - shutdown_time > 4) {
! 1410: shutdown_state = shutdown_dhcp;
! 1411: shutdown_time = cur_time;
! 1412: goto oncemore;
! 1413: } else if (shutdown_state == shutdown_dhcp &&
! 1414: cur_time - shutdown_time > 4) {
! 1415: shutdown_state = shutdown_done;
! 1416: shutdown_time = cur_time;
! 1417: }
! 1418:
! 1419: #if defined (FAILOVER_PROTOCOL)
! 1420: /* Set all failover peers into the shutdown state. */
! 1421: if (shutdown_state == shutdown_dhcp) {
! 1422: for (state = failover_states; state; state = state -> next) {
! 1423: if (state -> me.state == normal) {
! 1424: dhcp_failover_set_state (state, shut_down);
! 1425: failover_connection_count++;
! 1426: }
! 1427: if (state -> me.state == shut_down &&
! 1428: state -> partner.state != partner_down)
! 1429: failover_connection_count++;
! 1430: }
! 1431: }
! 1432:
! 1433: if (shutdown_state == shutdown_done) {
! 1434: for (state = failover_states; state; state = state -> next) {
! 1435: if (state -> me.state == shut_down) {
! 1436: if (state -> link_to_peer)
! 1437: dhcp_failover_link_dereference (&state -> link_to_peer,
! 1438: MDL);
! 1439: dhcp_failover_set_state (state, recover);
! 1440: }
! 1441: }
! 1442: #if defined (DEBUG_MEMORY_LEAKAGE) && \
! 1443: defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
! 1444: free_everything ();
! 1445: omapi_print_dmalloc_usage_by_caller ();
! 1446: #endif
! 1447: exit (0);
! 1448: }
! 1449: #else
! 1450: if (shutdown_state == shutdown_done) {
! 1451: #if defined (DEBUG_MEMORY_LEAKAGE) && \
! 1452: defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
! 1453: free_everything ();
! 1454: omapi_print_dmalloc_usage_by_caller ();
! 1455: #endif
! 1456: exit (0);
! 1457: }
! 1458: #endif
! 1459: if (shutdown_state == shutdown_dhcp &&
! 1460: #if defined(FAILOVER_PROTOCOL)
! 1461: !failover_connection_count &&
! 1462: #endif
! 1463: ISC_TRUE) {
! 1464: shutdown_state = shutdown_done;
! 1465: shutdown_time = cur_time;
! 1466: goto oncemore;
! 1467: }
! 1468: tv.tv_sec = cur_tv.tv_sec + 1;
! 1469: tv.tv_usec = cur_tv.tv_usec;
! 1470: add_timeout (&tv,
! 1471: (void (*)(void *))dhcp_io_shutdown_countdown, 0, 0, 0);
! 1472: return ISC_R_SUCCESS;
! 1473: }
! 1474:
! 1475: isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
! 1476: control_object_state_t newstate)
! 1477: {
! 1478: if (newstate == server_shutdown) {
! 1479: shutdown_time = cur_time;
! 1480: shutdown_state = shutdown_listeners;
! 1481: dhcp_io_shutdown_countdown (0);
! 1482: return ISC_R_SUCCESS;
! 1483: }
! 1484: return ISC_R_INVALIDARG;
! 1485: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>