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