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