3 Dynamic DNS updates. */
6 * Copyright (c) 2009-2011 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 2000-2003 by Internet Software Consortium
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * Internet Systems Consortium, Inc.
24 * Redwood City, CA 94063
26 * https://www.isc.org/
28 * This software has been donated to Internet Systems Consortium
29 * by Damien Neil of Nominum, Inc.
31 * To learn more about Internet Systems Consortium, see
32 * ``https://www.isc.org/''. To learn more about Nominum, Inc., see
33 * ``http://www.nominum.com''.
38 #include <dns/result.h>
42 static void ddns_fwd_srv_connector(struct lease *lease,
43 struct iasubopt *lease6,
44 struct binding_scope **inscope,
45 dhcp_ddns_cb_t *ddns_cb,
46 isc_result_t eresult);
48 /* DN: No way of checking that there is enough space in a data_string's
49 buffer. Be certain to allocate enough!
50 TL: This is why the expression evaluation code allocates a *new*
52 static void data_string_append (struct data_string *ds1,
53 struct data_string *ds2)
55 memcpy (ds1 -> buffer -> data + ds1 -> len,
58 ds1 -> len += ds2 -> len;
62 /* Determine what, if any, forward and reverse updates need to be
63 * performed, and carry them through.
66 ddns_updates(struct packet *packet, struct lease *lease, struct lease *old,
67 struct iasubopt *lease6, struct iasubopt *old6,
68 struct option_state *options)
70 unsigned long ddns_ttl = DEFAULT_DDNS_TTL;
71 struct data_string ddns_hostname;
72 struct data_string ddns_domainname;
73 struct data_string old_ddns_fwd_name;
74 struct data_string ddns_fwd_name;
75 //struct data_string ddns_rev_name;
76 struct data_string ddns_dhcid;
77 struct binding_scope **scope = NULL;
79 struct data_string d1;
80 struct option_cache *oc;
83 isc_result_t rcode1 = ISC_R_SUCCESS;
84 int server_updates_a = 1;
85 //int server_updates_ptr = 1;
86 struct buffer *bp = (struct buffer *)0;
87 int ignorep = 0, client_ignorep = 0;
91 dhcp_ddns_cb_t *ddns_cb;
94 if (ddns_update_style != 2)
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
101 * If there is a ddns request already outstanding cancel it.
105 if ((old != NULL) && (old->ddns_cb != NULL)) {
106 ddns_cancel(old->ddns_cb);
109 } else if (lease6 != NULL) {
110 if ((old6 != NULL) && (old6->ddns_cb != NULL)) {
111 ddns_cancel(old6->ddns_cb);
112 old6->ddns_cb = NULL;
115 log_fatal("Impossible condition at %s:%d.", MDL);
116 /* Silence compiler warnings. */
121 /* allocate our control block */
122 ddns_cb = ddns_cb_alloc(MDL);
123 if (ddns_cb == NULL) {
127 * Assume that we shall update both the A and ptr records and,
128 * as this is an update, set the active flag
130 ddns_cb->flags = DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR |
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.
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;
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_rev_name, 0, sizeof (ddns_rev_name));
155 memset (&ddns_dhcid, 0, sizeof (ddns_dhcid));
157 /* If we are allowed to accept the client's update of its own A
158 record, see if the client wants to update its own A record. */
159 if (!(oc = lookup_option(&server_universe, options,
160 SV_CLIENT_UPDATES)) ||
161 evaluate_boolean_option_cache(&client_ignorep, packet, lease, NULL,
162 packet->options, options, scope,
164 /* If there's no fqdn.no-client-update or if it's
165 nonzero, don't try to use the client-supplied
167 if (!(oc = lookup_option (&fqdn_universe, packet -> options,
168 FQDN_SERVER_UPDATE)) ||
169 evaluate_boolean_option_cache(&ignorep, packet, lease,
170 NULL, packet->options,
171 options, scope, oc, MDL))
173 /* Win98 and Win2k will happily claim to be willing to
174 update an unqualified domain name. */
175 if (!(oc = lookup_option (&fqdn_universe, packet -> options,
178 if (!(oc = lookup_option (&fqdn_universe, packet -> options,
180 !evaluate_option_cache(&ddns_fwd_name, packet, lease,
181 NULL, packet->options,
182 options, scope, oc, MDL))
184 ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
185 server_updates_a = 0;
189 /* If do-forward-updates is disabled, this basically means don't
190 do an update unless the client is participating, so if we get
191 here and do-forward-updates is disabled, we can stop. */
192 if ((oc = lookup_option (&server_universe, options,
193 SV_DO_FORWARD_UPDATES)) &&
194 !evaluate_boolean_option_cache(&ignorep, packet, lease,
195 NULL, packet->options,
196 options, scope, oc, MDL)) {
200 /* If it's a static lease, then don't do the DNS update unless we're
201 specifically configured to do so. If the client asked to do its
202 own update and we allowed that, we don't do this test. */
203 /* XXX: note that we cannot detect static DHCPv6 leases. */
204 if ((lease != NULL) && (lease->flags & STATIC_LEASE)) {
205 if (!(oc = lookup_option(&server_universe, options,
206 SV_UPDATE_STATIC_LEASES)) ||
207 !evaluate_boolean_option_cache(&ignorep, packet, lease,
208 NULL, packet->options,
209 options, scope, oc, MDL))
214 * Compute the name for the A record.
216 oc = lookup_option(&server_universe, options, SV_DDNS_HOST_NAME);
218 s1 = evaluate_option_cache(&ddns_hostname, packet, lease,
219 NULL, packet->options,
220 options, scope, oc, MDL);
224 oc = lookup_option(&server_universe, options, SV_DDNS_DOMAIN_NAME);
226 s2 = evaluate_option_cache(&ddns_domainname, packet, lease,
227 NULL, packet->options,
228 options, scope, oc, MDL);
233 if (ddns_hostname.len + ddns_domainname.len > 253) {
234 log_error ("ddns_update: host.domain name too long");
239 buffer_allocate (&ddns_fwd_name.buffer,
240 ddns_hostname.len + ddns_domainname.len + 2,
242 if (ddns_fwd_name.buffer) {
243 ddns_fwd_name.data = ddns_fwd_name.buffer->data;
244 data_string_append (&ddns_fwd_name, &ddns_hostname);
245 ddns_fwd_name.buffer->data[ddns_fwd_name.len] = '.';
247 data_string_append (&ddns_fwd_name, &ddns_domainname);
248 ddns_fwd_name.buffer->data[ddns_fwd_name.len] ='\0';
249 ddns_fwd_name.terminated = 1;
254 /* See if there's a name already stored on the lease. */
255 if (find_bound_string(&old_ddns_fwd_name, *scope, "ddns-fwd-name")) {
256 /* If there is, see if it's different. */
257 if (old_ddns_fwd_name.len != ddns_fwd_name.len ||
258 memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data,
259 old_ddns_fwd_name.len)) {
261 * If the name is different, mark the old record
262 * for deletion and continue getting the new info.
268 /* See if there's a DHCID on the lease, and if not
269 * then potentially look for 'on events' for ad-hoc ddns.
271 if (!find_bound_string(&ddns_dhcid, *scope, "ddns-txt") &&
273 /* If there's no DHCID, the update was probably
274 done with the old-style ad-hoc DDNS updates.
275 So if the expiry and release events look like
276 they're the same, run them. This should delete
277 the old DDNS data. */
278 if (old -> on_expiry == old -> on_release) {
279 execute_statements(NULL, NULL, lease, NULL,
282 if (old -> on_expiry)
283 executable_statement_dereference
284 (&old -> on_expiry, MDL);
285 if (old -> on_release)
286 executable_statement_dereference
287 (&old -> on_release, MDL);
288 /* Now, install the DDNS data the new way. */
292 data_string_forget(&ddns_dhcid, MDL);
294 /* See if the administrator wants to do updates even
295 in cases where the update already appears to have been
297 if (!(oc = lookup_option(&server_universe, options,
298 SV_UPDATE_OPTIMIZATION)) ||
299 evaluate_boolean_option_cache(&ignorep, packet, lease,
300 NULL, packet->options,
301 options, scope, oc, MDL)) {
305 /* If there's no "ddns-fwd-name" on the lease record, see if
306 * there's a ddns-client-fqdn indicating a previous client
307 * update (if it changes, we need to adjust the PTR).
309 } else if (find_bound_string(&old_ddns_fwd_name, *scope,
310 "ddns-client-fqdn")) {
311 /* If the name is not different, no need to update
313 if (old_ddns_fwd_name.len == ddns_fwd_name.len &&
314 !memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data,
315 old_ddns_fwd_name.len) &&
316 (!(oc = lookup_option(&server_universe, options,
317 SV_UPDATE_OPTIMIZATION)) ||
318 evaluate_boolean_option_cache(&ignorep, packet, lease,
319 NULL, packet->options,
320 options, scope, oc, MDL))) {
326 /* If we don't have a name that the client has been assigned, we
327 can just skip all this. */
329 if ((!ddns_fwd_name.len) || (ddns_fwd_name.len > 255)) {
330 if (ddns_fwd_name.len > 255) {
331 log_error ("client provided fqdn: too long");
334 /* If desired do the removals */
335 if (do_remove != 0) {
336 (void) ddns_removals(lease, lease6, NULL, ISC_TRUE);
342 * Compute the RR TTL.
344 * We have two ways of computing the TTL.
345 * The old behavior was to allow for the customer to set up
346 * the option or to default things. For v4 this was 1/2
347 * of the lease time, for v6 this was DEFAULT_DDNS_TTL.
348 * The new behavior continues to allow the customer to set
349 * up an option but the defaults are a little different.
350 * We now use 1/2 of the (preferred) lease time for both
351 * v4 and v6 and cap them at a maximum value.
352 * If the customer chooses to use an experession that references
353 * part of the lease the v6 value will be the default as there
354 * isn't a lease available for v6.
357 ddns_ttl = DEFAULT_DDNS_TTL;
359 if (lease->ends <= cur_time) {
362 ddns_ttl = (lease->ends - cur_time)/2;
365 #ifndef USE_OLD_DDNS_TTL
366 else if (lease6 != NULL) {
367 ddns_ttl = lease6->prefer/2;
370 if (ddns_ttl > MAX_DEFAULT_DDNS_TTL) {
371 ddns_ttl = MAX_DEFAULT_DDNS_TTL;
375 if ((oc = lookup_option(&server_universe, options, SV_DDNS_TTL))) {
376 if (evaluate_option_cache(&d1, packet, lease, NULL,
377 packet->options, options,
379 if (d1.len == sizeof (u_int32_t))
380 ddns_ttl = getULong (d1.data);
381 data_string_forget (&d1, MDL);
385 ddns_cb->ttl = ddns_ttl;
388 * Compute the reverse IP name, starting with the domain name.
390 oc = lookup_option(&server_universe, options, SV_DDNS_REV_DOMAIN_NAME);
392 s1 = evaluate_option_cache(&d1, packet, lease, NULL,
393 packet->options, options,
399 * Figure out the length of the part of the name that depends
402 if (ddns_cb->address.len == 4) {
404 /* XXX: WOW this is gross. */
405 rev_name_len = snprintf(buf, sizeof(buf), "%u.%u.%u.%u.",
406 ddns_cb->address.iabuf[3] & 0xff,
407 ddns_cb->address.iabuf[2] & 0xff,
408 ddns_cb->address.iabuf[1] & 0xff,
409 ddns_cb->address.iabuf[0] & 0xff) + 1;
412 rev_name_len += d1.len;
414 if (rev_name_len > 255) {
415 log_error("ddns_update: Calculated rev domain "
418 data_string_forget(&d1, MDL);
421 } else if (ddns_cb->address.len == 16) {
423 * IPv6 reverse names are always the same length, with
424 * 32 hex characters separated by dots.
426 rev_name_len = sizeof("0.1.2.3.4.5.6.7."
432 /* Set s1 to make sure we gate into updates. */
435 log_fatal("invalid address length %d", ddns_cb->address.len);
436 /* Silence compiler warnings. */
440 /* See if we are configured NOT to do reverse ptr updates */
441 if ((oc = lookup_option(&server_universe, options,
442 SV_DO_REVERSE_UPDATES)) &&
443 !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
444 packet->options, options,
446 ddns_cb->flags &= ~DDNS_UPDATE_PTR;
450 buffer_allocate(&ddns_cb->rev_name.buffer, rev_name_len, MDL);
451 if (ddns_cb->rev_name.buffer != NULL) {
452 struct data_string *rname = &ddns_cb->rev_name;
453 rname->data = rname->buffer->data;
455 if (ddns_cb->address.len == 4) {
457 sprintf((char *)rname->buffer->data,
459 ddns_cb->address.iabuf[3] & 0xff,
460 ddns_cb->address.iabuf[2] & 0xff,
461 ddns_cb->address.iabuf[1] & 0xff,
462 ddns_cb->address.iabuf[0] & 0xff);
465 * d1.data may be opaque, garbage bytes, from
466 * user (mis)configuration.
468 data_string_append(rname, &d1);
469 rname->buffer->data[rname->len] = '\0';
470 } else if (ddns_cb->address.len == 16) {
471 char *p = (char *)&rname->buffer->data;
472 unsigned char *a = ddns_cb->address.iabuf + 15;
473 for (i=0; i<16; i++) {
475 (*a & 0xF), ((*a >> 4) & 0xF));
479 strcat(p, "ip6.arpa.");
480 rname->len = strlen((const char *)rname->data);
483 rname->terminated = 1;
487 data_string_forget(&d1, MDL);
491 * If we are updating the A record, compute the DHCID value.
493 if ((ddns_cb->flags & DDNS_UPDATE_ADDR) != 0) {
495 result = get_dhcid(&ddns_cb->dhcid, 2,
496 lease6->ia->iaid_duid.data,
497 lease6->ia->iaid_duid.len);
498 else if ((lease != NULL) && (lease->uid != NULL) &&
499 (lease->uid_len != 0))
500 result = get_dhcid (&ddns_cb->dhcid,
501 DHO_DHCP_CLIENT_IDENTIFIER,
502 lease -> uid, lease -> uid_len);
503 else if (lease != NULL)
504 result = get_dhcid (&ddns_cb->dhcid, 0,
505 lease -> hardware_addr.hbuf,
506 lease -> hardware_addr.hlen);
508 log_fatal("Impossible condition at %s:%d.", MDL);
518 data_string_copy(&ddns_cb->fwd_name, &ddns_fwd_name, MDL);
520 if (ddns_cb->flags && DDNS_UPDATE_ADDR) {
521 oc = lookup_option(&server_universe, options,
522 SV_DDNS_CONFLICT_DETECT);
524 !evaluate_boolean_option_cache(&ignorep, packet, lease,
525 NULL, packet->options,
526 options, scope, oc, MDL))
527 ddns_cb->flags |= DDNS_CONFLICT_OVERRIDE;
532 * Previously if we failed during the removal operations
533 * we skipped the fqdn option processing. I'm not sure
534 * if we want to continue with that if we fail before sending
535 * the ddns messages. Currently we don't.
538 rcode1 = ddns_removals(lease, lease6, ddns_cb, ISC_TRUE);
541 ddns_fwd_srv_connector(lease, lease6, scope, ddns_cb,
548 * If fqdn-reply option is disabled in dhcpd.conf, then don't
549 * send the client an FQDN option at all, even if one was requested.
550 * (WinXP clients allegedly misbehave if the option is present,
551 * refusing to handle PTR updates themselves).
553 if ((oc = lookup_option (&server_universe, options, SV_FQDN_REPLY)) &&
554 !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
555 packet->options, options,
559 /* If we're ignoring client updates, then we tell a sort of 'white
560 * lie'. We've already updated the name the server wants (per the
561 * config written by the server admin). Now let the client do as
562 * it pleases with the name they supplied (if any).
564 * We only form an FQDN option this way if the client supplied an
565 * FQDN option that had FQDN_SERVER_UPDATE set false.
567 } else if (client_ignorep &&
568 (oc = lookup_option(&fqdn_universe, packet->options,
569 FQDN_SERVER_UPDATE)) &&
570 !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
571 packet->options, options,
573 oc = lookup_option(&fqdn_universe, packet->options, FQDN_FQDN);
574 if (oc && evaluate_option_cache(&d1, packet, lease, NULL,
575 packet->options, options,
578 !buffer_allocate(&bp, d1.len + 5, MDL))
581 /* Server pretends it is not updating. */
583 if (!save_option_buffer(&fqdn_universe, options,
585 FQDN_SERVER_UPDATE, 0))
588 /* Client is encouraged to update. */
590 if (!save_option_buffer(&fqdn_universe, options,
592 FQDN_NO_CLIENT_UPDATE, 0))
595 /* Use the encoding of client's FQDN option. */
596 oc = lookup_option(&fqdn_universe, packet->options,
599 evaluate_boolean_option_cache(&ignorep, packet,
604 bp->data[2] = 1; /* FQDN is encoded. */
606 bp->data[2] = 0; /* FQDN is not encoded. */
608 if (!save_option_buffer(&fqdn_universe, options,
613 /* Current FQDN drafts indicate 255 is mandatory. */
615 if (!save_option_buffer(&fqdn_universe, options,
621 if (!save_option_buffer(&fqdn_universe, options,
626 /* Copy in the FQDN supplied by the client. Note well
627 * that the format of this option in the cache is going
628 * to be in text format. If the fqdn supplied by the
629 * client is encoded, it is decoded into the option
630 * cache when parsed out of the packet. It will be
631 * re-encoded when the option is assembled to be
632 * transmitted if the client elects that encoding.
634 memcpy(&bp->data[5], d1.data, d1.len);
635 if (!save_option_buffer(&fqdn_universe, options,
636 bp, &bp->data[5], d1.len,
640 data_string_forget(&d1, MDL);
642 /* Set up the outgoing FQDN option if there was an incoming
643 * FQDN option. If there's a valid FQDN option, there MUST
644 * be an FQDN_SERVER_UPDATES suboption, it's part of the fixed
645 * length head of the option contents, so we test the latter
646 * to detect the presence of the former.
648 } else if ((oc = lookup_option(&fqdn_universe, packet->options,
650 buffer_allocate(&bp, ddns_fwd_name.len + 5, MDL)) {
651 bp -> data [0] = server_updates_a;
652 if (!save_option_buffer(&fqdn_universe, options,
653 bp, &bp->data [0], 1,
654 FQDN_SERVER_UPDATE, 0))
656 bp -> data [1] = server_updates_a;
657 if (!save_option_buffer(&fqdn_universe, options,
658 bp, &bp->data [1], 1,
659 FQDN_NO_CLIENT_UPDATE, 0))
662 /* Do the same encoding the client did. */
663 if (evaluate_boolean_option_cache(&ignorep, packet, lease,
664 NULL, packet->options,
665 options, scope, oc, MDL))
669 if (!save_option_buffer(&fqdn_universe, options,
670 bp, &bp->data [2], 1,
673 bp -> data [3] = 255;//isc_rcode_to_ns (rcode1);
674 if (!save_option_buffer(&fqdn_universe, options,
675 bp, &bp->data [3], 1,
678 bp -> data [4] = 255;//isc_rcode_to_ns (rcode2);
679 if (!save_option_buffer(&fqdn_universe, options,
680 bp, &bp->data [4], 1,
683 if (ddns_fwd_name.len) {
684 memcpy (&bp -> data [5],
685 ddns_fwd_name.data, ddns_fwd_name.len);
686 if (!save_option_buffer(&fqdn_universe, options,
699 if (ddns_cb != NULL) {
700 ddns_cb_free(ddns_cb, MDL);
703 data_string_forget(&d1, MDL);
704 data_string_forget(&ddns_hostname, MDL);
705 data_string_forget(&ddns_domainname, MDL);
706 data_string_forget(&old_ddns_fwd_name, MDL);
707 data_string_forget(&ddns_fwd_name, MDL);
708 //data_string_forget(&ddns_rev_name, MDL);
709 //data_string_forget(&ddns_dhcid, MDL);
711 buffer_dereference(&bp, MDL);
717 * Utility function to update text strings within a lease.
719 * The first issue is to find the proper scope. Sometimes we shall be
720 * called with a pointer to the scope in other cases we need to find
721 * the proper lease and then get the scope. Once we have the scope we update
722 * the proper strings, as indicated by the state value in the control block.
723 * Lastly, if we needed to find the scope we write it out, if we used a
724 * scope that was passed as an argument we don't write it, assuming that
725 * our caller (or his ...) will do the write.
729 ddns_update_lease_text(dhcp_ddns_cb_t *ddns_cb,
730 struct binding_scope **inscope)
732 struct binding_scope **scope = NULL;
733 struct lease *lease = NULL;
734 struct iasubopt *lease6 = NULL;
735 struct ipv6_pool *pool = NULL;
736 struct in6_addr addr;
737 struct data_string lease_dhcid;
740 * If the lease was static (for a fixed address)
741 * we don't need to do any work.
743 if (ddns_cb->flags & DDNS_STATIC_LEASE)
744 return (ISC_R_SUCCESS);
747 * If we are processing an expired or released v6 lease
748 * we don't actually have a scope to update
750 if ((ddns_cb->address.len == 16) &&
751 ((ddns_cb->flags & DDNS_ACTIVE_LEASE) == 0)) {
752 return (ISC_R_SUCCESS);
755 if (inscope != NULL) {
757 } else if (ddns_cb->address.len == 4) {
758 if (find_lease_by_ip_addr(&lease, ddns_cb->address, MDL) != 0){
759 scope = &(lease->scope);
761 } else if (ddns_cb->address.len == 16) {
762 memcpy(&addr, &ddns_cb->address.iabuf, 16);
763 if ((find_ipv6_pool(&pool, D6O_IA_TA, &addr) ==
765 (find_ipv6_pool(&pool, D6O_IA_NA, &addr) ==
767 if (iasubopt_hash_lookup(&lease6, pool->leases,
769 scope = &(lease6->scope);
771 ipv6_pool_dereference(&pool, MDL);
774 log_fatal("Impossible condition at %s:%d.", MDL);
778 /* If necessary get rid of the lease */
780 lease_dereference(&lease, MDL);
783 iasubopt_dereference(&lease6, MDL);
786 return(ISC_R_FAILURE);
789 /* We now have a scope and can proceed to update it */
790 switch(ddns_cb->state) {
791 case DDNS_STATE_REM_PTR:
792 unset(*scope, "ddns-rev-name");
793 if ((ddns_cb->flags & DDNS_CLIENT_DID_UPDATE) != 0) {
794 unset(*scope, "ddns-client-fqdn");
798 case DDNS_STATE_ADD_PTR:
799 case DDNS_STATE_CLEANUP:
800 bind_ds_value(scope, "ddns-rev-name", &ddns_cb->rev_name);
801 if ((ddns_cb->flags & DDNS_UPDATE_ADDR) == 0) {
802 bind_ds_value(scope, "ddns-client-fqdn",
807 case DDNS_STATE_ADD_FW_YXDHCID:
808 case DDNS_STATE_ADD_FW_NXDOMAIN:
809 bind_ds_value(scope, "ddns-fwd-name", &ddns_cb->fwd_name);
811 /* convert from dns version to lease version of dhcid */
812 memset(&lease_dhcid, 0, sizeof(lease_dhcid));
813 dhcid_tolease(&ddns_cb->dhcid, &lease_dhcid);
814 bind_ds_value(scope, "ddns-txt", &lease_dhcid);
815 data_string_forget(&lease_dhcid, MDL);
819 case DDNS_STATE_REM_FW_NXRR:
820 case DDNS_STATE_REM_FW_YXDHCID:
821 unset(*scope, "ddns-fwd-name");
822 unset(*scope, "ddns-txt");
826 /* If necessary write it out and get rid of the lease */
829 lease_dereference(&lease, MDL);
831 write_ia(lease6->ia);
832 iasubopt_dereference(&lease6, MDL);
835 return(ISC_R_SUCCESS);
839 * This function should be called when update_lease_ptr function fails.
840 * It does inform user about the condition, provides some hints how to
841 * resolve this and dies gracefully. This can happend in at least three
842 * cases (all are configuration mistakes):
843 * a) IPv4: user have duplicate fixed-address entries (the same
844 * address is defined twice). We may have found wrong lease.
845 * b) IPv6: user have overlapping pools (we tried to find
846 * a lease in a wrong pool)
847 * c) IPv6: user have duplicate fixed-address6 entires (the same
848 * address is defined twice). We may have found wrong lease.
850 * Comment: while it would be possible to recover from both cases
851 * by forcibly searching for leases in *all* following pools, that would
852 * only hide the real problem - a misconfiguration. Proper solution
853 * is to log the problem, die and let the user fix his config file.
856 update_lease_failed(struct lease *lease,
857 struct iasubopt *lease6,
858 dhcp_ddns_cb_t *ddns_cb,
859 dhcp_ddns_cb_t *ddns_cb_set,
860 const char * file, int line)
862 char lease_address[MAX_ADDRESS_STRING_LEN + 64];
863 char reason[128]; /* likely reason */
865 sprintf(reason, "unknown");
866 sprintf(lease_address, "unknown");
869 * let's pretend that everything is ok, so we can continue for
870 * information gathering purposes
873 if (ddns_cb != NULL) {
874 strncpy(lease_address, piaddr(ddns_cb->address),
875 MAX_ADDRESS_STRING_LEN);
877 if (ddns_cb->address.len == 4) {
878 sprintf(reason, "duplicate IPv4 fixed-address entry");
879 } else if (ddns_cb->address.len == 16) {
880 sprintf(reason, "duplicate IPv6 fixed-address6 entry "
881 "or overlapping pools");
884 * Should not happen. We have non-IPv4, non-IPv6
885 * address. Something is very wrong here.
887 sprintf(reason, "corrupted ddns_cb structure (address "
888 "length is %d)", ddns_cb->address.len);
892 log_error("Failed to properly update internal lease structure with "
894 log_error("control block structures. Tried to update lease for"
895 "%s address, ddns_cb=%p.", lease_address, ddns_cb);
898 log_error("This condition can occur, if DHCP server configuration is "
900 log_error("In particular, please do check that your configuration:");
901 log_error("a) does not have overlapping pools (especially containing");
902 log_error(" %s address).", lease_address);
903 log_error("b) there are no duplicate fixed-address or fixed-address6");
904 log_error("entries for the %s address.", lease_address);
906 log_error("Possible reason for this failure: %s", reason);
908 log_fatal("%s(%d): Failed to update lease database with DDNS info for "
909 "address %s. Lease database inconsistent. Unable to recover."
910 " Terminating.", file, line, lease_address);
914 * utility function to update found lease. It does extra checks
915 * that we are indeed updating the right lease. It may happen
916 * that user have duplicate fixed-address entries, so we attempt
917 * to update wrong lease. See also safe_lease6_update.
921 safe_lease_update(struct lease *lease,
922 dhcp_ddns_cb_t *oldcb,
923 dhcp_ddns_cb_t *newcb,
924 const char *file, int line)
927 /* should never get here */
928 log_fatal("Impossible condition at %s:%d (called from %s:%d).",
932 if ( (lease->ddns_cb == NULL) && (newcb == NULL) ) {
934 * Trying to clean up pointer that is already null. We
935 * are most likely trying to update wrong lease here.
939 * Previously this error message popped out during
940 * DNS update for fixed leases. As we no longer
941 * try to update the lease for a fixed (static) lease
942 * this should not be a problem.
944 log_error("%s(%d): Invalid lease update. Tried to "
945 "clear already NULL DDNS control block "
946 "pointer for lease %s.",
947 file, line, piaddr(lease->ip_addr) );
949 #if defined (DNS_UPDATES_MEMORY_CHECKS)
950 update_lease_failed(lease, NULL, oldcb, newcb, file, line);
953 * May not reach this: update_lease_failed calls
959 if ( (lease->ddns_cb != NULL) && (lease->ddns_cb != oldcb) ) {
961 * There is existing cb structure, but it differs from
962 * what we expected to see there. Most likely we are
963 * trying to update wrong lease.
965 log_error("%s(%d): Failed to update internal lease "
966 "structure with DDNS control block. Existing"
967 " ddns_cb structure does not match "
968 "expectations.IPv4=%s, old ddns_cb=%p, tried"
969 "to update to new ddns_cb=%p", file, line,
970 piaddr(lease->ip_addr), oldcb, newcb);
972 #if defined (DNS_UPDATES_MEMORY_CHECKS)
973 update_lease_failed(lease, NULL, oldcb, newcb, file, line);
976 * May not reach this: update_lease_failed calls
982 /* additional IPv4 specific checks may be added here */
984 /* update the lease */
985 lease->ddns_cb = newcb;
989 safe_lease6_update(struct iasubopt *lease6,
990 dhcp_ddns_cb_t *oldcb,
991 dhcp_ddns_cb_t *newcb,
992 const char *file, int line)
994 char addrbuf[MAX_ADDRESS_STRING_LEN];
996 if (lease6 == NULL) {
997 /* should never get here */
998 log_fatal("Impossible condition at %s:%d (called from %s:%d).",
1002 if ( (lease6->ddns_cb == NULL) && (newcb == NULL) ) {
1003 inet_ntop(AF_INET6, &lease6->addr, addrbuf,
1004 MAX_ADDRESS_STRING_LEN);
1006 * Trying to clean up pointer that is already null. We
1007 * are most likely trying to update wrong lease here.
1009 log_error("%s(%d): Failed to update internal lease "
1010 "structure. Tried to clear already NULL "
1011 "DDNS control block pointer for lease %s.",
1012 file, line, addrbuf);
1014 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1015 update_lease_failed(NULL, lease6, oldcb, newcb, file, line);
1019 * May not reach this: update_lease_failed calls
1025 if ( (lease6->ddns_cb != NULL) && (lease6->ddns_cb != oldcb) ) {
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.
1031 inet_ntop(AF_INET6, &lease6->addr, addrbuf,
1032 MAX_ADDRESS_STRING_LEN);
1034 log_error("%s(%d): Failed to update internal lease "
1035 "structure with DDNS control block. Existing"
1036 " ddns_cb structure does not match "
1037 "expectations.IPv6=%s, old ddns_cb=%p, tried"
1038 "to update to new ddns_cb=%p", file, line,
1039 addrbuf, oldcb, newcb);
1041 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1042 update_lease_failed(NULL, lease6, oldcb, newcb, file, line);
1045 * May not reach this: update_lease_failed calls
1050 /* additional IPv6 specific checks may be added here */
1052 /* update the lease */
1053 lease6->ddns_cb = newcb;
1057 * Utility function to update the pointer to the DDNS control block
1059 * SUCCESS - able to update the pointer
1060 * FAILURE - lease didn't exist or sanity checks failed
1061 * lease and lease6 may be empty in which case we attempt to find
1062 * the lease from the ddns_cb information.
1063 * ddns_cb is the control block to use if a lookup is necessary
1064 * ddns_cb_set is the pointer to insert into the lease and may be NULL
1065 * The last two arguments may look odd as they will be the same much of the
1066 * time, but I need an argument to tell me if I'm setting or clearing in
1067 * addition to the address information from the cb to look up the lease.
1068 * using the same value twice allows me more flexibility.
1072 ddns_update_lease_ptr(struct lease *lease,
1073 struct iasubopt *lease6,
1074 dhcp_ddns_cb_t *ddns_cb,
1075 dhcp_ddns_cb_t *ddns_cb_set,
1076 const char * file, int line)
1078 char ddns_address[MAX_ADDRESS_STRING_LEN];
1079 sprintf(ddns_address, "unknown");
1081 strncpy(ddns_address, piaddr(ddns_cb->address),
1082 MAX_ADDRESS_STRING_LEN);
1084 #if defined (DEBUG_DNS_UPDATES)
1085 log_info("%s(%d): Updating lease_ptr for ddns_cp=%p (addr=%s)",
1086 file, line, ddns_cb, ddns_address );
1090 * If the lease was static (for a fixed address)
1091 * we don't need to do any work.
1093 if (ddns_cb->flags & DDNS_STATIC_LEASE) {
1094 #if defined (DEBUG_DNS_UPDATES)
1095 log_info("lease is static, returning");
1097 return (ISC_R_SUCCESS);
1101 * If we are processing an expired or released v6 lease
1102 * we don't actually have a scope to update
1104 if ((ddns_cb->address.len == 16) &&
1105 ((ddns_cb->flags & DDNS_ACTIVE_LEASE) == 0)) {
1106 return (ISC_R_SUCCESS);
1109 if (lease != NULL) {
1110 safe_lease_update(lease, ddns_cb, ddns_cb_set,
1112 } else if (lease6 != NULL) {
1113 safe_lease6_update(lease6, ddns_cb, ddns_cb_set,
1115 } else if (ddns_cb->address.len == 4) {
1116 struct lease *find_lease = NULL;
1117 if (find_lease_by_ip_addr(&find_lease,
1118 ddns_cb->address, MDL) != 0) {
1119 #if defined (DEBUG_DNS_UPDATES)
1120 log_info("%s(%d): find_lease_by_ip_addr(%s) successful:"
1121 "lease=%p", file, line, ddns_address,
1125 safe_lease_update(find_lease, ddns_cb,
1126 ddns_cb_set, file, line);
1127 lease_dereference(&find_lease, MDL);
1130 log_error("%s(%d): ddns_update_lease_ptr failed. "
1131 "Lease for %s not found.",
1132 file, line, piaddr(ddns_cb->address));
1134 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1135 update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set,
1139 * may not reach this. update_lease_failed
1142 return(ISC_R_FAILURE);
1145 } else if (ddns_cb->address.len == 16) {
1146 struct iasubopt *find_lease6 = NULL;
1147 struct ipv6_pool *pool = NULL;
1148 struct in6_addr addr;
1149 char addrbuf[MAX_ADDRESS_STRING_LEN];
1151 memcpy(&addr, &ddns_cb->address.iabuf, 16);
1152 if ((find_ipv6_pool(&pool, D6O_IA_TA, &addr) !=
1154 (find_ipv6_pool(&pool, D6O_IA_NA, &addr) !=
1156 inet_ntop(AF_INET6, &addr, addrbuf,
1157 MAX_ADDRESS_STRING_LEN);
1158 log_error("%s(%d): Pool for lease %s not found.",
1159 file, line, addrbuf);
1160 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1161 update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set,
1165 * never reached. update_lease_failed
1168 return(ISC_R_FAILURE);
1171 if (iasubopt_hash_lookup(&find_lease6, pool->leases,
1173 find_lease6->ddns_cb = ddns_cb_set;
1174 iasubopt_dereference(&find_lease6, MDL);
1176 inet_ntop(AF_INET6, &addr, addrbuf,
1177 MAX_ADDRESS_STRING_LEN);
1178 log_error("%s(%d): Lease %s not found within pool.",
1179 file, line, addrbuf);
1180 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1181 update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set,
1185 * never reached. update_lease_failed
1188 return(ISC_R_FAILURE);
1190 ipv6_pool_dereference(&pool, MDL);
1192 /* shouldn't get here */
1193 log_fatal("Impossible condition at %s:%d, called from %s:%d.",
1197 return(ISC_R_SUCCESS);
1201 ddns_ptr_add(dhcp_ddns_cb_t *ddns_cb,
1202 isc_result_t eresult)
1204 if (eresult == ISC_R_SUCCESS) {
1205 log_info("Added reverse map from %.*s to %.*s",
1206 (int)ddns_cb->rev_name.len,
1207 (const char *)ddns_cb->rev_name.data,
1208 (int)ddns_cb->fwd_name.len,
1209 (const char *)ddns_cb->fwd_name.data);
1211 ddns_update_lease_text(ddns_cb, NULL);
1213 log_error("Unable to add reverse map from %.*s to %.*s: %s",
1214 (int)ddns_cb->rev_name.len,
1215 (const char *)ddns_cb->rev_name.data,
1216 (int)ddns_cb->fwd_name.len,
1217 (const char *)ddns_cb->fwd_name.data,
1218 isc_result_totext (eresult));
1221 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1222 ddns_cb_free(ddns_cb, MDL);
1224 * A single DDNS operation may require several calls depending on
1225 * the current state as the prerequisites for the first message
1226 * may not succeed requiring a second operation and potentially
1227 * a ptr operation after that. The commit_leases operation is
1228 * invoked at the end of this set of operations in order to require
1229 * a single write for all of the changes. We call commit_leases
1230 * here rather than immediately after the call to update the lease
1231 * text in order to save any previously written data.
1238 * action routine when trying to remove a pointer
1239 * this will be called after the ddns queries have completed
1240 * if we succeeded in removing the pointer we go to the next step (if any)
1241 * if not we cleanup and leave.
1245 ddns_ptr_remove(dhcp_ddns_cb_t *ddns_cb,
1246 isc_result_t eresult)
1248 isc_result_t result = eresult;
1252 log_info("Removed reverse map on %.*s",
1253 (int)ddns_cb->rev_name.len,
1254 (const char *)ddns_cb->rev_name.data);
1257 case DNS_R_NXDOMAIN:
1258 /* No entry is the same as success.
1259 * Remove the information from the lease and
1260 * continue with any next step */
1261 ddns_update_lease_text(ddns_cb, NULL);
1263 /* trigger any add operation */
1264 result = ISC_R_SUCCESS;
1268 log_error("Can't remove reverse map on %.*s: %s",
1269 (int)ddns_cb->rev_name.len,
1270 (const char *)ddns_cb->rev_name.data,
1271 isc_result_totext (eresult));
1275 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1276 ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, result);
1277 ddns_cb_free(ddns_cb, MDL);
1283 * If the first query succeeds, the updater can conclude that it
1284 * has added a new name whose only RRs are the A and DHCID RR records.
1285 * The A RR update is now complete (and a client updater is finished,
1286 * while a server might proceed to perform a PTR RR update).
1287 * -- "Interaction between DHCP and DNS"
1289 * If the second query succeeds, the updater can conclude that the current
1290 * client was the last client associated with the domain name, and that
1291 * the name now contains the updated A RR. The A RR update is now
1292 * complete (and a client updater is finished, while a server would
1293 * then proceed to perform a PTR RR update).
1294 * -- "Interaction between DHCP and DNS"
1296 * If the second query fails with NXRRSET, the updater must conclude
1297 * that the client's desired name is in use by another host. At this
1298 * juncture, the updater can decide (based on some administrative
1299 * configuration outside of the scope of this document) whether to let
1300 * the existing owner of the name keep that name, and to (possibly)
1301 * perform some name disambiguation operation on behalf of the current
1302 * client, or to replace the RRs on the name with RRs that represent
1303 * the current client. If the configured policy allows replacement of
1304 * existing records, the updater submits a query that deletes the
1305 * existing A RR and the existing DHCID RR, adding A and DHCID RRs that
1306 * represent the IP address and client-identity of the new client.
1307 * -- "Interaction between DHCP and DNS"
1311 ddns_fwd_srv_add2(dhcp_ddns_cb_t *ddns_cb,
1312 isc_result_t eresult)
1314 isc_result_t result;
1315 const char *logstr = NULL;
1316 char ddns_address[MAX_ADDRESS_STRING_LEN];
1318 /* Construct a printable form of the address for logging */
1319 strcpy(ddns_address, piaddr(ddns_cb->address));
1323 log_info("Added new forward map from %.*s to %s",
1324 (int)ddns_cb->fwd_name.len,
1325 (const char *)ddns_cb->fwd_name.data,
1328 ddns_update_lease_text(ddns_cb, NULL);
1330 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1331 /* if we have zone information get rid of it */
1332 if (ddns_cb->zone != NULL) {
1333 ddns_cb_forget_zone(ddns_cb);
1336 ddns_cb->state = DDNS_STATE_ADD_PTR;
1337 ddns_cb->cur_func = ddns_ptr_add;
1339 result = ddns_modify_ptr(ddns_cb);
1340 if (result == ISC_R_SUCCESS) {
1347 case DNS_R_YXDOMAIN:
1348 logstr = "DHCID mismatch, belongs to another client.";
1352 case DNS_R_NXDOMAIN:
1353 logstr = "Has an address record but no DHCID, not mine.";
1357 logstr = isc_result_totext(eresult);
1361 if (logstr != NULL) {
1362 log_error("Forward map from %.*s to %s FAILED: %s",
1363 (int)ddns_cb->fwd_name.len,
1364 (const char *)ddns_cb->fwd_name.data,
1365 ddns_address, logstr);
1368 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1369 ddns_cb_free(ddns_cb, MDL);
1371 * A single DDNS operation may require several calls depending on
1372 * the current state as the prerequisites for the first message
1373 * may not succeed requiring a second operation and potentially
1374 * a ptr operation after that. The commit_leases operation is
1375 * invoked at the end of this set of operations in order to require
1376 * a single write for all of the changes. We call commit_leases
1377 * here rather than immediately after the call to update the lease
1378 * text in order to save any previously written data.
1385 ddns_fwd_srv_add1(dhcp_ddns_cb_t *ddns_cb,
1386 isc_result_t eresult)
1388 isc_result_t result;
1389 char ddns_address[MAX_ADDRESS_STRING_LEN];
1391 /* Construct a printable form of the address for logging */
1392 strcpy(ddns_address, piaddr(ddns_cb->address));
1396 log_info ("Added new forward map from %.*s to %s",
1397 (int)ddns_cb->fwd_name.len,
1398 (const char *)ddns_cb->fwd_name.data,
1401 ddns_update_lease_text(ddns_cb, NULL);
1403 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1404 /* if we have zone information get rid of it */
1405 if (ddns_cb->zone != NULL) {
1406 ddns_cb_forget_zone(ddns_cb);
1409 ddns_cb->state = DDNS_STATE_ADD_PTR;
1410 ddns_cb->cur_func = ddns_ptr_add;
1412 result = ddns_modify_ptr(ddns_cb);
1413 if (result == ISC_R_SUCCESS) {
1420 case DNS_R_YXDOMAIN:
1421 /* we can reuse the zone information */
1422 ddns_cb->state = DDNS_STATE_ADD_FW_YXDHCID;
1423 ddns_cb->cur_func = ddns_fwd_srv_add2;
1425 result = ddns_modify_fwd(ddns_cb);
1426 if (result == ISC_R_SUCCESS) {
1433 log_error ("Unable to add forward map from %.*s to %s: %s",
1434 (int)ddns_cb->fwd_name.len,
1435 (const char *)ddns_cb->fwd_name.data,
1437 isc_result_totext (eresult));
1441 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1442 ddns_cb_free(ddns_cb, MDL);
1444 * A single DDNS operation may require several calls depending on
1445 * the current state as the prerequisites for the first message
1446 * may not succeed requiring a second operation and potentially
1447 * a ptr operation after that. The commit_leases operation is
1448 * invoked at the end of this set of operations in order to require
1449 * a single write for all of the changes. We call commit_leases
1450 * here rather than immediately after the call to update the lease
1451 * text in order to save any previously written data.
1458 ddns_fwd_srv_connector(struct lease *lease,
1459 struct iasubopt *lease6,
1460 struct binding_scope **inscope,
1461 dhcp_ddns_cb_t *ddns_cb,
1462 isc_result_t eresult)
1464 isc_result_t result = ISC_R_FAILURE;
1466 if (ddns_cb == NULL) {
1471 if (eresult == ISC_R_SUCCESS) {
1473 * If we have updates dispatch as appropriate,
1474 * if not do FQDN binding if desired.
1477 if (ddns_cb->flags & DDNS_UPDATE_ADDR) {
1478 ddns_cb->state = DDNS_STATE_ADD_FW_NXDOMAIN;
1479 ddns_cb->cur_func = ddns_fwd_srv_add1;
1480 result = ddns_modify_fwd(ddns_cb);
1481 } else if ((ddns_cb->flags & DDNS_UPDATE_PTR) &&
1482 (ddns_cb->rev_name.len != 0)) {
1483 ddns_cb->state = DDNS_STATE_ADD_PTR;
1484 ddns_cb->cur_func = ddns_ptr_add;
1485 result = ddns_modify_ptr(ddns_cb);
1487 ddns_update_lease_text(ddns_cb, inscope);
1491 if (result == ISC_R_SUCCESS) {
1492 ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, MDL);
1494 ddns_cb_free(ddns_cb, MDL);
1501 * If the first query fails, the updater MUST NOT delete the DNS name. It
1502 * may be that the host whose lease on the server has expired has moved
1503 * to another network and obtained a lease from a different server,
1504 * which has caused the client's A RR to be replaced. It may also be
1505 * that some other client has been configured with a name that matches
1506 * the name of the DHCP client, and the policy was that the last client
1507 * to specify the name would get the name. In this case, the DHCID RR
1508 * will no longer match the updater's notion of the client-identity of
1509 * the host pointed to by the DNS name.
1510 * -- "Interaction between DHCP and DNS"
1514 ddns_fwd_srv_rem2(dhcp_ddns_cb_t *ddns_cb,
1515 isc_result_t eresult)
1517 if (eresult == ISC_R_SUCCESS) {
1518 ddns_update_lease_text(ddns_cb, NULL);
1520 /* Do the next operation */
1521 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1522 /* if we have zone information get rid of it */
1523 if (ddns_cb->zone != NULL) {
1524 ddns_cb_forget_zone(ddns_cb);
1527 ddns_cb->state = DDNS_STATE_REM_PTR;
1528 ddns_cb->cur_func = ddns_ptr_remove;
1530 eresult = ddns_modify_ptr(ddns_cb);
1531 if (eresult == ISC_R_SUCCESS) {
1537 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1538 ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult);
1539 ddns_cb_free(ddns_cb, MDL);
1545 * First action routine when trying to remove a fwd
1546 * this will be called after the ddns queries have completed
1547 * if we succeeded in removing the fwd we go to the next step (if any)
1548 * if not we cleanup and leave.
1552 ddns_fwd_srv_rem1(dhcp_ddns_cb_t *ddns_cb,
1553 isc_result_t eresult)
1555 isc_result_t result = eresult;
1556 char ddns_address[MAX_ADDRESS_STRING_LEN];
1560 /* Construct a printable form of the address for logging */
1561 strcpy(ddns_address, piaddr(ddns_cb->address));
1562 log_info("Removed forward map from %.*s to %s",
1563 (int)ddns_cb->fwd_name.len,
1564 (const char*)ddns_cb->fwd_name.data,
1567 /* Do the second step of the FWD removal */
1568 ddns_cb->state = DDNS_STATE_REM_FW_NXRR;
1569 ddns_cb->cur_func = ddns_fwd_srv_rem2;
1570 result = ddns_modify_fwd(ddns_cb);
1571 if (result == ISC_R_SUCCESS) {
1577 case DNS_R_NXDOMAIN:
1578 ddns_update_lease_text(ddns_cb, NULL);
1580 /* Do the next operation */
1581 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1582 /* if we have zone information get rid of it */
1583 if (ddns_cb->zone != NULL) {
1584 ddns_cb_forget_zone(ddns_cb);
1587 ddns_cb->state = DDNS_STATE_REM_PTR;
1588 ddns_cb->cur_func = ddns_ptr_remove;
1590 result = ddns_modify_ptr(ddns_cb);
1591 if (result == ISC_R_SUCCESS) {
1596 /* Trigger the add operation */
1597 eresult = ISC_R_SUCCESS;
1605 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1606 ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult);
1607 ddns_cb_free(ddns_cb, MDL);
1612 * Remove relevant entries from DNS.
1615 * 0 - badness occurred and we weren't able to do what was wanted
1616 * 1 - we were able to do stuff but it's in progress
1617 * in both cases any additional block has been passed on to it's handler
1619 * active == ISC_TRUE if the lease is still active, and FALSE if the lease
1620 * is inactive. This is used to indicate if the lease is inactive or going
1621 * to inactive in IPv6 so we can avoid trying to update the lease with
1622 * cb pointers and text information.
1626 ddns_removals(struct lease *lease,
1627 struct iasubopt *lease6,
1628 dhcp_ddns_cb_t *add_ddns_cb,
1629 isc_boolean_t active)
1631 isc_result_t rcode, execute_add = ISC_R_FAILURE;
1632 struct binding_scope **scope = NULL;
1634 dhcp_ddns_cb_t *ddns_cb = NULL;
1635 struct data_string leaseid;
1638 * Cancel any outstanding requests. When called
1639 * from within the DNS code we probably will have
1640 * already done the cancel but if called from outside
1641 * - for example as part of a lease expiry - we won't.
1643 if ((lease != NULL) && (lease->ddns_cb != NULL)) {
1644 ddns_cancel(lease->ddns_cb);
1645 lease->ddns_cb = NULL;
1646 } else if ((lease6 != NULL) && (lease6->ddns_cb != NULL)) {
1647 ddns_cancel(lease6->ddns_cb);
1648 lease6->ddns_cb = NULL;
1651 /* allocate our control block */
1652 ddns_cb = ddns_cb_alloc(MDL);
1653 if (ddns_cb == NULL) {
1658 * For v4 we flag static leases so we don't try
1659 * and manipulate the lease later. For v6 we don't
1660 * get static leases and don't need to flag them.
1662 if (lease != NULL) {
1663 scope = &(lease->scope);
1664 ddns_cb->address = lease->ip_addr;
1665 if (lease->flags & STATIC_LEASE)
1666 ddns_cb->flags |= DDNS_STATIC_LEASE;
1667 } else if (lease6 != NULL) {
1668 scope = &(lease6->scope);
1669 memcpy(&ddns_cb->address.iabuf, lease6->addr.s6_addr, 16);
1670 ddns_cb->address.len = 16;
1675 * Set the flag bit if the lease is active, that is it isn't
1676 * expired or released. This is used in the IPv6 paths to
1677 * determine if we need to update the lease when the response
1678 * from the DNS code is processed.
1680 if (active == ISC_TRUE) {
1681 ddns_cb->flags |= DDNS_ACTIVE_LEASE;
1684 /* No scope implies that DDNS has not been performed for this lease. */
1688 if (ddns_update_style != 2)
1691 /* Assume that we are removing both records */
1692 ddns_cb->flags |= DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR;
1694 /* and that we want to do the add call */
1695 execute_add = ISC_R_SUCCESS;
1698 * Look up stored names.
1702 * Find the fwd name and copy it to the control block. If we don't
1703 * have it we can't delete the fwd record but we can still try to
1704 * remove the ptr record and cleanup the lease information if the
1705 * client did the fwd update.
1707 if (!find_bound_string(&ddns_cb->fwd_name, *scope, "ddns-fwd-name")) {
1708 /* don't try and delete the A, or do the add */
1709 ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
1710 execute_add = ISC_R_FAILURE;
1712 /* Check if client did update */
1713 if (find_bound_string(&ddns_cb->fwd_name, *scope,
1714 "ddns-client-fqdn")) {
1715 ddns_cb->flags |= DDNS_CLIENT_DID_UPDATE;
1720 * Find the ptr name and copy it to the control block. If we don't
1721 * have it this isn't an interim or rfc3??? record so we can't delete
1722 * the A record using this mechanism but we can delete the ptr record.
1723 * In this case we will attempt to do any requested next step.
1725 memset(&leaseid, 0, sizeof(leaseid));
1726 if (!find_bound_string (&leaseid, *scope, "ddns-txt")) {
1727 ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
1729 if (dhcid_fromlease(&ddns_cb->dhcid, &leaseid) !=
1731 /* We couldn't convert the dhcid from the lease
1732 * version to the dns version. We can't delete
1733 * the A record but can continue to the ptr
1735 ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
1737 data_string_forget(&leaseid, MDL);
1741 * Find the rev name and copy it to the control block. If we don't
1742 * have it we can't get rid of it but we can try to remove the fwd
1743 * pointer if desired.
1745 if (!find_bound_string(&ddns_cb->rev_name, *scope, "ddns-rev-name")) {
1746 ddns_cb->flags &= ~DDNS_UPDATE_PTR;
1750 * If we have a second control block for doing an add
1751 * after the remove finished attach it to our control block.
1753 ddns_cb->next_op = add_ddns_cb;
1756 * Now that we've collected the information we can try to process it.
1757 * If necessary we call an appropriate routine to send a message and
1758 * provide it with an action routine to run on the control block given
1759 * the results of the message. We have three entry points from here,
1760 * one for removing the A record, the next for removing the PTR and
1761 * the third for doing any requested add.
1763 if ((ddns_cb->flags & DDNS_UPDATE_ADDR) != 0) {
1764 if (ddns_cb->fwd_name.len != 0) {
1765 ddns_cb->state = DDNS_STATE_REM_FW_YXDHCID;
1766 ddns_cb->cur_func = ddns_fwd_srv_rem1;
1768 rcode = ddns_modify_fwd(ddns_cb);
1769 if (rcode == ISC_R_SUCCESS) {
1770 ddns_update_lease_ptr(lease, lease6, ddns_cb,
1776 * We weren't able to process the request tag the
1777 * add so we won't execute it.
1779 execute_add = ISC_R_FAILURE;
1783 /*remove info from scope */
1784 unset(*scope, "ddns-fwd-name");
1785 unset(*scope, "ddns-txt");
1789 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1790 ddns_cb->state = DDNS_STATE_REM_PTR;
1791 ddns_cb->cur_func = ddns_ptr_remove;
1794 * if execute add isn't success remove the control block so
1795 * it won't be processed when the remove completes. We
1796 * also arrange to clean it up and get rid of it.
1798 if (execute_add != ISC_R_SUCCESS) {
1799 ddns_cb->next_op = NULL;
1800 ddns_fwd_srv_connector(lease, lease6, scope,
1801 add_ddns_cb, execute_add);
1808 rcode = ddns_modify_ptr(ddns_cb);
1809 if (rcode == ISC_R_SUCCESS) {
1810 ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb,
1815 /* We weren't able to process the request tag the
1816 * add so we won't execute it */
1817 execute_add = ISC_R_FAILURE;
1823 * We've gotten here because we didn't need to send a message or
1824 * we failed when trying to do so. We send the additional cb
1825 * off to handle sending and/or cleanup and cleanup anything
1826 * we allocated here.
1828 ddns_fwd_srv_connector(lease, lease6, scope, add_ddns_cb, execute_add);
1829 if (ddns_cb != NULL)
1830 ddns_cb_free(ddns_cb, MDL);
1835 #endif /* NSUPDATE */