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