ISC DHCP  4.4.2-P1
A reference DHCPv4 and DHCPv6 implementation
isclib.c
Go to the documentation of this file.
1 /*
2  * Copyright(c) 2009-2019 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 
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 /* defined NSUPDATE */
86 
87 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 /* defined NSUPDATE */
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 
110  isc_app_ctxfinish(dhcp_gbl_ctx.actx);
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 /* 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);
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 
166 isc_result_t
168  struct in_addr *local4,
169  struct in6_addr *local6) {
170  isc_result_t result;
171 
172  if ((flags & DHCP_CONTEXT_PRE_DB) != 0) {
175 
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  }
184 
185  memset(&dhcp_gbl_ctx, 0, sizeof (dhcp_gbl_ctx));
186 
187  isc_lib_register();
188 
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);
192 
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 
202 #if defined (NSUPDATE)
203  result = dns_lib_init();
204  if (result != ISC_R_SUCCESS)
205  goto cleanup;
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)
211  goto cleanup;
212 
213 #endif /* defined NSUPDATE */
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 
220  result = isc_taskmgr_createinctx(dhcp_gbl_ctx.mctx,
222  1, 0,
224  if (result != ISC_R_SUCCESS)
225  goto cleanup;
226 
227  result = isc_socketmgr_createinctx(dhcp_gbl_ctx.mctx,
230  if (result != ISC_R_SUCCESS)
231  goto cleanup;
232 
233  result = isc_timermgr_createinctx(dhcp_gbl_ctx.mctx,
236  if (result != ISC_R_SUCCESS)
237  goto cleanup;
238 
239  result = isc_task_create(dhcp_gbl_ctx.taskmgr, 0,
240  &dhcp_gbl_ctx.task);
241  if (result != ISC_R_SUCCESS)
242  goto cleanup;
243 
244  result = isc_app_ctxstart(dhcp_gbl_ctx.actx);
245  if (result != ISC_R_SUCCESS)
246  goto cleanup;
247 
249 
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)
255  goto cleanup;
256 
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);
266  }
267 
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,
277  local4, 0);
278  }
279 
280  if (local6 != NULL) {
281  dhcp_gbl_ctx.use_local6 = 1;
282  isc_sockaddr_fromin6(&dhcp_gbl_ctx.local6_sockaddr,
283  local6, 0);
284  }
285 
286  if (!(flags & DHCP_DNS_CLIENT_LAZY_INIT)) {
287  result = dns_client_init();
288  }
289  }
290 #endif /* defined NSUPDATE */
291 
292  return(ISC_R_SUCCESS);
293 
294  cleanup:
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  */
299 
300  return(result);
301 }
302 
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 
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;
320 
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);
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;
342  unsigned int algorithm_code;
343 
344  isc_buffer_init(&b, secret, length);
345  isc_buffer_add(&b, length);
346 
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 {
360  return(DHCP_R_INVALIDARG);
361  }
362 
363  result = dhcp_isc_name((unsigned char *)inname, &name0, &name);
364  if (result != ISC_R_SUCCESS) {
365  return(result);
366  }
367 
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));
371 }
372 
378 void dhcp_signal_handler(int signal) {
379  if (shutdown_signal != 0) {
380  /* Already in shutdown. */
381  return;
382  }
383 
384  /* Possible race but does it matter? */
385  shutdown_signal = signal;
386 
387  /* If the application context is running tell it to shut down */
389  (void) isc_app_ctxsuspend(dhcp_gbl_ctx.actx);
390  }
391 }
392 
393 #if defined (NSUPDATE)
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,
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 }
430 #endif /* defined (NSUPDATE) */
#define IGNORE_UNUSED(x)
Definition: cdefs.h:67
#define ISC_TRUE
Definition: data.h:153
#define ISC_FALSE
Definition: data.h:152
#define _PATH_RESOLV_CONF
Definition: dhcpd.h:1610
struct timeval cur_tv
Definition: dispatch.c:35
void cleanup(void)
isc_result_t dhcp_context_create(int flags, struct in_addr *local4, struct in6_addr *local6)
Definition: isclib.c:167
int shutdown_signal
Definition: isclib.c:34
isc_result_t dhcp_isc_name(unsigned char *namestr, dns_fixedname_t *namefix, dns_name_t **name)
Definition: isclib.c:313
void dhcp_signal_handler(int signal)
Definition: isclib.c:378
void isclib_cleanup(void)
Definition: isclib.c:88
dhcp_context_t dhcp_gbl_ctx
Definition: isclib.c:33
isc_result_t isclib_make_dst_key(char *inname, char *algorithm, unsigned char *secret, int length, dst_key_t **dstkey)
Definition: isclib.c:332
#define DHCP_HMAC_SHA1_NAME
Definition: isclib.h:117
#define DHCP_HMAC_SHA384_NAME
Definition: isclib.h:120
#define DHCP_HMAC_SHA256_NAME
Definition: isclib.h:119
#define DHCP_HMAC_SHA224_NAME
Definition: isclib.h:118
#define DHCP_HMAC_SHA512_NAME
Definition: isclib.h:121
#define DHCP_DNS_CLIENT_LAZY_INIT
Definition: isclib.h:136
#define DHCP_CONTEXT_PRE_DB
Definition: isclib.h:134
#define DHCP_HMAC_MD5_NAME
Definition: isclib.h:116
#define DHCP_CONTEXT_POST_DB
Definition: isclib.h:135
#define ISC_R_SUCCESS
#define NS_DEFAULTPORT
Definition: nameser.h:86
int log_error(const char *,...) __attribute__((__format__(__printf__
int int int log_debug(const char *,...) __attribute__((__format__(__printf__
void log_fatal(const char *,...) __attribute__((__format__(__printf__
#define DHCP_R_INVALIDARG
Definition: result.h:49
isc_result_t dhcp_result_register(void)
Definition: result.c:79
int actx_started
Definition: isclib.h:97
isc_socketmgr_t * socketmgr
Definition: isclib.h:101
isc_appctx_t * actx
Definition: isclib.h:96
isc_timermgr_t * timermgr
Definition: isclib.h:102
int actx_running
Definition: isclib.h:98
isc_mem_t * mctx
Definition: isclib.h:95
isc_task_t * task
Definition: isclib.h:100
isc_taskmgr_t * taskmgr
Definition: isclib.h:99