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