Nuke unused macro and comment
[dragonfly.git] / contrib / dhcp-3.0 / server / dhcpd.c
blob61ca18a8887600b73215d4a665c22359183dce0e
1 /* dhcpd.c
3 DHCP Server Daemon. */
5 /*
6 * Copyright (c) 2004 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.115.2.15 2004/09/29 23:01:50 dhankins Exp $ Copyright 2004 Internet Systems Consortium.";
38 #endif
40 static char copyright[] =
41 "Copyright 2004 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 omapi_object_t *auth;
219 struct tsig_key *key;
220 omapi_typed_data_t *td;
221 int no_dhcpd_conf = 0;
222 int no_dhcpd_db = 0;
223 int no_dhcpd_pid = 0;
224 #if defined (TRACING)
225 char *traceinfile = (char *)0;
226 char *traceoutfile = (char *)0;
227 #endif
229 /* Make sure we have stdin, stdout and stderr. */
230 status = open ("/dev/null", O_RDWR);
231 if (status == 0)
232 status = open ("/dev/null", O_RDWR);
233 if (status == 1) {
234 status = open ("/dev/null", O_RDWR);
235 log_perror = 0; /* No sense logging to /dev/null. */
236 } else if (status != -1)
237 close (status);
239 /* Set up the client classification system. */
240 classification_setup ();
242 /* Initialize the omapi system. */
243 result = omapi_init ();
244 if (result != ISC_R_SUCCESS)
245 log_fatal ("Can't initialize OMAPI: %s",
246 isc_result_totext (result));
248 /* Set up the OMAPI wrappers for common objects. */
249 dhcp_db_objects_setup ();
250 /* Set up the OMAPI wrappers for various server database internal
251 objects. */
252 dhcp_common_objects_setup ();
254 /* Initially, log errors to stderr as well as to syslogd. */
255 #ifdef SYSLOG_4_2
256 openlog ("dhcpd", LOG_NDELAY);
257 log_priority = DHCPD_LOG_FACILITY;
258 #else
259 openlog ("dhcpd", LOG_NDELAY, DHCPD_LOG_FACILITY);
260 #endif
262 for (i = 1; i < argc; i++) {
263 if (!strcmp (argv [i], "-p")) {
264 if (++i == argc)
265 usage ();
266 for (s = argv [i]; *s; s++)
267 if (!isdigit (*s))
268 log_fatal ("%s: not a valid UDP port",
269 argv [i]);
270 status = atoi (argv [i]);
271 if (status < 1 || status > 65535)
272 log_fatal ("%s: not a valid UDP port",
273 argv [i]);
274 local_port = htons (status);
275 log_debug ("binding to user-specified port %d",
276 ntohs (local_port));
277 } else if (!strcmp (argv [i], "-f")) {
278 #ifndef DEBUG
279 daemon = 0;
280 #endif
281 } else if (!strcmp (argv [i], "-d")) {
282 #ifndef DEBUG
283 daemon = 0;
284 #endif
285 log_perror = -1;
286 } else if (!strcmp (argv [i], "-s")) {
287 if (++i == argc)
288 usage ();
289 server = argv [i];
290 } else if (!strcmp (argv [i], "-cf")) {
291 if (++i == argc)
292 usage ();
293 path_dhcpd_conf = argv [i];
294 no_dhcpd_conf = 1;
295 } else if (!strcmp (argv [i], "-lf")) {
296 if (++i == argc)
297 usage ();
298 path_dhcpd_db = argv [i];
299 no_dhcpd_db = 1;
300 } else if (!strcmp (argv [i], "-pf")) {
301 if (++i == argc)
302 usage ();
303 path_dhcpd_pid = argv [i];
304 no_dhcpd_pid = 1;
305 } else if (!strcmp (argv [i], "-t")) {
306 /* test configurations only */
307 #ifndef DEBUG
308 daemon = 0;
309 #endif
310 cftest = 1;
311 log_perror = -1;
312 } else if (!strcmp (argv [i], "-T")) {
313 /* test configurations and lease file only */
314 #ifndef DEBUG
315 daemon = 0;
316 #endif
317 cftest = 1;
318 lftest = 1;
319 log_perror = -1;
320 } else if (!strcmp (argv [i], "-q")) {
321 quiet = 1;
322 quiet_interface_discovery = 1;
323 } else if (!strcmp (argv [i], "--version")) {
324 log_info ("isc-dhcpd-%s", DHCP_VERSION);
325 exit (0);
326 #if defined (TRACING)
327 } else if (!strcmp (argv [i], "-tf")) {
328 if (++i == argc)
329 usage ();
330 traceoutfile = argv [i];
331 } else if (!strcmp (argv [i], "-play")) {
332 if (++i == argc)
333 usage ();
334 traceinfile = argv [i];
335 trace_replay_init ();
336 #endif /* TRACING */
337 } else if (argv [i][0] == '-') {
338 usage ();
339 } else {
340 struct interface_info *tmp =
341 (struct interface_info *)0;
342 result = interface_allocate (&tmp, MDL);
343 if (result != ISC_R_SUCCESS)
344 log_fatal ("Insufficient memory to %s %s: %s",
345 "record interface", argv [i],
346 isc_result_totext (result));
347 strcpy (tmp -> name, argv [i]);
348 if (interfaces) {
349 interface_reference (&tmp -> next,
350 interfaces, MDL);
351 interface_dereference (&interfaces, MDL);
353 interface_reference (&interfaces, tmp, MDL);
354 tmp -> flags = INTERFACE_REQUESTED;
358 if (!no_dhcpd_conf && (s = getenv ("PATH_DHCPD_CONF"))) {
359 path_dhcpd_conf = s;
361 if (!no_dhcpd_db && (s = getenv ("PATH_DHCPD_DB"))) {
362 path_dhcpd_db = s;
364 if (!no_dhcpd_pid && (s = getenv ("PATH_DHCPD_PID"))) {
365 path_dhcpd_pid = s;
368 if (!quiet) {
369 log_info ("%s %s", message, DHCP_VERSION);
370 log_info (copyright);
371 log_info (arr);
372 log_info (url);
373 } else {
374 quiet = 0;
375 log_perror = 0;
378 #if defined (TRACING)
379 trace_init (set_time, MDL);
380 if (traceoutfile) {
381 result = trace_begin (traceoutfile, MDL);
382 if (result != ISC_R_SUCCESS)
383 log_fatal ("Unable to begin trace: %s",
384 isc_result_totext (result));
386 interface_trace_setup ();
387 parse_trace_setup ();
388 trace_srandom = trace_type_register ("random-seed", (void *)0,
389 trace_seed_input,
390 trace_seed_stop, MDL);
391 #endif
393 /* Default to the DHCP/BOOTP port. */
394 if (!local_port)
396 if ((s = getenv ("DHCPD_PORT"))) {
397 local_port = htons (atoi (s));
398 log_debug ("binding to environment-specified port %d",
399 ntohs (local_port));
400 } else {
401 ent = getservbyname ("dhcp", "udp");
402 if (!ent)
403 local_port = htons (67);
404 else
405 local_port = ent -> s_port;
406 #ifndef __CYGWIN32__ /* XXX */
407 endservent ();
408 #endif
412 remote_port = htons (ntohs (local_port) + 1);
414 if (server) {
415 if (!inet_aton (server, &limited_broadcast)) {
416 struct hostent *he;
417 he = gethostbyname (server);
418 if (he) {
419 memcpy (&limited_broadcast,
420 he -> h_addr_list [0],
421 sizeof limited_broadcast);
422 } else
423 limited_broadcast.s_addr = INADDR_BROADCAST;
425 } else {
426 limited_broadcast.s_addr = INADDR_BROADCAST;
429 /* Get the current time... */
430 GET_TIME (&cur_time);
432 /* Set up the initial dhcp option universe. */
433 initialize_common_option_spaces ();
434 initialize_server_option_spaces ();
436 /* Add the ddns update style enumeration prior to parsing. */
437 add_enumeration (&ddns_styles);
438 add_enumeration (&syslog_enum);
440 if (!group_allocate (&root_group, MDL))
441 log_fatal ("Can't allocate root group!");
442 root_group -> authoritative = 0;
444 /* Set up various hooks. */
445 dhcp_interface_setup_hook = dhcpd_interface_setup_hook;
446 bootp_packet_handler = do_packet;
448 #if defined (NSUPDATE)
449 /* Set up the standard name service updater routine. */
450 parse = (struct parse *)0;
451 status = new_parse (&parse, -1,
452 std_nsupdate, (sizeof std_nsupdate) - 1,
453 "standard name service update routine", 0);
454 if (status != ISC_R_SUCCESS)
455 log_fatal ("can't begin parsing name service updater!");
457 lose = 0;
458 if (!(parse_executable_statements
459 (&root_group -> statements, parse, &lose, context_any))) {
460 end_parse (&parse);
461 log_fatal ("can't parse standard name service updater!");
463 end_parse (&parse);
464 #endif
466 /* Initialize icmp support... */
467 if (!cftest && !lftest)
468 icmp_startup (1, lease_pinged);
470 #if defined (TRACING)
471 if (traceinfile) {
472 if (!no_dhcpd_db) {
473 log_error ("%s", "");
474 log_error ("** You must specify a lease file with -lf.");
475 log_error (" Dhcpd will not overwrite your default");
476 log_fatal (" lease file when playing back a trace. **");
478 trace_file_replay (traceinfile);
480 #if defined (DEBUG_MEMORY_LEAKAGE) && \
481 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
482 free_everything ();
483 omapi_print_dmalloc_usage_by_caller ();
484 #endif
486 exit (0);
488 #endif
490 /* Read the dhcpd.conf file... */
491 if (readconf () != ISC_R_SUCCESS)
492 log_fatal ("Configuration file errors encountered -- exiting");
494 postconf_initialization (quiet);
496 /* test option should cause an early exit */
497 if (cftest && !lftest)
498 exit(0);
500 group_write_hook = group_writer;
502 /* Start up the database... */
503 db_startup (lftest);
505 if (lftest)
506 exit (0);
508 /* Discover all the network interfaces and initialize them. */
509 discover_interfaces (DISCOVER_SERVER);
511 /* Make up a seed for the random number generator from current
512 time plus the sum of the last four bytes of each
513 interface's hardware address interpreted as an integer.
514 Not much entropy, but we're booting, so we're not likely to
515 find anything better. */
516 seed = 0;
517 for (ip = interfaces; ip; ip = ip -> next) {
518 int junk;
519 memcpy (&junk,
520 &ip -> hw_address.hbuf [ip -> hw_address.hlen -
521 sizeof seed], sizeof seed);
522 seed += junk;
524 srandom (seed + cur_time);
525 #if defined (TRACING)
526 trace_seed_stash (trace_srandom, seed + cur_time);
527 #endif
528 postdb_startup ();
530 #ifndef DEBUG
531 if (daemon) {
532 /* First part of becoming a daemon... */
533 if ((pid = fork ()) < 0)
534 log_fatal ("Can't fork daemon: %m");
535 else if (pid)
536 exit (0);
539 /* Read previous pid file. */
540 if ((i = open (path_dhcpd_pid, O_RDONLY)) >= 0) {
541 status = read (i, pbuf, (sizeof pbuf) - 1);
542 close (i);
543 if (status > 0) {
544 pbuf [status] = 0;
545 pid = atoi (pbuf);
547 /* If the previous server process is not still running,
548 write a new pid file immediately. */
549 if (pid && (pid == getpid() || kill (pid, 0) < 0)) {
550 unlink (path_dhcpd_pid);
551 if ((i = open (path_dhcpd_pid,
552 O_WRONLY | O_CREAT, 0644)) >= 0) {
553 sprintf (pbuf, "%d\n", (int)getpid ());
554 write (i, pbuf, strlen (pbuf));
555 close (i);
556 pidfilewritten = 1;
558 } else
559 log_fatal ("There's already a DHCP server running.");
563 /* If we were requested to log to stdout on the command line,
564 keep doing so; otherwise, stop. */
565 if (log_perror == -1)
566 log_perror = 1;
567 else
568 log_perror = 0;
570 if (daemon) {
571 /* Become session leader and get pid... */
572 close (0);
573 close (1);
574 close (2);
575 pid = setsid ();
578 /* If we didn't write the pid file earlier because we found a
579 process running the logged pid, but we made it to here,
580 meaning nothing is listening on the bootp port, then write
581 the pid file out - what's in it now is bogus anyway. */
582 if (!pidfilewritten) {
583 unlink (path_dhcpd_pid);
584 if ((i = open (path_dhcpd_pid,
585 O_WRONLY | O_CREAT, 0644)) >= 0) {
586 sprintf (pbuf, "%d\n", (int)getpid ());
587 write (i, pbuf, strlen (pbuf));
588 close (i);
589 pidfilewritten = 1;
592 #endif /* !DEBUG */
594 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
595 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
596 dmalloc_cutoff_generation = dmalloc_generation;
597 dmalloc_longterm = dmalloc_outstanding;
598 dmalloc_outstanding = 0;
599 #endif
601 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
602 dump_rc_history ();
603 #endif
605 omapi_set_int_value ((omapi_object_t *)dhcp_control_object,
606 (omapi_object_t *)0, "state", server_running);
608 /* Receive packets and dispatch them... */
609 dispatch ();
611 /* Not reached */
612 return 0;
615 void postconf_initialization (int quiet)
617 struct option_state *options = (struct option_state *)0;
618 struct data_string db;
619 struct option_cache *oc;
620 char *s;
621 isc_result_t result;
622 struct parse *parse;
623 int tmp;
625 /* Now try to get the lease file name. */
626 option_state_allocate (&options, MDL);
628 execute_statements_in_scope ((struct binding_value **)0,
629 (struct packet *)0,
630 (struct lease *)0,
631 (struct client_state *)0,
632 (struct option_state *)0,
633 options, &global_scope,
634 root_group,
635 (struct group *)0);
636 memset (&db, 0, sizeof db);
637 oc = lookup_option (&server_universe, options, SV_LEASE_FILE_NAME);
638 if (oc &&
639 evaluate_option_cache (&db, (struct packet *)0,
640 (struct lease *)0, (struct client_state *)0,
641 options, (struct option_state *)0,
642 &global_scope, oc, MDL)) {
643 s = dmalloc (db.len + 1, MDL);
644 if (!s)
645 log_fatal ("no memory for lease db filename.");
646 memcpy (s, db.data, db.len);
647 s [db.len] = 0;
648 data_string_forget (&db, MDL);
649 path_dhcpd_db = s;
652 oc = lookup_option (&server_universe, options, SV_PID_FILE_NAME);
653 if (oc &&
654 evaluate_option_cache (&db, (struct packet *)0,
655 (struct lease *)0, (struct client_state *)0,
656 options, (struct option_state *)0,
657 &global_scope, oc, MDL)) {
658 s = dmalloc (db.len + 1, MDL);
659 if (!s)
660 log_fatal ("no memory for lease db filename.");
661 memcpy (s, db.data, db.len);
662 s [db.len] = 0;
663 data_string_forget (&db, MDL);
664 path_dhcpd_pid = s;
667 omapi_port = -1;
668 oc = lookup_option (&server_universe, options, SV_OMAPI_PORT);
669 if (oc &&
670 evaluate_option_cache (&db, (struct packet *)0,
671 (struct lease *)0, (struct client_state *)0,
672 options, (struct option_state *)0,
673 &global_scope, oc, MDL)) {
674 if (db.len == 2) {
675 omapi_port = getUShort (db.data);
676 } else
677 log_fatal ("invalid omapi port data length");
678 data_string_forget (&db, MDL);
681 oc = lookup_option (&server_universe, options, SV_OMAPI_KEY);
682 if (oc &&
683 evaluate_option_cache (&db, (struct packet *)0,
684 (struct lease *)0, (struct client_state *)0,
685 options,
686 (struct option_state *)0,
687 &global_scope, oc, MDL)) {
688 s = dmalloc (db.len + 1, MDL);
689 if (!s)
690 log_fatal ("no memory for OMAPI key filename.");
691 memcpy (s, db.data, db.len);
692 s [db.len] = 0;
693 data_string_forget (&db, MDL);
694 result = omapi_auth_key_lookup_name (&omapi_key, s);
695 dfree (s, MDL);
696 if (result != ISC_R_SUCCESS)
697 log_fatal ("OMAPI key %s: %s",
698 s, isc_result_totext (result));
701 oc = lookup_option (&server_universe, options, SV_LOCAL_PORT);
702 if (oc &&
703 evaluate_option_cache (&db, (struct packet *)0,
704 (struct lease *)0, (struct client_state *)0,
705 options,
706 (struct option_state *)0,
707 &global_scope, oc, MDL)) {
708 if (db.len == 2) {
709 local_port = htons (getUShort (db.data));
710 } else
711 log_fatal ("invalid local port data length");
712 data_string_forget (&db, MDL);
715 oc = lookup_option (&server_universe, options, SV_REMOTE_PORT);
716 if (oc &&
717 evaluate_option_cache (&db, (struct packet *)0,
718 (struct lease *)0, (struct client_state *)0,
719 options, (struct option_state *)0,
720 &global_scope, oc, MDL)) {
721 if (db.len == 2) {
722 remote_port = htons (getUShort (db.data));
723 } else
724 log_fatal ("invalid remote port data length");
725 data_string_forget (&db, MDL);
728 oc = lookup_option (&server_universe, options,
729 SV_LIMITED_BROADCAST_ADDRESS);
730 if (oc &&
731 evaluate_option_cache (&db, (struct packet *)0,
732 (struct lease *)0, (struct client_state *)0,
733 options, (struct option_state *)0,
734 &global_scope, oc, MDL)) {
735 if (db.len == 4) {
736 memcpy (&limited_broadcast, db.data, 4);
737 } else
738 log_fatal ("invalid remote port data length");
739 data_string_forget (&db, MDL);
742 oc = lookup_option (&server_universe, options,
743 SV_LOCAL_ADDRESS);
744 if (oc &&
745 evaluate_option_cache (&db, (struct packet *)0,
746 (struct lease *)0, (struct client_state *)0,
747 options, (struct option_state *)0,
748 &global_scope, oc, MDL)) {
749 if (db.len == 4) {
750 memcpy (&local_address, db.data, 4);
751 } else
752 log_fatal ("invalid remote port data length");
753 data_string_forget (&db, MDL);
756 oc = lookup_option (&server_universe, options, SV_DDNS_UPDATE_STYLE);
757 if (oc) {
758 if (evaluate_option_cache (&db, (struct packet *)0,
759 (struct lease *)0,
760 (struct client_state *)0,
761 options,
762 (struct option_state *)0,
763 &global_scope, oc, MDL)) {
764 if (db.len == 1) {
765 ddns_update_style = db.data [0];
766 } else
767 log_fatal ("invalid dns update type");
768 data_string_forget (&db, MDL);
770 } else {
771 log_info ("%s", "");
772 log_error ("** You must add a global ddns-update-style %s%s.",
773 "statement to ", path_dhcpd_conf);
774 log_error (" To get the same behaviour as in 3.0b2pl11 %s",
775 "and previous");
776 log_error (" versions, add a line that says \"%s\"",
777 "ddns-update-style ad-hoc;");
778 log_fatal (" Please read the dhcpd.conf manual page %s",
779 "for more information. **");
782 oc = lookup_option (&server_universe, options, SV_LOG_FACILITY);
783 if (oc) {
784 if (evaluate_option_cache (&db, (struct packet *)0,
785 (struct lease *)0,
786 (struct client_state *)0,
787 options,
788 (struct option_state *)0,
789 &global_scope, oc, MDL)) {
790 if (db.len == 1) {
791 closelog ();
792 #ifdef SYSLOG_4_2
793 openlog ("dhcpd", LOG_NDELAY);
794 log_priority = db.data [0];
795 #else
796 openlog ("dhcpd",
797 LOG_NDELAY, db.data [0]);
798 #endif
799 /* Log the startup banner into the new
800 log file. */
801 if (!quiet) {
802 /* Don't log to stderr twice. */
803 tmp = log_perror;
804 log_perror = 0;
805 log_info ("%s %s",
806 message, DHCP_VERSION);
807 log_info (copyright);
808 log_info (arr);
809 log_info (url);
810 log_perror = tmp;
812 } else
813 log_fatal ("invalid log facility");
814 data_string_forget (&db, MDL);
818 /* Don't need the options anymore. */
819 option_state_dereference (&options, MDL);
821 #if defined (NSUPDATE)
822 /* If old-style ddns updates have been requested, parse the
823 old-style ddns updater. */
824 if (ddns_update_style == 1) {
825 struct executable_statement **e, *s;
827 if (root_group -> statements) {
828 s = (struct executable_statement *)0;
829 if (!executable_statement_allocate (&s, MDL))
830 log_fatal ("no memory for ddns updater");
831 executable_statement_reference
832 (&s -> next, root_group -> statements, MDL);
833 executable_statement_dereference
834 (&root_group -> statements, MDL);
835 executable_statement_reference
836 (&root_group -> statements, s, MDL);
837 s -> op = statements_statement;
838 e = &s -> data.statements;
839 executable_statement_dereference (&s, MDL);
840 } else {
841 e = &root_group -> statements;
844 /* Set up the standard name service updater routine. */
845 parse = (struct parse *)0;
846 result = new_parse (&parse, -1,
847 old_nsupdate, (sizeof old_nsupdate) - 1,
848 "old name service update routine", 0);
849 if (result != ISC_R_SUCCESS)
850 log_fatal ("can't begin parsing old ddns updater!");
852 tmp = 0;
853 if (!(parse_executable_statements (e, parse,
854 &tmp, context_any))) {
855 end_parse (&parse);
856 log_fatal ("can't parse standard ddns updater!");
858 end_parse (&parse);
860 #endif
863 void postdb_startup (void)
865 /* Initialize the omapi listener state. */
866 if (omapi_port != -1) {
867 omapi_listener_start (0);
870 #if defined (FAILOVER_PROTOCOL)
871 /* Initialize the failover listener state. */
872 dhcp_failover_startup ();
873 #endif
876 /* Print usage message. */
878 static void usage ()
880 log_info ("%s %s", message, DHCP_VERSION);
881 log_info (copyright);
882 log_info (arr);
884 log_fatal ("Usage: dhcpd [-p <UDP port #>] [-d] [-f]%s%s%s%s",
885 "\n [-cf config-file] [-lf lease-file]",
886 #if defined (TRACING)
887 "\n [-tf trace-output-file]",
888 "\n [-play trace-input-file]",
889 #else
890 "", "",
891 #endif /* TRACING */
892 "\n [-t] [-T] [-s server] [if0 [...ifN]]");
895 void lease_pinged (from, packet, length)
896 struct iaddr from;
897 u_int8_t *packet;
898 int length;
900 struct lease *lp;
902 /* Don't try to look up a pinged lease if we aren't trying to
903 ping one - otherwise somebody could easily make us churn by
904 just forging repeated ICMP EchoReply packets for us to look
905 up. */
906 if (!outstanding_pings)
907 return;
909 lp = (struct lease *)0;
910 if (!find_lease_by_ip_addr (&lp, from, MDL)) {
911 log_debug ("unexpected ICMP Echo Reply from %s",
912 piaddr (from));
913 return;
916 if (!lp -> state) {
917 #if defined (FAILOVER_PROTOCOL)
918 if (!lp -> pool ||
919 !lp -> pool -> failover_peer)
920 #endif
921 log_debug ("ICMP Echo Reply for %s late or spurious.",
922 piaddr (from));
923 goto out;
926 if (lp -> ends > cur_time) {
927 log_debug ("ICMP Echo reply while lease %s valid.",
928 piaddr (from));
931 /* At this point it looks like we pinged a lease and got a
932 response, which shouldn't have happened. */
933 data_string_forget (&lp -> state -> parameter_request_list, MDL);
934 free_lease_state (lp -> state, MDL);
935 lp -> state = (struct lease_state *)0;
937 abandon_lease (lp, "pinged before offer");
938 cancel_timeout (lease_ping_timeout, lp);
939 --outstanding_pings;
940 out:
941 lease_dereference (&lp, MDL);
944 void lease_ping_timeout (vlp)
945 void *vlp;
947 struct lease *lp = vlp;
949 #if defined (DEBUG_MEMORY_LEAKAGE)
950 unsigned long previous_outstanding = dmalloc_outstanding;
951 #endif
953 --outstanding_pings;
954 dhcp_reply (lp);
956 #if defined (DEBUG_MEMORY_LEAKAGE)
957 log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
958 dmalloc_generation,
959 dmalloc_outstanding - previous_outstanding,
960 dmalloc_outstanding, dmalloc_longterm);
961 #endif
962 #if defined (DEBUG_MEMORY_LEAKAGE)
963 dmalloc_dump_outstanding ();
964 #endif
967 int dhcpd_interface_setup_hook (struct interface_info *ip, struct iaddr *ia)
969 struct subnet *subnet;
970 struct shared_network *share;
971 isc_result_t status;
973 /* Special case for fallback network - not sure why this is
974 necessary. */
975 if (!ia) {
976 const char *fnn = "fallback-net";
977 char *s;
978 status = shared_network_allocate (&ip -> shared_network, MDL);
979 if (status != ISC_R_SUCCESS)
980 log_fatal ("No memory for shared subnet: %s",
981 isc_result_totext (status));
982 ip -> shared_network -> name = dmalloc (strlen (fnn) + 1, MDL);
983 strcpy (ip -> shared_network -> name, fnn);
984 return 1;
987 /* If there's a registered subnet for this address,
988 connect it together... */
989 subnet = (struct subnet *)0;
990 if (find_subnet (&subnet, *ia, MDL)) {
991 /* If this interface has multiple aliases on the same
992 subnet, ignore all but the first we encounter. */
993 if (!subnet -> interface) {
994 interface_reference (&subnet -> interface, ip, MDL);
995 subnet -> interface_address = *ia;
996 } else if (subnet -> interface != ip) {
997 log_error ("Multiple interfaces match the %s: %s %s",
998 "same subnet",
999 subnet -> interface -> name, ip -> name);
1001 share = subnet -> shared_network;
1002 if (ip -> shared_network &&
1003 ip -> shared_network != share) {
1004 log_fatal ("Interface %s matches multiple shared %s",
1005 ip -> name, "networks");
1006 } else {
1007 if (!ip -> shared_network)
1008 shared_network_reference
1009 (&ip -> shared_network, share, MDL);
1012 if (!share -> interface) {
1013 interface_reference (&share -> interface, ip, MDL);
1014 } else if (share -> interface != ip) {
1015 log_error ("Multiple interfaces match the %s: %s %s",
1016 "same shared network",
1017 share -> interface -> name, ip -> name);
1019 subnet_dereference (&subnet, MDL);
1021 return 1;
1024 static TIME shutdown_time;
1025 static int omapi_connection_count;
1026 enum dhcp_shutdown_state shutdown_state;
1028 isc_result_t dhcp_io_shutdown (omapi_object_t *obj, void *foo)
1030 /* Shut down all listeners. */
1031 if (shutdown_state == shutdown_listeners &&
1032 obj -> type == omapi_type_listener &&
1033 obj -> inner &&
1034 obj -> inner -> type == omapi_type_protocol_listener) {
1035 omapi_listener_destroy (obj, MDL);
1036 return ISC_R_SUCCESS;
1039 /* Shut down all existing omapi connections. */
1040 if (obj -> type == omapi_type_connection &&
1041 obj -> inner &&
1042 obj -> inner -> type == omapi_type_protocol) {
1043 if (shutdown_state == shutdown_drop_omapi_connections) {
1044 omapi_disconnect (obj, 1);
1046 omapi_connection_count++;
1047 if (shutdown_state == shutdown_omapi_connections) {
1048 omapi_disconnect (obj, 0);
1049 return ISC_R_SUCCESS;
1053 /* Shutdown all DHCP interfaces. */
1054 if (obj -> type == dhcp_type_interface &&
1055 shutdown_state == shutdown_dhcp) {
1056 dhcp_interface_remove (obj, (omapi_object_t *)0);
1057 return ISC_R_SUCCESS;
1059 return ISC_R_SUCCESS;
1062 static isc_result_t dhcp_io_shutdown_countdown (void *vlp)
1064 dhcp_failover_state_t *state;
1065 #if defined (FAILOVER_PROTOCOL)
1066 int failover_connection_count = 0;
1067 #endif
1069 oncemore:
1070 if (shutdown_state == shutdown_listeners ||
1071 shutdown_state == shutdown_omapi_connections ||
1072 shutdown_state == shutdown_drop_omapi_connections ||
1073 shutdown_state == shutdown_dhcp) {
1074 omapi_connection_count = 0;
1075 omapi_io_state_foreach (dhcp_io_shutdown, 0);
1078 if ((shutdown_state == shutdown_listeners ||
1079 shutdown_state == shutdown_omapi_connections ||
1080 shutdown_state == shutdown_drop_omapi_connections) &&
1081 omapi_connection_count == 0) {
1082 shutdown_state = shutdown_dhcp;
1083 shutdown_time = cur_time;
1084 goto oncemore;
1085 } else if (shutdown_state == shutdown_listeners &&
1086 cur_time - shutdown_time > 4) {
1087 shutdown_state = shutdown_omapi_connections;
1088 shutdown_time = cur_time;
1089 } else if (shutdown_state == shutdown_omapi_connections &&
1090 cur_time - shutdown_time > 4) {
1091 shutdown_state = shutdown_drop_omapi_connections;
1092 shutdown_time = cur_time;
1093 } else if (shutdown_state == shutdown_drop_omapi_connections &&
1094 cur_time - shutdown_time > 4) {
1095 shutdown_state = shutdown_dhcp;
1096 shutdown_time = cur_time;
1097 goto oncemore;
1098 } else if (shutdown_state == shutdown_dhcp &&
1099 cur_time - shutdown_time > 4) {
1100 shutdown_state = shutdown_done;
1101 shutdown_time = cur_time;
1104 #if defined (FAILOVER_PROTOCOL)
1105 /* Set all failover peers into the shutdown state. */
1106 if (shutdown_state == shutdown_dhcp) {
1107 for (state = failover_states; state; state = state -> next) {
1108 if (state -> me.state == normal) {
1109 dhcp_failover_set_state (state, shut_down);
1110 failover_connection_count++;
1112 if (state -> me.state == shut_down &&
1113 state -> partner.state != partner_down)
1114 failover_connection_count++;
1118 if (shutdown_state == shutdown_done) {
1119 for (state = failover_states; state; state = state -> next) {
1120 if (state -> me.state == shut_down) {
1121 if (state -> link_to_peer)
1122 dhcp_failover_link_dereference (&state -> link_to_peer,
1123 MDL);
1124 dhcp_failover_set_state (state, recover);
1127 #if defined (DEBUG_MEMORY_LEAKAGE) && \
1128 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1129 free_everything ();
1130 omapi_print_dmalloc_usage_by_caller ();
1131 #endif
1132 exit (0);
1134 #else
1135 if (shutdown_state == shutdown_done) {
1136 #if defined (DEBUG_MEMORY_LEAKAGE) && \
1137 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1138 free_everything ();
1139 omapi_print_dmalloc_usage_by_caller ();
1140 #endif
1141 exit (0);
1143 #endif
1144 if (shutdown_state == shutdown_dhcp &&
1145 !failover_connection_count) {
1146 shutdown_state = shutdown_done;
1147 shutdown_time = cur_time;
1148 goto oncemore;
1150 add_timeout (cur_time + 1,
1151 (void (*)(void *))dhcp_io_shutdown_countdown, 0, 0, 0);
1152 return ISC_R_SUCCESS;
1155 isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
1156 control_object_state_t newstate)
1158 if (newstate == server_shutdown) {
1159 shutdown_time = cur_time;
1160 shutdown_state = shutdown_listeners;
1161 dhcp_io_shutdown_countdown (0);
1162 return ISC_R_SUCCESS;
1164 return ISC_R_INVALIDARG;