common/dns.c

Go to the documentation of this file.
00001 /* dns.c
00002 
00003    Domain Name Service subroutines. */
00004 
00005 /*
00006  * Copyright (c) 2009-2014 by Internet Systems Consortium, Inc. ("ISC")
00007  * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
00008  * Copyright (c) 2001-2003 by Internet Software Consortium
00009  *
00010  * Permission to use, copy, modify, and distribute this software for any
00011  * purpose with or without fee is hereby granted, provided that the above
00012  * copyright notice and this permission notice appear in all copies.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00015  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00016  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00017  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00018  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00019  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00020  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00021  *
00022  *   Internet Systems Consortium, Inc.
00023  *   950 Charter Street
00024  *   Redwood City, CA 94063
00025  *   <info@isc.org>
00026  *   https://www.isc.org/
00027  *
00028  */
00029 
00032 #include "dhcpd.h"
00033 #include "arpa/nameser.h"
00034 #include <isc/md5.h>
00035 #include <isc/sha2.h>
00036 #include <dns/result.h>
00037 
00038 /*
00039  * This file contains code to connect the DHCP code to the libdns modules.
00040  * As part of that function it maintains a database of zone cuts that can
00041  * be used to figure out which server should be contacted to update any
00042  * given domain name.  Included in the zone information may be a pointer
00043  * to a key in which case that key is used for the update.  If no zone
00044  * is found then the DNS code determines the zone on its own.
00045  *
00046  * The way this works is that you define the domain name to which an
00047  * SOA corresponds, and the addresses of some primaries for that domain name:
00048  *
00049  *      zone FOO.COM {
00050  *        primary 10.0.17.1;
00051  *        secondary 10.0.22.1, 10.0.23.1;
00052  *        key "FOO.COM Key";
00053  *      }
00054  *
00055  * If an update is requested for GAZANGA.TOPANGA.FOO.COM, then the name
00056  * server looks in its database for a zone record for "GAZANGA.TOPANGA.FOO.COM",
00057  * doesn't find it, looks for one for "TOPANGA.FOO.COM", doesn't find *that*,
00058  * looks for "FOO.COM", finds it. So it
00059  * attempts the update to the primary for FOO.COM.   If that times out, it
00060  * tries the secondaries.   You can list multiple primaries if you have some
00061  * kind of magic name server that supports that.   You shouldn't list
00062  * secondaries that don't know how to forward updates (e.g., BIND 8 doesn't
00063  * support update forwarding, AFAIK).   If no TSIG key is listed, the update
00064  * is attempted without TSIG.
00065  *
00066  * You can also include IPv6 addresses via the primary6 and secondary6
00067  * options.  The search order for the addresses is primary, primary6,
00068  * secondary and lastly secondary6, with a limit on the number of 
00069  * addresses used.  Currently this limit is 3.
00070  *
00071  * The DHCP server tries to find an existing zone for any given name by
00072  * trying to look up a local zone structure for each domain containing
00073  * that name, all the way up to '.'.   If it finds one cached, it tries
00074  * to use that one to do the update.   That's why it tries to update
00075  * "FOO.COM" above, even though theoretically it should try GAZANGA...
00076  * and TOPANGA... first.
00077  *
00078  * If the update fails with a predefined zone the zone is marked as bad
00079  * and another search of the predefined zones is done.  If no predefined
00080  * zone is found finding a zone is left to the DNS module via examination
00081  * of SOA records.  If the DNS module finds a zone it may cache the zone
00082  * but the zone won't be cached here.
00083  *
00084  * TSIG updates are not performed on zones found by the DNS module - if
00085  * you want TSIG updates you _must_ write a zone definition linking the
00086  * key to the zone.   In cases where you know for sure what the key is
00087  * but do not want to hardcode the IP addresses of the primary or
00088  * secondaries, a zone declaration can be made that doesn't include any
00089  * primary or secondary declarations.   When the DHCP server encounters
00090  * this while hunting up a matching zone for a name, it looks up the SOA,
00091  * fills in the IP addresses, and uses that record for the update.
00092  * If the SOA lookup returns NXRRSET, a warning is printed and the zone is
00093  * discarded, TSIG key and all.   The search for the zone then continues 
00094  * as if the zone record hadn't been found.   Zones without IP addresses 
00095  * don't match when initially hunting for a zone to update.
00096  *
00097  * When an update is attempted and no predefined zone is found
00098  * that matches any enclosing domain of the domain being updated, the DHCP
00099  * server goes through the same process that is done when the update to a
00100  * predefined zone fails - starting with the most specific domain
00101  * name (GAZANGA.TOPANGA.FOO.COM) and moving to the least specific (the root),
00102  * it tries to look up an SOA record.
00103  *
00104  * TSIG keys are defined like this:
00105  *
00106  *      key "FOO.COM Key" {
00107  *              algorithm HMAC-MD5.SIG-ALG.REG.INT;
00108  *              secret <Base64>;
00109  *      }
00110  *
00111  * <Base64> is a number expressed in base64 that represents the key.
00112  * It's also permissible to use a quoted string here - this will be
00113  * translated as the ASCII bytes making up the string, and will not
00114  * include any NUL termination.  The key name can be any text string,
00115  * and the key type must be one of the key types defined in the draft
00116  * or by the IANA.  Currently only the HMAC-MD5... key type is
00117  * supported.
00118  *
00119  * The DDNS processing has been split into two areas.  One is the
00120  * control code that determines what should be done.  That code is found
00121  * in the client or server directories.  The other is the common code
00122  * that performs functions such as properly formatting the arguments.
00123  * That code is found in this file.  The basic processing flow for a
00124  * DDNS update is:
00125  * In the client or server code determine what needs to be done and
00126  * collect the necesary information then pass it to a function from
00127  * this file.
00128  * In this code lookup the zone and extract the zone and key information
00129  * (if available) and prepare the arguments for the DNS module.
00130  * When the DNS module completes its work (times out or gets a reply)
00131  * it will trigger another function here which does generic processing
00132  * and then passes control back to the code from the server or client.
00133  * The server or client code then determines the next step which may
00134  * result in another call to this module in which case the process repeats.
00135  */
00136 
00137 dns_zone_hash_t *dns_zone_hash;
00138 
00139 /*
00140  * DHCP dns structures
00141  * Normally the relationship between these structures isn't one to one
00142  * but in the DHCP case it (mostly) is.  To make the allocations, frees,
00143  * and passing of the memory easier we make a single structure with all
00144  * the pieces.
00145  *
00146  * The maximum size of the data buffer should be large enough for any
00147  * items DHCP will generate
00148  */
00149 
00150 typedef struct dhcp_ddns_rdata {
00151         dns_rdata_t     rdata;
00152         dns_rdatalist_t rdatalist;
00153         dns_rdataset_t  rdataset;
00154 } dhcp_ddns_data_t;
00155 
00156 #if defined (NSUPDATE)
00157 #if defined (DNS_ZONE_LOOKUP)
00158 
00159 /*
00160  * The structure used to find a nameserver if there wasn't a zone entry.
00161  * Currently we assume we won't have many of these outstanding at any
00162  * time so we go with a simple linked list.
00163  * In use find_zone_start() will fill in the oname with the name
00164  * requested by the DDNS code.  zname will point to it and be
00165  * advanced as labels are removed.  If the DNS client code returns
00166  * a set of name servers eventp and rdataset will be set.  Then
00167  * the code will walk through the nameservers in namelist and
00168  * find addresses that are stored in addrs and addrs6.
00169  */
00170 
00171 typedef struct dhcp_ddns_ns {
00172         struct dhcp_ddns_ns *next;      
00173         struct data_string oname;     /* the original name for DDNS */
00174         char *zname;                  /* a pointer into the original name for
00175                                          the zone we are checking */
00176         dns_clientresevent_t *eventp; /* pointer to the event that provided the
00177                                          namelist, we can't free the eventp
00178                                          until we free the namelist */
00179         dns_name_t *ns_name;          /* current name server we are examining */
00180         dns_rdataset_t *rdataset; 
00181         dns_rdatatype_t rdtype;       /* type of address we want */
00182 
00183         struct in_addr addrs[DHCP_MAXNS];   /* space for v4 addresses */
00184         struct in6_addr addrs6[DHCP_MAXNS]; /* space for v6 addresses */
00185         int num_addrs;
00186         int num_addrs6;
00187         int ttl;
00188 
00189         void *transaction;             /* transaction id for DNS calls */
00190 } dhcp_ddns_ns_t;
00191 
00192 /*
00193  * The list of DDNS names for which we are attempting to find a name server.
00194  * This list is used for finding the name server, it doesn't include the
00195  * information necessary to do the DDNS request after finding a name server.
00196  * The code attempts to minimize duplicate requests by examining the list
00197  * to see if we are already trying to find a substring of the new request.
00198  * For example imagine the first request is "a.b.c.d.e." and the server has
00199  * already discarded the first two lables and is trying "c.d.e.".  If the
00200  * next request is for "x.y.c.d.e." the code assumes the in progress
00201  * request is sufficient and doesn't add a new request for the second name.
00202  * If the next request was for "x.y.z.d.e." the code doesn't assume they
00203  * will use the same nameserver and starts a second request.
00204  * This strategy will not eliminate all duplicates but is simple and
00205  * should be sufficient.
00206  */
00207 dhcp_ddns_ns_t *dns_outstanding_ns = NULL;
00208 
00209 /*
00210  * Routines to manipulate the list of outstanding searches
00211  *
00212  * add_to_ns_queue() - adds the given control block to the queue
00213  *
00214  * remove_from_ns_queue() - removes the given control block from
00215  * the queue
00216  *
00217  * find_in_ns_queue() compares the name from the given control
00218  * block with the control blocks in the queue.  It returns
00219  * success if a matching entry is found.  In order to match
00220  * the entry already on the queue must be shorter than the
00221  * incoming name must match the ending substring of the name.
00222  */
00223 
00224 void
00225 add_to_ns_queue(dhcp_ddns_ns_t *ns_cb)
00226 {
00227         ns_cb->next = dns_outstanding_ns;
00228         dns_outstanding_ns = ns_cb;
00229 }
00230 
00231 
00232 void
00233 remove_from_ns_queue(dhcp_ddns_ns_t *ns_cb)
00234 {
00235         dhcp_ddns_ns_t **foo;
00236 
00237         foo = &dns_outstanding_ns;
00238         while (*foo) {
00239                 if (*foo == ns_cb) {
00240                         *foo = ns_cb->next;
00241                         break;
00242                 }
00243                 foo = &((*foo)->next);
00244         }
00245         ns_cb->next = NULL;
00246 }
00247 
00248 isc_result_t
00249 find_in_ns_queue(dhcp_ddns_ns_t *ns_cb)
00250 {
00251         dhcp_ddns_ns_t *temp_cb;
00252         int in_len, temp_len;
00253 
00254         in_len = strlen(ns_cb->zname);
00255 
00256         for(temp_cb = dns_outstanding_ns;
00257             temp_cb != NULL;
00258             temp_cb = temp_cb->next) {
00259                 temp_len = strlen(temp_cb->zname);
00260                 if (temp_len > in_len)
00261                         continue;
00262                 if (strcmp(temp_cb->zname,
00263                            ns_cb->zname + (in_len - temp_len)) == 0)
00264                         return(ISC_R_SUCCESS);
00265         }
00266         return(ISC_R_NOTFOUND);
00267 }
00268 
00269 void cache_found_zone (dhcp_ddns_ns_t *);
00270 #endif
00271 
00272 void ddns_interlude(isc_task_t *, isc_event_t *);
00273 
00274 #if defined (TRACING)
00275 /*
00276  * Code to support tracing DDNS packets.  We trace packets going to and
00277  * coming from the libdns code but don't try to track the packets
00278  * exchanged between the libdns code and the dns server(s) it contacts.
00279  *
00280  * The code is split into two sets of routines
00281  *  input refers to messages received from the dns module
00282  *  output refers to messages sent to the dns module
00283  * Currently there are three routines in each set
00284  *  write is used to write information about the message to the trace file
00285  *        this routine is called directly from the proper place in the code.
00286  *  read is used to read information about a message from the trace file
00287  *       this routine is called from the trace loop as it reads through
00288  *       the file and is registered via the trace_type_register routine.
00289  *       When playing back a trace file we shall absorb records of output
00290  *       messages as part of processing the write function, therefore
00291  *       any output messages we encounter are flagged as errors.
00292  *  stop isn't currently used in this code but is needed for the register
00293  *       routine.
00294  *
00295  * We pass a pointer to a control block to the dns module which it returns
00296  * to use as part of the result.  As the pointer may vary between traces
00297  * we need to map between those from the trace file and the new ones during
00298  * playback.
00299  *
00300  * The mapping is complicated a little as a pointer could be 4 or 8 bytes
00301  * long.  We treat the old pointer as an 8 byte quantity and pad and compare
00302  * as necessary.
00303  */
00304 
00305 /*
00306  * Structure used to map old pointers to new pointers.
00307  * Old pointers are 8 bytes long as we don't know if the trace was 
00308  * done on a 64 bit or 32 bit machine.  
00309  */
00310 #define TRACE_PTR_LEN 8
00311 
00312 typedef struct dhcp_ddns_map {
00313         char  old_pointer[TRACE_PTR_LEN];
00314         void *new_pointer;
00315         struct dhcp_ddns_map *next;
00316 } dhcp_ddns_map_t;
00317 
00318 /* The starting point for the map structure */
00319 static dhcp_ddns_map_t *ddns_map;
00320 
00321 trace_type_t *trace_ddns_input;
00322 trace_type_t *trace_ddns_output;
00323 
00324 /*
00325  * The data written to the trace file is:
00326  * 32 bits result from dns
00327  * 64 bits pointer of cb
00328  */
00329 
00330 void
00331 trace_ddns_input_write(dhcp_ddns_cb_t *ddns_cb, isc_result_t result)
00332 {
00333         trace_iov_t iov[2];
00334         u_int32_t old_result;
00335         char old_pointer[TRACE_PTR_LEN];
00336         
00337         old_result = htonl((u_int32_t)result);
00338         memset(old_pointer, 0, TRACE_PTR_LEN);
00339         memcpy(old_pointer, &ddns_cb, sizeof(ddns_cb));
00340 
00341         iov[0].len = sizeof(old_result);
00342         iov[0].buf = (char *)&old_result;
00343         iov[1].len = TRACE_PTR_LEN;
00344         iov[1].buf = old_pointer;
00345         trace_write_packet_iov(trace_ddns_input, 2, iov, MDL);
00346 }
00347 
00348 /*
00349  * Process the result and pointer from the trace file.
00350  * We use the pointer map to find the proper pointer for this instance.
00351  * Then we need to construct an event to pass along to the interlude
00352  * function.
00353  */
00354 static void
00355 trace_ddns_input_read(trace_type_t *ttype, unsigned length,
00356                                   char *buf)
00357 {
00358         u_int32_t old_result;
00359         char old_pointer[TRACE_PTR_LEN];
00360         dns_clientupdateevent_t *eventp;
00361         void *new_pointer;
00362         dhcp_ddns_map_t *ddns_map_ptr;
00363 
00364         if (length < (sizeof(old_result) + TRACE_PTR_LEN)) {
00365                 log_error("trace_ddns_input_read: data too short");
00366                 return;
00367         }
00368 
00369         memcpy(&old_result, buf, sizeof(old_result));
00370         memcpy(old_pointer, buf + sizeof(old_result), TRACE_PTR_LEN);
00371 
00372         /* map the old pointer to a new pointer */
00373         for (ddns_map_ptr = ddns_map;
00374              ddns_map_ptr != NULL;
00375              ddns_map_ptr = ddns_map_ptr->next) {
00376                 if ((ddns_map_ptr->new_pointer != NULL) &&
00377                     memcmp(ddns_map_ptr->old_pointer,
00378                            old_pointer, TRACE_PTR_LEN) == 0) {
00379                         new_pointer = ddns_map_ptr->new_pointer;
00380                         ddns_map_ptr->new_pointer = NULL;
00381                         memset(ddns_map_ptr->old_pointer, 0, TRACE_PTR_LEN);
00382                         break;
00383                 }
00384         }
00385         if (ddns_map_ptr == NULL) {
00386                 log_error("trace_dns_input_read: unable to map cb pointer");
00387                 return;
00388         }               
00389 
00390         eventp = (dns_clientupdateevent_t *)
00391                 isc_event_allocate(dhcp_gbl_ctx.mctx,
00392                                    dhcp_gbl_ctx.task,
00393                                    0,
00394                                    ddns_interlude,
00395                                    new_pointer,
00396                                    sizeof(dns_clientupdateevent_t));
00397         if (eventp == NULL) {
00398                 log_error("trace_ddns_input_read: unable to allocate event");
00399                 return;
00400         }
00401         eventp->result = ntohl(old_result);
00402 
00403 
00404         ddns_interlude(dhcp_gbl_ctx.task, (isc_event_t *)eventp);
00405 
00406         return;
00407 }
00408 
00409 static void
00410 trace_ddns_input_stop(trace_type_t *ttype)
00411 {
00412 }
00413 
00414 /*
00415  * We use the same arguments as for the dns startupdate function to
00416  * allows us to choose between the two via a macro.  If tracing isn't
00417  * in use we simply call the dns function directly.
00418  *
00419  * If we are doing playback we read the next packet from the file
00420  * and compare the type.  If it matches we extract the results and pointer
00421  * from the trace file.  The results are returned to the caller as if
00422  * they had called the dns routine.  The pointer is used to construct a 
00423  * map for when the "reply" is processed.
00424  *
00425  * The data written to trace file is:
00426  * 32 bits result
00427  * 64 bits pointer of cb (DDNS Control block)
00428  * contents of cb
00429  */
00430 
00431 isc_result_t
00432 trace_ddns_output_write(dns_client_t *client, dns_rdataclass_t rdclass,
00433                         dns_name_t *zonename, dns_namelist_t *prerequisites,
00434                         dns_namelist_t *updates, isc_sockaddrlist_t *servers,
00435                         dns_tsec_t *tsec, unsigned int options,
00436                         isc_task_t *task, isc_taskaction_t action, void *arg,
00437                         dns_clientupdatetrans_t **transp)
00438 {
00439         isc_result_t result;
00440         u_int32_t old_result;
00441         char old_pointer[TRACE_PTR_LEN];
00442         dhcp_ddns_map_t *ddns_map_ptr;
00443         
00444         if (trace_playback() != 0) {
00445                 /* We are doing playback, extract the entry from the file */
00446                 unsigned buflen = 0;
00447                 char *inbuf = NULL;
00448 
00449                 result = trace_get_packet(&trace_ddns_output,
00450                                           &buflen, &inbuf);
00451                 if (result != ISC_R_SUCCESS) {
00452                         log_error("trace_ddns_output_write: no input found");
00453                         return (ISC_R_FAILURE);
00454                 }
00455                 if (buflen < (sizeof(old_result) + TRACE_PTR_LEN)) {
00456                         log_error("trace_ddns_output_write: data too short");
00457                         dfree(inbuf, MDL);
00458                         return (ISC_R_FAILURE);
00459                 }
00460                 memcpy(&old_result, inbuf, sizeof(old_result));
00461                 result = ntohl(old_result);
00462                 memcpy(old_pointer, inbuf + sizeof(old_result), TRACE_PTR_LEN);
00463                 dfree(inbuf, MDL);
00464 
00465                 /* add the pointer to the pointer map */
00466                 for (ddns_map_ptr = ddns_map;
00467                      ddns_map_ptr != NULL;
00468                      ddns_map_ptr = ddns_map_ptr->next) {
00469                         if (ddns_map_ptr->new_pointer == NULL) {
00470                                 break;
00471                         }
00472                 }
00473 
00474                 /*
00475                  * If we didn't find an empty entry, allocate an entry and
00476                  * link it into the list.  The list isn't ordered.
00477                  */
00478                 if (ddns_map_ptr == NULL) {
00479                         ddns_map_ptr = dmalloc(sizeof(*ddns_map_ptr), MDL);
00480                         if (ddns_map_ptr == NULL) {
00481                                 log_error("trace_ddns_output_write: " 
00482                                           "unable to allocate map entry");
00483                                 return(ISC_R_FAILURE);
00484                                 }
00485                         ddns_map_ptr->next = ddns_map;
00486                         ddns_map = ddns_map_ptr;
00487                 }
00488 
00489                 memcpy(ddns_map_ptr->old_pointer, old_pointer, TRACE_PTR_LEN);
00490                 ddns_map_ptr->new_pointer = arg;
00491         }
00492         else {
00493                 /* We aren't doing playback, make the actual call */
00494                 result = dns_client_startupdate(client, rdclass, zonename,
00495                                                 prerequisites, updates,
00496                                                 servers, tsec, options,
00497                                                 task, action, arg, transp);
00498         }
00499 
00500         if (trace_record() != 0) {
00501                 /* We are recording, save the information to the file */
00502                 trace_iov_t iov[3];
00503                 old_result = htonl((u_int32_t)result);
00504                 memset(old_pointer, 0, TRACE_PTR_LEN);
00505                 memcpy(old_pointer, &arg, sizeof(arg));
00506                 iov[0].len = sizeof(old_result);
00507                 iov[0].buf = (char *)&old_result;
00508                 iov[1].len = TRACE_PTR_LEN;
00509                 iov[1].buf = old_pointer;
00510 
00511                 /* Write out the entire cb, in case we want to look at it */
00512                 iov[2].len = sizeof(dhcp_ddns_cb_t);
00513                 iov[2].buf = (char *)arg;
00514 
00515                 trace_write_packet_iov(trace_ddns_output, 3, iov, MDL);
00516         }
00517 
00518         return(result);
00519 }
00520 
00521 static void
00522 trace_ddns_output_read(trace_type_t *ttype, unsigned length,
00523                                    char *buf)
00524 {
00525         log_error("unaccounted for ddns output.");
00526 }
00527 
00528 static void
00529 trace_ddns_output_stop(trace_type_t *ttype)
00530 {
00531 }
00532 
00533 void
00534 trace_ddns_init()
00535 {
00536         trace_ddns_output = trace_type_register("ddns-output", NULL,
00537                                                 trace_ddns_output_read,
00538                                                 trace_ddns_output_stop, MDL);
00539         trace_ddns_input  = trace_type_register("ddns-input", NULL,
00540                                                 trace_ddns_input_read,
00541                                                 trace_ddns_input_stop, MDL);
00542         ddns_map = NULL;
00543 }
00544 
00545 #define ddns_update trace_ddns_output_write
00546 #else
00547 #define ddns_update dns_client_startupdate
00548 #endif /* TRACING */
00549 
00550 #define zone_resolve dns_client_startresolve
00551 
00552 /*
00553  * Code to allocate and free a dddns control block.  This block is used
00554  * to pass and track the information associated with a DDNS update request.
00555  */
00556 dhcp_ddns_cb_t *
00557 ddns_cb_alloc(const char *file, int line)
00558 {
00559         dhcp_ddns_cb_t *ddns_cb;
00560         int i;
00561 
00562         ddns_cb = dmalloc(sizeof(*ddns_cb), file, line);
00563         if (ddns_cb != NULL) {
00564                 ISC_LIST_INIT(ddns_cb->zone_server_list);
00565                 for (i = 0; i < DHCP_MAXNS; i++) {
00566                         ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link);
00567                 }
00568         }
00569 
00570 #if defined (DEBUG_DNS_UPDATES)
00571         log_info("%s(%d): Allocating ddns_cb=%p", file, line, ddns_cb);
00572 #endif
00573 
00574         return(ddns_cb);
00575 }
00576                 
00577 void
00578 ddns_cb_free(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
00579 {
00580 #if defined (DEBUG_DNS_UPDATES)
00581         log_info("%s(%d): freeing ddns_cb=%p", file, line, ddns_cb);
00582 #endif
00583 
00584         data_string_forget(&ddns_cb->fwd_name, file, line);
00585         data_string_forget(&ddns_cb->rev_name, file, line);
00586         data_string_forget(&ddns_cb->dhcid, file, line);
00587         
00588         if (ddns_cb->zone != NULL) {
00589                 forget_zone((struct dns_zone **)&ddns_cb->zone);
00590         }
00591 
00592         /* Should be freed by now, check just in case. */
00593         if (ddns_cb->transaction != NULL)
00594                 log_error("Impossible memory leak at %s:%d (attempt to free "
00595                           "DDNS Control Block before transaction).", MDL);
00596 
00597         dfree(ddns_cb, file, line);
00598 }
00599 
00600 void
00601 ddns_cb_forget_zone(dhcp_ddns_cb_t *ddns_cb)
00602 {
00603         int i;
00604 
00605         forget_zone(&ddns_cb->zone);
00606         ddns_cb->zone_name[0] = 0;
00607         ISC_LIST_INIT(ddns_cb->zone_server_list);
00608         for (i = 0; i < DHCP_MAXNS; i++) {
00609                 ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link);
00610         }
00611 }
00612 
00613 isc_result_t find_tsig_key (ns_tsig_key **key, const char *zname,
00614                             struct dns_zone *zone)
00615 {
00616         ns_tsig_key *tkey;
00617 
00618         if (!zone)
00619                 return ISC_R_NOTFOUND;
00620 
00621         if (!zone -> key) {
00622                 return DHCP_R_KEY_UNKNOWN;
00623         }
00624         
00625         if ((!zone -> key -> name ||
00626              strlen (zone -> key -> name) > NS_MAXDNAME) ||
00627             (!zone -> key -> algorithm ||
00628              strlen (zone -> key -> algorithm) > NS_MAXDNAME) ||
00629             (!zone -> key) ||
00630             (!zone -> key -> key) ||
00631             (zone -> key -> key -> len == 0)) {
00632                 return DHCP_R_INVALIDKEY;
00633         }
00634         tkey = dmalloc (sizeof *tkey, MDL);
00635         if (!tkey) {
00636               nomem:
00637                 return ISC_R_NOMEMORY;
00638         }
00639         memset (tkey, 0, sizeof *tkey);
00640         tkey -> data = dmalloc (zone -> key -> key -> len, MDL);
00641         if (!tkey -> data) {
00642                 dfree (tkey, MDL);
00643                 goto nomem;
00644         }
00645         strcpy (tkey -> name, zone -> key -> name);
00646         strcpy (tkey -> alg, zone -> key -> algorithm);
00647         memcpy (tkey -> data,
00648                 zone -> key -> key -> value, zone -> key -> key -> len);
00649         tkey -> len = zone -> key -> key -> len;
00650         *key = tkey;
00651         return ISC_R_SUCCESS;
00652 }
00653 
00654 void tkey_free (ns_tsig_key **key)
00655 {
00656         if ((*key) -> data)
00657                 dfree ((*key) -> data, MDL);
00658         dfree ((*key), MDL);
00659         *key = (ns_tsig_key *)0;
00660 }
00661 #endif
00662 
00663 isc_result_t remove_dns_zone (struct dns_zone *zone)
00664 {
00665         struct dns_zone *tz = NULL;
00666 
00667         if (dns_zone_hash) {
00668                 dns_zone_hash_lookup(&tz, dns_zone_hash, zone->name, 0, MDL);
00669                 if (tz != NULL) {
00670                         dns_zone_hash_delete(dns_zone_hash, tz->name, 0, MDL);
00671                         dns_zone_dereference(&tz, MDL);
00672                 }
00673         }
00674 
00675         return (ISC_R_SUCCESS);
00676 }
00677 
00678 isc_result_t enter_dns_zone (struct dns_zone *zone)
00679 {
00680         struct dns_zone *tz = (struct dns_zone *)0;
00681 
00682         if (dns_zone_hash) {
00683                 dns_zone_hash_lookup (&tz,
00684                                       dns_zone_hash, zone -> name, 0, MDL);
00685                 if (tz == zone) {
00686                         dns_zone_dereference (&tz, MDL);
00687                         return ISC_R_SUCCESS;
00688                 }
00689                 if (tz) {
00690                         dns_zone_hash_delete (dns_zone_hash,
00691                                               zone -> name, 0, MDL);
00692                         dns_zone_dereference (&tz, MDL);
00693                 }
00694         } else {
00695                 if (!dns_zone_new_hash(&dns_zone_hash, DNS_HASH_SIZE, MDL))
00696                         return ISC_R_NOMEMORY;
00697         }
00698 
00699         dns_zone_hash_add (dns_zone_hash, zone -> name, 0, zone, MDL);
00700         return ISC_R_SUCCESS;
00701 }
00702 
00703 isc_result_t dns_zone_lookup (struct dns_zone **zone, const char *name)
00704 {
00705         int len;
00706         char *tname = (char *)0;
00707         isc_result_t status;
00708 
00709         if (!dns_zone_hash)
00710                 return ISC_R_NOTFOUND;
00711 
00712         len = strlen (name);
00713         if (name [len - 1] != '.') {
00714                 tname = dmalloc ((unsigned)len + 2, MDL);
00715                 if (!tname)
00716                         return ISC_R_NOMEMORY;
00717                 strcpy (tname, name);
00718                 tname [len] = '.';
00719                 tname [len + 1] = 0;
00720                 name = tname;
00721         }
00722         if (!dns_zone_hash_lookup (zone, dns_zone_hash, name, 0, MDL))
00723                 status = ISC_R_NOTFOUND;
00724         else if ((*zone)->timeout && (*zone)->timeout < cur_time) {
00725                 dns_zone_hash_delete(dns_zone_hash, (*zone)->name, 0, MDL);
00726                 dns_zone_dereference(zone, MDL);
00727                 status = ISC_R_NOTFOUND;
00728         } else 
00729                 status = ISC_R_SUCCESS;
00730 
00731         if (tname)
00732                 dfree (tname, MDL);
00733         return status;
00734 }
00735 
00736 int dns_zone_dereference (ptr, file, line)
00737         struct dns_zone **ptr;
00738         const char *file;
00739         int line;
00740 {
00741         struct dns_zone *dns_zone;
00742 
00743         if ((ptr == NULL) || (*ptr == NULL)) {
00744                 log_error("%s(%d): null pointer", file, line);
00745 #if defined (POINTER_DEBUG)
00746                 abort();
00747 #else
00748                 return (0);
00749 #endif
00750         }
00751 
00752         dns_zone = *ptr;
00753         *ptr = NULL;
00754         --dns_zone->refcnt;
00755         rc_register(file, line, ptr, dns_zone, dns_zone->refcnt, 1, RC_MISC);
00756         if (dns_zone->refcnt > 0)
00757                 return (1);
00758 
00759         if (dns_zone->refcnt < 0) {
00760                 log_error("%s(%d): negative refcnt!", file, line);
00761 #if defined (DEBUG_RC_HISTORY)
00762                 dump_rc_history(dns_zone);
00763 #endif
00764 #if defined (POINTER_DEBUG)
00765                 abort();
00766 #else
00767                 return (0);
00768 #endif
00769         }
00770 
00771         if (dns_zone->name)
00772                 dfree(dns_zone->name, file, line);
00773         if (dns_zone->key)
00774                 omapi_auth_key_dereference(&dns_zone->key, file, line);
00775         if (dns_zone->primary)
00776                 option_cache_dereference(&dns_zone->primary, file, line);
00777         if (dns_zone->secondary)
00778                 option_cache_dereference(&dns_zone->secondary, file, line);
00779         if (dns_zone->primary6)
00780                 option_cache_dereference(&dns_zone->primary6, file, line);
00781         if (dns_zone->secondary6)
00782                 option_cache_dereference(&dns_zone->secondary6, file, line);
00783         dfree(dns_zone, file, line);
00784         return (1);
00785 }
00786 
00787 #if defined (NSUPDATE)
00788 #if defined (DNS_ZONE_LOOKUP)
00789 
00790 /* Helper function to copy the address from an rdataset to 
00791  * the nameserver control block.  Mostly to avoid really long
00792  * lines in the nested for loops
00793  */
00794 void
00795 zone_addr_to_ns(dhcp_ddns_ns_t *ns_cb,
00796                 dns_rdataset_t *rdataset)
00797 {
00798         dns_rdata_t rdata;
00799         dns_rdata_in_a_t a;
00800         dns_rdata_in_aaaa_t aaaa;
00801         
00802         dns_rdata_init(&rdata);
00803         dns_rdataset_current(rdataset, &rdata);
00804         switch (rdataset->type) {
00805         case dns_rdatatype_a:
00806                 (void) dns_rdata_tostruct(&rdata, &a, NULL);
00807                 memcpy(&ns_cb->addrs[ns_cb->num_addrs], &a.in_addr, 4);
00808                 ns_cb->num_addrs++;
00809                 dns_rdata_freestruct(&a);
00810                 break;
00811         case dns_rdatatype_aaaa:
00812                 (void) dns_rdata_tostruct(&rdata, &aaaa, NULL);
00813                 memcpy(&ns_cb->addrs6[ns_cb->num_addrs6], &aaaa.in6_addr, 16);
00814                 ns_cb->num_addrs6++;
00815                 dns_rdata_freestruct(&aaaa);
00816                 break;
00817         default:
00818                 break;
00819         }
00820 
00821         if ((ns_cb->ttl == 0) || (ns_cb->ttl > rdataset->ttl))
00822                 ns_cb->ttl = rdataset->ttl;
00823 }
00824 
00825 /*
00826  * The following three routines co-operate to find the addresses of
00827  * the nameservers to use for a zone if we don't have a zone statement.
00828  * We strongly suggest the use of a zone statement to avoid problmes
00829  * and to allow for the use of TSIG and therefore better security, but
00830  * include this functionality for those that don't want such statements.
00831  *
00832  * find_zone_start(ddns_cb, direction)
00833  * This is the first of the routines, it is called from the rest of
00834  * the ddns code when we have received a request for DDNS for a name
00835  * and don't have a zone entry that would cover that name.  The name
00836  * is in the ddns_cb as specified by the direction (forward or reverse).
00837  * The start function pulls the name out and constructs the name server
00838  * block then starts the process by calling the DNS client code.
00839  *
00840  * find_zone_ns(taskp, eventp)
00841  * This is the second step of the process.  The DNS client code will
00842  * call this when it has gotten a response or timed out.  If the response
00843  * doesn't have a list of nameservers we remove another label from the
00844  * zone name and try again.  If the response does include a list of
00845  * nameservers we start walking through the list attempting to get
00846  * addresses for the nameservers.
00847  *
00848  * find_zone_addrs(taskp, eventp)
00849  * This is the third step of the process.  In find_zone_ns we got
00850  * a list of nameserves and started walking through them.  This continues
00851  * the walk and if we get back any addresses it adds them to our list.
00852  * When we get enough addresses or run out of nameservers we construct
00853  * a zone entry and insert it into the zone hash for the rest of the
00854  * DDNS code to use.
00855  */
00856 void
00857 find_zone_addrs(isc_task_t *taskp,
00858                 isc_event_t *eventp)
00859 {
00860         dns_clientresevent_t *ddns_event = (dns_clientresevent_t *)eventp;
00861         dhcp_ddns_ns_t *ns_cb = (dhcp_ddns_ns_t *)eventp->ev_arg;
00862         dns_name_t *ns_name = NULL;
00863         dns_rdataset_t *rdataset;
00864         isc_result_t result;
00865         dns_name_t *name;
00866         dns_rdata_t rdata = DNS_RDATA_INIT;
00867         dns_rdata_ns_t ns;
00868         
00869 
00870         /* the transaction is done, get rid of the tag */
00871         dns_client_destroyrestrans(&ns_cb->transaction);
00872 
00873         /* If we succeeded we try and extract the addresses, if we can
00874          * and we have enough we are done.  If we didn't succeed or
00875          * we don't have enough addresses afterwards we drop through
00876          * and try the next item on the list.
00877          */
00878         if (ddns_event->result == ISC_R_SUCCESS) {
00879 
00880                 for (name = ISC_LIST_HEAD(ddns_event->answerlist);
00881                      name != NULL;
00882                      name = ISC_LIST_NEXT(name, link)) {
00883 
00884                         for (rdataset = ISC_LIST_HEAD(name->list);
00885                              rdataset != NULL;
00886                              rdataset = ISC_LIST_NEXT(rdataset, link)) {
00887 
00888                                 for (result = dns_rdataset_first(rdataset);
00889                                      result == ISC_R_SUCCESS;
00890                                      result = dns_rdataset_next(rdataset)) {
00891 
00892                                         /* add address to cb */
00893                                         zone_addr_to_ns(ns_cb, rdataset);
00894 
00895                                         /* We are done if we have
00896                                          * enough addresses
00897                                          */
00898                                         if (ns_cb->num_addrs +
00899                                             ns_cb->num_addrs6 >= DHCP_MAXNS)
00900                                                 goto done;
00901                                 }
00902                         }
00903                 }
00904         }
00905 
00906         /* We need more addresses.
00907          * We restart the loop we were in before.
00908          */
00909 
00910         for (ns_name = ns_cb->ns_name;
00911              ns_name != NULL;
00912              ns_name = ISC_LIST_NEXT(ns_name, link)) {
00913 
00914                 if (ns_name == ns_cb->ns_name) {
00915                         /* first time through, use saved state */
00916                         rdataset = ns_cb->rdataset;
00917                 } else {
00918                         rdataset = ISC_LIST_HEAD(ns_name->list);
00919                 }
00920 
00921                 for (;
00922                      rdataset != NULL;
00923                      rdataset = ISC_LIST_NEXT(rdataset, link)) {
00924                         
00925                         if (rdataset->type != dns_rdatatype_ns)
00926                                 continue;
00927                         dns_rdata_init(&rdata);
00928 
00929                         if (rdataset == ns_cb->rdataset) {
00930                                 /* first time through use the saved state */
00931                                 if (ns_cb->rdtype == dns_rdatatype_a) {
00932                                         ns_cb->rdtype = dns_rdatatype_aaaa;
00933                                 } else {
00934                                         ns_cb->rdtype = dns_rdatatype_a;
00935                                         if (dns_rdataset_next(rdataset) !=
00936                                             ISC_R_SUCCESS)
00937                                                 continue;
00938                                 }
00939                         } else {
00940                                 if ((!dns_rdataset_isassociated(rdataset)) ||
00941                                     (dns_rdataset_first(rdataset) != 
00942                                      ISC_R_SUCCESS))
00943                                         continue;
00944                         }                               
00945 
00946                         dns_rdataset_current(rdataset, &rdata);
00947                         if (dns_rdata_tostruct(&rdata, &ns, NULL) !=
00948                             ISC_R_SUCCESS)
00949                                 continue;
00950 
00951                         /* Save our current state */
00952                         ns_cb->ns_name = ns_name;
00953                         ns_cb->rdataset = rdataset;
00954 
00955                         /* And call out to DNS */
00956                         result = zone_resolve(dhcp_gbl_ctx.dnsclient, &ns.name,
00957                                               dns_rdataclass_in,
00958                                               ns_cb->rdtype,
00959                                               DNS_CLIENTRESOPT_NODNSSEC,
00960                                               dhcp_gbl_ctx.task,
00961                                               find_zone_addrs,
00962                                               (void *)ns_cb,
00963                                               &ns_cb->transaction);
00964 
00965                         /* do we need to clean this? */
00966                         dns_rdata_freestruct(&ns);
00967 
00968                         if (result == ISC_R_SUCCESS)
00969                                 /* we have started the next step, cleanup
00970                                  * the structures associated with this call
00971                                  * but leave the cb for the next round
00972                                  */
00973                                 goto cleanup;
00974 
00975                         log_error("find_zone_ns: unable to continue "
00976                                   "resolve: %s %s",
00977                                   ns_cb->zname,
00978                                   isc_result_totext(result));
00979 
00980                         /* The call to start a resolve transaction failed,
00981                          * should we try to continue with any other names?
00982                          * For now let's not, but let's use whatever we
00983                          * may already have.
00984                          */
00985                         goto done;
00986                 }
00987         }
00988 
00989  done:
00990         /* we've either gotten our max number of addresses or
00991          * run out of nameservers to try.  Convert the cb into
00992          * a zone and insert it into the zone hash.  Then
00993          * we need to clean up the saved state.
00994          */
00995         if ((ns_cb->num_addrs != 0) ||
00996             (ns_cb->num_addrs6 != 0))
00997                 cache_found_zone(ns_cb);
00998 
00999         dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient,
01000                                  &ns_cb->eventp->answerlist);
01001         isc_event_free((isc_event_t **)&ns_cb->eventp);
01002 
01003         remove_from_ns_queue(ns_cb);
01004         data_string_forget(&ns_cb->oname, MDL);
01005         dfree(ns_cb, MDL);
01006 
01007  cleanup:
01008         /* cleanup any of the new state information */
01009 
01010         dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient,
01011                                  &ddns_event->answerlist);
01012         isc_event_free(&eventp);
01013 
01014         return;
01015          
01016 }
01017 
01018 /*
01019  * Routine to continue the process of finding a nameserver via the DNS
01020  * This is routine is called when we are still trying to get a list
01021  * of nameservers to process.
01022  */
01023  
01024 void
01025 find_zone_ns(isc_task_t *taskp,
01026              isc_event_t *eventp)
01027 {
01028         dns_clientresevent_t *ddns_event = (dns_clientresevent_t *)eventp;
01029         dhcp_ddns_ns_t *ns_cb = (dhcp_ddns_ns_t *)eventp->ev_arg;
01030         dns_fixedname_t zname0;
01031         dns_name_t *zname = NULL, *ns_name = NULL;
01032         dns_rdataset_t *rdataset;
01033         isc_result_t result;
01034         dns_rdata_t rdata = DNS_RDATA_INIT;
01035         dns_rdata_ns_t ns;
01036 
01037         /* the transaction is done, get rid of the tag */
01038         dns_client_destroyrestrans(&ns_cb->transaction);
01039 
01040         if (ddns_event->result != ISC_R_SUCCESS) {
01041                 /* We didn't find any nameservers, try again */
01042 
01043                 /* Remove a label and continue */
01044                 ns_cb->zname = strchr(ns_cb->zname, '.');
01045                 if ((ns_cb->zname == NULL) ||
01046                     (ns_cb->zname[1] == 0)) {
01047                         /* No more labels, all done */
01048                         goto cleanup;
01049                 }
01050                 ns_cb->zname++;
01051 
01052                 /* Create a DNS version of the zone name and call the
01053                  * resolver code */
01054                 if (((result = dhcp_isc_name((unsigned char *)ns_cb->zname,
01055                                              &zname0, &zname))
01056                      != ISC_R_SUCCESS) ||
01057                     ((result = zone_resolve(dhcp_gbl_ctx.dnsclient,
01058                                             zname, dns_rdataclass_in,
01059                                             dns_rdatatype_ns,
01060                                             DNS_CLIENTRESOPT_NODNSSEC,
01061                                             dhcp_gbl_ctx.task,
01062                                             find_zone_ns,
01063                                             (void *)ns_cb,
01064                                             &ns_cb->transaction))
01065                      != ISC_R_SUCCESS)) {
01066                         log_error("find_zone_ns: Unable to build "
01067                                   "name or start resolve: %s %s",
01068                                   ns_cb->zname,
01069                                   isc_result_totext(result));
01070                         goto cleanup;
01071                 }
01072                 
01073                 /* we have successfully started the next iteration
01074                  * of this step, clean up from the call and continue */
01075                 dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient,
01076                                          &ddns_event->answerlist);
01077                 isc_event_free(&eventp);
01078                 return;
01079         }
01080 
01081         /* We did get a set of nameservers, save the information and
01082          * start trying to get addresses
01083          */
01084         ns_cb->eventp = ddns_event;
01085         for (ns_name = ISC_LIST_HEAD(ddns_event->answerlist);
01086              ns_name != NULL;
01087              ns_name = ISC_LIST_NEXT(ns_name, link)) {
01088 
01089                 for (rdataset = ISC_LIST_HEAD(ns_name->list);
01090                      rdataset != NULL;
01091                      rdataset = ISC_LIST_NEXT(rdataset, link)) {
01092 
01093                         if (rdataset->type != dns_rdatatype_ns)
01094                                 continue;
01095 
01096                         if ((!dns_rdataset_isassociated(rdataset)) ||
01097                             (dns_rdataset_first(rdataset) != 
01098                              ISC_R_SUCCESS))
01099                                 continue;
01100 
01101                         dns_rdataset_current(rdataset, &rdata);
01102                         if (dns_rdata_tostruct(&rdata, &ns, NULL) !=
01103                             ISC_R_SUCCESS)
01104                                 continue;
01105 
01106                         /* Save our current state */
01107                         ns_cb->ns_name = ns_name;
01108                         ns_cb->rdataset = rdataset;
01109 
01110                         /* And call out to DNS */
01111                         result = zone_resolve(dhcp_gbl_ctx.dnsclient, &ns.name,
01112                                               dns_rdataclass_in,
01113                                               ns_cb->rdtype,
01114                                               DNS_CLIENTRESOPT_NODNSSEC,
01115                                               dhcp_gbl_ctx.task,
01116                                               find_zone_addrs,
01117                                               (void *)ns_cb,
01118                                               &ns_cb->transaction);
01119 
01120                         /* do we need to clean this? */
01121                         dns_rdata_freestruct(&ns);
01122 
01123                         if (result == ISC_R_SUCCESS)
01124                                 /* We have successfully started the next step
01125                                  * we don't cleanup the eventp block as we are
01126                                  * still using it.
01127                                  */
01128                                 return;
01129 
01130                         log_error("find_zone_ns: unable to continue "
01131                                   "resolve: %s %s",
01132                                   ns_cb->zname,
01133                                   isc_result_totext(result));
01134 
01135                         /* The call to start a resolve transaction failed,
01136                          * should we try to continue with any other names?
01137                          * For now let's not
01138                          */
01139                         goto cleanup;
01140                 }
01141         }
01142 
01143  cleanup:
01144         /* When we add a queue to manage the DDNS
01145          * requests we will need to remove any that
01146          * were waiting for this resolution */
01147 
01148         dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient,
01149                                  &ddns_event->answerlist);
01150         isc_event_free(&eventp);
01151 
01152         remove_from_ns_queue(ns_cb);
01153 
01154         data_string_forget(&ns_cb->oname, MDL);
01155         dfree(ns_cb, MDL);
01156         return;
01157         
01158 }
01159 
01160 /*
01161  * Start the process of finding nameservers via the DNS because
01162  * we don't have a zone entry already.
01163  * We construct a control block and fill in the DDNS name.  As
01164  * the process continues we shall move the zname pointer to
01165  * indicate which labels we are still using.  The rest of
01166  * the control block will be filled in as we continue processing.
01167  */
01168 isc_result_t
01169 find_zone_start(dhcp_ddns_cb_t *ddns_cb, int direction) 
01170 {
01171         isc_result_t status = ISC_R_NOTFOUND;
01172         dhcp_ddns_ns_t *ns_cb;
01173         dns_fixedname_t zname0;
01174         dns_name_t *zname = NULL;
01175 
01176         /*
01177          * We don't validate np as that was already done in find_cached_zone()
01178          */
01179 
01180         /* Allocate the control block for this request */
01181         ns_cb = dmalloc(sizeof(*ns_cb), MDL);
01182         if (ns_cb == NULL) {
01183                 log_error("find_zone_start: unable to allocate cb");
01184                 return(ISC_R_FAILURE);
01185         }
01186         ns_cb->rdtype = dns_rdatatype_a;
01187 
01188         /* Copy the data string so the NS lookup is independent of the DDNS */
01189         if (direction == FIND_FORWARD) {
01190                 data_string_copy(&ns_cb->oname,  &ddns_cb->fwd_name, MDL);
01191         } else {
01192                 data_string_copy(&ns_cb->oname,  &ddns_cb->rev_name, MDL);
01193         }
01194         ns_cb->zname = (char *)ns_cb->oname.data;
01195 
01196         /*
01197          * Check the dns_outstanding_ns queue to see if we are
01198          * already processing something that would cover this name
01199          */
01200         if (find_in_ns_queue(ns_cb) == ISC_R_SUCCESS) {
01201                 data_string_forget(&ns_cb->oname, MDL);
01202                 dfree(ns_cb, MDL);
01203                 return (ISC_R_SUCCESS);
01204         }
01205 
01206         /* Create a DNS version of the zone name and call the
01207          * resolver code */
01208         if (((status = dhcp_isc_name((unsigned char *)ns_cb->zname,
01209                                      &zname0, &zname))
01210              != ISC_R_SUCCESS) ||
01211             ((status = zone_resolve(dhcp_gbl_ctx.dnsclient,
01212                                     zname, dns_rdataclass_in,
01213                                     dns_rdatatype_ns,
01214                                     DNS_CLIENTRESOPT_NODNSSEC,
01215                                     dhcp_gbl_ctx.task,
01216                                     find_zone_ns,
01217                                     (void *)ns_cb,
01218                                     &ns_cb->transaction))
01219              != ISC_R_SUCCESS)) {
01220                 log_error("find_zone_start: Unable to build "
01221                           "name or start resolve: %s %s",
01222                           ns_cb->zname,
01223                           isc_result_totext(status));
01224 
01225                 /* We failed to start the process, clean up */
01226                 data_string_forget(&ns_cb->oname, MDL);
01227                 dfree(ns_cb, MDL);
01228         } else {
01229                 /* We started the process, attach the control block
01230                  * to the queue */
01231                 add_to_ns_queue(ns_cb);
01232         }
01233 
01234         return (status);
01235 }
01236 #endif
01237 
01238 isc_result_t
01239 find_cached_zone(dhcp_ddns_cb_t *ddns_cb, int direction) 
01240 {
01241         isc_result_t status = ISC_R_NOTFOUND;
01242         const char *np;
01243         struct dns_zone *zone = NULL;
01244         struct data_string nsaddrs;
01245         struct in_addr zone_addr;
01246         struct in6_addr zone_addr6;
01247         int ix;
01248 
01249         if (direction == FIND_FORWARD) {
01250                 np = (const char *)ddns_cb->fwd_name.data;
01251         } else {
01252                 np = (const char *)ddns_cb->rev_name.data;
01253         }
01254 
01255         /* We can't look up a null zone. */
01256         if ((np == NULL) || (*np == '\0')) {
01257                 return (DHCP_R_INVALIDARG);
01258         }
01259 
01260         /*
01261          * For each subzone, try to find a cached zone.
01262          */
01263         for (;;) {
01264                 status = dns_zone_lookup(&zone, np);
01265                 if (status == ISC_R_SUCCESS)
01266                         break;
01267 
01268                 np = strchr(np, '.');
01269                 if (np == NULL)
01270                         break;
01271                 np++;
01272         }
01273 
01274         if (status != ISC_R_SUCCESS)
01275                 return (status);
01276 
01277         /* Make sure the zone is valid, we've already gotten
01278          * rid of expired dynamic zones.  Check to see if
01279          * we repudiated this zone.  If so give up.
01280          */
01281         if ((zone->flags & DNS_ZONE_INACTIVE) != 0) {
01282                 dns_zone_dereference(&zone, MDL);
01283                 return (ISC_R_FAILURE);
01284         }
01285 
01286         /* Make sure the zone name will fit. */
01287         if (strlen(zone->name) > sizeof(ddns_cb->zone_name)) {
01288                 dns_zone_dereference(&zone, MDL);
01289                 return (ISC_R_NOSPACE);
01290         }
01291         strcpy((char *)&ddns_cb->zone_name[0], zone->name);
01292 
01293         memset (&nsaddrs, 0, sizeof nsaddrs);
01294         ix = 0;
01295 
01296         if (zone->primary) {
01297                 if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
01298                                           NULL, NULL, &global_scope,
01299                                           zone->primary, MDL)) {
01300                         int ip = 0;
01301                         while (ix < DHCP_MAXNS) {
01302                                 if (ip + 4 > nsaddrs.len)
01303                                         break;
01304                                 memcpy(&zone_addr, &nsaddrs.data[ip], 4);
01305                                 isc_sockaddr_fromin(&ddns_cb->zone_addrs[ix],
01306                                                     &zone_addr,
01307                                                     NS_DEFAULTPORT);
01308                                 ISC_LIST_APPEND(ddns_cb->zone_server_list,
01309                                                 &ddns_cb->zone_addrs[ix],
01310                                                 link);
01311                                 ip += 4;
01312                                 ix++;
01313                         }
01314                         data_string_forget(&nsaddrs, MDL);
01315                 }
01316         }
01317 
01318         if (zone->primary6) {
01319                 if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
01320                                           NULL, NULL, &global_scope,
01321                                           zone->primary6, MDL)) {
01322                         int ip = 0;
01323                         while (ix < DHCP_MAXNS) {
01324                                 if (ip + 16 > nsaddrs.len)
01325                                         break;
01326                                 memcpy(&zone_addr6, &nsaddrs.data[ip], 16);
01327                                 isc_sockaddr_fromin6(&ddns_cb->zone_addrs[ix],
01328                                                     &zone_addr6,
01329                                                     NS_DEFAULTPORT);
01330                                 ISC_LIST_APPEND(ddns_cb->zone_server_list,
01331                                                 &ddns_cb->zone_addrs[ix],
01332                                                 link);
01333                                 ip += 16;
01334                                 ix++;
01335                         }
01336                         data_string_forget(&nsaddrs, MDL);
01337                 }
01338         }
01339 
01340         if (zone->secondary) {
01341                 if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
01342                                           NULL, NULL, &global_scope,
01343                                           zone->secondary, MDL)) {
01344                         int ip = 0;
01345                         while (ix < DHCP_MAXNS) {
01346                                 if (ip + 4 > nsaddrs.len)
01347                                         break;
01348                                 memcpy(&zone_addr, &nsaddrs.data[ip], 4);
01349                                 isc_sockaddr_fromin(&ddns_cb->zone_addrs[ix],
01350                                                     &zone_addr,
01351                                                     NS_DEFAULTPORT);
01352                                 ISC_LIST_APPEND(ddns_cb->zone_server_list,
01353                                                 &ddns_cb->zone_addrs[ix],
01354                                                 link);
01355                                 ip += 4;
01356                                 ix++;
01357                         }
01358                         data_string_forget (&nsaddrs, MDL);
01359                 }
01360         }
01361 
01362         if (zone->secondary6) {
01363                 if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
01364                                           NULL, NULL, &global_scope,
01365                                           zone->secondary6, MDL)) {
01366                         int ip = 0;
01367                         while (ix < DHCP_MAXNS) {
01368                                 if (ip + 16 > nsaddrs.len)
01369                                         break;
01370                                 memcpy(&zone_addr6, &nsaddrs.data[ip], 16);
01371                                 isc_sockaddr_fromin6(&ddns_cb->zone_addrs[ix],
01372                                                     &zone_addr6,
01373                                                     NS_DEFAULTPORT);
01374                                 ISC_LIST_APPEND(ddns_cb->zone_server_list,
01375                                                 &ddns_cb->zone_addrs[ix],
01376                                                 link);
01377                                 ip += 16;
01378                                 ix++;
01379                         }
01380                         data_string_forget (&nsaddrs, MDL);
01381                 }
01382         }
01383 
01384         dns_zone_reference(&ddns_cb->zone, zone, MDL);
01385         dns_zone_dereference (&zone, MDL);
01386         return ISC_R_SUCCESS;
01387 }
01388 
01389 void forget_zone (struct dns_zone **zone)
01390 {
01391         dns_zone_dereference (zone, MDL);
01392 }
01393 
01394 void repudiate_zone (struct dns_zone **zone)
01395 {
01396         /* verify that we have a pointer at least */
01397         if ((zone == NULL) || (*zone == NULL)) {
01398                 log_info("Null argument to repudiate zone");
01399                 return;
01400         }
01401 
01402         (*zone)->flags |= DNS_ZONE_INACTIVE;
01403         dns_zone_dereference(zone, MDL);
01404 }
01405 
01406 #if defined (DNS_ZONE_LOOKUP)
01407 void cache_found_zone(dhcp_ddns_ns_t *ns_cb)
01408 {
01409         struct dns_zone *zone = NULL;
01410         int len, remove_zone = 0;
01411 
01412         /* See if there's already such a zone. */
01413         if (dns_zone_lookup(&zone, ns_cb->zname) == ISC_R_SUCCESS) {
01414                 /* If it's not a dynamic zone, leave it alone. */
01415                 if (zone->timeout == 0)
01416                         return;
01417 
01418                 /* Remove any old addresses in case they've changed */
01419                 if (zone->primary)
01420                         option_cache_dereference(&zone->primary, MDL);
01421                 if (zone->primary6)
01422                         option_cache_dereference(&zone->primary6, MDL);
01423 
01424                 /* Set the flag to remove the zone from the hash if
01425                    we have problems */
01426                 remove_zone = 1;
01427         } else if (dns_zone_allocate(&zone, MDL) == 0) {
01428                 return;
01429         } else {
01430                 /* We've just allocated the zone, now we need
01431                  * to allocate space for the name and addresses
01432                  */
01433 
01434                 /* allocate space for the name */
01435                 len = strlen(ns_cb->zname);
01436                 zone->name = dmalloc(len + 2, MDL);
01437                 if (zone->name == NULL) {
01438                         goto cleanup;
01439                 }
01440 
01441                 /* Copy the name and add a trailing '.' if necessary */
01442                 strcpy(zone->name, ns_cb->zname);
01443                 if (zone->name[len-1] != '.') {
01444                         zone->name[len] = '.';
01445                         zone->name[len+1] = 0;
01446                 }
01447         }
01448 
01449         zone->timeout = cur_time + ns_cb->ttl;
01450 
01451         if (ns_cb->num_addrs != 0) {
01452                 len = ns_cb->num_addrs * sizeof(struct in_addr);
01453                 if ((!option_cache_allocate(&zone->primary, MDL)) ||
01454                     (!buffer_allocate(&zone->primary->data.buffer,
01455                                       len, MDL))) {
01456                         if (remove_zone == 1)
01457                                 remove_dns_zone(zone);
01458                         goto cleanup;
01459                 }
01460                 memcpy(zone->primary->data.buffer->data, ns_cb->addrs, len);
01461                 zone->primary->data.data = 
01462                         &zone->primary->data.buffer->data[0];
01463                 zone->primary->data.len = len;
01464         }
01465         if (ns_cb->num_addrs6 != 0) {
01466                 len = ns_cb->num_addrs6 * sizeof(struct in6_addr);
01467                 if ((!option_cache_allocate(&zone->primary6, MDL)) ||
01468                     (!buffer_allocate(&zone->primary6->data.buffer,
01469                                       len, MDL))) {
01470                         if (remove_zone == 1)
01471                                 remove_dns_zone(zone);
01472                         goto cleanup;
01473                 }
01474                 memcpy(zone->primary6->data.buffer->data, ns_cb->addrs6, len);
01475                 zone->primary6->data.data = 
01476                         &zone->primary6->data.buffer->data[0];
01477                 zone->primary6->data.len = len;
01478         }
01479 
01480         enter_dns_zone(zone);
01481 
01482  cleanup:
01483         dns_zone_dereference(&zone, MDL);
01484         return;
01485 }
01486 #endif
01487 
01512 int get_std_dhcid(dhcp_ddns_cb_t *ddns_cb,
01513                   int type,
01514                   const u_int8_t *identifier,
01515                   unsigned id_len)
01516 {
01517         struct data_string *id = &ddns_cb->dhcid;
01518         isc_sha256_t sha256;
01519         unsigned char buf[ISC_SHA256_DIGESTLENGTH];
01520         unsigned char fwd_buf[256];
01521         unsigned fwd_buflen = 0;
01522 
01523         /* Types can only be 0..(2^16)-1. */
01524         if (type < 0 || type > 65535)
01525                 return (0);
01526 
01527         /* We need to convert the fwd name to wire representation */
01528         if (MRns_name_pton((char *)ddns_cb->fwd_name.data, fwd_buf, 256) == -1)
01529                 return (0);
01530         while(fwd_buf[fwd_buflen] != 0) {
01531                 fwd_buflen += fwd_buf[fwd_buflen] + 1;
01532         }
01533         fwd_buflen++;
01534 
01535         if (!buffer_allocate(&id->buffer,
01536                              ISC_SHA256_DIGESTLENGTH + 2 + 1,
01537                              MDL))
01538                 return (0);
01539         id->data = id->buffer->data;
01540 
01541         /* The two first bytes contain the type identifier. */
01542         putUShort(id->buffer->data, (unsigned)type);
01543 
01544         /* The next is the digest type, SHA-256 is 1 */
01545         putUChar(id->buffer->data + 2, 1u);
01546 
01547         /* Computing the digest */
01548         isc_sha256_init(&sha256);
01549         isc_sha256_update(&sha256, identifier, id_len);
01550         isc_sha256_update(&sha256, fwd_buf, fwd_buflen);
01551         isc_sha256_final(buf, &sha256);
01552 
01553         memcpy(id->buffer->data + 3, &buf, ISC_SHA256_DIGESTLENGTH);
01554 
01555         id->len = ISC_SHA256_DIGESTLENGTH + 2 + 1;
01556 
01557         return (1);
01558 }
01559 
01581 int get_int_dhcid (dhcp_ddns_cb_t *ddns_cb,
01582                    int type,
01583                    const u_int8_t *data,
01584                    unsigned len)
01585 {
01586         struct data_string *id = &ddns_cb->dhcid;
01587         unsigned char buf[ISC_MD5_DIGESTLENGTH];
01588         isc_md5_t md5;
01589         int i;
01590 
01591         /* Types can only be 0..(2^16)-1. */
01592         if (type < 0 || type > 65535)
01593                 return (0);
01594 
01595         /*
01596          * Hexadecimal MD5 digest plus two byte type, NUL,
01597          * and one byte for length for dns.
01598          */
01599         if (!buffer_allocate(&id -> buffer,
01600                              (ISC_MD5_DIGESTLENGTH * 2) + 4, MDL))
01601                 return (0);
01602         id->data = id->buffer->data;
01603 
01604         /*
01605          * We put the length into the first byte to turn 
01606          * this into a dns text string.  This avoid needing to
01607          * copy the string to add the byte later.
01608          */
01609         id->buffer->data[0] = ISC_MD5_DIGESTLENGTH * 2 + 2;
01610 
01611         /* Put the type in the next two bytes. */
01612         id->buffer->data[1] = "0123456789abcdef"[(type >> 4) & 0xf];
01613         /* This should have been [type & 0xf] but now that
01614          * it is in use we need to leave it this way in order
01615          * to avoid disturbing customer's lease files
01616          */
01617         id->buffer->data[2] = "0123456789abcdef"[type % 15];
01618   
01619         /* Mash together an MD5 hash of the identifier. */
01620         isc_md5_init(&md5);
01621         isc_md5_update(&md5, data, len);
01622         isc_md5_final(&md5, buf);
01623 
01624         /* Convert into ASCII. */
01625         for (i = 0; i < ISC_MD5_DIGESTLENGTH; i++) {
01626                 id->buffer->data[i * 2 + 3] =
01627                         "0123456789abcdef"[(buf[i] >> 4) & 0xf];
01628                 id->buffer->data[i * 2 + 4] =
01629                         "0123456789abcdef"[buf[i] & 0xf];
01630         }
01631 
01632         id->len = ISC_MD5_DIGESTLENGTH * 2 + 3;
01633         id->buffer->data[id->len] = 0;
01634         id->terminated = 1;
01635 
01636         return (1);
01637 }
01638 
01639 int get_dhcid(dhcp_ddns_cb_t *ddns_cb,
01640               int type,
01641               const u_int8_t *identifier,
01642               unsigned id_len)
01643 {
01644         if (ddns_cb->dhcid_class == dns_rdatatype_dhcid)
01645                 return get_std_dhcid(ddns_cb, type, identifier, id_len);
01646         else 
01647                 return get_int_dhcid(ddns_cb, type, identifier, id_len);
01648 }
01649 
01650 /*
01651  * The dhcid (text version) that we pass to DNS includes a length byte
01652  * at the start but the text we store in the lease doesn't include the
01653  * length byte.  The following routines are to convert between the two
01654  * styles.
01655  *
01656  * When converting from a dhcid to a leaseid we reuse the buffer and
01657  * simply adjust the data pointer and length fields in the data string.
01658  * This avoids any prolems with allocating space.
01659  */
01660 
01661 void
01662 dhcid_tolease(struct data_string *dhcid,
01663               struct data_string *leaseid)
01664 {
01665         /* copy the data string then update the fields */
01666         data_string_copy(leaseid, dhcid, MDL);
01667         leaseid->data++;
01668         leaseid->len--;
01669 }
01670 
01671 isc_result_t
01672 dhcid_fromlease(struct data_string *dhcid,
01673                 struct data_string *leaseid)
01674 {
01675         if (!buffer_allocate(&dhcid->buffer, leaseid->len + 2, MDL)) {
01676                 return(ISC_R_FAILURE);
01677         }
01678 
01679         dhcid->data = dhcid->buffer->data;
01680 
01681         dhcid->buffer->data[0] = leaseid->len;
01682         memcpy(dhcid->buffer->data + 1, leaseid->data, leaseid->len);
01683         dhcid->len = leaseid->len + 1;
01684         if (leaseid->terminated == 1) {
01685                 dhcid->buffer->data[dhcid->len] = 0;
01686                 dhcid->terminated = 1;
01687         }
01688 
01689         return(ISC_R_SUCCESS);
01690 }
01691 
01692 /* 
01693  * Construct the dataset for this item.
01694  * This is a fairly simple arrangement as the operations we do are simple.
01695  * If there is data we simply have the rdata point to it - the formatting
01696  * must be correct already.  We then link the rdatalist to the rdata and
01697  * create a rdataset from the rdatalist.
01698  */
01699 
01700 static isc_result_t
01701 make_dns_dataset(dns_rdataclass_t  dataclass,
01702                  dns_rdatatype_t   datatype,
01703                  dhcp_ddns_data_t *dataspace,
01704                  unsigned char    *data,
01705                  int               datalen,
01706                  int               ttl)
01707 {
01708         dns_rdata_t *rdata = &dataspace->rdata;
01709         dns_rdatalist_t *rdatalist = &dataspace->rdatalist;
01710         dns_rdataset_t *rdataset = &dataspace->rdataset;
01711 
01712         isc_region_t region;
01713 
01714         /* set up the rdata */
01715         dns_rdata_init(rdata);
01716 
01717         if (data == NULL) {
01718                 /* No data, set up the rdata fields we care about */
01719                 rdata->flags = DNS_RDATA_UPDATE;
01720                 rdata->type = datatype;
01721                 rdata->rdclass = dataclass;
01722         } else {
01723                 switch(datatype) {
01724                 case dns_rdatatype_a:
01725                 case dns_rdatatype_aaaa:
01726                 case dns_rdatatype_txt:
01727                 case dns_rdatatype_dhcid:
01728                 case dns_rdatatype_ptr:
01729                         /* The data must be in the right format we simply
01730                          * need to supply it via the correct structure */
01731                         region.base   = data;
01732                         region.length = datalen;
01733                         dns_rdata_fromregion(rdata, dataclass, datatype,
01734                                              &region);
01735                         break;
01736                 default:
01737                         return(DHCP_R_INVALIDARG);
01738                         break;
01739                 }
01740         }
01741 
01742         /* setup the datalist and attach the rdata to it */
01743         dns_rdatalist_init(rdatalist);
01744         rdatalist->type = datatype;
01745         rdatalist->rdclass = dataclass;
01746         rdatalist->ttl = ttl;
01747         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
01748 
01749         /* convert the datalist to a dataset */
01750         dns_rdataset_init(rdataset);
01751         dns_rdatalist_tordataset(rdatalist, rdataset);
01752 
01753         return(ISC_R_SUCCESS);
01754 }
01755 
01756 /*
01757  * When a DHCP client or server intends to update an A RR, it first
01758  * prepares a DNS UPDATE query which includes as a prerequisite the
01759  * assertion that the name does not exist.  The update section of the
01760  * query attempts to add the new name and its IP address mapping (an A
01761  * RR), and the DHCID RR with its unique client-identity.
01762  *   -- "Interaction between DHCP and DNS"
01763  *
01764  * There are two cases, one for the server and one for the client.
01765  *
01766  * For the server the first step will have a request of:
01767  * The name is not in use
01768  * Add an A RR
01769  * Add a DHCID RR
01770  *
01771  * For the client the first step will have a request of:
01772  * The A RR does not exist
01773  * Add an A RR
01774  * Add a DHCID RR
01775  */
01776 
01777 static isc_result_t
01778 ddns_modify_fwd_add1(dhcp_ddns_cb_t   *ddns_cb,
01779                      dhcp_ddns_data_t *dataspace,
01780                      dns_name_t       *pname,
01781                      dns_name_t       *uname)
01782 {
01783         isc_result_t result;
01784 
01785         /* Construct the prerequisite list */
01786         if ((ddns_cb->flags & DDNS_INCLUDE_RRSET) != 0) {
01787                 /* The A RR shouldn't exist */
01788                 result = make_dns_dataset(dns_rdataclass_none,
01789                                           ddns_cb->address_type,
01790                                           dataspace, NULL, 0, 0);
01791         } else {
01792                 /* The name is not in use */
01793                 result = make_dns_dataset(dns_rdataclass_none,
01794                                           dns_rdatatype_any,
01795                                           dataspace, NULL, 0, 0);
01796         }
01797         if (result != ISC_R_SUCCESS) {
01798                 return(result);
01799         }
01800         ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
01801         dataspace++;
01802 
01803         /* Construct the update list */
01804         /* Add the A RR */
01805         result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type,
01806                                   dataspace,
01807                                   (unsigned char *)ddns_cb->address.iabuf,
01808                                   ddns_cb->address.len, ddns_cb->ttl);
01809         if (result != ISC_R_SUCCESS) {
01810                 return(result);
01811         }
01812         ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
01813         dataspace++;
01814 
01815         /* Add the DHCID RR */
01816         result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
01817                                   dataspace, 
01818                                   (unsigned char *)ddns_cb->dhcid.data,
01819                                   ddns_cb->dhcid.len, ddns_cb->ttl);
01820         if (result != ISC_R_SUCCESS) {
01821                 return(result);
01822         }
01823         ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
01824 
01825         return(ISC_R_SUCCESS);
01826 }
01827 
01828 /*
01829  * If the first update operation fails with YXDOMAIN, the updater can
01830  * conclude that the intended name is in use.  The updater then
01831  * attempts to confirm that the DNS name is not being used by some
01832  * other host. The updater prepares a second UPDATE query in which the
01833  * prerequisite is that the desired name has attached to it a DHCID RR
01834  * whose contents match the client identity.  The update section of
01835  * this query deletes the existing A records on the name, and adds the
01836  * A record that matches the DHCP binding and the DHCID RR with the
01837  * client identity.
01838  *   -- "Interaction between DHCP and DNS"
01839  *
01840  * The message for the second step depends on if we are doing conflict
01841  * resolution.  If we are we include a prerequisite.  If not we delete
01842  * the DHCID in addition to all A rrsets.
01843  *
01844  * Conflict resolution:
01845  * DHCID RR exists, and matches client identity.
01846  * Delete A RRset.
01847  * Add A RR.
01848  *
01849  * Conflict override:
01850  * Delete DHCID RRs.
01851  * Add DHCID RR
01852  * Delete A RRset.
01853  * Add A RR.
01854  */
01855 
01856 static isc_result_t
01857 ddns_modify_fwd_add2(dhcp_ddns_cb_t   *ddns_cb,
01858                      dhcp_ddns_data_t *dataspace,
01859                      dns_name_t       *pname,
01860                      dns_name_t       *uname)
01861 {
01862         isc_result_t result = ISC_R_SUCCESS;
01863 
01864         /*
01865          * If we are doing conflict resolution (unset) we use a prereq list.
01866          * If not we delete the DHCID in addition to all A rrsets.
01867          */
01868         if ((ddns_cb->flags & DDNS_CONFLICT_OVERRIDE) == 0) {
01869                 /* Construct the prereq list */
01870                 /* The DHCID RR exists and matches the client identity */
01871                 result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
01872                                           dataspace, 
01873                                           (unsigned char *)ddns_cb->dhcid.data,
01874                                           ddns_cb->dhcid.len, 0);
01875                 if (result != ISC_R_SUCCESS) {
01876                         return(result);
01877                 }
01878                 ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
01879                 dataspace++;
01880         } else {
01881                 /* Start constructing the update list.
01882                  * Conflict detection override: delete DHCID RRs */
01883                 result = make_dns_dataset(dns_rdataclass_any,
01884                                           ddns_cb->dhcid_class,
01885                                           dataspace, NULL, 0, 0);
01886                 if (result != ISC_R_SUCCESS) {
01887                         return(result);
01888                 }
01889                 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
01890                 dataspace++;
01891 
01892                 /* Add current DHCID RR */
01893                 result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
01894                                           dataspace, 
01895                                           (unsigned char *)ddns_cb->dhcid.data,
01896                                           ddns_cb->dhcid.len, ddns_cb->ttl);
01897                 if (result != ISC_R_SUCCESS) {
01898                         return(result);
01899                 }
01900                 ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
01901                 dataspace++;
01902         }
01903 
01904         /* Start or continue constructing the update list */
01905         /* Delete the A RRset */
01906         result = make_dns_dataset(dns_rdataclass_any, ddns_cb->address_type,
01907                                   dataspace, NULL, 0, 0);
01908         if (result != ISC_R_SUCCESS) {
01909                 return(result);
01910         }
01911         ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
01912         dataspace++;
01913 
01914         /* Add the A RR */
01915         result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type,
01916                                   dataspace, 
01917                                   (unsigned char *)ddns_cb->address.iabuf,
01918                                   ddns_cb->address.len, ddns_cb->ttl);
01919         if (result != ISC_R_SUCCESS) {
01920                 return(result);
01921         }
01922         ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
01923 
01924         return(ISC_R_SUCCESS);
01925 }
01926 
01927 /*
01928  * The entity chosen to handle the A record for this client (either the
01929  * client or the server) SHOULD delete the A record that was added when
01930  * the lease was made to the client.
01931  *
01932  * In order to perform this delete, the updater prepares an UPDATE
01933  * query which contains two prerequisites.  The first prerequisite
01934  * asserts that the DHCID RR exists whose data is the client identity
01935  * described in Section 4.3. The second prerequisite asserts that the
01936  * data in the A RR contains the IP address of the lease that has
01937  * expired or been released.
01938  *   -- "Interaction between DHCP and DNS"
01939  *
01940  * RFC 4703 has relaxed the prereqisites to only checking the DHCID RR
01941  * and we have adopted that to minizmie problems due to interruptions
01942  * when doing a deletion.  
01943  *
01944  * First try has:
01945  * DHCID RR exists, and matches client identity.
01946  * Delete appropriate A RR.
01947  */
01948 
01949 static isc_result_t
01950 ddns_modify_fwd_rem1(dhcp_ddns_cb_t   *ddns_cb,
01951                      dhcp_ddns_data_t *dataspace,
01952                      dns_name_t       *pname,
01953                      dns_name_t       *uname)
01954 {
01955         isc_result_t result = ISC_R_SUCCESS;
01956 
01957         /* Consruct the prereq list */
01958         /* The DHCID RR exists and matches the client identity */
01959         result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
01960                                   dataspace, 
01961                                   (unsigned char *)ddns_cb->dhcid.data,
01962                                   ddns_cb->dhcid.len, 0);
01963         if (result != ISC_R_SUCCESS) {
01964                 return(result);
01965         }
01966         ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
01967         dataspace++;
01968 
01969         /* Construct the update list */
01970         /* Delete A RRset */
01971         result = make_dns_dataset(dns_rdataclass_none, ddns_cb->address_type,
01972                                   dataspace,
01973                                   (unsigned char *)ddns_cb->address.iabuf,
01974                                   ddns_cb->address.len, 0);
01975         if (result != ISC_R_SUCCESS) {
01976                 return(result);
01977         }
01978         ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
01979 
01980         return(ISC_R_SUCCESS);
01981 }
01982 
01983 /*
01984  * If the deletion of the A succeeded, and there are no A or AAAA
01985  * records left for this domain, then we can blow away the DHCID
01986  * record as well.   We can't blow away the DHCID record above
01987  * because it's possible that more than one record has been added
01988  * to this domain name.
01989  *
01990  * Second query has:
01991  * A RR does not exist.
01992  * AAAA RR does not exist.
01993  * Delete appropriate DHCID RR.
01994  */
01995 
01996 static isc_result_t
01997 ddns_modify_fwd_rem2(dhcp_ddns_cb_t   *ddns_cb,
01998                      dhcp_ddns_data_t *dataspace,
01999                      dns_name_t       *pname,
02000                      dns_name_t       *uname)
02001 {
02002         isc_result_t result;
02003 
02004         /* Construct the prereq list */
02005         /* The A RR does not exist */
02006         result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_a,
02007                                   dataspace, NULL, 0, 0);
02008         if (result != ISC_R_SUCCESS) {
02009                 return(result);
02010         }
02011         ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
02012         dataspace++;
02013 
02014         /* The AAAA RR does not exist */
02015         result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_aaaa,
02016                                   dataspace, NULL, 0, 0);
02017         if (result != ISC_R_SUCCESS) {
02018                 return(result);
02019         }
02020         ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
02021         dataspace++;
02022 
02023         /* Construct the update list */
02024         /* Delete DHCID RR */
02025         result = make_dns_dataset(dns_rdataclass_none, ddns_cb->dhcid_class,
02026                                   dataspace,
02027                                   (unsigned char *)ddns_cb->dhcid.data,
02028                                   ddns_cb->dhcid.len, 0);
02029         if (result != ISC_R_SUCCESS) {
02030                 return(result);
02031         }
02032         ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
02033 
02034         return(ISC_R_SUCCESS);
02035 }
02036 
02037 /*
02038  * This routine converts from the task action call into something
02039  * easier to work with.  It also handles the common case of a signature
02040  * or zone not being correct.
02041  */
02042 void ddns_interlude(isc_task_t  *taskp,
02043                     isc_event_t *eventp)
02044 {
02045         dhcp_ddns_cb_t *ddns_cb = (dhcp_ddns_cb_t *)eventp->ev_arg;
02046         dns_clientupdateevent_t *ddns_event = (dns_clientupdateevent_t *)eventp;
02047         isc_result_t eresult = ddns_event->result;
02048         isc_result_t result;
02049 
02050         /* We've extracted the information we want from it, get rid of
02051          * the event block.*/
02052         isc_event_free(&eventp);
02053 
02054 #if defined (TRACING)
02055         if (trace_record()) {
02056                 trace_ddns_input_write(ddns_cb, eresult);
02057         }
02058 #endif
02059 
02060 #if defined (DEBUG_DNS_UPDATES)
02061         print_dns_status(DDNS_PRINT_INBOUND, ddns_cb, eresult);
02062 #endif
02063 
02064         /* This transaction is complete, clear the value */
02065         dns_client_destroyupdatetrans(&ddns_cb->transaction);
02066 
02067         /* If we cancelled or tried to cancel the operation we just
02068          * need to clean up. */
02069         if ((eresult == ISC_R_CANCELED) ||
02070             ((ddns_cb->flags & DDNS_ABORT) != 0)) {
02071 #if defined (DEBUG_DNS_UPDATES)
02072                 log_info("DDNS: completeing transaction cancellation cb=%p, "
02073                          "flags=%x, %s",
02074                          ddns_cb, ddns_cb->flags, isc_result_totext(eresult));
02075 #endif
02076                 if ((ddns_cb->flags & DDNS_ABORT) == 0) {
02077                         log_info("DDNS: cleaning up lease pointer for a cancel "
02078                                  "cb=%p", ddns_cb);
02079                         /* 
02080                          * We shouldn't actually be able to get here but
02081                          * we are.  This means we haven't cleaned up
02082                          * the lease pointer so we need to do that before
02083                          * freeing the cb.  
02084                          */
02085                         ddns_cb->cur_func(ddns_cb, eresult);
02086                         return;
02087                 }
02088 
02089                 if (ddns_cb->next_op != NULL) {
02090                         /* if necessary cleanup up next op block */
02091                         ddns_cb_free(ddns_cb->next_op, MDL);
02092                 }
02093                 ddns_cb_free(ddns_cb, MDL);
02094                 return;
02095         }
02096 
02097         /* If we had a problem with our key or zone try again */
02098         if ((eresult == DNS_R_NOTAUTH) ||
02099             (eresult == DNS_R_NOTZONE)) {
02100                 int i;
02101                 /* Our zone information was questionable,
02102                  * repudiate it and try again */
02103                 log_error("DDNS: bad zone information, repudiating zone %s",
02104                           ddns_cb->zone_name);
02105                 repudiate_zone(&ddns_cb->zone);
02106                 ddns_cb->zone_name[0]    = 0;
02107                 ISC_LIST_INIT(ddns_cb->zone_server_list);
02108                 for (i = 0; i < DHCP_MAXNS; i++) {
02109                         ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link);
02110                 }
02111 
02112                 if ((ddns_cb->state == DDNS_STATE_ADD_PTR) ||
02113                     (ddns_cb->state == DDNS_STATE_REM_PTR)) {
02114                         result = ddns_modify_ptr(ddns_cb, MDL);
02115                 } else {
02116                         result = ddns_modify_fwd(ddns_cb, MDL);
02117                 }
02118 
02119                 if (result != ISC_R_SUCCESS) {
02120                         /* if we couldn't redo the query log it and
02121                          * let the next function clean it up */
02122                         log_info("DDNS: Failed to retry after zone failure");
02123                         ddns_cb->cur_func(ddns_cb, result);
02124                 }
02125                 return;
02126         } else {
02127                 /* pass it along to be processed */
02128                 ddns_cb->cur_func(ddns_cb, eresult);
02129         }
02130         
02131         return;
02132 }
02133 
02134 /*
02135  * This routine does the generic work for sending a ddns message to
02136  * modify the forward record (A or AAAA) and calls one of a set of
02137  * routines to build the specific message.
02138  */
02139 
02140 isc_result_t
02141 ddns_modify_fwd(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
02142 {
02143         isc_result_t result;
02144         dns_tsec_t *tsec_key = NULL;
02145 
02146         unsigned char *clientname;
02147         dhcp_ddns_data_t *dataspace = NULL;
02148         dns_namelist_t prereqlist, updatelist;
02149         dns_fixedname_t zname0, pname0, uname0;
02150         dns_name_t *zname = NULL, *pname, *uname;
02151 
02152         isc_sockaddrlist_t *zlist = NULL;
02153 
02154         /* Get a pointer to the clientname to make things easier. */
02155         clientname = (unsigned char *)ddns_cb->fwd_name.data;
02156 
02157         /* Extract and validate the type of the address. */
02158         if (ddns_cb->address.len == 4) {
02159                 ddns_cb->address_type = dns_rdatatype_a;
02160         } else if (ddns_cb->address.len == 16) {
02161                 ddns_cb->address_type = dns_rdatatype_aaaa;
02162         } else {
02163                 return DHCP_R_INVALIDARG;
02164         }
02165 
02166         /*
02167          * If we already have a zone use it, otherwise try to lookup the
02168          * zone in our cache.  If we find one we will have a pointer to
02169          * the zone that needs to be dereferenced when we are done with it.
02170          * If we don't find one that is okay we'll let the DNS code try and
02171          * find the information for us.
02172          */
02173 
02174         if (ddns_cb->zone == NULL) {
02175                 result = find_cached_zone(ddns_cb, FIND_FORWARD);
02176 #if defined (DNS_ZONE_LOOKUP)
02177                 if (result == ISC_R_NOTFOUND) {
02178                         /*
02179                          * We didn't find a cached zone, see if we can
02180                          * can find a nameserver and create a zone.
02181                          */
02182                         if (find_zone_start(ddns_cb, FIND_FORWARD)
02183                             == ISC_R_SUCCESS) {
02184                                 /*
02185                                  * We have started the process to find a zone
02186                                  * queue the ddns_cb for processing after we
02187                                  * create the zone
02188                                  */
02189                                 /* sar - not yet implemented, currently we just
02190                                  * arrange for things to get cleaned up
02191                                  */
02192                                 goto cleanup;
02193                         }
02194                 }
02195 #endif
02196                 if (result != ISC_R_SUCCESS)
02197                         goto cleanup;
02198         }
02199 
02200         /*
02201          * If we have a zone try to get any information we need
02202          * from it - name, addresses and the key.  The address 
02203          * and key may be empty the name can't be.
02204          */
02205         if (ddns_cb->zone) {
02206                 /* Set up the zone name for use by DNS */
02207                 result = dhcp_isc_name(ddns_cb->zone_name, &zname0, &zname);
02208                 if (result != ISC_R_SUCCESS) {
02209                         log_error("Unable to build name for zone for "
02210                                   "fwd update: %s %s",
02211                                   ddns_cb->zone_name,
02212                                   isc_result_totext(result));
02213                         goto cleanup;
02214                 }
02215 
02216                 if (!(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
02217                         /* If we have any addresses get them */
02218                         zlist = &ddns_cb->zone_server_list;
02219                 }
02220                 
02221 
02222                 if (ddns_cb->zone->key != NULL) {
02223                         /*
02224                          * Not having a key is fine, having a key
02225                          * but not a tsec is odd so we warn the user.
02226                          */
02227                         /*sar*/
02228                         /* should we do the warning? */
02229                         tsec_key = ddns_cb->zone->key->tsec_key;
02230                         if (tsec_key == NULL) {
02231                                 log_error("No tsec for use with key %s",
02232                                           ddns_cb->zone->key->name);
02233                         }
02234                 }
02235         }
02236 
02237         /* Set up the DNS names for the prereq and update lists */
02238         if (((result = dhcp_isc_name(clientname, &pname0, &pname))
02239              != ISC_R_SUCCESS) ||
02240             ((result = dhcp_isc_name(clientname, &uname0, &uname))
02241              != ISC_R_SUCCESS)) {
02242                 log_error("Unable to build name for fwd update: %s %s",
02243                           clientname, isc_result_totext(result));
02244                 goto cleanup;
02245         }
02246 
02247         /* Allocate the various isc dns library structures we may require. */
02248         dataspace = isc_mem_get(dhcp_gbl_ctx.mctx, sizeof(*dataspace) * 4);
02249         if (dataspace == NULL) {
02250                 log_error("Unable to allocate memory for fwd update");
02251                 result = ISC_R_NOMEMORY; 
02252                 goto cleanup;
02253         }
02254 
02255         ISC_LIST_INIT(prereqlist);
02256         ISC_LIST_INIT(updatelist);
02257 
02258         switch(ddns_cb->state) {
02259         case DDNS_STATE_ADD_FW_NXDOMAIN:
02260                 result = ddns_modify_fwd_add1(ddns_cb, dataspace,
02261                                               pname, uname);
02262                 if (result != ISC_R_SUCCESS) {
02263                         goto cleanup;
02264                 }
02265                 ISC_LIST_APPEND(prereqlist, pname, link);
02266                 break;
02267         case DDNS_STATE_ADD_FW_YXDHCID:
02268                 result = ddns_modify_fwd_add2(ddns_cb, dataspace,
02269                                                pname, uname);
02270                 if (result != ISC_R_SUCCESS) {
02271                         goto cleanup;
02272                 }
02273 
02274                 /* If we aren't doing conflict override we have entries
02275                  * in the pname list and we need to attach it to the
02276                  * prereqlist */
02277 
02278                 if ((ddns_cb->flags & DDNS_CONFLICT_OVERRIDE) == 0) {
02279                         ISC_LIST_APPEND(prereqlist, pname, link);
02280                 }
02281 
02282                 break;
02283         case DDNS_STATE_REM_FW_YXDHCID:
02284                 result = ddns_modify_fwd_rem1(ddns_cb, dataspace,
02285                                               pname, uname);
02286                 if (result != ISC_R_SUCCESS) {
02287                         goto cleanup;
02288                 }
02289                 ISC_LIST_APPEND(prereqlist, pname, link);
02290                 break;
02291         case DDNS_STATE_REM_FW_NXRR:
02292                 result = ddns_modify_fwd_rem2(ddns_cb, dataspace,
02293                                               pname, uname);
02294                 if (result != ISC_R_SUCCESS) {
02295                         goto cleanup;
02296                 }
02297                 ISC_LIST_APPEND(prereqlist, pname, link);
02298                 break;
02299 
02300         default:
02301                 log_error("Invalid operation in ddns code.");
02302                 result = DHCP_R_INVALIDARG;
02303                 goto cleanup;
02304                 break;
02305         }
02306 
02307         /*
02308          * We always have an update list but may not have a prereqlist
02309          * if we are doing conflict override.
02310          */
02311         ISC_LIST_APPEND(updatelist, uname, link);
02312 
02313         /* send the message, cleanup and return the result */
02314         result = ddns_update(dhcp_gbl_ctx.dnsclient,
02315                              dns_rdataclass_in, zname,
02316                              &prereqlist, &updatelist,
02317                              zlist, tsec_key,
02318                              DNS_CLIENTRESOPT_ALLOWRUN,
02319                              dhcp_gbl_ctx.task,
02320                              ddns_interlude,
02321                              (void *)ddns_cb,
02322                              &ddns_cb->transaction);
02323         if (result == ISC_R_FAMILYNOSUPPORT) {
02324                 log_info("Unable to perform DDNS update, "
02325                          "address family not supported");
02326         }
02327 
02328 #if defined (DEBUG_DNS_UPDATES)
02329         print_dns_status(DDNS_PRINT_OUTBOUND, ddns_cb, result);
02330 #endif
02331 
02332  cleanup:
02333 #if defined (DEBUG_DNS_UPDATES)
02334         if (result != ISC_R_SUCCESS) {
02335                 log_info("DDNS: %s(%d): error in ddns_modify_fwd %s for %p",
02336                          file, line, isc_result_totext(result), ddns_cb);
02337         }
02338 #endif
02339 
02340         if (dataspace != NULL) {
02341                 isc_mem_put(dhcp_gbl_ctx.mctx, dataspace,
02342                             sizeof(*dataspace) * 4);
02343         }
02344         return(result);
02345 }
02346 
02347 
02348 isc_result_t
02349 ddns_modify_ptr(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
02350 {
02351         isc_result_t result;
02352         dns_tsec_t *tsec_key  = NULL;
02353         unsigned char *ptrname;
02354         dhcp_ddns_data_t *dataspace = NULL;
02355         dns_namelist_t updatelist;
02356         dns_fixedname_t zname0, uname0;
02357         dns_name_t *zname = NULL, *uname;
02358         isc_sockaddrlist_t *zlist = NULL;
02359         unsigned char buf[256];
02360         int buflen;
02361 
02362         /*
02363          * Try to lookup the zone in the zone cache.  As with the forward
02364          * case it's okay if we don't have one, the DNS code will try to
02365          * find something also if we succeed we will need to dereference
02366          * the zone later.  Unlike with the forward case we assume we won't
02367          * have a pre-existing zone.
02368          */
02369         result = find_cached_zone(ddns_cb, FIND_REVERSE);
02370 
02371 #if defined (DNS_ZONE_LOOKUP)
02372         if (result == ISC_R_NOTFOUND) {
02373                 /*
02374                  * We didn't find a cached zone, see if we can
02375                  * can find a nameserver and create a zone.
02376                  */
02377                 if (find_zone_start(ddns_cb, FIND_REVERSE) == ISC_R_SUCCESS) {
02378                         /*
02379                          * We have started the process to find a zone
02380                          * queue the ddns_cb for processing after we
02381                          * create the zone
02382                          */
02383                         /* sar - not yet implemented, currently we just
02384                          * arrange for things to get cleaned up
02385                          */
02386                         goto cleanup;
02387                 }
02388         }
02389 #endif
02390         if (result != ISC_R_SUCCESS)
02391                 goto cleanup;
02392 
02393 
02394         if ((result == ISC_R_SUCCESS) &&
02395             !(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
02396                 /* Set up the zone name for use by DNS */
02397                 result = dhcp_isc_name(ddns_cb->zone_name, &zname0, &zname);
02398                 if (result != ISC_R_SUCCESS) {
02399                         log_error("Unable to build name for zone for "
02400                                   "fwd update: %s %s",
02401                                   ddns_cb->zone_name,
02402                                   isc_result_totext(result));
02403                         goto cleanup;
02404                 }
02405                 /* If we have any addresses get them */
02406                 if (!(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
02407                         zlist = &ddns_cb->zone_server_list;
02408                 }
02409 
02410                 /*
02411                  * If we now have a zone try to get the key, NULL is okay,
02412                  * having a key but not a tsec is odd so we warn.
02413                  */
02414                 /*sar*/
02415                 /* should we do the warning if we have a key but no tsec? */
02416                 if ((ddns_cb->zone != NULL) && (ddns_cb->zone->key != NULL)) {
02417                         tsec_key = ddns_cb->zone->key->tsec_key;
02418                         if (tsec_key == NULL) {
02419                                 log_error("No tsec for use with key %s",
02420                                           ddns_cb->zone->key->name);
02421                         }
02422                 }
02423         }
02424 
02425         /* We must have a name for the update list */
02426         /* Get a pointer to the ptrname to make things easier. */
02427         ptrname = (unsigned char *)ddns_cb->rev_name.data;
02428 
02429         if ((result = dhcp_isc_name(ptrname, &uname0, &uname))
02430              != ISC_R_SUCCESS) {
02431                 log_error("Unable to build name for fwd update: %s %s",
02432                           ptrname, isc_result_totext(result));
02433                 goto cleanup;
02434         }
02435 
02436         /*
02437          * Allocate the various isc dns library structures we may require.
02438          * Allocating one blob avoids being halfway through the process
02439          * and being unable to allocate as well as making the free easy.
02440          */
02441         dataspace = isc_mem_get(dhcp_gbl_ctx.mctx, sizeof(*dataspace) * 2);
02442         if (dataspace == NULL) {
02443                 log_error("Unable to allocate memory for fwd update");
02444                 result = ISC_R_NOMEMORY; 
02445                 goto cleanup;
02446         }
02447 
02448         ISC_LIST_INIT(updatelist);
02449 
02450         /*
02451          * Construct the update list
02452          * We always delete what's currently there
02453          * Delete PTR RR.
02454          */
02455         result = make_dns_dataset(dns_rdataclass_any, dns_rdatatype_ptr,
02456                                   &dataspace[0], NULL, 0, 0);
02457         if (result != ISC_R_SUCCESS) {
02458                 goto cleanup;
02459         }
02460         ISC_LIST_APPEND(uname->list, &dataspace[0].rdataset, link);
02461 
02462         /*
02463          * If we are updating the pointer we then add the new one 
02464          * Add PTR RR.
02465          */
02466         if (ddns_cb->state == DDNS_STATE_ADD_PTR) {
02467 #if 0
02468                 /*
02469                  * I've left this dead code in the file  for now in case
02470                  * we decide to try and get rid of the ns_name functions.
02471                  * sar
02472                  */
02473 
02474                 /*
02475                  * Need to convert pointer into on the wire representation
02476                  * We replace the '.' characters with the lengths of the
02477                  * next name and add a length to the beginning for the first
02478                  * name.
02479                  */
02480                 if (ddns_cb->fwd_name.len == 1) {
02481                         /* the root */
02482                         buf[0] = 0;
02483                         buflen = 1;
02484                 } else {
02485                         unsigned char *cp;
02486                         buf[0] = '.';
02487                         memcpy(&buf[1], ddns_cb->fwd_name.data,
02488                                ddns_cb->fwd_name.len);
02489                         for(cp = buf + ddns_cb->fwd_name.len, buflen = 0;
02490                             cp != buf;
02491                             cp--) {
02492                                 if (*cp == '.') {
02493                                         *cp = buflen;
02494                                         buflen = 0;
02495                                 } else {
02496                                         buflen++;
02497                                 }
02498                         }
02499                         *cp = buflen;
02500                         buflen = ddns_cb->fwd_name.len + 1;
02501                 }
02502 #endif
02503                 /*
02504                  * Need to convert pointer into on the wire representation
02505                  */
02506                 if (MRns_name_pton((char *)ddns_cb->fwd_name.data,
02507                                    buf, 256) == -1) {
02508                         goto cleanup;
02509                 }
02510                 buflen = 0;
02511                 while (buf[buflen] != 0) {
02512                         buflen += buf[buflen] + 1;
02513                 }
02514                 buflen++;
02515 
02516                 result = make_dns_dataset(dns_rdataclass_in,
02517                                           dns_rdatatype_ptr,
02518                                           &dataspace[1],
02519                                           buf, buflen, ddns_cb->ttl);
02520                 if (result != ISC_R_SUCCESS) {
02521                         goto cleanup;
02522                 }
02523                 ISC_LIST_APPEND(uname->list, &dataspace[1].rdataset, link);
02524         }
02525 
02526         ISC_LIST_APPEND(updatelist, uname, link);
02527 
02528         /*sar*/
02529         /*
02530          * for now I'll cleanup the dataset immediately, it would be
02531          * more efficient to keep it around in case the signaturure failed
02532          * and we wanted to retry it.
02533          */
02534         /* send the message, cleanup and return the result */
02535         result = ddns_update((dns_client_t *)dhcp_gbl_ctx.dnsclient,
02536                              dns_rdataclass_in, zname,
02537                              NULL, &updatelist,
02538                              zlist, tsec_key,
02539                              DNS_CLIENTRESOPT_ALLOWRUN,
02540                              dhcp_gbl_ctx.task,
02541                              ddns_interlude, (void *)ddns_cb,
02542                              &ddns_cb->transaction);
02543         if (result == ISC_R_FAMILYNOSUPPORT) {
02544                 log_info("Unable to perform DDNS update, "
02545                          "address family not supported");
02546         }
02547 
02548 #if defined (DEBUG_DNS_UPDATES)
02549         print_dns_status(DDNS_PRINT_OUTBOUND, ddns_cb, result);
02550 #endif
02551 
02552  cleanup:
02553 #if defined (DEBUG_DNS_UPDATES)
02554         if (result != ISC_R_SUCCESS) {
02555                 log_info("DDNS: %s(%d): error in ddns_modify_ptr %s for %p",
02556                          file, line, isc_result_totext(result), ddns_cb);
02557         }
02558 #endif
02559 
02560         if (dataspace != NULL) {
02561                 isc_mem_put(dhcp_gbl_ctx.mctx, dataspace,
02562                             sizeof(*dataspace) * 2);
02563         }
02564         return(result);
02565 }
02566 
02567 void
02568 ddns_cancel(dhcp_ddns_cb_t *ddns_cb, const char *file, int line) {
02569         ddns_cb->flags |= DDNS_ABORT;
02570         if (ddns_cb->transaction != NULL) {
02571                 dns_client_cancelupdate((dns_clientupdatetrans_t *)
02572                                         ddns_cb->transaction);
02573         }
02574         ddns_cb->lease = NULL;
02575 
02576 #if defined (DEBUG_DNS_UPDATES)
02577         log_info("DDNS: %s(%d): cancelling transaction for  %p",
02578                  file, line,  ddns_cb);
02579 #endif
02580 }
02581 
02582 #endif /* NSUPDATE */
02583 
02584 HASH_FUNCTIONS (dns_zone, const char *, struct dns_zone, dns_zone_hash_t,
02585                 dns_zone_reference, dns_zone_dereference, do_case_hash)

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1