1/* ddns.c 2 3 Dynamic DNS updates. */ 4 5/* 6 * Copyright (c) 2004-2005 by Internet Systems Consortium, Inc. ("ISC") 7 * Copyright (c) 2000-2003 by Internet Software Consortium 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 * 21 * Internet Systems Consortium, Inc. 22 * 950 Charter Street 23 * Redwood City, CA 94063 24 * <info@isc.org> 25 * http://www.isc.org/ 26 * 27 * This software has been donated to Internet Systems Consortium 28 * by Damien Neil of Nominum, Inc. 29 * 30 * To learn more about Internet Systems Consortium, see 31 * ``http://www.isc.org/''. To learn more about Nominum, Inc., see 32 * ``http://www.nominum.com''. 33 */ 34 35#ifndef lint 36static char copyright[] = 37"$Id: ddns.c,v 1.8 2011/08/16 16:36:38 christos Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n"; 38#endif /* not lint */ 39 40#include "dhcpd.h" 41#include "dst/md5.h" 42#include "minires/minires.h" 43 44#ifdef NSUPDATE 45 46/* DN: No way of checking that there is enough space in a data_string's 47 buffer. Be certain to allocate enough! 48 TL: This is why the expression evaluation code allocates a *new* 49 data_string. :') */ 50static void data_string_append (struct data_string *ds1, 51 struct data_string *ds2) 52{ 53 memcpy (ds1 -> buffer -> data + ds1 -> len, 54 ds2 -> data, 55 ds2 -> len); 56 ds1 -> len += ds2 -> len; 57} 58 59static isc_result_t ddns_update_ptr (struct data_string *ddns_fwd_name, 60 struct data_string *ddns_rev_name, 61 unsigned long ttl) 62{ 63 ns_updque updqueue; 64 ns_updrec *updrec; 65 isc_result_t result = ISC_R_UNEXPECTED; 66 67 /* 68 * The DHCP server submits a DNS query which deletes all of the PTR RRs 69 * associated with the lease IP address, and adds a PTR RR whose data 70 * is the client's (possibly disambiguated) host name. The server also 71 * adds a DHCID RR specified in Section 4.3. 72 * -- "Interaction between DHCP and DNS" 73 */ 74 75 ISC_LIST_INIT (updqueue); 76 77 /* 78 * Delete all PTR RRs. 79 */ 80 updrec = minires_mkupdrec (S_UPDATE, 81 (const char *)ddns_rev_name -> data, 82 C_IN, T_PTR, 0); 83 if (!updrec) { 84 result = ISC_R_NOMEMORY; 85 goto error; 86 } 87 88 updrec -> r_data = (unsigned char *)0; 89 updrec -> r_size = 0; 90 updrec -> r_opcode = DELETE; 91 92 ISC_LIST_APPEND (updqueue, updrec, r_link); 93 94 /* 95 * Add PTR RR. 96 */ 97 updrec = minires_mkupdrec (S_UPDATE, 98 (const char *)ddns_rev_name -> data, 99 C_IN, T_PTR, ttl); 100 if (!updrec) { 101 result = ISC_R_NOMEMORY; 102 goto error; 103 } 104 105 updrec -> r_data = ddns_fwd_name -> data; 106 updrec -> r_size = ddns_fwd_name -> len; 107 updrec -> r_opcode = ADD; 108 109 ISC_LIST_APPEND (updqueue, updrec, r_link); 110 111 /* 112 * Attempt to perform the update. 113 */ 114 result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue)); 115#if defined (DEBUG) 116 print_dns_status ((int)result, &updqueue); 117#endif 118 if (result == ISC_R_SUCCESS) { 119 log_info ("added reverse map from %.*s to %.*s", 120 (int)ddns_rev_name -> len, 121 (const char *)ddns_rev_name -> data, 122 (int)ddns_fwd_name -> len, 123 (const char *)ddns_fwd_name -> data); 124 } else { 125 log_error ("unable to add reverse map from %.*s to %.*s: %s", 126 (int)ddns_rev_name -> len, 127 (const char *)ddns_rev_name -> data, 128 (int)ddns_fwd_name -> len, 129 (const char *)ddns_fwd_name -> data, 130 isc_result_totext (result)); 131 } 132 133 /* Fall through. */ 134 error: 135 136 while (!ISC_LIST_EMPTY (updqueue)) { 137 updrec = ISC_LIST_HEAD (updqueue); 138 ISC_LIST_UNLINK (updqueue, updrec, r_link); 139 minires_freeupdrec (updrec); 140 } 141 142 return result; 143} 144 145 146static isc_result_t ddns_remove_ptr (struct data_string *ddns_rev_name) 147{ 148 ns_updque updqueue; 149 ns_updrec *updrec; 150 isc_result_t result; 151 152 /* 153 * When a lease expires or a DHCP client issues a DHCPRELEASE request, 154 * the DHCP server SHOULD delete the PTR RR that matches the DHCP 155 * binding, if one was successfully added. The server's update query 156 * SHOULD assert that the name in the PTR record matches the name of 157 * the client whose lease has expired or been released. 158 * -- "Interaction between DHCP and DNS" 159 */ 160 161 ISC_LIST_INIT (updqueue); 162 163 /* 164 * Delete the PTR RRset for the leased address. 165 */ 166 updrec = minires_mkupdrec (S_UPDATE, 167 (const char *)ddns_rev_name -> data, 168 C_IN, T_PTR, 0); 169 if (!updrec) { 170 result = ISC_R_NOMEMORY; 171 goto error; 172 } 173 174 updrec -> r_data = (unsigned char *)0; 175 updrec -> r_size = 0; 176 updrec -> r_opcode = DELETE; 177 178 ISC_LIST_APPEND (updqueue, updrec, r_link); 179 180 /* 181 * Attempt to perform the update. 182 */ 183 result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue)); 184#if defined (DEBUG) 185 print_dns_status ((int)result, &updqueue); 186#endif 187 if (result == ISC_R_SUCCESS) { 188 log_info ("removed reverse map on %.*s", 189 (int)ddns_rev_name -> len, 190 (const char *)ddns_rev_name -> data); 191 } else { 192 if (result != ISC_R_NXRRSET && result != ISC_R_NXDOMAIN) 193 log_error ("can't remove reverse map on %.*s: %s", 194 (int)ddns_rev_name -> len, 195 (const char *)ddns_rev_name -> data, 196 isc_result_totext (result)); 197 } 198 199 /* Not there is success. */ 200 if (result == ISC_R_NXRRSET || result == ISC_R_NXDOMAIN) 201 result = ISC_R_SUCCESS; 202 203 /* Fall through. */ 204 error: 205 206 while (!ISC_LIST_EMPTY (updqueue)) { 207 updrec = ISC_LIST_HEAD (updqueue); 208 ISC_LIST_UNLINK (updqueue, updrec, r_link); 209 minires_freeupdrec (updrec); 210 } 211 212 return result; 213} 214 215 216int ddns_updates (struct packet *packet, 217 struct lease *lease, struct lease *old, 218 struct lease_state *state) 219{ 220 unsigned long ddns_ttl = DEFAULT_DDNS_TTL; 221 struct data_string ddns_hostname; 222 struct data_string ddns_domainname; 223 struct data_string old_ddns_fwd_name; 224 struct data_string ddns_fwd_name; 225 struct data_string ddns_rev_name; 226 struct data_string ddns_dhcid; 227 struct data_string d1; 228 struct option_cache *oc; 229 int s1, s2; 230 int result = 0; 231 isc_result_t rcode1 = ISC_R_SUCCESS, rcode2 = ISC_R_SUCCESS; 232 int server_updates_a = 1; 233 struct buffer *bp = (struct buffer *)0; 234 int ignorep = 0; 235 236 s1 = 0; /* XXXGCC -Wuninitialized [arm / sparc64] */ 237 238 if (ddns_update_style != 2) 239 return 0; 240 241 /* Can only cope with IPv4 addrs at the moment. */ 242 if (lease -> ip_addr . len != 4) 243 return 0; 244 245 memset (&ddns_hostname, 0, sizeof (ddns_hostname)); 246 memset (&ddns_domainname, 0, sizeof (ddns_domainname)); 247 memset (&old_ddns_fwd_name, 0, sizeof (ddns_fwd_name)); 248 memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name)); 249 memset (&ddns_rev_name, 0, sizeof (ddns_rev_name)); 250 memset (&ddns_dhcid, 0, sizeof (ddns_dhcid)); 251 252 /* If we are allowed to accept the client's update of its own A 253 record, see if the client wants to update its own A record. */ 254 if (!(oc = lookup_option (&server_universe, state -> options, 255 SV_CLIENT_UPDATES)) || 256 evaluate_boolean_option_cache (&ignorep, packet, lease, 257 (struct client_state *)0, 258 packet -> options, 259 state -> options, 260 &lease -> scope, oc, MDL)) { 261 /* If there's no fqdn.no-client-update or if it's 262 nonzero, don't try to use the client-supplied 263 XXX */ 264 if (!(oc = lookup_option (&fqdn_universe, packet -> options, 265 FQDN_SERVER_UPDATE)) || 266 evaluate_boolean_option_cache (&ignorep, packet, lease, 267 (struct client_state *)0, 268 packet -> options, 269 state -> options, 270 &lease -> scope, oc, MDL)) 271 goto noclient; 272 /* Win98 and Win2k will happily claim to be willing to 273 update an unqualified domain name. */ 274 if (!(oc = lookup_option (&fqdn_universe, packet -> options, 275 FQDN_DOMAINNAME))) 276 goto noclient; 277 if (!(oc = lookup_option (&fqdn_universe, packet -> options, 278 FQDN_FQDN)) || 279 !evaluate_option_cache (&ddns_fwd_name, packet, lease, 280 (struct client_state *)0, 281 packet -> options, 282 state -> options, 283 &lease -> scope, oc, MDL)) 284 goto noclient; 285 server_updates_a = 0; 286 goto client_updates; 287 } 288 noclient: 289 /* If do-forward-updates is disabled, this basically means don't 290 do an update unless the client is participating, so if we get 291 here and do-forward-updates is disabled, we can stop. */ 292 if ((oc = lookup_option (&server_universe, state -> options, 293 SV_DO_FORWARD_UPDATES)) && 294 !evaluate_boolean_option_cache (&ignorep, packet, lease, 295 (struct client_state *)0, 296 packet -> options, 297 state -> options, 298 &lease -> scope, oc, MDL)) { 299 return 0; 300 } 301 302 /* If it's a static lease, then don't do the DNS update unless we're 303 specifically configured to do so. If the client asked to do its 304 own update and we allowed that, we don't do this test. */ 305 if (lease -> flags & STATIC_LEASE) { 306 if (!(oc = lookup_option (&server_universe, state -> options, 307 SV_UPDATE_STATIC_LEASES)) || 308 !evaluate_boolean_option_cache (&ignorep, packet, lease, 309 (struct client_state *)0, 310 packet -> options, 311 state -> options, 312 &lease -> scope, oc, MDL)) 313 return 0; 314 } 315 316 /* 317 * Compute the name for the A record. 318 */ 319 oc = lookup_option (&server_universe, state -> options, 320 SV_DDNS_HOST_NAME); 321 if (oc) 322 s1 = evaluate_option_cache (&ddns_hostname, packet, lease, 323 (struct client_state *)0, 324 packet -> options, 325 state -> options, 326 &lease -> scope, oc, MDL); 327 else 328 s1 = 0; 329 330 oc = lookup_option (&server_universe, state -> options, 331 SV_DDNS_DOMAIN_NAME); 332 if (oc) 333 s2 = evaluate_option_cache (&ddns_domainname, packet, lease, 334 (struct client_state *)0, 335 packet -> options, 336 state -> options, 337 &lease -> scope, oc, MDL); 338 else 339 s2 = 0; 340 341 if (s1 && s2) { 342 if (ddns_hostname.len + ddns_domainname.len > 253) { 343 log_error ("ddns_update: host.domain name too long"); 344 345 goto out; 346 } 347 348 buffer_allocate (&ddns_fwd_name.buffer, 349 ddns_hostname.len + ddns_domainname.len + 2, 350 MDL); 351 if (ddns_fwd_name.buffer) { 352 ddns_fwd_name.data = ddns_fwd_name.buffer -> data; 353 data_string_append (&ddns_fwd_name, &ddns_hostname); 354 ddns_fwd_name.buffer -> data [ddns_fwd_name.len] = '.'; 355 ddns_fwd_name.len++; 356 data_string_append (&ddns_fwd_name, &ddns_domainname); 357 ddns_fwd_name.buffer -> data [ddns_fwd_name.len] ='\0'; 358 ddns_fwd_name.terminated = 1; 359 } 360 } 361 client_updates: 362 363 /* See if there's a name already stored on the lease. */ 364 if (find_bound_string (&old_ddns_fwd_name, 365 lease -> scope, "ddns-fwd-name")) { 366 /* If there is, see if it's different. */ 367 if (old_ddns_fwd_name.len != ddns_fwd_name.len || 368 memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data, 369 old_ddns_fwd_name.len)) { 370 /* If the name is different, try to delete 371 the old A record. */ 372 if (!ddns_removals (lease)) 373 goto out; 374 /* If the delete succeeded, go install the new 375 record. */ 376 goto in; 377 } 378 379 /* See if there's a DHCID on the lease. */ 380 if (!find_bound_string (&ddns_dhcid, 381 lease -> scope, "ddns-txt")) { 382 /* If there's no DHCID, the update was probably 383 done with the old-style ad-hoc DDNS updates. 384 So if the expiry and release events look like 385 they're the same, run them. This should delete 386 the old DDNS data. */ 387 if (old -> on_expiry == old -> on_release) { 388 execute_statements ((struct binding_value **)0, 389 (struct packet *)0, lease, 390 (struct client_state *)0, 391 (struct option_state *)0, 392 (struct option_state *)0, 393 &lease -> scope, 394 old -> on_expiry); 395 if (old -> on_expiry) 396 executable_statement_dereference 397 (&old -> on_expiry, MDL); 398 if (old -> on_release) 399 executable_statement_dereference 400 (&old -> on_release, MDL); 401 /* Now, install the DDNS data the new way. */ 402 goto in; 403 } 404 } 405 406 /* See if the administrator wants to do updates even 407 in cases where the update already appears to have been 408 done. */ 409 if (!(oc = lookup_option (&server_universe, state -> options, 410 SV_UPDATE_OPTIMIZATION)) || 411 evaluate_boolean_option_cache (&ignorep, packet, lease, 412 (struct client_state *)0, 413 packet -> options, 414 state -> options, 415 &lease -> scope, oc, MDL)) { 416 result = 1; 417 goto noerror; 418 } 419 } 420 421 /* If there's no ddns-fwd-name on the lease, see if there's 422 a ddns-client-fqdn, indicating a prior client FQDN update. 423 If there is, and if we're still doing the client update, 424 see if the name has changed. If it hasn't, don't do the 425 PTR update. */ 426 if (find_bound_string (&old_ddns_fwd_name, 427 lease -> scope, "ddns-client-fqdn")) { 428 /* If the name is not different, no need to update 429 the PTR record. */ 430 if (old_ddns_fwd_name.len == ddns_fwd_name.len && 431 !memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data, 432 old_ddns_fwd_name.len) && 433 (!(oc = lookup_option (&server_universe, 434 state -> options, 435 SV_UPDATE_OPTIMIZATION)) || 436 evaluate_boolean_option_cache (&ignorep, packet, lease, 437 (struct client_state *)0, 438 packet -> options, 439 state -> options, 440 &lease -> scope, oc, 441 MDL))) { 442 goto noerror; 443 } 444 } 445 in: 446 447 /* If we don't have a name that the client has been assigned, we 448 can just skip all this. */ 449 if (!ddns_fwd_name.len) 450 goto out; 451 452 if (ddns_fwd_name.len > 255) { 453 log_error ("client provided fqdn: too long"); 454 goto out; 455 } 456 457 /* 458 * Compute the RR TTL. 459 */ 460 ddns_ttl = DEFAULT_DDNS_TTL; 461 memset (&d1, 0, sizeof d1); 462 if ((oc = lookup_option (&server_universe, state -> options, 463 SV_DDNS_TTL))) { 464 if (evaluate_option_cache (&d1, packet, lease, 465 (struct client_state *)0, 466 packet -> options, 467 state -> options, 468 &lease -> scope, oc, MDL)) { 469 if (d1.len == sizeof (u_int32_t)) 470 ddns_ttl = getULong (d1.data); 471 data_string_forget (&d1, MDL); 472 } 473 } 474 475 476 /* 477 * Compute the reverse IP name. 478 */ 479 oc = lookup_option (&server_universe, state -> options, 480 SV_DDNS_REV_DOMAIN_NAME); 481 if (oc) 482 s1 = evaluate_option_cache (&d1, packet, lease, 483 (struct client_state *)0, 484 packet -> options, 485 state -> options, 486 &lease -> scope, oc, MDL); 487 else 488 s1 = 0; 489 490 if (s1 && (d1.len > 238)) { 491 log_error ("ddns_update: Calculated rev domain name too long."); 492 s1 = 0; 493 data_string_forget (&d1, MDL); 494 } 495 496 if (oc && s1) { 497 /* Buffer length: 498 XXX.XXX.XXX.XXX.<ddns-rev-domain-name>\0 */ 499 buffer_allocate (&ddns_rev_name.buffer, 500 d1.len + 17, MDL); 501 if (ddns_rev_name.buffer) { 502 ddns_rev_name.data = ddns_rev_name.buffer -> data; 503 504 /* %Audit% Cannot exceed 17 bytes. %2004.06.17,Safe% */ 505 sprintf ((char *)ddns_rev_name.buffer -> data, 506 "%u.%u.%u.%u.", 507 lease -> ip_addr . iabuf[3] & 0xff, 508 lease -> ip_addr . iabuf[2] & 0xff, 509 lease -> ip_addr . iabuf[1] & 0xff, 510 lease -> ip_addr . iabuf[0] & 0xff); 511 512 ddns_rev_name.len = 513 strlen ((const char *)ddns_rev_name.data); 514 data_string_append (&ddns_rev_name, &d1); 515 ddns_rev_name.buffer -> data [ddns_rev_name.len] ='\0'; 516 ddns_rev_name.terminated = 1; 517 } 518 519 data_string_forget (&d1, MDL); 520 } 521 522 /* 523 * If we are updating the A record, compute the DHCID value. 524 */ 525 if (server_updates_a) { 526 memset (&ddns_dhcid, 0, sizeof ddns_dhcid); 527 if (lease -> uid && lease -> uid_len) 528 result = get_dhcid (&ddns_dhcid, 529 DHO_DHCP_CLIENT_IDENTIFIER, 530 lease -> uid, lease -> uid_len); 531 else 532 result = get_dhcid (&ddns_dhcid, 0, 533 lease -> hardware_addr.hbuf, 534 lease -> hardware_addr.hlen); 535 if (!result) 536 goto badfqdn; 537 } 538 539 /* 540 * Start the resolver, if necessary. 541 */ 542 if (!resolver_inited) { 543 minires_ninit (&resolver_state); 544 resolver_inited = 1; 545 resolver_state.retrans = 1; 546 resolver_state.retry = 1; 547 } 548 549 /* 550 * Perform updates. 551 */ 552 if (ddns_fwd_name.len && ddns_dhcid.len) 553 rcode1 = ddns_update_a (&ddns_fwd_name, lease -> ip_addr, 554 &ddns_dhcid, ddns_ttl, 0); 555 556 if (rcode1 == ISC_R_SUCCESS) { 557 if (ddns_fwd_name.len && ddns_rev_name.len) 558 rcode2 = ddns_update_ptr (&ddns_fwd_name, 559 &ddns_rev_name, ddns_ttl); 560 } else 561 rcode2 = rcode1; 562 563 if (rcode1 == ISC_R_SUCCESS && 564 (server_updates_a || rcode2 == ISC_R_SUCCESS)) { 565 bind_ds_value (&lease -> scope, 566 (server_updates_a 567 ? "ddns-fwd-name" : "ddns-client-fqdn"), 568 &ddns_fwd_name); 569 if (server_updates_a) 570 bind_ds_value (&lease -> scope, "ddns-txt", 571 &ddns_dhcid); 572 } 573 574 if (rcode2 == ISC_R_SUCCESS) { 575 bind_ds_value (&lease -> scope, "ddns-rev-name", 576 &ddns_rev_name); 577 } 578 579 /* Set up the outgoing FQDN option if there was an incoming 580 FQDN option. If there's a valid FQDN option, there should 581 be an FQDN_ENCODED suboption, so we test the latter to 582 detect the presence of the former. */ 583 noerror: 584 if ((oc = lookup_option (&fqdn_universe, 585 packet -> options, FQDN_ENCODED)) 586 && buffer_allocate (&bp, ddns_fwd_name.len + 5, MDL)) { 587 bp -> data [0] = server_updates_a; 588 if (!save_option_buffer (&fqdn_universe, state -> options, 589 bp, &bp -> data [0], 1, 590 &fqdn_options [FQDN_SERVER_UPDATE], 591 0)) 592 goto badfqdn; 593 bp -> data [1] = server_updates_a; 594 if (!save_option_buffer (&fqdn_universe, state -> options, 595 bp, &bp -> data [1], 1, 596 &fqdn_options [FQDN_NO_CLIENT_UPDATE], 597 0)) 598 goto badfqdn; 599 /* Do the same encoding the client did. */ 600 oc = lookup_option (&fqdn_universe, packet -> options, 601 FQDN_ENCODED); 602 if (oc && 603 evaluate_boolean_option_cache (&ignorep, packet, lease, 604 (struct client_state *)0, 605 packet -> options, 606 state -> options, 607 &lease -> scope, oc, MDL)) 608 bp -> data [2] = 1; 609 else 610 bp -> data [2] = 0; 611 if (!save_option_buffer (&fqdn_universe, state -> options, 612 bp, &bp -> data [2], 1, 613 &fqdn_options [FQDN_ENCODED], 614 0)) 615 goto badfqdn; 616 bp -> data [3] = isc_rcode_to_ns (rcode1); 617 if (!save_option_buffer (&fqdn_universe, state -> options, 618 bp, &bp -> data [3], 1, 619 &fqdn_options [FQDN_RCODE1], 620 0)) 621 goto badfqdn; 622 bp -> data [4] = isc_rcode_to_ns (rcode2); 623 if (!save_option_buffer (&fqdn_universe, state -> options, 624 bp, &bp -> data [4], 1, 625 &fqdn_options [FQDN_RCODE2], 626 0)) 627 goto badfqdn; 628 if (ddns_fwd_name.len) { 629 memcpy (&bp -> data [5], 630 ddns_fwd_name.data, ddns_fwd_name.len); 631 if (!save_option_buffer (&fqdn_universe, state -> options, 632 bp, &bp -> data [5], 633 ddns_fwd_name.len, 634 &fqdn_options [FQDN_FQDN], 635 0)) 636 goto badfqdn; 637 } 638 } 639 640 badfqdn: 641 out: 642 /* 643 * Final cleanup. 644 */ 645 data_string_forget (&ddns_hostname, MDL); 646 data_string_forget (&ddns_domainname, MDL); 647 data_string_forget (&old_ddns_fwd_name, MDL); 648 data_string_forget (&ddns_fwd_name, MDL); 649 data_string_forget (&ddns_rev_name, MDL); 650 data_string_forget (&ddns_dhcid, MDL); 651 if (bp) 652 buffer_dereference (&bp, MDL); 653 654 return result; 655} 656 657int ddns_removals (struct lease *lease) 658{ 659 struct data_string ddns_fwd_name; 660 struct data_string ddns_rev_name; 661 struct data_string ddns_dhcid; 662 isc_result_t rcode; 663 int result = 0; 664 int client_updated = 0; 665 666 /* No scope implies that DDNS has not been performed for this lease. */ 667 if (!lease -> scope) 668 return 0; 669 670 if (ddns_update_style != 2) 671 return 0; 672 673 /* 674 * Look up stored names. 675 */ 676 memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name)); 677 memset (&ddns_rev_name, 0, sizeof (ddns_rev_name)); 678 memset (&ddns_dhcid, 0, sizeof (ddns_dhcid)); 679 680 /* 681 * Start the resolver, if necessary. 682 */ 683 if (!resolver_inited) { 684 minires_ninit (&resolver_state); 685 resolver_inited = 1; 686 resolver_state.retrans = 1; 687 resolver_state.retry = 1; 688 } 689 690 /* We need the fwd name whether we are deleting both records or just 691 the PTR record, so if it's not there, we can't proceed. */ 692 if (!find_bound_string (&ddns_fwd_name, 693 lease -> scope, "ddns-fwd-name")) { 694 /* If there's no ddns-fwd-name, look for the client fqdn, 695 in case the client did the update. */ 696 if (!find_bound_string (&ddns_fwd_name, 697 lease -> scope, "ddns-client-fqdn")) 698 goto try_rev; 699 client_updated = 1; 700 goto try_rev; 701 } 702 703 /* If the ddns-txt binding isn't there, this isn't an interim 704 or rfc3??? record, so we can't delete the A record using 705 this mechanism, but we can delete the PTR record. */ 706 if (!find_bound_string (&ddns_dhcid, lease -> scope, "ddns-txt")) { 707 result = 1; 708 goto try_rev; 709 } 710 711 /* 712 * Perform removals. 713 */ 714 if (ddns_fwd_name.len) 715 rcode = ddns_remove_a (&ddns_fwd_name, 716 lease -> ip_addr, &ddns_dhcid); 717 else 718 rcode = ISC_R_SUCCESS; 719 720 if (rcode == ISC_R_SUCCESS) { 721 result = 1; 722 unset (lease -> scope, "ddns-fwd-name"); 723 unset (lease -> scope, "ddns-txt"); 724 try_rev: 725 if (find_bound_string (&ddns_rev_name, 726 lease -> scope, "ddns-rev-name")) { 727 if ((ns_rcode)ddns_remove_ptr(&ddns_rev_name) == NOERROR) { 728 unset (lease -> scope, "ddns-rev-name"); 729 if (client_updated) 730 unset (lease -> scope, 731 "ddns-client-fqdn"); 732 /* XXX this is to compensate for a bug in 733 XXX 3.0rc8, and should be removed before 734 XXX 3.0pl1. */ 735 else if (!ddns_fwd_name.len) 736 unset (lease -> scope, "ddns-text"); 737 } else 738 result = 0; 739 } 740 } 741 742 data_string_forget (&ddns_fwd_name, MDL); 743 data_string_forget (&ddns_rev_name, MDL); 744 data_string_forget (&ddns_dhcid, MDL); 745 746 return result; 747} 748 749#endif /* NSUPDATE */ 750