ISC DHCP  4.4.1
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  * never reached. update_lease_failed
1289  * calls log_fatal.
1290  */
1291  return(ISC_R_FAILURE);
1292  }
1294  } else {
1295  /* shouldn't get here */
1296  log_fatal("Impossible condition at %s:%d, called from %s:%d.",
1297  MDL, file, line);
1298  }
1299 
1300  return(ISC_R_SUCCESS);
1301 }
1302 
1303 void
1304 ddns_ptr_add(dhcp_ddns_cb_t *ddns_cb,
1305  isc_result_t eresult)
1306 {
1307  if (eresult == ISC_R_SUCCESS) {
1308  log_info("Added reverse map from %.*s to %.*s",
1309  (int)ddns_cb->rev_name.len,
1310  (const char *)ddns_cb->rev_name.data,
1311  (int)ddns_cb->fwd_name.len,
1312  (const char *)ddns_cb->fwd_name.data);
1313 
1314  ddns_update_lease_text(ddns_cb, NULL);
1315  } else {
1316  log_error("Unable to add reverse map from %.*s to %.*s: %s",
1317  (int)ddns_cb->rev_name.len,
1318  (const char *)ddns_cb->rev_name.data,
1319  (int)ddns_cb->fwd_name.len,
1320  (const char *)ddns_cb->fwd_name.data,
1321  isc_result_totext (eresult));
1322  }
1323 
1324  ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1325  destroy_ddns_cb(ddns_cb, MDL);
1326  /*
1327  * A single DDNS operation may require several calls depending on
1328  * the current state as the prerequisites for the first message
1329  * may not succeed requiring a second operation and potentially
1330  * a ptr operation after that. The commit_leases operation is
1331  * invoked at the end of this set of operations in order to require
1332  * a single write for all of the changes. We call commit_leases
1333  * here rather than immediately after the call to update the lease
1334  * text in order to save any previously written data.
1335  */
1336  commit_leases();
1337  return;
1338 }
1339 
1340 /*
1341  * action routine when trying to remove a pointer
1342  * this will be called after the ddns queries have completed
1343  * if we succeeded in removing the pointer we go to the next step (if any)
1344  * if not we cleanup and leave.
1345  */
1346 
1347 void
1348 ddns_ptr_remove(dhcp_ddns_cb_t *ddns_cb,
1349  isc_result_t eresult)
1350 {
1351  isc_result_t result = eresult;
1352 
1353  switch(eresult) {
1354  case ISC_R_SUCCESS:
1355  log_info("Removed reverse map on %.*s",
1356  (int)ddns_cb->rev_name.len,
1357  (const char *)ddns_cb->rev_name.data);
1358  /* fall through */
1359  case DNS_R_NXRRSET:
1360  case DNS_R_NXDOMAIN:
1361  /* No entry is the same as success.
1362  * Remove the information from the lease and
1363  * continue with any next step */
1364  ddns_update_lease_text(ddns_cb, NULL);
1365 
1366  /* trigger any add operation */
1367  result = ISC_R_SUCCESS;
1368 #if defined (DEBUG_DNS_UPDATES)
1369  log_info("DDNS: removed map or no reverse map to remove %.*s",
1370  (int)ddns_cb->rev_name.len,
1371  (const char *)ddns_cb->rev_name.data);
1372 #endif
1373  break;
1374 
1375  default:
1376  log_error("Can't remove reverse map on %.*s: %s",
1377  (int)ddns_cb->rev_name.len,
1378  (const char *)ddns_cb->rev_name.data,
1379  isc_result_totext (eresult));
1380  break;
1381  }
1382 
1383  /* If we aren't suppossed to do the next step, set the result
1384  * flag so ddns_fwd_srv_connector won't do much
1385  */
1386  if ((ddns_cb->flags & DDNS_EXECUTE_NEXT) == 0)
1387  result = ISC_R_FAILURE;
1388 
1389  ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1390  ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, result);
1391  destroy_ddns_cb(ddns_cb, MDL);
1392  return;
1393 }
1394 
1395 
1396 /*
1397  * If the first query succeeds, the updater can conclude that it
1398  * has added a new name whose only RRs are the A and DHCID RR records.
1399  * The A RR update is now complete (and a client updater is finished,
1400  * while a server might proceed to perform a PTR RR update).
1401  * -- "Interaction between DHCP and DNS"
1402  *
1403  * If the second query succeeds, the updater can conclude that the current
1404  * client was the last client associated with the domain name, and that
1405  * the name now contains the updated A RR. The A RR update is now
1406  * complete (and a client updater is finished, while a server would
1407  * then proceed to perform a PTR RR update).
1408  * -- "Interaction between DHCP and DNS"
1409  *
1410  * If the second query fails with NXRRSET, the updater must conclude
1411  * that the client's desired name is in use by another host. If
1412  * Dual Stack Mixed Mode (DSMM) is enabled and we proceed to a
1413  * third stage forward update attempt specific to DSMM rules. If not,
1414  * then the existing entries are left intact:
1415  *
1416  * At this juncture, the updater can decide (based on some administrative
1417  * configuration outside of the scope of this document) whether to let
1418  * the existing owner of the name keep that name, and to (possibly)
1419  * perform some name disambiguation operation on behalf of the current
1420  * client, or to replace the RRs on the name with RRs that represent
1421  * the current client. If the configured policy allows replacement of
1422  * existing records, the updater submits a query that deletes the
1423  * existing A RR and the existing DHCID RR, adding A and DHCID RRs that
1424  * represent the IP address and client-identity of the new client.
1425  * -- "Interaction between DHCP and DNS"
1426  */
1427 
1428 void
1429 ddns_fwd_srv_add2(dhcp_ddns_cb_t *ddns_cb,
1430  isc_result_t eresult)
1431 {
1432  isc_result_t result;
1433  const char *logstr = NULL;
1434  char ddns_address[MAX_ADDRESS_STRING_LEN];
1435 
1436 #if defined (DEBUG_DNS_UPDATES)
1437  log_info ("DDNS:ddns_fwd_srv_add2: %s eresult: %d",
1438  dump_ddns_cb(ddns_cb), eresult);
1439 #endif
1440 
1441  /* Construct a printable form of the address for logging */
1442  strcpy(ddns_address, piaddr(ddns_cb->address));
1443 
1444  switch(eresult) {
1445  case ISC_R_SUCCESS:
1446  log_info("Added new forward map from %.*s to %s",
1447  (int)ddns_cb->fwd_name.len,
1448  (const char *)ddns_cb->fwd_name.data,
1449  ddns_address);
1450 
1451  ddns_update_lease_text(ddns_cb, NULL);
1452 
1453  if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1454  /* if we have zone information get rid of it */
1455  if (ddns_cb->zone != NULL) {
1456  ddns_cb_forget_zone(ddns_cb);
1457  }
1458 
1459  ddns_cb->state = DDNS_STATE_ADD_PTR;
1460  ddns_cb->cur_func = ddns_ptr_add;
1461 
1462  result = ddns_modify_ptr(ddns_cb, MDL);
1463  if (result == ISC_R_SUCCESS) {
1464  return;
1465  }
1466  }
1467  break;
1468 
1469  case DNS_R_YXRRSET:
1470  case DNS_R_YXDOMAIN:
1471  logstr = "DHCID mismatch, belongs to another client.";
1472  break;
1473 
1474  case DNS_R_NXDOMAIN:
1475  case DNS_R_NXRRSET:
1476  /* If DSMM is on we need to try forward add3 */
1477  if (ddns_cb->flags & DDNS_DUAL_STACK_MIXED_MODE) {
1478  ddns_cb->state = DDNS_STATE_DSMM_FW_ADD3;
1479  ddns_cb->cur_func = ddns_fwd_srv_add3;
1480 
1481  result = ddns_modify_fwd(ddns_cb, MDL);
1482  if (result == ISC_R_SUCCESS) {
1483  return;
1484  }
1485 
1486  break;
1487  }
1488 
1489  logstr = "Has an address record but no DHCID, not mine.";
1490  break;
1491 
1492  default:
1493  logstr = isc_result_totext(eresult);
1494  break;
1495  }
1496 
1497  if (logstr != NULL) {
1498  log_error("Forward map from %.*s to %s FAILED: %s",
1499  (int)ddns_cb->fwd_name.len,
1500  (const char *)ddns_cb->fwd_name.data,
1501  ddns_address, logstr);
1502  }
1503 
1504  ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1505  destroy_ddns_cb(ddns_cb, MDL);
1506  /*
1507  * A single DDNS operation may require several calls depending on
1508  * the current state as the prerequisites for the first message
1509  * may not succeed requiring a second operation and potentially
1510  * a ptr operation after that. The commit_leases operation is
1511  * invoked at the end of this set of operations in order to require
1512  * a single write for all of the changes. We call commit_leases
1513  * here rather than immediately after the call to update the lease
1514  * text in order to save any previously written data.
1515  */
1516  commit_leases();
1517  return;
1518 }
1519 
1520 void
1521 ddns_fwd_srv_add1(dhcp_ddns_cb_t *ddns_cb,
1522  isc_result_t eresult)
1523 {
1524  isc_result_t result;
1525  char ddns_address[MAX_ADDRESS_STRING_LEN];
1526 
1527 #if defined (DEBUG_DNS_UPDATES)
1528  log_info ("DDNS: ddns_fwd_srv_add1: %s eresult: %d",
1529  dump_ddns_cb(ddns_cb), eresult);
1530 #endif
1531 
1532  /* Construct a printable form of the address for logging */
1533  strcpy(ddns_address, piaddr(ddns_cb->address));
1534 
1535  switch(eresult) {
1536  case ISC_R_SUCCESS:
1537  log_info ("Added new forward map from %.*s to %s",
1538  (int)ddns_cb->fwd_name.len,
1539  (const char *)ddns_cb->fwd_name.data,
1540  ddns_address);
1541 
1542  ddns_update_lease_text(ddns_cb, NULL);
1543 
1544  if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1545  /* if we have zone information get rid of it */
1546  if (ddns_cb->zone != NULL) {
1547  ddns_cb_forget_zone(ddns_cb);
1548  }
1549 
1550  ddns_cb->state = DDNS_STATE_ADD_PTR;
1551  ddns_cb->cur_func = ddns_ptr_add;
1552 
1553  result = ddns_modify_ptr(ddns_cb, MDL);
1554  if (result == ISC_R_SUCCESS) {
1555  return;
1556  }
1557  }
1558  break;
1559 
1560  case DNS_R_YXDOMAIN:
1561  /* we can reuse the zone information */
1562  ddns_cb->state = DDNS_STATE_ADD_FW_YXDHCID;
1563  ddns_cb->cur_func = ddns_fwd_srv_add2;
1564 
1565  result = ddns_modify_fwd(ddns_cb, MDL);
1566  if (result == ISC_R_SUCCESS) {
1567  return;
1568  }
1569  break;
1570  default:
1571  log_error ("Unable to add forward map from %.*s to %s: %s",
1572  (int)ddns_cb->fwd_name.len,
1573  (const char *)ddns_cb->fwd_name.data,
1574  ddns_address,
1575  isc_result_totext (eresult));
1576  break;
1577  }
1578 
1579  ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1580  destroy_ddns_cb(ddns_cb, MDL);
1581  /*
1582  * A single DDNS operation may require several calls depending on
1583  * the current state as the prerequisites for the first message
1584  * may not succeed requiring a second operation and potentially
1585  * a ptr operation after that. The commit_leases operation is
1586  * invoked at the end of this set of operations in order to require
1587  * a single write for all of the changes. We call commit_leases
1588  * here rather than immediately after the call to update the lease
1589  * text in order to save any previously written data.
1590  */
1591  commit_leases();
1592  return;
1593 }
1594 
1595 /*
1596  * This action routine is invoked after the DSMM third add stage is
1597  * attempted. If we succeeded we attempt to update the reverse DNS,
1598  * if not we cleanup and leave.
1599  */
1600 void
1601 ddns_fwd_srv_add3(dhcp_ddns_cb_t *ddns_cb,
1602  isc_result_t eresult)
1603 {
1604  isc_result_t result;
1605  const char *logstr = NULL;
1606  char ddns_address[MAX_ADDRESS_STRING_LEN+1];
1607 
1608 #if defined (DEBUG_DNS_UPDATES)
1609  log_info ("DDNS: ddns_fwd_srv_add3: %s eresult: %d",
1610  dump_ddns_cb(ddns_cb), eresult);
1611 #endif
1612 
1613  /* Construct a printable form of the address for logging */
1614  memset(ddns_address, 0x0, sizeof(ddns_address));
1615  strncpy(ddns_address, piaddr(ddns_cb->address),
1616  sizeof(ddns_address) - 1);
1617 
1618  switch(eresult) {
1619  case ISC_R_SUCCESS:
1620  log_info("Added new forward map from %.*s to %s",
1621  (int)ddns_cb->fwd_name.len,
1622  (const char *)ddns_cb->fwd_name.data,
1623  ddns_address);
1624 
1625  ddns_update_lease_text(ddns_cb, NULL);
1626 
1627  if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1628  /* if we have zone information get rid of it */
1629  if (ddns_cb->zone != NULL) {
1630  ddns_cb_forget_zone(ddns_cb);
1631  }
1632 
1633  ddns_cb->state = DDNS_STATE_ADD_PTR;
1634  ddns_cb->cur_func = ddns_ptr_add;
1635 
1636  result = ddns_modify_ptr(ddns_cb, MDL);
1637  if (result == ISC_R_SUCCESS) {
1638  return;
1639  }
1640  }
1641  break;
1642 
1643  case DNS_R_YXRRSET:
1644  logstr = "an entry that is either static or "
1645  "owned by another client exists.";
1646  break;
1647 
1648  case DNS_R_NXRRSET:
1649  logstr = "static entry of the other protocol type exists.";
1650  break;
1651 
1652  default:
1653  logstr = isc_result_totext(eresult);
1654  break;
1655  }
1656 
1657  if (logstr != NULL) {
1658  log_error("Forward map from %.*s to %s FAILED: %s",
1659  (int)ddns_cb->fwd_name.len,
1660  (const char *)ddns_cb->fwd_name.data,
1661  ddns_address, logstr);
1662  }
1663 
1664  ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1665  destroy_ddns_cb(ddns_cb, MDL);
1666  /*
1667  * A single DDNS operation may require several calls depending on
1668  * the current state as the prerequisites for the first message
1669  * may not succeed requiring a second operation and potentially
1670  * a ptr operation after that. The commit_leases operation is
1671  * invoked at the end of this set of operations in order to require
1672  * a single write for all of the changes. We call commit_leases
1673  * here rather than immediately after the call to update the lease
1674  * text in order to save any previously written data.
1675  */
1676  commit_leases();
1677  return;
1678 }
1679 
1680 static void
1681 ddns_fwd_srv_connector(struct lease *lease,
1682  struct iasubopt *lease6,
1683  struct binding_scope **inscope,
1684  dhcp_ddns_cb_t *ddns_cb,
1685  isc_result_t eresult)
1686 {
1687  isc_result_t result = ISC_R_FAILURE;
1688 
1689 #if defined (DEBUG_DNS_UPDATES)
1690  log_info ("DDNS: ddns_fwd_srv_connector: %s eresult: %d",
1691  dump_ddns_cb(ddns_cb), eresult);
1692 #endif
1693 
1694  if (ddns_cb == NULL) {
1695  /* nothing to do */
1696  return;
1697  }
1698 
1699  if (eresult == ISC_R_SUCCESS) {
1700  /*
1701  * If we have updates dispatch as appropriate,
1702  * if not do FQDN binding if desired.
1703  */
1704 
1705  if (ddns_cb->flags & DDNS_UPDATE_ADDR) {
1706  ddns_cb->state = DDNS_STATE_ADD_FW_NXDOMAIN;
1707  ddns_cb->cur_func = ddns_fwd_srv_add1;
1708  result = ddns_modify_fwd(ddns_cb, MDL);
1709  } else if ((ddns_cb->flags & DDNS_UPDATE_PTR) &&
1710  (ddns_cb->rev_name.len != 0)) {
1711  ddns_cb->state = DDNS_STATE_ADD_PTR;
1712  ddns_cb->cur_func = ddns_ptr_add;
1713  result = ddns_modify_ptr(ddns_cb, MDL);
1714  } else {
1715  ddns_update_lease_text(ddns_cb, inscope);
1716  }
1717  }
1718 
1719 
1720  if (result == ISC_R_SUCCESS) {
1721  ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, MDL);
1722  } else {
1723  destroy_ddns_cb(ddns_cb, MDL);
1724  }
1725 
1726  return;
1727 }
1728 
1729 /*
1730  * If the first query fails, the updater MUST NOT delete the DNS name. It
1731  * may be that the host whose lease on the server has expired has moved
1732  * to another network and obtained a lease from a different server,
1733  * which has caused the client's A RR to be replaced. It may also be
1734  * that some other client has been configured with a name that matches
1735  * the name of the DHCP client, and the policy was that the last client
1736  * to specify the name would get the name. In this case, the DHCID RR
1737  * will no longer match the updater's notion of the client-identity of
1738  * the host pointed to by the DNS name.
1739  * -- "Interaction between DHCP and DNS"
1740  */
1741 
1742 void
1743 ddns_fwd_srv_rem2(dhcp_ddns_cb_t *ddns_cb,
1744  isc_result_t eresult)
1745 {
1746 #if defined (DEBUG_DNS_UPDATES)
1747  log_info ("DDNS: ddns_fwd_srv_rem2: %s eresult: %d",
1748  dump_ddns_cb(ddns_cb), eresult);
1749 #endif
1750 
1751  /*
1752  * To get here we have already managed to remove the A/AAAA
1753  * record and are trying to remove the DHCID/TXT record as well.
1754  * On success (removed DHCID/TXT) or YXRRSET (DHCID/TXT still in
1755  * use by something else) we clean up the lease.
1756  * On some other error we don't clean up the lease and hope that
1757  * if we try this again it will work. An example would be if we
1758  * got a timeout as the DNS server halted between the first and
1759  * second steps. The DNS server would still have the DHCID/TXT
1760  * and we would like to remove that in the future.
1761  *
1762  * On success set the EXECUTE_NEXT flag which triggers any
1763  * add that is next in the chain.
1764  */
1765  if ((eresult == ISC_R_SUCCESS) ||
1766  (eresult == DNS_R_YXRRSET)) {
1767  ddns_update_lease_text(ddns_cb, NULL);
1768  eresult = ISC_R_SUCCESS;
1769  }
1770 
1771  /* Do the next operation */
1772  if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1773  /* if we have zone information get rid of it */
1774  if (ddns_cb->zone != NULL) {
1775  ddns_cb_forget_zone(ddns_cb);
1776  }
1777 
1778  ddns_cb->state = DDNS_STATE_REM_PTR;
1779  ddns_cb->cur_func = ddns_ptr_remove;
1780  if (eresult == ISC_R_SUCCESS)
1781  ddns_cb->flags |= DDNS_EXECUTE_NEXT;
1782 
1783  eresult = ddns_modify_ptr(ddns_cb, MDL);
1784  if (eresult == ISC_R_SUCCESS) {
1785  return;
1786  }
1787  }
1788 
1789  ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1790  ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult);
1791  destroy_ddns_cb(ddns_cb, MDL);
1792  return;
1793 }
1794 
1795 
1796 /*
1797  * First action routine when trying to remove a fwd
1798  * this will be called after the ddns queries have completed
1799  * if we succeeded in removing the fwd we go to the next step (if any)
1800  * if not we cleanup and leave.
1801  */
1802 
1803 void
1804 ddns_fwd_srv_rem1(dhcp_ddns_cb_t *ddns_cb,
1805  isc_result_t eresult)
1806 {
1807  isc_result_t result = eresult;
1808  char ddns_address[MAX_ADDRESS_STRING_LEN];
1809 
1810 #if defined (DEBUG_DNS_UPDATES)
1811  log_info ("DDNS: ddns_fwd_srv_rem1: %s eresult: %d",
1812  dump_ddns_cb(ddns_cb), eresult);
1813 #endif
1814 
1815  switch(eresult) {
1816  case ISC_R_SUCCESS:
1817  /* Construct a printable form of the address for logging */
1818  strcpy(ddns_address, piaddr(ddns_cb->address));
1819  log_info("Removed forward map from %.*s to %s",
1820  (int)ddns_cb->fwd_name.len,
1821  (const char*)ddns_cb->fwd_name.data,
1822  ddns_address);
1823 
1824  /* Do the second step of the FWD removal */
1825  ddns_cb->state = DDNS_STATE_REM_FW_NXRR;
1826  ddns_cb->cur_func = ddns_fwd_srv_rem2;
1827  result = ddns_modify_fwd(ddns_cb, MDL);
1828  if (result == ISC_R_SUCCESS) {
1829  return;
1830  }
1831  break;
1832 
1833  case DNS_R_NXRRSET:
1834  case DNS_R_NXDOMAIN:
1835  /* A result of not found means rem1 did not find a guard of
1836  * our * type. From this we assume either there are no address
1837  * record(s) of our type to delete or they are unguarded and
1838  * therefore presumed to be static. Either way, we're done
1839  * unless we're in DSMM and ddns-other-guard-is-dynamic is on.
1840  * In which case we need to see if a guard of the other type
1841  * exists, which permits us to delete any address records of
1842  * our type. */
1843  #define DSMM_OGD (DDNS_DUAL_STACK_MIXED_MODE | \
1844  DDNS_OTHER_GUARD_IS_DYNAMIC)
1845  if ((ddns_cb->flags & DSMM_OGD) == DSMM_OGD) {
1847  ddns_cb->cur_func = ddns_fwd_srv_rem2;
1848  result = ddns_modify_fwd(ddns_cb, MDL);
1849  if (result == ISC_R_SUCCESS) {
1850  return;
1851  }
1852  break;
1853  }
1854 
1855  ddns_update_lease_text(ddns_cb, NULL);
1856 
1857 #if defined (DEBUG_DNS_UPDATES)
1858  log_info("DDNS: no forward map to remove. %p", ddns_cb);
1859 #endif
1860  /* Trigger the add operation */
1861  eresult = ISC_R_SUCCESS;
1862 
1863  /* Fall through */
1864  default:
1865 
1866  /* We do the remove operation in most cases
1867  * but we don't want to continue with adding a forward
1868  * record if the forward removal had issues so we
1869  * check the eresult and set the EXECUTE_NEXT flag on
1870  * success.
1871  */
1872 
1873  /* Do the remove operation */
1874  if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1875  /* if we have zone information get rid of it */
1876  if (ddns_cb->zone != NULL) {
1877  ddns_cb_forget_zone(ddns_cb);
1878  }
1879 
1880  ddns_cb->state = DDNS_STATE_REM_PTR;
1881  ddns_cb->cur_func = ddns_ptr_remove;
1882  if (eresult == ISC_R_SUCCESS)
1883  ddns_cb->flags |= DDNS_EXECUTE_NEXT;
1884 
1885  result = ddns_modify_ptr(ddns_cb, MDL);
1886  if (result == ISC_R_SUCCESS) {
1887  return;
1888  }
1889  }
1890  break;
1891  }
1892 
1893  ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1894  ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult);
1895  destroy_ddns_cb(ddns_cb, MDL);
1896 }
1897 
1898 /*%<
1899  * Remove relevant entries from DNS.
1900  *
1901  * \li lease - lease to start with if this is for v4
1902  *
1903  * \li lease6 - lease to start with if this is for v6
1904  *
1905  * \li add_ddns_cb - control block for additional DDNS work. This
1906  * is used when the code is going to add a DDNS entry after removing
1907  * the current entry.
1908  *
1909  * \li active - indication about the status of the lease. It is
1910  * ISC_TRUE if the lease is still active, and FALSE if the lease
1911  * is inactive. This is used to indicate if the lease is inactive or going
1912  * to inactive so we can avoid trying to update the lease with cb pointers
1913  * and text information if it isn't useful.
1914  *
1915  * Returns
1916  * \li #ISC_R_FAILURE - badness occurred and we weren't able to do what was wanted
1917  * \li #ISC_R_SUCCESS - we were able to do stuff but it's in progress
1918  *
1919  * in both cases any additional block has been passed on to it's handler
1920  */
1921 
1922 isc_result_t
1923 ddns_removals(struct lease *lease,
1924  struct iasubopt *lease6,
1925  dhcp_ddns_cb_t *add_ddns_cb,
1926  isc_boolean_t active)
1927 {
1928  isc_result_t rcode, execute_add = ISC_R_FAILURE;
1929  struct binding_scope **scope = NULL;
1930  isc_result_t result = ISC_R_FAILURE;
1931  dhcp_ddns_cb_t *ddns_cb = NULL;
1932  struct data_string leaseid;
1933 
1934 #if defined (DEBUG_DNS_UPDATES)
1935  log_info ("DDNS: ddns_removals: %s",
1936  dump_ddns_cb(add_ddns_cb));
1937 #endif
1938 
1939  /*
1940  * See if we need to cancel an outstanding request. Mostly this is
1941  * used to handle the case where this routine is called twice for
1942  * the same release or abandon event.
1943  *
1944  * When called from the dns code as part of an update request
1945  * (add_ddns_cb != NULL) any outstanding requests will have already
1946  * been cancelled.
1947  *
1948  * If the new request is just a removal and we have an outstanding
1949  * request we have several options:
1950  *
1951  * - we are doing an update or we are doing a removal and the active
1952  * flag has changed from TRUE to FALSE. In these cases we need to
1953  * cancel the old request and start the new one.
1954  *
1955  * - other wise we are doing a removal with the active flag unchanged.
1956  * In this case we can let the current removal continue and do not need
1957  * to start a new one. If the old request included an update to be
1958  * done after the removal we need to kill the update part of the
1959  * request.
1960  */
1961 
1962  if (add_ddns_cb == NULL) {
1963  if ((lease != NULL) && (lease->ddns_cb != NULL)) {
1964  ddns_cb = lease->ddns_cb;
1965 
1966  /*
1967  * Is the old request an update or did the
1968  * the active flag change?
1969  */
1970  if (((ddns_cb->state == DDNS_STATE_ADD_PTR) ||
1971  (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) ||
1972  (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) ||
1973  ((active == ISC_FALSE) &&
1974  ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) {
1975  /* Cancel the current request */
1977  lease->ddns_cb = NULL;
1978  } else {
1979  /* Remvoval, check and remove updates */
1980  if (ddns_cb->next_op != NULL) {
1981  destroy_ddns_cb(ddns_cb->next_op, MDL);
1982  ddns_cb->next_op = NULL;
1983  }
1984 #if defined (DEBUG_DNS_UPDATES)
1985  log_info("DDNS %s(%d): removal already in "
1986  "progress new ddns_cb=%p",
1987  MDL, ddns_cb);
1988 #endif
1989  return (ISC_R_SUCCESS);
1990  }
1991  } else if ((lease6 != NULL) && (lease6->ddns_cb != NULL)) {
1992  ddns_cb = lease6->ddns_cb;
1993 
1994  /*
1995  * Is the old request an update or did the
1996  * the active flag change?
1997  */
1998  if (((ddns_cb->state == DDNS_STATE_ADD_PTR) ||
1999  (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) ||
2000  (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) ||
2001  ((active == ISC_FALSE) &&
2002  ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) {
2003  /* Cancel the current request */
2004  ddns_cancel(lease6->ddns_cb, MDL);
2005  lease6->ddns_cb = NULL;
2006  } else {
2007  /* Remvoval, check and remove updates */
2008  if (ddns_cb->next_op != NULL) {
2009  destroy_ddns_cb(ddns_cb->next_op, MDL);
2010  ddns_cb->next_op = NULL;
2011  }
2012 #if defined (DEBUG_DNS_UPDATES)
2013  log_info("DDNS %s(%d): removal already in "
2014  "progress new ddns_cb=%p",
2015  MDL, ddns_cb);
2016 #endif
2017  return (ISC_R_SUCCESS);
2018  }
2019  }
2020  ddns_cb = NULL;
2021  }
2022 
2023  /* allocate our control block */
2024  ddns_cb = ddns_cb_alloc(MDL);
2025  if (ddns_cb == NULL) {
2026  goto cleanup;
2027  }
2028 
2029  /* Set the conflict detection flags based on global configuration */
2030  copy_conflict_flags(&ddns_cb->flags, ddns_conflict_mask);
2031 
2032  /*
2033  * For v4 we flag static leases so we don't try
2034  * and manipulate the lease later. For v6 we don't
2035  * get static leases and don't need to flag them.
2036  */
2037  if (lease != NULL) {
2038  scope = &(lease->scope);
2039  ddns_cb->address = lease->ip_addr;
2040  if (lease->flags & STATIC_LEASE)
2041  ddns_cb->flags |= DDNS_STATIC_LEASE;
2042  } else if (lease6 != NULL) {
2043  scope = &(lease6->scope);
2044  memcpy(&ddns_cb->address.iabuf, lease6->addr.s6_addr, 16);
2045  ddns_cb->address.len = 16;
2046  } else
2047  goto cleanup;
2048 
2049  /*
2050  * Set the flag bit if the lease is active, that is it isn't
2051  * expired or released. This is used to determine if we need
2052  * to update the scope information for both v4 and v6 and
2053  * the lease information for v6 when the response
2054  * from the DNS code is processed.
2055  */
2056  if (active == ISC_TRUE) {
2057  ddns_cb->flags |= DDNS_ACTIVE_LEASE;
2058  }
2059 
2060  /* No scope implies that DDNS has not been performed for this lease. */
2061  if (*scope == NULL)
2062  goto cleanup;
2063 
2066  goto cleanup;
2067 
2068  /* Assume that we are removing both records */
2069  ddns_cb->flags |= DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR;
2070 
2071  /* and that we want to do the add call */
2072  execute_add = ISC_R_SUCCESS;
2073 
2074  /*
2075  * Look up stored names.
2076  */
2077 
2078  /*
2079  * Find the fwd name and copy it to the control block. If we don't
2080  * have it we can't delete the fwd record but we can still try to
2081  * remove the ptr record and cleanup the lease information if the
2082  * client did the fwd update.
2083  */
2084  if (!find_bound_string(&ddns_cb->fwd_name, *scope, "ddns-fwd-name")) {
2085  /* don't try and delete the A, or do the add */
2086  ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
2087  execute_add = ISC_R_FAILURE;
2088 
2089  /* Check if client did update */
2090  if (find_bound_string(&ddns_cb->fwd_name, *scope,
2091  "ddns-client-fqdn")) {
2092  ddns_cb->flags |= DDNS_CLIENT_DID_UPDATE;
2093  }
2094  }
2095 
2096  /*
2097  * Find the txt or dhcid tag and copy it to the control block. If we
2098  * don't have one this isn't an interim or standard record so we can't
2099  * delete the A record using this mechanism but we can delete the ptr
2100  * record. In this case we will attempt to do any requested next step.
2101  */
2102  memset(&leaseid, 0, sizeof(leaseid));
2103  if (find_bound_string (&leaseid, *scope, ddns_standard_tag)) {
2104  /* We have a standard tag */
2105  ddns_cb->lease_tag = ddns_standard_tag;
2106  ddns_cb->dhcid_class = dns_rdatatype_dhcid;
2107  ddns_cb->other_dhcid_class = dns_rdatatype_txt;
2108  data_string_copy(&ddns_cb->dhcid, &leaseid, MDL);
2109  data_string_forget(&leaseid, MDL);
2110  } else if (find_bound_string (&leaseid, *scope, ddns_interim_tag)) {
2111  /* we have an interim tag */
2112  ddns_cb->lease_tag = ddns_interim_tag;
2113  ddns_cb->dhcid_class = dns_rdatatype_txt;
2114  ddns_cb->other_dhcid_class = dns_rdatatype_dhcid;
2115  if (dhcid_fromlease(&ddns_cb->dhcid, &leaseid) !=
2116  ISC_R_SUCCESS) {
2117  /* We couldn't convert the dhcid from the lease
2118  * version to the dns version. We can't delete
2119  * the A record but can continue to the ptr
2120  */
2121  ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
2122  }
2123  data_string_forget(&leaseid, MDL);
2124  } else {
2125  ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
2126  }
2127 
2128  /*
2129  * Find the rev name and copy it to the control block. If we don't
2130  * have it we can't get rid of it but we can try to remove the fwd
2131  * pointer if desired.
2132  */
2133  if (!find_bound_string(&ddns_cb->rev_name, *scope, "ddns-rev-name")) {
2134  ddns_cb->flags &= ~DDNS_UPDATE_PTR;
2135  }
2136 
2137 
2138  /*
2139  * If we have a second control block for doing an add
2140  * after the remove finished attach it to our control block.
2141  */
2142  ddns_cb->next_op = add_ddns_cb;
2143 
2144  /*
2145  * Now that we've collected the information we can try to process it.
2146  * If necessary we call an appropriate routine to send a message and
2147  * provide it with an action routine to run on the control block given
2148  * the results of the message. We have three entry points from here,
2149  * one for removing the A record, the next for removing the PTR and
2150  * the third for doing any requested add.
2151  */
2152  if ((ddns_cb->flags & DDNS_UPDATE_ADDR) != 0) {
2153  if (ddns_cb->fwd_name.len != 0) {
2154  ddns_cb->state = DDNS_STATE_REM_FW_YXDHCID;
2155  ddns_cb->cur_func = ddns_fwd_srv_rem1;
2156 
2157  rcode = ddns_modify_fwd(ddns_cb, MDL);
2158  if (rcode == ISC_R_SUCCESS) {
2159  ddns_update_lease_ptr(lease, lease6, ddns_cb,
2160  ddns_cb, MDL);
2161  return (ISC_R_SUCCESS);
2162  }
2163 
2164  /*
2165  * We weren't able to process the request tag the
2166  * add so we won't execute it.
2167  */
2168  execute_add = ISC_R_FAILURE;
2169  goto cleanup;
2170  }
2171  else {
2172  /*remove info from scope */
2173  unset(*scope, "ddns-fwd-name");
2174  unset(*scope, ddns_cb->lease_tag);
2175  }
2176  }
2177 
2178  if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
2179  ddns_cb->state = DDNS_STATE_REM_PTR;
2180  ddns_cb->cur_func = ddns_ptr_remove;
2181  ddns_cb->flags |= DDNS_EXECUTE_NEXT;
2182 
2183  /*
2184  * if execute add isn't success remove the control block so
2185  * it won't be processed when the remove completes. We
2186  * also arrange to clean it up and get rid of it.
2187  */
2188  if (execute_add != ISC_R_SUCCESS) {
2189  ddns_cb->next_op = NULL;
2190  ddns_fwd_srv_connector(lease, lease6, scope,
2191  add_ddns_cb, execute_add);
2192  add_ddns_cb = NULL;
2193  }
2194  else {
2195  result = ISC_R_SUCCESS;
2196  }
2197 
2198  rcode = ddns_modify_ptr(ddns_cb, MDL);
2199  if (rcode == ISC_R_SUCCESS) {
2200  ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb,
2201  MDL);
2202  return (result);
2203  }
2204 
2205  /* We weren't able to process the request tag the
2206  * add so we won't execute it */
2207  execute_add = ISC_R_FAILURE;
2208  goto cleanup;
2209  }
2210 
2211  cleanup:
2212  /*
2213  * We've gotten here because we didn't need to send a message or
2214  * we failed when trying to do so. We send the additional cb
2215  * off to handle sending and/or cleanup and cleanup anything
2216  * we allocated here.
2217  */
2218  ddns_fwd_srv_connector(lease, lease6, scope, add_ddns_cb, execute_add);
2219  if (ddns_cb != NULL)
2220  destroy_ddns_cb(ddns_cb, MDL);
2221 
2222  return (result);
2223 }
2224 
2225 /* Convenience function for setting flag bits in a mask */
2226 void set_flag (u_int16_t *flags,
2227  u_int16_t flag,
2228  u_int16_t value) {
2229  if (flags) {
2230  if (value) {
2231  *flags |= flag;
2232  } else {
2233  *flags &= ~flag;
2234  }
2235  }
2236 }
2237 
2238 /*
2239  * Convenience function which replicates the conflict flags set in one
2240  * mask to another, while preserving all other flags.
2241  */
2242 void copy_conflict_flags(u_int16_t *target,
2243  u_int16_t source) {
2244  if (target) {
2245  /* Preserve non conflict flags */
2246  *target &= ~CONFLICT_BITS;
2247 
2248  /* Enable conflict flags per source */
2249  *target |= source & CONFLICT_BITS;
2250  }
2251 }
2252 
2253 /*
2254  * Given an option_state, create a mask of conflict detection flags based
2255  * on the appropriate configuration parameters within the option state.
2256  */
2257 u_int16_t
2258 get_conflict_mask(struct option_state *options) {
2259 
2260  int ddns_update_conflict_detection = 1; /* default on */
2261  int ddns_dual_stack_mixed_mode = 0; /* default off */
2262  int ddns_guard_id_must_match = 1; /* default on */
2263  int ddns_other_guard_is_dynamic = 0; /* default off */
2264  struct option_cache *oc = NULL;
2265 
2266  u_int16_t mask = 0;
2268  if (oc) {
2269  ddns_update_conflict_detection =
2270  evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options,
2271  NULL, &global_scope, oc, MDL);
2272  }
2273 
2274  set_flag(&mask, DDNS_CONFLICT_DETECTION,
2275  ddns_update_conflict_detection);
2276 
2277  if (!ddns_update_conflict_detection) {
2278 #if defined (DEBUG_DNS_UPDATES)
2279  log_info ("DDNS conflict detection: off");
2280 #endif
2281  /* Turn the rest of the conflict related flags off */
2282  set_flag(&mask, DDNS_DUAL_STACK_MIXED_MODE, 0);
2283  set_flag(&mask, DDNS_GUARD_ID_MUST_MATCH, 0);
2284  set_flag(&mask, DDNS_OTHER_GUARD_IS_DYNAMIC, 0);
2285  return (mask);
2286  }
2287 
2288  // Get the values
2289  oc = lookup_option(&server_universe, options,
2291  if (oc) {
2292  ddns_dual_stack_mixed_mode =
2293  evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options,
2294  NULL, &global_scope, oc, MDL);
2295  }
2296 
2297  oc = lookup_option(&server_universe, options,
2299  if (oc) {
2300  ddns_guard_id_must_match =
2301  evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options,
2302  NULL, &global_scope, oc, MDL);
2303  }
2304 
2305  oc = lookup_option(&server_universe, options,
2307  if (oc) {
2308  ddns_other_guard_is_dynamic =
2309  evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options,
2310  NULL, &global_scope, oc, MDL);
2311  }
2312 
2313  // Set the flags
2314  set_flag(&mask, DDNS_DUAL_STACK_MIXED_MODE,
2315  ddns_dual_stack_mixed_mode);
2316 
2317  set_flag(&mask, DDNS_GUARD_ID_MUST_MATCH,
2318  ddns_guard_id_must_match);
2319 
2320  set_flag(&mask, DDNS_OTHER_GUARD_IS_DYNAMIC,
2321  ddns_other_guard_is_dynamic);
2322 
2323 #if defined (DEBUG_DNS_UPDATES)
2324  log_info ("DDNS conflict behavior:\n"
2325  "\tddns-update-style: %s\n"
2326  "\tupdate-conflict-detection: %d\n"
2327  "\tddns-dual-stack-mixed-mode: %d\n"
2328  "\tddns-guard-id-must-match %d\n"
2329  "\tddns-other-guard-is-dynamic: %d\n",
2331  ddns_update_conflict_detection,
2332  ddns_dual_stack_mixed_mode,
2333  ddns_guard_id_must_match,
2334  ddns_other_guard_is_dynamic);
2335 #endif
2336  return (mask);
2337 }
2338 
2339 #if defined (DEBUG_DNS_UPDATES)
2340 /* Type used for creating lists of function pointers and their names */
2341 typedef struct {
2342  void *ptr;
2343  char *name;
2344 } LabeledPtr;
2345 
2346 /* Returns the name of the function referred to by the given address */
2347 char*
2348 dump_ddns_cb_func(void *func) {
2349  static LabeledPtr funcs[] = {
2350  { ddns_ptr_add, "ddns_ptr_add" },
2351  { ddns_fwd_srv_add2, "ddns_fwd_srv_add2" },
2352  { ddns_fwd_srv_add1, "ddns_fwd_srv_add1" },
2353  { ddns_ptr_remove, "ddns_ptr_remove" },
2354  { ddns_fwd_srv_rem2, "ddns_fwd_srv_rem2" },
2355  { ddns_fwd_srv_rem1, "ddns_fwd_srv_rem1" },
2356  { ddns_fwd_srv_add3, "ddns_fwd_srv_adde" },
2357  { NULL, "unknown" }
2358  };
2359 
2360  LabeledPtr* lp = funcs;
2361  if (!func) {
2362  return ("<null>");
2363  }
2364 
2365  while ((lp->ptr) && (lp->ptr != func)) {
2366  ++lp;
2367  }
2368 
2369  return (lp->name);
2370 }
2371 
2372 /* Dumps basic control block info to the log */
2373 char*
2374 dump_ddns_cb (dhcp_ddns_cb_t *ddns_cb) {
2375  static char output_buf[4096];
2376  if (!ddns_cb) {
2377  return ("<ddns_cb is null>");
2378  }
2379 
2380  sprintf (output_buf, "ddns_cb: %p flags: %x state: %s cur_func: %s",
2381  ddns_cb, ddns_cb->flags,
2382  ddns_state_name(ddns_cb->state),
2383  dump_ddns_cb_func(ddns_cb->cur_func));
2384 
2385  return(output_buf);
2386 }
2387 #endif /* DEBUG_DNS_UPDATES */
2388 
2389 #endif /* NSUPDATE */
#define SV_DDNS_GUARD_ID_MUST_MATCH
Definition: dhcpd.h:816
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
int find_lease(struct lease **, struct packet *, struct shared_network *, int *, int *, struct lease *, const char *, int)
Definition: dhcp.c:4089
const char int line
Definition: dhcpd.h:3781
#define DDNS_STATIC_LEASE
Definition: dhcpd.h:1767
struct binding_scope * global_scope
Definition: tree.c:38
struct dns_zone * zone
Definition: dhcpd.h:1815
#define SV_USE_HOST_DECL_NAMES
Definition: dhcpd.h:721
Definition: dhcpd.h:559
unsigned len
Definition: tree.h:79
const char * piaddr(const struct iaddr addr)
Definition: inet.c:579
u_int8_t hlen
Definition: dhcpd.h:492
#define FQDN_NO_CLIENT_UPDATE
Definition: dhcp.h:193
struct dhcp_ddns_cb * ddns_cb
Definition: dhcpd.h:649
#define DDNS_STATE_ADD_FW_NXDOMAIN
Definition: dhcpd.h:1781
unsigned char * uid
Definition: dhcpd.h:584
#define SV_FQDN_REPLY
Definition: dhcpd.h:761
int get_dhcid(dhcp_ddns_cb_t *, int, const u_int8_t *, unsigned)
#define DDNS_UPDATE_PTR
Definition: dhcpd.h:1761
#define DDNS_UPDATE_ADDR
Definition: dhcpd.h:1760
isc_result_t ia_dereference(struct ia_xx **ia, const char *file, int line)
Definition: mdb6.c:403
struct universe server_universe
Definition: stables.c:176
#define MDL
Definition: omapip.h:567
isc_result_t ddns_modify_ptr(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
unsigned char iabuf[16]
Definition: inet.h:33
#define DDNS_EXECUTE_NEXT
Definition: dhcpd.h:1765
#define DDNS_STATE_REM_PTR
Definition: dhcpd.h:1788
struct dhcp_ddns_cb * ddns_cb
Definition: dhcpd.h:1657
#define SV_DDNS_REV_DOMAIN_NAME
Definition: dhcpd.h:734
#define DDNS_GUARD_ID_MUST_MATCH
Definition: dhcpd.h:1770
int find_bound_string(struct data_string *value, struct binding_scope *scope, const char *name)
Definition: tree.c:4103
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
char * lease_tag
Definition: dhcpd.h:1833
int log_error(const char *,...) __attribute__((__format__(__printf__
char * ddns_state_name(int state)
#define DDNS_UPDATE_STYLE_STANDARD
Definition: dhcpd.h:706
struct binding_scope * scope
Definition: dhcpd.h:1634
#define DDNS_STATE_REM_FW_YXDHCID
Definition: dhcpd.h:1786
unsigned len
Definition: inet.h:32
struct data_string fwd_name
Definition: dhcpd.h:1803
#define DDNS_ACTIVE_LEASE
Definition: dhcpd.h:1768
char * ddns_interim_tag
Definition: ddns.c:39
int terminated
Definition: tree.h:80
#define DDNS_CLIENT_DID_UPDATE
Definition: dhcpd.h:1764
struct option_state * options
Definition: dhcpd.h:449
void ddns_cb_free(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
struct iaddr address
Definition: dhcpd.h:1806
unsigned long ttl
Definition: dhcpd.h:1809
#define SV_DDNS_HOST_NAME
Definition: dhcpd.h:733
void log_fatal(const char *,...) __attribute__((__format__(__printf__
#define D6O_IA_TA
Definition: dhcp6.h:33
void dhcid_tolease(struct data_string *, struct data_string *)
struct data_string dhcid
Definition: dhcpd.h:1805
struct data_string rev_name
Definition: dhcpd.h:1804
#define FQDN_RCODE2
Definition: dhcp.h:197
struct hardware hardware_addr
Definition: dhcpd.h:588
int unset(struct binding_scope *scope, const char *name)
Definition: tree.c:4134
u_int16_t ddns_conflict_mask
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
#define MAX_ADDRESS_STRING_LEN
Definition: dhcpd.h:3892
Definition: dhcpd.h:1014
dns_rdataclass_t dhcid_class
Definition: dhcpd.h:1831
#define SV_UPDATE_OPTIMIZATION
Definition: dhcpd.h:750
#define DDNS_STATE_ADD_PTR
Definition: dhcpd.h:1783
int buffer_allocate(struct buffer **ptr, unsigned len, const char *file, int line)
Definition: alloc.c:679
int write_lease(struct lease *lease)
Definition: dhclient.c:2084
struct dhcp_ddns_cb * next_op
Definition: dhcpd.h:1822
#define SV_DDNS_TTL
Definition: dhcpd.h:747
Definition: dhcpd.h:405
#define DDNS_OTHER_GUARD_IS_DYNAMIC
Definition: dhcpd.h:1771
char * name
Definition: dhcpd.h:963
struct data_string iaid_duid
Definition: dhcpd.h:1666
#define DDNS_UPDATE_STYLE_INTERIM
Definition: dhcpd.h:705
#define cur_time
Definition: dhcpd.h:2109
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:2507
u_int8_t flags
Definition: dhcpd.h:590
isc_result_t dhcid_fromlease(struct data_string *, struct data_string *)
void ddns_cancel(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)
u_int32_t prefer
Definition: dhcpd.h:1637
#define FQDN_FQDN
Definition: dhcp.h:200
struct option_cache * lookup_option(struct universe *universe, struct option_state *options, unsigned code)
Definition: options.c:2465
int int log_info(const char *,...) __attribute__((__format__(__printf__
u_int32_t getULong(const unsigned char *)
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 find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type, const struct in6_addr *addr)
Definition: mdb6.c:2289
#define SV_DO_REVERSE_UPDATES
Definition: dhcpd.h:760
void cleanup(void)
#define FQDN_DOMAINNAME
Definition: dhcp.h:199
ipv6_pool structure
Definition: dhcpd.h:1698
#define SV_DDNS_DOMAIN_NAME
Definition: dhcpd.h:732
unsigned short uid_len
Definition: dhcpd.h:585
struct iaddr ip_addr
Definition: dhcpd.h:568
#define FQDN_RCODE1
Definition: dhcp.h:196
isc_result_t ddns_removals(struct lease *, struct iasubopt *, struct dhcp_ddns_cb *, isc_boolean_t)
ddns_action_t cur_func
Definition: dhcpd.h:1820
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
#define D6O_IA_NA
Definition: dhcp6.h:32
int ddns_updates(struct packet *, struct lease *, struct lease *, struct iasubopt *, struct iasubopt *, struct option_state *)
struct host_decl * host
Definition: dhcpd.h:575
#define DDNS_DUAL_STACK_MIXED_MODE
Definition: dhcpd.h:1769
isc_result_t iasubopt_dereference(struct iasubopt **iasubopt, const char *file, int line)
Definition: mdb6.c:261
struct enumeration_value ddns_styles_values[]
Definition: stables.c:353
#define SV_DDNS_OTHER_GUARD_IS_DYNAMIC
Definition: dhcpd.h:817
#define FQDN_SERVER_UPDATE
Definition: dhcp.h:194
#define FQDN_ENCODED
Definition: dhcp.h:195
int commit_leases()
Definition: dhclient.c:2079
unsigned char data[1]
Definition: tree.h:62
Definition: tree.h:60
#define DDNS_STATE_REM_FW_DSMM_OTHER
Definition: dhcpd.h:1789
int state
Definition: dhcpd.h:1819
#define DDNS_STATE_ADD_FW_YXDHCID
Definition: dhcpd.h:1782
int ddns_update_style
Definition: dhcpd.c:80
u_int16_t get_conflict_mask(struct option_state *input_options)
#define STATIC_LEASE
Definition: dhcpd.h:591
u_int8_t hbuf[HARDWARE_ADDR_LEN+1]
Definition: dhcpd.h:493
dns_rdataclass_t other_dhcid_class
Definition: dhcpd.h:1832
u_int16_t flags
Definition: dhcpd.h:1817
struct ia_xx * fixed6_ia
Definition: dhcpd.h:1834
void ddns_cb_forget_zone(dhcp_ddns_cb_t *ddns_cb)
struct universe fqdn_universe
Definition: tables.c:310
int write_ia(const struct ia_xx *)
Definition: db.c:518
struct ia_xx * ia
Definition: dhcpd.h:1639
#define DDNS_CONFLICT_DETECTION
Definition: dhcpd.h:1763
#define SV_DDNS_CONFLICT_DETECT
Definition: dhcpd.h:757
int static_lease
Definition: dhcpd.h:1661
const char * file
Definition: dhcpd.h:3781
#define DHO_DHCP_CLIENT_IDENTIFIER
Definition: dhcp.h:152
#define CONFLICT_BITS
Definition: dhcpd.h:1773
#define DEFAULT_DDNS_TTL
Definition: dhcpd.h:859
struct in6_addr addr
Definition: dhcpd.h:1631
isc_result_t ia_reference(struct ia_xx **ia, struct ia_xx *src, const char *file, int line)
Definition: mdb6.c:377
char * ddns_standard_tag
Definition: ddns.c:38
const unsigned char * data
Definition: tree.h:78
int bind_ds_value(struct binding_scope **scope, const char *name, struct data_string *value)
Definition: tree.c:4080
TIME ends
Definition: dhcpd.h:569
struct binding_scope * scope
Definition: dhcpd.h:574
void data_string_copy(struct data_string *dest, const struct data_string *src, const char *file, int line)
Definition: alloc.c:1323
#define SV_UPDATE_STATIC_LEASES
Definition: dhcpd.h:752
#define DDNS_STATE_DSMM_FW_ADD3
Definition: dhcpd.h:1784
int find_lease_by_ip_addr(struct lease **, struct iaddr, const char *, int)
Definition: mdb.c:2029
#define DDNS_STATE_CLEANUP
Definition: dhcpd.h:1779
#define DDNS_STATE_REM_FW_NXRR
Definition: dhcpd.h:1787
#define MAX_DEFAULT_DDNS_TTL
Definition: dhcpd.h:862
#define SV_DDNS_DUAL_STACK_MIXED_MODE
Definition: dhcpd.h:815
struct buffer * buffer
Definition: tree.h:77
#define SV_CLIENT_UPDATES
Definition: dhcpd.h:749
#define SV_DO_FORWARD_UPDATES
Definition: dhcpd.h:754
int buffer_dereference(struct buffer **ptr, const char *file, int line)
Definition: alloc.c:726
isc_result_t ddns_modify_fwd(dhcp_ddns_cb_t *ddns_cb, const char *file, int line)