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