Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / dhcp / server / ddns.c
blobf835d546ce7e34e07ee88d673843c47c3c535d2b
1 /* ddns.c
3 Dynamic DNS updates. */
5 /*
6 * Copyright (c) 2004-2005 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.7 2005/08/11 17:13:30 drochner Exp $ Copyright (c) 2004-2005 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 struct data_string d1;
228 struct option_cache *oc;
229 int s1, s2;
230 int result = 0;
231 isc_result_t rcode1 = ISC_R_SUCCESS, rcode2 = ISC_R_SUCCESS;
232 int server_updates_a = 1;
233 struct buffer *bp = (struct buffer *)0;
234 int ignorep = 0;
236 s1 = 0; /* XXXGCC -Wuninitialized [arm / sparc64] */
238 if (ddns_update_style != 2)
239 return 0;
241 /* Can only cope with IPv4 addrs at the moment. */
242 if (lease -> ip_addr . len != 4)
243 return 0;
245 memset (&ddns_hostname, 0, sizeof (ddns_hostname));
246 memset (&ddns_domainname, 0, sizeof (ddns_domainname));
247 memset (&old_ddns_fwd_name, 0, sizeof (ddns_fwd_name));
248 memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name));
249 memset (&ddns_rev_name, 0, sizeof (ddns_rev_name));
250 memset (&ddns_dhcid, 0, sizeof (ddns_dhcid));
252 /* If we are allowed to accept the client's update of its own A
253 record, see if the client wants to update its own A record. */
254 if (!(oc = lookup_option (&server_universe, state -> options,
255 SV_CLIENT_UPDATES)) ||
256 evaluate_boolean_option_cache (&ignorep, packet, lease,
257 (struct client_state *)0,
258 packet -> options,
259 state -> options,
260 &lease -> scope, oc, MDL)) {
261 /* If there's no fqdn.no-client-update or if it's
262 nonzero, don't try to use the client-supplied
263 XXX */
264 if (!(oc = lookup_option (&fqdn_universe, packet -> options,
265 FQDN_SERVER_UPDATE)) ||
266 evaluate_boolean_option_cache (&ignorep, packet, lease,
267 (struct client_state *)0,
268 packet -> options,
269 state -> options,
270 &lease -> scope, oc, MDL))
271 goto noclient;
272 /* Win98 and Win2k will happily claim to be willing to
273 update an unqualified domain name. */
274 if (!(oc = lookup_option (&fqdn_universe, packet -> options,
275 FQDN_DOMAINNAME)))
276 goto noclient;
277 if (!(oc = lookup_option (&fqdn_universe, packet -> options,
278 FQDN_FQDN)) ||
279 !evaluate_option_cache (&ddns_fwd_name, packet, lease,
280 (struct client_state *)0,
281 packet -> options,
282 state -> options,
283 &lease -> scope, oc, MDL))
284 goto noclient;
285 server_updates_a = 0;
286 goto client_updates;
288 noclient:
289 /* If do-forward-updates is disabled, this basically means don't
290 do an update unless the client is participating, so if we get
291 here and do-forward-updates is disabled, we can stop. */
292 if ((oc = lookup_option (&server_universe, state -> options,
293 SV_DO_FORWARD_UPDATES)) &&
294 !evaluate_boolean_option_cache (&ignorep, packet, lease,
295 (struct client_state *)0,
296 packet -> options,
297 state -> options,
298 &lease -> scope, oc, MDL)) {
299 return 0;
302 /* If it's a static lease, then don't do the DNS update unless we're
303 specifically configured to do so. If the client asked to do its
304 own update and we allowed that, we don't do this test. */
305 if (lease -> flags & STATIC_LEASE) {
306 if (!(oc = lookup_option (&server_universe, state -> options,
307 SV_UPDATE_STATIC_LEASES)) ||
308 !evaluate_boolean_option_cache (&ignorep, packet, lease,
309 (struct client_state *)0,
310 packet -> options,
311 state -> options,
312 &lease -> scope, oc, MDL))
313 return 0;
317 * Compute the name for the A record.
319 oc = lookup_option (&server_universe, state -> options,
320 SV_DDNS_HOST_NAME);
321 if (oc)
322 s1 = evaluate_option_cache (&ddns_hostname, packet, lease,
323 (struct client_state *)0,
324 packet -> options,
325 state -> options,
326 &lease -> scope, oc, MDL);
327 else
328 s1 = 0;
330 oc = lookup_option (&server_universe, state -> options,
331 SV_DDNS_DOMAIN_NAME);
332 if (oc)
333 s2 = evaluate_option_cache (&ddns_domainname, packet, lease,
334 (struct client_state *)0,
335 packet -> options,
336 state -> options,
337 &lease -> scope, oc, MDL);
338 else
339 s2 = 0;
341 if (s1 && s2) {
342 if (ddns_hostname.len + ddns_domainname.len > 253) {
343 log_error ("ddns_update: host.domain name too long");
345 goto out;
348 buffer_allocate (&ddns_fwd_name.buffer,
349 ddns_hostname.len + ddns_domainname.len + 2,
350 MDL);
351 if (ddns_fwd_name.buffer) {
352 ddns_fwd_name.data = ddns_fwd_name.buffer -> data;
353 data_string_append (&ddns_fwd_name, &ddns_hostname);
354 ddns_fwd_name.buffer -> data [ddns_fwd_name.len] = '.';
355 ddns_fwd_name.len++;
356 data_string_append (&ddns_fwd_name, &ddns_domainname);
357 ddns_fwd_name.buffer -> data [ddns_fwd_name.len] ='\0';
358 ddns_fwd_name.terminated = 1;
361 client_updates:
363 /* See if there's a name already stored on the lease. */
364 if (find_bound_string (&old_ddns_fwd_name,
365 lease -> scope, "ddns-fwd-name")) {
366 /* If there is, see if it's different. */
367 if (old_ddns_fwd_name.len != ddns_fwd_name.len ||
368 memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data,
369 old_ddns_fwd_name.len)) {
370 /* If the name is different, try to delete
371 the old A record. */
372 if (!ddns_removals (lease))
373 goto out;
374 /* If the delete succeeded, go install the new
375 record. */
376 goto in;
379 /* See if there's a DHCID on the lease. */
380 if (!find_bound_string (&ddns_dhcid,
381 lease -> scope, "ddns-txt")) {
382 /* If there's no DHCID, the update was probably
383 done with the old-style ad-hoc DDNS updates.
384 So if the expiry and release events look like
385 they're the same, run them. This should delete
386 the old DDNS data. */
387 if (old -> on_expiry == old -> on_release) {
388 execute_statements ((struct binding_value **)0,
389 (struct packet *)0, lease,
390 (struct client_state *)0,
391 (struct option_state *)0,
392 (struct option_state *)0,
393 &lease -> scope,
394 old -> on_expiry);
395 if (old -> on_expiry)
396 executable_statement_dereference
397 (&old -> on_expiry, MDL);
398 if (old -> on_release)
399 executable_statement_dereference
400 (&old -> on_release, MDL);
401 /* Now, install the DDNS data the new way. */
402 goto in;
406 /* See if the administrator wants to do updates even
407 in cases where the update already appears to have been
408 done. */
409 if (!(oc = lookup_option (&server_universe, state -> options,
410 SV_UPDATE_OPTIMIZATION)) ||
411 evaluate_boolean_option_cache (&ignorep, packet, lease,
412 (struct client_state *)0,
413 packet -> options,
414 state -> options,
415 &lease -> scope, oc, MDL)) {
416 result = 1;
417 goto noerror;
421 /* If there's no ddns-fwd-name on the lease, see if there's
422 a ddns-client-fqdn, indicating a prior client FQDN update.
423 If there is, and if we're still doing the client update,
424 see if the name has changed. If it hasn't, don't do the
425 PTR update. */
426 if (find_bound_string (&old_ddns_fwd_name,
427 lease -> scope, "ddns-client-fqdn")) {
428 /* If the name is not different, no need to update
429 the PTR record. */
430 if (old_ddns_fwd_name.len == ddns_fwd_name.len &&
431 !memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data,
432 old_ddns_fwd_name.len) &&
433 (!(oc = lookup_option (&server_universe,
434 state -> options,
435 SV_UPDATE_OPTIMIZATION)) ||
436 evaluate_boolean_option_cache (&ignorep, packet, lease,
437 (struct client_state *)0,
438 packet -> options,
439 state -> options,
440 &lease -> scope, oc,
441 MDL))) {
442 goto noerror;
447 /* If we don't have a name that the client has been assigned, we
448 can just skip all this. */
449 if (!ddns_fwd_name.len)
450 goto out;
452 if (ddns_fwd_name.len > 255) {
453 log_error ("client provided fqdn: too long");
454 goto out;
458 * Compute the RR TTL.
460 ddns_ttl = DEFAULT_DDNS_TTL;
461 memset (&d1, 0, sizeof d1);
462 if ((oc = lookup_option (&server_universe, state -> options,
463 SV_DDNS_TTL))) {
464 if (evaluate_option_cache (&d1, packet, lease,
465 (struct client_state *)0,
466 packet -> options,
467 state -> options,
468 &lease -> scope, oc, MDL)) {
469 if (d1.len == sizeof (u_int32_t))
470 ddns_ttl = getULong (d1.data);
471 data_string_forget (&d1, MDL);
477 * Compute the reverse IP name.
479 oc = lookup_option (&server_universe, state -> options,
480 SV_DDNS_REV_DOMAIN_NAME);
481 if (oc)
482 s1 = evaluate_option_cache (&d1, packet, lease,
483 (struct client_state *)0,
484 packet -> options,
485 state -> options,
486 &lease -> scope, oc, MDL);
487 else
488 s1 = 0;
490 if (s1 && (d1.len > 238)) {
491 log_error ("ddns_update: Calculated rev domain name too long.");
492 s1 = 0;
493 data_string_forget (&d1, MDL);
496 if (oc && s1) {
497 /* Buffer length:
498 XXX.XXX.XXX.XXX.<ddns-rev-domain-name>\0 */
499 buffer_allocate (&ddns_rev_name.buffer,
500 d1.len + 17, MDL);
501 if (ddns_rev_name.buffer) {
502 ddns_rev_name.data = ddns_rev_name.buffer -> data;
504 /* %Audit% Cannot exceed 17 bytes. %2004.06.17,Safe% */
505 sprintf ((char *)ddns_rev_name.buffer -> data,
506 "%u.%u.%u.%u.",
507 lease -> ip_addr . iabuf[3] & 0xff,
508 lease -> ip_addr . iabuf[2] & 0xff,
509 lease -> ip_addr . iabuf[1] & 0xff,
510 lease -> ip_addr . iabuf[0] & 0xff);
512 ddns_rev_name.len =
513 strlen ((const char *)ddns_rev_name.data);
514 data_string_append (&ddns_rev_name, &d1);
515 ddns_rev_name.buffer -> data [ddns_rev_name.len] ='\0';
516 ddns_rev_name.terminated = 1;
519 data_string_forget (&d1, MDL);
523 * If we are updating the A record, compute the DHCID value.
525 if (server_updates_a) {
526 memset (&ddns_dhcid, 0, sizeof ddns_dhcid);
527 if (lease -> uid && lease -> uid_len)
528 result = get_dhcid (&ddns_dhcid,
529 DHO_DHCP_CLIENT_IDENTIFIER,
530 lease -> uid, lease -> uid_len);
531 else
532 result = get_dhcid (&ddns_dhcid, 0,
533 lease -> hardware_addr.hbuf,
534 lease -> hardware_addr.hlen);
535 if (!result)
536 goto badfqdn;
540 * Start the resolver, if necessary.
542 if (!resolver_inited) {
543 minires_ninit (&resolver_state);
544 resolver_inited = 1;
545 resolver_state.retrans = 1;
546 resolver_state.retry = 1;
550 * Perform updates.
552 if (ddns_fwd_name.len && ddns_dhcid.len)
553 rcode1 = ddns_update_a (&ddns_fwd_name, lease -> ip_addr,
554 &ddns_dhcid, ddns_ttl, 0);
556 if (rcode1 == ISC_R_SUCCESS) {
557 if (ddns_fwd_name.len && ddns_rev_name.len)
558 rcode2 = ddns_update_ptr (&ddns_fwd_name,
559 &ddns_rev_name, ddns_ttl);
560 } else
561 rcode2 = rcode1;
563 if (rcode1 == ISC_R_SUCCESS &&
564 (server_updates_a || rcode2 == ISC_R_SUCCESS)) {
565 bind_ds_value (&lease -> scope,
566 (server_updates_a
567 ? "ddns-fwd-name" : "ddns-client-fqdn"),
568 &ddns_fwd_name);
569 if (server_updates_a)
570 bind_ds_value (&lease -> scope, "ddns-txt",
571 &ddns_dhcid);
574 if (rcode2 == ISC_R_SUCCESS) {
575 bind_ds_value (&lease -> scope, "ddns-rev-name",
576 &ddns_rev_name);
579 /* Set up the outgoing FQDN option if there was an incoming
580 FQDN option. If there's a valid FQDN option, there should
581 be an FQDN_ENCODED suboption, so we test the latter to
582 detect the presence of the former. */
583 noerror:
584 if ((oc = lookup_option (&fqdn_universe,
585 packet -> options, FQDN_ENCODED))
586 && buffer_allocate (&bp, ddns_fwd_name.len + 5, MDL)) {
587 bp -> data [0] = server_updates_a;
588 if (!save_option_buffer (&fqdn_universe, state -> options,
589 bp, &bp -> data [0], 1,
590 &fqdn_options [FQDN_SERVER_UPDATE],
592 goto badfqdn;
593 bp -> data [1] = server_updates_a;
594 if (!save_option_buffer (&fqdn_universe, state -> options,
595 bp, &bp -> data [1], 1,
596 &fqdn_options [FQDN_NO_CLIENT_UPDATE],
598 goto badfqdn;
599 /* Do the same encoding the client did. */
600 oc = lookup_option (&fqdn_universe, packet -> options,
601 FQDN_ENCODED);
602 if (oc &&
603 evaluate_boolean_option_cache (&ignorep, packet, lease,
604 (struct client_state *)0,
605 packet -> options,
606 state -> options,
607 &lease -> scope, oc, MDL))
608 bp -> data [2] = 1;
609 else
610 bp -> data [2] = 0;
611 if (!save_option_buffer (&fqdn_universe, state -> options,
612 bp, &bp -> data [2], 1,
613 &fqdn_options [FQDN_ENCODED],
615 goto badfqdn;
616 bp -> data [3] = isc_rcode_to_ns (rcode1);
617 if (!save_option_buffer (&fqdn_universe, state -> options,
618 bp, &bp -> data [3], 1,
619 &fqdn_options [FQDN_RCODE1],
621 goto badfqdn;
622 bp -> data [4] = isc_rcode_to_ns (rcode2);
623 if (!save_option_buffer (&fqdn_universe, state -> options,
624 bp, &bp -> data [4], 1,
625 &fqdn_options [FQDN_RCODE2],
627 goto badfqdn;
628 if (ddns_fwd_name.len) {
629 memcpy (&bp -> data [5],
630 ddns_fwd_name.data, ddns_fwd_name.len);
631 if (!save_option_buffer (&fqdn_universe, state -> options,
632 bp, &bp -> data [5],
633 ddns_fwd_name.len,
634 &fqdn_options [FQDN_FQDN],
636 goto badfqdn;
640 badfqdn:
641 out:
643 * Final cleanup.
645 data_string_forget (&ddns_hostname, MDL);
646 data_string_forget (&ddns_domainname, MDL);
647 data_string_forget (&old_ddns_fwd_name, MDL);
648 data_string_forget (&ddns_fwd_name, MDL);
649 data_string_forget (&ddns_rev_name, MDL);
650 data_string_forget (&ddns_dhcid, MDL);
651 if (bp)
652 buffer_dereference (&bp, MDL);
654 return result;
657 int ddns_removals (struct lease *lease)
659 struct data_string ddns_fwd_name;
660 struct data_string ddns_rev_name;
661 struct data_string ddns_dhcid;
662 isc_result_t rcode;
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;
686 resolver_state.retrans = 1;
687 resolver_state.retry = 1;
690 /* We need the fwd name whether we are deleting both records or just
691 the PTR record, so if it's not there, we can't proceed. */
692 if (!find_bound_string (&ddns_fwd_name,
693 lease -> scope, "ddns-fwd-name")) {
694 /* If there's no ddns-fwd-name, look for the client fqdn,
695 in case the client did the update. */
696 if (!find_bound_string (&ddns_fwd_name,
697 lease -> scope, "ddns-client-fqdn"))
698 goto try_rev;
699 client_updated = 1;
700 goto try_rev;
703 /* If the ddns-txt binding isn't there, this isn't an interim
704 or rfc3??? record, so we can't delete the A record using
705 this mechanism, but we can delete the PTR record. */
706 if (!find_bound_string (&ddns_dhcid, lease -> scope, "ddns-txt")) {
707 result = 1;
708 goto try_rev;
712 * Perform removals.
714 if (ddns_fwd_name.len)
715 rcode = ddns_remove_a (&ddns_fwd_name,
716 lease -> ip_addr, &ddns_dhcid);
717 else
718 rcode = ISC_R_SUCCESS;
720 if (rcode == ISC_R_SUCCESS) {
721 result = 1;
722 unset (lease -> scope, "ddns-fwd-name");
723 unset (lease -> scope, "ddns-txt");
724 try_rev:
725 if (find_bound_string (&ddns_rev_name,
726 lease -> scope, "ddns-rev-name")) {
727 if (ddns_remove_ptr(&ddns_rev_name) == NOERROR) {
728 unset (lease -> scope, "ddns-rev-name");
729 if (client_updated)
730 unset (lease -> scope,
731 "ddns-client-fqdn");
732 /* XXX this is to compensate for a bug in
733 XXX 3.0rc8, and should be removed before
734 XXX 3.0pl1. */
735 else if (!ddns_fwd_name.len)
736 unset (lease -> scope, "ddns-text");
737 } else
738 result = 0;
742 data_string_forget (&ddns_fwd_name, MDL);
743 data_string_forget (&ddns_rev_name, MDL);
744 data_string_forget (&ddns_dhcid, MDL);
746 return result;
749 #endif /* NSUPDATE */