ISC DHCP  4.3.1
A reference DHCPv4 and DHCPv6 implementation
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
isclib.c
Go to the documentation of this file.
1 /*
2  * Copyright(c) 2009-2010,2013-2014 by Internet Systems Consortium, Inc.("ISC")
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
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 export 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
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
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 isc_result_t
125  struct in_addr *local4,
126  struct in6_addr *local6) {
127  isc_result_t result;
128 
129  if ((flags & DHCP_CONTEXT_PRE_DB) != 0) {
130  /*
131  * Set up the error messages, this isn't the right place
132  * for this call but it is convienent for now.
133  */
134  result = dhcp_result_register();
135  if (result != ISC_R_SUCCESS) {
136  log_fatal("register_table() %s: %u", "failed", result);
137  }
138 
139  memset(&dhcp_gbl_ctx, 0, sizeof (dhcp_gbl_ctx));
140 
141  isc_lib_register();
142 
143  /* get the current time for use as the random seed */
144  gettimeofday(&cur_tv, (struct timezone *)0);
145  isc_random_seed(cur_tv.tv_sec);
146 
147  /* we need to create the memory context before
148  * the lib inits in case we aren't doing NSUPDATE
149  * in which case dst needs a memory context
150  */
151  result = isc_mem_create(0, 0, &dhcp_gbl_ctx.mctx);
152  if (result != ISC_R_SUCCESS)
153  goto cleanup;
154 
155 
156 #if defined (NSUPDATE)
157  result = dns_lib_init();
158  if (result != ISC_R_SUCCESS)
159  goto cleanup;
160 #else
161  /* The dst library is inited as part of dns_lib_init, we don't
162  * need it if NSUPDATE is enabled */
163  result = dst_lib_init(dhcp_gbl_ctx.mctx, NULL, 0);
164  if (result != ISC_R_SUCCESS)
165  goto cleanup;
166 
167 #endif
168 
169  result = isc_appctx_create(dhcp_gbl_ctx.mctx,
170  &dhcp_gbl_ctx.actx);
171  if (result != ISC_R_SUCCESS)
172  goto cleanup;
173 
174  result = isc_app_ctxstart(dhcp_gbl_ctx.actx);
175  if (result != ISC_R_SUCCESS)
176  return (result);
177  dhcp_gbl_ctx.actx_started = ISC_TRUE;
178 
179  result = isc_taskmgr_createinctx(dhcp_gbl_ctx.mctx,
180  dhcp_gbl_ctx.actx,
181  1, 0,
182  &dhcp_gbl_ctx.taskmgr);
183  if (result != ISC_R_SUCCESS)
184  goto cleanup;
185 
186  result = isc_socketmgr_createinctx(dhcp_gbl_ctx.mctx,
187  dhcp_gbl_ctx.actx,
188  &dhcp_gbl_ctx.socketmgr);
189  if (result != ISC_R_SUCCESS)
190  goto cleanup;
191 
192  result = isc_timermgr_createinctx(dhcp_gbl_ctx.mctx,
193  dhcp_gbl_ctx.actx,
194  &dhcp_gbl_ctx.timermgr);
195  if (result != ISC_R_SUCCESS)
196  goto cleanup;
197 
198  result = isc_task_create(dhcp_gbl_ctx.taskmgr, 0, &dhcp_gbl_ctx.task);
199  if (result != ISC_R_SUCCESS)
200  goto cleanup;
201  }
202 
203 #if defined (NSUPDATE)
204  if ((flags & DHCP_CONTEXT_POST_DB) != 0) {
205  isc_sockaddr_t localaddr4, *localaddr4_ptr = NULL;
206  isc_sockaddr_t localaddr6, *localaddr6_ptr = NULL;
207  if (local4 != NULL) {
208  isc_sockaddr_fromin(&localaddr4, local4, 0);
209  localaddr4_ptr = &localaddr4;
210  }
211  if (local6 != NULL) {
212  isc_sockaddr_fromin6(&localaddr6, local6, 0);
213  localaddr6_ptr = &localaddr6;
214  }
215 
216  result = dns_client_createx2(dhcp_gbl_ctx.mctx,
217  dhcp_gbl_ctx.actx,
218  dhcp_gbl_ctx.taskmgr,
219  dhcp_gbl_ctx.socketmgr,
220  dhcp_gbl_ctx.timermgr,
221  0,
222  &dhcp_gbl_ctx.dnsclient,
223  localaddr4_ptr,
224  localaddr6_ptr);
225  if (result != ISC_R_SUCCESS)
226  goto cleanup;
227 
228  /*
229  * If we can't set up the servers we may not be able to
230  * do DDNS but we should continue to try and perform
231  * our basic functions and let the user sort it out.
232  */
233  result = dhcp_dns_client_setservers();
234  if (result != ISC_R_SUCCESS) {
235  log_error("Unable to set resolver from resolv.conf; "
236  "startup continuing but DDNS support "
237  "may be affected");
238  }
239  }
240 #endif
241 
242  return(ISC_R_SUCCESS);
243 
244  cleanup:
245  /*
246  * Currently we don't try and cleanup, just return an error
247  * expecting that our caller will log the error and exit.
248  */
249 
250  return(result);
251 }
252 
253 /*
254  * Convert a string name into the proper structure for the isc routines
255  *
256  * Previously we allowed names without a trailing '.' however the current
257  * dns and dst code requires the names to end in a period. If the
258  * name doesn't have a trailing period add one as part of creating
259  * the dns name.
260  */
261 
262 isc_result_t
263 dhcp_isc_name(unsigned char *namestr,
264  dns_fixedname_t *namefix,
265  dns_name_t **name)
266 {
267  size_t namelen;
268  isc_buffer_t b;
269  isc_result_t result;
270 
271  namelen = strlen((char *)namestr);
272  isc_buffer_init(&b, namestr, namelen);
273  isc_buffer_add(&b, namelen);
274  dns_fixedname_init(namefix);
275  *name = dns_fixedname_name(namefix);
276  result = dns_name_fromtext(*name, &b, dns_rootname, 0, NULL);
277  isc_buffer_invalidate(&b);
278  return(result);
279 }
280 
281 isc_result_t
282 isclib_make_dst_key(char *inname,
283  char *algorithm,
284  unsigned char *secret,
285  int length,
286  dst_key_t **dstkey)
287 {
288  isc_result_t result;
289  dns_name_t *name;
290  dns_fixedname_t name0;
291  isc_buffer_t b;
292 
293  isc_buffer_init(&b, secret, length);
294  isc_buffer_add(&b, length);
295 
296  /* We only support HMAC_MD5 currently */
297  if (strcasecmp(algorithm, DHCP_HMAC_MD5_NAME) != 0) {
298  return(DHCP_R_INVALIDARG);
299  }
300 
301  result = dhcp_isc_name((unsigned char *)inname, &name0, &name);
302  if (result != ISC_R_SUCCESS) {
303  return(result);
304  }
305 
306  return(dst_key_frombuffer(name, DST_ALG_HMACMD5, DNS_KEYOWNER_ENTITY,
307  DNS_KEYPROTO_DNSSEC, dns_rdataclass_in,
308  &b, dhcp_gbl_ctx.mctx, dstkey));
309 }
310 
316 void dhcp_signal_handler(int signal) {
317  isc_appctx_t *ctx = dhcp_gbl_ctx.actx;
318  int prev = shutdown_signal;
319 
320  if (prev != 0) {
321  /* Already in shutdown. */
322  return;
323  }
324  /* Possible race but does it matter? */
325  shutdown_signal = signal;
326 
327  /* Use reload (aka suspend) for easier dispatch() reenter. */
328  if (ctx && ctx->methods && ctx->methods->ctxsuspend) {
329  (void) isc_app_ctxsuspend(ctx);
330  }
331 }
isc_result_t dhcp_isc_name(unsigned char *namestr, dns_fixedname_t *namefix, dns_name_t **name)
Definition: isclib.c:263
isc_result_t dhcp_context_create(int flags, struct in_addr *local4, struct in6_addr *local6)
Definition: isclib.c:124
isc_result_t dhcp_result_register(void)
Definition: result.c:79
#define DHCP_R_INVALIDARG
Definition: result.h:48
isc_result_t isclib_make_dst_key(char *inname, char *algorithm, unsigned char *secret, int length, dst_key_t **dstkey)
Definition: isclib.c:282
#define DHCP_CONTEXT_PRE_DB
Definition: isclib.h:121
isc_timermgr_t * timermgr
Definition: isclib.h:98
isc_taskmgr_t * taskmgr
Definition: isclib.h:95
int log_error(const char *,...) __attribute__((__format__(__printf__
void dhcp_signal_handler(int signal)
Definition: isclib.c:316
isc_socketmgr_t * socketmgr
Definition: isclib.h:97
void log_fatal(const char *,...) __attribute__((__format__(__printf__
#define DHCP_CONTEXT_POST_DB
Definition: isclib.h:122
isc_mem_t * mctx
Definition: isclib.h:92
#define NS_DEFAULTPORT
Definition: nameser.h:86
int actx_started
Definition: isclib.h:94
const unsigned char * name
Definition: hash.h:52
isc_appctx_t * actx
Definition: isclib.h:93
int shutdown_signal
Definition: isclib.c:34
void cleanup(void)
void isclib_cleanup(void)
Definition: isclib.c:88
dhcp_context_t dhcp_gbl_ctx
Definition: isclib.c:33
struct timeval cur_tv
Definition: dispatch.c:35
#define DHCP_HMAC_MD5_NAME
Definition: isclib.h:108
isc_task_t * task
Definition: isclib.h:96
#define _PATH_RESOLV_CONF
Definition: dhcpd.h:1478