Updated PCI IDs to latest snapshot.
[tangerine.git] / workbench / network / stacks / AROSTCP / dhcp / server / dhcpd.c
blob76f6b14cffebeda09776bc71ef616853802d0ba8
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$ 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 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 #ifdef AMIGA
231 struct Process *me;
233 me = (struct Process *)FindTask(NULL);
234 if (!me->pr_COS)
235 log_perror = 0;
236 #else
237 status = open ("/dev/null", O_RDWR);
238 if (status == 0)
239 status = open ("/dev/null", O_RDWR);
240 if (status == 1) {
241 status = open ("/dev/null", O_RDWR);
242 log_perror = 0; /* No sense logging to /dev/null. */
243 } else if (status != -1)
244 close (status);
245 #endif
246 /* Set up the client classification system. */
247 classification_setup ();
249 /* Initialize the omapi system. */
250 result = omapi_init ();
251 if (result != ISC_R_SUCCESS)
252 log_fatal ("Can't initialize OMAPI: %s",
253 isc_result_totext (result));
255 /* Set up the OMAPI wrappers for common objects. */
256 dhcp_db_objects_setup ();
257 /* Set up the OMAPI wrappers for various server database internal
258 objects. */
259 dhcp_common_objects_setup ();
261 /* Initially, log errors to stderr as well as to syslogd. */
262 #ifdef SYSLOG_4_2
263 openlog ("dhcpd", LOG_NDELAY);
264 log_priority = DHCPD_LOG_FACILITY;
265 #else
266 openlog ("dhcpd", LOG_NDELAY, DHCPD_LOG_FACILITY);
267 #endif
269 for (i = 1; i < argc; i++) {
270 if (!strcmp (argv [i], "-p")) {
271 if (++i == argc)
272 usage ();
273 for (s = argv [i]; *s; s++)
274 if (!isdigit (*s))
275 log_fatal ("%s: not a valid UDP port",
276 argv [i]);
277 status = atoi (argv [i]);
278 if (status < 1 || status > 65535)
279 log_fatal ("%s: not a valid UDP port",
280 argv [i]);
281 local_port = htons (status);
282 log_debug ("binding to user-specified port %d",
283 ntohs (local_port));
284 } else if (!strcmp (argv [i], "-f")) {
285 #ifndef DEBUG
286 daemon = 0;
287 #endif
288 } else if (!strcmp (argv [i], "-d")) {
289 #ifndef DEBUG
290 daemon = 0;
291 #endif
292 log_perror = -1;
293 } else if (!strcmp (argv [i], "-s")) {
294 if (++i == argc)
295 usage ();
296 server = argv [i];
297 } else if (!strcmp (argv [i], "-cf")) {
298 if (++i == argc)
299 usage ();
300 path_dhcpd_conf = argv [i];
301 no_dhcpd_conf = 1;
302 } else if (!strcmp (argv [i], "-lf")) {
303 if (++i == argc)
304 usage ();
305 path_dhcpd_db = argv [i];
306 no_dhcpd_db = 1;
307 } else if (!strcmp (argv [i], "-pf")) {
308 if (++i == argc)
309 usage ();
310 path_dhcpd_pid = argv [i];
311 no_dhcpd_pid = 1;
312 } else if (!strcmp (argv [i], "-t")) {
313 /* test configurations only */
314 #ifndef DEBUG
315 daemon = 0;
316 #endif
317 cftest = 1;
318 log_perror = -1;
319 } else if (!strcmp (argv [i], "-T")) {
320 /* test configurations and lease file only */
321 #ifndef DEBUG
322 daemon = 0;
323 #endif
324 cftest = 1;
325 lftest = 1;
326 log_perror = -1;
327 } else if (!strcmp (argv [i], "-q")) {
328 quiet = 1;
329 quiet_interface_discovery = 1;
330 } else if (!strcmp (argv [i], "--version")) {
331 log_info ("isc-dhcpd-%s", DHCP_VERSION);
332 exit (0);
333 #if defined (TRACING)
334 } else if (!strcmp (argv [i], "-tf")) {
335 if (++i == argc)
336 usage ();
337 traceoutfile = argv [i];
338 } else if (!strcmp (argv [i], "-play")) {
339 if (++i == argc)
340 usage ();
341 traceinfile = argv [i];
342 trace_replay_init ();
343 #endif /* TRACING */
344 } else if (argv [i][0] == '-') {
345 usage ();
346 } else {
347 struct interface_info *tmp =
348 (struct interface_info *)0;
349 result = interface_allocate (&tmp, MDL);
350 if (result != ISC_R_SUCCESS)
351 log_fatal ("Insufficient memory to %s %s: %s",
352 "record interface", argv [i],
353 isc_result_totext (result));
354 strcpy (tmp -> name, argv [i]);
355 if (interfaces) {
356 interface_reference (&tmp -> next,
357 interfaces, MDL);
358 interface_dereference (&interfaces, MDL);
360 interface_reference (&interfaces, tmp, MDL);
361 tmp -> flags = INTERFACE_REQUESTED;
365 if (!no_dhcpd_conf && (s = getenv ("PATH_DHCPD_CONF"))) {
366 path_dhcpd_conf = s;
368 if (!no_dhcpd_db && (s = getenv ("PATH_DHCPD_DB"))) {
369 path_dhcpd_db = s;
371 if (!no_dhcpd_pid && (s = getenv ("PATH_DHCPD_PID"))) {
372 path_dhcpd_pid = s;
375 if (!quiet) {
376 log_info ("%s %s", message, DHCP_VERSION);
377 log_info (copyright);
378 log_info (arr);
379 log_info (url);
380 } else {
381 quiet = 0;
382 log_perror = 0;
385 #if defined (TRACING)
386 trace_init (set_time, MDL);
387 if (traceoutfile) {
388 result = trace_begin (traceoutfile, MDL);
389 if (result != ISC_R_SUCCESS)
390 log_fatal ("Unable to begin trace: %s",
391 isc_result_totext (result));
393 interface_trace_setup ();
394 parse_trace_setup ();
395 trace_srandom = trace_type_register ("random-seed", (void *)0,
396 trace_seed_input,
397 trace_seed_stop, MDL);
398 #endif
400 /* Default to the DHCP/BOOTP port. */
401 if (!local_port)
403 if ((s = getenv ("DHCPD_PORT"))) {
404 local_port = htons (atoi (s));
405 log_debug ("binding to environment-specified port %d",
406 ntohs (local_port));
407 } else {
408 ent = getservbyname ("dhcp", "udp");
409 if (!ent)
410 local_port = htons (67);
411 else
412 local_port = ent -> s_port;
413 #ifndef __CYGWIN32__ /* XXX */
414 endservent ();
415 #endif
419 remote_port = htons (ntohs (local_port) + 1);
421 if (server) {
422 if (!inet_aton (server, &limited_broadcast)) {
423 struct hostent *he;
424 he = gethostbyname (server);
425 if (he) {
426 memcpy (&limited_broadcast,
427 he -> h_addr_list [0],
428 sizeof limited_broadcast);
429 } else
430 limited_broadcast.s_addr = INADDR_BROADCAST;
432 } else {
433 limited_broadcast.s_addr = INADDR_BROADCAST;
436 /* Get the current time... */
437 GET_TIME (&cur_time);
439 /* Set up the initial dhcp option universe. */
440 initialize_common_option_spaces ();
441 initialize_server_option_spaces ();
443 /* Add the ddns update style enumeration prior to parsing. */
444 add_enumeration (&ddns_styles);
445 add_enumeration (&syslog_enum);
447 if (!group_allocate (&root_group, MDL))
448 log_fatal ("Can't allocate root group!");
449 root_group -> authoritative = 0;
451 /* Set up various hooks. */
452 dhcp_interface_setup_hook = dhcpd_interface_setup_hook;
453 bootp_packet_handler = do_packet;
455 #if defined (NSUPDATE)
456 /* Set up the standard name service updater routine. */
457 parse = (struct parse *)0;
458 status = new_parse (&parse, -1,
459 std_nsupdate, (sizeof std_nsupdate) - 1,
460 "standard name service update routine", 0);
461 if (status != ISC_R_SUCCESS)
462 log_fatal ("can't begin parsing name service updater!");
464 lose = 0;
465 if (!(parse_executable_statements
466 (&root_group -> statements, parse, &lose, context_any))) {
467 end_parse (&parse);
468 log_fatal ("can't parse standard name service updater!");
470 end_parse (&parse);
471 #endif
473 /* Initialize icmp support... */
474 if (!cftest && !lftest)
475 icmp_startup (1, lease_pinged);
477 #if defined (TRACING)
478 if (traceinfile) {
479 if (!no_dhcpd_db) {
480 log_error ("%s", "");
481 log_error ("** You must specify a lease file with -lf.");
482 log_error (" Dhcpd will not overwrite your default");
483 log_fatal (" lease file when playing back a trace. **");
485 trace_file_replay (traceinfile);
487 #if defined (DEBUG_MEMORY_LEAKAGE) && \
488 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
489 free_everything ();
490 omapi_print_dmalloc_usage_by_caller ();
491 #endif
493 exit (0);
495 #endif
497 /* Read the dhcpd.conf file... */
498 if (readconf () != ISC_R_SUCCESS)
499 log_fatal ("Configuration file errors encountered -- exiting");
501 postconf_initialization (quiet);
503 /* test option should cause an early exit */
504 if (cftest && !lftest)
505 exit(0);
507 group_write_hook = group_writer;
509 /* Start up the database... */
510 db_startup (lftest);
512 if (lftest)
513 exit (0);
515 /* Discover all the network interfaces and initialize them. */
516 discover_interfaces (DISCOVER_SERVER);
518 /* Make up a seed for the random number generator from current
519 time plus the sum of the last four bytes of each
520 interface's hardware address interpreted as an integer.
521 Not much entropy, but we're booting, so we're not likely to
522 find anything better. */
523 seed = 0;
524 for (ip = interfaces; ip; ip = ip -> next) {
525 int junk;
526 memcpy (&junk,
527 &ip -> hw_address.hbuf [ip -> hw_address.hlen -
528 sizeof seed], sizeof seed);
529 seed += junk;
531 srandom (seed + cur_time);
532 #if defined (TRACING)
533 trace_seed_stash (trace_srandom, seed + cur_time);
534 #endif
535 postdb_startup ();
537 #ifndef DEBUG
538 #ifndef FORK_MISSING
539 if (daemon) {
540 /* First part of becoming a daemon... */
541 if ((pid = fork ()) < 0)
542 log_fatal ("Can't fork daemon: %m");
543 else if (pid)
544 exit (0);
546 #endif
547 /* Read previous pid file. */
548 if ((i = open (path_dhcpd_pid, O_RDONLY)) >= 0) {
549 status = read (i, pbuf, (sizeof pbuf) - 1);
550 close (i);
551 if (status > 0) {
552 pbuf [status] = 0;
553 pid = atoi (pbuf);
555 /* If the previous server process is not still running,
556 write a new pid file immediately. */
557 if (pid && (pid == getpid() || kill (pid, 0) < 0)) {
558 unlink (path_dhcpd_pid);
559 if ((i = open (path_dhcpd_pid,
560 O_WRONLY | O_CREAT, 0644)) >= 0) {
561 sprintf (pbuf, "%d\n", (int)getpid ());
562 write (i, pbuf, strlen (pbuf));
563 close (i);
564 pidfilewritten = 1;
566 } else
567 log_fatal ("There's already a DHCP server running.");
571 /* If we were requested to log to stdout on the command line,
572 keep doing so; otherwise, stop. */
573 if (log_perror == -1)
574 log_perror = 1;
575 else
576 log_perror = 0;
578 if (daemon) {
579 /* Become session leader and get pid... */
580 close (0);
581 close (1);
582 close (2);
583 pid = setsid ();
586 /* If we didn't write the pid file earlier because we found a
587 process running the logged pid, but we made it to here,
588 meaning nothing is listening on the bootp port, then write
589 the pid file out - what's in it now is bogus anyway. */
590 if (!pidfilewritten) {
591 unlink (path_dhcpd_pid);
592 if ((i = open (path_dhcpd_pid,
593 O_WRONLY | O_CREAT, 0644)) >= 0) {
594 sprintf (pbuf, "%d\n", (int)getpid ());
595 write (i, pbuf, strlen (pbuf));
596 close (i);
597 pidfilewritten = 1;
600 #endif /* !DEBUG */
602 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
603 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
604 dmalloc_cutoff_generation = dmalloc_generation;
605 dmalloc_longterm = dmalloc_outstanding;
606 dmalloc_outstanding = 0;
607 #endif
609 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
610 dump_rc_history ();
611 #endif
613 omapi_set_int_value ((omapi_object_t *)dhcp_control_object,
614 (omapi_object_t *)0, "state", server_running);
616 /* Receive packets and dispatch them... */
617 dispatch ();
619 /* Not reached */
620 return 0;
623 void postconf_initialization (int quiet)
625 struct option_state *options = (struct option_state *)0;
626 struct data_string db;
627 struct option_cache *oc;
628 char *s;
629 isc_result_t result;
630 struct parse *parse;
631 int tmp;
633 /* Now try to get the lease file name. */
634 option_state_allocate (&options, MDL);
636 execute_statements_in_scope ((struct binding_value **)0,
637 (struct packet *)0,
638 (struct lease *)0,
639 (struct client_state *)0,
640 (struct option_state *)0,
641 options, &global_scope,
642 root_group,
643 (struct group *)0);
644 memset (&db, 0, sizeof db);
645 oc = lookup_option (&server_universe, options, SV_LEASE_FILE_NAME);
646 if (oc &&
647 evaluate_option_cache (&db, (struct packet *)0,
648 (struct lease *)0, (struct client_state *)0,
649 options, (struct option_state *)0,
650 &global_scope, oc, MDL)) {
651 s = dmalloc (db.len + 1, MDL);
652 if (!s)
653 log_fatal ("no memory for lease db filename.");
654 memcpy (s, db.data, db.len);
655 s [db.len] = 0;
656 data_string_forget (&db, MDL);
657 path_dhcpd_db = s;
660 oc = lookup_option (&server_universe, options, SV_PID_FILE_NAME);
661 if (oc &&
662 evaluate_option_cache (&db, (struct packet *)0,
663 (struct lease *)0, (struct client_state *)0,
664 options, (struct option_state *)0,
665 &global_scope, oc, MDL)) {
666 s = dmalloc (db.len + 1, MDL);
667 if (!s)
668 log_fatal ("no memory for lease db filename.");
669 memcpy (s, db.data, db.len);
670 s [db.len] = 0;
671 data_string_forget (&db, MDL);
672 path_dhcpd_pid = s;
675 omapi_port = -1;
676 oc = lookup_option (&server_universe, options, SV_OMAPI_PORT);
677 if (oc &&
678 evaluate_option_cache (&db, (struct packet *)0,
679 (struct lease *)0, (struct client_state *)0,
680 options, (struct option_state *)0,
681 &global_scope, oc, MDL)) {
682 if (db.len == 2) {
683 omapi_port = getUShort (db.data);
684 } else
685 log_fatal ("invalid omapi port data length");
686 data_string_forget (&db, MDL);
689 oc = lookup_option (&server_universe, options, SV_OMAPI_KEY);
690 if (oc &&
691 evaluate_option_cache (&db, (struct packet *)0,
692 (struct lease *)0, (struct client_state *)0,
693 options,
694 (struct option_state *)0,
695 &global_scope, oc, MDL)) {
696 s = dmalloc (db.len + 1, MDL);
697 if (!s)
698 log_fatal ("no memory for OMAPI key filename.");
699 memcpy (s, db.data, db.len);
700 s [db.len] = 0;
701 data_string_forget (&db, MDL);
702 result = omapi_auth_key_lookup_name (&omapi_key, s);
703 dfree (s, MDL);
704 if (result != ISC_R_SUCCESS)
705 log_fatal ("OMAPI key %s: %s",
706 s, isc_result_totext (result));
709 oc = lookup_option (&server_universe, options, SV_LOCAL_PORT);
710 if (oc &&
711 evaluate_option_cache (&db, (struct packet *)0,
712 (struct lease *)0, (struct client_state *)0,
713 options,
714 (struct option_state *)0,
715 &global_scope, oc, MDL)) {
716 if (db.len == 2) {
717 local_port = htons (getUShort (db.data));
718 } else
719 log_fatal ("invalid local port data length");
720 data_string_forget (&db, MDL);
723 oc = lookup_option (&server_universe, options, SV_REMOTE_PORT);
724 if (oc &&
725 evaluate_option_cache (&db, (struct packet *)0,
726 (struct lease *)0, (struct client_state *)0,
727 options, (struct option_state *)0,
728 &global_scope, oc, MDL)) {
729 if (db.len == 2) {
730 remote_port = htons (getUShort (db.data));
731 } else
732 log_fatal ("invalid remote port data length");
733 data_string_forget (&db, MDL);
736 oc = lookup_option (&server_universe, options,
737 SV_LIMITED_BROADCAST_ADDRESS);
738 if (oc &&
739 evaluate_option_cache (&db, (struct packet *)0,
740 (struct lease *)0, (struct client_state *)0,
741 options, (struct option_state *)0,
742 &global_scope, oc, MDL)) {
743 if (db.len == 4) {
744 memcpy (&limited_broadcast, db.data, 4);
745 } else
746 log_fatal ("invalid remote port data length");
747 data_string_forget (&db, MDL);
750 oc = lookup_option (&server_universe, options,
751 SV_LOCAL_ADDRESS);
752 if (oc &&
753 evaluate_option_cache (&db, (struct packet *)0,
754 (struct lease *)0, (struct client_state *)0,
755 options, (struct option_state *)0,
756 &global_scope, oc, MDL)) {
757 if (db.len == 4) {
758 memcpy (&local_address, db.data, 4);
759 } else
760 log_fatal ("invalid remote port data length");
761 data_string_forget (&db, MDL);
764 oc = lookup_option (&server_universe, options, SV_DDNS_UPDATE_STYLE);
765 if (oc) {
766 if (evaluate_option_cache (&db, (struct packet *)0,
767 (struct lease *)0,
768 (struct client_state *)0,
769 options,
770 (struct option_state *)0,
771 &global_scope, oc, MDL)) {
772 if (db.len == 1) {
773 ddns_update_style = db.data [0];
774 } else
775 log_fatal ("invalid dns update type");
776 data_string_forget (&db, MDL);
778 } else {
779 log_info ("%s", "");
780 log_error ("** You must add a global ddns-update-style %s%s.",
781 "statement to ", path_dhcpd_conf);
782 log_error (" To get the same behaviour as in 3.0b2pl11 %s",
783 "and previous");
784 log_error (" versions, add a line that says \"%s\"",
785 "ddns-update-style ad-hoc;");
786 log_fatal (" Please read the dhcpd.conf manual page %s",
787 "for more information. **");
790 oc = lookup_option (&server_universe, options, SV_LOG_FACILITY);
791 if (oc) {
792 if (evaluate_option_cache (&db, (struct packet *)0,
793 (struct lease *)0,
794 (struct client_state *)0,
795 options,
796 (struct option_state *)0,
797 &global_scope, oc, MDL)) {
798 if (db.len == 1) {
799 closelog ();
800 #ifdef SYSLOG_4_2
801 openlog ("dhcpd", LOG_NDELAY);
802 log_priority = db.data [0];
803 #else
804 openlog ("dhcpd",
805 LOG_NDELAY, db.data [0]);
806 #endif
807 /* Log the startup banner into the new
808 log file. */
809 if (!quiet) {
810 /* Don't log to stderr twice. */
811 tmp = log_perror;
812 log_perror = 0;
813 log_info ("%s %s",
814 message, DHCP_VERSION);
815 log_info (copyright);
816 log_info (arr);
817 log_info (url);
818 log_perror = tmp;
820 } else
821 log_fatal ("invalid log facility");
822 data_string_forget (&db, MDL);
826 /* Don't need the options anymore. */
827 option_state_dereference (&options, MDL);
829 #if defined (NSUPDATE)
830 /* If old-style ddns updates have been requested, parse the
831 old-style ddns updater. */
832 if (ddns_update_style == 1) {
833 struct executable_statement **e, *s;
835 if (root_group -> statements) {
836 s = (struct executable_statement *)0;
837 if (!executable_statement_allocate (&s, MDL))
838 log_fatal ("no memory for ddns updater");
839 executable_statement_reference
840 (&s -> next, root_group -> statements, MDL);
841 executable_statement_dereference
842 (&root_group -> statements, MDL);
843 executable_statement_reference
844 (&root_group -> statements, s, MDL);
845 s -> op = statements_statement;
846 e = &s -> data.statements;
847 executable_statement_dereference (&s, MDL);
848 } else {
849 e = &root_group -> statements;
852 /* Set up the standard name service updater routine. */
853 parse = (struct parse *)0;
854 result = new_parse (&parse, -1,
855 old_nsupdate, (sizeof old_nsupdate) - 1,
856 "old name service update routine", 0);
857 if (result != ISC_R_SUCCESS)
858 log_fatal ("can't begin parsing old ddns updater!");
860 tmp = 0;
861 if (!(parse_executable_statements (e, parse,
862 &tmp, context_any))) {
863 end_parse (&parse);
864 log_fatal ("can't parse standard ddns updater!");
866 end_parse (&parse);
868 #endif
871 void postdb_startup (void)
873 /* Initialize the omapi listener state. */
874 if (omapi_port != -1) {
875 omapi_listener_start (0);
878 #if defined (FAILOVER_PROTOCOL)
879 /* Initialize the failover listener state. */
880 dhcp_failover_startup ();
881 #endif
884 /* Print usage message. */
886 static void usage ()
888 log_info ("%s %s", message, DHCP_VERSION);
889 log_info (copyright);
890 log_info (arr);
892 log_fatal ("Usage: dhcpd [-p <UDP port #>] [-d] [-f]%s%s%s%s",
893 "\n [-cf config-file] [-lf lease-file]",
894 #if defined (TRACING)
895 "\n [-tf trace-output-file]",
896 "\n [-play trace-input-file]",
897 #else
898 "", "",
899 #endif /* TRACING */
900 "\n [-t] [-T] [-s server] [if0 [...ifN]]");
903 void lease_pinged (from, packet, length)
904 struct iaddr from;
905 u_int8_t *packet;
906 int length;
908 struct lease *lp;
910 /* Don't try to look up a pinged lease if we aren't trying to
911 ping one - otherwise somebody could easily make us churn by
912 just forging repeated ICMP EchoReply packets for us to look
913 up. */
914 if (!outstanding_pings)
915 return;
917 lp = (struct lease *)0;
918 if (!find_lease_by_ip_addr (&lp, from, MDL)) {
919 log_debug ("unexpected ICMP Echo Reply from %s",
920 piaddr (from));
921 return;
924 if (!lp -> state) {
925 #if defined (FAILOVER_PROTOCOL)
926 if (!lp -> pool ||
927 !lp -> pool -> failover_peer)
928 #endif
929 log_debug ("ICMP Echo Reply for %s late or spurious.",
930 piaddr (from));
931 goto out;
934 if (lp -> ends > cur_time) {
935 log_debug ("ICMP Echo reply while lease %s valid.",
936 piaddr (from));
939 /* At this point it looks like we pinged a lease and got a
940 response, which shouldn't have happened. */
941 data_string_forget (&lp -> state -> parameter_request_list, MDL);
942 free_lease_state (lp -> state, MDL);
943 lp -> state = (struct lease_state *)0;
945 abandon_lease (lp, "pinged before offer");
946 cancel_timeout (lease_ping_timeout, lp);
947 --outstanding_pings;
948 out:
949 lease_dereference (&lp, MDL);
952 void lease_ping_timeout (vlp)
953 void *vlp;
955 struct lease *lp = vlp;
957 #if defined (DEBUG_MEMORY_LEAKAGE)
958 unsigned long previous_outstanding = dmalloc_outstanding;
959 #endif
961 --outstanding_pings;
962 dhcp_reply (lp);
964 #if defined (DEBUG_MEMORY_LEAKAGE)
965 log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
966 dmalloc_generation,
967 dmalloc_outstanding - previous_outstanding,
968 dmalloc_outstanding, dmalloc_longterm);
969 #endif
970 #if defined (DEBUG_MEMORY_LEAKAGE)
971 dmalloc_dump_outstanding ();
972 #endif
975 int dhcpd_interface_setup_hook (struct interface_info *ip, struct iaddr *ia)
977 struct subnet *subnet;
978 struct shared_network *share;
979 isc_result_t status;
981 /* Special case for fallback network - not sure why this is
982 necessary. */
983 if (!ia) {
984 const char *fnn = "fallback-net";
985 char *s;
986 status = shared_network_allocate (&ip -> shared_network, MDL);
987 if (status != ISC_R_SUCCESS)
988 log_fatal ("No memory for shared subnet: %s",
989 isc_result_totext (status));
990 ip -> shared_network -> name = dmalloc (strlen (fnn) + 1, MDL);
991 strcpy (ip -> shared_network -> name, fnn);
992 return 1;
995 /* If there's a registered subnet for this address,
996 connect it together... */
997 subnet = (struct subnet *)0;
998 if (find_subnet (&subnet, *ia, MDL)) {
999 /* If this interface has multiple aliases on the same
1000 subnet, ignore all but the first we encounter. */
1001 if (!subnet -> interface) {
1002 interface_reference (&subnet -> interface, ip, MDL);
1003 subnet -> interface_address = *ia;
1004 } else if (subnet -> interface != ip) {
1005 log_error ("Multiple interfaces match the %s: %s %s",
1006 "same subnet",
1007 subnet -> interface -> name, ip -> name);
1009 share = subnet -> shared_network;
1010 if (ip -> shared_network &&
1011 ip -> shared_network != share) {
1012 log_fatal ("Interface %s matches multiple shared %s",
1013 ip -> name, "networks");
1014 } else {
1015 if (!ip -> shared_network)
1016 shared_network_reference
1017 (&ip -> shared_network, share, MDL);
1020 if (!share -> interface) {
1021 interface_reference (&share -> interface, ip, MDL);
1022 } else if (share -> interface != ip) {
1023 log_error ("Multiple interfaces match the %s: %s %s",
1024 "same shared network",
1025 share -> interface -> name, ip -> name);
1027 subnet_dereference (&subnet, MDL);
1029 return 1;
1032 static TIME shutdown_time;
1033 static int omapi_connection_count;
1034 enum dhcp_shutdown_state shutdown_state;
1036 isc_result_t dhcp_io_shutdown (omapi_object_t *obj, void *foo)
1038 /* Shut down all listeners. */
1039 if (shutdown_state == shutdown_listeners &&
1040 obj -> type == omapi_type_listener &&
1041 obj -> inner &&
1042 obj -> inner -> type == omapi_type_protocol_listener) {
1043 omapi_listener_destroy (obj, MDL);
1044 return ISC_R_SUCCESS;
1047 /* Shut down all existing omapi connections. */
1048 if (obj -> type == omapi_type_connection &&
1049 obj -> inner &&
1050 obj -> inner -> type == omapi_type_protocol) {
1051 if (shutdown_state == shutdown_drop_omapi_connections) {
1052 omapi_disconnect (obj, 1);
1054 omapi_connection_count++;
1055 if (shutdown_state == shutdown_omapi_connections) {
1056 omapi_disconnect (obj, 0);
1057 return ISC_R_SUCCESS;
1061 /* Shutdown all DHCP interfaces. */
1062 if (obj -> type == dhcp_type_interface &&
1063 shutdown_state == shutdown_dhcp) {
1064 dhcp_interface_remove (obj, (omapi_object_t *)0);
1065 return ISC_R_SUCCESS;
1067 return ISC_R_SUCCESS;
1070 static isc_result_t dhcp_io_shutdown_countdown (void *vlp)
1072 dhcp_failover_state_t *state;
1073 #if defined (FAILOVER_PROTOCOL)
1074 int failover_connection_count = 0;
1075 #endif
1077 oncemore:
1078 if (shutdown_state == shutdown_listeners ||
1079 shutdown_state == shutdown_omapi_connections ||
1080 shutdown_state == shutdown_drop_omapi_connections ||
1081 shutdown_state == shutdown_dhcp) {
1082 omapi_connection_count = 0;
1083 omapi_io_state_foreach (dhcp_io_shutdown, 0);
1086 if ((shutdown_state == shutdown_listeners ||
1087 shutdown_state == shutdown_omapi_connections ||
1088 shutdown_state == shutdown_drop_omapi_connections) &&
1089 omapi_connection_count == 0) {
1090 shutdown_state = shutdown_dhcp;
1091 shutdown_time = cur_time;
1092 goto oncemore;
1093 } else if (shutdown_state == shutdown_listeners &&
1094 cur_time - shutdown_time > 4) {
1095 shutdown_state = shutdown_omapi_connections;
1096 shutdown_time = cur_time;
1097 } else if (shutdown_state == shutdown_omapi_connections &&
1098 cur_time - shutdown_time > 4) {
1099 shutdown_state = shutdown_drop_omapi_connections;
1100 shutdown_time = cur_time;
1101 } else if (shutdown_state == shutdown_drop_omapi_connections &&
1102 cur_time - shutdown_time > 4) {
1103 shutdown_state = shutdown_dhcp;
1104 shutdown_time = cur_time;
1105 goto oncemore;
1106 } else if (shutdown_state == shutdown_dhcp &&
1107 cur_time - shutdown_time > 4) {
1108 shutdown_state = shutdown_done;
1109 shutdown_time = cur_time;
1112 #if defined (FAILOVER_PROTOCOL)
1113 /* Set all failover peers into the shutdown state. */
1114 if (shutdown_state == shutdown_dhcp) {
1115 for (state = failover_states; state; state = state -> next) {
1116 if (state -> me.state == normal) {
1117 dhcp_failover_set_state (state, shut_down);
1118 failover_connection_count++;
1120 if (state -> me.state == shut_down &&
1121 state -> partner.state != partner_down)
1122 failover_connection_count++;
1126 if (shutdown_state == shutdown_done) {
1127 for (state = failover_states; state; state = state -> next) {
1128 if (state -> me.state == shut_down) {
1129 if (state -> link_to_peer)
1130 dhcp_failover_link_dereference (&state -> link_to_peer,
1131 MDL);
1132 dhcp_failover_set_state (state, recover);
1135 #if defined (DEBUG_MEMORY_LEAKAGE) && \
1136 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1137 free_everything ();
1138 omapi_print_dmalloc_usage_by_caller ();
1139 #endif
1140 exit (0);
1142 #else
1143 if (shutdown_state == shutdown_done) {
1144 #if defined (DEBUG_MEMORY_LEAKAGE) && \
1145 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1146 free_everything ();
1147 omapi_print_dmalloc_usage_by_caller ();
1148 #endif
1149 exit (0);
1151 #endif
1152 if (shutdown_state == shutdown_dhcp &&
1153 !failover_connection_count) {
1154 shutdown_state = shutdown_done;
1155 shutdown_time = cur_time;
1156 goto oncemore;
1158 add_timeout (cur_time + 1,
1159 (void (*)(void *))dhcp_io_shutdown_countdown, 0, 0, 0);
1160 return ISC_R_SUCCESS;
1163 isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
1164 control_object_state_t newstate)
1166 if (newstate == server_shutdown) {
1167 shutdown_time = cur_time;
1168 shutdown_state = shutdown_listeners;
1169 dhcp_io_shutdown_countdown (0);
1170 return ISC_R_SUCCESS;
1172 return ISC_R_INVALIDARG;