]> git.ipfire.org Git - thirdparty/dhcp.git/blob - server/ddns.c
Added missing bracket (#47779)
[thirdparty/dhcp.git] / server / ddns.c
1 /* ddns.c
2
3 Dynamic DNS updates. */
4
5 /*
6 *
7 * Copyright (c) 2004-2017 by 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 * 950 Charter Street
24 * Redwood City, CA 94063
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 * never reached. update_lease_failed
1289 * calls log_fatal.
1290 */
1291 return(ISC_R_FAILURE);
1292 }
1293 ipv6_pool_dereference(&pool, MDL);
1294 } else {
1295 /* shouldn't get here */
1296 log_fatal("Impossible condition at %s:%d, called from %s:%d.",
1297 MDL, file, line);
1298 }
1299
1300 return(ISC_R_SUCCESS);
1301 }
1302
1303 void
1304 ddns_ptr_add(dhcp_ddns_cb_t *ddns_cb,
1305 isc_result_t eresult)
1306 {
1307 if (eresult == ISC_R_SUCCESS) {
1308 log_info("Added reverse map from %.*s to %.*s",
1309 (int)ddns_cb->rev_name.len,
1310 (const char *)ddns_cb->rev_name.data,
1311 (int)ddns_cb->fwd_name.len,
1312 (const char *)ddns_cb->fwd_name.data);
1313
1314 ddns_update_lease_text(ddns_cb, NULL);
1315 } else {
1316 log_error("Unable to add reverse map from %.*s to %.*s: %s",
1317 (int)ddns_cb->rev_name.len,
1318 (const char *)ddns_cb->rev_name.data,
1319 (int)ddns_cb->fwd_name.len,
1320 (const char *)ddns_cb->fwd_name.data,
1321 isc_result_totext (eresult));
1322 }
1323
1324 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1325 destroy_ddns_cb(ddns_cb, MDL);
1326 /*
1327 * A single DDNS operation may require several calls depending on
1328 * the current state as the prerequisites for the first message
1329 * may not succeed requiring a second operation and potentially
1330 * a ptr operation after that. The commit_leases operation is
1331 * invoked at the end of this set of operations in order to require
1332 * a single write for all of the changes. We call commit_leases
1333 * here rather than immediately after the call to update the lease
1334 * text in order to save any previously written data.
1335 */
1336 commit_leases();
1337 return;
1338 }
1339
1340 /*
1341 * action routine when trying to remove a pointer
1342 * this will be called after the ddns queries have completed
1343 * if we succeeded in removing the pointer we go to the next step (if any)
1344 * if not we cleanup and leave.
1345 */
1346
1347 void
1348 ddns_ptr_remove(dhcp_ddns_cb_t *ddns_cb,
1349 isc_result_t eresult)
1350 {
1351 isc_result_t result = eresult;
1352
1353 switch(eresult) {
1354 case ISC_R_SUCCESS:
1355 log_info("Removed reverse map on %.*s",
1356 (int)ddns_cb->rev_name.len,
1357 (const char *)ddns_cb->rev_name.data);
1358 /* fall through */
1359 case DNS_R_NXRRSET:
1360 case DNS_R_NXDOMAIN:
1361 /* No entry is the same as success.
1362 * Remove the information from the lease and
1363 * continue with any next step */
1364 ddns_update_lease_text(ddns_cb, NULL);
1365
1366 /* trigger any add operation */
1367 result = ISC_R_SUCCESS;
1368 #if defined (DEBUG_DNS_UPDATES)
1369 log_info("DDNS: removed map or no reverse map to remove %.*s",
1370 (int)ddns_cb->rev_name.len,
1371 (const char *)ddns_cb->rev_name.data);
1372 #endif
1373 break;
1374
1375 default:
1376 log_error("Can't remove reverse map on %.*s: %s",
1377 (int)ddns_cb->rev_name.len,
1378 (const char *)ddns_cb->rev_name.data,
1379 isc_result_totext (eresult));
1380 break;
1381 }
1382
1383 /* If we aren't suppossed to do the next step, set the result
1384 * flag so ddns_fwd_srv_connector won't do much
1385 */
1386 if ((ddns_cb->flags & DDNS_EXECUTE_NEXT) == 0)
1387 result = ISC_R_FAILURE;
1388
1389 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1390 ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, result);
1391 destroy_ddns_cb(ddns_cb, MDL);
1392 return;
1393 }
1394
1395
1396 /*
1397 * If the first query succeeds, the updater can conclude that it
1398 * has added a new name whose only RRs are the A and DHCID RR records.
1399 * The A RR update is now complete (and a client updater is finished,
1400 * while a server might proceed to perform a PTR RR update).
1401 * -- "Interaction between DHCP and DNS"
1402 *
1403 * If the second query succeeds, the updater can conclude that the current
1404 * client was the last client associated with the domain name, and that
1405 * the name now contains the updated A RR. The A RR update is now
1406 * complete (and a client updater is finished, while a server would
1407 * then proceed to perform a PTR RR update).
1408 * -- "Interaction between DHCP and DNS"
1409 *
1410 * If the second query fails with NXRRSET, the updater must conclude
1411 * that the client's desired name is in use by another host. If
1412 * Dual Stack Mixed Mode (DSMM) is enabled and we proceed to a
1413 * third stage forward update attempt specific to DSMM rules. If not,
1414 * then the existing entries are left intact:
1415 *
1416 * At this juncture, the updater can decide (based on some administrative
1417 * configuration outside of the scope of this document) whether to let
1418 * the existing owner of the name keep that name, and to (possibly)
1419 * perform some name disambiguation operation on behalf of the current
1420 * client, or to replace the RRs on the name with RRs that represent
1421 * the current client. If the configured policy allows replacement of
1422 * existing records, the updater submits a query that deletes the
1423 * existing A RR and the existing DHCID RR, adding A and DHCID RRs that
1424 * represent the IP address and client-identity of the new client.
1425 * -- "Interaction between DHCP and DNS"
1426 */
1427
1428 void
1429 ddns_fwd_srv_add2(dhcp_ddns_cb_t *ddns_cb,
1430 isc_result_t eresult)
1431 {
1432 isc_result_t result;
1433 const char *logstr = NULL;
1434 char ddns_address[MAX_ADDRESS_STRING_LEN];
1435
1436 #if defined (DEBUG_DNS_UPDATES)
1437 log_info ("DDNS:ddns_fwd_srv_add2: %s eresult: %d",
1438 dump_ddns_cb(ddns_cb), eresult);
1439 #endif
1440
1441 /* Construct a printable form of the address for logging */
1442 strcpy(ddns_address, piaddr(ddns_cb->address));
1443
1444 switch(eresult) {
1445 case ISC_R_SUCCESS:
1446 log_info("Added new forward map from %.*s to %s",
1447 (int)ddns_cb->fwd_name.len,
1448 (const char *)ddns_cb->fwd_name.data,
1449 ddns_address);
1450
1451 ddns_update_lease_text(ddns_cb, NULL);
1452
1453 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1454 /* if we have zone information get rid of it */
1455 if (ddns_cb->zone != NULL) {
1456 ddns_cb_forget_zone(ddns_cb);
1457 }
1458
1459 ddns_cb->state = DDNS_STATE_ADD_PTR;
1460 ddns_cb->cur_func = ddns_ptr_add;
1461
1462 result = ddns_modify_ptr(ddns_cb, MDL);
1463 if (result == ISC_R_SUCCESS) {
1464 return;
1465 }
1466 }
1467 break;
1468
1469 case DNS_R_YXRRSET:
1470 case DNS_R_YXDOMAIN:
1471 logstr = "DHCID mismatch, belongs to another client.";
1472 break;
1473
1474 case DNS_R_NXDOMAIN:
1475 case DNS_R_NXRRSET:
1476 /* If DSMM is on we need to try forward add3 */
1477 if (ddns_cb->flags & DDNS_DUAL_STACK_MIXED_MODE) {
1478 ddns_cb->state = DDNS_STATE_DSMM_FW_ADD3;
1479 ddns_cb->cur_func = ddns_fwd_srv_add3;
1480
1481 result = ddns_modify_fwd(ddns_cb, MDL);
1482 if (result == ISC_R_SUCCESS) {
1483 return;
1484 }
1485
1486 break;
1487 }
1488
1489 logstr = "Has an address record but no DHCID, not mine.";
1490 break;
1491
1492 default:
1493 logstr = isc_result_totext(eresult);
1494 break;
1495 }
1496
1497 if (logstr != NULL) {
1498 log_error("Forward map from %.*s to %s FAILED: %s",
1499 (int)ddns_cb->fwd_name.len,
1500 (const char *)ddns_cb->fwd_name.data,
1501 ddns_address, logstr);
1502 }
1503
1504 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1505 destroy_ddns_cb(ddns_cb, MDL);
1506 /*
1507 * A single DDNS operation may require several calls depending on
1508 * the current state as the prerequisites for the first message
1509 * may not succeed requiring a second operation and potentially
1510 * a ptr operation after that. The commit_leases operation is
1511 * invoked at the end of this set of operations in order to require
1512 * a single write for all of the changes. We call commit_leases
1513 * here rather than immediately after the call to update the lease
1514 * text in order to save any previously written data.
1515 */
1516 commit_leases();
1517 return;
1518 }
1519
1520 void
1521 ddns_fwd_srv_add1(dhcp_ddns_cb_t *ddns_cb,
1522 isc_result_t eresult)
1523 {
1524 isc_result_t result;
1525 char ddns_address[MAX_ADDRESS_STRING_LEN];
1526
1527 #if defined (DEBUG_DNS_UPDATES)
1528 log_info ("DDNS: ddns_fwd_srv_add1: %s eresult: %d",
1529 dump_ddns_cb(ddns_cb), eresult);
1530 #endif
1531
1532 /* Construct a printable form of the address for logging */
1533 strcpy(ddns_address, piaddr(ddns_cb->address));
1534
1535 switch(eresult) {
1536 case ISC_R_SUCCESS:
1537 log_info ("Added new forward map from %.*s to %s",
1538 (int)ddns_cb->fwd_name.len,
1539 (const char *)ddns_cb->fwd_name.data,
1540 ddns_address);
1541
1542 ddns_update_lease_text(ddns_cb, NULL);
1543
1544 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1545 /* if we have zone information get rid of it */
1546 if (ddns_cb->zone != NULL) {
1547 ddns_cb_forget_zone(ddns_cb);
1548 }
1549
1550 ddns_cb->state = DDNS_STATE_ADD_PTR;
1551 ddns_cb->cur_func = ddns_ptr_add;
1552
1553 result = ddns_modify_ptr(ddns_cb, MDL);
1554 if (result == ISC_R_SUCCESS) {
1555 return;
1556 }
1557 }
1558 break;
1559
1560 case DNS_R_YXDOMAIN:
1561 /* we can reuse the zone information */
1562 ddns_cb->state = DDNS_STATE_ADD_FW_YXDHCID;
1563 ddns_cb->cur_func = ddns_fwd_srv_add2;
1564
1565 result = ddns_modify_fwd(ddns_cb, MDL);
1566 if (result == ISC_R_SUCCESS) {
1567 return;
1568 }
1569 break;
1570 default:
1571 log_error ("Unable to add forward map from %.*s to %s: %s",
1572 (int)ddns_cb->fwd_name.len,
1573 (const char *)ddns_cb->fwd_name.data,
1574 ddns_address,
1575 isc_result_totext (eresult));
1576 break;
1577 }
1578
1579 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1580 destroy_ddns_cb(ddns_cb, MDL);
1581 /*
1582 * A single DDNS operation may require several calls depending on
1583 * the current state as the prerequisites for the first message
1584 * may not succeed requiring a second operation and potentially
1585 * a ptr operation after that. The commit_leases operation is
1586 * invoked at the end of this set of operations in order to require
1587 * a single write for all of the changes. We call commit_leases
1588 * here rather than immediately after the call to update the lease
1589 * text in order to save any previously written data.
1590 */
1591 commit_leases();
1592 return;
1593 }
1594
1595 /*
1596 * This action routine is invoked after the DSMM third add stage is
1597 * attempted. If we succeeded we attempt to update the reverse DNS,
1598 * if not we cleanup and leave.
1599 */
1600 void
1601 ddns_fwd_srv_add3(dhcp_ddns_cb_t *ddns_cb,
1602 isc_result_t eresult)
1603 {
1604 isc_result_t result;
1605 const char *logstr = NULL;
1606 char ddns_address[MAX_ADDRESS_STRING_LEN+1];
1607
1608 #if defined (DEBUG_DNS_UPDATES)
1609 log_info ("DDNS: ddns_fwd_srv_add3: %s eresult: %d",
1610 dump_ddns_cb(ddns_cb), eresult);
1611 #endif
1612
1613 /* Construct a printable form of the address for logging */
1614 memset(ddns_address, 0x0, sizeof(ddns_address));
1615 strncpy(ddns_address, piaddr(ddns_cb->address),
1616 sizeof(ddns_address) - 1);
1617
1618 switch(eresult) {
1619 case ISC_R_SUCCESS:
1620 log_info("Added new forward map from %.*s to %s",
1621 (int)ddns_cb->fwd_name.len,
1622 (const char *)ddns_cb->fwd_name.data,
1623 ddns_address);
1624
1625 ddns_update_lease_text(ddns_cb, NULL);
1626
1627 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1628 /* if we have zone information get rid of it */
1629 if (ddns_cb->zone != NULL) {
1630 ddns_cb_forget_zone(ddns_cb);
1631 }
1632
1633 ddns_cb->state = DDNS_STATE_ADD_PTR;
1634 ddns_cb->cur_func = ddns_ptr_add;
1635
1636 result = ddns_modify_ptr(ddns_cb, MDL);
1637 if (result == ISC_R_SUCCESS) {
1638 return;
1639 }
1640 }
1641 break;
1642
1643 case DNS_R_YXRRSET:
1644 logstr = "an entry that is either static or "
1645 "owned by another client exists.";
1646 break;
1647
1648 case DNS_R_NXRRSET:
1649 logstr = "static entry of the other protocol type exists.";
1650 break;
1651
1652 default:
1653 logstr = isc_result_totext(eresult);
1654 break;
1655 }
1656
1657 if (logstr != NULL) {
1658 log_error("Forward map from %.*s to %s FAILED: %s",
1659 (int)ddns_cb->fwd_name.len,
1660 (const char *)ddns_cb->fwd_name.data,
1661 ddns_address, logstr);
1662 }
1663
1664 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1665 destroy_ddns_cb(ddns_cb, MDL);
1666 /*
1667 * A single DDNS operation may require several calls depending on
1668 * the current state as the prerequisites for the first message
1669 * may not succeed requiring a second operation and potentially
1670 * a ptr operation after that. The commit_leases operation is
1671 * invoked at the end of this set of operations in order to require
1672 * a single write for all of the changes. We call commit_leases
1673 * here rather than immediately after the call to update the lease
1674 * text in order to save any previously written data.
1675 */
1676 commit_leases();
1677 return;
1678 }
1679
1680 static void
1681 ddns_fwd_srv_connector(struct lease *lease,
1682 struct iasubopt *lease6,
1683 struct binding_scope **inscope,
1684 dhcp_ddns_cb_t *ddns_cb,
1685 isc_result_t eresult)
1686 {
1687 isc_result_t result = ISC_R_FAILURE;
1688
1689 #if defined (DEBUG_DNS_UPDATES)
1690 log_info ("DDNS: ddns_fwd_srv_connector: %s eresult: %d",
1691 dump_ddns_cb(ddns_cb), eresult);
1692 #endif
1693
1694 if (ddns_cb == NULL) {
1695 /* nothing to do */
1696 return;
1697 }
1698
1699 if (eresult == ISC_R_SUCCESS) {
1700 /*
1701 * If we have updates dispatch as appropriate,
1702 * if not do FQDN binding if desired.
1703 */
1704
1705 if (ddns_cb->flags & DDNS_UPDATE_ADDR) {
1706 ddns_cb->state = DDNS_STATE_ADD_FW_NXDOMAIN;
1707 ddns_cb->cur_func = ddns_fwd_srv_add1;
1708 result = ddns_modify_fwd(ddns_cb, MDL);
1709 } else if ((ddns_cb->flags & DDNS_UPDATE_PTR) &&
1710 (ddns_cb->rev_name.len != 0)) {
1711 ddns_cb->state = DDNS_STATE_ADD_PTR;
1712 ddns_cb->cur_func = ddns_ptr_add;
1713 result = ddns_modify_ptr(ddns_cb, MDL);
1714 } else {
1715 ddns_update_lease_text(ddns_cb, inscope);
1716 }
1717 }
1718
1719
1720 if (result == ISC_R_SUCCESS) {
1721 ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, MDL);
1722 } else {
1723 destroy_ddns_cb(ddns_cb, MDL);
1724 }
1725
1726 return;
1727 }
1728
1729 /*
1730 * If the first query fails, the updater MUST NOT delete the DNS name. It
1731 * may be that the host whose lease on the server has expired has moved
1732 * to another network and obtained a lease from a different server,
1733 * which has caused the client's A RR to be replaced. It may also be
1734 * that some other client has been configured with a name that matches
1735 * the name of the DHCP client, and the policy was that the last client
1736 * to specify the name would get the name. In this case, the DHCID RR
1737 * will no longer match the updater's notion of the client-identity of
1738 * the host pointed to by the DNS name.
1739 * -- "Interaction between DHCP and DNS"
1740 */
1741
1742 void
1743 ddns_fwd_srv_rem2(dhcp_ddns_cb_t *ddns_cb,
1744 isc_result_t eresult)
1745 {
1746 #if defined (DEBUG_DNS_UPDATES)
1747 log_info ("DDNS: ddns_fwd_srv_rem2: %s eresult: %d",
1748 dump_ddns_cb(ddns_cb), eresult);
1749 #endif
1750
1751 /*
1752 * To get here we have already managed to remove the A/AAAA
1753 * record and are trying to remove the DHCID/TXT record as well.
1754 * On success (removed DHCID/TXT) or YXRRSET (DHCID/TXT still in
1755 * use by something else) we clean up the lease.
1756 * On some other error we don't clean up the lease and hope that
1757 * if we try this again it will work. An example would be if we
1758 * got a timeout as the DNS server halted between the first and
1759 * second steps. The DNS server would still have the DHCID/TXT
1760 * and we would like to remove that in the future.
1761 *
1762 * On success set the EXECUTE_NEXT flag which triggers any
1763 * add that is next in the chain.
1764 */
1765 if ((eresult == ISC_R_SUCCESS) ||
1766 (eresult == DNS_R_YXRRSET)) {
1767 ddns_update_lease_text(ddns_cb, NULL);
1768 eresult = ISC_R_SUCCESS;
1769 }
1770
1771 /* Do the next operation */
1772 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1773 /* if we have zone information get rid of it */
1774 if (ddns_cb->zone != NULL) {
1775 ddns_cb_forget_zone(ddns_cb);
1776 }
1777
1778 ddns_cb->state = DDNS_STATE_REM_PTR;
1779 ddns_cb->cur_func = ddns_ptr_remove;
1780 if (eresult == ISC_R_SUCCESS)
1781 ddns_cb->flags |= DDNS_EXECUTE_NEXT;
1782
1783 eresult = ddns_modify_ptr(ddns_cb, MDL);
1784 if (eresult == ISC_R_SUCCESS) {
1785 return;
1786 }
1787 }
1788
1789 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1790 ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult);
1791 destroy_ddns_cb(ddns_cb, MDL);
1792 return;
1793 }
1794
1795
1796 /*
1797 * First action routine when trying to remove a fwd
1798 * this will be called after the ddns queries have completed
1799 * if we succeeded in removing the fwd we go to the next step (if any)
1800 * if not we cleanup and leave.
1801 */
1802
1803 void
1804 ddns_fwd_srv_rem1(dhcp_ddns_cb_t *ddns_cb,
1805 isc_result_t eresult)
1806 {
1807 isc_result_t result = eresult;
1808 char ddns_address[MAX_ADDRESS_STRING_LEN];
1809
1810 #if defined (DEBUG_DNS_UPDATES)
1811 log_info ("DDNS: ddns_fwd_srv_rem1: %s eresult: %d",
1812 dump_ddns_cb(ddns_cb), eresult);
1813 #endif
1814
1815 switch(eresult) {
1816 case ISC_R_SUCCESS:
1817 /* Construct a printable form of the address for logging */
1818 strcpy(ddns_address, piaddr(ddns_cb->address));
1819 log_info("Removed forward map from %.*s to %s",
1820 (int)ddns_cb->fwd_name.len,
1821 (const char*)ddns_cb->fwd_name.data,
1822 ddns_address);
1823
1824 /* Do the second step of the FWD removal */
1825 ddns_cb->state = DDNS_STATE_REM_FW_NXRR;
1826 ddns_cb->cur_func = ddns_fwd_srv_rem2;
1827 result = ddns_modify_fwd(ddns_cb, MDL);
1828 if (result == ISC_R_SUCCESS) {
1829 return;
1830 }
1831 break;
1832
1833 case DNS_R_NXRRSET:
1834 case DNS_R_NXDOMAIN:
1835 /* A result of not found means rem1 did not find a guard of
1836 * our * type. From this we assume either there are no address
1837 * record(s) of our type to delete or they are unguarded and
1838 * therefore presumed to be static. Either way, we're done
1839 * unless we're in DSMM and ddns-other-guard-is-dynamic is on.
1840 * In which case we need to see if a guard of the other type
1841 * exists, which permits us to delete any address records of
1842 * our type. */
1843 #define DSMM_OGD (DDNS_DUAL_STACK_MIXED_MODE | \
1844 DDNS_OTHER_GUARD_IS_DYNAMIC)
1845 if ((ddns_cb->flags & DSMM_OGD) == DSMM_OGD) {
1846 ddns_cb->state = DDNS_STATE_REM_FW_DSMM_OTHER;
1847 ddns_cb->cur_func = ddns_fwd_srv_rem2;
1848 result = ddns_modify_fwd(ddns_cb, MDL);
1849 if (result == ISC_R_SUCCESS) {
1850 return;
1851 }
1852 break;
1853 }
1854
1855 ddns_update_lease_text(ddns_cb, NULL);
1856
1857 #if defined (DEBUG_DNS_UPDATES)
1858 log_info("DDNS: no forward map to remove. %p", ddns_cb);
1859 #endif
1860 /* Trigger the add operation */
1861 eresult = ISC_R_SUCCESS;
1862
1863 /* Fall through */
1864 default:
1865
1866 /* We do the remove operation in most cases
1867 * but we don't want to continue with adding a forward
1868 * record if the forward removal had issues so we
1869 * check the eresult and set the EXECUTE_NEXT flag on
1870 * success.
1871 */
1872
1873 /* Do the remove operation */
1874 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1875 /* if we have zone information get rid of it */
1876 if (ddns_cb->zone != NULL) {
1877 ddns_cb_forget_zone(ddns_cb);
1878 }
1879
1880 ddns_cb->state = DDNS_STATE_REM_PTR;
1881 ddns_cb->cur_func = ddns_ptr_remove;
1882 if (eresult == ISC_R_SUCCESS)
1883 ddns_cb->flags |= DDNS_EXECUTE_NEXT;
1884
1885 result = ddns_modify_ptr(ddns_cb, MDL);
1886 if (result == ISC_R_SUCCESS) {
1887 return;
1888 }
1889 }
1890 break;
1891 }
1892
1893 ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1894 ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult);
1895 destroy_ddns_cb(ddns_cb, MDL);
1896 }
1897
1898 /*%<
1899 * Remove relevant entries from DNS.
1900 *
1901 * \li lease - lease to start with if this is for v4
1902 *
1903 * \li lease6 - lease to start with if this is for v6
1904 *
1905 * \li add_ddns_cb - control block for additional DDNS work. This
1906 * is used when the code is going to add a DDNS entry after removing
1907 * the current entry.
1908 *
1909 * \li active - indication about the status of the lease. It is
1910 * ISC_TRUE if the lease is still active, and FALSE if the lease
1911 * is inactive. This is used to indicate if the lease is inactive or going
1912 * to inactive so we can avoid trying to update the lease with cb pointers
1913 * and text information if it isn't useful.
1914 *
1915 * Returns
1916 * \li #ISC_R_FAILURE - badness occurred and we weren't able to do what was wanted
1917 * \li #ISC_R_SUCCESS - we were able to do stuff but it's in progress
1918 *
1919 * in both cases any additional block has been passed on to it's handler
1920 */
1921
1922 isc_result_t
1923 ddns_removals(struct lease *lease,
1924 struct iasubopt *lease6,
1925 dhcp_ddns_cb_t *add_ddns_cb,
1926 isc_boolean_t active)
1927 {
1928 isc_result_t rcode, execute_add = ISC_R_FAILURE;
1929 struct binding_scope **scope = NULL;
1930 isc_result_t result = ISC_R_FAILURE;
1931 dhcp_ddns_cb_t *ddns_cb = NULL;
1932 struct data_string leaseid;
1933
1934 #if defined (DEBUG_DNS_UPDATES)
1935 log_info ("DDNS: ddns_removals: %s",
1936 dump_ddns_cb(add_ddns_cb));
1937 #endif
1938
1939 /*
1940 * See if we need to cancel an outstanding request. Mostly this is
1941 * used to handle the case where this routine is called twice for
1942 * the same release or abandon event.
1943 *
1944 * When called from the dns code as part of an update request
1945 * (add_ddns_cb != NULL) any outstanding requests will have already
1946 * been cancelled.
1947 *
1948 * If the new request is just a removal and we have an outstanding
1949 * request we have several options:
1950 *
1951 * - we are doing an update or we are doing a removal and the active
1952 * flag has changed from TRUE to FALSE. In these cases we need to
1953 * cancel the old request and start the new one.
1954 *
1955 * - other wise we are doing a removal with the active flag unchanged.
1956 * In this case we can let the current removal continue and do not need
1957 * to start a new one. If the old request included an update to be
1958 * done after the removal we need to kill the update part of the
1959 * request.
1960 */
1961
1962 if (add_ddns_cb == NULL) {
1963 if ((lease != NULL) && (lease->ddns_cb != NULL)) {
1964 ddns_cb = lease->ddns_cb;
1965
1966 /*
1967 * Is the old request an update or did the
1968 * the active flag change?
1969 */
1970 if (((ddns_cb->state == DDNS_STATE_ADD_PTR) ||
1971 (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) ||
1972 (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) ||
1973 ((active == ISC_FALSE) &&
1974 ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) {
1975 /* Cancel the current request */
1976 ddns_cancel(lease->ddns_cb, MDL);
1977 lease->ddns_cb = NULL;
1978 } else {
1979 /* Remvoval, check and remove updates */
1980 if (ddns_cb->next_op != NULL) {
1981 destroy_ddns_cb(ddns_cb->next_op, MDL);
1982 ddns_cb->next_op = NULL;
1983 }
1984 #if defined (DEBUG_DNS_UPDATES)
1985 log_info("DDNS %s(%d): removal already in "
1986 "progress new ddns_cb=%p",
1987 MDL, ddns_cb);
1988 #endif
1989 return (ISC_R_SUCCESS);
1990 }
1991 } else if ((lease6 != NULL) && (lease6->ddns_cb != NULL)) {
1992 ddns_cb = lease6->ddns_cb;
1993
1994 /*
1995 * Is the old request an update or did the
1996 * the active flag change?
1997 */
1998 if (((ddns_cb->state == DDNS_STATE_ADD_PTR) ||
1999 (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) ||
2000 (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) ||
2001 ((active == ISC_FALSE) &&
2002 ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) {
2003 /* Cancel the current request */
2004 ddns_cancel(lease6->ddns_cb, MDL);
2005 lease6->ddns_cb = NULL;
2006 } else {
2007 /* Remvoval, check and remove updates */
2008 if (ddns_cb->next_op != NULL) {
2009 destroy_ddns_cb(ddns_cb->next_op, MDL);
2010 ddns_cb->next_op = NULL;
2011 }
2012 #if defined (DEBUG_DNS_UPDATES)
2013 log_info("DDNS %s(%d): removal already in "
2014 "progress new ddns_cb=%p",
2015 MDL, ddns_cb);
2016 #endif
2017 return (ISC_R_SUCCESS);
2018 }
2019 }
2020 ddns_cb = NULL;
2021 }
2022
2023 /* allocate our control block */
2024 ddns_cb = ddns_cb_alloc(MDL);
2025 if (ddns_cb == NULL) {
2026 goto cleanup;
2027 }
2028
2029 /* Set the conflict detection flags based on global configuration */
2030 copy_conflict_flags(&ddns_cb->flags, ddns_conflict_mask);
2031
2032 /*
2033 * For v4 we flag static leases so we don't try
2034 * and manipulate the lease later. For v6 we don't
2035 * get static leases and don't need to flag them.
2036 */
2037 if (lease != NULL) {
2038 scope = &(lease->scope);
2039 ddns_cb->address = lease->ip_addr;
2040 if (lease->flags & STATIC_LEASE)
2041 ddns_cb->flags |= DDNS_STATIC_LEASE;
2042 } else if (lease6 != NULL) {
2043 scope = &(lease6->scope);
2044 memcpy(&ddns_cb->address.iabuf, lease6->addr.s6_addr, 16);
2045 ddns_cb->address.len = 16;
2046 } else
2047 goto cleanup;
2048
2049 /*
2050 * Set the flag bit if the lease is active, that is it isn't
2051 * expired or released. This is used to determine if we need
2052 * to update the scope information for both v4 and v6 and
2053 * the lease information for v6 when the response
2054 * from the DNS code is processed.
2055 */
2056 if (active == ISC_TRUE) {
2057 ddns_cb->flags |= DDNS_ACTIVE_LEASE;
2058 }
2059
2060 /* No scope implies that DDNS has not been performed for this lease. */
2061 if (*scope == NULL)
2062 goto cleanup;
2063
2064 if ((ddns_update_style != DDNS_UPDATE_STYLE_STANDARD) &&
2065 (ddns_update_style != DDNS_UPDATE_STYLE_INTERIM))
2066 goto cleanup;
2067
2068 /* Assume that we are removing both records */
2069 ddns_cb->flags |= DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR;
2070
2071 /* and that we want to do the add call */
2072 execute_add = ISC_R_SUCCESS;
2073
2074 /*
2075 * Look up stored names.
2076 */
2077
2078 /*
2079 * Find the fwd name and copy it to the control block. If we don't
2080 * have it we can't delete the fwd record but we can still try to
2081 * remove the ptr record and cleanup the lease information if the
2082 * client did the fwd update.
2083 */
2084 if (!find_bound_string(&ddns_cb->fwd_name, *scope, "ddns-fwd-name")) {
2085 /* don't try and delete the A, or do the add */
2086 ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
2087 execute_add = ISC_R_FAILURE;
2088
2089 /* Check if client did update */
2090 if (find_bound_string(&ddns_cb->fwd_name, *scope,
2091 "ddns-client-fqdn")) {
2092 ddns_cb->flags |= DDNS_CLIENT_DID_UPDATE;
2093 }
2094 }
2095
2096 /*
2097 * Find the txt or dhcid tag and copy it to the control block. If we
2098 * don't have one this isn't an interim or standard record so we can't
2099 * delete the A record using this mechanism but we can delete the ptr
2100 * record. In this case we will attempt to do any requested next step.
2101 */
2102 memset(&leaseid, 0, sizeof(leaseid));
2103 if (find_bound_string (&leaseid, *scope, ddns_standard_tag)) {
2104 /* We have a standard tag */
2105 ddns_cb->lease_tag = ddns_standard_tag;
2106 ddns_cb->dhcid_class = dns_rdatatype_dhcid;
2107 ddns_cb->other_dhcid_class = dns_rdatatype_txt;
2108 data_string_copy(&ddns_cb->dhcid, &leaseid, MDL);
2109 data_string_forget(&leaseid, MDL);
2110 } else if (find_bound_string (&leaseid, *scope, ddns_interim_tag)) {
2111 /* we have an interim tag */
2112 ddns_cb->lease_tag = ddns_interim_tag;
2113 ddns_cb->dhcid_class = dns_rdatatype_txt;
2114 ddns_cb->other_dhcid_class = dns_rdatatype_dhcid;
2115 if (dhcid_fromlease(&ddns_cb->dhcid, &leaseid) !=
2116 ISC_R_SUCCESS) {
2117 /* We couldn't convert the dhcid from the lease
2118 * version to the dns version. We can't delete
2119 * the A record but can continue to the ptr
2120 */
2121 ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
2122 }
2123 data_string_forget(&leaseid, MDL);
2124 } else {
2125 ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
2126 }
2127
2128 /*
2129 * Find the rev name and copy it to the control block. If we don't
2130 * have it we can't get rid of it but we can try to remove the fwd
2131 * pointer if desired.
2132 */
2133 if (!find_bound_string(&ddns_cb->rev_name, *scope, "ddns-rev-name")) {
2134 ddns_cb->flags &= ~DDNS_UPDATE_PTR;
2135 }
2136
2137
2138 /*
2139 * If we have a second control block for doing an add
2140 * after the remove finished attach it to our control block.
2141 */
2142 ddns_cb->next_op = add_ddns_cb;
2143
2144 /*
2145 * Now that we've collected the information we can try to process it.
2146 * If necessary we call an appropriate routine to send a message and
2147 * provide it with an action routine to run on the control block given
2148 * the results of the message. We have three entry points from here,
2149 * one for removing the A record, the next for removing the PTR and
2150 * the third for doing any requested add.
2151 */
2152 if ((ddns_cb->flags & DDNS_UPDATE_ADDR) != 0) {
2153 if (ddns_cb->fwd_name.len != 0) {
2154 ddns_cb->state = DDNS_STATE_REM_FW_YXDHCID;
2155 ddns_cb->cur_func = ddns_fwd_srv_rem1;
2156
2157 rcode = ddns_modify_fwd(ddns_cb, MDL);
2158 if (rcode == ISC_R_SUCCESS) {
2159 ddns_update_lease_ptr(lease, lease6, ddns_cb,
2160 ddns_cb, MDL);
2161 return (ISC_R_SUCCESS);
2162 }
2163
2164 /*
2165 * We weren't able to process the request tag the
2166 * add so we won't execute it.
2167 */
2168 execute_add = ISC_R_FAILURE;
2169 goto cleanup;
2170 }
2171 else {
2172 /*remove info from scope */
2173 unset(*scope, "ddns-fwd-name");
2174 unset(*scope, ddns_cb->lease_tag);
2175 }
2176 }
2177
2178 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
2179 ddns_cb->state = DDNS_STATE_REM_PTR;
2180 ddns_cb->cur_func = ddns_ptr_remove;
2181 ddns_cb->flags |= DDNS_EXECUTE_NEXT;
2182
2183 /*
2184 * if execute add isn't success remove the control block so
2185 * it won't be processed when the remove completes. We
2186 * also arrange to clean it up and get rid of it.
2187 */
2188 if (execute_add != ISC_R_SUCCESS) {
2189 ddns_cb->next_op = NULL;
2190 ddns_fwd_srv_connector(lease, lease6, scope,
2191 add_ddns_cb, execute_add);
2192 add_ddns_cb = NULL;
2193 }
2194 else {
2195 result = ISC_R_SUCCESS;
2196 }
2197
2198 rcode = ddns_modify_ptr(ddns_cb, MDL);
2199 if (rcode == ISC_R_SUCCESS) {
2200 ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb,
2201 MDL);
2202 return (result);
2203 }
2204
2205 /* We weren't able to process the request tag the
2206 * add so we won't execute it */
2207 execute_add = ISC_R_FAILURE;
2208 goto cleanup;
2209 }
2210
2211 cleanup:
2212 /*
2213 * We've gotten here because we didn't need to send a message or
2214 * we failed when trying to do so. We send the additional cb
2215 * off to handle sending and/or cleanup and cleanup anything
2216 * we allocated here.
2217 */
2218 ddns_fwd_srv_connector(lease, lease6, scope, add_ddns_cb, execute_add);
2219 if (ddns_cb != NULL)
2220 destroy_ddns_cb(ddns_cb, MDL);
2221
2222 return (result);
2223 }
2224
2225 /* Convenience function for setting flag bits in a mask */
2226 void set_flag (u_int16_t *flags,
2227 u_int16_t flag,
2228 u_int16_t value) {
2229 if (flags) {
2230 if (value) {
2231 *flags |= flag;
2232 } else {
2233 *flags &= ~flag;
2234 }
2235 }
2236 }
2237
2238 /*
2239 * Convenience function which replicates the conflict flags set in one
2240 * mask to another, while preserving all other flags.
2241 */
2242 void copy_conflict_flags(u_int16_t *target,
2243 u_int16_t source) {
2244 if (target) {
2245 /* Preserve non conflict flags */
2246 *target &= ~CONFLICT_BITS;
2247
2248 /* Enable conflict flags per source */
2249 *target |= source & CONFLICT_BITS;
2250 }
2251 }
2252
2253 /*
2254 * Given an option_state, create a mask of conflict detection flags based
2255 * on the appropriate configuration parameters within the option state.
2256 */
2257 u_int16_t
2258 get_conflict_mask(struct option_state *options) {
2259
2260 int ddns_update_conflict_detection = 1; /* default on */
2261 int ddns_dual_stack_mixed_mode = 0; /* default off */
2262 int ddns_guard_id_must_match = 1; /* default on */
2263 int ddns_other_guard_is_dynamic = 0; /* default off */
2264 struct option_cache *oc = NULL;
2265
2266 u_int16_t mask = 0;
2267 oc = lookup_option(&server_universe, options, SV_DDNS_CONFLICT_DETECT);
2268 if (oc) {
2269 ddns_update_conflict_detection =
2270 evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options,
2271 NULL, &global_scope, oc, MDL);
2272 }
2273
2274 set_flag(&mask, DDNS_CONFLICT_DETECTION,
2275 ddns_update_conflict_detection);
2276
2277 if (!ddns_update_conflict_detection) {
2278 #if defined (DEBUG_DNS_UPDATES)
2279 log_info ("DDNS conflict detection: off");
2280 #endif
2281 /* Turn the rest of the conflict related flags off */
2282 set_flag(&mask, DDNS_DUAL_STACK_MIXED_MODE, 0);
2283 set_flag(&mask, DDNS_GUARD_ID_MUST_MATCH, 0);
2284 set_flag(&mask, DDNS_OTHER_GUARD_IS_DYNAMIC, 0);
2285 return (mask);
2286 }
2287
2288 // Get the values
2289 oc = lookup_option(&server_universe, options,
2290 SV_DDNS_DUAL_STACK_MIXED_MODE);
2291 if (oc) {
2292 ddns_dual_stack_mixed_mode =
2293 evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options,
2294 NULL, &global_scope, oc, MDL);
2295 }
2296
2297 oc = lookup_option(&server_universe, options,
2298 SV_DDNS_GUARD_ID_MUST_MATCH);
2299 if (oc) {
2300 ddns_guard_id_must_match =
2301 evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options,
2302 NULL, &global_scope, oc, MDL);
2303 }
2304
2305 oc = lookup_option(&server_universe, options,
2306 SV_DDNS_OTHER_GUARD_IS_DYNAMIC);
2307 if (oc) {
2308 ddns_other_guard_is_dynamic =
2309 evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options,
2310 NULL, &global_scope, oc, MDL);
2311 }
2312
2313 // Set the flags
2314 set_flag(&mask, DDNS_DUAL_STACK_MIXED_MODE,
2315 ddns_dual_stack_mixed_mode);
2316
2317 set_flag(&mask, DDNS_GUARD_ID_MUST_MATCH,
2318 ddns_guard_id_must_match);
2319
2320 set_flag(&mask, DDNS_OTHER_GUARD_IS_DYNAMIC,
2321 ddns_other_guard_is_dynamic);
2322
2323 #if defined (DEBUG_DNS_UPDATES)
2324 log_info ("DDNS conflict behavior:\n"
2325 "\tddns-update-style: %s\n"
2326 "\tupdate-conflict-detection: %d\n"
2327 "\tddns-dual-stack-mixed-mode: %d\n"
2328 "\tddns-guard-id-must-match %d\n"
2329 "\tddns-other-guard-is-dynamic: %d\n",
2330 ddns_styles_values[ddns_update_style].name,
2331 ddns_update_conflict_detection,
2332 ddns_dual_stack_mixed_mode,
2333 ddns_guard_id_must_match,
2334 ddns_other_guard_is_dynamic);
2335 #endif
2336 return (mask);
2337 }
2338
2339 #if defined (DEBUG_DNS_UPDATES)
2340 /* Type used for creating lists of function pointers and their names */
2341 typedef struct {
2342 void *ptr;
2343 char *name;
2344 } LabeledPtr;
2345
2346 /* Returns the name of the function referred to by the given address */
2347 char*
2348 dump_ddns_cb_func(void *func) {
2349 static LabeledPtr funcs[] = {
2350 { ddns_ptr_add, "ddns_ptr_add" },
2351 { ddns_fwd_srv_add2, "ddns_fwd_srv_add2" },
2352 { ddns_fwd_srv_add1, "ddns_fwd_srv_add1" },
2353 { ddns_ptr_remove, "ddns_ptr_remove" },
2354 { ddns_fwd_srv_rem2, "ddns_fwd_srv_rem2" },
2355 { ddns_fwd_srv_rem1, "ddns_fwd_srv_rem1" },
2356 { ddns_fwd_srv_add3, "ddns_fwd_srv_adde" },
2357 { NULL, "unknown" }
2358 };
2359
2360 LabeledPtr* lp = funcs;
2361 if (!func) {
2362 return ("<null>");
2363 }
2364
2365 while ((lp->ptr) && (lp->ptr != func)) {
2366 ++lp;
2367 }
2368
2369 return (lp->name);
2370 }
2371
2372 /* Dumps basic control block info to the log */
2373 char*
2374 dump_ddns_cb (dhcp_ddns_cb_t *ddns_cb) {
2375 static char output_buf[4096];
2376 if (!ddns_cb) {
2377 return ("<ddns_cb is null>");
2378 }
2379
2380 sprintf (output_buf, "ddns_cb: %p flags: %x state: %s cur_func: %s",
2381 ddns_cb, ddns_cb->flags,
2382 ddns_state_name(ddns_cb->state),
2383 dump_ddns_cb_func(ddns_cb->cur_func));
2384
2385 return(output_buf);
2386 }
2387 #endif /* DEBUG_DNS_UPDATES */
2388
2389 #endif /* NSUPDATE */