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$ 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 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. */
233 me
= (struct Process
*)FindTask(NULL
);
237 status
= open ("/dev/null", O_RDWR
);
239 status
= open ("/dev/null", O_RDWR
);
241 status
= open ("/dev/null", O_RDWR
);
242 log_perror
= 0; /* No sense logging to /dev/null. */
243 } else if (status
!= -1)
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
259 dhcp_common_objects_setup ();
261 /* Initially, log errors to stderr as well as to syslogd. */
263 openlog ("dhcpd", LOG_NDELAY
);
264 log_priority
= DHCPD_LOG_FACILITY
;
266 openlog ("dhcpd", LOG_NDELAY
, DHCPD_LOG_FACILITY
);
269 for (i
= 1; i
< argc
; i
++) {
270 if (!strcmp (argv
[i
], "-p")) {
273 for (s
= argv
[i
]; *s
; s
++)
275 log_fatal ("%s: not a valid UDP port",
277 status
= atoi (argv
[i
]);
278 if (status
< 1 || status
> 65535)
279 log_fatal ("%s: not a valid UDP port",
281 local_port
= htons (status
);
282 log_debug ("binding to user-specified port %d",
284 } else if (!strcmp (argv
[i
], "-f")) {
288 } else if (!strcmp (argv
[i
], "-d")) {
293 } else if (!strcmp (argv
[i
], "-s")) {
297 } else if (!strcmp (argv
[i
], "-cf")) {
300 path_dhcpd_conf
= argv
[i
];
302 } else if (!strcmp (argv
[i
], "-lf")) {
305 path_dhcpd_db
= argv
[i
];
307 } else if (!strcmp (argv
[i
], "-pf")) {
310 path_dhcpd_pid
= argv
[i
];
312 } else if (!strcmp (argv
[i
], "-t")) {
313 /* test configurations only */
319 } else if (!strcmp (argv
[i
], "-T")) {
320 /* test configurations and lease file only */
327 } else if (!strcmp (argv
[i
], "-q")) {
329 quiet_interface_discovery
= 1;
330 } else if (!strcmp (argv
[i
], "--version")) {
331 log_info ("isc-dhcpd-%s", DHCP_VERSION
);
333 #if defined (TRACING)
334 } else if (!strcmp (argv
[i
], "-tf")) {
337 traceoutfile
= argv
[i
];
338 } else if (!strcmp (argv
[i
], "-play")) {
341 traceinfile
= argv
[i
];
342 trace_replay_init ();
344 } else if (argv
[i
][0] == '-') {
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
]);
356 interface_reference (&tmp
-> next
,
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"))) {
368 if (!no_dhcpd_db
&& (s
= getenv ("PATH_DHCPD_DB"))) {
371 if (!no_dhcpd_pid
&& (s
= getenv ("PATH_DHCPD_PID"))) {
376 log_info ("%s %s", message
, DHCP_VERSION
);
377 log_info (copyright
);
385 #if defined (TRACING)
386 trace_init (set_time
, MDL
);
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,
397 trace_seed_stop
, MDL
);
400 /* Default to the DHCP/BOOTP port. */
403 if ((s
= getenv ("DHCPD_PORT"))) {
404 local_port
= htons (atoi (s
));
405 log_debug ("binding to environment-specified port %d",
408 ent
= getservbyname ("dhcp", "udp");
410 local_port
= htons (67);
412 local_port
= ent
-> s_port
;
413 #ifndef __CYGWIN32__ /* XXX */
419 remote_port
= htons (ntohs (local_port
) + 1);
422 if (!inet_aton (server
, &limited_broadcast
)) {
424 he
= gethostbyname (server
);
426 memcpy (&limited_broadcast
,
427 he
-> h_addr_list
[0],
428 sizeof limited_broadcast
);
430 limited_broadcast
.s_addr
= INADDR_BROADCAST
;
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!");
465 if (!(parse_executable_statements
466 (&root_group
-> statements
, parse
, &lose
, context_any
))) {
468 log_fatal ("can't parse standard name service updater!");
473 /* Initialize icmp support... */
474 if (!cftest
&& !lftest
)
475 icmp_startup (1, lease_pinged
);
477 #if defined (TRACING)
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)
490 omapi_print_dmalloc_usage_by_caller ();
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
)
507 group_write_hook
= group_writer
;
509 /* Start up the database... */
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. */
524 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
527 &ip
-> hw_address
.hbuf
[ip
-> hw_address
.hlen
-
528 sizeof seed
], sizeof seed
);
531 srandom (seed
+ cur_time
);
532 #if defined (TRACING)
533 trace_seed_stash (trace_srandom
, seed
+ cur_time
);
540 /* First part of becoming a daemon... */
541 if ((pid
= fork ()) < 0)
542 log_fatal ("Can't fork daemon: %m");
547 /* Read previous pid file. */
548 if ((i
= open (path_dhcpd_pid
, O_RDONLY
)) >= 0) {
549 status
= read (i
, pbuf
, (sizeof pbuf
) - 1);
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
));
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)
579 /* Become session leader and get pid... */
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
));
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;
609 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
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... */
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
;
633 /* Now try to get the lease file name. */
634 option_state_allocate (&options
, MDL
);
636 execute_statements_in_scope ((struct binding_value
**)0,
639 (struct client_state
*)0,
640 (struct option_state
*)0,
641 options
, &global_scope
,
644 memset (&db
, 0, sizeof db
);
645 oc
= lookup_option (&server_universe
, options
, SV_LEASE_FILE_NAME
);
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
);
653 log_fatal ("no memory for lease db filename.");
654 memcpy (s
, db
.data
, db
.len
);
656 data_string_forget (&db
, MDL
);
660 oc
= lookup_option (&server_universe
, options
, SV_PID_FILE_NAME
);
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
);
668 log_fatal ("no memory for lease db filename.");
669 memcpy (s
, db
.data
, db
.len
);
671 data_string_forget (&db
, MDL
);
676 oc
= lookup_option (&server_universe
, options
, SV_OMAPI_PORT
);
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
)) {
683 omapi_port
= getUShort (db
.data
);
685 log_fatal ("invalid omapi port data length");
686 data_string_forget (&db
, MDL
);
689 oc
= lookup_option (&server_universe
, options
, SV_OMAPI_KEY
);
691 evaluate_option_cache (&db
, (struct packet
*)0,
692 (struct lease
*)0, (struct client_state
*)0,
694 (struct option_state
*)0,
695 &global_scope
, oc
, MDL
)) {
696 s
= dmalloc (db
.len
+ 1, MDL
);
698 log_fatal ("no memory for OMAPI key filename.");
699 memcpy (s
, db
.data
, db
.len
);
701 data_string_forget (&db
, MDL
);
702 result
= omapi_auth_key_lookup_name (&omapi_key
, s
);
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
);
711 evaluate_option_cache (&db
, (struct packet
*)0,
712 (struct lease
*)0, (struct client_state
*)0,
714 (struct option_state
*)0,
715 &global_scope
, oc
, MDL
)) {
717 local_port
= htons (getUShort (db
.data
));
719 log_fatal ("invalid local port data length");
720 data_string_forget (&db
, MDL
);
723 oc
= lookup_option (&server_universe
, options
, SV_REMOTE_PORT
);
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
)) {
730 remote_port
= htons (getUShort (db
.data
));
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
);
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
)) {
744 memcpy (&limited_broadcast
, db
.data
, 4);
746 log_fatal ("invalid remote port data length");
747 data_string_forget (&db
, MDL
);
750 oc
= lookup_option (&server_universe
, options
,
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
)) {
758 memcpy (&local_address
, db
.data
, 4);
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
);
766 if (evaluate_option_cache (&db
, (struct packet
*)0,
768 (struct client_state
*)0,
770 (struct option_state
*)0,
771 &global_scope
, oc
, MDL
)) {
773 ddns_update_style
= db
.data
[0];
775 log_fatal ("invalid dns update type");
776 data_string_forget (&db
, MDL
);
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",
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
);
792 if (evaluate_option_cache (&db
, (struct packet
*)0,
794 (struct client_state
*)0,
796 (struct option_state
*)0,
797 &global_scope
, oc
, MDL
)) {
801 openlog ("dhcpd", LOG_NDELAY
);
802 log_priority
= db
.data
[0];
805 LOG_NDELAY
, db
.data
[0]);
807 /* Log the startup banner into the new
810 /* Don't log to stderr twice. */
814 message
, DHCP_VERSION
);
815 log_info (copyright
);
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
);
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!");
861 if (!(parse_executable_statements (e
, parse
,
862 &tmp
, context_any
))) {
864 log_fatal ("can't parse standard ddns updater!");
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 ();
884 /* Print usage message. */
888 log_info ("%s %s", message
, DHCP_VERSION
);
889 log_info (copyright
);
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]",
900 "\n [-t] [-T] [-s server] [if0 [...ifN]]");
903 void lease_pinged (from
, packet
, length
)
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
914 if (!outstanding_pings
)
917 lp
= (struct lease
*)0;
918 if (!find_lease_by_ip_addr (&lp
, from
, MDL
)) {
919 log_debug ("unexpected ICMP Echo Reply from %s",
925 #if defined (FAILOVER_PROTOCOL)
927 !lp
-> pool
-> failover_peer
)
929 log_debug ("ICMP Echo Reply for %s late or spurious.",
934 if (lp
-> ends
> cur_time
) {
935 log_debug ("ICMP Echo reply while lease %s valid.",
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
);
949 lease_dereference (&lp
, MDL
);
952 void lease_ping_timeout (vlp
)
955 struct lease
*lp
= vlp
;
957 #if defined (DEBUG_MEMORY_LEAKAGE)
958 unsigned long previous_outstanding
= dmalloc_outstanding
;
964 #if defined (DEBUG_MEMORY_LEAKAGE)
965 log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
967 dmalloc_outstanding
- previous_outstanding
,
968 dmalloc_outstanding
, dmalloc_longterm
);
970 #if defined (DEBUG_MEMORY_LEAKAGE)
971 dmalloc_dump_outstanding ();
975 int dhcpd_interface_setup_hook (struct interface_info
*ip
, struct iaddr
*ia
)
977 struct subnet
*subnet
;
978 struct shared_network
*share
;
981 /* Special case for fallback network - not sure why this is
984 const char *fnn
= "fallback-net";
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
);
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",
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");
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
);
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
&&
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
&&
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;
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
;
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
;
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
,
1132 dhcp_failover_set_state (state
, recover
);
1135 #if defined (DEBUG_MEMORY_LEAKAGE) && \
1136 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1138 omapi_print_dmalloc_usage_by_caller ();
1143 if (shutdown_state
== shutdown_done
) {
1144 #if defined (DEBUG_MEMORY_LEAKAGE) && \
1145 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1147 omapi_print_dmalloc_usage_by_caller ();
1152 if (shutdown_state
== shutdown_dhcp
&&
1153 !failover_connection_count
) {
1154 shutdown_state
= shutdown_done
;
1155 shutdown_time
= cur_time
;
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
;