xref: /netbsd-src/external/mpl/dhcp/dist/omapip/isclib.c (revision e6c7e151de239c49d2e38720a061ed9d1fa99309)
1 /*	$NetBSD: isclib.c,v 1.3 2019/01/10 17:41:47 christos Exp $	*/
2 
3 /*
4  * Copyright(c) 2009-2017 by 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  *   950 Charter Street
20  *   Redwood City, CA 94063
21  *   <info@isc.org>
22  *   http://www.isc.org/
23  *
24  */
25 
26 #include <sys/cdefs.h>
27 __RCSID("$NetBSD: isclib.c,v 1.3 2019/01/10 17:41:47 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
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
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_taskmgr_destroy(&dhcp_gbl_ctx.taskmgr);
113 
114 	if (dhcp_gbl_ctx.actx_started != ISC_FALSE) {
115 		isc_app_ctxfinish(dhcp_gbl_ctx.actx);
116 		dhcp_gbl_ctx.actx_started = ISC_FALSE;
117 	}
118 
119 	if (dhcp_gbl_ctx.actx != NULL)
120 		isc_appctx_destroy(&dhcp_gbl_ctx.actx);
121 
122 	if (dhcp_gbl_ctx.mctx != NULL)
123 		isc_mem_detach(&dhcp_gbl_ctx.mctx);
124 
125 	return;
126 }
127 
128 /* Installs a handler for a signal using sigaction */
129 static void
130 handle_signal(int sig, void (*handler)(int)) {
131 	struct sigaction sa;
132 
133 	memset(&sa, 0, sizeof(sa));
134 	sa.sa_handler = handler;
135 	sigfillset(&sa.sa_mask);
136 	if (sigaction(sig, &sa, NULL) != 0) {
137 		log_debug("handle_signal() failed for signal %d error: %s",
138                           sig, strerror(errno));
139 	}
140 }
141 
142 isc_result_t
143 dhcp_context_create(int flags,
144 		    struct in_addr  *local4,
145 		    struct in6_addr *local6) {
146 	isc_result_t result;
147 
148 	if ((flags & DHCP_CONTEXT_PRE_DB) != 0) {
149 		/*
150 		 * Set up the error messages, this isn't the right place
151 		 * for this call but it is convienent for now.
152 		 */
153 		result = dhcp_result_register();
154 		if (result != ISC_R_SUCCESS) {
155 			log_fatal("register_table() %s: %u", "failed", result);
156 		}
157 
158 		memset(&dhcp_gbl_ctx, 0, sizeof (dhcp_gbl_ctx));
159 
160 		isc_lib_register();
161 
162 #if 0
163 		/* get the current time for use as the random seed */
164 		gettimeofday(&cur_tv, (struct timezone *)0);
165 		isc_random_seed(cur_tv.tv_sec);
166 #endif
167 
168 		/* we need to create the memory context before
169 		 * the lib inits in case we aren't doing NSUPDATE
170 		 * in which case dst needs a memory context
171 		 */
172 		result = isc_mem_create(0, 0, &dhcp_gbl_ctx.mctx);
173 		if (result != ISC_R_SUCCESS)
174 			goto cleanup;
175 
176 
177 #if defined (NSUPDATE)
178 		result = dns_lib_init();
179 		if (result != ISC_R_SUCCESS)
180 			goto cleanup;
181 #else
182 		/* The dst library is inited as part of dns_lib_init, we don't
183 		 * need it if NSUPDATE is enabled */
184 		result = dst_lib_init(dhcp_gbl_ctx.mctx, NULL, 0);
185 		if (result != ISC_R_SUCCESS)
186 			goto cleanup;
187 
188 #endif
189 
190 		result = isc_appctx_create(dhcp_gbl_ctx.mctx,
191 					   &dhcp_gbl_ctx.actx);
192 		if (result != ISC_R_SUCCESS)
193 			goto cleanup;
194 
195 		result = isc_taskmgr_createinctx(dhcp_gbl_ctx.mctx,
196 						 dhcp_gbl_ctx.actx,
197 						 1, 0,
198 						 &dhcp_gbl_ctx.taskmgr);
199 		if (result != ISC_R_SUCCESS)
200 			goto cleanup;
201 
202 		result = isc_socketmgr_createinctx(dhcp_gbl_ctx.mctx,
203 						   dhcp_gbl_ctx.actx,
204 						   &dhcp_gbl_ctx.socketmgr);
205 		if (result != ISC_R_SUCCESS)
206 			goto cleanup;
207 
208 		result = isc_timermgr_createinctx(dhcp_gbl_ctx.mctx,
209 						  dhcp_gbl_ctx.actx,
210 						  &dhcp_gbl_ctx.timermgr);
211 		if (result != ISC_R_SUCCESS)
212 			goto cleanup;
213 
214 		result = isc_task_create(dhcp_gbl_ctx.taskmgr, 0, &dhcp_gbl_ctx.task);
215 		if (result != ISC_R_SUCCESS)
216 			goto cleanup;
217 
218 		result = isc_app_ctxstart(dhcp_gbl_ctx.actx);
219 		if (result != ISC_R_SUCCESS)
220 			return (result);
221 		dhcp_gbl_ctx.actx_started = ISC_TRUE;
222 
223 		/* Not all OSs support suppressing SIGPIPE through socket
224 		 * options, so set the sigal action to be ignore.  This allows
225 		 * broken connections to fail gracefully with EPIPE on writes */
226 		handle_signal(SIGPIPE, SIG_IGN);
227 
228 		/* Reset handlers installed by isc_app_ctxstart()
229 		 * to default for control-c and kill */
230 		handle_signal(SIGINT, SIG_DFL);
231 		handle_signal(SIGTERM, SIG_DFL);
232 	}
233 
234 #if defined (NSUPDATE)
235 	if ((flags & DHCP_CONTEXT_POST_DB) != 0) {
236 		/* Setting addresses only.
237 		 * All real work will be done later on if needed to avoid
238 		 * listening on ddns port if client/server was compiled with
239 		 * ddns support but not using it. */
240 		if (local4 != NULL) {
241 			dhcp_gbl_ctx.use_local4 = 1;
242 			isc_sockaddr_fromin(&dhcp_gbl_ctx.local4_sockaddr,
243 					    local4, 0);
244 		}
245 
246 		if (local6 != NULL) {
247 			dhcp_gbl_ctx.use_local6 = 1;
248 			isc_sockaddr_fromin6(&dhcp_gbl_ctx.local6_sockaddr,
249 					     local6, 0);
250 		}
251 
252 		if (!(flags & DHCP_DNS_CLIENT_LAZY_INIT)) {
253 			result = dns_client_init();
254 		}
255 	}
256 #endif
257 
258 	return(ISC_R_SUCCESS);
259 
260  cleanup:
261 	/*
262 	 * Currently we don't try and cleanup, just return an error
263 	 * expecting that our caller will log the error and exit.
264 	 */
265 
266 	return(result);
267 }
268 
269 /*
270  * Convert a string name into the proper structure for the isc routines
271  *
272  * Previously we allowed names without a trailing '.' however the current
273  * dns and dst code requires the names to end in a period.  If the
274  * name doesn't have a trailing period add one as part of creating
275  * the dns name.
276  */
277 
278 isc_result_t
279 dhcp_isc_name(unsigned char   *namestr,
280 	      dns_fixedname_t *namefix,
281 	      dns_name_t     **name)
282 {
283 	size_t namelen;
284 	isc_buffer_t b;
285 	isc_result_t result;
286 
287 	namelen = strlen((char *)namestr);
288 	isc_buffer_init(&b, namestr, namelen);
289 	isc_buffer_add(&b, namelen);
290 	dns_fixedname_init(namefix);
291 	*name = dns_fixedname_name(namefix);
292 	result = dns_name_fromtext(*name, &b, dns_rootname, 0, NULL);
293 	isc_buffer_invalidate(&b);
294 	return(result);
295 }
296 
297 isc_result_t
298 isclib_make_dst_key(char          *inname,
299 		    char          *algorithm,
300 		    unsigned char *secret,
301 		    int            length,
302 		    dst_key_t    **dstkey)
303 {
304 	isc_result_t result;
305 	dns_name_t *name;
306 	dns_fixedname_t name0;
307 	isc_buffer_t b;
308 	unsigned int algorithm_code;
309 
310 	isc_buffer_init(&b, secret, length);
311 	isc_buffer_add(&b, length);
312 
313 	if (strcasecmp(algorithm, DHCP_HMAC_MD5_NAME) == 0) {
314 		algorithm_code =  DST_ALG_HMACMD5;
315 	} else if (strcasecmp(algorithm, DHCP_HMAC_SHA1_NAME) == 0) {
316 		algorithm_code =  DST_ALG_HMACSHA1;
317 	} else if (strcasecmp(algorithm, DHCP_HMAC_SHA224_NAME) == 0) {
318 		algorithm_code =  DST_ALG_HMACSHA224;
319 	} else if (strcasecmp(algorithm, DHCP_HMAC_SHA256_NAME) == 0) {
320 		algorithm_code =  DST_ALG_HMACSHA256;
321 	} else if (strcasecmp(algorithm, DHCP_HMAC_SHA384_NAME) == 0) {
322 		algorithm_code =  DST_ALG_HMACSHA384;
323 	} else if (strcasecmp(algorithm, DHCP_HMAC_SHA512_NAME) == 0) {
324 		algorithm_code =  DST_ALG_HMACSHA512;
325 	} else {
326 		return(DHCP_R_INVALIDARG);
327 	}
328 
329 	result = dhcp_isc_name((unsigned char *)inname, &name0, &name);
330 	if (result != ISC_R_SUCCESS) {
331 		return(result);
332 	}
333 
334 	return(dst_key_frombuffer(name, algorithm_code, DNS_KEYOWNER_ENTITY,
335 				  DNS_KEYPROTO_DNSSEC, dns_rdataclass_in,
336 				  &b, dhcp_gbl_ctx.mctx, dstkey));
337 }
338 
339 /**
340  * signal handler that initiates server shutdown
341  *
342  * @param signal signal code that we received
343  */
344 void dhcp_signal_handler(int signal) {
345 	isc_appctx_t *ctx = dhcp_gbl_ctx.actx;
346 	int prev = shutdown_signal;
347 
348 	if (prev != 0) {
349 		/* Already in shutdown. */
350 		return;
351 	}
352 	/* Possible race but does it matter? */
353 	shutdown_signal = signal;
354 
355 	/* Use reload (aka suspend) for easier dispatch() reenter. */
356 	if (ctx) {
357 		(void) isc_app_ctxsuspend(ctx);
358 	}
359 }
360 
361 isc_result_t dns_client_init() {
362 	isc_result_t result;
363 	if (dhcp_gbl_ctx.dnsclient == NULL) {
364 		result = dns_client_createx(dhcp_gbl_ctx.mctx,
365 					     dhcp_gbl_ctx.actx,
366 					     dhcp_gbl_ctx.taskmgr,
367 					     dhcp_gbl_ctx.socketmgr,
368 					     dhcp_gbl_ctx.timermgr,
369 					     0,
370 					     &dhcp_gbl_ctx.dnsclient,
371 					     (dhcp_gbl_ctx.use_local4 ?
372 					      &dhcp_gbl_ctx.local4_sockaddr
373 					      : NULL),
374 					     (dhcp_gbl_ctx.use_local6 ?
375 					      &dhcp_gbl_ctx.local6_sockaddr
376 					      : NULL));
377 
378 		if (result != ISC_R_SUCCESS) {
379 			log_error("Unable to create DNS client context:"
380 				  " result: %d", result);
381 			return result;
382 		}
383 
384 		/* If we can't set up the servers we may not be able to
385 		 * do DDNS but we should continue to try and perform
386 		 * our basic functions and let the user sort it out. */
387 		result = dhcp_dns_client_setservers();
388 		if (result != ISC_R_SUCCESS) {
389 			log_error("Unable to set resolver from resolv.conf; "
390 				  "startup continuing but DDNS support "
391 				  "may be affected: result %d", result);
392 		}
393 	}
394 
395 	return ISC_R_SUCCESS;
396 }
397