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