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