1 /* $NetBSD: ddns.c,v 1.2 2018/04/07 22:37:30 christos Exp $ */ 2 3 /* ddns.c 4 5 Dynamic DNS updates. */ 6 7 /* 8 * 9 * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC") 10 * Copyright (c) 2000-2003 by Internet Software Consortium 11 * 12 * This Source Code Form is subject to the terms of the Mozilla Public 13 * License, v. 2.0. If a copy of the MPL was not distributed with this 14 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 17 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 19 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 21 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 22 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 23 * 24 * Internet Systems Consortium, Inc. 25 * 950 Charter Street 26 * Redwood City, CA 94063 27 * <info@isc.org> 28 * https://www.isc.org/ 29 * 30 * This software has been donated to Internet Systems Consortium 31 * by Damien Neil of Nominum, Inc. 32 * 33 * To learn more about Internet Systems Consortium, see 34 * ``https://www.isc.org/''. 35 */ 36 37 #include <sys/cdefs.h> 38 __RCSID("$NetBSD: ddns.c,v 1.2 2018/04/07 22:37:30 christos Exp $"); 39 40 #include "dhcpd.h" 41 #include <dns/result.h> 42 43 char *ddns_standard_tag = "ddns-dhcid"; 44 char *ddns_interim_tag = "ddns-txt"; 45 46 #ifdef NSUPDATE 47 48 #if defined (DEBUG_DNS_UPDATES) 49 static char* dump_ddns_cb_func(void *func); 50 static char* dump_ddns_cb (dhcp_ddns_cb_t *ddns_cb); 51 52 extern struct enumeration_value ddns_styles_values[]; 53 #endif 54 55 static void ddns_fwd_srv_connector(struct lease *lease, 56 struct iasubopt *lease6, 57 struct binding_scope **inscope, 58 dhcp_ddns_cb_t *ddns_cb, 59 isc_result_t eresult); 60 61 static void copy_conflict_flags(u_int16_t *target, u_int16_t source); 62 63 static void ddns_fwd_srv_add3(dhcp_ddns_cb_t *ddns_cb, isc_result_t eresult); 64 65 /* 66 * ddns_cb_free() is part of common lib, while ia_* routines are known 67 * only in the server. Use this wrapper instead of ddns_cb_free() directly. 68 */ 69 static void 70 destroy_ddns_cb(struct dhcp_ddns_cb *ddns_cb, char* file, int line) { 71 if (!ddns_cb) { 72 return; 73 } 74 75 if (ddns_cb->fixed6_ia) { 76 ia_dereference(&ddns_cb->fixed6_ia, MDL); 77 } 78 79 ddns_cb_free(ddns_cb, file, line); 80 81 } 82 83 84 /* DN: No way of checking that there is enough space in a data_string's 85 buffer. Be certain to allocate enough! 86 TL: This is why the expression evaluation code allocates a *new* 87 data_string. :') */ 88 static void data_string_append (struct data_string *ds1, 89 struct data_string *ds2) 90 { 91 memcpy (ds1 -> buffer -> data + ds1 -> len, 92 ds2 -> data, 93 ds2 -> len); 94 ds1 -> len += ds2 -> len; 95 } 96 97 98 /* Determine what, if any, forward and reverse updates need to be 99 * performed, and carry them through. 100 */ 101 int 102 ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, 103 struct iasubopt *lease6, struct iasubopt *old6, 104 struct option_state *options) 105 { 106 unsigned long ddns_ttl = DEFAULT_DDNS_TTL; 107 struct data_string ddns_hostname; 108 struct data_string ddns_domainname; 109 struct data_string old_ddns_fwd_name; 110 struct data_string ddns_fwd_name; 111 struct data_string ddns_dhcid; 112 struct binding_scope **scope = NULL; 113 struct data_string d1; 114 struct option_cache *oc; 115 int s1, s2; 116 int result = 0; 117 int server_updates_a = 1; 118 struct buffer *bp = (struct buffer *)0; 119 int ignorep = 0, client_ignorep = 0; 120 int rev_name_len; 121 int i; 122 123 dhcp_ddns_cb_t *ddns_cb; 124 int do_remove = 0; 125 126 if ((ddns_update_style != DDNS_UPDATE_STYLE_STANDARD) && 127 (ddns_update_style != DDNS_UPDATE_STYLE_INTERIM)) 128 return (0); 129 130 /* 131 * sigh, I want to cancel any previous udpates before we do anything 132 * else but this means we need to deal with the lease vs lease6 133 * question twice. 134 * If there is a ddns request already outstanding cancel it. 135 */ 136 137 if (lease != NULL) { 138 if ((old != NULL) && (old->ddns_cb != NULL)) { 139 ddns_cancel(old->ddns_cb, MDL); 140 old->ddns_cb = NULL; 141 } 142 } else if (lease6 != NULL) { 143 if ((old6 != NULL) && (old6->ddns_cb != NULL)) { 144 ddns_cancel(old6->ddns_cb, MDL); 145 old6->ddns_cb = NULL; 146 } 147 } else { 148 log_fatal("Impossible condition at %s:%d.", MDL); 149 /* Silence compiler warnings. */ 150 result = 0; 151 return(0); 152 } 153 154 /* allocate our control block */ 155 ddns_cb = ddns_cb_alloc(MDL); 156 if (ddns_cb == NULL) { 157 return(0); 158 } 159 /* 160 * Assume that we shall update both the A and ptr records and, 161 * as this is an update, set the active flag 162 */ 163 ddns_cb->flags = DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR | 164 DDNS_ACTIVE_LEASE; 165 166 /* 167 * For v4 we flag static leases so we don't try 168 * and manipulate the lease later. For v6 we don't 169 * get static leases and don't need to flag them. 170 */ 171 if (lease != NULL) { 172 scope = &(lease->scope); 173 ddns_cb->address = lease->ip_addr; 174 if (lease->flags & STATIC_LEASE) 175 ddns_cb->flags |= DDNS_STATIC_LEASE; 176 } else if (lease6 != NULL) { 177 scope = &(lease6->scope); 178 memcpy(ddns_cb->address.iabuf, lease6->addr.s6_addr, 16); 179 ddns_cb->address.len = 16; 180 181 if (lease6->static_lease) { 182 /* We add a reference to keep ia && iasubopt alive 183 * since static v6s are retained anywhere */ 184 ia_reference(&ddns_cb->fixed6_ia, lease6->ia, MDL); 185 ddns_cb->flags |= DDNS_STATIC_LEASE; 186 } 187 } 188 189 memset (&d1, 0, sizeof(d1)); 190 memset (&ddns_hostname, 0, sizeof (ddns_hostname)); 191 memset (&ddns_domainname, 0, sizeof (ddns_domainname)); 192 memset (&old_ddns_fwd_name, 0, sizeof (ddns_fwd_name)); 193 memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name)); 194 memset (&ddns_dhcid, 0, sizeof (ddns_dhcid)); 195 196 /* If we are allowed to accept the client's update of its own A 197 record, see if the client wants to update its own A record. */ 198 if (!(oc = lookup_option(&server_universe, options, 199 SV_CLIENT_UPDATES)) || 200 evaluate_boolean_option_cache(&client_ignorep, packet, lease, NULL, 201 packet->options, options, scope, 202 oc, MDL)) { 203 /* If there's no fqdn.no-client-update or if it's 204 nonzero, don't try to use the client-supplied 205 XXX */ 206 if (!(oc = lookup_option (&fqdn_universe, packet -> options, 207 FQDN_SERVER_UPDATE)) || 208 evaluate_boolean_option_cache(&ignorep, packet, lease, 209 NULL, packet->options, 210 options, scope, oc, MDL)) 211 goto noclient; 212 /* Win98 and Win2k will happily claim to be willing to 213 update an unqualified domain name. */ 214 if (!(oc = lookup_option (&fqdn_universe, packet -> options, 215 FQDN_DOMAINNAME))) 216 goto noclient; 217 if (!(oc = lookup_option (&fqdn_universe, packet -> options, 218 FQDN_FQDN)) || 219 !evaluate_option_cache(&ddns_fwd_name, packet, lease, 220 NULL, packet->options, 221 options, scope, oc, MDL)) 222 goto noclient; 223 ddns_cb->flags &= ~DDNS_UPDATE_ADDR; 224 server_updates_a = 0; 225 goto client_updates; 226 } 227 noclient: 228 /* If do-forward-updates is disabled, this basically means don't 229 do an update unless the client is participating, so if we get 230 here and do-forward-updates is disabled, we can stop. */ 231 if ((oc = lookup_option (&server_universe, options, 232 SV_DO_FORWARD_UPDATES)) && 233 !evaluate_boolean_option_cache(&ignorep, packet, lease, 234 NULL, packet->options, 235 options, scope, oc, MDL)) { 236 goto out; 237 } 238 239 /* If it's a static lease, then don't do the DNS update unless we're 240 specifically configured to do so. If the client asked to do its 241 own update and we allowed that, we don't do this test. */ 242 /* XXX: note that we cannot detect static DHCPv6 leases. */ 243 if ((lease != NULL) && (lease->flags & STATIC_LEASE)) { 244 if (!(oc = lookup_option(&server_universe, options, 245 SV_UPDATE_STATIC_LEASES)) || 246 !evaluate_boolean_option_cache(&ignorep, packet, lease, 247 NULL, packet->options, 248 options, scope, oc, MDL)) 249 goto out; 250 } 251 252 /* 253 * Compute the name for the A record. 254 */ 255 oc = lookup_option(&server_universe, options, SV_DDNS_HOST_NAME); 256 if (oc) 257 s1 = evaluate_option_cache(&ddns_hostname, packet, lease, 258 NULL, packet->options, 259 options, scope, oc, MDL); 260 else 261 s1 = 0; 262 263 /* If we don't have a host name based on ddns-hostname then use 264 * the host declaration name if there is one and use-host-decl-names 265 * is turned on. */ 266 if ((s1 == 0) && (lease && lease->host && lease->host->name)) { 267 oc = lookup_option(&server_universe, options, 268 SV_USE_HOST_DECL_NAMES); 269 if (evaluate_boolean_option_cache(NULL, packet, lease, 270 NULL, packet->options, 271 options, scope, oc, MDL)) { 272 s1 = ((data_string_new(&ddns_hostname, 273 lease->host->name, 274 strlen(lease->host->name), 275 MDL) && ddns_hostname.len > 0)); 276 } 277 } 278 279 oc = lookup_option(&server_universe, options, SV_DDNS_DOMAIN_NAME); 280 if (oc) 281 s2 = evaluate_option_cache(&ddns_domainname, packet, lease, 282 NULL, packet->options, 283 options, scope, oc, MDL); 284 else 285 s2 = 0; 286 287 if (s1 && s2) { 288 if (ddns_hostname.len + ddns_domainname.len > 253) { 289 log_error ("ddns_update: host.domain name too long"); 290 291 goto out; 292 } 293 294 if (buffer_allocate (&ddns_fwd_name.buffer, 295 ddns_hostname.len + 296 ddns_domainname.len + 2, MDL)) { 297 ddns_fwd_name.data = ddns_fwd_name.buffer->data; 298 data_string_append (&ddns_fwd_name, &ddns_hostname); 299 ddns_fwd_name.buffer->data[ddns_fwd_name.len] = '.'; 300 ddns_fwd_name.len++; 301 data_string_append (&ddns_fwd_name, &ddns_domainname); 302 ddns_fwd_name.buffer->data[ddns_fwd_name.len] ='\0'; 303 ddns_fwd_name.terminated = 1; 304 } 305 } 306 client_updates: 307 308 /* See if there's a name already stored on the lease. */ 309 if (find_bound_string(&old_ddns_fwd_name, *scope, "ddns-fwd-name")) { 310 /* If there is, see if it's different. */ 311 if (old_ddns_fwd_name.len != ddns_fwd_name.len || 312 memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data, 313 old_ddns_fwd_name.len)) { 314 /* 315 * If the name is different, mark the old record 316 * for deletion and continue getting the new info. 317 */ 318 do_remove = 1; 319 goto in; 320 } 321 322 #if defined (DDNS_UPDATE_SLOW_TRANSITION) 323 /* 324 * If the slow transition code is enabled check to see 325 * if the stored type (standard or interim doesn't 326 * match the type currently in use. If it doesn't 327 * try to remove and replace the DNS record 328 */ 329 if (((ddns_update_style == DDNS_UPDATE_STYLE_STANDARD) && 330 find_bound_string(&ddns_dhcid, *scope, ddns_interim_tag)) || 331 ((ddns_update_style == DDNS_UPDATE_STYLE_INTERIM) && 332 find_bound_string(&ddns_dhcid, *scope, ddns_standard_tag))) { 333 data_string_forget(&ddns_dhcid, MDL); 334 do_remove = 1; 335 goto in; 336 } 337 #endif 338 339 /* See if the administrator wants to do updates even 340 in cases where the update already appears to have been 341 done. */ 342 if (!(oc = lookup_option(&server_universe, options, 343 SV_UPDATE_OPTIMIZATION)) || 344 evaluate_boolean_option_cache(&ignorep, packet, lease, 345 NULL, packet->options, 346 options, scope, oc, MDL)) { 347 result = 1; 348 goto noerror; 349 } 350 /* If there's no "ddns-fwd-name" on the lease record, see if 351 * there's a ddns-client-fqdn indicating a previous client 352 * update (if it changes, we need to adjust the PTR). 353 */ 354 } else if (find_bound_string(&old_ddns_fwd_name, *scope, 355 "ddns-client-fqdn")) { 356 /* If the name is not different, no need to update 357 the PTR record. */ 358 if (old_ddns_fwd_name.len == ddns_fwd_name.len && 359 !memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data, 360 old_ddns_fwd_name.len) && 361 (!(oc = lookup_option(&server_universe, options, 362 SV_UPDATE_OPTIMIZATION)) || 363 evaluate_boolean_option_cache(&ignorep, packet, lease, 364 NULL, packet->options, 365 options, scope, oc, MDL))) { 366 goto noerror; 367 } 368 } 369 in: 370 371 /* If we don't have a name that the client has been assigned, we 372 can just skip all this. */ 373 374 if ((!ddns_fwd_name.len) || (ddns_fwd_name.len > 255)) { 375 if (ddns_fwd_name.len > 255) { 376 log_error ("client provided fqdn: too long"); 377 } 378 379 /* If desired do the removals */ 380 if (do_remove != 0) { 381 (void) ddns_removals(lease, lease6, NULL, ISC_TRUE); 382 } 383 goto out; 384 } 385 386 /* 387 * Compute the RR TTL. 388 * 389 * We have two ways of computing the TTL. 390 * The old behavior was to allow for the customer to set up 391 * the option or to default things. For v4 this was 1/2 392 * of the lease time, for v6 this was DEFAULT_DDNS_TTL. 393 * The new behavior continues to allow the customer to set 394 * up an option but the defaults are a little different. 395 * We now use 1/2 of the (preferred) lease time for both 396 * v4 and v6 and cap them at a maximum value. 397 * If the customer chooses to use an experession that references 398 * part of the lease the v6 value will be the default as there 399 * isn't a lease available for v6. 400 */ 401 402 ddns_ttl = DEFAULT_DDNS_TTL; 403 if (lease != NULL) { 404 if (lease->ends <= cur_time) { 405 ddns_ttl = 0; 406 } else { 407 ddns_ttl = (lease->ends - cur_time)/2; 408 } 409 } 410 #ifndef USE_OLD_DDNS_TTL 411 else if (lease6 != NULL) { 412 ddns_ttl = lease6->prefer/2; 413 } 414 415 if (ddns_ttl > MAX_DEFAULT_DDNS_TTL) { 416 ddns_ttl = MAX_DEFAULT_DDNS_TTL; 417 } 418 #endif 419 420 if ((oc = lookup_option(&server_universe, options, SV_DDNS_TTL))) { 421 if (evaluate_option_cache(&d1, packet, lease, NULL, 422 packet->options, options, 423 scope, oc, MDL)) { 424 if (d1.len == sizeof (u_int32_t)) 425 ddns_ttl = getULong (d1.data); 426 data_string_forget (&d1, MDL); 427 } 428 } 429 430 ddns_cb->ttl = ddns_ttl; 431 432 /* 433 * Compute the reverse IP name, starting with the domain name. 434 */ 435 oc = lookup_option(&server_universe, options, SV_DDNS_REV_DOMAIN_NAME); 436 if (oc) 437 s1 = evaluate_option_cache(&d1, packet, lease, NULL, 438 packet->options, options, 439 scope, oc, MDL); 440 else 441 s1 = 0; 442 443 /* 444 * Figure out the length of the part of the name that depends 445 * on the address. 446 */ 447 if (ddns_cb->address.len == 4) { 448 char buf[17]; 449 /* XXX: WOW this is gross. */ 450 rev_name_len = snprintf(buf, sizeof(buf), "%u.%u.%u.%u.", 451 ddns_cb->address.iabuf[3] & 0xff, 452 ddns_cb->address.iabuf[2] & 0xff, 453 ddns_cb->address.iabuf[1] & 0xff, 454 ddns_cb->address.iabuf[0] & 0xff) + 1; 455 456 if (s1) { 457 rev_name_len += d1.len; 458 459 if (rev_name_len > 255) { 460 log_error("ddns_update: Calculated rev domain " 461 "name too long."); 462 s1 = 0; 463 data_string_forget(&d1, MDL); 464 } 465 } 466 } else if (ddns_cb->address.len == 16) { 467 /* 468 * IPv6 reverse names are always the same length, with 469 * 32 hex characters separated by dots. 470 */ 471 rev_name_len = sizeof("0.1.2.3.4.5.6.7." 472 "8.9.a.b.c.d.e.f." 473 "0.1.2.3.4.5.6.7." 474 "8.9.a.b.c.d.e.f." 475 "ip6.arpa."); 476 477 /* Set s1 to make sure we gate into updates. */ 478 s1 = 1; 479 } else { 480 log_fatal("invalid address length %d", ddns_cb->address.len); 481 /* Silence compiler warnings. */ 482 return 0; 483 } 484 485 /* See if we are configured NOT to do reverse ptr updates */ 486 if ((oc = lookup_option(&server_universe, options, 487 SV_DO_REVERSE_UPDATES)) && 488 !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL, 489 packet->options, options, 490 scope, oc, MDL)) { 491 ddns_cb->flags &= ~DDNS_UPDATE_PTR; 492 } 493 494 if (s1) { 495 if (buffer_allocate(&ddns_cb->rev_name.buffer, 496 rev_name_len, MDL)) { 497 struct data_string *rname = &ddns_cb->rev_name; 498 rname->data = rname->buffer->data; 499 500 if (ddns_cb->address.len == 4) { 501 rname->len = 502 sprintf((char *)rname->buffer->data, 503 "%u.%u.%u.%u.", 504 ddns_cb->address.iabuf[3] & 0xff, 505 ddns_cb->address.iabuf[2] & 0xff, 506 ddns_cb->address.iabuf[1] & 0xff, 507 ddns_cb->address.iabuf[0] & 0xff); 508 509 /* 510 * d1.data may be opaque, garbage bytes, from 511 * user (mis)configuration. 512 */ 513 data_string_append(rname, &d1); 514 rname->buffer->data[rname->len] = '\0'; 515 } else if (ddns_cb->address.len == 16) { 516 char *p = (char *)&rname->buffer->data; 517 unsigned char *a = ddns_cb->address.iabuf + 15; 518 for (i=0; i<16; i++) { 519 sprintf(p, "%x.%x.", 520 (*a & 0xF), ((*a >> 4) & 0xF)); 521 p += 4; 522 a -= 1; 523 } 524 strcat(p, "ip6.arpa."); 525 rname->len = strlen((const char *)rname->data); 526 } 527 528 rname->terminated = 1; 529 } 530 531 if (d1.data != NULL) 532 data_string_forget(&d1, MDL); 533 } 534 535 /* 536 * copy the string now so we can pass it to the dhcid routines 537 * via the ddns_cb pointer 538 */ 539 data_string_copy(&ddns_cb->fwd_name, &ddns_fwd_name, MDL); 540 541 /* 542 * If we are updating the A record, compute the DHCID value. 543 * We have two options for computing the DHCID value, the older 544 * interim version and the newer standard version. The interim 545 * has some issues but is left as is to avoid compatibility issues. 546 * 547 * We select the type of DHCID to construct and the information to 548 * use for the digest based on 4701 section 3.3 549 */ 550 if ((ddns_cb->flags & DDNS_UPDATE_ADDR) != 0) { 551 int ddns_type; 552 int ddns_len; 553 if (ddns_update_style == DDNS_UPDATE_STYLE_STANDARD) { 554 /* The standard style */ 555 ddns_cb->lease_tag = ddns_standard_tag; 556 ddns_cb->dhcid_class = dns_rdatatype_dhcid; 557 ddns_cb->other_dhcid_class = dns_rdatatype_txt; 558 ddns_type = 1; 559 ddns_len = 4; 560 } else { 561 /* The older interim style */ 562 ddns_cb->lease_tag = ddns_interim_tag; 563 ddns_cb->dhcid_class = dns_rdatatype_txt; 564 ddns_cb->other_dhcid_class = dns_rdatatype_dhcid; 565 /* for backwards compatibility */ 566 ddns_type = DHO_DHCP_CLIENT_IDENTIFIER; 567 /* IAID incorrectly included */ 568 ddns_len = 0; 569 } 570 571 572 if (lease6 != NULL) { 573 if (lease6->ia->iaid_duid.len < ddns_len) 574 goto badfqdn; 575 result = get_dhcid(ddns_cb, 2, 576 lease6->ia->iaid_duid.data + ddns_len, 577 lease6->ia->iaid_duid.len - ddns_len); 578 } else if ((lease != NULL) && 579 (lease->uid != NULL) && 580 (lease->uid_len != 0)) { 581 /* If this is standard check for an RFC 4361 582 * compliant client identifier 583 */ 584 if ((ddns_update_style == DDNS_UPDATE_STYLE_STANDARD) && 585 (lease->uid[0] == 255)) { 586 if (lease->uid_len < 5) 587 goto badfqdn; 588 result = get_dhcid(ddns_cb, 2, 589 lease->uid + 5, 590 lease->uid_len - 5); 591 } else { 592 result = get_dhcid(ddns_cb, ddns_type, 593 lease->uid, 594 lease->uid_len); 595 } 596 } else if (lease != NULL) 597 result = get_dhcid(ddns_cb, 0, 598 lease->hardware_addr.hbuf, 599 lease->hardware_addr.hlen); 600 else 601 log_fatal("Impossible condition at %s:%d.", MDL); 602 603 if (!result) 604 goto badfqdn; 605 } 606 607 /* 608 * Perform updates. 609 */ 610 611 if (ddns_cb->flags & DDNS_UPDATE_ADDR) { 612 copy_conflict_flags(&ddns_cb->flags, ddns_conflict_mask); 613 } 614 615 /* 616 * Previously if we failed during the removal operations 617 * we skipped the fqdn option processing. I'm not sure 618 * if we want to continue with that if we fail before sending 619 * the ddns messages. Currently we don't. 620 */ 621 if (do_remove) { 622 /* 623 * We should log a more specific error closer to the actual 624 * error if we want one. ddns_removal failure not logged here. 625 */ 626 (void) ddns_removals(lease, lease6, ddns_cb, ISC_TRUE); 627 } 628 else { 629 ddns_fwd_srv_connector(lease, lease6, scope, ddns_cb, 630 ISC_R_SUCCESS); 631 } 632 ddns_cb = NULL; 633 634 noerror: 635 /* 636 * If fqdn-reply option is disabled in dhcpd.conf, then don't 637 * send the client an FQDN option at all, even if one was requested. 638 * (WinXP clients allegedly misbehave if the option is present, 639 * refusing to handle PTR updates themselves). 640 */ 641 if ((oc = lookup_option (&server_universe, options, SV_FQDN_REPLY)) && 642 !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL, 643 packet->options, options, 644 scope, oc, MDL)) { 645 goto badfqdn; 646 647 /* If we're ignoring client updates, then we tell a sort of 'white 648 * lie'. We've already updated the name the server wants (per the 649 * config written by the server admin). Now let the client do as 650 * it pleases with the name they supplied (if any). 651 * 652 * We only form an FQDN option this way if the client supplied an 653 * FQDN option that had FQDN_SERVER_UPDATE set false. 654 */ 655 } else if (client_ignorep && 656 (oc = lookup_option(&fqdn_universe, packet->options, 657 FQDN_SERVER_UPDATE)) && 658 !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL, 659 packet->options, options, 660 scope, oc, MDL)) { 661 oc = lookup_option(&fqdn_universe, packet->options, FQDN_FQDN); 662 if (oc && evaluate_option_cache(&d1, packet, lease, NULL, 663 packet->options, options, 664 scope, oc, MDL)) { 665 if (d1.len == 0 || 666 !buffer_allocate(&bp, d1.len + 5, MDL)) 667 goto badfqdn; 668 669 /* Server pretends it is not updating. */ 670 bp->data[0] = 0; 671 if (!save_option_buffer(&fqdn_universe, options, 672 bp, &bp->data[0], 1, 673 FQDN_SERVER_UPDATE, 0)) 674 goto badfqdn; 675 676 /* Client is encouraged to update. */ 677 bp->data[1] = 0; 678 if (!save_option_buffer(&fqdn_universe, options, 679 bp, &bp->data[1], 1, 680 FQDN_NO_CLIENT_UPDATE, 0)) 681 goto badfqdn; 682 683 /* Use the encoding of client's FQDN option. */ 684 oc = lookup_option(&fqdn_universe, packet->options, 685 FQDN_ENCODED); 686 if (oc && 687 evaluate_boolean_option_cache(&ignorep, packet, 688 lease, NULL, 689 packet->options, 690 options, scope, 691 oc, MDL)) 692 bp->data[2] = 1; /* FQDN is encoded. */ 693 else 694 bp->data[2] = 0; /* FQDN is not encoded. */ 695 696 if (!save_option_buffer(&fqdn_universe, options, 697 bp, &bp->data[2], 1, 698 FQDN_ENCODED, 0)) 699 goto badfqdn; 700 701 /* Current FQDN drafts indicate 255 is mandatory. */ 702 bp->data[3] = 255; 703 if (!save_option_buffer(&fqdn_universe, options, 704 bp, &bp->data[3], 1, 705 FQDN_RCODE1, 0)) 706 goto badfqdn; 707 708 bp->data[4] = 255; 709 if (!save_option_buffer(&fqdn_universe, options, 710 bp, &bp->data[4], 1, 711 FQDN_RCODE2, 0)) 712 goto badfqdn; 713 714 /* Copy in the FQDN supplied by the client. Note well 715 * that the format of this option in the cache is going 716 * to be in text format. If the fqdn supplied by the 717 * client is encoded, it is decoded into the option 718 * cache when parsed out of the packet. It will be 719 * re-encoded when the option is assembled to be 720 * transmitted if the client elects that encoding. 721 */ 722 memcpy(&bp->data[5], d1.data, d1.len); 723 if (!save_option_buffer(&fqdn_universe, options, 724 bp, &bp->data[5], d1.len, 725 FQDN_FQDN, 0)) 726 goto badfqdn; 727 728 data_string_forget(&d1, MDL); 729 } 730 /* Set up the outgoing FQDN option if there was an incoming 731 * FQDN option. If there's a valid FQDN option, there MUST 732 * be an FQDN_SERVER_UPDATES suboption, it's part of the fixed 733 * length head of the option contents, so we test the latter 734 * to detect the presence of the former. 735 */ 736 } else if ((oc = lookup_option(&fqdn_universe, packet->options, 737 FQDN_ENCODED)) && 738 buffer_allocate(&bp, ddns_fwd_name.len + 5, MDL)) { 739 bp -> data [0] = server_updates_a; 740 if (!save_option_buffer(&fqdn_universe, options, 741 bp, &bp->data [0], 1, 742 FQDN_SERVER_UPDATE, 0)) 743 goto badfqdn; 744 bp -> data [1] = server_updates_a; 745 if (!save_option_buffer(&fqdn_universe, options, 746 bp, &bp->data [1], 1, 747 FQDN_NO_CLIENT_UPDATE, 0)) 748 goto badfqdn; 749 750 /* Do the same encoding the client did. */ 751 if (evaluate_boolean_option_cache(&ignorep, packet, lease, 752 NULL, packet->options, 753 options, scope, oc, MDL)) 754 bp -> data [2] = 1; 755 else 756 bp -> data [2] = 0; 757 if (!save_option_buffer(&fqdn_universe, options, 758 bp, &bp->data [2], 1, 759 FQDN_ENCODED, 0)) 760 goto badfqdn; 761 bp -> data [3] = 255;//isc_rcode_to_ns (rcode1); 762 if (!save_option_buffer(&fqdn_universe, options, 763 bp, &bp->data [3], 1, 764 FQDN_RCODE1, 0)) 765 goto badfqdn; 766 bp -> data [4] = 255;//isc_rcode_to_ns (rcode2); 767 if (!save_option_buffer(&fqdn_universe, options, 768 bp, &bp->data [4], 1, 769 FQDN_RCODE2, 0)) 770 goto badfqdn; 771 if (ddns_fwd_name.len) { 772 memcpy (&bp -> data [5], 773 ddns_fwd_name.data, ddns_fwd_name.len); 774 if (!save_option_buffer(&fqdn_universe, options, 775 bp, &bp->data [5], 776 ddns_fwd_name.len, 777 FQDN_FQDN, 0)) 778 goto badfqdn; 779 } 780 } 781 782 badfqdn: 783 out: 784 /* 785 * Final cleanup. 786 */ 787 if (ddns_cb != NULL) { 788 destroy_ddns_cb(ddns_cb, MDL); 789 } 790 791 data_string_forget(&d1, MDL); 792 data_string_forget(&ddns_hostname, MDL); 793 data_string_forget(&ddns_domainname, MDL); 794 data_string_forget(&old_ddns_fwd_name, MDL); 795 data_string_forget(&ddns_fwd_name, MDL); 796 if (bp) 797 buffer_dereference(&bp, MDL); 798 799 return result; 800 } 801 802 /*%< 803 * Utility function to update text strings within a lease. 804 * 805 * The first issue is to find the proper scope. Sometimes we shall be 806 * called with a pointer to the scope in other cases we need to find 807 * the proper lease and then get the scope. Once we have the scope we update 808 * the proper strings, as indicated by the state value in the control block. 809 * Lastly, if we needed to find the scope we write it out, if we used a 810 * scope that was passed as an argument we don't write it, assuming that 811 * our caller (or his ...) will do the write. 812 * 813 *\li ddns_cb - the control block for the DDNS request 814 * 815 *\li inscope - a pointer to the scope to update. This may be NULL 816 * in which case we use the control block to find the lease and 817 * then the scope. 818 * 819 * Returns 820 *\li ISC_R_SUCCESS 821 * 822 *\li ISC_R_FAILURE - The routine was unable to find an expected scope. 823 * In some cases (static and inactive leases) we don't expect a scope 824 * and return success. 825 */ 826 827 static isc_result_t 828 ddns_update_lease_text(dhcp_ddns_cb_t *ddns_cb, 829 struct binding_scope **inscope) 830 { 831 struct binding_scope **scope = NULL; 832 struct lease *lease = NULL; 833 struct iasubopt *lease6 = NULL; 834 struct ipv6_pool *pool = NULL; 835 struct in6_addr addr; 836 struct data_string lease_dhcid; 837 838 /* 839 * If the lease was static (for a fixed address) 840 * we don't need to do any work. 841 */ 842 if (ddns_cb->flags & DDNS_STATIC_LEASE) 843 return (ISC_R_SUCCESS); 844 845 /* 846 * If we are processing an expired or released v6 lease 847 * or some types of v4 leases we don't actually have a 848 * scope to update 849 */ 850 if ((ddns_cb->flags & DDNS_ACTIVE_LEASE) == 0) 851 return (ISC_R_SUCCESS); 852 853 if (inscope != NULL) { 854 scope = inscope; 855 } else if (ddns_cb->address.len == 4) { 856 if (find_lease_by_ip_addr(&lease, ddns_cb->address, MDL) != 0){ 857 scope = &(lease->scope); 858 } 859 } else if (ddns_cb->address.len == 16) { 860 memcpy(&addr, &ddns_cb->address.iabuf, 16); 861 if ((find_ipv6_pool(&pool, D6O_IA_TA, &addr) == 862 ISC_R_SUCCESS) || 863 (find_ipv6_pool(&pool, D6O_IA_NA, &addr) == 864 ISC_R_SUCCESS)) { 865 if (iasubopt_hash_lookup(&lease6, pool->leases, 866 &addr, 16, MDL)) { 867 scope = &(lease6->scope); 868 } 869 ipv6_pool_dereference(&pool, MDL); 870 } 871 } else { 872 log_fatal("Impossible condition at %s:%d.", MDL); 873 } 874 875 if (scope == NULL) { 876 /* If necessary get rid of the lease */ 877 if (lease) { 878 lease_dereference(&lease, MDL); 879 } 880 else if (lease6) { 881 iasubopt_dereference(&lease6, MDL); 882 } 883 884 return(ISC_R_FAILURE); 885 } 886 887 /* We now have a scope and can proceed to update it */ 888 switch(ddns_cb->state) { 889 case DDNS_STATE_REM_PTR: 890 unset(*scope, "ddns-rev-name"); 891 if ((ddns_cb->flags & DDNS_CLIENT_DID_UPDATE) != 0) { 892 unset(*scope, "ddns-client-fqdn"); 893 } 894 break; 895 896 case DDNS_STATE_ADD_PTR: 897 case DDNS_STATE_CLEANUP: 898 bind_ds_value(scope, "ddns-rev-name", &ddns_cb->rev_name); 899 if ((ddns_cb->flags & DDNS_UPDATE_ADDR) == 0) { 900 bind_ds_value(scope, "ddns-client-fqdn", 901 &ddns_cb->fwd_name); 902 } 903 break; 904 905 case DDNS_STATE_ADD_FW_YXDHCID: 906 case DDNS_STATE_ADD_FW_NXDOMAIN: 907 case DDNS_STATE_DSMM_FW_ADD3: 908 bind_ds_value(scope, "ddns-fwd-name", &ddns_cb->fwd_name); 909 910 if (ddns_cb->lease_tag == ddns_standard_tag) { 911 bind_ds_value(scope, ddns_standard_tag, 912 &ddns_cb->dhcid); 913 } else { 914 /* convert from dns version to lease version of dhcid */ 915 memset(&lease_dhcid, 0, sizeof(lease_dhcid)); 916 dhcid_tolease(&ddns_cb->dhcid, &lease_dhcid); 917 bind_ds_value(scope, ddns_interim_tag, &lease_dhcid); 918 data_string_forget(&lease_dhcid, MDL); 919 } 920 break; 921 922 case DDNS_STATE_REM_FW_NXRR: 923 case DDNS_STATE_REM_FW_YXDHCID: 924 case DDNS_STATE_REM_FW_DSMM_OTHER: 925 unset(*scope, "ddns-fwd-name"); 926 unset(*scope, ddns_cb->lease_tag); 927 break; 928 } 929 930 /* If necessary write it out and get rid of the lease */ 931 if (lease) { 932 write_lease(lease); 933 lease_dereference(&lease, MDL); 934 } else if (lease6) { 935 write_ia(lease6->ia); 936 iasubopt_dereference(&lease6, MDL); 937 } 938 939 return(ISC_R_SUCCESS); 940 } 941 942 #ifdef notdef 943 /* 944 * This function should be called when update_lease_ptr function fails. 945 * It does inform user about the condition, provides some hints how to 946 * resolve this and dies gracefully. This can happend in at least three 947 * cases (all are configuration mistakes): 948 * a) IPv4: user have duplicate fixed-address entries (the same 949 * address is defined twice). We may have found wrong lease. 950 * b) IPv6: user have overlapping pools (we tried to find 951 * a lease in a wrong pool) 952 * c) IPv6: user have duplicate fixed-address6 entires (the same 953 * address is defined twice). We may have found wrong lease. 954 * 955 * Comment: while it would be possible to recover from both cases 956 * by forcibly searching for leases in *all* following pools, that would 957 * only hide the real problem - a misconfiguration. Proper solution 958 * is to log the problem, die and let the user fix his config file. 959 */ 960 void 961 update_lease_failed(struct lease *lease, 962 struct iasubopt *lease6, 963 dhcp_ddns_cb_t *ddns_cb, 964 dhcp_ddns_cb_t *ddns_cb_set, 965 const char * file, int line) 966 { 967 char lease_address[MAX_ADDRESS_STRING_LEN + 64]; 968 char reason[128]; /* likely reason */ 969 970 sprintf(reason, "unknown"); 971 sprintf(lease_address, "unknown"); 972 973 /* 974 * let's pretend that everything is ok, so we can continue for 975 * information gathering purposes 976 */ 977 978 if (ddns_cb != NULL) { 979 strncpy(lease_address, piaddr(ddns_cb->address), 980 MAX_ADDRESS_STRING_LEN); 981 982 if (ddns_cb->address.len == 4) { 983 sprintf(reason, "duplicate IPv4 fixed-address entry"); 984 } else if (ddns_cb->address.len == 16) { 985 sprintf(reason, "duplicate IPv6 fixed-address6 entry " 986 "or overlapping pools"); 987 } else { 988 /* 989 * Should not happen. We have non-IPv4, non-IPv6 990 * address. Something is very wrong here. 991 */ 992 sprintf(reason, "corrupted ddns_cb structure (address " 993 "length is %d)", ddns_cb->address.len); 994 } 995 } 996 997 log_error("Failed to properly update internal lease structure with " 998 "DDNS"); 999 log_error("control block structures. Tried to update lease for" 1000 "%s address, ddns_cb=%p.", lease_address, ddns_cb); 1001 1002 log_error("%s", ""); 1003 log_error("This condition can occur, if DHCP server configuration is " 1004 "inconsistent."); 1005 log_error("In particular, please do check that your configuration:"); 1006 log_error("a) does not have overlapping pools (especially containing"); 1007 log_error(" %s address).", lease_address); 1008 log_error("b) there are no duplicate fixed-address or fixed-address6"); 1009 log_error("entries for the %s address.", lease_address); 1010 log_error("%s", ""); 1011 log_error("Possible reason for this failure: %s", reason); 1012 1013 log_fatal("%s(%d): Failed to update lease database with DDNS info for " 1014 "address %s. Lease database inconsistent. Unable to recover." 1015 " Terminating.", file, line, lease_address); 1016 } 1017 #endif 1018 1019 /* 1020 * utility function to update found lease. It does extra checks 1021 * that we are indeed updating the right lease. It may happen 1022 * that user have duplicate fixed-address entries, so we attempt 1023 * to update wrong lease. See also safe_lease6_update. 1024 */ 1025 1026 static void 1027 safe_lease_update(struct lease *lease, 1028 dhcp_ddns_cb_t *oldcb, 1029 dhcp_ddns_cb_t *newcb, 1030 const char *file, int line) 1031 { 1032 if (lease == NULL) { 1033 /* should never get here */ 1034 log_fatal("Impossible condition at %s:%d (called from %s:%d).", 1035 MDL, file, line); 1036 } 1037 1038 if ( (lease->ddns_cb == NULL) && (newcb == NULL) ) { 1039 /* 1040 * Trying to clean up pointer that is already null. We 1041 * are most likely trying to update wrong lease here. 1042 */ 1043 1044 /* 1045 * Previously this error message popped out during 1046 * DNS update for fixed leases. As we no longer 1047 * try to update the lease for a fixed (static) lease 1048 * this should not be a problem. 1049 */ 1050 log_error("%s(%d): Invalid lease update. Tried to " 1051 "clear already NULL DDNS control block " 1052 "pointer for lease %s.", 1053 file, line, piaddr(lease->ip_addr) ); 1054 1055 #if defined (DNS_UPDATES_MEMORY_CHECKS) 1056 update_lease_failed(lease, NULL, oldcb, newcb, file, line); 1057 #endif 1058 /* 1059 * May not reach this: update_lease_failed calls 1060 * log_fatal. 1061 */ 1062 return; 1063 } 1064 1065 if ( (lease->ddns_cb != NULL) && (lease->ddns_cb != oldcb) ) { 1066 /* 1067 * There is existing cb structure, but it differs from 1068 * what we expected to see there. Most likely we are 1069 * trying to update wrong lease. 1070 */ 1071 log_error("%s(%d): Failed to update internal lease " 1072 "structure with DDNS control block. Existing" 1073 " ddns_cb structure does not match " 1074 "expectations.IPv4=%s, old ddns_cb=%p, tried" 1075 "to update to new ddns_cb=%p", file, line, 1076 piaddr(lease->ip_addr), oldcb, newcb); 1077 1078 #if defined (DNS_UPDATES_MEMORY_CHECKS) 1079 update_lease_failed(lease, NULL, oldcb, newcb, file, line); 1080 #endif 1081 /* 1082 * May not reach this: update_lease_failed calls 1083 * log_fatal. 1084 */ 1085 return; 1086 } 1087 1088 /* additional IPv4 specific checks may be added here */ 1089 1090 /* update the lease */ 1091 lease->ddns_cb = newcb; 1092 } 1093 1094 static void 1095 safe_lease6_update(struct iasubopt *lease6, 1096 dhcp_ddns_cb_t *oldcb, 1097 dhcp_ddns_cb_t *newcb, 1098 const char *file, int line) 1099 { 1100 char addrbuf[MAX_ADDRESS_STRING_LEN]; 1101 1102 if (lease6 == NULL) { 1103 /* should never get here */ 1104 log_fatal("Impossible condition at %s:%d (called from %s:%d).", 1105 MDL, file, line); 1106 } 1107 1108 if ( (lease6->ddns_cb == NULL) && (newcb == NULL) ) { 1109 inet_ntop(AF_INET6, &lease6->addr, addrbuf, 1110 MAX_ADDRESS_STRING_LEN); 1111 /* 1112 * Trying to clean up pointer that is already null. We 1113 * are most likely trying to update wrong lease here. 1114 */ 1115 log_error("%s(%d): Failed to update internal lease " 1116 "structure. Tried to clear already NULL " 1117 "DDNS control block pointer for lease %s.", 1118 file, line, addrbuf); 1119 1120 #if defined (DNS_UPDATES_MEMORY_CHECKS) 1121 update_lease_failed(NULL, lease6, oldcb, newcb, file, line); 1122 #endif 1123 1124 /* 1125 * May not reach this: update_lease_failed calls 1126 * log_fatal. 1127 */ 1128 return; 1129 } 1130 1131 if ( (lease6->ddns_cb != NULL) && (lease6->ddns_cb != oldcb) ) { 1132 /* 1133 * there is existing cb structure, but it differs from 1134 * what we expected to see there. Most likely we are 1135 * trying to update wrong lease. 1136 */ 1137 inet_ntop(AF_INET6, &lease6->addr, addrbuf, 1138 MAX_ADDRESS_STRING_LEN); 1139 1140 log_error("%s(%d): Failed to update internal lease " 1141 "structure with DDNS control block. Existing" 1142 " ddns_cb structure does not match " 1143 "expectations.IPv6=%s, old ddns_cb=%p, tried" 1144 "to update to new ddns_cb=%p", file, line, 1145 addrbuf, oldcb, newcb); 1146 1147 #if defined (DNS_UPDATES_MEMORY_CHECKS) 1148 update_lease_failed(NULL, lease6, oldcb, newcb, file, line); 1149 #endif 1150 /* 1151 * May not reach this: update_lease_failed calls 1152 * log_fatal. 1153 */ 1154 return; 1155 } 1156 /* additional IPv6 specific checks may be added here */ 1157 1158 /* update the lease */ 1159 lease6->ddns_cb = newcb; 1160 } 1161 1162 /* 1163 * Utility function to update the pointer to the DDNS control block 1164 * in a lease. 1165 * SUCCESS - able to update the pointer 1166 * FAILURE - lease didn't exist or sanity checks failed 1167 * lease and lease6 may be empty in which case we attempt to find 1168 * the lease from the ddns_cb information. 1169 * ddns_cb is the control block to use if a lookup is necessary 1170 * ddns_cb_set is the pointer to insert into the lease and may be NULL 1171 * The last two arguments may look odd as they will be the same much of the 1172 * time, but I need an argument to tell me if I'm setting or clearing in 1173 * addition to the address information from the cb to look up the lease. 1174 * using the same value twice allows me more flexibility. 1175 */ 1176 1177 static isc_result_t 1178 ddns_update_lease_ptr(struct lease *lease, 1179 struct iasubopt *lease6, 1180 dhcp_ddns_cb_t *ddns_cb, 1181 dhcp_ddns_cb_t *ddns_cb_set, 1182 const char * file, int line) 1183 { 1184 char ddns_address[MAX_ADDRESS_STRING_LEN]; 1185 sprintf(ddns_address, "unknown"); 1186 if (ddns_cb == NULL) { 1187 log_info("%s(%d): No control block for lease update", 1188 file, line); 1189 return (ISC_R_FAILURE); 1190 } 1191 else { 1192 strcpy(ddns_address, piaddr(ddns_cb->address)); 1193 } 1194 #if defined (DEBUG_DNS_UPDATES) 1195 log_info("%s(%d): Updating lease_ptr for ddns_cp=%p (addr=%s)", 1196 file, line, ddns_cb, ddns_address ); 1197 #endif 1198 1199 /* 1200 * If the lease was static (for a fixed address) 1201 * we don't need to do any work. 1202 */ 1203 if (ddns_cb->flags & DDNS_STATIC_LEASE) { 1204 #if defined (DEBUG_DNS_UPDATES) 1205 log_info("lease is static, returning"); 1206 #endif 1207 return (ISC_R_SUCCESS); 1208 } 1209 1210 /* 1211 * If we are processing an expired or released v6 lease 1212 * we don't actually have a lease to update 1213 */ 1214 if ((ddns_cb->address.len == 16) && 1215 ((ddns_cb->flags & DDNS_ACTIVE_LEASE) == 0)) { 1216 return (ISC_R_SUCCESS); 1217 } 1218 1219 if (lease != NULL) { 1220 safe_lease_update(lease, ddns_cb, ddns_cb_set, 1221 file, line); 1222 } else if (lease6 != NULL) { 1223 safe_lease6_update(lease6, ddns_cb, ddns_cb_set, 1224 file, line); 1225 } else if (ddns_cb->address.len == 4) { 1226 struct lease *find_lease = NULL; 1227 if (find_lease_by_ip_addr(&find_lease, 1228 ddns_cb->address, MDL) != 0) { 1229 #if defined (DEBUG_DNS_UPDATES) 1230 log_info("%s(%d): find_lease_by_ip_addr(%s) successful:" 1231 "lease=%p", file, line, ddns_address, 1232 find_lease); 1233 #endif 1234 1235 safe_lease_update(find_lease, ddns_cb, 1236 ddns_cb_set, file, line); 1237 lease_dereference(&find_lease, MDL); 1238 } 1239 else { 1240 log_error("%s(%d): ddns_update_lease_ptr failed. " 1241 "Lease for %s not found.", 1242 file, line, piaddr(ddns_cb->address)); 1243 1244 #if defined (DNS_UPDATES_MEMORY_CHECKS) 1245 update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set, 1246 file, line); 1247 #endif 1248 /* 1249 * may not reach this. update_lease_failed 1250 * calls log_fatal. 1251 */ 1252 return(ISC_R_FAILURE); 1253 1254 } 1255 } else if (ddns_cb->address.len == 16) { 1256 struct iasubopt *find_lease6 = NULL; 1257 struct ipv6_pool *pool = NULL; 1258 struct in6_addr addr; 1259 char addrbuf[MAX_ADDRESS_STRING_LEN]; 1260 1261 memcpy(&addr, &ddns_cb->address.iabuf, 16); 1262 if ((find_ipv6_pool(&pool, D6O_IA_TA, &addr) != 1263 ISC_R_SUCCESS) && 1264 (find_ipv6_pool(&pool, D6O_IA_NA, &addr) != 1265 ISC_R_SUCCESS)) { 1266 inet_ntop(AF_INET6, &addr, addrbuf, 1267 MAX_ADDRESS_STRING_LEN); 1268 log_error("%s(%d): Pool for lease %s not found.", 1269 file, line, addrbuf); 1270 #if defined (DNS_UPDATES_MEMORY_CHECKS) 1271 update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set, 1272 file, line); 1273 #endif 1274 /* 1275 * never reached. update_lease_failed 1276 * calls log_fatal. 1277 */ 1278 return(ISC_R_FAILURE); 1279 } 1280 1281 if (iasubopt_hash_lookup(&find_lease6, pool->leases, 1282 &addr, 16, MDL)) { 1283 find_lease6->ddns_cb = ddns_cb_set; 1284 iasubopt_dereference(&find_lease6, MDL); 1285 } else { 1286 inet_ntop(AF_INET6, &addr, addrbuf, 1287 MAX_ADDRESS_STRING_LEN); 1288 log_error("%s(%d): Lease %s not found within pool.", 1289 file, line, addrbuf); 1290 #if defined (DNS_UPDATES_MEMORY_CHECKS) 1291 update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set, 1292 file, line); 1293 #endif 1294 /* 1295 * never reached. update_lease_failed 1296 * calls log_fatal. 1297 */ 1298 return(ISC_R_FAILURE); 1299 } 1300 ipv6_pool_dereference(&pool, MDL); 1301 } else { 1302 /* shouldn't get here */ 1303 log_fatal("Impossible condition at %s:%d, called from %s:%d.", 1304 MDL, file, line); 1305 } 1306 1307 return(ISC_R_SUCCESS); 1308 } 1309 1310 static void 1311 ddns_ptr_add(dhcp_ddns_cb_t *ddns_cb, 1312 isc_result_t eresult) 1313 { 1314 if (eresult == ISC_R_SUCCESS) { 1315 log_info("Added reverse map from %.*s to %.*s", 1316 (int)ddns_cb->rev_name.len, 1317 (const char *)ddns_cb->rev_name.data, 1318 (int)ddns_cb->fwd_name.len, 1319 (const char *)ddns_cb->fwd_name.data); 1320 1321 ddns_update_lease_text(ddns_cb, NULL); 1322 } else { 1323 log_error("Unable to add reverse map from %.*s to %.*s: %s", 1324 (int)ddns_cb->rev_name.len, 1325 (const char *)ddns_cb->rev_name.data, 1326 (int)ddns_cb->fwd_name.len, 1327 (const char *)ddns_cb->fwd_name.data, 1328 isc_result_totext (eresult)); 1329 } 1330 1331 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); 1332 destroy_ddns_cb(ddns_cb, MDL); 1333 /* 1334 * A single DDNS operation may require several calls depending on 1335 * the current state as the prerequisites for the first message 1336 * may not succeed requiring a second operation and potentially 1337 * a ptr operation after that. The commit_leases operation is 1338 * invoked at the end of this set of operations in order to require 1339 * a single write for all of the changes. We call commit_leases 1340 * here rather than immediately after the call to update the lease 1341 * text in order to save any previously written data. 1342 */ 1343 commit_leases(); 1344 return; 1345 } 1346 1347 /* 1348 * action routine when trying to remove a pointer 1349 * this will be called after the ddns queries have completed 1350 * if we succeeded in removing the pointer we go to the next step (if any) 1351 * if not we cleanup and leave. 1352 */ 1353 1354 static void 1355 ddns_ptr_remove(dhcp_ddns_cb_t *ddns_cb, 1356 isc_result_t eresult) 1357 { 1358 isc_result_t result = eresult; 1359 1360 switch(eresult) { 1361 case ISC_R_SUCCESS: 1362 log_info("Removed reverse map on %.*s", 1363 (int)ddns_cb->rev_name.len, 1364 (const char *)ddns_cb->rev_name.data); 1365 /* fall through */ 1366 case DNS_R_NXRRSET: 1367 case DNS_R_NXDOMAIN: 1368 /* No entry is the same as success. 1369 * Remove the information from the lease and 1370 * continue with any next step */ 1371 ddns_update_lease_text(ddns_cb, NULL); 1372 1373 /* trigger any add operation */ 1374 result = ISC_R_SUCCESS; 1375 #if defined (DEBUG_DNS_UPDATES) 1376 log_info("DDNS: removed map or no reverse map to remove %.*s", 1377 (int)ddns_cb->rev_name.len, 1378 (const char *)ddns_cb->rev_name.data); 1379 #endif 1380 break; 1381 1382 default: 1383 log_error("Can't remove reverse map on %.*s: %s", 1384 (int)ddns_cb->rev_name.len, 1385 (const char *)ddns_cb->rev_name.data, 1386 isc_result_totext (eresult)); 1387 break; 1388 } 1389 1390 /* If we aren't suppossed to do the next step, set the result 1391 * flag so ddns_fwd_srv_connector won't do much 1392 */ 1393 if ((ddns_cb->flags & DDNS_EXECUTE_NEXT) == 0) 1394 result = ISC_R_FAILURE; 1395 1396 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); 1397 ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, result); 1398 destroy_ddns_cb(ddns_cb, MDL); 1399 return; 1400 } 1401 1402 1403 /* 1404 * If the first query succeeds, the updater can conclude that it 1405 * has added a new name whose only RRs are the A and DHCID RR records. 1406 * The A RR update is now complete (and a client updater is finished, 1407 * while a server might proceed to perform a PTR RR update). 1408 * -- "Interaction between DHCP and DNS" 1409 * 1410 * If the second query succeeds, the updater can conclude that the current 1411 * client was the last client associated with the domain name, and that 1412 * the name now contains the updated A RR. The A RR update is now 1413 * complete (and a client updater is finished, while a server would 1414 * then proceed to perform a PTR RR update). 1415 * -- "Interaction between DHCP and DNS" 1416 * 1417 * If the second query fails with NXRRSET, the updater must conclude 1418 * that the client's desired name is in use by another host. If 1419 * Dual Stack Mixed Mode (DSMM) is enabled and we proceed to a 1420 * third stage forward update attempt specific to DSMM rules. If not, 1421 * then the existing entries are left intact: 1422 * 1423 * At this juncture, the updater can decide (based on some administrative 1424 * configuration outside of the scope of this document) whether to let 1425 * the existing owner of the name keep that name, and to (possibly) 1426 * perform some name disambiguation operation on behalf of the current 1427 * client, or to replace the RRs on the name with RRs that represent 1428 * the current client. If the configured policy allows replacement of 1429 * existing records, the updater submits a query that deletes the 1430 * existing A RR and the existing DHCID RR, adding A and DHCID RRs that 1431 * represent the IP address and client-identity of the new client. 1432 * -- "Interaction between DHCP and DNS" 1433 */ 1434 1435 static void 1436 ddns_fwd_srv_add2(dhcp_ddns_cb_t *ddns_cb, 1437 isc_result_t eresult) 1438 { 1439 isc_result_t result; 1440 const char *logstr = NULL; 1441 char ddns_address[MAX_ADDRESS_STRING_LEN]; 1442 1443 #if defined (DEBUG_DNS_UPDATES) 1444 log_info ("DDNS:ddns_fwd_srv_add2: %s eresult: %d", 1445 dump_ddns_cb(ddns_cb), eresult); 1446 #endif 1447 1448 /* Construct a printable form of the address for logging */ 1449 strcpy(ddns_address, piaddr(ddns_cb->address)); 1450 1451 switch(eresult) { 1452 case ISC_R_SUCCESS: 1453 log_info("Added new forward map from %.*s to %s", 1454 (int)ddns_cb->fwd_name.len, 1455 (const char *)ddns_cb->fwd_name.data, 1456 ddns_address); 1457 1458 ddns_update_lease_text(ddns_cb, NULL); 1459 1460 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { 1461 /* if we have zone information get rid of it */ 1462 if (ddns_cb->zone != NULL) { 1463 ddns_cb_forget_zone(ddns_cb); 1464 } 1465 1466 ddns_cb->state = DDNS_STATE_ADD_PTR; 1467 ddns_cb->cur_func = ddns_ptr_add; 1468 1469 result = ddns_modify_ptr(ddns_cb, MDL); 1470 if (result == ISC_R_SUCCESS) { 1471 return; 1472 } 1473 } 1474 break; 1475 1476 case DNS_R_YXRRSET: 1477 case DNS_R_YXDOMAIN: 1478 logstr = "DHCID mismatch, belongs to another client."; 1479 break; 1480 1481 case DNS_R_NXDOMAIN: 1482 case DNS_R_NXRRSET: 1483 /* If DSMM is on we need to try forward add3 */ 1484 if (ddns_cb->flags & DDNS_DUAL_STACK_MIXED_MODE) { 1485 ddns_cb->state = DDNS_STATE_DSMM_FW_ADD3; 1486 ddns_cb->cur_func = ddns_fwd_srv_add3; 1487 1488 result = ddns_modify_fwd(ddns_cb, MDL); 1489 if (result == ISC_R_SUCCESS) { 1490 return; 1491 } 1492 1493 break; 1494 } 1495 1496 logstr = "Has an address record but no DHCID, not mine."; 1497 break; 1498 1499 default: 1500 logstr = isc_result_totext(eresult); 1501 break; 1502 } 1503 1504 if (logstr != NULL) { 1505 log_error("Forward map from %.*s to %s FAILED: %s", 1506 (int)ddns_cb->fwd_name.len, 1507 (const char *)ddns_cb->fwd_name.data, 1508 ddns_address, logstr); 1509 } 1510 1511 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); 1512 destroy_ddns_cb(ddns_cb, MDL); 1513 /* 1514 * A single DDNS operation may require several calls depending on 1515 * the current state as the prerequisites for the first message 1516 * may not succeed requiring a second operation and potentially 1517 * a ptr operation after that. The commit_leases operation is 1518 * invoked at the end of this set of operations in order to require 1519 * a single write for all of the changes. We call commit_leases 1520 * here rather than immediately after the call to update the lease 1521 * text in order to save any previously written data. 1522 */ 1523 commit_leases(); 1524 return; 1525 } 1526 1527 static void 1528 ddns_fwd_srv_add1(dhcp_ddns_cb_t *ddns_cb, 1529 isc_result_t eresult) 1530 { 1531 isc_result_t result; 1532 char ddns_address[MAX_ADDRESS_STRING_LEN]; 1533 1534 #if defined (DEBUG_DNS_UPDATES) 1535 log_info ("DDNS: ddns_fwd_srv_add1: %s eresult: %d", 1536 dump_ddns_cb(ddns_cb), eresult); 1537 #endif 1538 1539 /* Construct a printable form of the address for logging */ 1540 strcpy(ddns_address, piaddr(ddns_cb->address)); 1541 1542 switch(eresult) { 1543 case ISC_R_SUCCESS: 1544 log_info ("Added new forward map from %.*s to %s", 1545 (int)ddns_cb->fwd_name.len, 1546 (const char *)ddns_cb->fwd_name.data, 1547 ddns_address); 1548 1549 ddns_update_lease_text(ddns_cb, NULL); 1550 1551 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { 1552 /* if we have zone information get rid of it */ 1553 if (ddns_cb->zone != NULL) { 1554 ddns_cb_forget_zone(ddns_cb); 1555 } 1556 1557 ddns_cb->state = DDNS_STATE_ADD_PTR; 1558 ddns_cb->cur_func = ddns_ptr_add; 1559 1560 result = ddns_modify_ptr(ddns_cb, MDL); 1561 if (result == ISC_R_SUCCESS) { 1562 return; 1563 } 1564 } 1565 break; 1566 1567 case DNS_R_YXDOMAIN: 1568 /* we can reuse the zone information */ 1569 ddns_cb->state = DDNS_STATE_ADD_FW_YXDHCID; 1570 ddns_cb->cur_func = ddns_fwd_srv_add2; 1571 1572 result = ddns_modify_fwd(ddns_cb, MDL); 1573 if (result == ISC_R_SUCCESS) { 1574 return; 1575 } 1576 break; 1577 default: 1578 log_error ("Unable to add forward map from %.*s to %s: %s", 1579 (int)ddns_cb->fwd_name.len, 1580 (const char *)ddns_cb->fwd_name.data, 1581 ddns_address, 1582 isc_result_totext (eresult)); 1583 break; 1584 } 1585 1586 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); 1587 destroy_ddns_cb(ddns_cb, MDL); 1588 /* 1589 * A single DDNS operation may require several calls depending on 1590 * the current state as the prerequisites for the first message 1591 * may not succeed requiring a second operation and potentially 1592 * a ptr operation after that. The commit_leases operation is 1593 * invoked at the end of this set of operations in order to require 1594 * a single write for all of the changes. We call commit_leases 1595 * here rather than immediately after the call to update the lease 1596 * text in order to save any previously written data. 1597 */ 1598 commit_leases(); 1599 return; 1600 } 1601 1602 /* 1603 * This action routine is invoked after the DSMM third add stage is 1604 * attempted. If we succeeded we attempt to update the reverse DNS, 1605 * if not we cleanup and leave. 1606 */ 1607 void 1608 ddns_fwd_srv_add3(dhcp_ddns_cb_t *ddns_cb, 1609 isc_result_t eresult) 1610 { 1611 isc_result_t result; 1612 const char *logstr = NULL; 1613 char ddns_address[MAX_ADDRESS_STRING_LEN+1]; 1614 1615 #if defined (DEBUG_DNS_UPDATES) 1616 log_info ("DDNS: ddns_fwd_srv_add3: %s eresult: %d", 1617 dump_ddns_cb(ddns_cb), eresult); 1618 #endif 1619 1620 /* Construct a printable form of the address for logging */ 1621 memset(ddns_address, 0x0, sizeof(ddns_address)); 1622 strncpy(ddns_address, piaddr(ddns_cb->address), 1623 sizeof(ddns_address) - 1); 1624 1625 switch(eresult) { 1626 case ISC_R_SUCCESS: 1627 log_info("Added new forward map from %.*s to %s", 1628 (int)ddns_cb->fwd_name.len, 1629 (const char *)ddns_cb->fwd_name.data, 1630 ddns_address); 1631 1632 ddns_update_lease_text(ddns_cb, NULL); 1633 1634 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { 1635 /* if we have zone information get rid of it */ 1636 if (ddns_cb->zone != NULL) { 1637 ddns_cb_forget_zone(ddns_cb); 1638 } 1639 1640 ddns_cb->state = DDNS_STATE_ADD_PTR; 1641 ddns_cb->cur_func = ddns_ptr_add; 1642 1643 result = ddns_modify_ptr(ddns_cb, MDL); 1644 if (result == ISC_R_SUCCESS) { 1645 return; 1646 } 1647 } 1648 break; 1649 1650 case DNS_R_YXRRSET: 1651 logstr = "an entry that is either static or " 1652 "owned by another client exists."; 1653 break; 1654 1655 case DNS_R_NXRRSET: 1656 logstr = "static entry of the other protocol type exists."; 1657 break; 1658 1659 default: 1660 logstr = isc_result_totext(eresult); 1661 break; 1662 } 1663 1664 if (logstr != NULL) { 1665 log_error("Forward map from %.*s to %s FAILED: %s", 1666 (int)ddns_cb->fwd_name.len, 1667 (const char *)ddns_cb->fwd_name.data, 1668 ddns_address, logstr); 1669 } 1670 1671 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); 1672 destroy_ddns_cb(ddns_cb, MDL); 1673 /* 1674 * A single DDNS operation may require several calls depending on 1675 * the current state as the prerequisites for the first message 1676 * may not succeed requiring a second operation and potentially 1677 * a ptr operation after that. The commit_leases operation is 1678 * invoked at the end of this set of operations in order to require 1679 * a single write for all of the changes. We call commit_leases 1680 * here rather than immediately after the call to update the lease 1681 * text in order to save any previously written data. 1682 */ 1683 commit_leases(); 1684 return; 1685 } 1686 1687 static void 1688 ddns_fwd_srv_connector(struct lease *lease, 1689 struct iasubopt *lease6, 1690 struct binding_scope **inscope, 1691 dhcp_ddns_cb_t *ddns_cb, 1692 isc_result_t eresult) 1693 { 1694 isc_result_t result = ISC_R_FAILURE; 1695 1696 #if defined (DEBUG_DNS_UPDATES) 1697 log_info ("DDNS: ddns_fwd_srv_connector: %s eresult: %d", 1698 dump_ddns_cb(ddns_cb), eresult); 1699 #endif 1700 1701 if (ddns_cb == NULL) { 1702 /* nothing to do */ 1703 return; 1704 } 1705 1706 if (eresult == ISC_R_SUCCESS) { 1707 /* 1708 * If we have updates dispatch as appropriate, 1709 * if not do FQDN binding if desired. 1710 */ 1711 1712 if (ddns_cb->flags & DDNS_UPDATE_ADDR) { 1713 ddns_cb->state = DDNS_STATE_ADD_FW_NXDOMAIN; 1714 ddns_cb->cur_func = ddns_fwd_srv_add1; 1715 result = ddns_modify_fwd(ddns_cb, MDL); 1716 } else if ((ddns_cb->flags & DDNS_UPDATE_PTR) && 1717 (ddns_cb->rev_name.len != 0)) { 1718 ddns_cb->state = DDNS_STATE_ADD_PTR; 1719 ddns_cb->cur_func = ddns_ptr_add; 1720 result = ddns_modify_ptr(ddns_cb, MDL); 1721 } else { 1722 ddns_update_lease_text(ddns_cb, inscope); 1723 } 1724 } 1725 1726 1727 if (result == ISC_R_SUCCESS) { 1728 ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, MDL); 1729 } else { 1730 destroy_ddns_cb(ddns_cb, MDL); 1731 } 1732 1733 return; 1734 } 1735 1736 /* 1737 * If the first query fails, the updater MUST NOT delete the DNS name. It 1738 * may be that the host whose lease on the server has expired has moved 1739 * to another network and obtained a lease from a different server, 1740 * which has caused the client's A RR to be replaced. It may also be 1741 * that some other client has been configured with a name that matches 1742 * the name of the DHCP client, and the policy was that the last client 1743 * to specify the name would get the name. In this case, the DHCID RR 1744 * will no longer match the updater's notion of the client-identity of 1745 * the host pointed to by the DNS name. 1746 * -- "Interaction between DHCP and DNS" 1747 */ 1748 1749 static void 1750 ddns_fwd_srv_rem2(dhcp_ddns_cb_t *ddns_cb, 1751 isc_result_t eresult) 1752 { 1753 #if defined (DEBUG_DNS_UPDATES) 1754 log_info ("DDNS: ddns_fwd_srv_rem2: %s eresult: %d", 1755 dump_ddns_cb(ddns_cb), eresult); 1756 #endif 1757 1758 /* 1759 * To get here we have already managed to remove the A/AAAA 1760 * record and are trying to remove the DHCID/TXT record as well. 1761 * On success (removed DHCID/TXT) or YXRRSET (DHCID/TXT still in 1762 * use by something else) we clean up the lease. 1763 * On some other error we don't clean up the lease and hope that 1764 * if we try this again it will work. An example would be if we 1765 * got a timeout as the DNS server halted between the first and 1766 * second steps. The DNS server would still have the DHCID/TXT 1767 * and we would like to remove that in the future. 1768 * 1769 * On success set the EXECUTE_NEXT flag which triggers any 1770 * add that is next in the chain. 1771 */ 1772 if ((eresult == ISC_R_SUCCESS) || 1773 (eresult == DNS_R_YXRRSET)) { 1774 ddns_update_lease_text(ddns_cb, NULL); 1775 eresult = ISC_R_SUCCESS; 1776 } 1777 1778 /* Do the next operation */ 1779 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { 1780 /* if we have zone information get rid of it */ 1781 if (ddns_cb->zone != NULL) { 1782 ddns_cb_forget_zone(ddns_cb); 1783 } 1784 1785 ddns_cb->state = DDNS_STATE_REM_PTR; 1786 ddns_cb->cur_func = ddns_ptr_remove; 1787 if (eresult == ISC_R_SUCCESS) 1788 ddns_cb->flags |= DDNS_EXECUTE_NEXT; 1789 1790 eresult = ddns_modify_ptr(ddns_cb, MDL); 1791 if (eresult == ISC_R_SUCCESS) { 1792 return; 1793 } 1794 } 1795 1796 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); 1797 ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult); 1798 destroy_ddns_cb(ddns_cb, MDL); 1799 return; 1800 } 1801 1802 1803 /* 1804 * First action routine when trying to remove a fwd 1805 * this will be called after the ddns queries have completed 1806 * if we succeeded in removing the fwd we go to the next step (if any) 1807 * if not we cleanup and leave. 1808 */ 1809 1810 static void 1811 ddns_fwd_srv_rem1(dhcp_ddns_cb_t *ddns_cb, 1812 isc_result_t eresult) 1813 { 1814 isc_result_t result = eresult; 1815 char ddns_address[MAX_ADDRESS_STRING_LEN]; 1816 1817 #if defined (DEBUG_DNS_UPDATES) 1818 log_info ("DDNS: ddns_fwd_srv_rem1: %s eresult: %d", 1819 dump_ddns_cb(ddns_cb), eresult); 1820 #endif 1821 1822 switch(eresult) { 1823 case ISC_R_SUCCESS: 1824 /* Construct a printable form of the address for logging */ 1825 strcpy(ddns_address, piaddr(ddns_cb->address)); 1826 log_info("Removed forward map from %.*s to %s", 1827 (int)ddns_cb->fwd_name.len, 1828 (const char*)ddns_cb->fwd_name.data, 1829 ddns_address); 1830 1831 /* Do the second step of the FWD removal */ 1832 ddns_cb->state = DDNS_STATE_REM_FW_NXRR; 1833 ddns_cb->cur_func = ddns_fwd_srv_rem2; 1834 result = ddns_modify_fwd(ddns_cb, MDL); 1835 if (result == ISC_R_SUCCESS) { 1836 return; 1837 } 1838 break; 1839 1840 case DNS_R_NXRRSET: 1841 case DNS_R_NXDOMAIN: 1842 /* A result of not found means rem1 did not find a guard of 1843 * our * type. From this we assume either there are no address 1844 * record(s) of our type to delete or they are unguarded and 1845 * therefore presumed to be static. Either way, we're done 1846 * unless we're in DSMM and ddns-other-guard-is-dynamic is on. 1847 * In which case we need to see if a guard of the other type 1848 * exists, which permits us to delete any address records of 1849 * our type. */ 1850 #define DSMM_OGD (DDNS_DUAL_STACK_MIXED_MODE | \ 1851 DDNS_OTHER_GUARD_IS_DYNAMIC) 1852 if ((ddns_cb->flags & DSMM_OGD) == DSMM_OGD) { 1853 ddns_cb->state = DDNS_STATE_REM_FW_DSMM_OTHER; 1854 ddns_cb->cur_func = ddns_fwd_srv_rem2; 1855 result = ddns_modify_fwd(ddns_cb, MDL); 1856 if (result == ISC_R_SUCCESS) { 1857 return; 1858 } 1859 break; 1860 } 1861 1862 ddns_update_lease_text(ddns_cb, NULL); 1863 1864 #if defined (DEBUG_DNS_UPDATES) 1865 log_info("DDNS: no forward map to remove. %p", ddns_cb); 1866 #endif 1867 /* Trigger the add operation */ 1868 eresult = ISC_R_SUCCESS; 1869 1870 /* Fall through */ 1871 default: 1872 1873 /* We do the remove operation in most cases 1874 * but we don't want to continue with adding a forward 1875 * record if the forward removal had issues so we 1876 * check the eresult and set the EXECUTE_NEXT flag on 1877 * success. 1878 */ 1879 1880 /* Do the remove operation */ 1881 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { 1882 /* if we have zone information get rid of it */ 1883 if (ddns_cb->zone != NULL) { 1884 ddns_cb_forget_zone(ddns_cb); 1885 } 1886 1887 ddns_cb->state = DDNS_STATE_REM_PTR; 1888 ddns_cb->cur_func = ddns_ptr_remove; 1889 if (eresult == ISC_R_SUCCESS) 1890 ddns_cb->flags |= DDNS_EXECUTE_NEXT; 1891 1892 result = ddns_modify_ptr(ddns_cb, MDL); 1893 if (result == ISC_R_SUCCESS) { 1894 return; 1895 } 1896 } 1897 break; 1898 } 1899 1900 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); 1901 ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult); 1902 destroy_ddns_cb(ddns_cb, MDL); 1903 } 1904 1905 /*%< 1906 * Remove relevant entries from DNS. 1907 * 1908 * \li lease - lease to start with if this is for v4 1909 * 1910 * \li lease6 - lease to start with if this is for v6 1911 * 1912 * \li add_ddns_cb - control block for additional DDNS work. This 1913 * is used when the code is going to add a DDNS entry after removing 1914 * the current entry. 1915 * 1916 * \li active - indication about the status of the lease. It is 1917 * ISC_TRUE if the lease is still active, and FALSE if the lease 1918 * is inactive. This is used to indicate if the lease is inactive or going 1919 * to inactive so we can avoid trying to update the lease with cb pointers 1920 * and text information if it isn't useful. 1921 * 1922 * Returns 1923 * \li #ISC_R_FAILURE - badness occurred and we weren't able to do what was wanted 1924 * \li #ISC_R_SUCCESS - we were able to do stuff but it's in progress 1925 * 1926 * in both cases any additional block has been passed on to it's handler 1927 */ 1928 1929 isc_result_t 1930 ddns_removals(struct lease *lease, 1931 struct iasubopt *lease6, 1932 dhcp_ddns_cb_t *add_ddns_cb, 1933 isc_boolean_t active) 1934 { 1935 isc_result_t rcode, execute_add = ISC_R_FAILURE; 1936 struct binding_scope **scope = NULL; 1937 isc_result_t result = ISC_R_FAILURE; 1938 dhcp_ddns_cb_t *ddns_cb = NULL; 1939 struct data_string leaseid; 1940 1941 #if defined (DEBUG_DNS_UPDATES) 1942 log_info ("DDNS: ddns_removals: %s", 1943 dump_ddns_cb(add_ddns_cb)); 1944 #endif 1945 1946 /* 1947 * See if we need to cancel an outstanding request. Mostly this is 1948 * used to handle the case where this routine is called twice for 1949 * the same release or abandon event. 1950 * 1951 * When called from the dns code as part of an update request 1952 * (add_ddns_cb != NULL) any outstanding requests will have already 1953 * been cancelled. 1954 * 1955 * If the new request is just a removal and we have an outstanding 1956 * request we have several options: 1957 * 1958 * - we are doing an update or we are doing a removal and the active 1959 * flag has changed from TRUE to FALSE. In these cases we need to 1960 * cancel the old request and start the new one. 1961 * 1962 * - other wise we are doing a removal with the active flag unchanged. 1963 * In this case we can let the current removal continue and do not need 1964 * to start a new one. If the old request included an update to be 1965 * done after the removal we need to kill the update part of the 1966 * request. 1967 */ 1968 1969 if (add_ddns_cb == NULL) { 1970 if ((lease != NULL) && (lease->ddns_cb != NULL)) { 1971 ddns_cb = lease->ddns_cb; 1972 1973 /* 1974 * Is the old request an update or did the 1975 * the active flag change? 1976 */ 1977 if (((ddns_cb->state == DDNS_STATE_ADD_PTR) || 1978 (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) || 1979 (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) || 1980 ((active == ISC_FALSE) && 1981 ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) { 1982 /* Cancel the current request */ 1983 ddns_cancel(lease->ddns_cb, MDL); 1984 lease->ddns_cb = NULL; 1985 } else { 1986 /* Remvoval, check and remove updates */ 1987 if (ddns_cb->next_op != NULL) { 1988 destroy_ddns_cb(ddns_cb->next_op, MDL); 1989 ddns_cb->next_op = NULL; 1990 } 1991 #if defined (DEBUG_DNS_UPDATES) 1992 log_info("DDNS %s(%d): removal already in " 1993 "progress new ddns_cb=%p", 1994 MDL, ddns_cb); 1995 #endif 1996 return (ISC_R_SUCCESS); 1997 } 1998 } else if ((lease6 != NULL) && (lease6->ddns_cb != NULL)) { 1999 ddns_cb = lease6->ddns_cb; 2000 2001 /* 2002 * Is the old request an update or did the 2003 * the active flag change? 2004 */ 2005 if (((ddns_cb->state == DDNS_STATE_ADD_PTR) || 2006 (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) || 2007 (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) || 2008 ((active == ISC_FALSE) && 2009 ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) { 2010 /* Cancel the current request */ 2011 ddns_cancel(lease6->ddns_cb, MDL); 2012 lease6->ddns_cb = NULL; 2013 } else { 2014 /* Remvoval, check and remove updates */ 2015 if (ddns_cb->next_op != NULL) { 2016 destroy_ddns_cb(ddns_cb->next_op, MDL); 2017 ddns_cb->next_op = NULL; 2018 } 2019 #if defined (DEBUG_DNS_UPDATES) 2020 log_info("DDNS %s(%d): removal already in " 2021 "progress new ddns_cb=%p", 2022 MDL, ddns_cb); 2023 #endif 2024 return (ISC_R_SUCCESS); 2025 } 2026 } 2027 ddns_cb = NULL; 2028 } 2029 2030 /* allocate our control block */ 2031 ddns_cb = ddns_cb_alloc(MDL); 2032 if (ddns_cb == NULL) { 2033 goto cleanup; 2034 } 2035 2036 /* Set the conflict detection flags based on global configuration */ 2037 copy_conflict_flags(&ddns_cb->flags, ddns_conflict_mask); 2038 2039 /* 2040 * For v4 we flag static leases so we don't try 2041 * and manipulate the lease later. For v6 we don't 2042 * get static leases and don't need to flag them. 2043 */ 2044 if (lease != NULL) { 2045 scope = &(lease->scope); 2046 ddns_cb->address = lease->ip_addr; 2047 if (lease->flags & STATIC_LEASE) 2048 ddns_cb->flags |= DDNS_STATIC_LEASE; 2049 } else if (lease6 != NULL) { 2050 scope = &(lease6->scope); 2051 memcpy(&ddns_cb->address.iabuf, lease6->addr.s6_addr, 16); 2052 ddns_cb->address.len = 16; 2053 } else 2054 goto cleanup; 2055 2056 /* 2057 * Set the flag bit if the lease is active, that is it isn't 2058 * expired or released. This is used to determine if we need 2059 * to update the scope information for both v4 and v6 and 2060 * the lease information for v6 when the response 2061 * from the DNS code is processed. 2062 */ 2063 if (active == ISC_TRUE) { 2064 ddns_cb->flags |= DDNS_ACTIVE_LEASE; 2065 } 2066 2067 /* No scope implies that DDNS has not been performed for this lease. */ 2068 if (*scope == NULL) 2069 goto cleanup; 2070 2071 if ((ddns_update_style != DDNS_UPDATE_STYLE_STANDARD) && 2072 (ddns_update_style != DDNS_UPDATE_STYLE_INTERIM)) 2073 goto cleanup; 2074 2075 /* Assume that we are removing both records */ 2076 ddns_cb->flags |= DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR; 2077 2078 /* and that we want to do the add call */ 2079 execute_add = ISC_R_SUCCESS; 2080 2081 /* 2082 * Look up stored names. 2083 */ 2084 2085 /* 2086 * Find the fwd name and copy it to the control block. If we don't 2087 * have it we can't delete the fwd record but we can still try to 2088 * remove the ptr record and cleanup the lease information if the 2089 * client did the fwd update. 2090 */ 2091 if (!find_bound_string(&ddns_cb->fwd_name, *scope, "ddns-fwd-name")) { 2092 /* don't try and delete the A, or do the add */ 2093 ddns_cb->flags &= ~DDNS_UPDATE_ADDR; 2094 execute_add = ISC_R_FAILURE; 2095 2096 /* Check if client did update */ 2097 if (find_bound_string(&ddns_cb->fwd_name, *scope, 2098 "ddns-client-fqdn")) { 2099 ddns_cb->flags |= DDNS_CLIENT_DID_UPDATE; 2100 } 2101 } 2102 2103 /* 2104 * Find the txt or dhcid tag and copy it to the control block. If we 2105 * don't have one this isn't an interim or standard record so we can't 2106 * delete the A record using this mechanism but we can delete the ptr 2107 * record. In this case we will attempt to do any requested next step. 2108 */ 2109 memset(&leaseid, 0, sizeof(leaseid)); 2110 if (find_bound_string (&leaseid, *scope, ddns_standard_tag)) { 2111 /* We have a standard tag */ 2112 ddns_cb->lease_tag = ddns_standard_tag; 2113 ddns_cb->dhcid_class = dns_rdatatype_dhcid; 2114 ddns_cb->other_dhcid_class = dns_rdatatype_txt; 2115 data_string_copy(&ddns_cb->dhcid, &leaseid, MDL); 2116 data_string_forget(&leaseid, MDL); 2117 } else if (find_bound_string (&leaseid, *scope, ddns_interim_tag)) { 2118 /* we have an interim tag */ 2119 ddns_cb->lease_tag = ddns_interim_tag; 2120 ddns_cb->dhcid_class = dns_rdatatype_txt; 2121 ddns_cb->other_dhcid_class = dns_rdatatype_dhcid; 2122 if (dhcid_fromlease(&ddns_cb->dhcid, &leaseid) != 2123 ISC_R_SUCCESS) { 2124 /* We couldn't convert the dhcid from the lease 2125 * version to the dns version. We can't delete 2126 * the A record but can continue to the ptr 2127 */ 2128 ddns_cb->flags &= ~DDNS_UPDATE_ADDR; 2129 } 2130 data_string_forget(&leaseid, MDL); 2131 } else { 2132 ddns_cb->flags &= ~DDNS_UPDATE_ADDR; 2133 } 2134 2135 /* 2136 * Find the rev name and copy it to the control block. If we don't 2137 * have it we can't get rid of it but we can try to remove the fwd 2138 * pointer if desired. 2139 */ 2140 if (!find_bound_string(&ddns_cb->rev_name, *scope, "ddns-rev-name")) { 2141 ddns_cb->flags &= ~DDNS_UPDATE_PTR; 2142 } 2143 2144 2145 /* 2146 * If we have a second control block for doing an add 2147 * after the remove finished attach it to our control block. 2148 */ 2149 ddns_cb->next_op = add_ddns_cb; 2150 2151 /* 2152 * Now that we've collected the information we can try to process it. 2153 * If necessary we call an appropriate routine to send a message and 2154 * provide it with an action routine to run on the control block given 2155 * the results of the message. We have three entry points from here, 2156 * one for removing the A record, the next for removing the PTR and 2157 * the third for doing any requested add. 2158 */ 2159 if ((ddns_cb->flags & DDNS_UPDATE_ADDR) != 0) { 2160 if (ddns_cb->fwd_name.len != 0) { 2161 ddns_cb->state = DDNS_STATE_REM_FW_YXDHCID; 2162 ddns_cb->cur_func = ddns_fwd_srv_rem1; 2163 2164 rcode = ddns_modify_fwd(ddns_cb, MDL); 2165 if (rcode == ISC_R_SUCCESS) { 2166 ddns_update_lease_ptr(lease, lease6, ddns_cb, 2167 ddns_cb, MDL); 2168 return (ISC_R_SUCCESS); 2169 } 2170 2171 /* 2172 * We weren't able to process the request tag the 2173 * add so we won't execute it. 2174 */ 2175 execute_add = ISC_R_FAILURE; 2176 goto cleanup; 2177 } 2178 else { 2179 /*remove info from scope */ 2180 unset(*scope, "ddns-fwd-name"); 2181 unset(*scope, ddns_cb->lease_tag); 2182 } 2183 } 2184 2185 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { 2186 ddns_cb->state = DDNS_STATE_REM_PTR; 2187 ddns_cb->cur_func = ddns_ptr_remove; 2188 ddns_cb->flags |= DDNS_EXECUTE_NEXT; 2189 2190 /* 2191 * if execute add isn't success remove the control block so 2192 * it won't be processed when the remove completes. We 2193 * also arrange to clean it up and get rid of it. 2194 */ 2195 if (execute_add != ISC_R_SUCCESS) { 2196 ddns_cb->next_op = NULL; 2197 ddns_fwd_srv_connector(lease, lease6, scope, 2198 add_ddns_cb, execute_add); 2199 add_ddns_cb = NULL; 2200 } 2201 else { 2202 result = ISC_R_SUCCESS; 2203 } 2204 2205 rcode = ddns_modify_ptr(ddns_cb, MDL); 2206 if (rcode == ISC_R_SUCCESS) { 2207 ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, 2208 MDL); 2209 return (result); 2210 } 2211 2212 /* We weren't able to process the request tag the 2213 * add so we won't execute it */ 2214 execute_add = ISC_R_FAILURE; 2215 goto cleanup; 2216 } 2217 2218 cleanup: 2219 /* 2220 * We've gotten here because we didn't need to send a message or 2221 * we failed when trying to do so. We send the additional cb 2222 * off to handle sending and/or cleanup and cleanup anything 2223 * we allocated here. 2224 */ 2225 ddns_fwd_srv_connector(lease, lease6, scope, add_ddns_cb, execute_add); 2226 if (ddns_cb != NULL) 2227 destroy_ddns_cb(ddns_cb, MDL); 2228 2229 return (result); 2230 } 2231 2232 /* Convenience function for setting flag bits in a mask */ 2233 static void 2234 set_flag (u_int16_t *flags, 2235 u_int16_t flag, 2236 u_int16_t value) { 2237 if (flags) { 2238 if (value) { 2239 *flags |= flag; 2240 } else { 2241 *flags &= ~flag; 2242 } 2243 } 2244 } 2245 2246 /* 2247 * Convenience function which replicates the conflict flags set in one 2248 * mask to another, while preserving all other flags. 2249 */ 2250 void copy_conflict_flags(u_int16_t *target, 2251 u_int16_t source) { 2252 if (target) { 2253 /* Preserve non conflict flags */ 2254 *target &= ~CONFLICT_BITS; 2255 2256 /* Enable conflict flags per source */ 2257 *target |= source & CONFLICT_BITS; 2258 } 2259 } 2260 2261 /* 2262 * Given an option_state, create a mask of conflict detection flags based 2263 * on the appropriate configuration parameters within the option state. 2264 */ 2265 u_int16_t 2266 get_conflict_mask(struct option_state *options) { 2267 2268 int ddns_update_conflict_detection = 1; /* default on */ 2269 int ddns_dual_stack_mixed_mode = 0; /* default off */ 2270 int ddns_guard_id_must_match = 1; /* default on */ 2271 int ddns_other_guard_is_dynamic = 0; /* default off */ 2272 struct option_cache *oc = NULL; 2273 2274 u_int16_t mask = 0; 2275 oc = lookup_option(&server_universe, options, SV_DDNS_CONFLICT_DETECT); 2276 if (oc) { 2277 ddns_update_conflict_detection = 2278 evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options, 2279 NULL, &global_scope, oc, MDL); 2280 } 2281 2282 set_flag(&mask, DDNS_CONFLICT_DETECTION, 2283 ddns_update_conflict_detection); 2284 2285 if (!ddns_update_conflict_detection) { 2286 #if defined (DEBUG_DNS_UPDATES) 2287 log_info ("DDNS conflict detection: off"); 2288 #endif 2289 /* Turn the rest of the conflict related flags off */ 2290 set_flag(&mask, DDNS_DUAL_STACK_MIXED_MODE, 0); 2291 set_flag(&mask, DDNS_GUARD_ID_MUST_MATCH, 0); 2292 set_flag(&mask, DDNS_OTHER_GUARD_IS_DYNAMIC, 0); 2293 return (mask); 2294 } 2295 2296 // Get the values 2297 oc = lookup_option(&server_universe, options, 2298 SV_DDNS_DUAL_STACK_MIXED_MODE); 2299 if (oc) { 2300 ddns_dual_stack_mixed_mode = 2301 evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options, 2302 NULL, &global_scope, oc, MDL); 2303 } 2304 2305 oc = lookup_option(&server_universe, options, 2306 SV_DDNS_GUARD_ID_MUST_MATCH); 2307 if (oc) { 2308 ddns_guard_id_must_match = 2309 evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options, 2310 NULL, &global_scope, oc, MDL); 2311 } 2312 2313 oc = lookup_option(&server_universe, options, 2314 SV_DDNS_OTHER_GUARD_IS_DYNAMIC); 2315 if (oc) { 2316 ddns_other_guard_is_dynamic = 2317 evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options, 2318 NULL, &global_scope, oc, MDL); 2319 } 2320 2321 // Set the flags 2322 set_flag(&mask, DDNS_DUAL_STACK_MIXED_MODE, 2323 ddns_dual_stack_mixed_mode); 2324 2325 set_flag(&mask, DDNS_GUARD_ID_MUST_MATCH, 2326 ddns_guard_id_must_match); 2327 2328 set_flag(&mask, DDNS_OTHER_GUARD_IS_DYNAMIC, 2329 ddns_other_guard_is_dynamic); 2330 2331 #if defined (DEBUG_DNS_UPDATES) 2332 log_info ("DDNS conflict behavior:\n" 2333 "\tddns-update-style: %s\n" 2334 "\tupdate-conflict-detection: %d\n" 2335 "\tddns-dual-stack-mixed-mode: %d\n" 2336 "\tddns-guard-id-must-match %d\n" 2337 "\tddns-other-guard-is-dynamic: %d\n", 2338 ddns_styles_values[ddns_update_style].name, 2339 ddns_update_conflict_detection, 2340 ddns_dual_stack_mixed_mode, 2341 ddns_guard_id_must_match, 2342 ddns_other_guard_is_dynamic); 2343 #endif 2344 return (mask); 2345 } 2346 2347 #if defined (DEBUG_DNS_UPDATES) 2348 /* Type used for creating lists of function pointers and their names */ 2349 typedef struct { 2350 void *ptr; 2351 char *name; 2352 } LabeledPtr; 2353 2354 /* Returns the name of the function referred to by the given address */ 2355 char* 2356 dump_ddns_cb_func(void *func) { 2357 static LabeledPtr funcs[] = { 2358 { ddns_ptr_add, "ddns_ptr_add" }, 2359 { ddns_fwd_srv_add2, "ddns_fwd_srv_add2" }, 2360 { ddns_fwd_srv_add1, "ddns_fwd_srv_add1" }, 2361 { ddns_ptr_remove, "ddns_ptr_remove" }, 2362 { ddns_fwd_srv_rem2, "ddns_fwd_srv_rem2" }, 2363 { ddns_fwd_srv_rem1, "ddns_fwd_srv_rem1" }, 2364 { ddns_fwd_srv_add3, "ddns_fwd_srv_adde" }, 2365 { NULL, "unknown" } 2366 }; 2367 2368 LabeledPtr* lp = funcs; 2369 if (!func) { 2370 return ("<null>"); 2371 } 2372 2373 while ((lp->ptr) && (lp->ptr != func)) { 2374 ++lp; 2375 } 2376 2377 return (lp->name); 2378 } 2379 2380 /* Dumps basic control block info to the log */ 2381 char* 2382 dump_ddns_cb (dhcp_ddns_cb_t *ddns_cb) { 2383 static char output_buf[4096]; 2384 if (!ddns_cb) { 2385 return ("<ddns_cb is null>"); 2386 } 2387 2388 sprintf (output_buf, "ddns_cb: %p flags: %x state: %s cur_func: %s", 2389 ddns_cb, ddns_cb->flags, 2390 ddns_state_name(ddns_cb->state), 2391 dump_ddns_cb_func(ddns_cb->cur_func)); 2392 2393 return(output_buf); 2394 } 2395 #endif /* DEBUG_DNS_UPDATES */ 2396 2397 #endif /* NSUPDATE */ 2398