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