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