Home | History | Annotate | Line # | Download | only in omapip
      1 /*	$NetBSD: isclib.c,v 1.8 2022/04/03 01:10:59 christos Exp $	*/
      2 
      3 /*
      4  * Copyright(C) 2009-2022 Internet Systems Consortium, Inc.("ISC")
      5  *
      6  * This Source Code Form is subject to the terms of the Mozilla Public
      7  * License, v. 2.0. If a copy of the MPL was not distributed with this
      8  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
      9  *
     10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
     11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
     13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     16  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17  *
     18  *   Internet Systems Consortium, Inc.
     19  *   PO Box 360
     20  *   Newmarket, NH 03857 USA
     21  *   <info (at) isc.org>
     22  *   http://www.isc.org/
     23  *
     24  */
     25 
     26 #include <sys/cdefs.h>
     27 __RCSID("$NetBSD: isclib.c,v 1.8 2022/04/03 01:10:59 christos Exp $");
     28 
     29 /*Trying to figure out what we need to define to get things to work.
     30   It looks like we want/need the library but need the fdwatchcommand
     31   which may be a problem */
     32 
     33 #include "dhcpd.h"
     34 
     35 #include <sys/time.h>
     36 #include <signal.h>
     37 
     38 dhcp_context_t dhcp_gbl_ctx;
     39 int shutdown_signal = 0;
     40 
     41 #if defined (NSUPDATE)
     42 
     43 /* This routine will open up the /etc/resolv.conf file and
     44  * send any nameservers it finds to the DNS client code.
     45  * It may be moved to be part of the dns client code instead
     46  * of being in the DHCP code
     47  */
     48 static isc_result_t
     49 dhcp_dns_client_setservers(void)
     50 {
     51 	isc_result_t result;
     52 	irs_resconf_t *resconf = NULL;
     53 	isc_sockaddrlist_t *nameservers;
     54 	isc_sockaddr_t *sa;
     55 
     56 	result = irs_resconf_load(dhcp_gbl_ctx.mctx, _PATH_RESOLV_CONF,
     57 				  &resconf);
     58 	if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
     59 		log_error("irs_resconf_load failed: %d.", result);
     60 		return (result);
     61 	}
     62 
     63 	nameservers = irs_resconf_getnameservers(resconf);
     64 
     65 	/* Initialize port numbers */
     66 	for (sa = ISC_LIST_HEAD(*nameservers);
     67 	     sa != NULL;
     68 	     sa = ISC_LIST_NEXT(sa, link)) {
     69 		switch (sa->type.sa.sa_family) {
     70 		case AF_INET:
     71 			sa->type.sin.sin_port = htons(NS_DEFAULTPORT);
     72 			break;
     73 		case AF_INET6:
     74 			sa->type.sin6.sin6_port = htons(NS_DEFAULTPORT);
     75 			break;
     76 		default:
     77 			break;
     78 		}
     79 	}
     80 
     81 	result = dns_client_setservers(dhcp_gbl_ctx.dnsclient,
     82 				       dns_rdataclass_in,
     83 				       NULL, nameservers);
     84 	if (result != ISC_R_SUCCESS) {
     85 		log_error("dns_client_setservers failed: %d.",
     86 			  result);
     87 	}
     88 	return (result);
     89 }
     90 #endif /* defined NSUPDATE */
     91 
     92 void
     93 isclib_cleanup(void)
     94 {
     95 #if defined (NSUPDATE)
     96 	if (dhcp_gbl_ctx.dnsclient != NULL)
     97 		dns_client_destroy((dns_client_t **)&dhcp_gbl_ctx.dnsclient);
     98 #endif /* defined NSUPDATE */
     99 
    100 	if (dhcp_gbl_ctx.task != NULL) {
    101 		isc_task_shutdown(dhcp_gbl_ctx.task);
    102 		isc_task_detach(&dhcp_gbl_ctx.task);
    103 	}
    104 
    105 	if (dhcp_gbl_ctx.timermgr != NULL)
    106 		isc_timermgr_destroy(&dhcp_gbl_ctx.timermgr);
    107 
    108 	if (dhcp_gbl_ctx.socketmgr != NULL)
    109 		isc_socketmgr_destroy(&dhcp_gbl_ctx.socketmgr);
    110 
    111 	if (dhcp_gbl_ctx.taskmgr != NULL)
    112 		isc_managers_destroy(&dhcp_gbl_ctx.netmgr,
    113 				     &dhcp_gbl_ctx.taskmgr);
    114 
    115 	if (dhcp_gbl_ctx.actx_started != ISC_FALSE) {
    116 		isc_app_ctxfinish(dhcp_gbl_ctx.actx);
    117 		dhcp_gbl_ctx.actx_started = ISC_FALSE;
    118 	}
    119 
    120 	if (dhcp_gbl_ctx.actx != NULL)
    121 		isc_appctx_destroy(&dhcp_gbl_ctx.actx);
    122 
    123 	if (dhcp_gbl_ctx.mctx != NULL)
    124 		isc_mem_detach(&dhcp_gbl_ctx.mctx);
    125 
    126 	return;
    127 }
    128 
    129 /* Installs a handler for a signal using sigaction */
    130 static void
    131 handle_signal(int sig, void (*handler)(int)) {
    132 	struct sigaction sa;
    133 
    134 	memset(&sa, 0, sizeof(sa));
    135 	sa.sa_handler = handler;
    136 	sigfillset(&sa.sa_mask);
    137 	if (sigaction(sig, &sa, NULL) != 0) {
    138 		log_debug("handle_signal() failed for signal %d error: %s",
    139                           sig, strerror(errno));
    140 	}
    141 }
    142 
    143 /* Callback passed to isc_app_ctxonrun
    144  *
    145  * BIND9 context code will invoke this handler once the context has
    146  * entered the running state.  We use it to set a global marker so that
    147  * we can tell if the context is running.  Several of the isc_app_
    148  * calls REQUIRE that the context is running and we need a way to
    149  * know that.
    150  *
    151  * We also check to see if we received a shutdown signal prior to
    152  * the context entering the run state.  If we did, then we can just
    153  * simply shut the context down now.  This closes the relatively
    154  * small window between start up and entering run via the call
    155  * to dispatch().
    156  *
    157  */
    158 static void
    159 set_ctx_running(isc_task_t *task, isc_event_t *event) {
    160     IGNORE_UNUSED(task);
    161 	dhcp_gbl_ctx.actx_running = ISC_TRUE;
    162 
    163 	if (shutdown_signal) {
    164 		// We got signaled shutdown before we entered running state.
    165 		// Now that we've reached running state, shut'er down.
    166 		isc_app_ctxsuspend(dhcp_gbl_ctx.actx);
    167 	}
    168 
    169         isc_event_free(&event);
    170 }
    171 
    172 isc_result_t
    173 dhcp_context_create(int flags,
    174 		    struct in_addr  *local4,
    175 		    struct in6_addr *local6) {
    176 	isc_result_t result;
    177 
    178 	if ((flags & DHCP_CONTEXT_PRE_DB) != 0) {
    179 		dhcp_gbl_ctx.actx_started = ISC_FALSE;
    180 		dhcp_gbl_ctx.actx_running = ISC_FALSE;
    181 
    182 		/*
    183 		 * Set up the error messages, this isn't the right place
    184 		 * for this call but it is convienent for now.
    185 		 */
    186 		result = dhcp_result_register();
    187 		if (result != ISC_R_SUCCESS) {
    188 			log_fatal("register_table() %s: %u", "failed", result);
    189 		}
    190 
    191 		memset(&dhcp_gbl_ctx, 0, sizeof (dhcp_gbl_ctx));
    192 
    193 		isc_lib_register();
    194 
    195 #if 0
    196 		/* get the current time for use as the random seed */
    197 		gettimeofday(&cur_tv, (struct timezone *)0);
    198 		isc_random_seed(cur_tv.tv_sec);
    199 #endif
    200 
    201 		/* we need to create the memory context before
    202 		 * the lib inits in case we aren't doing NSUPDATE
    203 		 * in which case dst needs a memory context
    204 		 */
    205 		isc_mem_create(&dhcp_gbl_ctx.mctx);
    206 
    207 #if defined (NSUPDATE)
    208 		result = dns_lib_init();
    209 		if (result != ISC_R_SUCCESS)
    210 			goto cleanup;
    211 #else /* defined NSUPDATE */
    212 		/* The dst library is inited as part of dns_lib_init, we don't
    213 		 * need it if NSUPDATE is enabled */
    214 		result = dst_lib_init(dhcp_gbl_ctx.mctx, NULL, 0);
    215 		if (result != ISC_R_SUCCESS)
    216 			goto cleanup;
    217 
    218 #endif /* defined NSUPDATE */
    219 
    220 		result = isc_appctx_create(dhcp_gbl_ctx.mctx,
    221 					   &dhcp_gbl_ctx.actx);
    222 
    223 		result = isc_managers_create(dhcp_gbl_ctx.mctx, 2, 0,
    224 		    &dhcp_gbl_ctx.netmgr, &dhcp_gbl_ctx.taskmgr);
    225 		if (result != ISC_R_SUCCESS)
    226 			goto cleanup;
    227 
    228 		result = isc_socketmgr_create(dhcp_gbl_ctx.mctx,
    229 					      &dhcp_gbl_ctx.socketmgr);
    230 		if (result != ISC_R_SUCCESS)
    231 			goto cleanup;
    232 
    233 		result = isc_timermgr_create(dhcp_gbl_ctx.mctx,
    234 					     &dhcp_gbl_ctx.timermgr);
    235 		if (result != ISC_R_SUCCESS)
    236 			goto cleanup;
    237 
    238 		result = isc_task_create(dhcp_gbl_ctx.taskmgr, 0,
    239 					 &dhcp_gbl_ctx.task);
    240 		if (result != ISC_R_SUCCESS)
    241 			goto cleanup;
    242 
    243 		result = isc_app_ctxstart(dhcp_gbl_ctx.actx);
    244 		if (result != ISC_R_SUCCESS)
    245 			goto cleanup;
    246 
    247 		dhcp_gbl_ctx.actx_started = ISC_TRUE;
    248 
    249 		// Install the onrun callback.
    250 		result = isc_app_ctxonrun(dhcp_gbl_ctx.actx, dhcp_gbl_ctx.mctx,
    251 					  dhcp_gbl_ctx.task, set_ctx_running,
    252 					  dhcp_gbl_ctx.actx);
    253 		if (result != ISC_R_SUCCESS)
    254 			goto cleanup;
    255 
    256 		/* Not all OSs support suppressing SIGPIPE through socket
    257 		 * options, so set the sigal action to be ignore.  This allows
    258 		 * broken connections to fail gracefully with EPIPE on writes */
    259 		handle_signal(SIGPIPE, SIG_IGN);
    260 
    261 		/* Reset handlers installed by isc_app_ctxstart()
    262 		 * to default for control-c and kill */
    263 		handle_signal(SIGINT, SIG_DFL);
    264 		handle_signal(SIGTERM, SIG_DFL);
    265 	}
    266 
    267 #if defined (NSUPDATE)
    268 	if ((flags & DHCP_CONTEXT_POST_DB) != 0) {
    269 		/* Setting addresses only.
    270 		 * All real work will be done later on if needed to avoid
    271 		 * listening on ddns port if client/server was compiled with
    272 		 * ddns support but not using it. */
    273 		if (local4 != NULL) {
    274 			dhcp_gbl_ctx.use_local4 = 1;
    275 			isc_sockaddr_fromin(&dhcp_gbl_ctx.local4_sockaddr,
    276 					    local4, 0);
    277 		}
    278 
    279 		if (local6 != NULL) {
    280 			dhcp_gbl_ctx.use_local6 = 1;
    281 			isc_sockaddr_fromin6(&dhcp_gbl_ctx.local6_sockaddr,
    282 					     local6, 0);
    283 		}
    284 
    285 		if (!(flags & DHCP_DNS_CLIENT_LAZY_INIT)) {
    286 			result = dns_client_init();
    287 		}
    288 	}
    289 #endif /* defined NSUPDATE */
    290 
    291 	return(ISC_R_SUCCESS);
    292 
    293  cleanup:
    294 	/*
    295 	 * Currently we don't try and cleanup, just return an error
    296 	 * expecting that our caller will log the error and exit.
    297 	 */
    298 
    299 	return(result);
    300 }
    301 
    302 /*
    303  * Convert a string name into the proper structure for the isc routines
    304  *
    305  * Previously we allowed names without a trailing '.' however the current
    306  * dns and dst code requires the names to end in a period.  If the
    307  * name doesn't have a trailing period add one as part of creating
    308  * the dns name.
    309  */
    310 
    311 isc_result_t
    312 dhcp_isc_name(unsigned char   *namestr,
    313 	      dns_fixedname_t *namefix,
    314 	      dns_name_t     **name)
    315 {
    316 	size_t namelen;
    317 	isc_buffer_t b;
    318 	isc_result_t result;
    319 
    320 	namelen = strlen((char *)namestr);
    321 	isc_buffer_init(&b, namestr, namelen);
    322 	isc_buffer_add(&b, namelen);
    323 	dns_fixedname_init(namefix);
    324 	*name = dns_fixedname_name(namefix);
    325 	result = dns_name_fromtext(*name, &b, dns_rootname, 0, NULL);
    326 	isc_buffer_invalidate(&b);
    327 	return(result);
    328 }
    329 
    330 isc_result_t
    331 isclib_make_dst_key(char          *inname,
    332 		    char          *algorithm,
    333 		    unsigned char *secret,
    334 		    int            length,
    335 		    dst_key_t    **dstkey)
    336 {
    337 	isc_result_t result;
    338 	dns_name_t *name;
    339 	dns_fixedname_t name0;
    340 	isc_buffer_t b;
    341 	unsigned int algorithm_code;
    342 
    343 	isc_buffer_init(&b, secret, length);
    344 	isc_buffer_add(&b, length);
    345 
    346 	if (strcasecmp(algorithm, DHCP_HMAC_MD5_NAME) == 0) {
    347 		algorithm_code =  DST_ALG_HMACMD5;
    348 	} else if (strcasecmp(algorithm, DHCP_HMAC_SHA1_NAME) == 0) {
    349 		algorithm_code =  DST_ALG_HMACSHA1;
    350 	} else if (strcasecmp(algorithm, DHCP_HMAC_SHA224_NAME) == 0) {
    351 		algorithm_code =  DST_ALG_HMACSHA224;
    352 	} else if (strcasecmp(algorithm, DHCP_HMAC_SHA256_NAME) == 0) {
    353 		algorithm_code =  DST_ALG_HMACSHA256;
    354 	} else if (strcasecmp(algorithm, DHCP_HMAC_SHA384_NAME) == 0) {
    355 		algorithm_code =  DST_ALG_HMACSHA384;
    356 	} else if (strcasecmp(algorithm, DHCP_HMAC_SHA512_NAME) == 0) {
    357 		algorithm_code =  DST_ALG_HMACSHA512;
    358 	} else {
    359 		return(DHCP_R_INVALIDARG);
    360 	}
    361 
    362 	result = dhcp_isc_name((unsigned char *)inname, &name0, &name);
    363 	if (result != ISC_R_SUCCESS) {
    364 		return(result);
    365 	}
    366 
    367 	return(dst_key_frombuffer(name, algorithm_code, DNS_KEYOWNER_ENTITY,
    368 				  DNS_KEYPROTO_DNSSEC, dns_rdataclass_in,
    369 				  &b, dhcp_gbl_ctx.mctx, dstkey));
    370 }
    371 
    372 /**
    373  * signal handler that initiates server shutdown
    374  *
    375  * @param signal signal code that we received
    376  */
    377 void dhcp_signal_handler(int signal) {
    378 	if (shutdown_signal != 0) {
    379 		/* Already in shutdown. */
    380 		return;
    381 	}
    382 
    383 	/* Possible race but does it matter? */
    384 	shutdown_signal = signal;
    385 
    386 	/* If the application context is running tell it to shut down */
    387 	if (dhcp_gbl_ctx.actx_running == ISC_TRUE) {
    388 		(void) isc_app_ctxsuspend(dhcp_gbl_ctx.actx);
    389 	}
    390 }
    391 
    392 #if defined (NSUPDATE)
    393 isc_result_t dns_client_init() {
    394 	isc_result_t result;
    395 	if (dhcp_gbl_ctx.dnsclient == NULL) {
    396 		result = dns_client_create(dhcp_gbl_ctx.mctx,
    397 					   dhcp_gbl_ctx.actx,
    398 					   dhcp_gbl_ctx.taskmgr,
    399 					   dhcp_gbl_ctx.socketmgr,
    400 					   dhcp_gbl_ctx.timermgr,
    401 					   0,
    402 					   &dhcp_gbl_ctx.dnsclient,
    403 					   (dhcp_gbl_ctx.use_local4 ?
    404 					    &dhcp_gbl_ctx.local4_sockaddr
    405 					    : NULL),
    406 					   (dhcp_gbl_ctx.use_local6 ?
    407 					    &dhcp_gbl_ctx.local6_sockaddr
    408 					    : NULL));
    409 
    410 		if (result != ISC_R_SUCCESS) {
    411 			log_error("Unable to create DNS client context:"
    412 				  " result: %d", result);
    413 			return result;
    414 		}
    415 
    416 		/* If we can't set up the servers we may not be able to
    417 		 * do DDNS but we should continue to try and perform
    418 		 * our basic functions and let the user sort it out. */
    419 		result = dhcp_dns_client_setservers();
    420 		if (result != ISC_R_SUCCESS) {
    421 			log_error("Unable to set resolver from resolv.conf; "
    422 				  "startup continuing but DDNS support "
    423 				  "may be affected: result %d", result);
    424 		}
    425 	}
    426 
    427 	return ISC_R_SUCCESS;
    428 }
    429 #endif /* defined (NSUPDATE) */
    430