3 Domain Name Service subroutines. */
6 * Copyright (c) 2001-2002 Internet Software Consortium.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon in cooperation with Nominum, Inc.
38 * To learn more about the Internet Software Consortium, see
39 * ``http://www.isc.org/''. To learn more about Nominum, Inc., see
40 * ``http://www.nominum.com''.
44 static char copyright[] =
45 "$Id: dns.c,v 1.35.2.13 2002/11/17 02:26:57 dhankins Exp $ Copyright (c) 2001-2002 The Internet Software Consortium. All rights reserved.\n";
49 #include "arpa/nameser.h"
52 /* This file is kind of a crutch for the BIND 8 nsupdate code, which has
53 * itself been cruelly hacked from its original state. What this code
54 * does is twofold: first, it maintains a database of zone cuts that can
55 * be used to figure out which server should be contacted to update any
56 * given domain name. Secondly, it maintains a set of named TSIG keys,
57 * and associates those keys with zones. When an update is requested for
58 * a particular zone, the key associated with that zone is used for the
61 * The way this works is that you define the domain name to which an
62 * SOA corresponds, and the addresses of some primaries for that domain name:
66 * secondary 10.0.22.1, 10.0.23.1;
70 * If an update is requested for GAZANGA.TOPANGA.FOO.COM, then the name
71 * server looks in its database for a zone record for "GAZANGA.TOPANGA.FOO.COM",
72 * doesn't find it, looks for one for "TOPANGA.FOO.COM", doesn't find *that*,
73 * looks for "FOO.COM", finds it. So it
74 * attempts the update to the primary for FOO.COM. If that times out, it
75 * tries the secondaries. You can list multiple primaries if you have some
76 * kind of magic name server that supports that. You shouldn't list
77 * secondaries that don't know how to forward updates (e.g., BIND 8 doesn't
78 * support update forwarding, AFAIK). If no TSIG key is listed, the update
79 * is attempted without TSIG.
81 * The DHCP server tries to find an existing zone for any given name by
82 * trying to look up a local zone structure for each domain containing
83 * that name, all the way up to '.'. If it finds one cached, it tries
84 * to use that one to do the update. That's why it tries to update
85 * "FOO.COM" above, even though theoretically it should try GAZANGA...
86 * and TOPANGA... first.
88 * If the update fails with a predefined or cached zone (we'll get to
89 * those in a second), then it tries to find a more specific zone. This
90 * is done by looking first for an SOA for GAZANGA.TOPANGA.FOO.COM. Then
91 * an SOA for TOPANGA.FOO.COM is sought. If during this search a predefined
92 * or cached zone is found, the update fails - there's something wrong
95 * If a more specific zone _is_ found, that zone is cached for the length of
96 * its TTL in the same database as that described above. TSIG updates are
97 * never done for cached zones - if you want TSIG updates you _must_
98 * write a zone definition linking the key to the zone. In cases where you
99 * know for sure what the key is but do not want to hardcode the IP addresses
100 * of the primary or secondaries, a zone declaration can be made that doesn't
101 * include any primary or secondary declarations. When the DHCP server
102 * encounters this while hunting up a matching zone for a name, it looks up
103 * the SOA, fills in the IP addresses, and uses that record for the update.
104 * If the SOA lookup returns NXRRSET, a warning is printed and the zone is
105 * discarded, TSIG key and all. The search for the zone then continues as if
106 * the zone record hadn't been found. Zones without IP addresses don't
107 * match when initially hunting for a predefined or cached zone to update.
109 * When an update is attempted and no predefined or cached zone is found
110 * that matches any enclosing domain of the domain being updated, the DHCP
111 * server goes through the same process that is done when the update to a
112 * predefined or cached zone fails - starting with the most specific domain
113 * name (GAZANGA.TOPANGA.FOO.COM) and moving to the least specific (the root),
114 * it tries to look up an SOA record. When it finds one, it creates a cached
115 * zone and attempts an update, and gives up if the update fails.
117 * TSIG keys are defined like this:
119 * key "FOO.COM Key" {
120 * algorithm HMAC-MD5.SIG-ALG.REG.INT;
124 * <Base64> is a number expressed in base64 that represents the key.
125 * It's also permissible to use a quoted string here - this will be
126 * translated as the ASCII bytes making up the string, and will not
127 * include any NUL termination. The key name can be any text string,
128 * and the key type must be one of the key types defined in the draft
129 * or by the IANA. Currently only the HMAC-MD5... key type is
133 dns_zone_hash_t *dns_zone_hash;
135 #if defined (NSUPDATE)
136 isc_result_t find_tsig_key (ns_tsig_key **key, const char *zname,
137 struct dns_zone *zone)
143 return ISC_R_NOTFOUND;
146 return ISC_R_KEY_UNKNOWN;
149 if ((!zone -> key -> name ||
150 strlen (zone -> key -> name) > NS_MAXDNAME) ||
151 (!zone -> key -> algorithm ||
152 strlen (zone -> key -> algorithm) > NS_MAXDNAME) ||
154 (!zone -> key -> key) ||
155 (zone -> key -> key -> len == 0)) {
156 return ISC_R_INVALIDKEY;
158 tkey = dmalloc (sizeof *tkey, MDL);
161 return ISC_R_NOMEMORY;
163 memset (tkey, 0, sizeof *tkey);
164 tkey -> data = dmalloc (zone -> key -> key -> len, MDL);
169 strcpy (tkey -> name, zone -> key -> name);
170 strcpy (tkey -> alg, zone -> key -> algorithm);
171 memcpy (tkey -> data,
172 zone -> key -> key -> value, zone -> key -> key -> len);
173 tkey -> len = zone -> key -> key -> len;
175 return ISC_R_SUCCESS;
178 void tkey_free (ns_tsig_key **key)
181 dfree ((*key) -> data, MDL);
183 *key = (ns_tsig_key *)0;
187 isc_result_t enter_dns_zone (struct dns_zone *zone)
189 struct dns_zone *tz = (struct dns_zone *)0;
192 dns_zone_hash_lookup (&tz,
193 dns_zone_hash, zone -> name, 0, MDL);
195 dns_zone_dereference (&tz, MDL);
196 return ISC_R_SUCCESS;
199 dns_zone_hash_delete (dns_zone_hash,
200 zone -> name, 0, MDL);
201 dns_zone_dereference (&tz, MDL);
204 if (!dns_zone_new_hash (&dns_zone_hash, 1, MDL))
205 return ISC_R_NOMEMORY;
207 dns_zone_hash_add (dns_zone_hash, zone -> name, 0, zone, MDL);
208 return ISC_R_SUCCESS;
211 isc_result_t dns_zone_lookup (struct dns_zone **zone, const char *name)
213 struct dns_zone *tz = (struct dns_zone *)0;
215 char *tname = (char *)0;
219 return ISC_R_NOTFOUND;
222 if (name [len - 1] != '.') {
223 tname = dmalloc ((unsigned)len + 2, MDL);
225 return ISC_R_NOMEMORY;;
226 strcpy (tname, name);
231 if (!dns_zone_hash_lookup (zone, dns_zone_hash, name, 0, MDL))
232 status = ISC_R_NOTFOUND;
234 status = ISC_R_SUCCESS;
241 int dns_zone_dereference (ptr, file, line)
242 struct dns_zone **ptr;
247 struct dns_zone *dns_zone;
250 log_error ("%s(%d): null pointer", file, line);
251 #if defined (POINTER_DEBUG)
259 *ptr = (struct dns_zone *)0;
260 --dns_zone -> refcnt;
261 rc_register (file, line, ptr, dns_zone, dns_zone -> refcnt, 1, RC_MISC);
262 if (dns_zone -> refcnt > 0)
265 if (dns_zone -> refcnt < 0) {
266 log_error ("%s(%d): negative refcnt!", file, line);
267 #if defined (DEBUG_RC_HISTORY)
268 dump_rc_history (dns_zone);
270 #if defined (POINTER_DEBUG)
277 if (dns_zone -> name)
278 dfree (dns_zone -> name, file, line);
280 omapi_auth_key_dereference (&dns_zone -> key, file, line);
281 if (dns_zone -> primary)
282 option_cache_dereference (&dns_zone -> primary, file, line);
283 if (dns_zone -> secondary)
284 option_cache_dereference (&dns_zone -> secondary, file, line);
285 dfree (dns_zone, file, line);
289 #if defined (NSUPDATE)
290 isc_result_t find_cached_zone (const char *dname, ns_class class,
291 char *zname, size_t zsize,
292 struct in_addr *addrs,
293 int naddrs, int *naddrout,
294 struct dns_zone **zcookie)
296 isc_result_t status = ISC_R_NOTFOUND;
298 struct dns_zone *zone = (struct dns_zone *)0;
299 struct data_string nsaddrs;
302 /* The absence of the zcookie pointer indicates that we
303 succeeded previously, but the update itself failed, meaning
304 that we shouldn't use the cached zone. */
306 return ISC_R_NOTFOUND;
308 /* We can't look up a null zone. */
309 if (!dname || !*dname)
310 return ISC_R_INVALIDARG;
312 /* For each subzone, try to find a cached zone. */
313 for (np = dname; np; np = strchr (np, '.')) {
315 status = dns_zone_lookup (&zone, np);
316 if (status == ISC_R_SUCCESS)
320 if (status != ISC_R_SUCCESS)
323 /* Make sure the zone is valid. */
324 if (zone -> timeout && zone -> timeout < cur_time) {
325 dns_zone_dereference (&zone, MDL);
326 return ISC_R_CANCELED;
329 /* Make sure the zone name will fit. */
330 if (strlen (zone -> name) > zsize) {
331 dns_zone_dereference (&zone, MDL);
332 return ISC_R_NOSPACE;
334 strcpy (zname, zone -> name);
336 memset (&nsaddrs, 0, sizeof nsaddrs);
339 if (zone -> primary) {
340 if (evaluate_option_cache (&nsaddrs, (struct packet *)0,
342 (struct client_state *)0,
343 (struct option_state *)0,
344 (struct option_state *)0,
346 zone -> primary, MDL)) {
348 while (ix < naddrs) {
349 if (ip + 4 > nsaddrs.len)
351 memcpy (&addrs [ix], &nsaddrs.data [ip], 4);
355 data_string_forget (&nsaddrs, MDL);
358 if (zone -> secondary) {
359 if (evaluate_option_cache (&nsaddrs, (struct packet *)0,
361 (struct client_state *)0,
362 (struct option_state *)0,
363 (struct option_state *)0,
365 zone -> secondary, MDL)) {
367 while (ix < naddrs) {
368 if (ip + 4 > nsaddrs.len)
370 memcpy (&addrs [ix], &nsaddrs.data [ip], 4);
374 data_string_forget (&nsaddrs, MDL);
378 /* It's not an error for zcookie to have a value here - actually,
379 it's quite likely, because res_nupdate cycles through all the
380 names in the update looking for their zones. */
382 dns_zone_reference (zcookie, zone, MDL);
383 dns_zone_dereference (&zone, MDL);
386 return ISC_R_SUCCESS;
389 void forget_zone (struct dns_zone **zone)
391 dns_zone_dereference (zone, MDL);
394 void repudiate_zone (struct dns_zone **zone)
396 /* XXX Currently we're not differentiating between a cached
397 XXX zone and a zone that's been repudiated, which means
398 XXX that if we reap cached zones, we blow away repudiated
399 XXX zones. This isn't a big problem since we're not yet
400 XXX caching zones... :'} */
402 (*zone) -> timeout = cur_time - 1;
403 dns_zone_dereference (zone, MDL);
406 void cache_found_zone (ns_class class,
407 char *zname, struct in_addr *addrs, int naddrs)
409 isc_result_t status = ISC_R_NOTFOUND;
410 struct dns_zone *zone = (struct dns_zone *)0;
411 struct data_string nsaddrs;
412 int ix = strlen (zname);
414 if (zname [ix - 1] == '.')
417 /* See if there's already such a zone. */
418 if (dns_zone_lookup (&zone, zname) == ISC_R_SUCCESS) {
419 /* If it's not a dynamic zone, leave it alone. */
420 if (!zone -> timeout)
422 /* Address may have changed, so just blow it away. */
424 option_cache_dereference (&zone -> primary, MDL);
425 if (zone -> secondary)
426 option_cache_dereference (&zone -> secondary, MDL);
427 } else if (!dns_zone_allocate (&zone, MDL))
432 dmalloc (strlen (zname) + 1 + (ix != 0), MDL);
434 dns_zone_dereference (&zone, MDL);
437 strcpy (zone -> name, zname);
438 /* Add a trailing '.' if it was missing. */
440 zone -> name [ix] = '.';
441 zone -> name [ix + 1] = 0;
445 /* XXX Need to get the lower-level code to push the actual zone
447 zone -> timeout = cur_time + 1800;
449 if (!option_cache_allocate (&zone -> primary, MDL)) {
450 dns_zone_dereference (&zone, MDL);
453 if (!buffer_allocate (&zone -> primary -> data.buffer,
454 naddrs * sizeof (struct in_addr), MDL)) {
455 dns_zone_dereference (&zone, MDL);
458 memcpy (zone -> primary -> data.buffer -> data,
459 addrs, naddrs * sizeof *addrs);
460 zone -> primary -> data.data =
461 &zone -> primary -> data.buffer -> data [0];
462 zone -> primary -> data.len = naddrs * sizeof *addrs;
464 enter_dns_zone (zone);
467 /* Have to use TXT records for now. */
468 #define T_DHCID T_TXT
470 int get_dhcid (struct data_string *id,
471 int type, const u_int8_t *data, unsigned len)
473 unsigned char buf[MD5_DIGEST_LENGTH];
477 /* Types can only be 0..(2^16)-1. */
478 if (type < 0 || type > 65535)
481 /* Hexadecimal MD5 digest plus two byte type and NUL. */
482 if (!buffer_allocate (&id -> buffer,
483 (MD5_DIGEST_LENGTH * 2) + 3, MDL))
485 id -> data = id -> buffer -> data;
488 * DHCP clients and servers should use the following forms of client
489 * identification, starting with the most preferable, and finishing
490 * with the least preferable. If the client does not send any of these
491 * forms of identification, the DHCP/DDNS interaction is not defined by
492 * this specification. The most preferable form of identification is
493 * the Globally Unique Identifier Option [TBD]. Next is the DHCP
494 * Client Identifier option. Last is the client's link-layer address,
495 * as conveyed in its DHCPREQUEST message. Implementors should note
496 * that the link-layer address cannot be used if there are no
497 * significant bytes in the chaddr field of the DHCP client's request,
498 * because this does not constitute a unique identifier.
499 * -- "Interaction between DHCP and DNS"
500 * <draft-ietf-dhc-dhcp-dns-12.txt>
501 * M. Stapp, Y. Rekhter
504 /* Put the type in the first two bytes. */
505 id -> buffer -> data [0] = "0123456789abcdef" [type >> 4];
506 id -> buffer -> data [1] = "0123456789abcdef" [type % 15];
508 /* Mash together an MD5 hash of the identifier. */
510 MD5_Update (&md5, data, len);
511 MD5_Final (buf, &md5);
513 /* Convert into ASCII. */
514 for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
515 id -> buffer -> data [i * 2 + 2] =
516 "0123456789abcdef" [(buf [i] >> 4) & 0xf];
517 id -> buffer -> data [i * 2 + 3] =
518 "0123456789abcdef" [buf [i] & 0xf];
520 id -> len = MD5_DIGEST_LENGTH * 2 + 2;
521 id -> buffer -> data [id -> len] = 0;
522 id -> terminated = 1;
527 /* Now for the DDNS update code that is shared between client and
530 isc_result_t ddns_update_a (struct data_string *ddns_fwd_name,
531 struct iaddr ddns_addr,
532 struct data_string *ddns_dhcid,
533 unsigned long ttl, int rrsetp)
538 char ddns_address [16];
540 if (ddns_addr.len != 4)
541 return ISC_R_INVALIDARG;
543 snprintf (ddns_address, 16, "%d.%d.%d.%d",
544 ddns_addr.iabuf[0], ddns_addr.iabuf[1],
545 ddns_addr.iabuf[2], ddns_addr.iabuf[3]);
547 sprintf (ddns_address, "%d.%d.%d.%d",
548 ddns_addr.iabuf[0], ddns_addr.iabuf[1],
549 ddns_addr.iabuf[2], ddns_addr.iabuf[3]);
553 * When a DHCP client or server intends to update an A RR, it first
554 * prepares a DNS UPDATE query which includes as a prerequisite the
555 * assertion that the name does not exist. The update section of the
556 * query attempts to add the new name and its IP address mapping (an A
557 * RR), and the DHCID RR with its unique client-identity.
558 * -- "Interaction between DHCP and DNS"
561 ISC_LIST_INIT (updqueue);
564 * A RR does not exist.
566 updrec = minires_mkupdrec (S_PREREQ,
567 (const char *)ddns_fwd_name -> data,
570 result = ISC_R_NOMEMORY;
574 updrec -> r_data = (unsigned char *)0;
575 updrec -> r_size = 0;
576 updrec -> r_opcode = rrsetp ? NXRRSET : NXDOMAIN;
578 ISC_LIST_APPEND (updqueue, updrec, r_link);
584 updrec = minires_mkupdrec (S_UPDATE,
585 (const char *)ddns_fwd_name -> data,
588 result = ISC_R_NOMEMORY;
592 updrec -> r_data = (unsigned char *)ddns_address;
593 updrec -> r_size = strlen (ddns_address);
594 updrec -> r_opcode = ADD;
596 ISC_LIST_APPEND (updqueue, updrec, r_link);
602 updrec = minires_mkupdrec (S_UPDATE,
603 (const char *)ddns_fwd_name -> data,
606 result = ISC_R_NOMEMORY;
610 updrec -> r_data = ddns_dhcid -> data;
611 updrec -> r_size = ddns_dhcid -> len;
612 updrec -> r_opcode = ADD;
614 ISC_LIST_APPEND (updqueue, updrec, r_link);
618 * Attempt to perform the update.
620 result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
622 #ifdef DEBUG_DNS_UPDATES
623 print_dns_status ((int)result, &updqueue);
627 * If this update operation succeeds, the updater can conclude that it
628 * has added a new name whose only RRs are the A and DHCID RR records.
629 * The A RR update is now complete (and a client updater is finished,
630 * while a server might proceed to perform a PTR RR update).
631 * -- "Interaction between DHCP and DNS"
634 if (result == ISC_R_SUCCESS) {
635 log_info ("Added new forward map from %.*s to %s",
636 (int)ddns_fwd_name -> len,
637 (const char *)ddns_fwd_name -> data, ddns_address);
643 * If the first update operation fails with YXDOMAIN, the updater can
644 * conclude that the intended name is in use. The updater then
645 * attempts to confirm that the DNS name is not being used by some
646 * other host. The updater prepares a second UPDATE query in which the
647 * prerequisite is that the desired name has attached to it a DHCID RR
648 * whose contents match the client identity. The update section of
649 * this query deletes the existing A records on the name, and adds the
650 * A record that matches the DHCP binding and the DHCID RR with the
652 * -- "Interaction between DHCP and DNS"
655 if (result != (rrsetp ? ISC_R_YXRRSET : ISC_R_YXDOMAIN)) {
656 log_error ("Unable to add forward map from %.*s to %s: %s",
657 (int)ddns_fwd_name -> len,
658 (const char *)ddns_fwd_name -> data, ddns_address,
659 isc_result_totext (result));
663 while (!ISC_LIST_EMPTY (updqueue)) {
664 updrec = ISC_LIST_HEAD (updqueue);
665 ISC_LIST_UNLINK (updqueue, updrec, r_link);
666 minires_freeupdrec (updrec);
670 * DHCID RR exists, and matches client identity.
672 updrec = minires_mkupdrec (S_PREREQ,
673 (const char *)ddns_fwd_name -> data,
676 result = ISC_R_NOMEMORY;
680 updrec -> r_data = ddns_dhcid -> data;
681 updrec -> r_size = ddns_dhcid -> len;
682 updrec -> r_opcode = YXRRSET;
684 ISC_LIST_APPEND (updqueue, updrec, r_link);
690 updrec = minires_mkupdrec (S_UPDATE,
691 (const char *)ddns_fwd_name -> data,
694 result = ISC_R_NOMEMORY;
698 updrec -> r_data = (unsigned char *)0;
699 updrec -> r_size = 0;
700 updrec -> r_opcode = DELETE;
702 ISC_LIST_APPEND (updqueue, updrec, r_link);
708 updrec = minires_mkupdrec (S_UPDATE,
709 (const char *)ddns_fwd_name -> data,
712 result = ISC_R_NOMEMORY;
716 updrec -> r_data = (unsigned char *)ddns_address;
717 updrec -> r_size = strlen (ddns_address);
718 updrec -> r_opcode = ADD;
720 ISC_LIST_APPEND (updqueue, updrec, r_link);
724 * Attempt to perform the update.
726 result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
728 if (result != ISC_R_SUCCESS) {
729 if (result == YXRRSET || result == YXDOMAIN ||
730 result == NXRRSET || result == NXDOMAIN)
731 log_error ("Forward map from %.*s to %s already in use",
732 (int)ddns_fwd_name -> len,
733 (const char *)ddns_fwd_name -> data,
736 log_error ("Can't update forward map %.*s to %s: %s",
737 (int)ddns_fwd_name -> len,
738 (const char *)ddns_fwd_name -> data,
739 ddns_address, isc_result_totext (result));
742 log_info ("Added new forward map from %.*s to %s",
743 (int)ddns_fwd_name -> len,
744 (const char *)ddns_fwd_name -> data, ddns_address);
746 #if defined (DEBUG_DNS_UPDATES)
747 print_dns_status ((int)result, &updqueue);
751 * If this query succeeds, the updater can conclude that the current
752 * client was the last client associated with the domain name, and that
753 * the name now contains the updated A RR. The A RR update is now
754 * complete (and a client updater is finished, while a server would
755 * then proceed to perform a PTR RR update).
756 * -- "Interaction between DHCP and DNS"
760 * If the second query fails with NXRRSET, the updater must conclude
761 * that the client's desired name is in use by another host. At this
762 * juncture, the updater can decide (based on some administrative
763 * configuration outside of the scope of this document) whether to let
764 * the existing owner of the name keep that name, and to (possibly)
765 * perform some name disambiguation operation on behalf of the current
766 * client, or to replace the RRs on the name with RRs that represent
767 * the current client. If the configured policy allows replacement of
768 * existing records, the updater submits a query that deletes the
769 * existing A RR and the existing DHCID RR, adding A and DHCID RRs that
770 * represent the IP address and client-identity of the new client.
771 * -- "Interaction between DHCP and DNS"
775 while (!ISC_LIST_EMPTY (updqueue)) {
776 updrec = ISC_LIST_HEAD (updqueue);
777 ISC_LIST_UNLINK (updqueue, updrec, r_link);
778 minires_freeupdrec (updrec);
784 isc_result_t ddns_remove_a (struct data_string *ddns_fwd_name,
785 struct iaddr ddns_addr,
786 struct data_string *ddns_dhcid)
790 isc_result_t result = SERVFAIL;
791 char ddns_address [16];
793 if (ddns_addr.len != 4)
794 return ISC_R_INVALIDARG;
797 snprintf (ddns_address, 16, "%d.%d.%d.%d",
798 ddns_addr.iabuf[0], ddns_addr.iabuf[1],
799 ddns_addr.iabuf[2], ddns_addr.iabuf[3]);
801 sprintf (ddns_address, "%d.%d.%d.%d",
802 ddns_addr.iabuf[0], ddns_addr.iabuf[1],
803 ddns_addr.iabuf[2], ddns_addr.iabuf[3]);
808 * The entity chosen to handle the A record for this client (either the
809 * client or the server) SHOULD delete the A record that was added when
810 * the lease was made to the client.
812 * In order to perform this delete, the updater prepares an UPDATE
813 * query which contains two prerequisites. The first prerequisite
814 * asserts that the DHCID RR exists whose data is the client identity
815 * described in Section 4.3. The second prerequisite asserts that the
816 * data in the A RR contains the IP address of the lease that has
817 * expired or been released.
818 * -- "Interaction between DHCP and DNS"
821 ISC_LIST_INIT (updqueue);
824 * DHCID RR exists, and matches client identity.
826 updrec = minires_mkupdrec (S_PREREQ,
827 (const char *)ddns_fwd_name -> data,
830 result = ISC_R_NOMEMORY;
834 updrec -> r_data = ddns_dhcid -> data;
835 updrec -> r_size = ddns_dhcid -> len;
836 updrec -> r_opcode = YXRRSET;
838 ISC_LIST_APPEND (updqueue, updrec, r_link);
842 * A RR matches the expiring lease.
844 updrec = minires_mkupdrec (S_PREREQ,
845 (const char *)ddns_fwd_name -> data,
848 result = ISC_R_NOMEMORY;
852 updrec -> r_data = (unsigned char *)ddns_address;
853 updrec -> r_size = strlen (ddns_address);
854 updrec -> r_opcode = YXRRSET;
856 ISC_LIST_APPEND (updqueue, updrec, r_link);
860 * Delete appropriate A RR.
862 updrec = minires_mkupdrec (S_UPDATE,
863 (const char *)ddns_fwd_name -> data,
866 result = ISC_R_NOMEMORY;
870 updrec -> r_data = (unsigned char *)ddns_address;
871 updrec -> r_size = strlen (ddns_address);
872 updrec -> r_opcode = DELETE;
874 ISC_LIST_APPEND (updqueue, updrec, r_link);
877 * Attempt to perform the update.
879 result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
880 print_dns_status ((int)result, &updqueue);
883 * If the query fails, the updater MUST NOT delete the DNS name. It
884 * may be that the host whose lease on the server has expired has moved
885 * to another network and obtained a lease from a different server,
886 * which has caused the client's A RR to be replaced. It may also be
887 * that some other client has been configured with a name that matches
888 * the name of the DHCP client, and the policy was that the last client
889 * to specify the name would get the name. In this case, the DHCID RR
890 * will no longer match the updater's notion of the client-identity of
891 * the host pointed to by the DNS name.
892 * -- "Interaction between DHCP and DNS"
895 if (result != ISC_R_SUCCESS) {
896 /* If the rrset isn't there, we didn't need to do the
897 delete, which is success. */
898 if (result == ISC_R_NXRRSET || result == ISC_R_NXDOMAIN)
899 result = ISC_R_SUCCESS;
903 while (!ISC_LIST_EMPTY (updqueue)) {
904 updrec = ISC_LIST_HEAD (updqueue);
905 ISC_LIST_UNLINK (updqueue, updrec, r_link);
906 minires_freeupdrec (updrec);
909 /* If the deletion of the A succeeded, and there are no A records
910 left for this domain, then we can blow away the DHCID record
911 as well. We can't blow away the DHCID record above because
912 it's possible that more than one A has been added to this
914 ISC_LIST_INIT (updqueue);
917 * A RR does not exist.
919 updrec = minires_mkupdrec (S_PREREQ,
920 (const char *)ddns_fwd_name -> data,
923 result = ISC_R_NOMEMORY;
927 updrec -> r_data = (unsigned char *)0;
928 updrec -> r_size = 0;
929 updrec -> r_opcode = NXRRSET;
931 ISC_LIST_APPEND (updqueue, updrec, r_link);
934 * Delete appropriate DHCID RR.
936 updrec = minires_mkupdrec (S_UPDATE,
937 (const char *)ddns_fwd_name -> data,
940 result = ISC_R_NOMEMORY;
944 updrec -> r_data = ddns_dhcid -> data;
945 updrec -> r_size = ddns_dhcid -> len;
946 updrec -> r_opcode = DELETE;
948 ISC_LIST_APPEND (updqueue, updrec, r_link);
951 * Attempt to perform the update.
953 result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
954 print_dns_status ((int)result, &updqueue);
959 while (!ISC_LIST_EMPTY (updqueue)) {
960 updrec = ISC_LIST_HEAD (updqueue);
961 ISC_LIST_UNLINK (updqueue, updrec, r_link);
962 minires_freeupdrec (updrec);
969 #endif /* NSUPDATE */
971 HASH_FUNCTIONS (dns_zone, const char *, struct dns_zone, dns_zone_hash_t,
972 dns_zone_reference, dns_zone_dereference)