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