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