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.
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.115.2.15 2004/09/29 23:01:50 dhankins Exp $ Copyright 2004 Internet Systems Consortium.";
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/";
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
)
206 int pidfilewritten
= 0;
212 char *server
= (char *)0;
215 struct interface_info
*ip
;
218 omapi_object_t
*auth
;
219 struct tsig_key
*key
;
220 omapi_typed_data_t
*td
;
221 int no_dhcpd_conf
= 0;
223 int no_dhcpd_pid
= 0;
224 #if defined (TRACING)
225 char *traceinfile
= (char *)0;
226 char *traceoutfile
= (char *)0;
229 /* Make sure we have stdin, stdout and stderr. */
230 status
= open ("/dev/null", O_RDWR
);
232 status
= open ("/dev/null", O_RDWR
);
234 status
= open ("/dev/null", O_RDWR
);
235 log_perror
= 0; /* No sense logging to /dev/null. */
236 } else if (status
!= -1)
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
252 dhcp_common_objects_setup ();
254 /* Initially, log errors to stderr as well as to syslogd. */
256 openlog ("dhcpd", LOG_NDELAY
);
257 log_priority
= DHCPD_LOG_FACILITY
;
259 openlog ("dhcpd", LOG_NDELAY
, DHCPD_LOG_FACILITY
);
262 for (i
= 1; i
< argc
; i
++) {
263 if (!strcmp (argv
[i
], "-p")) {
266 for (s
= argv
[i
]; *s
; s
++)
268 log_fatal ("%s: not a valid UDP port",
270 status
= atoi (argv
[i
]);
271 if (status
< 1 || status
> 65535)
272 log_fatal ("%s: not a valid UDP port",
274 local_port
= htons (status
);
275 log_debug ("binding to user-specified port %d",
277 } else if (!strcmp (argv
[i
], "-f")) {
281 } else if (!strcmp (argv
[i
], "-d")) {
286 } else if (!strcmp (argv
[i
], "-s")) {
290 } else if (!strcmp (argv
[i
], "-cf")) {
293 path_dhcpd_conf
= argv
[i
];
295 } else if (!strcmp (argv
[i
], "-lf")) {
298 path_dhcpd_db
= argv
[i
];
300 } else if (!strcmp (argv
[i
], "-pf")) {
303 path_dhcpd_pid
= argv
[i
];
305 } else if (!strcmp (argv
[i
], "-t")) {
306 /* test configurations only */
312 } else if (!strcmp (argv
[i
], "-T")) {
313 /* test configurations and lease file only */
320 } else if (!strcmp (argv
[i
], "-q")) {
322 quiet_interface_discovery
= 1;
323 } else if (!strcmp (argv
[i
], "--version")) {
324 log_info ("isc-dhcpd-%s", DHCP_VERSION
);
326 #if defined (TRACING)
327 } else if (!strcmp (argv
[i
], "-tf")) {
330 traceoutfile
= argv
[i
];
331 } else if (!strcmp (argv
[i
], "-play")) {
334 traceinfile
= argv
[i
];
335 trace_replay_init ();
337 } else if (argv
[i
][0] == '-') {
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
]);
349 interface_reference (&tmp
-> next
,
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"))) {
361 if (!no_dhcpd_db
&& (s
= getenv ("PATH_DHCPD_DB"))) {
364 if (!no_dhcpd_pid
&& (s
= getenv ("PATH_DHCPD_PID"))) {
369 log_info ("%s %s", message
, DHCP_VERSION
);
370 log_info (copyright
);
378 #if defined (TRACING)
379 trace_init (set_time
, MDL
);
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,
390 trace_seed_stop
, MDL
);
393 /* Default to the DHCP/BOOTP port. */
396 if ((s
= getenv ("DHCPD_PORT"))) {
397 local_port
= htons (atoi (s
));
398 log_debug ("binding to environment-specified port %d",
401 ent
= getservbyname ("dhcp", "udp");
403 local_port
= htons (67);
405 local_port
= ent
-> s_port
;
406 #ifndef __CYGWIN32__ /* XXX */
412 remote_port
= htons (ntohs (local_port
) + 1);
415 if (!inet_aton (server
, &limited_broadcast
)) {
417 he
= gethostbyname (server
);
419 memcpy (&limited_broadcast
,
420 he
-> h_addr_list
[0],
421 sizeof limited_broadcast
);
423 limited_broadcast
.s_addr
= INADDR_BROADCAST
;
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!");
458 if (!(parse_executable_statements
459 (&root_group
-> statements
, parse
, &lose
, context_any
))) {
461 log_fatal ("can't parse standard name service updater!");
466 /* Initialize icmp support... */
467 if (!cftest
&& !lftest
)
468 icmp_startup (1, lease_pinged
);
470 #if defined (TRACING)
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)
483 omapi_print_dmalloc_usage_by_caller ();
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
)
500 group_write_hook
= group_writer
;
502 /* Start up the database... */
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. */
517 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
520 &ip
-> hw_address
.hbuf
[ip
-> hw_address
.hlen
-
521 sizeof seed
], sizeof seed
);
524 srandom (seed
+ cur_time
);
525 #if defined (TRACING)
526 trace_seed_stash (trace_srandom
, seed
+ cur_time
);
532 /* First part of becoming a daemon... */
533 if ((pid
= fork ()) < 0)
534 log_fatal ("Can't fork daemon: %m");
539 /* Read previous pid file. */
540 if ((i
= open (path_dhcpd_pid
, O_RDONLY
)) >= 0) {
541 status
= read (i
, pbuf
, (sizeof pbuf
) - 1);
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
));
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)
571 /* Become session leader and get pid... */
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
));
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;
601 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
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... */
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
;
625 /* Now try to get the lease file name. */
626 option_state_allocate (&options
, MDL
);
628 execute_statements_in_scope ((struct binding_value
**)0,
631 (struct client_state
*)0,
632 (struct option_state
*)0,
633 options
, &global_scope
,
636 memset (&db
, 0, sizeof db
);
637 oc
= lookup_option (&server_universe
, options
, SV_LEASE_FILE_NAME
);
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
);
645 log_fatal ("no memory for lease db filename.");
646 memcpy (s
, db
.data
, db
.len
);
648 data_string_forget (&db
, MDL
);
652 oc
= lookup_option (&server_universe
, options
, SV_PID_FILE_NAME
);
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
);
660 log_fatal ("no memory for lease db filename.");
661 memcpy (s
, db
.data
, db
.len
);
663 data_string_forget (&db
, MDL
);
668 oc
= lookup_option (&server_universe
, options
, SV_OMAPI_PORT
);
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
)) {
675 omapi_port
= getUShort (db
.data
);
677 log_fatal ("invalid omapi port data length");
678 data_string_forget (&db
, MDL
);
681 oc
= lookup_option (&server_universe
, options
, SV_OMAPI_KEY
);
683 evaluate_option_cache (&db
, (struct packet
*)0,
684 (struct lease
*)0, (struct client_state
*)0,
686 (struct option_state
*)0,
687 &global_scope
, oc
, MDL
)) {
688 s
= dmalloc (db
.len
+ 1, MDL
);
690 log_fatal ("no memory for OMAPI key filename.");
691 memcpy (s
, db
.data
, db
.len
);
693 data_string_forget (&db
, MDL
);
694 result
= omapi_auth_key_lookup_name (&omapi_key
, s
);
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
);
703 evaluate_option_cache (&db
, (struct packet
*)0,
704 (struct lease
*)0, (struct client_state
*)0,
706 (struct option_state
*)0,
707 &global_scope
, oc
, MDL
)) {
709 local_port
= htons (getUShort (db
.data
));
711 log_fatal ("invalid local port data length");
712 data_string_forget (&db
, MDL
);
715 oc
= lookup_option (&server_universe
, options
, SV_REMOTE_PORT
);
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
)) {
722 remote_port
= htons (getUShort (db
.data
));
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
);
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
)) {
736 memcpy (&limited_broadcast
, db
.data
, 4);
738 log_fatal ("invalid remote port data length");
739 data_string_forget (&db
, MDL
);
742 oc
= lookup_option (&server_universe
, options
,
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
)) {
750 memcpy (&local_address
, db
.data
, 4);
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
);
758 if (evaluate_option_cache (&db
, (struct packet
*)0,
760 (struct client_state
*)0,
762 (struct option_state
*)0,
763 &global_scope
, oc
, MDL
)) {
765 ddns_update_style
= db
.data
[0];
767 log_fatal ("invalid dns update type");
768 data_string_forget (&db
, MDL
);
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",
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
);
784 if (evaluate_option_cache (&db
, (struct packet
*)0,
786 (struct client_state
*)0,
788 (struct option_state
*)0,
789 &global_scope
, oc
, MDL
)) {
793 openlog ("dhcpd", LOG_NDELAY
);
794 log_priority
= db
.data
[0];
797 LOG_NDELAY
, db
.data
[0]);
799 /* Log the startup banner into the new
802 /* Don't log to stderr twice. */
806 message
, DHCP_VERSION
);
807 log_info (copyright
);
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
);
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!");
853 if (!(parse_executable_statements (e
, parse
,
854 &tmp
, context_any
))) {
856 log_fatal ("can't parse standard ddns updater!");
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 ();
876 /* Print usage message. */
880 log_info ("%s %s", message
, DHCP_VERSION
);
881 log_info (copyright
);
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]",
892 "\n [-t] [-T] [-s server] [if0 [...ifN]]");
895 void lease_pinged (from
, packet
, length
)
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
906 if (!outstanding_pings
)
909 lp
= (struct lease
*)0;
910 if (!find_lease_by_ip_addr (&lp
, from
, MDL
)) {
911 log_debug ("unexpected ICMP Echo Reply from %s",
917 #if defined (FAILOVER_PROTOCOL)
919 !lp
-> pool
-> failover_peer
)
921 log_debug ("ICMP Echo Reply for %s late or spurious.",
926 if (lp
-> ends
> cur_time
) {
927 log_debug ("ICMP Echo reply while lease %s valid.",
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
);
941 lease_dereference (&lp
, MDL
);
944 void lease_ping_timeout (vlp
)
947 struct lease
*lp
= vlp
;
949 #if defined (DEBUG_MEMORY_LEAKAGE)
950 unsigned long previous_outstanding
= dmalloc_outstanding
;
956 #if defined (DEBUG_MEMORY_LEAKAGE)
957 log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
959 dmalloc_outstanding
- previous_outstanding
,
960 dmalloc_outstanding
, dmalloc_longterm
);
962 #if defined (DEBUG_MEMORY_LEAKAGE)
963 dmalloc_dump_outstanding ();
967 int dhcpd_interface_setup_hook (struct interface_info
*ip
, struct iaddr
*ia
)
969 struct subnet
*subnet
;
970 struct shared_network
*share
;
973 /* Special case for fallback network - not sure why this is
976 const char *fnn
= "fallback-net";
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
);
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",
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");
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
);
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
&&
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
&&
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;
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
;
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
;
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
,
1124 dhcp_failover_set_state (state
, recover
);
1127 #if defined (DEBUG_MEMORY_LEAKAGE) && \
1128 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1130 omapi_print_dmalloc_usage_by_caller ();
1135 if (shutdown_state
== shutdown_done
) {
1136 #if defined (DEBUG_MEMORY_LEAKAGE) && \
1137 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1139 omapi_print_dmalloc_usage_by_caller ();
1144 if (shutdown_state
== shutdown_dhcp
&&
1145 !failover_connection_count
) {
1146 shutdown_state
= shutdown_done
;
1147 shutdown_time
= cur_time
;
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
;