ISC DHCP  4.4.3-P1
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-2022 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  * PO Box 360
23  * Newmarket, NH 03857 USA
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) !=
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) !=
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  goto cleanup;
1379  }
1380 
1381  /* Remove any old addresses in case they've changed */
1382  if (zone->primary)
1384  if (zone->primary6)
1386 
1387  /* Set the flag to remove the zone from the hash if
1388  we have problems */
1389  remove_zone = 1;
1390  } else if (dns_zone_allocate(&zone, MDL) == 0) {
1391  return;
1392  } else {
1393  /* We've just allocated the zone, now we need
1394  * to allocate space for the name and addresses
1395  */
1396 
1397  /* allocate space for the name */
1398  len = strlen(ns_cb->zname);
1399  zone->name = dmalloc(len + 2, MDL);
1400  if (zone->name == NULL) {
1401  goto cleanup;
1402  }
1403 
1404  /* Copy the name and add a trailing '.' if necessary */
1405  strcpy(zone->name, ns_cb->zname);
1406  if (zone->name[len-1] != '.') {
1407  zone->name[len] = '.';
1408  zone->name[len+1] = 0;
1409  }
1410  }
1411 
1412  zone->timeout = cur_time + ns_cb->ttl;
1413 
1414  if (ns_cb->num_addrs != 0) {
1415  len = ns_cb->num_addrs * sizeof(struct in_addr);
1416  if ((!option_cache_allocate(&zone->primary, MDL)) ||
1417  (!buffer_allocate(&zone->primary->data.buffer,
1418  len, MDL))) {
1419  if (remove_zone == 1)
1420  remove_dns_zone(zone);
1421  goto cleanup;
1422  }
1423  memcpy(zone->primary->data.buffer->data, ns_cb->addrs, len);
1424  zone->primary->data.data =
1425  &zone->primary->data.buffer->data[0];
1426  zone->primary->data.len = len;
1427  }
1428  if (ns_cb->num_addrs6 != 0) {
1429  len = ns_cb->num_addrs6 * sizeof(struct in6_addr);
1430  if ((!option_cache_allocate(&zone->primary6, MDL)) ||
1431  (!buffer_allocate(&zone->primary6->data.buffer,
1432  len, MDL))) {
1433  if (remove_zone == 1)
1434  remove_dns_zone(zone);
1435  goto cleanup;
1436  }
1437  memcpy(zone->primary6->data.buffer->data, ns_cb->addrs6, len);
1438  zone->primary6->data.data =
1439  &zone->primary6->data.buffer->data[0];
1440  zone->primary6->data.len = len;
1441  }
1442 
1443  enter_dns_zone(zone);
1444 
1445  cleanup:
1446  dns_zone_dereference(&zone, MDL);
1447  return;
1448 }
1449 #endif
1450 
1475 int get_std_dhcid(dhcp_ddns_cb_t *ddns_cb,
1476  int type,
1477  const u_int8_t *identifier,
1478  unsigned id_len)
1479 {
1480  struct data_string *id = &ddns_cb->dhcid;
1481  isc_sha256_t sha256;
1482  unsigned char buf[ISC_SHA256_DIGESTLENGTH];
1483  unsigned char fwd_buf[256];
1484  unsigned fwd_buflen = 0;
1485 
1486  /* Types can only be 0..(2^16)-1. */
1487  if (type < 0 || type > 65535)
1488  return (0);
1489 
1490  /* We need to convert the fwd name to wire representation */
1491  if (MRns_name_pton((char *)ddns_cb->fwd_name.data, fwd_buf, 256) == -1)
1492  return (0);
1493  while(fwd_buf[fwd_buflen] != 0) {
1494  fwd_buflen += fwd_buf[fwd_buflen] + 1;
1495  }
1496  fwd_buflen++;
1497 
1498  if (!buffer_allocate(&id->buffer,
1499  ISC_SHA256_DIGESTLENGTH + 2 + 1,
1500  MDL))
1501  return (0);
1502  id->data = id->buffer->data;
1503 
1504  /* The two first bytes contain the type identifier. */
1505  putUShort(id->buffer->data, (unsigned)type);
1506 
1507  /* The next is the digest type, SHA-256 is 1 */
1508  putUChar(id->buffer->data + 2, 1u);
1509 
1510  /* Computing the digest */
1511  isc_sha256_init(&sha256);
1512  isc_sha256_update(&sha256, identifier, id_len);
1513  isc_sha256_update(&sha256, fwd_buf, fwd_buflen);
1514  isc_sha256_final(buf, &sha256);
1515 
1516  memcpy(id->buffer->data + 3, &buf, ISC_SHA256_DIGESTLENGTH);
1517 
1518  id->len = ISC_SHA256_DIGESTLENGTH + 2 + 1;
1519 
1520  return (1);
1521 }
1522 
1544 int get_int_dhcid (dhcp_ddns_cb_t *ddns_cb,
1545  int type,
1546  const u_int8_t *data,
1547  unsigned len)
1548 {
1549  struct data_string *id = &ddns_cb->dhcid;
1550  unsigned char buf[ISC_MD5_DIGESTLENGTH];
1551  isc_md5_t md5;
1552  int i;
1553 
1554  /* Types can only be 0..(2^16)-1. */
1555  if (type < 0 || type > 65535)
1556  return (0);
1557 
1558  /*
1559  * Hexadecimal MD5 digest plus two byte type, NUL,
1560  * and one byte for length for dns.
1561  */
1562  if (!buffer_allocate(&id -> buffer,
1563  (ISC_MD5_DIGESTLENGTH * 2) + 4, MDL))
1564  return (0);
1565  id->data = id->buffer->data;
1566 
1567  /*
1568  * We put the length into the first byte to turn
1569  * this into a dns text string. This avoid needing to
1570  * copy the string to add the byte later.
1571  */
1572  id->buffer->data[0] = ISC_MD5_DIGESTLENGTH * 2 + 2;
1573 
1574  /* Put the type in the next two bytes. */
1575  id->buffer->data[1] = "0123456789abcdef"[(type >> 4) & 0xf];
1576  /* This should have been [type & 0xf] but now that
1577  * it is in use we need to leave it this way in order
1578  * to avoid disturbing customer's lease files
1579  */
1580  id->buffer->data[2] = "0123456789abcdef"[type % 15];
1581 
1582  /* Mash together an MD5 hash of the identifier. */
1583  isc_md5_init(&md5);
1584  isc_md5_update(&md5, data, len);
1585  isc_md5_final(&md5, buf);
1586 
1587  /* Convert into ASCII. */
1588  for (i = 0; i < ISC_MD5_DIGESTLENGTH; i++) {
1589  id->buffer->data[i * 2 + 3] =
1590  "0123456789abcdef"[(buf[i] >> 4) & 0xf];
1591  id->buffer->data[i * 2 + 4] =
1592  "0123456789abcdef"[buf[i] & 0xf];
1593  }
1594 
1595  id->len = ISC_MD5_DIGESTLENGTH * 2 + 3;
1596  id->buffer->data[id->len] = 0;
1597  id->terminated = 1;
1598 
1599  return (1);
1600 }
1601 
1602 int get_dhcid(dhcp_ddns_cb_t *ddns_cb,
1603  int type,
1604  const u_int8_t *identifier,
1605  unsigned id_len)
1606 {
1607  if (ddns_cb->dhcid_class == dns_rdatatype_dhcid)
1608  return get_std_dhcid(ddns_cb, type, identifier, id_len);
1609  else
1610  return get_int_dhcid(ddns_cb, type, identifier, id_len);
1611 }
1612 
1613 /*
1614  * The dhcid (text version) that we pass to DNS includes a length byte
1615  * at the start but the text we store in the lease doesn't include the
1616  * length byte. The following routines are to convert between the two
1617  * styles.
1618  *
1619  * When converting from a dhcid to a leaseid we reuse the buffer and
1620  * simply adjust the data pointer and length fields in the data string.
1621  * This avoids any prolems with allocating space.
1622  */
1623 
1624 void
1625 dhcid_tolease(struct data_string *dhcid,
1626  struct data_string *leaseid)
1627 {
1628  /* copy the data string then update the fields */
1629  data_string_copy(leaseid, dhcid, MDL);
1630  leaseid->data++;
1631  leaseid->len--;
1632 }
1633 
1634 isc_result_t
1635 dhcid_fromlease(struct data_string *dhcid,
1636  struct data_string *leaseid)
1637 {
1638  if (!buffer_allocate(&dhcid->buffer, leaseid->len + 2, MDL)) {
1639  return(ISC_R_FAILURE);
1640  }
1641 
1642  dhcid->data = dhcid->buffer->data;
1643 
1644  dhcid->buffer->data[0] = leaseid->len;
1645  memcpy(dhcid->buffer->data + 1, leaseid->data, leaseid->len);
1646  dhcid->len = leaseid->len + 1;
1647  if (leaseid->terminated == 1) {
1648  dhcid->buffer->data[dhcid->len] = 0;
1649  dhcid->terminated = 1;
1650  }
1651 
1652  return(ISC_R_SUCCESS);
1653 }
1654 
1655 /*
1656  * Construct the dataset for this item.
1657  * This is a fairly simple arrangement as the operations we do are simple.
1658  * If there is data we simply have the rdata point to it - the formatting
1659  * must be correct already. We then link the rdatalist to the rdata and
1660  * create a rdataset from the rdatalist.
1661  */
1662 
1663 static isc_result_t
1664 make_dns_dataset(dns_rdataclass_t dataclass,
1665  dns_rdatatype_t datatype,
1666  dhcp_ddns_data_t *dataspace,
1667  unsigned char *data,
1668  int datalen,
1669  int ttl)
1670 {
1671  dns_rdata_t *rdata = &dataspace->rdata;
1672  dns_rdatalist_t *rdatalist = &dataspace->rdatalist;
1673  dns_rdataset_t *rdataset = &dataspace->rdataset;
1674 
1675  isc_region_t region;
1676 
1677  /* set up the rdata */
1678  dns_rdata_init(rdata);
1679 
1680  if (data == NULL) {
1681  /* No data, set up the rdata fields we care about */
1682  rdata->flags = DNS_RDATA_UPDATE;
1683  rdata->type = datatype;
1684  rdata->rdclass = dataclass;
1685  } else {
1686  switch(datatype) {
1687  case dns_rdatatype_a:
1688  case dns_rdatatype_aaaa:
1689  case dns_rdatatype_txt:
1690  case dns_rdatatype_dhcid:
1691  case dns_rdatatype_ptr:
1692  /* The data must be in the right format we simply
1693  * need to supply it via the correct structure */
1694  region.base = data;
1695  region.length = datalen;
1696  dns_rdata_fromregion(rdata, dataclass, datatype,
1697  &region);
1698  break;
1699  default:
1700  return(DHCP_R_INVALIDARG);
1701  break;
1702  }
1703  }
1704 
1705  /* setup the datalist and attach the rdata to it */
1706  dns_rdatalist_init(rdatalist);
1707  rdatalist->type = datatype;
1708  rdatalist->rdclass = dataclass;
1709  rdatalist->ttl = ttl;
1710  ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1711 
1712  /* convert the datalist to a dataset */
1713  dns_rdataset_init(rdataset);
1714  dns_rdatalist_tordataset(rdatalist, rdataset);
1715 
1716  return(ISC_R_SUCCESS);
1717 }
1718 
1719 #if defined (DEBUG_DNS_UPDATES)
1720 static void log_call(char *text, dns_name_t* pname, dns_name_t* uname) {
1721  char buf1[512];
1722  char buf2[512];
1723  if (pname) {
1724  dns_name_format(pname, buf1, 512);
1725  } else {
1726  *buf1=0;
1727  }
1728 
1729  if (uname) {
1730  dns_name_format(uname, buf2, 512);
1731  } else {
1732  *buf2=0;
1733  }
1734 
1735  log_info ("DDNS: %s: pname:[%s] uname:[%s]", text, buf1, buf2);
1736 }
1737 #endif
1738 
1739 
1740 /*
1741  * When a DHCP client or server intends to update an A RR, it first
1742  * prepares a DNS UPDATE query which includes as a prerequisite the
1743  * assertion that the name does not exist. The update section of the
1744  * query attempts to add the new name and its IP address mapping (an A
1745  * RR), and the DHCID RR with its unique client-identity.
1746  * -- "Interaction between DHCP and DNS"
1747  *
1748  * There are two cases, one for the server and one for the client.
1749  *
1750  * For the server the first step will have a request of:
1751  * The name is not in use
1752  * Add an A RR
1753  * Add a DHCID RR
1754  *
1755  * For the client the first step will have a request of:
1756  * The A RR does not exist
1757  * Add an A RR
1758  * Add a DHCID RR
1759  */
1760 
1761 static isc_result_t
1762 build_fwd_add1(dhcp_ddns_cb_t *ddns_cb,
1763  dhcp_ddns_data_t *dataspace,
1764  dns_name_t *pname,
1765  dns_name_t *uname)
1766 {
1767  isc_result_t result;
1768 
1769 #if defined (DEBUG_DNS_UPDATES)
1770  log_call("build_fwd_add1", pname, uname);
1771 #endif
1772 
1773  /* Construct the prerequisite list */
1774  if ((ddns_cb->flags & DDNS_INCLUDE_RRSET) != 0) {
1775  /* The A RR shouldn't exist */
1776  result = make_dns_dataset(dns_rdataclass_none,
1777  ddns_cb->address_type,
1778  dataspace, NULL, 0, 0);
1779  } else {
1780  /* The name is not in use */
1781  result = make_dns_dataset(dns_rdataclass_none,
1782  dns_rdatatype_any,
1783  dataspace, NULL, 0, 0);
1784  }
1785  if (result != ISC_R_SUCCESS) {
1786  return(result);
1787  }
1788  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1789  dataspace++;
1790 
1791  /* Construct the update list */
1792  /* Add the A RR */
1793  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type,
1794  dataspace,
1795  (unsigned char *)ddns_cb->address.iabuf,
1796  ddns_cb->address.len, ddns_cb->ttl);
1797  if (result != ISC_R_SUCCESS) {
1798  return(result);
1799  }
1800  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1801  dataspace++;
1802 
1803  /* Add the DHCID RR */
1804  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
1805  dataspace,
1806  (unsigned char *)ddns_cb->dhcid.data,
1807  ddns_cb->dhcid.len, ddns_cb->ttl);
1808  if (result != ISC_R_SUCCESS) {
1809  return(result);
1810  }
1811  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1812 
1813  return(ISC_R_SUCCESS);
1814 }
1815 
1816 /*
1817  * If the first update operation fails with YXDOMAIN, the updater can
1818  * conclude that the intended name is in use. The updater then
1819  * attempts to confirm that the DNS name is not being used by some
1820  * other host. The updater prepares a second UPDATE query in which the
1821  * prerequisite is that the desired name has attached to it a DHCID RR
1822  * whose contents match the client identity. The update section of
1823  * this query deletes the existing A records on the name, and adds the
1824  * A record that matches the DHCP binding and the DHCID RR with the
1825  * client identity.
1826  * -- "Interaction between DHCP and DNS"
1827  *
1828  * The message for the second step depends on if we are doing conflict
1829  * resolution. If we are we include the prerequisite. The prerequiste
1830  * will either:
1831  * A. require the data value of the DHCID RR to match that of the client
1832  * or
1833  * B. required only that the DHCID RR of the configured class (DHCID or
1834  * TXT) exist
1835  *
1836  * based on whether DDNS_GUARD_ID_MUST_MATCH is on (default) or off.
1837  *
1838  * The prerequisite is omitted if conflict detection is off.
1839  *
1840  * If not we delete the DHCID in addition to all A rrsets.
1841  *
1842  * Conflict resolution:
1843  * DHCID RR exists, and matches client identity.
1844  * Delete A RRset.
1845  * Add A RR.
1846  *
1847  * Conflict override:
1848  * Delete DHCID RRs.
1849  * Add DHCID RR
1850  * Delete A RRset.
1851  * Add A RR.
1852  */
1853 
1854 static isc_result_t
1855 build_fwd_add2(dhcp_ddns_cb_t *ddns_cb,
1856  dhcp_ddns_data_t *dataspace,
1857  dns_name_t *pname,
1858  dns_name_t *uname)
1859 {
1860  isc_result_t result = ISC_R_SUCCESS;
1861 
1862 #if defined (DEBUG_DNS_UPDATES)
1863  log_call("build_fwd_add2", pname, uname);
1864 #endif
1865 
1866  /*
1867  * If we are doing conflict detection we use a prereq list.
1868  * If not we delete the DHCID in addition to all A rrsets.
1869  */
1870  if (ddns_cb->flags & DDNS_CONFLICT_DETECTION) {
1871  /* Construct the prereq list */
1872  /* The DHCID RR exists and optionally matches the client's
1873  * identity. If matching is turned off, we use the presence
1874  * of a DHCID RR to signal that this is a dynamic entry and
1875  * thus eligible for us to overwrite. If matching is on
1876  * then we can only replace the entries if they belong to
1877  * this client. */
1878  unsigned char *match_id = NULL;
1879  int match_id_len = 0;
1880  int match_class = dns_rdataclass_any;
1881  if (ddns_cb->flags & DDNS_GUARD_ID_MUST_MATCH) {
1882  match_id = (unsigned char*)(ddns_cb->dhcid.data);
1883  match_id_len = ddns_cb->dhcid.len;
1884  match_class = dns_rdataclass_in;
1885  }
1886 
1887  result = make_dns_dataset(match_class,
1888  ddns_cb->dhcid_class,
1889  dataspace,
1890  match_id, match_id_len, 0);
1891  if (result != ISC_R_SUCCESS) {
1892  return(result);
1893  }
1894  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1895  dataspace++;
1896  } else {
1897  /* Start constructing the update list.
1898  * Conflict detection override: delete DHCID RRs */
1899  result = make_dns_dataset(dns_rdataclass_any,
1900  ddns_cb->dhcid_class,
1901  dataspace, NULL, 0, 0);
1902  if (result != ISC_R_SUCCESS) {
1903  return(result);
1904  }
1905  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1906  dataspace++;
1907 
1908  /* Add current DHCID RR, always include client id */
1909  result = make_dns_dataset(dns_rdataclass_in,
1910  ddns_cb->dhcid_class,
1911  dataspace,
1912  (unsigned char *)ddns_cb->dhcid.data,
1913  ddns_cb->dhcid.len, ddns_cb->ttl);
1914  if (result != ISC_R_SUCCESS) {
1915  return(result);
1916  }
1917  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1918  dataspace++;
1919  }
1920 
1921  /* Start or continue constructing the update list */
1922  /* Delete the address RRset */
1923  result = make_dns_dataset(dns_rdataclass_any, ddns_cb->address_type,
1924  dataspace, NULL, 0, 0);
1925  if (result != ISC_R_SUCCESS) {
1926  return(result);
1927  }
1928  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1929  dataspace++;
1930 
1931  /* Add the address RR */
1932  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type,
1933  dataspace,
1934  (unsigned char *)ddns_cb->address.iabuf,
1935  ddns_cb->address.len, ddns_cb->ttl);
1936  if (result != ISC_R_SUCCESS) {
1937  return(result);
1938  }
1939  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
1940 
1941  return(ISC_R_SUCCESS);
1942 }
1943 
1944 /*
1945  * Creates the DNS foward update add used for DSMM add attempt #3 and
1946  * ddns-other-guard-is-dynamic is off
1947  *
1948  *
1949  * If the second update failed with NXRRSET, this indicates that:
1950  *
1951  * 1. our FQDN is in use
1952  * 2 no guard record (DHCID RR) for that FQDN, of our class (and optionally
1953  * client id) exists
1954  *
1955  * In Dual Stack Mixed Mode, we need to attempt a third add, to distinguish
1956  * between static entries that we cannot modify and dynamic entries belonging
1957  * to the "other" side of dual stack. The prerequisites for this add are:
1958  *
1959  * 1. No address record of my type exists
1960  * 2. No guard record of my type exists
1961  * 3. A guard record of the other type exists
1962  *
1963  * and updates which will add the new address and guard record:
1964  *
1965  * prereq nxrrset <name> <addr_t> # no address record of my type
1966  * prereq nxrrset <name> <guard_t> # no guard record of my type
1967  * prereq yxrrset <name> <other_guard_t> # other guard type does exist
1968  * update add <name> <addr_t> <address> # add the new address record
1969  * update add <name> <guard_t> <client-id> # add the new address record
1970  */
1971 static isc_result_t
1972 build_dsmm_fwd_add3(dhcp_ddns_cb_t *ddns_cb,
1973  dhcp_ddns_data_t *dataspace,
1974  dns_name_t *pname,
1975  dns_name_t *uname)
1976 {
1977  isc_result_t result = ISC_R_SUCCESS;
1978 
1979 #if defined (DEBUG_DNS_UPDATES)
1980  log_call("build_fwd_add3", pname, uname);
1981 #endif
1982  /* Construct the prereq list */
1983  /* No address record of my type exists */
1984  result = make_dns_dataset(dns_rdataclass_none,
1985  ddns_cb->address_type,
1986  dataspace, NULL, 0, 0);
1987  if (result != ISC_R_SUCCESS) {
1988  return(result);
1989  }
1990  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
1991  dataspace++;
1992 
1993  /* No guard record of my type exists */
1994  result = make_dns_dataset(dns_rdataclass_none,
1995  ddns_cb->dhcid_class,
1996  dataspace, NULL, 0, 0);
1997  if (result != ISC_R_SUCCESS) {
1998  return(result);
1999  }
2000  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2001  dataspace++;
2002 
2003  /* Guard record of the other type DOES exist */
2004  result = make_dns_dataset(dns_rdataclass_any,
2005  ddns_cb->other_dhcid_class,
2006  dataspace, NULL, 0, 0);
2007  if (result != ISC_R_SUCCESS) {
2008  return(result);
2009  }
2010  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2011  dataspace++;
2012 
2013  /* Start constructing the update list. */
2014  /* Add the address RR */
2015  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type,
2016  dataspace,
2017  (unsigned char *)ddns_cb->address.iabuf,
2018  ddns_cb->address.len, ddns_cb->ttl);
2019  if (result != ISC_R_SUCCESS) {
2020  return(result);
2021  }
2022  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2023  dataspace++;
2024 
2025  /* Add current DHCID RR */
2026  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
2027  dataspace,
2028  (unsigned char *)ddns_cb->dhcid.data,
2029  ddns_cb->dhcid.len, ddns_cb->ttl);
2030  if (result != ISC_R_SUCCESS) {
2031  return(result);
2032  }
2033  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2034 
2035  return(ISC_R_SUCCESS);
2036 }
2037 
2038 /*
2039  * Creates the DNS foward update add used for DSMM add attempt #3 and
2040  * ddns-other-guard-is-dynamic is ON
2041  *
2042  * If the second update failed with NXRRSET, this indicates that:
2043  *
2044  * 1. our FQDN is in use
2045  * 2 no guard record (DHCID RR) for that FQDN, of our class (and optionally
2046  * client id) exists
2047  *
2048  * When we're In Dual Stack Mixed Mode and ddns-other-guard-is-dynamic is ON
2049  * we need only determine if a guard record of the other type exists, to know
2050  * if we can add/replace and address record of our type. In other words,
2051  * the presence of a dynamic entry belonging to the "other" stack means
2052  * all entries for this name should be dynamic and we overwrite an unguarded
2053  * address record of our type.
2054  *
2055  * The udpate will contain a single prequisite for a guard record of the
2056  * other type, an update to delete any address records of our type, and
2057  * updates to add the address and guard records:
2058  *
2059  * prereq yxrrset <name> <other_guard_t> # other guard type exists
2060  * update delete <name> <addr_t> # delete existing address record
2061  * # (if one)
2062  * update add <name> <addr_t> <address> # add new address record
2063  * update add <name> <guard_t> <client-id> # add new guard record
2064  */
2065 static isc_result_t
2066 build_dsmm_fwd_add3_other(dhcp_ddns_cb_t *ddns_cb,
2067  dhcp_ddns_data_t *dataspace,
2068  dns_name_t *pname,
2069  dns_name_t *uname)
2070 {
2071  isc_result_t result = ISC_R_SUCCESS;
2072 
2073 #if defined (DEBUG_DNS_UPDATES)
2074  log_call("build_fwd_add3_other", pname, uname);
2075 #endif
2076  /* Construct the prereq list */
2077 
2078  // If ID matching is on, a result of NXRRSET from add2 means
2079  // either there is no guard of my type, or there is but
2080  // it does not match this client. We need to distinguish
2081  // between those two cases here and only allow this add
2082  // if there is no guard of my type.
2083  if (ddns_cb->flags & DDNS_GUARD_ID_MUST_MATCH) {
2084  /* No guard record of my type exists */
2085  result = make_dns_dataset(dns_rdataclass_none,
2086  ddns_cb->dhcid_class,
2087  dataspace, NULL, 0, 0);
2088  if (result != ISC_R_SUCCESS) {
2089  return(result);
2090  }
2091 
2092  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2093  dataspace++;
2094  }
2095 
2096  /* A guard record of the other type exists */
2097  result = make_dns_dataset(dns_rdataclass_any,
2098  ddns_cb->other_dhcid_class,
2099  dataspace, NULL, 0, 0);
2100  if (result != ISC_R_SUCCESS) {
2101  return(result);
2102  }
2103  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2104  dataspace++;
2105 
2106  /* Start constructing the update list. */
2107  /* Delete the existing address record of my type (if one) */
2108  result = make_dns_dataset(dns_rdataclass_any,
2109  ddns_cb->address_type,
2110  dataspace, NULL, 0, 0);
2111  if (result != ISC_R_SUCCESS) {
2112  return(result);
2113  }
2114  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2115  dataspace++;
2116 
2117  /* Add the address RR */
2118  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->address_type,
2119  dataspace,
2120  (unsigned char *)ddns_cb->address.iabuf,
2121  ddns_cb->address.len, ddns_cb->ttl);
2122  if (result != ISC_R_SUCCESS) {
2123  return(result);
2124  }
2125  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2126  dataspace++;
2127 
2128  /* Add current DHCID RR */
2129  result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class,
2130  dataspace,
2131  (unsigned char *)ddns_cb->dhcid.data,
2132  ddns_cb->dhcid.len, ddns_cb->ttl);
2133  if (result != ISC_R_SUCCESS) {
2134  return(result);
2135  }
2136  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2137 
2138  return(ISC_R_SUCCESS);
2139 }
2140 
2141 /*
2142  * The entity chosen to handle the A record for this client (either the
2143  * client or the server) SHOULD delete the A (or AAAA) record that was
2144  * added when the lease was made to the client.
2145  *
2146  * If we are doing conflict resolution, the udpate will contain a prequisite
2147  * that will either:
2148  * A. require that a guard record of the configure class (DHCID or TXT) with
2149  * a data value matching that the client exist (per RFC 4703)
2150  * or
2151  * B. require only that the guard record of the configured class exist
2152  *
2153  * based on whether DDNS_GUARD_ID_MUST_MATCH is on (default) or off.
2154  *
2155  * The prerequisite is omitted if conflict detection is off.
2156  *
2157  */
2158 static isc_result_t
2159 build_fwd_rem1(dhcp_ddns_cb_t *ddns_cb,
2160  dhcp_ddns_data_t *dataspace,
2161  dns_name_t *pname,
2162  dns_name_t *uname)
2163 {
2164  isc_result_t result = ISC_R_SUCCESS;
2165 
2166 #if defined (DEBUG_DNS_UPDATES)
2167  log_call("build_fwd_rem1", pname, uname);
2168 #endif
2169 
2170  /* If we're doing conflict detection, add the guard record pre-req */
2171  if (ddns_cb->flags & DDNS_CONFLICT_DETECTION) {
2172  /* Construct the prereq list */
2173  /* The guard record exists and optionally matches the client's
2174  * identity. If matching is turned off, we use the presence
2175  * of a DHCID RR to signal that this is a dynamic entry and
2176  * thus eligible for us to overwrite. If matching is on
2177  * then we can only delete the entries if they belong to
2178  * this client. */
2179  unsigned char *match_id = NULL;
2180  int match_id_len = 0;
2181  int match_class = dns_rdataclass_any;
2182  if (ddns_cb->flags & DDNS_GUARD_ID_MUST_MATCH) {
2183  match_id = (unsigned char*)(ddns_cb->dhcid.data);
2184  match_id_len = ddns_cb->dhcid.len;
2185  match_class = dns_rdataclass_in;
2186  }
2187 
2188  result = make_dns_dataset(match_class,
2189  ddns_cb->dhcid_class,
2190  dataspace,
2191  match_id, match_id_len, 0);
2192  if (result != ISC_R_SUCCESS) {
2193  return(result);
2194  }
2195  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2196  dataspace++;
2197  }
2198 
2199  /* Construct the update list */
2200  /* Delete A RRset */
2201  result = make_dns_dataset(dns_rdataclass_none, ddns_cb->address_type,
2202  dataspace,
2203  (unsigned char *)ddns_cb->address.iabuf,
2204  ddns_cb->address.len, 0);
2205  if (result != ISC_R_SUCCESS) {
2206  return(result);
2207  }
2208  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2209 
2210  return(ISC_R_SUCCESS);
2211 }
2212 
2213 /*
2214  * If the deletion of the A succeeded, and there are no A or AAAA
2215  * records left for this domain, then we can blow away the DHCID
2216  * record as well. We can't blow away the DHCID record above
2217  * because it's possible that more than one record has been added
2218  * to this domain name.
2219  *
2220  * Second query has:
2221  * A RR does not exist.
2222  * AAAA RR does not exist.
2223  * Delete appropriate DHCID RR.
2224  */
2225 static isc_result_t
2226 build_fwd_rem2(dhcp_ddns_cb_t *ddns_cb,
2227  dhcp_ddns_data_t *dataspace,
2228  dns_name_t *pname,
2229  dns_name_t *uname)
2230 {
2231  isc_result_t result;
2232  unsigned char *match_id = NULL;
2233  int match_id_len = 0;
2234  int match_class = dns_rdataclass_any;
2235 
2236 #if defined (DEBUG_DNS_UPDATES)
2237  log_call("build_fwd_rem2", pname, uname);
2238 #endif
2239 
2240  /* Construct the prereq list */
2241  /* The A RR does not exist */
2242  result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_a,
2243  dataspace, NULL, 0, 0);
2244  if (result != ISC_R_SUCCESS) {
2245  return(result);
2246  }
2247  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2248  dataspace++;
2249 
2250  /* The AAAA RR does not exist */
2251  result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_aaaa,
2252  dataspace, NULL, 0, 0);
2253  if (result != ISC_R_SUCCESS) {
2254  return(result);
2255  }
2256  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2257  dataspace++;
2258 
2259  /* Construct the update list */
2260  /* Delete DHCID RR */
2261 
2262  /* We'll specify the client id in the guard record delete if
2263  * matching is enabled, otherwise we leave it off. */
2264  if (ddns_cb->flags & DDNS_GUARD_ID_MUST_MATCH) {
2265  match_id = (unsigned char*)(ddns_cb->dhcid.data);
2266  match_id_len = ddns_cb->dhcid.len;
2267  match_class = dns_rdataclass_none;
2268  }
2269 
2270  result = make_dns_dataset(match_class, ddns_cb->dhcid_class,
2271  dataspace,
2272  match_id, match_id_len, 0);
2273  if (result != ISC_R_SUCCESS) {
2274  return(result);
2275  }
2276  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2277 
2278  return(ISC_R_SUCCESS);
2279 }
2280 
2281 /*
2282  * Constructs the second stage forward remove, when the first stage
2283  * succeeds and DSMM is enabled, and ddns-other-guard-is-dynamic is OFF
2284  *
2285  * Normal conflict detection requires that the guard record of the
2286  * configured type only be deleted if there are no address records of
2287  * any type. In Dual Stack Mixed Mode, we are only concerned with whether
2288  * there any records or our configured address type remaining.
2289  *
2290  * This update consists of a single prequisite that there be no address
2291  * records of our type followed by a delete of the guard record of our type
2292  * and optionally matching client-id.
2293  *
2294  * prereq nxrrset name <addr_t> # no records of this address type exist
2295  * update delete name <guard_t> <client_id> # delete the existing guard record
2296  */
2297 static isc_result_t
2298 build_fwd_rem2_dsmm (dhcp_ddns_cb_t *ddns_cb,
2299  dhcp_ddns_data_t *dataspace,
2300  dns_name_t *pname,
2301  dns_name_t *uname)
2302 {
2303  isc_result_t result;
2304  unsigned char *match_id = NULL;
2305  int match_id_len = 0;
2306  int match_class = dns_rdataclass_any;
2307 
2308 #if defined (DEBUG_DNS_UPDATES)
2309  log_call("build_fwd_rem2_dsmm", pname, uname);
2310 #endif
2311 
2312  /* Construct the prereq list */
2313  /* The address RR does not exist */
2314  result = make_dns_dataset(dns_rdataclass_none,
2315  ddns_cb->address_type,
2316  dataspace, NULL, 0, 0);
2317  if (result != ISC_R_SUCCESS) {
2318  return(result);
2319  }
2320  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2321  dataspace++;
2322 
2323  /* Construct the update list */
2324  /* Delete DHCID RR */
2325 
2326  /* We'll specify the client id in the guard record delete if
2327  * matching is enabled, otherwise we leave it off. */
2328  if (ddns_cb->flags & DDNS_GUARD_ID_MUST_MATCH) {
2329  match_id = (unsigned char*)(ddns_cb->dhcid.data);
2330  match_id_len = ddns_cb->dhcid.len;
2331  match_class = dns_rdataclass_none;
2332  }
2333 
2334  result = make_dns_dataset(match_class, ddns_cb->dhcid_class,
2335  dataspace,
2336  match_id, match_id_len, 0);
2337  if (result != ISC_R_SUCCESS) {
2338  return(result);
2339  }
2340  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2341 
2342  return(ISC_R_SUCCESS);
2343 }
2344 
2345 /*
2346  * Constructs the second stage forward remove, when the first stage
2347  * succeeds and DSMM is enabled and ddns-other-guard-is-dynamic is ON
2348  *
2349  * This update addresses the case when an address record of our type exists
2350  * without a guard record of our type, yet a dynamic entry of the other type
2351  * exists. The presence of a guard of the other type indicates that all
2352  * entries for this name should be treated as dynamic, thus permitting us to
2353  * remove the address record of our type.
2354  *
2355  * prereq nxrrset <name> <guard_t> # my guard type does not exist
2356  * prereq yxrrset <name> <other_guard_t> # other guard type does exist
2357  * update delete <name> <addr_t> address # delete the existing address record
2358  *
2359  */
2360 static isc_result_t
2361 build_fwd_rem2_dsmm_other(dhcp_ddns_cb_t *ddns_cb,
2362  dhcp_ddns_data_t *dataspace,
2363  dns_name_t *pname,
2364  dns_name_t *uname)
2365 {
2366  isc_result_t result;
2367 
2368 #if defined (DEBUG_DNS_UPDATES)
2369  log_call("build_fwd_rem2_dsmm_other", pname, uname);
2370 #endif
2371 
2372  /* Construct the prereq list */
2373  /* No guard record of my type exists */
2374  result = make_dns_dataset(dns_rdataclass_none, ddns_cb->dhcid_class,
2375  dataspace, NULL, 0, 0);
2376  if (result != ISC_R_SUCCESS) {
2377  return(result);
2378  }
2379  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2380  dataspace++;
2381 
2382  /* Guard record of the OTHER type DOES exist */
2383  result = make_dns_dataset(dns_rdataclass_any,
2384  ddns_cb->other_dhcid_class,
2385  dataspace, NULL, 0, 0);
2386  if (result != ISC_R_SUCCESS) {
2387  return(result);
2388  }
2389  ISC_LIST_APPEND(pname->list, &dataspace->rdataset, link);
2390  dataspace++;
2391 
2392  /* Construct the update list */
2393  /* Delete the address RRset */
2394  result = make_dns_dataset(dns_rdataclass_none, ddns_cb->address_type,
2395  dataspace,
2396  (unsigned char *)ddns_cb->address.iabuf,
2397  ddns_cb->address.len, 0);
2398  if (result != ISC_R_SUCCESS) {
2399  return(result);
2400  }
2401  ISC_LIST_APPEND(uname->list, &dataspace->rdataset, link);
2402 
2403  return(ISC_R_SUCCESS);
2404 }
2405 
2406 /*
2407  * This routine converts from the task action call into something
2408  * easier to work with. It also handles the common case of a signature
2409  * or zone not being correct.
2410  */
2411 void ddns_interlude(isc_task_t *taskp,
2412  isc_event_t *eventp)
2413 {
2414  dhcp_ddns_cb_t *ddns_cb = (dhcp_ddns_cb_t *)eventp->ev_arg;
2415  dns_clientupdateevent_t *ddns_event = (dns_clientupdateevent_t *)eventp;
2416  isc_result_t eresult = ddns_event->result;
2417  isc_result_t result;
2418 
2419  /* We've extracted the information we want from it, get rid of
2420  * the event block.*/
2421  isc_event_free(&eventp);
2422 
2423 #if defined (TRACING)
2424  if (trace_record()) {
2425  trace_ddns_input_write(ddns_cb, eresult);
2426  }
2427 #endif
2428 
2429 #if defined (DEBUG_DNS_UPDATES)
2430  print_dns_status(DDNS_PRINT_INBOUND, ddns_cb, eresult);
2431 #endif
2432 
2433  /* This transaction is complete, clear the value */
2434  dns_client_destroyupdatetrans(&ddns_cb->transaction);
2435 
2436  /* If we cancelled or tried to cancel the operation we just
2437  * need to clean up. */
2438  if ((eresult == ISC_R_CANCELED) ||
2439  ((ddns_cb->flags & DDNS_ABORT) != 0)) {
2440 #if defined (DEBUG_DNS_UPDATES)
2441  log_info("DDNS: completeing transaction cancellation cb=%p, "
2442  "flags=%x, %s",
2443  ddns_cb, ddns_cb->flags, isc_result_totext(eresult));
2444 #endif
2445  if ((ddns_cb->flags & DDNS_ABORT) == 0) {
2446  log_info("DDNS: cleaning up lease pointer for a cancel "
2447  "cb=%p", ddns_cb);
2448  /*
2449  * We shouldn't actually be able to get here but
2450  * we are. This means we haven't cleaned up
2451  * the lease pointer so we need to do that before
2452  * freeing the cb.
2453  */
2454  ddns_cb->cur_func(ddns_cb, eresult);
2455  return;
2456  }
2457 
2458  if (ddns_cb->next_op != NULL) {
2459  /* if necessary cleanup up next op block */
2460  ddns_cb_free(ddns_cb->next_op, MDL);
2461  }
2462  ddns_cb_free(ddns_cb, MDL);
2463  return;
2464  }
2465 
2466  /* If we had a problem with our key or zone try again */
2467  if ((eresult == DNS_R_NOTAUTH) ||
2468  (eresult == DNS_R_NOTZONE)) {
2469  int i;
2470  /* Our zone information was questionable,
2471  * repudiate it and try again */
2472  log_error("DDNS: bad zone information, repudiating zone %s",
2473  ddns_cb->zone_name);
2474  repudiate_zone(&ddns_cb->zone);
2475  ddns_cb->zone_name[0] = 0;
2476  ISC_LIST_INIT(ddns_cb->zone_server_list);
2477  for (i = 0; i < DHCP_MAXNS; i++) {
2478  ISC_LINK_INIT(&ddns_cb->zone_addrs[i], link);
2479  }
2480 
2481  if ((ddns_cb->state == DDNS_STATE_ADD_PTR) ||
2482  (ddns_cb->state == DDNS_STATE_REM_PTR)) {
2483  result = ddns_modify_ptr(ddns_cb, MDL);
2484  } else {
2485  result = ddns_modify_fwd(ddns_cb, MDL);
2486  }
2487 
2488  if (result != ISC_R_SUCCESS) {
2489  /* if we couldn't redo the query log it and
2490  * let the next function clean it up */
2491  log_info("DDNS: Failed to retry after zone failure");
2492  ddns_cb->cur_func(ddns_cb, result);
2493  }
2494  return;
2495  } else {
2496  /* pass it along to be processed */
2497  ddns_cb->cur_func(ddns_cb, eresult);
2498  }
2499 
2500  return;
2501 }
2502 
2503 /*
2504  * This routine does the generic work for sending a ddns message to
2505  * modify the forward record (A or AAAA) and calls one of a set of
2506  * routines to build the specific message.
2507  */
2508 
2509 isc_result_t
2510 ddns_modify_fwd(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
2511 {
2512  isc_result_t result;
2513  dns_tsec_t *tsec_key = NULL;
2514 
2515 #if defined (DEBUG_DNS_UPDATES)
2516  log_info("DDNS: ddns_modify_fwd");
2517 #endif
2518 
2519  unsigned char *clientname;
2520  dhcp_ddns_data_t *dataspace = NULL;
2521  dns_namelist_t prereqlist, updatelist;
2522  dns_fixedname_t zname0, pname0, uname0;
2523  dns_name_t *zname = NULL, *pname, *uname;
2524 
2525  isc_sockaddrlist_t *zlist = NULL;
2526 
2527  /* Creates client context if we need to */
2528  result = dns_client_init();
2529  if (result != ISC_R_SUCCESS) {
2530  return result;
2531  }
2532 
2533  /* Get a pointer to the clientname to make things easier. */
2534  clientname = (unsigned char *)ddns_cb->fwd_name.data;
2535 
2536  /* Extract and validate the type of the address. */
2537  if (ddns_cb->address.len == 4) {
2538  ddns_cb->address_type = dns_rdatatype_a;
2539  } else if (ddns_cb->address.len == 16) {
2540  ddns_cb->address_type = dns_rdatatype_aaaa;
2541  } else {
2542  return DHCP_R_INVALIDARG;
2543  }
2544 
2545  /*
2546  * If we already have a zone use it, otherwise try to lookup the
2547  * zone in our cache. If we find one we will have a pointer to
2548  * the zone that needs to be dereferenced when we are done with it.
2549  * If we don't find one that is okay we'll let the DNS code try and
2550  * find the information for us.
2551  */
2552 
2553  if (ddns_cb->zone == NULL) {
2554  result = find_cached_zone(ddns_cb, FIND_FORWARD);
2555 #if defined (DNS_ZONE_LOOKUP)
2556  if (result == ISC_R_NOTFOUND) {
2557  /*
2558  * We didn't find a cached zone, see if we can
2559  * can find a nameserver and create a zone.
2560  */
2561  if (find_zone_start(ddns_cb, FIND_FORWARD)
2562  == ISC_R_SUCCESS) {
2563  /*
2564  * We have started the process to find a zone
2565  * queue the ddns_cb for processing after we
2566  * create the zone
2567  */
2568  /* sar - not yet implemented, currently we just
2569  * arrange for things to get cleaned up
2570  */
2571  goto cleanup;
2572  }
2573  }
2574 #endif
2575  if (result != ISC_R_SUCCESS)
2576  goto cleanup;
2577  }
2578 
2579  /*
2580  * If we have a zone try to get any information we need
2581  * from it - name, addresses and the key. The address
2582  * and key may be empty the name can't be.
2583  */
2584  if (ddns_cb->zone) {
2585  /* Set up the zone name for use by DNS */
2586  result = dhcp_isc_name(ddns_cb->zone_name, &zname0, &zname);
2587  if (result != ISC_R_SUCCESS) {
2588  log_error("Unable to build name for zone for "
2589  "fwd update: %s %s",
2590  ddns_cb->zone_name,
2591  isc_result_totext(result));
2592  goto cleanup;
2593  }
2594 
2595  if (!(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
2596  /* If we have any addresses get them */
2597  zlist = &ddns_cb->zone_server_list;
2598  }
2599 
2600 
2601  if (ddns_cb->zone->key != NULL) {
2602  /*
2603  * Not having a key is fine, having a key
2604  * but not a tsec is odd so we warn the user.
2605  */
2606  /*sar*/
2607  /* should we do the warning? */
2608  tsec_key = ddns_cb->zone->key->tsec_key;
2609  if (tsec_key == NULL) {
2610  log_error("No tsec for use with key %s",
2611  ddns_cb->zone->key->name);
2612  }
2613  }
2614  }
2615 
2616  /* Set up the DNS names for the prereq and update lists */
2617  if (((result = dhcp_isc_name(clientname, &pname0, &pname))
2618  != ISC_R_SUCCESS) ||
2619  ((result = dhcp_isc_name(clientname, &uname0, &uname))
2620  != ISC_R_SUCCESS)) {
2621  log_error("Unable to build name for fwd update: %s %s",
2622  clientname, isc_result_totext(result));
2623  goto cleanup;
2624  }
2625 
2626  /* Allocate the various isc dns library structures we may require. */
2627  dataspace = isc_mem_get(dhcp_gbl_ctx.mctx, sizeof(*dataspace) * 4);
2628  if (dataspace == NULL) {
2629  log_error("Unable to allocate memory for fwd update");
2630  result = ISC_R_NOMEMORY;
2631  goto cleanup;
2632  }
2633 
2634  ISC_LIST_INIT(prereqlist);
2635  ISC_LIST_INIT(updatelist);
2636 
2637  switch(ddns_cb->state) {
2639  result = build_fwd_add1(ddns_cb, dataspace, pname, uname);
2640  if (result != ISC_R_SUCCESS) {
2641  goto cleanup;
2642  }
2643  ISC_LIST_APPEND(prereqlist, pname, link);
2644  break;
2645 
2647  result = build_fwd_add2(ddns_cb, dataspace, pname, uname);
2648  if (result != ISC_R_SUCCESS) {
2649  goto cleanup;
2650  }
2651 
2652  /* If we are doing conflict detection we have entries
2653  * in the pname list and we need to attach it to the
2654  * prereqlist */
2655 
2656  if (ddns_cb->flags & DDNS_CONFLICT_DETECTION) {
2657  ISC_LIST_APPEND(prereqlist, pname, link);
2658  }
2659 
2660  break;
2661 
2662  case DDNS_STATE_DSMM_FW_ADD3: {
2663  /* We should only be here if we're doing DSMM */
2664  builder_func_t builder;
2665  if (ddns_cb->flags & DDNS_OTHER_GUARD_IS_DYNAMIC) {
2666  builder = build_dsmm_fwd_add3_other;
2667  } else {
2668  builder = build_dsmm_fwd_add3;
2669  }
2670 
2671  result = (*builder)(ddns_cb, dataspace, pname, uname);
2672  if (result != ISC_R_SUCCESS) {
2673  goto cleanup;
2674  }
2675 
2676  ISC_LIST_APPEND(prereqlist, pname, link);
2677  break;
2678  }
2679 
2681  result = build_fwd_rem1(ddns_cb, dataspace, pname, uname);
2682  if (result != ISC_R_SUCCESS) {
2683  goto cleanup;
2684  }
2685  ISC_LIST_APPEND(prereqlist, pname, link);
2686  break;
2687 
2688  case DDNS_STATE_REM_FW_NXRR: {
2689  builder_func_t builder;
2690 
2691  if (ddns_cb->flags & DDNS_DUAL_STACK_MIXED_MODE) {
2692  builder = build_fwd_rem2_dsmm;
2693  } else {
2694  builder = build_fwd_rem2;
2695  }
2696 
2697  result = (*builder)(ddns_cb, dataspace, pname, uname);
2698  if (result != ISC_R_SUCCESS) {
2699  goto cleanup; }
2700  ISC_LIST_APPEND(prereqlist, pname, link);
2701  break;
2702  }
2703 
2705  result = build_fwd_rem2_dsmm_other(ddns_cb, dataspace,
2706  pname, uname);
2707  if (result != ISC_R_SUCCESS) {
2708  goto cleanup; }
2709  ISC_LIST_APPEND(prereqlist, pname, link);
2710  break;
2711  }
2712 
2713  default:
2714  log_error("ddns_modify_fwd: Invalid state: %d", ddns_cb->state);
2715  result = DHCP_R_INVALIDARG;
2716  goto cleanup;
2717  break;
2718  }
2719 
2720  /*
2721  * We always have an update list but may not have a prereqlist
2722  * if we are doing conflict override.
2723  */
2724  ISC_LIST_APPEND(updatelist, uname, link);
2725 
2726  /* send the message, cleanup and return the result */
2727  result = ddns_update(dhcp_gbl_ctx.dnsclient,
2728  dns_rdataclass_in, zname,
2729  &prereqlist, &updatelist,
2730  zlist, tsec_key,
2731  DNS_CLIENTUPDOPT_ALLOWRUN,
2733  ddns_interlude,
2734  (void *)ddns_cb,
2735  &ddns_cb->transaction);
2736  if (result == ISC_R_FAMILYNOSUPPORT) {
2737  log_info("Unable to perform DDNS update, "
2738  "address family not supported");
2739  }
2740 
2741 #if defined (DEBUG_DNS_UPDATES)
2742  print_dns_status(DDNS_PRINT_OUTBOUND, ddns_cb, result);
2743 #endif
2744 
2745  cleanup:
2746 #if defined (DEBUG_DNS_UPDATES)
2747  if (result != ISC_R_SUCCESS) {
2748  log_info("DDNS: %s(%d): error in ddns_modify_fwd %s for %p",
2749  file, line, isc_result_totext(result), ddns_cb);
2750  }
2751 #endif
2752 
2753  if (dataspace != NULL) {
2754  isc_mem_put(dhcp_gbl_ctx.mctx, dataspace,
2755  sizeof(*dataspace) * 4);
2756  }
2757  return(result);
2758 }
2759 
2760 
2761 isc_result_t
2762 ddns_modify_ptr(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
2763 {
2764  isc_result_t result;
2765  dns_tsec_t *tsec_key = NULL;
2766  unsigned char *ptrname;
2767  dhcp_ddns_data_t *dataspace = NULL;
2768  dns_namelist_t updatelist;
2769  dns_fixedname_t zname0, uname0;
2770  dns_name_t *zname = NULL, *uname;
2771  isc_sockaddrlist_t *zlist = NULL;
2772  unsigned char buf[256];
2773  int buflen;
2774 
2775 #if defined (DEBUG_DNS_UPDATES)
2776  log_info("DDNS: ddns_modify_ptr");
2777 #endif
2778 
2779  /* Creates client context if we need to */
2780  result = dns_client_init();
2781  if (result != ISC_R_SUCCESS) {
2782  return result;
2783  }
2784 
2785  /*
2786  * Try to lookup the zone in the zone cache. As with the forward
2787  * case it's okay if we don't have one, the DNS code will try to
2788  * find something also if we succeed we will need to dereference
2789  * the zone later. Unlike with the forward case we assume we won't
2790  * have a pre-existing zone.
2791  */
2792  result = find_cached_zone(ddns_cb, FIND_REVERSE);
2793 
2794 #if defined (DNS_ZONE_LOOKUP)
2795  if (result == ISC_R_NOTFOUND) {
2796  /*
2797  * We didn't find a cached zone, see if we can
2798  * can find a nameserver and create a zone.
2799  */
2800  if (find_zone_start(ddns_cb, FIND_REVERSE) == ISC_R_SUCCESS) {
2801  /*
2802  * We have started the process to find a zone
2803  * queue the ddns_cb for processing after we
2804  * create the zone
2805  */
2806  /* sar - not yet implemented, currently we just
2807  * arrange for things to get cleaned up
2808  */
2809  goto cleanup;
2810  }
2811  }
2812 #endif
2813  if (result != ISC_R_SUCCESS)
2814  goto cleanup;
2815 
2816 
2817  if ((result == ISC_R_SUCCESS) &&
2818  !(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
2819  /* Set up the zone name for use by DNS */
2820  result = dhcp_isc_name(ddns_cb->zone_name, &zname0, &zname);
2821  if (result != ISC_R_SUCCESS) {
2822  log_error("Unable to build name for zone for "
2823  "fwd update: %s %s",
2824  ddns_cb->zone_name,
2825  isc_result_totext(result));
2826  goto cleanup;
2827  }
2828  /* If we have any addresses get them */
2829  if (!(ISC_LIST_EMPTY(ddns_cb->zone_server_list))) {
2830  zlist = &ddns_cb->zone_server_list;
2831  }
2832 
2833  /*
2834  * If we now have a zone try to get the key, NULL is okay,
2835  * having a key but not a tsec is odd so we warn.
2836  */
2837  /*sar*/
2838  /* should we do the warning if we have a key but no tsec? */
2839  if ((ddns_cb->zone != NULL) && (ddns_cb->zone->key != NULL)) {
2840  tsec_key = ddns_cb->zone->key->tsec_key;
2841  if (tsec_key == NULL) {
2842  log_error("No tsec for use with key %s",
2843  ddns_cb->zone->key->name);
2844  }
2845  }
2846  }
2847 
2848  /* We must have a name for the update list */
2849  /* Get a pointer to the ptrname to make things easier. */
2850  ptrname = (unsigned char *)ddns_cb->rev_name.data;
2851 
2852  if ((result = dhcp_isc_name(ptrname, &uname0, &uname))
2853  != ISC_R_SUCCESS) {
2854  log_error("Unable to build name for fwd update: %s %s",
2855  ptrname, isc_result_totext(result));
2856  goto cleanup;
2857  }
2858 
2859  /*
2860  * Allocate the various isc dns library structures we may require.
2861  * Allocating one blob avoids being halfway through the process
2862  * and being unable to allocate as well as making the free easy.
2863  */
2864  dataspace = isc_mem_get(dhcp_gbl_ctx.mctx, sizeof(*dataspace) * 2);
2865  if (dataspace == NULL) {
2866  log_error("Unable to allocate memory for fwd update");
2867  result = ISC_R_NOMEMORY;
2868  goto cleanup;
2869  }
2870 
2871  ISC_LIST_INIT(updatelist);
2872 
2873  /*
2874  * Construct the update list
2875  * We always delete what's currently there
2876  * Delete PTR RR.
2877  */
2878  result = make_dns_dataset(dns_rdataclass_any, dns_rdatatype_ptr,
2879  &dataspace[0], NULL, 0, 0);
2880  if (result != ISC_R_SUCCESS) {
2881  goto cleanup;
2882  }
2883  ISC_LIST_APPEND(uname->list, &dataspace[0].rdataset, link);
2884 
2885  /*
2886  * If we are updating the pointer we then add the new one
2887  * Add PTR RR.
2888  */
2889  if (ddns_cb->state == DDNS_STATE_ADD_PTR) {
2890  /*
2891  * Need to convert pointer into on the wire representation
2892  */
2893  if (MRns_name_pton((char *)ddns_cb->fwd_name.data,
2894  buf, 256) == -1) {
2895  goto cleanup;
2896  }
2897  buflen = 0;
2898  while (buf[buflen] != 0) {
2899  buflen += buf[buflen] + 1;
2900  }
2901  buflen++;
2902 
2903  result = make_dns_dataset(dns_rdataclass_in,
2904  dns_rdatatype_ptr,
2905  &dataspace[1],
2906  buf, buflen, ddns_cb->ttl);
2907  if (result != ISC_R_SUCCESS) {
2908  goto cleanup;
2909  }
2910  ISC_LIST_APPEND(uname->list, &dataspace[1].rdataset, link);
2911  }
2912 
2913  ISC_LIST_APPEND(updatelist, uname, link);
2914 
2915  /*sar*/
2916  /*
2917  * for now I'll cleanup the dataset immediately, it would be
2918  * more efficient to keep it around in case the signaturure failed
2919  * and we wanted to retry it.
2920  */
2921  /* send the message, cleanup and return the result */
2922  result = ddns_update((dns_client_t *)dhcp_gbl_ctx.dnsclient,
2923  dns_rdataclass_in, zname,
2924  NULL, &updatelist,
2925  zlist, tsec_key,
2926  DNS_CLIENTUPDOPT_ALLOWRUN,
2928  ddns_interlude, (void *)ddns_cb,
2929  &ddns_cb->transaction);
2930  if (result == ISC_R_FAMILYNOSUPPORT) {
2931  log_info("Unable to perform DDNS update, "
2932  "address family not supported");
2933  }
2934 
2935 #if defined (DEBUG_DNS_UPDATES)
2936  print_dns_status(DDNS_PRINT_OUTBOUND, ddns_cb, result);
2937 #endif
2938 
2939  cleanup:
2940 #if defined (DEBUG_DNS_UPDATES)
2941  if (result != ISC_R_SUCCESS) {
2942  log_info("DDNS: %s(%d): error in ddns_modify_ptr %s for %p",
2943  file, line, isc_result_totext(result), ddns_cb);
2944  }
2945 #endif
2946 
2947  if (dataspace != NULL) {
2948  isc_mem_put(dhcp_gbl_ctx.mctx, dataspace,
2949  sizeof(*dataspace) * 2);
2950  }
2951  return(result);
2952 }
2953 
2954 void
2955 ddns_cancel(dhcp_ddns_cb_t *ddns_cb, const char *file, int line) {
2956  ddns_cb->flags |= DDNS_ABORT;
2957  if (ddns_cb->transaction != NULL) {
2958  dns_client_cancelupdate((dns_clientupdatetrans_t *)
2959  ddns_cb->transaction);
2960  }
2961  ddns_cb->lease = NULL;
2962 
2963 #if defined (DEBUG_DNS_UPDATES)
2964  log_info("DDNS: %s(%d): cancelling transaction for %p",
2965  file, line, ddns_cb);
2966 #endif
2967 }
2968 
2969 #endif /* NSUPDATE */
2970 
2971 HASH_FUNCTIONS (dns_zone, const char *, struct dns_zone, dns_zone_hash_t,
2973 
2974 #if defined (NSUPDATE)
2975 #if defined (DEBUG_DNS_UPDATES)
2976 /* Defines a type for creating list of labeled integers */
2977 typedef struct {
2978  int val;
2979  char *name;
2980 } LabeledInt;
2981 
2982 char*
2983 ddns_state_name(int state) {
2984  static LabeledInt ints[] = {
2985  { DDNS_STATE_CLEANUP, "DDNS_STATE_CLEANUP" },
2986  { DDNS_STATE_ADD_FW_NXDOMAIN, "DDNS_STATE_ADD_FW_NXDOMAIN" },
2987  { DDNS_STATE_ADD_FW_YXDHCID, "DDNS_STATE_ADD_FW_YXDHCID" },
2988  { DDNS_STATE_ADD_PTR, "DDNS_STATE_ADD_PTR" },
2989  { DDNS_STATE_DSMM_FW_ADD3, "DDNS_STATE_DSMM_FW_ADD3" },
2990  { DDNS_STATE_REM_FW_YXDHCID, "DDNS_STATE_REM_FW_YXDHCID" },
2991  { DDNS_STATE_REM_FW_NXRR, "DDNS_STATE_FW_NXRR" },
2992  { DDNS_STATE_REM_PTR, "DDNS_STATE_REM_PTR" },
2993  { -1, "unknown" },
2994  };
2995 
2996  LabeledInt* li = ints;
2997  while (li->val != -1 && li->val != state) {
2998  ++li;
2999  }
3000 
3001  return (li->name);
3002 }
3003 
3004 int
3005 add_nstring(char **orig, char *max, char *add, int add_len) {
3006  if (*orig && (*orig + add_len < max)) {
3007  strncpy(*orig, add, add_len);
3008  *orig += add_len;
3009  **orig = 0;
3010  return (0);
3011  }
3012 
3013  return (-1);
3014 }
3015 
3016 int
3017 add_string(char **orig, char *max, char *add) {
3018  return (add_nstring(orig, max, add, strlen(add)));
3019 }
3020 
3021 /*
3022  * direction outbound (messages to the dns server)
3023  * inbound (messages from the dns server)
3024  * ddns_cb is the control block associated with the message
3025  * result is the result from the dns code. For outbound calls
3026  * it is from the call to pass the message to the dns library.
3027  * For inbound calls it is from the event returned by the library.
3028  *
3029  * For outbound messages we print whatever we think is interesting
3030  * from the control block.
3031  * For inbound messages we only print the transaction id pointer
3032  * and the result and expect that the user will match them up as
3033  * necessary. Note well: the transaction information is opaque to
3034  * us so we simply print the pointer to it. This should be sufficient
3035  * to match requests and replys in a short sequence but is awkward
3036  * when trying to use it for longer sequences.
3037  */
3038 void
3039 print_dns_status (int direction,
3040  struct dhcp_ddns_cb *ddns_cb,
3041  isc_result_t result)
3042 {
3043  char obuf[1024];
3044  char *s = obuf, *end = &obuf[sizeof(obuf)-2];
3045  char *en;
3046  const char *result_str;
3047  char ddns_address[
3048  sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
3049 
3050  if (direction == DDNS_PRINT_INBOUND) {
3051  log_info("DDNS reply: id ptr %p, result: %s",
3052  ddns_cb->transaction, isc_result_totext(result));
3053  return;
3054  }
3055 
3056  /*
3057  * To avoid having to figure out if any of the strings
3058  * aren't NULL terminated, just 0 the whole string
3059  */
3060  memset(obuf, 0, 1024);
3061 
3062  en = "DDNS request: id ptr ";
3063  if (s + strlen(en) + 16 < end) {
3064  sprintf(s, "%s%p", en, ddns_cb->transaction);
3065  s += strlen(s);
3066  } else {
3067  goto bailout;
3068  }
3069 
3070  en = ddns_state_name(ddns_cb->state);
3071 
3072  switch (ddns_cb->state) {
3078  strcpy(ddns_address, piaddr(ddns_cb->address));
3079  if (s + strlen(en) + strlen(ddns_address) +
3080  ddns_cb->fwd_name.len + 7 < end) {
3081  sprintf(s, " %s %s for %.*s", en, ddns_address,
3082  ddns_cb->fwd_name.len,
3083  ddns_cb->fwd_name.data);
3084  s += strlen(s);
3085  } else {
3086  goto bailout;
3087  }
3088  break;
3089 
3090  case DDNS_STATE_ADD_PTR:
3091  case DDNS_STATE_REM_PTR:
3092  if (s + strlen(en) + ddns_cb->fwd_name.len +
3093  ddns_cb->rev_name.len + 7 < end) {
3094  sprintf(s, " %s %.*s for %.*s", en,
3095  ddns_cb->fwd_name.len,
3096  ddns_cb->fwd_name.data,
3097  ddns_cb->rev_name.len,
3098  ddns_cb->rev_name.data);
3099  s += strlen(s);
3100  } else {
3101  goto bailout;
3102  }
3103  break;
3104 
3105  case DDNS_STATE_CLEANUP:
3106  default:
3107  if (s + strlen(en) < end) {
3108  sprintf(s, "%s", en);
3109  s += strlen(s);
3110  } else {
3111  goto bailout;
3112  }
3113  break;
3114  }
3115 
3116  en = " zone: ";
3117  if (s + strlen(en) + strlen((char *)ddns_cb->zone_name) < end) {
3118  sprintf(s, "%s%s", en, ddns_cb->zone_name);
3119  s += strlen(s);
3120  } else {
3121  goto bailout;
3122  }
3123 
3124  /* @todo replace with format that matches bind9 zone file */
3125  if (ddns_cb->dhcid_class == dns_rdatatype_dhcid) {
3126  char *idbuf = NULL;
3127  if (add_string(&s, end, "dhcid: [")) {
3128  goto bailout;
3129  }
3130 
3131  idbuf = buf_to_hex(ddns_cb->dhcid.data,
3132  ddns_cb->dhcid.len, MDL);
3133  if (idbuf) {
3134  int ret = add_string(&s, end, idbuf);
3135  dfree(idbuf, MDL);
3136  if (!ret) {
3137  goto bailout;
3138  }
3139  }
3140 
3141  if (add_string(&s, end, "]")) {
3142  goto bailout;
3143  }
3144  } else {
3145  /* 1st byte of a txt dhcid is length, so we skip printing it
3146  * In the event it's empty, we end up not adding anything */
3147  int skip_length_byte = (ddns_cb->dhcid.len > 0 ? 1 : 0);
3148  if (add_string (&s, end, "txt: [") ||
3149  add_nstring (&s, end,
3150  (char *)ddns_cb->dhcid.data + skip_length_byte,
3151  ddns_cb->dhcid.len - skip_length_byte) ||
3152  add_string (&s, end, "]")) {
3153  goto bailout;
3154  }
3155  }
3156 
3157  en = " ttl: ";
3158  if (s + strlen(en) + 10 < end) {
3159  sprintf(s, "%s%ld", en, ddns_cb->ttl);
3160  s += strlen(s);
3161  } else {
3162  goto bailout;
3163  }
3164 
3165  en = " result: ";
3166  result_str = isc_result_totext(result);
3167  if (s + strlen(en) + strlen(result_str) < end) {
3168  sprintf(s, "%s%s", en, result_str);
3169  s += strlen(s);
3170  } else {
3171  goto bailout;
3172  }
3173 
3174  bailout:
3175  /*
3176  * We either finished building the string or ran out
3177  * of space, print whatever we have in case it is useful
3178  */
3179  log_info("%s", obuf);
3180 
3181  return;
3182 }
3183 #endif /* DEBUG_DNS_UPDATES */
3184 #endif /* NSUPDATE */
#define RC_MISC
Definition: alloc.h:56
#define rc_register(file, line, reference, addr, refcnt, d, f)
Definition: alloc.h:88
int buffer_allocate(struct buffer **ptr, unsigned len, const char *file, int line)
Definition: alloc.c:679
void data_string_forget(struct data_string *data, const char *file, int line)
Definition: alloc.c:1339
int dns_zone_reference(struct dns_zone **ptr, struct dns_zone *bp, const char *file, int line)
Definition: alloc.c:1166
int dns_zone_allocate(struct dns_zone **ptr, const char *file, int line)
Definition: alloc.c:1134
void data_string_copy(struct data_string *dest, const struct data_string *src, const char *file, int line)
Definition: alloc.c:1323
int option_cache_allocate(struct option_cache **cptr, const char *file, int line)
Definition: alloc.c:630
int option_cache_dereference(struct option_cache **ptr, const char *file, int line)
Definition: options.c:2953
char * buf_to_hex(const unsigned char *s, unsigned len, const char *file, int line)
Definition: print.c:1372
void putUShort(unsigned char *, u_int32_t)
Definition: convert.c:86
void putUChar(unsigned char *, u_int32_t)
Definition: convert.c:102
void repudiate_zone(struct dns_zone **)
#define DNS_HASH_SIZE
Definition: dhcpd.h:140
#define DDNS_ABORT
Definition: dhcpd.h:1783
#define DDNS_GUARD_ID_MUST_MATCH
Definition: dhcpd.h:1787
#define DDNS_INCLUDE_RRSET
Definition: dhcpd.h:1779
#define DNS_ZONE_INACTIVE
Definition: dhcpd.h:1519
isc_result_t find_cached_zone(dhcp_ddns_cb_t *, int)
struct dhcp_ddns_cb dhcp_ddns_cb_t
void dhcid_tolease(struct data_string *, struct data_string *)
void ddns_cancel(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
#define DDNS_STATE_REM_FW_NXRR
Definition: dhcpd.h:1804
#define DDNS_STATE_ADD_FW_YXDHCID
Definition: dhcpd.h:1799
isc_result_t ddns_modify_fwd(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
#define DDNS_STATE_REM_PTR
Definition: dhcpd.h:1805
#define cur_time
Definition: dhcpd.h:2126
#define FIND_FORWARD
Definition: dhcpd.h:3218
#define DDNS_STATE_ADD_FW_NXDOMAIN
Definition: dhcpd.h:1798
#define DDNS_STATE_ADD_PTR
Definition: dhcpd.h:1800
isc_result_t dhcid_fromlease(struct data_string *, struct data_string *)
void ddns_cb_forget_zone(dhcp_ddns_cb_t *ddns_cb)
#define FIND_REVERSE
Definition: dhcpd.h:3219
#define DDNS_STATE_DSMM_FW_ADD3
Definition: dhcpd.h:1801
void trace_ddns_init(void)
#define DDNS_STATE_REM_FW_YXDHCID
Definition: dhcpd.h:1803
void forget_zone(struct dns_zone **)
#define DDNS_PRINT_OUTBOUND
Definition: dhcpd.h:1812
const char int line
Definition: dhcpd.h:3802
isc_result_t ddns_modify_ptr(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
#define DDNS_STATE_CLEANUP
Definition: dhcpd.h:1796
char * ddns_state_name(int state)
void print_dns_status(int, struct dhcp_ddns_cb *, isc_result_t)
#define DDNS_PRINT_INBOUND
Definition: dhcpd.h:1811
#define DDNS_OTHER_GUARD_IS_DYNAMIC
Definition: dhcpd.h:1788
int get_dhcid(dhcp_ddns_cb_t *, int, const u_int8_t *, unsigned)
#define DDNS_CONFLICT_DETECTION
Definition: dhcpd.h:1780
dhcp_ddns_cb_t * ddns_cb_alloc(const char *file, int line)
#define DDNS_STATE_REM_FW_DSMM_OTHER
Definition: dhcpd.h:1806
void ddns_cb_free(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
void cleanup(void)
const char * file
Definition: dhcpd.h:3802
#define DDNS_DUAL_STACK_MIXED_MODE
Definition: dhcpd.h:1786
struct server_list * servers
struct dhcp_ddns_rdata dhcp_ddns_data_t
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
isc_result_t dns_zone_lookup(struct dns_zone **zone, const char *name)
Definition: dns.c:665
isc_result_t remove_dns_zone(struct dns_zone *zone)
Definition: dns.c:625
isc_result_t enter_dns_zone(struct dns_zone *zone)
Definition: dns.c:640
int dns_zone_dereference(struct dns_zone **ptr, const char *file, int line)
Definition: dns.c:698
dns_zone_hash_t * dns_zone_hash
Definition: dns.c:136
unsigned do_case_hash(const void *, unsigned, unsigned)
Definition: hash.c:240
#define HASH_FUNCTIONS(name, bufarg, type, hashtype, ref, deref, hasher)
Definition: hash.h:89
const char * piaddr(const struct iaddr addr)
Definition: inet.c:579
isc_result_t dhcp_isc_name(unsigned char *namestr, dns_fixedname_t *namefix, dns_name_t **name)
Definition: isclib.c:313
dhcp_context_t dhcp_gbl_ctx
Definition: isclib.c:33
#define DHCP_MAXNS
Definition: isclib.h:115
#define ISC_R_SUCCESS
#define NS_DEFAULTPORT
Definition: nameser.h:86
int MRns_name_pton(const char *src, u_char *dst, size_t dstsiz)
Definition: ns_name.c:174
#define MDL
Definition: omapip.h:567
void * dmalloc(size_t, const char *, int)
Definition: alloc.c:57
void dfree(void *, const char *, int)
Definition: alloc.c:145
int log_error(const char *,...) __attribute__((__format__(__printf__
int int log_info(const char *,...) __attribute__((__format__(__printf__
#define DHCP_R_INVALIDARG
Definition: result.h:49
char * name
Definition: omapip.h:149
dns_tsec_t * tsec_key
Definition: omapip.h:152
Definition: tree.h:60
unsigned char data[1]
Definition: tree.h:62
struct buffer * buffer
Definition: tree.h:77
const unsigned char * data
Definition: tree.h:78
int terminated
Definition: tree.h:80
unsigned len
Definition: tree.h:79
isc_mem_t * mctx
Definition: isclib.h:95
isc_task_t * task
Definition: isclib.h:100
void * lease
Definition: dhcpd.h:1842
dns_rdataclass_t other_dhcid_class
Definition: dhcpd.h:1849
int state
Definition: dhcpd.h:1836
isc_sockaddr_t zone_addrs[DHCP_MAXNS]
Definition: dhcpd.h:1830
struct data_string fwd_name
Definition: dhcpd.h:1820
void * transaction
Definition: dhcpd.h:1845
u_int16_t flags
Definition: dhcpd.h:1834
struct ia_xx * fixed6_ia
Definition: dhcpd.h:1851
dns_rdataclass_t dhcid_class
Definition: dhcpd.h:1848
struct dns_zone * zone
Definition: dhcpd.h:1832
ddns_action_t cur_func
Definition: dhcpd.h:1837
struct iaddr address
Definition: dhcpd.h:1823
struct data_string rev_name
Definition: dhcpd.h:1821
unsigned char zone_name[DHCP_MAXDNS_WIRE]
Definition: dhcpd.h:1828
unsigned long ttl
Definition: dhcpd.h:1826
struct dhcp_ddns_cb * next_op
Definition: dhcpd.h:1839
isc_sockaddrlist_t zone_server_list
Definition: dhcpd.h:1829
int address_type
Definition: dhcpd.h:1824
struct data_string dhcid
Definition: dhcpd.h:1822
dns_rdatalist_t rdatalist
Definition: dns.c:151
dns_rdataset_t rdataset
Definition: dns.c:152
dns_rdata_t rdata
Definition: dns.c:150
struct option_cache * secondary6
Definition: dhcpd.h:1527
struct auth_key * key
Definition: dhcpd.h:1528
int refcnt
Definition: dhcpd.h:1521
u_int16_t flags
Definition: dhcpd.h:1529
struct option_cache * secondary
Definition: dhcpd.h:1525
struct option_cache * primary
Definition: dhcpd.h:1524
struct option_cache * primary6
Definition: dhcpd.h:1526
char * name
Definition: dhcpd.h:1523
TIME timeout
Definition: dhcpd.h:1522
unsigned char iabuf[16]
Definition: inet.h:33
unsigned len
Definition: inet.h:32
Definition: ip.h:47
struct data_string data
Definition: dhcpd.h:390
unsigned len
Definition: trace.h:76
const char * buf
Definition: trace.h:75
int trace_record(void)
isc_result_t trace_get_packet(trace_type_t **, unsigned *, char **)
trace_type_t * trace_type_register(const char *, void *, void(*)(trace_type_t *, unsigned, char *), void(*)(trace_type_t *), const char *, int)
isc_result_t trace_write_packet_iov(trace_type_t *, int, trace_iov_t *, const char *, int)
int trace_playback(void)
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
struct binding_scope * global_scope
Definition: tree.c:38