2 * Copyright(c) 2009-2019 by Internet Systems Consortium, Inc.("ISC")
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/.
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.
16 * Internet Systems Consortium, Inc.
18 * Redwood City, CA 94063
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 */
33 dhcp_context_t dhcp_gbl_ctx
;
34 int shutdown_signal
= 0;
36 #if defined (NSUPDATE)
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
44 dhcp_dns_client_setservers(void)
47 irs_resconf_t
*resconf
= NULL
;
48 isc_sockaddrlist_t
*nameservers
;
51 result
= irs_resconf_load(dhcp_gbl_ctx
.mctx
, _PATH_RESOLV_CONF
,
53 if (result
!= ISC_R_SUCCESS
&& result
!= ISC_R_FILENOTFOUND
) {
54 log_error("irs_resconf_load failed: %d.", result
);
58 nameservers
= irs_resconf_getnameservers(resconf
);
60 /* Initialize port numbers */
61 for (sa
= ISC_LIST_HEAD(*nameservers
);
63 sa
= ISC_LIST_NEXT(sa
, link
)) {
64 switch (sa
->type
.sa
.sa_family
) {
66 sa
->type
.sin
.sin_port
= htons(NS_DEFAULTPORT
);
69 sa
->type
.sin6
.sin6_port
= htons(NS_DEFAULTPORT
);
76 result
= dns_client_setservers(dhcp_gbl_ctx
.dnsclient
,
79 if (result
!= ISC_R_SUCCESS
) {
80 log_error("dns_client_setservers failed: %d.",
85 #endif /* defined NSUPDATE */
90 #if defined (NSUPDATE)
91 if (dhcp_gbl_ctx
.dnsclient
!= NULL
)
92 dns_client_destroy((dns_client_t
**)&dhcp_gbl_ctx
.dnsclient
);
93 #endif /* defined NSUPDATE */
95 if (dhcp_gbl_ctx
.task
!= NULL
) {
96 isc_task_shutdown(dhcp_gbl_ctx
.task
);
97 isc_task_detach(&dhcp_gbl_ctx
.task
);
100 if (dhcp_gbl_ctx
.timermgr
!= NULL
)
101 isc_timermgr_destroy(&dhcp_gbl_ctx
.timermgr
);
103 if (dhcp_gbl_ctx
.socketmgr
!= NULL
)
104 isc_socketmgr_destroy(&dhcp_gbl_ctx
.socketmgr
);
106 if (dhcp_gbl_ctx
.taskmgr
!= NULL
)
107 isc_taskmgr_destroy(&dhcp_gbl_ctx
.taskmgr
);
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
;
114 if (dhcp_gbl_ctx
.actx
!= NULL
)
115 isc_appctx_destroy(&dhcp_gbl_ctx
.actx
);
117 if (dhcp_gbl_ctx
.mctx
!= NULL
)
118 isc_mem_detach(&dhcp_gbl_ctx
.mctx
);
123 /* Installs a handler for a signal using sigaction */
125 handle_signal(int sig
, void (*handler
)(int)) {
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
));
137 /* Callback passed to isc_app_ctxonrun
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
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
153 set_ctx_running(isc_task_t
*task
, isc_event_t
*event
) {
155 dhcp_gbl_ctx
.actx_running
= ISC_TRUE
;
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
);
163 isc_event_free(&event
);
167 dhcp_context_create(int flags
,
168 struct in_addr
*local4
,
169 struct in6_addr
*local6
) {
172 if ((flags
& DHCP_CONTEXT_PRE_DB
) != 0) {
173 dhcp_gbl_ctx
.actx_started
= ISC_FALSE
;
174 dhcp_gbl_ctx
.actx_running
= ISC_FALSE
;
177 * Set up the error messages, this isn't the right place
178 * for this call but it is convienent for now.
180 result
= dhcp_result_register();
181 if (result
!= ISC_R_SUCCESS
) {
182 log_fatal("register_table() %s: %u", "failed", result
);
185 memset(&dhcp_gbl_ctx
, 0, sizeof (dhcp_gbl_ctx
));
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
);
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
197 result
= isc_mem_create(0, 0, &dhcp_gbl_ctx
.mctx
);
198 if (result
!= ISC_R_SUCCESS
)
202 #if defined (NSUPDATE)
203 result
= dns_lib_init();
204 if (result
!= ISC_R_SUCCESS
)
206 #else /* defined NSUPDATE */
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
)
213 #endif /* defined NSUPDATE */
215 result
= isc_appctx_create(dhcp_gbl_ctx
.mctx
,
217 if (result
!= ISC_R_SUCCESS
)
220 result
= isc_taskmgr_createinctx(dhcp_gbl_ctx
.mctx
,
223 &dhcp_gbl_ctx
.taskmgr
);
224 if (result
!= ISC_R_SUCCESS
)
227 result
= isc_socketmgr_createinctx(dhcp_gbl_ctx
.mctx
,
229 &dhcp_gbl_ctx
.socketmgr
);
230 if (result
!= ISC_R_SUCCESS
)
233 result
= isc_timermgr_createinctx(dhcp_gbl_ctx
.mctx
,
235 &dhcp_gbl_ctx
.timermgr
);
236 if (result
!= ISC_R_SUCCESS
)
239 result
= isc_task_create(dhcp_gbl_ctx
.taskmgr
, 0,
241 if (result
!= ISC_R_SUCCESS
)
244 result
= isc_app_ctxstart(dhcp_gbl_ctx
.actx
);
245 if (result
!= ISC_R_SUCCESS
)
248 dhcp_gbl_ctx
.actx_started
= ISC_TRUE
;
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
,
254 if (result
!= ISC_R_SUCCESS
)
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
);
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
);
268 #if defined (NSUPDATE)
269 if ((flags
& DHCP_CONTEXT_POST_DB
) != 0) {
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. */
274 if (local4
!= NULL
) {
275 dhcp_gbl_ctx
.use_local4
= 1;
276 isc_sockaddr_fromin(&dhcp_gbl_ctx
.local4_sockaddr
,
280 if (local6
!= NULL
) {
281 dhcp_gbl_ctx
.use_local6
= 1;
282 isc_sockaddr_fromin6(&dhcp_gbl_ctx
.local6_sockaddr
,
286 if (!(flags
& DHCP_DNS_CLIENT_LAZY_INIT
)) {
287 result
= dns_client_init();
290 #endif /* defined NSUPDATE */
292 return(ISC_R_SUCCESS
);
296 * Currently we don't try and cleanup, just return an error
297 * expecting that our caller will log the error and exit.
304 * Convert a string name into the proper structure for the isc routines
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
313 dhcp_isc_name(unsigned char *namestr
,
314 dns_fixedname_t
*namefix
,
321 namelen
= strlen((char *)namestr
);
322 isc_buffer_init(&b
, namestr
, namelen
);
323 isc_buffer_add(&b
, namelen
);
324 dns_fixedname_init(namefix
);
325 *name
= dns_fixedname_name(namefix
);
326 result
= dns_name_fromtext(*name
, &b
, dns_rootname
, 0, NULL
);
327 isc_buffer_invalidate(&b
);
332 isclib_make_dst_key(char *inname
,
334 unsigned char *secret
,
340 dns_fixedname_t name0
;
342 unsigned int algorithm_code
;
344 isc_buffer_init(&b
, secret
, length
);
345 isc_buffer_add(&b
, length
);
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
;
360 return(DHCP_R_INVALIDARG
);
363 result
= dhcp_isc_name((unsigned char *)inname
, &name0
, &name
);
364 if (result
!= ISC_R_SUCCESS
) {
368 return(dst_key_frombuffer(name
, algorithm_code
, DNS_KEYOWNER_ENTITY
,
369 DNS_KEYPROTO_DNSSEC
, dns_rdataclass_in
,
370 &b
, dhcp_gbl_ctx
.mctx
, dstkey
));
374 * signal handler that initiates server shutdown
376 * @param signal signal code that we received
378 void dhcp_signal_handler(int signal
) {
379 if (shutdown_signal
!= 0) {
380 /* Already in shutdown. */
384 /* Possible race but does it matter? */
385 shutdown_signal
= signal
;
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
);
393 #if defined (NSUPDATE)
394 isc_result_t
dns_client_init() {
396 if (dhcp_gbl_ctx
.dnsclient
== NULL
) {
397 result
= dns_client_createx2(dhcp_gbl_ctx
.mctx
,
399 dhcp_gbl_ctx
.taskmgr
,
400 dhcp_gbl_ctx
.socketmgr
,
401 dhcp_gbl_ctx
.timermgr
,
403 &dhcp_gbl_ctx
.dnsclient
,
404 (dhcp_gbl_ctx
.use_local4
?
405 &dhcp_gbl_ctx
.local4_sockaddr
407 (dhcp_gbl_ctx
.use_local6
?
408 &dhcp_gbl_ctx
.local6_sockaddr
411 if (result
!= ISC_R_SUCCESS
) {
412 log_error("Unable to create DNS client context:"
413 " result: %d", result
);
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
);
428 return ISC_R_SUCCESS
;
430 #endif /* defined (NSUPDATE) */