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