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