Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / dhcp / server / dhcpd.c
blob8a4ef6b906cc6626def752e6dcc2d3e1b0754509
1 /* dhcpd.c
3 DHCP Server Daemon. */
5 /*
6 * Copyright (c) 2004-2005 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1996-2003 by Internet Software Consortium
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.
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.
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
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''.
35 #ifndef lint
36 static char ocopyright[] =
37 "$Id: dhcpd.c,v 1.6 2005/08/11 17:13:30 drochner Exp $ Copyright 2004-2005 Internet Systems Consortium.";
38 #endif
40 static char copyright[] =
41 "Copyright 2004-2005 Internet Systems Consortium.";
42 static char arr [] = "All rights reserved.";
43 static char message [] = "Internet Systems Consortium DHCP Server";
44 static char url [] = "For info, please visit http://www.isc.org/sw/dhcp/";
46 #include "dhcpd.h"
47 #include "version.h"
48 #include <omapip/omapip_p.h>
50 static void usage PROTO ((void));
52 struct iaddr server_identifier;
53 int server_identifier_matched;
55 #if defined (NSUPDATE)
57 /* This stuff is always executed to figure the default values for certain
58 ddns variables. */
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.\";";
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. */
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\
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\
147 int ddns_update_style;
148 #endif /* NSUPDATE */
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;
154 int dhcp_max_agent_option_packet_length = DHCP_MTU_MAX;
156 static omapi_auth_key_t *omapi_key = (omapi_auth_key_t *)0;
157 int omapi_port;
159 #if defined (TRACING)
160 trace_type_t *trace_srandom;
161 #endif
163 static isc_result_t verify_addr (omapi_object_t *l, omapi_addr_t *addr) {
164 return ISC_R_SUCCESS;
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;
173 static void omapi_listener_start (void *foo)
175 omapi_object_t *listener;
176 isc_result_t result;
178 listener = (omapi_object_t *)0;
179 result = omapi_generic_new (&listener, MDL);
180 if (result != ISC_R_SUCCESS)
181 log_fatal ("Can't allocate new generic object: %s",
182 isc_result_totext (result));
183 result = omapi_protocol_listen (listener,
184 (unsigned)omapi_port, 1);
185 if (result == ISC_R_SUCCESS && omapi_key)
186 result = omapi_protocol_configure_security
187 (listener, verify_addr, verify_auth);
188 if (result != ISC_R_SUCCESS) {
189 log_error ("Can't start OMAPI protocol: %s",
190 isc_result_totext (result));
191 add_timeout (cur_time + 5, omapi_listener_start, 0, 0, 0);
193 omapi_object_dereference (&listener, MDL);
196 int main (argc, argv, envp)
197 int argc;
198 char **argv, **envp;
200 int i, status;
201 struct servent *ent;
202 char *s;
203 int cftest = 0;
204 int lftest = 0;
205 #ifndef DEBUG
206 int pidfilewritten = 0;
207 int pid;
208 char pbuf [20];
209 int daemon = 1;
210 #endif
211 int quiet = 0;
212 char *server = (char *)0;
213 isc_result_t result;
214 unsigned seed;
215 struct interface_info *ip;
216 struct parse *parse;
217 int lose;
218 int no_dhcpd_conf = 0;
219 int no_dhcpd_db = 0;
220 int no_dhcpd_pid = 0;
221 #if defined (TRACING)
222 char *traceinfile = (char *)0;
223 char *traceoutfile = (char *)0;
224 #endif
226 /* Make sure we have stdin, stdout and stderr. */
227 status = open ("/dev/null", O_RDWR);
228 if (status == 0)
229 status = open ("/dev/null", O_RDWR);
230 if (status == 1) {
231 status = open ("/dev/null", O_RDWR);
232 log_perror = 0; /* No sense logging to /dev/null. */
233 } else if (status != -1)
234 close (status);
236 /* Set up the client classification system. */
237 classification_setup ();
239 /* Initialize the omapi system. */
240 result = omapi_init ();
241 if (result != ISC_R_SUCCESS)
242 log_fatal ("Can't initialize OMAPI: %s",
243 isc_result_totext (result));
245 /* Set up the OMAPI wrappers for common objects. */
246 dhcp_db_objects_setup ();
247 /* Set up the OMAPI wrappers for various server database internal
248 objects. */
249 dhcp_common_objects_setup ();
251 /* Initially, log errors to stderr as well as to syslogd. */
252 #ifdef SYSLOG_4_2
253 openlog ("dhcpd", LOG_NDELAY);
254 log_priority = DHCPD_LOG_FACILITY;
255 #else
256 openlog ("dhcpd", LOG_NDELAY, DHCPD_LOG_FACILITY);
257 #endif
259 for (i = 1; i < argc; i++) {
260 if (!strcmp (argv [i], "-p")) {
261 if (++i == argc)
262 usage ();
263 for (s = argv [i]; *s; s++)
264 if (!isdigit ((unsigned char)*s))
265 log_fatal ("%s: not a valid UDP port",
266 argv [i]);
267 status = atoi (argv [i]);
268 if (status < 1 || status > 65535)
269 log_fatal ("%s: not a valid UDP port",
270 argv [i]);
271 local_port = htons (status);
272 log_debug ("binding to user-specified port %d",
273 ntohs (local_port));
274 } else if (!strcmp (argv [i], "-f")) {
275 #ifndef DEBUG
276 daemon = 0;
277 #endif
278 } else if (!strcmp (argv [i], "-d")) {
279 #ifndef DEBUG
280 daemon = 0;
281 #endif
282 log_perror = -1;
283 } else if (!strcmp (argv [i], "-s")) {
284 if (++i == argc)
285 usage ();
286 server = argv [i];
287 } else if (!strcmp (argv [i], "-cf")) {
288 if (++i == argc)
289 usage ();
290 path_dhcpd_conf = argv [i];
291 no_dhcpd_conf = 1;
292 } else if (!strcmp (argv [i], "-lf")) {
293 if (++i == argc)
294 usage ();
295 path_dhcpd_db = argv [i];
296 no_dhcpd_db = 1;
297 } else if (!strcmp (argv [i], "-pf")) {
298 if (++i == argc)
299 usage ();
300 path_dhcpd_pid = argv [i];
301 no_dhcpd_pid = 1;
302 } else if (!strcmp (argv [i], "-t")) {
303 /* test configurations only */
304 #ifndef DEBUG
305 daemon = 0;
306 #endif
307 cftest = 1;
308 log_perror = -1;
309 } else if (!strcmp (argv [i], "-T")) {
310 /* test configurations and lease file only */
311 #ifndef DEBUG
312 daemon = 0;
313 #endif
314 cftest = 1;
315 lftest = 1;
316 log_perror = -1;
317 } else if (!strcmp (argv [i], "-q")) {
318 quiet = 1;
319 quiet_interface_discovery = 1;
320 } else if (!strcmp (argv [i], "--version")) {
321 log_info ("isc-dhcpd-%s", DHCP_VERSION);
322 exit (0);
323 #if defined (TRACING)
324 } else if (!strcmp (argv [i], "-tf")) {
325 if (++i == argc)
326 usage ();
327 traceoutfile = argv [i];
328 } else if (!strcmp (argv [i], "-play")) {
329 if (++i == argc)
330 usage ();
331 traceinfile = argv [i];
332 trace_replay_init ();
333 #endif /* TRACING */
334 } else if (argv [i][0] == '-') {
335 usage ();
336 } else {
337 struct interface_info *tmp =
338 (struct interface_info *)0;
339 result = interface_allocate (&tmp, MDL);
340 if (result != ISC_R_SUCCESS)
341 log_fatal ("Insufficient memory to %s %s: %s",
342 "record interface", argv [i],
343 isc_result_totext (result));
344 strcpy (tmp -> name, argv [i]);
345 if (interfaces) {
346 interface_reference (&tmp -> next,
347 interfaces, MDL);
348 interface_dereference (&interfaces, MDL);
350 interface_reference (&interfaces, tmp, MDL);
351 tmp -> flags = INTERFACE_REQUESTED;
355 if (!no_dhcpd_conf && (s = getenv ("PATH_DHCPD_CONF"))) {
356 path_dhcpd_conf = s;
358 if (!no_dhcpd_db && (s = getenv ("PATH_DHCPD_DB"))) {
359 path_dhcpd_db = s;
361 if (!no_dhcpd_pid && (s = getenv ("PATH_DHCPD_PID"))) {
362 path_dhcpd_pid = s;
365 if (!quiet) {
366 log_info ("%s %s", message, DHCP_VERSION);
367 log_info (copyright);
368 log_info (arr);
369 log_info (url);
370 } else {
371 quiet = 0;
372 log_perror = 0;
375 #if defined (TRACING)
376 trace_init (set_time, MDL);
377 if (traceoutfile) {
378 result = trace_begin (traceoutfile, MDL);
379 if (result != ISC_R_SUCCESS)
380 log_fatal ("Unable to begin trace: %s",
381 isc_result_totext (result));
383 interface_trace_setup ();
384 parse_trace_setup ();
385 trace_srandom = trace_type_register ("random-seed", (void *)0,
386 trace_seed_input,
387 trace_seed_stop, MDL);
388 #endif
390 /* Default to the DHCP/BOOTP port. */
391 if (!local_port)
393 if ((s = getenv ("DHCPD_PORT"))) {
394 local_port = htons (atoi (s));
395 log_debug ("binding to environment-specified port %d",
396 ntohs (local_port));
397 } else {
398 ent = getservbyname ("dhcp", "udp");
399 if (!ent)
400 local_port = htons (67);
401 else
402 local_port = ent -> s_port;
403 #ifndef __CYGWIN32__ /* XXX */
404 endservent ();
405 #endif
409 remote_port = htons (ntohs (local_port) + 1);
411 if (server) {
412 if (!inet_aton (server, &limited_broadcast)) {
413 struct hostent *he;
414 he = gethostbyname (server);
415 if (he) {
416 memcpy (&limited_broadcast,
417 he -> h_addr_list [0],
418 sizeof limited_broadcast);
419 } else
420 limited_broadcast.s_addr = INADDR_BROADCAST;
422 } else {
423 limited_broadcast.s_addr = INADDR_BROADCAST;
426 /* Get the current time... */
427 GET_TIME (&cur_time);
429 /* Set up the initial dhcp option universe. */
430 initialize_common_option_spaces ();
431 initialize_server_option_spaces ();
433 /* Add the ddns update style enumeration prior to parsing. */
434 add_enumeration (&ddns_styles);
435 add_enumeration (&syslog_enum);
437 if (!group_allocate (&root_group, MDL))
438 log_fatal ("Can't allocate root group!");
439 root_group -> authoritative = 0;
441 /* Set up various hooks. */
442 dhcp_interface_setup_hook = dhcpd_interface_setup_hook;
443 bootp_packet_handler = do_packet;
445 #if defined (NSUPDATE)
446 /* Set up the standard name service updater routine. */
447 parse = (struct parse *)0;
448 status = new_parse (&parse, -1,
449 std_nsupdate, (sizeof std_nsupdate) - 1,
450 "standard name service update routine", 0);
451 if (status != ISC_R_SUCCESS)
452 log_fatal ("can't begin parsing name service updater!");
454 lose = 0;
455 if (!(parse_executable_statements
456 (&root_group -> statements, parse, &lose, context_any))) {
457 end_parse (&parse);
458 log_fatal ("can't parse standard name service updater!");
460 end_parse (&parse);
461 #endif
463 /* Initialize icmp support... */
464 if (!cftest && !lftest)
465 icmp_startup (1, lease_pinged);
467 #if defined (TRACING)
468 if (traceinfile) {
469 if (!no_dhcpd_db) {
470 log_error ("%s", "");
471 log_error ("** You must specify a lease file with -lf.");
472 log_error (" Dhcpd will not overwrite your default");
473 log_fatal (" lease file when playing back a trace. **");
475 trace_file_replay (traceinfile);
477 #if defined (DEBUG_MEMORY_LEAKAGE) && \
478 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
479 free_everything ();
480 omapi_print_dmalloc_usage_by_caller ();
481 #endif
483 exit (0);
485 #endif
487 /* Read the dhcpd.conf file... */
488 if (readconf () != ISC_R_SUCCESS)
489 log_fatal ("Configuration file errors encountered -- exiting");
491 postconf_initialization (quiet);
493 /* test option should cause an early exit */
494 if (cftest && !lftest)
495 exit(0);
497 group_write_hook = group_writer;
499 /* Start up the database... */
500 db_startup (lftest);
502 if (lftest)
503 exit (0);
505 /* Discover all the network interfaces and initialize them. */
506 discover_interfaces (DISCOVER_SERVER);
508 /* Make up a seed for the random number generator from current
509 time plus the sum of the last four bytes of each
510 interface's hardware address interpreted as an integer.
511 Not much entropy, but we're booting, so we're not likely to
512 find anything better. */
513 seed = 0;
514 for (ip = interfaces; ip; ip = ip -> next) {
515 int junk;
516 memcpy (&junk,
517 &ip -> hw_address.hbuf [ip -> hw_address.hlen -
518 sizeof seed], sizeof seed);
519 seed += junk;
521 srandom (seed + cur_time);
522 #if defined (TRACING)
523 trace_seed_stash (trace_srandom, seed + cur_time);
524 #endif
525 postdb_startup ();
527 #ifndef DEBUG
528 if (daemon) {
529 /* First part of becoming a daemon... */
530 if ((pid = fork ()) < 0)
531 log_fatal ("Can't fork daemon: %m");
532 else if (pid)
533 exit (0);
536 /* Read previous pid file. */
537 if ((i = open (path_dhcpd_pid, O_RDONLY)) >= 0) {
538 status = read (i, pbuf, (sizeof pbuf) - 1);
539 close (i);
540 if (status > 0) {
541 pbuf [status] = 0;
542 pid = atoi (pbuf);
544 /* If the previous server process is not still running,
545 write a new pid file immediately. */
546 if (pid && (pid == getpid() || kill (pid, 0) < 0)) {
547 unlink (path_dhcpd_pid);
548 if ((i = open (path_dhcpd_pid,
549 O_WRONLY | O_CREAT, 0644)) >= 0) {
550 sprintf (pbuf, "%d\n", (int)getpid ());
551 write (i, pbuf, strlen (pbuf));
552 close (i);
553 pidfilewritten = 1;
555 } else
556 log_fatal ("There's already a DHCP server running.");
560 /* If we were requested to log to stdout on the command line,
561 keep doing so; otherwise, stop. */
562 if (log_perror == -1)
563 log_perror = 1;
564 else
565 log_perror = 0;
567 if (daemon) {
568 /* Become session leader and get pid... */
569 close (0);
570 close (1);
571 close (2);
572 pid = setsid ();
575 /* If we didn't write the pid file earlier because we found a
576 process running the logged pid, but we made it to here,
577 meaning nothing is listening on the bootp port, then write
578 the pid file out - what's in it now is bogus anyway. */
579 if (!pidfilewritten) {
580 unlink (path_dhcpd_pid);
581 if ((i = open (path_dhcpd_pid,
582 O_WRONLY | O_CREAT, 0644)) >= 0) {
583 sprintf (pbuf, "%d\n", (int)getpid ());
584 write (i, pbuf, strlen (pbuf));
585 close (i);
586 pidfilewritten = 1;
589 #endif /* !DEBUG */
591 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
592 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
593 dmalloc_cutoff_generation = dmalloc_generation;
594 dmalloc_longterm = dmalloc_outstanding;
595 dmalloc_outstanding = 0;
596 #endif
598 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
599 dump_rc_history ();
600 #endif
602 omapi_set_int_value ((omapi_object_t *)dhcp_control_object,
603 (omapi_object_t *)0, "state", server_running);
605 /* Receive packets and dispatch them... */
606 dispatch ();
608 /* Not reached */
609 return 0;
612 void postconf_initialization (int quiet)
614 struct option_state *options = (struct option_state *)0;
615 struct data_string db;
616 struct option_cache *oc;
617 char *s;
618 isc_result_t result;
619 struct parse *parse;
620 int tmp;
622 /* Now try to get the lease file name. */
623 option_state_allocate (&options, MDL);
625 execute_statements_in_scope ((struct binding_value **)0,
626 (struct packet *)0,
627 (struct lease *)0,
628 (struct client_state *)0,
629 (struct option_state *)0,
630 options, &global_scope,
631 root_group,
632 (struct group *)0);
633 memset (&db, 0, sizeof db);
634 oc = lookup_option (&server_universe, options, SV_LEASE_FILE_NAME);
635 if (oc &&
636 evaluate_option_cache (&db, (struct packet *)0,
637 (struct lease *)0, (struct client_state *)0,
638 options, (struct option_state *)0,
639 &global_scope, oc, MDL)) {
640 s = dmalloc (db.len + 1, MDL);
641 if (!s)
642 log_fatal ("no memory for lease db filename.");
643 memcpy (s, db.data, db.len);
644 s [db.len] = 0;
645 data_string_forget (&db, MDL);
646 path_dhcpd_db = s;
649 oc = lookup_option (&server_universe, options, SV_PID_FILE_NAME);
650 if (oc &&
651 evaluate_option_cache (&db, (struct packet *)0,
652 (struct lease *)0, (struct client_state *)0,
653 options, (struct option_state *)0,
654 &global_scope, oc, MDL)) {
655 s = dmalloc (db.len + 1, MDL);
656 if (!s)
657 log_fatal ("no memory for lease db filename.");
658 memcpy (s, db.data, db.len);
659 s [db.len] = 0;
660 data_string_forget (&db, MDL);
661 path_dhcpd_pid = s;
664 omapi_port = -1;
665 oc = lookup_option (&server_universe, options, SV_OMAPI_PORT);
666 if (oc &&
667 evaluate_option_cache (&db, (struct packet *)0,
668 (struct lease *)0, (struct client_state *)0,
669 options, (struct option_state *)0,
670 &global_scope, oc, MDL)) {
671 if (db.len == 2) {
672 omapi_port = getUShort (db.data);
673 } else
674 log_fatal ("invalid omapi port data length");
675 data_string_forget (&db, MDL);
678 oc = lookup_option (&server_universe, options, SV_OMAPI_KEY);
679 if (oc &&
680 evaluate_option_cache (&db, (struct packet *)0,
681 (struct lease *)0, (struct client_state *)0,
682 options,
683 (struct option_state *)0,
684 &global_scope, oc, MDL)) {
685 s = dmalloc (db.len + 1, MDL);
686 if (!s)
687 log_fatal ("no memory for OMAPI key filename.");
688 memcpy (s, db.data, db.len);
689 s [db.len] = 0;
690 data_string_forget (&db, MDL);
691 result = omapi_auth_key_lookup_name (&omapi_key, s);
692 dfree (s, MDL);
693 if (result != ISC_R_SUCCESS)
694 log_fatal ("OMAPI key %s: %s",
695 s, isc_result_totext (result));
698 oc = lookup_option (&server_universe, options, SV_LOCAL_PORT);
699 if (oc &&
700 evaluate_option_cache (&db, (struct packet *)0,
701 (struct lease *)0, (struct client_state *)0,
702 options,
703 (struct option_state *)0,
704 &global_scope, oc, MDL)) {
705 if (db.len == 2) {
706 local_port = htons (getUShort (db.data));
707 } else
708 log_fatal ("invalid local port data length");
709 data_string_forget (&db, MDL);
712 oc = lookup_option (&server_universe, options, SV_REMOTE_PORT);
713 if (oc &&
714 evaluate_option_cache (&db, (struct packet *)0,
715 (struct lease *)0, (struct client_state *)0,
716 options, (struct option_state *)0,
717 &global_scope, oc, MDL)) {
718 if (db.len == 2) {
719 remote_port = htons (getUShort (db.data));
720 } else
721 log_fatal ("invalid remote port data length");
722 data_string_forget (&db, MDL);
725 oc = lookup_option (&server_universe, options,
726 SV_LIMITED_BROADCAST_ADDRESS);
727 if (oc &&
728 evaluate_option_cache (&db, (struct packet *)0,
729 (struct lease *)0, (struct client_state *)0,
730 options, (struct option_state *)0,
731 &global_scope, oc, MDL)) {
732 if (db.len == 4) {
733 memcpy (&limited_broadcast, db.data, 4);
734 } else
735 log_fatal ("invalid remote port data length");
736 data_string_forget (&db, MDL);
739 oc = lookup_option (&server_universe, options,
740 SV_LOCAL_ADDRESS);
741 if (oc &&
742 evaluate_option_cache (&db, (struct packet *)0,
743 (struct lease *)0, (struct client_state *)0,
744 options, (struct option_state *)0,
745 &global_scope, oc, MDL)) {
746 if (db.len == 4) {
747 memcpy (&local_address, db.data, 4);
748 } else
749 log_fatal ("invalid remote port data length");
750 data_string_forget (&db, MDL);
753 oc = lookup_option (&server_universe, options, SV_DDNS_UPDATE_STYLE);
754 if (oc) {
755 if (evaluate_option_cache (&db, (struct packet *)0,
756 (struct lease *)0,
757 (struct client_state *)0,
758 options,
759 (struct option_state *)0,
760 &global_scope, oc, MDL)) {
761 if (db.len == 1) {
762 ddns_update_style = db.data [0];
763 } else
764 log_fatal ("invalid dns update type");
765 data_string_forget (&db, MDL);
767 } else {
768 log_info ("%s", "");
769 log_error ("** You must add a global ddns-update-style %s%s.",
770 "statement to ", path_dhcpd_conf);
771 log_error (" To get the same behaviour as in 3.0b2pl11 %s",
772 "and previous");
773 log_error (" versions, add a line that says \"%s\"",
774 "ddns-update-style ad-hoc;");
775 log_fatal (" Please read the dhcpd.conf manual page %s",
776 "for more information. **");
779 oc = lookup_option (&server_universe, options, SV_LOG_FACILITY);
780 if (oc) {
781 if (evaluate_option_cache (&db, (struct packet *)0,
782 (struct lease *)0,
783 (struct client_state *)0,
784 options,
785 (struct option_state *)0,
786 &global_scope, oc, MDL)) {
787 if (db.len == 1) {
788 closelog ();
789 #ifdef SYSLOG_4_2
790 openlog ("dhcpd", LOG_NDELAY);
791 log_priority = db.data [0];
792 #else
793 openlog ("dhcpd",
794 LOG_NDELAY, db.data [0]);
795 #endif
796 /* Log the startup banner into the new
797 log file. */
798 if (!quiet) {
799 /* Don't log to stderr twice. */
800 tmp = log_perror;
801 log_perror = 0;
802 log_info ("%s %s",
803 message, DHCP_VERSION);
804 log_info (copyright);
805 log_info (arr);
806 log_info (url);
807 log_perror = tmp;
809 } else
810 log_fatal ("invalid log facility");
811 data_string_forget (&db, MDL);
815 /* Don't need the options anymore. */
816 option_state_dereference (&options, MDL);
818 #if defined (NSUPDATE)
819 /* If old-style ddns updates have been requested, parse the
820 old-style ddns updater. */
821 if (ddns_update_style == 1) {
822 struct executable_statement **e, *s;
824 if (root_group -> statements) {
825 s = (struct executable_statement *)0;
826 if (!executable_statement_allocate (&s, MDL))
827 log_fatal ("no memory for ddns updater");
828 executable_statement_reference
829 (&s -> next, root_group -> statements, MDL);
830 executable_statement_dereference
831 (&root_group -> statements, MDL);
832 executable_statement_reference
833 (&root_group -> statements, s, MDL);
834 s -> op = statements_statement;
835 e = &s -> data.statements;
836 executable_statement_dereference (&s, MDL);
837 } else {
838 e = &root_group -> statements;
841 /* Set up the standard name service updater routine. */
842 parse = (struct parse *)0;
843 result = new_parse (&parse, -1,
844 old_nsupdate, (sizeof old_nsupdate) - 1,
845 "old name service update routine", 0);
846 if (result != ISC_R_SUCCESS)
847 log_fatal ("can't begin parsing old ddns updater!");
849 tmp = 0;
850 if (!(parse_executable_statements (e, parse,
851 &tmp, context_any))) {
852 end_parse (&parse);
853 log_fatal ("can't parse standard ddns updater!");
855 end_parse (&parse);
857 #endif
860 void postdb_startup (void)
862 /* Initialize the omapi listener state. */
863 if (omapi_port != -1) {
864 omapi_listener_start (0);
867 #if defined (FAILOVER_PROTOCOL)
868 /* Initialize the failover listener state. */
869 dhcp_failover_startup ();
870 #endif
873 /* Print usage message. */
875 static void usage ()
877 log_info ("%s %s", message, DHCP_VERSION);
878 log_info (copyright);
879 log_info (arr);
881 log_fatal ("Usage: dhcpd [-p <UDP port #>] [-d] [-f]%s%s%s%s",
882 "\n [-cf config-file] [-lf lease-file]",
883 #if defined (TRACING)
884 "\n [-tf trace-output-file]",
885 "\n [-play trace-input-file]",
886 #else
887 "", "",
888 #endif /* TRACING */
889 "\n [-t] [-T] [-s server] [if0 [...ifN]]");
892 void lease_pinged (from, packet, length)
893 struct iaddr from;
894 u_int8_t *packet;
895 int length;
897 struct lease *lp;
899 /* Don't try to look up a pinged lease if we aren't trying to
900 ping one - otherwise somebody could easily make us churn by
901 just forging repeated ICMP EchoReply packets for us to look
902 up. */
903 if (!outstanding_pings)
904 return;
906 lp = (struct lease *)0;
907 if (!find_lease_by_ip_addr (&lp, from, MDL)) {
908 log_debug ("unexpected ICMP Echo Reply from %s",
909 piaddr (from));
910 return;
913 if (!lp -> state) {
914 #if defined (FAILOVER_PROTOCOL)
915 if (!lp -> pool ||
916 !lp -> pool -> failover_peer)
917 #endif
918 log_debug ("ICMP Echo Reply for %s late or spurious.",
919 piaddr (from));
920 goto out;
923 if (lp -> ends > cur_time) {
924 log_debug ("ICMP Echo reply while lease %s valid.",
925 piaddr (from));
928 /* At this point it looks like we pinged a lease and got a
929 response, which shouldn't have happened. */
930 data_string_forget (&lp -> state -> parameter_request_list, MDL);
931 free_lease_state (lp -> state, MDL);
932 lp -> state = (struct lease_state *)0;
934 abandon_lease (lp, "pinged before offer");
935 cancel_timeout (lease_ping_timeout, lp);
936 --outstanding_pings;
937 out:
938 lease_dereference (&lp, MDL);
941 void lease_ping_timeout (vlp)
942 void *vlp;
944 struct lease *lp = vlp;
946 #if defined (DEBUG_MEMORY_LEAKAGE)
947 unsigned long previous_outstanding = dmalloc_outstanding;
948 #endif
950 --outstanding_pings;
951 dhcp_reply (lp);
953 #if defined (DEBUG_MEMORY_LEAKAGE)
954 log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
955 dmalloc_generation,
956 dmalloc_outstanding - previous_outstanding,
957 dmalloc_outstanding, dmalloc_longterm);
958 #endif
959 #if defined (DEBUG_MEMORY_LEAKAGE)
960 dmalloc_dump_outstanding ();
961 #endif
964 int dhcpd_interface_setup_hook (struct interface_info *ip, struct iaddr *ia)
966 struct subnet *subnet;
967 struct shared_network *share;
968 isc_result_t status;
970 /* Special case for fallback network - not sure why this is
971 necessary. */
972 if (!ia) {
973 const char *fnn = "fallback-net";
974 status = shared_network_allocate (&ip -> shared_network, MDL);
975 if (status != ISC_R_SUCCESS)
976 log_fatal ("No memory for shared subnet: %s",
977 isc_result_totext (status));
978 ip -> shared_network -> name = dmalloc (strlen (fnn) + 1, MDL);
979 strcpy (ip -> shared_network -> name, fnn);
980 return 1;
983 /* If there's a registered subnet for this address,
984 connect it together... */
985 subnet = (struct subnet *)0;
986 if (find_subnet (&subnet, *ia, MDL)) {
987 /* If this interface has multiple aliases on the same
988 subnet, ignore all but the first we encounter. */
989 if (!subnet -> interface) {
990 interface_reference (&subnet -> interface, ip, MDL);
991 subnet -> interface_address = *ia;
992 } else if (subnet -> interface != ip) {
993 log_error ("Multiple interfaces match the %s: %s %s",
994 "same subnet",
995 subnet -> interface -> name, ip -> name);
997 share = subnet -> shared_network;
998 if (ip -> shared_network &&
999 ip -> shared_network != share) {
1000 log_fatal ("Interface %s matches multiple shared %s",
1001 ip -> name, "networks");
1002 } else {
1003 if (!ip -> shared_network)
1004 shared_network_reference
1005 (&ip -> shared_network, share, MDL);
1008 if (!share -> interface) {
1009 interface_reference (&share -> interface, ip, MDL);
1010 } else if (share -> interface != ip) {
1011 log_error ("Multiple interfaces match the %s: %s %s",
1012 "same shared network",
1013 share -> interface -> name, ip -> name);
1015 subnet_dereference (&subnet, MDL);
1017 return 1;
1020 static TIME shutdown_time;
1021 static int omapi_connection_count;
1022 enum dhcp_shutdown_state shutdown_state;
1024 isc_result_t dhcp_io_shutdown (omapi_object_t *obj, void *foo)
1026 /* Shut down all listeners. */
1027 if (shutdown_state == shutdown_listeners &&
1028 obj -> type == omapi_type_listener &&
1029 obj -> inner &&
1030 obj -> inner -> type == omapi_type_protocol_listener) {
1031 omapi_listener_destroy (obj, MDL);
1032 return ISC_R_SUCCESS;
1035 /* Shut down all existing omapi connections. */
1036 if (obj -> type == omapi_type_connection &&
1037 obj -> inner &&
1038 obj -> inner -> type == omapi_type_protocol) {
1039 if (shutdown_state == shutdown_drop_omapi_connections) {
1040 omapi_disconnect (obj, 1);
1042 omapi_connection_count++;
1043 if (shutdown_state == shutdown_omapi_connections) {
1044 omapi_disconnect (obj, 0);
1045 return ISC_R_SUCCESS;
1049 /* Shutdown all DHCP interfaces. */
1050 if (obj -> type == dhcp_type_interface &&
1051 shutdown_state == shutdown_dhcp) {
1052 dhcp_interface_remove (obj, (omapi_object_t *)0);
1053 return ISC_R_SUCCESS;
1055 return ISC_R_SUCCESS;
1058 static isc_result_t dhcp_io_shutdown_countdown (void *vlp)
1060 dhcp_failover_state_t *state;
1061 #if defined (FAILOVER_PROTOCOL)
1062 int failover_connection_count = 0;
1063 #endif
1065 oncemore:
1066 if (shutdown_state == shutdown_listeners ||
1067 shutdown_state == shutdown_omapi_connections ||
1068 shutdown_state == shutdown_drop_omapi_connections ||
1069 shutdown_state == shutdown_dhcp) {
1070 omapi_connection_count = 0;
1071 omapi_io_state_foreach (dhcp_io_shutdown, 0);
1074 if ((shutdown_state == shutdown_listeners ||
1075 shutdown_state == shutdown_omapi_connections ||
1076 shutdown_state == shutdown_drop_omapi_connections) &&
1077 omapi_connection_count == 0) {
1078 shutdown_state = shutdown_dhcp;
1079 shutdown_time = cur_time;
1080 goto oncemore;
1081 } else if (shutdown_state == shutdown_listeners &&
1082 cur_time - shutdown_time > 4) {
1083 shutdown_state = shutdown_omapi_connections;
1084 shutdown_time = cur_time;
1085 } else if (shutdown_state == shutdown_omapi_connections &&
1086 cur_time - shutdown_time > 4) {
1087 shutdown_state = shutdown_drop_omapi_connections;
1088 shutdown_time = cur_time;
1089 } else if (shutdown_state == shutdown_drop_omapi_connections &&
1090 cur_time - shutdown_time > 4) {
1091 shutdown_state = shutdown_dhcp;
1092 shutdown_time = cur_time;
1093 goto oncemore;
1094 } else if (shutdown_state == shutdown_dhcp &&
1095 cur_time - shutdown_time > 4) {
1096 shutdown_state = shutdown_done;
1097 shutdown_time = cur_time;
1100 #if defined (FAILOVER_PROTOCOL)
1101 /* Set all failover peers into the shutdown state. */
1102 if (shutdown_state == shutdown_dhcp) {
1103 for (state = failover_states; state; state = state -> next) {
1104 if (state -> me.state == normal) {
1105 dhcp_failover_set_state (state, shut_down);
1106 failover_connection_count++;
1108 if (state -> me.state == shut_down &&
1109 state -> partner.state != partner_down)
1110 failover_connection_count++;
1114 if (shutdown_state == shutdown_done) {
1115 for (state = failover_states; state; state = state -> next) {
1116 if (state -> me.state == shut_down) {
1117 if (state -> link_to_peer)
1118 dhcp_failover_link_dereference (&state -> link_to_peer,
1119 MDL);
1120 dhcp_failover_set_state (state, recover);
1123 #if defined (DEBUG_MEMORY_LEAKAGE) && \
1124 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1125 free_everything ();
1126 omapi_print_dmalloc_usage_by_caller ();
1127 #endif
1128 exit (0);
1130 #else
1131 if (shutdown_state == shutdown_done) {
1132 #if defined (DEBUG_MEMORY_LEAKAGE) && \
1133 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1134 free_everything ();
1135 omapi_print_dmalloc_usage_by_caller ();
1136 #endif
1137 exit (0);
1139 #endif
1140 if (shutdown_state == shutdown_dhcp &&
1141 !failover_connection_count) {
1142 shutdown_state = shutdown_done;
1143 shutdown_time = cur_time;
1144 goto oncemore;
1146 add_timeout (cur_time + 1,
1147 (void (*)(void *))dhcp_io_shutdown_countdown, 0, 0, 0);
1148 return ISC_R_SUCCESS;
1151 isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
1152 control_object_state_t newstate)
1154 if (newstate == server_shutdown) {
1155 shutdown_time = cur_time;
1156 shutdown_state = shutdown_listeners;
1157 dhcp_io_shutdown_countdown (0);
1158 return ISC_R_SUCCESS;
1160 return ISC_R_INVALIDARG;