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