File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / server / dhcpd.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:06:55 2012 UTC (11 years, 9 months ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

    1: /* dhcpd.c
    2: 
    3:    DHCP Server Daemon. */
    4: 
    5: /*
    6:  * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC")
    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[] =
   36: "Copyright 2004-2012 Internet Systems Consortium.";
   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: 
   61: #ifndef UNIT_TEST
   62: static void usage(void);
   63: #endif
   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. */
 1187: #ifndef UNIT_TEST
 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: }
 1211: #endif
 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>