]> git.ipfire.org Git - thirdparty/dhcp.git/blame - server/ddns.c
Allow trace output files (-tf option) to be overwritten, rather than
[thirdparty/dhcp.git] / server / ddns.c
CommitLineData
b992d7e2
DN
1/* ddns.c
2
3 Dynamic DNS updates. */
4
5/*
4d2eaafb 6 * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
98311e4b 7 * Copyright (c) 2000-2003 by Internet Software Consortium
b992d7e2 8 *
98311e4b
DH
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
b992d7e2 12 *
98311e4b
DH
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
b992d7e2 20 *
98311e4b
DH
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
b992d7e2 26 *
98311e4b 27 * This software has been donated to Internet Systems Consortium
0598e123
TL
28 * by Damien Neil of Nominum, Inc.
29 *
98311e4b 30 * To learn more about Internet Systems Consortium, see
0598e123 31 * ``http://www.isc.org/''. To learn more about Nominum, Inc., see
b992d7e2
DN
32 * ``http://www.nominum.com''.
33 */
34
35#ifndef lint
36static char copyright[] =
4d2eaafb 37"$Id: ddns.c,v 1.25 2007/04/03 16:46:03 dhankins Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n";
b992d7e2
DN
38#endif /* not lint */
39
40#include "dhcpd.h"
37ee426a 41#include "dst/md5.h"
ec64b462 42#include "minires/minires.h"
b992d7e2
DN
43
44#ifdef NSUPDATE
45
0598e123
TL
46/* DN: No way of checking that there is enough space in a data_string's
47 buffer. Be certain to allocate enough!
385fcb27 48 TL: This is why the expression evaluation code allocates a *new*
0598e123 49 data_string. :') */
b992d7e2
DN
50static void data_string_append (struct data_string *ds1,
51 struct data_string *ds2)
52{
53 memcpy (ds1 -> buffer -> data + ds1 -> len,
54 ds2 -> data,
55 ds2 -> len);
56 ds1 -> len += ds2 -> len;
57}
58
5b77c910
TL
59static isc_result_t ddns_update_ptr (struct data_string *ddns_fwd_name,
60 struct data_string *ddns_rev_name,
61 unsigned long ttl)
b992d7e2 62{
385fcb27 63 ns_updque updqueue;
b992d7e2 64 ns_updrec *updrec;
c2318c20 65 isc_result_t result = ISC_R_UNEXPECTED;
b992d7e2
DN
66
67 /*
68 * The DHCP server submits a DNS query which deletes all of the PTR RRs
69 * associated with the lease IP address, and adds a PTR RR whose data
70 * is the client's (possibly disambiguated) host name. The server also
71 * adds a DHCID RR specified in Section 4.3.
72 * -- "Interaction between DHCP and DNS"
73 */
74
385fcb27 75 ISC_LIST_INIT (updqueue);
b992d7e2
DN
76
77 /*
78 * Delete all PTR RRs.
79 */
478028e7
TL
80 updrec = minires_mkupdrec (S_UPDATE,
81 (const char *)ddns_rev_name -> data,
b992d7e2 82 C_IN, T_PTR, 0);
ec64b462
TL
83 if (!updrec) {
84 result = ISC_R_NOMEMORY;
85 goto error;
86 }
b992d7e2 87
478028e7
TL
88 updrec -> r_data = (unsigned char *)0;
89 updrec -> r_size = 0;
b992d7e2
DN
90 updrec -> r_opcode = DELETE;
91
385fcb27 92 ISC_LIST_APPEND (updqueue, updrec, r_link);
b992d7e2 93
b992d7e2
DN
94 /*
95 * Add PTR RR.
96 */
478028e7
TL
97 updrec = minires_mkupdrec (S_UPDATE,
98 (const char *)ddns_rev_name -> data,
b992d7e2 99 C_IN, T_PTR, ttl);
ec64b462
TL
100 if (!updrec) {
101 result = ISC_R_NOMEMORY;
102 goto error;
103 }
b992d7e2 104
ee83afae 105 updrec -> r_data = ddns_fwd_name -> data;
478028e7 106 updrec -> r_size = ddns_fwd_name -> len;
b992d7e2
DN
107 updrec -> r_opcode = ADD;
108
385fcb27 109 ISC_LIST_APPEND (updqueue, updrec, r_link);
b992d7e2 110
b992d7e2
DN
111 /*
112 * Attempt to perform the update.
113 */
385fcb27 114 result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
98311e4b 115#if defined (DEBUG)
385fcb27 116 print_dns_status ((int)result, &updqueue);
98311e4b
DH
117#endif
118 if (result == ISC_R_SUCCESS) {
119 log_info ("added reverse map from %.*s to %.*s",
120 (int)ddns_rev_name -> len,
121 (const char *)ddns_rev_name -> data,
122 (int)ddns_fwd_name -> len,
123 (const char *)ddns_fwd_name -> data);
124 } else {
125 log_error ("unable to add reverse map from %.*s to %.*s: %s",
126 (int)ddns_rev_name -> len,
127 (const char *)ddns_rev_name -> data,
128 (int)ddns_fwd_name -> len,
129 (const char *)ddns_fwd_name -> data,
130 isc_result_totext (result));
131 }
b992d7e2
DN
132
133 /* Fall through. */
ec64b462 134 error:
b992d7e2 135
385fcb27
TL
136 while (!ISC_LIST_EMPTY (updqueue)) {
137 updrec = ISC_LIST_HEAD (updqueue);
138 ISC_LIST_UNLINK (updqueue, updrec, r_link);
b992d7e2
DN
139 minires_freeupdrec (updrec);
140 }
141
142 return result;
143}
144
145
5b77c910 146static isc_result_t ddns_remove_ptr (struct data_string *ddns_rev_name)
b992d7e2 147{
385fcb27 148 ns_updque updqueue;
b992d7e2 149 ns_updrec *updrec;
ec64b462 150 isc_result_t result;
b992d7e2
DN
151
152 /*
153 * When a lease expires or a DHCP client issues a DHCPRELEASE request,
154 * the DHCP server SHOULD delete the PTR RR that matches the DHCP
155 * binding, if one was successfully added. The server's update query
156 * SHOULD assert that the name in the PTR record matches the name of
157 * the client whose lease has expired or been released.
158 * -- "Interaction between DHCP and DNS"
159 */
160
385fcb27 161 ISC_LIST_INIT (updqueue);
b992d7e2
DN
162
163 /*
ee83afae 164 * Delete the PTR RRset for the leased address.
b992d7e2 165 */
478028e7
TL
166 updrec = minires_mkupdrec (S_UPDATE,
167 (const char *)ddns_rev_name -> data,
b992d7e2 168 C_IN, T_PTR, 0);
ec64b462
TL
169 if (!updrec) {
170 result = ISC_R_NOMEMORY;
171 goto error;
172 }
b992d7e2 173
ee83afae
TL
174 updrec -> r_data = (unsigned char *)0;
175 updrec -> r_size = 0;
b992d7e2
DN
176 updrec -> r_opcode = DELETE;
177
385fcb27 178 ISC_LIST_APPEND (updqueue, updrec, r_link);
b992d7e2 179
b992d7e2
DN
180 /*
181 * Attempt to perform the update.
182 */
385fcb27 183 result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
98311e4b 184#if defined (DEBUG)
385fcb27 185 print_dns_status ((int)result, &updqueue);
98311e4b
DH
186#endif
187 if (result == ISC_R_SUCCESS) {
188 log_info ("removed reverse map on %.*s",
189 (int)ddns_rev_name -> len,
190 (const char *)ddns_rev_name -> data);
191 } else {
192 if (result != ISC_R_NXRRSET && result != ISC_R_NXDOMAIN)
193 log_error ("can't remove reverse map on %.*s: %s",
194 (int)ddns_rev_name -> len,
195 (const char *)ddns_rev_name -> data,
196 isc_result_totext (result));
197 }
198
199 /* Not there is success. */
200 if (result == ISC_R_NXRRSET || result == ISC_R_NXDOMAIN)
201 result = ISC_R_SUCCESS;
b992d7e2
DN
202
203 /* Fall through. */
ec64b462 204 error:
b992d7e2 205
385fcb27
TL
206 while (!ISC_LIST_EMPTY (updqueue)) {
207 updrec = ISC_LIST_HEAD (updqueue);
208 ISC_LIST_UNLINK (updqueue, updrec, r_link);
b992d7e2
DN
209 minires_freeupdrec (updrec);
210 }
211
212 return result;
213}
214
215
216int ddns_updates (struct packet *packet,
ec64b462 217 struct lease *lease, struct lease *old,
b992d7e2
DN
218 struct lease_state *state)
219{
220 unsigned long ddns_ttl = DEFAULT_DDNS_TTL;
221 struct data_string ddns_hostname;
222 struct data_string ddns_domainname;
478028e7 223 struct data_string old_ddns_fwd_name;
b992d7e2
DN
224 struct data_string ddns_fwd_name;
225 struct data_string ddns_rev_name;
b992d7e2
DN
226 struct data_string ddns_dhcid;
227 unsigned len;
b992d7e2
DN
228 struct data_string d1;
229 struct option_cache *oc;
230 int s1, s2;
231 int result = 0;
ec64b462 232 isc_result_t rcode1 = ISC_R_SUCCESS, rcode2 = ISC_R_SUCCESS;
478028e7 233 int server_updates_a = 1;
4d2eaafb 234 int server_updates_ptr = 1;
478028e7 235 struct buffer *bp = (struct buffer *)0;
a396d25f 236 int ignorep = 0, client_ignorep = 0;
b992d7e2 237
5fac73d6
TL
238 if (ddns_update_style != 2)
239 return 0;
240
b992d7e2
DN
241 /* Can only cope with IPv4 addrs at the moment. */
242 if (lease -> ip_addr . len != 4)
243 return 0;
244
57868747 245 memset(&d1, 0, sizeof(d1));
b992d7e2
DN
246 memset (&ddns_hostname, 0, sizeof (ddns_hostname));
247 memset (&ddns_domainname, 0, sizeof (ddns_domainname));
478028e7 248 memset (&old_ddns_fwd_name, 0, sizeof (ddns_fwd_name));
b992d7e2
DN
249 memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name));
250 memset (&ddns_rev_name, 0, sizeof (ddns_rev_name));
b992d7e2
DN
251 memset (&ddns_dhcid, 0, sizeof (ddns_dhcid));
252
478028e7
TL
253 /* If we are allowed to accept the client's update of its own A
254 record, see if the client wants to update its own A record. */
a396d25f
DH
255 if (!(oc = lookup_option(&server_universe, state->options,
256 SV_CLIENT_UPDATES)) ||
257 evaluate_boolean_option_cache(&client_ignorep, packet, lease, NULL,
258 packet->options, state->options,
259 &lease->scope, oc, MDL)) {
478028e7
TL
260 /* If there's no fqdn.no-client-update or if it's
261 nonzero, don't try to use the client-supplied
262 XXX */
ee83afae 263 if (!(oc = lookup_option (&fqdn_universe, packet -> options,
98311e4b 264 FQDN_SERVER_UPDATE)) ||
478028e7
TL
265 evaluate_boolean_option_cache (&ignorep, packet, lease,
266 (struct client_state *)0,
267 packet -> options,
268 state -> options,
269 &lease -> scope, oc, MDL))
270 goto noclient;
e9d45f83
TL
271 /* Win98 and Win2k will happily claim to be willing to
272 update an unqualified domain name. */
273 if (!(oc = lookup_option (&fqdn_universe, packet -> options,
274 FQDN_DOMAINNAME)))
275 goto noclient;
ee83afae 276 if (!(oc = lookup_option (&fqdn_universe, packet -> options,
478028e7 277 FQDN_FQDN)) ||
ee83afae
TL
278 !evaluate_option_cache (&ddns_fwd_name, packet, lease,
279 (struct client_state *)0,
280 packet -> options,
281 state -> options,
282 &lease -> scope, oc, MDL))
478028e7
TL
283 goto noclient;
284 server_updates_a = 0;
285 goto client_updates;
b992d7e2 286 }
478028e7 287 noclient:
98311e4b
DH
288 /* If do-forward-updates is disabled, this basically means don't
289 do an update unless the client is participating, so if we get
290 here and do-forward-updates is disabled, we can stop. */
291 if ((oc = lookup_option (&server_universe, state -> options,
292 SV_DO_FORWARD_UPDATES)) &&
293 !evaluate_boolean_option_cache (&ignorep, packet, lease,
294 (struct client_state *)0,
295 packet -> options,
296 state -> options,
297 &lease -> scope, oc, MDL)) {
298 return 0;
299 }
b992d7e2 300
ec64b462
TL
301 /* If it's a static lease, then don't do the DNS update unless we're
302 specifically configured to do so. If the client asked to do its
303 own update and we allowed that, we don't do this test. */
304 if (lease -> flags & STATIC_LEASE) {
0db87765 305 if (!(oc = lookup_option (&server_universe, state -> options,
ec64b462
TL
306 SV_UPDATE_STATIC_LEASES)) ||
307 !evaluate_boolean_option_cache (&ignorep, packet, lease,
308 (struct client_state *)0,
309 packet -> options,
310 state -> options,
311 &lease -> scope, oc, MDL))
312 return 0;
313 }
314
b992d7e2 315 /*
478028e7 316 * Compute the name for the A record.
b992d7e2 317 */
b992d7e2
DN
318 oc = lookup_option (&server_universe, state -> options,
319 SV_DDNS_HOST_NAME);
320 if (oc)
321 s1 = evaluate_option_cache (&ddns_hostname, packet, lease,
322 (struct client_state *)0,
323 packet -> options,
324 state -> options,
325 &lease -> scope, oc, MDL);
98311e4b
DH
326 else
327 s1 = 0;
b992d7e2
DN
328
329 oc = lookup_option (&server_universe, state -> options,
330 SV_DDNS_DOMAIN_NAME);
331 if (oc)
332 s2 = evaluate_option_cache (&ddns_domainname, packet, lease,
333 (struct client_state *)0,
334 packet -> options,
335 state -> options,
336 &lease -> scope, oc, MDL);
98311e4b
DH
337 else
338 s2 = 0;
b992d7e2
DN
339
340 if (s1 && s2) {
98311e4b
DH
341 if (ddns_hostname.len + ddns_domainname.len > 253) {
342 log_error ("ddns_update: host.domain name too long");
343
344 goto out;
345 }
346
b992d7e2
DN
347 buffer_allocate (&ddns_fwd_name.buffer,
348 ddns_hostname.len + ddns_domainname.len + 2,
349 MDL);
350 if (ddns_fwd_name.buffer) {
351 ddns_fwd_name.data = ddns_fwd_name.buffer -> data;
352 data_string_append (&ddns_fwd_name, &ddns_hostname);
353 ddns_fwd_name.buffer -> data [ddns_fwd_name.len] = '.';
354 ddns_fwd_name.len++;
355 data_string_append (&ddns_fwd_name, &ddns_domainname);
356 ddns_fwd_name.buffer -> data [ddns_fwd_name.len] ='\0';
357 ddns_fwd_name.terminated = 1;
358 }
359 }
478028e7
TL
360 client_updates:
361
362 /* See if there's a name already stored on the lease. */
363 if (find_bound_string (&old_ddns_fwd_name,
364 lease -> scope, "ddns-fwd-name")) {
365 /* If there is, see if it's different. */
366 if (old_ddns_fwd_name.len != ddns_fwd_name.len ||
367 memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data,
368 old_ddns_fwd_name.len)) {
369 /* If the name is different, try to delete
370 the old A record. */
371 if (!ddns_removals (lease))
372 goto out;
373 /* If the delete succeeded, go install the new
374 record. */
375 goto in;
376 }
377
378 /* See if there's a DHCID on the lease. */
379 if (!find_bound_string (&ddns_dhcid,
380 lease -> scope, "ddns-txt")) {
381 /* If there's no DHCID, the update was probably
382 done with the old-style ad-hoc DDNS updates.
383 So if the expiry and release events look like
384 they're the same, run them. This should delete
385 the old DDNS data. */
ec64b462 386 if (old -> on_expiry == old -> on_release) {
478028e7
TL
387 execute_statements ((struct binding_value **)0,
388 (struct packet *)0, lease,
389 (struct client_state *)0,
390 (struct option_state *)0,
391 (struct option_state *)0,
392 &lease -> scope,
ec64b462
TL
393 old -> on_expiry);
394 if (old -> on_expiry)
478028e7 395 executable_statement_dereference
ec64b462
TL
396 (&old -> on_expiry, MDL);
397 if (old -> on_release)
478028e7 398 executable_statement_dereference
ec64b462 399 (&old -> on_release, MDL);
478028e7
TL
400 /* Now, install the DDNS data the new way. */
401 goto in;
402 }
75ab3070
DH
403 } else
404 data_string_forget(&ddns_dhcid, MDL);
478028e7 405
ebd0310b
TL
406 /* See if the administrator wants to do updates even
407 in cases where the update already appears to have been
408 done. */
409 if (!(oc = lookup_option (&server_universe, state -> options,
410 SV_UPDATE_OPTIMIZATION)) ||
411 evaluate_boolean_option_cache (&ignorep, packet, lease,
412 (struct client_state *)0,
413 packet -> options,
414 state -> options,
415 &lease -> scope, oc, MDL)) {
416 result = 1;
417 goto noerror;
418 }
75ab3070
DH
419 /* If there's no "ddns-fwd-name" on the lease record, see if
420 * there's a ddns-client-fqdn indicating a previous client
421 * update (if it changes, we need to adjust the PTR).
422 */
423 } else if (find_bound_string(&old_ddns_fwd_name, lease->scope,
424 "ddns-client-fqdn")) {
98311e4b
DH
425 /* If the name is not different, no need to update
426 the PTR record. */
ee83afae
TL
427 if (old_ddns_fwd_name.len == ddns_fwd_name.len &&
428 !memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data,
98311e4b
DH
429 old_ddns_fwd_name.len) &&
430 (!(oc = lookup_option (&server_universe,
431 state -> options,
432 SV_UPDATE_OPTIMIZATION)) ||
433 evaluate_boolean_option_cache (&ignorep, packet, lease,
434 (struct client_state *)0,
435 packet -> options,
436 state -> options,
437 &lease -> scope, oc,
438 MDL))) {
478028e7
TL
439 goto noerror;
440 }
441 }
442 in:
443
d758ad8c
TL
444 /* If we don't have a name that the client has been assigned, we
445 can just skip all this. */
446 if (!ddns_fwd_name.len)
447 goto out;
448
98311e4b
DH
449 if (ddns_fwd_name.len > 255) {
450 log_error ("client provided fqdn: too long");
451 goto out;
452 }
453
b992d7e2 454 /*
478028e7
TL
455 * Compute the RR TTL.
456 */
457 ddns_ttl = DEFAULT_DDNS_TTL;
478028e7
TL
458 if ((oc = lookup_option (&server_universe, state -> options,
459 SV_DDNS_TTL))) {
460 if (evaluate_option_cache (&d1, packet, lease,
461 (struct client_state *)0,
462 packet -> options,
463 state -> options,
464 &lease -> scope, oc, MDL)) {
465 if (d1.len == sizeof (u_int32_t))
466 ddns_ttl = getULong (d1.data);
467 data_string_forget (&d1, MDL);
468 }
469 }
470
4d2eaafb
DH
471 /* CC: see if we are configured NOT to do reverse ptr updates
472 */
473 if ((oc = lookup_option (&server_universe, state -> options,
474 SV_DO_REVERSE_UPDATES)) &&
475 !evaluate_boolean_option_cache (&ignorep, packet, lease,
476 (struct client_state *)0,
477 packet -> options,
478 state -> options,
479 &lease -> scope, oc, MDL)) {
480 server_updates_ptr = 0;
481 }
478028e7
TL
482
483 /*
484 * Compute the reverse IP name.
b992d7e2
DN
485 */
486 oc = lookup_option (&server_universe, state -> options,
487 SV_DDNS_REV_DOMAIN_NAME);
488 if (oc)
489 s1 = evaluate_option_cache (&d1, packet, lease,
490 (struct client_state *)0,
491 packet -> options,
492 state -> options,
493 &lease -> scope, oc, MDL);
98311e4b
DH
494 else
495 s1 = 0;
496
497 if (s1 && (d1.len > 238)) {
498 log_error ("ddns_update: Calculated rev domain name too long.");
499 s1 = 0;
500 data_string_forget (&d1, MDL);
501 }
502
b992d7e2
DN
503 if (oc && s1) {
504 /* Buffer length:
505 XXX.XXX.XXX.XXX.<ddns-rev-domain-name>\0 */
506 buffer_allocate (&ddns_rev_name.buffer,
507 d1.len + 17, MDL);
508 if (ddns_rev_name.buffer) {
509 ddns_rev_name.data = ddns_rev_name.buffer -> data;
98311e4b
DH
510
511 /* %Audit% Cannot exceed 17 bytes. %2004.06.17,Safe% */
87fec475 512 sprintf ((char *)ddns_rev_name.buffer -> data,
98311e4b
DH
513 "%u.%u.%u.%u.",
514 lease -> ip_addr . iabuf[3] & 0xff,
515 lease -> ip_addr . iabuf[2] & 0xff,
516 lease -> ip_addr . iabuf[1] & 0xff,
517 lease -> ip_addr . iabuf[0] & 0xff);
518
478028e7
TL
519 ddns_rev_name.len =
520 strlen ((const char *)ddns_rev_name.data);
b992d7e2
DN
521 data_string_append (&ddns_rev_name, &d1);
522 ddns_rev_name.buffer -> data [ddns_rev_name.len] ='\0';
523 ddns_rev_name.terminated = 1;
524 }
525
526 data_string_forget (&d1, MDL);
527 }
528
b992d7e2 529 /*
478028e7 530 * If we are updating the A record, compute the DHCID value.
b992d7e2 531 */
478028e7 532 if (server_updates_a) {
d758ad8c
TL
533 if (lease -> uid && lease -> uid_len)
534 result = get_dhcid (&ddns_dhcid,
535 DHO_DHCP_CLIENT_IDENTIFIER,
536 lease -> uid, lease -> uid_len);
537 else
538 result = get_dhcid (&ddns_dhcid, 0,
539 lease -> hardware_addr.hbuf,
540 lease -> hardware_addr.hlen);
541 if (!result)
542 goto badfqdn;
478028e7 543 }
b992d7e2 544
b992d7e2
DN
545 /*
546 * Start the resolver, if necessary.
547 */
548 if (!resolver_inited) {
549 minires_ninit (&resolver_state);
550 resolver_inited = 1;
ec64b462
TL
551 resolver_state.retrans = 1;
552 resolver_state.retry = 1;
b992d7e2
DN
553 }
554
b992d7e2
DN
555 /*
556 * Perform updates.
557 */
3004bebf
DH
558 if (ddns_fwd_name.len && ddns_dhcid.len) {
559 unsigned conflict;
560
561 oc = lookup_option(&server_universe, state->options,
562 SV_DDNS_CONFLICT_DETECT);
563 if (!oc ||
564 evaluate_boolean_option_cache(&ignorep, packet, lease,
565 NULL, packet->options,
566 state->options,
567 &lease->scope, oc, MDL))
568 conflict = 1;
569 else
570 conflict = 0;
571
bdad826f 572 rcode1 = ddns_update_a (&ddns_fwd_name, lease -> ip_addr,
3004bebf
DH
573 &ddns_dhcid, ddns_ttl, 0, conflict);
574 }
75ab3070 575
4d2eaafb 576 if (rcode1 == ISC_R_SUCCESS && server_updates_ptr) {
478028e7 577 if (ddns_fwd_name.len && ddns_rev_name.len)
bdad826f
TL
578 rcode2 = ddns_update_ptr (&ddns_fwd_name,
579 &ddns_rev_name, ddns_ttl);
580 } else
ec64b462 581 rcode2 = rcode1;
b992d7e2 582
ec64b462
TL
583 if (rcode1 == ISC_R_SUCCESS &&
584 (server_updates_a || rcode2 == ISC_R_SUCCESS)) {
478028e7
TL
585 bind_ds_value (&lease -> scope,
586 (server_updates_a
587 ? "ddns-fwd-name" : "ddns-client-fqdn"),
b992d7e2 588 &ddns_fwd_name);
ee83afae
TL
589 if (server_updates_a)
590 bind_ds_value (&lease -> scope, "ddns-txt",
591 &ddns_dhcid);
b992d7e2 592 }
bdad826f 593
4d2eaafb 594 if (rcode2 == ISC_R_SUCCESS && server_updates_ptr) {
b992d7e2
DN
595 bind_ds_value (&lease -> scope, "ddns-rev-name",
596 &ddns_rev_name);
597 }
598
478028e7 599 noerror:
a396d25f
DH
600 /* If we're ignoring client updates, then we tell a sort of 'white
601 * lie'. We've already updated the name the server wants (per the
602 * config written by the server admin). Now let the client do as
603 * it pleases with the name they supplied (if any).
604 *
605 * We only form an FQDN option this way if the client supplied an
606 * FQDN option that had FQDN_SERVER_UPDATE set false.
607 */
608 if (client_ignorep &&
609 (oc = lookup_option(&fqdn_universe, packet->options,
610 FQDN_SERVER_UPDATE)) &&
611 !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
612 packet->options, state->options,
613 &lease->scope, oc, MDL)) {
614 oc = lookup_option(&fqdn_universe, packet->options, FQDN_FQDN);
615 if (oc && evaluate_option_cache(&d1, packet, lease, NULL,
616 packet->options, state->options,
617 &global_scope, oc, MDL)) {
618 if (d1.len == 0 ||
619 !buffer_allocate(&bp, d1.len + 5, MDL))
620 goto badfqdn;
621
622 /* Server pretends it is not updating. */
623 bp->data[0] = 0;
624 if (!save_option_buffer(&fqdn_universe, state->options,
625 bp, &bp->data[0], 1,
8f4c32a1 626 FQDN_SERVER_UPDATE, 0))
a396d25f
DH
627 goto badfqdn;
628
629 /* Client is encouraged to update. */
630 bp->data[1] = 0;
631 if (!save_option_buffer(&fqdn_universe, state->options,
632 bp, &bp->data[1], 1,
8f4c32a1 633 FQDN_NO_CLIENT_UPDATE, 0))
a396d25f
DH
634 goto badfqdn;
635
636 /* Use the encoding of client's FQDN option. */
637 oc = lookup_option(&fqdn_universe, packet->options,
638 FQDN_ENCODED);
639 if (oc && evaluate_boolean_option_cache(&ignorep,
640 packet, lease, NULL,
641 packet->options,
642 state->options,
643 &lease->scope, oc,
644 MDL))
645 bp->data[2] = 1; /* FQDN is encoded. */
646 else
647 bp->data[2] = 0; /* FQDN is not encoded. */
648
649 if (!save_option_buffer(&fqdn_universe, state->options,
650 bp, &bp->data[2], 1,
8f4c32a1 651 FQDN_ENCODED, 0))
a396d25f
DH
652 goto badfqdn;
653
654 /* Current FQDN drafts indicate 255 is mandatory. */
655 bp->data[3] = 255;
656 if (!save_option_buffer(&fqdn_universe, state->options,
657 bp, &bp->data[3], 1,
8f4c32a1 658 FQDN_RCODE1, 0))
a396d25f
DH
659 goto badfqdn;
660
661 bp->data[4] = 255;
662 if (!save_option_buffer(&fqdn_universe, state->options,
663 bp, &bp->data[4], 1,
8f4c32a1 664 FQDN_RCODE2, 0))
a396d25f
DH
665 goto badfqdn;
666
667 /* Copy in the FQDN supplied by the client. Note well
668 * that the format of this option in the cache is going
669 * to be in text format. If the fqdn supplied by the
670 * client is encoded, it is decoded into the option
671 * cache when parsed out of the packet. It will be
672 * re-encoded when the option is assembled to be
673 * transmitted if the client elects that encoding.
674 */
675 memcpy(&bp->data[5], d1.data, d1.len);
676 if (!save_option_buffer(&fqdn_universe, state->options,
677 bp, &bp->data[5], 1,
8f4c32a1 678 FQDN_FQDN, 0))
a396d25f
DH
679 goto badfqdn;
680
681 data_string_forget(&d1, MDL);
682 }
683 /* Set up the outgoing FQDN option if there was an incoming
684 * FQDN option. If there's a valid FQDN option, there MUST
685 * be an FQDN_SERVER_UPDATES suboption, it's part of the fixed
686 * length head of the option contents, so we test the latter
687 * to detect the presence of the former.
688 */
689 } else if ((oc = lookup_option(&fqdn_universe, packet->options,
690 FQDN_ENCODED)) &&
691 buffer_allocate(&bp, ddns_fwd_name.len + 5, MDL)) {
478028e7
TL
692 bp -> data [0] = server_updates_a;
693 if (!save_option_buffer (&fqdn_universe, state -> options,
694 bp, &bp -> data [0], 1,
f7fdb216 695 FQDN_SERVER_UPDATE, 0))
478028e7
TL
696 goto badfqdn;
697 bp -> data [1] = server_updates_a;
698 if (!save_option_buffer (&fqdn_universe, state -> options,
699 bp, &bp -> data [1], 1,
f7fdb216 700 FQDN_NO_CLIENT_UPDATE, 0))
478028e7 701 goto badfqdn;
a396d25f 702
478028e7 703 /* Do the same encoding the client did. */
a396d25f
DH
704 if (evaluate_boolean_option_cache(&ignorep, packet, lease,
705 NULL, packet->options,
706 state->options,
707 &lease->scope, oc, MDL))
478028e7
TL
708 bp -> data [2] = 1;
709 else
710 bp -> data [2] = 0;
711 if (!save_option_buffer (&fqdn_universe, state -> options,
712 bp, &bp -> data [2], 1,
f7fdb216 713 FQDN_ENCODED, 0))
478028e7 714 goto badfqdn;
ec64b462 715 bp -> data [3] = isc_rcode_to_ns (rcode1);
478028e7
TL
716 if (!save_option_buffer (&fqdn_universe, state -> options,
717 bp, &bp -> data [3], 1,
f7fdb216 718 FQDN_RCODE1, 0))
478028e7 719 goto badfqdn;
ec64b462 720 bp -> data [4] = isc_rcode_to_ns (rcode2);
478028e7
TL
721 if (!save_option_buffer (&fqdn_universe, state -> options,
722 bp, &bp -> data [4], 1,
f7fdb216 723 FQDN_RCODE2, 0))
478028e7
TL
724 goto badfqdn;
725 if (ddns_fwd_name.len) {
726 memcpy (&bp -> data [5],
727 ddns_fwd_name.data, ddns_fwd_name.len);
728 if (!save_option_buffer (&fqdn_universe, state -> options,
729 bp, &bp -> data [5],
730 ddns_fwd_name.len,
f7fdb216 731 FQDN_FQDN, 0))
478028e7
TL
732 goto badfqdn;
733 }
b992d7e2
DN
734 }
735
478028e7
TL
736 badfqdn:
737 out:
b992d7e2
DN
738 /*
739 * Final cleanup.
740 */
a396d25f
DH
741 data_string_forget(&d1, MDL);
742 data_string_forget(&ddns_hostname, MDL);
743 data_string_forget(&ddns_domainname, MDL);
744 data_string_forget(&old_ddns_fwd_name, MDL);
745 data_string_forget(&ddns_fwd_name, MDL);
746 data_string_forget(&ddns_rev_name, MDL);
747 data_string_forget(&ddns_dhcid, MDL);
c3993513 748 if (bp)
a396d25f 749 buffer_dereference(&bp, MDL);
b992d7e2 750
478028e7 751 return result;
b992d7e2
DN
752}
753
478028e7 754int ddns_removals (struct lease *lease)
385fcb27 755{
b992d7e2
DN
756 struct data_string ddns_fwd_name;
757 struct data_string ddns_rev_name;
b992d7e2 758 struct data_string ddns_dhcid;
ec64b462 759 isc_result_t rcode;
385fcb27 760 struct binding *binding;
478028e7 761 int result = 0;
ee83afae 762 int client_updated = 0;
b992d7e2
DN
763
764 /* No scope implies that DDNS has not been performed for this lease. */
765 if (!lease -> scope)
478028e7 766 return 0;
b992d7e2 767
98311e4b
DH
768 if (ddns_update_style != 2)
769 return 0;
770
b992d7e2
DN
771 /*
772 * Look up stored names.
773 */
774 memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name));
775 memset (&ddns_rev_name, 0, sizeof (ddns_rev_name));
b992d7e2
DN
776 memset (&ddns_dhcid, 0, sizeof (ddns_dhcid));
777
b992d7e2
DN
778 /*
779 * Start the resolver, if necessary.
780 */
781 if (!resolver_inited) {
782 minires_ninit (&resolver_state);
783 resolver_inited = 1;
98311e4b
DH
784 resolver_state.retrans = 1;
785 resolver_state.retry = 1;
b992d7e2
DN
786 }
787
478028e7
TL
788 /* We need the fwd name whether we are deleting both records or just
789 the PTR record, so if it's not there, we can't proceed. */
790 if (!find_bound_string (&ddns_fwd_name,
ee83afae
TL
791 lease -> scope, "ddns-fwd-name")) {
792 /* If there's no ddns-fwd-name, look for the client fqdn,
793 in case the client did the update. */
794 if (!find_bound_string (&ddns_fwd_name,
795 lease -> scope, "ddns-client-fqdn"))
d758ad8c 796 goto try_rev;
ee83afae
TL
797 client_updated = 1;
798 goto try_rev;
799 }
478028e7
TL
800
801 /* If the ddns-txt binding isn't there, this isn't an interim
802 or rfc3??? record, so we can't delete the A record using
803 this mechanism, but we can delete the PTR record. */
804 if (!find_bound_string (&ddns_dhcid, lease -> scope, "ddns-txt")) {
805 result = 1;
806 goto try_rev;
807 }
808
b992d7e2
DN
809 /*
810 * Perform removals.
811 */
d758ad8c
TL
812 if (ddns_fwd_name.len)
813 rcode = ddns_remove_a (&ddns_fwd_name,
814 lease -> ip_addr, &ddns_dhcid);
815 else
816 rcode = ISC_R_SUCCESS;
478028e7 817
ec64b462 818 if (rcode == ISC_R_SUCCESS) {
478028e7
TL
819 result = 1;
820 unset (lease -> scope, "ddns-fwd-name");
821 unset (lease -> scope, "ddns-txt");
822 try_rev:
823 if (find_bound_string (&ddns_rev_name,
824 lease -> scope, "ddns-rev-name")) {
ee83afae 825 if (ddns_remove_ptr(&ddns_rev_name) == NOERROR) {
478028e7 826 unset (lease -> scope, "ddns-rev-name");
ee83afae
TL
827 if (client_updated)
828 unset (lease -> scope,
829 "ddns-client-fqdn");
d758ad8c
TL
830 /* XXX this is to compensate for a bug in
831 XXX 3.0rc8, and should be removed before
832 XXX 3.0pl1. */
833 else if (!ddns_fwd_name.len)
834 unset (lease -> scope, "ddns-text");
ee83afae 835 } else
478028e7
TL
836 result = 0;
837 }
b992d7e2
DN
838 }
839
b992d7e2
DN
840 data_string_forget (&ddns_fwd_name, MDL);
841 data_string_forget (&ddns_rev_name, MDL);
b992d7e2
DN
842 data_string_forget (&ddns_dhcid, MDL);
843
478028e7 844 return result;
b992d7e2
DN
845}
846
b992d7e2 847#endif /* NSUPDATE */