server/dhcpd.c

Go to the documentation of this file.
00001 /* dhcpd.c
00002 
00003    DHCP Server Daemon. */
00004 
00005 /*
00006  * Copyright (c) 2004-2014 by Internet Systems Consortium, Inc. ("ISC")
00007  * Copyright (c) 1996-2003 by Internet Software Consortium
00008  *
00009  * Permission to use, copy, modify, and distribute this software for any
00010  * purpose with or without fee is hereby granted, provided that the above
00011  * copyright notice and this permission notice appear in all copies.
00012  *
00013  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00014  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00015  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00016  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00017  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00018  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00019  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00020  *
00021  *   Internet Systems Consortium, Inc.
00022  *   950 Charter Street
00023  *   Redwood City, CA 94063
00024  *   <info@isc.org>
00025  *   https://www.isc.org/
00026  *
00027  */
00028 
00029 static const char copyright[] =
00030 "Copyright 2004-2014 Internet Systems Consortium.";
00031 static const char arr [] = "All rights reserved.";
00032 static const char message [] = "Internet Systems Consortium DHCP Server";
00033 static const char url [] =
00034 "For info, please visit https://www.isc.org/software/dhcp/";
00035 
00036 #include "dhcpd.h"
00037 #include <omapip/omapip_p.h>
00038 #include <syslog.h>
00039 #include <signal.h>
00040 #include <errno.h>
00041 #include <limits.h>
00042 #include <sys/types.h>
00043 #include <sys/time.h>
00044 
00045 #if defined (PARANOIA)
00046 #  include <sys/types.h>
00047 #  include <unistd.h>
00048 #  include <pwd.h>
00049 /* get around the ISC declaration of group */
00050 #  define group real_group 
00051 #    include <grp.h>
00052 #  undef group
00053 #endif /* PARANOIA */
00054 
00055 #include "trace.h"
00056 
00057 #ifndef UNIT_TEST
00058 static void usage(void);
00059 #endif
00060 
00061 struct iaddr server_identifier;
00062 int server_identifier_matched;
00063 
00064 #if defined (NSUPDATE)
00065 
00066 /* This stuff is always executed to figure the default values for certain
00067    ddns variables. */
00068 
00069 char std_nsupdate [] = "                                                    \n\
00070 option server.ddns-hostname =                                               \n\
00071   pick (option fqdn.hostname, option host-name);                            \n\
00072 option server.ddns-domainname = config-option domain-name;                  \n\
00073 option server.ddns-rev-domainname = \"in-addr.arpa.\";";
00074 
00075 #endif /* NSUPDATE */
00076 int ddns_update_style;
00077 int dont_use_fsync = 0; /* 0 = default, use fsync, 1 = don't use fsync */
00078 
00079 const char *path_dhcpd_conf = _PATH_DHCPD_CONF;
00080 const char *path_dhcpd_db = _PATH_DHCPD_DB;
00081 const char *path_dhcpd_pid = _PATH_DHCPD_PID;
00082 /* False (default) => we write and use a pid file */
00083 isc_boolean_t no_pid_file = ISC_FALSE;
00084 
00085 int dhcp_max_agent_option_packet_length = DHCP_MTU_MAX;
00086 
00087 static omapi_auth_key_t *omapi_key = (omapi_auth_key_t *)0;
00088 int omapi_port;
00089 
00090 #if defined (TRACING)
00091 trace_type_t *trace_srandom;
00092 #endif
00093 
00094 static isc_result_t verify_addr (omapi_object_t *l, omapi_addr_t *addr) {
00095         return ISC_R_SUCCESS;
00096 }
00097 
00098 static isc_result_t verify_auth (omapi_object_t *p, omapi_auth_key_t *a) {
00099         if (a != omapi_key)
00100                 return DHCP_R_INVALIDKEY;
00101         return ISC_R_SUCCESS;
00102 }
00103 
00104 static void omapi_listener_start (void *foo)
00105 {
00106         omapi_object_t *listener;
00107         isc_result_t result;
00108         struct timeval tv;
00109 
00110         listener = (omapi_object_t *)0;
00111         result = omapi_generic_new (&listener, MDL);
00112         if (result != ISC_R_SUCCESS)
00113                 log_fatal ("Can't allocate new generic object: %s",
00114                            isc_result_totext (result));
00115         result = omapi_protocol_listen (listener,
00116                                         (unsigned)omapi_port, 1);
00117         if (result == ISC_R_SUCCESS && omapi_key)
00118                 result = omapi_protocol_configure_security
00119                         (listener, verify_addr, verify_auth);
00120         if (result != ISC_R_SUCCESS) {
00121                 log_error ("Can't start OMAPI protocol: %s",
00122                            isc_result_totext (result));
00123                 tv.tv_sec = cur_tv.tv_sec + 5;
00124                 tv.tv_usec = cur_tv.tv_usec;
00125                 add_timeout (&tv, omapi_listener_start, 0, 0, 0);
00126         }
00127         omapi_object_dereference (&listener, MDL);
00128 }
00129 
00130 #if defined (PARANOIA)
00131 /* to be used in one of two possible scenarios */
00132 static void setup_chroot (char *chroot_dir) {
00133   if (geteuid())
00134     log_fatal ("you must be root to use chroot");
00135 
00136   if (chroot(chroot_dir)) {
00137     log_fatal ("chroot(\"%s\"): %m", chroot_dir);
00138   }
00139   if (chdir ("/")) {
00140     /* probably permission denied */
00141     log_fatal ("chdir(\"/\"): %m");
00142   }
00143 }
00144 #endif /* PARANOIA */
00145 
00146 #ifndef UNIT_TEST
00147 int 
00148 main(int argc, char **argv) {
00149         int fd;
00150         int i, status;
00151         struct servent *ent;
00152         char *s;
00153         int cftest = 0;
00154         int lftest = 0;
00155 #ifndef DEBUG
00156         int pid;
00157         char pbuf [20];
00158         int daemon = 1;
00159 #endif
00160         int quiet = 0;
00161         char *server = (char *)0;
00162         isc_result_t result;
00163         unsigned seed;
00164         struct interface_info *ip;
00165 #if defined (NSUPDATE)
00166         struct parse *parse;
00167         int lose;
00168 #endif
00169         int no_dhcpd_conf = 0;
00170         int no_dhcpd_db = 0;
00171         int no_dhcpd_pid = 0;
00172 #ifdef DHCPv6
00173         int local_family_set = 0;
00174 #endif /* DHCPv6 */
00175 #if defined (TRACING)
00176         char *traceinfile = (char *)0;
00177         char *traceoutfile = (char *)0;
00178 #endif
00179 
00180 #if defined (PARANOIA)
00181         char *set_user   = 0;
00182         char *set_group  = 0;
00183         char *set_chroot = 0;
00184 
00185         uid_t set_uid = 0;
00186         gid_t set_gid = 0;
00187 #endif /* PARANOIA */
00188 
00189         /* Make sure that file descriptors 0 (stdin), 1, (stdout), and
00190            2 (stderr) are open. To do this, we assume that when we
00191            open a file the lowest available file descriptor is used. */
00192         fd = open("/dev/null", O_RDWR | O_CLOEXEC);
00193         if (fd == 0)
00194                 fd = open("/dev/null", O_RDWR | O_CLOEXEC);
00195         if (fd == 1)
00196                 fd = open("/dev/null", O_RDWR | O_CLOEXEC);
00197         if (fd == 2)
00198                 log_perror = 0; /* No sense logging to /dev/null. */
00199         else if (fd != -1)
00200                 close(fd);
00201 
00202         /* Set up the isc and dns library managers */
00203         status = dhcp_context_create(DHCP_CONTEXT_PRE_DB,
00204                                      NULL, NULL);
00205         if (status != ISC_R_SUCCESS)
00206                 log_fatal("Can't initialize context: %s",
00207                           isc_result_totext(status));
00208 
00209         /* Set up the client classification system. */
00210         classification_setup ();
00211 
00212         /* Initialize the omapi system. */
00213         result = omapi_init ();
00214         if (result != ISC_R_SUCCESS)
00215                 log_fatal ("Can't initialize OMAPI: %s",
00216                            isc_result_totext (result));
00217 
00218         /* Set up the OMAPI wrappers for common objects. */
00219         dhcp_db_objects_setup ();
00220         /* Set up the OMAPI wrappers for various server database internal
00221            objects. */
00222         dhcp_common_objects_setup ();
00223 
00224         /* Initially, log errors to stderr as well as to syslogd. */
00225         openlog ("dhcpd", LOG_NDELAY, DHCPD_LOG_FACILITY);
00226 
00227         for (i = 1; i < argc; i++) {
00228                 if (!strcmp (argv [i], "-p")) {
00229                         if (++i == argc)
00230                                 usage ();
00231                         local_port = validate_port (argv [i]);
00232                         log_debug ("binding to user-specified port %d",
00233                                ntohs (local_port));
00234                 } else if (!strcmp (argv [i], "-f")) {
00235 #ifndef DEBUG
00236                         daemon = 0;
00237 #endif
00238                         log_perror = 0;
00239                 } else if (!strcmp (argv [i], "-d")) {
00240 #ifndef DEBUG
00241                         daemon = 0;
00242 #endif
00243                         log_perror = -1;
00244                 } else if (!strcmp (argv [i], "-s")) {
00245                         if (++i == argc)
00246                                 usage ();
00247                         server = argv [i];
00248 #if defined (PARANOIA)
00249                 } else if (!strcmp (argv [i], "-user")) {
00250                         if (++i == argc)
00251                                 usage ();
00252                         set_user = argv [i];
00253                 } else if (!strcmp (argv [i], "-group")) {
00254                         if (++i == argc)
00255                                 usage ();
00256                         set_group = argv [i];
00257                 } else if (!strcmp (argv [i], "-chroot")) {
00258                         if (++i == argc)
00259                                 usage ();
00260                         set_chroot = argv [i];
00261 #endif /* PARANOIA */
00262                 } else if (!strcmp (argv [i], "-cf")) {
00263                         if (++i == argc)
00264                                 usage ();
00265                         path_dhcpd_conf = argv [i];
00266                         no_dhcpd_conf = 1;
00267                 } else if (!strcmp (argv [i], "-lf")) {
00268                         if (++i == argc)
00269                                 usage ();
00270                         path_dhcpd_db = argv [i];
00271                         no_dhcpd_db = 1;
00272                 } else if (!strcmp (argv [i], "-pf")) {
00273                         if (++i == argc)
00274                                 usage ();
00275                         path_dhcpd_pid = argv [i];
00276                         no_dhcpd_pid = 1;
00277                 } else if (!strcmp(argv[i], "--no-pid")) {
00278                         no_pid_file = ISC_TRUE;
00279                 } else if (!strcmp (argv [i], "-t")) {
00280                         /* test configurations only */
00281 #ifndef DEBUG
00282                         daemon = 0;
00283 #endif
00284                         cftest = 1;
00285                         log_perror = -1;
00286                 } else if (!strcmp (argv [i], "-T")) {
00287                         /* test configurations and lease file only */
00288 #ifndef DEBUG
00289                         daemon = 0;
00290 #endif
00291                         cftest = 1;
00292                         lftest = 1;
00293                         log_perror = -1;
00294                 } else if (!strcmp (argv [i], "-q")) {
00295                         quiet = 1;
00296                         quiet_interface_discovery = 1;
00297 #ifdef DHCPv6
00298                 } else if (!strcmp(argv[i], "-4")) {
00299                         if (local_family_set && (local_family != AF_INET)) {
00300                                 log_fatal("Server cannot run in both IPv4 and "
00301                                           "IPv6 mode at the same time.");
00302                         }
00303                         local_family = AF_INET;
00304                         local_family_set = 1;
00305                 } else if (!strcmp(argv[i], "-6")) {
00306                         if (local_family_set && (local_family != AF_INET6)) {
00307                                 log_fatal("Server cannot run in both IPv4 and "
00308                                           "IPv6 mode at the same time.");
00309                         }
00310                         local_family = AF_INET6;
00311                         local_family_set = 1;
00312 #endif /* DHCPv6 */
00313                 } else if (!strcmp (argv [i], "--version")) {
00314                         log_info("isc-dhcpd-%s", PACKAGE_VERSION);
00315                         exit (0);
00316 #if defined (TRACING)
00317                 } else if (!strcmp (argv [i], "-tf")) {
00318                         if (++i == argc)
00319                                 usage ();
00320                         traceoutfile = argv [i];
00321                 } else if (!strcmp (argv [i], "-play")) {
00322                         if (++i == argc)
00323                                 usage ();
00324                         traceinfile = argv [i];
00325                         trace_replay_init ();
00326 #endif /* TRACING */
00327                 } else if (argv [i][0] == '-') {
00328                         usage ();
00329                 } else {
00330                         struct interface_info *tmp =
00331                                 (struct interface_info *)0;
00332                         if (strlen(argv[i]) >= sizeof(tmp->name))
00333                                 log_fatal("%s: interface name too long "
00334                                           "(is %ld)",
00335                                           argv[i], (long)strlen(argv[i]));
00336                         result = interface_allocate (&tmp, MDL);
00337                         if (result != ISC_R_SUCCESS)
00338                                 log_fatal ("Insufficient memory to %s %s: %s",
00339                                            "record interface", argv [i],
00340                                            isc_result_totext (result));
00341                         strcpy (tmp -> name, argv [i]);
00342                         if (interfaces) {
00343                                 interface_reference (&tmp -> next,
00344                                                      interfaces, MDL);
00345                                 interface_dereference (&interfaces, MDL);
00346                         }
00347                         interface_reference (&interfaces, tmp, MDL);
00348                         tmp -> flags = INTERFACE_REQUESTED;
00349                 }
00350         }
00351 
00352         if (!no_dhcpd_conf && (s = getenv ("PATH_DHCPD_CONF"))) {
00353                 path_dhcpd_conf = s;
00354         }
00355 
00356 #ifdef DHCPv6
00357         if (local_family == AF_INET6) {
00358                 /* DHCPv6: override DHCPv4 lease and pid filenames */
00359                 if (!no_dhcpd_db) {
00360                         if ((s = getenv ("PATH_DHCPD6_DB")))
00361                                 path_dhcpd_db = s;
00362                         else
00363                                 path_dhcpd_db = _PATH_DHCPD6_DB;
00364                 }
00365                 if (!no_dhcpd_pid) {
00366                         if ((s = getenv ("PATH_DHCPD6_PID")))
00367                                 path_dhcpd_pid = s;
00368                         else
00369                                 path_dhcpd_pid = _PATH_DHCPD6_PID;
00370                 }
00371         } else
00372 #else /* !DHCPv6 */
00373         {
00374                 if (!no_dhcpd_db && (s = getenv ("PATH_DHCPD_DB"))) {
00375                         path_dhcpd_db = s;
00376                 }
00377                 if (!no_dhcpd_pid && (s = getenv ("PATH_DHCPD_PID"))) {
00378                         path_dhcpd_pid = s;
00379                 }
00380         }
00381 #endif /* DHCPv6 */
00382 
00383         /*
00384          * convert relative path names to absolute, for files that need
00385          * to be reopened after chdir() has been called
00386          */
00387         if (path_dhcpd_db[0] != '/') {
00388                 const char *path = path_dhcpd_db;
00389                 path_dhcpd_db = realpath(path_dhcpd_db, NULL);
00390                 if (path_dhcpd_db == NULL)
00391                         log_fatal("Failed to get realpath for %s: %s", path, 
00392                                    strerror(errno));
00393         }
00394 
00395         if (!quiet) {
00396                 log_info("%s %s", message, PACKAGE_VERSION);
00397                 log_info (copyright);
00398                 log_info (arr);
00399                 log_info (url);
00400         } else {
00401                 quiet = 0;
00402                 log_perror = 0;
00403         }
00404 
00405 #if defined (TRACING)
00406         trace_init (set_time, MDL);
00407         if (traceoutfile) {
00408                 result = trace_begin (traceoutfile, MDL);
00409                 if (result != ISC_R_SUCCESS)
00410                         log_fatal ("Unable to begin trace: %s",
00411                                 isc_result_totext (result));
00412         }
00413         interface_trace_setup ();
00414         parse_trace_setup ();
00415         trace_srandom = trace_type_register ("random-seed", (void *)0,
00416                                              trace_seed_input,
00417                                              trace_seed_stop, MDL);
00418         trace_ddns_init();
00419 #endif
00420 
00421 #if defined (PARANOIA)
00422         /* get user and group info if those options were given */
00423         if (set_user) {
00424                 struct passwd *tmp_pwd;
00425 
00426                 if (geteuid())
00427                         log_fatal ("you must be root to set user");
00428 
00429                 if (!(tmp_pwd = getpwnam(set_user)))
00430                         log_fatal ("no such user: %s", set_user);
00431 
00432                 set_uid = tmp_pwd->pw_uid;
00433 
00434                 /* use the user's group as the default gid */
00435                 if (!set_group)
00436                         set_gid = tmp_pwd->pw_gid;
00437         }
00438 
00439         if (set_group) {
00440 /* get around the ISC declaration of group */
00441 #define group real_group
00442                 struct group *tmp_grp;
00443 
00444                 if (geteuid())
00445                         log_fatal ("you must be root to set group");
00446 
00447                 if (!(tmp_grp = getgrnam(set_group)))
00448                         log_fatal ("no such group: %s", set_group);
00449 
00450                 set_gid = tmp_grp->gr_gid;
00451 #undef group
00452         }
00453 
00454 #  if defined (EARLY_CHROOT)
00455         if (set_chroot) setup_chroot (set_chroot);
00456 #  endif /* EARLY_CHROOT */
00457 #endif /* PARANOIA */
00458 
00459         /* Default to the DHCP/BOOTP port. */
00460         if (!local_port)
00461         {
00462                 if ((s = getenv ("DHCPD_PORT"))) {
00463                         local_port = validate_port (s);
00464                         log_debug ("binding to environment-specified port %d",
00465                                    ntohs (local_port));
00466                 } else {
00467                         if (local_family == AF_INET) {
00468                                 ent = getservbyname("dhcp", "udp");
00469                                 if (ent == NULL) {
00470                                         local_port = htons(67);
00471                                 } else {
00472                                         local_port = ent->s_port;
00473                                 }
00474                         } else {
00475                                 /* INSIST(local_family == AF_INET6); */
00476                                 ent = getservbyname("dhcpv6-server", "udp");
00477                                 if (ent == NULL) {
00478                                         local_port = htons(547);
00479                                 } else {
00480                                         local_port = ent->s_port;
00481                                 }
00482                         }
00483 #ifndef __CYGWIN32__ /* XXX */
00484                         endservent ();
00485 #endif
00486                 }
00487         }
00488   
00489         if (local_family == AF_INET) {
00490                 remote_port = htons(ntohs(local_port) + 1);
00491         } else {
00492                 /* INSIST(local_family == AF_INET6); */
00493                 ent = getservbyname("dhcpv6-client", "udp");
00494                 if (ent == NULL) {
00495                         remote_port = htons(546);
00496                 } else {
00497                         remote_port = ent->s_port;
00498                 }
00499         }
00500 
00501         if (server) {
00502                 if (local_family != AF_INET) {
00503                         log_fatal("You can only specify address to send "
00504                                   "replies to when running an IPv4 server.");
00505                 }
00506                 if (!inet_aton (server, &limited_broadcast)) {
00507                         struct hostent *he;
00508                         he = gethostbyname (server);
00509                         if (he) {
00510                                 memcpy (&limited_broadcast,
00511                                         he -> h_addr_list [0],
00512                                         sizeof limited_broadcast);
00513                         } else
00514                                 limited_broadcast.s_addr = INADDR_BROADCAST;
00515                 }
00516         } else {
00517                 limited_broadcast.s_addr = INADDR_BROADCAST;
00518         }
00519 
00520         /* Get the current time... */
00521         gettimeofday(&cur_tv, NULL);
00522 
00523         /* Set up the initial dhcp option universe. */
00524         initialize_common_option_spaces ();
00525         initialize_server_option_spaces ();
00526 
00527         /* Add the ddns update style enumeration prior to parsing. */
00528         add_enumeration (&ddns_styles);
00529         add_enumeration (&syslog_enum);
00530 #if defined (LDAP_CONFIGURATION)
00531         add_enumeration (&ldap_methods);
00532 #if defined (LDAP_USE_SSL)
00533         add_enumeration (&ldap_ssl_usage_enum);
00534         add_enumeration (&ldap_tls_reqcert_enum);
00535         add_enumeration (&ldap_tls_crlcheck_enum);
00536 #endif
00537 #endif
00538 
00539         if (!group_allocate (&root_group, MDL))
00540                 log_fatal ("Can't allocate root group!");
00541         root_group -> authoritative = 0;
00542 
00543         /* Set up various hooks. */
00544         dhcp_interface_setup_hook = dhcpd_interface_setup_hook;
00545         bootp_packet_handler = do_packet;
00546 #ifdef DHCPv6
00547         dhcpv6_packet_handler = do_packet6;
00548 #endif /* DHCPv6 */
00549 
00550 #if defined (NSUPDATE)
00551         /* Set up the standard name service updater routine. */
00552         parse = NULL;
00553         status = new_parse(&parse, -1, std_nsupdate, sizeof(std_nsupdate) - 1,
00554                             "standard name service update routine", 0);
00555         if (status != ISC_R_SUCCESS)
00556                 log_fatal ("can't begin parsing name service updater!");
00557 
00558         if (parse != NULL) {
00559                 lose = 0;
00560                 if (!(parse_executable_statements(&root_group->statements,
00561                                                   parse, &lose, context_any))) {
00562                         end_parse(&parse);
00563                         log_fatal("can't parse standard name service updater!");
00564                 }
00565                 end_parse(&parse);
00566         }
00567 #endif
00568 
00569         /* Initialize icmp support... */
00570         if (!cftest && !lftest)
00571                 icmp_startup (1, lease_pinged);
00572 
00573 #if defined (TRACING)
00574         if (traceinfile) {
00575             if (!no_dhcpd_db) {
00576                     log_error ("%s", "");
00577                     log_error ("** You must specify a lease file with -lf.");
00578                     log_error ("   Dhcpd will not overwrite your default");
00579                     log_fatal ("   lease file when playing back a trace. **");
00580             }           
00581             trace_file_replay (traceinfile);
00582 
00583 #if defined (DEBUG_MEMORY_LEAKAGE) && \
00584                 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
00585             free_everything ();
00586             omapi_print_dmalloc_usage_by_caller (); 
00587 #endif
00588 
00589             exit (0);
00590         }
00591 #endif
00592 
00593 #ifdef DHCPv6
00594         /* set up DHCPv6 hashes */
00595         if (!ia_new_hash(&ia_na_active, DEFAULT_HASH_SIZE, MDL)) {
00596                 log_fatal("Out of memory creating hash for active IA_NA.");
00597         }
00598         if (!ia_new_hash(&ia_ta_active, DEFAULT_HASH_SIZE, MDL)) {
00599                 log_fatal("Out of memory creating hash for active IA_TA.");
00600         }
00601         if (!ia_new_hash(&ia_pd_active, DEFAULT_HASH_SIZE, MDL)) {
00602                 log_fatal("Out of memory creating hash for active IA_PD.");
00603         }
00604 #endif /* DHCPv6 */
00605 
00606         /* Read the dhcpd.conf file... */
00607         if (readconf () != ISC_R_SUCCESS)
00608                 log_fatal ("Configuration file errors encountered -- exiting");
00609 
00610         postconf_initialization (quiet);
00611  
00612 #if defined (PARANOIA) && !defined (EARLY_CHROOT)
00613         if (set_chroot) setup_chroot (set_chroot);
00614 #endif /* PARANOIA && !EARLY_CHROOT */
00615 
00616         /* test option should cause an early exit */
00617         if (cftest && !lftest) 
00618                 exit(0);
00619 
00620         group_write_hook = group_writer;
00621 
00622         /* Start up the database... */
00623 #if defined (PARANOIA)
00624         db_startup (lftest, set_uid, set_gid);
00625 #else
00626         db_startup (lftest);
00627 #endif /* PARANOIA */
00628 
00629         if (lftest)
00630                 exit (0);
00631 
00632         /* Discover all the network interfaces and initialize them. */
00633         discover_interfaces(DISCOVER_SERVER);
00634 
00635 #ifdef DHCPv6
00636         /*
00637          * Remove addresses from our pools that we should not issue
00638          * to clients.
00639          *
00640          * We currently have no support for this in IPv4. It is not 
00641          * as important in IPv4, as making pools with ranges that 
00642          * leave out interfaces and hosts is fairly straightforward
00643          * using range notation, but not so handy with CIDR notation.
00644          */
00645         if (local_family == AF_INET6) {
00646                 mark_hosts_unavailable();
00647                 mark_phosts_unavailable();
00648                 mark_interfaces_unavailable();
00649         }
00650 #endif /* DHCPv6 */
00651 
00652 
00653         /* Make up a seed for the random number generator from current
00654            time plus the sum of the last four bytes of each
00655            interface's hardware address interpreted as an integer.
00656            Not much entropy, but we're booting, so we're not likely to
00657            find anything better. */
00658         seed = 0;
00659         for (ip = interfaces; ip; ip = ip -> next) {
00660                 int junk;
00661                 memcpy (&junk,
00662                         &ip -> hw_address.hbuf [ip -> hw_address.hlen -
00663                                                sizeof seed], sizeof seed);
00664                 seed += junk;
00665         }
00666         srandom (seed + cur_time);
00667 #if defined (TRACING)
00668         trace_seed_stash (trace_srandom, seed + cur_time);
00669 #endif
00670         postdb_startup ();
00671 
00672 #ifdef DHCPv6
00673         /*
00674          * Set server DHCPv6 identifier.
00675          * See dhcpv6.c for discussion of setting DUID.
00676          */
00677         if (set_server_duid_from_option() == ISC_R_SUCCESS) {
00678                 write_server_duid();
00679         } else {
00680                 if (!server_duid_isset()) {
00681                         if (generate_new_server_duid() != ISC_R_SUCCESS) {
00682                                 log_fatal("Unable to set server identifier.");
00683                         }
00684                         write_server_duid();
00685                 }
00686         }
00687 #endif /* DHCPv6 */
00688 
00689 #ifndef DEBUG
00690         if (daemon) {
00691                 /* First part of becoming a daemon... */
00692                 if ((pid = fork ()) < 0)
00693                         log_fatal ("Can't fork daemon: %m");
00694                 else if (pid)
00695                         exit (0);
00696         }
00697  
00698         /*
00699          * Deal with pid files.  If the user told us
00700          * not to write a file we don't read one either
00701          */
00702         if (no_pid_file == ISC_FALSE) {
00703                 /*Read previous pid file. */
00704                 if ((i = open (path_dhcpd_pid, O_RDONLY | O_CLOEXEC)) >= 0) {
00705                         status = read(i, pbuf, (sizeof pbuf) - 1);
00706                         close (i);
00707                         if (status > 0) {
00708                                 pbuf[status] = 0;
00709                                 pid = atoi(pbuf);
00710 
00711                                 /*
00712                                  * If there was a previous server process and
00713                                  * it is still running, abort
00714                                  */
00715                                 if (!pid ||
00716                                     (pid != getpid() && kill(pid, 0) == 0))
00717                                         log_fatal("There's already a "
00718                                                   "DHCP server running.");
00719                         }
00720                 }
00721 
00722                 /* Write new pid file. */
00723                 i = open(path_dhcpd_pid, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0644);
00724                 if (i >= 0) {
00725                         sprintf(pbuf, "%d\n", (int) getpid());
00726                         IGNORE_RET (write(i, pbuf, strlen(pbuf)));
00727                         close(i);
00728                 } else {
00729                         log_error("Can't create PID file %s: %m.",
00730                                   path_dhcpd_pid);
00731                 }
00732         }
00733 
00734 #if defined (PARANOIA)
00735         /* change uid to the specified one */
00736 
00737         if (set_gid) {
00738                 if (setgroups (0, (void *)0))
00739                         log_fatal ("setgroups: %m");
00740                 if (setgid (set_gid))
00741                         log_fatal ("setgid(%d): %m", (int) set_gid);
00742         }       
00743 
00744         if (set_uid) {
00745                 if (setuid (set_uid))
00746                         log_fatal ("setuid(%d): %m", (int) set_uid);
00747         }
00748 #endif /* PARANOIA */
00749 
00750         /* If we were requested to log to stdout on the command line,
00751            keep doing so; otherwise, stop. */
00752         if (log_perror == -1)
00753                 log_perror = 1;
00754         else
00755                 log_perror = 0;
00756 
00757         if (daemon) {
00758                 /* Become session leader and get pid... */
00759                 (void) setsid();
00760 
00761                 /* Close standard I/O descriptors. */
00762                 (void) close(0);
00763                 (void) close(1);
00764                 (void) close(2);
00765 
00766                 /* Reopen them on /dev/null. */
00767                 (void) open("/dev/null", O_RDWR | O_CLOEXEC);
00768                 (void) open("/dev/null", O_RDWR | O_CLOEXEC);
00769                 (void) open("/dev/null", O_RDWR | O_CLOEXEC);
00770                 log_perror = 0; /* No sense logging to /dev/null. */
00771 
00772                 IGNORE_RET (chdir("/"));
00773         }
00774 #endif /* !DEBUG */
00775 
00776 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
00777                 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
00778         dmalloc_cutoff_generation = dmalloc_generation;
00779         dmalloc_longterm = dmalloc_outstanding;
00780         dmalloc_outstanding = 0;
00781 #endif
00782 
00783         omapi_set_int_value ((omapi_object_t *)dhcp_control_object,
00784                              (omapi_object_t *)0, "state", server_running);
00785 
00786         /* install signal handlers */
00787         signal(SIGINT, dhcp_signal_handler);   /* control-c */
00788         signal(SIGTERM, dhcp_signal_handler);  /* kill */
00789 
00790         /* Log that we are about to start working */
00791         log_info("Server starting service.");
00792 
00793         TRACE(DHCPD_MAIN());
00794 
00795         /*
00796          * Receive packets and dispatch them...
00797          * dispatch() will never return.
00798          */
00799         dispatch ();
00800 
00801         /* Let's return status code */
00802         return 0;
00803 }
00804 #endif /* !UNIT_TEST */
00805 
00806 void postconf_initialization (int quiet)
00807 {
00808         struct option_state *options = NULL;
00809         struct data_string db;
00810         struct option_cache *oc;
00811         char *s;
00812         isc_result_t result;
00813         int tmp;
00814 #if defined (NSUPDATE)
00815         struct in_addr  local4, *local4_ptr = NULL;
00816         struct in6_addr local6, *local6_ptr = NULL;
00817 #endif
00818 
00819         /* Now try to get the lease file name. */
00820         option_state_allocate(&options, MDL);
00821 
00822         execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL,
00823                                     options, &global_scope, root_group,
00824                                     NULL, NULL);
00825         memset(&db, 0, sizeof db);
00826         oc = lookup_option(&server_universe, options, SV_LEASE_FILE_NAME);
00827         if (oc &&
00828             evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
00829                                   &global_scope, oc, MDL)) {
00830                 s = dmalloc(db.len + 1, MDL);
00831                 if (!s)
00832                         log_fatal("no memory for lease db filename.");
00833                 memcpy(s, db.data, db.len);
00834                 s[db.len] = 0;
00835                 data_string_forget(&db, MDL);
00836                 path_dhcpd_db = s;
00837         }
00838 
00839         oc = lookup_option(&server_universe, options, SV_PID_FILE_NAME);
00840         if (oc &&
00841             evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
00842                                   &global_scope, oc, MDL)) {
00843                 s = dmalloc(db.len + 1, MDL);
00844                 if (!s)
00845                         log_fatal("no memory for pid filename.");
00846                 memcpy(s, db.data, db.len);
00847                 s[db.len] = 0;
00848                 data_string_forget(&db, MDL);
00849                 path_dhcpd_pid = s;
00850         }
00851 
00852 #ifdef DHCPv6
00853         if (local_family == AF_INET6) {
00854                 /*
00855                  * Override lease file name with dhcpv6 lease file name,
00856                  * if it was set; then, do the same with the pid file name
00857                  */
00858                 oc = lookup_option(&server_universe, options,
00859                                    SV_DHCPV6_LEASE_FILE_NAME);
00860                 if (oc &&
00861                     evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
00862                                           &global_scope, oc, MDL)) {
00863                         s = dmalloc(db.len + 1, MDL);
00864                         if (!s)
00865                                 log_fatal("no memory for lease db filename.");
00866                         memcpy(s, db.data, db.len);
00867                         s[db.len] = 0;
00868                         data_string_forget(&db, MDL);
00869                         path_dhcpd_db = s;
00870                 }
00871 
00872                 oc = lookup_option(&server_universe, options,
00873                                    SV_DHCPV6_PID_FILE_NAME);
00874                 if (oc &&
00875                     evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
00876                                           &global_scope, oc, MDL)) {
00877                         s = dmalloc(db.len + 1, MDL);
00878                         if (!s)
00879                                 log_fatal("no memory for pid filename.");
00880                         memcpy(s, db.data, db.len);
00881                         s[db.len] = 0;
00882                         data_string_forget(&db, MDL);
00883                         path_dhcpd_pid = s;
00884                 }
00885         }
00886 #endif /* DHCPv6 */
00887 
00888         omapi_port = -1;
00889         oc = lookup_option(&server_universe, options, SV_OMAPI_PORT);
00890         if (oc &&
00891             evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
00892                                   &global_scope, oc, MDL)) {
00893                 if (db.len == 2) {
00894                         omapi_port = getUShort(db.data);
00895                 } else
00896                         log_fatal("invalid omapi port data length");
00897                 data_string_forget(&db, MDL);
00898         }
00899 
00900         oc = lookup_option(&server_universe, options, SV_OMAPI_KEY);
00901         if (oc &&
00902             evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
00903                                   &global_scope, oc, MDL)) {
00904                 s = dmalloc(db.len + 1, MDL);
00905                 if (!s)
00906                         log_fatal("no memory for OMAPI key filename.");
00907                 memcpy(s, db.data, db.len);
00908                 s[db.len] = 0;
00909                 data_string_forget(&db, MDL);
00910                 result = omapi_auth_key_lookup_name(&omapi_key, s);
00911                 dfree(s, MDL);
00912                 if (result != ISC_R_SUCCESS)
00913                         log_fatal("OMAPI key %s: %s",
00914                                   s, isc_result_totext (result));
00915         }
00916 
00917         oc = lookup_option(&server_universe, options, SV_LOCAL_PORT);
00918         if (oc &&
00919             evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
00920                                   &global_scope, oc, MDL)) {
00921                 if (db.len == 2) {
00922                         local_port = htons(getUShort (db.data));
00923                 } else
00924                         log_fatal("invalid local port data length");
00925                 data_string_forget(&db, MDL);
00926         }
00927 
00928         oc = lookup_option(&server_universe, options, SV_REMOTE_PORT);
00929         if (oc &&
00930             evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
00931                                   &global_scope, oc, MDL)) {
00932                 if (db.len == 2) {
00933                         remote_port = htons(getUShort (db.data));
00934                 } else
00935                         log_fatal("invalid remote port data length");
00936                 data_string_forget(&db, MDL);
00937         }
00938 
00939         oc = lookup_option(&server_universe, options,
00940                            SV_LIMITED_BROADCAST_ADDRESS);
00941         if (oc &&
00942             evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
00943                                   &global_scope, oc, MDL)) {
00944                 if (db.len == 4) {
00945                         memcpy(&limited_broadcast, db.data, 4);
00946                 } else
00947                         log_fatal("invalid broadcast address data length");
00948                 data_string_forget(&db, MDL);
00949         }
00950 
00951         oc = lookup_option(&server_universe, options, SV_LOCAL_ADDRESS);
00952         if (oc &&
00953             evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
00954                                   &global_scope, oc, MDL)) {
00955                 if (db.len == 4) {
00956                         memcpy(&local_address, db.data, 4);
00957                 } else
00958                         log_fatal("invalid local address data length");
00959                 data_string_forget(&db, MDL);
00960         }
00961 
00962         oc = lookup_option(&server_universe, options, SV_DDNS_UPDATE_STYLE);
00963         if (oc) {
00964                 if (evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
00965                                           &global_scope, oc, MDL)) {
00966                         if (db.len == 1) {
00967                                 ddns_update_style = db.data[0];
00968                         } else
00969                                 log_fatal("invalid dns update type");
00970                         data_string_forget(&db, MDL);
00971                 }
00972         } else {
00973                 ddns_update_style = DDNS_UPDATE_STYLE_NONE;
00974         }
00975 #if defined (NSUPDATE)
00976         /* We no longer support ad_hoc, tell the user */
00977         if (ddns_update_style == DDNS_UPDATE_STYLE_AD_HOC) {
00978                 log_fatal("ddns-update-style ad_hoc no longer supported");
00979         }
00980 
00981         oc = lookup_option(&server_universe, options, SV_DDNS_LOCAL_ADDRESS4);
00982         if (oc) {
00983                 if (evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
00984                                           &global_scope, oc, MDL)) {
00985                         if (db.len == 4) {
00986                                 memcpy(&local4, db.data, 4);
00987                                 local4_ptr = &local4;
00988                         }
00989                         data_string_forget(&db, MDL);
00990                 }
00991         }
00992 
00993         oc = lookup_option(&server_universe, options, SV_DDNS_LOCAL_ADDRESS6);
00994         if (oc) {
00995                 if (evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
00996                                           &global_scope, oc, MDL)) {
00997                         if (db.len == 16) {
00998                                 memcpy(&local6, db.data, 16);
00999                                 local6_ptr = &local6;
01000                         }
01001                         data_string_forget(&db, MDL);
01002                 }
01003         }
01004 
01005         if (dhcp_context_create(DHCP_CONTEXT_POST_DB, local4_ptr, local6_ptr)
01006             != ISC_R_SUCCESS)
01007                 log_fatal("Unable to complete ddns initialization");
01008 
01009 #else
01010         /* If we don't have support for updates compiled in tell the user */
01011         if (ddns_update_style != DDNS_UPDATE_STYLE_NONE) {
01012                 log_fatal("Support for ddns-update-style not compiled in");
01013         }
01014 #endif
01015 
01016         oc = lookup_option(&server_universe, options, SV_LOG_FACILITY);
01017         if (oc) {
01018                 if (evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
01019                                           &global_scope, oc, MDL)) {
01020                         if (db.len == 1) {
01021                                 closelog ();
01022                                 openlog("dhcpd", LOG_NDELAY, db.data[0]);
01023                                 /* Log the startup banner into the new
01024                                    log file. */
01025                                 if (!quiet) {
01026                                         /* Don't log to stderr twice. */
01027                                         tmp = log_perror;
01028                                         log_perror = 0;
01029                                         log_info("%s %s",
01030                                                  message, PACKAGE_VERSION);
01031                                         log_info(copyright);
01032                                         log_info(arr);
01033                                         log_info(url);
01034                                         log_perror = tmp;
01035                                 }
01036                         } else
01037                                 log_fatal("invalid log facility");
01038                         data_string_forget(&db, MDL);
01039                 }
01040         }
01041         
01042         oc = lookup_option(&server_universe, options, SV_DELAYED_ACK);
01043         if (oc &&
01044             evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
01045                                   &global_scope, oc, MDL)) {
01046                 if (db.len == 2) {
01047                         max_outstanding_acks = htons(getUShort(db.data));
01048                 } else {
01049                         log_fatal("invalid max delayed ACK count ");
01050                 }
01051                 data_string_forget(&db, MDL);
01052         }
01053 
01054         oc = lookup_option(&server_universe, options, SV_MAX_ACK_DELAY);
01055         if (oc &&
01056             evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
01057                                   &global_scope, oc, MDL)) {
01058                 u_int32_t timeval;
01059 
01060                 if (db.len != 4)
01061                         log_fatal("invalid max ack delay configuration");
01062 
01063                 timeval = getULong(db.data);
01064                 max_ack_delay_secs  = timeval / 1000000;
01065                 max_ack_delay_usecs = timeval % 1000000;
01066 
01067                 data_string_forget(&db, MDL);
01068         }
01069 
01070         oc = lookup_option(&server_universe, options, SV_DONT_USE_FSYNC);
01071         if ((oc != NULL) &&
01072             evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options, NULL,
01073                                           &global_scope, oc, MDL)) {
01074                 dont_use_fsync = 1;
01075                 log_error("Not using fsync() to flush lease writes");
01076         }
01077 
01078         /* Don't need the options anymore. */
01079         option_state_dereference(&options, MDL);
01080 }
01081 
01082 void postdb_startup (void)
01083 {
01084         /* Initialize the omapi listener state. */
01085         if (omapi_port != -1) {
01086                 omapi_listener_start (0);
01087         }
01088 
01089 #if defined (FAILOVER_PROTOCOL)
01090         /* Initialize the failover listener state. */
01091         dhcp_failover_startup ();
01092 #endif
01093 
01094         /*
01095          * Begin our lease timeout background task.
01096          */
01097         schedule_all_ipv6_lease_timeouts();
01098 }
01099 
01100 /* Print usage message. */
01101 #ifndef UNIT_TEST
01102 static void
01103 usage(void) {
01104         log_info("%s %s", message, PACKAGE_VERSION);
01105         log_info(copyright);
01106         log_info(arr);
01107 
01108         log_fatal("Usage: dhcpd [-p <UDP port #>] [-f] [-d] [-q] [-t|-T]\n"
01109 #ifdef DHCPv6
01110                   "             [-4|-6] [-cf config-file] [-lf lease-file]\n"
01111 #else /* !DHCPv6 */
01112                   "             [-cf config-file] [-lf lease-file]\n"
01113 #endif /* DHCPv6 */
01114 #if defined (PARANOIA)
01115                    /* meld into the following string */
01116                   "             [-user user] [-group group] [-chroot dir]\n"
01117 #endif /* PARANOIA */
01118 #if defined (TRACING)
01119                   "             [-tf trace-output-file]\n"
01120                   "             [-play trace-input-file]\n"
01121 #endif /* TRACING */
01122                   "             [-pf pid-file] [--no-pid] [-s server]\n"
01123                   "             [if0 [...ifN]]");
01124 }
01125 #endif
01126 
01127 void lease_pinged (from, packet, length)
01128         struct iaddr from;
01129         u_int8_t *packet;
01130         int length;
01131 {
01132         struct lease *lp;
01133 
01134         /* Don't try to look up a pinged lease if we aren't trying to
01135            ping one - otherwise somebody could easily make us churn by
01136            just forging repeated ICMP EchoReply packets for us to look
01137            up. */
01138         if (!outstanding_pings)
01139                 return;
01140 
01141         lp = (struct lease *)0;
01142         if (!find_lease_by_ip_addr (&lp, from, MDL)) {
01143                 log_debug ("unexpected ICMP Echo Reply from %s",
01144                            piaddr (from));
01145                 return;
01146         }
01147 
01148         if (!lp -> state) {
01149 #if defined (FAILOVER_PROTOCOL)
01150                 if (!lp -> pool ||
01151                     !lp -> pool -> failover_peer)
01152 #endif
01153                         log_debug ("ICMP Echo Reply for %s late or spurious.",
01154                                    piaddr (from));
01155                 goto out;
01156         }
01157 
01158         if (lp -> ends > cur_time) {
01159                 log_debug ("ICMP Echo reply while lease %s valid.",
01160                            piaddr (from));
01161         }
01162 
01163         /* At this point it looks like we pinged a lease and got a
01164            response, which shouldn't have happened. */
01165         data_string_forget (&lp -> state -> parameter_request_list, MDL);
01166         free_lease_state (lp -> state, MDL);
01167         lp -> state = (struct lease_state *)0;
01168 
01169         abandon_lease (lp, "pinged before offer");
01170         cancel_timeout (lease_ping_timeout, lp);
01171         --outstanding_pings;
01172       out:
01173         lease_dereference (&lp, MDL);
01174 }
01175 
01176 void lease_ping_timeout (vlp)
01177         void *vlp;
01178 {
01179         struct lease *lp = vlp;
01180 
01181 #if defined (DEBUG_MEMORY_LEAKAGE)
01182         unsigned long previous_outstanding = dmalloc_outstanding;
01183 #endif
01184 
01185         --outstanding_pings;
01186         dhcp_reply (lp);
01187 
01188 #if defined (DEBUG_MEMORY_LEAKAGE)
01189         log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
01190                   dmalloc_generation,
01191                   dmalloc_outstanding - previous_outstanding,
01192                   dmalloc_outstanding, dmalloc_longterm);
01193 #endif
01194 #if defined (DEBUG_MEMORY_LEAKAGE)
01195         dmalloc_dump_outstanding ();
01196 #endif
01197 }
01198 
01199 int dhcpd_interface_setup_hook (struct interface_info *ip, struct iaddr *ia)
01200 {
01201         struct subnet *subnet;
01202         struct shared_network *share;
01203         isc_result_t status;
01204 
01205         /* Special case for fallback network - not sure why this is
01206            necessary. */
01207         if (!ia) {
01208                 const char *fnn = "fallback-net";
01209                 status = shared_network_allocate (&ip -> shared_network, MDL);
01210                 if (status != ISC_R_SUCCESS)
01211                         log_fatal ("No memory for shared subnet: %s",
01212                                    isc_result_totext (status));
01213                 ip -> shared_network -> name = dmalloc (strlen (fnn) + 1, MDL);
01214                 strcpy (ip -> shared_network -> name, fnn);
01215                 return 1;
01216         }
01217 
01218         /* If there's a registered subnet for this address,
01219            connect it together... */
01220         subnet = (struct subnet *)0;
01221         if (find_subnet (&subnet, *ia, MDL)) {
01222                 /* If this interface has multiple aliases on the same
01223                    subnet, ignore all but the first we encounter. */
01224                 if (!subnet -> interface) {
01225                         interface_reference (&subnet -> interface, ip, MDL);
01226                         subnet -> interface_address = *ia;
01227                 } else if (subnet -> interface != ip) {
01228                         log_error ("Multiple interfaces match the %s: %s %s", 
01229                                    "same subnet",
01230                                    subnet -> interface -> name, ip -> name);
01231                 }
01232                 share = subnet -> shared_network;
01233                 if (ip -> shared_network &&
01234                     ip -> shared_network != share) {
01235                         log_fatal ("Interface %s matches multiple shared %s",
01236                                    ip -> name, "networks");
01237                 } else {
01238                         if (!ip -> shared_network)
01239                                 shared_network_reference
01240                                         (&ip -> shared_network, share, MDL);
01241                 }
01242                 
01243                 if (!share -> interface) {
01244                         interface_reference (&share -> interface, ip, MDL);
01245                 } else if (share -> interface != ip) {
01246                         log_error ("Multiple interfaces match the %s: %s %s", 
01247                                    "same shared network",
01248                                    share -> interface -> name, ip -> name);
01249                 }
01250                 subnet_dereference (&subnet, MDL);
01251         }
01252         return 1;
01253 }
01254 
01255 static TIME shutdown_time;
01256 static int omapi_connection_count;
01257 enum dhcp_shutdown_state shutdown_state;
01258 
01259 isc_result_t dhcp_io_shutdown (omapi_object_t *obj, void *foo)
01260 {
01261         /* Shut down all listeners. */
01262         if (shutdown_state == shutdown_listeners &&
01263             obj -> type == omapi_type_listener &&
01264             obj -> inner &&
01265             obj -> inner -> type == omapi_type_protocol_listener) {
01266                 omapi_listener_destroy (obj, MDL);
01267                 return ISC_R_SUCCESS;
01268         }
01269 
01270         /* Shut down all existing omapi connections. */
01271         if (obj -> type == omapi_type_connection &&
01272             obj -> inner &&
01273             obj -> inner -> type == omapi_type_protocol) {
01274                 if (shutdown_state == shutdown_drop_omapi_connections) {
01275                         omapi_disconnect (obj, 1);
01276                 }
01277                 omapi_connection_count++;
01278                 if (shutdown_state == shutdown_omapi_connections) {
01279                         omapi_disconnect (obj, 0);
01280                         return ISC_R_SUCCESS;
01281                 }
01282         }
01283 
01284         /* Shutdown all DHCP interfaces. */
01285         if (obj -> type == dhcp_type_interface &&
01286             shutdown_state == shutdown_dhcp) {
01287                 dhcp_interface_remove (obj, (omapi_object_t *)0);
01288                 return ISC_R_SUCCESS;
01289         }
01290         return ISC_R_SUCCESS;
01291 }
01292 
01293 static isc_result_t dhcp_io_shutdown_countdown (void *vlp)
01294 {
01295 #if defined (FAILOVER_PROTOCOL)
01296         dhcp_failover_state_t *state;
01297         int failover_connection_count = 0;
01298 #endif
01299         struct timeval tv;
01300 
01301       oncemore:
01302         if (shutdown_state == shutdown_listeners ||
01303             shutdown_state == shutdown_omapi_connections ||
01304             shutdown_state == shutdown_drop_omapi_connections ||
01305             shutdown_state == shutdown_dhcp) {
01306                 omapi_connection_count = 0;
01307                 omapi_io_state_foreach (dhcp_io_shutdown, 0);
01308         }
01309 
01310         if ((shutdown_state == shutdown_listeners ||
01311              shutdown_state == shutdown_omapi_connections ||
01312              shutdown_state == shutdown_drop_omapi_connections) &&
01313             omapi_connection_count == 0) {
01314                 shutdown_state = shutdown_dhcp;
01315                 shutdown_time = cur_time;
01316                 goto oncemore;
01317         } else if (shutdown_state == shutdown_listeners &&
01318                    cur_time - shutdown_time > 4) {
01319                 shutdown_state = shutdown_omapi_connections;
01320                 shutdown_time = cur_time;
01321         } else if (shutdown_state == shutdown_omapi_connections &&
01322                    cur_time - shutdown_time > 4) {
01323                 shutdown_state = shutdown_drop_omapi_connections;
01324                 shutdown_time = cur_time;
01325         } else if (shutdown_state == shutdown_drop_omapi_connections &&
01326                    cur_time - shutdown_time > 4) {
01327                 shutdown_state = shutdown_dhcp;
01328                 shutdown_time = cur_time;
01329                 goto oncemore;
01330         } else if (shutdown_state == shutdown_dhcp &&
01331                    cur_time - shutdown_time > 4) {
01332                 shutdown_state = shutdown_done;
01333                 shutdown_time = cur_time;
01334         }
01335 
01336 #if defined (FAILOVER_PROTOCOL)
01337         /* Set all failover peers into the shutdown state. */
01338         if (shutdown_state == shutdown_dhcp) {
01339             for (state = failover_states; state; state = state -> next) {
01340                 if (state -> me.state == normal) {
01341                     dhcp_failover_set_state (state, shut_down);
01342                     failover_connection_count++;
01343                 }
01344                 if (state -> me.state == shut_down &&
01345                     state -> partner.state != partner_down)
01346                         failover_connection_count++;
01347             }
01348         }
01349 
01350         if (shutdown_state == shutdown_done) {
01351             for (state = failover_states; state; state = state -> next) {
01352                 if (state -> me.state == shut_down) {
01353                     if (state -> link_to_peer)
01354                         dhcp_failover_link_dereference (&state -> link_to_peer,
01355                                                         MDL);
01356                     dhcp_failover_set_state (state, recover);
01357                 }
01358             }
01359 #if defined (DEBUG_MEMORY_LEAKAGE) && \
01360                 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
01361             free_everything ();
01362             omapi_print_dmalloc_usage_by_caller ();
01363 #endif
01364             exit (0);
01365         }               
01366 #else
01367         if (shutdown_state == shutdown_done) {
01368 #if defined (DEBUG_MEMORY_LEAKAGE) && \
01369                 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
01370                 free_everything ();
01371                 omapi_print_dmalloc_usage_by_caller (); 
01372 #endif
01373                 exit (0);
01374         }
01375 #endif
01376         if (shutdown_state == shutdown_dhcp &&
01377 #if defined(FAILOVER_PROTOCOL)
01378             !failover_connection_count &&
01379 #endif
01380             ISC_TRUE) {
01381                 shutdown_state = shutdown_done;
01382                 shutdown_time = cur_time;
01383                 goto oncemore;
01384         }
01385         tv.tv_sec = cur_tv.tv_sec + 1;
01386         tv.tv_usec = cur_tv.tv_usec;
01387         add_timeout (&tv,
01388                      (void (*)(void *))dhcp_io_shutdown_countdown, 0, 0, 0);
01389         return ISC_R_SUCCESS;
01390 }
01391 
01392 isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
01393                                      control_object_state_t newstate)
01394 {
01395         struct timeval tv;
01396 
01397         if (newstate != server_shutdown)
01398                 return DHCP_R_INVALIDARG;
01399         /* Re-entry. */
01400         if (shutdown_signal == SIGUSR1)
01401                 return ISC_R_SUCCESS;
01402         shutdown_time = cur_time;
01403         shutdown_state = shutdown_listeners;
01404         /* Called by user. */
01405         if (shutdown_signal == 0) {
01406                 shutdown_signal = SIGUSR1;
01407                 dhcp_io_shutdown_countdown (0);
01408                 return ISC_R_SUCCESS;
01409         }
01410         /* Called on signal. */
01411         log_info("Received signal %d, initiating shutdown.", shutdown_signal);
01412         shutdown_signal = SIGUSR1;
01413         
01414         /*
01415          * Prompt the shutdown event onto the timer queue
01416          * and return to the dispatch loop.
01417          */
01418         tv.tv_sec = cur_tv.tv_sec;
01419         tv.tv_usec = cur_tv.tv_usec + 1;
01420         add_timeout(&tv,
01421                     (void (*)(void *))dhcp_io_shutdown_countdown, 0, 0, 0);
01422         return ISC_R_SUCCESS;
01423 }

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1