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