1 /* $NetBSD: isclib.c,v 1.2 2014/07/12 12:09:37 spz Exp $ */ 2 /* 3 * Copyright(c) 2009-2010,2013-2014 by Internet Systems Consortium, Inc.("ISC") 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * Internet Systems Consortium, Inc. 18 * 950 Charter Street 19 * Redwood City, CA 94063 20 * <info@isc.org> 21 * http://www.isc.org/ 22 * 23 */ 24 25 #include <sys/cdefs.h> 26 __RCSID("$NetBSD: isclib.c,v 1.2 2014/07/12 12:09:37 spz Exp $"); 27 28 /*Trying to figure out what we need to define to get things to work. 29 It looks like we want/need the export library but need the fdwatchcommand 30 which may be a problem */ 31 32 #include "dhcpd.h" 33 34 #include <sys/time.h> 35 #include <signal.h> 36 37 dhcp_context_t dhcp_gbl_ctx; 38 int shutdown_signal = 0; 39 40 #if defined (NSUPDATE) 41 42 /* This routine will open up the /etc/resolv.conf file and 43 * send any nameservers it finds to the DNS client code. 44 * It may be moved to be part of the dns client code instead 45 * of being in the DHCP code 46 */ 47 static isc_result_t 48 dhcp_dns_client_setservers(void) 49 { 50 isc_result_t result; 51 irs_resconf_t *resconf = NULL; 52 isc_sockaddrlist_t *nameservers; 53 isc_sockaddr_t *sa; 54 55 result = irs_resconf_load(dhcp_gbl_ctx.mctx, _PATH_RESOLV_CONF, 56 &resconf); 57 if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) { 58 log_error("irs_resconf_load failed: %d.", result); 59 return (result); 60 } 61 62 nameservers = irs_resconf_getnameservers(resconf); 63 64 /* Initialize port numbers */ 65 for (sa = ISC_LIST_HEAD(*nameservers); 66 sa != NULL; 67 sa = ISC_LIST_NEXT(sa, link)) { 68 switch (sa->type.sa.sa_family) { 69 case AF_INET: 70 sa->type.sin.sin_port = htons(NS_DEFAULTPORT); 71 break; 72 case AF_INET6: 73 sa->type.sin6.sin6_port = htons(NS_DEFAULTPORT); 74 break; 75 default: 76 break; 77 } 78 } 79 80 result = dns_client_setservers(dhcp_gbl_ctx.dnsclient, 81 dns_rdataclass_in, 82 NULL, nameservers); 83 if (result != ISC_R_SUCCESS) { 84 log_error("dns_client_setservers failed: %d.", 85 result); 86 } 87 return (result); 88 } 89 #endif 90 91 void 92 isclib_cleanup(void) 93 { 94 #if defined (NSUPDATE) 95 if (dhcp_gbl_ctx.dnsclient != NULL) 96 dns_client_destroy((dns_client_t **)&dhcp_gbl_ctx.dnsclient); 97 #endif 98 99 if (dhcp_gbl_ctx.task != NULL) { 100 isc_task_shutdown(dhcp_gbl_ctx.task); 101 isc_task_detach(&dhcp_gbl_ctx.task); 102 } 103 104 if (dhcp_gbl_ctx.timermgr != NULL) 105 isc_timermgr_destroy(&dhcp_gbl_ctx.timermgr); 106 107 if (dhcp_gbl_ctx.socketmgr != NULL) 108 isc_socketmgr_destroy(&dhcp_gbl_ctx.socketmgr); 109 110 if (dhcp_gbl_ctx.taskmgr != NULL) 111 isc_taskmgr_destroy(&dhcp_gbl_ctx.taskmgr); 112 113 if (dhcp_gbl_ctx.actx_started != ISC_FALSE) { 114 isc_app_ctxfinish(dhcp_gbl_ctx.actx); 115 dhcp_gbl_ctx.actx_started = ISC_FALSE; 116 } 117 118 if (dhcp_gbl_ctx.actx != NULL) 119 isc_appctx_destroy(&dhcp_gbl_ctx.actx); 120 121 if (dhcp_gbl_ctx.mctx != NULL) 122 isc_mem_detach(&dhcp_gbl_ctx.mctx); 123 124 return; 125 } 126 127 isc_result_t 128 dhcp_context_create(int flags, 129 struct in_addr *local4, 130 struct in6_addr *local6) { 131 isc_result_t result; 132 133 if ((flags & DHCP_CONTEXT_PRE_DB) != 0) { 134 /* 135 * Set up the error messages, this isn't the right place 136 * for this call but it is convienent for now. 137 */ 138 result = dhcp_result_register(); 139 if (result != ISC_R_SUCCESS) { 140 log_fatal("register_table() %s: %u", "failed", result); 141 } 142 143 memset(&dhcp_gbl_ctx, 0, sizeof (dhcp_gbl_ctx)); 144 145 isc_lib_register(); 146 147 /* get the current time for use as the random seed */ 148 gettimeofday(&cur_tv, (struct timezone *)0); 149 isc_random_seed(cur_tv.tv_sec); 150 151 #if defined (NSUPDATE) 152 result = dns_lib_init(); 153 if (result != ISC_R_SUCCESS) 154 goto cleanup; 155 #else 156 /* The dst library is inited as part of dns_lib_init, we don't 157 * need it if NSUPDATE is enabled */ 158 result = dst_lib_init(dhcp_gbl_ctx.mctx, NULL, 0); 159 if (result != ISC_R_SUCCESS) 160 goto cleanup; 161 162 #endif 163 result = isc_mem_create(0, 0, &dhcp_gbl_ctx.mctx); 164 if (result != ISC_R_SUCCESS) 165 goto cleanup; 166 167 result = isc_appctx_create(dhcp_gbl_ctx.mctx, 168 &dhcp_gbl_ctx.actx); 169 if (result != ISC_R_SUCCESS) 170 goto cleanup; 171 172 result = isc_app_ctxstart(dhcp_gbl_ctx.actx); 173 if (result != ISC_R_SUCCESS) 174 return (result); 175 dhcp_gbl_ctx.actx_started = ISC_TRUE; 176 177 result = isc_taskmgr_createinctx(dhcp_gbl_ctx.mctx, 178 dhcp_gbl_ctx.actx, 179 1, 0, 180 &dhcp_gbl_ctx.taskmgr); 181 if (result != ISC_R_SUCCESS) 182 goto cleanup; 183 184 result = isc_socketmgr_createinctx(dhcp_gbl_ctx.mctx, 185 dhcp_gbl_ctx.actx, 186 &dhcp_gbl_ctx.socketmgr); 187 if (result != ISC_R_SUCCESS) 188 goto cleanup; 189 190 result = isc_timermgr_createinctx(dhcp_gbl_ctx.mctx, 191 dhcp_gbl_ctx.actx, 192 &dhcp_gbl_ctx.timermgr); 193 if (result != ISC_R_SUCCESS) 194 goto cleanup; 195 196 result = isc_task_create(dhcp_gbl_ctx.taskmgr, 0, &dhcp_gbl_ctx.task); 197 if (result != ISC_R_SUCCESS) 198 goto cleanup; 199 } 200 201 #if defined (NSUPDATE) 202 if ((flags & DHCP_CONTEXT_POST_DB) != 0) { 203 isc_sockaddr_t localaddr4, *localaddr4_ptr = NULL; 204 isc_sockaddr_t localaddr6, *localaddr6_ptr = NULL; 205 if (local4 != NULL) { 206 isc_sockaddr_fromin(&localaddr4, local4, 0); 207 localaddr4_ptr = &localaddr4; 208 } 209 if (local6 != NULL) { 210 isc_sockaddr_fromin6(&localaddr6, local6, 0); 211 localaddr6_ptr = &localaddr6; 212 } 213 214 result = dns_client_createx2(dhcp_gbl_ctx.mctx, 215 dhcp_gbl_ctx.actx, 216 dhcp_gbl_ctx.taskmgr, 217 dhcp_gbl_ctx.socketmgr, 218 dhcp_gbl_ctx.timermgr, 219 0, 220 &dhcp_gbl_ctx.dnsclient, 221 localaddr4_ptr, 222 localaddr6_ptr); 223 if (result != ISC_R_SUCCESS) 224 goto cleanup; 225 226 result = dhcp_dns_client_setservers(); 227 if (result != ISC_R_SUCCESS) 228 goto cleanup; 229 } 230 #endif 231 232 return(ISC_R_SUCCESS); 233 234 cleanup: 235 /* 236 * Currently we don't try and cleanup, just return an error 237 * expecting that our caller will log the error and exit. 238 */ 239 240 return(result); 241 } 242 243 /* 244 * Convert a string name into the proper structure for the isc routines 245 * 246 * Previously we allowed names without a trailing '.' however the current 247 * dns and dst code requires the names to end in a period. If the 248 * name doesn't have a trailing period add one as part of creating 249 * the dns name. 250 */ 251 252 isc_result_t 253 dhcp_isc_name(unsigned char *namestr, 254 dns_fixedname_t *namefix, 255 dns_name_t **name) 256 { 257 size_t namelen; 258 isc_buffer_t b; 259 isc_result_t result; 260 261 namelen = strlen((char *)namestr); 262 isc_buffer_init(&b, namestr, namelen); 263 isc_buffer_add(&b, namelen); 264 dns_fixedname_init(namefix); 265 *name = dns_fixedname_name(namefix); 266 result = dns_name_fromtext(*name, &b, dns_rootname, 0, NULL); 267 isc_buffer_invalidate(&b); 268 return(result); 269 } 270 271 isc_result_t 272 isclib_make_dst_key(char *inname, 273 char *algorithm, 274 unsigned char *secret, 275 int length, 276 dst_key_t **dstkey) 277 { 278 isc_result_t result; 279 dns_name_t *name; 280 dns_fixedname_t name0; 281 isc_buffer_t b; 282 283 isc_buffer_init(&b, secret, length); 284 isc_buffer_add(&b, length); 285 286 /* We only support HMAC_MD5 currently */ 287 if (strcasecmp(algorithm, DHCP_HMAC_MD5_NAME) != 0) { 288 return(DHCP_R_INVALIDARG); 289 } 290 291 result = dhcp_isc_name((unsigned char *)inname, &name0, &name); 292 if (result != ISC_R_SUCCESS) { 293 return(result); 294 } 295 296 return(dst_key_frombuffer(name, DST_ALG_HMACMD5, DNS_KEYOWNER_ENTITY, 297 DNS_KEYPROTO_DNSSEC, dns_rdataclass_in, 298 &b, dhcp_gbl_ctx.mctx, dstkey)); 299 } 300 301 /** 302 * signal handler that initiates server shutdown 303 * 304 * @param signal signal code that we received 305 */ 306 void dhcp_signal_handler(int signal) { 307 isc_appctx_t *ctx = dhcp_gbl_ctx.actx; 308 int prev = shutdown_signal; 309 310 if (prev != 0) { 311 /* Already in shutdown. */ 312 return; 313 } 314 /* Possible race but does it matter? */ 315 shutdown_signal = signal; 316 317 /* Use reload (aka suspend) for easier dispatch() reenter. */ 318 if (ctx && ctx->methods && ctx->methods->ctxsuspend) { 319 (void) isc_app_ctxsuspend(ctx); 320 } 321 } 322