1 /* $NetBSD: dns.c,v 1.5 2014/07/12 12:09:37 spz Exp $ */ 2 /* dns.c 3 4 Domain Name Service subroutines. */ 5 6 /* 7 * Copyright (c) 2009-2014 by Internet Systems Consortium, Inc. ("ISC") 8 * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC") 9 * Copyright (c) 2001-2003 by Internet Software Consortium 10 * 11 * Permission to use, copy, modify, and distribute this software for any 12 * purpose with or without fee is hereby granted, provided that the above 13 * copyright notice and this permission notice appear in all copies. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 * 23 * Internet Systems Consortium, Inc. 24 * 950 Charter Street 25 * Redwood City, CA 94063 26 * <info@isc.org> 27 * https://www.isc.org/ 28 * 29 */ 30 31 #include <sys/cdefs.h> 32 __RCSID("$NetBSD: dns.c,v 1.5 2014/07/12 12:09:37 spz Exp $"); 33 34 /*! \file common/dns.c 35 */ 36 #include "dhcpd.h" 37 #include "arpa/nameser.h" 38 #include <isc/md5.h> 39 #include <isc/sha2.h> 40 #include <dns/result.h> 41 42 /* 43 * This file contains code to connect the DHCP code to the libdns modules. 44 * As part of that function it maintains a database of zone cuts that can 45 * be used to figure out which server should be contacted to update any 46 * given domain name. Included in the zone information may be a pointer 47 * to a key in which case that key is used for the update. If no zone 48 * is found then the DNS code determines the zone on its own. 49 * 50 * The way this works is that you define the domain name to which an 51 * SOA corresponds, and the addresses of some primaries for that domain name: 52 * 53 * zone FOO.COM { 54 * primary 10.0.17.1; 55 * secondary 10.0.22.1, 10.0.23.1; 56 * key "FOO.COM Key"; 57 * } 58 * 59 * If an update is requested for GAZANGA.TOPANGA.FOO.COM, then the name 60 * server looks in its database for a zone record for "GAZANGA.TOPANGA.FOO.COM", 61 * doesn't find it, looks for one for "TOPANGA.FOO.COM", doesn't find *that*, 62 * looks for "FOO.COM", finds it. So it 63 * attempts the update to the primary for FOO.COM. If that times out, it 64 * tries the secondaries. You can list multiple primaries if you have some 65 * kind of magic name server that supports that. You shouldn't list 66 * secondaries that don't know how to forward updates (e.g., BIND 8 doesn't 67 * support update forwarding, AFAIK). If no TSIG key is listed, the update 68 * is attempted without TSIG. 69 * 70 * You can also include IPv6 addresses via the primary6 and secondary6 71 * options. The search order for the addresses is primary, primary6, 72 * secondary and lastly secondary6, with a limit on the number of 73 * addresses used. Currently this limit is 3. 74 * 75 * The DHCP server tries to find an existing zone for any given name by 76 * trying to look up a local zone structure for each domain containing 77 * that name, all the way up to '.'. If it finds one cached, it tries 78 * to use that one to do the update. That's why it tries to update 79 * "FOO.COM" above, even though theoretically it should try GAZANGA... 80 * and TOPANGA... first. 81 * 82 * If the update fails with a predefined zone the zone is marked as bad 83 * and another search of the predefined zones is done. If no predefined 84 * zone is found finding a zone is left to the DNS module via examination 85 * of SOA records. If the DNS module finds a zone it may cache the zone 86 * but the zone won't be cached here. 87 * 88 * TSIG updates are not performed on zones found by the DNS module - if 89 * you want TSIG updates you _must_ write a zone definition linking the 90 * key to the zone. In cases where you know for sure what the key is 91 * but do not want to hardcode the IP addresses of the primary or 92 * secondaries, a zone declaration can be made that doesn't include any 93 * primary or secondary declarations. When the DHCP server encounters 94 * this while hunting up a matching zone for a name, it looks up the SOA, 95 * fills in the IP addresses, and uses that record for the update. 96 * If the SOA lookup returns NXRRSET, a warning is printed and the zone is 97 * discarded, TSIG key and all. The search for the zone then continues 98 * as if the zone record hadn't been found. Zones without IP addresses 99 * don't match when initially hunting for a zone to update. 100 * 101 * When an update is attempted and no predefined zone is found 102 * that matches any enclosing domain of the domain being updated, the DHCP 103 * server goes through the same process that is done when the update to a 104 * predefined zone fails - starting with the most specific domain 105 * name (GAZANGA.TOPANGA.FOO.COM) and moving to the least specific (the root), 106 * it tries to look up an SOA record. 107 * 108 * TSIG keys are defined like this: 109 * 110 * key "FOO.COM Key" { 111 * algorithm HMAC-MD5.SIG-ALG.REG.INT; 112 * secret <Base64>; 113 * } 114 * 115 * <Base64> is a number expressed in base64 that represents the key. 116 * It's also permissible to use a quoted string here - this will be 117 * translated as the ASCII bytes making up the string, and will not 118 * include any NUL termination. The key name can be any text string, 119 * and the key type must be one of the key types defined in the draft 120 * or by the IANA. Currently only the HMAC-MD5... key type is 121 * supported. 122 * 123 * The DDNS processing has been split into two areas. One is the 124 * control code that determines what should be done. That code is found 125 * in the client or server directories. The other is the common code 126 * that performs functions such as properly formatting the arguments. 127 * That code is found in this file. The basic processing flow for a 128 * DDNS update is: 129 * In the client or server code determine what needs to be done and 130 * collect the necesary information then pass it to a function from 131 * this file. 132 * In this code lookup the zone and extract the zone and key information 133 * (if available) and prepare the arguments for the DNS module. 134 * When the DNS module completes its work (times out or gets a reply) 135 * it will trigger another function here which does generic processing 136 * and then passes control back to the code from the server or client. 137 * The server or client code then determines the next step which may 138 * result in another call to this module in which case the process repeats. 139 */ 140 141 dns_zone_hash_t *dns_zone_hash; 142 143 /* 144 * DHCP dns structures 145 * Normally the relationship between these structures isn't one to one 146 * but in the DHCP case it (mostly) is. To make the allocations, frees, 147 * and passing of the memory easier we make a single structure with all 148 * the pieces. 149 * 150 * The maximum size of the data buffer should be large enough for any 151 * items DHCP will generate 152 */ 153 154 typedef struct dhcp_ddns_rdata { 155 dns_rdata_t rdata; 156 dns_rdatalist_t rdatalist; 157 dns_rdataset_t rdataset; 158 } dhcp_ddns_data_t; 159 160 #if defined (NSUPDATE) 161 #if defined (DNS_ZONE_LOOKUP) 162 163 /* 164 * The structure used to find a nameserver if there wasn't a zone entry. 165 * Currently we assume we won't have many of these outstanding at any 166 * time so we go with a simple linked list. 167 * In use find_zone_start() will fill in the oname with the name 168 * requested by the DDNS code. zname will point to it and be 169 * advanced as labels are removed. If the DNS client code returns 170 * a set of name servers eventp and rdataset will be set. Then 171 * the code will walk through the nameservers in namelist and 172 * find addresses that are stored in addrs and addrs6. 173 */ 174 175 typedef struct dhcp_ddns_ns { 176 struct dhcp_ddns_ns *next; 177 struct data_string oname; /* the original name for DDNS */ 178 char *zname; /* a pointer into the original name for 179 the zone we are checking */ 180 dns_clientresevent_t *eventp; /* pointer to the event that provided the 181 namelist, we can't free the eventp 182 until we free the namelist */ 183 dns_name_t *ns_name; /* current name server we are examining */ 184 dns_rdataset_t *rdataset; 185 dns_rdatatype_t rdtype; /* type of address we want */ 186 187 struct in_addr addrs[DHCP_MAXNS]; /* space for v4 addresses */ 188 struct in6_addr addrs6[DHCP_MAXNS]; /* space for v6 addresses */ 189 int num_addrs; 190 int num_addrs6; 191 int ttl; 192 193 void *transaction; /* transaction id for DNS calls */ 194 } dhcp_ddns_ns_t; 195 196 /* 197 * The list of DDNS names for which we are attempting to find a name server. 198 * This list is used for finding the name server, it doesn't include the 199 * information necessary to do the DDNS request after finding a name server. 200 * The code attempts to minimize duplicate requests by examining the list 201 * to see if we are already trying to find a substring of the new request. 202 * For example imagine the first request is "a.b.c.d.e." and the server has 203 * already discarded the first two lables and is trying "c.d.e.". If the 204 * next request is for "x.y.c.d.e." the code assumes the in progress 205 * request is sufficient and doesn't add a new request for the second name. 206 * If the next request was for "x.y.z.d.e." the code doesn't assume they 207 * will use the same nameserver and starts a second request. 208 * This strategy will not eliminate all duplicates but is simple and 209 * should be sufficient. 210 */ 211 dhcp_ddns_ns_t *dns_outstanding_ns = NULL; 212 213 /* 214 * Routines to manipulate the list of outstanding searches 215 * 216 * add_to_ns_queue() - adds the given control block to the queue 217 * 218 * remove_from_ns_queue() - removes the given control block from 219 * the queue 220 * 221 * find_in_ns_queue() compares the name from the given control 222 * block with the control blocks in the queue. It returns 223 * success if a matching entry is found. In order to match 224 * the entry already on the queue must be shorter than the 225 * incoming name must match the ending substring of the name. 226 */ 227 228 static void 229 add_to_ns_queue(dhcp_ddns_ns_t *ns_cb) 230 { 231 ns_cb->next = dns_outstanding_ns; 232 dns_outstanding_ns = ns_cb; 233 } 234 235 236 static void 237 remove_from_ns_queue(dhcp_ddns_ns_t *ns_cb) 238 { 239 dhcp_ddns_ns_t **foo; 240 241 foo = &dns_outstanding_ns; 242 while (*foo) { 243 if (*foo == ns_cb) { 244 *foo = ns_cb->next; 245 break; 246 } 247 foo = &((*foo)->next); 248 } 249 ns_cb->next = NULL; 250 } 251 252 static isc_result_t 253 find_in_ns_queue(dhcp_ddns_ns_t *ns_cb) 254 { 255 dhcp_ddns_ns_t *temp_cb; 256 int in_len, temp_len; 257 258 in_len = strlen(ns_cb->zname); 259 260 for(temp_cb = dns_outstanding_ns; 261 temp_cb != NULL; 262 temp_cb = temp_cb->next) { 263 temp_len = strlen(temp_cb->zname); 264 if (temp_len > in_len) 265 continue; 266 if (strcmp(temp_cb->zname, 267 ns_cb->zname + (in_len - temp_len)) == 0) 268 return(ISC_R_SUCCESS); 269 } 270 return(ISC_R_NOTFOUND); 271 } 272 273 void cache_found_zone (dhcp_ddns_ns_t *); 274 #endif 275 276 void ddns_interlude(isc_task_t *, isc_event_t *); 277 278 #if defined (TRACING) 279 /* 280 * Code to support tracing DDNS packets. We trace packets going to and 281 * coming from the libdns code but don't try to track the packets 282 * exchanged between the libdns code and the dns server(s) it contacts. 283 * 284 * The code is split into two sets of routines 285 * input refers to messages received from the dns module 286 * output refers to messages sent to the dns module 287 * Currently there are three routines in each set 288 * write is used to write information about the message to the trace file 289 * this routine is called directly from the proper place in the code. 290 * read is used to read information about a message from the trace file 291 * this routine is called from the trace loop as it reads through 292 * the file and is registered via the trace_type_register routine. 293 * When playing back a trace file we shall absorb records of output 294 * messages as part of processing the write function, therefore 295 * any output messages we encounter are flagged as errors. 296 * stop isn't currently used in this code but is needed for the register 297 * routine. 298 * 299 * We pass a pointer to a control block to the dns module which it returns 300 * to use as part of the result. As the pointer may vary between traces 301 * we need to map between those from the trace file and the new ones during 302 * playback. 303 * 304 * The mapping is complicated a little as a pointer could be 4 or 8 bytes 305 * long. We treat the old pointer as an 8 byte quantity and pad and compare 306 * as necessary. 307 */ 308 309 /* 310 * Structure used to map old pointers to new pointers. 311 * Old pointers are 8 bytes long as we don't know if the trace was 312 * done on a 64 bit or 32 bit machine. 313 */ 314 #define TRACE_PTR_LEN 8 315 316 typedef struct dhcp_ddns_map { 317 char old_pointer[TRACE_PTR_LEN]; 318 void *new_pointer; 319 struct dhcp_ddns_map *next; 320 } dhcp_ddns_map_t; 321 322 /* The starting point for the map structure */ 323 static dhcp_ddns_map_t *ddns_map; 324 325 trace_type_t *trace_ddns_input; 326 trace_type_t *trace_ddns_output; 327 328 /* 329 * The data written to the trace file is: 330 * 32 bits result from dns 331 * 64 bits pointer of cb 332 */ 333 334 static void 335 trace_ddns_input_write(dhcp_ddns_cb_t *ddns_cb, isc_result_t result) 336 { 337 trace_iov_t iov[2]; 338 u_int32_t old_result; 339 char old_pointer[TRACE_PTR_LEN]; 340 341 old_result = htonl((u_int32_t)result); 342 memset(old_pointer, 0, TRACE_PTR_LEN); 343 memcpy(old_pointer, &ddns_cb, sizeof(ddns_cb)); 344 345 iov[0].len = sizeof(old_result); 346 iov[0].buf = (char *)&old_result; 347 iov[1].len = TRACE_PTR_LEN; 348 iov[1].buf = old_pointer; 349 trace_write_packet_iov(trace_ddns_input, 2, iov, MDL); 350 } 351 352 /* 353 * Process the result and pointer from the trace file. 354 * We use the pointer map to find the proper pointer for this instance. 355 * Then we need to construct an event to pass along to the interlude 356 * function. 357 */ 358 static void 359 trace_ddns_input_read(trace_type_t *ttype, unsigned length, 360 char *buf) 361 { 362 u_int32_t old_result; 363 char old_pointer[TRACE_PTR_LEN]; 364 dns_clientupdateevent_t *eventp; 365 void *new_pointer; 366 dhcp_ddns_map_t *ddns_map_ptr; 367 368 if (length < (sizeof(old_result) + TRACE_PTR_LEN)) { 369 log_error("trace_ddns_input_read: data too short"); 370 return; 371 } 372 373 memcpy(&old_result, buf, sizeof(old_result)); 374 memcpy(old_pointer, buf + sizeof(old_result), TRACE_PTR_LEN); 375 376 /* map the old pointer to a new pointer */ 377 for (ddns_map_ptr = ddns_map; 378 ddns_map_ptr != NULL; 379 ddns_map_ptr = ddns_map_ptr->next) { 380 if ((ddns_map_ptr->new_pointer != NULL) && 381 memcmp(ddns_map_ptr->old_pointer, 382 old_pointer, TRACE_PTR_LEN) == 0) { 383 new_pointer = ddns_map_ptr->new_pointer; 384 ddns_map_ptr->new_pointer = NULL; 385 memset(ddns_map_ptr->old_pointer, 0, TRACE_PTR_LEN); 386 break; 387 } 388 } 389 if (ddns_map_ptr == NULL) { 390 log_error("trace_dns_input_read: unable to map cb pointer"); 391 return; 392 } 393 394 eventp = (dns_clientupdateevent_t *) 395 isc_event_allocate(dhcp_gbl_ctx.mctx, 396 dhcp_gbl_ctx.task, 397 0, 398 ddns_interlude, 399 new_pointer, 400 sizeof(dns_clientupdateevent_t)); 401 if (eventp == NULL) { 402 log_error("trace_ddns_input_read: unable to allocate event"); 403 return; 404 } 405 eventp->result = ntohl(old_result); 406 407 408 ddns_interlude(dhcp_gbl_ctx.task, (isc_event_t *)eventp); 409 410 return; 411 } 412 413 static void 414 trace_ddns_input_stop(trace_type_t *ttype) 415 { 416 } 417 418 /* 419 * We use the same arguments as for the dns startupdate function to 420 * allows us to choose between the two via a macro. If tracing isn't 421 * in use we simply call the dns function directly. 422 * 423 * If we are doing playback we read the next packet from the file 424 * and compare the type. If it matches we extract the results and pointer 425 * from the trace file. The results are returned to the caller as if 426 * they had called the dns routine. The pointer is used to construct a 427 * map for when the "reply" is processed. 428 * 429 * The data written to trace file is: 430 * 32 bits result 431 * 64 bits pointer of cb (DDNS Control block) 432 * contents of cb 433 */ 434 435 static isc_result_t 436 trace_ddns_output_write(dns_client_t *client, dns_rdataclass_t rdclass, 437 dns_name_t *zonename, dns_namelist_t *prerequisites, 438 dns_namelist_t *updates, isc_sockaddrlist_t *servers, 439 dns_tsec_t *tsec, unsigned int options, 440 isc_task_t *task, isc_taskaction_t action, void *arg, 441 dns_clientupdatetrans_t **transp) 442 { 443 isc_result_t result; 444 u_int32_t old_result; 445 char old_pointer[TRACE_PTR_LEN]; 446 dhcp_ddns_map_t *ddns_map_ptr; 447 448 if (trace_playback() != 0) { 449 /* We are doing playback, extract the entry from the file */ 450 unsigned buflen = 0; 451 char *inbuf = NULL; 452 453 result = trace_get_packet(&trace_ddns_output, 454 &buflen, &inbuf); 455 if (result != ISC_R_SUCCESS) { 456 log_error("trace_ddns_output_write: no input found"); 457 return (ISC_R_FAILURE); 458 } 459 if (buflen < (sizeof(old_result) + TRACE_PTR_LEN)) { 460 log_error("trace_ddns_output_write: data too short"); 461 dfree(inbuf, MDL); 462 return (ISC_R_FAILURE); 463 } 464 memcpy(&old_result, inbuf, sizeof(old_result)); 465 result = ntohl(old_result); 466 memcpy(old_pointer, inbuf + sizeof(old_result), TRACE_PTR_LEN); 467 dfree(inbuf, MDL); 468 469 /* add the pointer to the pointer map */ 470 for (ddns_map_ptr = ddns_map; 471 ddns_map_ptr != NULL; 472 ddns_map_ptr = ddns_map_ptr->next) { 473 if (ddns_map_ptr->new_pointer == NULL) { 474 break; 475 } 476 } 477 478 /* 479 * If we didn't find an empty entry, allocate an entry and 480 * link it into the list. The list isn't ordered. 481 */ 482 if (ddns_map_ptr == NULL) { 483 ddns_map_ptr = dmalloc(sizeof(*ddns_map_ptr), MDL); 484 if (ddns_map_ptr == NULL) { 485 log_error("trace_ddns_output_write: " 486 "unable to allocate map entry"); 487 return(ISC_R_FAILURE); 488 } 489 ddns_map_ptr->next = ddns_map; 490 ddns_map = ddns_map_ptr; 491 } 492 493 memcpy(ddns_map_ptr->old_pointer, old_pointer, TRACE_PTR_LEN); 494 ddns_map_ptr->new_pointer = arg; 495 } 496 else { 497 /* We aren't doing playback, make the actual call */ 498 result = dns_client_startupdate(client, rdclass, zonename, 499 prerequisites, updates, 500 servers, tsec, options, 501 task, action, arg, transp); 502 } 503 504 if (trace_record() != 0) { 505 /* We are recording, save the information to the file */ 506 trace_iov_t iov[3]; 507 old_result = htonl((u_int32_t)result); 508 memset(old_pointer, 0, TRACE_PTR_LEN); 509 memcpy(old_pointer, &arg, sizeof(arg)); 510 iov[0].len = sizeof(old_result); 511 iov[0].buf = (char *)&old_result; 512 iov[1].len = TRACE_PTR_LEN; 513 iov[1].buf = old_pointer; 514 515 /* Write out the entire cb, in case we want to look at it */ 516 iov[2].len = sizeof(dhcp_ddns_cb_t); 517 iov[2].buf = (char *)arg; 518 519 trace_write_packet_iov(trace_ddns_output, 3, iov, MDL); 520 } 521 522 return(result); 523 } 524 525 static void 526 trace_ddns_output_read(trace_type_t *ttype, unsigned length, 527 char *buf) 528 { 529 log_error("unaccounted for ddns output."); 530 } 531 532 static void 533 trace_ddns_output_stop(trace_type_t *ttype) 534 { 535 } 536 537 void 538 trace_ddns_init() 539 { 540 trace_ddns_output = trace_type_register("ddns-output", NULL, 541 trace_ddns_output_read, 542 trace_ddns_output_stop, MDL); 543 trace_ddns_input = trace_type_register("ddns-input", NULL, 544 trace_ddns_input_read, 545 trace_ddns_input_stop, MDL); 546 ddns_map = NULL; 547 } 548 549 #define ddns_update trace_ddns_output_write 550 #else 551 #define ddns_update dns_client_startupdate 552 #endif /* TRACING */ 553 554 #define zone_resolve dns_client_startresolve 555 556 /* 557 * Code to allocate and free a dddns control block. This block is used 558 * to pass and track the information associated with a DDNS update request. 559 */ 560 dhcp_ddns_cb_t * 561 ddns_cb_alloc(const char *file, int line) 562 { 563 dhcp_ddns_cb_t *ddns_cb; 564 int i; 565 566 ddns_cb = dmalloc(sizeof(*ddns_cb), file, line); 567 if (ddns_cb != NULL) { 568 ISC_LIST_INIT(ddns_cb->zone_server_list); 569 for (i = 0; i < DHCP_MAXNS; i++) { 570 ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link); 571 } 572 } 573 574 #if defined (DEBUG_DNS_UPDATES) 575 log_info("%s(%d): Allocating ddns_cb=%p", file, line, ddns_cb); 576 #endif 577 578 return(ddns_cb); 579 } 580 581 void 582 ddns_cb_free(dhcp_ddns_cb_t *ddns_cb, const char *file, int line) 583 { 584 #if defined (DEBUG_DNS_UPDATES) 585 log_info("%s(%d): freeing ddns_cb=%p", file, line, ddns_cb); 586 #endif 587 588 data_string_forget(&ddns_cb->fwd_name, file, line); 589 data_string_forget(&ddns_cb->rev_name, file, line); 590 data_string_forget(&ddns_cb->dhcid, file, line); 591 592 if (ddns_cb->zone != NULL) { 593 forget_zone((struct dns_zone **)&ddns_cb->zone); 594 } 595 596 /* Should be freed by now, check just in case. */ 597 if (ddns_cb->transaction != NULL) 598 log_error("Impossible memory leak at %s:%d (attempt to free " 599 "DDNS Control Block before transaction).", MDL); 600 601 dfree(ddns_cb, file, line); 602 } 603 604 void 605 ddns_cb_forget_zone(dhcp_ddns_cb_t *ddns_cb) 606 { 607 int i; 608 609 forget_zone(&ddns_cb->zone); 610 ddns_cb->zone_name[0] = 0; 611 ISC_LIST_INIT(ddns_cb->zone_server_list); 612 for (i = 0; i < DHCP_MAXNS; i++) { 613 ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link); 614 } 615 } 616 617 isc_result_t find_tsig_key (ns_tsig_key **key, const char *zname, 618 struct dns_zone *zone) 619 { 620 ns_tsig_key *tkey; 621 622 if (!zone) 623 return ISC_R_NOTFOUND; 624 625 if (!zone -> key) { 626 return DHCP_R_KEY_UNKNOWN; 627 } 628 629 if ((!zone -> key -> name || 630 strlen (zone -> key -> name) > NS_MAXDNAME) || 631 (!zone -> key -> algorithm || 632 strlen (zone -> key -> algorithm) > NS_MAXDNAME) || 633 (!zone -> key) || 634 (!zone -> key -> key) || 635 (zone -> key -> key -> len == 0)) { 636 return DHCP_R_INVALIDKEY; 637 } 638 tkey = dmalloc (sizeof *tkey, MDL); 639 if (!tkey) { 640 nomem: 641 return ISC_R_NOMEMORY; 642 } 643 memset (tkey, 0, sizeof *tkey); 644 tkey -> data = dmalloc (zone -> key -> key -> len, MDL); 645 if (!tkey -> data) { 646 dfree (tkey, MDL); 647 goto nomem; 648 } 649 strcpy (tkey -> name, zone -> key -> name); 650 strcpy (tkey -> alg, zone -> key -> algorithm); 651 memcpy (tkey -> data, 652 zone -> key -> key -> value, zone -> key -> key -> len); 653 tkey -> len = zone -> key -> key -> len; 654 *key = tkey; 655 return ISC_R_SUCCESS; 656 } 657 658 void tkey_free (ns_tsig_key **key) 659 { 660 if ((*key) -> data) 661 dfree ((*key) -> data, MDL); 662 dfree ((*key), MDL); 663 *key = (ns_tsig_key *)0; 664 } 665 #endif 666 667 static isc_result_t remove_dns_zone (struct dns_zone *zone) 668 { 669 struct dns_zone *tz = NULL; 670 671 if (dns_zone_hash) { 672 dns_zone_hash_lookup(&tz, dns_zone_hash, zone->name, 0, MDL); 673 if (tz != NULL) { 674 dns_zone_hash_delete(dns_zone_hash, tz->name, 0, MDL); 675 dns_zone_dereference(&tz, MDL); 676 } 677 } 678 679 return (ISC_R_SUCCESS); 680 } 681 682 isc_result_t enter_dns_zone (struct dns_zone *zone) 683 { 684 struct dns_zone *tz = (struct dns_zone *)0; 685 686 if (dns_zone_hash) { 687 dns_zone_hash_lookup (&tz, 688 dns_zone_hash, zone -> name, 0, MDL); 689 if (tz == zone) { 690 dns_zone_dereference (&tz, MDL); 691 return ISC_R_SUCCESS; 692 } 693 if (tz) { 694 dns_zone_hash_delete (dns_zone_hash, 695 zone -> name, 0, MDL); 696 dns_zone_dereference (&tz, MDL); 697 } 698 } else { 699 if (!dns_zone_new_hash(&dns_zone_hash, DNS_HASH_SIZE, MDL)) 700 return ISC_R_NOMEMORY; 701 } 702 703 dns_zone_hash_add (dns_zone_hash, zone -> name, 0, zone, MDL); 704 return ISC_R_SUCCESS; 705 } 706 707 isc_result_t dns_zone_lookup (struct dns_zone **zone, const char *name) 708 { 709 int len; 710 char *tname = (char *)0; 711 isc_result_t status; 712 713 if (!dns_zone_hash) 714 return ISC_R_NOTFOUND; 715 716 len = strlen (name); 717 if (name [len - 1] != '.') { 718 tname = dmalloc ((unsigned)len + 2, MDL); 719 if (!tname) 720 return ISC_R_NOMEMORY; 721 strcpy (tname, name); 722 tname [len] = '.'; 723 tname [len + 1] = 0; 724 name = tname; 725 } 726 if (!dns_zone_hash_lookup (zone, dns_zone_hash, name, 0, MDL)) 727 status = ISC_R_NOTFOUND; 728 else if ((*zone)->timeout && (*zone)->timeout < cur_time) { 729 dns_zone_hash_delete(dns_zone_hash, (*zone)->name, 0, MDL); 730 dns_zone_dereference(zone, MDL); 731 status = ISC_R_NOTFOUND; 732 } else 733 status = ISC_R_SUCCESS; 734 735 if (tname) 736 dfree (tname, MDL); 737 return status; 738 } 739 740 int dns_zone_dereference (ptr, file, line) 741 struct dns_zone **ptr; 742 const char *file; 743 int line; 744 { 745 struct dns_zone *dns_zone; 746 747 if ((ptr == NULL) || (*ptr == NULL)) { 748 log_error("%s(%d): null pointer", file, line); 749 #if defined (POINTER_DEBUG) 750 abort(); 751 #else 752 return (0); 753 #endif 754 } 755 756 dns_zone = *ptr; 757 *ptr = NULL; 758 --dns_zone->refcnt; 759 rc_register(file, line, ptr, dns_zone, dns_zone->refcnt, 1, RC_MISC); 760 if (dns_zone->refcnt > 0) 761 return (1); 762 763 if (dns_zone->refcnt < 0) { 764 log_error("%s(%d): negative refcnt!", file, line); 765 #if defined (DEBUG_RC_HISTORY) 766 dump_rc_history(dns_zone); 767 #endif 768 #if defined (POINTER_DEBUG) 769 abort(); 770 #else 771 return (0); 772 #endif 773 } 774 775 if (dns_zone->name) 776 dfree(dns_zone->name, file, line); 777 if (dns_zone->key) 778 omapi_auth_key_dereference(&dns_zone->key, file, line); 779 if (dns_zone->primary) 780 option_cache_dereference(&dns_zone->primary, file, line); 781 if (dns_zone->secondary) 782 option_cache_dereference(&dns_zone->secondary, file, line); 783 if (dns_zone->primary6) 784 option_cache_dereference(&dns_zone->primary6, file, line); 785 if (dns_zone->secondary6) 786 option_cache_dereference(&dns_zone->secondary6, file, line); 787 dfree(dns_zone, file, line); 788 return (1); 789 } 790 791 #if defined (NSUPDATE) 792 #if defined (DNS_ZONE_LOOKUP) 793 794 /* Helper function to copy the address from an rdataset to 795 * the nameserver control block. Mostly to avoid really long 796 * lines in the nested for loops 797 */ 798 static void 799 zone_addr_to_ns(dhcp_ddns_ns_t *ns_cb, 800 dns_rdataset_t *rdataset) 801 { 802 dns_rdata_t rdata; 803 dns_rdata_in_a_t a; 804 dns_rdata_in_aaaa_t aaaa; 805 806 dns_rdata_init(&rdata); 807 dns_rdataset_current(rdataset, &rdata); 808 switch (rdataset->type) { 809 case dns_rdatatype_a: 810 (void) dns_rdata_tostruct(&rdata, &a, NULL); 811 memcpy(&ns_cb->addrs[ns_cb->num_addrs], &a.in_addr, 4); 812 ns_cb->num_addrs++; 813 dns_rdata_freestruct(&a); 814 break; 815 case dns_rdatatype_aaaa: 816 (void) dns_rdata_tostruct(&rdata, &aaaa, NULL); 817 memcpy(&ns_cb->addrs6[ns_cb->num_addrs6], &aaaa.in6_addr, 16); 818 ns_cb->num_addrs6++; 819 dns_rdata_freestruct(&aaaa); 820 break; 821 default: 822 break; 823 } 824 825 if ((ns_cb->ttl == 0) || (ns_cb->ttl > rdataset->ttl)) 826 ns_cb->ttl = rdataset->ttl; 827 } 828 829 /* 830 * The following three routines co-operate to find the addresses of 831 * the nameservers to use for a zone if we don't have a zone statement. 832 * We strongly suggest the use of a zone statement to avoid problmes 833 * and to allow for the use of TSIG and therefore better security, but 834 * include this functionality for those that don't want such statements. 835 * 836 * find_zone_start(ddns_cb, direction) 837 * This is the first of the routines, it is called from the rest of 838 * the ddns code when we have received a request for DDNS for a name 839 * and don't have a zone entry that would cover that name. The name 840 * is in the ddns_cb as specified by the direction (forward or reverse). 841 * The start function pulls the name out and constructs the name server 842 * block then starts the process by calling the DNS client code. 843 * 844 * find_zone_ns(taskp, eventp) 845 * This is the second step of the process. The DNS client code will 846 * call this when it has gotten a response or timed out. If the response 847 * doesn't have a list of nameservers we remove another label from the 848 * zone name and try again. If the response does include a list of 849 * nameservers we start walking through the list attempting to get 850 * addresses for the nameservers. 851 * 852 * find_zone_addrs(taskp, eventp) 853 * This is the third step of the process. In find_zone_ns we got 854 * a list of nameserves and started walking through them. This continues 855 * the walk and if we get back any addresses it adds them to our list. 856 * When we get enough addresses or run out of nameservers we construct 857 * a zone entry and insert it into the zone hash for the rest of the 858 * DDNS code to use. 859 */ 860 static void 861 find_zone_addrs(isc_task_t *taskp, 862 isc_event_t *eventp) 863 { 864 dns_clientresevent_t *ddns_event = (dns_clientresevent_t *)eventp; 865 dhcp_ddns_ns_t *ns_cb = (dhcp_ddns_ns_t *)eventp->ev_arg; 866 dns_name_t *ns_name = NULL; 867 dns_rdataset_t *rdataset; 868 isc_result_t result; 869 dns_name_t *name; 870 dns_rdata_t rdata = DNS_RDATA_INIT; 871 dns_rdata_ns_t ns; 872 873 874 /* the transaction is done, get rid of the tag */ 875 dns_client_destroyrestrans(&ns_cb->transaction); 876 877 /* If we succeeded we try and extract the addresses, if we can 878 * and we have enough we are done. If we didn't succeed or 879 * we don't have enough addresses afterwards we drop through 880 * and try the next item on the list. 881 */ 882 if (ddns_event->result == ISC_R_SUCCESS) { 883 884 for (name = ISC_LIST_HEAD(ddns_event->answerlist); 885 name != NULL; 886 name = ISC_LIST_NEXT(name, link)) { 887 888 for (rdataset = ISC_LIST_HEAD(name->list); 889 rdataset != NULL; 890 rdataset = ISC_LIST_NEXT(rdataset, link)) { 891 892 for (result = dns_rdataset_first(rdataset); 893 result == ISC_R_SUCCESS; 894 result = dns_rdataset_next(rdataset)) { 895 896 /* add address to cb */ 897 zone_addr_to_ns(ns_cb, rdataset); 898 899 /* We are done if we have 900 * enough addresses 901 */ 902 if (ns_cb->num_addrs + 903 ns_cb->num_addrs6 >= DHCP_MAXNS) 904 goto done; 905 } 906 } 907 } 908 } 909 910 /* We need more addresses. 911 * We restart the loop we were in before. 912 */ 913 914 for (ns_name = ns_cb->ns_name; 915 ns_name != NULL; 916 ns_name = ISC_LIST_NEXT(ns_name, link)) { 917 918 if (ns_name == ns_cb->ns_name) { 919 /* first time through, use saved state */ 920 rdataset = ns_cb->rdataset; 921 } else { 922 rdataset = ISC_LIST_HEAD(ns_name->list); 923 } 924 925 for (; 926 rdataset != NULL; 927 rdataset = ISC_LIST_NEXT(rdataset, link)) { 928 929 if (rdataset->type != dns_rdatatype_ns) 930 continue; 931 dns_rdata_init(&rdata); 932 933 if (rdataset == ns_cb->rdataset) { 934 /* first time through use the saved state */ 935 if (ns_cb->rdtype == dns_rdatatype_a) { 936 ns_cb->rdtype = dns_rdatatype_aaaa; 937 } else { 938 ns_cb->rdtype = dns_rdatatype_a; 939 if (dns_rdataset_next(rdataset) != 940 ISC_R_SUCCESS) 941 continue; 942 } 943 } else { 944 if ((!dns_rdataset_isassociated(rdataset)) || 945 (dns_rdataset_first(rdataset) != 946 ISC_R_SUCCESS)) 947 continue; 948 } 949 950 dns_rdataset_current(rdataset, &rdata); 951 if (dns_rdata_tostruct(&rdata, &ns, NULL) != 952 ISC_R_SUCCESS) 953 continue; 954 955 /* Save our current state */ 956 ns_cb->ns_name = ns_name; 957 ns_cb->rdataset = rdataset; 958 959 /* And call out to DNS */ 960 result = zone_resolve(dhcp_gbl_ctx.dnsclient, &ns.name, 961 dns_rdataclass_in, 962 ns_cb->rdtype, 963 DNS_CLIENTRESOPT_NODNSSEC, 964 dhcp_gbl_ctx.task, 965 find_zone_addrs, 966 (void *)ns_cb, 967 &ns_cb->transaction); 968 969 /* do we need to clean this? */ 970 dns_rdata_freestruct(&ns); 971 972 if (result == ISC_R_SUCCESS) 973 /* we have started the next step, cleanup 974 * the structures associated with this call 975 * but leave the cb for the next round 976 */ 977 goto cleanup; 978 979 log_error("find_zone_addrs: unable to continue " 980 "resolve: %s %s", 981 ns_cb->zname, 982 isc_result_totext(result)); 983 984 /* The call to start a resolve transaction failed, 985 * should we try to continue with any other names? 986 * For now let's not, but let's use whatever we 987 * may already have. 988 */ 989 goto done; 990 } 991 } 992 993 done: 994 /* we've either gotten our max number of addresses or 995 * run out of nameservers to try. Convert the cb into 996 * a zone and insert it into the zone hash. Then 997 * we need to clean up the saved state. 998 */ 999 if ((ns_cb->num_addrs != 0) || 1000 (ns_cb->num_addrs6 != 0)) 1001 cache_found_zone(ns_cb); 1002 1003 dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient, 1004 &ns_cb->eventp->answerlist); 1005 isc_event_free((isc_event_t **)&ns_cb->eventp); 1006 1007 remove_from_ns_queue(ns_cb); 1008 data_string_forget(&ns_cb->oname, MDL); 1009 dfree(ns_cb, MDL); 1010 1011 cleanup: 1012 /* cleanup any of the new state information */ 1013 1014 dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient, 1015 &ddns_event->answerlist); 1016 isc_event_free(&eventp); 1017 1018 return; 1019 1020 } 1021 1022 /* 1023 * Routine to continue the process of finding a nameserver via the DNS 1024 * This is routine is called when we are still trying to get a list 1025 * of nameservers to process. 1026 */ 1027 1028 static void 1029 find_zone_ns(isc_task_t *taskp, 1030 isc_event_t *eventp) 1031 { 1032 dns_clientresevent_t *ddns_event = (dns_clientresevent_t *)eventp; 1033 dhcp_ddns_ns_t *ns_cb = (dhcp_ddns_ns_t *)eventp->ev_arg; 1034 dns_fixedname_t zname0; 1035 dns_name_t *zname = NULL, *ns_name = NULL; 1036 dns_rdataset_t *rdataset; 1037 isc_result_t result; 1038 dns_rdata_t rdata = DNS_RDATA_INIT; 1039 dns_rdata_ns_t ns; 1040 1041 /* the transaction is done, get rid of the tag */ 1042 dns_client_destroyrestrans(&ns_cb->transaction); 1043 1044 if (ddns_event->result != ISC_R_SUCCESS) { 1045 /* We didn't find any nameservers, try again */ 1046 1047 /* Remove a label and continue */ 1048 ns_cb->zname = strchr(ns_cb->zname, '.'); 1049 if ((ns_cb->zname == NULL) || 1050 (ns_cb->zname[1] == 0)) { 1051 /* No more labels, all done */ 1052 goto cleanup; 1053 } 1054 ns_cb->zname++; 1055 1056 /* Create a DNS version of the zone name and call the 1057 * resolver code */ 1058 if (((result = dhcp_isc_name((unsigned char *)ns_cb->zname, 1059 &zname0, &zname)) 1060 != ISC_R_SUCCESS) || 1061 ((result = zone_resolve(dhcp_gbl_ctx.dnsclient, 1062 zname, dns_rdataclass_in, 1063 dns_rdatatype_ns, 1064 DNS_CLIENTRESOPT_NODNSSEC, 1065 dhcp_gbl_ctx.task, 1066 find_zone_ns, 1067 (void *)ns_cb, 1068 &ns_cb->transaction)) 1069 != ISC_R_SUCCESS)) { 1070 log_error("find_zone_ns: Unable to build " 1071 "name or start resolve: %s %s", 1072 ns_cb->zname, 1073 isc_result_totext(result)); 1074 goto cleanup; 1075 } 1076 1077 /* we have successfully started the next iteration 1078 * of this step, clean up from the call and continue */ 1079 dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient, 1080 &ddns_event->answerlist); 1081 isc_event_free(&eventp); 1082 return; 1083 } 1084 1085 /* We did get a set of nameservers, save the information and 1086 * start trying to get addresses 1087 */ 1088 ns_cb->eventp = ddns_event; 1089 for (ns_name = ISC_LIST_HEAD(ddns_event->answerlist); 1090 ns_name != NULL; 1091 ns_name = ISC_LIST_NEXT(ns_name, link)) { 1092 1093 for (rdataset = ISC_LIST_HEAD(ns_name->list); 1094 rdataset != NULL; 1095 rdataset = ISC_LIST_NEXT(rdataset, link)) { 1096 1097 if (rdataset->type != dns_rdatatype_ns) 1098 continue; 1099 1100 if ((!dns_rdataset_isassociated(rdataset)) || 1101 (dns_rdataset_first(rdataset) != 1102 ISC_R_SUCCESS)) 1103 continue; 1104 1105 dns_rdataset_current(rdataset, &rdata); 1106 if (dns_rdata_tostruct(&rdata, &ns, NULL) != 1107 ISC_R_SUCCESS) 1108 continue; 1109 1110 /* Save our current state */ 1111 ns_cb->ns_name = ns_name; 1112 ns_cb->rdataset = rdataset; 1113 1114 /* And call out to DNS */ 1115 result = zone_resolve(dhcp_gbl_ctx.dnsclient, &ns.name, 1116 dns_rdataclass_in, 1117 ns_cb->rdtype, 1118 DNS_CLIENTRESOPT_NODNSSEC, 1119 dhcp_gbl_ctx.task, 1120 find_zone_addrs, 1121 (void *)ns_cb, 1122 &ns_cb->transaction); 1123 1124 /* do we need to clean this? */ 1125 dns_rdata_freestruct(&ns); 1126 1127 if (result == ISC_R_SUCCESS) 1128 /* We have successfully started the next step 1129 * we don't cleanup the eventp block as we are 1130 * still using it. 1131 */ 1132 return; 1133 1134 log_error("find_zone_ns: unable to continue " 1135 "resolve: %s %s", 1136 ns_cb->zname, 1137 isc_result_totext(result)); 1138 1139 /* The call to start a resolve transaction failed, 1140 * should we try to continue with any other names? 1141 * For now let's not 1142 */ 1143 goto cleanup; 1144 } 1145 } 1146 1147 cleanup: 1148 /* When we add a queue to manage the DDNS 1149 * requests we will need to remove any that 1150 * were waiting for this resolution */ 1151 1152 dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient, 1153 &ddns_event->answerlist); 1154 isc_event_free(&eventp); 1155 1156 remove_from_ns_queue(ns_cb); 1157 1158 data_string_forget(&ns_cb->oname, MDL); 1159 dfree(ns_cb, MDL); 1160 return; 1161 1162 } 1163 1164 /* 1165 * Start the process of finding nameservers via the DNS because 1166 * we don't have a zone entry already. 1167 * We construct a control block and fill in the DDNS name. As 1168 * the process continues we shall move the zname pointer to 1169 * indicate which labels we are still using. The rest of 1170 * the control block will be filled in as we continue processing. 1171 */ 1172 static isc_result_t 1173 find_zone_start(dhcp_ddns_cb_t *ddns_cb, int direction) 1174 { 1175 isc_result_t status = ISC_R_NOTFOUND; 1176 dhcp_ddns_ns_t *ns_cb; 1177 dns_fixedname_t zname0; 1178 dns_name_t *zname = NULL; 1179 1180 /* 1181 * We don't validate np as that was already done in find_cached_zone() 1182 */ 1183 1184 /* Allocate the control block for this request */ 1185 ns_cb = dmalloc(sizeof(*ns_cb), MDL); 1186 if (ns_cb == NULL) { 1187 log_error("find_zone_start: unable to allocate cb"); 1188 return(ISC_R_FAILURE); 1189 } 1190 ns_cb->rdtype = dns_rdatatype_a; 1191 1192 /* Copy the data string so the NS lookup is independent of the DDNS */ 1193 if (direction == FIND_FORWARD) { 1194 data_string_copy(&ns_cb->oname, &ddns_cb->fwd_name, MDL); 1195 } else { 1196 data_string_copy(&ns_cb->oname, &ddns_cb->rev_name, MDL); 1197 } 1198 ns_cb->zname = (char *)ns_cb->oname.data; 1199 1200 /* 1201 * Check the dns_outstanding_ns queue to see if we are 1202 * already processing something that would cover this name 1203 */ 1204 if (find_in_ns_queue(ns_cb) == ISC_R_SUCCESS) { 1205 data_string_forget(&ns_cb->oname, MDL); 1206 dfree(ns_cb, MDL); 1207 return (ISC_R_SUCCESS); 1208 } 1209 1210 /* Create a DNS version of the zone name and call the 1211 * resolver code */ 1212 if (((status = dhcp_isc_name((unsigned char *)ns_cb->zname, 1213 &zname0, &zname)) 1214 != ISC_R_SUCCESS) || 1215 ((status = zone_resolve(dhcp_gbl_ctx.dnsclient, 1216 zname, dns_rdataclass_in, 1217 dns_rdatatype_ns, 1218 DNS_CLIENTRESOPT_NODNSSEC, 1219 dhcp_gbl_ctx.task, 1220 find_zone_ns, 1221 (void *)ns_cb, 1222 &ns_cb->transaction)) 1223 != ISC_R_SUCCESS)) { 1224 log_error("find_zone_start: Unable to build " 1225 "name or start resolve: %s %s", 1226 ns_cb->zname, 1227 isc_result_totext(status)); 1228 1229 /* We failed to start the process, clean up */ 1230 data_string_forget(&ns_cb->oname, MDL); 1231 dfree(ns_cb, MDL); 1232 } else { 1233 /* We started the process, attach the control block 1234 * to the queue */ 1235 add_to_ns_queue(ns_cb); 1236 } 1237 1238 return (status); 1239 } 1240 #endif 1241 1242 isc_result_t 1243 find_cached_zone(dhcp_ddns_cb_t *ddns_cb, int direction) 1244 { 1245 isc_result_t status = ISC_R_NOTFOUND; 1246 const char *np; 1247 struct dns_zone *zone = NULL; 1248 struct data_string nsaddrs; 1249 struct in_addr zone_addr; 1250 struct in6_addr zone_addr6; 1251 int ix; 1252 1253 if (direction == FIND_FORWARD) { 1254 np = (const char *)ddns_cb->fwd_name.data; 1255 } else { 1256 np = (const char *)ddns_cb->rev_name.data; 1257 } 1258 1259 /* We can't look up a null zone. */ 1260 if ((np == NULL) || (*np == '\0')) { 1261 return (DHCP_R_INVALIDARG); 1262 } 1263 1264 /* 1265 * For each subzone, try to find a cached zone. 1266 */ 1267 for (;;) { 1268 status = dns_zone_lookup(&zone, np); 1269 if (status == ISC_R_SUCCESS) 1270 break; 1271 1272 np = strchr(np, '.'); 1273 if (np == NULL) 1274 break; 1275 np++; 1276 } 1277 1278 if (status != ISC_R_SUCCESS) 1279 return (status); 1280 1281 /* Make sure the zone is valid, we've already gotten 1282 * rid of expired dynamic zones. Check to see if 1283 * we repudiated this zone. If so give up. 1284 */ 1285 if ((zone->flags & DNS_ZONE_INACTIVE) != 0) { 1286 dns_zone_dereference(&zone, MDL); 1287 return (ISC_R_FAILURE); 1288 } 1289 1290 /* Make sure the zone name will fit. */ 1291 if (strlen(zone->name) > sizeof(ddns_cb->zone_name)) { 1292 dns_zone_dereference(&zone, MDL); 1293 return (ISC_R_NOSPACE); 1294 } 1295 strcpy((char *)&ddns_cb->zone_name[0], zone->name); 1296 1297 memset (&nsaddrs, 0, sizeof nsaddrs); 1298 ix = 0; 1299 1300 if (zone->primary) { 1301 if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL, 1302 NULL, NULL, &global_scope, 1303 zone->primary, MDL)) { 1304 int ip = 0; 1305 while (ix < DHCP_MAXNS) { 1306 if (ip + 4 > nsaddrs.len) 1307 break; 1308 memcpy(&zone_addr, &nsaddrs.data[ip], 4); 1309 isc_sockaddr_fromin(&ddns_cb->zone_addrs[ix], 1310 &zone_addr, 1311 NS_DEFAULTPORT); 1312 ISC_LIST_APPEND(ddns_cb->zone_server_list, 1313 &ddns_cb->zone_addrs[ix], 1314 link); 1315 ip += 4; 1316 ix++; 1317 } 1318 data_string_forget(&nsaddrs, MDL); 1319 } 1320 } 1321 1322 if (zone->primary6) { 1323 if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL, 1324 NULL, NULL, &global_scope, 1325 zone->primary6, MDL)) { 1326 int ip = 0; 1327 while (ix < DHCP_MAXNS) { 1328 if (ip + 16 > nsaddrs.len) 1329 break; 1330 memcpy(&zone_addr6, &nsaddrs.data[ip], 16); 1331 isc_sockaddr_fromin6(&ddns_cb->zone_addrs[ix], 1332 &zone_addr6, 1333 NS_DEFAULTPORT); 1334 ISC_LIST_APPEND(ddns_cb->zone_server_list, 1335 &ddns_cb->zone_addrs[ix], 1336 link); 1337 ip += 16; 1338 ix++; 1339 } 1340 data_string_forget(&nsaddrs, MDL); 1341 } 1342 } 1343 1344 if (zone->secondary) { 1345 if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL, 1346 NULL, NULL, &global_scope, 1347 zone->secondary, MDL)) { 1348 int ip = 0; 1349 while (ix < DHCP_MAXNS) { 1350 if (ip + 4 > nsaddrs.len) 1351 break; 1352 memcpy(&zone_addr, &nsaddrs.data[ip], 4); 1353 isc_sockaddr_fromin(&ddns_cb->zone_addrs[ix], 1354 &zone_addr, 1355 NS_DEFAULTPORT); 1356 ISC_LIST_APPEND(ddns_cb->zone_server_list, 1357 &ddns_cb->zone_addrs[ix], 1358 link); 1359 ip += 4; 1360 ix++; 1361 } 1362 data_string_forget (&nsaddrs, MDL); 1363 } 1364 } 1365 1366 if (zone->secondary6) { 1367 if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL, 1368 NULL, NULL, &global_scope, 1369 zone->secondary6, MDL)) { 1370 int ip = 0; 1371 while (ix < DHCP_MAXNS) { 1372 if (ip + 16 > nsaddrs.len) 1373 break; 1374 memcpy(&zone_addr6, &nsaddrs.data[ip], 16); 1375 isc_sockaddr_fromin6(&ddns_cb->zone_addrs[ix], 1376 &zone_addr6, 1377 NS_DEFAULTPORT); 1378 ISC_LIST_APPEND(ddns_cb->zone_server_list, 1379 &ddns_cb->zone_addrs[ix], 1380 link); 1381 ip += 16; 1382 ix++; 1383 } 1384 data_string_forget (&nsaddrs, MDL); 1385 } 1386 } 1387 1388 dns_zone_reference(&ddns_cb->zone, zone, MDL); 1389 dns_zone_dereference (&zone, MDL); 1390 return ISC_R_SUCCESS; 1391 } 1392 1393 void forget_zone (struct dns_zone **zone) 1394 { 1395 dns_zone_dereference (zone, MDL); 1396 } 1397 1398 void repudiate_zone (struct dns_zone **zone) 1399 { 1400 /* verify that we have a pointer at least */ 1401 if ((zone == NULL) || (*zone == NULL)) { 1402 log_info("Null argument to repudiate zone"); 1403 return; 1404 } 1405 1406 (*zone)->flags |= DNS_ZONE_INACTIVE; 1407 dns_zone_dereference(zone, MDL); 1408 } 1409 1410 #if defined (DNS_ZONE_LOOKUP) 1411 void cache_found_zone(dhcp_ddns_ns_t *ns_cb) 1412 { 1413 struct dns_zone *zone = NULL; 1414 int len, remove_zone = 0; 1415 1416 /* See if there's already such a zone. */ 1417 if (dns_zone_lookup(&zone, ns_cb->zname) == ISC_R_SUCCESS) { 1418 /* If it's not a dynamic zone, leave it alone. */ 1419 if (zone->timeout == 0) 1420 return; 1421 1422 /* Remove any old addresses in case they've changed */ 1423 if (zone->primary) 1424 option_cache_dereference(&zone->primary, MDL); 1425 if (zone->primary6) 1426 option_cache_dereference(&zone->primary6, MDL); 1427 1428 /* Set the flag to remove the zone from the hash if 1429 we have problems */ 1430 remove_zone = 1; 1431 } else if (dns_zone_allocate(&zone, MDL) == 0) { 1432 return; 1433 } else { 1434 /* We've just allocated the zone, now we need 1435 * to allocate space for the name and addresses 1436 */ 1437 1438 /* allocate space for the name */ 1439 len = strlen(ns_cb->zname); 1440 zone->name = dmalloc(len + 2, MDL); 1441 if (zone->name == NULL) { 1442 goto cleanup; 1443 } 1444 1445 /* Copy the name and add a trailing '.' if necessary */ 1446 strcpy(zone->name, ns_cb->zname); 1447 if (zone->name[len-1] != '.') { 1448 zone->name[len] = '.'; 1449 zone->name[len+1] = 0; 1450 } 1451 } 1452 1453 zone->timeout = cur_time + ns_cb->ttl; 1454 1455 if (ns_cb->num_addrs != 0) { 1456 len = ns_cb->num_addrs * sizeof(struct in_addr); 1457 if ((!option_cache_allocate(&zone->primary, MDL)) || 1458 (!buffer_allocate(&zone->primary->data.buffer, 1459 len, MDL))) { 1460 if (remove_zone == 1) 1461 remove_dns_zone(zone); 1462 goto cleanup; 1463 } 1464 memcpy(zone->primary->data.buffer->data, ns_cb->addrs, len); 1465 zone->primary->data.data = 1466 &zone->primary->data.buffer->data[0]; 1467 zone->primary->data.len = len; 1468 } 1469 if (ns_cb->num_addrs6 != 0) { 1470 len = ns_cb->num_addrs6 * sizeof(struct in6_addr); 1471 if ((!option_cache_allocate(&zone->primary6, MDL)) || 1472 (!buffer_allocate(&zone->primary6->data.buffer, 1473 len, MDL))) { 1474 if (remove_zone == 1) 1475 remove_dns_zone(zone); 1476 goto cleanup; 1477 } 1478 memcpy(zone->primary6->data.buffer->data, ns_cb->addrs6, len); 1479 zone->primary6->data.data = 1480 &zone->primary6->data.buffer->data[0]; 1481 zone->primary6->data.len = len; 1482 } 1483 1484 enter_dns_zone(zone); 1485 1486 cleanup: 1487 dns_zone_dereference(&zone, MDL); 1488 return; 1489 } 1490 #endif 1491 1492 /*! 1493 * \brief Create an id for a client 1494 * 1495 * This function is used to create an id for a client to use with DDNS 1496 * This version of the function is for the standard style, RFC 4701 1497 * 1498 * This function takes information from the type and data fields and 1499 * mangles it into a dhcid string which it places in ddns_cb. It also 1500 * sets a field in ddns_cb to specify the class that should be used 1501 * when sending the dhcid, in this case it is a DHCID record so we use 1502 * dns_rdatatype_dhcid 1503 * 1504 * The DHCID we construct is: 1505 * 2 bytes - identifier type (see 4701 and IANA) 1506 * 1 byte - digest type, currently only SHA256 (1) 1507 * n bytes - digest, length depends on digest type, currently 32 for 1508 * SHA256 1509 * 1510 * What we base the digest on is up to the calling code for an id type of 1511 * 0 - 1 octet htype followed by hlen octets of chaddr from v4 client request 1512 * 1 - data octets from a dhcpv4 client's client identifier option 1513 * 2 - the client DUID from a v4 or v6 client's client id option 1514 * This identifier is concatenated with the fqdn and the result is digested. 1515 */ 1516 static int get_std_dhcid(dhcp_ddns_cb_t *ddns_cb, 1517 int type, 1518 const u_int8_t *identifier, 1519 unsigned id_len) 1520 { 1521 struct data_string *id = &ddns_cb->dhcid; 1522 isc_sha256_t sha256; 1523 unsigned char buf[ISC_SHA256_DIGESTLENGTH]; 1524 unsigned char fwd_buf[256]; 1525 unsigned fwd_buflen = 0; 1526 1527 /* Types can only be 0..(2^16)-1. */ 1528 if (type < 0 || type > 65535) 1529 return (0); 1530 1531 /* We need to convert the fwd name to wire representation */ 1532 if (MRns_name_pton((char *)ddns_cb->fwd_name.data, fwd_buf, 256) == -1) 1533 return (0); 1534 while(fwd_buf[fwd_buflen] != 0) { 1535 fwd_buflen += fwd_buf[fwd_buflen] + 1; 1536 } 1537 fwd_buflen++; 1538 1539 if (!buffer_allocate(&id->buffer, 1540 ISC_SHA256_DIGESTLENGTH + 2 + 1, 1541 MDL)) 1542 return (0); 1543 id->data = id->buffer->data; 1544 1545 /* The two first bytes contain the type identifier. */ 1546 putUShort(id->buffer->data, (unsigned)type); 1547 1548 /* The next is the digest type, SHA-256 is 1 */ 1549 putUChar(id->buffer->data + 2, 1u); 1550 1551 /* Computing the digest */ 1552 isc_sha256_init(&sha256); 1553 isc_sha256_update(&sha256, identifier, id_len); 1554 isc_sha256_update(&sha256, fwd_buf, fwd_buflen); 1555 isc_sha256_final(buf, &sha256); 1556 1557 memcpy(id->buffer->data + 3, &buf, ISC_SHA256_DIGESTLENGTH); 1558 1559 id->len = ISC_SHA256_DIGESTLENGTH + 2 + 1; 1560 1561 return (1); 1562 } 1563 1564 /*! 1565 * 1566 * \brief Create an id for a client 1567 * 1568 * This function is used to create an id for a client to use with DDNS 1569 * This version of the function is for the interim style. It is retained 1570 * to allow users to continue using the interim style but they should 1571 * switch to the standard style (which uses get_std_dhcid) for better 1572 * interoperability. 1573 * 1574 * This function takes information from the type and data fields and 1575 * mangles it into a dhcid string which it places in ddns_cb. It also 1576 * sets a field in ddns_cb to specify the class that should be used 1577 * when sending the dhcid, in this case it is a txt record so we use 1578 * dns_rdata_type_txt 1579 * 1580 * NOTE WELL: this function has issues with how it calculates the 1581 * dhcid, they can't be changed now as that would break the records 1582 * already in use. 1583 */ 1584 1585 static int get_int_dhcid (dhcp_ddns_cb_t *ddns_cb, 1586 int type, 1587 const u_int8_t *data, 1588 unsigned len) 1589 { 1590 struct data_string *id = &ddns_cb->dhcid; 1591 unsigned char buf[ISC_MD5_DIGESTLENGTH]; 1592 isc_md5_t md5; 1593 int i; 1594 1595 /* Types can only be 0..(2^16)-1. */ 1596 if (type < 0 || type > 65535) 1597 return (0); 1598 1599 /* 1600 * Hexadecimal MD5 digest plus two byte type, NUL, 1601 * and one byte for length for dns. 1602 */ 1603 if (!buffer_allocate(&id -> buffer, 1604 (ISC_MD5_DIGESTLENGTH * 2) + 4, MDL)) 1605 return (0); 1606 id->data = id->buffer->data; 1607 1608 /* 1609 * We put the length into the first byte to turn 1610 * this into a dns text string. This avoid needing to 1611 * copy the string to add the byte later. 1612 */ 1613 id->buffer->data[0] = ISC_MD5_DIGESTLENGTH * 2 + 2; 1614 1615 /* Put the type in the next two bytes. */ 1616 id->buffer->data[1] = "0123456789abcdef"[(type >> 4) & 0xf]; 1617 /* This should have been [type & 0xf] but now that 1618 * it is in use we need to leave it this way in order 1619 * to avoid disturbing customer's lease files 1620 */ 1621 id->buffer->data[2] = "0123456789abcdef"[type % 15]; 1622 1623 /* Mash together an MD5 hash of the identifier. */ 1624 isc_md5_init(&md5); 1625 isc_md5_update(&md5, data, len); 1626 isc_md5_final(&md5, buf); 1627 1628 /* Convert into ASCII. */ 1629 for (i = 0; i < ISC_MD5_DIGESTLENGTH; i++) { 1630 id->buffer->data[i * 2 + 3] = 1631 "0123456789abcdef"[(buf[i] >> 4) & 0xf]; 1632 id->buffer->data[i * 2 + 4] = 1633 "0123456789abcdef"[buf[i] & 0xf]; 1634 } 1635 1636 id->len = ISC_MD5_DIGESTLENGTH * 2 + 3; 1637 id->buffer->data[id->len] = 0; 1638 id->terminated = 1; 1639 1640 return (1); 1641 } 1642 1643 int get_dhcid(dhcp_ddns_cb_t *ddns_cb, 1644 int type, 1645 const u_int8_t *identifier, 1646 unsigned id_len) 1647 { 1648 if (ddns_cb->dhcid_class == dns_rdatatype_dhcid) 1649 return get_std_dhcid(ddns_cb, type, identifier, id_len); 1650 else 1651 return get_int_dhcid(ddns_cb, type, identifier, id_len); 1652 } 1653 1654 /* 1655 * The dhcid (text version) that we pass to DNS includes a length byte 1656 * at the start but the text we store in the lease doesn't include the 1657 * length byte. The following routines are to convert between the two 1658 * styles. 1659 * 1660 * When converting from a dhcid to a leaseid we reuse the buffer and 1661 * simply adjust the data pointer and length fields in the data string. 1662 * This avoids any prolems with allocating space. 1663 */ 1664 1665 void 1666 dhcid_tolease(struct data_string *dhcid, 1667 struct data_string *leaseid) 1668 { 1669 /* copy the data string then update the fields */ 1670 data_string_copy(leaseid, dhcid, MDL); 1671 leaseid->data++; 1672 leaseid->len--; 1673 } 1674 1675 isc_result_t 1676 dhcid_fromlease(struct data_string *dhcid, 1677 struct data_string *leaseid) 1678 { 1679 if (!buffer_allocate(&dhcid->buffer, leaseid->len + 2, MDL)) { 1680 return(ISC_R_FAILURE); 1681 } 1682 1683 dhcid->data = dhcid->buffer->data; 1684 1685 dhcid->buffer->data[0] = leaseid->len; 1686 memcpy(dhcid->buffer->data + 1, leaseid->data, leaseid->len); 1687 dhcid->len = leaseid->len + 1; 1688 if (leaseid->terminated == 1) { 1689 dhcid->buffer->data[dhcid->len] = 0; 1690 dhcid->terminated = 1; 1691 } 1692 1693 return(ISC_R_SUCCESS); 1694 } 1695 1696 /* 1697 * Construct the dataset for this item. 1698 * This is a fairly simple arrangement as the operations we do are simple. 1699 * If there is data we simply have the rdata point to it - the formatting 1700 * must be correct already. We then link the rdatalist to the rdata and 1701 * create a rdataset from the rdatalist. 1702 */ 1703 1704 static isc_result_t 1705 make_dns_dataset(dns_rdataclass_t dataclass, 1706 dns_rdatatype_t datatype, 1707 dhcp_ddns_data_t *dataspace, 1708 unsigned char *data, 1709 int datalen, 1710 int ttl) 1711 { 1712 dns_rdata_t *rdata = &dataspace->rdata; 1713 dns_rdatalist_t *rdatalist = &dataspace->rdatalist; 1714 dns_rdataset_t *rdataset = &dataspace->rdataset; 1715 1716 isc_region_t region; 1717 1718 /* set up the rdata */ 1719 dns_rdata_init(rdata); 1720 1721 if (data == NULL) { 1722 /* No data, set up the rdata fields we care about */ 1723 rdata->flags = DNS_RDATA_UPDATE; 1724 rdata->type = datatype; 1725 rdata->rdclass = dataclass; 1726 } else { 1727 switch(datatype) { 1728 case dns_rdatatype_a: 1729 case dns_rdatatype_aaaa: 1730 case dns_rdatatype_txt: 1731 case dns_rdatatype_dhcid: 1732 case dns_rdatatype_ptr: 1733 /* The data must be in the right format we simply 1734 * need to supply it via the correct structure */ 1735 region.base = data; 1736 region.length = datalen; 1737 dns_rdata_fromregion(rdata, dataclass, datatype, 1738 ®ion); 1739 break; 1740 default: 1741 return(DHCP_R_INVALIDARG); 1742 break; 1743 } 1744 } 1745 1746 /* setup the datalist and attach the rdata to it */ 1747 dns_rdatalist_init(rdatalist); 1748 rdatalist->type = datatype; 1749 rdatalist->rdclass = dataclass; 1750 rdatalist->ttl = ttl; 1751 ISC_LIST_APPEND(rdatalist->rdata, rdata, link); 1752 1753 /* convert the datalist to a dataset */ 1754 dns_rdataset_init(rdataset); 1755 dns_rdatalist_tordataset(rdatalist, rdataset); 1756 1757 return(ISC_R_SUCCESS); 1758 } 1759 1760 /* 1761 * When a DHCP client or server intends to update an A RR, it first 1762 * prepares a DNS UPDATE query which includes as a prerequisite the 1763 * assertion that the name does not exist. The update section of the 1764 * query attempts to add the new name and its IP address mapping (an A 1765 * RR), and the DHCID RR with its unique client-identity. 1766 * -- "Interaction between DHCP and DNS" 1767 * 1768 * There are two cases, one for the server and one for the client. 1769 * 1770 * For the server the first step will have a request of: 1771 * The name is not in use 1772 * Add an A RR 1773 * Add a DHCID RR 1774 * 1775 * For the client the first step will have a request of: 1776 * The A RR does not exist 1777 * Add an A RR 1778 * Add a DHCID RR 1779 */ 1780 1781 static isc_result_t 1782 ddns_modify_fwd_add1(dhcp_ddns_cb_t *ddns_cb, 1783 dhcp_ddns_data_t *dataspace, 1784 dns_name_t *pname, 1785 dns_name_t *uname) 1786 { 1787 isc_result_t result; 1788 1789 /* Construct the prerequisite list */ 1790 if ((ddns_cb->flags & DDNS_INCLUDE_RRSET) != 0) { 1791 /* The A RR shouldn't exist */ 1792 result = make_dns_dataset(dns_rdataclass_none, 1793 ddns_cb->address_type, 1794 dataspace, NULL, 0, 0); 1795 } else { 1796 /* The name is not in use */ 1797 result = make_dns_dataset(dns_rdataclass_none, 1798 dns_rdatatype_any, 1799 dataspace, NULL, 0, 0); 1800 } 1801 if (result != ISC_R_SUCCESS) { 1802 return(result); 1803 } 1804 ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link); 1805 dataspace++; 1806 1807 /* Construct the update list */ 1808 /* Add the A RR */ 1809 result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type, 1810 dataspace, 1811 (unsigned char *)ddns_cb->address.iabuf, 1812 ddns_cb->address.len, ddns_cb->ttl); 1813 if (result != ISC_R_SUCCESS) { 1814 return(result); 1815 } 1816 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link); 1817 dataspace++; 1818 1819 /* Add the DHCID RR */ 1820 result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class, 1821 dataspace, 1822 (unsigned char *)ddns_cb->dhcid.data, 1823 ddns_cb->dhcid.len, ddns_cb->ttl); 1824 if (result != ISC_R_SUCCESS) { 1825 return(result); 1826 } 1827 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link); 1828 1829 return(ISC_R_SUCCESS); 1830 } 1831 1832 /* 1833 * If the first update operation fails with YXDOMAIN, the updater can 1834 * conclude that the intended name is in use. The updater then 1835 * attempts to confirm that the DNS name is not being used by some 1836 * other host. The updater prepares a second UPDATE query in which the 1837 * prerequisite is that the desired name has attached to it a DHCID RR 1838 * whose contents match the client identity. The update section of 1839 * this query deletes the existing A records on the name, and adds the 1840 * A record that matches the DHCP binding and the DHCID RR with the 1841 * client identity. 1842 * -- "Interaction between DHCP and DNS" 1843 * 1844 * The message for the second step depends on if we are doing conflict 1845 * resolution. If we are we include a prerequisite. If not we delete 1846 * the DHCID in addition to all A rrsets. 1847 * 1848 * Conflict resolution: 1849 * DHCID RR exists, and matches client identity. 1850 * Delete A RRset. 1851 * Add A RR. 1852 * 1853 * Conflict override: 1854 * Delete DHCID RRs. 1855 * Add DHCID RR 1856 * Delete A RRset. 1857 * Add A RR. 1858 */ 1859 1860 static isc_result_t 1861 ddns_modify_fwd_add2(dhcp_ddns_cb_t *ddns_cb, 1862 dhcp_ddns_data_t *dataspace, 1863 dns_name_t *pname, 1864 dns_name_t *uname) 1865 { 1866 isc_result_t result = ISC_R_SUCCESS; 1867 1868 /* 1869 * If we are doing conflict resolution (unset) we use a prereq list. 1870 * If not we delete the DHCID in addition to all A rrsets. 1871 */ 1872 if ((ddns_cb->flags & DDNS_CONFLICT_OVERRIDE) == 0) { 1873 /* Construct the prereq list */ 1874 /* The DHCID RR exists and matches the client identity */ 1875 result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class, 1876 dataspace, 1877 (unsigned char *)ddns_cb->dhcid.data, 1878 ddns_cb->dhcid.len, 0); 1879 if (result != ISC_R_SUCCESS) { 1880 return(result); 1881 } 1882 ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link); 1883 dataspace++; 1884 } else { 1885 /* Start constructing the update list. 1886 * Conflict detection override: delete DHCID RRs */ 1887 result = make_dns_dataset(dns_rdataclass_any, 1888 ddns_cb->dhcid_class, 1889 dataspace, NULL, 0, 0); 1890 if (result != ISC_R_SUCCESS) { 1891 return(result); 1892 } 1893 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link); 1894 dataspace++; 1895 1896 /* Add current DHCID RR */ 1897 result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class, 1898 dataspace, 1899 (unsigned char *)ddns_cb->dhcid.data, 1900 ddns_cb->dhcid.len, ddns_cb->ttl); 1901 if (result != ISC_R_SUCCESS) { 1902 return(result); 1903 } 1904 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link); 1905 dataspace++; 1906 } 1907 1908 /* Start or continue constructing the update list */ 1909 /* Delete the A RRset */ 1910 result = make_dns_dataset(dns_rdataclass_any, ddns_cb->address_type, 1911 dataspace, NULL, 0, 0); 1912 if (result != ISC_R_SUCCESS) { 1913 return(result); 1914 } 1915 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link); 1916 dataspace++; 1917 1918 /* Add the A RR */ 1919 result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type, 1920 dataspace, 1921 (unsigned char *)ddns_cb->address.iabuf, 1922 ddns_cb->address.len, ddns_cb->ttl); 1923 if (result != ISC_R_SUCCESS) { 1924 return(result); 1925 } 1926 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link); 1927 1928 return(ISC_R_SUCCESS); 1929 } 1930 1931 /* 1932 * The entity chosen to handle the A record for this client (either the 1933 * client or the server) SHOULD delete the A record that was added when 1934 * the lease was made to the client. 1935 * 1936 * In order to perform this delete, the updater prepares an UPDATE 1937 * query which contains two prerequisites. The first prerequisite 1938 * asserts that the DHCID RR exists whose data is the client identity 1939 * described in Section 4.3. The second prerequisite asserts that the 1940 * data in the A RR contains the IP address of the lease that has 1941 * expired or been released. 1942 * -- "Interaction between DHCP and DNS" 1943 * 1944 * RFC 4703 has relaxed the prereqisites to only checking the DHCID RR 1945 * and we have adopted that to minizmie problems due to interruptions 1946 * when doing a deletion. 1947 * 1948 * First try has: 1949 * DHCID RR exists, and matches client identity. 1950 * Delete appropriate A RR. 1951 */ 1952 1953 static isc_result_t 1954 ddns_modify_fwd_rem1(dhcp_ddns_cb_t *ddns_cb, 1955 dhcp_ddns_data_t *dataspace, 1956 dns_name_t *pname, 1957 dns_name_t *uname) 1958 { 1959 isc_result_t result = ISC_R_SUCCESS; 1960 1961 /* Consruct the prereq list */ 1962 /* The DHCID RR exists and matches the client identity */ 1963 result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class, 1964 dataspace, 1965 (unsigned char *)ddns_cb->dhcid.data, 1966 ddns_cb->dhcid.len, 0); 1967 if (result != ISC_R_SUCCESS) { 1968 return(result); 1969 } 1970 ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link); 1971 dataspace++; 1972 1973 /* Construct the update list */ 1974 /* Delete A RRset */ 1975 result = make_dns_dataset(dns_rdataclass_none, ddns_cb->address_type, 1976 dataspace, 1977 (unsigned char *)ddns_cb->address.iabuf, 1978 ddns_cb->address.len, 0); 1979 if (result != ISC_R_SUCCESS) { 1980 return(result); 1981 } 1982 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link); 1983 1984 return(ISC_R_SUCCESS); 1985 } 1986 1987 /* 1988 * If the deletion of the A succeeded, and there are no A or AAAA 1989 * records left for this domain, then we can blow away the DHCID 1990 * record as well. We can't blow away the DHCID record above 1991 * because it's possible that more than one record has been added 1992 * to this domain name. 1993 * 1994 * Second query has: 1995 * A RR does not exist. 1996 * AAAA RR does not exist. 1997 * Delete appropriate DHCID RR. 1998 */ 1999 2000 static isc_result_t 2001 ddns_modify_fwd_rem2(dhcp_ddns_cb_t *ddns_cb, 2002 dhcp_ddns_data_t *dataspace, 2003 dns_name_t *pname, 2004 dns_name_t *uname) 2005 { 2006 isc_result_t result; 2007 2008 /* Construct the prereq list */ 2009 /* The A RR does not exist */ 2010 result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_a, 2011 dataspace, NULL, 0, 0); 2012 if (result != ISC_R_SUCCESS) { 2013 return(result); 2014 } 2015 ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link); 2016 dataspace++; 2017 2018 /* The AAAA RR does not exist */ 2019 result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_aaaa, 2020 dataspace, NULL, 0, 0); 2021 if (result != ISC_R_SUCCESS) { 2022 return(result); 2023 } 2024 ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link); 2025 dataspace++; 2026 2027 /* Construct the update list */ 2028 /* Delete DHCID RR */ 2029 result = make_dns_dataset(dns_rdataclass_none, ddns_cb->dhcid_class, 2030 dataspace, 2031 (unsigned char *)ddns_cb->dhcid.data, 2032 ddns_cb->dhcid.len, 0); 2033 if (result != ISC_R_SUCCESS) { 2034 return(result); 2035 } 2036 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link); 2037 2038 return(ISC_R_SUCCESS); 2039 } 2040 2041 /* 2042 * This routine converts from the task action call into something 2043 * easier to work with. It also handles the common case of a signature 2044 * or zone not being correct. 2045 */ 2046 void ddns_interlude(isc_task_t *taskp, 2047 isc_event_t *eventp) 2048 { 2049 dhcp_ddns_cb_t *ddns_cb = (dhcp_ddns_cb_t *)eventp->ev_arg; 2050 dns_clientupdateevent_t *ddns_event = (dns_clientupdateevent_t *)eventp; 2051 isc_result_t eresult = ddns_event->result; 2052 isc_result_t result; 2053 2054 /* We've extracted the information we want from it, get rid of 2055 * the event block.*/ 2056 isc_event_free(&eventp); 2057 2058 #if defined (TRACING) 2059 if (trace_record()) { 2060 trace_ddns_input_write(ddns_cb, eresult); 2061 } 2062 #endif 2063 2064 #if defined (DEBUG_DNS_UPDATES) 2065 print_dns_status(DDNS_PRINT_INBOUND, ddns_cb, eresult); 2066 #endif 2067 2068 /* This transaction is complete, clear the value */ 2069 dns_client_destroyupdatetrans(&ddns_cb->transaction); 2070 2071 /* If we cancelled or tried to cancel the operation we just 2072 * need to clean up. */ 2073 if ((eresult == ISC_R_CANCELED) || 2074 ((ddns_cb->flags & DDNS_ABORT) != 0)) { 2075 #if defined (DEBUG_DNS_UPDATES) 2076 log_info("DDNS: completeing transaction cancellation cb=%p, " 2077 "flags=%x, %s", 2078 ddns_cb, ddns_cb->flags, isc_result_totext(eresult)); 2079 #endif 2080 if ((ddns_cb->flags & DDNS_ABORT) == 0) { 2081 log_info("DDNS: cleaning up lease pointer for a cancel " 2082 "cb=%p", ddns_cb); 2083 /* 2084 * We shouldn't actually be able to get here but 2085 * we are. This means we haven't cleaned up 2086 * the lease pointer so we need to do that before 2087 * freeing the cb. 2088 */ 2089 ddns_cb->cur_func(ddns_cb, eresult); 2090 return; 2091 } 2092 2093 if (ddns_cb->next_op != NULL) { 2094 /* if necessary cleanup up next op block */ 2095 ddns_cb_free(ddns_cb->next_op, MDL); 2096 } 2097 ddns_cb_free(ddns_cb, MDL); 2098 return; 2099 } 2100 2101 /* If we had a problem with our key or zone try again */ 2102 if ((eresult == DNS_R_NOTAUTH) || 2103 (eresult == DNS_R_NOTZONE)) { 2104 int i; 2105 /* Our zone information was questionable, 2106 * repudiate it and try again */ 2107 log_error("DDNS: bad zone information, repudiating zone %s", 2108 ddns_cb->zone_name); 2109 repudiate_zone(&ddns_cb->zone); 2110 ddns_cb->zone_name[0] = 0; 2111 ISC_LIST_INIT(ddns_cb->zone_server_list); 2112 for (i = 0; i < DHCP_MAXNS; i++) { 2113 ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link); 2114 } 2115 2116 if ((ddns_cb->state == DDNS_STATE_ADD_PTR) || 2117 (ddns_cb->state == DDNS_STATE_REM_PTR)) { 2118 result = ddns_modify_ptr(ddns_cb, MDL); 2119 } else { 2120 result = ddns_modify_fwd(ddns_cb, MDL); 2121 } 2122 2123 if (result != ISC_R_SUCCESS) { 2124 /* if we couldn't redo the query log it and 2125 * let the next function clean it up */ 2126 log_info("DDNS: Failed to retry after zone failure"); 2127 ddns_cb->cur_func(ddns_cb, result); 2128 } 2129 return; 2130 } else { 2131 /* pass it along to be processed */ 2132 ddns_cb->cur_func(ddns_cb, eresult); 2133 } 2134 2135 return; 2136 } 2137 2138 /* 2139 * This routine does the generic work for sending a ddns message to 2140 * modify the forward record (A or AAAA) and calls one of a set of 2141 * routines to build the specific message. 2142 */ 2143 2144 isc_result_t 2145 ddns_modify_fwd(dhcp_ddns_cb_t *ddns_cb, const char *file, int line) 2146 { 2147 isc_result_t result; 2148 dns_tsec_t *tsec_key = NULL; 2149 2150 unsigned char *clientname; 2151 dhcp_ddns_data_t *dataspace = NULL; 2152 dns_namelist_t prereqlist, updatelist; 2153 dns_fixedname_t zname0, pname0, uname0; 2154 dns_name_t *zname = NULL, *pname, *uname; 2155 2156 isc_sockaddrlist_t *zlist = NULL; 2157 2158 /* Get a pointer to the clientname to make things easier. */ 2159 clientname = (unsigned char *)ddns_cb->fwd_name.data; 2160 2161 /* Extract and validate the type of the address. */ 2162 if (ddns_cb->address.len == 4) { 2163 ddns_cb->address_type = dns_rdatatype_a; 2164 } else if (ddns_cb->address.len == 16) { 2165 ddns_cb->address_type = dns_rdatatype_aaaa; 2166 } else { 2167 return DHCP_R_INVALIDARG; 2168 } 2169 2170 /* 2171 * If we already have a zone use it, otherwise try to lookup the 2172 * zone in our cache. If we find one we will have a pointer to 2173 * the zone that needs to be dereferenced when we are done with it. 2174 * If we don't find one that is okay we'll let the DNS code try and 2175 * find the information for us. 2176 */ 2177 2178 if (ddns_cb->zone == NULL) { 2179 result = find_cached_zone(ddns_cb, FIND_FORWARD); 2180 #if defined (DNS_ZONE_LOOKUP) 2181 if (result == ISC_R_NOTFOUND) { 2182 /* 2183 * We didn't find a cached zone, see if we can 2184 * can find a nameserver and create a zone. 2185 */ 2186 if (find_zone_start(ddns_cb, FIND_FORWARD) 2187 == ISC_R_SUCCESS) { 2188 /* 2189 * We have started the process to find a zone 2190 * queue the ddns_cb for processing after we 2191 * create the zone 2192 */ 2193 /* sar - not yet implemented, currently we just 2194 * arrange for things to get cleaned up 2195 */ 2196 goto cleanup; 2197 } 2198 } 2199 #endif 2200 if (result != ISC_R_SUCCESS) 2201 goto cleanup; 2202 } 2203 2204 /* 2205 * If we have a zone try to get any information we need 2206 * from it - name, addresses and the key. The address 2207 * and key may be empty the name can't be. 2208 */ 2209 if (ddns_cb->zone) { 2210 /* Set up the zone name for use by DNS */ 2211 result = dhcp_isc_name(ddns_cb->zone_name, &zname0, &zname); 2212 if (result != ISC_R_SUCCESS) { 2213 log_error("Unable to build name for zone for " 2214 "fwd update: %s %s", 2215 ddns_cb->zone_name, 2216 isc_result_totext(result)); 2217 goto cleanup; 2218 } 2219 2220 if (!(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) { 2221 /* If we have any addresses get them */ 2222 zlist = &ddns_cb->zone_server_list; 2223 } 2224 2225 2226 if (ddns_cb->zone->key != NULL) { 2227 /* 2228 * Not having a key is fine, having a key 2229 * but not a tsec is odd so we warn the user. 2230 */ 2231 /*sar*/ 2232 /* should we do the warning? */ 2233 tsec_key = ddns_cb->zone->key->tsec_key; 2234 if (tsec_key == NULL) { 2235 log_error("No tsec for use with key %s", 2236 ddns_cb->zone->key->name); 2237 } 2238 } 2239 } 2240 2241 /* Set up the DNS names for the prereq and update lists */ 2242 if (((result = dhcp_isc_name(clientname, &pname0, &pname)) 2243 != ISC_R_SUCCESS) || 2244 ((result = dhcp_isc_name(clientname, &uname0, &uname)) 2245 != ISC_R_SUCCESS)) { 2246 log_error("Unable to build name for fwd update: %s %s", 2247 clientname, isc_result_totext(result)); 2248 goto cleanup; 2249 } 2250 2251 /* Allocate the various isc dns library structures we may require. */ 2252 dataspace = isc_mem_get(dhcp_gbl_ctx.mctx, sizeof(*dataspace) * 4); 2253 if (dataspace == NULL) { 2254 log_error("Unable to allocate memory for fwd update"); 2255 result = ISC_R_NOMEMORY; 2256 goto cleanup; 2257 } 2258 2259 ISC_LIST_INIT(prereqlist); 2260 ISC_LIST_INIT(updatelist); 2261 2262 switch(ddns_cb->state) { 2263 case DDNS_STATE_ADD_FW_NXDOMAIN: 2264 result = ddns_modify_fwd_add1(ddns_cb, dataspace, 2265 pname, uname); 2266 if (result != ISC_R_SUCCESS) { 2267 goto cleanup; 2268 } 2269 ISC_LIST_APPEND(prereqlist, pname, link); 2270 break; 2271 case DDNS_STATE_ADD_FW_YXDHCID: 2272 result = ddns_modify_fwd_add2(ddns_cb, dataspace, 2273 pname, uname); 2274 if (result != ISC_R_SUCCESS) { 2275 goto cleanup; 2276 } 2277 2278 /* If we aren't doing conflict override we have entries 2279 * in the pname list and we need to attach it to the 2280 * prereqlist */ 2281 2282 if ((ddns_cb->flags & DDNS_CONFLICT_OVERRIDE) == 0) { 2283 ISC_LIST_APPEND(prereqlist, pname, link); 2284 } 2285 2286 break; 2287 case DDNS_STATE_REM_FW_YXDHCID: 2288 result = ddns_modify_fwd_rem1(ddns_cb, dataspace, 2289 pname, uname); 2290 if (result != ISC_R_SUCCESS) { 2291 goto cleanup; 2292 } 2293 ISC_LIST_APPEND(prereqlist, pname, link); 2294 break; 2295 case DDNS_STATE_REM_FW_NXRR: 2296 result = ddns_modify_fwd_rem2(ddns_cb, dataspace, 2297 pname, uname); 2298 if (result != ISC_R_SUCCESS) { 2299 goto cleanup; 2300 } 2301 ISC_LIST_APPEND(prereqlist, pname, link); 2302 break; 2303 2304 default: 2305 log_error("Invalid operation in ddns code."); 2306 result = DHCP_R_INVALIDARG; 2307 goto cleanup; 2308 break; 2309 } 2310 2311 /* 2312 * We always have an update list but may not have a prereqlist 2313 * if we are doing conflict override. 2314 */ 2315 ISC_LIST_APPEND(updatelist, uname, link); 2316 2317 /* send the message, cleanup and return the result */ 2318 result = ddns_update(dhcp_gbl_ctx.dnsclient, 2319 dns_rdataclass_in, zname, 2320 &prereqlist, &updatelist, 2321 zlist, tsec_key, 2322 DNS_CLIENTRESOPT_ALLOWRUN, 2323 dhcp_gbl_ctx.task, 2324 ddns_interlude, 2325 (void *)ddns_cb, 2326 &ddns_cb->transaction); 2327 if (result == ISC_R_FAMILYNOSUPPORT) { 2328 log_info("Unable to perform DDNS update, " 2329 "address family not supported"); 2330 } 2331 2332 #if defined (DEBUG_DNS_UPDATES) 2333 print_dns_status(DDNS_PRINT_OUTBOUND, ddns_cb, result); 2334 #endif 2335 2336 cleanup: 2337 #if defined (DEBUG_DNS_UPDATES) 2338 if (result != ISC_R_SUCCESS) { 2339 log_info("DDNS: %s(%d): error in ddns_modify_fwd %s for %p", 2340 file, line, isc_result_totext(result), ddns_cb); 2341 } 2342 #endif 2343 2344 if (dataspace != NULL) { 2345 isc_mem_put(dhcp_gbl_ctx.mctx, dataspace, 2346 sizeof(*dataspace) * 4); 2347 } 2348 return(result); 2349 } 2350 2351 2352 isc_result_t 2353 ddns_modify_ptr(dhcp_ddns_cb_t *ddns_cb, const char *file, int line) 2354 { 2355 isc_result_t result; 2356 dns_tsec_t *tsec_key = NULL; 2357 unsigned char *ptrname; 2358 dhcp_ddns_data_t *dataspace = NULL; 2359 dns_namelist_t updatelist; 2360 dns_fixedname_t zname0, uname0; 2361 dns_name_t *zname = NULL, *uname; 2362 isc_sockaddrlist_t *zlist = NULL; 2363 unsigned char buf[256]; 2364 int buflen; 2365 2366 /* 2367 * Try to lookup the zone in the zone cache. As with the forward 2368 * case it's okay if we don't have one, the DNS code will try to 2369 * find something also if we succeed we will need to dereference 2370 * the zone later. Unlike with the forward case we assume we won't 2371 * have a pre-existing zone. 2372 */ 2373 result = find_cached_zone(ddns_cb, FIND_REVERSE); 2374 2375 #if defined (DNS_ZONE_LOOKUP) 2376 if (result == ISC_R_NOTFOUND) { 2377 /* 2378 * We didn't find a cached zone, see if we can 2379 * can find a nameserver and create a zone. 2380 */ 2381 if (find_zone_start(ddns_cb, FIND_REVERSE) == ISC_R_SUCCESS) { 2382 /* 2383 * We have started the process to find a zone 2384 * queue the ddns_cb for processing after we 2385 * create the zone 2386 */ 2387 /* sar - not yet implemented, currently we just 2388 * arrange for things to get cleaned up 2389 */ 2390 goto cleanup; 2391 } 2392 } 2393 #endif 2394 if (result != ISC_R_SUCCESS) 2395 goto cleanup; 2396 2397 2398 if ((result == ISC_R_SUCCESS) && 2399 !(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) { 2400 /* Set up the zone name for use by DNS */ 2401 result = dhcp_isc_name(ddns_cb->zone_name, &zname0, &zname); 2402 if (result != ISC_R_SUCCESS) { 2403 log_error("Unable to build name for zone for " 2404 "fwd update: %s %s", 2405 ddns_cb->zone_name, 2406 isc_result_totext(result)); 2407 goto cleanup; 2408 } 2409 /* If we have any addresses get them */ 2410 if (!(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) { 2411 zlist = &ddns_cb->zone_server_list; 2412 } 2413 2414 /* 2415 * If we now have a zone try to get the key, NULL is okay, 2416 * having a key but not a tsec is odd so we warn. 2417 */ 2418 /*sar*/ 2419 /* should we do the warning if we have a key but no tsec? */ 2420 if ((ddns_cb->zone != NULL) && (ddns_cb->zone->key != NULL)) { 2421 tsec_key = ddns_cb->zone->key->tsec_key; 2422 if (tsec_key == NULL) { 2423 log_error("No tsec for use with key %s", 2424 ddns_cb->zone->key->name); 2425 } 2426 } 2427 } 2428 2429 /* We must have a name for the update list */ 2430 /* Get a pointer to the ptrname to make things easier. */ 2431 ptrname = (unsigned char *)ddns_cb->rev_name.data; 2432 2433 if ((result = dhcp_isc_name(ptrname, &uname0, &uname)) 2434 != ISC_R_SUCCESS) { 2435 log_error("Unable to build name for fwd update: %s %s", 2436 ptrname, isc_result_totext(result)); 2437 goto cleanup; 2438 } 2439 2440 /* 2441 * Allocate the various isc dns library structures we may require. 2442 * Allocating one blob avoids being halfway through the process 2443 * and being unable to allocate as well as making the free easy. 2444 */ 2445 dataspace = isc_mem_get(dhcp_gbl_ctx.mctx, sizeof(*dataspace) * 2); 2446 if (dataspace == NULL) { 2447 log_error("Unable to allocate memory for fwd update"); 2448 result = ISC_R_NOMEMORY; 2449 goto cleanup; 2450 } 2451 2452 ISC_LIST_INIT(updatelist); 2453 2454 /* 2455 * Construct the update list 2456 * We always delete what's currently there 2457 * Delete PTR RR. 2458 */ 2459 result = make_dns_dataset(dns_rdataclass_any, dns_rdatatype_ptr, 2460 &dataspace[0], NULL, 0, 0); 2461 if (result != ISC_R_SUCCESS) { 2462 goto cleanup; 2463 } 2464 ISC_LIST_APPEND(uname->list, &dataspace[0].rdataset, link); 2465 2466 /* 2467 * If we are updating the pointer we then add the new one 2468 * Add PTR RR. 2469 */ 2470 if (ddns_cb->state == DDNS_STATE_ADD_PTR) { 2471 #if 0 2472 /* 2473 * I've left this dead code in the file for now in case 2474 * we decide to try and get rid of the ns_name functions. 2475 * sar 2476 */ 2477 2478 /* 2479 * Need to convert pointer into on the wire representation 2480 * We replace the '.' characters with the lengths of the 2481 * next name and add a length to the beginning for the first 2482 * name. 2483 */ 2484 if (ddns_cb->fwd_name.len == 1) { 2485 /* the root */ 2486 buf[0] = 0; 2487 buflen = 1; 2488 } else { 2489 unsigned char *cp; 2490 buf[0] = '.'; 2491 memcpy(&buf[1], ddns_cb->fwd_name.data, 2492 ddns_cb->fwd_name.len); 2493 for(cp = buf + ddns_cb->fwd_name.len, buflen = 0; 2494 cp != buf; 2495 cp--) { 2496 if (*cp == '.') { 2497 *cp = buflen; 2498 buflen = 0; 2499 } else { 2500 buflen++; 2501 } 2502 } 2503 *cp = buflen; 2504 buflen = ddns_cb->fwd_name.len + 1; 2505 } 2506 #endif 2507 /* 2508 * Need to convert pointer into on the wire representation 2509 */ 2510 if (MRns_name_pton((char *)ddns_cb->fwd_name.data, 2511 buf, 256) == -1) { 2512 goto cleanup; 2513 } 2514 buflen = 0; 2515 while (buf[buflen] != 0) { 2516 buflen += buf[buflen] + 1; 2517 } 2518 buflen++; 2519 2520 result = make_dns_dataset(dns_rdataclass_in, 2521 dns_rdatatype_ptr, 2522 &dataspace[1], 2523 buf, buflen, ddns_cb->ttl); 2524 if (result != ISC_R_SUCCESS) { 2525 goto cleanup; 2526 } 2527 ISC_LIST_APPEND(uname->list, &dataspace[1].rdataset, link); 2528 } 2529 2530 ISC_LIST_APPEND(updatelist, uname, link); 2531 2532 /*sar*/ 2533 /* 2534 * for now I'll cleanup the dataset immediately, it would be 2535 * more efficient to keep it around in case the signaturure failed 2536 * and we wanted to retry it. 2537 */ 2538 /* send the message, cleanup and return the result */ 2539 result = ddns_update((dns_client_t *)dhcp_gbl_ctx.dnsclient, 2540 dns_rdataclass_in, zname, 2541 NULL, &updatelist, 2542 zlist, tsec_key, 2543 DNS_CLIENTRESOPT_ALLOWRUN, 2544 dhcp_gbl_ctx.task, 2545 ddns_interlude, (void *)ddns_cb, 2546 &ddns_cb->transaction); 2547 if (result == ISC_R_FAMILYNOSUPPORT) { 2548 log_info("Unable to perform DDNS update, " 2549 "address family not supported"); 2550 } 2551 2552 #if defined (DEBUG_DNS_UPDATES) 2553 print_dns_status(DDNS_PRINT_OUTBOUND, ddns_cb, result); 2554 #endif 2555 2556 cleanup: 2557 #if defined (DEBUG_DNS_UPDATES) 2558 if (result != ISC_R_SUCCESS) { 2559 log_info("DDNS: %s(%d): error in ddns_modify_ptr %s for %p", 2560 file, line, isc_result_totext(result), ddns_cb); 2561 } 2562 #endif 2563 2564 if (dataspace != NULL) { 2565 isc_mem_put(dhcp_gbl_ctx.mctx, dataspace, 2566 sizeof(*dataspace) * 2); 2567 } 2568 return(result); 2569 } 2570 2571 void 2572 ddns_cancel(dhcp_ddns_cb_t *ddns_cb, const char *file, int line) { 2573 ddns_cb->flags |= DDNS_ABORT; 2574 if (ddns_cb->transaction != NULL) { 2575 dns_client_cancelupdate((dns_clientupdatetrans_t *) 2576 ddns_cb->transaction); 2577 } 2578 ddns_cb->lease = NULL; 2579 2580 #if defined (DEBUG_DNS_UPDATES) 2581 log_info("DDNS: %s(%d): cancelling transaction for %p", 2582 file, line, ddns_cb); 2583 #endif 2584 } 2585 2586 #endif /* NSUPDATE */ 2587 2588 HASH_FUNCTIONS (dns_zone, const char *, struct dns_zone, dns_zone_hash_t, 2589 dns_zone_reference, dns_zone_dereference, do_case_hash) 2590