]>
Commit | Line | Data |
---|---|---|
98bf1607 | 1 | /* |
49a7fb58 | 2 | * Copyright(C) 2009-2022 Internet Systems Consortium, Inc.("ISC") |
98bf1607 | 3 | * |
7512d88b TM |
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/. | |
98bf1607 SR |
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. | |
429a56d7 TM |
17 | * PO Box 360 |
18 | * Newmarket, NH 03857 USA | |
98bf1607 SR |
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. | |
ae91e4db | 25 | It looks like we want/need the library but need the fdwatchcommand |
98bf1607 SR |
26 | which may be a problem */ |
27 | ||
28 | #include "dhcpd.h" | |
29 | ||
3ac2a573 | 30 | #include <sys/time.h> |
47e8308d | 31 | #include <signal.h> |
3ac2a573 | 32 | |
98bf1607 | 33 | dhcp_context_t dhcp_gbl_ctx; |
0895c955 | 34 | int shutdown_signal = 0; |
98bf1607 | 35 | |
e54ff84f SR |
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 | */ | |
f6b8f48d | 43 | isc_result_t |
e54ff84f SR |
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); | |
22ceb8bb | 53 | if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) { |
e54ff84f SR |
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 | } | |
650ae59e | 85 | #endif /* defined NSUPDATE */ |
e54ff84f | 86 | |
98bf1607 SR |
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); | |
650ae59e | 93 | #endif /* defined NSUPDATE */ |
98bf1607 SR |
94 | |
95 | if (dhcp_gbl_ctx.task != NULL) { | |
98bf1607 SR |
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 | ||
6067cd48 TM |
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 | ||
0cd94b5e TM |
137 | /* Callback passed to isc_app_ctxonrun |
138 | * | |
139 | * BIND9 context code will invoke this handler once the context has | |
140 | * entered the running state. We use it to set a global marker so that | |
141 | * we can tell if the context is running. Several of the isc_app_ | |
142 | * calls REQUIRE that the context is running and we need a way to | |
143 | * know that. | |
144 | * | |
145 | * We also check to see if we received a shutdown signal prior to | |
146 | * the context entering the run state. If we did, then we can just | |
147 | * simply shut the context down now. This closes the relatively | |
148 | * small window between start up and entering run via the call | |
149 | * to dispatch(). | |
150 | * | |
151 | */ | |
152 | static void | |
153 | set_ctx_running(isc_task_t *task, isc_event_t *event) { | |
154 | IGNORE_UNUSED(task); | |
155 | dhcp_gbl_ctx.actx_running = ISC_TRUE; | |
156 | ||
157 | if (shutdown_signal) { | |
158 | // We got signaled shutdown before we entered running state. | |
159 | // Now that we've reached running state, shut'er down. | |
160 | isc_app_ctxsuspend(dhcp_gbl_ctx.actx); | |
161 | } | |
162 | ||
163 | isc_event_free(&event); | |
164 | } | |
165 | ||
98bf1607 | 166 | isc_result_t |
61ef216b SR |
167 | dhcp_context_create(int flags, |
168 | struct in_addr *local4, | |
169 | struct in6_addr *local6) { | |
98bf1607 SR |
170 | isc_result_t result; |
171 | ||
61ef216b | 172 | if ((flags & DHCP_CONTEXT_PRE_DB) != 0) { |
0cd94b5e TM |
173 | dhcp_gbl_ctx.actx_started = ISC_FALSE; |
174 | dhcp_gbl_ctx.actx_running = ISC_FALSE; | |
175 | ||
61ef216b SR |
176 | /* |
177 | * Set up the error messages, this isn't the right place | |
178 | * for this call but it is convienent for now. | |
179 | */ | |
180 | result = dhcp_result_register(); | |
181 | if (result != ISC_R_SUCCESS) { | |
182 | log_fatal("register_table() %s: %u", "failed", result); | |
183 | } | |
98bf1607 | 184 | |
61ef216b | 185 | memset(&dhcp_gbl_ctx, 0, sizeof (dhcp_gbl_ctx)); |
f6b8f48d | 186 | |
61ef216b | 187 | isc_lib_register(); |
98bf1607 | 188 | |
61ef216b SR |
189 | /* get the current time for use as the random seed */ |
190 | gettimeofday(&cur_tv, (struct timezone *)0); | |
191 | isc_random_seed(cur_tv.tv_sec); | |
98bf1607 | 192 | |
158a34fb SR |
193 | /* we need to create the memory context before |
194 | * the lib inits in case we aren't doing NSUPDATE | |
195 | * in which case dst needs a memory context | |
196 | */ | |
197 | result = isc_mem_create(0, 0, &dhcp_gbl_ctx.mctx); | |
198 | if (result != ISC_R_SUCCESS) | |
199 | goto cleanup; | |
200 | ||
201 | ||
98bf1607 | 202 | #if defined (NSUPDATE) |
61ef216b SR |
203 | result = dns_lib_init(); |
204 | if (result != ISC_R_SUCCESS) | |
205 | goto cleanup; | |
650ae59e | 206 | #else /* defined NSUPDATE */ |
61ef216b SR |
207 | /* The dst library is inited as part of dns_lib_init, we don't |
208 | * need it if NSUPDATE is enabled */ | |
209 | result = dst_lib_init(dhcp_gbl_ctx.mctx, NULL, 0); | |
210 | if (result != ISC_R_SUCCESS) | |
211 | goto cleanup; | |
98bf1607 | 212 | |
650ae59e | 213 | #endif /* defined NSUPDATE */ |
61ef216b SR |
214 | |
215 | result = isc_appctx_create(dhcp_gbl_ctx.mctx, | |
216 | &dhcp_gbl_ctx.actx); | |
217 | if (result != ISC_R_SUCCESS) | |
218 | goto cleanup; | |
219 | ||
61ef216b SR |
220 | result = isc_taskmgr_createinctx(dhcp_gbl_ctx.mctx, |
221 | dhcp_gbl_ctx.actx, | |
222 | 1, 0, | |
223 | &dhcp_gbl_ctx.taskmgr); | |
224 | if (result != ISC_R_SUCCESS) | |
225 | goto cleanup; | |
226 | ||
227 | result = isc_socketmgr_createinctx(dhcp_gbl_ctx.mctx, | |
228 | dhcp_gbl_ctx.actx, | |
229 | &dhcp_gbl_ctx.socketmgr); | |
230 | if (result != ISC_R_SUCCESS) | |
231 | goto cleanup; | |
232 | ||
233 | result = isc_timermgr_createinctx(dhcp_gbl_ctx.mctx, | |
234 | dhcp_gbl_ctx.actx, | |
235 | &dhcp_gbl_ctx.timermgr); | |
236 | if (result != ISC_R_SUCCESS) | |
237 | goto cleanup; | |
238 | ||
0cd94b5e TM |
239 | result = isc_task_create(dhcp_gbl_ctx.taskmgr, 0, |
240 | &dhcp_gbl_ctx.task); | |
61ef216b SR |
241 | if (result != ISC_R_SUCCESS) |
242 | goto cleanup; | |
0985d149 FD |
243 | |
244 | result = isc_app_ctxstart(dhcp_gbl_ctx.actx); | |
245 | if (result != ISC_R_SUCCESS) | |
0cd94b5e TM |
246 | goto cleanup; |
247 | ||
0985d149 FD |
248 | dhcp_gbl_ctx.actx_started = ISC_TRUE; |
249 | ||
0cd94b5e TM |
250 | // Install the onrun callback. |
251 | result = isc_app_ctxonrun(dhcp_gbl_ctx.actx, dhcp_gbl_ctx.mctx, | |
252 | dhcp_gbl_ctx.task, set_ctx_running, | |
253 | dhcp_gbl_ctx.actx); | |
254 | if (result != ISC_R_SUCCESS) | |
255 | goto cleanup; | |
256 | ||
0985d149 FD |
257 | /* Not all OSs support suppressing SIGPIPE through socket |
258 | * options, so set the sigal action to be ignore. This allows | |
259 | * broken connections to fail gracefully with EPIPE on writes */ | |
260 | handle_signal(SIGPIPE, SIG_IGN); | |
261 | ||
262 | /* Reset handlers installed by isc_app_ctxstart() | |
263 | * to default for control-c and kill */ | |
264 | handle_signal(SIGINT, SIG_DFL); | |
265 | handle_signal(SIGTERM, SIG_DFL); | |
61ef216b | 266 | } |
98bf1607 SR |
267 | |
268 | #if defined (NSUPDATE) | |
61ef216b | 269 | if ((flags & DHCP_CONTEXT_POST_DB) != 0) { |
ca22af89 TM |
270 | /* Setting addresses only. |
271 | * All real work will be done later on if needed to avoid | |
272 | * listening on ddns port if client/server was compiled with | |
273 | * ddns support but not using it. */ | |
61ef216b | 274 | if (local4 != NULL) { |
ca22af89 TM |
275 | dhcp_gbl_ctx.use_local4 = 1; |
276 | isc_sockaddr_fromin(&dhcp_gbl_ctx.local4_sockaddr, | |
277 | local4, 0); | |
61ef216b | 278 | } |
ca22af89 | 279 | |
61ef216b | 280 | if (local6 != NULL) { |
ca22af89 TM |
281 | dhcp_gbl_ctx.use_local6 = 1; |
282 | isc_sockaddr_fromin6(&dhcp_gbl_ctx.local6_sockaddr, | |
283 | local6, 0); | |
61ef216b | 284 | } |
98bf1607 | 285 | |
ca22af89 TM |
286 | if (!(flags & DHCP_DNS_CLIENT_LAZY_INIT)) { |
287 | result = dns_client_init(); | |
0ab4a716 | 288 | } |
61ef216b | 289 | } |
650ae59e | 290 | #endif /* defined NSUPDATE */ |
61ef216b | 291 | |
98bf1607 SR |
292 | return(ISC_R_SUCCESS); |
293 | ||
294 | cleanup: | |
d122accf SR |
295 | /* |
296 | * Currently we don't try and cleanup, just return an error | |
297 | * expecting that our caller will log the error and exit. | |
298 | */ | |
98bf1607 SR |
299 | |
300 | return(result); | |
301 | } | |
302 | ||
f4bc8261 SR |
303 | /* |
304 | * Convert a string name into the proper structure for the isc routines | |
305 | * | |
306 | * Previously we allowed names without a trailing '.' however the current | |
307 | * dns and dst code requires the names to end in a period. If the | |
308 | * name doesn't have a trailing period add one as part of creating | |
309 | * the dns name. | |
310 | */ | |
311 | ||
98bf1607 SR |
312 | isc_result_t |
313 | dhcp_isc_name(unsigned char *namestr, | |
314 | dns_fixedname_t *namefix, | |
315 | dns_name_t **name) | |
316 | { | |
317 | size_t namelen; | |
318 | isc_buffer_t b; | |
319 | isc_result_t result; | |
f4bc8261 | 320 | |
f6b8f48d | 321 | namelen = strlen((char *)namestr); |
98bf1607 SR |
322 | isc_buffer_init(&b, namestr, namelen); |
323 | isc_buffer_add(&b, namelen); | |
324 | dns_fixedname_init(namefix); | |
325 | *name = dns_fixedname_name(namefix); | |
f4bc8261 | 326 | result = dns_name_fromtext(*name, &b, dns_rootname, 0, NULL); |
98bf1607 SR |
327 | isc_buffer_invalidate(&b); |
328 | return(result); | |
329 | } | |
330 | ||
331 | isc_result_t | |
332 | isclib_make_dst_key(char *inname, | |
333 | char *algorithm, | |
334 | unsigned char *secret, | |
335 | int length, | |
336 | dst_key_t **dstkey) | |
337 | { | |
338 | isc_result_t result; | |
339 | dns_name_t *name; | |
340 | dns_fixedname_t name0; | |
341 | isc_buffer_t b; | |
3ffc07de | 342 | unsigned int algorithm_code; |
98bf1607 SR |
343 | |
344 | isc_buffer_init(&b, secret, length); | |
345 | isc_buffer_add(&b, length); | |
346 | ||
3ffc07de TM |
347 | if (strcasecmp(algorithm, DHCP_HMAC_MD5_NAME) == 0) { |
348 | algorithm_code = DST_ALG_HMACMD5; | |
349 | } else if (strcasecmp(algorithm, DHCP_HMAC_SHA1_NAME) == 0) { | |
350 | algorithm_code = DST_ALG_HMACSHA1; | |
351 | } else if (strcasecmp(algorithm, DHCP_HMAC_SHA224_NAME) == 0) { | |
352 | algorithm_code = DST_ALG_HMACSHA224; | |
353 | } else if (strcasecmp(algorithm, DHCP_HMAC_SHA256_NAME) == 0) { | |
354 | algorithm_code = DST_ALG_HMACSHA256; | |
355 | } else if (strcasecmp(algorithm, DHCP_HMAC_SHA384_NAME) == 0) { | |
356 | algorithm_code = DST_ALG_HMACSHA384; | |
357 | } else if (strcasecmp(algorithm, DHCP_HMAC_SHA512_NAME) == 0) { | |
358 | algorithm_code = DST_ALG_HMACSHA512; | |
359 | } else { | |
98bf1607 SR |
360 | return(DHCP_R_INVALIDARG); |
361 | } | |
362 | ||
f4bc8261 | 363 | result = dhcp_isc_name((unsigned char *)inname, &name0, &name); |
98bf1607 SR |
364 | if (result != ISC_R_SUCCESS) { |
365 | return(result); | |
366 | } | |
367 | ||
3ffc07de | 368 | return(dst_key_frombuffer(name, algorithm_code, DNS_KEYOWNER_ENTITY, |
98bf1607 SR |
369 | DNS_KEYPROTO_DNSSEC, dns_rdataclass_in, |
370 | &b, dhcp_gbl_ctx.mctx, dstkey)); | |
371 | } | |
372 | ||
47e8308d SR |
373 | /** |
374 | * signal handler that initiates server shutdown | |
375 | * | |
376 | * @param signal signal code that we received | |
377 | */ | |
378 | void dhcp_signal_handler(int signal) { | |
0cd94b5e | 379 | if (shutdown_signal != 0) { |
0895c955 SR |
380 | /* Already in shutdown. */ |
381 | return; | |
382 | } | |
0cd94b5e | 383 | |
0895c955 SR |
384 | /* Possible race but does it matter? */ |
385 | shutdown_signal = signal; | |
386 | ||
0cd94b5e TM |
387 | /* If the application context is running tell it to shut down */ |
388 | if (dhcp_gbl_ctx.actx_running == ISC_TRUE) { | |
389 | (void) isc_app_ctxsuspend(dhcp_gbl_ctx.actx); | |
47e8308d SR |
390 | } |
391 | } | |
ca22af89 | 392 | |
1c779d3b | 393 | #if defined (NSUPDATE) |
ca22af89 TM |
394 | isc_result_t dns_client_init() { |
395 | isc_result_t result; | |
396 | if (dhcp_gbl_ctx.dnsclient == NULL) { | |
397 | result = dns_client_createx2(dhcp_gbl_ctx.mctx, | |
398 | dhcp_gbl_ctx.actx, | |
399 | dhcp_gbl_ctx.taskmgr, | |
400 | dhcp_gbl_ctx.socketmgr, | |
401 | dhcp_gbl_ctx.timermgr, | |
402 | 0, | |
403 | &dhcp_gbl_ctx.dnsclient, | |
404 | (dhcp_gbl_ctx.use_local4 ? | |
405 | &dhcp_gbl_ctx.local4_sockaddr | |
406 | : NULL), | |
407 | (dhcp_gbl_ctx.use_local6 ? | |
408 | &dhcp_gbl_ctx.local6_sockaddr | |
409 | : NULL)); | |
410 | ||
411 | if (result != ISC_R_SUCCESS) { | |
412 | log_error("Unable to create DNS client context:" | |
413 | " result: %d", result); | |
414 | return result; | |
415 | } | |
416 | ||
417 | /* If we can't set up the servers we may not be able to | |
418 | * do DDNS but we should continue to try and perform | |
419 | * our basic functions and let the user sort it out. */ | |
420 | result = dhcp_dns_client_setservers(); | |
421 | if (result != ISC_R_SUCCESS) { | |
422 | log_error("Unable to set resolver from resolv.conf; " | |
423 | "startup continuing but DDNS support " | |
424 | "may be affected: result %d", result); | |
425 | } | |
426 | } | |
427 | ||
428 | return ISC_R_SUCCESS; | |
429 | } | |
650ae59e | 430 | #endif /* defined (NSUPDATE) */ |