6 * Copyright (c) 2004-2007 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''.
35 static char copyright
[] =
36 "Copyright 2004-2007 Internet Systems Consortium.";
37 static char arr
[] = "All rights reserved.";
38 static char message
[] = "Internet Systems Consortium DHCP Server";
39 static char url
[] = "For info, please visit http://www.isc.org/sw/dhcp/";
42 #include <omapip/omapip_p.h>
46 #include <sys/types.h>
50 static void usage(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
;
179 listener
= (omapi_object_t
*)0;
180 result
= omapi_generic_new (&listener
, MDL
);
181 if (result
!= ISC_R_SUCCESS
)
182 log_fatal ("Can't allocate new generic object: %s",
183 isc_result_totext (result
));
184 result
= omapi_protocol_listen (listener
,
185 (unsigned)omapi_port
, 1);
186 if (result
== ISC_R_SUCCESS
&& omapi_key
)
187 result
= omapi_protocol_configure_security
188 (listener
, verify_addr
, verify_auth
);
189 if (result
!= ISC_R_SUCCESS
) {
190 log_error ("Can't start OMAPI protocol: %s",
191 isc_result_totext (result
));
192 tv
.tv_sec
= cur_time
+ 5;
194 add_timeout (&tv
, omapi_listener_start
, 0, 0, 0);
196 omapi_object_dereference (&listener
, MDL
);
201 main(int argc
, char **argv
) {
214 char *server
= (char *)0;
217 struct interface_info
*ip
;
220 int no_dhcpd_conf
= 0;
222 int no_dhcpd_pid
= 0;
223 int local_family_set
= 0;
224 #if defined (TRACING)
225 char *traceinfile
= (char *)0;
226 char *traceoutfile
= (char *)0;
229 /* Make sure that file descriptors 0 (stdin), 1, (stdout), and
230 2 (stderr) are open. To do this, we assume that when we
231 open a file the lowest available file descriptor is used. */
232 fd
= open("/dev/null", O_RDWR
);
234 fd
= open("/dev/null", O_RDWR
);
236 fd
= open("/dev/null", O_RDWR
);
238 log_perror
= 0; /* No sense logging to /dev/null. */
242 /* Set up the client classification system. */
243 classification_setup ();
245 /* Initialize the omapi system. */
246 result
= omapi_init ();
247 if (result
!= ISC_R_SUCCESS
)
248 log_fatal ("Can't initialize OMAPI: %s",
249 isc_result_totext (result
));
251 /* Set up the OMAPI wrappers for common objects. */
252 dhcp_db_objects_setup ();
253 /* Set up the OMAPI wrappers for various server database internal
255 dhcp_common_objects_setup ();
257 /* Initially, log errors to stderr as well as to syslogd. */
258 openlog ("dhcpd", LOG_NDELAY
, DHCPD_LOG_FACILITY
);
260 for (i
= 1; i
< argc
; i
++) {
261 if (!strcmp (argv
[i
], "-p")) {
264 for (s
= argv
[i
]; *s
; s
++)
265 if (!isdigit ((unsigned char)*s
))
266 log_fatal ("%s: not a valid UDP port",
268 status
= atoi (argv
[i
]);
269 if (status
< 1 || status
> 65535)
270 log_fatal ("%s: not a valid UDP port",
272 local_port
= htons (status
);
273 log_debug ("binding to user-specified port %d",
275 } else if (!strcmp (argv
[i
], "-f")) {
279 } else if (!strcmp (argv
[i
], "-d")) {
284 } else if (!strcmp (argv
[i
], "-s")) {
288 } else if (!strcmp (argv
[i
], "-cf")) {
291 path_dhcpd_conf
= argv
[i
];
293 } else if (!strcmp (argv
[i
], "-lf")) {
296 path_dhcpd_db
= argv
[i
];
298 } else if (!strcmp (argv
[i
], "-pf")) {
301 path_dhcpd_pid
= argv
[i
];
303 } else if (!strcmp (argv
[i
], "-t")) {
304 /* test configurations only */
310 } else if (!strcmp (argv
[i
], "-T")) {
311 /* test configurations and lease file only */
318 } else if (!strcmp (argv
[i
], "-q")) {
320 quiet_interface_discovery
= 1;
322 } else if (!strcmp(argv
[i
], "-4")) {
323 if (local_family_set
&& (local_family
!= AF_INET
)) {
324 log_fatal("Server cannot run in both IPv4 and "
325 "IPv6 mode at the same time.");
327 local_family
= AF_INET
;
328 local_family_set
= 1;
329 } else if (!strcmp(argv
[i
], "-6")) {
330 if (local_family_set
&& (local_family
!= AF_INET6
)) {
331 log_fatal("Server cannot run in both IPv4 and "
332 "IPv6 mode at the same time.");
334 local_family
= AF_INET6
;
335 local_family_set
= 1;
337 } else if (!strcmp (argv
[i
], "--version")) {
338 log_info("isc-dhcpd-%s", PACKAGE_VERSION
);
340 #if defined (TRACING)
341 } else if (!strcmp (argv
[i
], "-tf")) {
344 traceoutfile
= argv
[i
];
345 } else if (!strcmp (argv
[i
], "-play")) {
348 traceinfile
= argv
[i
];
349 trace_replay_init ();
351 } else if (argv
[i
][0] == '-') {
354 struct interface_info
*tmp
=
355 (struct interface_info
*)0;
356 result
= interface_allocate (&tmp
, MDL
);
357 if (result
!= ISC_R_SUCCESS
)
358 log_fatal ("Insufficient memory to %s %s: %s",
359 "record interface", argv
[i
],
360 isc_result_totext (result
));
361 strcpy (tmp
-> name
, argv
[i
]);
363 interface_reference (&tmp
-> next
,
365 interface_dereference (&interfaces
, MDL
);
367 interface_reference (&interfaces
, tmp
, MDL
);
368 tmp
-> flags
= INTERFACE_REQUESTED
;
372 if (!no_dhcpd_conf
&& (s
= getenv ("PATH_DHCPD_CONF"))) {
377 if (local_family
== AF_INET6
) {
378 /* DHCPv6: override DHCPv4 lease and pid filenames */
380 if ((s
= getenv ("PATH_DHCPD6_DB")))
383 path_dhcpd_db
= _PATH_DHCPD6_DB
;
386 if ((s
= getenv ("PATH_DHCPD6_PID")))
389 path_dhcpd_pid
= _PATH_DHCPD6_PID
;
394 if (!no_dhcpd_db
&& (s
= getenv ("PATH_DHCPD_DB"))) {
397 if (!no_dhcpd_pid
&& (s
= getenv ("PATH_DHCPD_PID"))) {
404 * convert relative path names to absolute, for files that need
405 * to be reopened after chdir() has been called
407 if (path_dhcpd_db
[0] != '/') {
408 char *path
= dmalloc(PATH_MAX
, MDL
);
410 log_fatal("No memory for filename\n");
411 path_dhcpd_db
= realpath(path_dhcpd_db
, path
);
412 if (path_dhcpd_db
== NULL
)
413 log_fatal("%s: %s", path
, strerror(errno
));
417 log_info("%s %s", message
, PACKAGE_VERSION
);
418 log_info (copyright
);
426 #if defined (TRACING)
427 trace_init (set_time
, MDL
);
429 result
= trace_begin (traceoutfile
, MDL
);
430 if (result
!= ISC_R_SUCCESS
)
431 log_fatal ("Unable to begin trace: %s",
432 isc_result_totext (result
));
434 interface_trace_setup ();
435 parse_trace_setup ();
436 trace_srandom
= trace_type_register ("random-seed", (void *)0,
438 trace_seed_stop
, MDL
);
441 /* Default to the DHCP/BOOTP port. */
444 if ((s
= getenv ("DHCPD_PORT"))) {
445 local_port
= htons (atoi (s
));
446 log_debug ("binding to environment-specified port %d",
449 if (local_family
== AF_INET
) {
450 ent
= getservbyname("dhcp", "udp");
452 local_port
= htons(67);
454 local_port
= ent
->s_port
;
457 /* INSIST(local_family == AF_INET6); */
458 ent
= getservbyname("dhcpv6-server", "udp");
460 local_port
= htons(547);
462 local_port
= ent
->s_port
;
465 #ifndef __CYGWIN32__ /* XXX */
471 if (local_family
== AF_INET
) {
472 remote_port
= htons(ntohs(local_port
) + 1);
474 /* INSIST(local_family == AF_INET6); */
475 ent
= getservbyname("dhcpv6-client", "udp");
477 remote_port
= htons(546);
479 remote_port
= ent
->s_port
;
484 if (local_family
!= AF_INET
) {
485 log_fatal("You can only specify address to send "
486 "replies to when running an IPv4 server.");
488 if (!inet_aton (server
, &limited_broadcast
)) {
490 he
= gethostbyname (server
);
492 memcpy (&limited_broadcast
,
493 he
-> h_addr_list
[0],
494 sizeof limited_broadcast
);
496 limited_broadcast
.s_addr
= INADDR_BROADCAST
;
499 limited_broadcast
.s_addr
= INADDR_BROADCAST
;
502 /* Get the current time... */
503 gettimeofday(&cur_tv
, NULL
);
505 /* Set up the initial dhcp option universe. */
506 initialize_common_option_spaces ();
507 initialize_server_option_spaces ();
509 /* Add the ddns update style enumeration prior to parsing. */
510 add_enumeration (&ddns_styles
);
511 add_enumeration (&syslog_enum
);
513 if (!group_allocate (&root_group
, MDL
))
514 log_fatal ("Can't allocate root group!");
515 root_group
-> authoritative
= 0;
517 /* Set up various hooks. */
518 dhcp_interface_setup_hook
= dhcpd_interface_setup_hook
;
519 bootp_packet_handler
= do_packet
;
521 dhcpv6_packet_handler
= do_packet6
;
524 #if defined (NSUPDATE)
525 /* Set up the standard name service updater routine. */
526 parse
= (struct parse
*)0;
527 status
= new_parse (&parse
, -1,
528 std_nsupdate
, (sizeof std_nsupdate
) - 1,
529 "standard name service update routine", 0);
530 if (status
!= ISC_R_SUCCESS
)
531 log_fatal ("can't begin parsing name service updater!");
534 if (!(parse_executable_statements
535 (&root_group
-> statements
, parse
, &lose
, context_any
))) {
537 log_fatal ("can't parse standard name service updater!");
542 /* Initialize icmp support... */
543 if (!cftest
&& !lftest
)
544 icmp_startup (1, lease_pinged
);
546 #if defined (TRACING)
549 log_error ("%s", "");
550 log_error ("** You must specify a lease file with -lf.");
551 log_error (" Dhcpd will not overwrite your default");
552 log_fatal (" lease file when playing back a trace. **");
554 trace_file_replay (traceinfile
);
556 #if defined (DEBUG_MEMORY_LEAKAGE) && \
557 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
559 omapi_print_dmalloc_usage_by_caller ();
567 /* set up DHCPv6 hashes */
568 if (!ia_na_new_hash(&ia_na_active
, DEFAULT_HASH_SIZE
, MDL
)) {
569 log_fatal("Out of memory creating hash for active IA_NA.");
571 if (!ia_na_new_hash(&ia_ta_active
, DEFAULT_HASH_SIZE
, MDL
)) {
572 log_fatal("Out of memory creating hash for active IA_TA.");
574 if (!ia_pd_new_hash(&ia_pd_active
, DEFAULT_HASH_SIZE
, MDL
)) {
575 log_fatal("Out of memory creating hash for active IA_PD.");
579 /* Read the dhcpd.conf file... */
580 if (readconf () != ISC_R_SUCCESS
)
581 log_fatal ("Configuration file errors encountered -- exiting");
583 postconf_initialization (quiet
);
585 /* test option should cause an early exit */
586 if (cftest
&& !lftest
)
589 group_write_hook
= group_writer
;
591 /* Start up the database... */
597 /* Discover all the network interfaces and initialize them. */
598 discover_interfaces(DISCOVER_SERVER
);
602 * Remove addresses from our pools that we should not issue
605 * We currently have no support for this in IPv4. It is not
606 * as important in IPv4, as making pools with ranges that
607 * leave out interfaces and hosts is fairly straightforward
608 * using range notation, but not so handy with CIDR notation.
610 if (local_family
== AF_INET6
) {
611 mark_hosts_unavailable();
612 mark_interfaces_unavailable();
617 /* Make up a seed for the random number generator from current
618 time plus the sum of the last four bytes of each
619 interface's hardware address interpreted as an integer.
620 Not much entropy, but we're booting, so we're not likely to
621 find anything better. */
623 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
626 &ip
-> hw_address
.hbuf
[ip
-> hw_address
.hlen
-
627 sizeof seed
], sizeof seed
);
630 srandom (seed
+ cur_time
);
631 #if defined (TRACING)
632 trace_seed_stash (trace_srandom
, seed
+ cur_time
);
638 * Set server DHCPv6 identifier.
639 * See dhcpv6.c for discussion of setting DUID.
641 if (set_server_duid_from_option() == ISC_R_SUCCESS
) {
644 if (!server_duid_isset()) {
645 if (generate_new_server_duid() != ISC_R_SUCCESS
) {
646 log_fatal("Unable to set server identifier.");
655 /* First part of becoming a daemon... */
656 if ((pid
= fork ()) < 0)
657 log_fatal ("Can't fork daemon: %m");
662 /* Read previous pid file. */
663 if ((i
= open (path_dhcpd_pid
, O_RDONLY
)) >= 0) {
664 status
= read(i
, pbuf
, (sizeof pbuf
) - 1);
671 * If there was a previous server process and it's
672 * is still running, abort
674 if (!pid
|| (pid
!= getpid() && kill(pid
, 0) == 0))
675 log_fatal("There's already a "
676 "DHCP server running.");
680 /* Write new pid file. */
681 if ((i
= open(path_dhcpd_pid
, O_WRONLY
|O_CREAT
|O_TRUNC
, 0644)) >= 0) {
682 sprintf(pbuf
, "%d\n", (int) getpid());
683 write(i
, pbuf
, strlen(pbuf
));
686 log_error("Can't create PID file %s: %m.", path_dhcpd_pid
);
690 /* If we were requested to log to stdout on the command line,
691 keep doing so; otherwise, stop. */
692 if (log_perror
== -1)
698 /* Become session leader and get pid... */
701 /* Close standard I/O descriptors. */
706 /* Reopen them on /dev/null. */
707 open("/dev/null", O_RDWR
);
708 open("/dev/null", O_RDWR
);
709 open("/dev/null", O_RDWR
);
710 log_perror
= 0; /* No sense logging to /dev/null. */
716 #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
717 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
718 dmalloc_cutoff_generation
= dmalloc_generation
;
719 dmalloc_longterm
= dmalloc_outstanding
;
720 dmalloc_outstanding
= 0;
723 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
727 omapi_set_int_value ((omapi_object_t
*)dhcp_control_object
,
728 (omapi_object_t
*)0, "state", server_running
);
730 /* Receive packets and dispatch them... */
736 #endif /* !UNIT_TEST */
738 void postconf_initialization (int quiet
)
740 struct option_state
*options
= (struct option_state
*)0;
741 struct data_string db
;
742 struct option_cache
*oc
;
748 /* Now try to get the lease file name. */
749 option_state_allocate (&options
, MDL
);
751 execute_statements_in_scope ((struct binding_value
**)0,
754 (struct client_state
*)0,
755 (struct option_state
*)0,
756 options
, &global_scope
,
759 memset (&db
, 0, sizeof db
);
760 oc
= lookup_option (&server_universe
, options
, SV_LEASE_FILE_NAME
);
762 evaluate_option_cache (&db
, (struct packet
*)0,
763 (struct lease
*)0, (struct client_state
*)0,
764 options
, (struct option_state
*)0,
765 &global_scope
, oc
, MDL
)) {
766 s
= dmalloc (db
.len
+ 1, MDL
);
768 log_fatal ("no memory for lease db filename.");
769 memcpy (s
, db
.data
, db
.len
);
771 data_string_forget (&db
, MDL
);
775 oc
= lookup_option (&server_universe
, options
, SV_PID_FILE_NAME
);
777 evaluate_option_cache (&db
, (struct packet
*)0,
778 (struct lease
*)0, (struct client_state
*)0,
779 options
, (struct option_state
*)0,
780 &global_scope
, oc
, MDL
)) {
781 s
= dmalloc (db
.len
+ 1, MDL
);
783 log_fatal ("no memory for lease db filename.");
784 memcpy (s
, db
.data
, db
.len
);
786 data_string_forget (&db
, MDL
);
791 if (local_family
== AF_INET6
) {
793 * Override lease file name with dhcpv6 lease file name,
794 * if it was set; then, do the same with the pid file name
796 oc
= lookup_option(&server_universe
, options
,
797 SV_DHCPV6_LEASE_FILE_NAME
);
799 evaluate_option_cache(&db
, NULL
, NULL
, NULL
,
800 options
, NULL
, &global_scope
,
802 s
= dmalloc (db
.len
+ 1, MDL
);
804 log_fatal ("no memory for lease db filename.");
805 memcpy (s
, db
.data
, db
.len
);
807 data_string_forget (&db
, MDL
);
811 oc
= lookup_option(&server_universe
, options
,
812 SV_DHCPV6_PID_FILE_NAME
);
814 evaluate_option_cache(&db
, NULL
, NULL
, NULL
,
815 options
, NULL
, &global_scope
,
817 s
= dmalloc (db
.len
+ 1, MDL
);
819 log_fatal ("no memory for lease db filename.");
820 memcpy (s
, db
.data
, db
.len
);
822 data_string_forget (&db
, MDL
);
829 oc
= lookup_option (&server_universe
, options
, SV_OMAPI_PORT
);
831 evaluate_option_cache (&db
, (struct packet
*)0,
832 (struct lease
*)0, (struct client_state
*)0,
833 options
, (struct option_state
*)0,
834 &global_scope
, oc
, MDL
)) {
836 omapi_port
= getUShort (db
.data
);
838 log_fatal ("invalid omapi port data length");
839 data_string_forget (&db
, MDL
);
842 oc
= lookup_option (&server_universe
, options
, SV_OMAPI_KEY
);
844 evaluate_option_cache (&db
, (struct packet
*)0,
845 (struct lease
*)0, (struct client_state
*)0,
847 (struct option_state
*)0,
848 &global_scope
, oc
, MDL
)) {
849 s
= dmalloc (db
.len
+ 1, MDL
);
851 log_fatal ("no memory for OMAPI key filename.");
852 memcpy (s
, db
.data
, db
.len
);
854 data_string_forget (&db
, MDL
);
855 result
= omapi_auth_key_lookup_name (&omapi_key
, s
);
857 if (result
!= ISC_R_SUCCESS
)
858 log_fatal ("OMAPI key %s: %s",
859 s
, isc_result_totext (result
));
862 oc
= lookup_option (&server_universe
, options
, SV_LOCAL_PORT
);
864 evaluate_option_cache (&db
, (struct packet
*)0,
865 (struct lease
*)0, (struct client_state
*)0,
867 (struct option_state
*)0,
868 &global_scope
, oc
, MDL
)) {
870 local_port
= htons (getUShort (db
.data
));
872 log_fatal ("invalid local port data length");
873 data_string_forget (&db
, MDL
);
876 oc
= lookup_option (&server_universe
, options
, SV_REMOTE_PORT
);
878 evaluate_option_cache (&db
, (struct packet
*)0,
879 (struct lease
*)0, (struct client_state
*)0,
880 options
, (struct option_state
*)0,
881 &global_scope
, oc
, MDL
)) {
883 remote_port
= htons (getUShort (db
.data
));
885 log_fatal ("invalid remote port data length");
886 data_string_forget (&db
, MDL
);
889 oc
= lookup_option (&server_universe
, options
,
890 SV_LIMITED_BROADCAST_ADDRESS
);
892 evaluate_option_cache (&db
, (struct packet
*)0,
893 (struct lease
*)0, (struct client_state
*)0,
894 options
, (struct option_state
*)0,
895 &global_scope
, oc
, MDL
)) {
897 memcpy (&limited_broadcast
, db
.data
, 4);
899 log_fatal ("invalid remote port data length");
900 data_string_forget (&db
, MDL
);
903 oc
= lookup_option (&server_universe
, options
,
906 evaluate_option_cache (&db
, (struct packet
*)0,
907 (struct lease
*)0, (struct client_state
*)0,
908 options
, (struct option_state
*)0,
909 &global_scope
, oc
, MDL
)) {
911 memcpy (&local_address
, db
.data
, 4);
913 log_fatal ("invalid remote port data length");
914 data_string_forget (&db
, MDL
);
917 oc
= lookup_option (&server_universe
, options
, SV_DDNS_UPDATE_STYLE
);
919 if (evaluate_option_cache (&db
, (struct packet
*)0,
921 (struct client_state
*)0,
923 (struct option_state
*)0,
924 &global_scope
, oc
, MDL
)) {
926 ddns_update_style
= db
.data
[0];
928 log_fatal ("invalid dns update type");
929 data_string_forget (&db
, MDL
);
932 ddns_update_style
= DDNS_UPDATE_STYLE_NONE
;
935 oc
= lookup_option (&server_universe
, options
, SV_LOG_FACILITY
);
937 if (evaluate_option_cache (&db
, (struct packet
*)0,
939 (struct client_state
*)0,
941 (struct option_state
*)0,
942 &global_scope
, oc
, MDL
)) {
945 openlog ("dhcpd", LOG_NDELAY
, db
.data
[0]);
946 /* Log the startup banner into the new
949 /* Don't log to stderr twice. */
953 message
, PACKAGE_VERSION
);
954 log_info (copyright
);
960 log_fatal ("invalid log facility");
961 data_string_forget (&db
, MDL
);
965 /* Don't need the options anymore. */
966 option_state_dereference (&options
, MDL
);
968 #if defined (NSUPDATE)
969 /* If old-style ddns updates have been requested, parse the
970 old-style ddns updater. */
971 if (ddns_update_style
== 1) {
972 struct executable_statement
**e
, *s
;
974 if (root_group
-> statements
) {
975 s
= (struct executable_statement
*)0;
976 if (!executable_statement_allocate (&s
, MDL
))
977 log_fatal ("no memory for ddns updater");
978 executable_statement_reference
979 (&s
-> next
, root_group
-> statements
, MDL
);
980 executable_statement_dereference
981 (&root_group
-> statements
, MDL
);
982 executable_statement_reference
983 (&root_group
-> statements
, s
, MDL
);
984 s
-> op
= statements_statement
;
985 e
= &s
-> data
.statements
;
986 executable_statement_dereference (&s
, MDL
);
988 e
= &root_group
-> statements
;
991 /* Set up the standard name service updater routine. */
992 parse
= (struct parse
*)0;
993 result
= new_parse (&parse
, -1,
994 old_nsupdate
, (sizeof old_nsupdate
) - 1,
995 "old name service update routine", 0);
996 if (result
!= ISC_R_SUCCESS
)
997 log_fatal ("can't begin parsing old ddns updater!");
1000 if (!(parse_executable_statements (e
, parse
,
1001 &tmp
, context_any
))) {
1003 log_fatal ("can't parse standard ddns updater!");
1010 void postdb_startup (void)
1012 /* Initialize the omapi listener state. */
1013 if (omapi_port
!= -1) {
1014 omapi_listener_start (0);
1017 #if defined (FAILOVER_PROTOCOL)
1018 /* Initialize the failover listener state. */
1019 dhcp_failover_startup ();
1023 * Begin our lease timeout background task.
1025 schedule_all_ipv6_lease_timeouts();
1028 /* Print usage message. */
1032 log_info("%s %s", message
, PACKAGE_VERSION
);
1033 log_info(copyright
);
1036 log_fatal("Usage: dhcpd [-p <UDP port #>] [-f] [-d] [-q] [-t|-T]\n"
1038 " [-4|-6] [-cf config-file] [-lf lease-file]\n"
1040 " [-cf config-file] [-lf lease-file]\n"
1042 #if defined (TRACING)
1043 " [-tf trace-output-file]\n"
1044 " [-play trace-input-file]\n"
1045 #endif /* TRACING */
1046 " [-pf pid-file] [-s server] [if0 [...ifN]]");
1049 void lease_pinged (from
, packet
, length
)
1056 /* Don't try to look up a pinged lease if we aren't trying to
1057 ping one - otherwise somebody could easily make us churn by
1058 just forging repeated ICMP EchoReply packets for us to look
1060 if (!outstanding_pings
)
1063 lp
= (struct lease
*)0;
1064 if (!find_lease_by_ip_addr (&lp
, from
, MDL
)) {
1065 log_debug ("unexpected ICMP Echo Reply from %s",
1071 #if defined (FAILOVER_PROTOCOL)
1073 !lp
-> pool
-> failover_peer
)
1075 log_debug ("ICMP Echo Reply for %s late or spurious.",
1080 if (lp
-> ends
> cur_time
) {
1081 log_debug ("ICMP Echo reply while lease %s valid.",
1085 /* At this point it looks like we pinged a lease and got a
1086 response, which shouldn't have happened. */
1087 data_string_forget (&lp
-> state
-> parameter_request_list
, MDL
);
1088 free_lease_state (lp
-> state
, MDL
);
1089 lp
-> state
= (struct lease_state
*)0;
1091 abandon_lease (lp
, "pinged before offer");
1092 cancel_timeout (lease_ping_timeout
, lp
);
1093 --outstanding_pings
;
1095 lease_dereference (&lp
, MDL
);
1098 void lease_ping_timeout (vlp
)
1101 struct lease
*lp
= vlp
;
1103 #if defined (DEBUG_MEMORY_LEAKAGE)
1104 unsigned long previous_outstanding
= dmalloc_outstanding
;
1107 --outstanding_pings
;
1110 #if defined (DEBUG_MEMORY_LEAKAGE)
1111 log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
1113 dmalloc_outstanding
- previous_outstanding
,
1114 dmalloc_outstanding
, dmalloc_longterm
);
1116 #if defined (DEBUG_MEMORY_LEAKAGE)
1117 dmalloc_dump_outstanding ();
1121 int dhcpd_interface_setup_hook (struct interface_info
*ip
, struct iaddr
*ia
)
1123 struct subnet
*subnet
;
1124 struct shared_network
*share
;
1125 isc_result_t status
;
1127 /* Special case for fallback network - not sure why this is
1130 const char *fnn
= "fallback-net";
1131 status
= shared_network_allocate (&ip
-> shared_network
, MDL
);
1132 if (status
!= ISC_R_SUCCESS
)
1133 log_fatal ("No memory for shared subnet: %s",
1134 isc_result_totext (status
));
1135 ip
-> shared_network
-> name
= dmalloc (strlen (fnn
) + 1, MDL
);
1136 strcpy (ip
-> shared_network
-> name
, fnn
);
1140 /* If there's a registered subnet for this address,
1141 connect it together... */
1142 subnet
= (struct subnet
*)0;
1143 if (find_subnet (&subnet
, *ia
, MDL
)) {
1144 /* If this interface has multiple aliases on the same
1145 subnet, ignore all but the first we encounter. */
1146 if (!subnet
-> interface
) {
1147 interface_reference (&subnet
-> interface
, ip
, MDL
);
1148 subnet
-> interface_address
= *ia
;
1149 } else if (subnet
-> interface
!= ip
) {
1150 log_error ("Multiple interfaces match the %s: %s %s",
1152 subnet
-> interface
-> name
, ip
-> name
);
1154 share
= subnet
-> shared_network
;
1155 if (ip
-> shared_network
&&
1156 ip
-> shared_network
!= share
) {
1157 log_fatal ("Interface %s matches multiple shared %s",
1158 ip
-> name
, "networks");
1160 if (!ip
-> shared_network
)
1161 shared_network_reference
1162 (&ip
-> shared_network
, share
, MDL
);
1165 if (!share
-> interface
) {
1166 interface_reference (&share
-> interface
, ip
, MDL
);
1167 } else if (share
-> interface
!= ip
) {
1168 log_error ("Multiple interfaces match the %s: %s %s",
1169 "same shared network",
1170 share
-> interface
-> name
, ip
-> name
);
1172 subnet_dereference (&subnet
, MDL
);
1177 static TIME shutdown_time
;
1178 static int omapi_connection_count
;
1179 enum dhcp_shutdown_state shutdown_state
;
1181 isc_result_t
dhcp_io_shutdown (omapi_object_t
*obj
, void *foo
)
1183 /* Shut down all listeners. */
1184 if (shutdown_state
== shutdown_listeners
&&
1185 obj
-> type
== omapi_type_listener
&&
1187 obj
-> inner
-> type
== omapi_type_protocol_listener
) {
1188 omapi_listener_destroy (obj
, MDL
);
1189 return ISC_R_SUCCESS
;
1192 /* Shut down all existing omapi connections. */
1193 if (obj
-> type
== omapi_type_connection
&&
1195 obj
-> inner
-> type
== omapi_type_protocol
) {
1196 if (shutdown_state
== shutdown_drop_omapi_connections
) {
1197 omapi_disconnect (obj
, 1);
1199 omapi_connection_count
++;
1200 if (shutdown_state
== shutdown_omapi_connections
) {
1201 omapi_disconnect (obj
, 0);
1202 return ISC_R_SUCCESS
;
1206 /* Shutdown all DHCP interfaces. */
1207 if (obj
-> type
== dhcp_type_interface
&&
1208 shutdown_state
== shutdown_dhcp
) {
1209 dhcp_interface_remove (obj
, (omapi_object_t
*)0);
1210 return ISC_R_SUCCESS
;
1212 return ISC_R_SUCCESS
;
1215 static isc_result_t
dhcp_io_shutdown_countdown (void *vlp
)
1217 dhcp_failover_state_t
*state
;
1218 #if defined (FAILOVER_PROTOCOL)
1219 int failover_connection_count
= 0;
1224 if (shutdown_state
== shutdown_listeners
||
1225 shutdown_state
== shutdown_omapi_connections
||
1226 shutdown_state
== shutdown_drop_omapi_connections
||
1227 shutdown_state
== shutdown_dhcp
) {
1228 omapi_connection_count
= 0;
1229 omapi_io_state_foreach (dhcp_io_shutdown
, 0);
1232 if ((shutdown_state
== shutdown_listeners
||
1233 shutdown_state
== shutdown_omapi_connections
||
1234 shutdown_state
== shutdown_drop_omapi_connections
) &&
1235 omapi_connection_count
== 0) {
1236 shutdown_state
= shutdown_dhcp
;
1237 shutdown_time
= cur_time
;
1239 } else if (shutdown_state
== shutdown_listeners
&&
1240 cur_time
- shutdown_time
> 4) {
1241 shutdown_state
= shutdown_omapi_connections
;
1242 shutdown_time
= cur_time
;
1243 } else if (shutdown_state
== shutdown_omapi_connections
&&
1244 cur_time
- shutdown_time
> 4) {
1245 shutdown_state
= shutdown_drop_omapi_connections
;
1246 shutdown_time
= cur_time
;
1247 } else if (shutdown_state
== shutdown_drop_omapi_connections
&&
1248 cur_time
- shutdown_time
> 4) {
1249 shutdown_state
= shutdown_dhcp
;
1250 shutdown_time
= cur_time
;
1252 } else if (shutdown_state
== shutdown_dhcp
&&
1253 cur_time
- shutdown_time
> 4) {
1254 shutdown_state
= shutdown_done
;
1255 shutdown_time
= cur_time
;
1258 #if defined (FAILOVER_PROTOCOL)
1259 /* Set all failover peers into the shutdown state. */
1260 if (shutdown_state
== shutdown_dhcp
) {
1261 for (state
= failover_states
; state
; state
= state
-> next
) {
1262 if (state
-> me
.state
== normal
) {
1263 dhcp_failover_set_state (state
, shut_down
);
1264 failover_connection_count
++;
1266 if (state
-> me
.state
== shut_down
&&
1267 state
-> partner
.state
!= partner_down
)
1268 failover_connection_count
++;
1272 if (shutdown_state
== shutdown_done
) {
1273 for (state
= failover_states
; state
; state
= state
-> next
) {
1274 if (state
-> me
.state
== shut_down
) {
1275 if (state
-> link_to_peer
)
1276 dhcp_failover_link_dereference (&state
-> link_to_peer
,
1278 dhcp_failover_set_state (state
, recover
);
1281 #if defined (DEBUG_MEMORY_LEAKAGE) && \
1282 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1284 omapi_print_dmalloc_usage_by_caller ();
1289 if (shutdown_state
== shutdown_done
) {
1290 #if defined (DEBUG_MEMORY_LEAKAGE) && \
1291 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1293 omapi_print_dmalloc_usage_by_caller ();
1298 if (shutdown_state
== shutdown_dhcp
&&
1299 #if defined(FAILOVER_PROTOCOL)
1300 !failover_connection_count
&&
1303 shutdown_state
= shutdown_done
;
1304 shutdown_time
= cur_time
;
1307 tv
.tv_sec
= cur_tv
.tv_sec
+ 1;
1308 tv
.tv_usec
= cur_tv
.tv_usec
;
1310 (void (*)(void *))dhcp_io_shutdown_countdown
, 0, 0, 0);
1311 return ISC_R_SUCCESS
;
1314 isc_result_t
dhcp_set_control_state (control_object_state_t oldstate
,
1315 control_object_state_t newstate
)
1317 if (newstate
== server_shutdown
) {
1318 shutdown_time
= cur_time
;
1319 shutdown_state
= shutdown_listeners
;
1320 dhcp_io_shutdown_countdown (0);
1321 return ISC_R_SUCCESS
;
1323 return ISC_R_INVALIDARG
;