1 1.2 christos /* $NetBSD: ddns.c,v 1.4 2022/04/03 01:10:59 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.4 christos * Copyright (C) 2004-2022 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.4 christos * PO Box 360 26 1.4 christos * Newmarket, NH 03857 USA 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.4 2022/04/03 01:10:59 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.3 christos * not reached when update_lease_failed is called, 1296 1.3 christos * it calls log_fatal. 1297 1.1 christos */ 1298 1.3 christos ipv6_pool_dereference(&pool, MDL); 1299 1.1 christos return(ISC_R_FAILURE); 1300 1.1 christos } 1301 1.1 christos ipv6_pool_dereference(&pool, MDL); 1302 1.1 christos } else { 1303 1.1 christos /* shouldn't get here */ 1304 1.1 christos log_fatal("Impossible condition at %s:%d, called from %s:%d.", 1305 1.1 christos MDL, file, line); 1306 1.1 christos } 1307 1.1 christos 1308 1.1 christos return(ISC_R_SUCCESS); 1309 1.1 christos } 1310 1.1 christos 1311 1.2 christos static void 1312 1.1 christos ddns_ptr_add(dhcp_ddns_cb_t *ddns_cb, 1313 1.1 christos isc_result_t eresult) 1314 1.1 christos { 1315 1.1 christos if (eresult == ISC_R_SUCCESS) { 1316 1.1 christos log_info("Added reverse map from %.*s to %.*s", 1317 1.1 christos (int)ddns_cb->rev_name.len, 1318 1.1 christos (const char *)ddns_cb->rev_name.data, 1319 1.1 christos (int)ddns_cb->fwd_name.len, 1320 1.1 christos (const char *)ddns_cb->fwd_name.data); 1321 1.1 christos 1322 1.1 christos ddns_update_lease_text(ddns_cb, NULL); 1323 1.1 christos } else { 1324 1.1 christos log_error("Unable to add reverse map from %.*s to %.*s: %s", 1325 1.1 christos (int)ddns_cb->rev_name.len, 1326 1.1 christos (const char *)ddns_cb->rev_name.data, 1327 1.1 christos (int)ddns_cb->fwd_name.len, 1328 1.1 christos (const char *)ddns_cb->fwd_name.data, 1329 1.1 christos isc_result_totext (eresult)); 1330 1.1 christos } 1331 1.1 christos 1332 1.1 christos ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); 1333 1.1 christos destroy_ddns_cb(ddns_cb, MDL); 1334 1.1 christos /* 1335 1.1 christos * A single DDNS operation may require several calls depending on 1336 1.1 christos * the current state as the prerequisites for the first message 1337 1.1 christos * may not succeed requiring a second operation and potentially 1338 1.1 christos * a ptr operation after that. The commit_leases operation is 1339 1.1 christos * invoked at the end of this set of operations in order to require 1340 1.1 christos * a single write for all of the changes. We call commit_leases 1341 1.1 christos * here rather than immediately after the call to update the lease 1342 1.1 christos * text in order to save any previously written data. 1343 1.1 christos */ 1344 1.1 christos commit_leases(); 1345 1.1 christos return; 1346 1.1 christos } 1347 1.1 christos 1348 1.1 christos /* 1349 1.1 christos * action routine when trying to remove a pointer 1350 1.1 christos * this will be called after the ddns queries have completed 1351 1.1 christos * if we succeeded in removing the pointer we go to the next step (if any) 1352 1.1 christos * if not we cleanup and leave. 1353 1.1 christos */ 1354 1.1 christos 1355 1.2 christos static void 1356 1.1 christos ddns_ptr_remove(dhcp_ddns_cb_t *ddns_cb, 1357 1.1 christos isc_result_t eresult) 1358 1.1 christos { 1359 1.1 christos isc_result_t result = eresult; 1360 1.1 christos 1361 1.1 christos switch(eresult) { 1362 1.1 christos case ISC_R_SUCCESS: 1363 1.1 christos log_info("Removed reverse map on %.*s", 1364 1.1 christos (int)ddns_cb->rev_name.len, 1365 1.1 christos (const char *)ddns_cb->rev_name.data); 1366 1.1 christos /* fall through */ 1367 1.1 christos case DNS_R_NXRRSET: 1368 1.1 christos case DNS_R_NXDOMAIN: 1369 1.1 christos /* No entry is the same as success. 1370 1.1 christos * Remove the information from the lease and 1371 1.1 christos * continue with any next step */ 1372 1.1 christos ddns_update_lease_text(ddns_cb, NULL); 1373 1.1 christos 1374 1.1 christos /* trigger any add operation */ 1375 1.1 christos result = ISC_R_SUCCESS; 1376 1.1 christos #if defined (DEBUG_DNS_UPDATES) 1377 1.1 christos log_info("DDNS: removed map or no reverse map to remove %.*s", 1378 1.1 christos (int)ddns_cb->rev_name.len, 1379 1.1 christos (const char *)ddns_cb->rev_name.data); 1380 1.1 christos #endif 1381 1.1 christos break; 1382 1.1 christos 1383 1.1 christos default: 1384 1.1 christos log_error("Can't remove reverse map on %.*s: %s", 1385 1.1 christos (int)ddns_cb->rev_name.len, 1386 1.1 christos (const char *)ddns_cb->rev_name.data, 1387 1.1 christos isc_result_totext (eresult)); 1388 1.1 christos break; 1389 1.1 christos } 1390 1.1 christos 1391 1.1 christos /* If we aren't suppossed to do the next step, set the result 1392 1.1 christos * flag so ddns_fwd_srv_connector won't do much 1393 1.1 christos */ 1394 1.1 christos if ((ddns_cb->flags & DDNS_EXECUTE_NEXT) == 0) 1395 1.1 christos result = ISC_R_FAILURE; 1396 1.1 christos 1397 1.1 christos ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); 1398 1.1 christos ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, result); 1399 1.1 christos destroy_ddns_cb(ddns_cb, MDL); 1400 1.1 christos return; 1401 1.1 christos } 1402 1.1 christos 1403 1.1 christos 1404 1.1 christos /* 1405 1.1 christos * If the first query succeeds, the updater can conclude that it 1406 1.1 christos * has added a new name whose only RRs are the A and DHCID RR records. 1407 1.1 christos * The A RR update is now complete (and a client updater is finished, 1408 1.1 christos * while a server might proceed to perform a PTR RR update). 1409 1.1 christos * -- "Interaction between DHCP and DNS" 1410 1.1 christos * 1411 1.1 christos * If the second query succeeds, the updater can conclude that the current 1412 1.1 christos * client was the last client associated with the domain name, and that 1413 1.1 christos * the name now contains the updated A RR. The A RR update is now 1414 1.1 christos * complete (and a client updater is finished, while a server would 1415 1.1 christos * then proceed to perform a PTR RR update). 1416 1.1 christos * -- "Interaction between DHCP and DNS" 1417 1.1 christos * 1418 1.1 christos * If the second query fails with NXRRSET, the updater must conclude 1419 1.1 christos * that the client's desired name is in use by another host. If 1420 1.1 christos * Dual Stack Mixed Mode (DSMM) is enabled and we proceed to a 1421 1.1 christos * third stage forward update attempt specific to DSMM rules. If not, 1422 1.1 christos * then the existing entries are left intact: 1423 1.1 christos * 1424 1.1 christos * At this juncture, the updater can decide (based on some administrative 1425 1.1 christos * configuration outside of the scope of this document) whether to let 1426 1.1 christos * the existing owner of the name keep that name, and to (possibly) 1427 1.1 christos * perform some name disambiguation operation on behalf of the current 1428 1.1 christos * client, or to replace the RRs on the name with RRs that represent 1429 1.1 christos * the current client. If the configured policy allows replacement of 1430 1.1 christos * existing records, the updater submits a query that deletes the 1431 1.1 christos * existing A RR and the existing DHCID RR, adding A and DHCID RRs that 1432 1.1 christos * represent the IP address and client-identity of the new client. 1433 1.1 christos * -- "Interaction between DHCP and DNS" 1434 1.1 christos */ 1435 1.1 christos 1436 1.2 christos static void 1437 1.1 christos ddns_fwd_srv_add2(dhcp_ddns_cb_t *ddns_cb, 1438 1.1 christos isc_result_t eresult) 1439 1.1 christos { 1440 1.1 christos isc_result_t result; 1441 1.1 christos const char *logstr = NULL; 1442 1.1 christos char ddns_address[MAX_ADDRESS_STRING_LEN]; 1443 1.1 christos 1444 1.1 christos #if defined (DEBUG_DNS_UPDATES) 1445 1.1 christos log_info ("DDNS:ddns_fwd_srv_add2: %s eresult: %d", 1446 1.1 christos dump_ddns_cb(ddns_cb), eresult); 1447 1.1 christos #endif 1448 1.1 christos 1449 1.1 christos /* Construct a printable form of the address for logging */ 1450 1.1 christos strcpy(ddns_address, piaddr(ddns_cb->address)); 1451 1.1 christos 1452 1.1 christos switch(eresult) { 1453 1.1 christos case ISC_R_SUCCESS: 1454 1.1 christos log_info("Added new forward map from %.*s to %s", 1455 1.1 christos (int)ddns_cb->fwd_name.len, 1456 1.1 christos (const char *)ddns_cb->fwd_name.data, 1457 1.1 christos ddns_address); 1458 1.1 christos 1459 1.1 christos ddns_update_lease_text(ddns_cb, NULL); 1460 1.1 christos 1461 1.1 christos if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { 1462 1.1 christos /* if we have zone information get rid of it */ 1463 1.1 christos if (ddns_cb->zone != NULL) { 1464 1.1 christos ddns_cb_forget_zone(ddns_cb); 1465 1.1 christos } 1466 1.1 christos 1467 1.1 christos ddns_cb->state = DDNS_STATE_ADD_PTR; 1468 1.1 christos ddns_cb->cur_func = ddns_ptr_add; 1469 1.1 christos 1470 1.1 christos result = ddns_modify_ptr(ddns_cb, MDL); 1471 1.1 christos if (result == ISC_R_SUCCESS) { 1472 1.1 christos return; 1473 1.1 christos } 1474 1.1 christos } 1475 1.1 christos break; 1476 1.1 christos 1477 1.1 christos case DNS_R_YXRRSET: 1478 1.1 christos case DNS_R_YXDOMAIN: 1479 1.1 christos logstr = "DHCID mismatch, belongs to another client."; 1480 1.1 christos break; 1481 1.1 christos 1482 1.1 christos case DNS_R_NXDOMAIN: 1483 1.1 christos case DNS_R_NXRRSET: 1484 1.1 christos /* If DSMM is on we need to try forward add3 */ 1485 1.1 christos if (ddns_cb->flags & DDNS_DUAL_STACK_MIXED_MODE) { 1486 1.1 christos ddns_cb->state = DDNS_STATE_DSMM_FW_ADD3; 1487 1.1 christos ddns_cb->cur_func = ddns_fwd_srv_add3; 1488 1.1 christos 1489 1.1 christos result = ddns_modify_fwd(ddns_cb, MDL); 1490 1.1 christos if (result == ISC_R_SUCCESS) { 1491 1.1 christos return; 1492 1.1 christos } 1493 1.1 christos 1494 1.1 christos break; 1495 1.1 christos } 1496 1.1 christos 1497 1.1 christos logstr = "Has an address record but no DHCID, not mine."; 1498 1.1 christos break; 1499 1.1 christos 1500 1.1 christos default: 1501 1.1 christos logstr = isc_result_totext(eresult); 1502 1.1 christos break; 1503 1.1 christos } 1504 1.1 christos 1505 1.1 christos if (logstr != NULL) { 1506 1.1 christos log_error("Forward map from %.*s to %s FAILED: %s", 1507 1.1 christos (int)ddns_cb->fwd_name.len, 1508 1.1 christos (const char *)ddns_cb->fwd_name.data, 1509 1.1 christos ddns_address, logstr); 1510 1.1 christos } 1511 1.1 christos 1512 1.1 christos ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); 1513 1.1 christos destroy_ddns_cb(ddns_cb, MDL); 1514 1.1 christos /* 1515 1.1 christos * A single DDNS operation may require several calls depending on 1516 1.1 christos * the current state as the prerequisites for the first message 1517 1.1 christos * may not succeed requiring a second operation and potentially 1518 1.1 christos * a ptr operation after that. The commit_leases operation is 1519 1.1 christos * invoked at the end of this set of operations in order to require 1520 1.1 christos * a single write for all of the changes. We call commit_leases 1521 1.1 christos * here rather than immediately after the call to update the lease 1522 1.1 christos * text in order to save any previously written data. 1523 1.1 christos */ 1524 1.1 christos commit_leases(); 1525 1.1 christos return; 1526 1.1 christos } 1527 1.1 christos 1528 1.2 christos static void 1529 1.1 christos ddns_fwd_srv_add1(dhcp_ddns_cb_t *ddns_cb, 1530 1.1 christos isc_result_t eresult) 1531 1.1 christos { 1532 1.1 christos isc_result_t result; 1533 1.1 christos char ddns_address[MAX_ADDRESS_STRING_LEN]; 1534 1.1 christos 1535 1.1 christos #if defined (DEBUG_DNS_UPDATES) 1536 1.1 christos log_info ("DDNS: ddns_fwd_srv_add1: %s eresult: %d", 1537 1.1 christos dump_ddns_cb(ddns_cb), eresult); 1538 1.1 christos #endif 1539 1.1 christos 1540 1.1 christos /* Construct a printable form of the address for logging */ 1541 1.1 christos strcpy(ddns_address, piaddr(ddns_cb->address)); 1542 1.1 christos 1543 1.1 christos switch(eresult) { 1544 1.1 christos case ISC_R_SUCCESS: 1545 1.1 christos log_info ("Added new forward map from %.*s to %s", 1546 1.1 christos (int)ddns_cb->fwd_name.len, 1547 1.1 christos (const char *)ddns_cb->fwd_name.data, 1548 1.1 christos ddns_address); 1549 1.1 christos 1550 1.1 christos ddns_update_lease_text(ddns_cb, NULL); 1551 1.1 christos 1552 1.1 christos if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { 1553 1.1 christos /* if we have zone information get rid of it */ 1554 1.1 christos if (ddns_cb->zone != NULL) { 1555 1.1 christos ddns_cb_forget_zone(ddns_cb); 1556 1.1 christos } 1557 1.1 christos 1558 1.1 christos ddns_cb->state = DDNS_STATE_ADD_PTR; 1559 1.1 christos ddns_cb->cur_func = ddns_ptr_add; 1560 1.1 christos 1561 1.1 christos result = ddns_modify_ptr(ddns_cb, MDL); 1562 1.1 christos if (result == ISC_R_SUCCESS) { 1563 1.1 christos return; 1564 1.1 christos } 1565 1.1 christos } 1566 1.1 christos break; 1567 1.1 christos 1568 1.1 christos case DNS_R_YXDOMAIN: 1569 1.1 christos /* we can reuse the zone information */ 1570 1.1 christos ddns_cb->state = DDNS_STATE_ADD_FW_YXDHCID; 1571 1.1 christos ddns_cb->cur_func = ddns_fwd_srv_add2; 1572 1.1 christos 1573 1.1 christos result = ddns_modify_fwd(ddns_cb, MDL); 1574 1.1 christos if (result == ISC_R_SUCCESS) { 1575 1.1 christos return; 1576 1.1 christos } 1577 1.1 christos break; 1578 1.1 christos default: 1579 1.1 christos log_error ("Unable to add forward map from %.*s to %s: %s", 1580 1.1 christos (int)ddns_cb->fwd_name.len, 1581 1.1 christos (const char *)ddns_cb->fwd_name.data, 1582 1.1 christos ddns_address, 1583 1.1 christos isc_result_totext (eresult)); 1584 1.1 christos break; 1585 1.1 christos } 1586 1.1 christos 1587 1.1 christos ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); 1588 1.1 christos destroy_ddns_cb(ddns_cb, MDL); 1589 1.1 christos /* 1590 1.1 christos * A single DDNS operation may require several calls depending on 1591 1.1 christos * the current state as the prerequisites for the first message 1592 1.1 christos * may not succeed requiring a second operation and potentially 1593 1.1 christos * a ptr operation after that. The commit_leases operation is 1594 1.1 christos * invoked at the end of this set of operations in order to require 1595 1.1 christos * a single write for all of the changes. We call commit_leases 1596 1.1 christos * here rather than immediately after the call to update the lease 1597 1.1 christos * text in order to save any previously written data. 1598 1.1 christos */ 1599 1.1 christos commit_leases(); 1600 1.1 christos return; 1601 1.1 christos } 1602 1.1 christos 1603 1.1 christos /* 1604 1.1 christos * This action routine is invoked after the DSMM third add stage is 1605 1.1 christos * attempted. If we succeeded we attempt to update the reverse DNS, 1606 1.1 christos * if not we cleanup and leave. 1607 1.1 christos */ 1608 1.1 christos void 1609 1.1 christos ddns_fwd_srv_add3(dhcp_ddns_cb_t *ddns_cb, 1610 1.1 christos isc_result_t eresult) 1611 1.1 christos { 1612 1.1 christos isc_result_t result; 1613 1.1 christos const char *logstr = NULL; 1614 1.1 christos char ddns_address[MAX_ADDRESS_STRING_LEN+1]; 1615 1.1 christos 1616 1.1 christos #if defined (DEBUG_DNS_UPDATES) 1617 1.1 christos log_info ("DDNS: ddns_fwd_srv_add3: %s eresult: %d", 1618 1.1 christos dump_ddns_cb(ddns_cb), eresult); 1619 1.1 christos #endif 1620 1.1 christos 1621 1.1 christos /* Construct a printable form of the address for logging */ 1622 1.1 christos memset(ddns_address, 0x0, sizeof(ddns_address)); 1623 1.1 christos strncpy(ddns_address, piaddr(ddns_cb->address), 1624 1.1 christos sizeof(ddns_address) - 1); 1625 1.1 christos 1626 1.1 christos switch(eresult) { 1627 1.1 christos case ISC_R_SUCCESS: 1628 1.1 christos log_info("Added new forward map from %.*s to %s", 1629 1.1 christos (int)ddns_cb->fwd_name.len, 1630 1.1 christos (const char *)ddns_cb->fwd_name.data, 1631 1.1 christos ddns_address); 1632 1.1 christos 1633 1.1 christos ddns_update_lease_text(ddns_cb, NULL); 1634 1.1 christos 1635 1.1 christos if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { 1636 1.1 christos /* if we have zone information get rid of it */ 1637 1.1 christos if (ddns_cb->zone != NULL) { 1638 1.1 christos ddns_cb_forget_zone(ddns_cb); 1639 1.1 christos } 1640 1.1 christos 1641 1.1 christos ddns_cb->state = DDNS_STATE_ADD_PTR; 1642 1.1 christos ddns_cb->cur_func = ddns_ptr_add; 1643 1.1 christos 1644 1.1 christos result = ddns_modify_ptr(ddns_cb, MDL); 1645 1.1 christos if (result == ISC_R_SUCCESS) { 1646 1.1 christos return; 1647 1.1 christos } 1648 1.1 christos } 1649 1.1 christos break; 1650 1.1 christos 1651 1.1 christos case DNS_R_YXRRSET: 1652 1.1 christos logstr = "an entry that is either static or " 1653 1.1 christos "owned by another client exists."; 1654 1.1 christos break; 1655 1.1 christos 1656 1.1 christos case DNS_R_NXRRSET: 1657 1.1 christos logstr = "static entry of the other protocol type exists."; 1658 1.1 christos break; 1659 1.1 christos 1660 1.1 christos default: 1661 1.1 christos logstr = isc_result_totext(eresult); 1662 1.1 christos break; 1663 1.1 christos } 1664 1.1 christos 1665 1.1 christos if (logstr != NULL) { 1666 1.1 christos log_error("Forward map from %.*s to %s FAILED: %s", 1667 1.1 christos (int)ddns_cb->fwd_name.len, 1668 1.1 christos (const char *)ddns_cb->fwd_name.data, 1669 1.1 christos ddns_address, logstr); 1670 1.1 christos } 1671 1.1 christos 1672 1.1 christos ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); 1673 1.1 christos destroy_ddns_cb(ddns_cb, MDL); 1674 1.1 christos /* 1675 1.1 christos * A single DDNS operation may require several calls depending on 1676 1.1 christos * the current state as the prerequisites for the first message 1677 1.1 christos * may not succeed requiring a second operation and potentially 1678 1.1 christos * a ptr operation after that. The commit_leases operation is 1679 1.1 christos * invoked at the end of this set of operations in order to require 1680 1.1 christos * a single write for all of the changes. We call commit_leases 1681 1.1 christos * here rather than immediately after the call to update the lease 1682 1.1 christos * text in order to save any previously written data. 1683 1.1 christos */ 1684 1.1 christos commit_leases(); 1685 1.1 christos return; 1686 1.1 christos } 1687 1.1 christos 1688 1.1 christos static void 1689 1.1 christos ddns_fwd_srv_connector(struct lease *lease, 1690 1.1 christos struct iasubopt *lease6, 1691 1.1 christos struct binding_scope **inscope, 1692 1.1 christos dhcp_ddns_cb_t *ddns_cb, 1693 1.1 christos isc_result_t eresult) 1694 1.1 christos { 1695 1.1 christos isc_result_t result = ISC_R_FAILURE; 1696 1.1 christos 1697 1.1 christos #if defined (DEBUG_DNS_UPDATES) 1698 1.1 christos log_info ("DDNS: ddns_fwd_srv_connector: %s eresult: %d", 1699 1.1 christos dump_ddns_cb(ddns_cb), eresult); 1700 1.1 christos #endif 1701 1.1 christos 1702 1.1 christos if (ddns_cb == NULL) { 1703 1.1 christos /* nothing to do */ 1704 1.1 christos return; 1705 1.1 christos } 1706 1.1 christos 1707 1.1 christos if (eresult == ISC_R_SUCCESS) { 1708 1.1 christos /* 1709 1.1 christos * If we have updates dispatch as appropriate, 1710 1.1 christos * if not do FQDN binding if desired. 1711 1.1 christos */ 1712 1.1 christos 1713 1.1 christos if (ddns_cb->flags & DDNS_UPDATE_ADDR) { 1714 1.1 christos ddns_cb->state = DDNS_STATE_ADD_FW_NXDOMAIN; 1715 1.1 christos ddns_cb->cur_func = ddns_fwd_srv_add1; 1716 1.1 christos result = ddns_modify_fwd(ddns_cb, MDL); 1717 1.1 christos } else if ((ddns_cb->flags & DDNS_UPDATE_PTR) && 1718 1.1 christos (ddns_cb->rev_name.len != 0)) { 1719 1.1 christos ddns_cb->state = DDNS_STATE_ADD_PTR; 1720 1.1 christos ddns_cb->cur_func = ddns_ptr_add; 1721 1.1 christos result = ddns_modify_ptr(ddns_cb, MDL); 1722 1.1 christos } else { 1723 1.1 christos ddns_update_lease_text(ddns_cb, inscope); 1724 1.1 christos } 1725 1.1 christos } 1726 1.1 christos 1727 1.1 christos 1728 1.1 christos if (result == ISC_R_SUCCESS) { 1729 1.1 christos ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, MDL); 1730 1.1 christos } else { 1731 1.1 christos destroy_ddns_cb(ddns_cb, MDL); 1732 1.1 christos } 1733 1.1 christos 1734 1.1 christos return; 1735 1.1 christos } 1736 1.1 christos 1737 1.1 christos /* 1738 1.1 christos * If the first query fails, the updater MUST NOT delete the DNS name. It 1739 1.1 christos * may be that the host whose lease on the server has expired has moved 1740 1.1 christos * to another network and obtained a lease from a different server, 1741 1.1 christos * which has caused the client's A RR to be replaced. It may also be 1742 1.1 christos * that some other client has been configured with a name that matches 1743 1.1 christos * the name of the DHCP client, and the policy was that the last client 1744 1.1 christos * to specify the name would get the name. In this case, the DHCID RR 1745 1.1 christos * will no longer match the updater's notion of the client-identity of 1746 1.1 christos * the host pointed to by the DNS name. 1747 1.1 christos * -- "Interaction between DHCP and DNS" 1748 1.1 christos */ 1749 1.1 christos 1750 1.2 christos static void 1751 1.1 christos ddns_fwd_srv_rem2(dhcp_ddns_cb_t *ddns_cb, 1752 1.1 christos isc_result_t eresult) 1753 1.1 christos { 1754 1.1 christos #if defined (DEBUG_DNS_UPDATES) 1755 1.1 christos log_info ("DDNS: ddns_fwd_srv_rem2: %s eresult: %d", 1756 1.1 christos dump_ddns_cb(ddns_cb), eresult); 1757 1.1 christos #endif 1758 1.1 christos 1759 1.1 christos /* 1760 1.1 christos * To get here we have already managed to remove the A/AAAA 1761 1.1 christos * record and are trying to remove the DHCID/TXT record as well. 1762 1.1 christos * On success (removed DHCID/TXT) or YXRRSET (DHCID/TXT still in 1763 1.1 christos * use by something else) we clean up the lease. 1764 1.1 christos * On some other error we don't clean up the lease and hope that 1765 1.1 christos * if we try this again it will work. An example would be if we 1766 1.1 christos * got a timeout as the DNS server halted between the first and 1767 1.1 christos * second steps. The DNS server would still have the DHCID/TXT 1768 1.1 christos * and we would like to remove that in the future. 1769 1.1 christos * 1770 1.1 christos * On success set the EXECUTE_NEXT flag which triggers any 1771 1.1 christos * add that is next in the chain. 1772 1.1 christos */ 1773 1.1 christos if ((eresult == ISC_R_SUCCESS) || 1774 1.1 christos (eresult == DNS_R_YXRRSET)) { 1775 1.1 christos ddns_update_lease_text(ddns_cb, NULL); 1776 1.1 christos eresult = ISC_R_SUCCESS; 1777 1.1 christos } 1778 1.1 christos 1779 1.1 christos /* Do the next operation */ 1780 1.1 christos if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { 1781 1.1 christos /* if we have zone information get rid of it */ 1782 1.1 christos if (ddns_cb->zone != NULL) { 1783 1.1 christos ddns_cb_forget_zone(ddns_cb); 1784 1.1 christos } 1785 1.1 christos 1786 1.1 christos ddns_cb->state = DDNS_STATE_REM_PTR; 1787 1.1 christos ddns_cb->cur_func = ddns_ptr_remove; 1788 1.1 christos if (eresult == ISC_R_SUCCESS) 1789 1.1 christos ddns_cb->flags |= DDNS_EXECUTE_NEXT; 1790 1.1 christos 1791 1.1 christos eresult = ddns_modify_ptr(ddns_cb, MDL); 1792 1.1 christos if (eresult == ISC_R_SUCCESS) { 1793 1.1 christos return; 1794 1.1 christos } 1795 1.1 christos } 1796 1.1 christos 1797 1.1 christos ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); 1798 1.1 christos ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult); 1799 1.1 christos destroy_ddns_cb(ddns_cb, MDL); 1800 1.1 christos return; 1801 1.1 christos } 1802 1.1 christos 1803 1.1 christos 1804 1.1 christos /* 1805 1.1 christos * First action routine when trying to remove a fwd 1806 1.1 christos * this will be called after the ddns queries have completed 1807 1.1 christos * if we succeeded in removing the fwd we go to the next step (if any) 1808 1.1 christos * if not we cleanup and leave. 1809 1.1 christos */ 1810 1.1 christos 1811 1.2 christos static void 1812 1.1 christos ddns_fwd_srv_rem1(dhcp_ddns_cb_t *ddns_cb, 1813 1.1 christos isc_result_t eresult) 1814 1.1 christos { 1815 1.1 christos isc_result_t result = eresult; 1816 1.1 christos char ddns_address[MAX_ADDRESS_STRING_LEN]; 1817 1.1 christos 1818 1.1 christos #if defined (DEBUG_DNS_UPDATES) 1819 1.1 christos log_info ("DDNS: ddns_fwd_srv_rem1: %s eresult: %d", 1820 1.1 christos dump_ddns_cb(ddns_cb), eresult); 1821 1.1 christos #endif 1822 1.1 christos 1823 1.1 christos switch(eresult) { 1824 1.1 christos case ISC_R_SUCCESS: 1825 1.1 christos /* Construct a printable form of the address for logging */ 1826 1.1 christos strcpy(ddns_address, piaddr(ddns_cb->address)); 1827 1.1 christos log_info("Removed forward map from %.*s to %s", 1828 1.1 christos (int)ddns_cb->fwd_name.len, 1829 1.1 christos (const char*)ddns_cb->fwd_name.data, 1830 1.1 christos ddns_address); 1831 1.1 christos 1832 1.1 christos /* Do the second step of the FWD removal */ 1833 1.1 christos ddns_cb->state = DDNS_STATE_REM_FW_NXRR; 1834 1.1 christos ddns_cb->cur_func = ddns_fwd_srv_rem2; 1835 1.1 christos result = ddns_modify_fwd(ddns_cb, MDL); 1836 1.1 christos if (result == ISC_R_SUCCESS) { 1837 1.1 christos return; 1838 1.1 christos } 1839 1.1 christos break; 1840 1.1 christos 1841 1.1 christos case DNS_R_NXRRSET: 1842 1.1 christos case DNS_R_NXDOMAIN: 1843 1.1 christos /* A result of not found means rem1 did not find a guard of 1844 1.1 christos * our * type. From this we assume either there are no address 1845 1.1 christos * record(s) of our type to delete or they are unguarded and 1846 1.1 christos * therefore presumed to be static. Either way, we're done 1847 1.1 christos * unless we're in DSMM and ddns-other-guard-is-dynamic is on. 1848 1.1 christos * In which case we need to see if a guard of the other type 1849 1.1 christos * exists, which permits us to delete any address records of 1850 1.1 christos * our type. */ 1851 1.1 christos #define DSMM_OGD (DDNS_DUAL_STACK_MIXED_MODE | \ 1852 1.1 christos DDNS_OTHER_GUARD_IS_DYNAMIC) 1853 1.1 christos if ((ddns_cb->flags & DSMM_OGD) == DSMM_OGD) { 1854 1.1 christos ddns_cb->state = DDNS_STATE_REM_FW_DSMM_OTHER; 1855 1.1 christos ddns_cb->cur_func = ddns_fwd_srv_rem2; 1856 1.1 christos result = ddns_modify_fwd(ddns_cb, MDL); 1857 1.1 christos if (result == ISC_R_SUCCESS) { 1858 1.1 christos return; 1859 1.1 christos } 1860 1.1 christos break; 1861 1.1 christos } 1862 1.1 christos 1863 1.1 christos ddns_update_lease_text(ddns_cb, NULL); 1864 1.1 christos 1865 1.1 christos #if defined (DEBUG_DNS_UPDATES) 1866 1.1 christos log_info("DDNS: no forward map to remove. %p", ddns_cb); 1867 1.1 christos #endif 1868 1.1 christos /* Trigger the add operation */ 1869 1.1 christos eresult = ISC_R_SUCCESS; 1870 1.1 christos 1871 1.1 christos /* Fall through */ 1872 1.1 christos default: 1873 1.1 christos 1874 1.1 christos /* We do the remove operation in most cases 1875 1.1 christos * but we don't want to continue with adding a forward 1876 1.1 christos * record if the forward removal had issues so we 1877 1.1 christos * check the eresult and set the EXECUTE_NEXT flag on 1878 1.1 christos * success. 1879 1.1 christos */ 1880 1.1 christos 1881 1.1 christos /* Do the remove operation */ 1882 1.1 christos if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { 1883 1.1 christos /* if we have zone information get rid of it */ 1884 1.1 christos if (ddns_cb->zone != NULL) { 1885 1.1 christos ddns_cb_forget_zone(ddns_cb); 1886 1.1 christos } 1887 1.1 christos 1888 1.1 christos ddns_cb->state = DDNS_STATE_REM_PTR; 1889 1.1 christos ddns_cb->cur_func = ddns_ptr_remove; 1890 1.1 christos if (eresult == ISC_R_SUCCESS) 1891 1.1 christos ddns_cb->flags |= DDNS_EXECUTE_NEXT; 1892 1.1 christos 1893 1.1 christos result = ddns_modify_ptr(ddns_cb, MDL); 1894 1.1 christos if (result == ISC_R_SUCCESS) { 1895 1.1 christos return; 1896 1.1 christos } 1897 1.1 christos } 1898 1.1 christos break; 1899 1.1 christos } 1900 1.1 christos 1901 1.1 christos ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL); 1902 1.1 christos ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult); 1903 1.1 christos destroy_ddns_cb(ddns_cb, MDL); 1904 1.1 christos } 1905 1.1 christos 1906 1.1 christos /*%< 1907 1.1 christos * Remove relevant entries from DNS. 1908 1.1 christos * 1909 1.1 christos * \li lease - lease to start with if this is for v4 1910 1.1 christos * 1911 1.1 christos * \li lease6 - lease to start with if this is for v6 1912 1.1 christos * 1913 1.1 christos * \li add_ddns_cb - control block for additional DDNS work. This 1914 1.1 christos * is used when the code is going to add a DDNS entry after removing 1915 1.1 christos * the current entry. 1916 1.1 christos * 1917 1.1 christos * \li active - indication about the status of the lease. It is 1918 1.1 christos * ISC_TRUE if the lease is still active, and FALSE if the lease 1919 1.1 christos * is inactive. This is used to indicate if the lease is inactive or going 1920 1.1 christos * to inactive so we can avoid trying to update the lease with cb pointers 1921 1.1 christos * and text information if it isn't useful. 1922 1.1 christos * 1923 1.1 christos * Returns 1924 1.1 christos * \li #ISC_R_FAILURE - badness occurred and we weren't able to do what was wanted 1925 1.1 christos * \li #ISC_R_SUCCESS - we were able to do stuff but it's in progress 1926 1.1 christos * 1927 1.1 christos * in both cases any additional block has been passed on to it's handler 1928 1.1 christos */ 1929 1.1 christos 1930 1.1 christos isc_result_t 1931 1.1 christos ddns_removals(struct lease *lease, 1932 1.1 christos struct iasubopt *lease6, 1933 1.1 christos dhcp_ddns_cb_t *add_ddns_cb, 1934 1.1 christos isc_boolean_t active) 1935 1.1 christos { 1936 1.1 christos isc_result_t rcode, execute_add = ISC_R_FAILURE; 1937 1.1 christos struct binding_scope **scope = NULL; 1938 1.1 christos isc_result_t result = ISC_R_FAILURE; 1939 1.1 christos dhcp_ddns_cb_t *ddns_cb = NULL; 1940 1.1 christos struct data_string leaseid; 1941 1.1 christos 1942 1.1 christos #if defined (DEBUG_DNS_UPDATES) 1943 1.1 christos log_info ("DDNS: ddns_removals: %s", 1944 1.1 christos dump_ddns_cb(add_ddns_cb)); 1945 1.1 christos #endif 1946 1.1 christos 1947 1.1 christos /* 1948 1.1 christos * See if we need to cancel an outstanding request. Mostly this is 1949 1.1 christos * used to handle the case where this routine is called twice for 1950 1.1 christos * the same release or abandon event. 1951 1.1 christos * 1952 1.1 christos * When called from the dns code as part of an update request 1953 1.1 christos * (add_ddns_cb != NULL) any outstanding requests will have already 1954 1.1 christos * been cancelled. 1955 1.1 christos * 1956 1.1 christos * If the new request is just a removal and we have an outstanding 1957 1.1 christos * request we have several options: 1958 1.1 christos * 1959 1.1 christos * - we are doing an update or we are doing a removal and the active 1960 1.1 christos * flag has changed from TRUE to FALSE. In these cases we need to 1961 1.1 christos * cancel the old request and start the new one. 1962 1.1 christos * 1963 1.1 christos * - other wise we are doing a removal with the active flag unchanged. 1964 1.1 christos * In this case we can let the current removal continue and do not need 1965 1.1 christos * to start a new one. If the old request included an update to be 1966 1.1 christos * done after the removal we need to kill the update part of the 1967 1.1 christos * request. 1968 1.1 christos */ 1969 1.1 christos 1970 1.1 christos if (add_ddns_cb == NULL) { 1971 1.1 christos if ((lease != NULL) && (lease->ddns_cb != NULL)) { 1972 1.1 christos ddns_cb = lease->ddns_cb; 1973 1.1 christos 1974 1.1 christos /* 1975 1.1 christos * Is the old request an update or did the 1976 1.1 christos * the active flag change? 1977 1.1 christos */ 1978 1.1 christos if (((ddns_cb->state == DDNS_STATE_ADD_PTR) || 1979 1.1 christos (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) || 1980 1.1 christos (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) || 1981 1.1 christos ((active == ISC_FALSE) && 1982 1.1 christos ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) { 1983 1.1 christos /* Cancel the current request */ 1984 1.1 christos ddns_cancel(lease->ddns_cb, MDL); 1985 1.1 christos lease->ddns_cb = NULL; 1986 1.1 christos } else { 1987 1.1 christos /* Remvoval, check and remove updates */ 1988 1.1 christos if (ddns_cb->next_op != NULL) { 1989 1.1 christos destroy_ddns_cb(ddns_cb->next_op, MDL); 1990 1.1 christos ddns_cb->next_op = NULL; 1991 1.1 christos } 1992 1.1 christos #if defined (DEBUG_DNS_UPDATES) 1993 1.1 christos log_info("DDNS %s(%d): removal already in " 1994 1.1 christos "progress new ddns_cb=%p", 1995 1.1 christos MDL, ddns_cb); 1996 1.1 christos #endif 1997 1.1 christos return (ISC_R_SUCCESS); 1998 1.1 christos } 1999 1.1 christos } else if ((lease6 != NULL) && (lease6->ddns_cb != NULL)) { 2000 1.1 christos ddns_cb = lease6->ddns_cb; 2001 1.1 christos 2002 1.1 christos /* 2003 1.1 christos * Is the old request an update or did the 2004 1.1 christos * the active flag change? 2005 1.1 christos */ 2006 1.1 christos if (((ddns_cb->state == DDNS_STATE_ADD_PTR) || 2007 1.1 christos (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) || 2008 1.1 christos (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) || 2009 1.1 christos ((active == ISC_FALSE) && 2010 1.1 christos ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) { 2011 1.1 christos /* Cancel the current request */ 2012 1.1 christos ddns_cancel(lease6->ddns_cb, MDL); 2013 1.1 christos lease6->ddns_cb = NULL; 2014 1.1 christos } else { 2015 1.1 christos /* Remvoval, check and remove updates */ 2016 1.1 christos if (ddns_cb->next_op != NULL) { 2017 1.1 christos destroy_ddns_cb(ddns_cb->next_op, MDL); 2018 1.1 christos ddns_cb->next_op = NULL; 2019 1.1 christos } 2020 1.1 christos #if defined (DEBUG_DNS_UPDATES) 2021 1.1 christos log_info("DDNS %s(%d): removal already in " 2022 1.1 christos "progress new ddns_cb=%p", 2023 1.1 christos MDL, ddns_cb); 2024 1.1 christos #endif 2025 1.1 christos return (ISC_R_SUCCESS); 2026 1.1 christos } 2027 1.1 christos } 2028 1.1 christos ddns_cb = NULL; 2029 1.1 christos } 2030 1.1 christos 2031 1.1 christos /* allocate our control block */ 2032 1.1 christos ddns_cb = ddns_cb_alloc(MDL); 2033 1.1 christos if (ddns_cb == NULL) { 2034 1.1 christos goto cleanup; 2035 1.1 christos } 2036 1.1 christos 2037 1.1 christos /* Set the conflict detection flags based on global configuration */ 2038 1.1 christos copy_conflict_flags(&ddns_cb->flags, ddns_conflict_mask); 2039 1.1 christos 2040 1.1 christos /* 2041 1.1 christos * For v4 we flag static leases so we don't try 2042 1.1 christos * and manipulate the lease later. For v6 we don't 2043 1.1 christos * get static leases and don't need to flag them. 2044 1.1 christos */ 2045 1.1 christos if (lease != NULL) { 2046 1.1 christos scope = &(lease->scope); 2047 1.1 christos ddns_cb->address = lease->ip_addr; 2048 1.1 christos if (lease->flags & STATIC_LEASE) 2049 1.1 christos ddns_cb->flags |= DDNS_STATIC_LEASE; 2050 1.1 christos } else if (lease6 != NULL) { 2051 1.1 christos scope = &(lease6->scope); 2052 1.1 christos memcpy(&ddns_cb->address.iabuf, lease6->addr.s6_addr, 16); 2053 1.1 christos ddns_cb->address.len = 16; 2054 1.1 christos } else 2055 1.1 christos goto cleanup; 2056 1.1 christos 2057 1.1 christos /* 2058 1.1 christos * Set the flag bit if the lease is active, that is it isn't 2059 1.1 christos * expired or released. This is used to determine if we need 2060 1.1 christos * to update the scope information for both v4 and v6 and 2061 1.1 christos * the lease information for v6 when the response 2062 1.1 christos * from the DNS code is processed. 2063 1.1 christos */ 2064 1.1 christos if (active == ISC_TRUE) { 2065 1.1 christos ddns_cb->flags |= DDNS_ACTIVE_LEASE; 2066 1.1 christos } 2067 1.1 christos 2068 1.1 christos /* No scope implies that DDNS has not been performed for this lease. */ 2069 1.1 christos if (*scope == NULL) 2070 1.1 christos goto cleanup; 2071 1.1 christos 2072 1.1 christos if ((ddns_update_style != DDNS_UPDATE_STYLE_STANDARD) && 2073 1.1 christos (ddns_update_style != DDNS_UPDATE_STYLE_INTERIM)) 2074 1.1 christos goto cleanup; 2075 1.1 christos 2076 1.1 christos /* Assume that we are removing both records */ 2077 1.1 christos ddns_cb->flags |= DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR; 2078 1.1 christos 2079 1.1 christos /* and that we want to do the add call */ 2080 1.1 christos execute_add = ISC_R_SUCCESS; 2081 1.1 christos 2082 1.1 christos /* 2083 1.1 christos * Look up stored names. 2084 1.1 christos */ 2085 1.1 christos 2086 1.1 christos /* 2087 1.1 christos * Find the fwd name and copy it to the control block. If we don't 2088 1.1 christos * have it we can't delete the fwd record but we can still try to 2089 1.1 christos * remove the ptr record and cleanup the lease information if the 2090 1.1 christos * client did the fwd update. 2091 1.1 christos */ 2092 1.1 christos if (!find_bound_string(&ddns_cb->fwd_name, *scope, "ddns-fwd-name")) { 2093 1.1 christos /* don't try and delete the A, or do the add */ 2094 1.1 christos ddns_cb->flags &= ~DDNS_UPDATE_ADDR; 2095 1.1 christos execute_add = ISC_R_FAILURE; 2096 1.1 christos 2097 1.1 christos /* Check if client did update */ 2098 1.1 christos if (find_bound_string(&ddns_cb->fwd_name, *scope, 2099 1.1 christos "ddns-client-fqdn")) { 2100 1.1 christos ddns_cb->flags |= DDNS_CLIENT_DID_UPDATE; 2101 1.1 christos } 2102 1.1 christos } 2103 1.1 christos 2104 1.1 christos /* 2105 1.1 christos * Find the txt or dhcid tag and copy it to the control block. If we 2106 1.1 christos * don't have one this isn't an interim or standard record so we can't 2107 1.1 christos * delete the A record using this mechanism but we can delete the ptr 2108 1.1 christos * record. In this case we will attempt to do any requested next step. 2109 1.1 christos */ 2110 1.1 christos memset(&leaseid, 0, sizeof(leaseid)); 2111 1.1 christos if (find_bound_string (&leaseid, *scope, ddns_standard_tag)) { 2112 1.1 christos /* We have a standard tag */ 2113 1.1 christos ddns_cb->lease_tag = ddns_standard_tag; 2114 1.1 christos ddns_cb->dhcid_class = dns_rdatatype_dhcid; 2115 1.1 christos ddns_cb->other_dhcid_class = dns_rdatatype_txt; 2116 1.1 christos data_string_copy(&ddns_cb->dhcid, &leaseid, MDL); 2117 1.1 christos data_string_forget(&leaseid, MDL); 2118 1.1 christos } else if (find_bound_string (&leaseid, *scope, ddns_interim_tag)) { 2119 1.1 christos /* we have an interim tag */ 2120 1.1 christos ddns_cb->lease_tag = ddns_interim_tag; 2121 1.1 christos ddns_cb->dhcid_class = dns_rdatatype_txt; 2122 1.1 christos ddns_cb->other_dhcid_class = dns_rdatatype_dhcid; 2123 1.1 christos if (dhcid_fromlease(&ddns_cb->dhcid, &leaseid) != 2124 1.1 christos ISC_R_SUCCESS) { 2125 1.1 christos /* We couldn't convert the dhcid from the lease 2126 1.1 christos * version to the dns version. We can't delete 2127 1.1 christos * the A record but can continue to the ptr 2128 1.1 christos */ 2129 1.1 christos ddns_cb->flags &= ~DDNS_UPDATE_ADDR; 2130 1.1 christos } 2131 1.1 christos data_string_forget(&leaseid, MDL); 2132 1.1 christos } else { 2133 1.1 christos ddns_cb->flags &= ~DDNS_UPDATE_ADDR; 2134 1.1 christos } 2135 1.1 christos 2136 1.1 christos /* 2137 1.1 christos * Find the rev name and copy it to the control block. If we don't 2138 1.1 christos * have it we can't get rid of it but we can try to remove the fwd 2139 1.1 christos * pointer if desired. 2140 1.1 christos */ 2141 1.1 christos if (!find_bound_string(&ddns_cb->rev_name, *scope, "ddns-rev-name")) { 2142 1.1 christos ddns_cb->flags &= ~DDNS_UPDATE_PTR; 2143 1.1 christos } 2144 1.1 christos 2145 1.1 christos 2146 1.1 christos /* 2147 1.1 christos * If we have a second control block for doing an add 2148 1.1 christos * after the remove finished attach it to our control block. 2149 1.1 christos */ 2150 1.1 christos ddns_cb->next_op = add_ddns_cb; 2151 1.1 christos 2152 1.1 christos /* 2153 1.1 christos * Now that we've collected the information we can try to process it. 2154 1.1 christos * If necessary we call an appropriate routine to send a message and 2155 1.1 christos * provide it with an action routine to run on the control block given 2156 1.1 christos * the results of the message. We have three entry points from here, 2157 1.1 christos * one for removing the A record, the next for removing the PTR and 2158 1.1 christos * the third for doing any requested add. 2159 1.1 christos */ 2160 1.1 christos if ((ddns_cb->flags & DDNS_UPDATE_ADDR) != 0) { 2161 1.1 christos if (ddns_cb->fwd_name.len != 0) { 2162 1.1 christos ddns_cb->state = DDNS_STATE_REM_FW_YXDHCID; 2163 1.1 christos ddns_cb->cur_func = ddns_fwd_srv_rem1; 2164 1.1 christos 2165 1.1 christos rcode = ddns_modify_fwd(ddns_cb, MDL); 2166 1.1 christos if (rcode == ISC_R_SUCCESS) { 2167 1.1 christos ddns_update_lease_ptr(lease, lease6, ddns_cb, 2168 1.1 christos ddns_cb, MDL); 2169 1.1 christos return (ISC_R_SUCCESS); 2170 1.1 christos } 2171 1.1 christos 2172 1.1 christos /* 2173 1.1 christos * We weren't able to process the request tag the 2174 1.1 christos * add so we won't execute it. 2175 1.1 christos */ 2176 1.1 christos execute_add = ISC_R_FAILURE; 2177 1.1 christos goto cleanup; 2178 1.1 christos } 2179 1.1 christos else { 2180 1.1 christos /*remove info from scope */ 2181 1.1 christos unset(*scope, "ddns-fwd-name"); 2182 1.1 christos unset(*scope, ddns_cb->lease_tag); 2183 1.1 christos } 2184 1.1 christos } 2185 1.1 christos 2186 1.1 christos if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) { 2187 1.1 christos ddns_cb->state = DDNS_STATE_REM_PTR; 2188 1.1 christos ddns_cb->cur_func = ddns_ptr_remove; 2189 1.1 christos ddns_cb->flags |= DDNS_EXECUTE_NEXT; 2190 1.1 christos 2191 1.1 christos /* 2192 1.1 christos * if execute add isn't success remove the control block so 2193 1.1 christos * it won't be processed when the remove completes. We 2194 1.1 christos * also arrange to clean it up and get rid of it. 2195 1.1 christos */ 2196 1.1 christos if (execute_add != ISC_R_SUCCESS) { 2197 1.1 christos ddns_cb->next_op = NULL; 2198 1.1 christos ddns_fwd_srv_connector(lease, lease6, scope, 2199 1.1 christos add_ddns_cb, execute_add); 2200 1.1 christos add_ddns_cb = NULL; 2201 1.1 christos } 2202 1.1 christos else { 2203 1.1 christos result = ISC_R_SUCCESS; 2204 1.1 christos } 2205 1.1 christos 2206 1.1 christos rcode = ddns_modify_ptr(ddns_cb, MDL); 2207 1.1 christos if (rcode == ISC_R_SUCCESS) { 2208 1.1 christos ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, 2209 1.1 christos MDL); 2210 1.1 christos return (result); 2211 1.1 christos } 2212 1.1 christos 2213 1.1 christos /* We weren't able to process the request tag the 2214 1.1 christos * add so we won't execute it */ 2215 1.1 christos execute_add = ISC_R_FAILURE; 2216 1.1 christos goto cleanup; 2217 1.1 christos } 2218 1.1 christos 2219 1.1 christos cleanup: 2220 1.1 christos /* 2221 1.1 christos * We've gotten here because we didn't need to send a message or 2222 1.1 christos * we failed when trying to do so. We send the additional cb 2223 1.1 christos * off to handle sending and/or cleanup and cleanup anything 2224 1.1 christos * we allocated here. 2225 1.1 christos */ 2226 1.1 christos ddns_fwd_srv_connector(lease, lease6, scope, add_ddns_cb, execute_add); 2227 1.1 christos if (ddns_cb != NULL) 2228 1.1 christos destroy_ddns_cb(ddns_cb, MDL); 2229 1.1 christos 2230 1.1 christos return (result); 2231 1.1 christos } 2232 1.1 christos 2233 1.1 christos /* Convenience function for setting flag bits in a mask */ 2234 1.2 christos static void 2235 1.2 christos set_flag (u_int16_t *flags, 2236 1.1 christos u_int16_t flag, 2237 1.1 christos u_int16_t value) { 2238 1.1 christos if (flags) { 2239 1.1 christos if (value) { 2240 1.1 christos *flags |= flag; 2241 1.1 christos } else { 2242 1.1 christos *flags &= ~flag; 2243 1.1 christos } 2244 1.1 christos } 2245 1.1 christos } 2246 1.1 christos 2247 1.1 christos /* 2248 1.1 christos * Convenience function which replicates the conflict flags set in one 2249 1.1 christos * mask to another, while preserving all other flags. 2250 1.1 christos */ 2251 1.1 christos void copy_conflict_flags(u_int16_t *target, 2252 1.1 christos u_int16_t source) { 2253 1.1 christos if (target) { 2254 1.1 christos /* Preserve non conflict flags */ 2255 1.1 christos *target &= ~CONFLICT_BITS; 2256 1.1 christos 2257 1.1 christos /* Enable conflict flags per source */ 2258 1.1 christos *target |= source & CONFLICT_BITS; 2259 1.1 christos } 2260 1.1 christos } 2261 1.1 christos 2262 1.1 christos /* 2263 1.1 christos * Given an option_state, create a mask of conflict detection flags based 2264 1.1 christos * on the appropriate configuration parameters within the option state. 2265 1.1 christos */ 2266 1.1 christos u_int16_t 2267 1.1 christos get_conflict_mask(struct option_state *options) { 2268 1.1 christos 2269 1.1 christos int ddns_update_conflict_detection = 1; /* default on */ 2270 1.1 christos int ddns_dual_stack_mixed_mode = 0; /* default off */ 2271 1.1 christos int ddns_guard_id_must_match = 1; /* default on */ 2272 1.1 christos int ddns_other_guard_is_dynamic = 0; /* default off */ 2273 1.1 christos struct option_cache *oc = NULL; 2274 1.1 christos 2275 1.1 christos u_int16_t mask = 0; 2276 1.1 christos oc = lookup_option(&server_universe, options, SV_DDNS_CONFLICT_DETECT); 2277 1.1 christos if (oc) { 2278 1.1 christos ddns_update_conflict_detection = 2279 1.1 christos evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options, 2280 1.1 christos NULL, &global_scope, oc, MDL); 2281 1.1 christos } 2282 1.1 christos 2283 1.1 christos set_flag(&mask, DDNS_CONFLICT_DETECTION, 2284 1.1 christos ddns_update_conflict_detection); 2285 1.1 christos 2286 1.1 christos if (!ddns_update_conflict_detection) { 2287 1.1 christos #if defined (DEBUG_DNS_UPDATES) 2288 1.1 christos log_info ("DDNS conflict detection: off"); 2289 1.1 christos #endif 2290 1.1 christos /* Turn the rest of the conflict related flags off */ 2291 1.1 christos set_flag(&mask, DDNS_DUAL_STACK_MIXED_MODE, 0); 2292 1.1 christos set_flag(&mask, DDNS_GUARD_ID_MUST_MATCH, 0); 2293 1.1 christos set_flag(&mask, DDNS_OTHER_GUARD_IS_DYNAMIC, 0); 2294 1.1 christos return (mask); 2295 1.1 christos } 2296 1.1 christos 2297 1.1 christos // Get the values 2298 1.1 christos oc = lookup_option(&server_universe, options, 2299 1.1 christos SV_DDNS_DUAL_STACK_MIXED_MODE); 2300 1.1 christos if (oc) { 2301 1.1 christos ddns_dual_stack_mixed_mode = 2302 1.1 christos evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options, 2303 1.1 christos NULL, &global_scope, oc, MDL); 2304 1.1 christos } 2305 1.1 christos 2306 1.1 christos oc = lookup_option(&server_universe, options, 2307 1.1 christos SV_DDNS_GUARD_ID_MUST_MATCH); 2308 1.1 christos if (oc) { 2309 1.1 christos ddns_guard_id_must_match = 2310 1.1 christos evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options, 2311 1.1 christos NULL, &global_scope, oc, MDL); 2312 1.1 christos } 2313 1.1 christos 2314 1.1 christos oc = lookup_option(&server_universe, options, 2315 1.1 christos SV_DDNS_OTHER_GUARD_IS_DYNAMIC); 2316 1.1 christos if (oc) { 2317 1.1 christos ddns_other_guard_is_dynamic = 2318 1.1 christos evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options, 2319 1.1 christos NULL, &global_scope, oc, MDL); 2320 1.1 christos } 2321 1.1 christos 2322 1.1 christos // Set the flags 2323 1.1 christos set_flag(&mask, DDNS_DUAL_STACK_MIXED_MODE, 2324 1.1 christos ddns_dual_stack_mixed_mode); 2325 1.1 christos 2326 1.1 christos set_flag(&mask, DDNS_GUARD_ID_MUST_MATCH, 2327 1.1 christos ddns_guard_id_must_match); 2328 1.1 christos 2329 1.1 christos set_flag(&mask, DDNS_OTHER_GUARD_IS_DYNAMIC, 2330 1.1 christos ddns_other_guard_is_dynamic); 2331 1.1 christos 2332 1.1 christos #if defined (DEBUG_DNS_UPDATES) 2333 1.1 christos log_info ("DDNS conflict behavior:\n" 2334 1.1 christos "\tddns-update-style: %s\n" 2335 1.1 christos "\tupdate-conflict-detection: %d\n" 2336 1.1 christos "\tddns-dual-stack-mixed-mode: %d\n" 2337 1.1 christos "\tddns-guard-id-must-match %d\n" 2338 1.1 christos "\tddns-other-guard-is-dynamic: %d\n", 2339 1.1 christos ddns_styles_values[ddns_update_style].name, 2340 1.1 christos ddns_update_conflict_detection, 2341 1.1 christos ddns_dual_stack_mixed_mode, 2342 1.1 christos ddns_guard_id_must_match, 2343 1.1 christos ddns_other_guard_is_dynamic); 2344 1.1 christos #endif 2345 1.1 christos return (mask); 2346 1.1 christos } 2347 1.1 christos 2348 1.1 christos #if defined (DEBUG_DNS_UPDATES) 2349 1.1 christos /* Type used for creating lists of function pointers and their names */ 2350 1.1 christos typedef struct { 2351 1.1 christos void *ptr; 2352 1.1 christos char *name; 2353 1.1 christos } LabeledPtr; 2354 1.1 christos 2355 1.1 christos /* Returns the name of the function referred to by the given address */ 2356 1.1 christos char* 2357 1.1 christos dump_ddns_cb_func(void *func) { 2358 1.1 christos static LabeledPtr funcs[] = { 2359 1.1 christos { ddns_ptr_add, "ddns_ptr_add" }, 2360 1.1 christos { ddns_fwd_srv_add2, "ddns_fwd_srv_add2" }, 2361 1.1 christos { ddns_fwd_srv_add1, "ddns_fwd_srv_add1" }, 2362 1.1 christos { ddns_ptr_remove, "ddns_ptr_remove" }, 2363 1.1 christos { ddns_fwd_srv_rem2, "ddns_fwd_srv_rem2" }, 2364 1.1 christos { ddns_fwd_srv_rem1, "ddns_fwd_srv_rem1" }, 2365 1.1 christos { ddns_fwd_srv_add3, "ddns_fwd_srv_adde" }, 2366 1.1 christos { NULL, "unknown" } 2367 1.1 christos }; 2368 1.1 christos 2369 1.1 christos LabeledPtr* lp = funcs; 2370 1.1 christos if (!func) { 2371 1.1 christos return ("<null>"); 2372 1.1 christos } 2373 1.1 christos 2374 1.1 christos while ((lp->ptr) && (lp->ptr != func)) { 2375 1.1 christos ++lp; 2376 1.1 christos } 2377 1.1 christos 2378 1.1 christos return (lp->name); 2379 1.1 christos } 2380 1.1 christos 2381 1.1 christos /* Dumps basic control block info to the log */ 2382 1.1 christos char* 2383 1.1 christos dump_ddns_cb (dhcp_ddns_cb_t *ddns_cb) { 2384 1.1 christos static char output_buf[4096]; 2385 1.1 christos if (!ddns_cb) { 2386 1.1 christos return ("<ddns_cb is null>"); 2387 1.1 christos } 2388 1.1 christos 2389 1.1 christos sprintf (output_buf, "ddns_cb: %p flags: %x state: %s cur_func: %s", 2390 1.1 christos ddns_cb, ddns_cb->flags, 2391 1.1 christos ddns_state_name(ddns_cb->state), 2392 1.1 christos dump_ddns_cb_func(ddns_cb->cur_func)); 2393 1.1 christos 2394 1.1 christos return(output_buf); 2395 1.1 christos } 2396 1.1 christos #endif /* DEBUG_DNS_UPDATES */ 2397 1.1 christos 2398 1.1 christos #endif /* NSUPDATE */ 2399