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.
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.6 2005/08/11 17:13:30 drochner Exp $ Copyright 2004-2005 Internet Systems Consortium.";
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/";
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 int no_dhcpd_conf
= 0;
220 int no_dhcpd_pid
= 0;
221 #if defined (TRACING)
222 char *traceinfile
= (char *)0;
223 char *traceoutfile
= (char *)0;
226 /* Make sure we have stdin, stdout and stderr. */
227 status
= open ("/dev/null", O_RDWR
);
229 status
= open ("/dev/null", O_RDWR
);
231 status
= open ("/dev/null", O_RDWR
);
232 log_perror
= 0; /* No sense logging to /dev/null. */
233 } else if (status
!= -1)
236 /* Set up the client classification system. */
237 classification_setup ();
239 /* Initialize the omapi system. */
240 result
= omapi_init ();
241 if (result
!= ISC_R_SUCCESS
)
242 log_fatal ("Can't initialize OMAPI: %s",
243 isc_result_totext (result
));
245 /* Set up the OMAPI wrappers for common objects. */
246 dhcp_db_objects_setup ();
247 /* Set up the OMAPI wrappers for various server database internal
249 dhcp_common_objects_setup ();
251 /* Initially, log errors to stderr as well as to syslogd. */
253 openlog ("dhcpd", LOG_NDELAY
);
254 log_priority
= DHCPD_LOG_FACILITY
;
256 openlog ("dhcpd", LOG_NDELAY
, DHCPD_LOG_FACILITY
);
259 for (i
= 1; i
< argc
; i
++) {
260 if (!strcmp (argv
[i
], "-p")) {
263 for (s
= argv
[i
]; *s
; s
++)
264 if (!isdigit ((unsigned char)*s
))
265 log_fatal ("%s: not a valid UDP port",
267 status
= atoi (argv
[i
]);
268 if (status
< 1 || status
> 65535)
269 log_fatal ("%s: not a valid UDP port",
271 local_port
= htons (status
);
272 log_debug ("binding to user-specified port %d",
274 } else if (!strcmp (argv
[i
], "-f")) {
278 } else if (!strcmp (argv
[i
], "-d")) {
283 } else if (!strcmp (argv
[i
], "-s")) {
287 } else if (!strcmp (argv
[i
], "-cf")) {
290 path_dhcpd_conf
= argv
[i
];
292 } else if (!strcmp (argv
[i
], "-lf")) {
295 path_dhcpd_db
= argv
[i
];
297 } else if (!strcmp (argv
[i
], "-pf")) {
300 path_dhcpd_pid
= argv
[i
];
302 } else if (!strcmp (argv
[i
], "-t")) {
303 /* test configurations only */
309 } else if (!strcmp (argv
[i
], "-T")) {
310 /* test configurations and lease file only */
317 } else if (!strcmp (argv
[i
], "-q")) {
319 quiet_interface_discovery
= 1;
320 } else if (!strcmp (argv
[i
], "--version")) {
321 log_info ("isc-dhcpd-%s", DHCP_VERSION
);
323 #if defined (TRACING)
324 } else if (!strcmp (argv
[i
], "-tf")) {
327 traceoutfile
= argv
[i
];
328 } else if (!strcmp (argv
[i
], "-play")) {
331 traceinfile
= argv
[i
];
332 trace_replay_init ();
334 } else if (argv
[i
][0] == '-') {
337 struct interface_info
*tmp
=
338 (struct interface_info
*)0;
339 result
= interface_allocate (&tmp
, MDL
);
340 if (result
!= ISC_R_SUCCESS
)
341 log_fatal ("Insufficient memory to %s %s: %s",
342 "record interface", argv
[i
],
343 isc_result_totext (result
));
344 strcpy (tmp
-> name
, argv
[i
]);
346 interface_reference (&tmp
-> next
,
348 interface_dereference (&interfaces
, MDL
);
350 interface_reference (&interfaces
, tmp
, MDL
);
351 tmp
-> flags
= INTERFACE_REQUESTED
;
355 if (!no_dhcpd_conf
&& (s
= getenv ("PATH_DHCPD_CONF"))) {
358 if (!no_dhcpd_db
&& (s
= getenv ("PATH_DHCPD_DB"))) {
361 if (!no_dhcpd_pid
&& (s
= getenv ("PATH_DHCPD_PID"))) {
366 log_info ("%s %s", message
, DHCP_VERSION
);
367 log_info (copyright
);
375 #if defined (TRACING)
376 trace_init (set_time
, MDL
);
378 result
= trace_begin (traceoutfile
, MDL
);
379 if (result
!= ISC_R_SUCCESS
)
380 log_fatal ("Unable to begin trace: %s",
381 isc_result_totext (result
));
383 interface_trace_setup ();
384 parse_trace_setup ();
385 trace_srandom
= trace_type_register ("random-seed", (void *)0,
387 trace_seed_stop
, MDL
);
390 /* Default to the DHCP/BOOTP port. */
393 if ((s
= getenv ("DHCPD_PORT"))) {
394 local_port
= htons (atoi (s
));
395 log_debug ("binding to environment-specified port %d",
398 ent
= getservbyname ("dhcp", "udp");
400 local_port
= htons (67);
402 local_port
= ent
-> s_port
;
403 #ifndef __CYGWIN32__ /* XXX */
409 remote_port
= htons (ntohs (local_port
) + 1);
412 if (!inet_aton (server
, &limited_broadcast
)) {
414 he
= gethostbyname (server
);
416 memcpy (&limited_broadcast
,
417 he
-> h_addr_list
[0],
418 sizeof limited_broadcast
);
420 limited_broadcast
.s_addr
= INADDR_BROADCAST
;
423 limited_broadcast
.s_addr
= INADDR_BROADCAST
;
426 /* Get the current time... */
427 GET_TIME (&cur_time
);
429 /* Set up the initial dhcp option universe. */
430 initialize_common_option_spaces ();
431 initialize_server_option_spaces ();
433 /* Add the ddns update style enumeration prior to parsing. */
434 add_enumeration (&ddns_styles
);
435 add_enumeration (&syslog_enum
);
437 if (!group_allocate (&root_group
, MDL
))
438 log_fatal ("Can't allocate root group!");
439 root_group
-> authoritative
= 0;
441 /* Set up various hooks. */
442 dhcp_interface_setup_hook
= dhcpd_interface_setup_hook
;
443 bootp_packet_handler
= do_packet
;
445 #if defined (NSUPDATE)
446 /* Set up the standard name service updater routine. */
447 parse
= (struct parse
*)0;
448 status
= new_parse (&parse
, -1,
449 std_nsupdate
, (sizeof std_nsupdate
) - 1,
450 "standard name service update routine", 0);
451 if (status
!= ISC_R_SUCCESS
)
452 log_fatal ("can't begin parsing name service updater!");
455 if (!(parse_executable_statements
456 (&root_group
-> statements
, parse
, &lose
, context_any
))) {
458 log_fatal ("can't parse standard name service updater!");
463 /* Initialize icmp support... */
464 if (!cftest
&& !lftest
)
465 icmp_startup (1, lease_pinged
);
467 #if defined (TRACING)
470 log_error ("%s", "");
471 log_error ("** You must specify a lease file with -lf.");
472 log_error (" Dhcpd will not overwrite your default");
473 log_fatal (" lease file when playing back a trace. **");
475 trace_file_replay (traceinfile
);
477 #if defined (DEBUG_MEMORY_LEAKAGE) && \
478 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
480 omapi_print_dmalloc_usage_by_caller ();
487 /* Read the dhcpd.conf file... */
488 if (readconf () != ISC_R_SUCCESS
)
489 log_fatal ("Configuration file errors encountered -- exiting");
491 postconf_initialization (quiet
);
493 /* test option should cause an early exit */
494 if (cftest
&& !lftest
)
497 group_write_hook
= group_writer
;
499 /* Start up the database... */
505 /* Discover all the network interfaces and initialize them. */
506 discover_interfaces (DISCOVER_SERVER
);
508 /* Make up a seed for the random number generator from current
509 time plus the sum of the last four bytes of each
510 interface's hardware address interpreted as an integer.
511 Not much entropy, but we're booting, so we're not likely to
512 find anything better. */
514 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
517 &ip
-> hw_address
.hbuf
[ip
-> hw_address
.hlen
-
518 sizeof seed
], sizeof seed
);
521 srandom (seed
+ cur_time
);
522 #if defined (TRACING)
523 trace_seed_stash (trace_srandom
, seed
+ cur_time
);
529 /* First part of becoming a daemon... */
530 if ((pid
= fork ()) < 0)
531 log_fatal ("Can't fork daemon: %m");
536 /* Read previous pid file. */
537 if ((i
= open (path_dhcpd_pid
, O_RDONLY
)) >= 0) {
538 status
= read (i
, pbuf
, (sizeof pbuf
) - 1);
544 /* If the previous server process is not still running,
545 write a new pid file immediately. */
546 if (pid
&& (pid
== getpid() || kill (pid
, 0) < 0)) {
547 unlink (path_dhcpd_pid
);
548 if ((i
= open (path_dhcpd_pid
,
549 O_WRONLY
| O_CREAT
, 0644)) >= 0) {
550 sprintf (pbuf
, "%d\n", (int)getpid ());
551 write (i
, pbuf
, strlen (pbuf
));
556 log_fatal ("There's already a DHCP server running.");
560 /* If we were requested to log to stdout on the command line,
561 keep doing so; otherwise, stop. */
562 if (log_perror
== -1)
568 /* Become session leader and get pid... */
575 /* If we didn't write the pid file earlier because we found a
576 process running the logged pid, but we made it to here,
577 meaning nothing is listening on the bootp port, then write
578 the pid file out - what's in it now is bogus anyway. */
579 if (!pidfilewritten
) {
580 unlink (path_dhcpd_pid
);
581 if ((i
= open (path_dhcpd_pid
,
582 O_WRONLY
| O_CREAT
, 0644)) >= 0) {
583 sprintf (pbuf
, "%d\n", (int)getpid ());
584 write (i
, pbuf
, strlen (pbuf
));
591 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
592 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
593 dmalloc_cutoff_generation
= dmalloc_generation
;
594 dmalloc_longterm
= dmalloc_outstanding
;
595 dmalloc_outstanding
= 0;
598 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
602 omapi_set_int_value ((omapi_object_t
*)dhcp_control_object
,
603 (omapi_object_t
*)0, "state", server_running
);
605 /* Receive packets and dispatch them... */
612 void postconf_initialization (int quiet
)
614 struct option_state
*options
= (struct option_state
*)0;
615 struct data_string db
;
616 struct option_cache
*oc
;
622 /* Now try to get the lease file name. */
623 option_state_allocate (&options
, MDL
);
625 execute_statements_in_scope ((struct binding_value
**)0,
628 (struct client_state
*)0,
629 (struct option_state
*)0,
630 options
, &global_scope
,
633 memset (&db
, 0, sizeof db
);
634 oc
= lookup_option (&server_universe
, options
, SV_LEASE_FILE_NAME
);
636 evaluate_option_cache (&db
, (struct packet
*)0,
637 (struct lease
*)0, (struct client_state
*)0,
638 options
, (struct option_state
*)0,
639 &global_scope
, oc
, MDL
)) {
640 s
= dmalloc (db
.len
+ 1, MDL
);
642 log_fatal ("no memory for lease db filename.");
643 memcpy (s
, db
.data
, db
.len
);
645 data_string_forget (&db
, MDL
);
649 oc
= lookup_option (&server_universe
, options
, SV_PID_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
);
665 oc
= lookup_option (&server_universe
, options
, SV_OMAPI_PORT
);
667 evaluate_option_cache (&db
, (struct packet
*)0,
668 (struct lease
*)0, (struct client_state
*)0,
669 options
, (struct option_state
*)0,
670 &global_scope
, oc
, MDL
)) {
672 omapi_port
= getUShort (db
.data
);
674 log_fatal ("invalid omapi port data length");
675 data_string_forget (&db
, MDL
);
678 oc
= lookup_option (&server_universe
, options
, SV_OMAPI_KEY
);
680 evaluate_option_cache (&db
, (struct packet
*)0,
681 (struct lease
*)0, (struct client_state
*)0,
683 (struct option_state
*)0,
684 &global_scope
, oc
, MDL
)) {
685 s
= dmalloc (db
.len
+ 1, MDL
);
687 log_fatal ("no memory for OMAPI key filename.");
688 memcpy (s
, db
.data
, db
.len
);
690 data_string_forget (&db
, MDL
);
691 result
= omapi_auth_key_lookup_name (&omapi_key
, s
);
693 if (result
!= ISC_R_SUCCESS
)
694 log_fatal ("OMAPI key %s: %s",
695 s
, isc_result_totext (result
));
698 oc
= lookup_option (&server_universe
, options
, SV_LOCAL_PORT
);
700 evaluate_option_cache (&db
, (struct packet
*)0,
701 (struct lease
*)0, (struct client_state
*)0,
703 (struct option_state
*)0,
704 &global_scope
, oc
, MDL
)) {
706 local_port
= htons (getUShort (db
.data
));
708 log_fatal ("invalid local port data length");
709 data_string_forget (&db
, MDL
);
712 oc
= lookup_option (&server_universe
, options
, SV_REMOTE_PORT
);
714 evaluate_option_cache (&db
, (struct packet
*)0,
715 (struct lease
*)0, (struct client_state
*)0,
716 options
, (struct option_state
*)0,
717 &global_scope
, oc
, MDL
)) {
719 remote_port
= htons (getUShort (db
.data
));
721 log_fatal ("invalid remote port data length");
722 data_string_forget (&db
, MDL
);
725 oc
= lookup_option (&server_universe
, options
,
726 SV_LIMITED_BROADCAST_ADDRESS
);
728 evaluate_option_cache (&db
, (struct packet
*)0,
729 (struct lease
*)0, (struct client_state
*)0,
730 options
, (struct option_state
*)0,
731 &global_scope
, oc
, MDL
)) {
733 memcpy (&limited_broadcast
, db
.data
, 4);
735 log_fatal ("invalid remote port data length");
736 data_string_forget (&db
, MDL
);
739 oc
= lookup_option (&server_universe
, options
,
742 evaluate_option_cache (&db
, (struct packet
*)0,
743 (struct lease
*)0, (struct client_state
*)0,
744 options
, (struct option_state
*)0,
745 &global_scope
, oc
, MDL
)) {
747 memcpy (&local_address
, db
.data
, 4);
749 log_fatal ("invalid remote port data length");
750 data_string_forget (&db
, MDL
);
753 oc
= lookup_option (&server_universe
, options
, SV_DDNS_UPDATE_STYLE
);
755 if (evaluate_option_cache (&db
, (struct packet
*)0,
757 (struct client_state
*)0,
759 (struct option_state
*)0,
760 &global_scope
, oc
, MDL
)) {
762 ddns_update_style
= db
.data
[0];
764 log_fatal ("invalid dns update type");
765 data_string_forget (&db
, MDL
);
769 log_error ("** You must add a global ddns-update-style %s%s.",
770 "statement to ", path_dhcpd_conf
);
771 log_error (" To get the same behaviour as in 3.0b2pl11 %s",
773 log_error (" versions, add a line that says \"%s\"",
774 "ddns-update-style ad-hoc;");
775 log_fatal (" Please read the dhcpd.conf manual page %s",
776 "for more information. **");
779 oc
= lookup_option (&server_universe
, options
, SV_LOG_FACILITY
);
781 if (evaluate_option_cache (&db
, (struct packet
*)0,
783 (struct client_state
*)0,
785 (struct option_state
*)0,
786 &global_scope
, oc
, MDL
)) {
790 openlog ("dhcpd", LOG_NDELAY
);
791 log_priority
= db
.data
[0];
794 LOG_NDELAY
, db
.data
[0]);
796 /* Log the startup banner into the new
799 /* Don't log to stderr twice. */
803 message
, DHCP_VERSION
);
804 log_info (copyright
);
810 log_fatal ("invalid log facility");
811 data_string_forget (&db
, MDL
);
815 /* Don't need the options anymore. */
816 option_state_dereference (&options
, MDL
);
818 #if defined (NSUPDATE)
819 /* If old-style ddns updates have been requested, parse the
820 old-style ddns updater. */
821 if (ddns_update_style
== 1) {
822 struct executable_statement
**e
, *s
;
824 if (root_group
-> statements
) {
825 s
= (struct executable_statement
*)0;
826 if (!executable_statement_allocate (&s
, MDL
))
827 log_fatal ("no memory for ddns updater");
828 executable_statement_reference
829 (&s
-> next
, root_group
-> statements
, MDL
);
830 executable_statement_dereference
831 (&root_group
-> statements
, MDL
);
832 executable_statement_reference
833 (&root_group
-> statements
, s
, MDL
);
834 s
-> op
= statements_statement
;
835 e
= &s
-> data
.statements
;
836 executable_statement_dereference (&s
, MDL
);
838 e
= &root_group
-> statements
;
841 /* Set up the standard name service updater routine. */
842 parse
= (struct parse
*)0;
843 result
= new_parse (&parse
, -1,
844 old_nsupdate
, (sizeof old_nsupdate
) - 1,
845 "old name service update routine", 0);
846 if (result
!= ISC_R_SUCCESS
)
847 log_fatal ("can't begin parsing old ddns updater!");
850 if (!(parse_executable_statements (e
, parse
,
851 &tmp
, context_any
))) {
853 log_fatal ("can't parse standard ddns updater!");
860 void postdb_startup (void)
862 /* Initialize the omapi listener state. */
863 if (omapi_port
!= -1) {
864 omapi_listener_start (0);
867 #if defined (FAILOVER_PROTOCOL)
868 /* Initialize the failover listener state. */
869 dhcp_failover_startup ();
873 /* Print usage message. */
877 log_info ("%s %s", message
, DHCP_VERSION
);
878 log_info (copyright
);
881 log_fatal ("Usage: dhcpd [-p <UDP port #>] [-d] [-f]%s%s%s%s",
882 "\n [-cf config-file] [-lf lease-file]",
883 #if defined (TRACING)
884 "\n [-tf trace-output-file]",
885 "\n [-play trace-input-file]",
889 "\n [-t] [-T] [-s server] [if0 [...ifN]]");
892 void lease_pinged (from
, packet
, length
)
899 /* Don't try to look up a pinged lease if we aren't trying to
900 ping one - otherwise somebody could easily make us churn by
901 just forging repeated ICMP EchoReply packets for us to look
903 if (!outstanding_pings
)
906 lp
= (struct lease
*)0;
907 if (!find_lease_by_ip_addr (&lp
, from
, MDL
)) {
908 log_debug ("unexpected ICMP Echo Reply from %s",
914 #if defined (FAILOVER_PROTOCOL)
916 !lp
-> pool
-> failover_peer
)
918 log_debug ("ICMP Echo Reply for %s late or spurious.",
923 if (lp
-> ends
> cur_time
) {
924 log_debug ("ICMP Echo reply while lease %s valid.",
928 /* At this point it looks like we pinged a lease and got a
929 response, which shouldn't have happened. */
930 data_string_forget (&lp
-> state
-> parameter_request_list
, MDL
);
931 free_lease_state (lp
-> state
, MDL
);
932 lp
-> state
= (struct lease_state
*)0;
934 abandon_lease (lp
, "pinged before offer");
935 cancel_timeout (lease_ping_timeout
, lp
);
938 lease_dereference (&lp
, MDL
);
941 void lease_ping_timeout (vlp
)
944 struct lease
*lp
= vlp
;
946 #if defined (DEBUG_MEMORY_LEAKAGE)
947 unsigned long previous_outstanding
= dmalloc_outstanding
;
953 #if defined (DEBUG_MEMORY_LEAKAGE)
954 log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
956 dmalloc_outstanding
- previous_outstanding
,
957 dmalloc_outstanding
, dmalloc_longterm
);
959 #if defined (DEBUG_MEMORY_LEAKAGE)
960 dmalloc_dump_outstanding ();
964 int dhcpd_interface_setup_hook (struct interface_info
*ip
, struct iaddr
*ia
)
966 struct subnet
*subnet
;
967 struct shared_network
*share
;
970 /* Special case for fallback network - not sure why this is
973 const char *fnn
= "fallback-net";
974 status
= shared_network_allocate (&ip
-> shared_network
, MDL
);
975 if (status
!= ISC_R_SUCCESS
)
976 log_fatal ("No memory for shared subnet: %s",
977 isc_result_totext (status
));
978 ip
-> shared_network
-> name
= dmalloc (strlen (fnn
) + 1, MDL
);
979 strcpy (ip
-> shared_network
-> name
, fnn
);
983 /* If there's a registered subnet for this address,
984 connect it together... */
985 subnet
= (struct subnet
*)0;
986 if (find_subnet (&subnet
, *ia
, MDL
)) {
987 /* If this interface has multiple aliases on the same
988 subnet, ignore all but the first we encounter. */
989 if (!subnet
-> interface
) {
990 interface_reference (&subnet
-> interface
, ip
, MDL
);
991 subnet
-> interface_address
= *ia
;
992 } else if (subnet
-> interface
!= ip
) {
993 log_error ("Multiple interfaces match the %s: %s %s",
995 subnet
-> interface
-> name
, ip
-> name
);
997 share
= subnet
-> shared_network
;
998 if (ip
-> shared_network
&&
999 ip
-> shared_network
!= share
) {
1000 log_fatal ("Interface %s matches multiple shared %s",
1001 ip
-> name
, "networks");
1003 if (!ip
-> shared_network
)
1004 shared_network_reference
1005 (&ip
-> shared_network
, share
, MDL
);
1008 if (!share
-> interface
) {
1009 interface_reference (&share
-> interface
, ip
, MDL
);
1010 } else if (share
-> interface
!= ip
) {
1011 log_error ("Multiple interfaces match the %s: %s %s",
1012 "same shared network",
1013 share
-> interface
-> name
, ip
-> name
);
1015 subnet_dereference (&subnet
, MDL
);
1020 static TIME shutdown_time
;
1021 static int omapi_connection_count
;
1022 enum dhcp_shutdown_state shutdown_state
;
1024 isc_result_t
dhcp_io_shutdown (omapi_object_t
*obj
, void *foo
)
1026 /* Shut down all listeners. */
1027 if (shutdown_state
== shutdown_listeners
&&
1028 obj
-> type
== omapi_type_listener
&&
1030 obj
-> inner
-> type
== omapi_type_protocol_listener
) {
1031 omapi_listener_destroy (obj
, MDL
);
1032 return ISC_R_SUCCESS
;
1035 /* Shut down all existing omapi connections. */
1036 if (obj
-> type
== omapi_type_connection
&&
1038 obj
-> inner
-> type
== omapi_type_protocol
) {
1039 if (shutdown_state
== shutdown_drop_omapi_connections
) {
1040 omapi_disconnect (obj
, 1);
1042 omapi_connection_count
++;
1043 if (shutdown_state
== shutdown_omapi_connections
) {
1044 omapi_disconnect (obj
, 0);
1045 return ISC_R_SUCCESS
;
1049 /* Shutdown all DHCP interfaces. */
1050 if (obj
-> type
== dhcp_type_interface
&&
1051 shutdown_state
== shutdown_dhcp
) {
1052 dhcp_interface_remove (obj
, (omapi_object_t
*)0);
1053 return ISC_R_SUCCESS
;
1055 return ISC_R_SUCCESS
;
1058 static isc_result_t
dhcp_io_shutdown_countdown (void *vlp
)
1060 dhcp_failover_state_t
*state
;
1061 #if defined (FAILOVER_PROTOCOL)
1062 int failover_connection_count
= 0;
1066 if (shutdown_state
== shutdown_listeners
||
1067 shutdown_state
== shutdown_omapi_connections
||
1068 shutdown_state
== shutdown_drop_omapi_connections
||
1069 shutdown_state
== shutdown_dhcp
) {
1070 omapi_connection_count
= 0;
1071 omapi_io_state_foreach (dhcp_io_shutdown
, 0);
1074 if ((shutdown_state
== shutdown_listeners
||
1075 shutdown_state
== shutdown_omapi_connections
||
1076 shutdown_state
== shutdown_drop_omapi_connections
) &&
1077 omapi_connection_count
== 0) {
1078 shutdown_state
= shutdown_dhcp
;
1079 shutdown_time
= cur_time
;
1081 } else if (shutdown_state
== shutdown_listeners
&&
1082 cur_time
- shutdown_time
> 4) {
1083 shutdown_state
= shutdown_omapi_connections
;
1084 shutdown_time
= cur_time
;
1085 } else if (shutdown_state
== shutdown_omapi_connections
&&
1086 cur_time
- shutdown_time
> 4) {
1087 shutdown_state
= shutdown_drop_omapi_connections
;
1088 shutdown_time
= cur_time
;
1089 } else if (shutdown_state
== shutdown_drop_omapi_connections
&&
1090 cur_time
- shutdown_time
> 4) {
1091 shutdown_state
= shutdown_dhcp
;
1092 shutdown_time
= cur_time
;
1094 } else if (shutdown_state
== shutdown_dhcp
&&
1095 cur_time
- shutdown_time
> 4) {
1096 shutdown_state
= shutdown_done
;
1097 shutdown_time
= cur_time
;
1100 #if defined (FAILOVER_PROTOCOL)
1101 /* Set all failover peers into the shutdown state. */
1102 if (shutdown_state
== shutdown_dhcp
) {
1103 for (state
= failover_states
; state
; state
= state
-> next
) {
1104 if (state
-> me
.state
== normal
) {
1105 dhcp_failover_set_state (state
, shut_down
);
1106 failover_connection_count
++;
1108 if (state
-> me
.state
== shut_down
&&
1109 state
-> partner
.state
!= partner_down
)
1110 failover_connection_count
++;
1114 if (shutdown_state
== shutdown_done
) {
1115 for (state
= failover_states
; state
; state
= state
-> next
) {
1116 if (state
-> me
.state
== shut_down
) {
1117 if (state
-> link_to_peer
)
1118 dhcp_failover_link_dereference (&state
-> link_to_peer
,
1120 dhcp_failover_set_state (state
, recover
);
1123 #if defined (DEBUG_MEMORY_LEAKAGE) && \
1124 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1126 omapi_print_dmalloc_usage_by_caller ();
1131 if (shutdown_state
== shutdown_done
) {
1132 #if defined (DEBUG_MEMORY_LEAKAGE) && \
1133 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1135 omapi_print_dmalloc_usage_by_caller ();
1140 if (shutdown_state
== shutdown_dhcp
&&
1141 !failover_connection_count
) {
1142 shutdown_state
= shutdown_done
;
1143 shutdown_time
= cur_time
;
1146 add_timeout (cur_time
+ 1,
1147 (void (*)(void *))dhcp_io_shutdown_countdown
, 0, 0, 0);
1148 return ISC_R_SUCCESS
;
1151 isc_result_t
dhcp_set_control_state (control_object_state_t oldstate
,
1152 control_object_state_t newstate
)
1154 if (newstate
== server_shutdown
) {
1155 shutdown_time
= cur_time
;
1156 shutdown_state
= shutdown_listeners
;
1157 dhcp_io_shutdown_countdown (0);
1158 return ISC_R_SUCCESS
;
1160 return ISC_R_INVALIDARG
;