3 Domain Name Service subroutines. */
6 * Copyright (c) 2009-2011 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 2001-2003 by Internet Software Consortium
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * Internet Systems Consortium, Inc.
24 * Redwood City, CA 94063
26 * https://www.isc.org/
28 * The original software was written for Internet Systems Consortium
29 * by Ted Lemon it has since been extensively modified to use the
30 * asynchronous DNS routines.
34 #include "arpa/nameser.h"
37 #include <dns/result.h>
40 * This file contains code to connect the DHCP code to the libdns modules.
41 * As part of that function it maintains a database of zone cuts that can
42 * be used to figure out which server should be contacted to update any
43 * given domain name. Included in the zone information may be a pointer
44 * to a key in which case that key is used for the update. If no zone
45 * is found then the DNS code determines the zone on its own.
47 * The way this works is that you define the domain name to which an
48 * SOA corresponds, and the addresses of some primaries for that domain name:
52 * secondary 10.0.22.1, 10.0.23.1;
56 * If an update is requested for GAZANGA.TOPANGA.FOO.COM, then the name
57 * server looks in its database for a zone record for "GAZANGA.TOPANGA.FOO.COM",
58 * doesn't find it, looks for one for "TOPANGA.FOO.COM", doesn't find *that*,
59 * looks for "FOO.COM", finds it. So it
60 * attempts the update to the primary for FOO.COM. If that times out, it
61 * tries the secondaries. You can list multiple primaries if you have some
62 * kind of magic name server that supports that. You shouldn't list
63 * secondaries that don't know how to forward updates (e.g., BIND 8 doesn't
64 * support update forwarding, AFAIK). If no TSIG key is listed, the update
65 * is attempted without TSIG.
67 * You can also include IPv6 addresses via the primary6 and secondary6
68 * options. The search order for the addresses is primary, primary6,
69 * secondary and lastly secondary6, with a limit on the number of
70 * addresses used. Currently this limit is 3.
72 * The DHCP server tries to find an existing zone for any given name by
73 * trying to look up a local zone structure for each domain containing
74 * that name, all the way up to '.'. If it finds one cached, it tries
75 * to use that one to do the update. That's why it tries to update
76 * "FOO.COM" above, even though theoretically it should try GAZANGA...
77 * and TOPANGA... first.
79 * If the update fails with a predefined zone the zone is marked as bad
80 * and another search of the predefined zones is done. If no predefined
81 * zone is found finding a zone is left to the DNS module via examination
82 * of SOA records. If the DNS module finds a zone it may cache the zone
83 * but the zone won't be cached here.
85 * TSIG updates are not performed on zones found by the DNS module - if
86 * you want TSIG updates you _must_ write a zone definition linking the
87 * key to the zone. In cases where you know for sure what the key is
88 * but do not want to hardcode the IP addresses of the primary or
89 * secondaries, a zone declaration can be made that doesn't include any
90 * primary or secondary declarations. When the DHCP server encounters
91 * this while hunting up a matching zone for a name, it looks up the SOA,
92 * fills in the IP addresses, and uses that record for the update.
93 * If the SOA lookup returns NXRRSET, a warning is printed and the zone is
94 * discarded, TSIG key and all. The search for the zone then continues
95 * as if the zone record hadn't been found. Zones without IP addresses
96 * don't match when initially hunting for a zone to update.
98 * When an update is attempted and no predefined zone is found
99 * that matches any enclosing domain of the domain being updated, the DHCP
100 * server goes through the same process that is done when the update to a
101 * predefined zone fails - starting with the most specific domain
102 * name (GAZANGA.TOPANGA.FOO.COM) and moving to the least specific (the root),
103 * it tries to look up an SOA record.
105 * TSIG keys are defined like this:
107 * key "FOO.COM Key" {
108 * algorithm HMAC-MD5.SIG-ALG.REG.INT;
112 * <Base64> is a number expressed in base64 that represents the key.
113 * It's also permissible to use a quoted string here - this will be
114 * translated as the ASCII bytes making up the string, and will not
115 * include any NUL termination. The key name can be any text string,
116 * and the key type must be one of the key types defined in the draft
117 * or by the IANA. Currently only the HMAC-MD5... key type is
120 * The DDNS processing has been split into two areas. One is the
121 * control code that determines what should be done. That code is found
122 * in the client or server directories. The other is the common code
123 * that performs functions such as properly formatting the arguments.
124 * That code is found in this file. The basic processing flow for a
126 * In the client or server code determine what needs to be done and
127 * collect the necesary information then pass it to a function from
129 * In this code lookup the zone and extract the zone and key information
130 * (if available) and prepare the arguments for the DNS module.
131 * When the DNS module completes its work (times out or gets a reply)
132 * it will trigger another function here which does generic processing
133 * and then passes control back to the code from the server or client.
134 * The server or client code then determines the next step which may
135 * result in another call to this module in which case the process repeats.
138 dns_zone_hash_t *dns_zone_hash;
141 * DHCP dns structures
142 * Normally the relationship between these structures isn't one to one
143 * but in the DHCP case it (mostly) is. To make the allocations, frees,
144 * and passing of the memory easier we make a single structure with all
147 * The maximum size of the data buffer should be large enough for any
148 * items DHCP will generate
151 typedef struct dhcp_ddns_rdata {
153 dns_rdatalist_t rdatalist;
154 dns_rdataset_t rdataset;
157 #if defined (NSUPDATE)
159 void ddns_interlude(isc_task_t *, isc_event_t *);
162 #if defined (TRACING)
164 * Code to support tracing DDNS packets. We trace packets going to and
165 * coming from the libdns code but don't try to track the packets
166 * exchanged between the libdns code and the dns server(s) it contacts.
168 * The code is split into two sets of routines
169 * input refers to messages received from the dns module
170 * output refers to messages sent to the dns module
171 * Currently there are three routines in each set
172 * write is used to write information about the message to the trace file
173 * this routine is called directly from the proper place in the code.
174 * read is used to read information about a message from the trace file
175 * this routine is called from the trace loop as it reads through
176 * the file and is registered via the trace_type_register routine.
177 * When playing back a trace file we shall absorb records of output
178 * messages as part of processing the write function, therefore
179 * any output messages we encounter are flagged as errors.
180 * stop isn't currently used in this code but is needed for the register
183 * We pass a pointer to a control block to the dns module which it returns
184 * to use as part of the result. As the pointer may vary between traces
185 * we need to map between those from the trace file and the new ones during
188 * The mapping is complicated a little as a pointer could be 4 or 8 bytes
189 * long. We treat the old pointer as an 8 byte quantity and pad and compare
194 * Structure used to map old pointers to new pointers.
195 * Old pointers are 8 bytes long as we don't know if the trace was
196 * done on a 64 bit or 32 bit machine.
198 #define TRACE_PTR_LEN 8
200 typedef struct dhcp_ddns_map {
201 char old_pointer[TRACE_PTR_LEN];
203 struct dhcp_ddns_map *next;
206 /* The starting point for the map structure */
207 static dhcp_ddns_map_t *ddns_map;
209 trace_type_t *trace_ddns_input;
210 trace_type_t *trace_ddns_output;
213 * The data written to the trace file is:
214 * 32 bits result from dns
215 * 64 bits pointer of cb
219 trace_ddns_input_write(dhcp_ddns_cb_t *ddns_cb, isc_result_t result)
222 u_int32_t old_result;
223 char old_pointer[TRACE_PTR_LEN];
225 old_result = htonl((u_int32_t)result);
226 memset(old_pointer, 0, TRACE_PTR_LEN);
227 memcpy(old_pointer, &ddns_cb, sizeof(ddns_cb));
229 iov[0].len = sizeof(old_result);
230 iov[0].buf = (char *)&old_result;
231 iov[1].len = TRACE_PTR_LEN;
232 iov[1].buf = old_pointer;
233 trace_write_packet_iov(trace_ddns_input, 2, iov, MDL);
237 * Process the result and pointer from the trace file.
238 * We use the pointer map to find the proper pointer for this instance.
239 * Then we need to construct an event to pass along to the interlude
243 trace_ddns_input_read(trace_type_t *ttype, unsigned length,
246 u_int32_t old_result;
247 char old_pointer[TRACE_PTR_LEN];
248 dns_clientupdateevent_t *eventp;
250 dhcp_ddns_map_t *ddns_map_ptr;
252 if (length < (sizeof(old_result) + TRACE_PTR_LEN)) {
253 log_error("trace_ddns_input_read: data too short");
257 memcpy(&old_result, buf, sizeof(old_result));
258 memcpy(old_pointer, buf + sizeof(old_result), TRACE_PTR_LEN);
260 /* map the old pointer to a new pointer */
261 for (ddns_map_ptr = ddns_map;
262 ddns_map_ptr != NULL;
263 ddns_map_ptr = ddns_map_ptr->next) {
264 if ((ddns_map_ptr->new_pointer != NULL) &&
265 memcmp(ddns_map_ptr->old_pointer,
266 old_pointer, TRACE_PTR_LEN) == 0) {
267 new_pointer = ddns_map_ptr->new_pointer;
268 ddns_map_ptr->new_pointer = NULL;
269 memset(ddns_map_ptr->old_pointer, 0, TRACE_PTR_LEN);
273 if (ddns_map_ptr == NULL) {
274 log_error("trace_dns_input_read: unable to map cb pointer");
278 eventp = (dns_clientupdateevent_t *)
279 isc_event_allocate(dhcp_gbl_ctx.mctx,
284 sizeof(dns_clientupdateevent_t));
285 if (eventp == NULL) {
286 log_error("trace_ddns_input_read: unable to allocate event");
289 eventp->result = ntohl(old_result);
292 ddns_interlude(dhcp_gbl_ctx.task, (isc_event_t *)eventp);
298 trace_ddns_input_stop(trace_type_t *ttype)
303 * We use the same arguments as for the dns startupdate function to
304 * allows us to choose between the two via a macro. If tracing isn't
305 * in use we simply call the dns function directly.
307 * If we are doing playback we read the next packet from the file
308 * and compare the type. If it matches we extract the results and pointer
309 * from the trace file. The results are returned to the caller as if
310 * they had called the dns routine. The pointer is used to construct a
311 * map for when the "reply" is processed.
313 * The data written to trace file is:
315 * 64 bits pointer of cb (DDNS Control block)
320 trace_ddns_output_write(dns_client_t *client, dns_rdataclass_t rdclass,
321 dns_name_t *zonename, dns_namelist_t *prerequisites,
322 dns_namelist_t *updates, isc_sockaddrlist_t *servers,
323 dns_tsec_t *tsec, unsigned int options,
324 isc_task_t *task, isc_taskaction_t action, void *arg,
325 dns_clientupdatetrans_t **transp)
328 u_int32_t old_result;
329 char old_pointer[TRACE_PTR_LEN];
330 dhcp_ddns_map_t *ddns_map_ptr;
332 if (trace_playback() != 0) {
333 /* We are doing playback, extract the entry from the file */
337 result = trace_get_packet(&trace_ddns_output,
339 if (result != ISC_R_SUCCESS) {
340 log_error("trace_ddns_output_write: no input found");
341 return (ISC_R_FAILURE);
343 if (buflen < (sizeof(old_result) + TRACE_PTR_LEN)) {
344 log_error("trace_ddns_output_write: data too short");
346 return (ISC_R_FAILURE);
348 memcpy(&old_result, inbuf, sizeof(old_result));
349 result = ntohl(old_result);
350 memcpy(old_pointer, inbuf + sizeof(old_result), TRACE_PTR_LEN);
353 /* add the pointer to the pointer map */
354 for (ddns_map_ptr = ddns_map;
355 ddns_map_ptr != NULL;
356 ddns_map_ptr = ddns_map_ptr->next) {
357 if (ddns_map_ptr->new_pointer == NULL) {
363 * If we didn't find an empty entry, allocate an entry and
364 * link it into the list. The list isn't ordered.
366 if (ddns_map_ptr == NULL) {
367 ddns_map_ptr = dmalloc(sizeof(*ddns_map_ptr), MDL);
368 if (ddns_map_ptr == NULL) {
369 log_error("trace_ddns_output_write: "
370 "unable to allocate map entry");
371 return(ISC_R_FAILURE);
373 ddns_map_ptr->next = ddns_map;
374 ddns_map = ddns_map_ptr;
377 memcpy(ddns_map_ptr->old_pointer, old_pointer, TRACE_PTR_LEN);
378 ddns_map_ptr->new_pointer = arg;
381 /* We aren't doing playback, make the actual call */
382 result = dns_client_startupdate(client, rdclass, zonename,
383 prerequisites, updates,
384 servers, tsec, options,
385 task, action, arg, transp);
388 if (trace_record() != 0) {
389 /* We are recording, save the information to the file */
391 old_result = htonl((u_int32_t)result);
392 memset(old_pointer, 0, TRACE_PTR_LEN);
393 memcpy(old_pointer, &arg, sizeof(arg));
394 iov[0].len = sizeof(old_result);
395 iov[0].buf = (char *)&old_result;
396 iov[1].len = TRACE_PTR_LEN;
397 iov[1].buf = old_pointer;
399 /* Write out the entire cb, in case we want to look at it */
400 iov[2].len = sizeof(dhcp_ddns_cb_t);
401 iov[2].buf = (char *)arg;
403 trace_write_packet_iov(trace_ddns_output, 3, iov, MDL);
410 trace_ddns_output_read(trace_type_t *ttype, unsigned length,
413 log_error("unaccounted for ddns output.");
417 trace_ddns_output_stop(trace_type_t *ttype)
424 trace_ddns_output = trace_type_register("ddns-output", NULL,
425 trace_ddns_output_read,
426 trace_ddns_output_stop, MDL);
427 trace_ddns_input = trace_type_register("ddns-input", NULL,
428 trace_ddns_input_read,
429 trace_ddns_input_stop, MDL);
433 #define ddns_update trace_ddns_output_write
435 #define ddns_update dns_client_startupdate
439 * Code to allocate and free a dddns control block. This block is used
440 * to pass and track the information associated with a DDNS update request.
443 ddns_cb_alloc(const char *file, int line)
445 dhcp_ddns_cb_t *ddns_cb;
448 ddns_cb = dmalloc(sizeof(*ddns_cb), file, line);
449 if (ddns_cb != NULL) {
450 ISC_LIST_INIT(ddns_cb->zone_server_list);
451 for (i = 0; i < DHCP_MAXNS; i++) {
452 ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link);
456 #if defined (DEBUG_DNS_UPDATES)
457 log_info("%s(%d): Allocating ddns_cb=%p", file, line, ddns_cb);
464 ddns_cb_free(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
466 #if defined (DEBUG_DNS_UPDATES)
467 log_info("%s(%d): freeing ddns_cb=%p", file, line, ddns_cb);
470 data_string_forget(&ddns_cb->fwd_name, file, line);
471 data_string_forget(&ddns_cb->rev_name, file, line);
472 data_string_forget(&ddns_cb->dhcid, file, line);
474 if (ddns_cb->zone != NULL) {
475 forget_zone((struct dns_zone **)&ddns_cb->zone);
478 /* Should be freed by now, check just in case. */
479 if (ddns_cb->transaction != NULL)
480 log_error("Impossible memory leak at %s:%d (attempt to free "
481 "DDNS Control Block before transaction).", MDL);
483 dfree(ddns_cb, file, line);
487 ddns_cb_forget_zone(dhcp_ddns_cb_t *ddns_cb)
491 forget_zone(&ddns_cb->zone);
492 ddns_cb->zone_name[0] = 0;
493 ISC_LIST_INIT(ddns_cb->zone_server_list);
494 for (i = 0; i < DHCP_MAXNS; i++) {
495 ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link);
499 isc_result_t find_tsig_key (ns_tsig_key **key, const char *zname,
500 struct dns_zone *zone)
505 return ISC_R_NOTFOUND;
508 return DHCP_R_KEY_UNKNOWN;
511 if ((!zone -> key -> name ||
512 strlen (zone -> key -> name) > NS_MAXDNAME) ||
513 (!zone -> key -> algorithm ||
514 strlen (zone -> key -> algorithm) > NS_MAXDNAME) ||
516 (!zone -> key -> key) ||
517 (zone -> key -> key -> len == 0)) {
518 return DHCP_R_INVALIDKEY;
520 tkey = dmalloc (sizeof *tkey, MDL);
523 return ISC_R_NOMEMORY;
525 memset (tkey, 0, sizeof *tkey);
526 tkey -> data = dmalloc (zone -> key -> key -> len, MDL);
531 strcpy (tkey -> name, zone -> key -> name);
532 strcpy (tkey -> alg, zone -> key -> algorithm);
533 memcpy (tkey -> data,
534 zone -> key -> key -> value, zone -> key -> key -> len);
535 tkey -> len = zone -> key -> key -> len;
537 return ISC_R_SUCCESS;
540 void tkey_free (ns_tsig_key **key)
543 dfree ((*key) -> data, MDL);
545 *key = (ns_tsig_key *)0;
549 isc_result_t enter_dns_zone (struct dns_zone *zone)
551 struct dns_zone *tz = (struct dns_zone *)0;
554 dns_zone_hash_lookup (&tz,
555 dns_zone_hash, zone -> name, 0, MDL);
557 dns_zone_dereference (&tz, MDL);
558 return ISC_R_SUCCESS;
561 dns_zone_hash_delete (dns_zone_hash,
562 zone -> name, 0, MDL);
563 dns_zone_dereference (&tz, MDL);
566 if (!dns_zone_new_hash(&dns_zone_hash, DNS_HASH_SIZE, MDL))
567 return ISC_R_NOMEMORY;
570 dns_zone_hash_add (dns_zone_hash, zone -> name, 0, zone, MDL);
571 return ISC_R_SUCCESS;
574 isc_result_t dns_zone_lookup (struct dns_zone **zone, const char *name)
577 char *tname = (char *)0;
581 return ISC_R_NOTFOUND;
584 if (name [len - 1] != '.') {
585 tname = dmalloc ((unsigned)len + 2, MDL);
587 return ISC_R_NOMEMORY;
588 strcpy (tname, name);
593 if (!dns_zone_hash_lookup (zone, dns_zone_hash, name, 0, MDL))
594 status = ISC_R_NOTFOUND;
596 status = ISC_R_SUCCESS;
603 int dns_zone_dereference (ptr, file, line)
604 struct dns_zone **ptr;
608 struct dns_zone *dns_zone;
610 if ((ptr == NULL) || (*ptr == NULL)) {
611 log_error("%s(%d): null pointer", file, line);
612 #if defined (POINTER_DEBUG)
622 rc_register(file, line, ptr, dns_zone, dns_zone->refcnt, 1, RC_MISC);
623 if (dns_zone->refcnt > 0)
626 if (dns_zone->refcnt < 0) {
627 log_error("%s(%d): negative refcnt!", file, line);
628 #if defined (DEBUG_RC_HISTORY)
629 dump_rc_history(dns_zone);
631 #if defined (POINTER_DEBUG)
639 dfree(dns_zone->name, file, line);
641 omapi_auth_key_dereference(&dns_zone->key, file, line);
642 if (dns_zone->primary)
643 option_cache_dereference(&dns_zone->primary, file, line);
644 if (dns_zone->secondary)
645 option_cache_dereference(&dns_zone->secondary, file, line);
646 if (dns_zone->primary6)
647 option_cache_dereference(&dns_zone->primary6, file, line);
648 if (dns_zone->secondary6)
649 option_cache_dereference(&dns_zone->secondary6, file, line);
650 dfree(dns_zone, file, line);
654 #if defined (NSUPDATE)
656 find_cached_zone(dhcp_ddns_cb_t *ddns_cb, int direction)
658 isc_result_t status = ISC_R_NOTFOUND;
660 struct dns_zone *zone = NULL;
661 struct data_string nsaddrs;
662 struct in_addr zone_addr;
663 struct in6_addr zone_addr6;
666 if (direction == FIND_FORWARD) {
667 np = (const char *)ddns_cb->fwd_name.data;
669 np = (const char *)ddns_cb->rev_name.data;
672 /* We can't look up a null zone. */
673 if ((np == NULL) || (*np == '\0')) {
674 return (DHCP_R_INVALIDARG);
678 * For each subzone, try to find a cached zone.
681 status = dns_zone_lookup(&zone, np);
682 if (status == ISC_R_SUCCESS)
685 np = strchr(np, '.');
691 if (status != ISC_R_SUCCESS)
694 /* Make sure the zone is valid. */
695 if (zone->timeout && zone->timeout < cur_time) {
696 dns_zone_dereference(&zone, MDL);
697 return (ISC_R_CANCELED);
700 /* Make sure the zone name will fit. */
701 if (strlen(zone->name) > sizeof(ddns_cb->zone_name)) {
702 dns_zone_dereference(&zone, MDL);
703 return (ISC_R_NOSPACE);
705 strcpy((char *)&ddns_cb->zone_name[0], zone->name);
707 memset (&nsaddrs, 0, sizeof nsaddrs);
711 if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
712 NULL, NULL, &global_scope,
713 zone->primary, MDL)) {
715 while (ix < DHCP_MAXNS) {
716 if (ip + 4 > nsaddrs.len)
718 memcpy(&zone_addr, &nsaddrs.data[ip], 4);
719 isc_sockaddr_fromin(&ddns_cb->zone_addrs[ix],
722 ISC_LIST_APPEND(ddns_cb->zone_server_list,
723 &ddns_cb->zone_addrs[ix],
728 data_string_forget(&nsaddrs, MDL);
732 if (zone->primary6) {
733 if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
734 NULL, NULL, &global_scope,
735 zone->primary6, MDL)) {
737 while (ix < DHCP_MAXNS) {
738 if (ip + 16 > nsaddrs.len)
740 memcpy(&zone_addr6, &nsaddrs.data[ip], 16);
741 isc_sockaddr_fromin6(&ddns_cb->zone_addrs[ix],
744 ISC_LIST_APPEND(ddns_cb->zone_server_list,
745 &ddns_cb->zone_addrs[ix],
750 data_string_forget(&nsaddrs, MDL);
754 if (zone->secondary) {
755 if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
756 NULL, NULL, &global_scope,
757 zone->secondary, MDL)) {
759 while (ix < DHCP_MAXNS) {
760 if (ip + 4 > nsaddrs.len)
762 memcpy(&zone_addr, &nsaddrs.data[ip], 4);
763 isc_sockaddr_fromin(&ddns_cb->zone_addrs[ix],
766 ISC_LIST_APPEND(ddns_cb->zone_server_list,
767 &ddns_cb->zone_addrs[ix],
772 data_string_forget (&nsaddrs, MDL);
776 if (zone->secondary6) {
777 if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
778 NULL, NULL, &global_scope,
779 zone->secondary6, MDL)) {
781 while (ix < DHCP_MAXNS) {
782 if (ip + 16 > nsaddrs.len)
784 memcpy(&zone_addr6, &nsaddrs.data[ip], 16);
785 isc_sockaddr_fromin6(&ddns_cb->zone_addrs[ix],
788 ISC_LIST_APPEND(ddns_cb->zone_server_list,
789 &ddns_cb->zone_addrs[ix],
794 data_string_forget (&nsaddrs, MDL);
798 dns_zone_reference(&ddns_cb->zone, zone, MDL);
799 dns_zone_dereference (&zone, MDL);
800 return ISC_R_SUCCESS;
803 void forget_zone (struct dns_zone **zone)
805 dns_zone_dereference (zone, MDL);
808 void repudiate_zone (struct dns_zone **zone)
810 /* XXX Currently we're not differentiating between a cached
811 XXX zone and a zone that's been repudiated, which means
812 XXX that if we reap cached zones, we blow away repudiated
813 XXX zones. This isn't a big problem since we're not yet
814 XXX caching zones... :'} */
816 (*zone) -> timeout = cur_time - 1;
817 dns_zone_dereference (zone, MDL);
820 /* Have to use TXT records for now. */
821 #define T_DHCID T_TXT
823 int get_dhcid (struct data_string *id,
824 int type, const u_int8_t *data, unsigned len)
826 unsigned char buf[ISC_MD5_DIGESTLENGTH];
830 /* Types can only be 0..(2^16)-1. */
831 if (type < 0 || type > 65535)
835 * Hexadecimal MD5 digest plus two byte type, NUL,
836 * and one byte for length for dns.
838 if (!buffer_allocate (&id -> buffer,
839 (ISC_MD5_DIGESTLENGTH * 2) + 4, MDL))
841 id -> data = id -> buffer -> data;
844 * DHCP clients and servers should use the following forms of client
845 * identification, starting with the most preferable, and finishing
846 * with the least preferable. If the client does not send any of these
847 * forms of identification, the DHCP/DDNS interaction is not defined by
848 * this specification. The most preferable form of identification is
849 * the Globally Unique Identifier Option [TBD]. Next is the DHCP
850 * Client Identifier option. Last is the client's link-layer address,
851 * as conveyed in its DHCPREQUEST message. Implementors should note
852 * that the link-layer address cannot be used if there are no
853 * significant bytes in the chaddr field of the DHCP client's request,
854 * because this does not constitute a unique identifier.
855 * -- "Interaction between DHCP and DNS"
856 * <draft-ietf-dhc-dhcp-dns-12.txt>
857 * M. Stapp, Y. Rekhter
859 * We put the length into the first byte to turn
860 * this into a dns text string. This avoid needing to
861 * copy the string to add the byte later.
863 id->buffer->data[0] = ISC_MD5_DIGESTLENGTH * 2 + 2;
865 /* Put the type in the next two bytes. */
866 id->buffer->data[1] = "0123456789abcdef"[(type >> 4) & 0xf];
867 /* This should have been [type & 0xf] but now that
868 * it is in use we need to leave it this way in order
869 * to avoid disturbing customer's lease files
871 id->buffer->data[2] = "0123456789abcdef"[type % 15];
873 /* Mash together an MD5 hash of the identifier. */
875 isc_md5_update(&md5, data, len);
876 isc_md5_final(&md5, buf);
878 /* Convert into ASCII. */
879 for (i = 0; i < ISC_MD5_DIGESTLENGTH; i++) {
880 id->buffer->data[i * 2 + 3] =
881 "0123456789abcdef"[(buf[i] >> 4) & 0xf];
882 id->buffer->data[i * 2 + 4] =
883 "0123456789abcdef"[buf[i] & 0xf];
886 id->len = ISC_MD5_DIGESTLENGTH * 2 + 3;
887 id->buffer->data[id->len] = 0;
894 * The dhcid (text version) that we pass to DNS includes a length byte
895 * at the start but the text we store in the lease doesn't include the
896 * length byte. The following routines are to convert between the two
899 * When converting from a dhcid to a leaseid we reuse the buffer and
900 * simply adjust the data pointer and length fields in the data string.
901 * This avoids any prolems with allocating space.
905 dhcid_tolease(struct data_string *dhcid,
906 struct data_string *leaseid)
908 /* copy the data string then update the fields */
909 data_string_copy(leaseid, dhcid, MDL);
915 dhcid_fromlease(struct data_string *dhcid,
916 struct data_string *leaseid)
918 if (!buffer_allocate(&dhcid->buffer, leaseid->len + 2, MDL)) {
919 return(ISC_R_FAILURE);
922 dhcid->data = dhcid->buffer->data;
924 dhcid->buffer->data[0] = leaseid->len;
925 memcpy(dhcid->buffer->data + 1, leaseid->data, leaseid->len);
926 dhcid->len = leaseid->len + 1;
927 if (leaseid->terminated == 1) {
928 dhcid->buffer->data[dhcid->len] = 0;
929 dhcid->terminated = 1;
932 return(ISC_R_SUCCESS);
936 * Construct the dataset for this item.
937 * This is a fairly simple arrangement as the operations we do are simple.
938 * If there is data we simply have the rdata point to it - the formatting
939 * must be correct already. We then link the rdatalist to the rdata and
940 * create a rdataset from the rdatalist.
944 make_dns_dataset(dns_rdataclass_t dataclass,
945 dns_rdatatype_t datatype,
946 dhcp_ddns_data_t *dataspace,
951 dns_rdata_t *rdata = &dataspace->rdata;
952 dns_rdatalist_t *rdatalist = &dataspace->rdatalist;
953 dns_rdataset_t *rdataset = &dataspace->rdataset;
957 /* set up the rdata */
958 dns_rdata_init(rdata);
961 /* No data, set up the rdata fields we care about */
962 rdata->flags = DNS_RDATA_UPDATE;
963 rdata->type = datatype;
964 rdata->rdclass = dataclass;
967 case dns_rdatatype_a:
968 case dns_rdatatype_aaaa:
969 case dns_rdatatype_txt:
970 case dns_rdatatype_dhcid:
971 case dns_rdatatype_ptr:
972 /* The data must be in the right format we simply
973 * need to supply it via the correct structure */
975 region.length = datalen;
976 dns_rdata_fromregion(rdata, dataclass, datatype,
980 return(DHCP_R_INVALIDARG);
985 /* setup the datalist and attach the rdata to it */
986 dns_rdatalist_init(rdatalist);
987 rdatalist->type = datatype;
988 rdatalist->rdclass = dataclass;
989 rdatalist->ttl = ttl;
990 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
992 /* convert the datalist to a dataset */
993 dns_rdataset_init(rdataset);
994 dns_rdatalist_tordataset(rdatalist, rdataset);
996 return(ISC_R_SUCCESS);
1000 * When a DHCP client or server intends to update an A RR, it first
1001 * prepares a DNS UPDATE query which includes as a prerequisite the
1002 * assertion that the name does not exist. The update section of the
1003 * query attempts to add the new name and its IP address mapping (an A
1004 * RR), and the DHCID RR with its unique client-identity.
1005 * -- "Interaction between DHCP and DNS"
1007 * There are two cases, one for the server and one for the client.
1009 * For the server the first step will have a request of:
1010 * The name is not in use
1012 * Add a DHCID RR (currently txt)
1014 * For the client the first step will have a request of:
1015 * The A RR does not exist
1017 * Add a DHCID RR (currently txt)
1021 ddns_modify_fwd_add1(dhcp_ddns_cb_t *ddns_cb,
1022 dhcp_ddns_data_t *dataspace,
1026 isc_result_t result;
1028 /* Construct the prerequisite list */
1029 if ((ddns_cb->flags & DDNS_INCLUDE_RRSET) != 0) {
1030 /* The A RR shouldn't exist */
1031 result = make_dns_dataset(dns_rdataclass_none,
1032 ddns_cb->address_type,
1033 dataspace, NULL, 0, 0);
1035 /* The name is not in use */
1036 result = make_dns_dataset(dns_rdataclass_none,
1038 dataspace, NULL, 0, 0);
1040 if (result != ISC_R_SUCCESS) {
1043 ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1046 /* Construct the update list */
1048 result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type,
1050 (unsigned char *)ddns_cb->address.iabuf,
1051 ddns_cb->address.len, ddns_cb->ttl);
1052 if (result != ISC_R_SUCCESS) {
1055 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1058 /* Add the DHCID RR */
1059 result = make_dns_dataset(dns_rdataclass_in, dns_rdatatype_txt,
1061 (unsigned char *)ddns_cb->dhcid.data,
1062 ddns_cb->dhcid.len, ddns_cb->ttl);
1063 if (result != ISC_R_SUCCESS) {
1066 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1068 return(ISC_R_SUCCESS);
1072 * If the first update operation fails with YXDOMAIN, the updater can
1073 * conclude that the intended name is in use. The updater then
1074 * attempts to confirm that the DNS name is not being used by some
1075 * other host. The updater prepares a second UPDATE query in which the
1076 * prerequisite is that the desired name has attached to it a DHCID RR
1077 * whose contents match the client identity. The update section of
1078 * this query deletes the existing A records on the name, and adds the
1079 * A record that matches the DHCP binding and the DHCID RR with the
1081 * -- "Interaction between DHCP and DNS"
1083 * The message for the second step depends on if we are doing conflict
1084 * resolution. If we are we include a prerequisite. If not we delete
1085 * the DHCID in addition to all A rrsets.
1087 * Conflict resolution:
1088 * DHCID RR exists, and matches client identity.
1092 * Conflict override:
1100 ddns_modify_fwd_add2(dhcp_ddns_cb_t *ddns_cb,
1101 dhcp_ddns_data_t *dataspace,
1105 isc_result_t result;
1108 * If we are doing conflict resolution (unset) we use a prereq list.
1109 * If not we delete the DHCID in addition to all A rrsets.
1111 if ((ddns_cb->flags & DDNS_CONFLICT_OVERRIDE) == 0) {
1112 /* Construct the prereq list */
1113 /* The DHCID RR exists and matches the client identity */
1114 result = make_dns_dataset(dns_rdataclass_in, dns_rdatatype_txt,
1116 (unsigned char *)ddns_cb->dhcid.data,
1117 ddns_cb->dhcid.len, 0);
1118 if (result != ISC_R_SUCCESS) {
1121 ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1124 /* Start constructing the update list.
1125 * Conflict detection override: delete DHCID RRs */
1126 result = make_dns_dataset(dns_rdataclass_any,
1128 dataspace, NULL, 0, 0);
1129 if (result != ISC_R_SUCCESS) {
1132 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1135 /* Add current DHCID RR */
1136 result = make_dns_dataset(dns_rdataclass_in, dns_rdatatype_txt,
1138 (unsigned char *)ddns_cb->dhcid.data,
1139 ddns_cb->dhcid.len, ddns_cb->ttl);
1140 if (result != ISC_R_SUCCESS) {
1143 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1147 /* Start or continue constructing the update list */
1148 /* Delete the A RRset */
1149 result = make_dns_dataset(dns_rdataclass_any, ddns_cb->address_type,
1150 dataspace, NULL, 0, 0);
1151 if (result != ISC_R_SUCCESS) {
1154 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1158 result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type,
1160 (unsigned char *)ddns_cb->address.iabuf,
1161 ddns_cb->address.len, ddns_cb->ttl);
1162 if (result != ISC_R_SUCCESS) {
1165 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1167 return(ISC_R_SUCCESS);
1171 * The entity chosen to handle the A record for this client (either the
1172 * client or the server) SHOULD delete the A record that was added when
1173 * the lease was made to the client.
1175 * In order to perform this delete, the updater prepares an UPDATE
1176 * query which contains two prerequisites. The first prerequisite
1177 * asserts that the DHCID RR exists whose data is the client identity
1178 * described in Section 4.3. The second prerequisite asserts that the
1179 * data in the A RR contains the IP address of the lease that has
1180 * expired or been released.
1181 * -- "Interaction between DHCP and DNS"
1184 * DHCID RR exists, and matches client identity.
1185 * A RR matches the expiring lease.
1186 * Delete appropriate A RR.
1190 ddns_modify_fwd_rem1(dhcp_ddns_cb_t *ddns_cb,
1191 dhcp_ddns_data_t *dataspace,
1195 isc_result_t result;
1197 /* Consruct the prereq list */
1198 /* The DHCID RR exists and matches the client identity */
1199 result = make_dns_dataset(dns_rdataclass_in, dns_rdatatype_txt,
1201 (unsigned char *)ddns_cb->dhcid.data,
1202 ddns_cb->dhcid.len, 0);
1203 if (result != ISC_R_SUCCESS) {
1206 ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1209 /* The A RR matches the expiring lease */
1210 result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type,
1212 (unsigned char *)ddns_cb->address.iabuf,
1213 ddns_cb->address.len, 0);
1214 if (result != ISC_R_SUCCESS) {
1217 ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1220 /* Construct the update list */
1221 /* Delete A RRset */
1222 result = make_dns_dataset(dns_rdataclass_none, ddns_cb->address_type,
1224 (unsigned char *)ddns_cb->address.iabuf,
1225 ddns_cb->address.len, 0);
1226 if (result != ISC_R_SUCCESS) {
1229 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1231 return(ISC_R_SUCCESS);
1235 * If the deletion of the A succeeded, and there are no A or AAAA
1236 * records left for this domain, then we can blow away the DHCID
1237 * record as well. We can't blow away the DHCID record above
1238 * because it's possible that more than one record has been added
1239 * to this domain name.
1242 * A RR does not exist.
1243 * AAAA RR does not exist.
1244 * Delete appropriate DHCID RR.
1248 ddns_modify_fwd_rem2(dhcp_ddns_cb_t *ddns_cb,
1249 dhcp_ddns_data_t *dataspace,
1253 isc_result_t result;
1255 /* Construct the prereq list */
1256 /* The A RR does not exist */
1257 result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_a,
1258 dataspace, NULL, 0, 0);
1259 if (result != ISC_R_SUCCESS) {
1262 ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1265 /* The AAAA RR does not exist */
1266 result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_aaaa,
1267 dataspace, NULL, 0, 0);
1268 if (result != ISC_R_SUCCESS) {
1271 ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1274 /* Construct the update list */
1275 /* Delete DHCID RR */
1276 result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_txt,
1278 (unsigned char *)ddns_cb->dhcid.data,
1279 ddns_cb->dhcid.len, 0);
1280 if (result != ISC_R_SUCCESS) {
1283 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1285 return(ISC_R_SUCCESS);
1289 * This routine converts from the task action call into something
1290 * easier to work with. It also handles the common case of a signature
1291 * or zone not being correct.
1293 void ddns_interlude(isc_task_t *taskp,
1294 isc_event_t *eventp)
1296 dhcp_ddns_cb_t *ddns_cb = (dhcp_ddns_cb_t *)eventp->ev_arg;
1297 dns_clientupdateevent_t *ddns_event = (dns_clientupdateevent_t *)eventp;
1298 isc_result_t eresult = ddns_event->result;
1299 isc_result_t result;
1301 /* We've extracted the information we want from it, get rid of
1302 * the event block.*/
1303 isc_event_free(&eventp);
1305 #if defined (TRACING)
1306 if (trace_record()) {
1307 trace_ddns_input_write(ddns_cb, eresult);
1311 #if defined (DEBUG_DNS_UPDATES)
1312 print_dns_status(DDNS_PRINT_INBOUND, ddns_cb, eresult);
1315 /* This transaction is complete, clear the value */
1316 dns_client_destroyupdatetrans(&ddns_cb->transaction);
1318 /* If we cancelled or tried to cancel the operation we just
1319 * need to clean up. */
1320 if ((eresult == ISC_R_CANCELED) ||
1321 ((ddns_cb->flags & DDNS_ABORT) != 0)) {
1322 if (ddns_cb->next_op != NULL) {
1323 /* if necessary cleanup up next op block */
1324 ddns_cb_free(ddns_cb->next_op, MDL);
1326 ddns_cb_free(ddns_cb, MDL);
1330 /* If we had a problem with our key or zone try again */
1331 if ((eresult == DNS_R_NOTAUTH) ||
1332 (eresult == DNS_R_NOTZONE)) {
1334 /* Our zone information was questionable,
1335 * repudiate it and try again */
1336 repudiate_zone(&ddns_cb->zone);
1337 ddns_cb->zone_name[0] = 0;
1338 ISC_LIST_INIT(ddns_cb->zone_server_list);
1339 for (i = 0; i < DHCP_MAXNS; i++) {
1340 ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link);
1343 if ((ddns_cb->state &
1344 (DDNS_STATE_ADD_PTR | DDNS_STATE_REM_PTR)) != 0) {
1345 result = ddns_modify_ptr(ddns_cb);
1347 result = ddns_modify_fwd(ddns_cb);
1350 if (result != ISC_R_SUCCESS) {
1351 /* if we couldn't redo the query toss it */
1352 if (ddns_cb->next_op != NULL) {
1353 /* cleanup up next op block */
1354 ddns_cb_free(ddns_cb->next_op, MDL);
1356 ddns_cb_free(ddns_cb, MDL);
1360 /* pass it along to be processed */
1361 ddns_cb->cur_func(ddns_cb, eresult);
1368 * This routine does the generic work for sending a ddns message to
1369 * modify the forward record (A or AAAA) and calls one of a set of
1370 * routines to build the specific message.
1374 ddns_modify_fwd(dhcp_ddns_cb_t *ddns_cb)
1376 isc_result_t result;
1377 dns_tsec_t *tsec_key = NULL;
1379 unsigned char *clientname;
1380 dhcp_ddns_data_t *dataspace = NULL;
1381 dns_namelist_t prereqlist, updatelist;
1382 dns_fixedname_t zname0, pname0, uname0;
1383 dns_name_t *zname = NULL, *pname, *uname;
1385 isc_sockaddrlist_t *zlist = NULL;
1387 /* Get a pointer to the clientname to make things easier. */
1388 clientname = (unsigned char *)ddns_cb->fwd_name.data;
1390 /* Extract and validate the type of the address. */
1391 if (ddns_cb->address.len == 4) {
1392 ddns_cb->address_type = dns_rdatatype_a;
1393 } else if (ddns_cb->address.len == 16) {
1394 ddns_cb->address_type = dns_rdatatype_aaaa;
1396 return DHCP_R_INVALIDARG;
1400 * If we already have a zone use it, otherwise try to lookup the
1401 * zone in our cache. If we find one we will have a pointer to
1402 * the zone that needs to be dereferenced when we are done with it.
1403 * If we don't find one that is okay we'll let the DNS code try and
1404 * find the information for us.
1407 if (ddns_cb->zone == NULL) {
1408 result = find_cached_zone(ddns_cb, FIND_FORWARD);
1412 * If we have a zone try to get any information we need
1413 * from it - name, addresses and the key. The address
1414 * and key may be empty the name can't be.
1416 if (ddns_cb->zone) {
1417 /* Set up the zone name for use by DNS */
1418 result = dhcp_isc_name(ddns_cb->zone_name, &zname0, &zname);
1419 if (result != ISC_R_SUCCESS) {
1420 log_error("Unable to build name for zone for "
1421 "fwd update: %s %s",
1423 isc_result_totext(result));
1427 if (!(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
1428 /* If we have any addresses get them */
1429 zlist = &ddns_cb->zone_server_list;
1433 if (ddns_cb->zone->key != NULL) {
1435 * Not having a key is fine, having a key
1436 * but not a tsec is odd so we warn the user.
1439 /* should we do the warning? */
1440 tsec_key = ddns_cb->zone->key->tsec_key;
1441 if (tsec_key == NULL) {
1442 log_error("No tsec for use with key %s",
1443 ddns_cb->zone->key->name);
1448 /* Set up the DNS names for the prereq and update lists */
1449 if (((result = dhcp_isc_name(clientname, &pname0, &pname))
1450 != ISC_R_SUCCESS) ||
1451 ((result = dhcp_isc_name(clientname, &uname0, &uname))
1452 != ISC_R_SUCCESS)) {
1453 log_error("Unable to build name for fwd update: %s %s",
1454 clientname, isc_result_totext(result));
1458 /* Allocate the various isc dns library structures we may require. */
1459 dataspace = isc_mem_get(dhcp_gbl_ctx.mctx, sizeof(*dataspace) * 4);
1460 if (dataspace == NULL) {
1461 log_error("Unable to allocate memory for fwd update");
1462 result = ISC_R_NOMEMORY;
1466 ISC_LIST_INIT(prereqlist);
1467 ISC_LIST_INIT(updatelist);
1469 switch(ddns_cb->state) {
1470 case DDNS_STATE_ADD_FW_NXDOMAIN:
1471 result = ddns_modify_fwd_add1(ddns_cb, dataspace,
1473 if (result != ISC_R_SUCCESS) {
1476 ISC_LIST_APPEND(prereqlist, pname, link);
1478 case DDNS_STATE_ADD_FW_YXDHCID:
1479 result = ddns_modify_fwd_add2(ddns_cb, dataspace,
1481 if (result != ISC_R_SUCCESS) {
1485 /* If we aren't doing conflict override we have entries
1486 * in the pname list and we need to attach it to the
1489 if ((ddns_cb->flags & DDNS_CONFLICT_OVERRIDE) == 0) {
1490 ISC_LIST_APPEND(prereqlist, pname, link);
1494 case DDNS_STATE_REM_FW_YXDHCID:
1495 result = ddns_modify_fwd_rem1(ddns_cb, dataspace,
1497 if (result != ISC_R_SUCCESS) {
1500 ISC_LIST_APPEND(prereqlist, pname, link);
1502 case DDNS_STATE_REM_FW_NXRR:
1503 result = ddns_modify_fwd_rem2(ddns_cb, dataspace,
1505 if (result != ISC_R_SUCCESS) {
1508 ISC_LIST_APPEND(prereqlist, pname, link);
1512 log_error("Invalid operation in ddns code.");
1513 result = DHCP_R_INVALIDARG;
1519 * We always have an update list but may not have a prereqlist
1520 * if we are doing conflict override.
1522 ISC_LIST_APPEND(updatelist, uname, link);
1524 /* send the message, cleanup and return the result */
1525 result = ddns_update(dhcp_gbl_ctx.dnsclient,
1526 dns_rdataclass_in, zname,
1527 &prereqlist, &updatelist,
1529 DNS_CLIENTRESOPT_ALLOWRUN,
1533 &ddns_cb->transaction);
1534 if (result == ISC_R_FAMILYNOSUPPORT) {
1535 log_info("Unable to perform DDNS update, "
1536 "address family not supported");
1539 #if defined (DEBUG_DNS_UPDATES)
1540 print_dns_status(DDNS_PRINT_OUTBOUND, ddns_cb, result);
1544 if (dataspace != NULL) {
1545 isc_mem_put(dhcp_gbl_ctx.mctx, dataspace,
1546 sizeof(*dataspace) * 4);
1553 ddns_modify_ptr(dhcp_ddns_cb_t *ddns_cb)
1555 isc_result_t result;
1556 dns_tsec_t *tsec_key = NULL;
1557 unsigned char *ptrname;
1558 dhcp_ddns_data_t *dataspace = NULL;
1559 dns_namelist_t updatelist;
1560 dns_fixedname_t zname0, uname0;
1561 dns_name_t *zname = NULL, *uname;
1562 isc_sockaddrlist_t *zlist = NULL;
1563 unsigned char buf[256];
1567 * Try to lookup the zone in the zone cache. As with the forward
1568 * case it's okay if we don't have one, the DNS code will try to
1569 * find something also if we succeed we will need to dereference
1570 * the zone later. Unlike with the forward case we assume we won't
1571 * have a pre-existing zone.
1573 result = find_cached_zone(ddns_cb, FIND_REVERSE);
1574 if ((result == ISC_R_SUCCESS) &&
1575 !(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
1576 /* Set up the zone name for use by DNS */
1577 result = dhcp_isc_name(ddns_cb->zone_name, &zname0, &zname);
1578 if (result != ISC_R_SUCCESS) {
1579 log_error("Unable to build name for zone for "
1580 "fwd update: %s %s",
1582 isc_result_totext(result));
1585 /* If we have any addresses get them */
1586 if (!(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
1587 zlist = &ddns_cb->zone_server_list;
1591 * If we now have a zone try to get the key, NULL is okay,
1592 * having a key but not a tsec is odd so we warn.
1595 /* should we do the warning if we have a key but no tsec? */
1596 if ((ddns_cb->zone != NULL) && (ddns_cb->zone->key != NULL)) {
1597 tsec_key = ddns_cb->zone->key->tsec_key;
1598 if (tsec_key == NULL) {
1599 log_error("No tsec for use with key %s",
1600 ddns_cb->zone->key->name);
1605 /* We must have a name for the update list */
1606 /* Get a pointer to the ptrname to make things easier. */
1607 ptrname = (unsigned char *)ddns_cb->rev_name.data;
1609 if ((result = dhcp_isc_name(ptrname, &uname0, &uname))
1611 log_error("Unable to build name for fwd update: %s %s",
1612 ptrname, isc_result_totext(result));
1617 * Allocate the various isc dns library structures we may require.
1618 * Allocating one blob avoids being halfway through the process
1619 * and being unable to allocate as well as making the free easy.
1621 dataspace = isc_mem_get(dhcp_gbl_ctx.mctx, sizeof(*dataspace) * 2);
1622 if (dataspace == NULL) {
1623 log_error("Unable to allocate memory for fwd update");
1624 result = ISC_R_NOMEMORY;
1628 ISC_LIST_INIT(updatelist);
1631 * Construct the update list
1632 * We always delete what's currently there
1635 result = make_dns_dataset(dns_rdataclass_any, dns_rdatatype_ptr,
1636 &dataspace[0], NULL, 0, 0);
1637 if (result != ISC_R_SUCCESS) {
1640 ISC_LIST_APPEND(uname->list, &dataspace[0].rdataset, link);
1643 * If we are updating the pointer we then add the new one
1646 if (ddns_cb->state == DDNS_STATE_ADD_PTR) {
1649 * I've left this dead code in the file for now in case
1650 * we decide to try and get rid of the ns_name functions.
1655 * Need to convert pointer into on the wire representation
1656 * We replace the '.' characters with the lengths of the
1657 * next name and add a length to the beginning for the first
1660 if (ddns_cb->fwd_name.len == 1) {
1667 memcpy(&buf[1], ddns_cb->fwd_name.data,
1668 ddns_cb->fwd_name.len);
1669 for(cp = buf + ddns_cb->fwd_name.len, buflen = 0;
1680 buflen = ddns_cb->fwd_name.len + 1;
1684 * Need to convert pointer into on the wire representation
1686 if (MRns_name_pton((char *)ddns_cb->fwd_name.data,
1691 while (buf[buflen] != 0) {
1692 buflen += buf[buflen] + 1;
1696 result = make_dns_dataset(dns_rdataclass_in,
1699 buf, buflen, ddns_cb->ttl);
1700 if (result != ISC_R_SUCCESS) {
1703 ISC_LIST_APPEND(uname->list, &dataspace[1].rdataset, link);
1706 ISC_LIST_APPEND(updatelist, uname, link);
1710 * for now I'll cleanup the dataset immediately, it would be
1711 * more efficient to keep it around in case the signaturure failed
1712 * and we wanted to retry it.
1714 /* send the message, cleanup and return the result */
1715 result = ddns_update((dns_client_t *)dhcp_gbl_ctx.dnsclient,
1716 dns_rdataclass_in, zname,
1719 DNS_CLIENTRESOPT_ALLOWRUN,
1721 ddns_interlude, (void *)ddns_cb,
1722 &ddns_cb->transaction);
1723 if (result == ISC_R_FAMILYNOSUPPORT) {
1724 log_info("Unable to perform DDNS update, "
1725 "address family not supported");
1728 #if defined (DEBUG_DNS_UPDATES)
1729 print_dns_status(DDNS_PRINT_OUTBOUND, ddns_cb, result);
1733 if (dataspace != NULL) {
1734 isc_mem_put(dhcp_gbl_ctx.mctx, dataspace,
1735 sizeof(*dataspace) * 2);
1741 ddns_cancel(dhcp_ddns_cb_t *ddns_cb) {
1742 ddns_cb->flags |= DDNS_ABORT;
1743 if (ddns_cb->transaction != NULL) {
1744 dns_client_cancelupdate((dns_clientupdatetrans_t *)
1745 ddns_cb->transaction);
1747 ddns_cb->lease = NULL;
1750 #endif /* NSUPDATE */
1752 HASH_FUNCTIONS (dns_zone, const char *, struct dns_zone, dns_zone_hash_t,
1753 dns_zone_reference, dns_zone_dereference, do_case_hash)