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