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