3 Dynamic DNS updates. */
7 * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 2000-2003 by Internet Software Consortium
10 * This Source Code Form is subject to the terms of the Mozilla Public
11 * License, v. 2.0. If a copy of the MPL was not distributed with this
12 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
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 * Newmarket, NH 03857 USA
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/''.
36 #include <dns/result.h>
38 char *ddns_standard_tag
= "ddns-dhcid";
39 char *ddns_interim_tag
= "ddns-txt";
43 #if defined (DEBUG_DNS_UPDATES)
44 static char* dump_ddns_cb_func(void *func
);
45 static char* dump_ddns_cb (dhcp_ddns_cb_t
*ddns_cb
);
47 extern struct enumeration_value ddns_styles_values
[];
50 static void ddns_fwd_srv_connector(struct lease
*lease
,
51 struct iasubopt
*lease6
,
52 struct binding_scope
**inscope
,
53 dhcp_ddns_cb_t
*ddns_cb
,
54 isc_result_t eresult
);
56 static void copy_conflict_flags(u_int16_t
*target
, u_int16_t source
);
58 static void ddns_fwd_srv_add3(dhcp_ddns_cb_t
*ddns_cb
, isc_result_t eresult
);
61 * ddns_cb_free() is part of common lib, while ia_* routines are known
62 * only in the server. Use this wrapper instead of ddns_cb_free() directly.
65 destroy_ddns_cb(struct dhcp_ddns_cb
*ddns_cb
, char* file
, int line
) {
70 if (ddns_cb
->fixed6_ia
) {
71 ia_dereference(&ddns_cb
->fixed6_ia
, MDL
);
74 ddns_cb_free(ddns_cb
, file
, line
);
79 /* DN: No way of checking that there is enough space in a data_string's
80 buffer. Be certain to allocate enough!
81 TL: This is why the expression evaluation code allocates a *new*
83 static void data_string_append (struct data_string
*ds1
,
84 struct data_string
*ds2
)
86 memcpy (ds1
-> buffer
-> data
+ ds1
-> len
,
89 ds1
-> len
+= ds2
-> len
;
93 /* Determine what, if any, forward and reverse updates need to be
94 * performed, and carry them through.
97 ddns_updates(struct packet
*packet
, struct lease
*lease
, struct lease
*old
,
98 struct iasubopt
*lease6
, struct iasubopt
*old6
,
99 struct option_state
*options
)
101 unsigned long ddns_ttl
= DEFAULT_DDNS_TTL
;
102 struct data_string ddns_hostname
;
103 struct data_string ddns_domainname
;
104 struct data_string old_ddns_fwd_name
;
105 struct data_string ddns_fwd_name
;
106 struct data_string ddns_dhcid
;
107 struct binding_scope
**scope
= NULL
;
108 struct data_string d1
;
109 struct option_cache
*oc
;
112 int server_updates_a
= 1;
113 struct buffer
*bp
= (struct buffer
*)0;
114 int ignorep
= 0, client_ignorep
= 0;
118 dhcp_ddns_cb_t
*ddns_cb
;
121 if ((ddns_update_style
!= DDNS_UPDATE_STYLE_STANDARD
) &&
122 (ddns_update_style
!= DDNS_UPDATE_STYLE_INTERIM
))
126 * sigh, I want to cancel any previous udpates before we do anything
127 * else but this means we need to deal with the lease vs lease6
129 * If there is a ddns request already outstanding cancel it.
133 if ((old
!= NULL
) && (old
->ddns_cb
!= NULL
)) {
134 ddns_cancel(old
->ddns_cb
, MDL
);
137 } else if (lease6
!= NULL
) {
138 if ((old6
!= NULL
) && (old6
->ddns_cb
!= NULL
)) {
139 ddns_cancel(old6
->ddns_cb
, MDL
);
140 old6
->ddns_cb
= NULL
;
143 log_fatal("Impossible condition at %s:%d.", MDL
);
144 /* Silence compiler warnings. */
149 /* allocate our control block */
150 ddns_cb
= ddns_cb_alloc(MDL
);
151 if (ddns_cb
== NULL
) {
155 * Assume that we shall update both the A and ptr records and,
156 * as this is an update, set the active flag
158 ddns_cb
->flags
= DDNS_UPDATE_ADDR
| DDNS_UPDATE_PTR
|
162 * For v4 we flag static leases so we don't try
163 * and manipulate the lease later. For v6 we don't
164 * get static leases and don't need to flag them.
167 scope
= &(lease
->scope
);
168 ddns_cb
->address
= lease
->ip_addr
;
169 if (lease
->flags
& STATIC_LEASE
)
170 ddns_cb
->flags
|= DDNS_STATIC_LEASE
;
171 } else if (lease6
!= NULL
) {
172 scope
= &(lease6
->scope
);
173 memcpy(ddns_cb
->address
.iabuf
, lease6
->addr
.s6_addr
, 16);
174 ddns_cb
->address
.len
= 16;
176 if (lease6
->static_lease
) {
177 /* We add a reference to keep ia && iasubopt alive
178 * since static v6s are retained anywhere */
179 ia_reference(&ddns_cb
->fixed6_ia
, lease6
->ia
, MDL
);
180 ddns_cb
->flags
|= DDNS_STATIC_LEASE
;
184 memset (&d1
, 0, sizeof(d1
));
185 memset (&ddns_hostname
, 0, sizeof (ddns_hostname
));
186 memset (&ddns_domainname
, 0, sizeof (ddns_domainname
));
187 memset (&old_ddns_fwd_name
, 0, sizeof (ddns_fwd_name
));
188 memset (&ddns_fwd_name
, 0, sizeof (ddns_fwd_name
));
189 memset (&ddns_dhcid
, 0, sizeof (ddns_dhcid
));
191 /* If we are allowed to accept the client's update of its own A
192 record, see if the client wants to update its own A record. */
193 if (!(oc
= lookup_option(&server_universe
, options
,
194 SV_CLIENT_UPDATES
)) ||
195 evaluate_boolean_option_cache(&client_ignorep
, packet
, lease
, NULL
,
196 packet
->options
, options
, scope
,
198 /* If there's no fqdn.no-client-update or if it's
199 nonzero, don't try to use the client-supplied
201 if (!(oc
= lookup_option (&fqdn_universe
, packet
-> options
,
202 FQDN_SERVER_UPDATE
)) ||
203 evaluate_boolean_option_cache(&ignorep
, packet
, lease
,
204 NULL
, packet
->options
,
205 options
, scope
, oc
, MDL
))
207 /* Win98 and Win2k will happily claim to be willing to
208 update an unqualified domain name. */
209 if (!(oc
= lookup_option (&fqdn_universe
, packet
-> options
,
212 if (!(oc
= lookup_option (&fqdn_universe
, packet
-> options
,
214 !evaluate_option_cache(&ddns_fwd_name
, packet
, lease
,
215 NULL
, packet
->options
,
216 options
, scope
, oc
, MDL
))
218 ddns_cb
->flags
&= ~DDNS_UPDATE_ADDR
;
219 server_updates_a
= 0;
223 /* If do-forward-updates is disabled, this basically means don't
224 do an update unless the client is participating, so if we get
225 here and do-forward-updates is disabled, we can stop. */
226 if ((oc
= lookup_option (&server_universe
, options
,
227 SV_DO_FORWARD_UPDATES
)) &&
228 !evaluate_boolean_option_cache(&ignorep
, packet
, lease
,
229 NULL
, packet
->options
,
230 options
, scope
, oc
, MDL
)) {
234 /* If it's a static lease, then don't do the DNS update unless we're
235 specifically configured to do so. If the client asked to do its
236 own update and we allowed that, we don't do this test. */
237 /* XXX: note that we cannot detect static DHCPv6 leases. */
238 if ((lease
!= NULL
) && (lease
->flags
& STATIC_LEASE
)) {
239 if (!(oc
= lookup_option(&server_universe
, options
,
240 SV_UPDATE_STATIC_LEASES
)) ||
241 !evaluate_boolean_option_cache(&ignorep
, packet
, lease
,
242 NULL
, packet
->options
,
243 options
, scope
, oc
, MDL
))
248 * Compute the name for the A record.
250 oc
= lookup_option(&server_universe
, options
, SV_DDNS_HOST_NAME
);
252 s1
= evaluate_option_cache(&ddns_hostname
, packet
, lease
,
253 NULL
, packet
->options
,
254 options
, scope
, oc
, MDL
);
258 /* If we don't have a host name based on ddns-hostname then use
259 * the host declaration name if there is one and use-host-decl-names
261 if ((s1
== 0) && (lease
&& lease
->host
&& lease
->host
->name
)) {
262 oc
= lookup_option(&server_universe
, options
,
263 SV_USE_HOST_DECL_NAMES
);
264 if (evaluate_boolean_option_cache(NULL
, packet
, lease
,
265 NULL
, packet
->options
,
266 options
, scope
, oc
, MDL
)) {
267 s1
= ((data_string_new(&ddns_hostname
,
269 strlen(lease
->host
->name
),
270 MDL
) && ddns_hostname
.len
> 0));
274 oc
= lookup_option(&server_universe
, options
, SV_DDNS_DOMAIN_NAME
);
276 s2
= evaluate_option_cache(&ddns_domainname
, packet
, lease
,
277 NULL
, packet
->options
,
278 options
, scope
, oc
, MDL
);
283 if (ddns_hostname
.len
+ ddns_domainname
.len
> 253) {
284 log_error ("ddns_update: host.domain name too long");
289 if (buffer_allocate (&ddns_fwd_name
.buffer
,
291 ddns_domainname
.len
+ 2, MDL
)) {
292 ddns_fwd_name
.data
= ddns_fwd_name
.buffer
->data
;
293 data_string_append (&ddns_fwd_name
, &ddns_hostname
);
294 ddns_fwd_name
.buffer
->data
[ddns_fwd_name
.len
] = '.';
296 data_string_append (&ddns_fwd_name
, &ddns_domainname
);
297 ddns_fwd_name
.buffer
->data
[ddns_fwd_name
.len
] ='\0';
298 ddns_fwd_name
.terminated
= 1;
303 /* See if there's a name already stored on the lease. */
304 if (find_bound_string(&old_ddns_fwd_name
, *scope
, "ddns-fwd-name")) {
305 /* If there is, see if it's different. */
306 if (old_ddns_fwd_name
.len
!= ddns_fwd_name
.len
||
307 memcmp (old_ddns_fwd_name
.data
, ddns_fwd_name
.data
,
308 old_ddns_fwd_name
.len
)) {
310 * If the name is different, mark the old record
311 * for deletion and continue getting the new info.
317 #if defined (DDNS_UPDATE_SLOW_TRANSITION)
319 * If the slow transition code is enabled check to see
320 * if the stored type (standard or interim doesn't
321 * match the type currently in use. If it doesn't
322 * try to remove and replace the DNS record
324 if (((ddns_update_style
== DDNS_UPDATE_STYLE_STANDARD
) &&
325 find_bound_string(&ddns_dhcid
, *scope
, ddns_interim_tag
)) ||
326 ((ddns_update_style
== DDNS_UPDATE_STYLE_INTERIM
) &&
327 find_bound_string(&ddns_dhcid
, *scope
, ddns_standard_tag
))) {
328 data_string_forget(&ddns_dhcid
, MDL
);
334 /* See if the administrator wants to do updates even
335 in cases where the update already appears to have been
337 if (!(oc
= lookup_option(&server_universe
, options
,
338 SV_UPDATE_OPTIMIZATION
)) ||
339 evaluate_boolean_option_cache(&ignorep
, packet
, lease
,
340 NULL
, packet
->options
,
341 options
, scope
, oc
, MDL
)) {
345 /* If there's no "ddns-fwd-name" on the lease record, see if
346 * there's a ddns-client-fqdn indicating a previous client
347 * update (if it changes, we need to adjust the PTR).
349 } else if (find_bound_string(&old_ddns_fwd_name
, *scope
,
350 "ddns-client-fqdn")) {
351 /* If the name is not different, no need to update
353 if (old_ddns_fwd_name
.len
== ddns_fwd_name
.len
&&
354 !memcmp (old_ddns_fwd_name
.data
, ddns_fwd_name
.data
,
355 old_ddns_fwd_name
.len
) &&
356 (!(oc
= lookup_option(&server_universe
, options
,
357 SV_UPDATE_OPTIMIZATION
)) ||
358 evaluate_boolean_option_cache(&ignorep
, packet
, lease
,
359 NULL
, packet
->options
,
360 options
, scope
, oc
, MDL
))) {
366 /* If we don't have a name that the client has been assigned, we
367 can just skip all this. */
369 if ((!ddns_fwd_name
.len
) || (ddns_fwd_name
.len
> 255)) {
370 if (ddns_fwd_name
.len
> 255) {
371 log_error ("client provided fqdn: too long");
374 /* If desired do the removals */
375 if (do_remove
!= 0) {
376 (void) ddns_removals(lease
, lease6
, NULL
, ISC_TRUE
);
382 * Compute the RR TTL.
384 * We have two ways of computing the TTL.
385 * The old behavior was to allow for the customer to set up
386 * the option or to default things. For v4 this was 1/2
387 * of the lease time, for v6 this was DEFAULT_DDNS_TTL.
388 * The new behavior continues to allow the customer to set
389 * up an option but the defaults are a little different.
390 * We now use 1/2 of the (preferred) lease time for both
391 * v4 and v6 and cap them at a maximum value.
392 * If the customer chooses to use an experession that references
393 * part of the lease the v6 value will be the default as there
394 * isn't a lease available for v6.
397 ddns_ttl
= DEFAULT_DDNS_TTL
;
399 if (lease
->ends
<= cur_time
) {
402 ddns_ttl
= (lease
->ends
- cur_time
)/2;
405 #ifndef USE_OLD_DDNS_TTL
406 else if (lease6
!= NULL
) {
407 ddns_ttl
= lease6
->prefer
/2;
410 if (ddns_ttl
> MAX_DEFAULT_DDNS_TTL
) {
411 ddns_ttl
= MAX_DEFAULT_DDNS_TTL
;
415 if ((oc
= lookup_option(&server_universe
, options
, SV_DDNS_TTL
))) {
416 if (evaluate_option_cache(&d1
, packet
, lease
, NULL
,
417 packet
->options
, options
,
419 if (d1
.len
== sizeof (u_int32_t
))
420 ddns_ttl
= getULong (d1
.data
);
421 data_string_forget (&d1
, MDL
);
425 ddns_cb
->ttl
= ddns_ttl
;
428 * Compute the reverse IP name, starting with the domain name.
430 oc
= lookup_option(&server_universe
, options
, SV_DDNS_REV_DOMAIN_NAME
);
432 s1
= evaluate_option_cache(&d1
, packet
, lease
, NULL
,
433 packet
->options
, options
,
439 * Figure out the length of the part of the name that depends
442 if (ddns_cb
->address
.len
== 4) {
444 /* XXX: WOW this is gross. */
445 rev_name_len
= snprintf(buf
, sizeof(buf
), "%u.%u.%u.%u.",
446 ddns_cb
->address
.iabuf
[3] & 0xff,
447 ddns_cb
->address
.iabuf
[2] & 0xff,
448 ddns_cb
->address
.iabuf
[1] & 0xff,
449 ddns_cb
->address
.iabuf
[0] & 0xff) + 1;
452 rev_name_len
+= d1
.len
;
454 if (rev_name_len
> 255) {
455 log_error("ddns_update: Calculated rev domain "
458 data_string_forget(&d1
, MDL
);
461 } else if (ddns_cb
->address
.len
== 16) {
463 * IPv6 reverse names are always the same length, with
464 * 32 hex characters separated by dots.
466 rev_name_len
= sizeof("0.1.2.3.4.5.6.7."
472 /* Set s1 to make sure we gate into updates. */
475 log_fatal("invalid address length %d", ddns_cb
->address
.len
);
476 /* Silence compiler warnings. */
480 /* See if we are configured NOT to do reverse ptr updates */
481 if ((oc
= lookup_option(&server_universe
, options
,
482 SV_DO_REVERSE_UPDATES
)) &&
483 !evaluate_boolean_option_cache(&ignorep
, packet
, lease
, NULL
,
484 packet
->options
, options
,
486 ddns_cb
->flags
&= ~DDNS_UPDATE_PTR
;
490 if (buffer_allocate(&ddns_cb
->rev_name
.buffer
,
491 rev_name_len
, MDL
)) {
492 struct data_string
*rname
= &ddns_cb
->rev_name
;
493 rname
->data
= rname
->buffer
->data
;
495 if (ddns_cb
->address
.len
== 4) {
497 sprintf((char *)rname
->buffer
->data
,
499 ddns_cb
->address
.iabuf
[3] & 0xff,
500 ddns_cb
->address
.iabuf
[2] & 0xff,
501 ddns_cb
->address
.iabuf
[1] & 0xff,
502 ddns_cb
->address
.iabuf
[0] & 0xff);
505 * d1.data may be opaque, garbage bytes, from
506 * user (mis)configuration.
508 data_string_append(rname
, &d1
);
509 rname
->buffer
->data
[rname
->len
] = '\0';
510 } else if (ddns_cb
->address
.len
== 16) {
511 char *p
= (char *)&rname
->buffer
->data
;
512 unsigned char *a
= ddns_cb
->address
.iabuf
+ 15;
513 for (i
=0; i
<16; i
++) {
515 (*a
& 0xF), ((*a
>> 4) & 0xF));
519 strcat(p
, "ip6.arpa.");
520 rname
->len
= strlen((const char *)rname
->data
);
523 rname
->terminated
= 1;
527 data_string_forget(&d1
, MDL
);
531 * copy the string now so we can pass it to the dhcid routines
532 * via the ddns_cb pointer
534 data_string_copy(&ddns_cb
->fwd_name
, &ddns_fwd_name
, MDL
);
537 * If we are updating the A record, compute the DHCID value.
538 * We have two options for computing the DHCID value, the older
539 * interim version and the newer standard version. The interim
540 * has some issues but is left as is to avoid compatibility issues.
542 * We select the type of DHCID to construct and the information to
543 * use for the digest based on 4701 section 3.3
545 if ((ddns_cb
->flags
& DDNS_UPDATE_ADDR
) != 0) {
548 if (ddns_update_style
== DDNS_UPDATE_STYLE_STANDARD
) {
549 /* The standard style */
550 ddns_cb
->lease_tag
= ddns_standard_tag
;
551 ddns_cb
->dhcid_class
= dns_rdatatype_dhcid
;
552 ddns_cb
->other_dhcid_class
= dns_rdatatype_txt
;
556 /* The older interim style */
557 ddns_cb
->lease_tag
= ddns_interim_tag
;
558 ddns_cb
->dhcid_class
= dns_rdatatype_txt
;
559 ddns_cb
->other_dhcid_class
= dns_rdatatype_dhcid
;
560 /* for backwards compatibility */
561 ddns_type
= DHO_DHCP_CLIENT_IDENTIFIER
;
562 /* IAID incorrectly included */
567 if (lease6
!= NULL
) {
568 if (lease6
->ia
->iaid_duid
.len
< ddns_len
)
570 result
= get_dhcid(ddns_cb
, 2,
571 lease6
->ia
->iaid_duid
.data
+ ddns_len
,
572 lease6
->ia
->iaid_duid
.len
- ddns_len
);
573 } else if ((lease
!= NULL
) &&
574 (lease
->uid
!= NULL
) &&
575 (lease
->uid_len
!= 0)) {
576 /* If this is standard check for an RFC 4361
577 * compliant client identifier
579 if ((ddns_update_style
== DDNS_UPDATE_STYLE_STANDARD
) &&
580 (lease
->uid
[0] == 255)) {
581 if (lease
->uid_len
< 5)
583 result
= get_dhcid(ddns_cb
, 2,
587 result
= get_dhcid(ddns_cb
, ddns_type
,
591 } else if (lease
!= NULL
)
592 result
= get_dhcid(ddns_cb
, 0,
593 lease
->hardware_addr
.hbuf
,
594 lease
->hardware_addr
.hlen
);
596 log_fatal("Impossible condition at %s:%d.", MDL
);
606 if (ddns_cb
->flags
& DDNS_UPDATE_ADDR
) {
607 copy_conflict_flags(&ddns_cb
->flags
, ddns_conflict_mask
);
611 * Previously if we failed during the removal operations
612 * we skipped the fqdn option processing. I'm not sure
613 * if we want to continue with that if we fail before sending
614 * the ddns messages. Currently we don't.
618 * We should log a more specific error closer to the actual
619 * error if we want one. ddns_removal failure not logged here.
621 (void) ddns_removals(lease
, lease6
, ddns_cb
, ISC_TRUE
);
624 ddns_fwd_srv_connector(lease
, lease6
, scope
, ddns_cb
,
631 * If fqdn-reply option is disabled in dhcpd.conf, then don't
632 * send the client an FQDN option at all, even if one was requested.
633 * (WinXP clients allegedly misbehave if the option is present,
634 * refusing to handle PTR updates themselves).
636 if ((oc
= lookup_option (&server_universe
, options
, SV_FQDN_REPLY
)) &&
637 !evaluate_boolean_option_cache(&ignorep
, packet
, lease
, NULL
,
638 packet
->options
, options
,
642 /* If we're ignoring client updates, then we tell a sort of 'white
643 * lie'. We've already updated the name the server wants (per the
644 * config written by the server admin). Now let the client do as
645 * it pleases with the name they supplied (if any).
647 * We only form an FQDN option this way if the client supplied an
648 * FQDN option that had FQDN_SERVER_UPDATE set false.
650 } else if (client_ignorep
&&
651 (oc
= lookup_option(&fqdn_universe
, packet
->options
,
652 FQDN_SERVER_UPDATE
)) &&
653 !evaluate_boolean_option_cache(&ignorep
, packet
, lease
, NULL
,
654 packet
->options
, options
,
656 oc
= lookup_option(&fqdn_universe
, packet
->options
, FQDN_FQDN
);
657 if (oc
&& evaluate_option_cache(&d1
, packet
, lease
, NULL
,
658 packet
->options
, options
,
661 !buffer_allocate(&bp
, d1
.len
+ 5, MDL
))
664 /* Server pretends it is not updating. */
666 if (!save_option_buffer(&fqdn_universe
, options
,
668 FQDN_SERVER_UPDATE
, 0))
671 /* Client is encouraged to update. */
673 if (!save_option_buffer(&fqdn_universe
, options
,
675 FQDN_NO_CLIENT_UPDATE
, 0))
678 /* Use the encoding of client's FQDN option. */
679 oc
= lookup_option(&fqdn_universe
, packet
->options
,
682 evaluate_boolean_option_cache(&ignorep
, packet
,
687 bp
->data
[2] = 1; /* FQDN is encoded. */
689 bp
->data
[2] = 0; /* FQDN is not encoded. */
691 if (!save_option_buffer(&fqdn_universe
, options
,
696 /* Current FQDN drafts indicate 255 is mandatory. */
698 if (!save_option_buffer(&fqdn_universe
, options
,
704 if (!save_option_buffer(&fqdn_universe
, options
,
709 /* Copy in the FQDN supplied by the client. Note well
710 * that the format of this option in the cache is going
711 * to be in text format. If the fqdn supplied by the
712 * client is encoded, it is decoded into the option
713 * cache when parsed out of the packet. It will be
714 * re-encoded when the option is assembled to be
715 * transmitted if the client elects that encoding.
717 memcpy(&bp
->data
[5], d1
.data
, d1
.len
);
718 if (!save_option_buffer(&fqdn_universe
, options
,
719 bp
, &bp
->data
[5], d1
.len
,
723 data_string_forget(&d1
, MDL
);
725 /* Set up the outgoing FQDN option if there was an incoming
726 * FQDN option. If there's a valid FQDN option, there MUST
727 * be an FQDN_SERVER_UPDATES suboption, it's part of the fixed
728 * length head of the option contents, so we test the latter
729 * to detect the presence of the former.
731 } else if ((oc
= lookup_option(&fqdn_universe
, packet
->options
,
733 buffer_allocate(&bp
, ddns_fwd_name
.len
+ 5, MDL
)) {
734 bp
-> data
[0] = server_updates_a
;
735 if (!save_option_buffer(&fqdn_universe
, options
,
736 bp
, &bp
->data
[0], 1,
737 FQDN_SERVER_UPDATE
, 0))
739 bp
-> data
[1] = server_updates_a
;
740 if (!save_option_buffer(&fqdn_universe
, options
,
741 bp
, &bp
->data
[1], 1,
742 FQDN_NO_CLIENT_UPDATE
, 0))
745 /* Do the same encoding the client did. */
746 if (evaluate_boolean_option_cache(&ignorep
, packet
, lease
,
747 NULL
, packet
->options
,
748 options
, scope
, oc
, MDL
))
752 if (!save_option_buffer(&fqdn_universe
, options
,
753 bp
, &bp
->data
[2], 1,
756 bp
-> data
[3] = 255;//isc_rcode_to_ns (rcode1);
757 if (!save_option_buffer(&fqdn_universe
, options
,
758 bp
, &bp
->data
[3], 1,
761 bp
-> data
[4] = 255;//isc_rcode_to_ns (rcode2);
762 if (!save_option_buffer(&fqdn_universe
, options
,
763 bp
, &bp
->data
[4], 1,
766 if (ddns_fwd_name
.len
) {
767 memcpy (&bp
-> data
[5],
768 ddns_fwd_name
.data
, ddns_fwd_name
.len
);
769 if (!save_option_buffer(&fqdn_universe
, options
,
782 if (ddns_cb
!= NULL
) {
783 destroy_ddns_cb(ddns_cb
, MDL
);
786 data_string_forget(&d1
, MDL
);
787 data_string_forget(&ddns_hostname
, MDL
);
788 data_string_forget(&ddns_domainname
, MDL
);
789 data_string_forget(&old_ddns_fwd_name
, MDL
);
790 data_string_forget(&ddns_fwd_name
, MDL
);
792 buffer_dereference(&bp
, MDL
);
798 * Utility function to update text strings within a lease.
800 * The first issue is to find the proper scope. Sometimes we shall be
801 * called with a pointer to the scope in other cases we need to find
802 * the proper lease and then get the scope. Once we have the scope we update
803 * the proper strings, as indicated by the state value in the control block.
804 * Lastly, if we needed to find the scope we write it out, if we used a
805 * scope that was passed as an argument we don't write it, assuming that
806 * our caller (or his ...) will do the write.
808 *\li ddns_cb - the control block for the DDNS request
810 *\li inscope - a pointer to the scope to update. This may be NULL
811 * in which case we use the control block to find the lease and
817 *\li ISC_R_FAILURE - The routine was unable to find an expected scope.
818 * In some cases (static and inactive leases) we don't expect a scope
819 * and return success.
823 ddns_update_lease_text(dhcp_ddns_cb_t
*ddns_cb
,
824 struct binding_scope
**inscope
)
826 struct binding_scope
**scope
= NULL
;
827 struct lease
*lease
= NULL
;
828 struct iasubopt
*lease6
= NULL
;
829 struct ipv6_pool
*pool
= NULL
;
830 struct in6_addr addr
;
831 struct data_string lease_dhcid
;
834 * If the lease was static (for a fixed address)
835 * we don't need to do any work.
837 if (ddns_cb
->flags
& DDNS_STATIC_LEASE
)
838 return (ISC_R_SUCCESS
);
841 * If we are processing an expired or released v6 lease
842 * or some types of v4 leases we don't actually have a
845 if ((ddns_cb
->flags
& DDNS_ACTIVE_LEASE
) == 0)
846 return (ISC_R_SUCCESS
);
848 if (inscope
!= NULL
) {
850 } else if (ddns_cb
->address
.len
== 4) {
851 if (find_lease_by_ip_addr(&lease
, ddns_cb
->address
, MDL
) != 0){
852 scope
= &(lease
->scope
);
854 } else if (ddns_cb
->address
.len
== 16) {
855 memcpy(&addr
, &ddns_cb
->address
.iabuf
, 16);
856 if ((find_ipv6_pool(&pool
, D6O_IA_TA
, &addr
) ==
858 (find_ipv6_pool(&pool
, D6O_IA_NA
, &addr
) ==
860 if (iasubopt_hash_lookup(&lease6
, pool
->leases
,
862 scope
= &(lease6
->scope
);
864 ipv6_pool_dereference(&pool
, MDL
);
867 log_fatal("Impossible condition at %s:%d.", MDL
);
871 /* If necessary get rid of the lease */
873 lease_dereference(&lease
, MDL
);
876 iasubopt_dereference(&lease6
, MDL
);
879 return(ISC_R_FAILURE
);
882 /* We now have a scope and can proceed to update it */
883 switch(ddns_cb
->state
) {
884 case DDNS_STATE_REM_PTR
:
885 unset(*scope
, "ddns-rev-name");
886 if ((ddns_cb
->flags
& DDNS_CLIENT_DID_UPDATE
) != 0) {
887 unset(*scope
, "ddns-client-fqdn");
891 case DDNS_STATE_ADD_PTR
:
892 case DDNS_STATE_CLEANUP
:
893 bind_ds_value(scope
, "ddns-rev-name", &ddns_cb
->rev_name
);
894 if ((ddns_cb
->flags
& DDNS_UPDATE_ADDR
) == 0) {
895 bind_ds_value(scope
, "ddns-client-fqdn",
900 case DDNS_STATE_ADD_FW_YXDHCID
:
901 case DDNS_STATE_ADD_FW_NXDOMAIN
:
902 case DDNS_STATE_DSMM_FW_ADD3
:
903 bind_ds_value(scope
, "ddns-fwd-name", &ddns_cb
->fwd_name
);
905 if (ddns_cb
->lease_tag
== ddns_standard_tag
) {
906 bind_ds_value(scope
, ddns_standard_tag
,
909 /* convert from dns version to lease version of dhcid */
910 memset(&lease_dhcid
, 0, sizeof(lease_dhcid
));
911 dhcid_tolease(&ddns_cb
->dhcid
, &lease_dhcid
);
912 bind_ds_value(scope
, ddns_interim_tag
, &lease_dhcid
);
913 data_string_forget(&lease_dhcid
, MDL
);
917 case DDNS_STATE_REM_FW_NXRR
:
918 case DDNS_STATE_REM_FW_YXDHCID
:
919 case DDNS_STATE_REM_FW_DSMM_OTHER
:
920 unset(*scope
, "ddns-fwd-name");
921 unset(*scope
, ddns_cb
->lease_tag
);
925 /* If necessary write it out and get rid of the lease */
928 lease_dereference(&lease
, MDL
);
930 write_ia(lease6
->ia
);
931 iasubopt_dereference(&lease6
, MDL
);
934 return(ISC_R_SUCCESS
);
938 * This function should be called when update_lease_ptr function fails.
939 * It does inform user about the condition, provides some hints how to
940 * resolve this and dies gracefully. This can happend in at least three
941 * cases (all are configuration mistakes):
942 * a) IPv4: user have duplicate fixed-address entries (the same
943 * address is defined twice). We may have found wrong lease.
944 * b) IPv6: user have overlapping pools (we tried to find
945 * a lease in a wrong pool)
946 * c) IPv6: user have duplicate fixed-address6 entires (the same
947 * address is defined twice). We may have found wrong lease.
949 * Comment: while it would be possible to recover from both cases
950 * by forcibly searching for leases in *all* following pools, that would
951 * only hide the real problem - a misconfiguration. Proper solution
952 * is to log the problem, die and let the user fix his config file.
955 update_lease_failed(struct lease
*lease
,
956 struct iasubopt
*lease6
,
957 dhcp_ddns_cb_t
*ddns_cb
,
958 dhcp_ddns_cb_t
*ddns_cb_set
,
959 const char * file
, int line
)
961 char lease_address
[MAX_ADDRESS_STRING_LEN
+ 64];
962 char reason
[128]; /* likely reason */
964 sprintf(reason
, "unknown");
965 sprintf(lease_address
, "unknown");
968 * let's pretend that everything is ok, so we can continue for
969 * information gathering purposes
972 if (ddns_cb
!= NULL
) {
973 strncpy(lease_address
, piaddr(ddns_cb
->address
),
974 MAX_ADDRESS_STRING_LEN
);
976 if (ddns_cb
->address
.len
== 4) {
977 sprintf(reason
, "duplicate IPv4 fixed-address entry");
978 } else if (ddns_cb
->address
.len
== 16) {
979 sprintf(reason
, "duplicate IPv6 fixed-address6 entry "
980 "or overlapping pools");
983 * Should not happen. We have non-IPv4, non-IPv6
984 * address. Something is very wrong here.
986 sprintf(reason
, "corrupted ddns_cb structure (address "
987 "length is %d)", ddns_cb
->address
.len
);
991 log_error("Failed to properly update internal lease structure with "
993 log_error("control block structures. Tried to update lease for"
994 "%s address, ddns_cb=%p.", lease_address
, ddns_cb
);
997 log_error("This condition can occur, if DHCP server configuration is "
999 log_error("In particular, please do check that your configuration:");
1000 log_error("a) does not have overlapping pools (especially containing");
1001 log_error(" %s address).", lease_address
);
1002 log_error("b) there are no duplicate fixed-address or fixed-address6");
1003 log_error("entries for the %s address.", lease_address
);
1004 log_error("%s", "");
1005 log_error("Possible reason for this failure: %s", reason
);
1007 log_fatal("%s(%d): Failed to update lease database with DDNS info for "
1008 "address %s. Lease database inconsistent. Unable to recover."
1009 " Terminating.", file
, line
, lease_address
);
1013 * utility function to update found lease. It does extra checks
1014 * that we are indeed updating the right lease. It may happen
1015 * that user have duplicate fixed-address entries, so we attempt
1016 * to update wrong lease. See also safe_lease6_update.
1020 safe_lease_update(struct lease
*lease
,
1021 dhcp_ddns_cb_t
*oldcb
,
1022 dhcp_ddns_cb_t
*newcb
,
1023 const char *file
, int line
)
1025 if (lease
== NULL
) {
1026 /* should never get here */
1027 log_fatal("Impossible condition at %s:%d (called from %s:%d).",
1031 if ( (lease
->ddns_cb
== NULL
) && (newcb
== NULL
) ) {
1033 * Trying to clean up pointer that is already null. We
1034 * are most likely trying to update wrong lease here.
1038 * Previously this error message popped out during
1039 * DNS update for fixed leases. As we no longer
1040 * try to update the lease for a fixed (static) lease
1041 * this should not be a problem.
1043 log_error("%s(%d): Invalid lease update. Tried to "
1044 "clear already NULL DDNS control block "
1045 "pointer for lease %s.",
1046 file
, line
, piaddr(lease
->ip_addr
) );
1048 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1049 update_lease_failed(lease
, NULL
, oldcb
, newcb
, file
, line
);
1052 * May not reach this: update_lease_failed calls
1058 if ( (lease
->ddns_cb
!= NULL
) && (lease
->ddns_cb
!= oldcb
) ) {
1060 * There is existing cb structure, but it differs from
1061 * what we expected to see there. Most likely we are
1062 * trying to update wrong lease.
1064 log_error("%s(%d): Failed to update internal lease "
1065 "structure with DDNS control block. Existing"
1066 " ddns_cb structure does not match "
1067 "expectations.IPv4=%s, old ddns_cb=%p, tried"
1068 "to update to new ddns_cb=%p", file
, line
,
1069 piaddr(lease
->ip_addr
), oldcb
, newcb
);
1071 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1072 update_lease_failed(lease
, NULL
, oldcb
, newcb
, file
, line
);
1075 * May not reach this: update_lease_failed calls
1081 /* additional IPv4 specific checks may be added here */
1083 /* update the lease */
1084 lease
->ddns_cb
= newcb
;
1088 safe_lease6_update(struct iasubopt
*lease6
,
1089 dhcp_ddns_cb_t
*oldcb
,
1090 dhcp_ddns_cb_t
*newcb
,
1091 const char *file
, int line
)
1093 char addrbuf
[MAX_ADDRESS_STRING_LEN
];
1095 if (lease6
== NULL
) {
1096 /* should never get here */
1097 log_fatal("Impossible condition at %s:%d (called from %s:%d).",
1101 if ( (lease6
->ddns_cb
== NULL
) && (newcb
== NULL
) ) {
1102 inet_ntop(AF_INET6
, &lease6
->addr
, addrbuf
,
1103 MAX_ADDRESS_STRING_LEN
);
1105 * Trying to clean up pointer that is already null. We
1106 * are most likely trying to update wrong lease here.
1108 log_error("%s(%d): Failed to update internal lease "
1109 "structure. Tried to clear already NULL "
1110 "DDNS control block pointer for lease %s.",
1111 file
, line
, addrbuf
);
1113 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1114 update_lease_failed(NULL
, lease6
, oldcb
, newcb
, file
, line
);
1118 * May not reach this: update_lease_failed calls
1124 if ( (lease6
->ddns_cb
!= NULL
) && (lease6
->ddns_cb
!= oldcb
) ) {
1126 * there is existing cb structure, but it differs from
1127 * what we expected to see there. Most likely we are
1128 * trying to update wrong lease.
1130 inet_ntop(AF_INET6
, &lease6
->addr
, addrbuf
,
1131 MAX_ADDRESS_STRING_LEN
);
1133 log_error("%s(%d): Failed to update internal lease "
1134 "structure with DDNS control block. Existing"
1135 " ddns_cb structure does not match "
1136 "expectations.IPv6=%s, old ddns_cb=%p, tried"
1137 "to update to new ddns_cb=%p", file
, line
,
1138 addrbuf
, oldcb
, newcb
);
1140 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1141 update_lease_failed(NULL
, lease6
, oldcb
, newcb
, file
, line
);
1144 * May not reach this: update_lease_failed calls
1149 /* additional IPv6 specific checks may be added here */
1151 /* update the lease */
1152 lease6
->ddns_cb
= newcb
;
1156 * Utility function to update the pointer to the DDNS control block
1158 * SUCCESS - able to update the pointer
1159 * FAILURE - lease didn't exist or sanity checks failed
1160 * lease and lease6 may be empty in which case we attempt to find
1161 * the lease from the ddns_cb information.
1162 * ddns_cb is the control block to use if a lookup is necessary
1163 * ddns_cb_set is the pointer to insert into the lease and may be NULL
1164 * The last two arguments may look odd as they will be the same much of the
1165 * time, but I need an argument to tell me if I'm setting or clearing in
1166 * addition to the address information from the cb to look up the lease.
1167 * using the same value twice allows me more flexibility.
1171 ddns_update_lease_ptr(struct lease
*lease
,
1172 struct iasubopt
*lease6
,
1173 dhcp_ddns_cb_t
*ddns_cb
,
1174 dhcp_ddns_cb_t
*ddns_cb_set
,
1175 const char * file
, int line
)
1177 char ddns_address
[MAX_ADDRESS_STRING_LEN
];
1178 sprintf(ddns_address
, "unknown");
1179 if (ddns_cb
== NULL
) {
1180 log_info("%s(%d): No control block for lease update",
1182 return (ISC_R_FAILURE
);
1185 strcpy(ddns_address
, piaddr(ddns_cb
->address
));
1187 #if defined (DEBUG_DNS_UPDATES)
1188 log_info("%s(%d): Updating lease_ptr for ddns_cp=%p (addr=%s)",
1189 file
, line
, ddns_cb
, ddns_address
);
1193 * If the lease was static (for a fixed address)
1194 * we don't need to do any work.
1196 if (ddns_cb
->flags
& DDNS_STATIC_LEASE
) {
1197 #if defined (DEBUG_DNS_UPDATES)
1198 log_info("lease is static, returning");
1200 return (ISC_R_SUCCESS
);
1204 * If we are processing an expired or released v6 lease
1205 * we don't actually have a lease to update
1207 if ((ddns_cb
->address
.len
== 16) &&
1208 ((ddns_cb
->flags
& DDNS_ACTIVE_LEASE
) == 0)) {
1209 return (ISC_R_SUCCESS
);
1212 if (lease
!= NULL
) {
1213 safe_lease_update(lease
, ddns_cb
, ddns_cb_set
,
1215 } else if (lease6
!= NULL
) {
1216 safe_lease6_update(lease6
, ddns_cb
, ddns_cb_set
,
1218 } else if (ddns_cb
->address
.len
== 4) {
1219 struct lease
*find_lease
= NULL
;
1220 if (find_lease_by_ip_addr(&find_lease
,
1221 ddns_cb
->address
, MDL
) != 0) {
1222 #if defined (DEBUG_DNS_UPDATES)
1223 log_info("%s(%d): find_lease_by_ip_addr(%s) successful:"
1224 "lease=%p", file
, line
, ddns_address
,
1228 safe_lease_update(find_lease
, ddns_cb
,
1229 ddns_cb_set
, file
, line
);
1230 lease_dereference(&find_lease
, MDL
);
1233 log_error("%s(%d): ddns_update_lease_ptr failed. "
1234 "Lease for %s not found.",
1235 file
, line
, piaddr(ddns_cb
->address
));
1237 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1238 update_lease_failed(NULL
, NULL
, ddns_cb
, ddns_cb_set
,
1242 * may not reach this. update_lease_failed
1245 return(ISC_R_FAILURE
);
1248 } else if (ddns_cb
->address
.len
== 16) {
1249 struct iasubopt
*find_lease6
= NULL
;
1250 struct ipv6_pool
*pool
= NULL
;
1251 struct in6_addr addr
;
1252 char addrbuf
[MAX_ADDRESS_STRING_LEN
];
1254 memcpy(&addr
, &ddns_cb
->address
.iabuf
, 16);
1255 if ((find_ipv6_pool(&pool
, D6O_IA_TA
, &addr
) !=
1257 (find_ipv6_pool(&pool
, D6O_IA_NA
, &addr
) !=
1259 inet_ntop(AF_INET6
, &addr
, addrbuf
,
1260 MAX_ADDRESS_STRING_LEN
);
1261 log_error("%s(%d): Pool for lease %s not found.",
1262 file
, line
, addrbuf
);
1263 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1264 update_lease_failed(NULL
, NULL
, ddns_cb
, ddns_cb_set
,
1268 * never reached. update_lease_failed
1271 return(ISC_R_FAILURE
);
1274 if (iasubopt_hash_lookup(&find_lease6
, pool
->leases
,
1276 find_lease6
->ddns_cb
= ddns_cb_set
;
1277 iasubopt_dereference(&find_lease6
, MDL
);
1279 inet_ntop(AF_INET6
, &addr
, addrbuf
,
1280 MAX_ADDRESS_STRING_LEN
);
1281 log_error("%s(%d): Lease %s not found within pool.",
1282 file
, line
, addrbuf
);
1283 #if defined (DNS_UPDATES_MEMORY_CHECKS)
1284 update_lease_failed(NULL
, NULL
, ddns_cb
, ddns_cb_set
,
1288 * not reached when update_lease_failed is called,
1289 * it calls log_fatal.
1291 ipv6_pool_dereference(&pool
, MDL
);
1292 return(ISC_R_FAILURE
);
1294 ipv6_pool_dereference(&pool
, MDL
);
1296 /* shouldn't get here */
1297 log_fatal("Impossible condition at %s:%d, called from %s:%d.",
1301 return(ISC_R_SUCCESS
);
1305 ddns_ptr_add(dhcp_ddns_cb_t
*ddns_cb
,
1306 isc_result_t eresult
)
1308 if (eresult
== ISC_R_SUCCESS
) {
1309 log_info("Added reverse map from %.*s to %.*s",
1310 (int)ddns_cb
->rev_name
.len
,
1311 (const char *)ddns_cb
->rev_name
.data
,
1312 (int)ddns_cb
->fwd_name
.len
,
1313 (const char *)ddns_cb
->fwd_name
.data
);
1315 ddns_update_lease_text(ddns_cb
, NULL
);
1317 log_error("Unable to add reverse map from %.*s to %.*s: %s",
1318 (int)ddns_cb
->rev_name
.len
,
1319 (const char *)ddns_cb
->rev_name
.data
,
1320 (int)ddns_cb
->fwd_name
.len
,
1321 (const char *)ddns_cb
->fwd_name
.data
,
1322 isc_result_totext (eresult
));
1325 ddns_update_lease_ptr(NULL
, NULL
, ddns_cb
, NULL
, MDL
);
1326 destroy_ddns_cb(ddns_cb
, MDL
);
1328 * A single DDNS operation may require several calls depending on
1329 * the current state as the prerequisites for the first message
1330 * may not succeed requiring a second operation and potentially
1331 * a ptr operation after that. The commit_leases operation is
1332 * invoked at the end of this set of operations in order to require
1333 * a single write for all of the changes. We call commit_leases
1334 * here rather than immediately after the call to update the lease
1335 * text in order to save any previously written data.
1342 * action routine when trying to remove a pointer
1343 * this will be called after the ddns queries have completed
1344 * if we succeeded in removing the pointer we go to the next step (if any)
1345 * if not we cleanup and leave.
1349 ddns_ptr_remove(dhcp_ddns_cb_t
*ddns_cb
,
1350 isc_result_t eresult
)
1352 isc_result_t result
= eresult
;
1356 log_info("Removed reverse map on %.*s",
1357 (int)ddns_cb
->rev_name
.len
,
1358 (const char *)ddns_cb
->rev_name
.data
);
1361 case DNS_R_NXDOMAIN
:
1362 /* No entry is the same as success.
1363 * Remove the information from the lease and
1364 * continue with any next step */
1365 ddns_update_lease_text(ddns_cb
, NULL
);
1367 /* trigger any add operation */
1368 result
= ISC_R_SUCCESS
;
1369 #if defined (DEBUG_DNS_UPDATES)
1370 log_info("DDNS: removed map or no reverse map to remove %.*s",
1371 (int)ddns_cb
->rev_name
.len
,
1372 (const char *)ddns_cb
->rev_name
.data
);
1377 log_error("Can't remove reverse map on %.*s: %s",
1378 (int)ddns_cb
->rev_name
.len
,
1379 (const char *)ddns_cb
->rev_name
.data
,
1380 isc_result_totext (eresult
));
1384 /* If we aren't suppossed to do the next step, set the result
1385 * flag so ddns_fwd_srv_connector won't do much
1387 if ((ddns_cb
->flags
& DDNS_EXECUTE_NEXT
) == 0)
1388 result
= ISC_R_FAILURE
;
1390 ddns_update_lease_ptr(NULL
, NULL
, ddns_cb
, NULL
, MDL
);
1391 ddns_fwd_srv_connector(NULL
, NULL
, NULL
, ddns_cb
->next_op
, result
);
1392 destroy_ddns_cb(ddns_cb
, MDL
);
1398 * If the first query succeeds, the updater can conclude that it
1399 * has added a new name whose only RRs are the A and DHCID RR records.
1400 * The A RR update is now complete (and a client updater is finished,
1401 * while a server might proceed to perform a PTR RR update).
1402 * -- "Interaction between DHCP and DNS"
1404 * If the second query succeeds, the updater can conclude that the current
1405 * client was the last client associated with the domain name, and that
1406 * the name now contains the updated A RR. The A RR update is now
1407 * complete (and a client updater is finished, while a server would
1408 * then proceed to perform a PTR RR update).
1409 * -- "Interaction between DHCP and DNS"
1411 * If the second query fails with NXRRSET, the updater must conclude
1412 * that the client's desired name is in use by another host. If
1413 * Dual Stack Mixed Mode (DSMM) is enabled and we proceed to a
1414 * third stage forward update attempt specific to DSMM rules. If not,
1415 * then the existing entries are left intact:
1417 * At this juncture, the updater can decide (based on some administrative
1418 * configuration outside of the scope of this document) whether to let
1419 * the existing owner of the name keep that name, and to (possibly)
1420 * perform some name disambiguation operation on behalf of the current
1421 * client, or to replace the RRs on the name with RRs that represent
1422 * the current client. If the configured policy allows replacement of
1423 * existing records, the updater submits a query that deletes the
1424 * existing A RR and the existing DHCID RR, adding A and DHCID RRs that
1425 * represent the IP address and client-identity of the new client.
1426 * -- "Interaction between DHCP and DNS"
1430 ddns_fwd_srv_add2(dhcp_ddns_cb_t
*ddns_cb
,
1431 isc_result_t eresult
)
1433 isc_result_t result
;
1434 const char *logstr
= NULL
;
1435 char ddns_address
[MAX_ADDRESS_STRING_LEN
];
1437 #if defined (DEBUG_DNS_UPDATES)
1438 log_info ("DDNS:ddns_fwd_srv_add2: %s eresult: %d",
1439 dump_ddns_cb(ddns_cb
), eresult
);
1442 /* Construct a printable form of the address for logging */
1443 strcpy(ddns_address
, piaddr(ddns_cb
->address
));
1447 log_info("Added new forward map from %.*s to %s",
1448 (int)ddns_cb
->fwd_name
.len
,
1449 (const char *)ddns_cb
->fwd_name
.data
,
1452 ddns_update_lease_text(ddns_cb
, NULL
);
1454 if ((ddns_cb
->flags
& DDNS_UPDATE_PTR
) != 0) {
1455 /* if we have zone information get rid of it */
1456 if (ddns_cb
->zone
!= NULL
) {
1457 ddns_cb_forget_zone(ddns_cb
);
1460 ddns_cb
->state
= DDNS_STATE_ADD_PTR
;
1461 ddns_cb
->cur_func
= ddns_ptr_add
;
1463 result
= ddns_modify_ptr(ddns_cb
, MDL
);
1464 if (result
== ISC_R_SUCCESS
) {
1471 case DNS_R_YXDOMAIN
:
1472 logstr
= "DHCID mismatch, belongs to another client.";
1475 case DNS_R_NXDOMAIN
:
1477 /* If DSMM is on we need to try forward add3 */
1478 if (ddns_cb
->flags
& DDNS_DUAL_STACK_MIXED_MODE
) {
1479 ddns_cb
->state
= DDNS_STATE_DSMM_FW_ADD3
;
1480 ddns_cb
->cur_func
= ddns_fwd_srv_add3
;
1482 result
= ddns_modify_fwd(ddns_cb
, MDL
);
1483 if (result
== ISC_R_SUCCESS
) {
1490 logstr
= "Has an address record but no DHCID, not mine.";
1494 logstr
= isc_result_totext(eresult
);
1498 if (logstr
!= NULL
) {
1499 log_error("Forward map from %.*s to %s FAILED: %s",
1500 (int)ddns_cb
->fwd_name
.len
,
1501 (const char *)ddns_cb
->fwd_name
.data
,
1502 ddns_address
, logstr
);
1505 ddns_update_lease_ptr(NULL
, NULL
, ddns_cb
, NULL
, MDL
);
1506 destroy_ddns_cb(ddns_cb
, MDL
);
1508 * A single DDNS operation may require several calls depending on
1509 * the current state as the prerequisites for the first message
1510 * may not succeed requiring a second operation and potentially
1511 * a ptr operation after that. The commit_leases operation is
1512 * invoked at the end of this set of operations in order to require
1513 * a single write for all of the changes. We call commit_leases
1514 * here rather than immediately after the call to update the lease
1515 * text in order to save any previously written data.
1522 ddns_fwd_srv_add1(dhcp_ddns_cb_t
*ddns_cb
,
1523 isc_result_t eresult
)
1525 isc_result_t result
;
1526 char ddns_address
[MAX_ADDRESS_STRING_LEN
];
1528 #if defined (DEBUG_DNS_UPDATES)
1529 log_info ("DDNS: ddns_fwd_srv_add1: %s eresult: %d",
1530 dump_ddns_cb(ddns_cb
), eresult
);
1533 /* Construct a printable form of the address for logging */
1534 strcpy(ddns_address
, piaddr(ddns_cb
->address
));
1538 log_info ("Added new forward map from %.*s to %s",
1539 (int)ddns_cb
->fwd_name
.len
,
1540 (const char *)ddns_cb
->fwd_name
.data
,
1543 ddns_update_lease_text(ddns_cb
, NULL
);
1545 if ((ddns_cb
->flags
& DDNS_UPDATE_PTR
) != 0) {
1546 /* if we have zone information get rid of it */
1547 if (ddns_cb
->zone
!= NULL
) {
1548 ddns_cb_forget_zone(ddns_cb
);
1551 ddns_cb
->state
= DDNS_STATE_ADD_PTR
;
1552 ddns_cb
->cur_func
= ddns_ptr_add
;
1554 result
= ddns_modify_ptr(ddns_cb
, MDL
);
1555 if (result
== ISC_R_SUCCESS
) {
1561 case DNS_R_YXDOMAIN
:
1562 /* we can reuse the zone information */
1563 ddns_cb
->state
= DDNS_STATE_ADD_FW_YXDHCID
;
1564 ddns_cb
->cur_func
= ddns_fwd_srv_add2
;
1566 result
= ddns_modify_fwd(ddns_cb
, MDL
);
1567 if (result
== ISC_R_SUCCESS
) {
1572 log_error ("Unable to add forward map from %.*s to %s: %s",
1573 (int)ddns_cb
->fwd_name
.len
,
1574 (const char *)ddns_cb
->fwd_name
.data
,
1576 isc_result_totext (eresult
));
1580 ddns_update_lease_ptr(NULL
, NULL
, ddns_cb
, NULL
, MDL
);
1581 destroy_ddns_cb(ddns_cb
, MDL
);
1583 * A single DDNS operation may require several calls depending on
1584 * the current state as the prerequisites for the first message
1585 * may not succeed requiring a second operation and potentially
1586 * a ptr operation after that. The commit_leases operation is
1587 * invoked at the end of this set of operations in order to require
1588 * a single write for all of the changes. We call commit_leases
1589 * here rather than immediately after the call to update the lease
1590 * text in order to save any previously written data.
1597 * This action routine is invoked after the DSMM third add stage is
1598 * attempted. If we succeeded we attempt to update the reverse DNS,
1599 * if not we cleanup and leave.
1602 ddns_fwd_srv_add3(dhcp_ddns_cb_t
*ddns_cb
,
1603 isc_result_t eresult
)
1605 isc_result_t result
;
1606 const char *logstr
= NULL
;
1607 char ddns_address
[MAX_ADDRESS_STRING_LEN
+1];
1609 #if defined (DEBUG_DNS_UPDATES)
1610 log_info ("DDNS: ddns_fwd_srv_add3: %s eresult: %d",
1611 dump_ddns_cb(ddns_cb
), eresult
);
1614 /* Construct a printable form of the address for logging */
1615 memset(ddns_address
, 0x0, sizeof(ddns_address
));
1616 strncpy(ddns_address
, piaddr(ddns_cb
->address
),
1617 sizeof(ddns_address
) - 1);
1621 log_info("Added new forward map from %.*s to %s",
1622 (int)ddns_cb
->fwd_name
.len
,
1623 (const char *)ddns_cb
->fwd_name
.data
,
1626 ddns_update_lease_text(ddns_cb
, NULL
);
1628 if ((ddns_cb
->flags
& DDNS_UPDATE_PTR
) != 0) {
1629 /* if we have zone information get rid of it */
1630 if (ddns_cb
->zone
!= NULL
) {
1631 ddns_cb_forget_zone(ddns_cb
);
1634 ddns_cb
->state
= DDNS_STATE_ADD_PTR
;
1635 ddns_cb
->cur_func
= ddns_ptr_add
;
1637 result
= ddns_modify_ptr(ddns_cb
, MDL
);
1638 if (result
== ISC_R_SUCCESS
) {
1645 logstr
= "an entry that is either static or "
1646 "owned by another client exists.";
1650 logstr
= "static entry of the other protocol type exists.";
1654 logstr
= isc_result_totext(eresult
);
1658 if (logstr
!= NULL
) {
1659 log_error("Forward map from %.*s to %s FAILED: %s",
1660 (int)ddns_cb
->fwd_name
.len
,
1661 (const char *)ddns_cb
->fwd_name
.data
,
1662 ddns_address
, logstr
);
1665 ddns_update_lease_ptr(NULL
, NULL
, ddns_cb
, NULL
, MDL
);
1666 destroy_ddns_cb(ddns_cb
, MDL
);
1668 * A single DDNS operation may require several calls depending on
1669 * the current state as the prerequisites for the first message
1670 * may not succeed requiring a second operation and potentially
1671 * a ptr operation after that. The commit_leases operation is
1672 * invoked at the end of this set of operations in order to require
1673 * a single write for all of the changes. We call commit_leases
1674 * here rather than immediately after the call to update the lease
1675 * text in order to save any previously written data.
1682 ddns_fwd_srv_connector(struct lease
*lease
,
1683 struct iasubopt
*lease6
,
1684 struct binding_scope
**inscope
,
1685 dhcp_ddns_cb_t
*ddns_cb
,
1686 isc_result_t eresult
)
1688 isc_result_t result
= ISC_R_FAILURE
;
1690 #if defined (DEBUG_DNS_UPDATES)
1691 log_info ("DDNS: ddns_fwd_srv_connector: %s eresult: %d",
1692 dump_ddns_cb(ddns_cb
), eresult
);
1695 if (ddns_cb
== NULL
) {
1700 if (eresult
== ISC_R_SUCCESS
) {
1702 * If we have updates dispatch as appropriate,
1703 * if not do FQDN binding if desired.
1706 if (ddns_cb
->flags
& DDNS_UPDATE_ADDR
) {
1707 ddns_cb
->state
= DDNS_STATE_ADD_FW_NXDOMAIN
;
1708 ddns_cb
->cur_func
= ddns_fwd_srv_add1
;
1709 result
= ddns_modify_fwd(ddns_cb
, MDL
);
1710 } else if ((ddns_cb
->flags
& DDNS_UPDATE_PTR
) &&
1711 (ddns_cb
->rev_name
.len
!= 0)) {
1712 ddns_cb
->state
= DDNS_STATE_ADD_PTR
;
1713 ddns_cb
->cur_func
= ddns_ptr_add
;
1714 result
= ddns_modify_ptr(ddns_cb
, MDL
);
1716 ddns_update_lease_text(ddns_cb
, inscope
);
1721 if (result
== ISC_R_SUCCESS
) {
1722 ddns_update_lease_ptr(lease
, lease6
, ddns_cb
, ddns_cb
, MDL
);
1724 destroy_ddns_cb(ddns_cb
, MDL
);
1731 * If the first query fails, the updater MUST NOT delete the DNS name. It
1732 * may be that the host whose lease on the server has expired has moved
1733 * to another network and obtained a lease from a different server,
1734 * which has caused the client's A RR to be replaced. It may also be
1735 * that some other client has been configured with a name that matches
1736 * the name of the DHCP client, and the policy was that the last client
1737 * to specify the name would get the name. In this case, the DHCID RR
1738 * will no longer match the updater's notion of the client-identity of
1739 * the host pointed to by the DNS name.
1740 * -- "Interaction between DHCP and DNS"
1744 ddns_fwd_srv_rem2(dhcp_ddns_cb_t
*ddns_cb
,
1745 isc_result_t eresult
)
1747 #if defined (DEBUG_DNS_UPDATES)
1748 log_info ("DDNS: ddns_fwd_srv_rem2: %s eresult: %d",
1749 dump_ddns_cb(ddns_cb
), eresult
);
1753 * To get here we have already managed to remove the A/AAAA
1754 * record and are trying to remove the DHCID/TXT record as well.
1755 * On success (removed DHCID/TXT) or YXRRSET (DHCID/TXT still in
1756 * use by something else) we clean up the lease.
1757 * On some other error we don't clean up the lease and hope that
1758 * if we try this again it will work. An example would be if we
1759 * got a timeout as the DNS server halted between the first and
1760 * second steps. The DNS server would still have the DHCID/TXT
1761 * and we would like to remove that in the future.
1763 * On success set the EXECUTE_NEXT flag which triggers any
1764 * add that is next in the chain.
1766 if ((eresult
== ISC_R_SUCCESS
) ||
1767 (eresult
== DNS_R_YXRRSET
)) {
1768 ddns_update_lease_text(ddns_cb
, NULL
);
1769 eresult
= ISC_R_SUCCESS
;
1772 /* Do the next operation */
1773 if ((ddns_cb
->flags
& DDNS_UPDATE_PTR
) != 0) {
1774 /* if we have zone information get rid of it */
1775 if (ddns_cb
->zone
!= NULL
) {
1776 ddns_cb_forget_zone(ddns_cb
);
1779 ddns_cb
->state
= DDNS_STATE_REM_PTR
;
1780 ddns_cb
->cur_func
= ddns_ptr_remove
;
1781 if (eresult
== ISC_R_SUCCESS
)
1782 ddns_cb
->flags
|= DDNS_EXECUTE_NEXT
;
1784 eresult
= ddns_modify_ptr(ddns_cb
, MDL
);
1785 if (eresult
== ISC_R_SUCCESS
) {
1790 ddns_update_lease_ptr(NULL
, NULL
, ddns_cb
, NULL
, MDL
);
1791 ddns_fwd_srv_connector(NULL
, NULL
, NULL
, ddns_cb
->next_op
, eresult
);
1792 destroy_ddns_cb(ddns_cb
, MDL
);
1798 * First action routine when trying to remove a fwd
1799 * this will be called after the ddns queries have completed
1800 * if we succeeded in removing the fwd we go to the next step (if any)
1801 * if not we cleanup and leave.
1805 ddns_fwd_srv_rem1(dhcp_ddns_cb_t
*ddns_cb
,
1806 isc_result_t eresult
)
1808 isc_result_t result
= eresult
;
1809 char ddns_address
[MAX_ADDRESS_STRING_LEN
];
1811 #if defined (DEBUG_DNS_UPDATES)
1812 log_info ("DDNS: ddns_fwd_srv_rem1: %s eresult: %d",
1813 dump_ddns_cb(ddns_cb
), eresult
);
1818 /* Construct a printable form of the address for logging */
1819 strcpy(ddns_address
, piaddr(ddns_cb
->address
));
1820 log_info("Removed forward map from %.*s to %s",
1821 (int)ddns_cb
->fwd_name
.len
,
1822 (const char*)ddns_cb
->fwd_name
.data
,
1825 /* Do the second step of the FWD removal */
1826 ddns_cb
->state
= DDNS_STATE_REM_FW_NXRR
;
1827 ddns_cb
->cur_func
= ddns_fwd_srv_rem2
;
1828 result
= ddns_modify_fwd(ddns_cb
, MDL
);
1829 if (result
== ISC_R_SUCCESS
) {
1835 case DNS_R_NXDOMAIN
:
1836 /* A result of not found means rem1 did not find a guard of
1837 * our * type. From this we assume either there are no address
1838 * record(s) of our type to delete or they are unguarded and
1839 * therefore presumed to be static. Either way, we're done
1840 * unless we're in DSMM and ddns-other-guard-is-dynamic is on.
1841 * In which case we need to see if a guard of the other type
1842 * exists, which permits us to delete any address records of
1844 #define DSMM_OGD (DDNS_DUAL_STACK_MIXED_MODE | \
1845 DDNS_OTHER_GUARD_IS_DYNAMIC)
1846 if ((ddns_cb
->flags
& DSMM_OGD
) == DSMM_OGD
) {
1847 ddns_cb
->state
= DDNS_STATE_REM_FW_DSMM_OTHER
;
1848 ddns_cb
->cur_func
= ddns_fwd_srv_rem2
;
1849 result
= ddns_modify_fwd(ddns_cb
, MDL
);
1850 if (result
== ISC_R_SUCCESS
) {
1856 ddns_update_lease_text(ddns_cb
, NULL
);
1858 #if defined (DEBUG_DNS_UPDATES)
1859 log_info("DDNS: no forward map to remove. %p", ddns_cb
);
1861 /* Trigger the add operation */
1862 eresult
= ISC_R_SUCCESS
;
1867 /* We do the remove operation in most cases
1868 * but we don't want to continue with adding a forward
1869 * record if the forward removal had issues so we
1870 * check the eresult and set the EXECUTE_NEXT flag on
1874 /* Do the remove operation */
1875 if ((ddns_cb
->flags
& DDNS_UPDATE_PTR
) != 0) {
1876 /* if we have zone information get rid of it */
1877 if (ddns_cb
->zone
!= NULL
) {
1878 ddns_cb_forget_zone(ddns_cb
);
1881 ddns_cb
->state
= DDNS_STATE_REM_PTR
;
1882 ddns_cb
->cur_func
= ddns_ptr_remove
;
1883 if (eresult
== ISC_R_SUCCESS
)
1884 ddns_cb
->flags
|= DDNS_EXECUTE_NEXT
;
1886 result
= ddns_modify_ptr(ddns_cb
, MDL
);
1887 if (result
== ISC_R_SUCCESS
) {
1894 ddns_update_lease_ptr(NULL
, NULL
, ddns_cb
, NULL
, MDL
);
1895 ddns_fwd_srv_connector(NULL
, NULL
, NULL
, ddns_cb
->next_op
, eresult
);
1896 destroy_ddns_cb(ddns_cb
, MDL
);
1900 * Remove relevant entries from DNS.
1902 * \li lease - lease to start with if this is for v4
1904 * \li lease6 - lease to start with if this is for v6
1906 * \li add_ddns_cb - control block for additional DDNS work. This
1907 * is used when the code is going to add a DDNS entry after removing
1908 * the current entry.
1910 * \li active - indication about the status of the lease. It is
1911 * ISC_TRUE if the lease is still active, and FALSE if the lease
1912 * is inactive. This is used to indicate if the lease is inactive or going
1913 * to inactive so we can avoid trying to update the lease with cb pointers
1914 * and text information if it isn't useful.
1917 * \li #ISC_R_FAILURE - badness occurred and we weren't able to do what was wanted
1918 * \li #ISC_R_SUCCESS - we were able to do stuff but it's in progress
1920 * in both cases any additional block has been passed on to it's handler
1924 ddns_removals(struct lease
*lease
,
1925 struct iasubopt
*lease6
,
1926 dhcp_ddns_cb_t
*add_ddns_cb
,
1927 isc_boolean_t active
)
1929 isc_result_t rcode
, execute_add
= ISC_R_FAILURE
;
1930 struct binding_scope
**scope
= NULL
;
1931 isc_result_t result
= ISC_R_FAILURE
;
1932 dhcp_ddns_cb_t
*ddns_cb
= NULL
;
1933 struct data_string leaseid
;
1935 #if defined (DEBUG_DNS_UPDATES)
1936 log_info ("DDNS: ddns_removals: %s",
1937 dump_ddns_cb(add_ddns_cb
));
1941 * See if we need to cancel an outstanding request. Mostly this is
1942 * used to handle the case where this routine is called twice for
1943 * the same release or abandon event.
1945 * When called from the dns code as part of an update request
1946 * (add_ddns_cb != NULL) any outstanding requests will have already
1949 * If the new request is just a removal and we have an outstanding
1950 * request we have several options:
1952 * - we are doing an update or we are doing a removal and the active
1953 * flag has changed from TRUE to FALSE. In these cases we need to
1954 * cancel the old request and start the new one.
1956 * - other wise we are doing a removal with the active flag unchanged.
1957 * In this case we can let the current removal continue and do not need
1958 * to start a new one. If the old request included an update to be
1959 * done after the removal we need to kill the update part of the
1963 if (add_ddns_cb
== NULL
) {
1964 if ((lease
!= NULL
) && (lease
->ddns_cb
!= NULL
)) {
1965 ddns_cb
= lease
->ddns_cb
;
1968 * Is the old request an update or did the
1969 * the active flag change?
1971 if (((ddns_cb
->state
== DDNS_STATE_ADD_PTR
) ||
1972 (ddns_cb
->state
== DDNS_STATE_ADD_FW_NXDOMAIN
) ||
1973 (ddns_cb
->state
== DDNS_STATE_ADD_FW_YXDHCID
)) ||
1974 ((active
== ISC_FALSE
) &&
1975 ((ddns_cb
->flags
& DDNS_ACTIVE_LEASE
) != 0))) {
1976 /* Cancel the current request */
1977 ddns_cancel(lease
->ddns_cb
, MDL
);
1978 lease
->ddns_cb
= NULL
;
1980 /* Remvoval, check and remove updates */
1981 if (ddns_cb
->next_op
!= NULL
) {
1982 destroy_ddns_cb(ddns_cb
->next_op
, MDL
);
1983 ddns_cb
->next_op
= NULL
;
1985 #if defined (DEBUG_DNS_UPDATES)
1986 log_info("DDNS %s(%d): removal already in "
1987 "progress new ddns_cb=%p",
1990 return (ISC_R_SUCCESS
);
1992 } else if ((lease6
!= NULL
) && (lease6
->ddns_cb
!= NULL
)) {
1993 ddns_cb
= lease6
->ddns_cb
;
1996 * Is the old request an update or did the
1997 * the active flag change?
1999 if (((ddns_cb
->state
== DDNS_STATE_ADD_PTR
) ||
2000 (ddns_cb
->state
== DDNS_STATE_ADD_FW_NXDOMAIN
) ||
2001 (ddns_cb
->state
== DDNS_STATE_ADD_FW_YXDHCID
)) ||
2002 ((active
== ISC_FALSE
) &&
2003 ((ddns_cb
->flags
& DDNS_ACTIVE_LEASE
) != 0))) {
2004 /* Cancel the current request */
2005 ddns_cancel(lease6
->ddns_cb
, MDL
);
2006 lease6
->ddns_cb
= NULL
;
2008 /* Remvoval, check and remove updates */
2009 if (ddns_cb
->next_op
!= NULL
) {
2010 destroy_ddns_cb(ddns_cb
->next_op
, MDL
);
2011 ddns_cb
->next_op
= NULL
;
2013 #if defined (DEBUG_DNS_UPDATES)
2014 log_info("DDNS %s(%d): removal already in "
2015 "progress new ddns_cb=%p",
2018 return (ISC_R_SUCCESS
);
2024 /* allocate our control block */
2025 ddns_cb
= ddns_cb_alloc(MDL
);
2026 if (ddns_cb
== NULL
) {
2030 /* Set the conflict detection flags based on global configuration */
2031 copy_conflict_flags(&ddns_cb
->flags
, ddns_conflict_mask
);
2034 * For v4 we flag static leases so we don't try
2035 * and manipulate the lease later. For v6 we don't
2036 * get static leases and don't need to flag them.
2038 if (lease
!= NULL
) {
2039 scope
= &(lease
->scope
);
2040 ddns_cb
->address
= lease
->ip_addr
;
2041 if (lease
->flags
& STATIC_LEASE
)
2042 ddns_cb
->flags
|= DDNS_STATIC_LEASE
;
2043 } else if (lease6
!= NULL
) {
2044 scope
= &(lease6
->scope
);
2045 memcpy(&ddns_cb
->address
.iabuf
, lease6
->addr
.s6_addr
, 16);
2046 ddns_cb
->address
.len
= 16;
2051 * Set the flag bit if the lease is active, that is it isn't
2052 * expired or released. This is used to determine if we need
2053 * to update the scope information for both v4 and v6 and
2054 * the lease information for v6 when the response
2055 * from the DNS code is processed.
2057 if (active
== ISC_TRUE
) {
2058 ddns_cb
->flags
|= DDNS_ACTIVE_LEASE
;
2061 /* No scope implies that DDNS has not been performed for this lease. */
2065 if ((ddns_update_style
!= DDNS_UPDATE_STYLE_STANDARD
) &&
2066 (ddns_update_style
!= DDNS_UPDATE_STYLE_INTERIM
))
2069 /* Assume that we are removing both records */
2070 ddns_cb
->flags
|= DDNS_UPDATE_ADDR
| DDNS_UPDATE_PTR
;
2072 /* and that we want to do the add call */
2073 execute_add
= ISC_R_SUCCESS
;
2076 * Look up stored names.
2080 * Find the fwd name and copy it to the control block. If we don't
2081 * have it we can't delete the fwd record but we can still try to
2082 * remove the ptr record and cleanup the lease information if the
2083 * client did the fwd update.
2085 if (!find_bound_string(&ddns_cb
->fwd_name
, *scope
, "ddns-fwd-name")) {
2086 /* don't try and delete the A, or do the add */
2087 ddns_cb
->flags
&= ~DDNS_UPDATE_ADDR
;
2088 execute_add
= ISC_R_FAILURE
;
2090 /* Check if client did update */
2091 if (find_bound_string(&ddns_cb
->fwd_name
, *scope
,
2092 "ddns-client-fqdn")) {
2093 ddns_cb
->flags
|= DDNS_CLIENT_DID_UPDATE
;
2098 * Find the txt or dhcid tag and copy it to the control block. If we
2099 * don't have one this isn't an interim or standard record so we can't
2100 * delete the A record using this mechanism but we can delete the ptr
2101 * record. In this case we will attempt to do any requested next step.
2103 memset(&leaseid
, 0, sizeof(leaseid
));
2104 if (find_bound_string (&leaseid
, *scope
, ddns_standard_tag
)) {
2105 /* We have a standard tag */
2106 ddns_cb
->lease_tag
= ddns_standard_tag
;
2107 ddns_cb
->dhcid_class
= dns_rdatatype_dhcid
;
2108 ddns_cb
->other_dhcid_class
= dns_rdatatype_txt
;
2109 data_string_copy(&ddns_cb
->dhcid
, &leaseid
, MDL
);
2110 data_string_forget(&leaseid
, MDL
);
2111 } else if (find_bound_string (&leaseid
, *scope
, ddns_interim_tag
)) {
2112 /* we have an interim tag */
2113 ddns_cb
->lease_tag
= ddns_interim_tag
;
2114 ddns_cb
->dhcid_class
= dns_rdatatype_txt
;
2115 ddns_cb
->other_dhcid_class
= dns_rdatatype_dhcid
;
2116 if (dhcid_fromlease(&ddns_cb
->dhcid
, &leaseid
) !=
2118 /* We couldn't convert the dhcid from the lease
2119 * version to the dns version. We can't delete
2120 * the A record but can continue to the ptr
2122 ddns_cb
->flags
&= ~DDNS_UPDATE_ADDR
;
2124 data_string_forget(&leaseid
, MDL
);
2126 ddns_cb
->flags
&= ~DDNS_UPDATE_ADDR
;
2130 * Find the rev name and copy it to the control block. If we don't
2131 * have it we can't get rid of it but we can try to remove the fwd
2132 * pointer if desired.
2134 if (!find_bound_string(&ddns_cb
->rev_name
, *scope
, "ddns-rev-name")) {
2135 ddns_cb
->flags
&= ~DDNS_UPDATE_PTR
;
2140 * If we have a second control block for doing an add
2141 * after the remove finished attach it to our control block.
2143 ddns_cb
->next_op
= add_ddns_cb
;
2146 * Now that we've collected the information we can try to process it.
2147 * If necessary we call an appropriate routine to send a message and
2148 * provide it with an action routine to run on the control block given
2149 * the results of the message. We have three entry points from here,
2150 * one for removing the A record, the next for removing the PTR and
2151 * the third for doing any requested add.
2153 if ((ddns_cb
->flags
& DDNS_UPDATE_ADDR
) != 0) {
2154 if (ddns_cb
->fwd_name
.len
!= 0) {
2155 ddns_cb
->state
= DDNS_STATE_REM_FW_YXDHCID
;
2156 ddns_cb
->cur_func
= ddns_fwd_srv_rem1
;
2158 rcode
= ddns_modify_fwd(ddns_cb
, MDL
);
2159 if (rcode
== ISC_R_SUCCESS
) {
2160 ddns_update_lease_ptr(lease
, lease6
, ddns_cb
,
2162 return (ISC_R_SUCCESS
);
2166 * We weren't able to process the request tag the
2167 * add so we won't execute it.
2169 execute_add
= ISC_R_FAILURE
;
2173 /*remove info from scope */
2174 unset(*scope
, "ddns-fwd-name");
2175 unset(*scope
, ddns_cb
->lease_tag
);
2179 if ((ddns_cb
->flags
& DDNS_UPDATE_PTR
) != 0) {
2180 ddns_cb
->state
= DDNS_STATE_REM_PTR
;
2181 ddns_cb
->cur_func
= ddns_ptr_remove
;
2182 ddns_cb
->flags
|= DDNS_EXECUTE_NEXT
;
2185 * if execute add isn't success remove the control block so
2186 * it won't be processed when the remove completes. We
2187 * also arrange to clean it up and get rid of it.
2189 if (execute_add
!= ISC_R_SUCCESS
) {
2190 ddns_cb
->next_op
= NULL
;
2191 ddns_fwd_srv_connector(lease
, lease6
, scope
,
2192 add_ddns_cb
, execute_add
);
2196 result
= ISC_R_SUCCESS
;
2199 rcode
= ddns_modify_ptr(ddns_cb
, MDL
);
2200 if (rcode
== ISC_R_SUCCESS
) {
2201 ddns_update_lease_ptr(lease
, lease6
, ddns_cb
, ddns_cb
,
2206 /* We weren't able to process the request tag the
2207 * add so we won't execute it */
2208 execute_add
= ISC_R_FAILURE
;
2214 * We've gotten here because we didn't need to send a message or
2215 * we failed when trying to do so. We send the additional cb
2216 * off to handle sending and/or cleanup and cleanup anything
2217 * we allocated here.
2219 ddns_fwd_srv_connector(lease
, lease6
, scope
, add_ddns_cb
, execute_add
);
2220 if (ddns_cb
!= NULL
)
2221 destroy_ddns_cb(ddns_cb
, MDL
);
2226 /* Convenience function for setting flag bits in a mask */
2227 void set_flag (u_int16_t
*flags
,
2240 * Convenience function which replicates the conflict flags set in one
2241 * mask to another, while preserving all other flags.
2243 void copy_conflict_flags(u_int16_t
*target
,
2246 /* Preserve non conflict flags */
2247 *target
&= ~CONFLICT_BITS
;
2249 /* Enable conflict flags per source */
2250 *target
|= source
& CONFLICT_BITS
;
2255 * Given an option_state, create a mask of conflict detection flags based
2256 * on the appropriate configuration parameters within the option state.
2259 get_conflict_mask(struct option_state
*options
) {
2261 int ddns_update_conflict_detection
= 1; /* default on */
2262 int ddns_dual_stack_mixed_mode
= 0; /* default off */
2263 int ddns_guard_id_must_match
= 1; /* default on */
2264 int ddns_other_guard_is_dynamic
= 0; /* default off */
2265 struct option_cache
*oc
= NULL
;
2268 oc
= lookup_option(&server_universe
, options
, SV_DDNS_CONFLICT_DETECT
);
2270 ddns_update_conflict_detection
=
2271 evaluate_boolean_option_cache(NULL
, NULL
, NULL
, NULL
, options
,
2272 NULL
, &global_scope
, oc
, MDL
);
2275 set_flag(&mask
, DDNS_CONFLICT_DETECTION
,
2276 ddns_update_conflict_detection
);
2278 if (!ddns_update_conflict_detection
) {
2279 #if defined (DEBUG_DNS_UPDATES)
2280 log_info ("DDNS conflict detection: off");
2282 /* Turn the rest of the conflict related flags off */
2283 set_flag(&mask
, DDNS_DUAL_STACK_MIXED_MODE
, 0);
2284 set_flag(&mask
, DDNS_GUARD_ID_MUST_MATCH
, 0);
2285 set_flag(&mask
, DDNS_OTHER_GUARD_IS_DYNAMIC
, 0);
2290 oc
= lookup_option(&server_universe
, options
,
2291 SV_DDNS_DUAL_STACK_MIXED_MODE
);
2293 ddns_dual_stack_mixed_mode
=
2294 evaluate_boolean_option_cache(NULL
, NULL
, NULL
, NULL
, options
,
2295 NULL
, &global_scope
, oc
, MDL
);
2298 oc
= lookup_option(&server_universe
, options
,
2299 SV_DDNS_GUARD_ID_MUST_MATCH
);
2301 ddns_guard_id_must_match
=
2302 evaluate_boolean_option_cache(NULL
, NULL
, NULL
, NULL
, options
,
2303 NULL
, &global_scope
, oc
, MDL
);
2306 oc
= lookup_option(&server_universe
, options
,
2307 SV_DDNS_OTHER_GUARD_IS_DYNAMIC
);
2309 ddns_other_guard_is_dynamic
=
2310 evaluate_boolean_option_cache(NULL
, NULL
, NULL
, NULL
, options
,
2311 NULL
, &global_scope
, oc
, MDL
);
2315 set_flag(&mask
, DDNS_DUAL_STACK_MIXED_MODE
,
2316 ddns_dual_stack_mixed_mode
);
2318 set_flag(&mask
, DDNS_GUARD_ID_MUST_MATCH
,
2319 ddns_guard_id_must_match
);
2321 set_flag(&mask
, DDNS_OTHER_GUARD_IS_DYNAMIC
,
2322 ddns_other_guard_is_dynamic
);
2324 #if defined (DEBUG_DNS_UPDATES)
2325 log_info ("DDNS conflict behavior:\n"
2326 "\tddns-update-style: %s\n"
2327 "\tupdate-conflict-detection: %d\n"
2328 "\tddns-dual-stack-mixed-mode: %d\n"
2329 "\tddns-guard-id-must-match %d\n"
2330 "\tddns-other-guard-is-dynamic: %d\n",
2331 ddns_styles_values
[ddns_update_style
].name
,
2332 ddns_update_conflict_detection
,
2333 ddns_dual_stack_mixed_mode
,
2334 ddns_guard_id_must_match
,
2335 ddns_other_guard_is_dynamic
);
2340 #if defined (DEBUG_DNS_UPDATES)
2341 /* Type used for creating lists of function pointers and their names */
2347 /* Returns the name of the function referred to by the given address */
2349 dump_ddns_cb_func(void *func
) {
2350 static LabeledPtr funcs
[] = {
2351 { ddns_ptr_add
, "ddns_ptr_add" },
2352 { ddns_fwd_srv_add2
, "ddns_fwd_srv_add2" },
2353 { ddns_fwd_srv_add1
, "ddns_fwd_srv_add1" },
2354 { ddns_ptr_remove
, "ddns_ptr_remove" },
2355 { ddns_fwd_srv_rem2
, "ddns_fwd_srv_rem2" },
2356 { ddns_fwd_srv_rem1
, "ddns_fwd_srv_rem1" },
2357 { ddns_fwd_srv_add3
, "ddns_fwd_srv_adde" },
2361 LabeledPtr
* lp
= funcs
;
2366 while ((lp
->ptr
) && (lp
->ptr
!= func
)) {
2373 /* Dumps basic control block info to the log */
2375 dump_ddns_cb (dhcp_ddns_cb_t
*ddns_cb
) {
2376 static char output_buf
[4096];
2378 return ("<ddns_cb is null>");
2381 sprintf (output_buf
, "ddns_cb: %p flags: %x state: %s cur_func: %s",
2382 ddns_cb
, ddns_cb
->flags
,
2383 ddns_state_name(ddns_cb
->state
),
2384 dump_ddns_cb_func(ddns_cb
->cur_func
));
2388 #endif /* DEBUG_DNS_UPDATES */
2390 #endif /* NSUPDATE */