ISC DHCP  4.4.2-P1
A reference DHCPv4 and DHCPv6 implementation
ddns.c
Go to the documentation of this file.
1 /* ddns.c
2 
3  Dynamic DNS updates. */
4 
5 /*
6  *
7  * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
8  * Copyright (c) 2000-2003 by Internet Software Consortium
9  *
10  * This Source Code Form is subject to the terms of the Mozilla Public
11  * License, v. 2.0. If a copy of the MPL was not distributed with this
12  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  *
22  * Internet Systems Consortium, Inc.
23  * 950 Charter Street
24  * Redwood City, CA 94063
25  * <info@isc.org>
26  * https://www.isc.org/
27  *
28  * This software has been donated to Internet Systems Consortium
29  * by Damien Neil of Nominum, Inc.
30  *
31  * To learn more about Internet Systems Consortium, see
32  * ``https://www.isc.org/''.
33  */
34 
35 #include "dhcpd.h"
36 #include <dns/result.h>
37 
38 char *ddns_standard_tag = "ddns-dhcid";
39 char *ddns_interim_tag = "ddns-txt";
40 
41 #ifdef NSUPDATE
42 
43 #if defined (DEBUG_DNS_UPDATES)
44 static char* dump_ddns_cb_func(void *func);
45 static char* dump_ddns_cb (dhcp_ddns_cb_t *ddns_cb);
46 
48 #endif
49 
50 static void ddns_fwd_srv_connector(struct lease *lease,
51  struct iasubopt *lease6,
52  struct binding_scope **inscope,
53  dhcp_ddns_cb_t *ddns_cb,
54  isc_result_t eresult);
55 
56 static void copy_conflict_flags(u_int16_t *target, u_int16_t source);
57 
58 static void ddns_fwd_srv_add3(dhcp_ddns_cb_t *ddns_cb, isc_result_t eresult);
59 
60 /*
61  * ddns_cb_free() is part of common lib, while ia_* routines are known
62  * only in the server. Use this wrapper instead of ddns_cb_free() directly.
63  */
64 static void
65 destroy_ddns_cb(struct dhcp_ddns_cb *ddns_cb, char* file, int line) {
66  if (!ddns_cb) {
67  return;
68  }
69 
70  if (ddns_cb->fixed6_ia) {
71  ia_dereference(&ddns_cb->fixed6_ia, MDL);
72  }
73 
74  ddns_cb_free(ddns_cb, file, line);
75 
76 }
77 
78 
79 /* DN: No way of checking that there is enough space in a data_string's
80  buffer. Be certain to allocate enough!
81  TL: This is why the expression evaluation code allocates a *new*
82  data_string. :') */
83 static void data_string_append (struct data_string *ds1,
84  struct data_string *ds2)
85 {
86  memcpy (ds1 -> buffer -> data + ds1 -> len,
87  ds2 -> data,
88  ds2 -> len);
89  ds1 -> len += ds2 -> len;
90 }
91 
92 
93 /* Determine what, if any, forward and reverse updates need to be
94  * performed, and carry them through.
95  */
96 int
97 ddns_updates(struct packet *packet, struct lease *lease, struct lease *old,
98  struct iasubopt *lease6, struct iasubopt *old6,
99  struct option_state *options)
100 {
101  unsigned long ddns_ttl = DEFAULT_DDNS_TTL;
102  struct data_string ddns_hostname;
103  struct data_string ddns_domainname;
104  struct data_string old_ddns_fwd_name;
105  struct data_string ddns_fwd_name;
106  struct data_string ddns_dhcid;
107  struct binding_scope **scope = NULL;
108  struct data_string d1;
109  struct option_cache *oc;
110  int s1, s2;
111  int result = 0;
112  int server_updates_a = 1;
113  struct buffer *bp = (struct buffer *)0;
114  int ignorep = 0, client_ignorep = 0;
115  int rev_name_len;
116  int i;
117 
118  dhcp_ddns_cb_t *ddns_cb;
119  int do_remove = 0;
120 
123  return (0);
124 
125  /*
126  * sigh, I want to cancel any previous udpates before we do anything
127  * else but this means we need to deal with the lease vs lease6
128  * question twice.
129  * If there is a ddns request already outstanding cancel it.
130  */
131 
132  if (lease != NULL) {
133  if ((old != NULL) && (old->ddns_cb != NULL)) {
134  ddns_cancel(old->ddns_cb, MDL);
135  old->ddns_cb = NULL;
136  }
137  } else if (lease6 != NULL) {
138  if ((old6 != NULL) && (old6->ddns_cb != NULL)) {
139  ddns_cancel(old6->ddns_cb, MDL);
140  old6->ddns_cb = NULL;
141  }
142  } else {
143  log_fatal("Impossible condition at %s:%d.", MDL);
144  /* Silence compiler warnings. */
145  result = 0;
146  return(0);
147  }
148 
149  /* allocate our control block */
150  ddns_cb = ddns_cb_alloc(MDL);
151  if (ddns_cb == NULL) {
152  return(0);
153  }
154  /*
155  * Assume that we shall update both the A and ptr records and,
156  * as this is an update, set the active flag
157  */
158  ddns_cb->flags = DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR |
160 
161  /*
162  * For v4 we flag static leases so we don't try
163  * and manipulate the lease later. For v6 we don't
164  * get static leases and don't need to flag them.
165  */
166  if (lease != NULL) {
167  scope = &(lease->scope);
168  ddns_cb->address = lease->ip_addr;
169  if (lease->flags & STATIC_LEASE)
170  ddns_cb->flags |= DDNS_STATIC_LEASE;
171  } else if (lease6 != NULL) {
172  scope = &(lease6->scope);
173  memcpy(ddns_cb->address.iabuf, lease6->addr.s6_addr, 16);
174  ddns_cb->address.len = 16;
175 
176  if (lease6->static_lease) {
177  /* We add a reference to keep ia && iasubopt alive
178  * since static v6s are retained anywhere */
179  ia_reference(&ddns_cb->fixed6_ia, lease6->ia, MDL);
180  ddns_cb->flags |= DDNS_STATIC_LEASE;
181  }
182  }
183 
184  memset (&d1, 0, sizeof(d1));
185  memset (&ddns_hostname, 0, sizeof (ddns_hostname));
186  memset (&ddns_domainname, 0, sizeof (ddns_domainname));
187  memset (&old_ddns_fwd_name, 0, sizeof (ddns_fwd_name));
188  memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name));
189  memset (&ddns_dhcid, 0, sizeof (ddns_dhcid));
190 
191  /* If we are allowed to accept the client's update of its own A
192  record, see if the client wants to update its own A record. */
193  if (!(oc = lookup_option(&server_universe, options,
194  SV_CLIENT_UPDATES)) ||
195  evaluate_boolean_option_cache(&client_ignorep, packet, lease, NULL,
196  packet->options, options, scope,
197  oc, MDL)) {
198  /* If there's no fqdn.no-client-update or if it's
199  nonzero, don't try to use the client-supplied
200  XXX */
201  if (!(oc = lookup_option (&fqdn_universe, packet -> options,
202  FQDN_SERVER_UPDATE)) ||
204  NULL, packet->options,
205  options, scope, oc, MDL))
206  goto noclient;
207  /* Win98 and Win2k will happily claim to be willing to
208  update an unqualified domain name. */
209  if (!(oc = lookup_option (&fqdn_universe, packet -> options,
210  FQDN_DOMAINNAME)))
211  goto noclient;
212  if (!(oc = lookup_option (&fqdn_universe, packet -> options,
213  FQDN_FQDN)) ||
214  !evaluate_option_cache(&ddns_fwd_name, packet, lease,
215  NULL, packet->options,
216  options, scope, oc, MDL))
217  goto noclient;
218  ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
219  server_updates_a = 0;
220  goto client_updates;
221  }
222  noclient:
223  /* If do-forward-updates is disabled, this basically means don't
224  do an update unless the client is participating, so if we get
225  here and do-forward-updates is disabled, we can stop. */
226  if ((oc = lookup_option (&server_universe, options,
229  NULL, packet->options,
230  options, scope, oc, MDL)) {
231  goto out;
232  }
233 
234  /* If it's a static lease, then don't do the DNS update unless we're
235  specifically configured to do so. If the client asked to do its
236  own update and we allowed that, we don't do this test. */
237  /* XXX: note that we cannot detect static DHCPv6 leases. */
238  if ((lease != NULL) && (lease->flags & STATIC_LEASE)) {
239  if (!(oc = lookup_option(&server_universe, options,
242  NULL, packet->options,
243  options, scope, oc, MDL))
244  goto out;
245  }
246 
247  /*
248  * Compute the name for the A record.
249  */
251  if (oc)
252  s1 = evaluate_option_cache(&ddns_hostname, packet, lease,
253  NULL, packet->options,
254  options, scope, oc, MDL);
255  else
256  s1 = 0;
257 
258  /* If we don't have a host name based on ddns-hostname then use
259  * the host declaration name if there is one and use-host-decl-names
260  * is turned on. */
261  if ((s1 == 0) && (lease && lease->host && lease->host->name)) {
262  oc = lookup_option(&server_universe, options,
265  NULL, packet->options,
266  options, scope, oc, MDL)) {
267  s1 = ((data_string_new(&ddns_hostname,
268  lease->host->name,
269  strlen(lease->host->name),
270  MDL) && ddns_hostname.len > 0));
271  }
272  }
273 
275  if (oc)
276  s2 = evaluate_option_cache(&ddns_domainname, packet, lease,
277  NULL, packet->options,
278  options, scope, oc, MDL);
279  else
280  s2 = 0;
281 
282  if (s1 && s2) {
283  if (ddns_hostname.len + ddns_domainname.len > 253) {
284  log_error ("ddns_update: host.domain name too long");
285 
286  goto out;
287  }
288 
289  if (buffer_allocate (&ddns_fwd_name.buffer,
290  ddns_hostname.len +
291  ddns_domainname.len + 2, MDL)) {
292  ddns_fwd_name.data = ddns_fwd_name.buffer->data;
293  data_string_append (&ddns_fwd_name, &ddns_hostname);
294  ddns_fwd_name.buffer->data[ddns_fwd_name.len] = '.';
295  ddns_fwd_name.len++;
296  data_string_append (&ddns_fwd_name, &ddns_domainname);
297  ddns_fwd_name.buffer->data[ddns_fwd_name.len] ='\0';
298  ddns_fwd_name.terminated = 1;
299  }
300  }
301  client_updates:
302 
303  /* See if there's a name already stored on the lease. */
304  if (find_bound_string(&old_ddns_fwd_name, *scope, "ddns-fwd-name")) {
305  /* If there is, see if it's different. */
306  if (old_ddns_fwd_name.len != ddns_fwd_name.len ||
307  memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data,
308  old_ddns_fwd_name.len)) {
309  /*
310  * If the name is different, mark the old record
311  * for deletion and continue getting the new info.
312  */
313  do_remove = 1;
314  goto in;
315  }
316 
317 #if defined (DDNS_UPDATE_SLOW_TRANSITION)
318  /*
319  * If the slow transition code is enabled check to see
320  * if the stored type (standard or interim doesn't
321  * match the type currently in use. If it doesn't
322  * try to remove and replace the DNS record
323  */
325  find_bound_string(&ddns_dhcid, *scope, ddns_interim_tag)) ||
327  find_bound_string(&ddns_dhcid, *scope, ddns_standard_tag))) {
328  data_string_forget(&ddns_dhcid, MDL);
329  do_remove = 1;
330  goto in;
331  }
332 #endif
333 
334  /* See if the administrator wants to do updates even
335  in cases where the update already appears to have been
336  done. */
337  if (!(oc = lookup_option(&server_universe, options,
340  NULL, packet->options,
341  options, scope, oc, MDL)) {
342  result = 1;
343  goto noerror;
344  }
345  /* If there's no "ddns-fwd-name" on the lease record, see if
346  * there's a ddns-client-fqdn indicating a previous client
347  * update (if it changes, we need to adjust the PTR).
348  */
349  } else if (find_bound_string(&old_ddns_fwd_name, *scope,
350  "ddns-client-fqdn")) {
351  /* If the name is not different, no need to update
352  the PTR record. */
353  if (old_ddns_fwd_name.len == ddns_fwd_name.len &&
354  !memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data,
355  old_ddns_fwd_name.len) &&
356  (!(oc = lookup_option(&server_universe, options,
359  NULL, packet->options,
360  options, scope, oc, MDL))) {
361  goto noerror;
362  }
363  }
364  in:
365 
366  /* If we don't have a name that the client has been assigned, we
367  can just skip all this. */
368 
369  if ((!ddns_fwd_name.len) || (ddns_fwd_name.len > 255)) {
370  if (ddns_fwd_name.len > 255) {
371  log_error ("client provided fqdn: too long");
372  }
373 
374  /* If desired do the removals */
375  if (do_remove != 0) {
376  (void) ddns_removals(lease, lease6, NULL, ISC_TRUE);
377  }
378  goto out;
379  }
380 
381  /*
382  * Compute the RR TTL.
383  *
384  * We have two ways of computing the TTL.
385  * The old behavior was to allow for the customer to set up
386  * the option or to default things. For v4 this was 1/2
387  * of the lease time, for v6 this was DEFAULT_DDNS_TTL.
388  * The new behavior continues to allow the customer to set
389  * up an option but the defaults are a little different.
390  * We now use 1/2 of the (preferred) lease time for both
391  * v4 and v6 and cap them at a maximum value.
392  * If the customer chooses to use an experession that references
393  * part of the lease the v6 value will be the default as there
394  * isn't a lease available for v6.
395  */
396 
397  ddns_ttl = DEFAULT_DDNS_TTL;
398  if (lease != NULL) {
399  if (lease->ends <= cur_time) {
400  ddns_ttl = 0;
401  } else {
402  ddns_ttl = (lease->ends - cur_time)/2;
403  }
404  }
405 #ifndef USE_OLD_DDNS_TTL
406  else if (lease6 != NULL) {
407  ddns_ttl = lease6->prefer/2;
408  }
409 
410  if (ddns_ttl > MAX_DEFAULT_DDNS_TTL) {
411  ddns_ttl = MAX_DEFAULT_DDNS_TTL;
412  }
413 #endif
414 
415  if ((oc = lookup_option(&server_universe, options, SV_DDNS_TTL))) {
416  if (evaluate_option_cache(&d1, packet, lease, NULL,
417  packet->options, options,
418  scope, oc, MDL)) {
419  if (d1.len == sizeof (u_int32_t))
420  ddns_ttl = getULong (d1.data);
421  data_string_forget (&d1, MDL);
422  }
423  }
424 
425  ddns_cb->ttl = ddns_ttl;
426 
427  /*
428  * Compute the reverse IP name, starting with the domain name.
429  */
431  if (oc)
432  s1 = evaluate_option_cache(&d1, packet, lease, NULL,
433  packet->options, options,
434  scope, oc, MDL);
435  else
436  s1 = 0;
437 
438  /*
439  * Figure out the length of the part of the name that depends
440  * on the address.
441  */
442  if (ddns_cb->address.len == 4) {
443  char buf[17];
444  /* XXX: WOW this is gross. */
445  rev_name_len = snprintf(buf, sizeof(buf), "%u.%u.%u.%u.",
446  ddns_cb->address.iabuf[3] & 0xff,
447  ddns_cb->address.iabuf[2] & 0xff,
448  ddns_cb->address.iabuf[1] & 0xff,
449  ddns_cb->address.iabuf[0] & 0xff) + 1;
450 
451  if (s1) {
452  rev_name_len += d1.len;
453 
454  if (rev_name_len > 255) {
455  log_error("ddns_update: Calculated rev domain "
456  "name too long.");
457  s1 = 0;
458  data_string_forget(&d1, MDL);
459  }
460  }
461  } else if (ddns_cb->address.len == 16) {
462  /*
463  * IPv6 reverse names are always the same length, with
464  * 32 hex characters separated by dots.
465  */
466  rev_name_len = sizeof("0.1.2.3.4.5.6.7."
467  "8.9.a.b.c.d.e.f."
468  "0.1.2.3.4.5.6.7."
469  "8.9.a.b.c.d.e.f."
470  "ip6.arpa.");
471 
472  /* Set s1 to make sure we gate into updates. */
473  s1 = 1;
474  } else {
475  log_fatal("invalid address length %d", ddns_cb->address.len);
476  /* Silence compiler warnings. */
477  return 0;
478  }
479 
480  /* See if we are configured NOT to do reverse ptr updates */
481  if ((oc = lookup_option(&server_universe, options,
483  !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
484  packet->options, options,
485  scope, oc, MDL)) {
486  ddns_cb->flags &= ~DDNS_UPDATE_PTR;
487  }
488 
489  if (s1) {
490  if (buffer_allocate(&ddns_cb->rev_name.buffer,
491  rev_name_len, MDL)) {
492  struct data_string *rname = &ddns_cb->rev_name;
493  rname->data = rname->buffer->data;
494 
495  if (ddns_cb->address.len == 4) {
496  rname->len =
497  sprintf((char *)rname->buffer->data,
498  "%u.%u.%u.%u.",
499  ddns_cb->address.iabuf[3] & 0xff,
500  ddns_cb->address.iabuf[2] & 0xff,
501  ddns_cb->address.iabuf[1] & 0xff,
502  ddns_cb->address.iabuf[0] & 0xff);
503 
504  /*
505  * d1.data may be opaque, garbage bytes, from
506  * user (mis)configuration.
507  */
508  data_string_append(rname, &d1);
509  rname->buffer->data[rname->len] = '\0';
510  } else if (ddns_cb->address.len == 16) {
511  char *p = (char *)&rname->buffer->data;
512  unsigned char *a = ddns_cb->address.iabuf + 15;
513  for (i=0; i<16; i++) {
514  sprintf(p, "%x.%x.",
515  (*a & 0xF), ((*a >> 4) & 0xF));
516  p += 4;
517  a -= 1;
518  }
519  strcat(p, "ip6.arpa.");
520  rname->len = strlen((const char *)rname->data);
521  }
522 
523  rname->terminated = 1;
524  }
525 
526  if (d1.data != NULL)
527  data_string_forget(&d1, MDL);
528  }
529 
530  /*
531  * copy the string now so we can pass it to the dhcid routines
532  * via the ddns_cb pointer
533  */
534  data_string_copy(&ddns_cb->fwd_name, &ddns_fwd_name, MDL);
535 
536  /*
537  * If we are updating the A record, compute the DHCID value.
538  * We have two options for computing the DHCID value, the older
539  * interim version and the newer standard version. The interim
540  * has some issues but is left as is to avoid compatibility issues.
541  *
542  * We select the type of DHCID to construct and the information to
543  * use for the digest based on 4701 section 3.3
544  */
545  if ((ddns_cb->flags & DDNS_UPDATE_ADDR) != 0) {
546  int ddns_type;
547  int ddns_len;
549  /* The standard style */
550  ddns_cb->lease_tag = ddns_standard_tag;
551  ddns_cb->dhcid_class = dns_rdatatype_dhcid;
552  ddns_cb->other_dhcid_class = dns_rdatatype_txt;
553  ddns_type = 1;
554  ddns_len = 4;
555  } else {
556  /* The older interim style */
557  ddns_cb->lease_tag = ddns_interim_tag;
558  ddns_cb->dhcid_class = dns_rdatatype_txt;
559  ddns_cb->other_dhcid_class = dns_rdatatype_dhcid;
560  /* for backwards compatibility */
561  ddns_type = DHO_DHCP_CLIENT_IDENTIFIER;
562  /* IAID incorrectly included */
563  ddns_len = 0;
564  }
565 
566 
567  if (lease6 != NULL) {
568  if (lease6->ia->iaid_duid.len < ddns_len)
569  goto badfqdn;
570  result = get_dhcid(ddns_cb, 2,
571  lease6->ia->iaid_duid.data + ddns_len,
572  lease6->ia->iaid_duid.len - ddns_len);
573  } else if ((lease != NULL) &&
574  (lease->uid != NULL) &&
575  (lease->uid_len != 0)) {
576  /* If this is standard check for an RFC 4361
577  * compliant client identifier
578  */
580  (lease->uid[0] == 255)) {
581  if (lease->uid_len < 5)
582  goto badfqdn;
583  result = get_dhcid(ddns_cb, 2,
584  lease->uid + 5,
585  lease->uid_len - 5);
586  } else {
587  result = get_dhcid(ddns_cb, ddns_type,
588  lease->uid,
589  lease->uid_len);
590  }
591  } else if (lease != NULL)
592  result = get_dhcid(ddns_cb, 0,
595  else
596  log_fatal("Impossible condition at %s:%d.", MDL);
597 
598  if (!result)
599  goto badfqdn;
600  }
601 
602  /*
603  * Perform updates.
604  */
605 
606  if (ddns_cb->flags & DDNS_UPDATE_ADDR) {
607  copy_conflict_flags(&ddns_cb->flags, ddns_conflict_mask);
608  }
609 
610  /*
611  * Previously if we failed during the removal operations
612  * we skipped the fqdn option processing. I'm not sure
613  * if we want to continue with that if we fail before sending
614  * the ddns messages. Currently we don't.
615  */
616  if (do_remove) {
617  /*
618  * We should log a more specific error closer to the actual
619  * error if we want one. ddns_removal failure not logged here.
620  */
621  (void) ddns_removals(lease, lease6, ddns_cb, ISC_TRUE);
622  }
623  else {
624  ddns_fwd_srv_connector(lease, lease6, scope, ddns_cb,
625  ISC_R_SUCCESS);
626  }
627  ddns_cb = NULL;
628 
629  noerror:
630  /*
631  * If fqdn-reply option is disabled in dhcpd.conf, then don't
632  * send the client an FQDN option at all, even if one was requested.
633  * (WinXP clients allegedly misbehave if the option is present,
634  * refusing to handle PTR updates themselves).
635  */
636  if ((oc = lookup_option (&server_universe, options, SV_FQDN_REPLY)) &&
637  !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
638  packet->options, options,
639  scope, oc, MDL)) {
640  goto badfqdn;
641 
642  /* If we're ignoring client updates, then we tell a sort of 'white
643  * lie'. We've already updated the name the server wants (per the
644  * config written by the server admin). Now let the client do as
645  * it pleases with the name they supplied (if any).
646  *
647  * We only form an FQDN option this way if the client supplied an
648  * FQDN option that had FQDN_SERVER_UPDATE set false.
649  */
650  } else if (client_ignorep &&
652  FQDN_SERVER_UPDATE)) &&
653  !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
654  packet->options, options,
655  scope, oc, MDL)) {
657  if (oc && evaluate_option_cache(&d1, packet, lease, NULL,
658  packet->options, options,
659  scope, oc, MDL)) {
660  if (d1.len == 0 ||
661  !buffer_allocate(&bp, d1.len + 5, MDL))
662  goto badfqdn;
663 
664  /* Server pretends it is not updating. */
665  bp->data[0] = 0;
666  if (!save_option_buffer(&fqdn_universe, options,
667  bp, &bp->data[0], 1,
668  FQDN_SERVER_UPDATE, 0))
669  goto badfqdn;
670 
671  /* Client is encouraged to update. */
672  bp->data[1] = 0;
673  if (!save_option_buffer(&fqdn_universe, options,
674  bp, &bp->data[1], 1,
676  goto badfqdn;
677 
678  /* Use the encoding of client's FQDN option. */
680  FQDN_ENCODED);
681  if (oc &&
683  lease, NULL,
684  packet->options,
685  options, scope,
686  oc, MDL))
687  bp->data[2] = 1; /* FQDN is encoded. */
688  else
689  bp->data[2] = 0; /* FQDN is not encoded. */
690 
691  if (!save_option_buffer(&fqdn_universe, options,
692  bp, &bp->data[2], 1,
693  FQDN_ENCODED, 0))
694  goto badfqdn;
695 
696  /* Current FQDN drafts indicate 255 is mandatory. */
697  bp->data[3] = 255;
698  if (!save_option_buffer(&fqdn_universe, options,
699  bp, &bp->data[3], 1,
700  FQDN_RCODE1, 0))
701  goto badfqdn;
702 
703  bp->data[4] = 255;
704  if (!save_option_buffer(&fqdn_universe, options,
705  bp, &bp->data[4], 1,
706  FQDN_RCODE2, 0))
707  goto badfqdn;
708 
709  /* Copy in the FQDN supplied by the client. Note well
710  * that the format of this option in the cache is going
711  * to be in text format. If the fqdn supplied by the
712  * client is encoded, it is decoded into the option
713  * cache when parsed out of the packet. It will be
714  * re-encoded when the option is assembled to be
715  * transmitted if the client elects that encoding.
716  */
717  memcpy(&bp->data[5], d1.data, d1.len);
718  if (!save_option_buffer(&fqdn_universe, options,
719  bp, &bp->data[5], d1.len,
720  FQDN_FQDN, 0))
721  goto badfqdn;
722 
723  data_string_forget(&d1, MDL);
724  }
725  /* Set up the outgoing FQDN option if there was an incoming
726  * FQDN option. If there's a valid FQDN option, there MUST
727  * be an FQDN_SERVER_UPDATES suboption, it's part of the fixed
728  * length head of the option contents, so we test the latter
729  * to detect the presence of the former.
730  */
731  } else if ((oc = lookup_option(&fqdn_universe, packet->options,
732  FQDN_ENCODED)) &&
733  buffer_allocate(&bp, ddns_fwd_name.len + 5, MDL)) {
734  bp -> data [0] = server_updates_a;
735  if (!save_option_buffer(&fqdn_universe, options,
736  bp, &bp->data [0], 1,
737  FQDN_SERVER_UPDATE, 0))
738  goto badfqdn;
739  bp -> data [1] = server_updates_a;
740  if (!save_option_buffer(&fqdn_universe, options,
741  bp, &bp->data [1], 1,
743  goto badfqdn;
744 
745  /* Do the same encoding the client did. */
747  NULL, packet->options,
748  options, scope, oc, MDL))
749  bp -> data [2] = 1;
750  else
751  bp -> data [2] = 0;
752  if (!save_option_buffer(&fqdn_universe, options,
753  bp, &bp->data [2], 1,
754  FQDN_ENCODED, 0))
755  goto badfqdn;
756  bp -> data [3] = 255;//isc_rcode_to_ns (rcode1);
757  if (!save_option_buffer(&fqdn_universe, options,
758  bp, &bp->data [3], 1,
759  FQDN_RCODE1, 0))
760  goto badfqdn;
761  bp -> data [4] = 255;//isc_rcode_to_ns (rcode2);
762  if (!save_option_buffer(&fqdn_universe, options,
763  bp, &bp->data [4], 1,
764  FQDN_RCODE2, 0))
765  goto badfqdn;
766  if (ddns_fwd_name.len) {
767  memcpy (&bp -> data [5],
768  ddns_fwd_name.data, ddns_fwd_name.len);
769  if (!save_option_buffer(&fqdn_universe, options,
770  bp, &bp->data [5],
771  ddns_fwd_name.len,
772  FQDN_FQDN, 0))
773  goto badfqdn;
774  }
775  }
776 
777  badfqdn:
778  out:
779  /*
780  * Final cleanup.
781  */
782  if (ddns_cb != NULL) {
783  destroy_ddns_cb(ddns_cb, MDL);
784  }
785 
786  data_string_forget(&d1, MDL);
787  data_string_forget(&ddns_hostname, MDL);
788  data_string_forget(&ddns_domainname, MDL);
789  data_string_forget(&old_ddns_fwd_name, MDL);
790  data_string_forget(&ddns_fwd_name, MDL);
791  if (bp)
792  buffer_dereference(&bp, MDL);
793 
794  return result;
795 }
796 
797 /*%<
798  * Utility function to update text strings within a lease.
799  *
800  * The first issue is to find the proper scope. Sometimes we shall be
801  * called with a pointer to the scope in other cases we need to find
802  * the proper lease and then get the scope. Once we have the scope we update
803  * the proper strings, as indicated by the state value in the control block.
804  * Lastly, if we needed to find the scope we write it out, if we used a
805  * scope that was passed as an argument we don't write it, assuming that
806  * our caller (or his ...) will do the write.
807  *
808  *\li ddns_cb - the control block for the DDNS request
809  *
810  *\li inscope - a pointer to the scope to update. This may be NULL
811  * in which case we use the control block to find the lease and
812  * then the scope.
813  *
814  * Returns
815  *\li ISC_R_SUCCESS
816  *
817  *\li ISC_R_FAILURE - The routine was unable to find an expected scope.
818  * In some cases (static and inactive leases) we don't expect a scope
819  * and return success.
820  */
821 
822 isc_result_t
823 ddns_update_lease_text(dhcp_ddns_cb_t *ddns_cb,
824  struct binding_scope **inscope)
825 {
826  struct binding_scope **scope = NULL;
827  struct lease *lease = NULL;
828  struct iasubopt *lease6 = NULL;
829  struct ipv6_pool *pool = NULL;
830  struct in6_addr addr;
831  struct data_string lease_dhcid;
832 
833  /*
834  * If the lease was static (for a fixed address)
835  * we don't need to do any work.
836  */
837  if (ddns_cb->flags & DDNS_STATIC_LEASE)
838  return (ISC_R_SUCCESS);
839 
840  /*
841  * If we are processing an expired or released v6 lease
842  * or some types of v4 leases we don't actually have a
843  * scope to update
844  */
845  if ((ddns_cb->flags & DDNS_ACTIVE_LEASE) == 0)
846  return (ISC_R_SUCCESS);
847 
848  if (inscope != NULL) {
849  scope = inscope;
850  } else if (ddns_cb->address.len == 4) {
851  if (find_lease_by_ip_addr(&lease, ddns_cb->address, MDL) != 0){
852  scope = &(lease->scope);
853  }
854  } else if (ddns_cb->address.len == 16) {
855  memcpy(&addr, &ddns_cb->address.iabuf, 16);
856  if ((find_ipv6_pool(&pool, D6O_IA_TA, &addr) ==
857  ISC_R_SUCCESS) ||
858  (find_ipv6_pool(&pool, D6O_IA_NA, &addr) ==
859  ISC_R_SUCCESS)) {
860  if (iasubopt_hash_lookup(&lease6, pool->leases,
861  &addr, 16, MDL)) {
862  scope = &(lease6->scope);
863  }
865  }
866  } else {
867  log_fatal("Impossible condition at %s:%d.", MDL);
868  }
869 
870  if (scope == NULL) {
871  /* If necessary get rid of the lease */
872  if (lease) {
873  lease_dereference(&lease, MDL);
874  }
875  else if (lease6) {
876  iasubopt_dereference(&lease6, MDL);
877  }
878 
879  return(ISC_R_FAILURE);
880  }
881 
882  /* We now have a scope and can proceed to update it */
883  switch(ddns_cb->state) {
884  case DDNS_STATE_REM_PTR:
885  unset(*scope, "ddns-rev-name");
886  if ((ddns_cb->flags & DDNS_CLIENT_DID_UPDATE) != 0) {
887  unset(*scope, "ddns-client-fqdn");
888  }
889  break;
890 
891  case DDNS_STATE_ADD_PTR:
892  case DDNS_STATE_CLEANUP:
893  bind_ds_value(scope, "ddns-rev-name", &ddns_cb->rev_name);
894  if ((ddns_cb->flags & DDNS_UPDATE_ADDR) == 0) {
895  bind_ds_value(scope, "ddns-client-fqdn",
896  &ddns_cb->fwd_name);
897  }
898  break;
899 
903  bind_ds_value(scope, "ddns-fwd-name", &ddns_cb->fwd_name);
904 
905  if (ddns_cb->lease_tag == ddns_standard_tag) {
907  &ddns_cb->dhcid);
908  } else {
909  /* convert from dns version to lease version of dhcid */
910  memset(&lease_dhcid, 0, sizeof(lease_dhcid));
911  dhcid_tolease(&ddns_cb->dhcid, &lease_dhcid);
912  bind_ds_value(scope, ddns_interim_tag, &lease_dhcid);
913  data_string_forget(&lease_dhcid, MDL);
914  }
915  break;
916 
920  unset(*scope, "ddns-fwd-name");
921  unset(*scope, ddns_cb->lease_tag);
922  break;
923  }
924 
925  /* If necessary write it out and get rid of the lease */
926  if (lease) {
928  lease_dereference(&lease, MDL);
929  } else if (lease6) {
930  write_ia(lease6->ia);
931  iasubopt_dereference(&lease6, MDL);
932  }
933 
934  return(ISC_R_SUCCESS);
935 }
936 
937 /*
938  * This function should be called when update_lease_ptr function fails.
939  * It does inform user about the condition, provides some hints how to
940  * resolve this and dies gracefully. This can happend in at least three
941  * cases (all are configuration mistakes):
942  * a) IPv4: user have duplicate fixed-address entries (the same
943  * address is defined twice). We may have found wrong lease.
944  * b) IPv6: user have overlapping pools (we tried to find
945  * a lease in a wrong pool)
946  * c) IPv6: user have duplicate fixed-address6 entires (the same
947  * address is defined twice). We may have found wrong lease.
948  *
949  * Comment: while it would be possible to recover from both cases
950  * by forcibly searching for leases in *all* following pools, that would
951  * only hide the real problem - a misconfiguration. Proper solution
952  * is to log the problem, die and let the user fix his config file.
953  */
954 void
955 update_lease_failed(struct lease *lease,
956  struct iasubopt *lease6,
957  dhcp_ddns_cb_t *ddns_cb,
958  dhcp_ddns_cb_t *ddns_cb_set,
959  const char * file, int line)
960 {
961  char lease_address[MAX_ADDRESS_STRING_LEN + 64];
962  char reason[128]; /* likely reason */
963 
964  sprintf(reason, "unknown");
965  sprintf(lease_address, "unknown");
966 
967  /*
968  * let's pretend that everything is ok, so we can continue for
969  * information gathering purposes
970  */
971 
972  if (ddns_cb != NULL) {
973  strncpy(lease_address, piaddr(ddns_cb->address),
975 
976  if (ddns_cb->address.len == 4) {
977  sprintf(reason, "duplicate IPv4 fixed-address entry");
978  } else if (ddns_cb->address.len == 16) {
979  sprintf(reason, "duplicate IPv6 fixed-address6 entry "
980  "or overlapping pools");
981  } else {
982  /*
983  * Should not happen. We have non-IPv4, non-IPv6
984  * address. Something is very wrong here.
985  */
986  sprintf(reason, "corrupted ddns_cb structure (address "
987  "length is %d)", ddns_cb->address.len);
988  }
989  }
990 
991  log_error("Failed to properly update internal lease structure with "
992  "DDNS");
993  log_error("control block structures. Tried to update lease for"
994  "%s address, ddns_cb=%p.", lease_address, ddns_cb);
995 
996  log_error("%s", "");
997  log_error("This condition can occur, if DHCP server configuration is "
998  "inconsistent.");
999  log_error("In particular, please do check that your configuration:");
1000  log_error("a) does not have overlapping pools (especially containing");
1001  log_error(" %s address).", lease_address);
1002  log_error("b) there are no duplicate fixed-address or fixed-address6");
1003  log_error("entries for the %s address.", lease_address);
1004  log_error("%s", "");
1005  log_error("Possible reason for this failure: %s", reason);
1006 
1007  log_fatal("%s(%d): Failed to update lease database with DDNS info for "
1008  "address %s. Lease database inconsistent. Unable to recover."
1009  " Terminating.", file, line, lease_address);
1010 }
1011 
1012 /*
1013  * utility function to update found lease. It does extra checks
1014  * that we are indeed updating the right lease. It may happen
1015  * that user have duplicate fixed-address entries, so we attempt
1016  * to update wrong lease. See also safe_lease6_update.
1017  */
1018 
1019 void
1020 safe_lease_update(struct lease *lease,
1021  dhcp_ddns_cb_t *oldcb,
1022  dhcp_ddns_cb_t *newcb,
1023  const char *file, int line)
1024 {
1025  if (lease == NULL) {
1026  /* should never get here */
1027  log_fatal("Impossible condition at %s:%d (called from %s:%d).",
1028  MDL, file, line);
1029  }
1030 
1031  if ( (lease->ddns_cb == NULL) && (newcb == NULL) ) {
1032  /*
1033  * Trying to clean up pointer that is already null. We
1034  * are most likely trying to update wrong lease here.
1035  */
1036 
1037  /*
1038  * Previously this error message popped out during
1039  * DNS update for fixed leases. As we no longer
1040  * try to update the lease for a fixed (static) lease
1041  * this should not be a problem.
1042  */
1043  log_error("%s(%d): Invalid lease update. Tried to "
1044  "clear already NULL DDNS control block "
1045  "pointer for lease %s.",
1046  file, line, piaddr(lease->ip_addr) );
1047 
1048 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1049  update_lease_failed(lease, NULL, oldcb, newcb, file, line);
1050 #endif
1051  /*
1052  * May not reach this: update_lease_failed calls
1053  * log_fatal.
1054  */
1055  return;
1056  }
1057 
1058  if ( (lease->ddns_cb != NULL) && (lease->ddns_cb != oldcb) ) {
1059  /*
1060  * There is existing cb structure, but it differs from
1061  * what we expected to see there. Most likely we are
1062  * trying to update wrong lease.
1063  */
1064  log_error("%s(%d): Failed to update internal lease "
1065  "structure with DDNS control block. Existing"
1066  " ddns_cb structure does not match "
1067  "expectations.IPv4=%s, old ddns_cb=%p, tried"
1068  "to update to new ddns_cb=%p", file, line,
1069  piaddr(lease->ip_addr), oldcb, newcb);
1070 
1071 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1072  update_lease_failed(lease, NULL, oldcb, newcb, file, line);
1073 #endif
1074  /*
1075  * May not reach this: update_lease_failed calls
1076  * log_fatal.
1077  */
1078  return;
1079  }
1080 
1081  /* additional IPv4 specific checks may be added here */
1082 
1083  /* update the lease */
1084  lease->ddns_cb = newcb;
1085 }
1086 
1087 void
1088 safe_lease6_update(struct iasubopt *lease6,
1089  dhcp_ddns_cb_t *oldcb,
1090  dhcp_ddns_cb_t *newcb,
1091  const char *file, int line)
1092 {
1093  char addrbuf[MAX_ADDRESS_STRING_LEN];
1094 
1095  if (lease6 == NULL) {
1096  /* should never get here */
1097  log_fatal("Impossible condition at %s:%d (called from %s:%d).",
1098  MDL, file, line);
1099  }
1100 
1101  if ( (lease6->ddns_cb == NULL) && (newcb == NULL) ) {
1102  inet_ntop(AF_INET6, &lease6->addr, addrbuf,
1104  /*
1105  * Trying to clean up pointer that is already null. We
1106  * are most likely trying to update wrong lease here.
1107  */
1108  log_error("%s(%d): Failed to update internal lease "
1109  "structure. Tried to clear already NULL "
1110  "DDNS control block pointer for lease %s.",
1111  file, line, addrbuf);
1112 
1113 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1114  update_lease_failed(NULL, lease6, oldcb, newcb, file, line);
1115 #endif
1116 
1117  /*
1118  * May not reach this: update_lease_failed calls
1119  * log_fatal.
1120  */
1121  return;
1122  }
1123 
1124  if ( (lease6->ddns_cb != NULL) && (lease6->ddns_cb != oldcb) ) {
1125  /*
1126  * there is existing cb structure, but it differs from
1127  * what we expected to see there. Most likely we are
1128  * trying to update wrong lease.
1129  */
1130  inet_ntop(AF_INET6, &lease6->addr, addrbuf,
1132 
1133  log_error("%s(%d): Failed to update internal lease "
1134  "structure with DDNS control block. Existing"
1135  " ddns_cb structure does not match "
1136  "expectations.IPv6=%s, old ddns_cb=%p, tried"
1137  "to update to new ddns_cb=%p", file, line,
1138  addrbuf, oldcb, newcb);
1139 
1140 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1141  update_lease_failed(NULL, lease6, oldcb, newcb, file, line);
1142 #endif
1143  /*
1144  * May not reach this: update_lease_failed calls
1145  * log_fatal.
1146  */
1147  return;
1148  }
1149  /* additional IPv6 specific checks may be added here */
1150 
1151  /* update the lease */
1152  lease6->ddns_cb = newcb;
1153 }
1154 
1155 /*
1156  * Utility function to update the pointer to the DDNS control block
1157  * in a lease.
1158  * SUCCESS - able to update the pointer
1159  * FAILURE - lease didn't exist or sanity checks failed
1160  * lease and lease6 may be empty in which case we attempt to find
1161  * the lease from the ddns_cb information.
1162  * ddns_cb is the control block to use if a lookup is necessary
1163  * ddns_cb_set is the pointer to insert into the lease and may be NULL
1164  * The last two arguments may look odd as they will be the same much of the
1165  * time, but I need an argument to tell me if I'm setting or clearing in
1166  * addition to the address information from the cb to look up the lease.
1167  * using the same value twice allows me more flexibility.
1168  */
1169 
1170 isc_result_t
1171 ddns_update_lease_ptr(struct lease *lease,
1172  struct iasubopt *lease6,
1173  dhcp_ddns_cb_t *ddns_cb,
1174  dhcp_ddns_cb_t *ddns_cb_set,
1175  const char * file, int line)
1176 {
1177  char ddns_address[MAX_ADDRESS_STRING_LEN];
1178  sprintf(ddns_address, "unknown");
1179  if (ddns_cb == NULL) {
1180  log_info("%s(%d): No control block for lease update",
1181  file, line);
1182  return (ISC_R_FAILURE);
1183  }
1184  else {
1185  strcpy(ddns_address, piaddr(ddns_cb->address));
1186  }
1187 #if defined (DEBUG_DNS_UPDATES)
1188  log_info("%s(%d): Updating lease_ptr for ddns_cp=%p (addr=%s)",
1189  file, line, ddns_cb, ddns_address );
1190 #endif
1191 
1192  /*
1193  * If the lease was static (for a fixed address)
1194  * we don't need to do any work.
1195  */
1196  if (ddns_cb->flags & DDNS_STATIC_LEASE) {
1197 #if defined (DEBUG_DNS_UPDATES)
1198  log_info("lease is static, returning");
1199 #endif
1200  return (ISC_R_SUCCESS);
1201  }
1202 
1203  /*
1204  * If we are processing an expired or released v6 lease
1205  * we don't actually have a lease to update
1206  */
1207  if ((ddns_cb->address.len == 16) &&
1208  ((ddns_cb->flags & DDNS_ACTIVE_LEASE) == 0)) {
1209  return (ISC_R_SUCCESS);
1210  }
1211 
1212  if (lease != NULL) {
1213  safe_lease_update(lease, ddns_cb, ddns_cb_set,
1214  file, line);
1215  } else if (lease6 != NULL) {
1216  safe_lease6_update(lease6, ddns_cb, ddns_cb_set,
1217  file, line);
1218  } else if (ddns_cb->address.len == 4) {
1219  struct lease *find_lease = NULL;
1221  ddns_cb->address, MDL) != 0) {
1222 #if defined (DEBUG_DNS_UPDATES)
1223  log_info("%s(%d): find_lease_by_ip_addr(%s) successful:"
1224  "lease=%p", file, line, ddns_address,
1225  find_lease);
1226 #endif
1227 
1228  safe_lease_update(find_lease, ddns_cb,
1229  ddns_cb_set, file, line);
1230  lease_dereference(&find_lease, MDL);
1231  }
1232  else {
1233  log_error("%s(%d): ddns_update_lease_ptr failed. "
1234  "Lease for %s not found.",
1236 
1237 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1238  update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set,
1239  file, line);
1240 #endif
1241  /*
1242  * may not reach this. update_lease_failed
1243  * calls log_fatal.
1244  */
1245  return(ISC_R_FAILURE);
1246 
1247  }
1248  } else if (ddns_cb->address.len == 16) {
1249  struct iasubopt *find_lease6 = NULL;
1250  struct ipv6_pool *pool = NULL;
1251  struct in6_addr addr;
1252  char addrbuf[MAX_ADDRESS_STRING_LEN];
1253 
1254  memcpy(&addr, &ddns_cb->address.iabuf, 16);
1255  if ((find_ipv6_pool(&pool, D6O_IA_TA, &addr) !=
1256  ISC_R_SUCCESS) &&
1257  (find_ipv6_pool(&pool, D6O_IA_NA, &addr) !=
1258  ISC_R_SUCCESS)) {
1259  inet_ntop(AF_INET6, &addr, addrbuf,
1261  log_error("%s(%d): Pool for lease %s not found.",
1262  file, line, addrbuf);
1263 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1264  update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set,
1265  file, line);
1266 #endif
1267  /*
1268  * never reached. update_lease_failed
1269  * calls log_fatal.
1270  */
1271  return(ISC_R_FAILURE);
1272  }
1273 
1274  if (iasubopt_hash_lookup(&find_lease6, pool->leases,
1275  &addr, 16, MDL)) {
1276  find_lease6->ddns_cb = ddns_cb_set;
1277  iasubopt_dereference(&find_lease6, MDL);
1278  } else {
1279  inet_ntop(AF_INET6, &addr, addrbuf,
1281  log_error("%s(%d): Lease %s not found within pool.",
1282  file, line, addrbuf);
1283 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1284  update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set,
1285  file, line);
1286 #endif
1287  /*
1288  * not reached when update_lease_failed is called,
1289  * it calls log_fatal.
1290  */
1292  return(ISC_R_FAILURE);
1293  }
1295  } else {
1296  /* shouldn't get here */
1297  log_fatal("Impossible condition at %s:%d, called from %s:%d.",
1298  MDL, file, line);
1299  }
1300 
1301  return(ISC_R_SUCCESS);
1302 }
1303 
1304 void
1305 ddns_ptr_add(dhcp_ddns_cb_t *ddns_cb,
1306  isc_result_t eresult)
1307 {
1308  if (eresult == ISC_R_SUCCESS) {
1309  log_info("Added reverse map from %.*s to %.*s",
1310  (int)ddns_cb->rev_name.len,
1311  (const char *)ddns_cb->rev_name.data,
1312  (int)ddns_cb->fwd_name.len,
1313  (const char *)ddns_cb->fwd_name.data);
1314 
1315  ddns_update_lease_text(ddns_cb, NULL);
1316  } else {
1317  log_error("Unable to add reverse map from %.*s to %.*s: %s",
1318  (int)ddns_cb->rev_name.len,
1319  (const char *)ddns_cb->rev_name.data,
1320  (int)ddns_cb->fwd_name.len,
1321  (const char *)ddns_cb->fwd_name.data,
1322  isc_result_totext (eresult));
1323  }
1324 
1325  ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1326  destroy_ddns_cb(ddns_cb, MDL);
1327  /*
1328  * A single DDNS operation may require several calls depending on
1329  * the current state as the prerequisites for the first message
1330  * may not succeed requiring a second operation and potentially
1331  * a ptr operation after that. The commit_leases operation is
1332  * invoked at the end of this set of operations in order to require
1333  * a single write for all of the changes. We call commit_leases
1334  * here rather than immediately after the call to update the lease
1335  * text in order to save any previously written data.
1336  */
1337  commit_leases();
1338  return;
1339 }
1340 
1341 /*
1342  * action routine when trying to remove a pointer
1343  * this will be called after the ddns queries have completed
1344  * if we succeeded in removing the pointer we go to the next step (if any)
1345  * if not we cleanup and leave.
1346  */
1347 
1348 void
1349 ddns_ptr_remove(dhcp_ddns_cb_t *ddns_cb,
1350  isc_result_t eresult)
1351 {
1352  isc_result_t result = eresult;
1353 
1354  switch(eresult) {
1355  case ISC_R_SUCCESS:
1356  log_info("Removed reverse map on %.*s",
1357  (int)ddns_cb->rev_name.len,
1358  (const char *)ddns_cb->rev_name.data);
1359  /* fall through */
1360  case DNS_R_NXRRSET:
1361  case DNS_R_NXDOMAIN:
1362  /* No entry is the same as success.
1363  * Remove the information from the lease and
1364  * continue with any next step */
1365  ddns_update_lease_text(ddns_cb, NULL);
1366 
1367  /* trigger any add operation */
1368  result = ISC_R_SUCCESS;
1369 #if defined (DEBUG_DNS_UPDATES)
1370  log_info("DDNS: removed map or no reverse map to remove %.*s",
1371  (int)ddns_cb->rev_name.len,
1372  (const char *)ddns_cb->rev_name.data);
1373 #endif
1374  break;
1375 
1376  default:
1377  log_error("Can't remove reverse map on %.*s: %s",
1378  (int)ddns_cb->rev_name.len,
1379  (const char *)ddns_cb->rev_name.data,
1380  isc_result_totext (eresult));
1381  break;
1382  }
1383 
1384  /* If we aren't suppossed to do the next step, set the result
1385  * flag so ddns_fwd_srv_connector won't do much
1386  */
1387  if ((ddns_cb->flags & DDNS_EXECUTE_NEXT) == 0)
1388  result = ISC_R_FAILURE;
1389 
1390  ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1391  ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, result);
1392  destroy_ddns_cb(ddns_cb, MDL);
1393  return;
1394 }
1395 
1396 
1397 /*
1398  * If the first query succeeds, the updater can conclude that it
1399  * has added a new name whose only RRs are the A and DHCID RR records.
1400  * The A RR update is now complete (and a client updater is finished,
1401  * while a server might proceed to perform a PTR RR update).
1402  * -- "Interaction between DHCP and DNS"
1403  *
1404  * If the second query succeeds, the updater can conclude that the current
1405  * client was the last client associated with the domain name, and that
1406  * the name now contains the updated A RR. The A RR update is now
1407  * complete (and a client updater is finished, while a server would
1408  * then proceed to perform a PTR RR update).
1409  * -- "Interaction between DHCP and DNS"
1410  *
1411  * If the second query fails with NXRRSET, the updater must conclude
1412  * that the client's desired name is in use by another host. If
1413  * Dual Stack Mixed Mode (DSMM) is enabled and we proceed to a
1414  * third stage forward update attempt specific to DSMM rules. If not,
1415  * then the existing entries are left intact:
1416  *
1417  * At this juncture, the updater can decide (based on some administrative
1418  * configuration outside of the scope of this document) whether to let
1419  * the existing owner of the name keep that name, and to (possibly)
1420  * perform some name disambiguation operation on behalf of the current
1421  * client, or to replace the RRs on the name with RRs that represent
1422  * the current client. If the configured policy allows replacement of
1423  * existing records, the updater submits a query that deletes the
1424  * existing A RR and the existing DHCID RR, adding A and DHCID RRs that
1425  * represent the IP address and client-identity of the new client.
1426  * -- "Interaction between DHCP and DNS"
1427  */
1428 
1429 void
1430 ddns_fwd_srv_add2(dhcp_ddns_cb_t *ddns_cb,
1431  isc_result_t eresult)
1432 {
1433  isc_result_t result;
1434  const char *logstr = NULL;
1435  char ddns_address[MAX_ADDRESS_STRING_LEN];
1436 
1437 #if defined (DEBUG_DNS_UPDATES)
1438  log_info ("DDNS:ddns_fwd_srv_add2: %s eresult: %d",
1439  dump_ddns_cb(ddns_cb), eresult);
1440 #endif
1441 
1442  /* Construct a printable form of the address for logging */
1443  strcpy(ddns_address, piaddr(ddns_cb->address));
1444 
1445  switch(eresult) {
1446  case ISC_R_SUCCESS:
1447  log_info("Added new forward map from %.*s to %s",
1448  (int)ddns_cb->fwd_name.len,
1449  (const char *)ddns_cb->fwd_name.data,
1450  ddns_address);
1451 
1452  ddns_update_lease_text(ddns_cb, NULL);
1453 
1454  if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1455  /* if we have zone information get rid of it */
1456  if (ddns_cb->zone != NULL) {
1457  ddns_cb_forget_zone(ddns_cb);
1458  }
1459 
1460  ddns_cb->state = DDNS_STATE_ADD_PTR;
1461  ddns_cb->cur_func = ddns_ptr_add;
1462 
1463  result = ddns_modify_ptr(ddns_cb, MDL);
1464  if (result == ISC_R_SUCCESS) {
1465  return;
1466  }
1467  }
1468  break;
1469 
1470  case DNS_R_YXRRSET:
1471  case DNS_R_YXDOMAIN:
1472  logstr = "DHCID mismatch, belongs to another client.";
1473  break;
1474 
1475  case DNS_R_NXDOMAIN:
1476  case DNS_R_NXRRSET:
1477  /* If DSMM is on we need to try forward add3 */
1478  if (ddns_cb->flags & DDNS_DUAL_STACK_MIXED_MODE) {
1479  ddns_cb->state = DDNS_STATE_DSMM_FW_ADD3;
1480  ddns_cb->cur_func = ddns_fwd_srv_add3;
1481 
1482  result = ddns_modify_fwd(ddns_cb, MDL);
1483  if (result == ISC_R_SUCCESS) {
1484  return;
1485  }
1486 
1487  break;
1488  }
1489 
1490  logstr = "Has an address record but no DHCID, not mine.";
1491  break;
1492 
1493  default:
1494  logstr = isc_result_totext(eresult);
1495  break;
1496  }
1497 
1498  if (logstr != NULL) {
1499  log_error("Forward map from %.*s to %s FAILED: %s",
1500  (int)ddns_cb->fwd_name.len,
1501  (const char *)ddns_cb->fwd_name.data,
1502  ddns_address, logstr);
1503  }
1504 
1505  ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1506  destroy_ddns_cb(ddns_cb, MDL);
1507  /*
1508  * A single DDNS operation may require several calls depending on
1509  * the current state as the prerequisites for the first message
1510  * may not succeed requiring a second operation and potentially
1511  * a ptr operation after that. The commit_leases operation is
1512  * invoked at the end of this set of operations in order to require
1513  * a single write for all of the changes. We call commit_leases
1514  * here rather than immediately after the call to update the lease
1515  * text in order to save any previously written data.
1516  */
1517  commit_leases();
1518  return;
1519 }
1520 
1521 void
1522 ddns_fwd_srv_add1(dhcp_ddns_cb_t *ddns_cb,
1523  isc_result_t eresult)
1524 {
1525  isc_result_t result;
1526  char ddns_address[MAX_ADDRESS_STRING_LEN];
1527 
1528 #if defined (DEBUG_DNS_UPDATES)
1529  log_info ("DDNS: ddns_fwd_srv_add1: %s eresult: %d",
1530  dump_ddns_cb(ddns_cb), eresult);
1531 #endif
1532 
1533  /* Construct a printable form of the address for logging */
1534  strcpy(ddns_address, piaddr(ddns_cb->address));
1535 
1536  switch(eresult) {
1537  case ISC_R_SUCCESS:
1538  log_info ("Added new forward map from %.*s to %s",
1539  (int)ddns_cb->fwd_name.len,
1540  (const char *)ddns_cb->fwd_name.data,
1541  ddns_address);
1542 
1543  ddns_update_lease_text(ddns_cb, NULL);
1544 
1545  if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1546  /* if we have zone information get rid of it */
1547  if (ddns_cb->zone != NULL) {
1548  ddns_cb_forget_zone(ddns_cb);
1549  }
1550 
1551  ddns_cb->state = DDNS_STATE_ADD_PTR;
1552  ddns_cb->cur_func = ddns_ptr_add;
1553 
1554  result = ddns_modify_ptr(ddns_cb, MDL);
1555  if (result == ISC_R_SUCCESS) {
1556  return;
1557  }
1558  }
1559  break;
1560 
1561  case DNS_R_YXDOMAIN:
1562  /* we can reuse the zone information */
1563  ddns_cb->state = DDNS_STATE_ADD_FW_YXDHCID;
1564  ddns_cb->cur_func = ddns_fwd_srv_add2;
1565 
1566  result = ddns_modify_fwd(ddns_cb, MDL);
1567  if (result == ISC_R_SUCCESS) {
1568  return;
1569  }
1570  break;
1571  default:
1572  log_error ("Unable to add forward map from %.*s to %s: %s",
1573  (int)ddns_cb->fwd_name.len,
1574  (const char *)ddns_cb->fwd_name.data,
1575  ddns_address,
1576  isc_result_totext (eresult));
1577  break;
1578  }
1579 
1580  ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1581  destroy_ddns_cb(ddns_cb, MDL);
1582  /*
1583  * A single DDNS operation may require several calls depending on
1584  * the current state as the prerequisites for the first message
1585  * may not succeed requiring a second operation and potentially
1586  * a ptr operation after that. The commit_leases operation is
1587  * invoked at the end of this set of operations in order to require
1588  * a single write for all of the changes. We call commit_leases
1589  * here rather than immediately after the call to update the lease
1590  * text in order to save any previously written data.
1591  */
1592  commit_leases();
1593  return;
1594 }
1595 
1596 /*
1597  * This action routine is invoked after the DSMM third add stage is
1598  * attempted. If we succeeded we attempt to update the reverse DNS,
1599  * if not we cleanup and leave.
1600  */
1601 void
1602 ddns_fwd_srv_add3(dhcp_ddns_cb_t *ddns_cb,
1603  isc_result_t eresult)
1604 {
1605  isc_result_t result;
1606  const char *logstr = NULL;
1607  char ddns_address[MAX_ADDRESS_STRING_LEN+1];
1608 
1609 #if defined (DEBUG_DNS_UPDATES)
1610  log_info ("DDNS: ddns_fwd_srv_add3: %s eresult: %d",
1611  dump_ddns_cb(ddns_cb), eresult);
1612 #endif
1613 
1614  /* Construct a printable form of the address for logging */
1615  memset(ddns_address, 0x0, sizeof(ddns_address));
1616  strncpy(ddns_address, piaddr(ddns_cb->address),
1617  sizeof(ddns_address) - 1);
1618 
1619  switch(eresult) {
1620  case ISC_R_SUCCESS:
1621  log_info("Added new forward map from %.*s to %s",
1622  (int)ddns_cb->fwd_name.len,
1623  (const char *)ddns_cb->fwd_name.data,
1624  ddns_address);
1625 
1626  ddns_update_lease_text(ddns_cb, NULL);
1627 
1628  if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1629  /* if we have zone information get rid of it */
1630  if (ddns_cb->zone != NULL) {
1631  ddns_cb_forget_zone(ddns_cb);
1632  }
1633 
1634  ddns_cb->state = DDNS_STATE_ADD_PTR;
1635  ddns_cb->cur_func = ddns_ptr_add;
1636 
1637  result = ddns_modify_ptr(ddns_cb, MDL);
1638  if (result == ISC_R_SUCCESS) {
1639  return;
1640  }
1641  }
1642  break;
1643 
1644  case DNS_R_YXRRSET:
1645  logstr = "an entry that is either static or "
1646  "owned by another client exists.";
1647  break;
1648 
1649  case DNS_R_NXRRSET:
1650  logstr = "static entry of the other protocol type exists.";
1651  break;
1652 
1653  default:
1654  logstr = isc_result_totext(eresult);
1655  break;
1656  }
1657 
1658  if (logstr != NULL) {
1659  log_error("Forward map from %.*s to %s FAILED: %s",
1660  (int)ddns_cb->fwd_name.len,
1661  (const char *)ddns_cb->fwd_name.data,
1662  ddns_address, logstr);
1663  }
1664 
1665  ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1666  destroy_ddns_cb(ddns_cb, MDL);
1667  /*
1668  * A single DDNS operation may require several calls depending on
1669  * the current state as the prerequisites for the first message
1670  * may not succeed requiring a second operation and potentially
1671  * a ptr operation after that. The commit_leases operation is
1672  * invoked at the end of this set of operations in order to require
1673  * a single write for all of the changes. We call commit_leases
1674  * here rather than immediately after the call to update the lease
1675  * text in order to save any previously written data.
1676  */
1677  commit_leases();
1678  return;
1679 }
1680 
1681 static void
1682 ddns_fwd_srv_connector(struct lease *lease,
1683  struct iasubopt *lease6,
1684  struct binding_scope **inscope,
1685  dhcp_ddns_cb_t *ddns_cb,
1686  isc_result_t eresult)
1687 {
1688  isc_result_t result = ISC_R_FAILURE;
1689 
1690 #if defined (DEBUG_DNS_UPDATES)
1691  log_info ("DDNS: ddns_fwd_srv_connector: %s eresult: %d",
1692  dump_ddns_cb(ddns_cb), eresult);
1693 #endif
1694 
1695  if (ddns_cb == NULL) {
1696  /* nothing to do */
1697  return;
1698  }
1699 
1700  if (eresult == ISC_R_SUCCESS) {
1701  /*
1702  * If we have updates dispatch as appropriate,
1703  * if not do FQDN binding if desired.
1704  */
1705 
1706  if (ddns_cb->flags & DDNS_UPDATE_ADDR) {
1707  ddns_cb->state = DDNS_STATE_ADD_FW_NXDOMAIN;
1708  ddns_cb->cur_func = ddns_fwd_srv_add1;
1709  result = ddns_modify_fwd(ddns_cb, MDL);
1710  } else if ((ddns_cb->flags & DDNS_UPDATE_PTR) &&
1711  (ddns_cb->rev_name.len != 0)) {
1712  ddns_cb->state = DDNS_STATE_ADD_PTR;
1713  ddns_cb->cur_func = ddns_ptr_add;
1714  result = ddns_modify_ptr(ddns_cb, MDL);
1715  } else {
1716  ddns_update_lease_text(ddns_cb, inscope);
1717  }
1718  }
1719 
1720 
1721  if (result == ISC_R_SUCCESS) {
1722  ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, MDL);
1723  } else {
1724  destroy_ddns_cb(ddns_cb, MDL);
1725  }
1726 
1727  return;
1728 }
1729 
1730 /*
1731  * If the first query fails, the updater MUST NOT delete the DNS name. It
1732  * may be that the host whose lease on the server has expired has moved
1733  * to another network and obtained a lease from a different server,
1734  * which has caused the client's A RR to be replaced. It may also be
1735  * that some other client has been configured with a name that matches
1736  * the name of the DHCP client, and the policy was that the last client
1737  * to specify the name would get the name. In this case, the DHCID RR
1738  * will no longer match the updater's notion of the client-identity of
1739  * the host pointed to by the DNS name.
1740  * -- "Interaction between DHCP and DNS"
1741  */
1742 
1743 void
1744 ddns_fwd_srv_rem2(dhcp_ddns_cb_t *ddns_cb,
1745  isc_result_t eresult)
1746 {
1747 #if defined (DEBUG_DNS_UPDATES)
1748  log_info ("DDNS: ddns_fwd_srv_rem2: %s eresult: %d",
1749  dump_ddns_cb(ddns_cb), eresult);
1750 #endif
1751 
1752  /*
1753  * To get here we have already managed to remove the A/AAAA
1754  * record and are trying to remove the DHCID/TXT record as well.
1755  * On success (removed DHCID/TXT) or YXRRSET (DHCID/TXT still in
1756  * use by something else) we clean up the lease.
1757  * On some other error we don't clean up the lease and hope that
1758  * if we try this again it will work. An example would be if we
1759  * got a timeout as the DNS server halted between the first and
1760  * second steps. The DNS server would still have the DHCID/TXT
1761  * and we would like to remove that in the future.
1762  *
1763  * On success set the EXECUTE_NEXT flag which triggers any
1764  * add that is next in the chain.
1765  */
1766  if ((eresult == ISC_R_SUCCESS) ||
1767  (eresult == DNS_R_YXRRSET)) {
1768  ddns_update_lease_text(ddns_cb, NULL);
1769  eresult = ISC_R_SUCCESS;
1770  }
1771 
1772  /* Do the next operation */
1773  if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1774  /* if we have zone information get rid of it */
1775  if (ddns_cb->zone != NULL) {
1776  ddns_cb_forget_zone(ddns_cb);
1777  }
1778 
1779  ddns_cb->state = DDNS_STATE_REM_PTR;
1780  ddns_cb->cur_func = ddns_ptr_remove;
1781  if (eresult == ISC_R_SUCCESS)
1782  ddns_cb->flags |= DDNS_EXECUTE_NEXT;
1783 
1784  eresult = ddns_modify_ptr(ddns_cb, MDL);
1785  if (eresult == ISC_R_SUCCESS) {
1786  return;
1787  }
1788  }
1789 
1790  ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1791  ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult);
1792  destroy_ddns_cb(ddns_cb, MDL);
1793  return;
1794 }
1795 
1796 
1797 /*
1798  * First action routine when trying to remove a fwd
1799  * this will be called after the ddns queries have completed
1800  * if we succeeded in removing the fwd we go to the next step (if any)
1801  * if not we cleanup and leave.
1802  */
1803 
1804 void
1805 ddns_fwd_srv_rem1(dhcp_ddns_cb_t *ddns_cb,
1806  isc_result_t eresult)
1807 {
1808  isc_result_t result = eresult;
1809  char ddns_address[MAX_ADDRESS_STRING_LEN];
1810 
1811 #if defined (DEBUG_DNS_UPDATES)
1812  log_info ("DDNS: ddns_fwd_srv_rem1: %s eresult: %d",
1813  dump_ddns_cb(ddns_cb), eresult);
1814 #endif
1815 
1816  switch(eresult) {
1817  case ISC_R_SUCCESS:
1818  /* Construct a printable form of the address for logging */
1819  strcpy(ddns_address, piaddr(ddns_cb->address));
1820  log_info("Removed forward map from %.*s to %s",
1821  (int)ddns_cb->fwd_name.len,
1822  (const char*)ddns_cb->fwd_name.data,
1823  ddns_address);
1824 
1825  /* Do the second step of the FWD removal */
1826  ddns_cb->state = DDNS_STATE_REM_FW_NXRR;
1827  ddns_cb->cur_func = ddns_fwd_srv_rem2;
1828  result = ddns_modify_fwd(ddns_cb, MDL);
1829  if (result == ISC_R_SUCCESS) {
1830  return;
1831  }
1832  break;
1833 
1834  case DNS_R_NXRRSET:
1835  case DNS_R_NXDOMAIN:
1836  /* A result of not found means rem1 did not find a guard of
1837  * our * type. From this we assume either there are no address
1838  * record(s) of our type to delete or they are unguarded and
1839  * therefore presumed to be static. Either way, we're done
1840  * unless we're in DSMM and ddns-other-guard-is-dynamic is on.
1841  * In which case we need to see if a guard of the other type
1842  * exists, which permits us to delete any address records of
1843  * our type. */
1844  #define DSMM_OGD (DDNS_DUAL_STACK_MIXED_MODE | \
1845  DDNS_OTHER_GUARD_IS_DYNAMIC)
1846  if ((ddns_cb->flags & DSMM_OGD) == DSMM_OGD) {
1848  ddns_cb->cur_func = ddns_fwd_srv_rem2;
1849  result = ddns_modify_fwd(ddns_cb, MDL);
1850  if (result == ISC_R_SUCCESS) {
1851  return;
1852  }
1853  break;
1854  }
1855 
1856  ddns_update_lease_text(ddns_cb, NULL);
1857 
1858 #if defined (DEBUG_DNS_UPDATES)
1859  log_info("DDNS: no forward map to remove. %p", ddns_cb);
1860 #endif
1861  /* Trigger the add operation */
1862  eresult = ISC_R_SUCCESS;
1863 
1864  /* Fall through */
1865  default:
1866 
1867  /* We do the remove operation in most cases
1868  * but we don't want to continue with adding a forward
1869  * record if the forward removal had issues so we
1870  * check the eresult and set the EXECUTE_NEXT flag on
1871  * success.
1872  */
1873 
1874  /* Do the remove operation */
1875  if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1876  /* if we have zone information get rid of it */
1877  if (ddns_cb->zone != NULL) {
1878  ddns_cb_forget_zone(ddns_cb);
1879  }
1880 
1881  ddns_cb->state = DDNS_STATE_REM_PTR;
1882  ddns_cb->cur_func = ddns_ptr_remove;
1883  if (eresult == ISC_R_SUCCESS)
1884  ddns_cb->flags |= DDNS_EXECUTE_NEXT;
1885 
1886  result = ddns_modify_ptr(ddns_cb, MDL);
1887  if (result == ISC_R_SUCCESS) {
1888  return;
1889  }
1890  }
1891  break;
1892  }
1893 
1894  ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1895  ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult);
1896  destroy_ddns_cb(ddns_cb, MDL);
1897 }
1898 
1899 /*%<
1900  * Remove relevant entries from DNS.
1901  *
1902  * \li lease - lease to start with if this is for v4
1903  *
1904  * \li lease6 - lease to start with if this is for v6
1905  *
1906  * \li add_ddns_cb - control block for additional DDNS work. This
1907  * is used when the code is going to add a DDNS entry after removing
1908  * the current entry.
1909  *
1910  * \li active - indication about the status of the lease. It is
1911  * ISC_TRUE if the lease is still active, and FALSE if the lease
1912  * is inactive. This is used to indicate if the lease is inactive or going
1913  * to inactive so we can avoid trying to update the lease with cb pointers
1914  * and text information if it isn't useful.
1915  *
1916  * Returns
1917  * \li #ISC_R_FAILURE - badness occurred and we weren't able to do what was wanted
1918  * \li #ISC_R_SUCCESS - we were able to do stuff but it's in progress
1919  *
1920  * in both cases any additional block has been passed on to it's handler
1921  */
1922 
1923 isc_result_t
1924 ddns_removals(struct lease *lease,
1925  struct iasubopt *lease6,
1926  dhcp_ddns_cb_t *add_ddns_cb,
1927  isc_boolean_t active)
1928 {
1929  isc_result_t rcode, execute_add = ISC_R_FAILURE;
1930  struct binding_scope **scope = NULL;
1931  isc_result_t result = ISC_R_FAILURE;
1932  dhcp_ddns_cb_t *ddns_cb = NULL;
1933  struct data_string leaseid;
1934 
1935 #if defined (DEBUG_DNS_UPDATES)
1936  log_info ("DDNS: ddns_removals: %s",
1937  dump_ddns_cb(add_ddns_cb));
1938 #endif
1939 
1940  /*
1941  * See if we need to cancel an outstanding request. Mostly this is
1942  * used to handle the case where this routine is called twice for
1943  * the same release or abandon event.
1944  *
1945  * When called from the dns code as part of an update request
1946  * (add_ddns_cb != NULL) any outstanding requests will have already
1947  * been cancelled.
1948  *
1949  * If the new request is just a removal and we have an outstanding
1950  * request we have several options:
1951  *
1952  * - we are doing an update or we are doing a removal and the active
1953  * flag has changed from TRUE to FALSE. In these cases we need to
1954  * cancel the old request and start the new one.
1955  *
1956  * - other wise we are doing a removal with the active flag unchanged.
1957  * In this case we can let the current removal continue and do not need
1958  * to start a new one. If the old request included an update to be
1959  * done after the removal we need to kill the update part of the
1960  * request.
1961  */
1962 
1963  if (add_ddns_cb == NULL) {
1964  if ((lease != NULL) && (lease->ddns_cb != NULL)) {
1965  ddns_cb = lease->ddns_cb;
1966 
1967  /*
1968  * Is the old request an update or did the
1969  * the active flag change?
1970  */
1971  if (((ddns_cb->state == DDNS_STATE_ADD_PTR) ||
1972  (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) ||
1973  (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) ||
1974  ((active == ISC_FALSE) &&
1975  ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) {
1976  /* Cancel the current request */
1978  lease->ddns_cb = NULL;
1979  } else {
1980  /* Remvoval, check and remove updates */
1981  if (ddns_cb->next_op != NULL) {
1982  destroy_ddns_cb(ddns_cb->next_op, MDL);
1983  ddns_cb->next_op = NULL;
1984  }
1985 #if defined (DEBUG_DNS_UPDATES)
1986  log_info("DDNS %s(%d): removal already in "
1987  "progress new ddns_cb=%p",
1988  MDL, ddns_cb);
1989 #endif
1990  return (ISC_R_SUCCESS);
1991  }
1992  } else if ((lease6 != NULL) && (lease6->ddns_cb != NULL)) {
1993  ddns_cb = lease6->ddns_cb;
1994 
1995  /*
1996  * Is the old request an update or did the
1997  * the active flag change?
1998  */
1999  if (((ddns_cb->state == DDNS_STATE_ADD_PTR) ||
2000  (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) ||
2001  (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) ||
2002  ((active == ISC_FALSE) &&
2003  ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) {
2004  /* Cancel the current request */
2005  ddns_cancel(lease6->ddns_cb, MDL);
2006  lease6->ddns_cb = NULL;
2007  } else {
2008  /* Remvoval, check and remove updates */
2009  if (ddns_cb->next_op != NULL) {
2010  destroy_ddns_cb(ddns_cb->next_op, MDL);
2011  ddns_cb->next_op = NULL;
2012  }
2013 #if defined (DEBUG_DNS_UPDATES)
2014  log_info("DDNS %s(%d): removal already in "
2015  "progress new ddns_cb=%p",
2016  MDL, ddns_cb);
2017 #endif
2018  return (ISC_R_SUCCESS);
2019  }
2020  }
2021  ddns_cb = NULL;
2022  }
2023 
2024  /* allocate our control block */
2025  ddns_cb = ddns_cb_alloc(MDL);
2026  if (ddns_cb == NULL) {
2027  goto cleanup;
2028  }
2029 
2030  /* Set the conflict detection flags based on global configuration */
2031  copy_conflict_flags(&ddns_cb->flags, ddns_conflict_mask);
2032 
2033  /*
2034  * For v4 we flag static leases so we don't try
2035  * and manipulate the lease later. For v6 we don't
2036  * get static leases and don't need to flag them.
2037  */
2038  if (lease != NULL) {
2039  scope = &(lease->scope);
2040  ddns_cb->address = lease->ip_addr;
2041  if (lease->flags & STATIC_LEASE)
2042  ddns_cb->flags |= DDNS_STATIC_LEASE;
2043  } else if (lease6 != NULL) {
2044  scope = &(lease6->scope);
2045  memcpy(&ddns_cb->address.iabuf, lease6->addr.s6_addr, 16);
2046  ddns_cb->address.len = 16;
2047  } else
2048  goto cleanup;
2049 
2050  /*
2051  * Set the flag bit if the lease is active, that is it isn't
2052  * expired or released. This is used to determine if we need
2053  * to update the scope information for both v4 and v6 and
2054  * the lease information for v6 when the response
2055  * from the DNS code is processed.
2056  */
2057  if (active == ISC_TRUE) {
2058  ddns_cb->flags |= DDNS_ACTIVE_LEASE;
2059  }
2060 
2061  /* No scope implies that DDNS has not been performed for this lease. */
2062  if (*scope == NULL)
2063  goto cleanup;
2064 
2067  goto cleanup;
2068 
2069  /* Assume that we are removing both records */
2070  ddns_cb->flags |= DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR;
2071 
2072  /* and that we want to do the add call */
2073  execute_add = ISC_R_SUCCESS;
2074 
2075  /*
2076  * Look up stored names.
2077  */
2078 
2079  /*
2080  * Find the fwd name and copy it to the control block. If we don't
2081  * have it we can't delete the fwd record but we can still try to
2082  * remove the ptr record and cleanup the lease information if the
2083  * client did the fwd update.
2084  */
2085  if (!find_bound_string(&ddns_cb->fwd_name, *scope, "ddns-fwd-name")) {
2086  /* don't try and delete the A, or do the add */
2087  ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
2088  execute_add = ISC_R_FAILURE;
2089 
2090  /* Check if client did update */
2091  if (find_bound_string(&ddns_cb->fwd_name, *scope,
2092  "ddns-client-fqdn")) {
2093  ddns_cb->flags |= DDNS_CLIENT_DID_UPDATE;
2094  }
2095  }
2096 
2097  /*
2098  * Find the txt or dhcid tag and copy it to the control block. If we
2099  * don't have one this isn't an interim or standard record so we can't
2100  * delete the A record using this mechanism but we can delete the ptr
2101  * record. In this case we will attempt to do any requested next step.
2102  */
2103  memset(&leaseid, 0, sizeof(leaseid));
2104  if (find_bound_string (&leaseid, *scope, ddns_standard_tag)) {
2105  /* We have a standard tag */
2106  ddns_cb->lease_tag = ddns_standard_tag;
2107  ddns_cb->dhcid_class = dns_rdatatype_dhcid;
2108  ddns_cb->other_dhcid_class = dns_rdatatype_txt;
2109  data_string_copy(&ddns_cb->dhcid, &leaseid, MDL);
2110  data_string_forget(&leaseid, MDL);
2111  } else if (find_bound_string (&leaseid, *scope, ddns_interim_tag)) {
2112  /* we have an interim tag */
2113  ddns_cb->lease_tag = ddns_interim_tag;
2114  ddns_cb->dhcid_class = dns_rdatatype_txt;
2115  ddns_cb->other_dhcid_class = dns_rdatatype_dhcid;
2116  if (dhcid_fromlease(&ddns_cb->dhcid, &leaseid) !=
2117  ISC_R_SUCCESS) {
2118  /* We couldn't convert the dhcid from the lease
2119  * version to the dns version. We can't delete
2120  * the A record but can continue to the ptr
2121  */
2122  ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
2123  }
2124  data_string_forget(&leaseid, MDL);
2125  } else {
2126  ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
2127  }
2128 
2129  /*
2130  * Find the rev name and copy it to the control block. If we don't
2131  * have it we can't get rid of it but we can try to remove the fwd
2132  * pointer if desired.
2133  */
2134  if (!find_bound_string(&ddns_cb->rev_name, *scope, "ddns-rev-name")) {
2135  ddns_cb->flags &= ~DDNS_UPDATE_PTR;
2136  }
2137 
2138 
2139  /*
2140  * If we have a second control block for doing an add
2141  * after the remove finished attach it to our control block.
2142  */
2143  ddns_cb->next_op = add_ddns_cb;
2144 
2145  /*
2146  * Now that we've collected the information we can try to process it.
2147  * If necessary we call an appropriate routine to send a message and
2148  * provide it with an action routine to run on the control block given
2149  * the results of the message. We have three entry points from here,
2150  * one for removing the A record, the next for removing the PTR and
2151  * the third for doing any requested add.
2152  */
2153  if ((ddns_cb->flags & DDNS_UPDATE_ADDR) != 0) {
2154  if (ddns_cb->fwd_name.len != 0) {
2155  ddns_cb->state = DDNS_STATE_REM_FW_YXDHCID;
2156  ddns_cb->cur_func = ddns_fwd_srv_rem1;
2157 
2158  rcode = ddns_modify_fwd(ddns_cb, MDL);
2159  if (rcode == ISC_R_SUCCESS) {
2160  ddns_update_lease_ptr(lease, lease6, ddns_cb,
2161  ddns_cb, MDL);
2162  return (ISC_R_SUCCESS);
2163  }
2164 
2165  /*
2166  * We weren't able to process the request tag the
2167  * add so we won't execute it.
2168  */
2169  execute_add = ISC_R_FAILURE;
2170  goto cleanup;
2171  }
2172  else {
2173  /*remove info from scope */
2174  unset(*scope, "ddns-fwd-name");
2175  unset(*scope, ddns_cb->lease_tag);
2176  }
2177  }
2178 
2179  if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
2180  ddns_cb->state = DDNS_STATE_REM_PTR;
2181  ddns_cb->cur_func = ddns_ptr_remove;
2182  ddns_cb->flags |= DDNS_EXECUTE_NEXT;
2183 
2184  /*
2185  * if execute add isn't success remove the control block so
2186  * it won't be processed when the remove completes. We
2187  * also arrange to clean it up and get rid of it.
2188  */
2189  if (execute_add != ISC_R_SUCCESS) {
2190  ddns_cb->next_op = NULL;
2191  ddns_fwd_srv_connector(lease, lease6, scope,
2192  add_ddns_cb, execute_add);
2193  add_ddns_cb = NULL;
2194  }
2195  else {
2196  result = ISC_R_SUCCESS;
2197  }
2198 
2199  rcode = ddns_modify_ptr(ddns_cb, MDL);
2200  if (rcode == ISC_R_SUCCESS) {
2201  ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb,
2202  MDL);
2203  return (result);
2204  }
2205 
2206  /* We weren't able to process the request tag the
2207  * add so we won't execute it */
2208  execute_add = ISC_R_FAILURE;
2209  goto cleanup;
2210  }
2211 
2212  cleanup:
2213  /*
2214  * We've gotten here because we didn't need to send a message or
2215  * we failed when trying to do so. We send the additional cb
2216  * off to handle sending and/or cleanup and cleanup anything
2217  * we allocated here.
2218  */
2219  ddns_fwd_srv_connector(lease, lease6, scope, add_ddns_cb, execute_add);
2220  if (ddns_cb != NULL)
2221  destroy_ddns_cb(ddns_cb, MDL);
2222 
2223  return (result);
2224 }
2225 
2226 /* Convenience function for setting flag bits in a mask */
2227 void set_flag (u_int16_t *flags,
2228  u_int16_t flag,
2229  u_int16_t value) {
2230  if (flags) {
2231  if (value) {
2232  *flags |= flag;
2233  } else {
2234  *flags &= ~flag;
2235  }
2236  }
2237 }
2238 
2239 /*
2240  * Convenience function which replicates the conflict flags set in one
2241  * mask to another, while preserving all other flags.
2242  */
2243 void copy_conflict_flags(u_int16_t *target,
2244  u_int16_t source) {
2245  if (target) {
2246  /* Preserve non conflict flags */
2247  *target &= ~CONFLICT_BITS;
2248 
2249  /* Enable conflict flags per source */
2250  *target |= source & CONFLICT_BITS;
2251  }
2252 }
2253 
2254 /*
2255  * Given an option_state, create a mask of conflict detection flags based
2256  * on the appropriate configuration parameters within the option state.
2257  */
2258 u_int16_t
2259 get_conflict_mask(struct option_state *options) {
2260 
2261  int ddns_update_conflict_detection = 1; /* default on */
2262  int ddns_dual_stack_mixed_mode = 0; /* default off */
2263  int ddns_guard_id_must_match = 1; /* default on */
2264  int ddns_other_guard_is_dynamic = 0; /* default off */
2265  struct option_cache *oc = NULL;
2266 
2267  u_int16_t mask = 0;
2269  if (oc) {
2270  ddns_update_conflict_detection =
2271  evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options,
2272  NULL, &global_scope, oc, MDL);
2273  }
2274 
2275  set_flag(&mask, DDNS_CONFLICT_DETECTION,
2276  ddns_update_conflict_detection);
2277 
2278  if (!ddns_update_conflict_detection) {
2279 #if defined (DEBUG_DNS_UPDATES)
2280  log_info ("DDNS conflict detection: off");
2281 #endif
2282  /* Turn the rest of the conflict related flags off */
2283  set_flag(&mask, DDNS_DUAL_STACK_MIXED_MODE, 0);
2284  set_flag(&mask, DDNS_GUARD_ID_MUST_MATCH, 0);
2285  set_flag(&mask, DDNS_OTHER_GUARD_IS_DYNAMIC, 0);
2286  return (mask);
2287  }
2288 
2289  // Get the values
2290  oc = lookup_option(&server_universe, options,
2292  if (oc) {
2293  ddns_dual_stack_mixed_mode =
2294  evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options,
2295  NULL, &global_scope, oc, MDL);
2296  }
2297 
2298  oc = lookup_option(&server_universe, options,
2300  if (oc) {
2301  ddns_guard_id_must_match =
2302  evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options,
2303  NULL, &global_scope, oc, MDL);
2304  }
2305 
2306  oc = lookup_option(&server_universe, options,
2308  if (oc) {
2309  ddns_other_guard_is_dynamic =
2310  evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options,
2311  NULL, &global_scope, oc, MDL);
2312  }
2313 
2314  // Set the flags
2315  set_flag(&mask, DDNS_DUAL_STACK_MIXED_MODE,
2316  ddns_dual_stack_mixed_mode);
2317 
2318  set_flag(&mask, DDNS_GUARD_ID_MUST_MATCH,
2319  ddns_guard_id_must_match);
2320 
2321  set_flag(&mask, DDNS_OTHER_GUARD_IS_DYNAMIC,
2322  ddns_other_guard_is_dynamic);
2323 
2324 #if defined (DEBUG_DNS_UPDATES)
2325  log_info ("DDNS conflict behavior:\n"
2326  "\tddns-update-style: %s\n"
2327  "\tupdate-conflict-detection: %d\n"
2328  "\tddns-dual-stack-mixed-mode: %d\n"
2329  "\tddns-guard-id-must-match %d\n"
2330  "\tddns-other-guard-is-dynamic: %d\n",
2332  ddns_update_conflict_detection,
2333  ddns_dual_stack_mixed_mode,
2334  ddns_guard_id_must_match,
2335  ddns_other_guard_is_dynamic);
2336 #endif
2337  return (mask);
2338 }
2339 
2340 #if defined (DEBUG_DNS_UPDATES)
2341 /* Type used for creating lists of function pointers and their names */
2342 typedef struct {
2343  void *ptr;
2344  char *name;
2345 } LabeledPtr;
2346 
2347 /* Returns the name of the function referred to by the given address */
2348 char*
2349 dump_ddns_cb_func(void *func) {
2350  static LabeledPtr funcs[] = {
2351  { ddns_ptr_add, "ddns_ptr_add" },
2352  { ddns_fwd_srv_add2, "ddns_fwd_srv_add2" },
2353  { ddns_fwd_srv_add1, "ddns_fwd_srv_add1" },
2354  { ddns_ptr_remove, "ddns_ptr_remove" },
2355  { ddns_fwd_srv_rem2, "ddns_fwd_srv_rem2" },
2356  { ddns_fwd_srv_rem1, "ddns_fwd_srv_rem1" },
2357  { ddns_fwd_srv_add3, "ddns_fwd_srv_adde" },
2358  { NULL, "unknown" }
2359  };
2360 
2361  LabeledPtr* lp = funcs;
2362  if (!func) {
2363  return ("<null>");
2364  }
2365 
2366  while ((lp->ptr) && (lp->ptr != func)) {
2367  ++lp;
2368  }
2369 
2370  return (lp->name);
2371 }
2372 
2373 /* Dumps basic control block info to the log */
2374 char*
2375 dump_ddns_cb (dhcp_ddns_cb_t *ddns_cb) {
2376  static char output_buf[4096];
2377  if (!ddns_cb) {
2378  return ("<ddns_cb is null>");
2379  }
2380 
2381  sprintf (output_buf, "ddns_cb: %p flags: %x state: %s cur_func: %s",
2382  ddns_cb, ddns_cb->flags,
2383  ddns_state_name(ddns_cb->state),
2384  dump_ddns_cb_func(ddns_cb->cur_func));
2385 
2386  return(output_buf);
2387 }
2388 #endif /* DEBUG_DNS_UPDATES */
2389 
2390 #endif /* NSUPDATE */
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 data_string_new(struct data_string *new_string, const char *src, unsigned int len, const char *file, int line)
Constructs a null-terminated data_string from a char* and length.
Definition: alloc.c:1272
void data_string_copy(struct data_string *dest, const struct data_string *src, const char *file, int line)
Definition: alloc.c:1323
int buffer_dereference(struct buffer **ptr, const char *file, int line)
Definition: alloc.c:726
struct option_cache * lookup_option(struct universe *universe, struct option_state *options, unsigned code)
Definition: options.c:2503
int save_option_buffer(struct universe *universe, struct option_state *options, struct buffer *bp, unsigned char *buffer, unsigned length, unsigned code, int terminatep)
Definition: options.c:2545
u_int32_t getULong(const unsigned char *)
isc_boolean_t
Definition: data.h:150
#define ISC_TRUE
Definition: data.h:153
#define ISC_FALSE
Definition: data.h:152
char * ddns_standard_tag
Definition: ddns.c:38
char * ddns_interim_tag
Definition: ddns.c:39
int commit_leases()
Definition: dhclient.c:2104
int write_lease(struct lease *lease)
Definition: dhclient.c:2109
#define D6O_IA_TA
Definition: dhcp6.h:33
#define D6O_IA_NA
Definition: dhcp6.h:32
#define FQDN_FQDN
Definition: dhcp.h:199
#define FQDN_RCODE1
Definition: dhcp.h:195
#define FQDN_SERVER_UPDATE
Definition: dhcp.h:193
#define DHO_DHCP_CLIENT_IDENTIFIER
Definition: dhcp.h:150
#define FQDN_NO_CLIENT_UPDATE
Definition: dhcp.h:192
#define FQDN_ENCODED
Definition: dhcp.h:194
#define FQDN_RCODE2
Definition: dhcp.h:196
#define FQDN_DOMAINNAME
Definition: dhcp.h:198
#define DEFAULT_DDNS_TTL
Definition: dhcpd.h:870
#define SV_DDNS_DOMAIN_NAME
Definition: dhcpd.h:733
#define SV_UPDATE_STATIC_LEASES
Definition: dhcpd.h:753
#define DDNS_STATIC_LEASE
Definition: dhcpd.h:1779
#define SV_DO_FORWARD_UPDATES
Definition: dhcpd.h:755
#define SV_DDNS_CONFLICT_DETECT
Definition: dhcpd.h:758
#define SV_DDNS_TTL
Definition: dhcpd.h:748
#define SV_DDNS_REV_DOMAIN_NAME
Definition: dhcpd.h:735
#define DDNS_EXECUTE_NEXT
Definition: dhcpd.h:1777
#define DDNS_GUARD_ID_MUST_MATCH
Definition: dhcpd.h:1782
#define SV_CLIENT_UPDATES
Definition: dhcpd.h:750
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:1799
#define DDNS_STATE_ADD_FW_YXDHCID
Definition: dhcpd.h:1794
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:1800
#define MAX_DEFAULT_DDNS_TTL
Definition: dhcpd.h:873
#define cur_time
Definition: dhcpd.h:2121
#define STATIC_LEASE
Definition: dhcpd.h:592
u_int16_t get_conflict_mask(struct option_state *input_options)
#define DDNS_STATE_ADD_FW_NXDOMAIN
Definition: dhcpd.h:1793
#define DDNS_UPDATE_ADDR
Definition: dhcpd.h:1772
#define DDNS_STATE_ADD_PTR
Definition: dhcpd.h:1795
int ddns_updates(struct packet *, struct lease *, struct lease *, struct iasubopt *, struct iasubopt *, struct option_state *)
isc_result_t dhcid_fromlease(struct data_string *, struct data_string *)
#define SV_DDNS_HOST_NAME
Definition: dhcpd.h:734
#define SV_DDNS_GUARD_ID_MUST_MATCH
Definition: dhcpd.h:817
#define MAX_ADDRESS_STRING_LEN
Definition: dhcpd.h:3904
void ddns_cb_forget_zone(dhcp_ddns_cb_t *ddns_cb)
struct universe server_universe
Definition: stables.c:176
isc_result_t ia_dereference(struct ia_xx **ia, const char *file, int line)
Definition: mdb6.c:403
#define DDNS_STATE_DSMM_FW_ADD3
Definition: dhcpd.h:1796
#define DDNS_ACTIVE_LEASE
Definition: dhcpd.h:1780
#define DDNS_UPDATE_STYLE_INTERIM
Definition: dhcpd.h:706
#define SV_USE_HOST_DECL_NAMES
Definition: dhcpd.h:722
#define DDNS_STATE_REM_FW_YXDHCID
Definition: dhcpd.h:1798
#define DDNS_UPDATE_STYLE_STANDARD
Definition: dhcpd.h:707
isc_result_t find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type, const struct in6_addr *addr)
Definition: mdb6.c:2291
const char int line
Definition: dhcpd.h:3793
int find_lease_by_ip_addr(struct lease **, struct iaddr, const char *, int)
Definition: mdb.c:2052
isc_result_t ipv6_pool_dereference(struct ipv6_pool **pool, const char *file, int line)
de-reference an IPv6 pool structure.
Definition: mdb6.c:777
isc_result_t ddns_modify_ptr(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
int write_ia(const struct ia_xx *)
Definition: db.c:518
#define SV_DDNS_OTHER_GUARD_IS_DYNAMIC
Definition: dhcpd.h:818
#define DDNS_STATE_CLEANUP
Definition: dhcpd.h:1791
char * ddns_state_name(int state)
isc_result_t iasubopt_dereference(struct iasubopt **iasubopt, const char *file, int line)
Definition: mdb6.c:261
isc_result_t ddns_removals(struct lease *, struct iasubopt *, struct dhcp_ddns_cb *, isc_boolean_t)
#define SV_DDNS_DUAL_STACK_MIXED_MODE
Definition: dhcpd.h:816
#define DDNS_OTHER_GUARD_IS_DYNAMIC
Definition: dhcpd.h:1783
int get_dhcid(dhcp_ddns_cb_t *, int, const u_int8_t *, unsigned)
#define SV_UPDATE_OPTIMIZATION
Definition: dhcpd.h:751
#define DDNS_CLIENT_DID_UPDATE
Definition: dhcpd.h:1776
#define DDNS_CONFLICT_DETECTION
Definition: dhcpd.h:1775
dhcp_ddns_cb_t * ddns_cb_alloc(const char *file, int line)
#define DDNS_UPDATE_PTR
Definition: dhcpd.h:1773
#define DDNS_STATE_REM_FW_DSMM_OTHER
Definition: dhcpd.h:1801
int find_lease(struct lease **, struct packet *, struct shared_network *, int *, int *, struct lease *, const char *, int)
Definition: dhcp.c:4213
int ddns_update_style
Definition: dhcpd.c:84
void ddns_cb_free(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
void cleanup(void)
isc_result_t ia_reference(struct ia_xx **ia, struct ia_xx *src, const char *file, int line)
Definition: mdb6.c:377
#define CONFLICT_BITS
Definition: dhcpd.h:1785
const char * file
Definition: dhcpd.h:3793
#define DDNS_DUAL_STACK_MIXED_MODE
Definition: dhcpd.h:1781
u_int16_t ddns_conflict_mask
#define SV_FQDN_REPLY
Definition: dhcpd.h:762
#define SV_DO_REVERSE_UPDATES
Definition: dhcpd.h:761
const char * piaddr(const struct iaddr addr)
Definition: inet.c:579
#define ISC_R_SUCCESS
#define MDL
Definition: omapip.h:567
int log_error(const char *,...) __attribute__((__format__(__printf__
void log_fatal(const char *,...) __attribute__((__format__(__printf__
int int log_info(const char *,...) __attribute__((__format__(__printf__
struct enumeration_value ddns_styles_values[]
Definition: stables.c:355
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
dns_rdataclass_t other_dhcid_class
Definition: dhcpd.h:1844
int state
Definition: dhcpd.h:1831
struct data_string fwd_name
Definition: dhcpd.h:1815
u_int16_t flags
Definition: dhcpd.h:1829
char * lease_tag
Definition: dhcpd.h:1845
struct ia_xx * fixed6_ia
Definition: dhcpd.h:1846
dns_rdataclass_t dhcid_class
Definition: dhcpd.h:1843
struct dns_zone * zone
Definition: dhcpd.h:1827
ddns_action_t cur_func
Definition: dhcpd.h:1832
struct iaddr address
Definition: dhcpd.h:1818
struct data_string rev_name
Definition: dhcpd.h:1816
unsigned long ttl
Definition: dhcpd.h:1821
struct dhcp_ddns_cb * next_op
Definition: dhcpd.h:1834
struct data_string dhcid
Definition: dhcpd.h:1817
u_int8_t hlen
Definition: dhcpd.h:492
u_int8_t hbuf[HARDWARE_ADDR_LEN+1]
Definition: dhcpd.h:493
char * name
Definition: dhcpd.h:974
struct data_string iaid_duid
Definition: dhcpd.h:1678
unsigned char iabuf[16]
Definition: inet.h:33
unsigned len
Definition: inet.h:32
int static_lease
Definition: dhcpd.h:1673
struct dhcp_ddns_cb * ddns_cb
Definition: dhcpd.h:1669
u_int32_t prefer
Definition: dhcpd.h:1649
struct in6_addr addr
Definition: dhcpd.h:1643
struct ia_xx * ia
Definition: dhcpd.h:1651
struct binding_scope * scope
Definition: dhcpd.h:1646
ipv6_pool structure
Definition: dhcpd.h:1710
Definition: dhcpd.h:560
TIME ends
Definition: dhcpd.h:570
u_int8_t flags
Definition: dhcpd.h:591
struct dhcp_ddns_cb * ddns_cb
Definition: dhcpd.h:650
struct binding_scope * scope
Definition: dhcpd.h:575
struct iaddr ip_addr
Definition: dhcpd.h:569
struct hardware hardware_addr
Definition: dhcpd.h:589
unsigned char * uid
Definition: dhcpd.h:585
struct host_decl * host
Definition: dhcpd.h:576
unsigned short uid_len
Definition: dhcpd.h:586
Definition: dhcpd.h:405
struct option_state * options
Definition: dhcpd.h:449
Definition: dhcpd.h:1025
struct universe fqdn_universe
Definition: tables.c:315
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
int evaluate_boolean_option_cache(int *ignorep, 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:2733
int bind_ds_value(struct binding_scope **scope, const char *name, struct data_string *value)
Definition: tree.c:4080
int unset(struct binding_scope *scope, const char *name)
Definition: tree.c:4134
struct binding_scope * global_scope
Definition: tree.c:38
int find_bound_string(struct data_string *value, struct binding_scope *scope, const char *name)
Definition: tree.c:4103
Definition: data.h:205