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