ISC DHCP  4.3.2
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) 2009-2014 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
8  * Copyright (c) 2001-2003 by Internet Software Consortium
9  *
10  * Permission to use, copy, modify, and distribute this software for any
11  * purpose with or without fee is hereby granted, provided that the above
12  * copyright notice and this permission notice appear in all copies.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  *
22  * Internet Systems Consortium, Inc.
23  * 950 Charter Street
24  * Redwood City, CA 94063
25  * <info@isc.org>
26  * https://www.isc.org/
27  *
28  */
29 
32 #include "dhcpd.h"
33 #include "arpa/nameser.h"
34 #include <isc/md5.h>
35 #include <isc/sha2.h>
36 #include <dns/result.h>
37 
38 /*
39  * This file contains code to connect the DHCP code to the libdns modules.
40  * As part of that function it maintains a database of zone cuts that can
41  * be used to figure out which server should be contacted to update any
42  * given domain name. Included in the zone information may be a pointer
43  * to a key in which case that key is used for the update. If no zone
44  * is found then the DNS code determines the zone on its own.
45  *
46  * The way this works is that you define the domain name to which an
47  * SOA corresponds, and the addresses of some primaries for that domain name:
48  *
49  * zone FOO.COM {
50  * primary 10.0.17.1;
51  * secondary 10.0.22.1, 10.0.23.1;
52  * key "FOO.COM Key";
53  * }
54  *
55  * If an update is requested for GAZANGA.TOPANGA.FOO.COM, then the name
56  * server looks in its database for a zone record for "GAZANGA.TOPANGA.FOO.COM",
57  * doesn't find it, looks for one for "TOPANGA.FOO.COM", doesn't find *that*,
58  * looks for "FOO.COM", finds it. So it
59  * attempts the update to the primary for FOO.COM. If that times out, it
60  * tries the secondaries. You can list multiple primaries if you have some
61  * kind of magic name server that supports that. You shouldn't list
62  * secondaries that don't know how to forward updates (e.g., BIND 8 doesn't
63  * support update forwarding, AFAIK). If no TSIG key is listed, the update
64  * is attempted without TSIG.
65  *
66  * You can also include IPv6 addresses via the primary6 and secondary6
67  * options. The search order for the addresses is primary, primary6,
68  * secondary and lastly secondary6, with a limit on the number of
69  * addresses used. Currently this limit is 3.
70  *
71  * The DHCP server tries to find an existing zone for any given name by
72  * trying to look up a local zone structure for each domain containing
73  * that name, all the way up to '.'. If it finds one cached, it tries
74  * to use that one to do the update. That's why it tries to update
75  * "FOO.COM" above, even though theoretically it should try GAZANGA...
76  * and TOPANGA... first.
77  *
78  * If the update fails with a predefined zone the zone is marked as bad
79  * and another search of the predefined zones is done. If no predefined
80  * zone is found finding a zone is left to the DNS module via examination
81  * of SOA records. If the DNS module finds a zone it may cache the zone
82  * but the zone won't be cached here.
83  *
84  * TSIG updates are not performed on zones found by the DNS module - if
85  * you want TSIG updates you _must_ write a zone definition linking the
86  * key to the zone. In cases where you know for sure what the key is
87  * but do not want to hardcode the IP addresses of the primary or
88  * secondaries, a zone declaration can be made that doesn't include any
89  * primary or secondary declarations. When the DHCP server encounters
90  * this while hunting up a matching zone for a name, it looks up the SOA,
91  * fills in the IP addresses, and uses that record for the update.
92  * If the SOA lookup returns NXRRSET, a warning is printed and the zone is
93  * discarded, TSIG key and all. The search for the zone then continues
94  * as if the zone record hadn't been found. Zones without IP addresses
95  * don't match when initially hunting for a zone to update.
96  *
97  * When an update is attempted and no predefined zone is found
98  * that matches any enclosing domain of the domain being updated, the DHCP
99  * server goes through the same process that is done when the update to a
100  * predefined zone fails - starting with the most specific domain
101  * name (GAZANGA.TOPANGA.FOO.COM) and moving to the least specific (the root),
102  * it tries to look up an SOA record.
103  *
104  * TSIG keys are defined like this:
105  *
106  * key "FOO.COM Key" {
107  * algorithm HMAC-MD5.SIG-ALG.REG.INT;
108  * secret <Base64>;
109  * }
110  *
111  * <Base64> is a number expressed in base64 that represents the key.
112  * It's also permissible to use a quoted string here - this will be
113  * translated as the ASCII bytes making up the string, and will not
114  * include any NUL termination. The key name can be any text string,
115  * and the key type must be one of the key types defined in the draft
116  * or by the IANA. Currently only the HMAC-MD5... key type is
117  * supported.
118  *
119  * The DDNS processing has been split into two areas. One is the
120  * control code that determines what should be done. That code is found
121  * in the client or server directories. The other is the common code
122  * that performs functions such as properly formatting the arguments.
123  * That code is found in this file. The basic processing flow for a
124  * DDNS update is:
125  * In the client or server code determine what needs to be done and
126  * collect the necesary information then pass it to a function from
127  * this file.
128  * In this code lookup the zone and extract the zone and key information
129  * (if available) and prepare the arguments for the DNS module.
130  * When the DNS module completes its work (times out or gets a reply)
131  * it will trigger another function here which does generic processing
132  * and then passes control back to the code from the server or client.
133  * The server or client code then determines the next step which may
134  * result in another call to this module in which case the process repeats.
135  */
136 
138 
139 /*
140  * DHCP dns structures
141  * Normally the relationship between these structures isn't one to one
142  * but in the DHCP case it (mostly) is. To make the allocations, frees,
143  * and passing of the memory easier we make a single structure with all
144  * the pieces.
145  *
146  * The maximum size of the data buffer should be large enough for any
147  * items DHCP will generate
148  */
149 
150 typedef struct dhcp_ddns_rdata {
151  dns_rdata_t rdata;
152  dns_rdatalist_t rdatalist;
153  dns_rdataset_t rdataset;
155 
156 #if defined (NSUPDATE)
157 #if defined (DNS_ZONE_LOOKUP)
158 
159 /*
160  * The structure used to find a nameserver if there wasn't a zone entry.
161  * Currently we assume we won't have many of these outstanding at any
162  * time so we go with a simple linked list.
163  * In use find_zone_start() will fill in the oname with the name
164  * requested by the DDNS code. zname will point to it and be
165  * advanced as labels are removed. If the DNS client code returns
166  * a set of name servers eventp and rdataset will be set. Then
167  * the code will walk through the nameservers in namelist and
168  * find addresses that are stored in addrs and addrs6.
169  */
170 
171 typedef struct dhcp_ddns_ns {
172  struct dhcp_ddns_ns *next;
173  struct data_string oname; /* the original name for DDNS */
174  char *zname; /* a pointer into the original name for
175  the zone we are checking */
176  dns_clientresevent_t *eventp; /* pointer to the event that provided the
177  namelist, we can't free the eventp
178  until we free the namelist */
179  dns_name_t *ns_name; /* current name server we are examining */
180  dns_rdataset_t *rdataset;
181  dns_rdatatype_t rdtype; /* type of address we want */
182 
183  struct in_addr addrs[DHCP_MAXNS]; /* space for v4 addresses */
184  struct in6_addr addrs6[DHCP_MAXNS]; /* space for v6 addresses */
185  int num_addrs;
186  int num_addrs6;
187  int ttl;
188 
189  void *transaction; /* transaction id for DNS calls */
190 } dhcp_ddns_ns_t;
191 
192 /*
193  * The list of DDNS names for which we are attempting to find a name server.
194  * This list is used for finding the name server, it doesn't include the
195  * information necessary to do the DDNS request after finding a name server.
196  * The code attempts to minimize duplicate requests by examining the list
197  * to see if we are already trying to find a substring of the new request.
198  * For example imagine the first request is "a.b.c.d.e." and the server has
199  * already discarded the first two lables and is trying "c.d.e.". If the
200  * next request is for "x.y.c.d.e." the code assumes the in progress
201  * request is sufficient and doesn't add a new request for the second name.
202  * If the next request was for "x.y.z.d.e." the code doesn't assume they
203  * will use the same nameserver and starts a second request.
204  * This strategy will not eliminate all duplicates but is simple and
205  * should be sufficient.
206  */
207 dhcp_ddns_ns_t *dns_outstanding_ns = NULL;
208 
209 /*
210  * Routines to manipulate the list of outstanding searches
211  *
212  * add_to_ns_queue() - adds the given control block to the queue
213  *
214  * remove_from_ns_queue() - removes the given control block from
215  * the queue
216  *
217  * find_in_ns_queue() compares the name from the given control
218  * block with the control blocks in the queue. It returns
219  * success if a matching entry is found. In order to match
220  * the entry already on the queue must be shorter than the
221  * incoming name must match the ending substring of the name.
222  */
223 
224 void
225 add_to_ns_queue(dhcp_ddns_ns_t *ns_cb)
226 {
227  ns_cb->next = dns_outstanding_ns;
228  dns_outstanding_ns = ns_cb;
229 }
230 
231 
232 void
233 remove_from_ns_queue(dhcp_ddns_ns_t *ns_cb)
234 {
235  dhcp_ddns_ns_t **foo;
236 
237  foo = &dns_outstanding_ns;
238  while (*foo) {
239  if (*foo == ns_cb) {
240  *foo = ns_cb->next;
241  break;
242  }
243  foo = &((*foo)->next);
244  }
245  ns_cb->next = NULL;
246 }
247 
248 isc_result_t
249 find_in_ns_queue(dhcp_ddns_ns_t *ns_cb)
250 {
251  dhcp_ddns_ns_t *temp_cb;
252  int in_len, temp_len;
253 
254  in_len = strlen(ns_cb->zname);
255 
256  for(temp_cb = dns_outstanding_ns;
257  temp_cb != NULL;
258  temp_cb = temp_cb->next) {
259  temp_len = strlen(temp_cb->zname);
260  if (temp_len > in_len)
261  continue;
262  if (strcmp(temp_cb->zname,
263  ns_cb->zname + (in_len - temp_len)) == 0)
264  return(ISC_R_SUCCESS);
265  }
266  return(ISC_R_NOTFOUND);
267 }
268 
269 void cache_found_zone (dhcp_ddns_ns_t *);
270 #endif
271 
272 void ddns_interlude(isc_task_t *, isc_event_t *);
273 
274 #if defined (TRACING)
275 /*
276  * Code to support tracing DDNS packets. We trace packets going to and
277  * coming from the libdns code but don't try to track the packets
278  * exchanged between the libdns code and the dns server(s) it contacts.
279  *
280  * The code is split into two sets of routines
281  * input refers to messages received from the dns module
282  * output refers to messages sent to the dns module
283  * Currently there are three routines in each set
284  * write is used to write information about the message to the trace file
285  * this routine is called directly from the proper place in the code.
286  * read is used to read information about a message from the trace file
287  * this routine is called from the trace loop as it reads through
288  * the file and is registered via the trace_type_register routine.
289  * When playing back a trace file we shall absorb records of output
290  * messages as part of processing the write function, therefore
291  * any output messages we encounter are flagged as errors.
292  * stop isn't currently used in this code but is needed for the register
293  * routine.
294  *
295  * We pass a pointer to a control block to the dns module which it returns
296  * to use as part of the result. As the pointer may vary between traces
297  * we need to map between those from the trace file and the new ones during
298  * playback.
299  *
300  * The mapping is complicated a little as a pointer could be 4 or 8 bytes
301  * long. We treat the old pointer as an 8 byte quantity and pad and compare
302  * as necessary.
303  */
304 
305 /*
306  * Structure used to map old pointers to new pointers.
307  * Old pointers are 8 bytes long as we don't know if the trace was
308  * done on a 64 bit or 32 bit machine.
309  */
310 #define TRACE_PTR_LEN 8
311 
312 typedef struct dhcp_ddns_map {
313  char old_pointer[TRACE_PTR_LEN];
314  void *new_pointer;
315  struct dhcp_ddns_map *next;
316 } dhcp_ddns_map_t;
317 
318 /* The starting point for the map structure */
319 static dhcp_ddns_map_t *ddns_map;
320 
321 trace_type_t *trace_ddns_input;
322 trace_type_t *trace_ddns_output;
323 
324 /*
325  * The data written to the trace file is:
326  * 32 bits result from dns
327  * 64 bits pointer of cb
328  */
329 
330 void
331 trace_ddns_input_write(dhcp_ddns_cb_t *ddns_cb, isc_result_t result)
332 {
333  trace_iov_t iov[2];
334  u_int32_t old_result;
335  char old_pointer[TRACE_PTR_LEN];
336 
337  old_result = htonl((u_int32_t)result);
338  memset(old_pointer, 0, TRACE_PTR_LEN);
339  memcpy(old_pointer, &ddns_cb, sizeof(ddns_cb));
340 
341  iov[0].len = sizeof(old_result);
342  iov[0].buf = (char *)&old_result;
343  iov[1].len = TRACE_PTR_LEN;
344  iov[1].buf = old_pointer;
345  trace_write_packet_iov(trace_ddns_input, 2, iov, MDL);
346 }
347 
348 /*
349  * Process the result and pointer from the trace file.
350  * We use the pointer map to find the proper pointer for this instance.
351  * Then we need to construct an event to pass along to the interlude
352  * function.
353  */
354 static void
355 trace_ddns_input_read(trace_type_t *ttype, unsigned length,
356  char *buf)
357 {
358  u_int32_t old_result;
359  char old_pointer[TRACE_PTR_LEN];
360  dns_clientupdateevent_t *eventp;
361  void *new_pointer;
362  dhcp_ddns_map_t *ddns_map_ptr;
363 
364  if (length < (sizeof(old_result) + TRACE_PTR_LEN)) {
365  log_error("trace_ddns_input_read: data too short");
366  return;
367  }
368 
369  memcpy(&old_result, buf, sizeof(old_result));
370  memcpy(old_pointer, buf + sizeof(old_result), TRACE_PTR_LEN);
371 
372  /* map the old pointer to a new pointer */
373  for (ddns_map_ptr = ddns_map;
374  ddns_map_ptr != NULL;
375  ddns_map_ptr = ddns_map_ptr->next) {
376  if ((ddns_map_ptr->new_pointer != NULL) &&
377  memcmp(ddns_map_ptr->old_pointer,
378  old_pointer, TRACE_PTR_LEN) == 0) {
379  new_pointer = ddns_map_ptr->new_pointer;
380  ddns_map_ptr->new_pointer = NULL;
381  memset(ddns_map_ptr->old_pointer, 0, TRACE_PTR_LEN);
382  break;
383  }
384  }
385  if (ddns_map_ptr == NULL) {
386  log_error("trace_dns_input_read: unable to map cb pointer");
387  return;
388  }
389 
390  eventp = (dns_clientupdateevent_t *)
391  isc_event_allocate(dhcp_gbl_ctx.mctx,
393  0,
394  ddns_interlude,
395  new_pointer,
396  sizeof(dns_clientupdateevent_t));
397  if (eventp == NULL) {
398  log_error("trace_ddns_input_read: unable to allocate event");
399  return;
400  }
401  eventp->result = ntohl(old_result);
402 
403 
404  ddns_interlude(dhcp_gbl_ctx.task, (isc_event_t *)eventp);
405 
406  return;
407 }
408 
409 static void
410 trace_ddns_input_stop(trace_type_t *ttype)
411 {
412 }
413 
414 /*
415  * We use the same arguments as for the dns startupdate function to
416  * allows us to choose between the two via a macro. If tracing isn't
417  * in use we simply call the dns function directly.
418  *
419  * If we are doing playback we read the next packet from the file
420  * and compare the type. If it matches we extract the results and pointer
421  * from the trace file. The results are returned to the caller as if
422  * they had called the dns routine. The pointer is used to construct a
423  * map for when the "reply" is processed.
424  *
425  * The data written to trace file is:
426  * 32 bits result
427  * 64 bits pointer of cb (DDNS Control block)
428  * contents of cb
429  */
430 
431 isc_result_t
432 trace_ddns_output_write(dns_client_t *client, dns_rdataclass_t rdclass,
433  dns_name_t *zonename, dns_namelist_t *prerequisites,
434  dns_namelist_t *updates, isc_sockaddrlist_t *servers,
435  dns_tsec_t *tsec, unsigned int options,
436  isc_task_t *task, isc_taskaction_t action, void *arg,
437  dns_clientupdatetrans_t **transp)
438 {
439  isc_result_t result;
440  u_int32_t old_result;
441  char old_pointer[TRACE_PTR_LEN];
442  dhcp_ddns_map_t *ddns_map_ptr;
443 
444  if (trace_playback() != 0) {
445  /* We are doing playback, extract the entry from the file */
446  unsigned buflen = 0;
447  char *inbuf = NULL;
448 
449  result = trace_get_packet(&trace_ddns_output,
450  &buflen, &inbuf);
451  if (result != ISC_R_SUCCESS) {
452  log_error("trace_ddns_output_write: no input found");
453  return (ISC_R_FAILURE);
454  }
455  if (buflen < (sizeof(old_result) + TRACE_PTR_LEN)) {
456  log_error("trace_ddns_output_write: data too short");
457  dfree(inbuf, MDL);
458  return (ISC_R_FAILURE);
459  }
460  memcpy(&old_result, inbuf, sizeof(old_result));
461  result = ntohl(old_result);
462  memcpy(old_pointer, inbuf + sizeof(old_result), TRACE_PTR_LEN);
463  dfree(inbuf, MDL);
464 
465  /* add the pointer to the pointer map */
466  for (ddns_map_ptr = ddns_map;
467  ddns_map_ptr != NULL;
468  ddns_map_ptr = ddns_map_ptr->next) {
469  if (ddns_map_ptr->new_pointer == NULL) {
470  break;
471  }
472  }
473 
474  /*
475  * If we didn't find an empty entry, allocate an entry and
476  * link it into the list. The list isn't ordered.
477  */
478  if (ddns_map_ptr == NULL) {
479  ddns_map_ptr = dmalloc(sizeof(*ddns_map_ptr), MDL);
480  if (ddns_map_ptr == NULL) {
481  log_error("trace_ddns_output_write: "
482  "unable to allocate map entry");
483  return(ISC_R_FAILURE);
484  }
485  ddns_map_ptr->next = ddns_map;
486  ddns_map = ddns_map_ptr;
487  }
488 
489  memcpy(ddns_map_ptr->old_pointer, old_pointer, TRACE_PTR_LEN);
490  ddns_map_ptr->new_pointer = arg;
491  }
492  else {
493  /* We aren't doing playback, make the actual call */
494  result = dns_client_startupdate(client, rdclass, zonename,
495  prerequisites, updates,
496  servers, tsec, options,
497  task, action, arg, transp);
498  }
499 
500  if (trace_record() != 0) {
501  /* We are recording, save the information to the file */
502  trace_iov_t iov[3];
503  old_result = htonl((u_int32_t)result);
504  memset(old_pointer, 0, TRACE_PTR_LEN);
505  memcpy(old_pointer, &arg, sizeof(arg));
506  iov[0].len = sizeof(old_result);
507  iov[0].buf = (char *)&old_result;
508  iov[1].len = TRACE_PTR_LEN;
509  iov[1].buf = old_pointer;
510 
511  /* Write out the entire cb, in case we want to look at it */
512  iov[2].len = sizeof(dhcp_ddns_cb_t);
513  iov[2].buf = (char *)arg;
514 
515  trace_write_packet_iov(trace_ddns_output, 3, iov, MDL);
516  }
517 
518  return(result);
519 }
520 
521 static void
522 trace_ddns_output_read(trace_type_t *ttype, unsigned length,
523  char *buf)
524 {
525  log_error("unaccounted for ddns output.");
526 }
527 
528 static void
529 trace_ddns_output_stop(trace_type_t *ttype)
530 {
531 }
532 
533 void
535 {
536  trace_ddns_output = trace_type_register("ddns-output", NULL,
537  trace_ddns_output_read,
538  trace_ddns_output_stop, MDL);
539  trace_ddns_input = trace_type_register("ddns-input", NULL,
540  trace_ddns_input_read,
541  trace_ddns_input_stop, MDL);
542  ddns_map = NULL;
543 }
544 
545 #define ddns_update trace_ddns_output_write
546 #else
547 #define ddns_update dns_client_startupdate
548 #endif /* TRACING */
549 
550 #define zone_resolve dns_client_startresolve
551 
552 /*
553  * Code to allocate and free a dddns control block. This block is used
554  * to pass and track the information associated with a DDNS update request.
555  */
557 ddns_cb_alloc(const char *file, int line)
558 {
559  dhcp_ddns_cb_t *ddns_cb;
560  int i;
561 
562  ddns_cb = dmalloc(sizeof(*ddns_cb), file, line);
563  if (ddns_cb != NULL) {
564  ISC_LIST_INIT(ddns_cb->zone_server_list);
565  for (i = 0; i < DHCP_MAXNS; i++) {
566  ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link);
567  }
568  }
569 
570 #if defined (DEBUG_DNS_UPDATES)
571  log_info("%s(%d): Allocating ddns_cb=%p", file, line, ddns_cb);
572 #endif
573 
574  return(ddns_cb);
575 }
576 
577 void
578 ddns_cb_free(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
579 {
580 #if defined (DEBUG_DNS_UPDATES)
581  log_info("%s(%d): freeing ddns_cb=%p", file, line, ddns_cb);
582 #endif
583 
584  data_string_forget(&ddns_cb->fwd_name, file, line);
585  data_string_forget(&ddns_cb->rev_name, file, line);
586  data_string_forget(&ddns_cb->dhcid, file, line);
587 
588  if (ddns_cb->zone != NULL) {
589  forget_zone((struct dns_zone **)&ddns_cb->zone);
590  }
591 
592  /* Should be freed by now, check just in case. */
593  if (ddns_cb->transaction != NULL)
594  log_error("Impossible memory leak at %s:%d (attempt to free "
595  "DDNS Control Block before transaction).", MDL);
596 
597  dfree(ddns_cb, file, line);
598 }
599 
600 void
602 {
603  int i;
604 
605  forget_zone(&ddns_cb->zone);
606  ddns_cb->zone_name[0] = 0;
607  ISC_LIST_INIT(ddns_cb->zone_server_list);
608  for (i = 0; i < DHCP_MAXNS; i++) {
609  ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link);
610  }
611 }
612 
613 isc_result_t find_tsig_key (ns_tsig_key **key, const char *zname,
614  struct dns_zone *zone)
615 {
616  ns_tsig_key *tkey;
617 
618  if (!zone)
619  return ISC_R_NOTFOUND;
620 
621  if (!zone -> key) {
622  return DHCP_R_KEY_UNKNOWN;
623  }
624 
625  if ((!zone -> key -> name ||
626  strlen (zone -> key -> name) > NS_MAXDNAME) ||
627  (!zone -> key -> algorithm ||
628  strlen (zone -> key -> algorithm) > NS_MAXDNAME) ||
629  (!zone -> key) ||
630  (!zone -> key -> key) ||
631  (zone -> key -> key -> len == 0)) {
632  return DHCP_R_INVALIDKEY;
633  }
634  tkey = dmalloc (sizeof *tkey, MDL);
635  if (!tkey) {
636  nomem:
637  return ISC_R_NOMEMORY;
638  }
639  memset (tkey, 0, sizeof *tkey);
640  tkey -> data = dmalloc (zone -> key -> key -> len, MDL);
641  if (!tkey -> data) {
642  dfree (tkey, MDL);
643  goto nomem;
644  }
645  strcpy (tkey -> name, zone -> key -> name);
646  strcpy (tkey -> alg, zone -> key -> algorithm);
647  memcpy (tkey -> data,
648  zone -> key -> key -> value, zone -> key -> key -> len);
649  tkey -> len = zone -> key -> key -> len;
650  *key = tkey;
651  return ISC_R_SUCCESS;
652 }
653 
654 void tkey_free (ns_tsig_key **key)
655 {
656  if ((*key) -> data)
657  dfree ((*key) -> data, MDL);
658  dfree ((*key), MDL);
659  *key = (ns_tsig_key *)0;
660 }
661 #endif
662 
663 isc_result_t remove_dns_zone (struct dns_zone *zone)
664 {
665  struct dns_zone *tz = NULL;
666 
667  if (dns_zone_hash) {
668  dns_zone_hash_lookup(&tz, dns_zone_hash, zone->name, 0, MDL);
669  if (tz != NULL) {
670  dns_zone_hash_delete(dns_zone_hash, tz->name, 0, MDL);
672  }
673  }
674 
675  return (ISC_R_SUCCESS);
676 }
677 
678 isc_result_t enter_dns_zone (struct dns_zone *zone)
679 {
680  struct dns_zone *tz = (struct dns_zone *)0;
681 
682  if (dns_zone_hash) {
683  dns_zone_hash_lookup (&tz,
684  dns_zone_hash, zone -> name, 0, MDL);
685  if (tz == zone) {
686  dns_zone_dereference (&tz, MDL);
687  return ISC_R_SUCCESS;
688  }
689  if (tz) {
690  dns_zone_hash_delete (dns_zone_hash,
691  zone -> name, 0, MDL);
692  dns_zone_dereference (&tz, MDL);
693  }
694  } else {
695  if (!dns_zone_new_hash(&dns_zone_hash, DNS_HASH_SIZE, MDL))
696  return ISC_R_NOMEMORY;
697  }
698 
699  dns_zone_hash_add (dns_zone_hash, zone -> name, 0, zone, MDL);
700  return ISC_R_SUCCESS;
701 }
702 
703 isc_result_t dns_zone_lookup (struct dns_zone **zone, const char *name)
704 {
705  int len;
706  char *tname = (char *)0;
707  isc_result_t status;
708 
709  if (!dns_zone_hash)
710  return ISC_R_NOTFOUND;
711 
712  len = strlen (name);
713  if (name [len - 1] != '.') {
714  tname = dmalloc ((unsigned)len + 2, MDL);
715  if (!tname)
716  return ISC_R_NOMEMORY;
717  strcpy (tname, name);
718  tname [len] = '.';
719  tname [len + 1] = 0;
720  name = tname;
721  }
722  if (!dns_zone_hash_lookup (zone, dns_zone_hash, name, 0, MDL))
723  status = ISC_R_NOTFOUND;
724  else if ((*zone)->timeout && (*zone)->timeout < cur_time) {
725  dns_zone_hash_delete(dns_zone_hash, (*zone)->name, 0, MDL);
726  dns_zone_dereference(zone, MDL);
727  status = ISC_R_NOTFOUND;
728  } else
729  status = ISC_R_SUCCESS;
730 
731  if (tname)
732  dfree (tname, MDL);
733  return status;
734 }
735 
736 int dns_zone_dereference (ptr, file, line)
737  struct dns_zone **ptr;
738  const char *file;
739  int line;
740 {
741  struct dns_zone *dns_zone;
742 
743  if ((ptr == NULL) || (*ptr == NULL)) {
744  log_error("%s(%d): null pointer", file, line);
745 #if defined (POINTER_DEBUG)
746  abort();
747 #else
748  return (0);
749 #endif
750  }
751 
752  dns_zone = *ptr;
753  *ptr = NULL;
754  --dns_zone->refcnt;
755  rc_register(file, line, ptr, dns_zone, dns_zone->refcnt, 1, RC_MISC);
756  if (dns_zone->refcnt > 0)
757  return (1);
758 
759  if (dns_zone->refcnt < 0) {
760  log_error("%s(%d): negative refcnt!", file, line);
761 #if defined (DEBUG_RC_HISTORY)
762  dump_rc_history(dns_zone);
763 #endif
764 #if defined (POINTER_DEBUG)
765  abort();
766 #else
767  return (0);
768 #endif
769  }
770 
771  if (dns_zone->name)
772  dfree(dns_zone->name, file, line);
773  if (dns_zone->key)
774  omapi_auth_key_dereference(&dns_zone->key, file, line);
775  if (dns_zone->primary)
776  option_cache_dereference(&dns_zone->primary, file, line);
777  if (dns_zone->secondary)
778  option_cache_dereference(&dns_zone->secondary, file, line);
779  if (dns_zone->primary6)
780  option_cache_dereference(&dns_zone->primary6, file, line);
781  if (dns_zone->secondary6)
782  option_cache_dereference(&dns_zone->secondary6, file, line);
783  dfree(dns_zone, file, line);
784  return (1);
785 }
786 
787 #if defined (NSUPDATE)
788 #if defined (DNS_ZONE_LOOKUP)
789 
790 /* Helper function to copy the address from an rdataset to
791  * the nameserver control block. Mostly to avoid really long
792  * lines in the nested for loops
793  */
794 void
795 zone_addr_to_ns(dhcp_ddns_ns_t *ns_cb,
796  dns_rdataset_t *rdataset)
797 {
798  dns_rdata_t rdata;
799  dns_rdata_in_a_t a;
800  dns_rdata_in_aaaa_t aaaa;
801 
802  dns_rdata_init(&rdata);
803  dns_rdataset_current(rdataset, &rdata);
804  switch (rdataset->type) {
805  case dns_rdatatype_a:
806  (void) dns_rdata_tostruct(&rdata, &a, NULL);
807  memcpy(&ns_cb->addrs[ns_cb->num_addrs], &a.in_addr, 4);
808  ns_cb->num_addrs++;
809  dns_rdata_freestruct(&a);
810  break;
811  case dns_rdatatype_aaaa:
812  (void) dns_rdata_tostruct(&rdata, &aaaa, NULL);
813  memcpy(&ns_cb->addrs6[ns_cb->num_addrs6], &aaaa.in6_addr, 16);
814  ns_cb->num_addrs6++;
815  dns_rdata_freestruct(&aaaa);
816  break;
817  default:
818  break;
819  }
820 
821  if ((ns_cb->ttl == 0) || (ns_cb->ttl > rdataset->ttl))
822  ns_cb->ttl = rdataset->ttl;
823 }
824 
825 /*
826  * The following three routines co-operate to find the addresses of
827  * the nameservers to use for a zone if we don't have a zone statement.
828  * We strongly suggest the use of a zone statement to avoid problmes
829  * and to allow for the use of TSIG and therefore better security, but
830  * include this functionality for those that don't want such statements.
831  *
832  * find_zone_start(ddns_cb, direction)
833  * This is the first of the routines, it is called from the rest of
834  * the ddns code when we have received a request for DDNS for a name
835  * and don't have a zone entry that would cover that name. The name
836  * is in the ddns_cb as specified by the direction (forward or reverse).
837  * The start function pulls the name out and constructs the name server
838  * block then starts the process by calling the DNS client code.
839  *
840  * find_zone_ns(taskp, eventp)
841  * This is the second step of the process. The DNS client code will
842  * call this when it has gotten a response or timed out. If the response
843  * doesn't have a list of nameservers we remove another label from the
844  * zone name and try again. If the response does include a list of
845  * nameservers we start walking through the list attempting to get
846  * addresses for the nameservers.
847  *
848  * find_zone_addrs(taskp, eventp)
849  * This is the third step of the process. In find_zone_ns we got
850  * a list of nameserves and started walking through them. This continues
851  * the walk and if we get back any addresses it adds them to our list.
852  * When we get enough addresses or run out of nameservers we construct
853  * a zone entry and insert it into the zone hash for the rest of the
854  * DDNS code to use.
855  */
856 void
857 find_zone_addrs(isc_task_t *taskp,
858  isc_event_t *eventp)
859 {
860  dns_clientresevent_t *ddns_event = (dns_clientresevent_t *)eventp;
861  dhcp_ddns_ns_t *ns_cb = (dhcp_ddns_ns_t *)eventp->ev_arg;
862  dns_name_t *ns_name = NULL;
863  dns_rdataset_t *rdataset;
864  isc_result_t result;
865  dns_name_t *name;
866  dns_rdata_t rdata = DNS_RDATA_INIT;
867  dns_rdata_ns_t ns;
868 
869 
870  /* the transaction is done, get rid of the tag */
871  dns_client_destroyrestrans(&ns_cb->transaction);
872 
873  /* If we succeeded we try and extract the addresses, if we can
874  * and we have enough we are done. If we didn't succeed or
875  * we don't have enough addresses afterwards we drop through
876  * and try the next item on the list.
877  */
878  if (ddns_event->result == ISC_R_SUCCESS) {
879 
880  for (name = ISC_LIST_HEAD(ddns_event->answerlist);
881  name != NULL;
882  name = ISC_LIST_NEXT(name, link)) {
883 
884  for (rdataset = ISC_LIST_HEAD(name->list);
885  rdataset != NULL;
886  rdataset = ISC_LIST_NEXT(rdataset, link)) {
887 
888  for (result = dns_rdataset_first(rdataset);
889  result == ISC_R_SUCCESS;
890  result = dns_rdataset_next(rdataset)) {
891 
892  /* add address to cb */
893  zone_addr_to_ns(ns_cb, rdataset);
894 
895  /* We are done if we have
896  * enough addresses
897  */
898  if (ns_cb->num_addrs +
899  ns_cb->num_addrs6 >= DHCP_MAXNS)
900  goto done;
901  }
902  }
903  }
904  }
905 
906  /* We need more addresses.
907  * We restart the loop we were in before.
908  */
909 
910  for (ns_name = ns_cb->ns_name;
911  ns_name != NULL;
912  ns_name = ISC_LIST_NEXT(ns_name, link)) {
913 
914  if (ns_name == ns_cb->ns_name) {
915  /* first time through, use saved state */
916  rdataset = ns_cb->rdataset;
917  } else {
918  rdataset = ISC_LIST_HEAD(ns_name->list);
919  }
920 
921  for (;
922  rdataset != NULL;
923  rdataset = ISC_LIST_NEXT(rdataset, link)) {
924 
925  if (rdataset->type != dns_rdatatype_ns)
926  continue;
927  dns_rdata_init(&rdata);
928 
929  if (rdataset == ns_cb->rdataset) {
930  /* first time through use the saved state */
931  if (ns_cb->rdtype == dns_rdatatype_a) {
932  ns_cb->rdtype = dns_rdatatype_aaaa;
933  } else {
934  ns_cb->rdtype = dns_rdatatype_a;
935  if (dns_rdataset_next(rdataset) !=
936  ISC_R_SUCCESS)
937  continue;
938  }
939  } else {
940  if ((!dns_rdataset_isassociated(rdataset)) ||
941  (dns_rdataset_first(rdataset) !=
942  ISC_R_SUCCESS))
943  continue;
944  }
945 
946  dns_rdataset_current(rdataset, &rdata);
947  if (dns_rdata_tostruct(&rdata, &ns, NULL) !=
948  ISC_R_SUCCESS)
949  continue;
950 
951  /* Save our current state */
952  ns_cb->ns_name = ns_name;
953  ns_cb->rdataset = rdataset;
954 
955  /* And call out to DNS */
956  result = zone_resolve(dhcp_gbl_ctx.dnsclient, &ns.name,
957  dns_rdataclass_in,
958  ns_cb->rdtype,
959  DNS_CLIENTRESOPT_NODNSSEC,
961  find_zone_addrs,
962  (void *)ns_cb,
963  &ns_cb->transaction);
964 
965  /* do we need to clean this? */
966  dns_rdata_freestruct(&ns);
967 
968  if (result == ISC_R_SUCCESS)
969  /* we have started the next step, cleanup
970  * the structures associated with this call
971  * but leave the cb for the next round
972  */
973  goto cleanup;
974 
975  log_error("find_zone_ns: unable to continue "
976  "resolve: %s %s",
977  ns_cb->zname,
978  isc_result_totext(result));
979 
980  /* The call to start a resolve transaction failed,
981  * should we try to continue with any other names?
982  * For now let's not, but let's use whatever we
983  * may already have.
984  */
985  goto done;
986  }
987  }
988 
989  done:
990  /* we've either gotten our max number of addresses or
991  * run out of nameservers to try. Convert the cb into
992  * a zone and insert it into the zone hash. Then
993  * we need to clean up the saved state.
994  */
995  if ((ns_cb->num_addrs != 0) ||
996  (ns_cb->num_addrs6 != 0))
997  cache_found_zone(ns_cb);
998 
999  dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient,
1000  &ns_cb->eventp->answerlist);
1001  isc_event_free((isc_event_t **)&ns_cb->eventp);
1002 
1003  remove_from_ns_queue(ns_cb);
1004  data_string_forget(&ns_cb->oname, MDL);
1005  dfree(ns_cb, MDL);
1006 
1007  cleanup:
1008  /* cleanup any of the new state information */
1009 
1010  dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient,
1011  &ddns_event->answerlist);
1012  isc_event_free(&eventp);
1013 
1014  return;
1015 
1016 }
1017 
1018 /*
1019  * Routine to continue the process of finding a nameserver via the DNS
1020  * This is routine is called when we are still trying to get a list
1021  * of nameservers to process.
1022  */
1023 
1024 void
1025 find_zone_ns(isc_task_t *taskp,
1026  isc_event_t *eventp)
1027 {
1028  dns_clientresevent_t *ddns_event = (dns_clientresevent_t *)eventp;
1029  dhcp_ddns_ns_t *ns_cb = (dhcp_ddns_ns_t *)eventp->ev_arg;
1030  dns_fixedname_t zname0;
1031  dns_name_t *zname = NULL, *ns_name = NULL;
1032  dns_rdataset_t *rdataset;
1033  isc_result_t result;
1034  dns_rdata_t rdata = DNS_RDATA_INIT;
1035  dns_rdata_ns_t ns;
1036 
1037  /* the transaction is done, get rid of the tag */
1038  dns_client_destroyrestrans(&ns_cb->transaction);
1039 
1040  if (ddns_event->result != ISC_R_SUCCESS) {
1041  /* We didn't find any nameservers, try again */
1042 
1043  /* Remove a label and continue */
1044  ns_cb->zname = strchr(ns_cb->zname, '.');
1045  if ((ns_cb->zname == NULL) ||
1046  (ns_cb->zname[1] == 0)) {
1047  /* No more labels, all done */
1048  goto cleanup;
1049  }
1050  ns_cb->zname++;
1051 
1052  /* Create a DNS version of the zone name and call the
1053  * resolver code */
1054  if (((result = dhcp_isc_name((unsigned char *)ns_cb->zname,
1055  &zname0, &zname))
1056  != ISC_R_SUCCESS) ||
1057  ((result = zone_resolve(dhcp_gbl_ctx.dnsclient,
1058  zname, dns_rdataclass_in,
1059  dns_rdatatype_ns,
1060  DNS_CLIENTRESOPT_NODNSSEC,
1062  find_zone_ns,
1063  (void *)ns_cb,
1064  &ns_cb->transaction))
1065  != ISC_R_SUCCESS)) {
1066  log_error("find_zone_ns: Unable to build "
1067  "name or start resolve: %s %s",
1068  ns_cb->zname,
1069  isc_result_totext(result));
1070  goto cleanup;
1071  }
1072 
1073  /* we have successfully started the next iteration
1074  * of this step, clean up from the call and continue */
1075  dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient,
1076  &ddns_event->answerlist);
1077  isc_event_free(&eventp);
1078  return;
1079  }
1080 
1081  /* We did get a set of nameservers, save the information and
1082  * start trying to get addresses
1083  */
1084  ns_cb->eventp = ddns_event;
1085  for (ns_name = ISC_LIST_HEAD(ddns_event->answerlist);
1086  ns_name != NULL;
1087  ns_name = ISC_LIST_NEXT(ns_name, link)) {
1088 
1089  for (rdataset = ISC_LIST_HEAD(ns_name->list);
1090  rdataset != NULL;
1091  rdataset = ISC_LIST_NEXT(rdataset, link)) {
1092 
1093  if (rdataset->type != dns_rdatatype_ns)
1094  continue;
1095 
1096  if ((!dns_rdataset_isassociated(rdataset)) ||
1097  (dns_rdataset_first(rdataset) !=
1098  ISC_R_SUCCESS))
1099  continue;
1100 
1101  dns_rdataset_current(rdataset, &rdata);
1102  if (dns_rdata_tostruct(&rdata, &ns, NULL) !=
1103  ISC_R_SUCCESS)
1104  continue;
1105 
1106  /* Save our current state */
1107  ns_cb->ns_name = ns_name;
1108  ns_cb->rdataset = rdataset;
1109 
1110  /* And call out to DNS */
1111  result = zone_resolve(dhcp_gbl_ctx.dnsclient, &ns.name,
1112  dns_rdataclass_in,
1113  ns_cb->rdtype,
1114  DNS_CLIENTRESOPT_NODNSSEC,
1116  find_zone_addrs,
1117  (void *)ns_cb,
1118  &ns_cb->transaction);
1119 
1120  /* do we need to clean this? */
1121  dns_rdata_freestruct(&ns);
1122 
1123  if (result == ISC_R_SUCCESS)
1124  /* We have successfully started the next step
1125  * we don't cleanup the eventp block as we are
1126  * still using it.
1127  */
1128  return;
1129 
1130  log_error("find_zone_ns: unable to continue "
1131  "resolve: %s %s",
1132  ns_cb->zname,
1133  isc_result_totext(result));
1134 
1135  /* The call to start a resolve transaction failed,
1136  * should we try to continue with any other names?
1137  * For now let's not
1138  */
1139  goto cleanup;
1140  }
1141  }
1142 
1143  cleanup:
1144  /* When we add a queue to manage the DDNS
1145  * requests we will need to remove any that
1146  * were waiting for this resolution */
1147 
1148  dns_client_freeresanswer(dhcp_gbl_ctx.dnsclient,
1149  &ddns_event->answerlist);
1150  isc_event_free(&eventp);
1151 
1152  remove_from_ns_queue(ns_cb);
1153 
1154  data_string_forget(&ns_cb->oname, MDL);
1155  dfree(ns_cb, MDL);
1156  return;
1157 
1158 }
1159 
1160 /*
1161  * Start the process of finding nameservers via the DNS because
1162  * we don't have a zone entry already.
1163  * We construct a control block and fill in the DDNS name. As
1164  * the process continues we shall move the zname pointer to
1165  * indicate which labels we are still using. The rest of
1166  * the control block will be filled in as we continue processing.
1167  */
1168 isc_result_t
1169 find_zone_start(dhcp_ddns_cb_t *ddns_cb, int direction)
1170 {
1171  isc_result_t status = ISC_R_NOTFOUND;
1172  dhcp_ddns_ns_t *ns_cb;
1173  dns_fixedname_t zname0;
1174  dns_name_t *zname = NULL;
1175 
1176  /*
1177  * We don't validate np as that was already done in find_cached_zone()
1178  */
1179 
1180  /* Allocate the control block for this request */
1181  ns_cb = dmalloc(sizeof(*ns_cb), MDL);
1182  if (ns_cb == NULL) {
1183  log_error("find_zone_start: unable to allocate cb");
1184  return(ISC_R_FAILURE);
1185  }
1186  ns_cb->rdtype = dns_rdatatype_a;
1187 
1188  /* Copy the data string so the NS lookup is independent of the DDNS */
1189  if (direction == FIND_FORWARD) {
1190  data_string_copy(&ns_cb->oname, &ddns_cb->fwd_name, MDL);
1191  } else {
1192  data_string_copy(&ns_cb->oname, &ddns_cb->rev_name, MDL);
1193  }
1194  ns_cb->zname = (char *)ns_cb->oname.data;
1195 
1196  /*
1197  * Check the dns_outstanding_ns queue to see if we are
1198  * already processing something that would cover this name
1199  */
1200  if (find_in_ns_queue(ns_cb) == ISC_R_SUCCESS) {
1201  data_string_forget(&ns_cb->oname, MDL);
1202  dfree(ns_cb, MDL);
1203  return (ISC_R_SUCCESS);
1204  }
1205 
1206  /* Create a DNS version of the zone name and call the
1207  * resolver code */
1208  if (((status = dhcp_isc_name((unsigned char *)ns_cb->zname,
1209  &zname0, &zname))
1210  != ISC_R_SUCCESS) ||
1211  ((status = zone_resolve(dhcp_gbl_ctx.dnsclient,
1212  zname, dns_rdataclass_in,
1213  dns_rdatatype_ns,
1214  DNS_CLIENTRESOPT_NODNSSEC,
1216  find_zone_ns,
1217  (void *)ns_cb,
1218  &ns_cb->transaction))
1219  != ISC_R_SUCCESS)) {
1220  log_error("find_zone_start: Unable to build "
1221  "name or start resolve: %s %s",
1222  ns_cb->zname,
1223  isc_result_totext(status));
1224 
1225  /* We failed to start the process, clean up */
1226  data_string_forget(&ns_cb->oname, MDL);
1227  dfree(ns_cb, MDL);
1228  } else {
1229  /* We started the process, attach the control block
1230  * to the queue */
1231  add_to_ns_queue(ns_cb);
1232  }
1233 
1234  return (status);
1235 }
1236 #endif
1237 
1238 isc_result_t
1239 find_cached_zone(dhcp_ddns_cb_t *ddns_cb, int direction)
1240 {
1241  isc_result_t status = ISC_R_NOTFOUND;
1242  const char *np;
1243  struct dns_zone *zone = NULL;
1244  struct data_string nsaddrs;
1245  struct in_addr zone_addr;
1246  struct in6_addr zone_addr6;
1247  int ix;
1248 
1249  if (direction == FIND_FORWARD) {
1250  np = (const char *)ddns_cb->fwd_name.data;
1251  } else {
1252  np = (const char *)ddns_cb->rev_name.data;
1253  }
1254 
1255  /* We can't look up a null zone. */
1256  if ((np == NULL) || (*np == '\0')) {
1257  return (DHCP_R_INVALIDARG);
1258  }
1259 
1260  /*
1261  * For each subzone, try to find a cached zone.
1262  */
1263  for (;;) {
1264  status = dns_zone_lookup(&zone, np);
1265  if (status == ISC_R_SUCCESS)
1266  break;
1267 
1268  np = strchr(np, '.');
1269  if (np == NULL)
1270  break;
1271  np++;
1272  }
1273 
1274  if (status != ISC_R_SUCCESS)
1275  return (status);
1276 
1277  /* Make sure the zone is valid, we've already gotten
1278  * rid of expired dynamic zones. Check to see if
1279  * we repudiated this zone. If so give up.
1280  */
1281  if ((zone->flags & DNS_ZONE_INACTIVE) != 0) {
1282  dns_zone_dereference(&zone, MDL);
1283  return (ISC_R_FAILURE);
1284  }
1285 
1286  /* Make sure the zone name will fit. */
1287  if (strlen(zone->name) > sizeof(ddns_cb->zone_name)) {
1288  dns_zone_dereference(&zone, MDL);
1289  return (ISC_R_NOSPACE);
1290  }
1291  strcpy((char *)&ddns_cb->zone_name[0], zone->name);
1292 
1293  memset (&nsaddrs, 0, sizeof nsaddrs);
1294  ix = 0;
1295 
1296  if (zone->primary) {
1297  if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
1298  NULL, NULL, &global_scope,
1299  zone->primary, MDL)) {
1300  int ip = 0;
1301  while (ix < DHCP_MAXNS) {
1302  if (ip + 4 > nsaddrs.len)
1303  break;
1304  memcpy(&zone_addr, &nsaddrs.data[ip], 4);
1305  isc_sockaddr_fromin(&ddns_cb->zone_addrs[ix],
1306  &zone_addr,
1307  NS_DEFAULTPORT);
1308  ISC_LIST_APPEND(ddns_cb->zone_server_list,
1309  &ddns_cb->zone_addrs[ix],
1310  link);
1311  ip += 4;
1312  ix++;
1313  }
1314  data_string_forget(&nsaddrs, MDL);
1315  }
1316  }
1317 
1318  if (zone->primary6) {
1319  if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
1320  NULL, NULL, &global_scope,
1321  zone->primary6, MDL)) {
1322  int ip = 0;
1323  while (ix < DHCP_MAXNS) {
1324  if (ip + 16 > nsaddrs.len)
1325  break;
1326  memcpy(&zone_addr6, &nsaddrs.data[ip], 16);
1327  isc_sockaddr_fromin6(&ddns_cb->zone_addrs[ix],
1328  &zone_addr6,
1329  NS_DEFAULTPORT);
1330  ISC_LIST_APPEND(ddns_cb->zone_server_list,
1331  &ddns_cb->zone_addrs[ix],
1332  link);
1333  ip += 16;
1334  ix++;
1335  }
1336  data_string_forget(&nsaddrs, MDL);
1337  }
1338  }
1339 
1340  if (zone->secondary) {
1341  if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
1342  NULL, NULL, &global_scope,
1343  zone->secondary, MDL)) {
1344  int ip = 0;
1345  while (ix < DHCP_MAXNS) {
1346  if (ip + 4 > nsaddrs.len)
1347  break;
1348  memcpy(&zone_addr, &nsaddrs.data[ip], 4);
1349  isc_sockaddr_fromin(&ddns_cb->zone_addrs[ix],
1350  &zone_addr,
1351  NS_DEFAULTPORT);
1352  ISC_LIST_APPEND(ddns_cb->zone_server_list,
1353  &ddns_cb->zone_addrs[ix],
1354  link);
1355  ip += 4;
1356  ix++;
1357  }
1358  data_string_forget (&nsaddrs, MDL);
1359  }
1360  }
1361 
1362  if (zone->secondary6) {
1363  if (evaluate_option_cache(&nsaddrs, NULL, NULL, NULL,
1364  NULL, NULL, &global_scope,
1365  zone->secondary6, MDL)) {
1366  int ip = 0;
1367  while (ix < DHCP_MAXNS) {
1368  if (ip + 16 > nsaddrs.len)
1369  break;
1370  memcpy(&zone_addr6, &nsaddrs.data[ip], 16);
1371  isc_sockaddr_fromin6(&ddns_cb->zone_addrs[ix],
1372  &zone_addr6,
1373  NS_DEFAULTPORT);
1374  ISC_LIST_APPEND(ddns_cb->zone_server_list,
1375  &ddns_cb->zone_addrs[ix],
1376  link);
1377  ip += 16;
1378  ix++;
1379  }
1380  data_string_forget (&nsaddrs, MDL);
1381  }
1382  }
1383 
1384  dns_zone_reference(&ddns_cb->zone, zone, MDL);
1385  dns_zone_dereference (&zone, MDL);
1386  return ISC_R_SUCCESS;
1387 }
1388 
1389 void forget_zone (struct dns_zone **zone)
1390 {
1391  dns_zone_dereference (zone, MDL);
1392 }
1393 
1394 void repudiate_zone (struct dns_zone **zone)
1395 {
1396  /* verify that we have a pointer at least */
1397  if ((zone == NULL) || (*zone == NULL)) {
1398  log_info("Null argument to repudiate zone");
1399  return;
1400  }
1401 
1402  (*zone)->flags |= DNS_ZONE_INACTIVE;
1403  dns_zone_dereference(zone, MDL);
1404 }
1405 
1406 #if defined (DNS_ZONE_LOOKUP)
1407 void cache_found_zone(dhcp_ddns_ns_t *ns_cb)
1408 {
1409  struct dns_zone *zone = NULL;
1410  int len, remove_zone = 0;
1411 
1412  /* See if there's already such a zone. */
1413  if (dns_zone_lookup(&zone, ns_cb->zname) == ISC_R_SUCCESS) {
1414  /* If it's not a dynamic zone, leave it alone. */
1415  if (zone->timeout == 0)
1416  return;
1417 
1418  /* Remove any old addresses in case they've changed */
1419  if (zone->primary)
1421  if (zone->primary6)
1423 
1424  /* Set the flag to remove the zone from the hash if
1425  we have problems */
1426  remove_zone = 1;
1427  } else if (dns_zone_allocate(&zone, MDL) == 0) {
1428  return;
1429  } else {
1430  /* We've just allocated the zone, now we need
1431  * to allocate space for the name and addresses
1432  */
1433 
1434  /* allocate space for the name */
1435  len = strlen(ns_cb->zname);
1436  zone->name = dmalloc(len + 2, MDL);
1437  if (zone->name == NULL) {
1438  goto cleanup;
1439  }
1440 
1441  /* Copy the name and add a trailing '.' if necessary */
1442  strcpy(zone->name, ns_cb->zname);
1443  if (zone->name[len-1] != '.') {
1444  zone->name[len] = '.';
1445  zone->name[len+1] = 0;
1446  }
1447  }
1448 
1449  zone->timeout = cur_time + ns_cb->ttl;
1450 
1451  if (ns_cb->num_addrs != 0) {
1452  len = ns_cb->num_addrs * sizeof(struct in_addr);
1453  if ((!option_cache_allocate(&zone->primary, MDL)) ||
1454  (!buffer_allocate(&zone->primary->data.buffer,
1455  len, MDL))) {
1456  if (remove_zone == 1)
1457  remove_dns_zone(zone);
1458  goto cleanup;
1459  }
1460  memcpy(zone->primary->data.buffer->data, ns_cb->addrs, len);
1461  zone->primary->data.data =
1462  &zone->primary->data.buffer->data[0];
1463  zone->primary->data.len = len;
1464  }
1465  if (ns_cb->num_addrs6 != 0) {
1466  len = ns_cb->num_addrs6 * sizeof(struct in6_addr);
1467  if ((!option_cache_allocate(&zone->primary6, MDL)) ||
1468  (!buffer_allocate(&zone->primary6->data.buffer,
1469  len, MDL))) {
1470  if (remove_zone == 1)
1471  remove_dns_zone(zone);
1472  goto cleanup;
1473  }
1474  memcpy(zone->primary6->data.buffer->data, ns_cb->addrs6, len);
1475  zone->primary6->data.data =
1476  &zone->primary6->data.buffer->data[0];
1477  zone->primary6->data.len = len;
1478  }
1479 
1480  enter_dns_zone(zone);
1481 
1482  cleanup:
1483  dns_zone_dereference(&zone, MDL);
1484  return;
1485 }
1486 #endif
1487 
1512 int get_std_dhcid(dhcp_ddns_cb_t *ddns_cb,
1513  int type,
1514  const u_int8_t *identifier,
1515  unsigned id_len)
1516 {
1517  struct data_string *id = &ddns_cb->dhcid;
1518  isc_sha256_t sha256;
1519  unsigned char buf[ISC_SHA256_DIGESTLENGTH];
1520  unsigned char fwd_buf[256];
1521  unsigned fwd_buflen = 0;
1522 
1523  /* Types can only be 0..(2^16)-1. */
1524  if (type < 0 || type > 65535)
1525  return (0);
1526 
1527  /* We need to convert the fwd name to wire representation */
1528  if (MRns_name_pton((char *)ddns_cb->fwd_name.data, fwd_buf, 256) == -1)
1529  return (0);
1530  while(fwd_buf[fwd_buflen] != 0) {
1531  fwd_buflen += fwd_buf[fwd_buflen] + 1;
1532  }
1533  fwd_buflen++;
1534 
1535  if (!buffer_allocate(&id->buffer,
1536  ISC_SHA256_DIGESTLENGTH + 2 + 1,
1537  MDL))
1538  return (0);
1539  id->data = id->buffer->data;
1540 
1541  /* The two first bytes contain the type identifier. */
1542  putUShort(id->buffer->data, (unsigned)type);
1543 
1544  /* The next is the digest type, SHA-256 is 1 */
1545  putUChar(id->buffer->data + 2, 1u);
1546 
1547  /* Computing the digest */
1548  isc_sha256_init(&sha256);
1549  isc_sha256_update(&sha256, identifier, id_len);
1550  isc_sha256_update(&sha256, fwd_buf, fwd_buflen);
1551  isc_sha256_final(buf, &sha256);
1552 
1553  memcpy(id->buffer->data + 3, &buf, ISC_SHA256_DIGESTLENGTH);
1554 
1555  id->len = ISC_SHA256_DIGESTLENGTH + 2 + 1;
1556 
1557  return (1);
1558 }
1559 
1581 int get_int_dhcid (dhcp_ddns_cb_t *ddns_cb,
1582  int type,
1583  const u_int8_t *data,
1584  unsigned len)
1585 {
1586  struct data_string *id = &ddns_cb->dhcid;
1587  unsigned char buf[ISC_MD5_DIGESTLENGTH];
1588  isc_md5_t md5;
1589  int i;
1590 
1591  /* Types can only be 0..(2^16)-1. */
1592  if (type < 0 || type > 65535)
1593  return (0);
1594 
1595  /*
1596  * Hexadecimal MD5 digest plus two byte type, NUL,
1597  * and one byte for length for dns.
1598  */
1599  if (!buffer_allocate(&id -> buffer,
1600  (ISC_MD5_DIGESTLENGTH * 2) + 4, MDL))
1601  return (0);
1602  id->data = id->buffer->data;
1603 
1604  /*
1605  * We put the length into the first byte to turn
1606  * this into a dns text string. This avoid needing to
1607  * copy the string to add the byte later.
1608  */
1609  id->buffer->data[0] = ISC_MD5_DIGESTLENGTH * 2 + 2;
1610 
1611  /* Put the type in the next two bytes. */
1612  id->buffer->data[1] = "0123456789abcdef"[(type >> 4) & 0xf];
1613  /* This should have been [type & 0xf] but now that
1614  * it is in use we need to leave it this way in order
1615  * to avoid disturbing customer's lease files
1616  */
1617  id->buffer->data[2] = "0123456789abcdef"[type % 15];
1618 
1619  /* Mash together an MD5 hash of the identifier. */
1620  isc_md5_init(&md5);
1621  isc_md5_update(&md5, data, len);
1622  isc_md5_final(&md5, buf);
1623 
1624  /* Convert into ASCII. */
1625  for (i = 0; i < ISC_MD5_DIGESTLENGTH; i++) {
1626  id->buffer->data[i * 2 + 3] =
1627  "0123456789abcdef"[(buf[i] >> 4) & 0xf];
1628  id->buffer->data[i * 2 + 4] =
1629  "0123456789abcdef"[buf[i] & 0xf];
1630  }
1631 
1632  id->len = ISC_MD5_DIGESTLENGTH * 2 + 3;
1633  id->buffer->data[id->len] = 0;
1634  id->terminated = 1;
1635 
1636  return (1);
1637 }
1638 
1639 int get_dhcid(dhcp_ddns_cb_t *ddns_cb,
1640  int type,
1641  const u_int8_t *identifier,
1642  unsigned id_len)
1643 {
1644  if (ddns_cb->dhcid_class == dns_rdatatype_dhcid)
1645  return get_std_dhcid(ddns_cb, type, identifier, id_len);
1646  else
1647  return get_int_dhcid(ddns_cb, type, identifier, id_len);
1648 }
1649 
1650 /*
1651  * The dhcid (text version) that we pass to DNS includes a length byte
1652  * at the start but the text we store in the lease doesn't include the
1653  * length byte. The following routines are to convert between the two
1654  * styles.
1655  *
1656  * When converting from a dhcid to a leaseid we reuse the buffer and
1657  * simply adjust the data pointer and length fields in the data string.
1658  * This avoids any prolems with allocating space.
1659  */
1660 
1661 void
1662 dhcid_tolease(struct data_string *dhcid,
1663  struct data_string *leaseid)
1664 {
1665  /* copy the data string then update the fields */
1666  data_string_copy(leaseid, dhcid, MDL);
1667  leaseid->data++;
1668  leaseid->len--;
1669 }
1670 
1671 isc_result_t
1672 dhcid_fromlease(struct data_string *dhcid,
1673  struct data_string *leaseid)
1674 {
1675  if (!buffer_allocate(&dhcid->buffer, leaseid->len + 2, MDL)) {
1676  return(ISC_R_FAILURE);
1677  }
1678 
1679  dhcid->data = dhcid->buffer->data;
1680 
1681  dhcid->buffer->data[0] = leaseid->len;
1682  memcpy(dhcid->buffer->data + 1, leaseid->data, leaseid->len);
1683  dhcid->len = leaseid->len + 1;
1684  if (leaseid->terminated == 1) {
1685  dhcid->buffer->data[dhcid->len] = 0;
1686  dhcid->terminated = 1;
1687  }
1688 
1689  return(ISC_R_SUCCESS);
1690 }
1691 
1692 /*
1693  * Construct the dataset for this item.
1694  * This is a fairly simple arrangement as the operations we do are simple.
1695  * If there is data we simply have the rdata point to it - the formatting
1696  * must be correct already. We then link the rdatalist to the rdata and
1697  * create a rdataset from the rdatalist.
1698  */
1699 
1700 static isc_result_t
1701 make_dns_dataset(dns_rdataclass_t dataclass,
1702  dns_rdatatype_t datatype,
1703  dhcp_ddns_data_t *dataspace,
1704  unsigned char *data,
1705  int datalen,
1706  int ttl)
1707 {
1708  dns_rdata_t *rdata = &dataspace->rdata;
1709  dns_rdatalist_t *rdatalist = &dataspace->rdatalist;
1710  dns_rdataset_t *rdataset = &dataspace->rdataset;
1711 
1712  isc_region_t region;
1713 
1714  /* set up the rdata */
1715  dns_rdata_init(rdata);
1716 
1717  if (data == NULL) {
1718  /* No data, set up the rdata fields we care about */
1719  rdata->flags = DNS_RDATA_UPDATE;
1720  rdata->type = datatype;
1721  rdata->rdclass = dataclass;
1722  } else {
1723  switch(datatype) {
1724  case dns_rdatatype_a:
1725  case dns_rdatatype_aaaa:
1726  case dns_rdatatype_txt:
1727  case dns_rdatatype_dhcid:
1728  case dns_rdatatype_ptr:
1729  /* The data must be in the right format we simply
1730  * need to supply it via the correct structure */
1731  region.base = data;
1732  region.length = datalen;
1733  dns_rdata_fromregion(rdata, dataclass, datatype,
1734  &region);
1735  break;
1736  default:
1737  return(DHCP_R_INVALIDARG);
1738  break;
1739  }
1740  }
1741 
1742  /* setup the datalist and attach the rdata to it */
1743  dns_rdatalist_init(rdatalist);
1744  rdatalist->type = datatype;
1745  rdatalist->rdclass = dataclass;
1746  rdatalist->ttl = ttl;
1747  ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1748 
1749  /* convert the datalist to a dataset */
1750  dns_rdataset_init(rdataset);
1751  dns_rdatalist_tordataset(rdatalist, rdataset);
1752 
1753  return(ISC_R_SUCCESS);
1754 }
1755 
1756 /*
1757  * When a DHCP client or server intends to update an A RR, it first
1758  * prepares a DNS UPDATE query which includes as a prerequisite the
1759  * assertion that the name does not exist. The update section of the
1760  * query attempts to add the new name and its IP address mapping (an A
1761  * RR), and the DHCID RR with its unique client-identity.
1762  * -- "Interaction between DHCP and DNS"
1763  *
1764  * There are two cases, one for the server and one for the client.
1765  *
1766  * For the server the first step will have a request of:
1767  * The name is not in use
1768  * Add an A RR
1769  * Add a DHCID RR
1770  *
1771  * For the client the first step will have a request of:
1772  * The A RR does not exist
1773  * Add an A RR
1774  * Add a DHCID RR
1775  */
1776 
1777 static isc_result_t
1778 ddns_modify_fwd_add1(dhcp_ddns_cb_t *ddns_cb,
1779  dhcp_ddns_data_t *dataspace,
1780  dns_name_t *pname,
1781  dns_name_t *uname)
1782 {
1783  isc_result_t result;
1784 
1785  /* Construct the prerequisite list */
1786  if ((ddns_cb->flags & DDNS_INCLUDE_RRSET) != 0) {
1787  /* The A RR shouldn't exist */
1788  result = make_dns_dataset(dns_rdataclass_none,
1789  ddns_cb->address_type,
1790  dataspace, NULL, 0, 0);
1791  } else {
1792  /* The name is not in use */
1793  result = make_dns_dataset(dns_rdataclass_none,
1794  dns_rdatatype_any,
1795  dataspace, NULL, 0, 0);
1796  }
1797  if (result != ISC_R_SUCCESS) {
1798  return(result);
1799  }
1800  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1801  dataspace++;
1802 
1803  /* Construct the update list */
1804  /* Add the A RR */
1805  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type,
1806  dataspace,
1807  (unsigned char *)ddns_cb->address.iabuf,
1808  ddns_cb->address.len, ddns_cb->ttl);
1809  if (result != ISC_R_SUCCESS) {
1810  return(result);
1811  }
1812  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1813  dataspace++;
1814 
1815  /* Add the DHCID RR */
1816  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
1817  dataspace,
1818  (unsigned char *)ddns_cb->dhcid.data,
1819  ddns_cb->dhcid.len, ddns_cb->ttl);
1820  if (result != ISC_R_SUCCESS) {
1821  return(result);
1822  }
1823  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1824 
1825  return(ISC_R_SUCCESS);
1826 }
1827 
1828 /*
1829  * If the first update operation fails with YXDOMAIN, the updater can
1830  * conclude that the intended name is in use. The updater then
1831  * attempts to confirm that the DNS name is not being used by some
1832  * other host. The updater prepares a second UPDATE query in which the
1833  * prerequisite is that the desired name has attached to it a DHCID RR
1834  * whose contents match the client identity. The update section of
1835  * this query deletes the existing A records on the name, and adds the
1836  * A record that matches the DHCP binding and the DHCID RR with the
1837  * client identity.
1838  * -- "Interaction between DHCP and DNS"
1839  *
1840  * The message for the second step depends on if we are doing conflict
1841  * resolution. If we are we include a prerequisite. If not we delete
1842  * the DHCID in addition to all A rrsets.
1843  *
1844  * Conflict resolution:
1845  * DHCID RR exists, and matches client identity.
1846  * Delete A RRset.
1847  * Add A RR.
1848  *
1849  * Conflict override:
1850  * Delete DHCID RRs.
1851  * Add DHCID RR
1852  * Delete A RRset.
1853  * Add A RR.
1854  */
1855 
1856 static isc_result_t
1857 ddns_modify_fwd_add2(dhcp_ddns_cb_t *ddns_cb,
1858  dhcp_ddns_data_t *dataspace,
1859  dns_name_t *pname,
1860  dns_name_t *uname)
1861 {
1862  isc_result_t result = ISC_R_SUCCESS;
1863 
1864  /*
1865  * If we are doing conflict resolution (unset) we use a prereq list.
1866  * If not we delete the DHCID in addition to all A rrsets.
1867  */
1868  if ((ddns_cb->flags & DDNS_CONFLICT_OVERRIDE) == 0) {
1869  /* Construct the prereq list */
1870  /* The DHCID RR exists and matches the client identity */
1871  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
1872  dataspace,
1873  (unsigned char *)ddns_cb->dhcid.data,
1874  ddns_cb->dhcid.len, 0);
1875  if (result != ISC_R_SUCCESS) {
1876  return(result);
1877  }
1878  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1879  dataspace++;
1880  } else {
1881  /* Start constructing the update list.
1882  * Conflict detection override: delete DHCID RRs */
1883  result = make_dns_dataset(dns_rdataclass_any,
1884  ddns_cb->dhcid_class,
1885  dataspace, NULL, 0, 0);
1886  if (result != ISC_R_SUCCESS) {
1887  return(result);
1888  }
1889  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1890  dataspace++;
1891 
1892  /* Add current DHCID RR */
1893  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
1894  dataspace,
1895  (unsigned char *)ddns_cb->dhcid.data,
1896  ddns_cb->dhcid.len, ddns_cb->ttl);
1897  if (result != ISC_R_SUCCESS) {
1898  return(result);
1899  }
1900  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1901  dataspace++;
1902  }
1903 
1904  /* Start or continue constructing the update list */
1905  /* Delete the A RRset */
1906  result = make_dns_dataset(dns_rdataclass_any, ddns_cb->address_type,
1907  dataspace, NULL, 0, 0);
1908  if (result != ISC_R_SUCCESS) {
1909  return(result);
1910  }
1911  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1912  dataspace++;
1913 
1914  /* Add the A RR */
1915  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type,
1916  dataspace,
1917  (unsigned char *)ddns_cb->address.iabuf,
1918  ddns_cb->address.len, ddns_cb->ttl);
1919  if (result != ISC_R_SUCCESS) {
1920  return(result);
1921  }
1922  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1923 
1924  return(ISC_R_SUCCESS);
1925 }
1926 
1927 /*
1928  * The entity chosen to handle the A record for this client (either the
1929  * client or the server) SHOULD delete the A record that was added when
1930  * the lease was made to the client.
1931  *
1932  * In order to perform this delete, the updater prepares an UPDATE
1933  * query which contains two prerequisites. The first prerequisite
1934  * asserts that the DHCID RR exists whose data is the client identity
1935  * described in Section 4.3. The second prerequisite asserts that the
1936  * data in the A RR contains the IP address of the lease that has
1937  * expired or been released.
1938  * -- "Interaction between DHCP and DNS"
1939  *
1940  * RFC 4703 has relaxed the prereqisites to only checking the DHCID RR
1941  * and we have adopted that to minizmie problems due to interruptions
1942  * when doing a deletion.
1943  *
1944  * First try has:
1945  * DHCID RR exists, and matches client identity.
1946  * Delete appropriate A RR.
1947  */
1948 
1949 static isc_result_t
1950 ddns_modify_fwd_rem1(dhcp_ddns_cb_t *ddns_cb,
1951  dhcp_ddns_data_t *dataspace,
1952  dns_name_t *pname,
1953  dns_name_t *uname)
1954 {
1955  isc_result_t result = ISC_R_SUCCESS;
1956 
1957  /* Consruct the prereq list */
1958  /* The DHCID RR exists and matches the client identity */
1959  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
1960  dataspace,
1961  (unsigned char *)ddns_cb->dhcid.data,
1962  ddns_cb->dhcid.len, 0);
1963  if (result != ISC_R_SUCCESS) {
1964  return(result);
1965  }
1966  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1967  dataspace++;
1968 
1969  /* Construct the update list */
1970  /* Delete A RRset */
1971  result = make_dns_dataset(dns_rdataclass_none, ddns_cb->address_type,
1972  dataspace,
1973  (unsigned char *)ddns_cb->address.iabuf,
1974  ddns_cb->address.len, 0);
1975  if (result != ISC_R_SUCCESS) {
1976  return(result);
1977  }
1978  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1979 
1980  return(ISC_R_SUCCESS);
1981 }
1982 
1983 /*
1984  * If the deletion of the A succeeded, and there are no A or AAAA
1985  * records left for this domain, then we can blow away the DHCID
1986  * record as well. We can't blow away the DHCID record above
1987  * because it's possible that more than one record has been added
1988  * to this domain name.
1989  *
1990  * Second query has:
1991  * A RR does not exist.
1992  * AAAA RR does not exist.
1993  * Delete appropriate DHCID RR.
1994  */
1995 
1996 static isc_result_t
1997 ddns_modify_fwd_rem2(dhcp_ddns_cb_t *ddns_cb,
1998  dhcp_ddns_data_t *dataspace,
1999  dns_name_t *pname,
2000  dns_name_t *uname)
2001 {
2002  isc_result_t result;
2003 
2004  /* Construct the prereq list */
2005  /* The A RR does not exist */
2006  result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_a,
2007  dataspace, NULL, 0, 0);
2008  if (result != ISC_R_SUCCESS) {
2009  return(result);
2010  }
2011  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2012  dataspace++;
2013 
2014  /* The AAAA RR does not exist */
2015  result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_aaaa,
2016  dataspace, NULL, 0, 0);
2017  if (result != ISC_R_SUCCESS) {
2018  return(result);
2019  }
2020  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2021  dataspace++;
2022 
2023  /* Construct the update list */
2024  /* Delete DHCID RR */
2025  result = make_dns_dataset(dns_rdataclass_none, ddns_cb->dhcid_class,
2026  dataspace,
2027  (unsigned char *)ddns_cb->dhcid.data,
2028  ddns_cb->dhcid.len, 0);
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  * This routine converts from the task action call into something
2039  * easier to work with. It also handles the common case of a signature
2040  * or zone not being correct.
2041  */
2042 void ddns_interlude(isc_task_t *taskp,
2043  isc_event_t *eventp)
2044 {
2045  dhcp_ddns_cb_t *ddns_cb = (dhcp_ddns_cb_t *)eventp->ev_arg;
2046  dns_clientupdateevent_t *ddns_event = (dns_clientupdateevent_t *)eventp;
2047  isc_result_t eresult = ddns_event->result;
2048  isc_result_t result;
2049 
2050  /* We've extracted the information we want from it, get rid of
2051  * the event block.*/
2052  isc_event_free(&eventp);
2053 
2054 #if defined (TRACING)
2055  if (trace_record()) {
2056  trace_ddns_input_write(ddns_cb, eresult);
2057  }
2058 #endif
2059 
2060 #if defined (DEBUG_DNS_UPDATES)
2061  print_dns_status(DDNS_PRINT_INBOUND, ddns_cb, eresult);
2062 #endif
2063 
2064  /* This transaction is complete, clear the value */
2065  dns_client_destroyupdatetrans(&ddns_cb->transaction);
2066 
2067  /* If we cancelled or tried to cancel the operation we just
2068  * need to clean up. */
2069  if ((eresult == ISC_R_CANCELED) ||
2070  ((ddns_cb->flags & DDNS_ABORT) != 0)) {
2071 #if defined (DEBUG_DNS_UPDATES)
2072  log_info("DDNS: completeing transaction cancellation cb=%p, "
2073  "flags=%x, %s",
2074  ddns_cb, ddns_cb->flags, isc_result_totext(eresult));
2075 #endif
2076  if ((ddns_cb->flags & DDNS_ABORT) == 0) {
2077  log_info("DDNS: cleaning up lease pointer for a cancel "
2078  "cb=%p", ddns_cb);
2079  /*
2080  * We shouldn't actually be able to get here but
2081  * we are. This means we haven't cleaned up
2082  * the lease pointer so we need to do that before
2083  * freeing the cb.
2084  */
2085  ddns_cb->cur_func(ddns_cb, eresult);
2086  return;
2087  }
2088 
2089  if (ddns_cb->next_op != NULL) {
2090  /* if necessary cleanup up next op block */
2091  ddns_cb_free(ddns_cb->next_op, MDL);
2092  }
2093  ddns_cb_free(ddns_cb, MDL);
2094  return;
2095  }
2096 
2097  /* If we had a problem with our key or zone try again */
2098  if ((eresult == DNS_R_NOTAUTH) ||
2099  (eresult == DNS_R_NOTZONE)) {
2100  int i;
2101  /* Our zone information was questionable,
2102  * repudiate it and try again */
2103  log_error("DDNS: bad zone information, repudiating zone %s",
2104  ddns_cb->zone_name);
2105  repudiate_zone(&ddns_cb->zone);
2106  ddns_cb->zone_name[0] = 0;
2107  ISC_LIST_INIT(ddns_cb->zone_server_list);
2108  for (i = 0; i < DHCP_MAXNS; i++) {
2109  ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link);
2110  }
2111 
2112  if ((ddns_cb->state == DDNS_STATE_ADD_PTR) ||
2113  (ddns_cb->state == DDNS_STATE_REM_PTR)) {
2114  result = ddns_modify_ptr(ddns_cb, MDL);
2115  } else {
2116  result = ddns_modify_fwd(ddns_cb, MDL);
2117  }
2118 
2119  if (result != ISC_R_SUCCESS) {
2120  /* if we couldn't redo the query log it and
2121  * let the next function clean it up */
2122  log_info("DDNS: Failed to retry after zone failure");
2123  ddns_cb->cur_func(ddns_cb, result);
2124  }
2125  return;
2126  } else {
2127  /* pass it along to be processed */
2128  ddns_cb->cur_func(ddns_cb, eresult);
2129  }
2130 
2131  return;
2132 }
2133 
2134 /*
2135  * This routine does the generic work for sending a ddns message to
2136  * modify the forward record (A or AAAA) and calls one of a set of
2137  * routines to build the specific message.
2138  */
2139 
2140 isc_result_t
2141 ddns_modify_fwd(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
2142 {
2143  isc_result_t result;
2144  dns_tsec_t *tsec_key = NULL;
2145 
2146  unsigned char *clientname;
2147  dhcp_ddns_data_t *dataspace = NULL;
2148  dns_namelist_t prereqlist, updatelist;
2149  dns_fixedname_t zname0, pname0, uname0;
2150  dns_name_t *zname = NULL, *pname, *uname;
2151 
2152  isc_sockaddrlist_t *zlist = NULL;
2153 
2154  /* Get a pointer to the clientname to make things easier. */
2155  clientname = (unsigned char *)ddns_cb->fwd_name.data;
2156 
2157  /* Extract and validate the type of the address. */
2158  if (ddns_cb->address.len == 4) {
2159  ddns_cb->address_type = dns_rdatatype_a;
2160  } else if (ddns_cb->address.len == 16) {
2161  ddns_cb->address_type = dns_rdatatype_aaaa;
2162  } else {
2163  return DHCP_R_INVALIDARG;
2164  }
2165 
2166  /*
2167  * If we already have a zone use it, otherwise try to lookup the
2168  * zone in our cache. If we find one we will have a pointer to
2169  * the zone that needs to be dereferenced when we are done with it.
2170  * If we don't find one that is okay we'll let the DNS code try and
2171  * find the information for us.
2172  */
2173 
2174  if (ddns_cb->zone == NULL) {
2175  result = find_cached_zone(ddns_cb, FIND_FORWARD);
2176 #if defined (DNS_ZONE_LOOKUP)
2177  if (result == ISC_R_NOTFOUND) {
2178  /*
2179  * We didn't find a cached zone, see if we can
2180  * can find a nameserver and create a zone.
2181  */
2182  if (find_zone_start(ddns_cb, FIND_FORWARD)
2183  == ISC_R_SUCCESS) {
2184  /*
2185  * We have started the process to find a zone
2186  * queue the ddns_cb for processing after we
2187  * create the zone
2188  */
2189  /* sar - not yet implemented, currently we just
2190  * arrange for things to get cleaned up
2191  */
2192  goto cleanup;
2193  }
2194  }
2195 #endif
2196  if (result != ISC_R_SUCCESS)
2197  goto cleanup;
2198  }
2199 
2200  /*
2201  * If we have a zone try to get any information we need
2202  * from it - name, addresses and the key. The address
2203  * and key may be empty the name can't be.
2204  */
2205  if (ddns_cb->zone) {
2206  /* Set up the zone name for use by DNS */
2207  result = dhcp_isc_name(ddns_cb->zone_name, &zname0, &zname);
2208  if (result != ISC_R_SUCCESS) {
2209  log_error("Unable to build name for zone for "
2210  "fwd update: %s %s",
2211  ddns_cb->zone_name,
2212  isc_result_totext(result));
2213  goto cleanup;
2214  }
2215 
2216  if (!(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
2217  /* If we have any addresses get them */
2218  zlist = &ddns_cb->zone_server_list;
2219  }
2220 
2221 
2222  if (ddns_cb->zone->key != NULL) {
2223  /*
2224  * Not having a key is fine, having a key
2225  * but not a tsec is odd so we warn the user.
2226  */
2227  /*sar*/
2228  /* should we do the warning? */
2229  tsec_key = ddns_cb->zone->key->tsec_key;
2230  if (tsec_key == NULL) {
2231  log_error("No tsec for use with key %s",
2232  ddns_cb->zone->key->name);
2233  }
2234  }
2235  }
2236 
2237  /* Set up the DNS names for the prereq and update lists */
2238  if (((result = dhcp_isc_name(clientname, &pname0, &pname))
2239  != ISC_R_SUCCESS) ||
2240  ((result = dhcp_isc_name(clientname, &uname0, &uname))
2241  != ISC_R_SUCCESS)) {
2242  log_error("Unable to build name for fwd update: %s %s",
2243  clientname, isc_result_totext(result));
2244  goto cleanup;
2245  }
2246 
2247  /* Allocate the various isc dns library structures we may require. */
2248  dataspace = isc_mem_get(dhcp_gbl_ctx.mctx, sizeof(*dataspace) * 4);
2249  if (dataspace == NULL) {
2250  log_error("Unable to allocate memory for fwd update");
2251  result = ISC_R_NOMEMORY;
2252  goto cleanup;
2253  }
2254 
2255  ISC_LIST_INIT(prereqlist);
2256  ISC_LIST_INIT(updatelist);
2257 
2258  switch(ddns_cb->state) {
2260  result = ddns_modify_fwd_add1(ddns_cb, dataspace,
2261  pname, uname);
2262  if (result != ISC_R_SUCCESS) {
2263  goto cleanup;
2264  }
2265  ISC_LIST_APPEND(prereqlist, pname, link);
2266  break;
2268  result = ddns_modify_fwd_add2(ddns_cb, dataspace,
2269  pname, uname);
2270  if (result != ISC_R_SUCCESS) {
2271  goto cleanup;
2272  }
2273 
2274  /* If we aren't doing conflict override we have entries
2275  * in the pname list and we need to attach it to the
2276  * prereqlist */
2277 
2278  if ((ddns_cb->flags & DDNS_CONFLICT_OVERRIDE) == 0) {
2279  ISC_LIST_APPEND(prereqlist, pname, link);
2280  }
2281 
2282  break;
2284  result = ddns_modify_fwd_rem1(ddns_cb, dataspace,
2285  pname, uname);
2286  if (result != ISC_R_SUCCESS) {
2287  goto cleanup;
2288  }
2289  ISC_LIST_APPEND(prereqlist, pname, link);
2290  break;
2292  result = ddns_modify_fwd_rem2(ddns_cb, dataspace,
2293  pname, uname);
2294  if (result != ISC_R_SUCCESS) {
2295  goto cleanup;
2296  }
2297  ISC_LIST_APPEND(prereqlist, pname, link);
2298  break;
2299 
2300  default:
2301  log_error("Invalid operation in ddns code.");
2302  result = DHCP_R_INVALIDARG;
2303  goto cleanup;
2304  break;
2305  }
2306 
2307  /*
2308  * We always have an update list but may not have a prereqlist
2309  * if we are doing conflict override.
2310  */
2311  ISC_LIST_APPEND(updatelist, uname, link);
2312 
2313  /* send the message, cleanup and return the result */
2314  result = ddns_update(dhcp_gbl_ctx.dnsclient,
2315  dns_rdataclass_in, zname,
2316  &prereqlist, &updatelist,
2317  zlist, tsec_key,
2318  DNS_CLIENTRESOPT_ALLOWRUN,
2320  ddns_interlude,
2321  (void *)ddns_cb,
2322  &ddns_cb->transaction);
2323  if (result == ISC_R_FAMILYNOSUPPORT) {
2324  log_info("Unable to perform DDNS update, "
2325  "address family not supported");
2326  }
2327 
2328 #if defined (DEBUG_DNS_UPDATES)
2329  print_dns_status(DDNS_PRINT_OUTBOUND, ddns_cb, result);
2330 #endif
2331 
2332  cleanup:
2333 #if defined (DEBUG_DNS_UPDATES)
2334  if (result != ISC_R_SUCCESS) {
2335  log_info("DDNS: %s(%d): error in ddns_modify_fwd %s for %p",
2336  file, line, isc_result_totext(result), ddns_cb);
2337  }
2338 #endif
2339 
2340  if (dataspace != NULL) {
2341  isc_mem_put(dhcp_gbl_ctx.mctx, dataspace,
2342  sizeof(*dataspace) * 4);
2343  }
2344  return(result);
2345 }
2346 
2347 
2348 isc_result_t
2349 ddns_modify_ptr(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
2350 {
2351  isc_result_t result;
2352  dns_tsec_t *tsec_key = NULL;
2353  unsigned char *ptrname;
2354  dhcp_ddns_data_t *dataspace = NULL;
2355  dns_namelist_t updatelist;
2356  dns_fixedname_t zname0, uname0;
2357  dns_name_t *zname = NULL, *uname;
2358  isc_sockaddrlist_t *zlist = NULL;
2359  unsigned char buf[256];
2360  int buflen;
2361 
2362  /*
2363  * Try to lookup the zone in the zone cache. As with the forward
2364  * case it's okay if we don't have one, the DNS code will try to
2365  * find something also if we succeed we will need to dereference
2366  * the zone later. Unlike with the forward case we assume we won't
2367  * have a pre-existing zone.
2368  */
2369  result = find_cached_zone(ddns_cb, FIND_REVERSE);
2370 
2371 #if defined (DNS_ZONE_LOOKUP)
2372  if (result == ISC_R_NOTFOUND) {
2373  /*
2374  * We didn't find a cached zone, see if we can
2375  * can find a nameserver and create a zone.
2376  */
2377  if (find_zone_start(ddns_cb, FIND_REVERSE) == ISC_R_SUCCESS) {
2378  /*
2379  * We have started the process to find a zone
2380  * queue the ddns_cb for processing after we
2381  * create the zone
2382  */
2383  /* sar - not yet implemented, currently we just
2384  * arrange for things to get cleaned up
2385  */
2386  goto cleanup;
2387  }
2388  }
2389 #endif
2390  if (result != ISC_R_SUCCESS)
2391  goto cleanup;
2392 
2393 
2394  if ((result == ISC_R_SUCCESS) &&
2395  !(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
2396  /* Set up the zone name for use by DNS */
2397  result = dhcp_isc_name(ddns_cb->zone_name, &zname0, &zname);
2398  if (result != ISC_R_SUCCESS) {
2399  log_error("Unable to build name for zone for "
2400  "fwd update: %s %s",
2401  ddns_cb->zone_name,
2402  isc_result_totext(result));
2403  goto cleanup;
2404  }
2405  /* If we have any addresses get them */
2406  if (!(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
2407  zlist = &ddns_cb->zone_server_list;
2408  }
2409 
2410  /*
2411  * If we now have a zone try to get the key, NULL is okay,
2412  * having a key but not a tsec is odd so we warn.
2413  */
2414  /*sar*/
2415  /* should we do the warning if we have a key but no tsec? */
2416  if ((ddns_cb->zone != NULL) && (ddns_cb->zone->key != NULL)) {
2417  tsec_key = ddns_cb->zone->key->tsec_key;
2418  if (tsec_key == NULL) {
2419  log_error("No tsec for use with key %s",
2420  ddns_cb->zone->key->name);
2421  }
2422  }
2423  }
2424 
2425  /* We must have a name for the update list */
2426  /* Get a pointer to the ptrname to make things easier. */
2427  ptrname = (unsigned char *)ddns_cb->rev_name.data;
2428 
2429  if ((result = dhcp_isc_name(ptrname, &uname0, &uname))
2430  != ISC_R_SUCCESS) {
2431  log_error("Unable to build name for fwd update: %s %s",
2432  ptrname, isc_result_totext(result));
2433  goto cleanup;
2434  }
2435 
2436  /*
2437  * Allocate the various isc dns library structures we may require.
2438  * Allocating one blob avoids being halfway through the process
2439  * and being unable to allocate as well as making the free easy.
2440  */
2441  dataspace = isc_mem_get(dhcp_gbl_ctx.mctx, sizeof(*dataspace) * 2);
2442  if (dataspace == NULL) {
2443  log_error("Unable to allocate memory for fwd update");
2444  result = ISC_R_NOMEMORY;
2445  goto cleanup;
2446  }
2447 
2448  ISC_LIST_INIT(updatelist);
2449 
2450  /*
2451  * Construct the update list
2452  * We always delete what's currently there
2453  * Delete PTR RR.
2454  */
2455  result = make_dns_dataset(dns_rdataclass_any, dns_rdatatype_ptr,
2456  &dataspace[0], NULL, 0, 0);
2457  if (result != ISC_R_SUCCESS) {
2458  goto cleanup;
2459  }
2460  ISC_LIST_APPEND(uname->list, &dataspace[0].rdataset, link);
2461 
2462  /*
2463  * If we are updating the pointer we then add the new one
2464  * Add PTR RR.
2465  */
2466  if (ddns_cb->state == DDNS_STATE_ADD_PTR) {
2467 #if 0
2468  /*
2469  * I've left this dead code in the file for now in case
2470  * we decide to try and get rid of the ns_name functions.
2471  * sar
2472  */
2473 
2474  /*
2475  * Need to convert pointer into on the wire representation
2476  * We replace the '.' characters with the lengths of the
2477  * next name and add a length to the beginning for the first
2478  * name.
2479  */
2480  if (ddns_cb->fwd_name.len == 1) {
2481  /* the root */
2482  buf[0] = 0;
2483  buflen = 1;
2484  } else {
2485  unsigned char *cp;
2486  buf[0] = '.';
2487  memcpy(&buf[1], ddns_cb->fwd_name.data,
2488  ddns_cb->fwd_name.len);
2489  for(cp = buf + ddns_cb->fwd_name.len, buflen = 0;
2490  cp != buf;
2491  cp--) {
2492  if (*cp == '.') {
2493  *cp = buflen;
2494  buflen = 0;
2495  } else {
2496  buflen++;
2497  }
2498  }
2499  *cp = buflen;
2500  buflen = ddns_cb->fwd_name.len + 1;
2501  }
2502 #endif
2503  /*
2504  * Need to convert pointer into on the wire representation
2505  */
2506  if (MRns_name_pton((char *)ddns_cb->fwd_name.data,
2507  buf, 256) == -1) {
2508  goto cleanup;
2509  }
2510  buflen = 0;
2511  while (buf[buflen] != 0) {
2512  buflen += buf[buflen] + 1;
2513  }
2514  buflen++;
2515 
2516  result = make_dns_dataset(dns_rdataclass_in,
2517  dns_rdatatype_ptr,
2518  &dataspace[1],
2519  buf, buflen, ddns_cb->ttl);
2520  if (result != ISC_R_SUCCESS) {
2521  goto cleanup;
2522  }
2523  ISC_LIST_APPEND(uname->list, &dataspace[1].rdataset, link);
2524  }
2525 
2526  ISC_LIST_APPEND(updatelist, uname, link);
2527 
2528  /*sar*/
2529  /*
2530  * for now I'll cleanup the dataset immediately, it would be
2531  * more efficient to keep it around in case the signaturure failed
2532  * and we wanted to retry it.
2533  */
2534  /* send the message, cleanup and return the result */
2535  result = ddns_update((dns_client_t *)dhcp_gbl_ctx.dnsclient,
2536  dns_rdataclass_in, zname,
2537  NULL, &updatelist,
2538  zlist, tsec_key,
2539  DNS_CLIENTRESOPT_ALLOWRUN,
2541  ddns_interlude, (void *)ddns_cb,
2542  &ddns_cb->transaction);
2543  if (result == ISC_R_FAMILYNOSUPPORT) {
2544  log_info("Unable to perform DDNS update, "
2545  "address family not supported");
2546  }
2547 
2548 #if defined (DEBUG_DNS_UPDATES)
2549  print_dns_status(DDNS_PRINT_OUTBOUND, ddns_cb, result);
2550 #endif
2551 
2552  cleanup:
2553 #if defined (DEBUG_DNS_UPDATES)
2554  if (result != ISC_R_SUCCESS) {
2555  log_info("DDNS: %s(%d): error in ddns_modify_ptr %s for %p",
2556  file, line, isc_result_totext(result), ddns_cb);
2557  }
2558 #endif
2559 
2560  if (dataspace != NULL) {
2561  isc_mem_put(dhcp_gbl_ctx.mctx, dataspace,
2562  sizeof(*dataspace) * 2);
2563  }
2564  return(result);
2565 }
2566 
2567 void
2568 ddns_cancel(dhcp_ddns_cb_t *ddns_cb, const char *file, int line) {
2569  ddns_cb->flags |= DDNS_ABORT;
2570  if (ddns_cb->transaction != NULL) {
2571  dns_client_cancelupdate((dns_clientupdatetrans_t *)
2572  ddns_cb->transaction);
2573  }
2574  ddns_cb->lease = NULL;
2575 
2576 #if defined (DEBUG_DNS_UPDATES)
2577  log_info("DDNS: %s(%d): cancelling transaction for %p",
2578  file, line, ddns_cb);
2579 #endif
2580 }
2581 
2582 #endif /* NSUPDATE */
2583 
2584 HASH_FUNCTIONS (dns_zone, const char *, struct dns_zone, dns_zone_hash_t,
const char * buf
Definition: trace.h:75
void tkey_free(ns_tsig_key **)
#define rc_register(file, line, reference, addr, refcnt, d, f)
Definition: alloc.h:88
int trace_playback(void)
const char int line
Definition: dhcpd.h:3615
dns_rdatalist_t rdatalist
Definition: dns.c:152
#define DDNS_PRINT_INBOUND
Definition: dhcpd.h:1693
struct binding_scope * global_scope
Definition: tree.c:39
struct dns_zone * zone
Definition: dhcpd.h:1714
isc_result_t find_tsig_key(ns_tsig_key **, const char *, struct dns_zone *)
unsigned char zone_name[DHCP_MAXDNS_WIRE]
Definition: dhcpd.h:1710
unsigned len
Definition: tree.h:80
#define DDNS_STATE_ADD_FW_NXDOMAIN
Definition: dhcpd.h:1682
dns_rdataset_t rdataset
Definition: dns.c:153
#define DDNS_PRINT_OUTBOUND
Definition: dhcpd.h:1694
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:282
void * dmalloc(unsigned, const char *, int)
Definition: alloc.c:56
int option_cache_dereference(struct option_cache **ptr, const char *file, int line)
Definition: options.c:2798
#define MDL
Definition: omapip.h:568
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:1688
#define DHCP_R_INVALIDARG
Definition: result.h:48
isc_sockaddr_t zone_addrs[DHCP_MAXNS]
Definition: dhcpd.h:1712
isc_result_t trace_write_packet_iov(trace_type_t *, int, trace_iov_t *, const char *, int)
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:1340
dns_tsec_t * tsec_key
Definition: omapip.h:153
void print_dns_status(int, struct dhcp_ddns_cb *, isc_result_t)
#define DDNS_ABORT
Definition: dhcpd.h:1673
int log_error(const char *,...) __attribute__((__format__(__printf__
int dns_zone_reference(struct dns_zone **ptr, struct dns_zone *bp, const char *file, int line)
Definition: alloc.c:1167
#define DDNS_INCLUDE_RRSET
Definition: dhcpd.h:1669
struct option_cache * secondary6
Definition: dhcpd.h:1423
#define DDNS_STATE_REM_FW_YXDHCID
Definition: dhcpd.h:1686
unsigned len
Definition: inet.h:32
isc_result_t enter_dns_zone(struct dns_zone *zone)
Definition: dns.c:678
struct data_string fwd_name
Definition: dhcpd.h:1702
#define DHCP_R_INVALIDKEY
Definition: result.h:56
void forget_zone(struct dns_zone **)
int terminated
Definition: tree.h:81
#define NS_MAXDNAME
Definition: nameser.h:74
void ddns_cb_free(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
struct iaddr address
Definition: dhcpd.h:1705
unsigned long ttl
Definition: dhcpd.h:1708
void * lease
Definition: dhcpd.h:1724
#define DHCP_MAXNS
Definition: isclib.h:107
isc_mem_t * mctx
Definition: isclib.h:92
#define FIND_REVERSE
Definition: dhcpd.h:3040
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:631
struct data_string dhcid
Definition: dhcpd.h:1704
struct data_string rev_name
Definition: dhcpd.h:1703
#define DHCP_R_KEY_UNKNOWN
Definition: result.h:55
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:2688
char * name
Definition: dhcpd.h:1419
dns_rdataclass_t dhcid_class
Definition: dhcpd.h:1730
#define NS_DEFAULTPORT
Definition: nameser.h:86
#define DDNS_STATE_ADD_PTR
Definition: dhcpd.h:1684
int buffer_allocate(struct buffer **ptr, unsigned len, const char *file, int line)
Definition: alloc.c:680
struct auth_key * key
Definition: dhcpd.h:1424
struct dhcp_ddns_cb * next_op
Definition: dhcpd.h:1721
unsigned len
Definition: trace.h:76
trace_type_t * trace_type_register(const char *, void *, void(*)(trace_type_t *, unsigned, char *), void(*)(trace_type_t *), const char *, int)
#define FIND_FORWARD
Definition: dhcpd.h:3039
#define DDNS_CONFLICT_OVERRIDE
Definition: dhcpd.h:1670
#define cur_time
Definition: dhcpd.h:1988
Definition: ip.h:47
int trace_record(void)
void dfree(void *, const char *, int)
Definition: alloc.c:131
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)
isc_sockaddrlist_t zone_server_list
Definition: dhcpd.h:1711
void repudiate_zone(struct dns_zone **)
int int log_info(const char *,...) __attribute__((__format__(__printf__
int refcnt
Definition: dhcpd.h:1417
#define DNS_ZONE_INACTIVE
Definition: dhcpd.h:1415
void putUChar(unsigned char *, u_int32_t)
Definition: convert.c:102
void cleanup(void)
int address_type
Definition: dhcpd.h:1706
struct option_cache * secondary
Definition: dhcpd.h:1421
void trace_ddns_init(void)
ddns_action_t cur_func
Definition: dhcpd.h:1719
isc_result_t remove_dns_zone(struct dns_zone *zone)
Definition: dns.c:663
isc_result_t trace_get_packet(trace_type_t **, unsigned *, char **)
int MRns_name_pton(const char *src, u_char *dst, size_t dstsiz)
Definition: ns_name.c:141
TIME timeout
Definition: dhcpd.h:1418
isc_task_t * task
Definition: isclib.h:96
struct option_cache * primary6
Definition: dhcpd.h:1422
dns_zone_hash_t * dns_zone_hash
Definition: dns.c:137
unsigned char data[1]
Definition: tree.h:63
Definition: tree.h:61
int state
Definition: dhcpd.h:1718
#define DDNS_STATE_ADD_FW_YXDHCID
Definition: dhcpd.h:1683
u_int16_t flags
Definition: dhcpd.h:1716
dns_rdata_t rdata
Definition: dns.c:151
struct server_list * servers
struct data_string data
Definition: dhcpd.h:361
void * transaction
Definition: dhcpd.h:1727
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:1135
struct dhcp_ddns_rdata dhcp_ddns_data_t
const char * file
Definition: dhcpd.h:3615
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:79
char * name
Definition: omapip.h:150
void data_string_copy(struct data_string *dest, const struct data_string *src, const char *file, int line)
Definition: alloc.c:1324
unsigned do_case_hash(const void *, unsigned, unsigned)
Definition: hash.c:241
#define DNS_HASH_SIZE
Definition: dhcpd.h:147
isc_result_t dns_zone_lookup(struct dns_zone **zone, const char *name)
Definition: dns.c:703
#define RC_MISC
Definition: alloc.h:56
#define DDNS_STATE_REM_FW_NXRR
Definition: dhcpd.h:1687
u_int16_t flags
Definition: dhcpd.h:1425
#define HASH_FUNCTIONS(name, bufarg, type, hashtype, ref, deref, hasher)
Definition: hash.h:89
struct buffer * buffer
Definition: tree.h:78
int dns_zone_dereference(struct dns_zone **ptr, const char *file, int line)
Definition: dns.c:736
struct option_cache * primary
Definition: dhcpd.h:1420
isc_result_t ddns_modify_fwd(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)