1*13df4856Schristos /* $NetBSD: dhcpd.c,v 1.5 2022/04/03 01:10:59 christos Exp $ */
23965be93Schristos
33965be93Schristos /* dhcpd.c
43965be93Schristos
53965be93Schristos DHCP Server Daemon. */
63965be93Schristos
73965be93Schristos /*
8*13df4856Schristos * Copyright (c) 2004-2022 by Internet Systems Consortium, Inc. ("ISC")
93965be93Schristos * Copyright (c) 1996-2003 by Internet Software Consortium
103965be93Schristos *
113965be93Schristos * This Source Code Form is subject to the terms of the Mozilla Public
123965be93Schristos * License, v. 2.0. If a copy of the MPL was not distributed with this
133965be93Schristos * file, You can obtain one at http://mozilla.org/MPL/2.0/.
143965be93Schristos *
153965be93Schristos * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
163965be93Schristos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
173965be93Schristos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
183965be93Schristos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
193965be93Schristos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
203965be93Schristos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
213965be93Schristos * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
223965be93Schristos *
233965be93Schristos * Internet Systems Consortium, Inc.
24*13df4856Schristos * PO Box 360
25*13df4856Schristos * Newmarket, NH 03857 USA
263965be93Schristos * <info@isc.org>
273965be93Schristos * https://www.isc.org/
283965be93Schristos *
293965be93Schristos */
303965be93Schristos
313965be93Schristos #include <sys/cdefs.h>
32*13df4856Schristos __RCSID("$NetBSD: dhcpd.c,v 1.5 2022/04/03 01:10:59 christos Exp $");
333965be93Schristos
343965be93Schristos static const char copyright[] =
35*13df4856Schristos "Copyright 2004-2022 Internet Systems Consortium.";
363965be93Schristos static const char arr [] = "All rights reserved.";
373965be93Schristos static const char message [] = "Internet Systems Consortium DHCP Server";
383965be93Schristos static const char url [] =
393965be93Schristos "For info, please visit https://www.isc.org/software/dhcp/";
403965be93Schristos
413965be93Schristos #include "dhcpd.h"
423965be93Schristos #include <omapip/omapip_p.h>
433965be93Schristos #include <syslog.h>
443965be93Schristos #include <signal.h>
453965be93Schristos #include <errno.h>
463965be93Schristos #include <limits.h>
473965be93Schristos #include <sys/types.h>
483965be93Schristos #include <sys/time.h>
493965be93Schristos #include <isc/file.h>
503965be93Schristos
513965be93Schristos #if defined (PARANOIA)
523965be93Schristos # include <sys/types.h>
533965be93Schristos # include <unistd.h>
543965be93Schristos # include <pwd.h>
553965be93Schristos /* get around the ISC declaration of group */
563965be93Schristos # define group real_group
573965be93Schristos # include <grp.h>
583965be93Schristos # undef group
593965be93Schristos
603965be93Schristos /* global values so db.c can look at them */
613965be93Schristos uid_t set_uid = 0;
623965be93Schristos gid_t set_gid = 0;
633965be93Schristos #endif /* PARANOIA */
643965be93Schristos
653965be93Schristos struct class unknown_class;
663965be93Schristos struct class known_class;
673965be93Schristos
683965be93Schristos struct iaddr server_identifier;
693965be93Schristos int server_identifier_matched;
703965be93Schristos
713965be93Schristos #if defined (NSUPDATE)
723965be93Schristos
733965be93Schristos /* This stuff is always executed to figure the default values for certain
743965be93Schristos ddns variables. */
753965be93Schristos char std_nsupdate [] = " \n\
763965be93Schristos option server.ddns-hostname = \n\
773965be93Schristos pick (option fqdn.hostname, option host-name, config-option host-name); \n\
783965be93Schristos option server.ddns-domainname = config-option domain-name; \n\
793965be93Schristos option server.ddns-rev-domainname = \"in-addr.arpa.\";";
803965be93Schristos
813965be93Schristos /* Stores configured DDNS conflict detection flags */
823965be93Schristos u_int16_t ddns_conflict_mask;
833965be93Schristos #endif /* NSUPDATE */
843965be93Schristos
853965be93Schristos int ddns_update_style;
863965be93Schristos int dont_use_fsync = 0; /* 0 = default, use fsync, 1 = don't use fsync */
873965be93Schristos int server_id_check = 0; /* 0 = default, don't check server id, 1 = do check */
883965be93Schristos
893965be93Schristos #ifdef DHCPv6
903965be93Schristos int prefix_length_mode = PLM_PREFER;
913965be93Schristos int do_release_on_roam = 0; /* 0 = default, do not release v6 leases on roam */
923965be93Schristos #endif
933965be93Schristos
943965be93Schristos #ifdef EUI_64
953965be93Schristos int persist_eui64 = 1; /* 1 = write EUI64 leases to disk, 0 = don't */
963965be93Schristos #endif
973965be93Schristos
983965be93Schristos int authoring_byte_order = 0; /* 0 = not set */
993965be93Schristos int lease_id_format = TOKEN_OCTAL; /* octal by default */
1003965be93Schristos u_int32_t abandon_lease_time = DEFAULT_ABANDON_LEASE_TIME;
1013965be93Schristos
1023965be93Schristos const char *path_dhcpd_conf = _PATH_DHCPD_CONF;
1033965be93Schristos const char *path_dhcpd_db = _PATH_DHCPD_DB;
1043965be93Schristos const char *path_dhcpd_pid = _PATH_DHCPD_PID;
1053965be93Schristos /* False (default) => we write and use a pid file */
1063965be93Schristos isc_boolean_t no_pid_file = ISC_FALSE;
1073965be93Schristos
1083965be93Schristos int dhcp_max_agent_option_packet_length = DHCP_MTU_MAX;
1093965be93Schristos
1103965be93Schristos static omapi_auth_key_t *omapi_key = (omapi_auth_key_t *)0;
1113965be93Schristos int omapi_port;
1123965be93Schristos
1133965be93Schristos #if defined (TRACING)
1143965be93Schristos trace_type_t *trace_srandom;
1153965be93Schristos #endif
1163965be93Schristos
117*13df4856Schristos extern uint16_t local_port;
118*13df4856Schristos extern uint16_t remote_port;
11907146da4Schristos libdhcp_callbacks_t dhcpd_callbacks = {
12007146da4Schristos &local_port,
12107146da4Schristos &remote_port,
12207146da4Schristos classify,
12307146da4Schristos check_collection,
12407146da4Schristos dhcp,
12507146da4Schristos #ifdef DHCPv6
12607146da4Schristos dhcpv6,
12707146da4Schristos #endif /* DHCPv6 */
12807146da4Schristos bootp,
12907146da4Schristos find_class,
13007146da4Schristos parse_allow_deny,
13107146da4Schristos dhcp_set_control_state,
13207146da4Schristos };
13307146da4Schristos
1343965be93Schristos char *progname;
1353965be93Schristos
verify_addr(omapi_object_t * l,omapi_addr_t * addr)1363965be93Schristos static isc_result_t verify_addr (omapi_object_t *l, omapi_addr_t *addr) {
1373965be93Schristos return ISC_R_SUCCESS;
1383965be93Schristos }
1393965be93Schristos
verify_auth(omapi_object_t * p,omapi_auth_key_t * a)1403965be93Schristos static isc_result_t verify_auth (omapi_object_t *p, omapi_auth_key_t *a) {
1413965be93Schristos if (a != omapi_key)
1423965be93Schristos return DHCP_R_INVALIDKEY;
1433965be93Schristos return ISC_R_SUCCESS;
1443965be93Schristos }
1453965be93Schristos
omapi_listener_start(void * foo)1463965be93Schristos static void omapi_listener_start (void *foo)
1473965be93Schristos {
1483965be93Schristos omapi_object_t *listener;
1493965be93Schristos isc_result_t result;
1503965be93Schristos struct timeval tv;
1513965be93Schristos
1523965be93Schristos listener = (omapi_object_t *)0;
1533965be93Schristos result = omapi_generic_new (&listener, MDL);
1543965be93Schristos if (result != ISC_R_SUCCESS)
1553965be93Schristos log_fatal ("Can't allocate new generic object: %s",
1563965be93Schristos isc_result_totext (result));
1573965be93Schristos result = omapi_protocol_listen (listener,
1583965be93Schristos (unsigned)omapi_port, 1);
1593965be93Schristos if (result == ISC_R_SUCCESS && omapi_key)
1603965be93Schristos result = omapi_protocol_configure_security
1613965be93Schristos (listener, verify_addr, verify_auth);
1623965be93Schristos if (result != ISC_R_SUCCESS) {
1633965be93Schristos log_error ("Can't start OMAPI protocol: %s",
1643965be93Schristos isc_result_totext (result));
1653965be93Schristos tv.tv_sec = cur_tv.tv_sec + 5;
1663965be93Schristos tv.tv_usec = cur_tv.tv_usec;
1673965be93Schristos add_timeout (&tv, omapi_listener_start, 0, 0, 0);
1683965be93Schristos }
1693965be93Schristos omapi_object_dereference (&listener, MDL);
1703965be93Schristos }
1713965be93Schristos
1723965be93Schristos #ifndef UNIT_TEST
1733965be93Schristos
1743965be93Schristos #define DHCPD_USAGE0 \
1753965be93Schristos "[-p <UDP port #>] [-f] [-d] [-q] [-t|-T]\n"
1763965be93Schristos
1773965be93Schristos #ifdef DHCPv6
1783965be93Schristos #ifdef DHCP4o6
1793965be93Schristos #define DHCPD_USAGE1 \
1803965be93Schristos " [-4|-6] [-4o6 <port>]\n" \
1813965be93Schristos " [-cf config-file] [-lf lease-file]\n"
1823965be93Schristos #else /* DHCP4o6 */
1833965be93Schristos #define DHCPD_USAGE1 \
1843965be93Schristos " [-4|-6] [-cf config-file] [-lf lease-file]\n"
1853965be93Schristos #endif /* DHCP4o6 */
1863965be93Schristos #else /* !DHCPv6 */
1873965be93Schristos #define DHCPD_USAGE1 \
1883965be93Schristos " [-cf config-file] [-lf lease-file]\n"
1893965be93Schristos #endif /* DHCPv6 */
1903965be93Schristos
1913965be93Schristos #if defined (PARANOIA)
1923965be93Schristos #define DHCPD_USAGEP \
1933965be93Schristos " [-user user] [-group group] [-chroot dir]\n"
1943965be93Schristos #else
1953965be93Schristos #define DHCPD_USAGEP ""
1963965be93Schristos #endif /* PARANOIA */
1973965be93Schristos
1983965be93Schristos #if defined (TRACING)
1993965be93Schristos #define DHCPD_USAGET \
2003965be93Schristos " [-tf trace-output-file]\n" \
2013965be93Schristos " [-play trace-input-file]\n"
2023965be93Schristos #else
2033965be93Schristos #define DHCPD_USAGET ""
2043965be93Schristos #endif /* TRACING */
2053965be93Schristos
2063965be93Schristos #define DHCPD_USAGEC \
2073965be93Schristos " [-pf pid-file] [--no-pid] [-s server]\n" \
2083965be93Schristos " [if0 [...ifN]]"
2093965be93Schristos
2103965be93Schristos #define DHCPD_USAGEH "{--version|--help|-h}"
2113965be93Schristos
2123965be93Schristos /*!
2133965be93Schristos *
2143965be93Schristos * \brief Print the generic usage message
2153965be93Schristos *
2163965be93Schristos * If the user has provided an incorrect command line print out
2173965be93Schristos * the description of the command line. The arguments provide
2183965be93Schristos * a way for the caller to request more specific information about
2193965be93Schristos * the error be printed as well. Mostly this will be that some
220*13df4856Schristos * command doesn't include its argument.
2213965be93Schristos *
2223965be93Schristos * \param sfmt - The basic string and format for the specific error
223*13df4856Schristos * \param sarg - Generally the offending argument from the command line.
2243965be93Schristos *
2253965be93Schristos * \return Nothing
2263965be93Schristos */
2273965be93Schristos
2283965be93Schristos #include <sys/cdefs.h>
229*13df4856Schristos __RCSID("$NetBSD: dhcpd.c,v 1.5 2022/04/03 01:10:59 christos Exp $");
2303965be93Schristos static char use_noarg[] = "No argument for command: %s ";
2313965be93Schristos
2323965be93Schristos static void
usage(const char * sfmt,const char * sarg)2333965be93Schristos usage(const char *sfmt, const char *sarg) {
2343965be93Schristos log_info("%s %s", message, PACKAGE_VERSION);
2353965be93Schristos log_info(copyright);
2363965be93Schristos log_info(arr);
2373965be93Schristos log_info(url);
2383965be93Schristos
2393965be93Schristos /* If desired print out the specific error message */
2403965be93Schristos #ifdef PRINT_SPECIFIC_CL_ERRORS
2413965be93Schristos if (sfmt != NULL)
2423965be93Schristos log_error(sfmt, sarg);
2433965be93Schristos #endif
2443965be93Schristos
2453965be93Schristos log_fatal("Usage: %s %s%s%s%s%s\n %s %s",
2463965be93Schristos isc_file_basename(progname),
2473965be93Schristos DHCPD_USAGE0,
2483965be93Schristos DHCPD_USAGE1,
2493965be93Schristos DHCPD_USAGEP,
2503965be93Schristos DHCPD_USAGET,
2513965be93Schristos DHCPD_USAGEC,
2523965be93Schristos isc_file_basename(progname),
2533965be93Schristos DHCPD_USAGEH);
2543965be93Schristos }
2553965be93Schristos
2563965be93Schristos /* Note: If we add unit tests to test setup_chroot it will
2573965be93Schristos * need to be moved to be outside the ifndef UNIT_TEST block.
2583965be93Schristos */
2593965be93Schristos
2603965be93Schristos #if defined (PARANOIA)
2613965be93Schristos /* to be used in one of two possible scenarios */
setup_chroot(char * chroot_dir)2623965be93Schristos static void setup_chroot (char *chroot_dir) {
2633965be93Schristos if (geteuid())
2643965be93Schristos log_fatal ("you must be root to use chroot");
2653965be93Schristos
2663965be93Schristos if (chroot(chroot_dir)) {
2673965be93Schristos log_fatal ("chroot(\"%s\"): %m", chroot_dir);
2683965be93Schristos }
2693965be93Schristos if (chdir ("/")) {
2703965be93Schristos /* probably permission denied */
2713965be93Schristos log_fatal ("chdir(\"/\"): %m");
2723965be93Schristos }
2733965be93Schristos }
2743965be93Schristos #endif /* PARANOIA */
2753965be93Schristos
2763965be93Schristos int
main(int argc,char ** argv)2773965be93Schristos main(int argc, char **argv) {
2783965be93Schristos int fd;
2793965be93Schristos int i, status;
2803965be93Schristos struct servent *ent;
2813965be93Schristos char *s;
2823965be93Schristos int cftest = 0;
2833965be93Schristos int lftest = 0;
2843965be93Schristos int pid;
2853965be93Schristos char pbuf [20];
2863965be93Schristos #ifndef DEBUG
2873965be93Schristos int daemon = 1;
2883965be93Schristos int dfd[2] = { -1, -1 };
2893965be93Schristos #endif
2903965be93Schristos int quiet = 0;
2913965be93Schristos char *server = (char *)0;
2923965be93Schristos isc_result_t result;
2933965be93Schristos unsigned seed;
2943965be93Schristos struct interface_info *ip;
2953965be93Schristos #if defined (NSUPDATE)
2963965be93Schristos struct parse *parse;
2973965be93Schristos int lose;
2983965be93Schristos #endif
2993965be93Schristos int have_dhcpd_conf = 0;
3003965be93Schristos int have_dhcpd_db = 0;
3013965be93Schristos int have_dhcpd_pid = 0;
3023965be93Schristos #ifdef DHCPv6
3033965be93Schristos int local_family_set = 0;
3043965be93Schristos #ifdef DHCP4o6
3053965be93Schristos u_int16_t dhcp4o6_port = 0;
3063965be93Schristos #endif /* DHCP4o6 */
3073965be93Schristos #endif /* DHCPv6 */
3083965be93Schristos #if defined (TRACING)
3093965be93Schristos char *traceinfile = (char *)0;
3103965be93Schristos char *traceoutfile = (char *)0;
3113965be93Schristos #endif
3123965be93Schristos
3133965be93Schristos #if defined (PARANOIA)
3143965be93Schristos char *set_user = 0;
3153965be93Schristos char *set_group = 0;
3163965be93Schristos char *set_chroot = 0;
3173965be93Schristos #endif /* PARANOIA */
3183965be93Schristos
31907146da4Schristos libdhcp_callbacks_register(&dhcpd_callbacks);
32007146da4Schristos
3213965be93Schristos #ifdef OLD_LOG_NAME
3223965be93Schristos progname = "dhcpd";
3233965be93Schristos #else
3243965be93Schristos progname = argv[0];
3253965be93Schristos #endif
3263965be93Schristos
3273965be93Schristos /* Make sure that file descriptors 0 (stdin), 1, (stdout), and
3283965be93Schristos 2 (stderr) are open. To do this, we assume that when we
3293965be93Schristos open a file the lowest available file descriptor is used. */
3303965be93Schristos fd = open("/dev/null", O_RDWR);
3313965be93Schristos if (fd == 0)
3323965be93Schristos fd = open("/dev/null", O_RDWR);
3333965be93Schristos if (fd == 1)
3343965be93Schristos fd = open("/dev/null", O_RDWR);
3353965be93Schristos if (fd == 2)
3363965be93Schristos log_perror = 0; /* No sense logging to /dev/null. */
3373965be93Schristos else if (fd != -1)
3383965be93Schristos close(fd);
3393965be93Schristos
3403965be93Schristos /* Parse arguments changing daemon */
3413965be93Schristos for (i = 1; i < argc; i++) {
3423965be93Schristos if (!strcmp (argv [i], "-f")) {
3433965be93Schristos #ifndef DEBUG
3443965be93Schristos daemon = 0;
3453965be93Schristos #endif
3463965be93Schristos } else if (!strcmp (argv [i], "-d")) {
3473965be93Schristos #ifndef DEBUG
3483965be93Schristos daemon = 0;
3493965be93Schristos #endif
3503965be93Schristos } else if (!strcmp (argv [i], "-t")) {
3513965be93Schristos #ifndef DEBUG
3523965be93Schristos daemon = 0;
3533965be93Schristos #endif
3543965be93Schristos } else if (!strcmp (argv [i], "-T")) {
3553965be93Schristos #ifndef DEBUG
3563965be93Schristos daemon = 0;
3573965be93Schristos #endif
3583965be93Schristos } else if (!strcmp (argv [i], "--version")) {
3593965be93Schristos const char vstring[] = "isc-dhcpd-";
3603965be93Schristos IGNORE_RET(write(STDERR_FILENO, vstring,
3613965be93Schristos strlen(vstring)));
3623965be93Schristos IGNORE_RET(write(STDERR_FILENO,
3633965be93Schristos PACKAGE_VERSION,
3643965be93Schristos strlen(PACKAGE_VERSION)));
3653965be93Schristos IGNORE_RET(write(STDERR_FILENO, "\n", 1));
3663965be93Schristos exit (0);
3673965be93Schristos } else if (!strcmp(argv[i], "--help") ||
3683965be93Schristos !strcmp(argv[i], "-h")) {
3693965be93Schristos const char *pname = isc_file_basename(progname);
3703965be93Schristos IGNORE_RET(write(STDERR_FILENO, "Usage: ", 7));
3713965be93Schristos IGNORE_RET(write(STDERR_FILENO, pname, strlen(pname)));
3723965be93Schristos IGNORE_RET(write(STDERR_FILENO, " ", 1));
3733965be93Schristos IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGE0,
3743965be93Schristos strlen(DHCPD_USAGE0)));
3753965be93Schristos IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGE1,
3763965be93Schristos strlen(DHCPD_USAGE1)));
3773965be93Schristos #if defined (PARANOIA)
3783965be93Schristos IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGEP,
3793965be93Schristos strlen(DHCPD_USAGEP)));
3803965be93Schristos #endif
3813965be93Schristos #if defined (TRACING)
3823965be93Schristos IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGET,
3833965be93Schristos strlen(DHCPD_USAGET)));
3843965be93Schristos #endif
3853965be93Schristos IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGEC,
3863965be93Schristos strlen(DHCPD_USAGEC)));
3873965be93Schristos IGNORE_RET(write(STDERR_FILENO, "\n", 1));
3883965be93Schristos IGNORE_RET(write(STDERR_FILENO, " ", 7));
3893965be93Schristos IGNORE_RET(write(STDERR_FILENO, pname, strlen(pname)));
3903965be93Schristos IGNORE_RET(write(STDERR_FILENO, " ", 1));
3913965be93Schristos IGNORE_RET(write(STDERR_FILENO, DHCPD_USAGEH,
3923965be93Schristos strlen(DHCPD_USAGEH)));
3933965be93Schristos IGNORE_RET(write(STDERR_FILENO, "\n", 1));
3943965be93Schristos exit(0);
3953965be93Schristos #ifdef TRACING
3963965be93Schristos } else if (!strcmp (argv [i], "-play")) {
3973965be93Schristos #ifndef DEBUG
3983965be93Schristos daemon = 0;
3993965be93Schristos #endif
4003965be93Schristos #endif
4013965be93Schristos }
4023965be93Schristos }
4033965be93Schristos
4043965be93Schristos #ifndef DEBUG
4053965be93Schristos /* When not forbidden prepare to become a daemon */
4063965be93Schristos if (daemon) {
4073965be93Schristos if (pipe(dfd) == -1)
4083965be93Schristos log_fatal("Can't get pipe: %m");
4093965be93Schristos if ((pid = fork ()) < 0)
4103965be93Schristos log_fatal("Can't fork daemon: %m");
4113965be93Schristos if (pid != 0) {
4123965be93Schristos /* Parent: wait for the child to start */
4133965be93Schristos int n;
4143965be93Schristos
4153965be93Schristos (void) close(dfd[1]);
4163965be93Schristos do {
4173965be93Schristos char buf;
4183965be93Schristos
4193965be93Schristos n = read(dfd[0], &buf, 1);
4203965be93Schristos if (n == 1)
4213965be93Schristos _exit((int)buf);
4223965be93Schristos } while (n == -1 && errno == EINTR);
4233965be93Schristos _exit(1);
4243965be93Schristos }
4253965be93Schristos /* Child */
4263965be93Schristos (void) close(dfd[0]);
4273965be93Schristos }
4283965be93Schristos #endif
4293965be93Schristos
4303965be93Schristos /* Set up the isc and dns library managers */
4313965be93Schristos status = dhcp_context_create(DHCP_CONTEXT_PRE_DB,
4323965be93Schristos NULL, NULL);
4333965be93Schristos if (status != ISC_R_SUCCESS)
4343965be93Schristos log_fatal("Can't initialize context: %s",
4353965be93Schristos isc_result_totext(status));
4363965be93Schristos
4373965be93Schristos /* Set up the client classification system. */
4383965be93Schristos classification_setup ();
4393965be93Schristos
4403965be93Schristos /* Initialize the omapi system. */
4413965be93Schristos result = omapi_init ();
4423965be93Schristos if (result != ISC_R_SUCCESS)
4433965be93Schristos log_fatal ("Can't initialize OMAPI: %s",
4443965be93Schristos isc_result_totext (result));
4453965be93Schristos
4463965be93Schristos /* Set up the OMAPI wrappers for common objects. */
4473965be93Schristos dhcp_db_objects_setup ();
4483965be93Schristos /* Set up the OMAPI wrappers for various server database internal
4493965be93Schristos objects. */
4503965be93Schristos dhcp_common_objects_setup ();
4513965be93Schristos
4523965be93Schristos /* Initially, log errors to stderr as well as to syslogd. */
4533965be93Schristos openlog (isc_file_basename(progname),
4543965be93Schristos DHCP_LOG_OPTIONS, DHCPD_LOG_FACILITY);
4553965be93Schristos
4563965be93Schristos for (i = 1; i < argc; i++) {
4573965be93Schristos if (!strcmp (argv [i], "-p")) {
4583965be93Schristos if (++i == argc)
4593965be93Schristos usage(use_noarg, argv[i-1]);
4603965be93Schristos local_port = validate_port (argv [i]);
4613965be93Schristos log_debug ("binding to user-specified port %d",
4623965be93Schristos ntohs (local_port));
4633965be93Schristos } else if (!strcmp (argv [i], "-f")) {
4643965be93Schristos #ifndef DEBUG
4653965be93Schristos /* daemon = 0; */
4663965be93Schristos #endif
4673965be93Schristos } else if (!strcmp (argv [i], "-d")) {
4683965be93Schristos #ifndef DEBUG
4693965be93Schristos /* daemon = 0; */
4703965be93Schristos #endif
4713965be93Schristos log_perror = -1;
4723965be93Schristos } else if (!strcmp (argv [i], "-s")) {
4733965be93Schristos if (++i == argc)
4743965be93Schristos usage(use_noarg, argv[i-1]);
4753965be93Schristos server = argv [i];
4763965be93Schristos #if defined (PARANOIA)
4773965be93Schristos } else if (!strcmp (argv [i], "-user")) {
4783965be93Schristos if (++i == argc)
4793965be93Schristos usage(use_noarg, argv[i-1]);
4803965be93Schristos set_user = argv [i];
4813965be93Schristos } else if (!strcmp (argv [i], "-group")) {
4823965be93Schristos if (++i == argc)
4833965be93Schristos usage(use_noarg, argv[i-1]);
4843965be93Schristos set_group = argv [i];
4853965be93Schristos } else if (!strcmp (argv [i], "-chroot")) {
4863965be93Schristos if (++i == argc)
4873965be93Schristos usage(use_noarg, argv[i-1]);
4883965be93Schristos set_chroot = argv [i];
4893965be93Schristos #endif /* PARANOIA */
4903965be93Schristos } else if (!strcmp (argv [i], "-cf")) {
4913965be93Schristos if (++i == argc)
4923965be93Schristos usage(use_noarg, argv[i-1]);
4933965be93Schristos path_dhcpd_conf = argv [i];
4943965be93Schristos have_dhcpd_conf = 1;
4953965be93Schristos } else if (!strcmp (argv [i], "-lf")) {
4963965be93Schristos if (++i == argc)
4973965be93Schristos usage(use_noarg, argv[i-1]);
4983965be93Schristos path_dhcpd_db = argv [i];
4993965be93Schristos have_dhcpd_db = 1;
5003965be93Schristos } else if (!strcmp (argv [i], "-pf")) {
5013965be93Schristos if (++i == argc)
5023965be93Schristos usage(use_noarg, argv[i-1]);
5033965be93Schristos path_dhcpd_pid = argv [i];
5043965be93Schristos have_dhcpd_pid = 1;
5053965be93Schristos } else if (!strcmp(argv[i], "--no-pid")) {
5063965be93Schristos no_pid_file = ISC_TRUE;
5073965be93Schristos } else if (!strcmp (argv [i], "-t")) {
5083965be93Schristos /* test configurations only */
5093965be93Schristos #ifndef DEBUG
5103965be93Schristos /* daemon = 0; */
5113965be93Schristos #endif
5123965be93Schristos cftest = 1;
5133965be93Schristos log_perror = -1;
5143965be93Schristos } else if (!strcmp (argv [i], "-T")) {
5153965be93Schristos /* test configurations and lease file only */
5163965be93Schristos #ifndef DEBUG
5173965be93Schristos /* daemon = 0; */
5183965be93Schristos #endif
5193965be93Schristos cftest = 1;
5203965be93Schristos lftest = 1;
5213965be93Schristos log_perror = -1;
5223965be93Schristos } else if (!strcmp (argv [i], "-q")) {
5233965be93Schristos quiet = 1;
5243965be93Schristos quiet_interface_discovery = 1;
5253965be93Schristos #ifdef DHCPv6
5263965be93Schristos } else if (!strcmp(argv[i], "-4")) {
5273965be93Schristos if (local_family_set && (local_family != AF_INET)) {
5283965be93Schristos log_fatal("Server cannot run in both IPv4 and "
5293965be93Schristos "IPv6 mode at the same time.");
5303965be93Schristos }
5313965be93Schristos local_family = AF_INET;
5323965be93Schristos local_family_set = 1;
5333965be93Schristos } else if (!strcmp(argv[i], "-6")) {
5343965be93Schristos if (local_family_set && (local_family != AF_INET6)) {
5353965be93Schristos log_fatal("Server cannot run in both IPv4 and "
5363965be93Schristos "IPv6 mode at the same time.");
5373965be93Schristos }
5383965be93Schristos local_family = AF_INET6;
5393965be93Schristos local_family_set = 1;
5403965be93Schristos #ifdef DHCP4o6
5413965be93Schristos } else if (!strcmp(argv[i], "-4o6")) {
5423965be93Schristos if (++i == argc)
5433965be93Schristos usage(use_noarg, argv[i-1]);
5443965be93Schristos dhcp4o6_port = validate_port_pair(argv[i]);
5453965be93Schristos
5463965be93Schristos log_debug("DHCPv4 over DHCPv6 over ::1 port %d and %d",
5473965be93Schristos ntohs(dhcp4o6_port),
5483965be93Schristos ntohs(dhcp4o6_port) + 1);
5493965be93Schristos dhcpv4_over_dhcpv6 = 1;
5503965be93Schristos #endif /* DHCP4o6 */
5513965be93Schristos #endif /* DHCPv6 */
5523965be93Schristos #if defined (TRACING)
5533965be93Schristos } else if (!strcmp (argv [i], "-tf")) {
5543965be93Schristos if (++i == argc)
5553965be93Schristos usage(use_noarg, argv[i-1]);
5563965be93Schristos traceoutfile = argv [i];
5573965be93Schristos } else if (!strcmp (argv [i], "-play")) {
5583965be93Schristos if (++i == argc)
5593965be93Schristos usage(use_noarg, argv[i-1]);
5603965be93Schristos traceinfile = argv [i];
5613965be93Schristos trace_replay_init ();
5623965be93Schristos #endif /* TRACING */
5633965be93Schristos } else if (argv [i][0] == '-') {
5643965be93Schristos usage("Unknown command %s", argv[i]);
5653965be93Schristos } else {
5663965be93Schristos struct interface_info *tmp =
5673965be93Schristos (struct interface_info *)0;
5683965be93Schristos if (strlen(argv[i]) >= sizeof(tmp->name))
5693965be93Schristos log_fatal("%s: interface name too long "
5703965be93Schristos "(is %ld)",
5713965be93Schristos argv[i], (long)strlen(argv[i]));
5723965be93Schristos result = interface_allocate (&tmp, MDL);
5733965be93Schristos if (result != ISC_R_SUCCESS)
5743965be93Schristos log_fatal ("Insufficient memory to %s %s: %s",
5753965be93Schristos "record interface", argv [i],
5763965be93Schristos isc_result_totext (result));
5773965be93Schristos strcpy (tmp -> name, argv [i]);
5783965be93Schristos if (interfaces) {
5793965be93Schristos interface_reference (&tmp -> next,
5803965be93Schristos interfaces, MDL);
5813965be93Schristos interface_dereference (&interfaces, MDL);
5823965be93Schristos }
5833965be93Schristos interface_reference (&interfaces, tmp, MDL);
5843965be93Schristos tmp -> flags = INTERFACE_REQUESTED;
5853965be93Schristos }
5863965be93Schristos }
5873965be93Schristos
5883965be93Schristos #if defined(DHCPv6) && defined(DHCP4o6)
5893965be93Schristos if (dhcpv4_over_dhcpv6) {
5903965be93Schristos if (!local_family_set)
5913965be93Schristos log_error("please specify the address family "
5923965be93Schristos "with DHPv4 over DHCPv6 [-4|-6].");
5933965be93Schristos if ((local_family == AF_INET) && (interfaces != NULL))
5943965be93Schristos log_fatal("DHCPv4 server in DHPv4 over DHCPv6 "
5953965be93Schristos "mode with command line specified "
5963965be93Schristos "interfaces.");
5973965be93Schristos }
5983965be93Schristos #endif /* DHCPv6 && DHCP4o6 */
5993965be93Schristos
6003965be93Schristos if (!have_dhcpd_conf && (s = getenv ("PATH_DHCPD_CONF"))) {
6013965be93Schristos path_dhcpd_conf = s;
6023965be93Schristos }
6033965be93Schristos
6043965be93Schristos #ifdef DHCPv6
6053965be93Schristos if (local_family == AF_INET6) {
6063965be93Schristos /* DHCPv6: override DHCPv4 lease and pid filenames */
6073965be93Schristos if (!have_dhcpd_db) {
6083965be93Schristos if ((s = getenv ("PATH_DHCPD6_DB")))
6093965be93Schristos path_dhcpd_db = s;
6103965be93Schristos else
6113965be93Schristos path_dhcpd_db = _PATH_DHCPD6_DB;
6123965be93Schristos }
6133965be93Schristos if (!have_dhcpd_pid) {
6143965be93Schristos if ((s = getenv ("PATH_DHCPD6_PID")))
6153965be93Schristos path_dhcpd_pid = s;
6163965be93Schristos else
6173965be93Schristos path_dhcpd_pid = _PATH_DHCPD6_PID;
6183965be93Schristos }
6193965be93Schristos } else
6203965be93Schristos #endif /* DHCPv6 */
6213965be93Schristos {
6223965be93Schristos if (!have_dhcpd_db && (s = getenv ("PATH_DHCPD_DB"))) {
6233965be93Schristos path_dhcpd_db = s;
6243965be93Schristos have_dhcpd_db = 1;
6253965be93Schristos }
6263965be93Schristos if (!have_dhcpd_pid && (s = getenv ("PATH_DHCPD_PID"))) {
6273965be93Schristos path_dhcpd_pid = s;
6283965be93Schristos have_dhcpd_pid = 1;
6293965be93Schristos }
6303965be93Schristos }
6313965be93Schristos
6323965be93Schristos /*
6333965be93Schristos * convert relative path names to absolute, for files that need
6343965be93Schristos * to be reopened after chdir() has been called
6353965be93Schristos */
6363965be93Schristos if (have_dhcpd_db && path_dhcpd_db[0] != '/') {
6373965be93Schristos path_dhcpd_db = absolute_path(path_dhcpd_db);
6383965be93Schristos }
6393965be93Schristos
6403965be93Schristos if (!quiet) {
6413965be93Schristos log_info("%s %s", message, PACKAGE_VERSION);
6423965be93Schristos log_info (copyright);
6433965be93Schristos log_info (arr);
6443965be93Schristos log_info (url);
6453965be93Schristos } else {
6463965be93Schristos log_perror = 0;
6473965be93Schristos }
6483965be93Schristos
64907146da4Schristos #ifndef DEBUG
65007146da4Schristos /*
65107146da4Schristos * We need to fork before we call the context create
65207146da4Schristos * call that creates the worker threads!
65307146da4Schristos */
65407146da4Schristos if (daemon) {
65507146da4Schristos /* First part of becoming a daemon... */
65607146da4Schristos if ((pid = fork ()) < 0)
65707146da4Schristos log_fatal ("Can't fork daemon: %m");
65807146da4Schristos else if (pid)
65907146da4Schristos exit (0);
66007146da4Schristos }
66107146da4Schristos #endif
66207146da4Schristos
66307146da4Schristos /* Set up the isc and dns library managers */
66407146da4Schristos status = dhcp_context_create(DHCP_CONTEXT_PRE_DB, NULL, NULL);
66507146da4Schristos if (status != ISC_R_SUCCESS)
66607146da4Schristos log_fatal("Can't initialize context: %s",
66707146da4Schristos isc_result_totext(status));
66807146da4Schristos
66907146da4Schristos /* Set up the client classification system. */
67007146da4Schristos classification_setup ();
67107146da4Schristos
6723965be93Schristos #if defined (TRACING)
6733965be93Schristos trace_init (set_time, MDL);
6743965be93Schristos if (traceoutfile) {
6753965be93Schristos result = trace_begin (traceoutfile, MDL);
6763965be93Schristos if (result != ISC_R_SUCCESS)
6773965be93Schristos log_fatal ("Unable to begin trace: %s",
6783965be93Schristos isc_result_totext (result));
6793965be93Schristos }
6803965be93Schristos interface_trace_setup ();
6813965be93Schristos parse_trace_setup ();
6823965be93Schristos trace_srandom = trace_type_register ("random-seed", (void *)0,
6833965be93Schristos trace_seed_input,
6843965be93Schristos trace_seed_stop, MDL);
6853965be93Schristos #if defined (NSUPDATE)
6863965be93Schristos trace_ddns_init();
6873965be93Schristos #endif /* NSUPDATE */
6883965be93Schristos #endif
6893965be93Schristos
6903965be93Schristos #if defined (PARANOIA)
6913965be93Schristos /* get user and group info if those options were given */
6923965be93Schristos if (set_user) {
6933965be93Schristos struct passwd *tmp_pwd;
6943965be93Schristos
6953965be93Schristos if (geteuid())
6963965be93Schristos log_fatal ("you must be root to set user");
6973965be93Schristos
6983965be93Schristos if (!(tmp_pwd = getpwnam(set_user)))
6993965be93Schristos log_fatal ("no such user: %s", set_user);
7003965be93Schristos
7013965be93Schristos set_uid = tmp_pwd->pw_uid;
7023965be93Schristos
7033965be93Schristos /* use the user's group as the default gid */
7043965be93Schristos if (!set_group)
7053965be93Schristos set_gid = tmp_pwd->pw_gid;
7063965be93Schristos }
7073965be93Schristos
7083965be93Schristos if (set_group) {
7093965be93Schristos /* get around the ISC declaration of group */
7103965be93Schristos #define group real_group
7113965be93Schristos struct group *tmp_grp;
7123965be93Schristos
7133965be93Schristos if (geteuid())
7143965be93Schristos log_fatal ("you must be root to set group");
7153965be93Schristos
7163965be93Schristos if (!(tmp_grp = getgrnam(set_group)))
7173965be93Schristos log_fatal ("no such group: %s", set_group);
7183965be93Schristos
7193965be93Schristos set_gid = tmp_grp->gr_gid;
7203965be93Schristos #undef group
7213965be93Schristos }
7223965be93Schristos
7233965be93Schristos # if defined (EARLY_CHROOT)
7243965be93Schristos if (set_chroot) setup_chroot (set_chroot);
7253965be93Schristos # endif /* EARLY_CHROOT */
7263965be93Schristos #endif /* PARANOIA */
7273965be93Schristos
7283965be93Schristos /* Default to the DHCP/BOOTP port. */
7293965be93Schristos if (!local_port)
7303965be93Schristos {
7313965be93Schristos if ((s = getenv ("DHCPD_PORT"))) {
7323965be93Schristos local_port = validate_port (s);
7333965be93Schristos log_debug ("binding to environment-specified port %d",
7343965be93Schristos ntohs (local_port));
7353965be93Schristos } else {
7363965be93Schristos if (local_family == AF_INET) {
7373965be93Schristos ent = getservbyname("dhcp", "udp");
7383965be93Schristos if (ent == NULL) {
7393965be93Schristos local_port = htons(67);
7403965be93Schristos } else {
7413965be93Schristos local_port = ent->s_port;
7423965be93Schristos }
7433965be93Schristos } else {
7443965be93Schristos /* INSIST(local_family == AF_INET6); */
7453965be93Schristos ent = getservbyname("dhcpv6-server", "udp");
7463965be93Schristos if (ent == NULL) {
7473965be93Schristos local_port = htons(547);
7483965be93Schristos } else {
7493965be93Schristos local_port = ent->s_port;
7503965be93Schristos }
7513965be93Schristos }
7523965be93Schristos #ifndef __CYGWIN32__ /* XXX */
7533965be93Schristos endservent ();
7543965be93Schristos #endif
7553965be93Schristos }
7563965be93Schristos }
7573965be93Schristos
7583965be93Schristos if (local_family == AF_INET) {
7593965be93Schristos remote_port = htons(ntohs(local_port) + 1);
7603965be93Schristos } else {
7613965be93Schristos /* INSIST(local_family == AF_INET6); */
7623965be93Schristos ent = getservbyname("dhcpv6-client", "udp");
7633965be93Schristos if (ent == NULL) {
7643965be93Schristos remote_port = htons(546);
7653965be93Schristos } else {
7663965be93Schristos remote_port = ent->s_port;
7673965be93Schristos }
7683965be93Schristos }
7693965be93Schristos
7703965be93Schristos if (server) {
7713965be93Schristos if (local_family != AF_INET) {
7723965be93Schristos log_fatal("You can only specify address to send "
7733965be93Schristos "replies to when running an IPv4 server.");
7743965be93Schristos }
7753965be93Schristos if (!inet_aton (server, &limited_broadcast)) {
7763965be93Schristos struct hostent *he;
7773965be93Schristos he = gethostbyname (server);
7783965be93Schristos if (he) {
7793965be93Schristos memcpy (&limited_broadcast,
7803965be93Schristos he -> h_addr_list [0],
7813965be93Schristos sizeof limited_broadcast);
7823965be93Schristos } else
7833965be93Schristos limited_broadcast.s_addr = INADDR_BROADCAST;
7843965be93Schristos }
7853965be93Schristos } else {
7863965be93Schristos limited_broadcast.s_addr = INADDR_BROADCAST;
7873965be93Schristos }
7883965be93Schristos
7893965be93Schristos /* Get the current time... */
7903965be93Schristos gettimeofday(&cur_tv, NULL);
7913965be93Schristos
7923965be93Schristos /* Set up the initial dhcp option universe. */
7933965be93Schristos initialize_common_option_spaces ();
7943965be93Schristos initialize_server_option_spaces ();
7953965be93Schristos
7963965be93Schristos /* Add the ddns update style enumeration prior to parsing. */
7973965be93Schristos add_enumeration (&ddns_styles);
7983965be93Schristos add_enumeration (&syslog_enum);
7993965be93Schristos #if defined (LDAP_CONFIGURATION)
8003965be93Schristos add_enumeration (&ldap_methods);
8013965be93Schristos #if defined (LDAP_USE_SSL)
8023965be93Schristos add_enumeration (&ldap_ssl_usage_enum);
8033965be93Schristos add_enumeration (&ldap_tls_reqcert_enum);
8043965be93Schristos add_enumeration (&ldap_tls_crlcheck_enum);
8053965be93Schristos #endif
8063965be93Schristos #endif
8073965be93Schristos
8083965be93Schristos if (!group_allocate (&root_group, MDL))
8093965be93Schristos log_fatal ("Can't allocate root group!");
8103965be93Schristos root_group -> authoritative = 0;
8113965be93Schristos
8123965be93Schristos /* Set up various hooks. */
8133965be93Schristos dhcp_interface_setup_hook = dhcpd_interface_setup_hook;
8143965be93Schristos bootp_packet_handler = do_packet;
8153965be93Schristos #ifdef DHCPv6
8163965be93Schristos add_enumeration (&prefix_length_modes);
8173965be93Schristos dhcpv6_packet_handler = do_packet6;
8183965be93Schristos #endif /* DHCPv6 */
8193965be93Schristos
8203965be93Schristos #if defined (NSUPDATE)
8213965be93Schristos /* Set up the standard name service updater routine. */
8223965be93Schristos parse = NULL;
8233965be93Schristos status = new_parse(&parse, -1, std_nsupdate, sizeof(std_nsupdate) - 1,
8243965be93Schristos "standard name service update routine", 0);
8253965be93Schristos if (status != ISC_R_SUCCESS)
8263965be93Schristos log_fatal ("can't begin parsing name service updater!");
8273965be93Schristos
8283965be93Schristos if (parse != NULL) {
8293965be93Schristos lose = 0;
8303965be93Schristos if (!(parse_executable_statements(&root_group->statements,
8313965be93Schristos parse, &lose, context_any))) {
8323965be93Schristos end_parse(&parse);
8333965be93Schristos log_fatal("can't parse standard name service updater!");
8343965be93Schristos }
8353965be93Schristos end_parse(&parse);
8363965be93Schristos }
8373965be93Schristos #endif
8383965be93Schristos
8393965be93Schristos /* Initialize icmp support... */
8403965be93Schristos if (!cftest && !lftest)
8413965be93Schristos icmp_startup (1, lease_pinged);
8423965be93Schristos
8433965be93Schristos #if defined (TRACING)
8443965be93Schristos if (traceinfile) {
8453965be93Schristos if (!have_dhcpd_db) {
8463965be93Schristos log_error ("%s", "");
8473965be93Schristos log_error ("** You must specify a lease file with -lf.");
8483965be93Schristos log_error (" Dhcpd will not overwrite your default");
8493965be93Schristos log_fatal (" lease file when playing back a trace. **");
8503965be93Schristos }
8513965be93Schristos trace_file_replay (traceinfile);
8523965be93Schristos
8533965be93Schristos #if defined (DEBUG_MEMORY_LEAKAGE) && \
8543965be93Schristos defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
8553965be93Schristos free_everything ();
8563965be93Schristos omapi_print_dmalloc_usage_by_caller ();
8573965be93Schristos #endif
8583965be93Schristos
8593965be93Schristos exit (0);
8603965be93Schristos }
8613965be93Schristos #endif
8623965be93Schristos
8633965be93Schristos #ifdef DHCPv6
8643965be93Schristos /* set up DHCPv6 hashes */
8653965be93Schristos if (!ia_new_hash(&ia_na_active, DEFAULT_HASH_SIZE, MDL)) {
8663965be93Schristos log_fatal("Out of memory creating hash for active IA_NA.");
8673965be93Schristos }
8683965be93Schristos if (!ia_new_hash(&ia_ta_active, DEFAULT_HASH_SIZE, MDL)) {
8693965be93Schristos log_fatal("Out of memory creating hash for active IA_TA.");
8703965be93Schristos }
8713965be93Schristos if (!ia_new_hash(&ia_pd_active, DEFAULT_HASH_SIZE, MDL)) {
8723965be93Schristos log_fatal("Out of memory creating hash for active IA_PD.");
8733965be93Schristos }
8743965be93Schristos #endif /* DHCPv6 */
8753965be93Schristos
8763965be93Schristos /* Read the dhcpd.conf file... */
8773965be93Schristos if (readconf () != ISC_R_SUCCESS)
8783965be93Schristos log_fatal ("Configuration file errors encountered -- exiting");
8793965be93Schristos
8803965be93Schristos postconf_initialization (quiet);
8813965be93Schristos
8823965be93Schristos #if defined (FAILOVER_PROTOCOL)
8833965be93Schristos dhcp_failover_sanity_check();
8843965be93Schristos #endif
8853965be93Schristos
8863965be93Schristos #if defined(DHCPv6) && defined(DHCP4o6)
8873965be93Schristos if (dhcpv4_over_dhcpv6) {
8883965be93Schristos if ((local_family == AF_INET) && (interfaces != NULL))
8893965be93Schristos log_fatal("DHCPv4 server in DHPv4 over DHCPv6 "
8903965be93Schristos "mode with config file specified "
8913965be93Schristos "interfaces.");
8923965be93Schristos }
8933965be93Schristos #endif /* DHCPv6 && DHCP4o6 */
8943965be93Schristos
8953965be93Schristos #if defined (PARANOIA) && !defined (EARLY_CHROOT)
8963965be93Schristos if (set_chroot) setup_chroot (set_chroot);
8973965be93Schristos #endif /* PARANOIA && !EARLY_CHROOT */
8983965be93Schristos
8993965be93Schristos #ifdef DHCPv6
9003965be93Schristos /* log info about ipv6_ponds with large address ranges */
9013965be93Schristos report_jumbo_ranges();
9023965be93Schristos #endif
9033965be93Schristos
9043965be93Schristos /* test option should cause an early exit */
9053965be93Schristos if (cftest && !lftest) {
9063965be93Schristos exit(0);
9073965be93Schristos }
9083965be93Schristos
9093965be93Schristos /*
9103965be93Schristos * First part of dealing with pid files. Check to see if
9113965be93Schristos * we should continue running or not. We run if:
9123965be93Schristos * - we are testing the lease file out
9133965be93Schristos * - we don't have a pid file to check
9143965be93Schristos * - there is no other process running
9153965be93Schristos */
9163965be93Schristos if ((lftest == 0) && (no_pid_file == ISC_FALSE)) {
9173965be93Schristos /*Read previous pid file. */
9183965be93Schristos if ((i = open(path_dhcpd_pid, O_RDONLY)) >= 0) {
9193965be93Schristos status = read(i, pbuf, (sizeof pbuf) - 1);
9203965be93Schristos close(i);
9213965be93Schristos if (status > 0) {
9223965be93Schristos pbuf[status] = 0;
9233965be93Schristos pid = atoi(pbuf);
9243965be93Schristos
9253965be93Schristos /*
9263965be93Schristos * If there was a previous server process and
9273965be93Schristos * it is still running, abort
9283965be93Schristos */
9293965be93Schristos if (!pid ||
9303965be93Schristos (pid != getpid() && kill(pid, 0) == 0))
9313965be93Schristos log_fatal("There's already a "
9323965be93Schristos "DHCP server running.");
9333965be93Schristos }
9343965be93Schristos }
9353965be93Schristos }
9363965be93Schristos
9373965be93Schristos group_write_hook = group_writer;
9383965be93Schristos
9393965be93Schristos /* Start up the database... */
9403965be93Schristos db_startup (lftest);
9413965be93Schristos
9423965be93Schristos if (lftest)
9433965be93Schristos exit (0);
9443965be93Schristos
9453965be93Schristos /* Discover all the network interfaces and initialize them. */
9463965be93Schristos #if defined(DHCPv6) && defined(DHCP4o6)
9473965be93Schristos if (dhcpv4_over_dhcpv6) {
9483965be93Schristos int real_family = local_family;
9493965be93Schristos local_family = AF_INET6;
9503965be93Schristos /* The DHCPv4 side of DHCPv4-over-DHCPv6 service
9513965be93Schristos uses a specific discovery which doesn't register
9523965be93Schristos DHCPv6 sockets. */
9533965be93Schristos if (real_family == AF_INET)
9543965be93Schristos discover_interfaces(DISCOVER_SERVER46);
9553965be93Schristos else
9563965be93Schristos discover_interfaces(DISCOVER_SERVER);
9573965be93Schristos local_family = real_family;
9583965be93Schristos } else
9593965be93Schristos #endif /* DHCPv6 && DHCP4o6 */
9603965be93Schristos discover_interfaces(DISCOVER_SERVER);
9613965be93Schristos
9623965be93Schristos #ifdef DHCPv6
9633965be93Schristos /*
9643965be93Schristos * Remove addresses from our pools that we should not issue
9653965be93Schristos * to clients.
9663965be93Schristos *
9673965be93Schristos * We currently have no support for this in IPv4. It is not
9683965be93Schristos * as important in IPv4, as making pools with ranges that
9693965be93Schristos * leave out interfaces and hosts is fairly straightforward
9703965be93Schristos * using range notation, but not so handy with CIDR notation.
9713965be93Schristos */
9723965be93Schristos if (local_family == AF_INET6) {
9733965be93Schristos mark_hosts_unavailable();
9743965be93Schristos mark_phosts_unavailable();
9753965be93Schristos mark_interfaces_unavailable();
9763965be93Schristos }
9773965be93Schristos #endif /* DHCPv6 */
9783965be93Schristos
9793965be93Schristos /* Make up a seed for the random number generator from current
9803965be93Schristos time plus the sum of the last four bytes of each
9813965be93Schristos interface's hardware address interpreted as an integer.
9823965be93Schristos Not much entropy, but we're booting, so we're not likely to
9833965be93Schristos find anything better. */
9843965be93Schristos seed = 0;
9853965be93Schristos for (ip = interfaces; ip; ip = ip -> next) {
9863965be93Schristos int junk;
9873965be93Schristos memcpy (&junk,
9883965be93Schristos &ip -> hw_address.hbuf [ip -> hw_address.hlen -
9893965be93Schristos sizeof seed], sizeof seed);
9903965be93Schristos seed += junk;
9913965be93Schristos }
9923965be93Schristos srandom (seed + cur_time);
9933965be93Schristos #if defined (TRACING)
9943965be93Schristos trace_seed_stash (trace_srandom, seed + cur_time);
9953965be93Schristos #endif
9963965be93Schristos postdb_startup ();
9973965be93Schristos
9983965be93Schristos #ifdef DHCPv6
9993965be93Schristos /*
10003965be93Schristos * Set server DHCPv6 identifier - we go in order:
10013965be93Schristos * dhcp6.server-id in the config file
10023965be93Schristos * server-duid from the lease file
10033965be93Schristos * server-duid from the config file (the config file is read first
10043965be93Schristos * and the lease file overwrites the config file information)
10053965be93Schristos * generate a new one from the interface hardware addresses.
10063965be93Schristos * In all cases we write it out to the lease file.
10073965be93Schristos * See dhcpv6.c for discussion of setting DUID.
10083965be93Schristos */
10093965be93Schristos if ((set_server_duid_from_option() != ISC_R_SUCCESS) &&
10103965be93Schristos (!server_duid_isset()) &&
10113965be93Schristos (generate_new_server_duid() != ISC_R_SUCCESS)) {
10123965be93Schristos log_fatal("Unable to set server identifier.");
10133965be93Schristos }
10143965be93Schristos write_server_duid();
10153965be93Schristos #ifdef DHCP4o6
10163965be93Schristos if (dhcpv4_over_dhcpv6)
10173965be93Schristos dhcp4o6_setup(dhcp4o6_port);
10183965be93Schristos #endif /* DHCP4o6 */
10193965be93Schristos #endif /* DHCPv6 */
10203965be93Schristos
10213965be93Schristos #ifndef DEBUG
10223965be93Schristos /*
10233965be93Schristos * Second part of dealing with pid files. Now
10243965be93Schristos * that we have forked we can write our pid if
10253965be93Schristos * appropriate.
10263965be93Schristos */
10273965be93Schristos if (no_pid_file == ISC_FALSE) {
10283965be93Schristos i = open(path_dhcpd_pid, O_WRONLY|O_CREAT|O_TRUNC, 0644);
10293965be93Schristos if (i >= 0) {
10303965be93Schristos sprintf(pbuf, "%d\n", (int) getpid());
10313965be93Schristos IGNORE_RET(write(i, pbuf, strlen(pbuf)));
10323965be93Schristos close(i);
10333965be93Schristos } else {
10343965be93Schristos log_error("Can't create PID file %s: %m.",
10353965be93Schristos path_dhcpd_pid);
10363965be93Schristos }
10373965be93Schristos }
10383965be93Schristos
10393965be93Schristos #if defined (PARANOIA)
10403965be93Schristos /* change uid to the specified one */
10413965be93Schristos
10423965be93Schristos if (set_gid) {
10433965be93Schristos if (setgroups (0, (void *)0))
10443965be93Schristos log_fatal ("setgroups: %m");
10453965be93Schristos if (setgid (set_gid))
10463965be93Schristos log_fatal ("setgid(%d): %m", (int) set_gid);
10473965be93Schristos }
10483965be93Schristos
10493965be93Schristos if (set_uid) {
10503965be93Schristos if (setuid (set_uid))
10513965be93Schristos log_fatal ("setuid(%d): %m", (int) set_uid);
10523965be93Schristos }
10533965be93Schristos #endif /* PARANOIA */
10543965be93Schristos
10553965be93Schristos /* If we were requested to log to stdout on the command line,
10563965be93Schristos keep doing so; otherwise, stop. */
10573965be93Schristos if (log_perror == -1)
10583965be93Schristos log_perror = 1;
10593965be93Schristos else
10603965be93Schristos log_perror = 0;
10613965be93Schristos
10623965be93Schristos if (daemon) {
10633965be93Schristos if (dfd[0] != -1 && dfd[1] != -1) {
10643965be93Schristos char buf = 0;
10653965be93Schristos
10663965be93Schristos if (write(dfd[1], &buf, 1) != 1)
10673965be93Schristos log_fatal("write to parent: %m");
10683965be93Schristos (void) close(dfd[1]);
10693965be93Schristos dfd[0] = dfd[1] = -1;
10703965be93Schristos }
10713965be93Schristos
10723965be93Schristos /* Become session leader and get pid... */
10733965be93Schristos (void) setsid();
10743965be93Schristos
10753965be93Schristos /* Close standard I/O descriptors. */
10763965be93Schristos (void) close(0);
10773965be93Schristos (void) close(1);
10783965be93Schristos (void) close(2);
10793965be93Schristos
10803965be93Schristos /* Reopen them on /dev/null. */
10813965be93Schristos (void) open("/dev/null", O_RDWR);
10823965be93Schristos (void) open("/dev/null", O_RDWR);
10833965be93Schristos (void) open("/dev/null", O_RDWR);
10843965be93Schristos log_perror = 0; /* No sense logging to /dev/null. */
10853965be93Schristos
10863965be93Schristos IGNORE_RET (chdir("/"));
10873965be93Schristos }
10883965be93Schristos #endif /* !DEBUG */
10893965be93Schristos
10903965be93Schristos #if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \
10913965be93Schristos defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
10923965be93Schristos dmalloc_cutoff_generation = dmalloc_generation;
10933965be93Schristos dmalloc_longterm = dmalloc_outstanding;
10943965be93Schristos dmalloc_outstanding = 0;
10953965be93Schristos #endif
10963965be93Schristos
10973965be93Schristos omapi_set_int_value ((omapi_object_t *)dhcp_control_object,
10983965be93Schristos (omapi_object_t *)0, "state", server_running);
10993965be93Schristos
11003965be93Schristos #if defined(ENABLE_GENTLE_SHUTDOWN)
11013965be93Schristos /* no signal handlers until we deal with the side effects */
11023965be93Schristos /* install signal handlers */
11033965be93Schristos signal(SIGINT, dhcp_signal_handler); /* control-c */
11043965be93Schristos signal(SIGTERM, dhcp_signal_handler); /* kill */
11053965be93Schristos #endif
11063965be93Schristos
11073965be93Schristos /* Log that we are about to start working */
11083965be93Schristos log_info("Server starting service.");
11093965be93Schristos
11103965be93Schristos /*
11113965be93Schristos * Receive packets and dispatch them...
11123965be93Schristos * dispatch() will never return.
11133965be93Schristos */
11143965be93Schristos dispatch ();
11153965be93Schristos
11163965be93Schristos /* Let's return status code */
11173965be93Schristos return 0;
11183965be93Schristos }
11193965be93Schristos #endif /* !UNIT_TEST */
11203965be93Schristos
postconf_initialization(int quiet)11213965be93Schristos void postconf_initialization (int quiet)
11223965be93Schristos {
11233965be93Schristos struct option_state *options = NULL;
11243965be93Schristos struct data_string db;
11253965be93Schristos struct option_cache *oc;
11263965be93Schristos char *s;
11273965be93Schristos isc_result_t result;
11283965be93Schristos int tmp;
11293965be93Schristos #if defined (NSUPDATE)
11303965be93Schristos struct in_addr local4, *local4_ptr = NULL;
11313965be93Schristos struct in6_addr local6, *local6_ptr = NULL;
11323965be93Schristos #endif
11333965be93Schristos
11343965be93Schristos /* Now try to get the lease file name. */
11353965be93Schristos option_state_allocate(&options, MDL);
11363965be93Schristos
11373965be93Schristos execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL,
11383965be93Schristos options, &global_scope, root_group,
11393965be93Schristos NULL, NULL);
11403965be93Schristos memset(&db, 0, sizeof db);
11413965be93Schristos oc = lookup_option(&server_universe, options, SV_LEASE_FILE_NAME);
11423965be93Schristos if (oc &&
11433965be93Schristos evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
11443965be93Schristos &global_scope, oc, MDL)) {
11453965be93Schristos s = dmalloc(db.len + 1, MDL);
11463965be93Schristos if (!s)
11473965be93Schristos log_fatal("no memory for lease db filename.");
11483965be93Schristos memcpy(s, db.data, db.len);
11493965be93Schristos s[db.len] = 0;
11503965be93Schristos data_string_forget(&db, MDL);
11513965be93Schristos path_dhcpd_db = s;
11523965be93Schristos }
11533965be93Schristos
11543965be93Schristos oc = lookup_option(&server_universe, options, SV_PID_FILE_NAME);
11553965be93Schristos if (oc &&
11563965be93Schristos evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
11573965be93Schristos &global_scope, oc, MDL)) {
11583965be93Schristos s = dmalloc(db.len + 1, MDL);
11593965be93Schristos if (!s)
11603965be93Schristos log_fatal("no memory for pid filename.");
11613965be93Schristos memcpy(s, db.data, db.len);
11623965be93Schristos s[db.len] = 0;
11633965be93Schristos data_string_forget(&db, MDL);
11643965be93Schristos path_dhcpd_pid = s;
11653965be93Schristos }
11663965be93Schristos
11673965be93Schristos #ifdef DHCPv6
11683965be93Schristos if (local_family == AF_INET6) {
11693965be93Schristos /*
11703965be93Schristos * Override lease file name with dhcpv6 lease file name,
11713965be93Schristos * if it was set; then, do the same with the pid file name
11723965be93Schristos */
11733965be93Schristos oc = lookup_option(&server_universe, options,
11743965be93Schristos SV_DHCPV6_LEASE_FILE_NAME);
11753965be93Schristos if (oc &&
11763965be93Schristos evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
11773965be93Schristos &global_scope, oc, MDL)) {
11783965be93Schristos s = dmalloc(db.len + 1, MDL);
11793965be93Schristos if (!s)
11803965be93Schristos log_fatal("no memory for lease db filename.");
11813965be93Schristos memcpy(s, db.data, db.len);
11823965be93Schristos s[db.len] = 0;
11833965be93Schristos data_string_forget(&db, MDL);
11843965be93Schristos path_dhcpd_db = s;
11853965be93Schristos }
11863965be93Schristos
11873965be93Schristos oc = lookup_option(&server_universe, options,
11883965be93Schristos SV_DHCPV6_PID_FILE_NAME);
11893965be93Schristos if (oc &&
11903965be93Schristos evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
11913965be93Schristos &global_scope, oc, MDL)) {
11923965be93Schristos s = dmalloc(db.len + 1, MDL);
11933965be93Schristos if (!s)
11943965be93Schristos log_fatal("no memory for pid filename.");
11953965be93Schristos memcpy(s, db.data, db.len);
11963965be93Schristos s[db.len] = 0;
11973965be93Schristos data_string_forget(&db, MDL);
11983965be93Schristos path_dhcpd_pid = s;
11993965be93Schristos }
12003965be93Schristos
12013965be93Schristos oc = lookup_option(&server_universe, options,
12023965be93Schristos SV_LOCAL_ADDRESS6);
12033965be93Schristos if (oc &&
12043965be93Schristos evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
12053965be93Schristos &global_scope, oc, MDL)) {
12063965be93Schristos if (db.len == 16) {
12073965be93Schristos memcpy(&local_address6, db.data, 16);
12083965be93Schristos } else
12093965be93Schristos log_fatal("invalid local address "
12103965be93Schristos "data length");
12113965be93Schristos data_string_forget(&db, MDL);
12123965be93Schristos }
12133965be93Schristos
12143965be93Schristos oc = lookup_option(&server_universe, options,
12153965be93Schristos SV_BIND_LOCAL_ADDRESS6);
12163965be93Schristos if (oc &&
12173965be93Schristos evaluate_boolean_option_cache(NULL, NULL, NULL,
12183965be93Schristos NULL, options, NULL,
12193965be93Schristos &global_scope, oc, MDL)) {
12203965be93Schristos bind_local_address6 = 1;
12213965be93Schristos }
12223965be93Schristos
12233965be93Schristos }
12243965be93Schristos #endif /* DHCPv6 */
12253965be93Schristos
12263965be93Schristos omapi_port = -1;
12273965be93Schristos oc = lookup_option(&server_universe, options, SV_OMAPI_PORT);
12283965be93Schristos if (oc &&
12293965be93Schristos evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
12303965be93Schristos &global_scope, oc, MDL)) {
12313965be93Schristos if (db.len == 2) {
12323965be93Schristos omapi_port = getUShort(db.data);
12333965be93Schristos } else
12343965be93Schristos log_fatal("invalid omapi port data length");
12353965be93Schristos data_string_forget(&db, MDL);
12363965be93Schristos }
12373965be93Schristos
12383965be93Schristos oc = lookup_option(&server_universe, options, SV_OMAPI_KEY);
12393965be93Schristos if (oc &&
12403965be93Schristos evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
12413965be93Schristos &global_scope, oc, MDL)) {
12423965be93Schristos s = dmalloc(db.len + 1, MDL);
12433965be93Schristos if (!s)
12443965be93Schristos log_fatal("no memory for OMAPI key filename.");
12453965be93Schristos memcpy(s, db.data, db.len);
12463965be93Schristos s[db.len] = 0;
12473965be93Schristos data_string_forget(&db, MDL);
12483965be93Schristos result = omapi_auth_key_lookup_name(&omapi_key, s);
12493965be93Schristos dfree(s, MDL);
12503965be93Schristos if (result != ISC_R_SUCCESS)
12513965be93Schristos log_fatal("OMAPI key %s: %s",
12523965be93Schristos s, isc_result_totext (result));
12533965be93Schristos }
12543965be93Schristos
12553965be93Schristos oc = lookup_option(&server_universe, options, SV_LOCAL_PORT);
12563965be93Schristos if (oc &&
12573965be93Schristos evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
12583965be93Schristos &global_scope, oc, MDL)) {
12593965be93Schristos if (db.len == 2) {
12603965be93Schristos local_port = htons(getUShort (db.data));
12613965be93Schristos } else
12623965be93Schristos log_fatal("invalid local port data length");
12633965be93Schristos data_string_forget(&db, MDL);
12643965be93Schristos }
12653965be93Schristos
12663965be93Schristos oc = lookup_option(&server_universe, options, SV_REMOTE_PORT);
12673965be93Schristos if (oc &&
12683965be93Schristos evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
12693965be93Schristos &global_scope, oc, MDL)) {
12703965be93Schristos if (db.len == 2) {
12713965be93Schristos remote_port = htons(getUShort (db.data));
12723965be93Schristos } else
12733965be93Schristos log_fatal("invalid remote port data length");
12743965be93Schristos data_string_forget(&db, MDL);
12753965be93Schristos }
12763965be93Schristos
12773965be93Schristos oc = lookup_option(&server_universe, options,
12783965be93Schristos SV_LIMITED_BROADCAST_ADDRESS);
12793965be93Schristos if (oc &&
12803965be93Schristos evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
12813965be93Schristos &global_scope, oc, MDL)) {
12823965be93Schristos if (db.len == 4) {
12833965be93Schristos memcpy(&limited_broadcast, db.data, 4);
12843965be93Schristos } else
12853965be93Schristos log_fatal("invalid broadcast address data length");
12863965be93Schristos data_string_forget(&db, MDL);
12873965be93Schristos }
12883965be93Schristos
12893965be93Schristos oc = lookup_option(&server_universe, options, SV_LOCAL_ADDRESS);
12903965be93Schristos if (oc &&
12913965be93Schristos evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
12923965be93Schristos &global_scope, oc, MDL)) {
12933965be93Schristos if (db.len == 4) {
12943965be93Schristos memcpy(&local_address, db.data, 4);
12953965be93Schristos } else
12963965be93Schristos log_fatal("invalid local address data length");
12973965be93Schristos data_string_forget(&db, MDL);
12983965be93Schristos }
12993965be93Schristos
13003965be93Schristos oc = lookup_option(&server_universe, options, SV_DDNS_UPDATE_STYLE);
13013965be93Schristos if (oc) {
13023965be93Schristos if (evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
13033965be93Schristos &global_scope, oc, MDL)) {
13043965be93Schristos if (db.len == 1) {
13053965be93Schristos ddns_update_style = db.data[0];
13063965be93Schristos } else
13073965be93Schristos log_fatal("invalid dns update type");
13083965be93Schristos data_string_forget(&db, MDL);
13093965be93Schristos }
13103965be93Schristos } else {
13113965be93Schristos ddns_update_style = DDNS_UPDATE_STYLE_NONE;
13123965be93Schristos }
13133965be93Schristos #if defined (NSUPDATE)
13143965be93Schristos /* We no longer support ad_hoc, tell the user */
13153965be93Schristos if (ddns_update_style == DDNS_UPDATE_STYLE_AD_HOC) {
13163965be93Schristos log_fatal("ddns-update-style ad_hoc no longer supported");
13173965be93Schristos }
13183965be93Schristos
13193965be93Schristos oc = lookup_option(&server_universe, options, SV_DDNS_LOCAL_ADDRESS4);
13203965be93Schristos if (oc) {
13213965be93Schristos if (evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
13223965be93Schristos &global_scope, oc, MDL)) {
13233965be93Schristos if (db.len == 4) {
13243965be93Schristos memcpy(&local4, db.data, 4);
13253965be93Schristos local4_ptr = &local4;
13263965be93Schristos }
13273965be93Schristos data_string_forget(&db, MDL);
13283965be93Schristos }
13293965be93Schristos }
13303965be93Schristos
13313965be93Schristos oc = lookup_option(&server_universe, options, SV_DDNS_LOCAL_ADDRESS6);
13323965be93Schristos if (oc) {
13333965be93Schristos if (evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
13343965be93Schristos &global_scope, oc, MDL)) {
13353965be93Schristos if (db.len == 16) {
13363965be93Schristos memcpy(&local6, db.data, 16);
13373965be93Schristos local6_ptr = &local6;
13383965be93Schristos }
13393965be93Schristos data_string_forget(&db, MDL);
13403965be93Schristos }
13413965be93Schristos }
13423965be93Schristos
13433965be93Schristos /* Don't init DNS client if update style is none. This avoids
13443965be93Schristos * listening ports that aren't needed. We don't use ddns-udpates
13453965be93Schristos * as that has multiple levels of scope. */
13463965be93Schristos if (ddns_update_style != DDNS_UPDATE_STYLE_NONE) {
13473965be93Schristos if (dhcp_context_create(DHCP_CONTEXT_POST_DB,
13483965be93Schristos local4_ptr, local6_ptr)
13493965be93Schristos != ISC_R_SUCCESS) {
13503965be93Schristos log_fatal("Unable to complete ddns initialization");
13513965be93Schristos }
13523965be93Schristos }
13533965be93Schristos
13543965be93Schristos /* Set the conflict detection flag mask based on globally
13553965be93Schristos * defined DDNS configuration params. This mask should be
13563965be93Schristos * to init ddns_cb::flags before for every DDNS transaction. */
13573965be93Schristos ddns_conflict_mask = get_conflict_mask(options);
13583965be93Schristos
13593965be93Schristos #else
13603965be93Schristos /* If we don't have support for updates compiled in tell the user */
13613965be93Schristos if (ddns_update_style != DDNS_UPDATE_STYLE_NONE) {
13623965be93Schristos log_fatal("Support for ddns-update-style not compiled in");
13633965be93Schristos }
13643965be93Schristos #endif
13653965be93Schristos
13663965be93Schristos if (!quiet) {
13673965be93Schristos log_info ("Config file: %s", path_dhcpd_conf);
13683965be93Schristos log_info ("Database file: %s", path_dhcpd_db);
13693965be93Schristos log_info ("PID file: %s", path_dhcpd_pid);
13703965be93Schristos }
13713965be93Schristos
13723965be93Schristos oc = lookup_option(&server_universe, options, SV_LOG_FACILITY);
13733965be93Schristos if (oc) {
13743965be93Schristos if (evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
13753965be93Schristos &global_scope, oc, MDL)) {
13763965be93Schristos if (db.len == 1) {
13773965be93Schristos closelog ();
13783965be93Schristos openlog(isc_file_basename(progname),
13793965be93Schristos DHCP_LOG_OPTIONS, db.data[0]);
13803965be93Schristos /* Log the startup banner into the new
13813965be93Schristos log file. */
13823965be93Schristos /* Don't log to stderr twice. */
13833965be93Schristos tmp = log_perror;
13843965be93Schristos log_perror = 0;
13853965be93Schristos log_info("%s %s", message, PACKAGE_VERSION);
13863965be93Schristos log_info(copyright);
13873965be93Schristos log_info(arr);
13883965be93Schristos log_info(url);
13893965be93Schristos log_perror = tmp;
13903965be93Schristos } else
13913965be93Schristos log_fatal("invalid log facility");
13923965be93Schristos data_string_forget(&db, MDL);
13933965be93Schristos }
13943965be93Schristos }
13953965be93Schristos
13963965be93Schristos #if defined(DELAYED_ACK)
13973965be93Schristos oc = lookup_option(&server_universe, options, SV_DELAYED_ACK);
13983965be93Schristos if (oc &&
13993965be93Schristos evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
14003965be93Schristos &global_scope, oc, MDL)) {
14013965be93Schristos if (db.len == 2) {
14023965be93Schristos max_outstanding_acks = htons(getUShort(db.data));
14033965be93Schristos } else {
14043965be93Schristos log_fatal("invalid max delayed ACK count ");
14053965be93Schristos }
14063965be93Schristos data_string_forget(&db, MDL);
14073965be93Schristos }
14083965be93Schristos #if defined(DHCP4o6)
14093965be93Schristos /* Delayed acks and DHCPv4-over-DHCPv6 are incompatible */
14103965be93Schristos if (dhcpv4_over_dhcpv6) {
14113965be93Schristos if (max_outstanding_acks > 0) {
14123965be93Schristos log_debug("DHCP4o6 enabled, "
14133965be93Schristos "setting delayed-ack to zero (incompatible)");
14143965be93Schristos }
14153965be93Schristos
14163965be93Schristos max_outstanding_acks = 0;
14173965be93Schristos }
14183965be93Schristos #endif
14193965be93Schristos
14203965be93Schristos oc = lookup_option(&server_universe, options, SV_MAX_ACK_DELAY);
14213965be93Schristos if (oc &&
14223965be93Schristos evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
14233965be93Schristos &global_scope, oc, MDL)) {
14243965be93Schristos u_int32_t timeval;
14253965be93Schristos
14263965be93Schristos if (db.len != 4)
14273965be93Schristos log_fatal("invalid max ack delay configuration");
14283965be93Schristos
14293965be93Schristos timeval = getULong(db.data);
14303965be93Schristos max_ack_delay_secs = timeval / 1000000;
14313965be93Schristos max_ack_delay_usecs = timeval % 1000000;
14323965be93Schristos
14333965be93Schristos data_string_forget(&db, MDL);
14343965be93Schristos }
14353965be93Schristos #endif
14363965be93Schristos
14373965be93Schristos oc = lookup_option(&server_universe, options, SV_DONT_USE_FSYNC);
14383965be93Schristos if ((oc != NULL) &&
14393965be93Schristos evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options, NULL,
14403965be93Schristos &global_scope, oc, MDL)) {
14413965be93Schristos dont_use_fsync = 1;
14423965be93Schristos log_error("Not using fsync() to flush lease writes");
14433965be93Schristos }
14443965be93Schristos
14453965be93Schristos oc = lookup_option(&server_universe, options, SV_SERVER_ID_CHECK);
14463965be93Schristos if ((oc != NULL) &&
14473965be93Schristos evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options, NULL,
14483965be93Schristos &global_scope, oc, MDL)) {
14493965be93Schristos log_info("Setting server-id-check true");
14503965be93Schristos server_id_check = 1;
14513965be93Schristos }
14523965be93Schristos
14533965be93Schristos #ifdef DHCPv6
14543965be93Schristos oc = lookup_option(&server_universe, options, SV_PREFIX_LEN_MODE);
14553965be93Schristos if ((oc != NULL) &&
14563965be93Schristos evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
14573965be93Schristos &global_scope, oc, MDL)) {
14583965be93Schristos if (db.len == 1) {
14593965be93Schristos prefix_length_mode = db.data[0];
14603965be93Schristos } else {
14613965be93Schristos log_fatal("invalid prefix-len-mode");
14623965be93Schristos }
14633965be93Schristos
14643965be93Schristos data_string_forget(&db, MDL);
14653965be93Schristos }
14663965be93Schristos #endif
14673965be93Schristos
14683965be93Schristos // Set global abandon-lease-time option.
14693965be93Schristos oc = lookup_option (&server_universe, options, SV_ABANDON_LEASE_TIME);
14703965be93Schristos if ((oc != NULL) &&
14713965be93Schristos evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
14723965be93Schristos &global_scope, oc, MDL)) {
14733965be93Schristos if (db.len == sizeof (u_int32_t)) {
14743965be93Schristos abandon_lease_time = getULong (db.data);
14753965be93Schristos } else {
14763965be93Schristos log_fatal("invalid abandon-lease-time");
14773965be93Schristos }
14783965be93Schristos
14793965be93Schristos data_string_forget (&db, MDL);
14803965be93Schristos }
14813965be93Schristos
14823965be93Schristos #if defined (FAILOVER_PROTOCOL)
14833965be93Schristos oc = lookup_option(&server_universe, options, SV_CHECK_SECS_BYTE_ORDER);
14843965be93Schristos if ((oc != NULL) &&
14853965be93Schristos evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options, NULL,
14863965be93Schristos &global_scope, oc, MDL)) {
14873965be93Schristos check_secs_byte_order = 1;
14883965be93Schristos }
14893965be93Schristos #endif
14903965be93Schristos
14913965be93Schristos #ifdef EUI_64
14923965be93Schristos oc = lookup_option(&server_universe, options, SV_PERSIST_EUI_64_LEASES);
14933965be93Schristos if (oc != NULL) {
14943965be93Schristos persist_eui64 = evaluate_boolean_option_cache(NULL, NULL, NULL,
14953965be93Schristos NULL, options,
14963965be93Schristos NULL,
14973965be93Schristos &global_scope,
14983965be93Schristos oc, MDL);
14993965be93Schristos }
15003965be93Schristos
15013965be93Schristos if (!persist_eui64) {
15023965be93Schristos log_info("EUI64 leases will not be written to lease file");
15033965be93Schristos }
15043965be93Schristos #endif
15053965be93Schristos
15063965be93Schristos #ifdef DHCPv6
15073965be93Schristos oc = lookup_option(&server_universe, options, SV_RELEASE_ON_ROAM);
15083965be93Schristos if (oc != NULL) {
15093965be93Schristos do_release_on_roam =
15103965be93Schristos evaluate_boolean_option_cache(NULL, NULL, NULL, NULL,
15113965be93Schristos options, NULL,
15123965be93Schristos &global_scope, oc, MDL);
15133965be93Schristos }
15143965be93Schristos #endif
15153965be93Schristos
15163965be93Schristos #if defined (BINARY_LEASES)
15173965be93Schristos if (local_family == AF_INET) {
15183965be93Schristos log_info("Source compiled to use binary-leases");
15193965be93Schristos }
15203965be93Schristos #endif
15213965be93Schristos
15223965be93Schristos /* Don't need the options anymore. */
15233965be93Schristos option_state_dereference(&options, MDL);
15243965be93Schristos }
15253965be93Schristos
postdb_startup(void)15263965be93Schristos void postdb_startup (void)
15273965be93Schristos {
15283965be93Schristos /* Initialize the omapi listener state. */
15293965be93Schristos if (omapi_port != -1) {
15303965be93Schristos omapi_listener_start (0);
15313965be93Schristos }
15323965be93Schristos
15333965be93Schristos #if defined (FAILOVER_PROTOCOL)
15343965be93Schristos /* Initialize the failover listener state. */
15353965be93Schristos dhcp_failover_startup ();
15363965be93Schristos #endif
15373965be93Schristos
15383965be93Schristos /*
15393965be93Schristos * Begin our lease timeout background task.
15403965be93Schristos */
15413965be93Schristos schedule_all_ipv6_lease_timeouts();
15423965be93Schristos }
15433965be93Schristos
lease_pinged(from,packet,length)15443965be93Schristos void lease_pinged (from, packet, length)
15453965be93Schristos struct iaddr from;
15463965be93Schristos u_int8_t *packet;
15473965be93Schristos int length;
15483965be93Schristos {
15493965be93Schristos struct lease *lp;
15503965be93Schristos
15513965be93Schristos /* Don't try to look up a pinged lease if we aren't trying to
15523965be93Schristos ping one - otherwise somebody could easily make us churn by
15533965be93Schristos just forging repeated ICMP EchoReply packets for us to look
15543965be93Schristos up. */
15553965be93Schristos if (!outstanding_pings)
15563965be93Schristos return;
15573965be93Schristos
15583965be93Schristos lp = (struct lease *)0;
15593965be93Schristos if (!find_lease_by_ip_addr (&lp, from, MDL)) {
15603965be93Schristos log_debug ("unexpected ICMP Echo Reply from %s",
15613965be93Schristos piaddr (from));
15623965be93Schristos return;
15633965be93Schristos }
15643965be93Schristos
15653965be93Schristos if (!lp -> state) {
15663965be93Schristos #if defined (FAILOVER_PROTOCOL)
15673965be93Schristos if (!lp -> pool ||
15683965be93Schristos !lp -> pool -> failover_peer)
15693965be93Schristos #endif
15703965be93Schristos log_debug ("ICMP Echo Reply for %s late or spurious.",
15713965be93Schristos piaddr (from));
15723965be93Schristos goto out;
15733965be93Schristos }
15743965be93Schristos
15753965be93Schristos if (lp -> ends > cur_time) {
15763965be93Schristos log_debug ("ICMP Echo reply while lease %s valid.",
15773965be93Schristos piaddr (from));
15783965be93Schristos }
15793965be93Schristos
15803965be93Schristos /* At this point it looks like we pinged a lease and got a
15813965be93Schristos response, which shouldn't have happened. */
15823965be93Schristos data_string_forget (&lp -> state -> parameter_request_list, MDL);
15833965be93Schristos free_lease_state (lp -> state, MDL);
15843965be93Schristos lp -> state = (struct lease_state *)0;
15853965be93Schristos
15863965be93Schristos abandon_lease (lp, "pinged before offer");
15873965be93Schristos cancel_timeout (lease_ping_timeout, lp);
15883965be93Schristos --outstanding_pings;
15893965be93Schristos out:
15903965be93Schristos lease_dereference (&lp, MDL);
15913965be93Schristos }
15923965be93Schristos
lease_ping_timeout(vlp)15933965be93Schristos void lease_ping_timeout (vlp)
15943965be93Schristos void *vlp;
15953965be93Schristos {
15963965be93Schristos struct lease *lp = vlp;
15973965be93Schristos
15983965be93Schristos #if defined (DEBUG_MEMORY_LEAKAGE)
15993965be93Schristos unsigned long previous_outstanding = dmalloc_outstanding;
16003965be93Schristos #endif
16013965be93Schristos
16023965be93Schristos --outstanding_pings;
16033965be93Schristos dhcp_reply (lp);
16043965be93Schristos
16053965be93Schristos #if defined (DEBUG_MEMORY_LEAKAGE)
16063965be93Schristos log_info ("generation %ld: %ld new, %ld outstanding, %ld long-term",
16073965be93Schristos dmalloc_generation,
16083965be93Schristos dmalloc_outstanding - previous_outstanding,
16093965be93Schristos dmalloc_outstanding, dmalloc_longterm);
16103965be93Schristos #endif
16113965be93Schristos #if defined (DEBUG_MEMORY_LEAKAGE)
16123965be93Schristos dmalloc_dump_outstanding ();
16133965be93Schristos #endif
16143965be93Schristos }
16153965be93Schristos
dhcpd_interface_setup_hook(struct interface_info * ip,struct iaddr * ia)16163965be93Schristos int dhcpd_interface_setup_hook (struct interface_info *ip, struct iaddr *ia)
16173965be93Schristos {
16183965be93Schristos struct subnet *subnet;
16193965be93Schristos struct shared_network *share;
16203965be93Schristos isc_result_t status;
16213965be93Schristos
16223965be93Schristos /* Special case for fallback network - not sure why this is
16233965be93Schristos necessary. */
16243965be93Schristos if (!ia) {
16253965be93Schristos const char *fnn = "fallback-net";
16263965be93Schristos status = shared_network_allocate (&ip -> shared_network, MDL);
16273965be93Schristos if (status != ISC_R_SUCCESS)
16283965be93Schristos log_fatal ("No memory for shared subnet: %s",
16293965be93Schristos isc_result_totext (status));
16303965be93Schristos ip -> shared_network -> name = dmalloc (strlen (fnn) + 1, MDL);
16313965be93Schristos if (!ip -> shared_network -> name)
16323965be93Schristos log_fatal("no memory for shared network");
16333965be93Schristos strcpy (ip -> shared_network -> name, fnn);
16343965be93Schristos return 1;
16353965be93Schristos }
16363965be93Schristos
16373965be93Schristos /* If there's a registered subnet for this address,
16383965be93Schristos connect it together... */
16393965be93Schristos subnet = (struct subnet *)0;
16403965be93Schristos if (find_subnet (&subnet, *ia, MDL)) {
16413965be93Schristos /* If this interface has multiple aliases on the same
16423965be93Schristos subnet, ignore all but the first we encounter. */
16433965be93Schristos if (!subnet -> interface) {
16443965be93Schristos interface_reference (&subnet -> interface, ip, MDL);
16453965be93Schristos subnet -> interface_address = *ia;
16463965be93Schristos } else if (subnet -> interface != ip) {
16473965be93Schristos log_error ("Multiple interfaces match the %s: %s %s",
16483965be93Schristos "same subnet",
16493965be93Schristos subnet -> interface -> name, ip -> name);
16503965be93Schristos }
16513965be93Schristos share = subnet -> shared_network;
16523965be93Schristos if (ip -> shared_network &&
16533965be93Schristos ip -> shared_network != share) {
16543965be93Schristos log_fatal ("Interface %s matches multiple shared %s",
16553965be93Schristos ip -> name, "networks");
16563965be93Schristos } else {
16573965be93Schristos if (!ip -> shared_network)
16583965be93Schristos shared_network_reference
16593965be93Schristos (&ip -> shared_network, share, MDL);
16603965be93Schristos }
16613965be93Schristos
16623965be93Schristos if (!share -> interface) {
16633965be93Schristos interface_reference (&share -> interface, ip, MDL);
16643965be93Schristos } else if (share -> interface != ip) {
16653965be93Schristos log_error ("Multiple interfaces match the %s: %s %s",
16663965be93Schristos "same shared network",
16673965be93Schristos share -> interface -> name, ip -> name);
16683965be93Schristos }
16693965be93Schristos subnet_dereference (&subnet, MDL);
16703965be93Schristos }
16713965be93Schristos return 1;
16723965be93Schristos }
16733965be93Schristos
16743965be93Schristos static TIME shutdown_time;
16753965be93Schristos static int omapi_connection_count;
16763965be93Schristos enum dhcp_shutdown_state shutdown_state;
16773965be93Schristos
dhcp_io_shutdown(omapi_object_t * obj,void * foo)16783965be93Schristos isc_result_t dhcp_io_shutdown (omapi_object_t *obj, void *foo)
16793965be93Schristos {
16803965be93Schristos /* Shut down all listeners. */
16813965be93Schristos if (shutdown_state == shutdown_listeners &&
16823965be93Schristos obj -> type == omapi_type_listener &&
16833965be93Schristos obj -> inner &&
16843965be93Schristos obj -> inner -> type == omapi_type_protocol_listener) {
16853965be93Schristos omapi_listener_destroy (obj, MDL);
16863965be93Schristos return ISC_R_SUCCESS;
16873965be93Schristos }
16883965be93Schristos
16893965be93Schristos /* Shut down all existing omapi connections. */
16903965be93Schristos if (obj -> type == omapi_type_connection &&
16913965be93Schristos obj -> inner &&
16923965be93Schristos obj -> inner -> type == omapi_type_protocol) {
16933965be93Schristos if (shutdown_state == shutdown_drop_omapi_connections) {
16943965be93Schristos omapi_disconnect (obj, 1);
16953965be93Schristos }
16963965be93Schristos omapi_connection_count++;
16973965be93Schristos if (shutdown_state == shutdown_omapi_connections) {
16983965be93Schristos omapi_disconnect (obj, 0);
16993965be93Schristos return ISC_R_SUCCESS;
17003965be93Schristos }
17013965be93Schristos }
17023965be93Schristos
17033965be93Schristos /* Shutdown all DHCP interfaces. */
17043965be93Schristos if (obj -> type == dhcp_type_interface &&
17053965be93Schristos shutdown_state == shutdown_dhcp) {
17063965be93Schristos dhcp_interface_remove (obj, (omapi_object_t *)0);
17073965be93Schristos return ISC_R_SUCCESS;
17083965be93Schristos }
17093965be93Schristos return ISC_R_SUCCESS;
17103965be93Schristos }
17113965be93Schristos
dhcp_io_shutdown_countdown(void * vlp)17123965be93Schristos static isc_result_t dhcp_io_shutdown_countdown (void *vlp)
17133965be93Schristos {
17143965be93Schristos #if defined (FAILOVER_PROTOCOL)
17153965be93Schristos dhcp_failover_state_t *state;
17163965be93Schristos int failover_connection_count = 0;
17173965be93Schristos #endif
17183965be93Schristos struct timeval tv;
17193965be93Schristos
17203965be93Schristos oncemore:
17213965be93Schristos if (shutdown_state == shutdown_listeners ||
17223965be93Schristos shutdown_state == shutdown_omapi_connections ||
17233965be93Schristos shutdown_state == shutdown_drop_omapi_connections ||
17243965be93Schristos shutdown_state == shutdown_dhcp) {
17253965be93Schristos omapi_connection_count = 0;
17263965be93Schristos omapi_io_state_foreach (dhcp_io_shutdown, 0);
17273965be93Schristos }
17283965be93Schristos
17293965be93Schristos if ((shutdown_state == shutdown_listeners ||
17303965be93Schristos shutdown_state == shutdown_omapi_connections ||
17313965be93Schristos shutdown_state == shutdown_drop_omapi_connections) &&
17323965be93Schristos omapi_connection_count == 0) {
17333965be93Schristos shutdown_state = shutdown_dhcp;
17343965be93Schristos shutdown_time = cur_time;
17353965be93Schristos goto oncemore;
17363965be93Schristos } else if (shutdown_state == shutdown_listeners &&
17373965be93Schristos cur_time - shutdown_time > 4) {
17383965be93Schristos shutdown_state = shutdown_omapi_connections;
17393965be93Schristos shutdown_time = cur_time;
17403965be93Schristos } else if (shutdown_state == shutdown_omapi_connections &&
17413965be93Schristos cur_time - shutdown_time > 4) {
17423965be93Schristos shutdown_state = shutdown_drop_omapi_connections;
17433965be93Schristos shutdown_time = cur_time;
17443965be93Schristos } else if (shutdown_state == shutdown_drop_omapi_connections &&
17453965be93Schristos cur_time - shutdown_time > 4) {
17463965be93Schristos shutdown_state = shutdown_dhcp;
17473965be93Schristos shutdown_time = cur_time;
17483965be93Schristos goto oncemore;
17493965be93Schristos } else if (shutdown_state == shutdown_dhcp &&
17503965be93Schristos cur_time - shutdown_time > 4) {
17513965be93Schristos shutdown_state = shutdown_done;
17523965be93Schristos shutdown_time = cur_time;
17533965be93Schristos }
17543965be93Schristos
17553965be93Schristos #if defined (FAILOVER_PROTOCOL)
17563965be93Schristos /* Set all failover peers into the shutdown state. */
17573965be93Schristos if (shutdown_state == shutdown_dhcp) {
17583965be93Schristos for (state = failover_states; state; state = state -> next) {
17593965be93Schristos if (state -> me.state == normal) {
17603965be93Schristos dhcp_failover_set_state (state, shut_down);
17613965be93Schristos failover_connection_count++;
17623965be93Schristos }
17633965be93Schristos if (state -> me.state == shut_down &&
17643965be93Schristos state -> partner.state != partner_down)
17653965be93Schristos failover_connection_count++;
17663965be93Schristos }
17673965be93Schristos }
17683965be93Schristos
17693965be93Schristos if (shutdown_state == shutdown_done) {
17703965be93Schristos for (state = failover_states; state; state = state -> next) {
17713965be93Schristos if (state -> me.state == shut_down) {
17723965be93Schristos if (state -> link_to_peer)
17733965be93Schristos dhcp_failover_link_dereference (&state -> link_to_peer,
17743965be93Schristos MDL);
17753965be93Schristos dhcp_failover_set_state (state, recover);
17763965be93Schristos }
17773965be93Schristos }
17783965be93Schristos #if defined (DEBUG_MEMORY_LEAKAGE) && \
17793965be93Schristos defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
17803965be93Schristos free_everything ();
17813965be93Schristos omapi_print_dmalloc_usage_by_caller ();
17823965be93Schristos #endif
17833965be93Schristos if (no_pid_file == ISC_FALSE)
17843965be93Schristos (void) unlink(path_dhcpd_pid);
17853965be93Schristos exit (0);
17863965be93Schristos }
17873965be93Schristos #else
17883965be93Schristos if (shutdown_state == shutdown_done) {
17893965be93Schristos #if defined (DEBUG_MEMORY_LEAKAGE) && \
17903965be93Schristos defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
17913965be93Schristos free_everything ();
17923965be93Schristos omapi_print_dmalloc_usage_by_caller ();
17933965be93Schristos #endif
17943965be93Schristos if (no_pid_file == ISC_FALSE)
17953965be93Schristos (void) unlink(path_dhcpd_pid);
17963965be93Schristos exit (0);
17973965be93Schristos }
17983965be93Schristos #endif
17993965be93Schristos if (shutdown_state == shutdown_dhcp &&
18003965be93Schristos #if defined(FAILOVER_PROTOCOL)
18013965be93Schristos !failover_connection_count &&
18023965be93Schristos #endif
18033965be93Schristos ISC_TRUE) {
18043965be93Schristos shutdown_state = shutdown_done;
18053965be93Schristos shutdown_time = cur_time;
18063965be93Schristos goto oncemore;
18073965be93Schristos }
18083965be93Schristos tv.tv_sec = cur_tv.tv_sec + 1;
18093965be93Schristos tv.tv_usec = cur_tv.tv_usec;
18103965be93Schristos add_timeout (&tv,
18113965be93Schristos (void (*)(void *))dhcp_io_shutdown_countdown, 0, 0, 0);
18123965be93Schristos return ISC_R_SUCCESS;
18133965be93Schristos }
18143965be93Schristos
dhcp_set_control_state(control_object_state_t oldstate,control_object_state_t newstate)18153965be93Schristos isc_result_t dhcp_set_control_state (control_object_state_t oldstate,
18163965be93Schristos control_object_state_t newstate)
18173965be93Schristos {
18183965be93Schristos struct timeval tv;
18193965be93Schristos
18203965be93Schristos if (newstate != server_shutdown)
18213965be93Schristos return DHCP_R_INVALIDARG;
18223965be93Schristos /* Re-entry. */
18233965be93Schristos if (shutdown_signal == SIGUSR1)
18243965be93Schristos return ISC_R_SUCCESS;
18253965be93Schristos shutdown_time = cur_time;
18263965be93Schristos shutdown_state = shutdown_listeners;
18273965be93Schristos /* Called by user. */
18283965be93Schristos if (shutdown_signal == 0) {
18293965be93Schristos shutdown_signal = SIGUSR1;
18303965be93Schristos dhcp_io_shutdown_countdown (0);
18313965be93Schristos return ISC_R_SUCCESS;
18323965be93Schristos }
18333965be93Schristos /* Called on signal. */
18343965be93Schristos log_info("Received signal %d, initiating shutdown.", shutdown_signal);
18353965be93Schristos shutdown_signal = SIGUSR1;
18363965be93Schristos
18373965be93Schristos /*
18383965be93Schristos * Prompt the shutdown event onto the timer queue
18393965be93Schristos * and return to the dispatch loop.
18403965be93Schristos */
18413965be93Schristos tv.tv_sec = cur_tv.tv_sec;
18423965be93Schristos tv.tv_usec = cur_tv.tv_usec + 1;
18433965be93Schristos add_timeout(&tv,
18443965be93Schristos (void (*)(void *))dhcp_io_shutdown_countdown, 0, 0, 0);
18453965be93Schristos return ISC_R_SUCCESS;
18463965be93Schristos }
1847