ISC DHCP  4.4.1
A reference DHCPv4 and DHCPv6 implementation
dns.c
Go to the documentation of this file.
1 /* dns.c
2 
3  Domain Name Service subroutines. */
4 
5 /*
6  * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 2001-2003 by Internet Software Consortium
8  *
9  * This Source Code Form is subject to the terms of the Mozilla Public
10  * License, v. 2.0. If a copy of the MPL was not distributed with this
11  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  *
21  * Internet Systems Consortium, Inc.
22  * 950 Charter Street
23  * Redwood City, CA 94063
24  * <info@isc.org>
25  * https://www.isc.org/
26  *
27  */
28 
31 #include "dhcpd.h"
32 #include "arpa/nameser.h"
33 #include <isc/md5.h>
34 #include <isc/sha2.h>
35 #include <dns/result.h>
36 
37 /*
38  * This file contains code to connect the DHCP code to the libdns modules.
39  * As part of that function it maintains a database of zone cuts that can
40  * be used to figure out which server should be contacted to update any
41  * given domain name. Included in the zone information may be a pointer
42  * to a key in which case that key is used for the update. If no zone
43  * is found then the DNS code determines the zone on its own.
44  *
45  * The way this works is that you define the domain name to which an
46  * SOA corresponds, and the addresses of some primaries for that domain name:
47  *
48  * zone FOO.COM {
49  * primary 10.0.17.1;
50  * secondary 10.0.22.1, 10.0.23.1;
51  * key "FOO.COM Key";
52  * }
53  *
54  * If an update is requested for GAZANGA.TOPANGA.FOO.COM, then the name
55  * server looks in its database for a zone record for "GAZANGA.TOPANGA.FOO.COM",
56  * doesn't find it, looks for one for "TOPANGA.FOO.COM", doesn't find *that*,
57  * looks for "FOO.COM", finds it. So it
58  * attempts the update to the primary for FOO.COM. If that times out, it
59  * tries the secondaries. You can list multiple primaries if you have some
60  * kind of magic name server that supports that. You shouldn't list
61  * secondaries that don't know how to forward updates (e.g., BIND 8 doesn't
62  * support update forwarding, AFAIK). If no TSIG key is listed, the update
63  * is attempted without TSIG.
64  *
65  * You can also include IPv6 addresses via the primary6 and secondary6
66  * options. The search order for the addresses is primary, primary6,
67  * secondary and lastly secondary6, with a limit on the number of
68  * addresses used. Currently this limit is 3.
69  *
70  * The DHCP server tries to find an existing zone for any given name by
71  * trying to look up a local zone structure for each domain containing
72  * that name, all the way up to '.'. If it finds one cached, it tries
73  * to use that one to do the update. That's why it tries to update
74  * "FOO.COM" above, even though theoretically it should try GAZANGA...
75  * and TOPANGA... first.
76  *
77  * If the update fails with a predefined zone the zone is marked as bad
78  * and another search of the predefined zones is done. If no predefined
79  * zone is found finding a zone is left to the DNS module via examination
80  * of SOA records. If the DNS module finds a zone it may cache the zone
81  * but the zone won't be cached here.
82  *
83  * TSIG updates are not performed on zones found by the DNS module - if
84  * you want TSIG updates you _must_ write a zone definition linking the
85  * key to the zone. In cases where you know for sure what the key is
86  * but do not want to hardcode the IP addresses of the primary or
87  * secondaries, a zone declaration can be made that doesn't include any
88  * primary or secondary declarations. When the DHCP server encounters
89  * this while hunting up a matching zone for a name, it looks up the SOA,
90  * fills in the IP addresses, and uses that record for the update.
91  * If the SOA lookup returns NXRRSET, a warning is printed and the zone is
92  * discarded, TSIG key and all. The search for the zone then continues
93  * as if the zone record hadn't been found. Zones without IP addresses
94  * don't match when initially hunting for a zone to update.
95  *
96  * When an update is attempted and no predefined zone is found
97  * that matches any enclosing domain of the domain being updated, the DHCP
98  * server goes through the same process that is done when the update to a
99  * predefined zone fails - starting with the most specific domain
100  * name (GAZANGA.TOPANGA.FOO.COM) and moving to the least specific (the root),
101  * it tries to look up an SOA record.
102  *
103  * TSIG keys are defined like this:
104  *
105  * key "FOO.COM Key" {
106  * algorithm HMAC-MD5.SIG-ALG.REG.INT;
107  * secret <Base64>;
108  * }
109  *
110  * <Base64> is a number expressed in base64 that represents the key.
111  * It's also permissible to use a quoted string here - this will be
112  * translated as the ASCII bytes making up the string, and will not
113  * include any NUL termination. The key name can be any text string,
114  * and the key type must be one of the key types defined in the draft
115  * or by the IANA. Currently only the HMAC-MD5... key type is
116  * supported.
117  *
118  * The DDNS processing has been split into two areas. One is the
119  * control code that determines what should be done. That code is found
120  * in the client or server directories. The other is the common code
121  * that performs functions such as properly formatting the arguments.
122  * That code is found in this file. The basic processing flow for a
123  * DDNS update is:
124  * In the client or server code determine what needs to be done and
125  * collect the necesary information then pass it to a function from
126  * this file.
127  * In this code lookup the zone and extract the zone and key information
128  * (if available) and prepare the arguments for the DNS module.
129  * When the DNS module completes its work (times out or gets a reply)
130  * it will trigger another function here which does generic processing
131  * and then passes control back to the code from the server or client.
132  * The server or client code then determines the next step which may
133  * result in another call to this module in which case the process repeats.
134  */
135 
137 
138 /*
139  * DHCP dns structures
140  * Normally the relationship between these structures isn't one to one
141  * but in the DHCP case it (mostly) is. To make the allocations, frees,
142  * and passing of the memory easier we make a single structure with all
143  * the pieces.
144  *
145  * The maximum size of the data buffer should be large enough for any
146  * items DHCP will generate
147  */
148 
149 typedef struct dhcp_ddns_rdata {
150  dns_rdata_t rdata;
151  dns_rdatalist_t rdatalist;
152  dns_rdataset_t rdataset;
154 
155 /* Function pointer type for functions which build DDNS update contents */
156 typedef isc_result_t (*builder_func_t)(dhcp_ddns_cb_t *ddns_cb,
157  dhcp_ddns_data_t *dataspace,
158  dns_name_t *pname, dns_name_t *uname);
159 
160 #if defined (NSUPDATE)
161 #if defined (DNS_ZONE_LOOKUP)
162 
163 /*
164  * The structure used to find a nameserver if there wasn't a zone entry.
165  * Currently we assume we won't have many of these outstanding at any
166  * time so we go with a simple linked list.
167  * In use find_zone_start() will fill in the oname with the name
168  * requested by the DDNS code. zname will point to it and be
169  * advanced as labels are removed. If the DNS client code returns
170  * a set of name servers eventp and rdataset will be set. Then
171  * the code will walk through the nameservers in namelist and
172  * find addresses that are stored in addrs and addrs6.
173  */
174 
175 typedef struct dhcp_ddns_ns {
176  struct dhcp_ddns_ns *next;
177  struct data_string oname; /* the original name for DDNS */
178  char *zname; /* a pointer into the original name for
179  the zone we are checking */
180  dns_clientresevent_t *eventp; /* pointer to the event that provided the
181  namelist, we can't free the eventp
182  until we free the namelist */
183  dns_name_t *ns_name; /* current name server we are examining */
184  dns_rdataset_t *rdataset;
185  dns_rdatatype_t rdtype; /* type of address we want */
186 
187  struct in_addr addrs[DHCP_MAXNS]; /* space for v4 addresses */
188  struct in6_addr addrs6[DHCP_MAXNS]; /* space for v6 addresses */
189  int num_addrs;
190  int num_addrs6;
191  int ttl;
192 
193  void *transaction; /* transaction id for DNS calls */
194 } dhcp_ddns_ns_t;
195 
196 /*
197  * The list of DDNS names for which we are attempting to find a name server.
198  * This list is used for finding the name server, it doesn't include the
199  * information necessary to do the DDNS request after finding a name server.
200  * The code attempts to minimize duplicate requests by examining the list
201  * to see if we are already trying to find a substring of the new request.
202  * For example imagine the first request is "a.b.c.d.e." and the server has
203  * already discarded the first two lables and is trying "c.d.e.". If the
204  * next request is for "x.y.c.d.e." the code assumes the in progress
205  * request is sufficient and doesn't add a new request for the second name.
206  * If the next request was for "x.y.z.d.e." the code doesn't assume they
207  * will use the same nameserver and starts a second request.
208  * This strategy will not eliminate all duplicates but is simple and
209  * should be sufficient.
210  */
211 dhcp_ddns_ns_t *dns_outstanding_ns = NULL;
212 
213 /*
214  * Routines to manipulate the list of outstanding searches
215  *
216  * add_to_ns_queue() - adds the given control block to the queue
217  *
218  * remove_from_ns_queue() - removes the given control block from
219  * the queue
220  *
221  * find_in_ns_queue() compares the name from the given control
222  * block with the control blocks in the queue. It returns
223  * success if a matching entry is found. In order to match
224  * the entry already on the queue must be shorter than the
225  * incoming name must match the ending substring of the name.
226  */
227 
228 void
229 add_to_ns_queue(dhcp_ddns_ns_t *ns_cb)
230 {
231  ns_cb->next = dns_outstanding_ns;
232  dns_outstanding_ns = ns_cb;
233 }
234 
235 
236 void
237 remove_from_ns_queue(dhcp_ddns_ns_t *ns_cb)
238 {
239  dhcp_ddns_ns_t **foo;
240 
241  foo = &dns_outstanding_ns;
242  while (*foo) {
243  if (*foo == ns_cb) {
244  *foo = ns_cb->next;
245  break;
246  }
247  foo = &((*foo)->next);
248  }
249  ns_cb->next = NULL;
250 }
251 
252 isc_result_t
253 find_in_ns_queue(dhcp_ddns_ns_t *ns_cb)
254 {
255  dhcp_ddns_ns_t *temp_cb;
256  int in_len, temp_len;
257 
258  in_len = strlen(ns_cb->zname);
259 
260  for(temp_cb = dns_outstanding_ns;
261  temp_cb != NULL;
262  temp_cb = temp_cb->next) {
263  temp_len = strlen(temp_cb->zname);
264  if (temp_len > in_len)
265  continue;
266  if (strcmp(temp_cb->zname,
267  ns_cb->zname + (in_len - temp_len)) == 0)
268  return(ISC_R_SUCCESS);
269  }
270  return(ISC_R_NOTFOUND);
271 }
272 
273 void cache_found_zone (dhcp_ddns_ns_t *);
274 #endif
275 
276 void ddns_interlude(isc_task_t *, isc_event_t *);
277 
278 #if defined (TRACING)
279 /*
280  * Code to support tracing DDNS packets. We trace packets going to and
281  * coming from the libdns code but don't try to track the packets
282  * exchanged between the libdns code and the dns server(s) it contacts.
283  *
284  * The code is split into two sets of routines
285  * input refers to messages received from the dns module
286  * output refers to messages sent to the dns module
287  * Currently there are three routines in each set
288  * write is used to write information about the message to the trace file
289  * this routine is called directly from the proper place in the code.
290  * read is used to read information about a message from the trace file
291  * this routine is called from the trace loop as it reads through
292  * the file and is registered via the trace_type_register routine.
293  * When playing back a trace file we shall absorb records of output
294  * messages as part of processing the write function, therefore
295  * any output messages we encounter are flagged as errors.
296  * stop isn't currently used in this code but is needed for the register
297  * routine.
298  *
299  * We pass a pointer to a control block to the dns module which it returns
300  * to use as part of the result. As the pointer may vary between traces
301  * we need to map between those from the trace file and the new ones during
302  * playback.
303  *
304  * The mapping is complicated a little as a pointer could be 4 or 8 bytes
305  * long. We treat the old pointer as an 8 byte quantity and pad and compare
306  * as necessary.
307  */
308 
309 /*
310  * Structure used to map old pointers to new pointers.
311  * Old pointers are 8 bytes long as we don't know if the trace was
312  * done on a 64 bit or 32 bit machine.
313  */
314 #define TRACE_PTR_LEN 8
315 
316 typedef struct dhcp_ddns_map {
317  char old_pointer[TRACE_PTR_LEN];
318  void *new_pointer;
319  struct dhcp_ddns_map *next;
320 } dhcp_ddns_map_t;
321 
322 /* The starting point for the map structure */
323 static dhcp_ddns_map_t *ddns_map;
324 
325 trace_type_t *trace_ddns_input;
326 trace_type_t *trace_ddns_output;
327 
328 /*
329  * The data written to the trace file is:
330  * 32 bits result from dns
331  * 64 bits pointer of cb
332  */
333 
334 void
335 trace_ddns_input_write(dhcp_ddns_cb_t *ddns_cb, isc_result_t result)
336 {
337  trace_iov_t iov[2];
338  u_int32_t old_result;
339  char old_pointer[TRACE_PTR_LEN];
340 
341  old_result = htonl((u_int32_t)result);
342  memset(old_pointer, 0, TRACE_PTR_LEN);
343  memcpy(old_pointer, &ddns_cb, sizeof(ddns_cb));
344 
345  iov[0].len = sizeof(old_result);
346  iov[0].buf = (char *)&old_result;
347  iov[1].len = TRACE_PTR_LEN;
348  iov[1].buf = old_pointer;
349  trace_write_packet_iov(trace_ddns_input, 2, iov, MDL);
350 }
351 
352 /*
353  * Process the result and pointer from the trace file.
354  * We use the pointer map to find the proper pointer for this instance.
355  * Then we need to construct an event to pass along to the interlude
356  * function.
357  */
358 static void
359 trace_ddns_input_read(trace_type_t *ttype, unsigned length,
360  char *buf)
361 {
362  u_int32_t old_result;
363  char old_pointer[TRACE_PTR_LEN];
364  dns_clientupdateevent_t *eventp;
365  void *new_pointer;
366  dhcp_ddns_map_t *ddns_map_ptr;
367 
368  if (length < (sizeof(old_result) + TRACE_PTR_LEN)) {
369  log_error("trace_ddns_input_read: data too short");
370  return;
371  }
372 
373  memcpy(&old_result, buf, sizeof(old_result));
374  memcpy(old_pointer, buf + sizeof(old_result), TRACE_PTR_LEN);
375 
376  /* map the old pointer to a new pointer */
377  for (ddns_map_ptr = ddns_map;
378  ddns_map_ptr != NULL;
379  ddns_map_ptr = ddns_map_ptr->next) {
380  if ((ddns_map_ptr->new_pointer != NULL) &&
381  memcmp(ddns_map_ptr->old_pointer,
382  old_pointer, TRACE_PTR_LEN) == 0) {
383  new_pointer = ddns_map_ptr->new_pointer;
384  ddns_map_ptr->new_pointer = NULL;
385  memset(ddns_map_ptr->old_pointer, 0, TRACE_PTR_LEN);
386  break;
387  }
388  }
389  if (ddns_map_ptr == NULL) {
390  log_error("trace_dns_input_read: unable to map cb pointer");
391  return;
392  }
393 
394  eventp = (dns_clientupdateevent_t *)
395  isc_event_allocate(dhcp_gbl_ctx.mctx,
397  0,
398  ddns_interlude,
399  new_pointer,
400  sizeof(dns_clientupdateevent_t));
401  if (eventp == NULL) {
402  log_error("trace_ddns_input_read: unable to allocate event");
403  return;
404  }
405  eventp->result = ntohl(old_result);
406 
407 
408  ddns_interlude(dhcp_gbl_ctx.task, (isc_event_t *)eventp);
409 
410  return;
411 }
412 
413 static void
414 trace_ddns_input_stop(trace_type_t *ttype)
415 {
416 }
417 
418 /*
419  * We use the same arguments as for the dns startupdate function to
420  * allows us to choose between the two via a macro. If tracing isn't
421  * in use we simply call the dns function directly.
422  *
423  * If we are doing playback we read the next packet from the file
424  * and compare the type. If it matches we extract the results and pointer
425  * from the trace file. The results are returned to the caller as if
426  * they had called the dns routine. The pointer is used to construct a
427  * map for when the "reply" is processed.
428  *
429  * The data written to trace file is:
430  * 32 bits result
431  * 64 bits pointer of cb (DDNS Control block)
432  * contents of cb
433  */
434 
435 isc_result_t
436 trace_ddns_output_write(dns_client_t *client, dns_rdataclass_t rdclass,
437  dns_name_t *zonename, dns_namelist_t *prerequisites,
438  dns_namelist_t *updates, isc_sockaddrlist_t *servers,
439  dns_tsec_t *tsec, unsigned int options,
440  isc_task_t *task, isc_taskaction_t action, void *arg,
441  dns_clientupdatetrans_t **transp)
442 {
443  isc_result_t result;
444  u_int32_t old_result;
445  char old_pointer[TRACE_PTR_LEN];
446  dhcp_ddns_map_t *ddns_map_ptr;
447 
448  if (trace_playback() != 0) {
449  /* We are doing playback, extract the entry from the file */
450  unsigned buflen = 0;
451  char *inbuf = NULL;
452 
453  result = trace_get_packet(&trace_ddns_output,
454  &buflen, &inbuf);
455  if (result != ISC_R_SUCCESS) {
456  log_error("trace_ddns_output_write: no input found");
457  return (ISC_R_FAILURE);
458  }
459  if (buflen < (sizeof(old_result) + TRACE_PTR_LEN)) {
460  log_error("trace_ddns_output_write: data too short");
461  dfree(inbuf, MDL);
462  return (ISC_R_FAILURE);
463  }
464  memcpy(&old_result, inbuf, sizeof(old_result));
465  result = ntohl(old_result);
466  memcpy(old_pointer, inbuf + sizeof(old_result), TRACE_PTR_LEN);
467  dfree(inbuf, MDL);
468 
469  /* add the pointer to the pointer map */
470  for (ddns_map_ptr = ddns_map;
471  ddns_map_ptr != NULL;
472  ddns_map_ptr = ddns_map_ptr->next) {
473  if (ddns_map_ptr->new_pointer == NULL) {
474  break;
475  }
476  }
477 
478  /*
479  * If we didn't find an empty entry, allocate an entry and
480  * link it into the list. The list isn't ordered.
481  */
482  if (ddns_map_ptr == NULL) {
483  ddns_map_ptr = dmalloc(sizeof(*ddns_map_ptr), MDL);
484  if (ddns_map_ptr == NULL) {
485  log_error("trace_ddns_output_write: "
486  "unable to allocate map entry");
487  return(ISC_R_FAILURE);
488  }
489  ddns_map_ptr->next = ddns_map;
490  ddns_map = ddns_map_ptr;
491  }
492 
493  memcpy(ddns_map_ptr->old_pointer, old_pointer, TRACE_PTR_LEN);
494  ddns_map_ptr->new_pointer = arg;
495  }
496  else {
497  /* We aren't doing playback, make the actual call */
498  result = dns_client_startupdate(client, rdclass, zonename,
499  prerequisites, updates,
500  servers, tsec, options,
501  task, action, arg, transp);
502  }
503 
504  if (trace_record() != 0) {
505  /* We are recording, save the information to the file */
506  trace_iov_t iov[3];
507  old_result = htonl((u_int32_t)result);
508  memset(old_pointer, 0, TRACE_PTR_LEN);
509  memcpy(old_pointer, &arg, sizeof(arg));
510  iov[0].len = sizeof(old_result);
511  iov[0].buf = (char *)&old_result;
512  iov[1].len = TRACE_PTR_LEN;
513  iov[1].buf = old_pointer;
514 
515  /* Write out the entire cb, in case we want to look at it */
516  iov[2].len = sizeof(dhcp_ddns_cb_t);
517  iov[2].buf = (char *)arg;
518 
519  trace_write_packet_iov(trace_ddns_output, 3, iov, MDL);
520  }
521 
522  return(result);
523 }
524 
525 static void
526 trace_ddns_output_read(trace_type_t *ttype, unsigned length,
527  char *buf)
528 {
529  log_error("unaccounted for ddns output.");
530 }
531 
532 static void
533 trace_ddns_output_stop(trace_type_t *ttype)
534 {
535 }
536 
537 void
539 {
540  trace_ddns_output = trace_type_register("ddns-output", NULL,
541  trace_ddns_output_read,
542  trace_ddns_output_stop, MDL);
543  trace_ddns_input = trace_type_register("ddns-input", NULL,
544  trace_ddns_input_read,
545  trace_ddns_input_stop, MDL);
546  ddns_map = NULL;
547 }
548 
549 #define ddns_update trace_ddns_output_write
550 #else
551 #define ddns_update dns_client_startupdate
552 #endif /* TRACING */
553 
554 #define zone_resolve dns_client_startresolve
555 
556 /*
557  * Code to allocate and free a dddns control block. This block is used
558  * to pass and track the information associated with a DDNS update request.
559  */
561 ddns_cb_alloc(const char *file, int line)
562 {
563  dhcp_ddns_cb_t *ddns_cb;
564  int i;
565 
566  ddns_cb = dmalloc(sizeof(*ddns_cb), file, line);
567  if (ddns_cb != NULL) {
568  ISC_LIST_INIT(ddns_cb->zone_server_list);
569  for (i = 0; i < DHCP_MAXNS; i++) {
570  ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link);
571  }
572  }
573 
574 #if defined (DEBUG_DNS_UPDATES)
575  log_info("%s(%d): Allocating ddns_cb=%p", file, line, ddns_cb);
576 #endif
577 
578  return(ddns_cb);
579 }
580 
581 void
582 ddns_cb_free(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
583 {
584 #if defined (DEBUG_DNS_UPDATES)
585  log_info("%s(%d): freeing ddns_cb=%p", file, line, ddns_cb);
586 #endif
587 
588  data_string_forget(&ddns_cb->fwd_name, file, line);
589  data_string_forget(&ddns_cb->rev_name, file, line);
590  data_string_forget(&ddns_cb->dhcid, file, line);
591 
592  if (ddns_cb->zone != NULL) {
593  forget_zone((struct dns_zone **)&ddns_cb->zone);
594  }
595 
596  /* Should be freed by now, check just in case. */
597  if (ddns_cb->transaction != NULL) {
598  log_error("Impossible memory leak at %s:%d (attempt to free "
599  "DDNS Control Block before transaction).", MDL);
600  }
601 
602  /* Should be freed by now, check just in case. */
603  if (ddns_cb->fixed6_ia) {
604  log_error("Possible memory leak at %s:%d (attempt to free "
605  "DDNS Control Block before fxed6_ia).", MDL);
606  }
607 
608  dfree(ddns_cb, file, line);
609 }
610 
611 void
613 {
614  int i;
615 
616  forget_zone(&ddns_cb->zone);
617  ddns_cb->zone_name[0] = 0;
618  ISC_LIST_INIT(ddns_cb->zone_server_list);
619  for (i = 0; i < DHCP_MAXNS; i++) {
620  ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link);
621  }
622 }
623 #endif
624 
625 isc_result_t remove_dns_zone (struct dns_zone *zone)
626 {
627  struct dns_zone *tz = NULL;
628 
629  if (dns_zone_hash) {
630  dns_zone_hash_lookup(&tz, dns_zone_hash, zone->name, 0, MDL);
631  if (tz != NULL) {
632  dns_zone_hash_delete(dns_zone_hash, tz->name, 0, MDL);
634  }
635  }
636 
637  return (ISC_R_SUCCESS);
638 }
639 
640 isc_result_t enter_dns_zone (struct dns_zone *zone)
641 {
642  struct dns_zone *tz = (struct dns_zone *)0;
643 
644  if (dns_zone_hash) {
645  dns_zone_hash_lookup (&tz,
646  dns_zone_hash, zone -> name, 0, MDL);
647  if (tz == zone) {
648  dns_zone_dereference (&tz, MDL);
649  return ISC_R_SUCCESS;
650  }
651  if (tz) {
652  dns_zone_hash_delete (dns_zone_hash,
653  zone -> name, 0, MDL);
654  dns_zone_dereference (&tz, MDL);
655  }
656  } else {
657  if (!dns_zone_new_hash(&dns_zone_hash, DNS_HASH_SIZE, MDL))
658  return ISC_R_NOMEMORY;
659  }
660 
661  dns_zone_hash_add (dns_zone_hash, zone -> name, 0, zone, MDL);
662  return ISC_R_SUCCESS;
663 }
664 
665 isc_result_t dns_zone_lookup (struct dns_zone **zone, const char *name)
666 {
667  int len;
668  char *tname = (char *)0;
669  isc_result_t status;
670 
671  if (!dns_zone_hash)
672  return ISC_R_NOTFOUND;
673 
674  len = strlen (name);
675  if (name [len - 1] != '.') {
676  tname = dmalloc ((unsigned)len + 2, MDL);
677  if (!tname)
678  return ISC_R_NOMEMORY;
679  strcpy (tname, name);
680  tname [len] = '.';
681  tname [len + 1] = 0;
682  name = tname;
683  }
684  if (!dns_zone_hash_lookup (zone, dns_zone_hash, name, 0, MDL))
685  status = ISC_R_NOTFOUND;
686  else if ((*zone)->timeout && (*zone)->timeout < cur_time) {
687  dns_zone_hash_delete(dns_zone_hash, (*zone)->name, 0, MDL);
688  dns_zone_dereference(zone, MDL);
689  status = ISC_R_NOTFOUND;
690  } else
691  status = ISC_R_SUCCESS;
692 
693  if (tname)
694  dfree (tname, MDL);
695  return status;
696 }
697 
699  struct dns_zone **ptr;
700  const char *file;
701  int line;
702 {
703  struct dns_zone *dns_zone;
704 
705  if ((ptr == NULL) || (*ptr == NULL)) {
706  log_error("%s(%d): null pointer", file, line);
707 #if defined (POINTER_DEBUG)
708  abort();
709 #else
710  return (0);
711 #endif
712  }
713 
714  dns_zone = *ptr;
715  *ptr = NULL;
716  --dns_zone->refcnt;
718  if (dns_zone->refcnt > 0)
719  return (1);
720 
721  if (dns_zone->refcnt < 0) {
722  log_error("%s(%d): negative refcnt!", file, line);
723 #if defined (DEBUG_RC_HISTORY)
724  dump_rc_history(dns_zone);
725 #endif
726 #if defined (POINTER_DEBUG)
727  abort();
728 #else
729  return (0);
730 #endif
731  }
732 
733  if (dns_zone->name)
735  if (dns_zone->key)
736  omapi_auth_key_dereference(&dns_zone->key, file, line);
737  if (dns_zone->primary)
739  if (dns_zone->secondary)
741  if (dns_zone->primary6)
743  if (dns_zone->secondary6)
745  dfree(dns_zone, file, line);
746  return (1);
747 }
748 
749 #if defined (NSUPDATE)
750 #if defined (DNS_ZONE_LOOKUP)
751 
752 /* Helper function to copy the address from an rdataset to
753  * the nameserver control block. Mostly to avoid really long
754  * lines in the nested for loops
755  */
756 void
757 zone_addr_to_ns(dhcp_ddns_ns_t *ns_cb,
758  dns_rdataset_t *rdataset)
759 {
760  dns_rdata_t rdata;
761  dns_rdata_in_a_t a;
762  dns_rdata_in_aaaa_t aaaa;
763 
764  dns_rdata_init(&rdata);
765  dns_rdataset_current(rdataset, &rdata);
766  switch (rdataset->type) {
767  case dns_rdatatype_a:
768  (void) dns_rdata_tostruct(&rdata, &a, NULL);
769  memcpy(&ns_cb->addrs[ns_cb->num_addrs], &a.in_addr, 4);
770  ns_cb->num_addrs++;
771  dns_rdata_freestruct(&a);
772  break;
773  case dns_rdatatype_aaaa:
774  (void) dns_rdata_tostruct(&rdata, &aaaa, NULL);
775  memcpy(&ns_cb->addrs6[ns_cb->num_addrs6], &aaaa.in6_addr, 16);
776  ns_cb->num_addrs6++;
777  dns_rdata_freestruct(&aaaa);
778  break;
779  default:
780  break;
781  }
782 
783  if ((ns_cb->ttl == 0) || (ns_cb->ttl > rdataset->ttl))
784  ns_cb->ttl = rdataset->ttl;
785 }
786 
787 /*
788  * The following three routines co-operate to find the addresses of
789  * the nameservers to use for a zone if we don't have a zone statement.
790  * We strongly suggest the use of a zone statement to avoid problmes
791  * and to allow for the use of TSIG and therefore better security, but
792  * include this functionality for those that don't want such statements.
793  *
794  * find_zone_start(ddns_cb, direction)
795  * This is the first of the routines, it is called from the rest of
796  * the ddns code when we have received a request for DDNS for a name
797  * and don't have a zone entry that would cover that name. The name
798  * is in the ddns_cb as specified by the direction (forward or reverse).
799  * The start function pulls the name out and constructs the name server
800  * block then starts the process by calling the DNS client code.
801  *
802  * find_zone_ns(taskp, eventp)
803  * This is the second step of the process. The DNS client code will
804  * call this when it has gotten a response or timed out. If the response
805  * doesn't have a list of nameservers we remove another label from the
806  * zone name and try again. If the response does include a list of
807  * nameservers we start walking through the list attempting to get
808  * addresses for the nameservers.
809  *
810  * find_zone_addrs(taskp, eventp)
811  * This is the third step of the process. In find_zone_ns we got
812  * a list of nameserves and started walking through them. This continues
813  * the walk and if we get back any addresses it adds them to our list.
814  * When we get enough addresses or run out of nameservers we construct
815  * a zone entry and insert it into the zone hash for the rest of the
816  * DDNS code to use.
817  */
818 void
819 find_zone_addrs(isc_task_t *taskp,
820  isc_event_t *eventp)
821 {
822  dns_clientresevent_t *ddns_event = (dns_clientresevent_t *)eventp;
823  dhcp_ddns_ns_t *ns_cb = (dhcp_ddns_ns_t *)eventp->ev_arg;
824  dns_name_t *ns_name = NULL;
825  dns_rdataset_t *rdataset;
826  isc_result_t result;
827  dns_name_t *name;
828  dns_rdata_t rdata = DNS_RDATA_INIT;
829  dns_rdata_ns_t ns;
830 
831 
832  /* the transaction is done, get rid of the tag */
833  dns_client_destroyrestrans(&ns_cb->transaction);
834 
835  /* If we succeeded we try and extract the addresses, if we can
836  * and we have enough we are done. If we didn't succeed or
837  * we don't have enough addresses afterwards we drop through
838  * and try the next item on the list.
839  */
840  if (ddns_event->result == ISC_R_SUCCESS) {
841 
842  for (name = ISC_LIST_HEAD(ddns_event->answerlist);
843  name != NULL;
844  name = ISC_LIST_NEXT(name, link)) {
845 
846  for (rdataset = ISC_LIST_HEAD(name->list);
847  rdataset != NULL;
848  rdataset = ISC_LIST_NEXT(rdataset, link)) {
849 
850  for (result = dns_rdataset_first(rdataset);
851  result == ISC_R_SUCCESS;
852  result = dns_rdataset_next(rdataset)) {
853 
854  /* add address to cb */
855  zone_addr_to_ns(ns_cb, rdataset);
856 
857  /* We are done if we have
858  * enough addresses
859  */
860  if (ns_cb->num_addrs +
861  ns_cb->num_addrs6 >= DHCP_MAXNS)
862  goto done;
863  }
864  }
865  }
866  }
867 
868  /* We need more addresses.
869  * We restart the loop we were in before.
870  */
871 
872  for (ns_name = ns_cb->ns_name;
873  ns_name != NULL;
874  ns_name = ISC_LIST_NEXT(ns_name, link)) {
875 
876  if (ns_name == ns_cb->ns_name) {
877  /* first time through, use saved state */
878  rdataset = ns_cb->rdataset;
879  } else {
880  rdataset = ISC_LIST_HEAD(ns_name->list);
881  }
882 
883  for (;
884  rdataset != NULL;
885  rdataset = ISC_LIST_NEXT(rdataset, link)) {
886 
887  if (rdataset->type != dns_rdatatype_ns)
888  continue;
889  dns_rdata_init(&rdata);
890 
891  if (rdataset == ns_cb->rdataset) {
892  /* first time through use the saved state */
893  if (ns_cb->rdtype == dns_rdatatype_a) {
894  ns_cb->rdtype = dns_rdatatype_aaaa;
895  } else {
896  ns_cb->rdtype = dns_rdatatype_a;
897  if (dns_rdataset_next(rdataset) !=
898  ISC_R_SUCCESS)
899  continue;
900  }
901  } else {
902  if ((!dns_rdataset_isassociated(rdataset)) ||
903  (dns_rdataset_first(rdataset) !=
904  ISC_R_SUCCESS))
905  continue;
906  }
907 
908  dns_rdataset_current(rdataset, &rdata);
909  if (dns_rdata_tostruct(&rdata, &ns, NULL) !=
910  ISC_R_SUCCESS)
911  continue;
912 
913  /* Save our current state */
914  ns_cb->ns_name = ns_name;
915  ns_cb->rdataset = rdataset;
916 
917  /* And call out to DNS */
918  result = zone_resolve(dhcp_gbl_ctx.dnsclient, &ns.name,
919  dns_rdataclass_in,
920  ns_cb->rdtype,
921  DNS_CLIENTRESOPT_NODNSSEC,
923  find_zone_addrs,
924  (void *)ns_cb,
925  &ns_cb->transaction);
926 
927  /* do we need to clean this? */
928  dns_rdata_freestruct(&ns);
929 
930  if (result == ISC_R_SUCCESS)
931  /* we have started the next step, cleanup
932  * the structures associated with this call
933  * but leave the cb for the next round
934  */
935  goto cleanup;
936 
937  log_error("find_zone_ns: unable to continue "
938  "resolve: %s %s",
939  ns_cb->zname,
940  isc_result_totext(result));
941 
942  /* The call to start a resolve transaction failed,
943  * should we try to continue with any other names?
944  * For now let's not, but let's use whatever we
945  * may already have.
946  */
947  goto done;
948  }
949  }
950 
951  done:
952  /* we've either gotten our max number of addresses or
953  * run out of nameservers to try. Convert the cb into
954  * a zone and insert it into the zone hash. Then
955  * we need to clean up the saved state.
956  */
957  if ((ns_cb->num_addrs != 0) ||
958  (ns_cb->num_addrs6 != 0))
959  cache_found_zone(ns_cb);
960 
961  dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient,
962  &ns_cb->eventp->answerlist);
963  isc_event_free((isc_event_t **)&ns_cb->eventp);
964 
965  remove_from_ns_queue(ns_cb);
966  data_string_forget(&ns_cb->oname, MDL);
967  dfree(ns_cb, MDL);
968 
969  cleanup:
970  /* cleanup any of the new state information */
971 
972  dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient,
973  &ddns_event->answerlist);
974  isc_event_free(&eventp);
975 
976  return;
977 
978 }
979 
980 /*
981  * Routine to continue the process of finding a nameserver via the DNS
982  * This is routine is called when we are still trying to get a list
983  * of nameservers to process.
984  */
985 
986 void
987 find_zone_ns(isc_task_t *taskp,
988  isc_event_t *eventp)
989 {
990  dns_clientresevent_t *ddns_event = (dns_clientresevent_t *)eventp;
991  dhcp_ddns_ns_t *ns_cb = (dhcp_ddns_ns_t *)eventp->ev_arg;
992  dns_fixedname_t zname0;
993  dns_name_t *zname = NULL, *ns_name = NULL;
994  dns_rdataset_t *rdataset;
995  isc_result_t result;
996  dns_rdata_t rdata = DNS_RDATA_INIT;
997  dns_rdata_ns_t ns;
998 
999  /* the transaction is done, get rid of the tag */
1000  dns_client_destroyrestrans(&ns_cb->transaction);
1001 
1002  if (ddns_event->result != ISC_R_SUCCESS) {
1003  /* We didn't find any nameservers, try again */
1004 
1005  /* Remove a label and continue */
1006  ns_cb->zname = strchr(ns_cb->zname, '.');
1007  if ((ns_cb->zname == NULL) ||
1008  (ns_cb->zname[1] == 0)) {
1009  /* No more labels, all done */
1010  goto cleanup;
1011  }
1012  ns_cb->zname++;
1013 
1014  /* Create a DNS version of the zone name and call the
1015  * resolver code */
1016  if (((result = dhcp_isc_name((unsigned char *)ns_cb->zname,
1017  &zname0, &zname))
1018  != ISC_R_SUCCESS) ||
1019  ((result = zone_resolve(dhcp_gbl_ctx.dnsclient,
1020  zname, dns_rdataclass_in,
1021  dns_rdatatype_ns,
1022  DNS_CLIENTRESOPT_NODNSSEC,
1024  find_zone_ns,
1025  (void *)ns_cb,
1026  &ns_cb->transaction))
1027  != ISC_R_SUCCESS)) {
1028  log_error("find_zone_ns: Unable to build "
1029  "name or start resolve: %s %s",
1030  ns_cb->zname,
1031  isc_result_totext(result));
1032  goto cleanup;
1033  }
1034 
1035  /* we have successfully started the next iteration
1036  * of this step, clean up from the call and continue */
1037  dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient,
1038  &ddns_event->answerlist);
1039  isc_event_free(&eventp);
1040  return;
1041  }
1042 
1043  /* We did get a set of nameservers, save the information and
1044  * start trying to get addresses
1045  */
1046  ns_cb->eventp = ddns_event;
1047  for (ns_name = ISC_LIST_HEAD(ddns_event->answerlist);
1048  ns_name != NULL;
1049  ns_name = ISC_LIST_NEXT(ns_name, link)) {
1050 
1051  for (rdataset = ISC_LIST_HEAD(ns_name->list);
1052  rdataset != NULL;
1053  rdataset = ISC_LIST_NEXT(rdataset, link)) {
1054 
1055  if (rdataset->type != dns_rdatatype_ns)
1056  continue;
1057 
1058  if ((!dns_rdataset_isassociated(rdataset)) ||
1059  (dns_rdataset_first(rdataset) !=
1060  ISC_R_SUCCESS))
1061  continue;
1062 
1063  dns_rdataset_current(rdataset, &rdata);
1064  if (dns_rdata_tostruct(&rdata, &ns, NULL) !=
1065  ISC_R_SUCCESS)
1066  continue;
1067 
1068  /* Save our current state */
1069  ns_cb->ns_name = ns_name;
1070  ns_cb->rdataset = rdataset;
1071 
1072  /* And call out to DNS */
1073  result = zone_resolve(dhcp_gbl_ctx.dnsclient, &ns.name,
1074  dns_rdataclass_in,
1075  ns_cb->rdtype,
1076  DNS_CLIENTRESOPT_NODNSSEC,
1078  find_zone_addrs,
1079  (void *)ns_cb,
1080  &ns_cb->transaction);
1081 
1082  /* do we need to clean this? */
1083  dns_rdata_freestruct(&ns);
1084 
1085  if (result == ISC_R_SUCCESS)
1086  /* We have successfully started the next step
1087  * we don't cleanup the eventp block as we are
1088  * still using it.
1089  */
1090  return;
1091 
1092  log_error("find_zone_ns: unable to continue "
1093  "resolve: %s %s",
1094  ns_cb->zname,
1095  isc_result_totext(result));
1096 
1097  /* The call to start a resolve transaction failed,
1098  * should we try to continue with any other names?
1099  * For now let's not
1100  */
1101  goto cleanup;
1102  }
1103  }
1104 
1105  cleanup:
1106  /* When we add a queue to manage the DDNS
1107  * requests we will need to remove any that
1108  * were waiting for this resolution */
1109 
1110  dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient,
1111  &ddns_event->answerlist);
1112  isc_event_free(&eventp);
1113 
1114  remove_from_ns_queue(ns_cb);
1115 
1116  data_string_forget(&ns_cb->oname, MDL);
1117  dfree(ns_cb, MDL);
1118  return;
1119 
1120 }
1121 
1122 /*
1123  * Start the process of finding nameservers via the DNS because
1124  * we don't have a zone entry already.
1125  * We construct a control block and fill in the DDNS name. As
1126  * the process continues we shall move the zname pointer to
1127  * indicate which labels we are still using. The rest of
1128  * the control block will be filled in as we continue processing.
1129  */
1130 isc_result_t
1131 find_zone_start(dhcp_ddns_cb_t *ddns_cb, int direction)
1132 {
1133  isc_result_t status = ISC_R_NOTFOUND;
1134  dhcp_ddns_ns_t *ns_cb;
1135  dns_fixedname_t zname0;
1136  dns_name_t *zname = NULL;
1137 
1138  /*
1139  * We don't validate np as that was already done in find_cached_zone()
1140  */
1141 
1142  /* Allocate the control block for this request */
1143  ns_cb = dmalloc(sizeof(*ns_cb), MDL);
1144  if (ns_cb == NULL) {
1145  log_error("find_zone_start: unable to allocate cb");
1146  return(ISC_R_FAILURE);
1147  }
1148  ns_cb->rdtype = dns_rdatatype_a;
1149 
1150  /* Copy the data string so the NS lookup is independent of the DDNS */
1151  if (direction == FIND_FORWARD) {
1152  data_string_copy(&ns_cb->oname, &ddns_cb->fwd_name, MDL);
1153  } else {
1154  data_string_copy(&ns_cb->oname, &ddns_cb->rev_name, MDL);
1155  }
1156  ns_cb->zname = (char *)ns_cb->oname.data;
1157 
1158  /*
1159  * Check the dns_outstanding_ns queue to see if we are
1160  * already processing something that would cover this name
1161  */
1162  if (find_in_ns_queue(ns_cb) == ISC_R_SUCCESS) {
1163  data_string_forget(&ns_cb->oname, MDL);
1164  dfree(ns_cb, MDL);
1165  return (ISC_R_SUCCESS);
1166  }
1167 
1168  /* Create a DNS version of the zone name and call the
1169  * resolver code */
1170  if (((status = dhcp_isc_name((unsigned char *)ns_cb->zname,
1171  &zname0, &zname))
1172  != ISC_R_SUCCESS) ||
1173  ((status = zone_resolve(dhcp_gbl_ctx.dnsclient,
1174  zname, dns_rdataclass_in,
1175  dns_rdatatype_ns,
1176  DNS_CLIENTRESOPT_NODNSSEC,
1178  find_zone_ns,
1179  (void *)ns_cb,
1180  &ns_cb->transaction))
1181  != ISC_R_SUCCESS)) {
1182  log_error("find_zone_start: Unable to build "
1183  "name or start resolve: %s %s",
1184  ns_cb->zname,
1185  isc_result_totext(status));
1186 
1187  /* We failed to start the process, clean up */
1188  data_string_forget(&ns_cb->oname, MDL);
1189  dfree(ns_cb, MDL);
1190  } else {
1191  /* We started the process, attach the control block
1192  * to the queue */
1193  add_to_ns_queue(ns_cb);
1194  }
1195 
1196  return (status);
1197 }
1198 #endif
1199 
1200 isc_result_t
1201 find_cached_zone(dhcp_ddns_cb_t *ddns_cb, int direction)
1202 {
1203  isc_result_t status = ISC_R_NOTFOUND;
1204  const char *np;
1205  struct dns_zone *zone = NULL;
1206  struct data_string nsaddrs;
1207  struct in_addr zone_addr;
1208  struct in6_addr zone_addr6;
1209  int ix;
1210 
1211  if (direction == FIND_FORWARD) {
1212  np = (const char *)ddns_cb->fwd_name.data;
1213  } else {
1214  np = (const char *)ddns_cb->rev_name.data;
1215  }
1216 
1217  /* We can't look up a null zone. */
1218  if ((np == NULL) || (*np == '\0')) {
1219  return (DHCP_R_INVALIDARG);
1220  }
1221 
1222  /*
1223  * For each subzone, try to find a cached zone.
1224  */
1225  for (;;) {
1226  status = dns_zone_lookup(&zone, np);
1227  if (status == ISC_R_SUCCESS)
1228  break;
1229 
1230  np = strchr(np, '.');
1231  if (np == NULL)
1232  break;
1233  np++;
1234  }
1235 
1236  if (status != ISC_R_SUCCESS)
1237  return (status);
1238 
1239  /* Make sure the zone is valid, we've already gotten
1240  * rid of expired dynamic zones. Check to see if
1241  * we repudiated this zone. If so give up.
1242  */
1243  if ((zone->flags & DNS_ZONE_INACTIVE) != 0) {
1244  dns_zone_dereference(&zone, MDL);
1245  return (ISC_R_FAILURE);
1246  }
1247 
1248  /* Make sure the zone name will fit. */
1249  if (strlen(zone->name) > sizeof(ddns_cb->zone_name)) {
1250  dns_zone_dereference(&zone, MDL);
1251  return (ISC_R_NOSPACE);
1252  }
1253  strcpy((char *)&ddns_cb->zone_name[0], zone->name);
1254 
1255  memset (&nsaddrs, 0, sizeof nsaddrs);
1256  ix = 0;
1257 
1258  if (zone->primary) {
1259  if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
1260  NULL, NULL, &global_scope,
1261  zone->primary, MDL)) {
1262  int ip = 0;
1263  while (ix < DHCP_MAXNS) {
1264  if (ip + 4 > nsaddrs.len)
1265  break;
1266  memcpy(&zone_addr, &nsaddrs.data[ip], 4);
1267  isc_sockaddr_fromin(&ddns_cb->zone_addrs[ix],
1268  &zone_addr,
1269  NS_DEFAULTPORT);
1270  ISC_LIST_APPEND(ddns_cb->zone_server_list,
1271  &ddns_cb->zone_addrs[ix],
1272  link);
1273  ip += 4;
1274  ix++;
1275  }
1276  data_string_forget(&nsaddrs, MDL);
1277  }
1278  }
1279 
1280  if (zone->primary6) {
1281  if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
1282  NULL, NULL, &global_scope,
1283  zone->primary6, MDL)) {
1284  int ip = 0;
1285  while (ix < DHCP_MAXNS) {
1286  if (ip + 16 > nsaddrs.len)
1287  break;
1288  memcpy(&zone_addr6, &nsaddrs.data[ip], 16);
1289  isc_sockaddr_fromin6(&ddns_cb->zone_addrs[ix],
1290  &zone_addr6,
1291  NS_DEFAULTPORT);
1292  ISC_LIST_APPEND(ddns_cb->zone_server_list,
1293  &ddns_cb->zone_addrs[ix],
1294  link);
1295  ip += 16;
1296  ix++;
1297  }
1298  data_string_forget(&nsaddrs, MDL);
1299  }
1300  }
1301 
1302  if (zone->secondary) {
1303  if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
1304  NULL, NULL, &global_scope,
1305  zone->secondary, MDL)) {
1306  int ip = 0;
1307  while (ix < DHCP_MAXNS) {
1308  if (ip + 4 > nsaddrs.len)
1309  break;
1310  memcpy(&zone_addr, &nsaddrs.data[ip], 4);
1311  isc_sockaddr_fromin(&ddns_cb->zone_addrs[ix],
1312  &zone_addr,
1313  NS_DEFAULTPORT);
1314  ISC_LIST_APPEND(ddns_cb->zone_server_list,
1315  &ddns_cb->zone_addrs[ix],
1316  link);
1317  ip += 4;
1318  ix++;
1319  }
1320  data_string_forget (&nsaddrs, MDL);
1321  }
1322  }
1323 
1324  if (zone->secondary6) {
1325  if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
1326  NULL, NULL, &global_scope,
1327  zone->secondary6, MDL)) {
1328  int ip = 0;
1329  while (ix < DHCP_MAXNS) {
1330  if (ip + 16 > nsaddrs.len)
1331  break;
1332  memcpy(&zone_addr6, &nsaddrs.data[ip], 16);
1333  isc_sockaddr_fromin6(&ddns_cb->zone_addrs[ix],
1334  &zone_addr6,
1335  NS_DEFAULTPORT);
1336  ISC_LIST_APPEND(ddns_cb->zone_server_list,
1337  &ddns_cb->zone_addrs[ix],
1338  link);
1339  ip += 16;
1340  ix++;
1341  }
1342  data_string_forget (&nsaddrs, MDL);
1343  }
1344  }
1345 
1346  dns_zone_reference(&ddns_cb->zone, zone, MDL);
1347  dns_zone_dereference (&zone, MDL);
1348  return ISC_R_SUCCESS;
1349 }
1350 
1351 void forget_zone (struct dns_zone **zone)
1352 {
1353  dns_zone_dereference (zone, MDL);
1354 }
1355 
1356 void repudiate_zone (struct dns_zone **zone)
1357 {
1358  /* verify that we have a pointer at least */
1359  if ((zone == NULL) || (*zone == NULL)) {
1360  log_info("Null argument to repudiate zone");
1361  return;
1362  }
1363 
1364  (*zone)->flags |= DNS_ZONE_INACTIVE;
1365  dns_zone_dereference(zone, MDL);
1366 }
1367 
1368 #if defined (DNS_ZONE_LOOKUP)
1369 void cache_found_zone(dhcp_ddns_ns_t *ns_cb)
1370 {
1371  struct dns_zone *zone = NULL;
1372  int len, remove_zone = 0;
1373 
1374  /* See if there's already such a zone. */
1375  if (dns_zone_lookup(&zone, ns_cb->zname) == ISC_R_SUCCESS) {
1376  /* If it's not a dynamic zone, leave it alone. */
1377  if (zone->timeout == 0)
1378  return;
1379 
1380  /* Remove any old addresses in case they've changed */
1381  if (zone->primary)
1383  if (zone->primary6)
1385 
1386  /* Set the flag to remove the zone from the hash if
1387  we have problems */
1388  remove_zone = 1;
1389  } else if (dns_zone_allocate(&zone, MDL) == 0) {
1390  return;
1391  } else {
1392  /* We've just allocated the zone, now we need
1393  * to allocate space for the name and addresses
1394  */
1395 
1396  /* allocate space for the name */
1397  len = strlen(ns_cb->zname);
1398  zone->name = dmalloc(len + 2, MDL);
1399  if (zone->name == NULL) {
1400  goto cleanup;
1401  }
1402 
1403  /* Copy the name and add a trailing '.' if necessary */
1404  strcpy(zone->name, ns_cb->zname);
1405  if (zone->name[len-1] != '.') {
1406  zone->name[len] = '.';
1407  zone->name[len+1] = 0;
1408  }
1409  }
1410 
1411  zone->timeout = cur_time + ns_cb->ttl;
1412 
1413  if (ns_cb->num_addrs != 0) {
1414  len = ns_cb->num_addrs * sizeof(struct in_addr);
1415  if ((!option_cache_allocate(&zone->primary, MDL)) ||
1416  (!buffer_allocate(&zone->primary->data.buffer,
1417  len, MDL))) {
1418  if (remove_zone == 1)
1419  remove_dns_zone(zone);
1420  goto cleanup;
1421  }
1422  memcpy(zone->primary->data.buffer->data, ns_cb->addrs, len);
1423  zone->primary->data.data =
1424  &zone->primary->data.buffer->data[0];
1425  zone->primary->data.len = len;
1426  }
1427  if (ns_cb->num_addrs6 != 0) {
1428  len = ns_cb->num_addrs6 * sizeof(struct in6_addr);
1429  if ((!option_cache_allocate(&zone->primary6, MDL)) ||
1430  (!buffer_allocate(&zone->primary6->data.buffer,
1431  len, MDL))) {
1432  if (remove_zone == 1)
1433  remove_dns_zone(zone);
1434  goto cleanup;
1435  }
1436  memcpy(zone->primary6->data.buffer->data, ns_cb->addrs6, len);
1437  zone->primary6->data.data =
1438  &zone->primary6->data.buffer->data[0];
1439  zone->primary6->data.len = len;
1440  }
1441 
1442  enter_dns_zone(zone);
1443 
1444  cleanup:
1445  dns_zone_dereference(&zone, MDL);
1446  return;
1447 }
1448 #endif
1449 
1474 int get_std_dhcid(dhcp_ddns_cb_t *ddns_cb,
1475  int type,
1476  const u_int8_t *identifier,
1477  unsigned id_len)
1478 {
1479  struct data_string *id = &ddns_cb->dhcid;
1480  isc_sha256_t sha256;
1481  unsigned char buf[ISC_SHA256_DIGESTLENGTH];
1482  unsigned char fwd_buf[256];
1483  unsigned fwd_buflen = 0;
1484 
1485  /* Types can only be 0..(2^16)-1. */
1486  if (type < 0 || type > 65535)
1487  return (0);
1488 
1489  /* We need to convert the fwd name to wire representation */
1490  if (MRns_name_pton((char *)ddns_cb->fwd_name.data, fwd_buf, 256) == -1)
1491  return (0);
1492  while(fwd_buf[fwd_buflen] != 0) {
1493  fwd_buflen += fwd_buf[fwd_buflen] + 1;
1494  }
1495  fwd_buflen++;
1496 
1497  if (!buffer_allocate(&id->buffer,
1498  ISC_SHA256_DIGESTLENGTH + 2 + 1,
1499  MDL))
1500  return (0);
1501  id->data = id->buffer->data;
1502 
1503  /* The two first bytes contain the type identifier. */
1504  putUShort(id->buffer->data, (unsigned)type);
1505 
1506  /* The next is the digest type, SHA-256 is 1 */
1507  putUChar(id->buffer->data + 2, 1u);
1508 
1509  /* Computing the digest */
1510  isc_sha256_init(&sha256);
1511  isc_sha256_update(&sha256, identifier, id_len);
1512  isc_sha256_update(&sha256, fwd_buf, fwd_buflen);
1513  isc_sha256_final(buf, &sha256);
1514 
1515  memcpy(id->buffer->data + 3, &buf, ISC_SHA256_DIGESTLENGTH);
1516 
1517  id->len = ISC_SHA256_DIGESTLENGTH + 2 + 1;
1518 
1519  return (1);
1520 }
1521 
1543 int get_int_dhcid (dhcp_ddns_cb_t *ddns_cb,
1544  int type,
1545  const u_int8_t *data,
1546  unsigned len)
1547 {
1548  struct data_string *id = &ddns_cb->dhcid;
1549  unsigned char buf[ISC_MD5_DIGESTLENGTH];
1550  isc_md5_t md5;
1551  int i;
1552 
1553  /* Types can only be 0..(2^16)-1. */
1554  if (type < 0 || type > 65535)
1555  return (0);
1556 
1557  /*
1558  * Hexadecimal MD5 digest plus two byte type, NUL,
1559  * and one byte for length for dns.
1560  */
1561  if (!buffer_allocate(&id -> buffer,
1562  (ISC_MD5_DIGESTLENGTH * 2) + 4, MDL))
1563  return (0);
1564  id->data = id->buffer->data;
1565 
1566  /*
1567  * We put the length into the first byte to turn
1568  * this into a dns text string. This avoid needing to
1569  * copy the string to add the byte later.
1570  */
1571  id->buffer->data[0] = ISC_MD5_DIGESTLENGTH * 2 + 2;
1572 
1573  /* Put the type in the next two bytes. */
1574  id->buffer->data[1] = "0123456789abcdef"[(type >> 4) & 0xf];
1575  /* This should have been [type & 0xf] but now that
1576  * it is in use we need to leave it this way in order
1577  * to avoid disturbing customer's lease files
1578  */
1579  id->buffer->data[2] = "0123456789abcdef"[type % 15];
1580 
1581  /* Mash together an MD5 hash of the identifier. */
1582  isc_md5_init(&md5);
1583  isc_md5_update(&md5, data, len);
1584  isc_md5_final(&md5, buf);
1585 
1586  /* Convert into ASCII. */
1587  for (i = 0; i < ISC_MD5_DIGESTLENGTH; i++) {
1588  id->buffer->data[i * 2 + 3] =
1589  "0123456789abcdef"[(buf[i] >> 4) & 0xf];
1590  id->buffer->data[i * 2 + 4] =
1591  "0123456789abcdef"[buf[i] & 0xf];
1592  }
1593 
1594  id->len = ISC_MD5_DIGESTLENGTH * 2 + 3;
1595  id->buffer->data[id->len] = 0;
1596  id->terminated = 1;
1597 
1598  return (1);
1599 }
1600 
1601 int get_dhcid(dhcp_ddns_cb_t *ddns_cb,
1602  int type,
1603  const u_int8_t *identifier,
1604  unsigned id_len)
1605 {
1606  if (ddns_cb->dhcid_class == dns_rdatatype_dhcid)
1607  return get_std_dhcid(ddns_cb, type, identifier, id_len);
1608  else
1609  return get_int_dhcid(ddns_cb, type, identifier, id_len);
1610 }
1611 
1612 /*
1613  * The dhcid (text version) that we pass to DNS includes a length byte
1614  * at the start but the text we store in the lease doesn't include the
1615  * length byte. The following routines are to convert between the two
1616  * styles.
1617  *
1618  * When converting from a dhcid to a leaseid we reuse the buffer and
1619  * simply adjust the data pointer and length fields in the data string.
1620  * This avoids any prolems with allocating space.
1621  */
1622 
1623 void
1624 dhcid_tolease(struct data_string *dhcid,
1625  struct data_string *leaseid)
1626 {
1627  /* copy the data string then update the fields */
1628  data_string_copy(leaseid, dhcid, MDL);
1629  leaseid->data++;
1630  leaseid->len--;
1631 }
1632 
1633 isc_result_t
1634 dhcid_fromlease(struct data_string *dhcid,
1635  struct data_string *leaseid)
1636 {
1637  if (!buffer_allocate(&dhcid->buffer, leaseid->len + 2, MDL)) {
1638  return(ISC_R_FAILURE);
1639  }
1640 
1641  dhcid->data = dhcid->buffer->data;
1642 
1643  dhcid->buffer->data[0] = leaseid->len;
1644  memcpy(dhcid->buffer->data + 1, leaseid->data, leaseid->len);
1645  dhcid->len = leaseid->len + 1;
1646  if (leaseid->terminated == 1) {
1647  dhcid->buffer->data[dhcid->len] = 0;
1648  dhcid->terminated = 1;
1649  }
1650 
1651  return(ISC_R_SUCCESS);
1652 }
1653 
1654 /*
1655  * Construct the dataset for this item.
1656  * This is a fairly simple arrangement as the operations we do are simple.
1657  * If there is data we simply have the rdata point to it - the formatting
1658  * must be correct already. We then link the rdatalist to the rdata and
1659  * create a rdataset from the rdatalist.
1660  */
1661 
1662 static isc_result_t
1663 make_dns_dataset(dns_rdataclass_t dataclass,
1664  dns_rdatatype_t datatype,
1665  dhcp_ddns_data_t *dataspace,
1666  unsigned char *data,
1667  int datalen,
1668  int ttl)
1669 {
1670  dns_rdata_t *rdata = &dataspace->rdata;
1671  dns_rdatalist_t *rdatalist = &dataspace->rdatalist;
1672  dns_rdataset_t *rdataset = &dataspace->rdataset;
1673 
1674  isc_region_t region;
1675 
1676  /* set up the rdata */
1677  dns_rdata_init(rdata);
1678 
1679  if (data == NULL) {
1680  /* No data, set up the rdata fields we care about */
1681  rdata->flags = DNS_RDATA_UPDATE;
1682  rdata->type = datatype;
1683  rdata->rdclass = dataclass;
1684  } else {
1685  switch(datatype) {
1686  case dns_rdatatype_a:
1687  case dns_rdatatype_aaaa:
1688  case dns_rdatatype_txt:
1689  case dns_rdatatype_dhcid:
1690  case dns_rdatatype_ptr:
1691  /* The data must be in the right format we simply
1692  * need to supply it via the correct structure */
1693  region.base = data;
1694  region.length = datalen;
1695  dns_rdata_fromregion(rdata, dataclass, datatype,
1696  &region);
1697  break;
1698  default:
1699  return(DHCP_R_INVALIDARG);
1700  break;
1701  }
1702  }
1703 
1704  /* setup the datalist and attach the rdata to it */
1705  dns_rdatalist_init(rdatalist);
1706  rdatalist->type = datatype;
1707  rdatalist->rdclass = dataclass;
1708  rdatalist->ttl = ttl;
1709  ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1710 
1711  /* convert the datalist to a dataset */
1712  dns_rdataset_init(rdataset);
1713  dns_rdatalist_tordataset(rdatalist, rdataset);
1714 
1715  return(ISC_R_SUCCESS);
1716 }
1717 
1718 #if defined (DEBUG_DNS_UPDATES)
1719 static void log_call(char *text, dns_name_t* pname, dns_name_t* uname) {
1720  char buf1[512];
1721  char buf2[512];
1722  if (pname) {
1723  dns_name_format(pname, buf1, 512);
1724  } else {
1725  *buf1=0;
1726  }
1727 
1728  if (uname) {
1729  dns_name_format(uname, buf2, 512);
1730  } else {
1731  *buf2=0;
1732  }
1733 
1734  log_info ("DDNS: %s: pname:[%s] uname:[%s]", text, buf1, buf2);
1735 }
1736 #endif
1737 
1738 
1739 /*
1740  * When a DHCP client or server intends to update an A RR, it first
1741  * prepares a DNS UPDATE query which includes as a prerequisite the
1742  * assertion that the name does not exist. The update section of the
1743  * query attempts to add the new name and its IP address mapping (an A
1744  * RR), and the DHCID RR with its unique client-identity.
1745  * -- "Interaction between DHCP and DNS"
1746  *
1747  * There are two cases, one for the server and one for the client.
1748  *
1749  * For the server the first step will have a request of:
1750  * The name is not in use
1751  * Add an A RR
1752  * Add a DHCID RR
1753  *
1754  * For the client the first step will have a request of:
1755  * The A RR does not exist
1756  * Add an A RR
1757  * Add a DHCID RR
1758  */
1759 
1760 static isc_result_t
1761 build_fwd_add1(dhcp_ddns_cb_t *ddns_cb,
1762  dhcp_ddns_data_t *dataspace,
1763  dns_name_t *pname,
1764  dns_name_t *uname)
1765 {
1766  isc_result_t result;
1767 
1768 #if defined (DEBUG_DNS_UPDATES)
1769  log_call("build_fwd_add1", pname, uname);
1770 #endif
1771 
1772  /* Construct the prerequisite list */
1773  if ((ddns_cb->flags & DDNS_INCLUDE_RRSET) != 0) {
1774  /* The A RR shouldn't exist */
1775  result = make_dns_dataset(dns_rdataclass_none,
1776  ddns_cb->address_type,
1777  dataspace, NULL, 0, 0);
1778  } else {
1779  /* The name is not in use */
1780  result = make_dns_dataset(dns_rdataclass_none,
1781  dns_rdatatype_any,
1782  dataspace, NULL, 0, 0);
1783  }
1784  if (result != ISC_R_SUCCESS) {
1785  return(result);
1786  }
1787  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1788  dataspace++;
1789 
1790  /* Construct the update list */
1791  /* Add the A RR */
1792  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type,
1793  dataspace,
1794  (unsigned char *)ddns_cb->address.iabuf,
1795  ddns_cb->address.len, ddns_cb->ttl);
1796  if (result != ISC_R_SUCCESS) {
1797  return(result);
1798  }
1799  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1800  dataspace++;
1801 
1802  /* Add the DHCID RR */
1803  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
1804  dataspace,
1805  (unsigned char *)ddns_cb->dhcid.data,
1806  ddns_cb->dhcid.len, ddns_cb->ttl);
1807  if (result != ISC_R_SUCCESS) {
1808  return(result);
1809  }
1810  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1811 
1812  return(ISC_R_SUCCESS);
1813 }
1814 
1815 /*
1816  * If the first update operation fails with YXDOMAIN, the updater can
1817  * conclude that the intended name is in use. The updater then
1818  * attempts to confirm that the DNS name is not being used by some
1819  * other host. The updater prepares a second UPDATE query in which the
1820  * prerequisite is that the desired name has attached to it a DHCID RR
1821  * whose contents match the client identity. The update section of
1822  * this query deletes the existing A records on the name, and adds the
1823  * A record that matches the DHCP binding and the DHCID RR with the
1824  * client identity.
1825  * -- "Interaction between DHCP and DNS"
1826  *
1827  * The message for the second step depends on if we are doing conflict
1828  * resolution. If we are we include the prerequisite. The prerequiste
1829  * will either:
1830  * A. require the data value of the DHCID RR to match that of the client
1831  * or
1832  * B. required only that the DHCID RR of the configured class (DHCID or
1833  * TXT) exist
1834  *
1835  * based on whether DDNS_GUARD_ID_MUST_MATCH is on (default) or off.
1836  *
1837  * The prerequisite is omitted if conflict detection is off.
1838  *
1839  * If not we delete the DHCID in addition to all A rrsets.
1840  *
1841  * Conflict resolution:
1842  * DHCID RR exists, and matches client identity.
1843  * Delete A RRset.
1844  * Add A RR.
1845  *
1846  * Conflict override:
1847  * Delete DHCID RRs.
1848  * Add DHCID RR
1849  * Delete A RRset.
1850  * Add A RR.
1851  */
1852 
1853 static isc_result_t
1854 build_fwd_add2(dhcp_ddns_cb_t *ddns_cb,
1855  dhcp_ddns_data_t *dataspace,
1856  dns_name_t *pname,
1857  dns_name_t *uname)
1858 {
1859  isc_result_t result = ISC_R_SUCCESS;
1860 
1861 #if defined (DEBUG_DNS_UPDATES)
1862  log_call("build_fwd_add2", pname, uname);
1863 #endif
1864 
1865  /*
1866  * If we are doing conflict detection we use a prereq list.
1867  * If not we delete the DHCID in addition to all A rrsets.
1868  */
1869  if (ddns_cb->flags & DDNS_CONFLICT_DETECTION) {
1870  /* Construct the prereq list */
1871  /* The DHCID RR exists and optionally matches the client's
1872  * identity. If matching is turned off, we use the presence
1873  * of a DHCID RR to signal that this is a dynamic entry and
1874  * thus eligible for us to overwrite. If matching is on
1875  * then we can only replace the entries if they belong to
1876  * this client. */
1877  unsigned char *match_id = NULL;
1878  int match_id_len = 0;
1879  int match_class = dns_rdataclass_any;
1880  if (ddns_cb->flags & DDNS_GUARD_ID_MUST_MATCH) {
1881  match_id = (unsigned char*)(ddns_cb->dhcid.data);
1882  match_id_len = ddns_cb->dhcid.len;
1883  match_class = dns_rdataclass_in;
1884  }
1885 
1886  result = make_dns_dataset(match_class,
1887  ddns_cb->dhcid_class,
1888  dataspace,
1889  match_id, match_id_len, 0);
1890  if (result != ISC_R_SUCCESS) {
1891  return(result);
1892  }
1893  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1894  dataspace++;
1895  } else {
1896  /* Start constructing the update list.
1897  * Conflict detection override: delete DHCID RRs */
1898  result = make_dns_dataset(dns_rdataclass_any,
1899  ddns_cb->dhcid_class,
1900  dataspace, NULL, 0, 0);
1901  if (result != ISC_R_SUCCESS) {
1902  return(result);
1903  }
1904  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1905  dataspace++;
1906 
1907  /* Add current DHCID RR, always include client id */
1908  result = make_dns_dataset(dns_rdataclass_in,
1909  ddns_cb->dhcid_class,
1910  dataspace,
1911  (unsigned char *)ddns_cb->dhcid.data,
1912  ddns_cb->dhcid.len, ddns_cb->ttl);
1913  if (result != ISC_R_SUCCESS) {
1914  return(result);
1915  }
1916  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1917  dataspace++;
1918  }
1919 
1920  /* Start or continue constructing the update list */
1921  /* Delete the address RRset */
1922  result = make_dns_dataset(dns_rdataclass_any, ddns_cb->address_type,
1923  dataspace, NULL, 0, 0);
1924  if (result != ISC_R_SUCCESS) {
1925  return(result);
1926  }
1927  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1928  dataspace++;
1929 
1930  /* Add the address RR */
1931  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type,
1932  dataspace,
1933  (unsigned char *)ddns_cb->address.iabuf,
1934  ddns_cb->address.len, ddns_cb->ttl);
1935  if (result != ISC_R_SUCCESS) {
1936  return(result);
1937  }
1938  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1939 
1940  return(ISC_R_SUCCESS);
1941 }
1942 
1943 /*
1944  * Creates the DNS foward update add used for DSMM add attempt #3 and
1945  * ddns-other-guard-is-dynamic is off
1946  *
1947  *
1948  * If the second update failed with NXRRSET, this indicates that:
1949  *
1950  * 1. our FQDN is in use
1951  * 2 no guard record (DHCID RR) for that FQDN, of our class (and optionally
1952  * client id) exists
1953  *
1954  * In Dual Stack Mixed Mode, we need to attempt a third add, to distinguish
1955  * between static entries that we cannot modify and dynamic entries belonging
1956  * to the "other" side of dual stack. The prerequisites for this add are:
1957  *
1958  * 1. No address record of my type exists
1959  * 2. No guard record of my type exists
1960  * 3. A guard record of the other type exists
1961  *
1962  * and updates which will add the new address and guard record:
1963  *
1964  * prereq nxrrset <name> <addr_t> # no address record of my type
1965  * prereq nxrrset <name> <guard_t> # no guard record of my type
1966  * prereq yxrrset <name> <other_guard_t> # other guard type does exist
1967  * update add <name> <addr_t> <address> # add the new address record
1968  * update add <name> <guard_t> <client-id> # add the new address record
1969  */
1970 static isc_result_t
1971 build_dsmm_fwd_add3(dhcp_ddns_cb_t *ddns_cb,
1972  dhcp_ddns_data_t *dataspace,
1973  dns_name_t *pname,
1974  dns_name_t *uname)
1975 {
1976  isc_result_t result = ISC_R_SUCCESS;
1977 
1978 #if defined (DEBUG_DNS_UPDATES)
1979  log_call("build_fwd_add3", pname, uname);
1980 #endif
1981  /* Construct the prereq list */
1982  /* No address record of my type exists */
1983  result = make_dns_dataset(dns_rdataclass_none,
1984  ddns_cb->address_type,
1985  dataspace, NULL, 0, 0);
1986  if (result != ISC_R_SUCCESS) {
1987  return(result);
1988  }
1989  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1990  dataspace++;
1991 
1992  /* No guard record of my type exists */
1993  result = make_dns_dataset(dns_rdataclass_none,
1994  ddns_cb->dhcid_class,
1995  dataspace, NULL, 0, 0);
1996  if (result != ISC_R_SUCCESS) {
1997  return(result);
1998  }
1999  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2000  dataspace++;
2001 
2002  /* Guard record of the other type DOES exist */
2003  result = make_dns_dataset(dns_rdataclass_any,
2004  ddns_cb->other_dhcid_class,
2005  dataspace, NULL, 0, 0);
2006  if (result != ISC_R_SUCCESS) {
2007  return(result);
2008  }
2009  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2010  dataspace++;
2011 
2012  /* Start constructing the update list. */
2013  /* Add the address RR */
2014  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type,
2015  dataspace,
2016  (unsigned char *)ddns_cb->address.iabuf,
2017  ddns_cb->address.len, ddns_cb->ttl);
2018  if (result != ISC_R_SUCCESS) {
2019  return(result);
2020  }
2021  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2022  dataspace++;
2023 
2024  /* Add current DHCID RR */
2025  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
2026  dataspace,
2027  (unsigned char *)ddns_cb->dhcid.data,
2028  ddns_cb->dhcid.len, ddns_cb->ttl);
2029  if (result != ISC_R_SUCCESS) {
2030  return(result);
2031  }
2032  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2033 
2034  return(ISC_R_SUCCESS);
2035 }
2036 
2037 /*
2038  * Creates the DNS foward update add used for DSMM add attempt #3 and
2039  * ddns-other-guard-is-dynamic is ON
2040  *
2041  * If the second update failed with NXRRSET, this indicates that:
2042  *
2043  * 1. our FQDN is in use
2044  * 2 no guard record (DHCID RR) for that FQDN, of our class (and optionally
2045  * client id) exists
2046  *
2047  * When we're In Dual Stack Mixed Mode and ddns-other-guard-is-dynamic is ON
2048  * we need only determine if a guard record of the other type exists, to know
2049  * if we can add/replace and address record of our type. In other words,
2050  * the presence of a dynamic entry made belonging to the "other" stack means
2051  * all entries for this name should be dynamic and we overwrite an unguarded
2052  * address record of our type.
2053  *
2054  * The udpate will contain a single prequisite for a guard record of the
2055  * other type, an update to delete any address records of our type, and
2056  * updates to add the address and guard records:
2057  *
2058  * prereq yxrrset <name> <other_guard_t> # other guard type exists
2059  * update delete <name> <addr_t> # delete existing address record
2060  * # (if one)
2061  * update add <name> <addr_t> <address> # add new address record
2062  * update add <name> <guard_t> <client-id> # add new guard record
2063  */
2064 static isc_result_t
2065 build_dsmm_fwd_add3_other(dhcp_ddns_cb_t *ddns_cb,
2066  dhcp_ddns_data_t *dataspace,
2067  dns_name_t *pname,
2068  dns_name_t *uname)
2069 {
2070  isc_result_t result = ISC_R_SUCCESS;
2071 
2072 #if defined (DEBUG_DNS_UPDATES)
2073  log_call("build_fwd_add3_other", pname, uname);
2074 #endif
2075  /* Construct the prereq list */
2076  /* A guard record of the other type exists */
2077  result = make_dns_dataset(dns_rdataclass_any,
2078  ddns_cb->other_dhcid_class,
2079  dataspace, NULL, 0, 0);
2080  if (result != ISC_R_SUCCESS) {
2081  return(result);
2082  }
2083  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2084  dataspace++;
2085 
2086  /* Start constructing the update list. */
2087  /* Delete the existing address record of my type (if one) */
2088  result = make_dns_dataset(dns_rdataclass_any,
2089  ddns_cb->address_type,
2090  dataspace, NULL, 0, 0);
2091  if (result != ISC_R_SUCCESS) {
2092  return(result);
2093  }
2094  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2095  dataspace++;
2096 
2097  /* Add the address RR */
2098  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type,
2099  dataspace,
2100  (unsigned char *)ddns_cb->address.iabuf,
2101  ddns_cb->address.len, ddns_cb->ttl);
2102  if (result != ISC_R_SUCCESS) {
2103  return(result);
2104  }
2105  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2106  dataspace++;
2107 
2108  /* Add current DHCID RR */
2109  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
2110  dataspace,
2111  (unsigned char *)ddns_cb->dhcid.data,
2112  ddns_cb->dhcid.len, ddns_cb->ttl);
2113  if (result != ISC_R_SUCCESS) {
2114  return(result);
2115  }
2116  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2117 
2118  return(ISC_R_SUCCESS);
2119 }
2120 
2121 /*
2122  * The entity chosen to handle the A record for this client (either the
2123  * client or the server) SHOULD delete the A (or AAAA) record that was
2124  * added when the lease was made to the client.
2125  *
2126  * If we are doing conflict resolution, the udpate will contain a prequisite
2127  * that will either:
2128  * A. require that a guard record of the configure class (DHCID or TXT) with
2129  * a data value matching that the client exist (per RFC 4703)
2130  * or
2131  * B. require only that the guard record of the configured class exist
2132  *
2133  * based on whether DDNS_GUARD_ID_MUST_MATCH is on (default) or off.
2134  *
2135  * The prerequisite is omitted if conflict detection is off.
2136  *
2137  */
2138 static isc_result_t
2139 build_fwd_rem1(dhcp_ddns_cb_t *ddns_cb,
2140  dhcp_ddns_data_t *dataspace,
2141  dns_name_t *pname,
2142  dns_name_t *uname)
2143 {
2144  isc_result_t result = ISC_R_SUCCESS;
2145 
2146 #if defined (DEBUG_DNS_UPDATES)
2147  log_call("build_fwd_rem1", pname, uname);
2148 #endif
2149 
2150  /* If we're doing conflict detection, add the guard record pre-req */
2151  if (ddns_cb->flags & DDNS_CONFLICT_DETECTION) {
2152  /* Construct the prereq list */
2153  /* The guard record exists and optionally matches the client's
2154  * identity. If matching is turned off, we use the presence
2155  * of a DHCID RR to signal that this is a dynamic entry and
2156  * thus eligible for us to overwrite. If matching is on
2157  * then we can only delete the entries if they belong to
2158  * this client. */
2159  unsigned char *match_id = NULL;
2160  int match_id_len = 0;
2161  int match_class = dns_rdataclass_any;
2162  if (ddns_cb->flags & DDNS_GUARD_ID_MUST_MATCH) {
2163  match_id = (unsigned char*)(ddns_cb->dhcid.data);
2164  match_id_len = ddns_cb->dhcid.len;
2165  match_class = dns_rdataclass_in;
2166  }
2167 
2168  result = make_dns_dataset(match_class,
2169  ddns_cb->dhcid_class,
2170  dataspace,
2171  match_id, match_id_len, 0);
2172  if (result != ISC_R_SUCCESS) {
2173  return(result);
2174  }
2175  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2176  dataspace++;
2177  }
2178 
2179  /* Construct the update list */
2180  /* Delete A RRset */
2181  result = make_dns_dataset(dns_rdataclass_none, ddns_cb->address_type,
2182  dataspace,
2183  (unsigned char *)ddns_cb->address.iabuf,
2184  ddns_cb->address.len, 0);
2185  if (result != ISC_R_SUCCESS) {
2186  return(result);
2187  }
2188  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2189 
2190  return(ISC_R_SUCCESS);
2191 }
2192 
2193 /*
2194  * If the deletion of the A succeeded, and there are no A or AAAA
2195  * records left for this domain, then we can blow away the DHCID
2196  * record as well. We can't blow away the DHCID record above
2197  * because it's possible that more than one record has been added
2198  * to this domain name.
2199  *
2200  * Second query has:
2201  * A RR does not exist.
2202  * AAAA RR does not exist.
2203  * Delete appropriate DHCID RR.
2204  */
2205 static isc_result_t
2206 build_fwd_rem2(dhcp_ddns_cb_t *ddns_cb,
2207  dhcp_ddns_data_t *dataspace,
2208  dns_name_t *pname,
2209  dns_name_t *uname)
2210 {
2211  isc_result_t result;
2212  unsigned char *match_id = NULL;
2213  int match_id_len = 0;
2214  int match_class = dns_rdataclass_any;
2215 
2216 #if defined (DEBUG_DNS_UPDATES)
2217  log_call("build_fwd_rem2", pname, uname);
2218 #endif
2219 
2220  /* Construct the prereq list */
2221  /* The A RR does not exist */
2222  result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_a,
2223  dataspace, NULL, 0, 0);
2224  if (result != ISC_R_SUCCESS) {
2225  return(result);
2226  }
2227  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2228  dataspace++;
2229 
2230  /* The AAAA RR does not exist */
2231  result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_aaaa,
2232  dataspace, NULL, 0, 0);
2233  if (result != ISC_R_SUCCESS) {
2234  return(result);
2235  }
2236  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2237  dataspace++;
2238 
2239  /* Construct the update list */
2240  /* Delete DHCID RR */
2241 
2242  /* We'll specify the client id in the guard record delete if
2243  * matching is enabled, otherwise we leave it off. */
2244  if (ddns_cb->flags & DDNS_GUARD_ID_MUST_MATCH) {
2245  match_id = (unsigned char*)(ddns_cb->dhcid.data);
2246  match_id_len = ddns_cb->dhcid.len;
2247  match_class = dns_rdataclass_none;
2248  }
2249 
2250  result = make_dns_dataset(match_class, ddns_cb->dhcid_class,
2251  dataspace,
2252  match_id, match_id_len, 0);
2253  if (result != ISC_R_SUCCESS) {
2254  return(result);
2255  }
2256  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2257 
2258  return(ISC_R_SUCCESS);
2259 }
2260 
2261 /*
2262  * Constructs the second stage forward remove, when the first stage
2263  * succeeds and DSMM is enabled, and ddns-other-guard-is-dynamic is OFF
2264  *
2265  * Normal conflict detection requires that the guard record of the
2266  * configured type only be deleted if there are no address records of
2267  * any type. In Dual Stack Mixed Mode, we are only concerned with whether
2268  * there any records or our configured address type remaining.
2269  *
2270  * This update consists of a single prequisite that there be no address
2271  * records of our type followed by a delete of the guard record of our type
2272  * and optionally matching client-id.
2273  *
2274  * prereq nxrrset name <addr_t> # no records of this address type exist
2275  * update delete name <guard_t> <client_id> # delete the existing guard record
2276  */
2277 static isc_result_t
2278 build_fwd_rem2_dsmm (dhcp_ddns_cb_t *ddns_cb,
2279  dhcp_ddns_data_t *dataspace,
2280  dns_name_t *pname,
2281  dns_name_t *uname)
2282 {
2283  isc_result_t result;
2284  unsigned char *match_id = NULL;
2285  int match_id_len = 0;
2286  int match_class = dns_rdataclass_any;
2287 
2288 #if defined (DEBUG_DNS_UPDATES)
2289  log_call("build_fwd_rem2_dsmm", pname, uname);
2290 #endif
2291 
2292  /* Construct the prereq list */
2293  /* The address RR does not exist */
2294  result = make_dns_dataset(dns_rdataclass_none,
2295  ddns_cb->address_type,
2296  dataspace, NULL, 0, 0);
2297  if (result != ISC_R_SUCCESS) {
2298  return(result);
2299  }
2300  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2301  dataspace++;
2302 
2303  /* Construct the update list */
2304  /* Delete DHCID RR */
2305 
2306  /* We'll specify the client id in the guard record delete if
2307  * matching is enabled, otherwise we leave it off. */
2308  if (ddns_cb->flags & DDNS_GUARD_ID_MUST_MATCH) {
2309  match_id = (unsigned char*)(ddns_cb->dhcid.data);
2310  match_id_len = ddns_cb->dhcid.len;
2311  match_class = dns_rdataclass_none;
2312  }
2313 
2314  result = make_dns_dataset(match_class, ddns_cb->dhcid_class,
2315  dataspace,
2316  match_id, match_id_len, 0);
2317  if (result != ISC_R_SUCCESS) {
2318  return(result);
2319  }
2320  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2321 
2322  return(ISC_R_SUCCESS);
2323 }
2324 
2325 /*
2326  * Constructs the second stage forward remove, when the first stage
2327  * succeeds and DSMM is enabled and ddns-other-guard-is-dynamic is ON
2328  *
2329  * This update addresses the case when an address record of our type exists
2330  * without a guard record of our type, yet a dynamic entry of the other type
2331  * exists. The presence of a guard of the other type indicates that all
2332  * entries for this name should be treated as dynamic, thus permitting us to
2333  * remove the address record of our type.
2334  *
2335  * prereq nxrrset <name> <guard_t> # my guard type does not exist
2336  * prereq yxrrset <name> <other_guard_t> # other guard type does exist
2337  * update delete <name> <addr_t> address # delete the existing address record
2338  *
2339  */
2340 static isc_result_t
2341 build_fwd_rem2_dsmm_other(dhcp_ddns_cb_t *ddns_cb,
2342  dhcp_ddns_data_t *dataspace,
2343  dns_name_t *pname,
2344  dns_name_t *uname)
2345 {
2346  isc_result_t result;
2347 
2348 #if defined (DEBUG_DNS_UPDATES)
2349  log_call("build_fwd_rem2_dsmm_other", pname, uname);
2350 #endif
2351 
2352  /* Construct the prereq list */
2353  /* No guard record of my type exists */
2354  result = make_dns_dataset(dns_rdataclass_none, ddns_cb->dhcid_class,
2355  dataspace, NULL, 0, 0);
2356  if (result != ISC_R_SUCCESS) {
2357  return(result);
2358  }
2359  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2360  dataspace++;
2361 
2362  /* Guard record of the OTHER type DOES exist */
2363  result = make_dns_dataset(dns_rdataclass_any,
2364  ddns_cb->other_dhcid_class,
2365  dataspace, NULL, 0, 0);
2366  if (result != ISC_R_SUCCESS) {
2367  return(result);
2368  }
2369  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2370  dataspace++;
2371 
2372  /* Construct the update list */
2373  /* Delete the address RRset */
2374  result = make_dns_dataset(dns_rdataclass_none, ddns_cb->address_type,
2375  dataspace,
2376  (unsigned char *)ddns_cb->address.iabuf,
2377  ddns_cb->address.len, 0);
2378  if (result != ISC_R_SUCCESS) {
2379  return(result);
2380  }
2381  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2382 
2383  return(ISC_R_SUCCESS);
2384 }
2385 
2386 /*
2387  * This routine converts from the task action call into something
2388  * easier to work with. It also handles the common case of a signature
2389  * or zone not being correct.
2390  */
2391 void ddns_interlude(isc_task_t *taskp,
2392  isc_event_t *eventp)
2393 {
2394  dhcp_ddns_cb_t *ddns_cb = (dhcp_ddns_cb_t *)eventp->ev_arg;
2395  dns_clientupdateevent_t *ddns_event = (dns_clientupdateevent_t *)eventp;
2396  isc_result_t eresult = ddns_event->result;
2397  isc_result_t result;
2398 
2399  /* We've extracted the information we want from it, get rid of
2400  * the event block.*/
2401  isc_event_free(&eventp);
2402 
2403 #if defined (TRACING)
2404  if (trace_record()) {
2405  trace_ddns_input_write(ddns_cb, eresult);
2406  }
2407 #endif
2408 
2409 #if defined (DEBUG_DNS_UPDATES)
2410  print_dns_status(DDNS_PRINT_INBOUND, ddns_cb, eresult);
2411 #endif
2412 
2413  /* This transaction is complete, clear the value */
2414  dns_client_destroyupdatetrans(&ddns_cb->transaction);
2415 
2416  /* If we cancelled or tried to cancel the operation we just
2417  * need to clean up. */
2418  if ((eresult == ISC_R_CANCELED) ||
2419  ((ddns_cb->flags & DDNS_ABORT) != 0)) {
2420 #if defined (DEBUG_DNS_UPDATES)
2421  log_info("DDNS: completeing transaction cancellation cb=%p, "
2422  "flags=%x, %s",
2423  ddns_cb, ddns_cb->flags, isc_result_totext(eresult));
2424 #endif
2425  if ((ddns_cb->flags & DDNS_ABORT) == 0) {
2426  log_info("DDNS: cleaning up lease pointer for a cancel "
2427  "cb=%p", ddns_cb);
2428  /*
2429  * We shouldn't actually be able to get here but
2430  * we are. This means we haven't cleaned up
2431  * the lease pointer so we need to do that before
2432  * freeing the cb.
2433  */
2434  ddns_cb->cur_func(ddns_cb, eresult);
2435  return;
2436  }
2437 
2438  if (ddns_cb->next_op != NULL) {
2439  /* if necessary cleanup up next op block */
2440  ddns_cb_free(ddns_cb->next_op, MDL);
2441  }
2442  ddns_cb_free(ddns_cb, MDL);
2443  return;
2444  }
2445 
2446  /* If we had a problem with our key or zone try again */
2447  if ((eresult == DNS_R_NOTAUTH) ||
2448  (eresult == DNS_R_NOTZONE)) {
2449  int i;
2450  /* Our zone information was questionable,
2451  * repudiate it and try again */
2452  log_error("DDNS: bad zone information, repudiating zone %s",
2453  ddns_cb->zone_name);
2454  repudiate_zone(&ddns_cb->zone);
2455  ddns_cb->zone_name[0] = 0;
2456  ISC_LIST_INIT(ddns_cb->zone_server_list);
2457  for (i = 0; i < DHCP_MAXNS; i++) {
2458  ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link);
2459  }
2460 
2461  if ((ddns_cb->state == DDNS_STATE_ADD_PTR) ||
2462  (ddns_cb->state == DDNS_STATE_REM_PTR)) {
2463  result = ddns_modify_ptr(ddns_cb, MDL);
2464  } else {
2465  result = ddns_modify_fwd(ddns_cb, MDL);
2466  }
2467 
2468  if (result != ISC_R_SUCCESS) {
2469  /* if we couldn't redo the query log it and
2470  * let the next function clean it up */
2471  log_info("DDNS: Failed to retry after zone failure");
2472  ddns_cb->cur_func(ddns_cb, result);
2473  }
2474  return;
2475  } else {
2476  /* pass it along to be processed */
2477  ddns_cb->cur_func(ddns_cb, eresult);
2478  }
2479 
2480  return;
2481 }
2482 
2483 /*
2484  * This routine does the generic work for sending a ddns message to
2485  * modify the forward record (A or AAAA) and calls one of a set of
2486  * routines to build the specific message.
2487  */
2488 
2489 isc_result_t
2490 ddns_modify_fwd(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
2491 {
2492  isc_result_t result;
2493  dns_tsec_t *tsec_key = NULL;
2494 
2495 #if defined (DEBUG_DNS_UPDATES)
2496  log_info("DDNS: ddns_modify_fwd");
2497 #endif
2498 
2499  unsigned char *clientname;
2500  dhcp_ddns_data_t *dataspace = NULL;
2501  dns_namelist_t prereqlist, updatelist;
2502  dns_fixedname_t zname0, pname0, uname0;
2503  dns_name_t *zname = NULL, *pname, *uname;
2504 
2505  isc_sockaddrlist_t *zlist = NULL;
2506 
2507  /* Creates client context if we need to */
2508  result = dns_client_init();
2509  if (result != ISC_R_SUCCESS) {
2510  return result;
2511  }
2512 
2513  /* Get a pointer to the clientname to make things easier. */
2514  clientname = (unsigned char *)ddns_cb->fwd_name.data;
2515 
2516  /* Extract and validate the type of the address. */
2517  if (ddns_cb->address.len == 4) {
2518  ddns_cb->address_type = dns_rdatatype_a;
2519  } else if (ddns_cb->address.len == 16) {
2520  ddns_cb->address_type = dns_rdatatype_aaaa;
2521  } else {
2522  return DHCP_R_INVALIDARG;
2523  }
2524 
2525  /*
2526  * If we already have a zone use it, otherwise try to lookup the
2527  * zone in our cache. If we find one we will have a pointer to
2528  * the zone that needs to be dereferenced when we are done with it.
2529  * If we don't find one that is okay we'll let the DNS code try and
2530  * find the information for us.
2531  */
2532 
2533  if (ddns_cb->zone == NULL) {
2534  result = find_cached_zone(ddns_cb, FIND_FORWARD);
2535 #if defined (DNS_ZONE_LOOKUP)
2536  if (result == ISC_R_NOTFOUND) {
2537  /*
2538  * We didn't find a cached zone, see if we can
2539  * can find a nameserver and create a zone.
2540  */
2541  if (find_zone_start(ddns_cb, FIND_FORWARD)
2542  == ISC_R_SUCCESS) {
2543  /*
2544  * We have started the process to find a zone
2545  * queue the ddns_cb for processing after we
2546  * create the zone
2547  */
2548  /* sar - not yet implemented, currently we just
2549  * arrange for things to get cleaned up
2550  */
2551  goto cleanup;
2552  }
2553  }
2554 #endif
2555  if (result != ISC_R_SUCCESS)
2556  goto cleanup;
2557  }
2558 
2559  /*
2560  * If we have a zone try to get any information we need
2561  * from it - name, addresses and the key. The address
2562  * and key may be empty the name can't be.
2563  */
2564  if (ddns_cb->zone) {
2565  /* Set up the zone name for use by DNS */
2566  result = dhcp_isc_name(ddns_cb->zone_name, &zname0, &zname);
2567  if (result != ISC_R_SUCCESS) {
2568  log_error("Unable to build name for zone for "
2569  "fwd update: %s %s",
2570  ddns_cb->zone_name,
2571  isc_result_totext(result));
2572  goto cleanup;
2573  }
2574 
2575  if (!(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
2576  /* If we have any addresses get them */
2577  zlist = &ddns_cb->zone_server_list;
2578  }
2579 
2580 
2581  if (ddns_cb->zone->key != NULL) {
2582  /*
2583  * Not having a key is fine, having a key
2584  * but not a tsec is odd so we warn the user.
2585  */
2586  /*sar*/
2587  /* should we do the warning? */
2588  tsec_key = ddns_cb->zone->key->tsec_key;
2589  if (tsec_key == NULL) {
2590  log_error("No tsec for use with key %s",
2591  ddns_cb->zone->key->name);
2592  }
2593  }
2594  }
2595 
2596  /* Set up the DNS names for the prereq and update lists */
2597  if (((result = dhcp_isc_name(clientname, &pname0, &pname))
2598  != ISC_R_SUCCESS) ||
2599  ((result = dhcp_isc_name(clientname, &uname0, &uname))
2600  != ISC_R_SUCCESS)) {
2601  log_error("Unable to build name for fwd update: %s %s",
2602  clientname, isc_result_totext(result));
2603  goto cleanup;
2604  }
2605 
2606  /* Allocate the various isc dns library structures we may require. */
2607  dataspace = isc_mem_get(dhcp_gbl_ctx.mctx, sizeof(*dataspace) * 4);
2608  if (dataspace == NULL) {
2609  log_error("Unable to allocate memory for fwd update");
2610  result = ISC_R_NOMEMORY;
2611  goto cleanup;
2612  }
2613 
2614  ISC_LIST_INIT(prereqlist);
2615  ISC_LIST_INIT(updatelist);
2616 
2617  switch(ddns_cb->state) {
2619  result = build_fwd_add1(ddns_cb, dataspace, pname, uname);
2620  if (result != ISC_R_SUCCESS) {
2621  goto cleanup;
2622  }
2623  ISC_LIST_APPEND(prereqlist, pname, link);
2624  break;
2625 
2627  result = build_fwd_add2(ddns_cb, dataspace, pname, uname);
2628  if (result != ISC_R_SUCCESS) {
2629  goto cleanup;
2630  }
2631 
2632  /* If we are doing conflict detection we have entries
2633  * in the pname list and we need to attach it to the
2634  * prereqlist */
2635 
2636  if (ddns_cb->flags & DDNS_CONFLICT_DETECTION) {
2637  ISC_LIST_APPEND(prereqlist, pname, link);
2638  }
2639 
2640  break;
2641 
2642  case DDNS_STATE_DSMM_FW_ADD3: {
2643  /* We should only be here if we're doing DSMM */
2644  builder_func_t builder;
2645  if (ddns_cb->flags & DDNS_OTHER_GUARD_IS_DYNAMIC) {
2646  builder = build_dsmm_fwd_add3_other;
2647  } else {
2648  builder = build_dsmm_fwd_add3;
2649  }
2650 
2651  result = (*builder)(ddns_cb, dataspace, pname, uname);
2652  if (result != ISC_R_SUCCESS) {
2653  goto cleanup;
2654  }
2655 
2656  ISC_LIST_APPEND(prereqlist, pname, link);
2657  break;
2658  }
2659 
2661  result = build_fwd_rem1(ddns_cb, dataspace, pname, uname);
2662  if (result != ISC_R_SUCCESS) {
2663  goto cleanup;
2664  }
2665  ISC_LIST_APPEND(prereqlist, pname, link);
2666  break;
2667 
2668  case DDNS_STATE_REM_FW_NXRR: {
2669  builder_func_t builder;
2670 
2671  if (ddns_cb->flags & DDNS_DUAL_STACK_MIXED_MODE) {
2672  builder = build_fwd_rem2_dsmm;
2673  } else {
2674  builder = build_fwd_rem2;
2675  }
2676 
2677  result = (*builder)(ddns_cb, dataspace, pname, uname);
2678  if (result != ISC_R_SUCCESS) {
2679  goto cleanup; }
2680  ISC_LIST_APPEND(prereqlist, pname, link);
2681  break;
2682  }
2683 
2685  result = build_fwd_rem2_dsmm_other(ddns_cb, dataspace,
2686  pname, uname);
2687  if (result != ISC_R_SUCCESS) {
2688  goto cleanup; }
2689  ISC_LIST_APPEND(prereqlist, pname, link);
2690  break;
2691  }
2692 
2693  default:
2694  log_error("ddns_modify_fwd: Invalid state: %d", ddns_cb->state);
2695  result = DHCP_R_INVALIDARG;
2696  goto cleanup;
2697  break;
2698  }
2699 
2700  /*
2701  * We always have an update list but may not have a prereqlist
2702  * if we are doing conflict override.
2703  */
2704  ISC_LIST_APPEND(updatelist, uname, link);
2705 
2706  /* send the message, cleanup and return the result */
2707  result = ddns_update(dhcp_gbl_ctx.dnsclient,
2708  dns_rdataclass_in, zname,
2709  &prereqlist, &updatelist,
2710  zlist, tsec_key,
2711  DNS_CLIENTRESOPT_ALLOWRUN,
2713  ddns_interlude,
2714  (void *)ddns_cb,
2715  &ddns_cb->transaction);
2716  if (result == ISC_R_FAMILYNOSUPPORT) {
2717  log_info("Unable to perform DDNS update, "
2718  "address family not supported");
2719  }
2720 
2721 #if defined (DEBUG_DNS_UPDATES)
2722  print_dns_status(DDNS_PRINT_OUTBOUND, ddns_cb, result);
2723 #endif
2724 
2725  cleanup:
2726 #if defined (DEBUG_DNS_UPDATES)
2727  if (result != ISC_R_SUCCESS) {
2728  log_info("DDNS: %s(%d): error in ddns_modify_fwd %s for %p",
2729  file, line, isc_result_totext(result), ddns_cb);
2730  }
2731 #endif
2732 
2733  if (dataspace != NULL) {
2734  isc_mem_put(dhcp_gbl_ctx.mctx, dataspace,
2735  sizeof(*dataspace) * 4);
2736  }
2737  return(result);
2738 }
2739 
2740 
2741 isc_result_t
2742 ddns_modify_ptr(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
2743 {
2744  isc_result_t result;
2745  dns_tsec_t *tsec_key = NULL;
2746  unsigned char *ptrname;
2747  dhcp_ddns_data_t *dataspace = NULL;
2748  dns_namelist_t updatelist;
2749  dns_fixedname_t zname0, uname0;
2750  dns_name_t *zname = NULL, *uname;
2751  isc_sockaddrlist_t *zlist = NULL;
2752  unsigned char buf[256];
2753  int buflen;
2754 
2755 #if defined (DEBUG_DNS_UPDATES)
2756  log_info("DDNS: ddns_modify_ptr");
2757 #endif
2758 
2759  /* Creates client context if we need to */
2760  result = dns_client_init();
2761  if (result != ISC_R_SUCCESS) {
2762  return result;
2763  }
2764 
2765  /*
2766  * Try to lookup the zone in the zone cache. As with the forward
2767  * case it's okay if we don't have one, the DNS code will try to
2768  * find something also if we succeed we will need to dereference
2769  * the zone later. Unlike with the forward case we assume we won't
2770  * have a pre-existing zone.
2771  */
2772  result = find_cached_zone(ddns_cb, FIND_REVERSE);
2773 
2774 #if defined (DNS_ZONE_LOOKUP)
2775  if (result == ISC_R_NOTFOUND) {
2776  /*
2777  * We didn't find a cached zone, see if we can
2778  * can find a nameserver and create a zone.
2779  */
2780  if (find_zone_start(ddns_cb, FIND_REVERSE) == ISC_R_SUCCESS) {
2781  /*
2782  * We have started the process to find a zone
2783  * queue the ddns_cb for processing after we
2784  * create the zone
2785  */
2786  /* sar - not yet implemented, currently we just
2787  * arrange for things to get cleaned up
2788  */
2789  goto cleanup;
2790  }
2791  }
2792 #endif
2793  if (result != ISC_R_SUCCESS)
2794  goto cleanup;
2795 
2796 
2797  if ((result == ISC_R_SUCCESS) &&
2798  !(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
2799  /* Set up the zone name for use by DNS */
2800  result = dhcp_isc_name(ddns_cb->zone_name, &zname0, &zname);
2801  if (result != ISC_R_SUCCESS) {
2802  log_error("Unable to build name for zone for "
2803  "fwd update: %s %s",
2804  ddns_cb->zone_name,
2805  isc_result_totext(result));
2806  goto cleanup;
2807  }
2808  /* If we have any addresses get them */
2809  if (!(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
2810  zlist = &ddns_cb->zone_server_list;
2811  }
2812 
2813  /*
2814  * If we now have a zone try to get the key, NULL is okay,
2815  * having a key but not a tsec is odd so we warn.
2816  */
2817  /*sar*/
2818  /* should we do the warning if we have a key but no tsec? */
2819  if ((ddns_cb->zone != NULL) && (ddns_cb->zone->key != NULL)) {
2820  tsec_key = ddns_cb->zone->key->tsec_key;
2821  if (tsec_key == NULL) {
2822  log_error("No tsec for use with key %s",
2823  ddns_cb->zone->key->name);
2824  }
2825  }
2826  }
2827 
2828  /* We must have a name for the update list */
2829  /* Get a pointer to the ptrname to make things easier. */
2830  ptrname = (unsigned char *)ddns_cb->rev_name.data;
2831 
2832  if ((result = dhcp_isc_name(ptrname, &uname0, &uname))
2833  != ISC_R_SUCCESS) {
2834  log_error("Unable to build name for fwd update: %s %s",
2835  ptrname, isc_result_totext(result));
2836  goto cleanup;
2837  }
2838 
2839  /*
2840  * Allocate the various isc dns library structures we may require.
2841  * Allocating one blob avoids being halfway through the process
2842  * and being unable to allocate as well as making the free easy.
2843  */
2844  dataspace = isc_mem_get(dhcp_gbl_ctx.mctx, sizeof(*dataspace) * 2);
2845  if (dataspace == NULL) {
2846  log_error("Unable to allocate memory for fwd update");
2847  result = ISC_R_NOMEMORY;
2848  goto cleanup;
2849  }
2850 
2851  ISC_LIST_INIT(updatelist);
2852 
2853  /*
2854  * Construct the update list
2855  * We always delete what's currently there
2856  * Delete PTR RR.
2857  */
2858  result = make_dns_dataset(dns_rdataclass_any, dns_rdatatype_ptr,
2859  &dataspace[0], NULL, 0, 0);
2860  if (result != ISC_R_SUCCESS) {
2861  goto cleanup;
2862  }
2863  ISC_LIST_APPEND(uname->list, &dataspace[0].rdataset, link);
2864 
2865  /*
2866  * If we are updating the pointer we then add the new one
2867  * Add PTR RR.
2868  */
2869  if (ddns_cb->state == DDNS_STATE_ADD_PTR) {
2870  /*
2871  * Need to convert pointer into on the wire representation
2872  */
2873  if (MRns_name_pton((char *)ddns_cb->fwd_name.data,
2874  buf, 256) == -1) {
2875  goto cleanup;
2876  }
2877  buflen = 0;
2878  while (buf[buflen] != 0) {
2879  buflen += buf[buflen] + 1;
2880  }
2881  buflen++;
2882 
2883  result = make_dns_dataset(dns_rdataclass_in,
2884  dns_rdatatype_ptr,
2885  &dataspace[1],
2886  buf, buflen, ddns_cb->ttl);
2887  if (result != ISC_R_SUCCESS) {
2888  goto cleanup;
2889  }
2890  ISC_LIST_APPEND(uname->list, &dataspace[1].rdataset, link);
2891  }
2892 
2893  ISC_LIST_APPEND(updatelist, uname, link);
2894 
2895  /*sar*/
2896  /*
2897  * for now I'll cleanup the dataset immediately, it would be
2898  * more efficient to keep it around in case the signaturure failed
2899  * and we wanted to retry it.
2900  */
2901  /* send the message, cleanup and return the result */
2902  result = ddns_update((dns_client_t *)dhcp_gbl_ctx.dnsclient,
2903  dns_rdataclass_in, zname,
2904  NULL, &updatelist,
2905  zlist, tsec_key,
2906  DNS_CLIENTRESOPT_ALLOWRUN,
2908  ddns_interlude, (void *)ddns_cb,
2909  &ddns_cb->transaction);
2910  if (result == ISC_R_FAMILYNOSUPPORT) {
2911  log_info("Unable to perform DDNS update, "
2912  "address family not supported");
2913  }
2914 
2915 #if defined (DEBUG_DNS_UPDATES)
2916  print_dns_status(DDNS_PRINT_OUTBOUND, ddns_cb, result);
2917 #endif
2918 
2919  cleanup:
2920 #if defined (DEBUG_DNS_UPDATES)
2921  if (result != ISC_R_SUCCESS) {
2922  log_info("DDNS: %s(%d): error in ddns_modify_ptr %s for %p",
2923  file, line, isc_result_totext(result), ddns_cb);
2924  }
2925 #endif
2926 
2927  if (dataspace != NULL) {
2928  isc_mem_put(dhcp_gbl_ctx.mctx, dataspace,
2929  sizeof(*dataspace) * 2);
2930  }
2931  return(result);
2932 }
2933 
2934 void
2935 ddns_cancel(dhcp_ddns_cb_t *ddns_cb, const char *file, int line) {
2936  ddns_cb->flags |= DDNS_ABORT;
2937  if (ddns_cb->transaction != NULL) {
2938  dns_client_cancelupdate((dns_clientupdatetrans_t *)
2939  ddns_cb->transaction);
2940  }
2941  ddns_cb->lease = NULL;
2942 
2943 #if defined (DEBUG_DNS_UPDATES)
2944  log_info("DDNS: %s(%d): cancelling transaction for %p",
2945  file, line, ddns_cb);
2946 #endif
2947 }
2948 
2949 #endif /* NSUPDATE */
2950 
2951 HASH_FUNCTIONS (dns_zone, const char *, struct dns_zone, dns_zone_hash_t,
2953 
2954 #if defined (NSUPDATE)
2955 #if defined (DEBUG_DNS_UPDATES)
2956 /* Defines a type for creating list of labeled integers */
2957 typedef struct {
2958  int val;
2959  char *name;
2960 } LabeledInt;
2961 
2962 char*
2963 ddns_state_name(int state) {
2964  static LabeledInt ints[] = {
2965  { DDNS_STATE_CLEANUP, "DDNS_STATE_CLEANUP" },
2966  { DDNS_STATE_ADD_FW_NXDOMAIN, "DDNS_STATE_ADD_FW_NXDOMAIN" },
2967  { DDNS_STATE_ADD_FW_YXDHCID, "DDNS_STATE_ADD_FW_YXDHCID" },
2968  { DDNS_STATE_ADD_PTR, "DDNS_STATE_ADD_PTR" },
2969  { DDNS_STATE_DSMM_FW_ADD3, "DDNS_STATE_DSMM_FW_ADD3" },
2970  { DDNS_STATE_REM_FW_YXDHCID, "DDNS_STATE_REM_FW_YXDHCID" },
2971  { DDNS_STATE_REM_FW_NXRR, "DDNS_STATE_FW_NXRR" },
2972  { DDNS_STATE_REM_PTR, "DDNS_STATE_REM_PTR" },
2973  { -1, "unknown" },
2974  };
2975 
2976  LabeledInt* li = ints;
2977  while (li->val != -1 && li->val != state) {
2978  ++li;
2979  }
2980 
2981  return (li->name);
2982 }
2983 
2984 int
2985 add_nstring(char **orig, char *max, char *add, int add_len) {
2986  if (*orig && (*orig + add_len < max)) {
2987  strncpy(*orig, add, add_len);
2988  *orig += add_len;
2989  **orig = 0;
2990  return (0);
2991  }
2992 
2993  return (-1);
2994 }
2995 
2996 int
2997 add_string(char **orig, char *max, char *add) {
2998  return (add_nstring(orig, max, add, strlen(add)));
2999 }
3000 
3001 /*
3002  * direction outbound (messages to the dns server)
3003  * inbound (messages from the dns server)
3004  * ddns_cb is the control block associated with the message
3005  * result is the result from the dns code. For outbound calls
3006  * it is from the call to pass the message to the dns library.
3007  * For inbound calls it is from the event returned by the library.
3008  *
3009  * For outbound messages we print whatever we think is interesting
3010  * from the control block.
3011  * For inbound messages we only print the transaction id pointer
3012  * and the result and expect that the user will match them up as
3013  * necessary. Note well: the transaction information is opaque to
3014  * us so we simply print the pointer to it. This should be sufficient
3015  * to match requests and replys in a short sequence but is awkward
3016  * when trying to use it for longer sequences.
3017  */
3018 void
3019 print_dns_status (int direction,
3020  struct dhcp_ddns_cb *ddns_cb,
3021  isc_result_t result)
3022 {
3023  char obuf[1024];
3024  char *s = obuf, *end = &obuf[sizeof(obuf)-2];
3025  char *en;
3026  const char *result_str;
3027  char ddns_address[
3028  sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
3029 
3030  if (direction == DDNS_PRINT_INBOUND) {
3031  log_info("DDNS reply: id ptr %p, result: %s",
3032  ddns_cb->transaction, isc_result_totext(result));
3033  return;
3034  }
3035 
3036  /*
3037  * To avoid having to figure out if any of the strings
3038  * aren't NULL terminated, just 0 the whole string
3039  */
3040  memset(obuf, 0, 1024);
3041 
3042  en = "DDNS request: id ptr ";
3043  if (s + strlen(en) + 16 < end) {
3044  sprintf(s, "%s%p", en, ddns_cb->transaction);
3045  s += strlen(s);
3046  } else {
3047  goto bailout;
3048  }
3049 
3050  en = ddns_state_name(ddns_cb->state);
3051 
3052  switch (ddns_cb->state) {
3058  strcpy(ddns_address, piaddr(ddns_cb->address));
3059  if (s + strlen(en) + strlen(ddns_address) +
3060  ddns_cb->fwd_name.len + 7 < end) {
3061  sprintf(s, " %s %s for %.*s", en, ddns_address,
3062  ddns_cb->fwd_name.len,
3063  ddns_cb->fwd_name.data);
3064  s += strlen(s);
3065  } else {
3066  goto bailout;
3067  }
3068  break;
3069 
3070  case DDNS_STATE_ADD_PTR:
3071  case DDNS_STATE_REM_PTR:
3072  if (s + strlen(en) + ddns_cb->fwd_name.len +
3073  ddns_cb->rev_name.len + 7 < end) {
3074  sprintf(s, " %s %.*s for %.*s", en,
3075  ddns_cb->fwd_name.len,
3076  ddns_cb->fwd_name.data,
3077  ddns_cb->rev_name.len,
3078  ddns_cb->rev_name.data);
3079  s += strlen(s);
3080  } else {
3081  goto bailout;
3082  }
3083  break;
3084 
3085  case DDNS_STATE_CLEANUP:
3086  default:
3087  if (s + strlen(en) < end) {
3088  sprintf(s, "%s", en);
3089  s += strlen(s);
3090  } else {
3091  goto bailout;
3092  }
3093  break;
3094  }
3095 
3096  en = " zone: ";
3097  if (s + strlen(en) + strlen((char *)ddns_cb->zone_name) < end) {
3098  sprintf(s, "%s%s", en, ddns_cb->zone_name);
3099  s += strlen(s);
3100  } else {
3101  goto bailout;
3102  }
3103 
3104  /* @todo replace with format that matches bind9 zone file */
3105  if (ddns_cb->dhcid_class == dns_rdatatype_dhcid) {
3106  char *idbuf = NULL;
3107  if (add_string(&s, end, "dhcid: [")) {
3108  goto bailout;
3109  }
3110 
3111  idbuf = buf_to_hex(ddns_cb->dhcid.data,
3112  ddns_cb->dhcid.len, MDL);
3113  if (idbuf) {
3114  int ret = add_string(&s, end, idbuf);
3115  dfree(idbuf, MDL);
3116  if (!ret) {
3117  goto bailout;
3118  }
3119  }
3120 
3121  if (add_string(&s, end, "]")) {
3122  goto bailout;
3123  }
3124  } else {
3125  /* 1st byte of a txt dhcid is length, so we skip printing it
3126  * In the event it's empty, we end up not adding anything */
3127  int skip_length_byte = (ddns_cb->dhcid.len > 0 ? 1 : 0);
3128  if (add_string (&s, end, "txt: [") ||
3129  add_nstring (&s, end,
3130  (char *)ddns_cb->dhcid.data + skip_length_byte,
3131  ddns_cb->dhcid.len - skip_length_byte) ||
3132  add_string (&s, end, "]")) {
3133  goto bailout;
3134  }
3135  }
3136 
3137  en = " ttl: ";
3138  if (s + strlen(en) + 10 < end) {
3139  sprintf(s, "%s%ld", en, ddns_cb->ttl);
3140  s += strlen(s);
3141  } else {
3142  goto bailout;
3143  }
3144 
3145  en = " result: ";
3146  result_str = isc_result_totext(result);
3147  if (s + strlen(en) + strlen(result_str) < end) {
3148  sprintf(s, "%s%s", en, result_str);
3149  s += strlen(s);
3150  } else {
3151  goto bailout;
3152  }
3153 
3154  bailout:
3155  /*
3156  * We either finished building the string or ran out
3157  * of space, print whatever we have in case it is useful
3158  */
3159  log_info("%s", obuf);
3160 
3161  return;
3162 }
3163 #endif /* DEBUG_DNS_UPDATES */
3164 #endif /* NSUPDATE */
const char * buf
Definition: trace.h:75
#define rc_register(file, line, reference, addr, refcnt, d, f)
Definition: alloc.h:88
const char int line
Definition: dhcpd.h:3781
dns_rdatalist_t rdatalist
Definition: dns.c:151
#define DDNS_PRINT_INBOUND
Definition: dhcpd.h:1794
struct binding_scope * global_scope
Definition: tree.c:38
struct dns_zone * zone
Definition: dhcpd.h:1815
unsigned char zone_name[DHCP_MAXDNS_WIRE]
Definition: dhcpd.h:1811
unsigned len
Definition: tree.h:79
const char * piaddr(const struct iaddr addr)
Definition: inet.c:579
#define DDNS_STATE_ADD_FW_NXDOMAIN
Definition: dhcpd.h:1781
dns_rdataset_t rdataset
Definition: dns.c:152
#define DDNS_PRINT_OUTBOUND
Definition: dhcpd.h:1795
int get_dhcid(dhcp_ddns_cb_t *, int, const u_int8_t *, unsigned)
isc_result_t dhcp_isc_name(unsigned char *namestr, dns_fixedname_t *namefix, dns_name_t **name)
Definition: isclib.c:272
int option_cache_dereference(struct option_cache **ptr, const char *file, int line)
Definition: options.c:2915
#define MDL
Definition: omapip.h:567
isc_result_t ddns_modify_ptr(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
unsigned char iabuf[16]
Definition: inet.h:33
dhcp_context_t dhcp_gbl_ctx
Definition: isclib.c:33
#define DDNS_STATE_REM_PTR
Definition: dhcpd.h:1788
#define DHCP_R_INVALIDARG
Definition: result.h:48
isc_sockaddr_t zone_addrs[DHCP_MAXNS]
Definition: dhcpd.h:1813
#define HASH_FUNCTIONS(name, bufarg, type, hashtype, ref, deref, hasher)
Definition: hash.h:89
#define DDNS_GUARD_ID_MUST_MATCH
Definition: dhcpd.h:1770
dhcp_ddns_cb_t * ddns_cb_alloc(const char *file, int line)
void data_string_forget(struct data_string *data, const char *file, int line)
Definition: alloc.c:1339
dns_tsec_t * tsec_key
Definition: omapip.h:152
int trace_playback(void)
void print_dns_status(int, struct dhcp_ddns_cb *, isc_result_t)
#define DDNS_ABORT
Definition: dhcpd.h:1766
int log_error(const char *,...) __attribute__((__format__(__printf__
char * ddns_state_name(int state)
int dns_zone_reference(struct dns_zone **ptr, struct dns_zone *bp, const char *file, int line)
Definition: alloc.c:1166
#define DDNS_INCLUDE_RRSET
Definition: dhcpd.h:1762
struct option_cache * secondary6
Definition: dhcpd.h:1510
#define DDNS_STATE_REM_FW_YXDHCID
Definition: dhcpd.h:1786
unsigned len
Definition: inet.h:32
isc_result_t enter_dns_zone(struct dns_zone *zone)
Definition: dns.c:640
struct data_string fwd_name
Definition: dhcpd.h:1803
void forget_zone(struct dns_zone **)
int terminated
Definition: tree.h:80
void ddns_cb_free(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
struct iaddr address
Definition: dhcpd.h:1806
unsigned long ttl
Definition: dhcpd.h:1809
void * lease
Definition: dhcpd.h:1825
#define DHCP_MAXNS
Definition: isclib.h:111
isc_mem_t * mctx
Definition: isclib.h:92
#define FIND_REVERSE
Definition: dhcpd.h:3198
void dhcid_tolease(struct data_string *, struct data_string *)
int option_cache_allocate(struct option_cache **cptr, const char *file, int line)
Definition: alloc.c:630
struct data_string dhcid
Definition: dhcpd.h:1805
struct data_string rev_name
Definition: dhcpd.h:1804
int evaluate_option_cache(struct data_string *result, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct option_cache *oc, const char *file, int line)
Definition: tree.c:2699
char * name
Definition: dhcpd.h:1506
isc_result_t dns_client_init()
Definition: isclib.c:354
dns_rdataclass_t dhcid_class
Definition: dhcpd.h:1831
#define NS_DEFAULTPORT
Definition: nameser.h:86
#define DDNS_STATE_ADD_PTR
Definition: dhcpd.h:1783
int buffer_allocate(struct buffer **ptr, unsigned len, const char *file, int line)
Definition: alloc.c:679
struct auth_key * key
Definition: dhcpd.h:1511
struct dhcp_ddns_cb * next_op
Definition: dhcpd.h:1822
trace_type_t * trace_type_register(const char *, void *, void(*)(trace_type_t *, unsigned, char *), void(*)(trace_type_t *), const char *, int)
unsigned len
Definition: trace.h:76
#define DDNS_OTHER_GUARD_IS_DYNAMIC
Definition: dhcpd.h:1771
#define FIND_FORWARD
Definition: dhcpd.h:3197
isc_result_t trace_write_packet_iov(trace_type_t *, int, trace_iov_t *, const char *, int)
isc_result_t(* builder_func_t)(dhcp_ddns_cb_t *ddns_cb, dhcp_ddns_data_t *dataspace, dns_name_t *pname, dns_name_t *uname)
Definition: dns.c:156
#define cur_time
Definition: dhcpd.h:2109
Definition: ip.h:47
void dfree(void *, const char *, int)
Definition: alloc.c:145
isc_result_t dhcid_fromlease(struct data_string *, struct data_string *)
struct dhcp_ddns_cb dhcp_ddns_cb_t
void ddns_cancel(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
int trace_record(void)
isc_sockaddrlist_t zone_server_list
Definition: dhcpd.h:1812
void repudiate_zone(struct dns_zone **)
int int log_info(const char *,...) __attribute__((__format__(__printf__
void * dmalloc(size_t, const char *, int)
Definition: alloc.c:57
int refcnt
Definition: dhcpd.h:1504
#define DNS_ZONE_INACTIVE
Definition: dhcpd.h:1502
void putUChar(unsigned char *, u_int32_t)
Definition: convert.c:102
void cleanup(void)
int address_type
Definition: dhcpd.h:1807
struct option_cache * secondary
Definition: dhcpd.h:1508
void trace_ddns_init(void)
ddns_action_t cur_func
Definition: dhcpd.h:1820
isc_result_t remove_dns_zone(struct dns_zone *zone)
Definition: dns.c:625
#define DDNS_DUAL_STACK_MIXED_MODE
Definition: dhcpd.h:1769
int MRns_name_pton(const char *src, u_char *dst, size_t dstsiz)
Definition: ns_name.c:141
TIME timeout
Definition: dhcpd.h:1505
isc_task_t * task
Definition: isclib.h:96
struct option_cache * primary6
Definition: dhcpd.h:1509
dns_zone_hash_t * dns_zone_hash
Definition: dns.c:136
unsigned char data[1]
Definition: tree.h:62
Definition: tree.h:60
#define DDNS_STATE_REM_FW_DSMM_OTHER
Definition: dhcpd.h:1789
isc_result_t trace_get_packet(trace_type_t **, unsigned *, char **)
int state
Definition: dhcpd.h:1819
#define DDNS_STATE_ADD_FW_YXDHCID
Definition: dhcpd.h:1782
dns_rdataclass_t other_dhcid_class
Definition: dhcpd.h:1832
u_int16_t flags
Definition: dhcpd.h:1817
dns_rdata_t rdata
Definition: dns.c:150
struct server_list * servers
struct data_string data
Definition: dhcpd.h:390
void * transaction
Definition: dhcpd.h:1828
struct ia_xx * fixed6_ia
Definition: dhcpd.h:1834
void ddns_cb_forget_zone(dhcp_ddns_cb_t *ddns_cb)
int dns_zone_allocate(struct dns_zone **ptr, const char *file, int line)
Definition: alloc.c:1134
#define DDNS_CONFLICT_DETECTION
Definition: dhcpd.h:1763
struct dhcp_ddns_rdata dhcp_ddns_data_t
const char * file
Definition: dhcpd.h:3781
isc_result_t find_cached_zone(dhcp_ddns_cb_t *, int)
void putUShort(unsigned char *, u_int32_t)
Definition: convert.c:86
const unsigned char * data
Definition: tree.h:78
char * name
Definition: omapip.h:149
void data_string_copy(struct data_string *dest, const struct data_string *src, const char *file, int line)
Definition: alloc.c:1323
unsigned do_case_hash(const void *, unsigned, unsigned)
Definition: hash.c:240
#define DNS_HASH_SIZE
Definition: dhcpd.h:140
isc_result_t dns_zone_lookup(struct dns_zone **zone, const char *name)
Definition: dns.c:665
#define DDNS_STATE_DSMM_FW_ADD3
Definition: dhcpd.h:1784
#define RC_MISC
Definition: alloc.h:56
#define DDNS_STATE_CLEANUP
Definition: dhcpd.h:1779
#define DDNS_STATE_REM_FW_NXRR
Definition: dhcpd.h:1787
u_int16_t flags
Definition: dhcpd.h:1512
struct buffer * buffer
Definition: tree.h:77
int dns_zone_dereference(struct dns_zone **ptr, const char *file, int line)
Definition: dns.c:698
struct option_cache * primary
Definition: dhcpd.h:1507
isc_result_t ddns_modify_fwd(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)