]> git.ipfire.org Git - thirdparty/dhcp.git/blame - server/dhcpd.c
[master] Prepare for 4.3.0a1
[thirdparty/dhcp.git] / server / dhcpd.c
CommitLineData
d7837182
TL
1/* dhcpd.c
2
3 DHCP Server Daemon. */
4
5/*
32da1939 6 * Copyright (c) 2004-2013 by Internet Systems Consortium, Inc. ("ISC")
98311e4b 7 * Copyright (c) 1996-2003 by Internet Software Consortium
d7837182 8 *
98311e4b
DH
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.
d7837182 12 *
98311e4b
DH
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.
d7837182 20 *
98311e4b
DH
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
2c85ac9b 25 * https://www.isc.org/
49733f31 26 *
98311e4b 27 * This software has been written for Internet Systems Consortium
49733f31 28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
98311e4b 29 * To learn more about Internet Systems Consortium, see
2c85ac9b 30 * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
49733f31
TL
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
d7837182
TL
33 */
34
ae566556 35static const char copyright[] =
32da1939 36"Copyright 2004-2013 Internet Systems Consortium.";
ae566556
SR
37static const char arr [] = "All rights reserved.";
38static const char message [] = "Internet Systems Consortium DHCP Server";
39static const char url [] =
2c85ac9b 40"For info, please visit https://www.isc.org/software/dhcp/";
d7837182
TL
41
42#include "dhcpd.h"
68e50b9e 43#include <omapip/omapip_p.h>
fe5b0fdd 44#include <syslog.h>
47e8308d 45#include <signal.h>
a546f2a7 46#include <errno.h>
e847f983 47#include <limits.h>
28868515 48#include <sys/types.h>
be62cf06 49#include <sys/time.h>
d7837182 50
63971a83
DH
51#if defined (PARANOIA)
52# include <sys/types.h>
53# include <unistd.h>
54# include <pwd.h>
55/* get around the ISC declaration of group */
56# define group real_group
57# include <grp.h>
58# undef group
59#endif /* PARANOIA */
60
f9effb95 61#ifndef UNIT_TEST
2e13ba55 62static void usage(void);
f9effb95 63#endif
d7837182 64
3b5a1486
TL
65struct iaddr server_identifier;
66int server_identifier_matched;
67
144cdb49 68#if defined (NSUPDATE)
fafe8463
TL
69
70/* This stuff is always executed to figure the default values for certain
71 ddns variables. */
72
68f55908 73char std_nsupdate [] = " \n\
d7f6db15
TL
74option server.ddns-hostname = \n\
75 pick (option fqdn.hostname, option host-name); \n\
ac9c906a 76option server.ddns-domainname = config-option domain-name; \n\
fafe8463
TL
77option server.ddns-rev-domainname = \"in-addr.arpa.\";";
78
144cdb49 79#endif /* NSUPDATE */
98bf1607 80int ddns_update_style;
cde11a4c 81int dont_use_fsync = 0; /* 0 = default, use fsync, 1 = don't use fsync */
77222488 82
b1b7b521
TL
83const char *path_dhcpd_conf = _PATH_DHCPD_CONF;
84const char *path_dhcpd_db = _PATH_DHCPD_DB;
85const char *path_dhcpd_pid = _PATH_DHCPD_PID;
4a5bfeac
SR
86/* False (default) => we write and use a pid file */
87isc_boolean_t no_pid_file = ISC_FALSE;
d7837182 88
0a347607
TL
89int dhcp_max_agent_option_packet_length = DHCP_MTU_MAX;
90
49146f3c 91static omapi_auth_key_t *omapi_key = (omapi_auth_key_t *)0;
a920d3da
TL
92int omapi_port;
93
94#if defined (TRACING)
95trace_type_t *trace_srandom;
96#endif
49146f3c
DN
97
98static isc_result_t verify_addr (omapi_object_t *l, omapi_addr_t *addr) {
99 return ISC_R_SUCCESS;
100}
101
102static isc_result_t verify_auth (omapi_object_t *p, omapi_auth_key_t *a) {
103 if (a != omapi_key)
98bf1607 104 return DHCP_R_INVALIDKEY;
49146f3c
DN
105 return ISC_R_SUCCESS;
106}
107
d758ad8c
TL
108static void omapi_listener_start (void *foo)
109{
110 omapi_object_t *listener;
111 isc_result_t result;
be62cf06 112 struct timeval tv;
d758ad8c
TL
113
114 listener = (omapi_object_t *)0;
115 result = omapi_generic_new (&listener, MDL);
116 if (result != ISC_R_SUCCESS)
117 log_fatal ("Can't allocate new generic object: %s",
118 isc_result_totext (result));
119 result = omapi_protocol_listen (listener,
120 (unsigned)omapi_port, 1);
121 if (result == ISC_R_SUCCESS && omapi_key)
122 result = omapi_protocol_configure_security
123 (listener, verify_addr, verify_auth);
124 if (result != ISC_R_SUCCESS) {
125 log_error ("Can't start OMAPI protocol: %s",
126 isc_result_totext (result));
5d082abd
TM
127 tv.tv_sec = cur_tv.tv_sec + 5;
128 tv.tv_usec = cur_tv.tv_usec;
be62cf06 129 add_timeout (&tv, omapi_listener_start, 0, 0, 0);
d758ad8c
TL
130 }
131 omapi_object_dereference (&listener, MDL);
132}
133
63971a83
DH
134#if defined (PARANOIA)
135/* to be used in one of two possible scenarios */
136static void setup_chroot (char *chroot_dir) {
137 if (geteuid())
138 log_fatal ("you must be root to use chroot");
139
140 if (chroot(chroot_dir)) {
141 log_fatal ("chroot(\"%s\"): %m", chroot_dir);
142 }
143 if (chdir ("/")) {
144 /* probably permission denied */
145 log_fatal ("chdir(\"/\"): %m");
146 }
147}
148#endif /* PARANOIA */
149
98bd7ca0
DH
150#ifndef UNIT_TEST
151int
152main(int argc, char **argv) {
185d16f9 153 int fd;
c6dff01f 154 int i, status;
d7837182 155 struct servent *ent;
28868515 156 char *s;
1ac5bc1a 157 int cftest = 0;
8f450cac 158 int lftest = 0;
955d158b 159#ifndef DEBUG
d7837182 160 int pid;
c6dff01f
TL
161 char pbuf [20];
162 int daemon = 1;
955d158b 163#endif
632d8396 164 int quiet = 0;
e3a84e35 165 char *server = (char *)0;
972bde18 166 isc_result_t result;
b1b7b521 167 unsigned seed;
972bde18 168 struct interface_info *ip;
98bf1607 169#if defined (NSUPDATE)
77222488
TL
170 struct parse *parse;
171 int lose;
98bf1607 172#endif
cfa7212d
TL
173 int no_dhcpd_conf = 0;
174 int no_dhcpd_db = 0;
175 int no_dhcpd_pid = 0;
c998be87 176#ifdef DHCPv6
98bd7ca0 177 int local_family_set = 0;
c998be87 178#endif /* DHCPv6 */
662df45a 179#if defined (TRACING)
a920d3da
TL
180 char *traceinfile = (char *)0;
181 char *traceoutfile = (char *)0;
662df45a 182#endif
d7837182 183
63971a83
DH
184#if defined (PARANOIA)
185 char *set_user = 0;
186 char *set_group = 0;
187 char *set_chroot = 0;
188
189 uid_t set_uid = 0;
190 gid_t set_gid = 0;
191#endif /* PARANOIA */
192
185d16f9
SK
193 /* Make sure that file descriptors 0 (stdin), 1, (stdout), and
194 2 (stderr) are open. To do this, we assume that when we
20ae1aff 195 open a file the lowest available file descriptor is used. */
509df655 196 fd = open("/dev/null", O_RDWR);
185d16f9 197 if (fd == 0)
509df655 198 fd = open("/dev/null", O_RDWR);
185d16f9 199 if (fd == 1)
509df655 200 fd = open("/dev/null", O_RDWR);
185d16f9
SK
201 if (fd == 2)
202 log_perror = 0; /* No sense logging to /dev/null. */
203 else if (fd != -1)
509df655 204 close(fd);
fb5f8793 205
98bf1607 206 /* Set up the isc and dns library managers */
61ef216b
SR
207 status = dhcp_context_create(DHCP_CONTEXT_PRE_DB,
208 NULL, NULL);
98bf1607
SR
209 if (status != ISC_R_SUCCESS)
210 log_fatal("Can't initialize context: %s",
211 isc_result_totext(status));
212
f3a05d72
TL
213 /* Set up the client classification system. */
214 classification_setup ();
215
216 /* Initialize the omapi system. */
217 result = omapi_init ();
218 if (result != ISC_R_SUCCESS)
219 log_fatal ("Can't initialize OMAPI: %s",
220 isc_result_totext (result));
221
fafe8463
TL
222 /* Set up the OMAPI wrappers for common objects. */
223 dhcp_db_objects_setup ();
f3a05d72
TL
224 /* Set up the OMAPI wrappers for various server database internal
225 objects. */
f3a05d72
TL
226 dhcp_common_objects_setup ();
227
c6dff01f 228 /* Initially, log errors to stderr as well as to syslogd. */
9de9c626 229 openlog ("dhcpd", LOG_NDELAY, DHCPD_LOG_FACILITY);
40950384 230
d7837182
TL
231 for (i = 1; i < argc; i++) {
232 if (!strcmp (argv [i], "-p")) {
233 if (++i == argc)
234 usage ();
59112e84 235 local_port = validate_port (argv [i]);
8ae2d595 236 log_debug ("binding to user-specified port %d",
a60076f9 237 ntohs (local_port));
c6dff01f
TL
238 } else if (!strcmp (argv [i], "-f")) {
239#ifndef DEBUG
240 daemon = 0;
241#endif
242 } else if (!strcmp (argv [i], "-d")) {
77549355 243#ifndef DEBUG
c6dff01f 244 daemon = 0;
77549355 245#endif
f5d07a38 246 log_perror = -1;
e3a84e35
TL
247 } else if (!strcmp (argv [i], "-s")) {
248 if (++i == argc)
249 usage ();
250 server = argv [i];
63971a83
DH
251#if defined (PARANOIA)
252 } else if (!strcmp (argv [i], "-user")) {
253 if (++i == argc)
254 usage ();
255 set_user = argv [i];
256 } else if (!strcmp (argv [i], "-group")) {
257 if (++i == argc)
258 usage ();
259 set_group = argv [i];
260 } else if (!strcmp (argv [i], "-chroot")) {
261 if (++i == argc)
262 usage ();
263 set_chroot = argv [i];
264#endif /* PARANOIA */
840bd203
TL
265 } else if (!strcmp (argv [i], "-cf")) {
266 if (++i == argc)
267 usage ();
268 path_dhcpd_conf = argv [i];
cfa7212d 269 no_dhcpd_conf = 1;
840bd203
TL
270 } else if (!strcmp (argv [i], "-lf")) {
271 if (++i == argc)
272 usage ();
273 path_dhcpd_db = argv [i];
cfa7212d 274 no_dhcpd_db = 1;
23b21725
TL
275 } else if (!strcmp (argv [i], "-pf")) {
276 if (++i == argc)
277 usage ();
278 path_dhcpd_pid = argv [i];
cfa7212d 279 no_dhcpd_pid = 1;
4a5bfeac
SR
280 } else if (!strcmp(argv[i], "--no-pid")) {
281 no_pid_file = ISC_TRUE;
40f63fcd
TL
282 } else if (!strcmp (argv [i], "-t")) {
283 /* test configurations only */
284#ifndef DEBUG
285 daemon = 0;
286#endif
287 cftest = 1;
288 log_perror = -1;
8f450cac
TL
289 } else if (!strcmp (argv [i], "-T")) {
290 /* test configurations and lease file only */
291#ifndef DEBUG
292 daemon = 0;
293#endif
294 cftest = 1;
295 lftest = 1;
296 log_perror = -1;
deb0cb72 297 } else if (!strcmp (argv [i], "-q")) {
632d8396
TL
298 quiet = 1;
299 quiet_interface_discovery = 1;
75135a3f 300#ifdef DHCPv6
98bd7ca0
DH
301 } else if (!strcmp(argv[i], "-4")) {
302 if (local_family_set && (local_family != AF_INET)) {
303 log_fatal("Server cannot run in both IPv4 and "
304 "IPv6 mode at the same time.");
305 }
306 local_family = AF_INET;
307 local_family_set = 1;
308 } else if (!strcmp(argv[i], "-6")) {
309 if (local_family_set && (local_family != AF_INET6)) {
310 log_fatal("Server cannot run in both IPv4 and "
311 "IPv6 mode at the same time.");
312 }
313 local_family = AF_INET6;
314 local_family_set = 1;
75135a3f 315#endif /* DHCPv6 */
a920d3da 316 } else if (!strcmp (argv [i], "--version")) {
fe5b0fdd 317 log_info("isc-dhcpd-%s", PACKAGE_VERSION);
a920d3da 318 exit (0);
662df45a 319#if defined (TRACING)
a920d3da
TL
320 } else if (!strcmp (argv [i], "-tf")) {
321 if (++i == argc)
322 usage ();
323 traceoutfile = argv [i];
324 } else if (!strcmp (argv [i], "-play")) {
325 if (++i == argc)
326 usage ();
327 traceinfile = argv [i];
328 trace_replay_init ();
662df45a 329#endif /* TRACING */
d992e204 330 } else if (argv [i][0] == '-') {
d7837182 331 usage ();
d992e204
TL
332 } else {
333 struct interface_info *tmp =
f3a05d72 334 (struct interface_info *)0;
66be0ad1
SR
335 if (strlen(argv[i]) >= sizeof(tmp->name))
336 log_fatal("%s: interface name too long "
337 "(is %ld)",
338 argv[i], (long)strlen(argv[i]));
f3a05d72
TL
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));
d992e204 344 strcpy (tmp -> name, argv [i]);
f3a05d72
TL
345 if (interfaces) {
346 interface_reference (&tmp -> next,
347 interfaces, MDL);
348 interface_dereference (&interfaces, MDL);
349 }
350 interface_reference (&interfaces, tmp, MDL);
d992e204 351 tmp -> flags = INTERFACE_REQUESTED;
d992e204 352 }
d7837182
TL
353 }
354
cfa7212d
TL
355 if (!no_dhcpd_conf && (s = getenv ("PATH_DHCPD_CONF"))) {
356 path_dhcpd_conf = s;
357 }
75135a3f
EH
358
359#ifdef DHCPv6
360 if (local_family == AF_INET6) {
361 /* DHCPv6: override DHCPv4 lease and pid filenames */
362 if (!no_dhcpd_db) {
363 if ((s = getenv ("PATH_DHCPD6_DB")))
364 path_dhcpd_db = s;
365 else
366 path_dhcpd_db = _PATH_DHCPD6_DB;
367 }
368 if (!no_dhcpd_pid) {
369 if ((s = getenv ("PATH_DHCPD6_PID")))
370 path_dhcpd_pid = s;
371 else
372 path_dhcpd_pid = _PATH_DHCPD6_PID;
373 }
374 } else
375#else /* !DHCPv6 */
376 {
377 if (!no_dhcpd_db && (s = getenv ("PATH_DHCPD_DB"))) {
378 path_dhcpd_db = s;
379 }
380 if (!no_dhcpd_pid && (s = getenv ("PATH_DHCPD_PID"))) {
381 path_dhcpd_pid = s;
382 }
383 }
384#endif /* DHCPv6 */
cfa7212d 385
a546f2a7
EH
386 /*
387 * convert relative path names to absolute, for files that need
388 * to be reopened after chdir() has been called
389 */
390 if (path_dhcpd_db[0] != '/') {
32e651c4
SR
391 const char *path = path_dhcpd_db;
392 path_dhcpd_db = realpath(path_dhcpd_db, NULL);
a546f2a7 393 if (path_dhcpd_db == NULL)
32e651c4
SR
394 log_fatal("Failed to get realpath for %s: %s", path,
395 strerror(errno));
a546f2a7
EH
396 }
397
632d8396 398 if (!quiet) {
fe5b0fdd 399 log_info("%s %s", message, PACKAGE_VERSION);
8ae2d595
TL
400 log_info (copyright);
401 log_info (arr);
8ae2d595 402 log_info (url);
77222488 403 } else {
c4f74946 404 quiet = 0;
77222488
TL
405 log_perror = 0;
406 }
c6dff01f 407
a920d3da
TL
408#if defined (TRACING)
409 trace_init (set_time, MDL);
98311e4b
DH
410 if (traceoutfile) {
411 result = trace_begin (traceoutfile, MDL);
412 if (result != ISC_R_SUCCESS)
413 log_fatal ("Unable to begin trace: %s",
414 isc_result_totext (result));
415 }
a920d3da
TL
416 interface_trace_setup ();
417 parse_trace_setup ();
418 trace_srandom = trace_type_register ("random-seed", (void *)0,
419 trace_seed_input,
420 trace_seed_stop, MDL);
7aa153b8 421 trace_ddns_init();
a920d3da
TL
422#endif
423
63971a83
DH
424#if defined (PARANOIA)
425 /* get user and group info if those options were given */
426 if (set_user) {
427 struct passwd *tmp_pwd;
428
429 if (geteuid())
430 log_fatal ("you must be root to set user");
431
432 if (!(tmp_pwd = getpwnam(set_user)))
433 log_fatal ("no such user: %s", set_user);
434
435 set_uid = tmp_pwd->pw_uid;
436
437 /* use the user's group as the default gid */
438 if (!set_group)
439 set_gid = tmp_pwd->pw_gid;
440 }
441
442 if (set_group) {
443/* get around the ISC declaration of group */
444#define group real_group
445 struct group *tmp_grp;
446
447 if (geteuid())
448 log_fatal ("you must be root to set group");
449
450 if (!(tmp_grp = getgrnam(set_group)))
451 log_fatal ("no such group: %s", set_group);
452
453 set_gid = tmp_grp->gr_gid;
454#undef group
455 }
456
457# if defined (EARLY_CHROOT)
458 if (set_chroot) setup_chroot (set_chroot);
459# endif /* EARLY_CHROOT */
460#endif /* PARANOIA */
461
d7837182 462 /* Default to the DHCP/BOOTP port. */
a60076f9 463 if (!local_port)
d7837182 464 {
a920d3da 465 if ((s = getenv ("DHCPD_PORT"))) {
59112e84 466 local_port = validate_port (s);
a920d3da
TL
467 log_debug ("binding to environment-specified port %d",
468 ntohs (local_port));
469 } else {
98bd7ca0
DH
470 if (local_family == AF_INET) {
471 ent = getservbyname("dhcp", "udp");
472 if (ent == NULL) {
473 local_port = htons(67);
474 } else {
475 local_port = ent->s_port;
476 }
477 } else {
478 /* INSIST(local_family == AF_INET6); */
479 ent = getservbyname("dhcpv6-server", "udp");
480 if (ent == NULL) {
481 local_port = htons(547);
482 } else {
483 local_port = ent->s_port;
484 }
485 }
1e39d101 486#ifndef __CYGWIN32__ /* XXX */
a920d3da 487 endservent ();
1e39d101 488#endif
a920d3da 489 }
d7837182
TL
490 }
491
98bd7ca0
DH
492 if (local_family == AF_INET) {
493 remote_port = htons(ntohs(local_port) + 1);
494 } else {
495 /* INSIST(local_family == AF_INET6); */
496 ent = getservbyname("dhcpv6-client", "udp");
497 if (ent == NULL) {
498 remote_port = htons(546);
499 } else {
500 remote_port = ent->s_port;
501 }
502 }
a60076f9 503
e3a84e35 504 if (server) {
2e13ba55
SK
505 if (local_family != AF_INET) {
506 log_fatal("You can only specify address to send "
507 "replies to when running an IPv4 server.");
508 }
e3a84e35
TL
509 if (!inet_aton (server, &limited_broadcast)) {
510 struct hostent *he;
511 he = gethostbyname (server);
512 if (he) {
513 memcpy (&limited_broadcast,
514 he -> h_addr_list [0],
515 sizeof limited_broadcast);
516 } else
517 limited_broadcast.s_addr = INADDR_BROADCAST;
518 }
519 } else {
520 limited_broadcast.s_addr = INADDR_BROADCAST;
521 }
522
d7837182 523 /* Get the current time... */
be62cf06 524 gettimeofday(&cur_tv, NULL);
d7837182 525
77222488
TL
526 /* Set up the initial dhcp option universe. */
527 initialize_common_option_spaces ();
528 initialize_server_option_spaces ();
529
fafe8463
TL
530 /* Add the ddns update style enumeration prior to parsing. */
531 add_enumeration (&ddns_styles);
ee5a7404 532 add_enumeration (&syslog_enum);
33692791
DH
533#if defined (LDAP_CONFIGURATION)
534 add_enumeration (&ldap_methods);
535#if defined (LDAP_USE_SSL)
536 add_enumeration (&ldap_ssl_usage_enum);
537 add_enumeration (&ldap_tls_reqcert_enum);
538 add_enumeration (&ldap_tls_crlcheck_enum);
539#endif
540#endif
fafe8463 541
20916cae
TL
542 if (!group_allocate (&root_group, MDL))
543 log_fatal ("Can't allocate root group!");
544 root_group -> authoritative = 0;
77222488 545
a920d3da
TL
546 /* Set up various hooks. */
547 dhcp_interface_setup_hook = dhcpd_interface_setup_hook;
548 bootp_packet_handler = do_packet;
fe5b0fdd 549#ifdef DHCPv6
98bd7ca0 550 dhcpv6_packet_handler = do_packet6;
fe5b0fdd 551#endif /* DHCPv6 */
a920d3da 552
144cdb49 553#if defined (NSUPDATE)
77222488 554 /* Set up the standard name service updater routine. */
c40e954c
EH
555 parse = NULL;
556 status = new_parse(&parse, -1, std_nsupdate, sizeof(std_nsupdate) - 1,
dc66a995 557 "standard name service update routine", 0);
77222488 558 if (status != ISC_R_SUCCESS)
d8e1567c 559 log_fatal ("can't begin parsing name service updater!");
77222488 560
c40e954c
EH
561 if (parse != NULL) {
562 lose = 0;
563 if (!(parse_executable_statements(&root_group->statements,
564 parse, &lose, context_any))) {
565 end_parse(&parse);
566 log_fatal("can't parse standard name service updater!");
567 }
568 end_parse(&parse);
77222488 569 }
144cdb49 570#endif
77222488 571
a920d3da 572 /* Initialize icmp support... */
30a122ee
TL
573 if (!cftest && !lftest)
574 icmp_startup (1, lease_pinged);
a920d3da
TL
575
576#if defined (TRACING)
577 if (traceinfile) {
578 if (!no_dhcpd_db) {
579 log_error ("%s", "");
580 log_error ("** You must specify a lease file with -lf.");
581 log_error (" Dhcpd will not overwrite your default");
582 log_fatal (" lease file when playing back a trace. **");
583 }
584 trace_file_replay (traceinfile);
d758ad8c 585
98311e4b 586#if defined (DEBUG_MEMORY_LEAKAGE) && \
d758ad8c
TL
587 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
588 free_everything ();
589 omapi_print_dmalloc_usage_by_caller ();
590#endif
591
a920d3da
TL
592 exit (0);
593 }
594#endif
595
98bd7ca0 596#ifdef DHCPv6
1d9774ab 597 /* set up DHCPv6 hashes */
9322442f 598 if (!ia_new_hash(&ia_na_active, DEFAULT_HASH_SIZE, MDL)) {
1d9774ab
FD
599 log_fatal("Out of memory creating hash for active IA_NA.");
600 }
9322442f 601 if (!ia_new_hash(&ia_ta_active, DEFAULT_HASH_SIZE, MDL)) {
1d9774ab
FD
602 log_fatal("Out of memory creating hash for active IA_TA.");
603 }
9322442f 604 if (!ia_new_hash(&ia_pd_active, DEFAULT_HASH_SIZE, MDL)) {
1d9774ab 605 log_fatal("Out of memory creating hash for active IA_PD.");
98bd7ca0
DH
606 }
607#endif /* DHCPv6 */
608
d7837182 609 /* Read the dhcpd.conf file... */
8f450cac 610 if (readconf () != ISC_R_SUCCESS)
8ae2d595 611 log_fatal ("Configuration file errors encountered -- exiting");
d7837182 612
d758ad8c 613 postconf_initialization (quiet);
63971a83
DH
614
615#if defined (PARANOIA) && !defined (EARLY_CHROOT)
616 if (set_chroot) setup_chroot (set_chroot);
617#endif /* PARANOIA && !EARLY_CHROOT */
d758ad8c 618
40f63fcd 619 /* test option should cause an early exit */
8f450cac 620 if (cftest && !lftest)
40f63fcd
TL
621 exit(0);
622
a920d3da
TL
623 group_write_hook = group_writer;
624
625 /* Start up the database... */
626 db_startup (lftest);
627
628 if (lftest)
629 exit (0);
630
631 /* Discover all the network interfaces and initialize them. */
98bd7ca0
DH
632 discover_interfaces(DISCOVER_SERVER);
633
634#ifdef DHCPv6
635 /*
636 * Remove addresses from our pools that we should not issue
637 * to clients.
c61eba3b
SK
638 *
639 * We currently have no support for this in IPv4. It is not
640 * as important in IPv4, as making pools with ranges that
641 * leave out interfaces and hosts is fairly straightforward
642 * using range notation, but not so handy with CIDR notation.
98bd7ca0 643 */
c61eba3b
SK
644 if (local_family == AF_INET6) {
645 mark_hosts_unavailable();
80c9fdb0 646 mark_phosts_unavailable();
c61eba3b
SK
647 mark_interfaces_unavailable();
648 }
98bd7ca0
DH
649#endif /* DHCPv6 */
650
a920d3da
TL
651
652 /* Make up a seed for the random number generator from current
653 time plus the sum of the last four bytes of each
654 interface's hardware address interpreted as an integer.
655 Not much entropy, but we're booting, so we're not likely to
656 find anything better. */
657 seed = 0;
658 for (ip = interfaces; ip; ip = ip -> next) {
659 int junk;
660 memcpy (&junk,
661 &ip -> hw_address.hbuf [ip -> hw_address.hlen -
662 sizeof seed], sizeof seed);
663 seed += junk;
664 }
665 srandom (seed + cur_time);
666#if defined (TRACING)
667 trace_seed_stash (trace_srandom, seed + cur_time);
668#endif
d758ad8c 669 postdb_startup ();
a920d3da 670
fe5b0fdd 671#ifdef DHCPv6
98bd7ca0
DH
672 /*
673 * Set server DHCPv6 identifier.
674 * See dhcpv6.c for discussion of setting DUID.
675 */
676 if (set_server_duid_from_option() == ISC_R_SUCCESS) {
677 write_server_duid();
678 } else {
679 if (!server_duid_isset()) {
680 if (generate_new_server_duid() != ISC_R_SUCCESS) {
681 log_fatal("Unable to set server identifier.");
682 }
683 write_server_duid();
684 }
685 }
fe5b0fdd 686#endif /* DHCPv6 */
98bd7ca0 687
a920d3da
TL
688#ifndef DEBUG
689 if (daemon) {
690 /* First part of becoming a daemon... */
691 if ((pid = fork ()) < 0)
692 log_fatal ("Can't fork daemon: %m");
693 else if (pid)
694 exit (0);
695 }
63971a83
DH
696
697#if defined (PARANOIA)
698 /* change uid to the specified one */
699
700 if (set_gid) {
701 if (setgroups (0, (void *)0))
702 log_fatal ("setgroups: %m");
703 if (setgid (set_gid))
704 log_fatal ("setgid(%d): %m", (int) set_gid);
705 }
706
707 if (set_uid) {
708 if (setuid (set_uid))
709 log_fatal ("setuid(%d): %m", (int) set_uid);
710 }
711#endif /* PARANOIA */
a920d3da 712
4a5bfeac
SR
713 /*
714 * Deal with pid files. If the user told us
715 * not to write a file we don't read one either
716 */
717 if (no_pid_file == ISC_FALSE) {
718 /*Read previous pid file. */
719 if ((i = open (path_dhcpd_pid, O_RDONLY)) >= 0) {
720 status = read(i, pbuf, (sizeof pbuf) - 1);
721 close (i);
722 if (status > 0) {
723 pbuf[status] = 0;
724 pid = atoi(pbuf);
725
726 /*
727 * If there was a previous server process and
728 * it is still running, abort
729 */
730 if (!pid ||
731 (pid != getpid() && kill(pid, 0) == 0))
732 log_fatal("There's already a "
733 "DHCP server running.");
734 }
98311e4b 735 }
182b187e 736
4a5bfeac
SR
737 /* Write new pid file. */
738 i = open(path_dhcpd_pid, O_WRONLY|O_CREAT|O_TRUNC, 0644);
739 if (i >= 0) {
740 sprintf(pbuf, "%d\n", (int) getpid());
741 IGNORE_RET (write(i, pbuf, strlen(pbuf)));
742 close(i);
743 } else {
744 log_error("Can't create PID file %s: %m.",
745 path_dhcpd_pid);
746 }
747 }
182b187e 748
a920d3da
TL
749 /* If we were requested to log to stdout on the command line,
750 keep doing so; otherwise, stop. */
751 if (log_perror == -1)
752 log_perror = 1;
753 else
754 log_perror = 0;
755
756 if (daemon) {
757 /* Become session leader and get pid... */
dc9d7b08 758 (void) setsid();
185d16f9
SK
759
760 /* Close standard I/O descriptors. */
dc9d7b08
MA
761 (void) close(0);
762 (void) close(1);
763 (void) close(2);
185d16f9
SK
764
765 /* Reopen them on /dev/null. */
dc9d7b08
MA
766 (void) open("/dev/null", O_RDWR);
767 (void) open("/dev/null", O_RDWR);
768 (void) open("/dev/null", O_RDWR);
185d16f9 769 log_perror = 0; /* No sense logging to /dev/null. */
a920d3da 770
ae566556 771 IGNORE_RET (chdir("/"));
a920d3da
TL
772 }
773#endif /* !DEBUG */
774
d758ad8c
TL
775#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
776 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
a920d3da
TL
777 dmalloc_cutoff_generation = dmalloc_generation;
778 dmalloc_longterm = dmalloc_outstanding;
779 dmalloc_outstanding = 0;
780#endif
781
d758ad8c
TL
782 omapi_set_int_value ((omapi_object_t *)dhcp_control_object,
783 (omapi_object_t *)0, "state", server_running);
784
47e8308d
SR
785 /* install signal handlers */
786 signal(SIGINT, dhcp_signal_handler); /* control-c */
787 signal(SIGTERM, dhcp_signal_handler); /* kill */
788
f88446f1
SR
789 /* Log that we are about to start working */
790 log_info("Server starting service.");
791
47e8308d
SR
792 /*
793 * Receive packets and dispatch them...
0895c955 794 * dispatch() will never return.
47e8308d 795 */
a920d3da
TL
796 dispatch ();
797
47e8308d 798 /* Let's return status code */
a920d3da
TL
799 return 0;
800}
98bd7ca0 801#endif /* !UNIT_TEST */
a920d3da
TL
802
803void postconf_initialization (int quiet)
804{
cde11a4c 805 struct option_state *options = NULL;
a920d3da
TL
806 struct data_string db;
807 struct option_cache *oc;
808 char *s;
809 isc_result_t result;
a920d3da 810 int tmp;
61ef216b
SR
811#if defined (NSUPDATE)
812 struct in_addr local4, *local4_ptr = NULL;
813 struct in6_addr local6, *local6_ptr = NULL;
814#endif
a920d3da 815
b62e4418 816 /* Now try to get the lease file name. */
cde11a4c 817 option_state_allocate(&options, MDL);
b62e4418 818
a7341359
SR
819 execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL,
820 options, &global_scope, root_group,
821 NULL, NULL);
cde11a4c
SR
822 memset(&db, 0, sizeof db);
823 oc = lookup_option(&server_universe, options, SV_LEASE_FILE_NAME);
b62e4418 824 if (oc &&
cde11a4c
SR
825 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
826 &global_scope, oc, MDL)) {
827 s = dmalloc(db.len + 1, MDL);
b62e4418 828 if (!s)
cde11a4c
SR
829 log_fatal("no memory for lease db filename.");
830 memcpy(s, db.data, db.len);
831 s[db.len] = 0;
832 data_string_forget(&db, MDL);
b62e4418
TL
833 path_dhcpd_db = s;
834 }
75135a3f 835
cde11a4c 836 oc = lookup_option(&server_universe, options, SV_PID_FILE_NAME);
b62e4418 837 if (oc &&
cde11a4c
SR
838 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
839 &global_scope, oc, MDL)) {
840 s = dmalloc(db.len + 1, MDL);
b62e4418 841 if (!s)
cde11a4c
SR
842 log_fatal("no memory for pid filename.");
843 memcpy(s, db.data, db.len);
844 s[db.len] = 0;
845 data_string_forget(&db, MDL);
b62e4418
TL
846 path_dhcpd_pid = s;
847 }
848
75135a3f
EH
849#ifdef DHCPv6
850 if (local_family == AF_INET6) {
851 /*
852 * Override lease file name with dhcpv6 lease file name,
853 * if it was set; then, do the same with the pid file name
854 */
855 oc = lookup_option(&server_universe, options,
856 SV_DHCPV6_LEASE_FILE_NAME);
857 if (oc &&
cde11a4c
SR
858 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
859 &global_scope, oc, MDL)) {
860 s = dmalloc(db.len + 1, MDL);
75135a3f 861 if (!s)
cde11a4c
SR
862 log_fatal("no memory for lease db filename.");
863 memcpy(s, db.data, db.len);
864 s[db.len] = 0;
865 data_string_forget(&db, MDL);
75135a3f
EH
866 path_dhcpd_db = s;
867 }
868
869 oc = lookup_option(&server_universe, options,
870 SV_DHCPV6_PID_FILE_NAME);
871 if (oc &&
cde11a4c
SR
872 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
873 &global_scope, oc, MDL)) {
874 s = dmalloc(db.len + 1, MDL);
75135a3f 875 if (!s)
cde11a4c
SR
876 log_fatal("no memory for pid filename.");
877 memcpy(s, db.data, db.len);
878 s[db.len] = 0;
879 data_string_forget(&db, MDL);
75135a3f
EH
880 path_dhcpd_pid = s;
881 }
882 }
883#endif /* DHCPv6 */
884
312a6a35 885 omapi_port = -1;
cde11a4c 886 oc = lookup_option(&server_universe, options, SV_OMAPI_PORT);
ece9e253 887 if (oc &&
cde11a4c
SR
888 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
889 &global_scope, oc, MDL)) {
ece9e253 890 if (db.len == 2) {
cde11a4c 891 omapi_port = getUShort(db.data);
ece9e253 892 } else
cde11a4c
SR
893 log_fatal("invalid omapi port data length");
894 data_string_forget(&db, MDL);
ece9e253
TL
895 }
896
cde11a4c 897 oc = lookup_option(&server_universe, options, SV_OMAPI_KEY);
49146f3c 898 if (oc &&
cde11a4c
SR
899 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
900 &global_scope, oc, MDL)) {
901 s = dmalloc(db.len + 1, MDL);
49146f3c 902 if (!s)
cde11a4c
SR
903 log_fatal("no memory for OMAPI key filename.");
904 memcpy(s, db.data, db.len);
905 s[db.len] = 0;
906 data_string_forget(&db, MDL);
907 result = omapi_auth_key_lookup_name(&omapi_key, s);
908 dfree(s, MDL);
49146f3c 909 if (result != ISC_R_SUCCESS)
cde11a4c
SR
910 log_fatal("OMAPI key %s: %s",
911 s, isc_result_totext (result));
49146f3c
DN
912 }
913
cde11a4c 914 oc = lookup_option(&server_universe, options, SV_LOCAL_PORT);
ece9e253 915 if (oc &&
cde11a4c
SR
916 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
917 &global_scope, oc, MDL)) {
ece9e253 918 if (db.len == 2) {
cde11a4c 919 local_port = htons(getUShort (db.data));
ece9e253 920 } else
cde11a4c
SR
921 log_fatal("invalid local port data length");
922 data_string_forget(&db, MDL);
ece9e253
TL
923 }
924
cde11a4c 925 oc = lookup_option(&server_universe, options, SV_REMOTE_PORT);
ece9e253 926 if (oc &&
cde11a4c
SR
927 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
928 &global_scope, oc, MDL)) {
ece9e253 929 if (db.len == 2) {
cde11a4c 930 remote_port = htons(getUShort (db.data));
ece9e253 931 } else
cde11a4c
SR
932 log_fatal("invalid remote port data length");
933 data_string_forget(&db, MDL);
ece9e253
TL
934 }
935
cde11a4c
SR
936 oc = lookup_option(&server_universe, options,
937 SV_LIMITED_BROADCAST_ADDRESS);
ece9e253 938 if (oc &&
cde11a4c
SR
939 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
940 &global_scope, oc, MDL)) {
ece9e253 941 if (db.len == 4) {
cde11a4c 942 memcpy(&limited_broadcast, db.data, 4);
ece9e253 943 } else
cde11a4c
SR
944 log_fatal("invalid broadcast address data length");
945 data_string_forget(&db, MDL);
ece9e253
TL
946 }
947
cde11a4c 948 oc = lookup_option(&server_universe, options, SV_LOCAL_ADDRESS);
ece9e253 949 if (oc &&
cde11a4c
SR
950 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
951 &global_scope, oc, MDL)) {
ece9e253 952 if (db.len == 4) {
cde11a4c 953 memcpy(&local_address, db.data, 4);
ece9e253 954 } else
cde11a4c
SR
955 log_fatal("invalid local address data length");
956 data_string_forget(&db, MDL);
ece9e253
TL
957 }
958
cde11a4c 959 oc = lookup_option(&server_universe, options, SV_DDNS_UPDATE_STYLE);
fafe8463 960 if (oc) {
cde11a4c
SR
961 if (evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
962 &global_scope, oc, MDL)) {
fafe8463 963 if (db.len == 1) {
cde11a4c 964 ddns_update_style = db.data[0];
fafe8463 965 } else
cde11a4c
SR
966 log_fatal("invalid dns update type");
967 data_string_forget(&db, MDL);
fafe8463 968 }
d7f6db15 969 } else {
884a458f 970 ddns_update_style = DDNS_UPDATE_STYLE_NONE;
d7f6db15 971 }
98bf1607
SR
972#if defined (NSUPDATE)
973 /* We no longer support ad_hoc, tell the user */
974 if (ddns_update_style == DDNS_UPDATE_STYLE_AD_HOC) {
975 log_fatal("ddns-update-style ad_hoc no longer supported");
976 }
61ef216b
SR
977
978 oc = lookup_option(&server_universe, options, SV_DDNS_LOCAL_ADDRESS4);
979 if (oc) {
980 if (evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
981 &global_scope, oc, MDL)) {
982 if (db.len == 4) {
983 memcpy(&local4, db.data, 4);
984 local4_ptr = &local4;
985 }
986 data_string_forget(&db, MDL);
987 }
988 }
989
990 oc = lookup_option(&server_universe, options, SV_DDNS_LOCAL_ADDRESS6);
991 if (oc) {
992 if (evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
993 &global_scope, oc, MDL)) {
994 if (db.len == 16) {
995 memcpy(&local6, db.data, 16);
996 local6_ptr = &local6;
997 }
998 data_string_forget(&db, MDL);
999 }
1000 }
1001
1002 if (dhcp_context_create(DHCP_CONTEXT_POST_DB, local4_ptr, local6_ptr)
1003 != ISC_R_SUCCESS)
1004 log_fatal("Unable to complete ddns initialization");
1005
98bf1607
SR
1006#else
1007 /* If we don't have support for updates compiled in tell the user */
1008 if (ddns_update_style != DDNS_UPDATE_STYLE_NONE) {
1009 log_fatal("Support for ddns-update-style not compiled in");
1010 }
1011#endif
fafe8463 1012
cde11a4c 1013 oc = lookup_option(&server_universe, options, SV_LOG_FACILITY);
ee5a7404 1014 if (oc) {
cde11a4c
SR
1015 if (evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
1016 &global_scope, oc, MDL)) {
ee5a7404
TL
1017 if (db.len == 1) {
1018 closelog ();
cde11a4c 1019 openlog("dhcpd", LOG_NDELAY, db.data[0]);
a920d3da
TL
1020 /* Log the startup banner into the new
1021 log file. */
ee5a7404 1022 if (!quiet) {
a920d3da
TL
1023 /* Don't log to stderr twice. */
1024 tmp = log_perror;
1025 log_perror = 0;
fe5b0fdd
DH
1026 log_info("%s %s",
1027 message, PACKAGE_VERSION);
cde11a4c
SR
1028 log_info(copyright);
1029 log_info(arr);
1030 log_info(url);
a920d3da 1031 log_perror = tmp;
ee5a7404
TL
1032 }
1033 } else
cde11a4c
SR
1034 log_fatal("invalid log facility");
1035 data_string_forget(&db, MDL);
ee5a7404
TL
1036 }
1037 }
6368a1bd
DH
1038
1039 oc = lookup_option(&server_universe, options, SV_DELAYED_ACK);
1040 if (oc &&
1041 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
1042 &global_scope, oc, MDL)) {
1043 if (db.len == 2) {
1044 max_outstanding_acks = htons(getUShort(db.data));
1045 } else {
1046 log_fatal("invalid max delayed ACK count ");
1047 }
1048 data_string_forget(&db, MDL);
1049 }
ee5a7404 1050
f8cbf390
DH
1051 oc = lookup_option(&server_universe, options, SV_MAX_ACK_DELAY);
1052 if (oc &&
1053 evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
1054 &global_scope, oc, MDL)) {
1055 u_int32_t timeval;
1056
1057 if (db.len != 4)
1058 log_fatal("invalid max ack delay configuration");
1059
1060 timeval = getULong(db.data);
1061 max_ack_delay_secs = timeval / 1000000;
1062 max_ack_delay_usecs = timeval % 1000000;
1063
1064 data_string_forget(&db, MDL);
1065 }
1066
cde11a4c
SR
1067 oc = lookup_option(&server_universe, options, SV_DONT_USE_FSYNC);
1068 if ((oc != NULL) &&
1069 evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options, NULL,
1070 &global_scope, oc, MDL)) {
1071 dont_use_fsync = 1;
1072 log_error("Not using fsync() to flush lease writes");
1073 }
1074
b62e4418 1075 /* Don't need the options anymore. */
cde11a4c 1076 option_state_dereference(&options, MDL);
d7837182
TL
1077}
1078
d758ad8c
TL
1079void postdb_startup (void)
1080{
1081 /* Initialize the omapi listener state. */
1082 if (omapi_port != -1) {
1083 omapi_listener_start (0);
1084 }
1085
1086#if defined (FAILOVER_PROTOCOL)
1087 /* Initialize the failover listener state. */
1088 dhcp_failover_startup ();
1089#endif
d9b43370
SK
1090
1091 /*
1092 * Begin our lease timeout background task.
1093 */
1094 schedule_all_ipv6_lease_timeouts();
d758ad8c
TL
1095}
1096
d7837182 1097/* Print usage message. */
f9effb95 1098#ifndef UNIT_TEST
2e13ba55
SK
1099static void
1100usage(void) {
fe5b0fdd 1101 log_info("%s %s", message, PACKAGE_VERSION);
2e13ba55
SK
1102 log_info(copyright);
1103 log_info(arr);
deb0cb72 1104
2e13ba55 1105 log_fatal("Usage: dhcpd [-p <UDP port #>] [-f] [-d] [-q] [-t|-T]\n"
75135a3f 1106#ifdef DHCPv6
2e13ba55 1107 " [-4|-6] [-cf config-file] [-lf lease-file]\n"
75135a3f
EH
1108#else /* !DHCPv6 */
1109 " [-cf config-file] [-lf lease-file]\n"
1110#endif /* DHCPv6 */
63971a83
DH
1111#if defined (PARANOIA)
1112 /* meld into the following string */
1113 " [-user user] [-group group] [-chroot dir]\n"
1114#endif /* PARANOIA */
662df45a 1115#if defined (TRACING)
2e13ba55
SK
1116 " [-tf trace-output-file]\n"
1117 " [-play trace-input-file]\n"
662df45a 1118#endif /* TRACING */
4a5bfeac
SR
1119 " [-pf pid-file] [--no-pid] [-s server]\n"
1120 " [if0 [...ifN]]");
d7837182 1121}
f9effb95 1122#endif
d7837182 1123
9acb0bab
TL
1124void lease_pinged (from, packet, length)
1125 struct iaddr from;
1126 u_int8_t *packet;
1127 int length;
1128{
1129 struct lease *lp;
1130
1131 /* Don't try to look up a pinged lease if we aren't trying to
1132 ping one - otherwise somebody could easily make us churn by
1133 just forging repeated ICMP EchoReply packets for us to look
1134 up. */
1135 if (!outstanding_pings)
1136 return;
1137
20916cae
TL
1138 lp = (struct lease *)0;
1139 if (!find_lease_by_ip_addr (&lp, from, MDL)) {
1140 log_debug ("unexpected ICMP Echo Reply from %s",
1141 piaddr (from));
9acb0bab
TL
1142 return;
1143 }
1144
1145 if (!lp -> state) {
d8e1567c 1146#if defined (FAILOVER_PROTOCOL)
b73c184a
TL
1147 if (!lp -> pool ||
1148 !lp -> pool -> failover_peer)
d8e1567c 1149#endif
b73c184a
TL
1150 log_debug ("ICMP Echo Reply for %s late or spurious.",
1151 piaddr (from));
20916cae 1152 goto out;
9acb0bab
TL
1153 }
1154
c0a8b011 1155 if (lp -> ends > cur_time) {
b73c184a 1156 log_debug ("ICMP Echo reply while lease %s valid.",
4bd8800e 1157 piaddr (from));
c0a8b011
TL
1158 }
1159
9acb0bab
TL
1160 /* At this point it looks like we pinged a lease and got a
1161 response, which shouldn't have happened. */
4bd8800e
TL
1162 data_string_forget (&lp -> state -> parameter_request_list, MDL);
1163 free_lease_state (lp -> state, MDL);
9acb0bab
TL
1164 lp -> state = (struct lease_state *)0;
1165
1166 abandon_lease (lp, "pinged before offer");
1167 cancel_timeout (lease_ping_timeout, lp);
1168 --outstanding_pings;
20916cae
TL
1169 out:
1170 lease_dereference (&lp, MDL);
9acb0bab
TL
1171}
1172
1173void lease_ping_timeout (vlp)
1174 void *vlp;
1175{
1176 struct lease *lp = vlp;
1177
77222488
TL
1178#if defined (DEBUG_MEMORY_LEAKAGE)
1179 unsigned long previous_outstanding = dmalloc_outstanding;
1180#endif
1181
9acb0bab
TL
1182 --outstanding_pings;
1183 dhcp_reply (lp);
77222488
TL
1184
1185#if defined (DEBUG_MEMORY_LEAKAGE)
1186 log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
1187 dmalloc_generation,
1188 dmalloc_outstanding - previous_outstanding,
1189 dmalloc_outstanding, dmalloc_longterm);
1190#endif
d758ad8c 1191#if defined (DEBUG_MEMORY_LEAKAGE)
77222488
TL
1192 dmalloc_dump_outstanding ();
1193#endif
9acb0bab 1194}
20916cae
TL
1195
1196int dhcpd_interface_setup_hook (struct interface_info *ip, struct iaddr *ia)
1197{
1198 struct subnet *subnet;
1199 struct shared_network *share;
1200 isc_result_t status;
1201
1202 /* Special case for fallback network - not sure why this is
1203 necessary. */
1204 if (!ia) {
1205 const char *fnn = "fallback-net";
20916cae
TL
1206 status = shared_network_allocate (&ip -> shared_network, MDL);
1207 if (status != ISC_R_SUCCESS)
1208 log_fatal ("No memory for shared subnet: %s",
1209 isc_result_totext (status));
1210 ip -> shared_network -> name = dmalloc (strlen (fnn) + 1, MDL);
1211 strcpy (ip -> shared_network -> name, fnn);
1212 return 1;
1213 }
1214
1215 /* If there's a registered subnet for this address,
1216 connect it together... */
1217 subnet = (struct subnet *)0;
1218 if (find_subnet (&subnet, *ia, MDL)) {
1219 /* If this interface has multiple aliases on the same
1220 subnet, ignore all but the first we encounter. */
1221 if (!subnet -> interface) {
d758ad8c 1222 interface_reference (&subnet -> interface, ip, MDL);
20916cae
TL
1223 subnet -> interface_address = *ia;
1224 } else if (subnet -> interface != ip) {
1225 log_error ("Multiple interfaces match the %s: %s %s",
1226 "same subnet",
1227 subnet -> interface -> name, ip -> name);
1228 }
1229 share = subnet -> shared_network;
1230 if (ip -> shared_network &&
1231 ip -> shared_network != share) {
1232 log_fatal ("Interface %s matches multiple shared %s",
1233 ip -> name, "networks");
1234 } else {
1235 if (!ip -> shared_network)
1236 shared_network_reference
1237 (&ip -> shared_network, share, MDL);
1238 }
1239
1240 if (!share -> interface) {
1241 interface_reference (&share -> interface, ip, MDL);
1242 } else if (share -> interface != ip) {
1243 log_error ("Multiple interfaces match the %s: %s %s",
1244 "same shared network",
1245 share -> interface -> name, ip -> name);
1246 }
d758ad8c 1247 subnet_dereference (&subnet, MDL);
20916cae
TL
1248 }
1249 return 1;
1250}
d758ad8c
TL
1251
1252static TIME shutdown_time;
1253static int omapi_connection_count;
1254enum dhcp_shutdown_state shutdown_state;
1255
1256isc_result_t dhcp_io_shutdown (omapi_object_t *obj, void *foo)
1257{
1258 /* Shut down all listeners. */
1259 if (shutdown_state == shutdown_listeners &&
1260 obj -> type == omapi_type_listener &&
1261 obj -> inner &&
1262 obj -> inner -> type == omapi_type_protocol_listener) {
1263 omapi_listener_destroy (obj, MDL);
1264 return ISC_R_SUCCESS;
1265 }
1266
1267 /* Shut down all existing omapi connections. */
1268 if (obj -> type == omapi_type_connection &&
1269 obj -> inner &&
1270 obj -> inner -> type == omapi_type_protocol) {
1271 if (shutdown_state == shutdown_drop_omapi_connections) {
1272 omapi_disconnect (obj, 1);
1273 }
1274 omapi_connection_count++;
1275 if (shutdown_state == shutdown_omapi_connections) {
1276 omapi_disconnect (obj, 0);
1277 return ISC_R_SUCCESS;
1278 }
1279 }
1280
1281 /* Shutdown all DHCP interfaces. */
1282 if (obj -> type == dhcp_type_interface &&
1283 shutdown_state == shutdown_dhcp) {
1284 dhcp_interface_remove (obj, (omapi_object_t *)0);
1285 return ISC_R_SUCCESS;
1286 }
1287 return ISC_R_SUCCESS;
1288}
1289
1290static isc_result_t dhcp_io_shutdown_countdown (void *vlp)
1291{
d758ad8c 1292#if defined (FAILOVER_PROTOCOL)
66cebfcb 1293 dhcp_failover_state_t *state;
d758ad8c
TL
1294 int failover_connection_count = 0;
1295#endif
be62cf06 1296 struct timeval tv;
d758ad8c
TL
1297
1298 oncemore:
1299 if (shutdown_state == shutdown_listeners ||
1300 shutdown_state == shutdown_omapi_connections ||
1301 shutdown_state == shutdown_drop_omapi_connections ||
1302 shutdown_state == shutdown_dhcp) {
1303 omapi_connection_count = 0;
1304 omapi_io_state_foreach (dhcp_io_shutdown, 0);
1305 }
1306
1307 if ((shutdown_state == shutdown_listeners ||
1308 shutdown_state == shutdown_omapi_connections ||
1309 shutdown_state == shutdown_drop_omapi_connections) &&
1310 omapi_connection_count == 0) {
1311 shutdown_state = shutdown_dhcp;
1312 shutdown_time = cur_time;
1313 goto oncemore;
1314 } else if (shutdown_state == shutdown_listeners &&
1315 cur_time - shutdown_time > 4) {
1316 shutdown_state = shutdown_omapi_connections;
1317 shutdown_time = cur_time;
1318 } else if (shutdown_state == shutdown_omapi_connections &&
1319 cur_time - shutdown_time > 4) {
1320 shutdown_state = shutdown_drop_omapi_connections;
1321 shutdown_time = cur_time;
1322 } else if (shutdown_state == shutdown_drop_omapi_connections &&
1323 cur_time - shutdown_time > 4) {
1324 shutdown_state = shutdown_dhcp;
1325 shutdown_time = cur_time;
1326 goto oncemore;
1327 } else if (shutdown_state == shutdown_dhcp &&
1328 cur_time - shutdown_time > 4) {
1329 shutdown_state = shutdown_done;
1330 shutdown_time = cur_time;
1331 }
1332
1333#if defined (FAILOVER_PROTOCOL)
1334 /* Set all failover peers into the shutdown state. */
1335 if (shutdown_state == shutdown_dhcp) {
1336 for (state = failover_states; state; state = state -> next) {
1337 if (state -> me.state == normal) {
1338 dhcp_failover_set_state (state, shut_down);
1339 failover_connection_count++;
1340 }
1341 if (state -> me.state == shut_down &&
1342 state -> partner.state != partner_down)
1343 failover_connection_count++;
1344 }
1345 }
1346
1347 if (shutdown_state == shutdown_done) {
1348 for (state = failover_states; state; state = state -> next) {
1349 if (state -> me.state == shut_down) {
1350 if (state -> link_to_peer)
1351 dhcp_failover_link_dereference (&state -> link_to_peer,
1352 MDL);
1353 dhcp_failover_set_state (state, recover);
1354 }
1355 }
98311e4b 1356#if defined (DEBUG_MEMORY_LEAKAGE) && \
d758ad8c
TL
1357 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1358 free_everything ();
1359 omapi_print_dmalloc_usage_by_caller ();
1360#endif
1361 exit (0);
1362 }
1363#else
1364 if (shutdown_state == shutdown_done) {
98311e4b
DH
1365#if defined (DEBUG_MEMORY_LEAKAGE) && \
1366 defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
1367 free_everything ();
1368 omapi_print_dmalloc_usage_by_caller ();
d758ad8c
TL
1369#endif
1370 exit (0);
1371 }
1372#endif
1373 if (shutdown_state == shutdown_dhcp &&
33e1cb2b
DH
1374#if defined(FAILOVER_PROTOCOL)
1375 !failover_connection_count &&
1376#endif
1377 ISC_TRUE) {
d758ad8c
TL
1378 shutdown_state = shutdown_done;
1379 shutdown_time = cur_time;
1380 goto oncemore;
1381 }
be62cf06
FD
1382 tv.tv_sec = cur_tv.tv_sec + 1;
1383 tv.tv_usec = cur_tv.tv_usec;
1384 add_timeout (&tv,
d758ad8c
TL
1385 (void (*)(void *))dhcp_io_shutdown_countdown, 0, 0, 0);
1386 return ISC_R_SUCCESS;
1387}
1388
1389isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
1390 control_object_state_t newstate)
1391{
0895c955
SR
1392 struct timeval tv;
1393
1394 if (newstate != server_shutdown)
1395 return DHCP_R_INVALIDARG;
1396 /* Re-entry. */
1397 if (shutdown_signal == SIGUSR1)
1398 return ISC_R_SUCCESS;
1399 shutdown_time = cur_time;
1400 shutdown_state = shutdown_listeners;
1401 /* Called by user. */
1402 if (shutdown_signal == 0) {
1403 shutdown_signal = SIGUSR1;
d758ad8c
TL
1404 dhcp_io_shutdown_countdown (0);
1405 return ISC_R_SUCCESS;
1406 }
0895c955
SR
1407 /* Called on signal. */
1408 log_info("Received signal %d, initiating shutdown.", shutdown_signal);
1409 shutdown_signal = SIGUSR1;
1410
1411 /*
1412 * Prompt the shutdown event onto the timer queue
1413 * and return to the dispatch loop.
1414 */
1415 tv.tv_sec = cur_tv.tv_sec;
1416 tv.tv_usec = cur_tv.tv_usec + 1;
1417 add_timeout(&tv,
1418 (void (*)(void *))dhcp_io_shutdown_countdown, 0, 0, 0);
1419 return ISC_R_SUCCESS;
d758ad8c 1420}