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