6 * Copyright (c) 2004-2006 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.
23 * Redwood City, CA 94063
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''.
36 static char ocopyright
[] =
37 "$Id: dhcpd.c,v 1.121 2006/07/17 15:21:45 dhankins Exp $ Copyright 2004-2006 Internet Systems Consortium.";
40 static char copyright
[] =
41 "Copyright 2004-2006 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/";
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
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
71 char old_nsupdate
[] = " \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\
84 unset ddns-fwd-name; \n\
85 on expiry or release { \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\
97 unset ddns-fwd-name; \n\
101 set ddns-rev-name = \n\
102 concat (binary-to-ascii (10, 8, \".\", \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\
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\
117 unset ddns-fwd-name; \n\
120 on release or expiry; \n\
125 on release or expiry { \n\
126 switch (ns-update (delete (IN, PTR, ddns-rev-name, null))) {\n\
128 unset ddns-rev-name; \n\
131 switch (ns-update (delete (IN, A, ddns-fwd-name, \n\
132 leased-address))) { \n\
134 unset ddns-fwd-name; \n\
137 on release or expiry; \n\
143 unset new-ddns-fwd-name; \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;
159 #if defined (TRACING)
160 trace_type_t
*trace_srandom
;
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
) {
169 return ISC_R_INVALIDKEY
;
170 return ISC_R_SUCCESS
;
173 static void omapi_listener_start (void *foo
)
175 omapi_object_t
*listener
;
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
)
207 int pidfilewritten
= 0;
213 char *server
= (char *)0;
216 struct interface_info
*ip
;
219 omapi_object_t
*auth
;
220 struct tsig_key
*key
;
221 omapi_typed_data_t
*td
;
222 int no_dhcpd_conf
= 0;
224 int no_dhcpd_pid
= 0;
225 #if defined (TRACING)
226 char *traceinfile
= (char *)0;
227 char *traceoutfile
= (char *)0;
230 /* Make sure that file descriptors 0 (stdin), 1, (stdout), and
231 2 (stderr) are open. To do this, we assume that when we
232 open a file the lowest available file decriptor is used. */
233 fd
= open("/dev/null", O_RDWR
);
235 fd
= open("/dev/null", O_RDWR
);
237 fd
= open("/dev/null", O_RDWR
);
239 log_perror
= 0; /* No sense logging to /dev/null. */
243 /* Set up the client classification system. */
244 classification_setup ();
246 /* Initialize the omapi system. */
247 result
= omapi_init ();
248 if (result
!= ISC_R_SUCCESS
)
249 log_fatal ("Can't initialize OMAPI: %s",
250 isc_result_totext (result
));
252 /* Set up the OMAPI wrappers for common objects. */
253 dhcp_db_objects_setup ();
254 /* Set up the OMAPI wrappers for various server database internal
256 dhcp_common_objects_setup ();
258 /* Initially, log errors to stderr as well as to syslogd. */
260 openlog ("dhcpd", LOG_NDELAY
);
261 log_priority
= DHCPD_LOG_FACILITY
;
263 openlog ("dhcpd", LOG_NDELAY
, DHCPD_LOG_FACILITY
);
266 for (i
= 1; i
< argc
; i
++) {
267 if (!strcmp (argv
[i
], "-p")) {
270 for (s
= argv
[i
]; *s
; s
++)
272 log_fatal ("%s: not a valid UDP port",
274 status
= atoi (argv
[i
]);
275 if (status
< 1 || status
> 65535)
276 log_fatal ("%s: not a valid UDP port",
278 local_port
= htons (status
);
279 log_debug ("binding to user-specified port %d",
281 } else if (!strcmp (argv
[i
], "-f")) {
285 } else if (!strcmp (argv
[i
], "-d")) {
290 } else if (!strcmp (argv
[i
], "-s")) {
294 } else if (!strcmp (argv
[i
], "-cf")) {
297 path_dhcpd_conf
= argv
[i
];
299 } else if (!strcmp (argv
[i
], "-lf")) {
302 path_dhcpd_db
= argv
[i
];
304 } else if (!strcmp (argv
[i
], "-pf")) {
307 path_dhcpd_pid
= argv
[i
];
309 } else if (!strcmp (argv
[i
], "-t")) {
310 /* test configurations only */
316 } else if (!strcmp (argv
[i
], "-T")) {
317 /* test configurations and lease file only */
324 } else if (!strcmp (argv
[i
], "-q")) {
326 quiet_interface_discovery
= 1;
327 } else if (!strcmp (argv
[i
], "--version")) {
328 log_info ("isc-dhcpd-%s", DHCP_VERSION
);
330 #if defined (TRACING)
331 } else if (!strcmp (argv
[i
], "-tf")) {
334 traceoutfile
= argv
[i
];
335 } else if (!strcmp (argv
[i
], "-play")) {
338 traceinfile
= argv
[i
];
339 trace_replay_init ();
341 } else if (argv
[i
][0] == '-') {
344 struct interface_info
*tmp
=
345 (struct interface_info
*)0;
346 result
= interface_allocate (&tmp
, MDL
);
347 if (result
!= ISC_R_SUCCESS
)
348 log_fatal ("Insufficient memory to %s %s: %s",
349 "record interface", argv
[i
],
350 isc_result_totext (result
));
351 strcpy (tmp
-> name
, argv
[i
]);
353 interface_reference (&tmp
-> next
,
355 interface_dereference (&interfaces
, MDL
);
357 interface_reference (&interfaces
, tmp
, MDL
);
358 tmp
-> flags
= INTERFACE_REQUESTED
;
362 if (!no_dhcpd_conf
&& (s
= getenv ("PATH_DHCPD_CONF"))) {
365 if (!no_dhcpd_db
&& (s
= getenv ("PATH_DHCPD_DB"))) {
368 if (!no_dhcpd_pid
&& (s
= getenv ("PATH_DHCPD_PID"))) {
373 log_info ("%s %s", message
, DHCP_VERSION
);
374 log_info (copyright
);
382 #if defined (TRACING)
383 trace_init (set_time
, MDL
);
385 result
= trace_begin (traceoutfile
, MDL
);
386 if (result
!= ISC_R_SUCCESS
)
387 log_fatal ("Unable to begin trace: %s",
388 isc_result_totext (result
));
390 interface_trace_setup ();
391 parse_trace_setup ();
392 trace_srandom
= trace_type_register ("random-seed", (void *)0,
394 trace_seed_stop
, MDL
);
397 /* Default to the DHCP/BOOTP port. */
400 if ((s
= getenv ("DHCPD_PORT"))) {
401 local_port
= htons (atoi (s
));
402 log_debug ("binding to environment-specified port %d",
405 ent
= getservbyname ("dhcp", "udp");
407 local_port
= htons (67);
409 local_port
= ent
-> s_port
;
410 #ifndef __CYGWIN32__ /* XXX */
416 remote_port
= htons (ntohs (local_port
) + 1);
419 if (!inet_aton (server
, &limited_broadcast
)) {
421 he
= gethostbyname (server
);
423 memcpy (&limited_broadcast
,
424 he
-> h_addr_list
[0],
425 sizeof limited_broadcast
);
427 limited_broadcast
.s_addr
= INADDR_BROADCAST
;
430 limited_broadcast
.s_addr
= INADDR_BROADCAST
;
433 /* Get the current time... */
434 GET_TIME (&cur_time
);
436 /* Set up the initial dhcp option universe. */
437 initialize_common_option_spaces ();
438 initialize_server_option_spaces ();
440 /* Add the ddns update style enumeration prior to parsing. */
441 add_enumeration (&ddns_styles
);
442 add_enumeration (&syslog_enum
);
444 if (!group_allocate (&root_group
, MDL
))
445 log_fatal ("Can't allocate root group!");
446 root_group
-> authoritative
= 0;
448 /* Set up various hooks. */
449 dhcp_interface_setup_hook
= dhcpd_interface_setup_hook
;
450 bootp_packet_handler
= do_packet
;
452 #if defined (NSUPDATE)
453 /* Set up the standard name service updater routine. */
454 parse
= (struct parse
*)0;
455 status
= new_parse (&parse
, -1,
456 std_nsupdate
, (sizeof std_nsupdate
) - 1,
457 "standard name service update routine", 0);
458 if (status
!= ISC_R_SUCCESS
)
459 log_fatal ("can't begin parsing name service updater!");
462 if (!(parse_executable_statements
463 (&root_group
-> statements
, parse
, &lose
, context_any
))) {
465 log_fatal ("can't parse standard name service updater!");
470 /* Initialize icmp support... */
471 if (!cftest
&& !lftest
)
472 icmp_startup (1, lease_pinged
);
474 #if defined (TRACING)
477 log_error ("%s", "");
478 log_error ("** You must specify a lease file with -lf.");
479 log_error (" Dhcpd will not overwrite your default");
480 log_fatal (" lease file when playing back a trace. **");
482 trace_file_replay (traceinfile
);
484 #if defined (DEBUG_MEMORY_LEAKAGE) && \
485 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
487 omapi_print_dmalloc_usage_by_caller ();
494 /* Read the dhcpd.conf file... */
495 if (readconf () != ISC_R_SUCCESS
)
496 log_fatal ("Configuration file errors encountered -- exiting");
498 postconf_initialization (quiet
);
500 /* test option should cause an early exit */
501 if (cftest
&& !lftest
)
504 group_write_hook
= group_writer
;
506 /* Start up the database... */
512 /* Discover all the network interfaces and initialize them. */
513 discover_interfaces (DISCOVER_SERVER
);
515 /* Make up a seed for the random number generator from current
516 time plus the sum of the last four bytes of each
517 interface's hardware address interpreted as an integer.
518 Not much entropy, but we're booting, so we're not likely to
519 find anything better. */
521 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
524 &ip
-> hw_address
.hbuf
[ip
-> hw_address
.hlen
-
525 sizeof seed
], sizeof seed
);
528 srandom (seed
+ cur_time
);
529 #if defined (TRACING)
530 trace_seed_stash (trace_srandom
, seed
+ cur_time
);
536 /* First part of becoming a daemon... */
537 if ((pid
= fork ()) < 0)
538 log_fatal ("Can't fork daemon: %m");
543 /* Read previous pid file. */
544 if ((i
= open (path_dhcpd_pid
, O_RDONLY
)) >= 0) {
545 status
= read (i
, pbuf
, (sizeof pbuf
) - 1);
551 /* If the previous server process is not still running,
552 write a new pid file immediately. */
553 if (pid
&& (pid
== getpid() || kill (pid
, 0) < 0)) {
554 unlink (path_dhcpd_pid
);
555 if ((i
= open (path_dhcpd_pid
,
556 O_WRONLY
| O_CREAT
, 0644)) >= 0) {
557 sprintf (pbuf
, "%d\n", (int)getpid ());
558 write (i
, pbuf
, strlen (pbuf
));
563 log_fatal ("There's already a DHCP server running.");
567 /* If we were requested to log to stdout on the command line,
568 keep doing so; otherwise, stop. */
569 if (log_perror
== -1)
575 /* Become session leader and get pid... */
578 /* Close standard I/O descriptors. */
583 /* Reopen them on /dev/null. */
584 open("/dev/null", O_RDWR
);
585 open("/dev/null", O_RDWR
);
586 open("/dev/null", O_RDWR
);
587 log_perror
= 0; /* No sense logging to /dev/null. */
590 /* If we didn't write the pid file earlier because we found a
591 process running the logged pid, but we made it to here,
592 meaning nothing is listening on the bootp port, then write
593 the pid file out - what's in it now is bogus anyway. */
594 if (!pidfilewritten
) {
595 unlink (path_dhcpd_pid
);
596 if ((i
= open (path_dhcpd_pid
,
597 O_WRONLY
| O_CREAT
, 0644)) >= 0) {
598 sprintf (pbuf
, "%d\n", (int)getpid ());
599 write (i
, pbuf
, strlen (pbuf
));
606 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
607 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
608 dmalloc_cutoff_generation
= dmalloc_generation
;
609 dmalloc_longterm
= dmalloc_outstanding
;
610 dmalloc_outstanding
= 0;
613 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
617 omapi_set_int_value ((omapi_object_t
*)dhcp_control_object
,
618 (omapi_object_t
*)0, "state", server_running
);
620 /* Receive packets and dispatch them... */
627 void postconf_initialization (int quiet
)
629 struct option_state
*options
= (struct option_state
*)0;
630 struct data_string db
;
631 struct option_cache
*oc
;
637 /* Now try to get the lease file name. */
638 option_state_allocate (&options
, MDL
);
640 execute_statements_in_scope ((struct binding_value
**)0,
643 (struct client_state
*)0,
644 (struct option_state
*)0,
645 options
, &global_scope
,
648 memset (&db
, 0, sizeof db
);
649 oc
= lookup_option (&server_universe
, options
, SV_LEASE_FILE_NAME
);
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
);
657 log_fatal ("no memory for lease db filename.");
658 memcpy (s
, db
.data
, db
.len
);
660 data_string_forget (&db
, MDL
);
664 oc
= lookup_option (&server_universe
, options
, SV_PID_FILE_NAME
);
666 evaluate_option_cache (&db
, (struct packet
*)0,
667 (struct lease
*)0, (struct client_state
*)0,
668 options
, (struct option_state
*)0,
669 &global_scope
, oc
, MDL
)) {
670 s
= dmalloc (db
.len
+ 1, MDL
);
672 log_fatal ("no memory for lease db filename.");
673 memcpy (s
, db
.data
, db
.len
);
675 data_string_forget (&db
, MDL
);
680 oc
= lookup_option (&server_universe
, options
, SV_OMAPI_PORT
);
682 evaluate_option_cache (&db
, (struct packet
*)0,
683 (struct lease
*)0, (struct client_state
*)0,
684 options
, (struct option_state
*)0,
685 &global_scope
, oc
, MDL
)) {
687 omapi_port
= getUShort (db
.data
);
689 log_fatal ("invalid omapi port data length");
690 data_string_forget (&db
, MDL
);
693 oc
= lookup_option (&server_universe
, options
, SV_OMAPI_KEY
);
695 evaluate_option_cache (&db
, (struct packet
*)0,
696 (struct lease
*)0, (struct client_state
*)0,
698 (struct option_state
*)0,
699 &global_scope
, oc
, MDL
)) {
700 s
= dmalloc (db
.len
+ 1, MDL
);
702 log_fatal ("no memory for OMAPI key filename.");
703 memcpy (s
, db
.data
, db
.len
);
705 data_string_forget (&db
, MDL
);
706 result
= omapi_auth_key_lookup_name (&omapi_key
, s
);
708 if (result
!= ISC_R_SUCCESS
)
709 log_fatal ("OMAPI key %s: %s",
710 s
, isc_result_totext (result
));
713 oc
= lookup_option (&server_universe
, options
, SV_LOCAL_PORT
);
715 evaluate_option_cache (&db
, (struct packet
*)0,
716 (struct lease
*)0, (struct client_state
*)0,
718 (struct option_state
*)0,
719 &global_scope
, oc
, MDL
)) {
721 local_port
= htons (getUShort (db
.data
));
723 log_fatal ("invalid local port data length");
724 data_string_forget (&db
, MDL
);
727 oc
= lookup_option (&server_universe
, options
, SV_REMOTE_PORT
);
729 evaluate_option_cache (&db
, (struct packet
*)0,
730 (struct lease
*)0, (struct client_state
*)0,
731 options
, (struct option_state
*)0,
732 &global_scope
, oc
, MDL
)) {
734 remote_port
= htons (getUShort (db
.data
));
736 log_fatal ("invalid remote port data length");
737 data_string_forget (&db
, MDL
);
740 oc
= lookup_option (&server_universe
, options
,
741 SV_LIMITED_BROADCAST_ADDRESS
);
743 evaluate_option_cache (&db
, (struct packet
*)0,
744 (struct lease
*)0, (struct client_state
*)0,
745 options
, (struct option_state
*)0,
746 &global_scope
, oc
, MDL
)) {
748 memcpy (&limited_broadcast
, db
.data
, 4);
750 log_fatal ("invalid remote port data length");
751 data_string_forget (&db
, MDL
);
754 oc
= lookup_option (&server_universe
, options
,
757 evaluate_option_cache (&db
, (struct packet
*)0,
758 (struct lease
*)0, (struct client_state
*)0,
759 options
, (struct option_state
*)0,
760 &global_scope
, oc
, MDL
)) {
762 memcpy (&local_address
, db
.data
, 4);
764 log_fatal ("invalid remote port data length");
765 data_string_forget (&db
, MDL
);
768 oc
= lookup_option (&server_universe
, options
, SV_DDNS_UPDATE_STYLE
);
770 if (evaluate_option_cache (&db
, (struct packet
*)0,
772 (struct client_state
*)0,
774 (struct option_state
*)0,
775 &global_scope
, oc
, MDL
)) {
777 ddns_update_style
= db
.data
[0];
779 log_fatal ("invalid dns update type");
780 data_string_forget (&db
, MDL
);
784 log_error ("** You must add a global ddns-update-style %s%s.",
785 "statement to ", path_dhcpd_conf
);
786 log_error (" To get the same behaviour as in 3.0b2pl11 %s",
788 log_error (" versions, add a line that says \"%s\"",
789 "ddns-update-style ad-hoc;");
790 log_fatal (" Please read the dhcpd.conf manual page %s",
791 "for more information. **");
794 oc
= lookup_option (&server_universe
, options
, SV_LOG_FACILITY
);
796 if (evaluate_option_cache (&db
, (struct packet
*)0,
798 (struct client_state
*)0,
800 (struct option_state
*)0,
801 &global_scope
, oc
, MDL
)) {
805 openlog ("dhcpd", LOG_NDELAY
);
806 log_priority
= db
.data
[0];
809 LOG_NDELAY
, db
.data
[0]);
811 /* Log the startup banner into the new
814 /* Don't log to stderr twice. */
818 message
, DHCP_VERSION
);
819 log_info (copyright
);
825 log_fatal ("invalid log facility");
826 data_string_forget (&db
, MDL
);
830 /* Don't need the options anymore. */
831 option_state_dereference (&options
, MDL
);
833 #if defined (NSUPDATE)
834 /* If old-style ddns updates have been requested, parse the
835 old-style ddns updater. */
836 if (ddns_update_style
== 1) {
837 struct executable_statement
**e
, *s
;
839 if (root_group
-> statements
) {
840 s
= (struct executable_statement
*)0;
841 if (!executable_statement_allocate (&s
, MDL
))
842 log_fatal ("no memory for ddns updater");
843 executable_statement_reference
844 (&s
-> next
, root_group
-> statements
, MDL
);
845 executable_statement_dereference
846 (&root_group
-> statements
, MDL
);
847 executable_statement_reference
848 (&root_group
-> statements
, s
, MDL
);
849 s
-> op
= statements_statement
;
850 e
= &s
-> data
.statements
;
851 executable_statement_dereference (&s
, MDL
);
853 e
= &root_group
-> statements
;
856 /* Set up the standard name service updater routine. */
857 parse
= (struct parse
*)0;
858 result
= new_parse (&parse
, -1,
859 old_nsupdate
, (sizeof old_nsupdate
) - 1,
860 "old name service update routine", 0);
861 if (result
!= ISC_R_SUCCESS
)
862 log_fatal ("can't begin parsing old ddns updater!");
865 if (!(parse_executable_statements (e
, parse
,
866 &tmp
, context_any
))) {
868 log_fatal ("can't parse standard ddns updater!");
875 void postdb_startup (void)
877 /* Initialize the omapi listener state. */
878 if (omapi_port
!= -1) {
879 omapi_listener_start (0);
882 #if defined (FAILOVER_PROTOCOL)
883 /* Initialize the failover listener state. */
884 dhcp_failover_startup ();
888 /* Print usage message. */
892 log_info ("%s %s", message
, DHCP_VERSION
);
893 log_info (copyright
);
896 log_fatal ("Usage: dhcpd [-p <UDP port #>] [-d] [-f]%s%s%s%s",
897 "\n [-cf config-file] [-lf lease-file]",
898 #if defined (TRACING)
899 "\n [-tf trace-output-file]",
900 "\n [-play trace-input-file]",
904 "\n [-t] [-T] [-s server] [if0 [...ifN]]");
907 void lease_pinged (from
, packet
, length
)
914 /* Don't try to look up a pinged lease if we aren't trying to
915 ping one - otherwise somebody could easily make us churn by
916 just forging repeated ICMP EchoReply packets for us to look
918 if (!outstanding_pings
)
921 lp
= (struct lease
*)0;
922 if (!find_lease_by_ip_addr (&lp
, from
, MDL
)) {
923 log_debug ("unexpected ICMP Echo Reply from %s",
929 #if defined (FAILOVER_PROTOCOL)
931 !lp
-> pool
-> failover_peer
)
933 log_debug ("ICMP Echo Reply for %s late or spurious.",
938 if (lp
-> ends
> cur_time
) {
939 log_debug ("ICMP Echo reply while lease %s valid.",
943 /* At this point it looks like we pinged a lease and got a
944 response, which shouldn't have happened. */
945 data_string_forget (&lp
-> state
-> parameter_request_list
, MDL
);
946 free_lease_state (lp
-> state
, MDL
);
947 lp
-> state
= (struct lease_state
*)0;
949 abandon_lease (lp
, "pinged before offer");
950 cancel_timeout (lease_ping_timeout
, lp
);
953 lease_dereference (&lp
, MDL
);
956 void lease_ping_timeout (vlp
)
959 struct lease
*lp
= vlp
;
961 #if defined (DEBUG_MEMORY_LEAKAGE)
962 unsigned long previous_outstanding
= dmalloc_outstanding
;
968 #if defined (DEBUG_MEMORY_LEAKAGE)
969 log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
971 dmalloc_outstanding
- previous_outstanding
,
972 dmalloc_outstanding
, dmalloc_longterm
);
974 #if defined (DEBUG_MEMORY_LEAKAGE)
975 dmalloc_dump_outstanding ();
979 int dhcpd_interface_setup_hook (struct interface_info
*ip
, struct iaddr
*ia
)
981 struct subnet
*subnet
;
982 struct shared_network
*share
;
985 /* Special case for fallback network - not sure why this is
988 const char *fnn
= "fallback-net";
990 status
= shared_network_allocate (&ip
-> shared_network
, MDL
);
991 if (status
!= ISC_R_SUCCESS
)
992 log_fatal ("No memory for shared subnet: %s",
993 isc_result_totext (status
));
994 ip
-> shared_network
-> name
= dmalloc (strlen (fnn
) + 1, MDL
);
995 strcpy (ip
-> shared_network
-> name
, fnn
);
999 /* If there's a registered subnet for this address,
1000 connect it together... */
1001 subnet
= (struct subnet
*)0;
1002 if (find_subnet (&subnet
, *ia
, MDL
)) {
1003 /* If this interface has multiple aliases on the same
1004 subnet, ignore all but the first we encounter. */
1005 if (!subnet
-> interface
) {
1006 interface_reference (&subnet
-> interface
, ip
, MDL
);
1007 subnet
-> interface_address
= *ia
;
1008 } else if (subnet
-> interface
!= ip
) {
1009 log_error ("Multiple interfaces match the %s: %s %s",
1011 subnet
-> interface
-> name
, ip
-> name
);
1013 share
= subnet
-> shared_network
;
1014 if (ip
-> shared_network
&&
1015 ip
-> shared_network
!= share
) {
1016 log_fatal ("Interface %s matches multiple shared %s",
1017 ip
-> name
, "networks");
1019 if (!ip
-> shared_network
)
1020 shared_network_reference
1021 (&ip
-> shared_network
, share
, MDL
);
1024 if (!share
-> interface
) {
1025 interface_reference (&share
-> interface
, ip
, MDL
);
1026 } else if (share
-> interface
!= ip
) {
1027 log_error ("Multiple interfaces match the %s: %s %s",
1028 "same shared network",
1029 share
-> interface
-> name
, ip
-> name
);
1031 subnet_dereference (&subnet
, MDL
);
1036 static TIME shutdown_time
;
1037 static int omapi_connection_count
;
1038 enum dhcp_shutdown_state shutdown_state
;
1040 isc_result_t
dhcp_io_shutdown (omapi_object_t
*obj
, void *foo
)
1042 /* Shut down all listeners. */
1043 if (shutdown_state
== shutdown_listeners
&&
1044 obj
-> type
== omapi_type_listener
&&
1046 obj
-> inner
-> type
== omapi_type_protocol_listener
) {
1047 omapi_listener_destroy (obj
, MDL
);
1048 return ISC_R_SUCCESS
;
1051 /* Shut down all existing omapi connections. */
1052 if (obj
-> type
== omapi_type_connection
&&
1054 obj
-> inner
-> type
== omapi_type_protocol
) {
1055 if (shutdown_state
== shutdown_drop_omapi_connections
) {
1056 omapi_disconnect (obj
, 1);
1058 omapi_connection_count
++;
1059 if (shutdown_state
== shutdown_omapi_connections
) {
1060 omapi_disconnect (obj
, 0);
1061 return ISC_R_SUCCESS
;
1065 /* Shutdown all DHCP interfaces. */
1066 if (obj
-> type
== dhcp_type_interface
&&
1067 shutdown_state
== shutdown_dhcp
) {
1068 dhcp_interface_remove (obj
, (omapi_object_t
*)0);
1069 return ISC_R_SUCCESS
;
1071 return ISC_R_SUCCESS
;
1074 static isc_result_t
dhcp_io_shutdown_countdown (void *vlp
)
1076 dhcp_failover_state_t
*state
;
1077 #if defined (FAILOVER_PROTOCOL)
1078 int failover_connection_count
= 0;
1082 if (shutdown_state
== shutdown_listeners
||
1083 shutdown_state
== shutdown_omapi_connections
||
1084 shutdown_state
== shutdown_drop_omapi_connections
||
1085 shutdown_state
== shutdown_dhcp
) {
1086 omapi_connection_count
= 0;
1087 omapi_io_state_foreach (dhcp_io_shutdown
, 0);
1090 if ((shutdown_state
== shutdown_listeners
||
1091 shutdown_state
== shutdown_omapi_connections
||
1092 shutdown_state
== shutdown_drop_omapi_connections
) &&
1093 omapi_connection_count
== 0) {
1094 shutdown_state
= shutdown_dhcp
;
1095 shutdown_time
= cur_time
;
1097 } else if (shutdown_state
== shutdown_listeners
&&
1098 cur_time
- shutdown_time
> 4) {
1099 shutdown_state
= shutdown_omapi_connections
;
1100 shutdown_time
= cur_time
;
1101 } else if (shutdown_state
== shutdown_omapi_connections
&&
1102 cur_time
- shutdown_time
> 4) {
1103 shutdown_state
= shutdown_drop_omapi_connections
;
1104 shutdown_time
= cur_time
;
1105 } else if (shutdown_state
== shutdown_drop_omapi_connections
&&
1106 cur_time
- shutdown_time
> 4) {
1107 shutdown_state
= shutdown_dhcp
;
1108 shutdown_time
= cur_time
;
1110 } else if (shutdown_state
== shutdown_dhcp
&&
1111 cur_time
- shutdown_time
> 4) {
1112 shutdown_state
= shutdown_done
;
1113 shutdown_time
= cur_time
;
1116 #if defined (FAILOVER_PROTOCOL)
1117 /* Set all failover peers into the shutdown state. */
1118 if (shutdown_state
== shutdown_dhcp
) {
1119 for (state
= failover_states
; state
; state
= state
-> next
) {
1120 if (state
-> me
.state
== normal
) {
1121 dhcp_failover_set_state (state
, shut_down
);
1122 failover_connection_count
++;
1124 if (state
-> me
.state
== shut_down
&&
1125 state
-> partner
.state
!= partner_down
)
1126 failover_connection_count
++;
1130 if (shutdown_state
== shutdown_done
) {
1131 for (state
= failover_states
; state
; state
= state
-> next
) {
1132 if (state
-> me
.state
== shut_down
) {
1133 if (state
-> link_to_peer
)
1134 dhcp_failover_link_dereference (&state
-> link_to_peer
,
1136 dhcp_failover_set_state (state
, recover
);
1139 #if defined (DEBUG_MEMORY_LEAKAGE) && \
1140 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1142 omapi_print_dmalloc_usage_by_caller ();
1147 if (shutdown_state
== shutdown_done
) {
1148 #if defined (DEBUG_MEMORY_LEAKAGE) && \
1149 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1151 omapi_print_dmalloc_usage_by_caller ();
1156 if (shutdown_state
== shutdown_dhcp
&&
1157 #if defined(FAILOVER_PROTOCOL)
1158 !failover_connection_count
&&
1161 shutdown_state
= shutdown_done
;
1162 shutdown_time
= cur_time
;
1165 add_timeout (cur_time
+ 1,
1166 (void (*)(void *))dhcp_io_shutdown_countdown
, 0, 0, 0);
1167 return ISC_R_SUCCESS
;
1170 isc_result_t
dhcp_set_control_state (control_object_state_t oldstate
,
1171 control_object_state_t newstate
)
1173 if (newstate
== server_shutdown
) {
1174 shutdown_time
= cur_time
;
1175 shutdown_state
= shutdown_listeners
;
1176 dhcp_io_shutdown_countdown (0);
1177 return ISC_R_SUCCESS
;
1179 return ISC_R_INVALIDARG
;