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