ddns.c revision 1.2 1 1.2 christos /* $NetBSD: ddns.c,v 1.2 2018/04/07 22:37:30 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.2 christos __RCSID("$NetBSD: ddns.c,v 1.2 2018/04/07 22:37:30 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.2 christos static 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.2 christos #ifdef notdef
943 1.1 christos /*
944 1.1 christos * This function should be called when update_lease_ptr function fails.
945 1.1 christos * It does inform user about the condition, provides some hints how to
946 1.1 christos * resolve this and dies gracefully. This can happend in at least three
947 1.1 christos * cases (all are configuration mistakes):
948 1.1 christos * a) IPv4: user have duplicate fixed-address entries (the same
949 1.1 christos * address is defined twice). We may have found wrong lease.
950 1.1 christos * b) IPv6: user have overlapping pools (we tried to find
951 1.1 christos * a lease in a wrong pool)
952 1.1 christos * c) IPv6: user have duplicate fixed-address6 entires (the same
953 1.1 christos * address is defined twice). We may have found wrong lease.
954 1.1 christos *
955 1.1 christos * Comment: while it would be possible to recover from both cases
956 1.1 christos * by forcibly searching for leases in *all* following pools, that would
957 1.1 christos * only hide the real problem - a misconfiguration. Proper solution
958 1.1 christos * is to log the problem, die and let the user fix his config file.
959 1.1 christos */
960 1.1 christos void
961 1.1 christos update_lease_failed(struct lease *lease,
962 1.1 christos struct iasubopt *lease6,
963 1.1 christos dhcp_ddns_cb_t *ddns_cb,
964 1.1 christos dhcp_ddns_cb_t *ddns_cb_set,
965 1.1 christos const char * file, int line)
966 1.1 christos {
967 1.1 christos char lease_address[MAX_ADDRESS_STRING_LEN + 64];
968 1.1 christos char reason[128]; /* likely reason */
969 1.1 christos
970 1.1 christos sprintf(reason, "unknown");
971 1.1 christos sprintf(lease_address, "unknown");
972 1.1 christos
973 1.1 christos /*
974 1.1 christos * let's pretend that everything is ok, so we can continue for
975 1.1 christos * information gathering purposes
976 1.1 christos */
977 1.1 christos
978 1.1 christos if (ddns_cb != NULL) {
979 1.1 christos strncpy(lease_address, piaddr(ddns_cb->address),
980 1.1 christos MAX_ADDRESS_STRING_LEN);
981 1.1 christos
982 1.1 christos if (ddns_cb->address.len == 4) {
983 1.1 christos sprintf(reason, "duplicate IPv4 fixed-address entry");
984 1.1 christos } else if (ddns_cb->address.len == 16) {
985 1.1 christos sprintf(reason, "duplicate IPv6 fixed-address6 entry "
986 1.1 christos "or overlapping pools");
987 1.1 christos } else {
988 1.1 christos /*
989 1.1 christos * Should not happen. We have non-IPv4, non-IPv6
990 1.1 christos * address. Something is very wrong here.
991 1.1 christos */
992 1.1 christos sprintf(reason, "corrupted ddns_cb structure (address "
993 1.1 christos "length is %d)", ddns_cb->address.len);
994 1.1 christos }
995 1.1 christos }
996 1.1 christos
997 1.1 christos log_error("Failed to properly update internal lease structure with "
998 1.1 christos "DDNS");
999 1.1 christos log_error("control block structures. Tried to update lease for"
1000 1.1 christos "%s address, ddns_cb=%p.", lease_address, ddns_cb);
1001 1.1 christos
1002 1.1 christos log_error("%s", "");
1003 1.1 christos log_error("This condition can occur, if DHCP server configuration is "
1004 1.1 christos "inconsistent.");
1005 1.1 christos log_error("In particular, please do check that your configuration:");
1006 1.1 christos log_error("a) does not have overlapping pools (especially containing");
1007 1.1 christos log_error(" %s address).", lease_address);
1008 1.1 christos log_error("b) there are no duplicate fixed-address or fixed-address6");
1009 1.1 christos log_error("entries for the %s address.", lease_address);
1010 1.1 christos log_error("%s", "");
1011 1.1 christos log_error("Possible reason for this failure: %s", reason);
1012 1.1 christos
1013 1.1 christos log_fatal("%s(%d): Failed to update lease database with DDNS info for "
1014 1.1 christos "address %s. Lease database inconsistent. Unable to recover."
1015 1.1 christos " Terminating.", file, line, lease_address);
1016 1.1 christos }
1017 1.2 christos #endif
1018 1.1 christos
1019 1.1 christos /*
1020 1.1 christos * utility function to update found lease. It does extra checks
1021 1.1 christos * that we are indeed updating the right lease. It may happen
1022 1.1 christos * that user have duplicate fixed-address entries, so we attempt
1023 1.1 christos * to update wrong lease. See also safe_lease6_update.
1024 1.1 christos */
1025 1.1 christos
1026 1.2 christos static void
1027 1.1 christos safe_lease_update(struct lease *lease,
1028 1.1 christos dhcp_ddns_cb_t *oldcb,
1029 1.1 christos dhcp_ddns_cb_t *newcb,
1030 1.1 christos const char *file, int line)
1031 1.1 christos {
1032 1.1 christos if (lease == NULL) {
1033 1.1 christos /* should never get here */
1034 1.1 christos log_fatal("Impossible condition at %s:%d (called from %s:%d).",
1035 1.1 christos MDL, file, line);
1036 1.1 christos }
1037 1.1 christos
1038 1.1 christos if ( (lease->ddns_cb == NULL) && (newcb == NULL) ) {
1039 1.1 christos /*
1040 1.1 christos * Trying to clean up pointer that is already null. We
1041 1.1 christos * are most likely trying to update wrong lease here.
1042 1.1 christos */
1043 1.1 christos
1044 1.1 christos /*
1045 1.1 christos * Previously this error message popped out during
1046 1.1 christos * DNS update for fixed leases. As we no longer
1047 1.1 christos * try to update the lease for a fixed (static) lease
1048 1.1 christos * this should not be a problem.
1049 1.1 christos */
1050 1.1 christos log_error("%s(%d): Invalid lease update. Tried to "
1051 1.1 christos "clear already NULL DDNS control block "
1052 1.1 christos "pointer for lease %s.",
1053 1.1 christos file, line, piaddr(lease->ip_addr) );
1054 1.1 christos
1055 1.1 christos #if defined (DNS_UPDATES_MEMORY_CHECKS)
1056 1.1 christos update_lease_failed(lease, NULL, oldcb, newcb, file, line);
1057 1.1 christos #endif
1058 1.1 christos /*
1059 1.1 christos * May not reach this: update_lease_failed calls
1060 1.1 christos * log_fatal.
1061 1.1 christos */
1062 1.1 christos return;
1063 1.1 christos }
1064 1.1 christos
1065 1.1 christos if ( (lease->ddns_cb != NULL) && (lease->ddns_cb != oldcb) ) {
1066 1.1 christos /*
1067 1.1 christos * There is existing cb structure, but it differs from
1068 1.1 christos * what we expected to see there. Most likely we are
1069 1.1 christos * trying to update wrong lease.
1070 1.1 christos */
1071 1.1 christos log_error("%s(%d): Failed to update internal lease "
1072 1.1 christos "structure with DDNS control block. Existing"
1073 1.1 christos " ddns_cb structure does not match "
1074 1.1 christos "expectations.IPv4=%s, old ddns_cb=%p, tried"
1075 1.1 christos "to update to new ddns_cb=%p", file, line,
1076 1.1 christos piaddr(lease->ip_addr), oldcb, newcb);
1077 1.1 christos
1078 1.1 christos #if defined (DNS_UPDATES_MEMORY_CHECKS)
1079 1.1 christos update_lease_failed(lease, NULL, oldcb, newcb, file, line);
1080 1.1 christos #endif
1081 1.1 christos /*
1082 1.1 christos * May not reach this: update_lease_failed calls
1083 1.1 christos * log_fatal.
1084 1.1 christos */
1085 1.1 christos return;
1086 1.1 christos }
1087 1.1 christos
1088 1.1 christos /* additional IPv4 specific checks may be added here */
1089 1.1 christos
1090 1.1 christos /* update the lease */
1091 1.1 christos lease->ddns_cb = newcb;
1092 1.1 christos }
1093 1.1 christos
1094 1.2 christos static void
1095 1.1 christos safe_lease6_update(struct iasubopt *lease6,
1096 1.1 christos dhcp_ddns_cb_t *oldcb,
1097 1.1 christos dhcp_ddns_cb_t *newcb,
1098 1.1 christos const char *file, int line)
1099 1.1 christos {
1100 1.1 christos char addrbuf[MAX_ADDRESS_STRING_LEN];
1101 1.1 christos
1102 1.1 christos if (lease6 == NULL) {
1103 1.1 christos /* should never get here */
1104 1.1 christos log_fatal("Impossible condition at %s:%d (called from %s:%d).",
1105 1.1 christos MDL, file, line);
1106 1.1 christos }
1107 1.1 christos
1108 1.1 christos if ( (lease6->ddns_cb == NULL) && (newcb == NULL) ) {
1109 1.1 christos inet_ntop(AF_INET6, &lease6->addr, addrbuf,
1110 1.1 christos MAX_ADDRESS_STRING_LEN);
1111 1.1 christos /*
1112 1.1 christos * Trying to clean up pointer that is already null. We
1113 1.1 christos * are most likely trying to update wrong lease here.
1114 1.1 christos */
1115 1.1 christos log_error("%s(%d): Failed to update internal lease "
1116 1.1 christos "structure. Tried to clear already NULL "
1117 1.1 christos "DDNS control block pointer for lease %s.",
1118 1.1 christos file, line, addrbuf);
1119 1.1 christos
1120 1.1 christos #if defined (DNS_UPDATES_MEMORY_CHECKS)
1121 1.1 christos update_lease_failed(NULL, lease6, oldcb, newcb, file, line);
1122 1.1 christos #endif
1123 1.1 christos
1124 1.1 christos /*
1125 1.1 christos * May not reach this: update_lease_failed calls
1126 1.1 christos * log_fatal.
1127 1.1 christos */
1128 1.1 christos return;
1129 1.1 christos }
1130 1.1 christos
1131 1.1 christos if ( (lease6->ddns_cb != NULL) && (lease6->ddns_cb != oldcb) ) {
1132 1.1 christos /*
1133 1.1 christos * there is existing cb structure, but it differs from
1134 1.1 christos * what we expected to see there. Most likely we are
1135 1.1 christos * trying to update wrong lease.
1136 1.1 christos */
1137 1.1 christos inet_ntop(AF_INET6, &lease6->addr, addrbuf,
1138 1.1 christos MAX_ADDRESS_STRING_LEN);
1139 1.1 christos
1140 1.1 christos log_error("%s(%d): Failed to update internal lease "
1141 1.1 christos "structure with DDNS control block. Existing"
1142 1.1 christos " ddns_cb structure does not match "
1143 1.1 christos "expectations.IPv6=%s, old ddns_cb=%p, tried"
1144 1.1 christos "to update to new ddns_cb=%p", file, line,
1145 1.1 christos addrbuf, oldcb, newcb);
1146 1.1 christos
1147 1.1 christos #if defined (DNS_UPDATES_MEMORY_CHECKS)
1148 1.1 christos update_lease_failed(NULL, lease6, oldcb, newcb, file, line);
1149 1.1 christos #endif
1150 1.1 christos /*
1151 1.1 christos * May not reach this: update_lease_failed calls
1152 1.1 christos * log_fatal.
1153 1.1 christos */
1154 1.1 christos return;
1155 1.1 christos }
1156 1.1 christos /* additional IPv6 specific checks may be added here */
1157 1.1 christos
1158 1.1 christos /* update the lease */
1159 1.1 christos lease6->ddns_cb = newcb;
1160 1.1 christos }
1161 1.1 christos
1162 1.1 christos /*
1163 1.1 christos * Utility function to update the pointer to the DDNS control block
1164 1.1 christos * in a lease.
1165 1.1 christos * SUCCESS - able to update the pointer
1166 1.1 christos * FAILURE - lease didn't exist or sanity checks failed
1167 1.1 christos * lease and lease6 may be empty in which case we attempt to find
1168 1.1 christos * the lease from the ddns_cb information.
1169 1.1 christos * ddns_cb is the control block to use if a lookup is necessary
1170 1.1 christos * ddns_cb_set is the pointer to insert into the lease and may be NULL
1171 1.1 christos * The last two arguments may look odd as they will be the same much of the
1172 1.1 christos * time, but I need an argument to tell me if I'm setting or clearing in
1173 1.1 christos * addition to the address information from the cb to look up the lease.
1174 1.1 christos * using the same value twice allows me more flexibility.
1175 1.1 christos */
1176 1.1 christos
1177 1.2 christos static isc_result_t
1178 1.1 christos ddns_update_lease_ptr(struct lease *lease,
1179 1.1 christos struct iasubopt *lease6,
1180 1.1 christos dhcp_ddns_cb_t *ddns_cb,
1181 1.1 christos dhcp_ddns_cb_t *ddns_cb_set,
1182 1.1 christos const char * file, int line)
1183 1.1 christos {
1184 1.1 christos char ddns_address[MAX_ADDRESS_STRING_LEN];
1185 1.1 christos sprintf(ddns_address, "unknown");
1186 1.1 christos if (ddns_cb == NULL) {
1187 1.1 christos log_info("%s(%d): No control block for lease update",
1188 1.1 christos file, line);
1189 1.1 christos return (ISC_R_FAILURE);
1190 1.1 christos }
1191 1.1 christos else {
1192 1.1 christos strcpy(ddns_address, piaddr(ddns_cb->address));
1193 1.1 christos }
1194 1.1 christos #if defined (DEBUG_DNS_UPDATES)
1195 1.1 christos log_info("%s(%d): Updating lease_ptr for ddns_cp=%p (addr=%s)",
1196 1.1 christos file, line, ddns_cb, ddns_address );
1197 1.1 christos #endif
1198 1.1 christos
1199 1.1 christos /*
1200 1.1 christos * If the lease was static (for a fixed address)
1201 1.1 christos * we don't need to do any work.
1202 1.1 christos */
1203 1.1 christos if (ddns_cb->flags & DDNS_STATIC_LEASE) {
1204 1.1 christos #if defined (DEBUG_DNS_UPDATES)
1205 1.1 christos log_info("lease is static, returning");
1206 1.1 christos #endif
1207 1.1 christos return (ISC_R_SUCCESS);
1208 1.1 christos }
1209 1.1 christos
1210 1.1 christos /*
1211 1.1 christos * If we are processing an expired or released v6 lease
1212 1.1 christos * we don't actually have a lease to update
1213 1.1 christos */
1214 1.1 christos if ((ddns_cb->address.len == 16) &&
1215 1.1 christos ((ddns_cb->flags & DDNS_ACTIVE_LEASE) == 0)) {
1216 1.1 christos return (ISC_R_SUCCESS);
1217 1.1 christos }
1218 1.1 christos
1219 1.1 christos if (lease != NULL) {
1220 1.1 christos safe_lease_update(lease, ddns_cb, ddns_cb_set,
1221 1.1 christos file, line);
1222 1.1 christos } else if (lease6 != NULL) {
1223 1.1 christos safe_lease6_update(lease6, ddns_cb, ddns_cb_set,
1224 1.1 christos file, line);
1225 1.1 christos } else if (ddns_cb->address.len == 4) {
1226 1.1 christos struct lease *find_lease = NULL;
1227 1.1 christos if (find_lease_by_ip_addr(&find_lease,
1228 1.1 christos ddns_cb->address, MDL) != 0) {
1229 1.1 christos #if defined (DEBUG_DNS_UPDATES)
1230 1.1 christos log_info("%s(%d): find_lease_by_ip_addr(%s) successful:"
1231 1.1 christos "lease=%p", file, line, ddns_address,
1232 1.1 christos find_lease);
1233 1.1 christos #endif
1234 1.1 christos
1235 1.1 christos safe_lease_update(find_lease, ddns_cb,
1236 1.1 christos ddns_cb_set, file, line);
1237 1.1 christos lease_dereference(&find_lease, MDL);
1238 1.1 christos }
1239 1.1 christos else {
1240 1.1 christos log_error("%s(%d): ddns_update_lease_ptr failed. "
1241 1.1 christos "Lease for %s not found.",
1242 1.1 christos file, line, piaddr(ddns_cb->address));
1243 1.1 christos
1244 1.1 christos #if defined (DNS_UPDATES_MEMORY_CHECKS)
1245 1.1 christos update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set,
1246 1.1 christos file, line);
1247 1.1 christos #endif
1248 1.1 christos /*
1249 1.1 christos * may not reach this. update_lease_failed
1250 1.1 christos * calls log_fatal.
1251 1.1 christos */
1252 1.1 christos return(ISC_R_FAILURE);
1253 1.1 christos
1254 1.1 christos }
1255 1.1 christos } else if (ddns_cb->address.len == 16) {
1256 1.1 christos struct iasubopt *find_lease6 = NULL;
1257 1.1 christos struct ipv6_pool *pool = NULL;
1258 1.1 christos struct in6_addr addr;
1259 1.1 christos char addrbuf[MAX_ADDRESS_STRING_LEN];
1260 1.1 christos
1261 1.1 christos memcpy(&addr, &ddns_cb->address.iabuf, 16);
1262 1.1 christos if ((find_ipv6_pool(&pool, D6O_IA_TA, &addr) !=
1263 1.1 christos ISC_R_SUCCESS) &&
1264 1.1 christos (find_ipv6_pool(&pool, D6O_IA_NA, &addr) !=
1265 1.1 christos ISC_R_SUCCESS)) {
1266 1.1 christos inet_ntop(AF_INET6, &addr, addrbuf,
1267 1.1 christos MAX_ADDRESS_STRING_LEN);
1268 1.1 christos log_error("%s(%d): Pool for lease %s not found.",
1269 1.1 christos file, line, addrbuf);
1270 1.1 christos #if defined (DNS_UPDATES_MEMORY_CHECKS)
1271 1.1 christos update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set,
1272 1.1 christos file, line);
1273 1.1 christos #endif
1274 1.1 christos /*
1275 1.1 christos * never reached. update_lease_failed
1276 1.1 christos * calls log_fatal.
1277 1.1 christos */
1278 1.1 christos return(ISC_R_FAILURE);
1279 1.1 christos }
1280 1.1 christos
1281 1.1 christos if (iasubopt_hash_lookup(&find_lease6, pool->leases,
1282 1.1 christos &addr, 16, MDL)) {
1283 1.1 christos find_lease6->ddns_cb = ddns_cb_set;
1284 1.1 christos iasubopt_dereference(&find_lease6, MDL);
1285 1.1 christos } else {
1286 1.1 christos inet_ntop(AF_INET6, &addr, addrbuf,
1287 1.1 christos MAX_ADDRESS_STRING_LEN);
1288 1.1 christos log_error("%s(%d): Lease %s not found within pool.",
1289 1.1 christos file, line, addrbuf);
1290 1.1 christos #if defined (DNS_UPDATES_MEMORY_CHECKS)
1291 1.1 christos update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set,
1292 1.1 christos file, line);
1293 1.1 christos #endif
1294 1.1 christos /*
1295 1.1 christos * never reached. update_lease_failed
1296 1.1 christos * calls log_fatal.
1297 1.1 christos */
1298 1.1 christos return(ISC_R_FAILURE);
1299 1.1 christos }
1300 1.1 christos ipv6_pool_dereference(&pool, MDL);
1301 1.1 christos } else {
1302 1.1 christos /* shouldn't get here */
1303 1.1 christos log_fatal("Impossible condition at %s:%d, called from %s:%d.",
1304 1.1 christos MDL, file, line);
1305 1.1 christos }
1306 1.1 christos
1307 1.1 christos return(ISC_R_SUCCESS);
1308 1.1 christos }
1309 1.1 christos
1310 1.2 christos static void
1311 1.1 christos ddns_ptr_add(dhcp_ddns_cb_t *ddns_cb,
1312 1.1 christos isc_result_t eresult)
1313 1.1 christos {
1314 1.1 christos if (eresult == ISC_R_SUCCESS) {
1315 1.1 christos log_info("Added reverse map from %.*s to %.*s",
1316 1.1 christos (int)ddns_cb->rev_name.len,
1317 1.1 christos (const char *)ddns_cb->rev_name.data,
1318 1.1 christos (int)ddns_cb->fwd_name.len,
1319 1.1 christos (const char *)ddns_cb->fwd_name.data);
1320 1.1 christos
1321 1.1 christos ddns_update_lease_text(ddns_cb, NULL);
1322 1.1 christos } else {
1323 1.1 christos log_error("Unable to add reverse map from %.*s to %.*s: %s",
1324 1.1 christos (int)ddns_cb->rev_name.len,
1325 1.1 christos (const char *)ddns_cb->rev_name.data,
1326 1.1 christos (int)ddns_cb->fwd_name.len,
1327 1.1 christos (const char *)ddns_cb->fwd_name.data,
1328 1.1 christos isc_result_totext (eresult));
1329 1.1 christos }
1330 1.1 christos
1331 1.1 christos ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1332 1.1 christos destroy_ddns_cb(ddns_cb, MDL);
1333 1.1 christos /*
1334 1.1 christos * A single DDNS operation may require several calls depending on
1335 1.1 christos * the current state as the prerequisites for the first message
1336 1.1 christos * may not succeed requiring a second operation and potentially
1337 1.1 christos * a ptr operation after that. The commit_leases operation is
1338 1.1 christos * invoked at the end of this set of operations in order to require
1339 1.1 christos * a single write for all of the changes. We call commit_leases
1340 1.1 christos * here rather than immediately after the call to update the lease
1341 1.1 christos * text in order to save any previously written data.
1342 1.1 christos */
1343 1.1 christos commit_leases();
1344 1.1 christos return;
1345 1.1 christos }
1346 1.1 christos
1347 1.1 christos /*
1348 1.1 christos * action routine when trying to remove a pointer
1349 1.1 christos * this will be called after the ddns queries have completed
1350 1.1 christos * if we succeeded in removing the pointer we go to the next step (if any)
1351 1.1 christos * if not we cleanup and leave.
1352 1.1 christos */
1353 1.1 christos
1354 1.2 christos static void
1355 1.1 christos ddns_ptr_remove(dhcp_ddns_cb_t *ddns_cb,
1356 1.1 christos isc_result_t eresult)
1357 1.1 christos {
1358 1.1 christos isc_result_t result = eresult;
1359 1.1 christos
1360 1.1 christos switch(eresult) {
1361 1.1 christos case ISC_R_SUCCESS:
1362 1.1 christos log_info("Removed reverse map on %.*s",
1363 1.1 christos (int)ddns_cb->rev_name.len,
1364 1.1 christos (const char *)ddns_cb->rev_name.data);
1365 1.1 christos /* fall through */
1366 1.1 christos case DNS_R_NXRRSET:
1367 1.1 christos case DNS_R_NXDOMAIN:
1368 1.1 christos /* No entry is the same as success.
1369 1.1 christos * Remove the information from the lease and
1370 1.1 christos * continue with any next step */
1371 1.1 christos ddns_update_lease_text(ddns_cb, NULL);
1372 1.1 christos
1373 1.1 christos /* trigger any add operation */
1374 1.1 christos result = ISC_R_SUCCESS;
1375 1.1 christos #if defined (DEBUG_DNS_UPDATES)
1376 1.1 christos log_info("DDNS: removed map or no reverse map to remove %.*s",
1377 1.1 christos (int)ddns_cb->rev_name.len,
1378 1.1 christos (const char *)ddns_cb->rev_name.data);
1379 1.1 christos #endif
1380 1.1 christos break;
1381 1.1 christos
1382 1.1 christos default:
1383 1.1 christos log_error("Can't remove reverse map on %.*s: %s",
1384 1.1 christos (int)ddns_cb->rev_name.len,
1385 1.1 christos (const char *)ddns_cb->rev_name.data,
1386 1.1 christos isc_result_totext (eresult));
1387 1.1 christos break;
1388 1.1 christos }
1389 1.1 christos
1390 1.1 christos /* If we aren't suppossed to do the next step, set the result
1391 1.1 christos * flag so ddns_fwd_srv_connector won't do much
1392 1.1 christos */
1393 1.1 christos if ((ddns_cb->flags & DDNS_EXECUTE_NEXT) == 0)
1394 1.1 christos result = ISC_R_FAILURE;
1395 1.1 christos
1396 1.1 christos ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1397 1.1 christos ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, result);
1398 1.1 christos destroy_ddns_cb(ddns_cb, MDL);
1399 1.1 christos return;
1400 1.1 christos }
1401 1.1 christos
1402 1.1 christos
1403 1.1 christos /*
1404 1.1 christos * If the first query succeeds, the updater can conclude that it
1405 1.1 christos * has added a new name whose only RRs are the A and DHCID RR records.
1406 1.1 christos * The A RR update is now complete (and a client updater is finished,
1407 1.1 christos * while a server might proceed to perform a PTR RR update).
1408 1.1 christos * -- "Interaction between DHCP and DNS"
1409 1.1 christos *
1410 1.1 christos * If the second query succeeds, the updater can conclude that the current
1411 1.1 christos * client was the last client associated with the domain name, and that
1412 1.1 christos * the name now contains the updated A RR. The A RR update is now
1413 1.1 christos * complete (and a client updater is finished, while a server would
1414 1.1 christos * then proceed to perform a PTR RR update).
1415 1.1 christos * -- "Interaction between DHCP and DNS"
1416 1.1 christos *
1417 1.1 christos * If the second query fails with NXRRSET, the updater must conclude
1418 1.1 christos * that the client's desired name is in use by another host. If
1419 1.1 christos * Dual Stack Mixed Mode (DSMM) is enabled and we proceed to a
1420 1.1 christos * third stage forward update attempt specific to DSMM rules. If not,
1421 1.1 christos * then the existing entries are left intact:
1422 1.1 christos *
1423 1.1 christos * At this juncture, the updater can decide (based on some administrative
1424 1.1 christos * configuration outside of the scope of this document) whether to let
1425 1.1 christos * the existing owner of the name keep that name, and to (possibly)
1426 1.1 christos * perform some name disambiguation operation on behalf of the current
1427 1.1 christos * client, or to replace the RRs on the name with RRs that represent
1428 1.1 christos * the current client. If the configured policy allows replacement of
1429 1.1 christos * existing records, the updater submits a query that deletes the
1430 1.1 christos * existing A RR and the existing DHCID RR, adding A and DHCID RRs that
1431 1.1 christos * represent the IP address and client-identity of the new client.
1432 1.1 christos * -- "Interaction between DHCP and DNS"
1433 1.1 christos */
1434 1.1 christos
1435 1.2 christos static void
1436 1.1 christos ddns_fwd_srv_add2(dhcp_ddns_cb_t *ddns_cb,
1437 1.1 christos isc_result_t eresult)
1438 1.1 christos {
1439 1.1 christos isc_result_t result;
1440 1.1 christos const char *logstr = NULL;
1441 1.1 christos char ddns_address[MAX_ADDRESS_STRING_LEN];
1442 1.1 christos
1443 1.1 christos #if defined (DEBUG_DNS_UPDATES)
1444 1.1 christos log_info ("DDNS:ddns_fwd_srv_add2: %s eresult: %d",
1445 1.1 christos dump_ddns_cb(ddns_cb), eresult);
1446 1.1 christos #endif
1447 1.1 christos
1448 1.1 christos /* Construct a printable form of the address for logging */
1449 1.1 christos strcpy(ddns_address, piaddr(ddns_cb->address));
1450 1.1 christos
1451 1.1 christos switch(eresult) {
1452 1.1 christos case ISC_R_SUCCESS:
1453 1.1 christos log_info("Added new forward map from %.*s to %s",
1454 1.1 christos (int)ddns_cb->fwd_name.len,
1455 1.1 christos (const char *)ddns_cb->fwd_name.data,
1456 1.1 christos ddns_address);
1457 1.1 christos
1458 1.1 christos ddns_update_lease_text(ddns_cb, NULL);
1459 1.1 christos
1460 1.1 christos if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1461 1.1 christos /* if we have zone information get rid of it */
1462 1.1 christos if (ddns_cb->zone != NULL) {
1463 1.1 christos ddns_cb_forget_zone(ddns_cb);
1464 1.1 christos }
1465 1.1 christos
1466 1.1 christos ddns_cb->state = DDNS_STATE_ADD_PTR;
1467 1.1 christos ddns_cb->cur_func = ddns_ptr_add;
1468 1.1 christos
1469 1.1 christos result = ddns_modify_ptr(ddns_cb, MDL);
1470 1.1 christos if (result == ISC_R_SUCCESS) {
1471 1.1 christos return;
1472 1.1 christos }
1473 1.1 christos }
1474 1.1 christos break;
1475 1.1 christos
1476 1.1 christos case DNS_R_YXRRSET:
1477 1.1 christos case DNS_R_YXDOMAIN:
1478 1.1 christos logstr = "DHCID mismatch, belongs to another client.";
1479 1.1 christos break;
1480 1.1 christos
1481 1.1 christos case DNS_R_NXDOMAIN:
1482 1.1 christos case DNS_R_NXRRSET:
1483 1.1 christos /* If DSMM is on we need to try forward add3 */
1484 1.1 christos if (ddns_cb->flags & DDNS_DUAL_STACK_MIXED_MODE) {
1485 1.1 christos ddns_cb->state = DDNS_STATE_DSMM_FW_ADD3;
1486 1.1 christos ddns_cb->cur_func = ddns_fwd_srv_add3;
1487 1.1 christos
1488 1.1 christos result = ddns_modify_fwd(ddns_cb, MDL);
1489 1.1 christos if (result == ISC_R_SUCCESS) {
1490 1.1 christos return;
1491 1.1 christos }
1492 1.1 christos
1493 1.1 christos break;
1494 1.1 christos }
1495 1.1 christos
1496 1.1 christos logstr = "Has an address record but no DHCID, not mine.";
1497 1.1 christos break;
1498 1.1 christos
1499 1.1 christos default:
1500 1.1 christos logstr = isc_result_totext(eresult);
1501 1.1 christos break;
1502 1.1 christos }
1503 1.1 christos
1504 1.1 christos if (logstr != NULL) {
1505 1.1 christos log_error("Forward map from %.*s to %s FAILED: %s",
1506 1.1 christos (int)ddns_cb->fwd_name.len,
1507 1.1 christos (const char *)ddns_cb->fwd_name.data,
1508 1.1 christos ddns_address, logstr);
1509 1.1 christos }
1510 1.1 christos
1511 1.1 christos ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1512 1.1 christos destroy_ddns_cb(ddns_cb, MDL);
1513 1.1 christos /*
1514 1.1 christos * A single DDNS operation may require several calls depending on
1515 1.1 christos * the current state as the prerequisites for the first message
1516 1.1 christos * may not succeed requiring a second operation and potentially
1517 1.1 christos * a ptr operation after that. The commit_leases operation is
1518 1.1 christos * invoked at the end of this set of operations in order to require
1519 1.1 christos * a single write for all of the changes. We call commit_leases
1520 1.1 christos * here rather than immediately after the call to update the lease
1521 1.1 christos * text in order to save any previously written data.
1522 1.1 christos */
1523 1.1 christos commit_leases();
1524 1.1 christos return;
1525 1.1 christos }
1526 1.1 christos
1527 1.2 christos static void
1528 1.1 christos ddns_fwd_srv_add1(dhcp_ddns_cb_t *ddns_cb,
1529 1.1 christos isc_result_t eresult)
1530 1.1 christos {
1531 1.1 christos isc_result_t result;
1532 1.1 christos char ddns_address[MAX_ADDRESS_STRING_LEN];
1533 1.1 christos
1534 1.1 christos #if defined (DEBUG_DNS_UPDATES)
1535 1.1 christos log_info ("DDNS: ddns_fwd_srv_add1: %s eresult: %d",
1536 1.1 christos dump_ddns_cb(ddns_cb), eresult);
1537 1.1 christos #endif
1538 1.1 christos
1539 1.1 christos /* Construct a printable form of the address for logging */
1540 1.1 christos strcpy(ddns_address, piaddr(ddns_cb->address));
1541 1.1 christos
1542 1.1 christos switch(eresult) {
1543 1.1 christos case ISC_R_SUCCESS:
1544 1.1 christos log_info ("Added new forward map from %.*s to %s",
1545 1.1 christos (int)ddns_cb->fwd_name.len,
1546 1.1 christos (const char *)ddns_cb->fwd_name.data,
1547 1.1 christos ddns_address);
1548 1.1 christos
1549 1.1 christos ddns_update_lease_text(ddns_cb, NULL);
1550 1.1 christos
1551 1.1 christos if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1552 1.1 christos /* if we have zone information get rid of it */
1553 1.1 christos if (ddns_cb->zone != NULL) {
1554 1.1 christos ddns_cb_forget_zone(ddns_cb);
1555 1.1 christos }
1556 1.1 christos
1557 1.1 christos ddns_cb->state = DDNS_STATE_ADD_PTR;
1558 1.1 christos ddns_cb->cur_func = ddns_ptr_add;
1559 1.1 christos
1560 1.1 christos result = ddns_modify_ptr(ddns_cb, MDL);
1561 1.1 christos if (result == ISC_R_SUCCESS) {
1562 1.1 christos return;
1563 1.1 christos }
1564 1.1 christos }
1565 1.1 christos break;
1566 1.1 christos
1567 1.1 christos case DNS_R_YXDOMAIN:
1568 1.1 christos /* we can reuse the zone information */
1569 1.1 christos ddns_cb->state = DDNS_STATE_ADD_FW_YXDHCID;
1570 1.1 christos ddns_cb->cur_func = ddns_fwd_srv_add2;
1571 1.1 christos
1572 1.1 christos result = ddns_modify_fwd(ddns_cb, MDL);
1573 1.1 christos if (result == ISC_R_SUCCESS) {
1574 1.1 christos return;
1575 1.1 christos }
1576 1.1 christos break;
1577 1.1 christos default:
1578 1.1 christos log_error ("Unable to add forward map from %.*s to %s: %s",
1579 1.1 christos (int)ddns_cb->fwd_name.len,
1580 1.1 christos (const char *)ddns_cb->fwd_name.data,
1581 1.1 christos ddns_address,
1582 1.1 christos isc_result_totext (eresult));
1583 1.1 christos break;
1584 1.1 christos }
1585 1.1 christos
1586 1.1 christos ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1587 1.1 christos destroy_ddns_cb(ddns_cb, MDL);
1588 1.1 christos /*
1589 1.1 christos * A single DDNS operation may require several calls depending on
1590 1.1 christos * the current state as the prerequisites for the first message
1591 1.1 christos * may not succeed requiring a second operation and potentially
1592 1.1 christos * a ptr operation after that. The commit_leases operation is
1593 1.1 christos * invoked at the end of this set of operations in order to require
1594 1.1 christos * a single write for all of the changes. We call commit_leases
1595 1.1 christos * here rather than immediately after the call to update the lease
1596 1.1 christos * text in order to save any previously written data.
1597 1.1 christos */
1598 1.1 christos commit_leases();
1599 1.1 christos return;
1600 1.1 christos }
1601 1.1 christos
1602 1.1 christos /*
1603 1.1 christos * This action routine is invoked after the DSMM third add stage is
1604 1.1 christos * attempted. If we succeeded we attempt to update the reverse DNS,
1605 1.1 christos * if not we cleanup and leave.
1606 1.1 christos */
1607 1.1 christos void
1608 1.1 christos ddns_fwd_srv_add3(dhcp_ddns_cb_t *ddns_cb,
1609 1.1 christos isc_result_t eresult)
1610 1.1 christos {
1611 1.1 christos isc_result_t result;
1612 1.1 christos const char *logstr = NULL;
1613 1.1 christos char ddns_address[MAX_ADDRESS_STRING_LEN+1];
1614 1.1 christos
1615 1.1 christos #if defined (DEBUG_DNS_UPDATES)
1616 1.1 christos log_info ("DDNS: ddns_fwd_srv_add3: %s eresult: %d",
1617 1.1 christos dump_ddns_cb(ddns_cb), eresult);
1618 1.1 christos #endif
1619 1.1 christos
1620 1.1 christos /* Construct a printable form of the address for logging */
1621 1.1 christos memset(ddns_address, 0x0, sizeof(ddns_address));
1622 1.1 christos strncpy(ddns_address, piaddr(ddns_cb->address),
1623 1.1 christos sizeof(ddns_address) - 1);
1624 1.1 christos
1625 1.1 christos switch(eresult) {
1626 1.1 christos case ISC_R_SUCCESS:
1627 1.1 christos log_info("Added new forward map from %.*s to %s",
1628 1.1 christos (int)ddns_cb->fwd_name.len,
1629 1.1 christos (const char *)ddns_cb->fwd_name.data,
1630 1.1 christos ddns_address);
1631 1.1 christos
1632 1.1 christos ddns_update_lease_text(ddns_cb, NULL);
1633 1.1 christos
1634 1.1 christos if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1635 1.1 christos /* if we have zone information get rid of it */
1636 1.1 christos if (ddns_cb->zone != NULL) {
1637 1.1 christos ddns_cb_forget_zone(ddns_cb);
1638 1.1 christos }
1639 1.1 christos
1640 1.1 christos ddns_cb->state = DDNS_STATE_ADD_PTR;
1641 1.1 christos ddns_cb->cur_func = ddns_ptr_add;
1642 1.1 christos
1643 1.1 christos result = ddns_modify_ptr(ddns_cb, MDL);
1644 1.1 christos if (result == ISC_R_SUCCESS) {
1645 1.1 christos return;
1646 1.1 christos }
1647 1.1 christos }
1648 1.1 christos break;
1649 1.1 christos
1650 1.1 christos case DNS_R_YXRRSET:
1651 1.1 christos logstr = "an entry that is either static or "
1652 1.1 christos "owned by another client exists.";
1653 1.1 christos break;
1654 1.1 christos
1655 1.1 christos case DNS_R_NXRRSET:
1656 1.1 christos logstr = "static entry of the other protocol type exists.";
1657 1.1 christos break;
1658 1.1 christos
1659 1.1 christos default:
1660 1.1 christos logstr = isc_result_totext(eresult);
1661 1.1 christos break;
1662 1.1 christos }
1663 1.1 christos
1664 1.1 christos if (logstr != NULL) {
1665 1.1 christos log_error("Forward map from %.*s to %s FAILED: %s",
1666 1.1 christos (int)ddns_cb->fwd_name.len,
1667 1.1 christos (const char *)ddns_cb->fwd_name.data,
1668 1.1 christos ddns_address, logstr);
1669 1.1 christos }
1670 1.1 christos
1671 1.1 christos ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1672 1.1 christos destroy_ddns_cb(ddns_cb, MDL);
1673 1.1 christos /*
1674 1.1 christos * A single DDNS operation may require several calls depending on
1675 1.1 christos * the current state as the prerequisites for the first message
1676 1.1 christos * may not succeed requiring a second operation and potentially
1677 1.1 christos * a ptr operation after that. The commit_leases operation is
1678 1.1 christos * invoked at the end of this set of operations in order to require
1679 1.1 christos * a single write for all of the changes. We call commit_leases
1680 1.1 christos * here rather than immediately after the call to update the lease
1681 1.1 christos * text in order to save any previously written data.
1682 1.1 christos */
1683 1.1 christos commit_leases();
1684 1.1 christos return;
1685 1.1 christos }
1686 1.1 christos
1687 1.1 christos static void
1688 1.1 christos ddns_fwd_srv_connector(struct lease *lease,
1689 1.1 christos struct iasubopt *lease6,
1690 1.1 christos struct binding_scope **inscope,
1691 1.1 christos dhcp_ddns_cb_t *ddns_cb,
1692 1.1 christos isc_result_t eresult)
1693 1.1 christos {
1694 1.1 christos isc_result_t result = ISC_R_FAILURE;
1695 1.1 christos
1696 1.1 christos #if defined (DEBUG_DNS_UPDATES)
1697 1.1 christos log_info ("DDNS: ddns_fwd_srv_connector: %s eresult: %d",
1698 1.1 christos dump_ddns_cb(ddns_cb), eresult);
1699 1.1 christos #endif
1700 1.1 christos
1701 1.1 christos if (ddns_cb == NULL) {
1702 1.1 christos /* nothing to do */
1703 1.1 christos return;
1704 1.1 christos }
1705 1.1 christos
1706 1.1 christos if (eresult == ISC_R_SUCCESS) {
1707 1.1 christos /*
1708 1.1 christos * If we have updates dispatch as appropriate,
1709 1.1 christos * if not do FQDN binding if desired.
1710 1.1 christos */
1711 1.1 christos
1712 1.1 christos if (ddns_cb->flags & DDNS_UPDATE_ADDR) {
1713 1.1 christos ddns_cb->state = DDNS_STATE_ADD_FW_NXDOMAIN;
1714 1.1 christos ddns_cb->cur_func = ddns_fwd_srv_add1;
1715 1.1 christos result = ddns_modify_fwd(ddns_cb, MDL);
1716 1.1 christos } else if ((ddns_cb->flags & DDNS_UPDATE_PTR) &&
1717 1.1 christos (ddns_cb->rev_name.len != 0)) {
1718 1.1 christos ddns_cb->state = DDNS_STATE_ADD_PTR;
1719 1.1 christos ddns_cb->cur_func = ddns_ptr_add;
1720 1.1 christos result = ddns_modify_ptr(ddns_cb, MDL);
1721 1.1 christos } else {
1722 1.1 christos ddns_update_lease_text(ddns_cb, inscope);
1723 1.1 christos }
1724 1.1 christos }
1725 1.1 christos
1726 1.1 christos
1727 1.1 christos if (result == ISC_R_SUCCESS) {
1728 1.1 christos ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, MDL);
1729 1.1 christos } else {
1730 1.1 christos destroy_ddns_cb(ddns_cb, MDL);
1731 1.1 christos }
1732 1.1 christos
1733 1.1 christos return;
1734 1.1 christos }
1735 1.1 christos
1736 1.1 christos /*
1737 1.1 christos * If the first query fails, the updater MUST NOT delete the DNS name. It
1738 1.1 christos * may be that the host whose lease on the server has expired has moved
1739 1.1 christos * to another network and obtained a lease from a different server,
1740 1.1 christos * which has caused the client's A RR to be replaced. It may also be
1741 1.1 christos * that some other client has been configured with a name that matches
1742 1.1 christos * the name of the DHCP client, and the policy was that the last client
1743 1.1 christos * to specify the name would get the name. In this case, the DHCID RR
1744 1.1 christos * will no longer match the updater's notion of the client-identity of
1745 1.1 christos * the host pointed to by the DNS name.
1746 1.1 christos * -- "Interaction between DHCP and DNS"
1747 1.1 christos */
1748 1.1 christos
1749 1.2 christos static void
1750 1.1 christos ddns_fwd_srv_rem2(dhcp_ddns_cb_t *ddns_cb,
1751 1.1 christos isc_result_t eresult)
1752 1.1 christos {
1753 1.1 christos #if defined (DEBUG_DNS_UPDATES)
1754 1.1 christos log_info ("DDNS: ddns_fwd_srv_rem2: %s eresult: %d",
1755 1.1 christos dump_ddns_cb(ddns_cb), eresult);
1756 1.1 christos #endif
1757 1.1 christos
1758 1.1 christos /*
1759 1.1 christos * To get here we have already managed to remove the A/AAAA
1760 1.1 christos * record and are trying to remove the DHCID/TXT record as well.
1761 1.1 christos * On success (removed DHCID/TXT) or YXRRSET (DHCID/TXT still in
1762 1.1 christos * use by something else) we clean up the lease.
1763 1.1 christos * On some other error we don't clean up the lease and hope that
1764 1.1 christos * if we try this again it will work. An example would be if we
1765 1.1 christos * got a timeout as the DNS server halted between the first and
1766 1.1 christos * second steps. The DNS server would still have the DHCID/TXT
1767 1.1 christos * and we would like to remove that in the future.
1768 1.1 christos *
1769 1.1 christos * On success set the EXECUTE_NEXT flag which triggers any
1770 1.1 christos * add that is next in the chain.
1771 1.1 christos */
1772 1.1 christos if ((eresult == ISC_R_SUCCESS) ||
1773 1.1 christos (eresult == DNS_R_YXRRSET)) {
1774 1.1 christos ddns_update_lease_text(ddns_cb, NULL);
1775 1.1 christos eresult = ISC_R_SUCCESS;
1776 1.1 christos }
1777 1.1 christos
1778 1.1 christos /* Do the next operation */
1779 1.1 christos if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1780 1.1 christos /* if we have zone information get rid of it */
1781 1.1 christos if (ddns_cb->zone != NULL) {
1782 1.1 christos ddns_cb_forget_zone(ddns_cb);
1783 1.1 christos }
1784 1.1 christos
1785 1.1 christos ddns_cb->state = DDNS_STATE_REM_PTR;
1786 1.1 christos ddns_cb->cur_func = ddns_ptr_remove;
1787 1.1 christos if (eresult == ISC_R_SUCCESS)
1788 1.1 christos ddns_cb->flags |= DDNS_EXECUTE_NEXT;
1789 1.1 christos
1790 1.1 christos eresult = ddns_modify_ptr(ddns_cb, MDL);
1791 1.1 christos if (eresult == ISC_R_SUCCESS) {
1792 1.1 christos return;
1793 1.1 christos }
1794 1.1 christos }
1795 1.1 christos
1796 1.1 christos ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1797 1.1 christos ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult);
1798 1.1 christos destroy_ddns_cb(ddns_cb, MDL);
1799 1.1 christos return;
1800 1.1 christos }
1801 1.1 christos
1802 1.1 christos
1803 1.1 christos /*
1804 1.1 christos * First action routine when trying to remove a fwd
1805 1.1 christos * this will be called after the ddns queries have completed
1806 1.1 christos * if we succeeded in removing the fwd we go to the next step (if any)
1807 1.1 christos * if not we cleanup and leave.
1808 1.1 christos */
1809 1.1 christos
1810 1.2 christos static void
1811 1.1 christos ddns_fwd_srv_rem1(dhcp_ddns_cb_t *ddns_cb,
1812 1.1 christos isc_result_t eresult)
1813 1.1 christos {
1814 1.1 christos isc_result_t result = eresult;
1815 1.1 christos char ddns_address[MAX_ADDRESS_STRING_LEN];
1816 1.1 christos
1817 1.1 christos #if defined (DEBUG_DNS_UPDATES)
1818 1.1 christos log_info ("DDNS: ddns_fwd_srv_rem1: %s eresult: %d",
1819 1.1 christos dump_ddns_cb(ddns_cb), eresult);
1820 1.1 christos #endif
1821 1.1 christos
1822 1.1 christos switch(eresult) {
1823 1.1 christos case ISC_R_SUCCESS:
1824 1.1 christos /* Construct a printable form of the address for logging */
1825 1.1 christos strcpy(ddns_address, piaddr(ddns_cb->address));
1826 1.1 christos log_info("Removed forward map from %.*s to %s",
1827 1.1 christos (int)ddns_cb->fwd_name.len,
1828 1.1 christos (const char*)ddns_cb->fwd_name.data,
1829 1.1 christos ddns_address);
1830 1.1 christos
1831 1.1 christos /* Do the second step of the FWD removal */
1832 1.1 christos ddns_cb->state = DDNS_STATE_REM_FW_NXRR;
1833 1.1 christos ddns_cb->cur_func = ddns_fwd_srv_rem2;
1834 1.1 christos result = ddns_modify_fwd(ddns_cb, MDL);
1835 1.1 christos if (result == ISC_R_SUCCESS) {
1836 1.1 christos return;
1837 1.1 christos }
1838 1.1 christos break;
1839 1.1 christos
1840 1.1 christos case DNS_R_NXRRSET:
1841 1.1 christos case DNS_R_NXDOMAIN:
1842 1.1 christos /* A result of not found means rem1 did not find a guard of
1843 1.1 christos * our * type. From this we assume either there are no address
1844 1.1 christos * record(s) of our type to delete or they are unguarded and
1845 1.1 christos * therefore presumed to be static. Either way, we're done
1846 1.1 christos * unless we're in DSMM and ddns-other-guard-is-dynamic is on.
1847 1.1 christos * In which case we need to see if a guard of the other type
1848 1.1 christos * exists, which permits us to delete any address records of
1849 1.1 christos * our type. */
1850 1.1 christos #define DSMM_OGD (DDNS_DUAL_STACK_MIXED_MODE | \
1851 1.1 christos DDNS_OTHER_GUARD_IS_DYNAMIC)
1852 1.1 christos if ((ddns_cb->flags & DSMM_OGD) == DSMM_OGD) {
1853 1.1 christos ddns_cb->state = DDNS_STATE_REM_FW_DSMM_OTHER;
1854 1.1 christos ddns_cb->cur_func = ddns_fwd_srv_rem2;
1855 1.1 christos result = ddns_modify_fwd(ddns_cb, MDL);
1856 1.1 christos if (result == ISC_R_SUCCESS) {
1857 1.1 christos return;
1858 1.1 christos }
1859 1.1 christos break;
1860 1.1 christos }
1861 1.1 christos
1862 1.1 christos ddns_update_lease_text(ddns_cb, NULL);
1863 1.1 christos
1864 1.1 christos #if defined (DEBUG_DNS_UPDATES)
1865 1.1 christos log_info("DDNS: no forward map to remove. %p", ddns_cb);
1866 1.1 christos #endif
1867 1.1 christos /* Trigger the add operation */
1868 1.1 christos eresult = ISC_R_SUCCESS;
1869 1.1 christos
1870 1.1 christos /* Fall through */
1871 1.1 christos default:
1872 1.1 christos
1873 1.1 christos /* We do the remove operation in most cases
1874 1.1 christos * but we don't want to continue with adding a forward
1875 1.1 christos * record if the forward removal had issues so we
1876 1.1 christos * check the eresult and set the EXECUTE_NEXT flag on
1877 1.1 christos * success.
1878 1.1 christos */
1879 1.1 christos
1880 1.1 christos /* Do the remove operation */
1881 1.1 christos if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
1882 1.1 christos /* if we have zone information get rid of it */
1883 1.1 christos if (ddns_cb->zone != NULL) {
1884 1.1 christos ddns_cb_forget_zone(ddns_cb);
1885 1.1 christos }
1886 1.1 christos
1887 1.1 christos ddns_cb->state = DDNS_STATE_REM_PTR;
1888 1.1 christos ddns_cb->cur_func = ddns_ptr_remove;
1889 1.1 christos if (eresult == ISC_R_SUCCESS)
1890 1.1 christos ddns_cb->flags |= DDNS_EXECUTE_NEXT;
1891 1.1 christos
1892 1.1 christos result = ddns_modify_ptr(ddns_cb, MDL);
1893 1.1 christos if (result == ISC_R_SUCCESS) {
1894 1.1 christos return;
1895 1.1 christos }
1896 1.1 christos }
1897 1.1 christos break;
1898 1.1 christos }
1899 1.1 christos
1900 1.1 christos ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
1901 1.1 christos ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult);
1902 1.1 christos destroy_ddns_cb(ddns_cb, MDL);
1903 1.1 christos }
1904 1.1 christos
1905 1.1 christos /*%<
1906 1.1 christos * Remove relevant entries from DNS.
1907 1.1 christos *
1908 1.1 christos * \li lease - lease to start with if this is for v4
1909 1.1 christos *
1910 1.1 christos * \li lease6 - lease to start with if this is for v6
1911 1.1 christos *
1912 1.1 christos * \li add_ddns_cb - control block for additional DDNS work. This
1913 1.1 christos * is used when the code is going to add a DDNS entry after removing
1914 1.1 christos * the current entry.
1915 1.1 christos *
1916 1.1 christos * \li active - indication about the status of the lease. It is
1917 1.1 christos * ISC_TRUE if the lease is still active, and FALSE if the lease
1918 1.1 christos * is inactive. This is used to indicate if the lease is inactive or going
1919 1.1 christos * to inactive so we can avoid trying to update the lease with cb pointers
1920 1.1 christos * and text information if it isn't useful.
1921 1.1 christos *
1922 1.1 christos * Returns
1923 1.1 christos * \li #ISC_R_FAILURE - badness occurred and we weren't able to do what was wanted
1924 1.1 christos * \li #ISC_R_SUCCESS - we were able to do stuff but it's in progress
1925 1.1 christos *
1926 1.1 christos * in both cases any additional block has been passed on to it's handler
1927 1.1 christos */
1928 1.1 christos
1929 1.1 christos isc_result_t
1930 1.1 christos ddns_removals(struct lease *lease,
1931 1.1 christos struct iasubopt *lease6,
1932 1.1 christos dhcp_ddns_cb_t *add_ddns_cb,
1933 1.1 christos isc_boolean_t active)
1934 1.1 christos {
1935 1.1 christos isc_result_t rcode, execute_add = ISC_R_FAILURE;
1936 1.1 christos struct binding_scope **scope = NULL;
1937 1.1 christos isc_result_t result = ISC_R_FAILURE;
1938 1.1 christos dhcp_ddns_cb_t *ddns_cb = NULL;
1939 1.1 christos struct data_string leaseid;
1940 1.1 christos
1941 1.1 christos #if defined (DEBUG_DNS_UPDATES)
1942 1.1 christos log_info ("DDNS: ddns_removals: %s",
1943 1.1 christos dump_ddns_cb(add_ddns_cb));
1944 1.1 christos #endif
1945 1.1 christos
1946 1.1 christos /*
1947 1.1 christos * See if we need to cancel an outstanding request. Mostly this is
1948 1.1 christos * used to handle the case where this routine is called twice for
1949 1.1 christos * the same release or abandon event.
1950 1.1 christos *
1951 1.1 christos * When called from the dns code as part of an update request
1952 1.1 christos * (add_ddns_cb != NULL) any outstanding requests will have already
1953 1.1 christos * been cancelled.
1954 1.1 christos *
1955 1.1 christos * If the new request is just a removal and we have an outstanding
1956 1.1 christos * request we have several options:
1957 1.1 christos *
1958 1.1 christos * - we are doing an update or we are doing a removal and the active
1959 1.1 christos * flag has changed from TRUE to FALSE. In these cases we need to
1960 1.1 christos * cancel the old request and start the new one.
1961 1.1 christos *
1962 1.1 christos * - other wise we are doing a removal with the active flag unchanged.
1963 1.1 christos * In this case we can let the current removal continue and do not need
1964 1.1 christos * to start a new one. If the old request included an update to be
1965 1.1 christos * done after the removal we need to kill the update part of the
1966 1.1 christos * request.
1967 1.1 christos */
1968 1.1 christos
1969 1.1 christos if (add_ddns_cb == NULL) {
1970 1.1 christos if ((lease != NULL) && (lease->ddns_cb != NULL)) {
1971 1.1 christos ddns_cb = lease->ddns_cb;
1972 1.1 christos
1973 1.1 christos /*
1974 1.1 christos * Is the old request an update or did the
1975 1.1 christos * the active flag change?
1976 1.1 christos */
1977 1.1 christos if (((ddns_cb->state == DDNS_STATE_ADD_PTR) ||
1978 1.1 christos (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) ||
1979 1.1 christos (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) ||
1980 1.1 christos ((active == ISC_FALSE) &&
1981 1.1 christos ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) {
1982 1.1 christos /* Cancel the current request */
1983 1.1 christos ddns_cancel(lease->ddns_cb, MDL);
1984 1.1 christos lease->ddns_cb = NULL;
1985 1.1 christos } else {
1986 1.1 christos /* Remvoval, check and remove updates */
1987 1.1 christos if (ddns_cb->next_op != NULL) {
1988 1.1 christos destroy_ddns_cb(ddns_cb->next_op, MDL);
1989 1.1 christos ddns_cb->next_op = NULL;
1990 1.1 christos }
1991 1.1 christos #if defined (DEBUG_DNS_UPDATES)
1992 1.1 christos log_info("DDNS %s(%d): removal already in "
1993 1.1 christos "progress new ddns_cb=%p",
1994 1.1 christos MDL, ddns_cb);
1995 1.1 christos #endif
1996 1.1 christos return (ISC_R_SUCCESS);
1997 1.1 christos }
1998 1.1 christos } else if ((lease6 != NULL) && (lease6->ddns_cb != NULL)) {
1999 1.1 christos ddns_cb = lease6->ddns_cb;
2000 1.1 christos
2001 1.1 christos /*
2002 1.1 christos * Is the old request an update or did the
2003 1.1 christos * the active flag change?
2004 1.1 christos */
2005 1.1 christos if (((ddns_cb->state == DDNS_STATE_ADD_PTR) ||
2006 1.1 christos (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) ||
2007 1.1 christos (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) ||
2008 1.1 christos ((active == ISC_FALSE) &&
2009 1.1 christos ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) {
2010 1.1 christos /* Cancel the current request */
2011 1.1 christos ddns_cancel(lease6->ddns_cb, MDL);
2012 1.1 christos lease6->ddns_cb = NULL;
2013 1.1 christos } else {
2014 1.1 christos /* Remvoval, check and remove updates */
2015 1.1 christos if (ddns_cb->next_op != NULL) {
2016 1.1 christos destroy_ddns_cb(ddns_cb->next_op, MDL);
2017 1.1 christos ddns_cb->next_op = NULL;
2018 1.1 christos }
2019 1.1 christos #if defined (DEBUG_DNS_UPDATES)
2020 1.1 christos log_info("DDNS %s(%d): removal already in "
2021 1.1 christos "progress new ddns_cb=%p",
2022 1.1 christos MDL, ddns_cb);
2023 1.1 christos #endif
2024 1.1 christos return (ISC_R_SUCCESS);
2025 1.1 christos }
2026 1.1 christos }
2027 1.1 christos ddns_cb = NULL;
2028 1.1 christos }
2029 1.1 christos
2030 1.1 christos /* allocate our control block */
2031 1.1 christos ddns_cb = ddns_cb_alloc(MDL);
2032 1.1 christos if (ddns_cb == NULL) {
2033 1.1 christos goto cleanup;
2034 1.1 christos }
2035 1.1 christos
2036 1.1 christos /* Set the conflict detection flags based on global configuration */
2037 1.1 christos copy_conflict_flags(&ddns_cb->flags, ddns_conflict_mask);
2038 1.1 christos
2039 1.1 christos /*
2040 1.1 christos * For v4 we flag static leases so we don't try
2041 1.1 christos * and manipulate the lease later. For v6 we don't
2042 1.1 christos * get static leases and don't need to flag them.
2043 1.1 christos */
2044 1.1 christos if (lease != NULL) {
2045 1.1 christos scope = &(lease->scope);
2046 1.1 christos ddns_cb->address = lease->ip_addr;
2047 1.1 christos if (lease->flags & STATIC_LEASE)
2048 1.1 christos ddns_cb->flags |= DDNS_STATIC_LEASE;
2049 1.1 christos } else if (lease6 != NULL) {
2050 1.1 christos scope = &(lease6->scope);
2051 1.1 christos memcpy(&ddns_cb->address.iabuf, lease6->addr.s6_addr, 16);
2052 1.1 christos ddns_cb->address.len = 16;
2053 1.1 christos } else
2054 1.1 christos goto cleanup;
2055 1.1 christos
2056 1.1 christos /*
2057 1.1 christos * Set the flag bit if the lease is active, that is it isn't
2058 1.1 christos * expired or released. This is used to determine if we need
2059 1.1 christos * to update the scope information for both v4 and v6 and
2060 1.1 christos * the lease information for v6 when the response
2061 1.1 christos * from the DNS code is processed.
2062 1.1 christos */
2063 1.1 christos if (active == ISC_TRUE) {
2064 1.1 christos ddns_cb->flags |= DDNS_ACTIVE_LEASE;
2065 1.1 christos }
2066 1.1 christos
2067 1.1 christos /* No scope implies that DDNS has not been performed for this lease. */
2068 1.1 christos if (*scope == NULL)
2069 1.1 christos goto cleanup;
2070 1.1 christos
2071 1.1 christos if ((ddns_update_style != DDNS_UPDATE_STYLE_STANDARD) &&
2072 1.1 christos (ddns_update_style != DDNS_UPDATE_STYLE_INTERIM))
2073 1.1 christos goto cleanup;
2074 1.1 christos
2075 1.1 christos /* Assume that we are removing both records */
2076 1.1 christos ddns_cb->flags |= DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR;
2077 1.1 christos
2078 1.1 christos /* and that we want to do the add call */
2079 1.1 christos execute_add = ISC_R_SUCCESS;
2080 1.1 christos
2081 1.1 christos /*
2082 1.1 christos * Look up stored names.
2083 1.1 christos */
2084 1.1 christos
2085 1.1 christos /*
2086 1.1 christos * Find the fwd name and copy it to the control block. If we don't
2087 1.1 christos * have it we can't delete the fwd record but we can still try to
2088 1.1 christos * remove the ptr record and cleanup the lease information if the
2089 1.1 christos * client did the fwd update.
2090 1.1 christos */
2091 1.1 christos if (!find_bound_string(&ddns_cb->fwd_name, *scope, "ddns-fwd-name")) {
2092 1.1 christos /* don't try and delete the A, or do the add */
2093 1.1 christos ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
2094 1.1 christos execute_add = ISC_R_FAILURE;
2095 1.1 christos
2096 1.1 christos /* Check if client did update */
2097 1.1 christos if (find_bound_string(&ddns_cb->fwd_name, *scope,
2098 1.1 christos "ddns-client-fqdn")) {
2099 1.1 christos ddns_cb->flags |= DDNS_CLIENT_DID_UPDATE;
2100 1.1 christos }
2101 1.1 christos }
2102 1.1 christos
2103 1.1 christos /*
2104 1.1 christos * Find the txt or dhcid tag and copy it to the control block. If we
2105 1.1 christos * don't have one this isn't an interim or standard record so we can't
2106 1.1 christos * delete the A record using this mechanism but we can delete the ptr
2107 1.1 christos * record. In this case we will attempt to do any requested next step.
2108 1.1 christos */
2109 1.1 christos memset(&leaseid, 0, sizeof(leaseid));
2110 1.1 christos if (find_bound_string (&leaseid, *scope, ddns_standard_tag)) {
2111 1.1 christos /* We have a standard tag */
2112 1.1 christos ddns_cb->lease_tag = ddns_standard_tag;
2113 1.1 christos ddns_cb->dhcid_class = dns_rdatatype_dhcid;
2114 1.1 christos ddns_cb->other_dhcid_class = dns_rdatatype_txt;
2115 1.1 christos data_string_copy(&ddns_cb->dhcid, &leaseid, MDL);
2116 1.1 christos data_string_forget(&leaseid, MDL);
2117 1.1 christos } else if (find_bound_string (&leaseid, *scope, ddns_interim_tag)) {
2118 1.1 christos /* we have an interim tag */
2119 1.1 christos ddns_cb->lease_tag = ddns_interim_tag;
2120 1.1 christos ddns_cb->dhcid_class = dns_rdatatype_txt;
2121 1.1 christos ddns_cb->other_dhcid_class = dns_rdatatype_dhcid;
2122 1.1 christos if (dhcid_fromlease(&ddns_cb->dhcid, &leaseid) !=
2123 1.1 christos ISC_R_SUCCESS) {
2124 1.1 christos /* We couldn't convert the dhcid from the lease
2125 1.1 christos * version to the dns version. We can't delete
2126 1.1 christos * the A record but can continue to the ptr
2127 1.1 christos */
2128 1.1 christos ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
2129 1.1 christos }
2130 1.1 christos data_string_forget(&leaseid, MDL);
2131 1.1 christos } else {
2132 1.1 christos ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
2133 1.1 christos }
2134 1.1 christos
2135 1.1 christos /*
2136 1.1 christos * Find the rev name and copy it to the control block. If we don't
2137 1.1 christos * have it we can't get rid of it but we can try to remove the fwd
2138 1.1 christos * pointer if desired.
2139 1.1 christos */
2140 1.1 christos if (!find_bound_string(&ddns_cb->rev_name, *scope, "ddns-rev-name")) {
2141 1.1 christos ddns_cb->flags &= ~DDNS_UPDATE_PTR;
2142 1.1 christos }
2143 1.1 christos
2144 1.1 christos
2145 1.1 christos /*
2146 1.1 christos * If we have a second control block for doing an add
2147 1.1 christos * after the remove finished attach it to our control block.
2148 1.1 christos */
2149 1.1 christos ddns_cb->next_op = add_ddns_cb;
2150 1.1 christos
2151 1.1 christos /*
2152 1.1 christos * Now that we've collected the information we can try to process it.
2153 1.1 christos * If necessary we call an appropriate routine to send a message and
2154 1.1 christos * provide it with an action routine to run on the control block given
2155 1.1 christos * the results of the message. We have three entry points from here,
2156 1.1 christos * one for removing the A record, the next for removing the PTR and
2157 1.1 christos * the third for doing any requested add.
2158 1.1 christos */
2159 1.1 christos if ((ddns_cb->flags & DDNS_UPDATE_ADDR) != 0) {
2160 1.1 christos if (ddns_cb->fwd_name.len != 0) {
2161 1.1 christos ddns_cb->state = DDNS_STATE_REM_FW_YXDHCID;
2162 1.1 christos ddns_cb->cur_func = ddns_fwd_srv_rem1;
2163 1.1 christos
2164 1.1 christos rcode = ddns_modify_fwd(ddns_cb, MDL);
2165 1.1 christos if (rcode == ISC_R_SUCCESS) {
2166 1.1 christos ddns_update_lease_ptr(lease, lease6, ddns_cb,
2167 1.1 christos ddns_cb, MDL);
2168 1.1 christos return (ISC_R_SUCCESS);
2169 1.1 christos }
2170 1.1 christos
2171 1.1 christos /*
2172 1.1 christos * We weren't able to process the request tag the
2173 1.1 christos * add so we won't execute it.
2174 1.1 christos */
2175 1.1 christos execute_add = ISC_R_FAILURE;
2176 1.1 christos goto cleanup;
2177 1.1 christos }
2178 1.1 christos else {
2179 1.1 christos /*remove info from scope */
2180 1.1 christos unset(*scope, "ddns-fwd-name");
2181 1.1 christos unset(*scope, ddns_cb->lease_tag);
2182 1.1 christos }
2183 1.1 christos }
2184 1.1 christos
2185 1.1 christos if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
2186 1.1 christos ddns_cb->state = DDNS_STATE_REM_PTR;
2187 1.1 christos ddns_cb->cur_func = ddns_ptr_remove;
2188 1.1 christos ddns_cb->flags |= DDNS_EXECUTE_NEXT;
2189 1.1 christos
2190 1.1 christos /*
2191 1.1 christos * if execute add isn't success remove the control block so
2192 1.1 christos * it won't be processed when the remove completes. We
2193 1.1 christos * also arrange to clean it up and get rid of it.
2194 1.1 christos */
2195 1.1 christos if (execute_add != ISC_R_SUCCESS) {
2196 1.1 christos ddns_cb->next_op = NULL;
2197 1.1 christos ddns_fwd_srv_connector(lease, lease6, scope,
2198 1.1 christos add_ddns_cb, execute_add);
2199 1.1 christos add_ddns_cb = NULL;
2200 1.1 christos }
2201 1.1 christos else {
2202 1.1 christos result = ISC_R_SUCCESS;
2203 1.1 christos }
2204 1.1 christos
2205 1.1 christos rcode = ddns_modify_ptr(ddns_cb, MDL);
2206 1.1 christos if (rcode == ISC_R_SUCCESS) {
2207 1.1 christos ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb,
2208 1.1 christos MDL);
2209 1.1 christos return (result);
2210 1.1 christos }
2211 1.1 christos
2212 1.1 christos /* We weren't able to process the request tag the
2213 1.1 christos * add so we won't execute it */
2214 1.1 christos execute_add = ISC_R_FAILURE;
2215 1.1 christos goto cleanup;
2216 1.1 christos }
2217 1.1 christos
2218 1.1 christos cleanup:
2219 1.1 christos /*
2220 1.1 christos * We've gotten here because we didn't need to send a message or
2221 1.1 christos * we failed when trying to do so. We send the additional cb
2222 1.1 christos * off to handle sending and/or cleanup and cleanup anything
2223 1.1 christos * we allocated here.
2224 1.1 christos */
2225 1.1 christos ddns_fwd_srv_connector(lease, lease6, scope, add_ddns_cb, execute_add);
2226 1.1 christos if (ddns_cb != NULL)
2227 1.1 christos destroy_ddns_cb(ddns_cb, MDL);
2228 1.1 christos
2229 1.1 christos return (result);
2230 1.1 christos }
2231 1.1 christos
2232 1.1 christos /* Convenience function for setting flag bits in a mask */
2233 1.2 christos static void
2234 1.2 christos set_flag (u_int16_t *flags,
2235 1.1 christos u_int16_t flag,
2236 1.1 christos u_int16_t value) {
2237 1.1 christos if (flags) {
2238 1.1 christos if (value) {
2239 1.1 christos *flags |= flag;
2240 1.1 christos } else {
2241 1.1 christos *flags &= ~flag;
2242 1.1 christos }
2243 1.1 christos }
2244 1.1 christos }
2245 1.1 christos
2246 1.1 christos /*
2247 1.1 christos * Convenience function which replicates the conflict flags set in one
2248 1.1 christos * mask to another, while preserving all other flags.
2249 1.1 christos */
2250 1.1 christos void copy_conflict_flags(u_int16_t *target,
2251 1.1 christos u_int16_t source) {
2252 1.1 christos if (target) {
2253 1.1 christos /* Preserve non conflict flags */
2254 1.1 christos *target &= ~CONFLICT_BITS;
2255 1.1 christos
2256 1.1 christos /* Enable conflict flags per source */
2257 1.1 christos *target |= source & CONFLICT_BITS;
2258 1.1 christos }
2259 1.1 christos }
2260 1.1 christos
2261 1.1 christos /*
2262 1.1 christos * Given an option_state, create a mask of conflict detection flags based
2263 1.1 christos * on the appropriate configuration parameters within the option state.
2264 1.1 christos */
2265 1.1 christos u_int16_t
2266 1.1 christos get_conflict_mask(struct option_state *options) {
2267 1.1 christos
2268 1.1 christos int ddns_update_conflict_detection = 1; /* default on */
2269 1.1 christos int ddns_dual_stack_mixed_mode = 0; /* default off */
2270 1.1 christos int ddns_guard_id_must_match = 1; /* default on */
2271 1.1 christos int ddns_other_guard_is_dynamic = 0; /* default off */
2272 1.1 christos struct option_cache *oc = NULL;
2273 1.1 christos
2274 1.1 christos u_int16_t mask = 0;
2275 1.1 christos oc = lookup_option(&server_universe, options, SV_DDNS_CONFLICT_DETECT);
2276 1.1 christos if (oc) {
2277 1.1 christos ddns_update_conflict_detection =
2278 1.1 christos evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options,
2279 1.1 christos NULL, &global_scope, oc, MDL);
2280 1.1 christos }
2281 1.1 christos
2282 1.1 christos set_flag(&mask, DDNS_CONFLICT_DETECTION,
2283 1.1 christos ddns_update_conflict_detection);
2284 1.1 christos
2285 1.1 christos if (!ddns_update_conflict_detection) {
2286 1.1 christos #if defined (DEBUG_DNS_UPDATES)
2287 1.1 christos log_info ("DDNS conflict detection: off");
2288 1.1 christos #endif
2289 1.1 christos /* Turn the rest of the conflict related flags off */
2290 1.1 christos set_flag(&mask, DDNS_DUAL_STACK_MIXED_MODE, 0);
2291 1.1 christos set_flag(&mask, DDNS_GUARD_ID_MUST_MATCH, 0);
2292 1.1 christos set_flag(&mask, DDNS_OTHER_GUARD_IS_DYNAMIC, 0);
2293 1.1 christos return (mask);
2294 1.1 christos }
2295 1.1 christos
2296 1.1 christos // Get the values
2297 1.1 christos oc = lookup_option(&server_universe, options,
2298 1.1 christos SV_DDNS_DUAL_STACK_MIXED_MODE);
2299 1.1 christos if (oc) {
2300 1.1 christos ddns_dual_stack_mixed_mode =
2301 1.1 christos evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options,
2302 1.1 christos NULL, &global_scope, oc, MDL);
2303 1.1 christos }
2304 1.1 christos
2305 1.1 christos oc = lookup_option(&server_universe, options,
2306 1.1 christos SV_DDNS_GUARD_ID_MUST_MATCH);
2307 1.1 christos if (oc) {
2308 1.1 christos ddns_guard_id_must_match =
2309 1.1 christos evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options,
2310 1.1 christos NULL, &global_scope, oc, MDL);
2311 1.1 christos }
2312 1.1 christos
2313 1.1 christos oc = lookup_option(&server_universe, options,
2314 1.1 christos SV_DDNS_OTHER_GUARD_IS_DYNAMIC);
2315 1.1 christos if (oc) {
2316 1.1 christos ddns_other_guard_is_dynamic =
2317 1.1 christos evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options,
2318 1.1 christos NULL, &global_scope, oc, MDL);
2319 1.1 christos }
2320 1.1 christos
2321 1.1 christos // Set the flags
2322 1.1 christos set_flag(&mask, DDNS_DUAL_STACK_MIXED_MODE,
2323 1.1 christos ddns_dual_stack_mixed_mode);
2324 1.1 christos
2325 1.1 christos set_flag(&mask, DDNS_GUARD_ID_MUST_MATCH,
2326 1.1 christos ddns_guard_id_must_match);
2327 1.1 christos
2328 1.1 christos set_flag(&mask, DDNS_OTHER_GUARD_IS_DYNAMIC,
2329 1.1 christos ddns_other_guard_is_dynamic);
2330 1.1 christos
2331 1.1 christos #if defined (DEBUG_DNS_UPDATES)
2332 1.1 christos log_info ("DDNS conflict behavior:\n"
2333 1.1 christos "\tddns-update-style: %s\n"
2334 1.1 christos "\tupdate-conflict-detection: %d\n"
2335 1.1 christos "\tddns-dual-stack-mixed-mode: %d\n"
2336 1.1 christos "\tddns-guard-id-must-match %d\n"
2337 1.1 christos "\tddns-other-guard-is-dynamic: %d\n",
2338 1.1 christos ddns_styles_values[ddns_update_style].name,
2339 1.1 christos ddns_update_conflict_detection,
2340 1.1 christos ddns_dual_stack_mixed_mode,
2341 1.1 christos ddns_guard_id_must_match,
2342 1.1 christos ddns_other_guard_is_dynamic);
2343 1.1 christos #endif
2344 1.1 christos return (mask);
2345 1.1 christos }
2346 1.1 christos
2347 1.1 christos #if defined (DEBUG_DNS_UPDATES)
2348 1.1 christos /* Type used for creating lists of function pointers and their names */
2349 1.1 christos typedef struct {
2350 1.1 christos void *ptr;
2351 1.1 christos char *name;
2352 1.1 christos } LabeledPtr;
2353 1.1 christos
2354 1.1 christos /* Returns the name of the function referred to by the given address */
2355 1.1 christos char*
2356 1.1 christos dump_ddns_cb_func(void *func) {
2357 1.1 christos static LabeledPtr funcs[] = {
2358 1.1 christos { ddns_ptr_add, "ddns_ptr_add" },
2359 1.1 christos { ddns_fwd_srv_add2, "ddns_fwd_srv_add2" },
2360 1.1 christos { ddns_fwd_srv_add1, "ddns_fwd_srv_add1" },
2361 1.1 christos { ddns_ptr_remove, "ddns_ptr_remove" },
2362 1.1 christos { ddns_fwd_srv_rem2, "ddns_fwd_srv_rem2" },
2363 1.1 christos { ddns_fwd_srv_rem1, "ddns_fwd_srv_rem1" },
2364 1.1 christos { ddns_fwd_srv_add3, "ddns_fwd_srv_adde" },
2365 1.1 christos { NULL, "unknown" }
2366 1.1 christos };
2367 1.1 christos
2368 1.1 christos LabeledPtr* lp = funcs;
2369 1.1 christos if (!func) {
2370 1.1 christos return ("<null>");
2371 1.1 christos }
2372 1.1 christos
2373 1.1 christos while ((lp->ptr) && (lp->ptr != func)) {
2374 1.1 christos ++lp;
2375 1.1 christos }
2376 1.1 christos
2377 1.1 christos return (lp->name);
2378 1.1 christos }
2379 1.1 christos
2380 1.1 christos /* Dumps basic control block info to the log */
2381 1.1 christos char*
2382 1.1 christos dump_ddns_cb (dhcp_ddns_cb_t *ddns_cb) {
2383 1.1 christos static char output_buf[4096];
2384 1.1 christos if (!ddns_cb) {
2385 1.1 christos return ("<ddns_cb is null>");
2386 1.1 christos }
2387 1.1 christos
2388 1.1 christos sprintf (output_buf, "ddns_cb: %p flags: %x state: %s cur_func: %s",
2389 1.1 christos ddns_cb, ddns_cb->flags,
2390 1.1 christos ddns_state_name(ddns_cb->state),
2391 1.1 christos dump_ddns_cb_func(ddns_cb->cur_func));
2392 1.1 christos
2393 1.1 christos return(output_buf);
2394 1.1 christos }
2395 1.1 christos #endif /* DEBUG_DNS_UPDATES */
2396 1.1 christos
2397 1.1 christos #endif /* NSUPDATE */
2398