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