Switch from bioq_insert_tail() to bioqdisksort(). When the kernel is
[dragonfly.git] / contrib / dhcp-3.0 / server / ddns.c
blob5254b49c4105284bf2db96b10f5d4dc918f241f5
1 /* ddns.c
3 Dynamic DNS updates. */
5 /*
6 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 2000-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
27 * This software has been donated to Internet Systems Consortium
28 * by Damien Neil of Nominum, Inc.
30 * To learn more about Internet Systems Consortium, see
31 * ``http://www.isc.org/''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
35 #ifndef lint
36 static char copyright[] =
37 "$Id: ddns.c,v 1.15.2.15 2004/11/24 17:39:18 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
38 #endif /* not lint */
40 #include "dhcpd.h"
41 #include "dst/md5.h"
42 #include "minires/minires.h"
44 #ifdef NSUPDATE
46 /* DN: No way of checking that there is enough space in a data_string's
47 buffer. Be certain to allocate enough!
48 TL: This is why the expression evaluation code allocates a *new*
49 data_string. :') */
50 static void data_string_append (struct data_string *ds1,
51 struct data_string *ds2)
53 memcpy (ds1 -> buffer -> data + ds1 -> len,
54 ds2 -> data,
55 ds2 -> len);
56 ds1 -> len += ds2 -> len;
59 static isc_result_t ddns_update_ptr (struct data_string *ddns_fwd_name,
60 struct data_string *ddns_rev_name,
61 unsigned long ttl)
63 ns_updque updqueue;
64 ns_updrec *updrec;
65 isc_result_t result = ISC_R_UNEXPECTED;
68 * The DHCP server submits a DNS query which deletes all of the PTR RRs
69 * associated with the lease IP address, and adds a PTR RR whose data
70 * is the client's (possibly disambiguated) host name. The server also
71 * adds a DHCID RR specified in Section 4.3.
72 * -- "Interaction between DHCP and DNS"
75 ISC_LIST_INIT (updqueue);
78 * Delete all PTR RRs.
80 updrec = minires_mkupdrec (S_UPDATE,
81 (const char *)ddns_rev_name -> data,
82 C_IN, T_PTR, 0);
83 if (!updrec) {
84 result = ISC_R_NOMEMORY;
85 goto error;
88 updrec -> r_data = (unsigned char *)0;
89 updrec -> r_size = 0;
90 updrec -> r_opcode = DELETE;
92 ISC_LIST_APPEND (updqueue, updrec, r_link);
95 * Add PTR RR.
97 updrec = minires_mkupdrec (S_UPDATE,
98 (const char *)ddns_rev_name -> data,
99 C_IN, T_PTR, ttl);
100 if (!updrec) {
101 result = ISC_R_NOMEMORY;
102 goto error;
105 updrec -> r_data = ddns_fwd_name -> data;
106 updrec -> r_size = ddns_fwd_name -> len;
107 updrec -> r_opcode = ADD;
109 ISC_LIST_APPEND (updqueue, updrec, r_link);
112 * Attempt to perform the update.
114 result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
115 #if defined (DEBUG)
116 print_dns_status ((int)result, &updqueue);
117 #endif
118 if (result == ISC_R_SUCCESS) {
119 log_info ("added reverse map from %.*s to %.*s",
120 (int)ddns_rev_name -> len,
121 (const char *)ddns_rev_name -> data,
122 (int)ddns_fwd_name -> len,
123 (const char *)ddns_fwd_name -> data);
124 } else {
125 log_error ("unable to add reverse map from %.*s to %.*s: %s",
126 (int)ddns_rev_name -> len,
127 (const char *)ddns_rev_name -> data,
128 (int)ddns_fwd_name -> len,
129 (const char *)ddns_fwd_name -> data,
130 isc_result_totext (result));
133 /* Fall through. */
134 error:
136 while (!ISC_LIST_EMPTY (updqueue)) {
137 updrec = ISC_LIST_HEAD (updqueue);
138 ISC_LIST_UNLINK (updqueue, updrec, r_link);
139 minires_freeupdrec (updrec);
142 return result;
146 static isc_result_t ddns_remove_ptr (struct data_string *ddns_rev_name)
148 ns_updque updqueue;
149 ns_updrec *updrec;
150 isc_result_t result;
153 * When a lease expires or a DHCP client issues a DHCPRELEASE request,
154 * the DHCP server SHOULD delete the PTR RR that matches the DHCP
155 * binding, if one was successfully added. The server's update query
156 * SHOULD assert that the name in the PTR record matches the name of
157 * the client whose lease has expired or been released.
158 * -- "Interaction between DHCP and DNS"
161 ISC_LIST_INIT (updqueue);
164 * Delete the PTR RRset for the leased address.
166 updrec = minires_mkupdrec (S_UPDATE,
167 (const char *)ddns_rev_name -> data,
168 C_IN, T_PTR, 0);
169 if (!updrec) {
170 result = ISC_R_NOMEMORY;
171 goto error;
174 updrec -> r_data = (unsigned char *)0;
175 updrec -> r_size = 0;
176 updrec -> r_opcode = DELETE;
178 ISC_LIST_APPEND (updqueue, updrec, r_link);
181 * Attempt to perform the update.
183 result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
184 #if defined (DEBUG)
185 print_dns_status ((int)result, &updqueue);
186 #endif
187 if (result == ISC_R_SUCCESS) {
188 log_info ("removed reverse map on %.*s",
189 (int)ddns_rev_name -> len,
190 (const char *)ddns_rev_name -> data);
191 } else {
192 if (result != ISC_R_NXRRSET && result != ISC_R_NXDOMAIN)
193 log_error ("can't remove reverse map on %.*s: %s",
194 (int)ddns_rev_name -> len,
195 (const char *)ddns_rev_name -> data,
196 isc_result_totext (result));
199 /* Not there is success. */
200 if (result == ISC_R_NXRRSET || result == ISC_R_NXDOMAIN)
201 result = ISC_R_SUCCESS;
203 /* Fall through. */
204 error:
206 while (!ISC_LIST_EMPTY (updqueue)) {
207 updrec = ISC_LIST_HEAD (updqueue);
208 ISC_LIST_UNLINK (updqueue, updrec, r_link);
209 minires_freeupdrec (updrec);
212 return result;
216 int ddns_updates (struct packet *packet,
217 struct lease *lease, struct lease *old,
218 struct lease_state *state)
220 unsigned long ddns_ttl = DEFAULT_DDNS_TTL;
221 struct data_string ddns_hostname;
222 struct data_string ddns_domainname;
223 struct data_string old_ddns_fwd_name;
224 struct data_string ddns_fwd_name;
225 struct data_string ddns_rev_name;
226 struct data_string ddns_dhcid;
227 unsigned len;
228 struct data_string d1;
229 struct option_cache *oc;
230 int s1, s2;
231 int result = 0;
232 isc_result_t rcode1 = ISC_R_SUCCESS, rcode2 = ISC_R_SUCCESS;
233 int server_updates_a = 1;
234 struct buffer *bp = (struct buffer *)0;
235 int ignorep = 0;
237 if (ddns_update_style != 2)
238 return 0;
240 /* Can only cope with IPv4 addrs at the moment. */
241 if (lease -> ip_addr . len != 4)
242 return 0;
244 memset (&ddns_hostname, 0, sizeof (ddns_hostname));
245 memset (&ddns_domainname, 0, sizeof (ddns_domainname));
246 memset (&old_ddns_fwd_name, 0, sizeof (ddns_fwd_name));
247 memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name));
248 memset (&ddns_rev_name, 0, sizeof (ddns_rev_name));
249 memset (&ddns_dhcid, 0, sizeof (ddns_dhcid));
251 /* If we are allowed to accept the client's update of its own A
252 record, see if the client wants to update its own A record. */
253 if (!(oc = lookup_option (&server_universe, state -> options,
254 SV_CLIENT_UPDATES)) ||
255 evaluate_boolean_option_cache (&ignorep, packet, lease,
256 (struct client_state *)0,
257 packet -> options,
258 state -> options,
259 &lease -> scope, oc, MDL)) {
260 /* If there's no fqdn.no-client-update or if it's
261 nonzero, don't try to use the client-supplied
262 XXX */
263 if (!(oc = lookup_option (&fqdn_universe, packet -> options,
264 FQDN_SERVER_UPDATE)) ||
265 evaluate_boolean_option_cache (&ignorep, packet, lease,
266 (struct client_state *)0,
267 packet -> options,
268 state -> options,
269 &lease -> scope, oc, MDL))
270 goto noclient;
271 /* Win98 and Win2k will happily claim to be willing to
272 update an unqualified domain name. */
273 if (!(oc = lookup_option (&fqdn_universe, packet -> options,
274 FQDN_DOMAINNAME)))
275 goto noclient;
276 if (!(oc = lookup_option (&fqdn_universe, packet -> options,
277 FQDN_FQDN)) ||
278 !evaluate_option_cache (&ddns_fwd_name, packet, lease,
279 (struct client_state *)0,
280 packet -> options,
281 state -> options,
282 &lease -> scope, oc, MDL))
283 goto noclient;
284 server_updates_a = 0;
285 goto client_updates;
287 noclient:
288 /* If do-forward-updates is disabled, this basically means don't
289 do an update unless the client is participating, so if we get
290 here and do-forward-updates is disabled, we can stop. */
291 if ((oc = lookup_option (&server_universe, state -> options,
292 SV_DO_FORWARD_UPDATES)) &&
293 !evaluate_boolean_option_cache (&ignorep, packet, lease,
294 (struct client_state *)0,
295 packet -> options,
296 state -> options,
297 &lease -> scope, oc, MDL)) {
298 return 0;
301 /* If it's a static lease, then don't do the DNS update unless we're
302 specifically configured to do so. If the client asked to do its
303 own update and we allowed that, we don't do this test. */
304 if (lease -> flags & STATIC_LEASE) {
305 if (!(oc = lookup_option (&server_universe, state -> options,
306 SV_UPDATE_STATIC_LEASES)) ||
307 !evaluate_boolean_option_cache (&ignorep, packet, lease,
308 (struct client_state *)0,
309 packet -> options,
310 state -> options,
311 &lease -> scope, oc, MDL))
312 return 0;
316 * Compute the name for the A record.
318 oc = lookup_option (&server_universe, state -> options,
319 SV_DDNS_HOST_NAME);
320 if (oc)
321 s1 = evaluate_option_cache (&ddns_hostname, packet, lease,
322 (struct client_state *)0,
323 packet -> options,
324 state -> options,
325 &lease -> scope, oc, MDL);
326 else
327 s1 = 0;
329 oc = lookup_option (&server_universe, state -> options,
330 SV_DDNS_DOMAIN_NAME);
331 if (oc)
332 s2 = evaluate_option_cache (&ddns_domainname, packet, lease,
333 (struct client_state *)0,
334 packet -> options,
335 state -> options,
336 &lease -> scope, oc, MDL);
337 else
338 s2 = 0;
340 if (s1 && s2) {
341 if (ddns_hostname.len + ddns_domainname.len > 253) {
342 log_error ("ddns_update: host.domain name too long");
344 goto out;
347 buffer_allocate (&ddns_fwd_name.buffer,
348 ddns_hostname.len + ddns_domainname.len + 2,
349 MDL);
350 if (ddns_fwd_name.buffer) {
351 ddns_fwd_name.data = ddns_fwd_name.buffer -> data;
352 data_string_append (&ddns_fwd_name, &ddns_hostname);
353 ddns_fwd_name.buffer -> data [ddns_fwd_name.len] = '.';
354 ddns_fwd_name.len++;
355 data_string_append (&ddns_fwd_name, &ddns_domainname);
356 ddns_fwd_name.buffer -> data [ddns_fwd_name.len] ='\0';
357 ddns_fwd_name.terminated = 1;
360 client_updates:
362 /* See if there's a name already stored on the lease. */
363 if (find_bound_string (&old_ddns_fwd_name,
364 lease -> scope, "ddns-fwd-name")) {
365 /* If there is, see if it's different. */
366 if (old_ddns_fwd_name.len != ddns_fwd_name.len ||
367 memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data,
368 old_ddns_fwd_name.len)) {
369 /* If the name is different, try to delete
370 the old A record. */
371 if (!ddns_removals (lease))
372 goto out;
373 /* If the delete succeeded, go install the new
374 record. */
375 goto in;
378 /* See if there's a DHCID on the lease. */
379 if (!find_bound_string (&ddns_dhcid,
380 lease -> scope, "ddns-txt")) {
381 /* If there's no DHCID, the update was probably
382 done with the old-style ad-hoc DDNS updates.
383 So if the expiry and release events look like
384 they're the same, run them. This should delete
385 the old DDNS data. */
386 if (old -> on_expiry == old -> on_release) {
387 execute_statements ((struct binding_value **)0,
388 (struct packet *)0, lease,
389 (struct client_state *)0,
390 (struct option_state *)0,
391 (struct option_state *)0,
392 &lease -> scope,
393 old -> on_expiry);
394 if (old -> on_expiry)
395 executable_statement_dereference
396 (&old -> on_expiry, MDL);
397 if (old -> on_release)
398 executable_statement_dereference
399 (&old -> on_release, MDL);
400 /* Now, install the DDNS data the new way. */
401 goto in;
405 /* See if the administrator wants to do updates even
406 in cases where the update already appears to have been
407 done. */
408 if (!(oc = lookup_option (&server_universe, state -> options,
409 SV_UPDATE_OPTIMIZATION)) ||
410 evaluate_boolean_option_cache (&ignorep, packet, lease,
411 (struct client_state *)0,
412 packet -> options,
413 state -> options,
414 &lease -> scope, oc, MDL)) {
415 result = 1;
416 goto noerror;
420 /* If there's no ddns-fwd-name on the lease, see if there's
421 a ddns-client-fqdn, indicating a prior client FQDN update.
422 If there is, and if we're still doing the client update,
423 see if the name has changed. If it hasn't, don't do the
424 PTR update. */
425 if (find_bound_string (&old_ddns_fwd_name,
426 lease -> scope, "ddns-client-fqdn")) {
427 /* If the name is not different, no need to update
428 the PTR record. */
429 if (old_ddns_fwd_name.len == ddns_fwd_name.len &&
430 !memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data,
431 old_ddns_fwd_name.len) &&
432 (!(oc = lookup_option (&server_universe,
433 state -> options,
434 SV_UPDATE_OPTIMIZATION)) ||
435 evaluate_boolean_option_cache (&ignorep, packet, lease,
436 (struct client_state *)0,
437 packet -> options,
438 state -> options,
439 &lease -> scope, oc,
440 MDL))) {
441 goto noerror;
446 /* If we don't have a name that the client has been assigned, we
447 can just skip all this. */
448 if (!ddns_fwd_name.len)
449 goto out;
451 if (ddns_fwd_name.len > 255) {
452 log_error ("client provided fqdn: too long");
453 goto out;
457 * Compute the RR TTL.
459 ddns_ttl = DEFAULT_DDNS_TTL;
460 memset (&d1, 0, sizeof d1);
461 if ((oc = lookup_option (&server_universe, state -> options,
462 SV_DDNS_TTL))) {
463 if (evaluate_option_cache (&d1, packet, lease,
464 (struct client_state *)0,
465 packet -> options,
466 state -> options,
467 &lease -> scope, oc, MDL)) {
468 if (d1.len == sizeof (u_int32_t))
469 ddns_ttl = getULong (d1.data);
470 data_string_forget (&d1, MDL);
476 * Compute the reverse IP name.
478 oc = lookup_option (&server_universe, state -> options,
479 SV_DDNS_REV_DOMAIN_NAME);
480 if (oc)
481 s1 = evaluate_option_cache (&d1, packet, lease,
482 (struct client_state *)0,
483 packet -> options,
484 state -> options,
485 &lease -> scope, oc, MDL);
486 else
487 s1 = 0;
489 if (s1 && (d1.len > 238)) {
490 log_error ("ddns_update: Calculated rev domain name too long.");
491 s1 = 0;
492 data_string_forget (&d1, MDL);
495 if (oc && s1) {
496 /* Buffer length:
497 XXX.XXX.XXX.XXX.<ddns-rev-domain-name>\0 */
498 buffer_allocate (&ddns_rev_name.buffer,
499 d1.len + 17, MDL);
500 if (ddns_rev_name.buffer) {
501 ddns_rev_name.data = ddns_rev_name.buffer -> data;
503 /* %Audit% Cannot exceed 17 bytes. %2004.06.17,Safe% */
504 sprintf ((char *)ddns_rev_name.buffer -> data,
505 "%u.%u.%u.%u.",
506 lease -> ip_addr . iabuf[3] & 0xff,
507 lease -> ip_addr . iabuf[2] & 0xff,
508 lease -> ip_addr . iabuf[1] & 0xff,
509 lease -> ip_addr . iabuf[0] & 0xff);
511 ddns_rev_name.len =
512 strlen ((const char *)ddns_rev_name.data);
513 data_string_append (&ddns_rev_name, &d1);
514 ddns_rev_name.buffer -> data [ddns_rev_name.len] ='\0';
515 ddns_rev_name.terminated = 1;
518 data_string_forget (&d1, MDL);
522 * If we are updating the A record, compute the DHCID value.
524 if (server_updates_a) {
525 memset (&ddns_dhcid, 0, sizeof ddns_dhcid);
526 if (lease -> uid && lease -> uid_len)
527 result = get_dhcid (&ddns_dhcid,
528 DHO_DHCP_CLIENT_IDENTIFIER,
529 lease -> uid, lease -> uid_len);
530 else
531 result = get_dhcid (&ddns_dhcid, 0,
532 lease -> hardware_addr.hbuf,
533 lease -> hardware_addr.hlen);
534 if (!result)
535 goto badfqdn;
539 * Start the resolver, if necessary.
541 if (!resolver_inited) {
542 minires_ninit (&resolver_state);
543 resolver_inited = 1;
544 resolver_state.retrans = 1;
545 resolver_state.retry = 1;
549 * Perform updates.
551 if (ddns_fwd_name.len && ddns_dhcid.len)
552 rcode1 = ddns_update_a (&ddns_fwd_name, lease -> ip_addr,
553 &ddns_dhcid, ddns_ttl, 0);
555 if (rcode1 == ISC_R_SUCCESS) {
556 if (ddns_fwd_name.len && ddns_rev_name.len)
557 rcode2 = ddns_update_ptr (&ddns_fwd_name,
558 &ddns_rev_name, ddns_ttl);
559 } else
560 rcode2 = rcode1;
562 if (rcode1 == ISC_R_SUCCESS &&
563 (server_updates_a || rcode2 == ISC_R_SUCCESS)) {
564 bind_ds_value (&lease -> scope,
565 (server_updates_a
566 ? "ddns-fwd-name" : "ddns-client-fqdn"),
567 &ddns_fwd_name);
568 if (server_updates_a)
569 bind_ds_value (&lease -> scope, "ddns-txt",
570 &ddns_dhcid);
573 if (rcode2 == ISC_R_SUCCESS) {
574 bind_ds_value (&lease -> scope, "ddns-rev-name",
575 &ddns_rev_name);
578 /* Set up the outgoing FQDN option if there was an incoming
579 FQDN option. If there's a valid FQDN option, there should
580 be an FQDN_ENCODED suboption, so we test the latter to
581 detect the presence of the former. */
582 noerror:
583 if ((oc = lookup_option (&fqdn_universe,
584 packet -> options, FQDN_ENCODED))
585 && buffer_allocate (&bp, ddns_fwd_name.len + 5, MDL)) {
586 bp -> data [0] = server_updates_a;
587 if (!save_option_buffer (&fqdn_universe, state -> options,
588 bp, &bp -> data [0], 1,
589 &fqdn_options [FQDN_SERVER_UPDATE],
591 goto badfqdn;
592 bp -> data [1] = server_updates_a;
593 if (!save_option_buffer (&fqdn_universe, state -> options,
594 bp, &bp -> data [1], 1,
595 &fqdn_options [FQDN_NO_CLIENT_UPDATE],
597 goto badfqdn;
598 /* Do the same encoding the client did. */
599 oc = lookup_option (&fqdn_universe, packet -> options,
600 FQDN_ENCODED);
601 if (oc &&
602 evaluate_boolean_option_cache (&ignorep, packet, lease,
603 (struct client_state *)0,
604 packet -> options,
605 state -> options,
606 &lease -> scope, oc, MDL))
607 bp -> data [2] = 1;
608 else
609 bp -> data [2] = 0;
610 if (!save_option_buffer (&fqdn_universe, state -> options,
611 bp, &bp -> data [2], 1,
612 &fqdn_options [FQDN_ENCODED],
614 goto badfqdn;
615 bp -> data [3] = isc_rcode_to_ns (rcode1);
616 if (!save_option_buffer (&fqdn_universe, state -> options,
617 bp, &bp -> data [3], 1,
618 &fqdn_options [FQDN_RCODE1],
620 goto badfqdn;
621 bp -> data [4] = isc_rcode_to_ns (rcode2);
622 if (!save_option_buffer (&fqdn_universe, state -> options,
623 bp, &bp -> data [4], 1,
624 &fqdn_options [FQDN_RCODE2],
626 goto badfqdn;
627 if (ddns_fwd_name.len) {
628 memcpy (&bp -> data [5],
629 ddns_fwd_name.data, ddns_fwd_name.len);
630 if (!save_option_buffer (&fqdn_universe, state -> options,
631 bp, &bp -> data [5],
632 ddns_fwd_name.len,
633 &fqdn_options [FQDN_FQDN],
635 goto badfqdn;
639 badfqdn:
640 out:
642 * Final cleanup.
644 data_string_forget (&ddns_hostname, MDL);
645 data_string_forget (&ddns_domainname, MDL);
646 data_string_forget (&old_ddns_fwd_name, MDL);
647 data_string_forget (&ddns_fwd_name, MDL);
648 data_string_forget (&ddns_rev_name, MDL);
649 data_string_forget (&ddns_dhcid, MDL);
650 if (bp)
651 buffer_dereference (&bp, MDL);
653 return result;
656 int ddns_removals (struct lease *lease)
658 struct data_string ddns_fwd_name;
659 struct data_string ddns_rev_name;
660 struct data_string ddns_dhcid;
661 isc_result_t rcode;
662 struct binding *binding;
663 int result = 0;
664 int client_updated = 0;
666 /* No scope implies that DDNS has not been performed for this lease. */
667 if (!lease -> scope)
668 return 0;
670 if (ddns_update_style != 2)
671 return 0;
674 * Look up stored names.
676 memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name));
677 memset (&ddns_rev_name, 0, sizeof (ddns_rev_name));
678 memset (&ddns_dhcid, 0, sizeof (ddns_dhcid));
681 * Start the resolver, if necessary.
683 if (!resolver_inited) {
684 minires_ninit (&resolver_state);
685 resolver_inited = 1;
688 /* We need the fwd name whether we are deleting both records or just
689 the PTR record, so if it's not there, we can't proceed. */
690 if (!find_bound_string (&ddns_fwd_name,
691 lease -> scope, "ddns-fwd-name")) {
692 /* If there's no ddns-fwd-name, look for the client fqdn,
693 in case the client did the update. */
694 if (!find_bound_string (&ddns_fwd_name,
695 lease -> scope, "ddns-client-fqdn"))
696 goto try_rev;
697 client_updated = 1;
698 goto try_rev;
701 /* If the ddns-txt binding isn't there, this isn't an interim
702 or rfc3??? record, so we can't delete the A record using
703 this mechanism, but we can delete the PTR record. */
704 if (!find_bound_string (&ddns_dhcid, lease -> scope, "ddns-txt")) {
705 result = 1;
706 goto try_rev;
710 * Perform removals.
712 if (ddns_fwd_name.len)
713 rcode = ddns_remove_a (&ddns_fwd_name,
714 lease -> ip_addr, &ddns_dhcid);
715 else
716 rcode = ISC_R_SUCCESS;
718 if (rcode == ISC_R_SUCCESS) {
719 result = 1;
720 unset (lease -> scope, "ddns-fwd-name");
721 unset (lease -> scope, "ddns-txt");
722 try_rev:
723 if (find_bound_string (&ddns_rev_name,
724 lease -> scope, "ddns-rev-name")) {
725 if (ddns_remove_ptr(&ddns_rev_name) == NOERROR) {
726 unset (lease -> scope, "ddns-rev-name");
727 if (client_updated)
728 unset (lease -> scope,
729 "ddns-client-fqdn");
730 /* XXX this is to compensate for a bug in
731 XXX 3.0rc8, and should be removed before
732 XXX 3.0pl1. */
733 else if (!ddns_fwd_name.len)
734 unset (lease -> scope, "ddns-text");
735 } else
736 result = 0;
740 data_string_forget (&ddns_fwd_name, MDL);
741 data_string_forget (&ddns_rev_name, MDL);
742 data_string_forget (&ddns_dhcid, MDL);
744 return result;
747 #endif /* NSUPDATE */