server/ddns.c

Go to the documentation of this file.
00001 /* ddns.c
00002 
00003    Dynamic DNS updates. */
00004 
00005 /*
00006  * 
00007  * Copyright (c) 2009-2014 by Internet Systems Consortium, Inc. ("ISC")
00008  * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
00009  * Copyright (c) 2000-2003 by Internet Software Consortium
00010  *
00011  * Permission to use, copy, modify, and distribute this software for any
00012  * purpose with or without fee is hereby granted, provided that the above
00013  * copyright notice and this permission notice appear in all copies.
00014  *
00015  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
00016  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00017  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
00018  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00019  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00020  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
00021  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00022  *
00023  *   Internet Systems Consortium, Inc.
00024  *   950 Charter Street
00025  *   Redwood City, CA 94063
00026  *   <info@isc.org>
00027  *   https://www.isc.org/
00028  *
00029  * This software has been donated to Internet Systems Consortium
00030  * by Damien Neil of Nominum, Inc.
00031  *
00032  * To learn more about Internet Systems Consortium, see
00033  * ``https://www.isc.org/''.   To learn more about Nominum, Inc., see
00034  * ``http://www.nominum.com''.
00035  */
00036 
00037 #include "dhcpd.h"
00038 #include <dns/result.h>
00039 
00040 char *ddns_standard_tag = "ddns-dhcid";
00041 char *ddns_interim_tag  = "ddns-txt";
00042 
00043 #ifdef NSUPDATE
00044 
00045 static void ddns_fwd_srv_connector(struct lease          *lease,
00046                                    struct iasubopt       *lease6,
00047                                    struct binding_scope **inscope,
00048                                    dhcp_ddns_cb_t        *ddns_cb,
00049                                    isc_result_t           eresult);
00050 
00051 /* DN: No way of checking that there is enough space in a data_string's
00052    buffer.  Be certain to allocate enough!
00053    TL: This is why the expression evaluation code allocates a *new*
00054    data_string.   :') */
00055 static void data_string_append (struct data_string *ds1,
00056                                 struct data_string *ds2)
00057 {
00058         memcpy (ds1 -> buffer -> data + ds1 -> len,
00059                 ds2 -> data,
00060                 ds2 -> len);
00061         ds1 -> len += ds2 -> len;
00062 }
00063 
00064 
00065 /* Determine what, if any, forward and reverse updates need to be
00066  * performed, and carry them through.
00067  */
00068 int
00069 ddns_updates(struct packet *packet, struct lease *lease, struct lease *old,
00070              struct iasubopt *lease6, struct iasubopt *old6,
00071              struct option_state *options)
00072 {
00073         unsigned long ddns_ttl = DEFAULT_DDNS_TTL;
00074         struct data_string ddns_hostname;
00075         struct data_string ddns_domainname;
00076         struct data_string old_ddns_fwd_name;
00077         struct data_string ddns_fwd_name;
00078         struct data_string ddns_dhcid;
00079         struct binding_scope **scope = NULL;
00080         struct data_string d1;
00081         struct option_cache *oc;
00082         int s1, s2;
00083         int result = 0;
00084         int server_updates_a = 1;
00085         struct buffer *bp = (struct buffer *)0;
00086         int ignorep = 0, client_ignorep = 0;
00087         int rev_name_len;
00088         int i;
00089 
00090         dhcp_ddns_cb_t *ddns_cb;
00091         int do_remove = 0;
00092 
00093         if ((ddns_update_style != DDNS_UPDATE_STYLE_STANDARD) &&
00094             (ddns_update_style != DDNS_UPDATE_STYLE_INTERIM))
00095                 return (0);
00096 
00097         /*
00098          * sigh, I want to cancel any previous udpates before we do anything
00099          * else but this means we need to deal with the lease vs lease6
00100          * question twice.
00101          * If there is a ddns request already outstanding cancel it.
00102          */
00103 
00104         if (lease != NULL) {
00105                 if ((old != NULL) && (old->ddns_cb != NULL)) {
00106                         ddns_cancel(old->ddns_cb, MDL);
00107                         old->ddns_cb = NULL;
00108                 }
00109         } else if (lease6 != NULL) {
00110                 if ((old6 != NULL) && (old6->ddns_cb != NULL)) {
00111                         ddns_cancel(old6->ddns_cb, MDL);
00112                         old6->ddns_cb = NULL;
00113                 }
00114         } else {
00115                 log_fatal("Impossible condition at %s:%d.", MDL);
00116                 /* Silence compiler warnings. */
00117                 result = 0;
00118                 return(0);
00119         }
00120 
00121         /* allocate our control block */
00122         ddns_cb = ddns_cb_alloc(MDL);
00123         if (ddns_cb == NULL) {
00124                 return(0);
00125         }
00126         /*
00127          * Assume that we shall update both the A and ptr records and,
00128          * as this is an update, set the active flag 
00129          */
00130         ddns_cb->flags = DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR |
00131                 DDNS_ACTIVE_LEASE;
00132 
00133         /*
00134          * For v4 we flag static leases so we don't try
00135          * and manipulate the lease later.  For v6 we don't
00136          * get static leases and don't need to flag them.
00137          */
00138         if (lease != NULL) {
00139                 scope = &(lease->scope);
00140                 ddns_cb->address = lease->ip_addr;
00141                 if (lease->flags & STATIC_LEASE)
00142                         ddns_cb->flags |= DDNS_STATIC_LEASE;
00143         } else if (lease6 != NULL) {
00144                 scope = &(lease6->scope);
00145                 memcpy(ddns_cb->address.iabuf, lease6->addr.s6_addr, 16);
00146                 ddns_cb->address.len = 16;
00147         }
00148 
00149         memset (&d1, 0, sizeof(d1));
00150         memset (&ddns_hostname, 0, sizeof (ddns_hostname));
00151         memset (&ddns_domainname, 0, sizeof (ddns_domainname));
00152         memset (&old_ddns_fwd_name, 0, sizeof (ddns_fwd_name));
00153         memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name));
00154         memset (&ddns_dhcid, 0, sizeof (ddns_dhcid));
00155 
00156         /* If we are allowed to accept the client's update of its own A
00157            record, see if the client wants to update its own A record. */
00158         if (!(oc = lookup_option(&server_universe, options,
00159                                  SV_CLIENT_UPDATES)) ||
00160             evaluate_boolean_option_cache(&client_ignorep, packet, lease, NULL,
00161                                           packet->options, options, scope,
00162                                           oc, MDL)) {
00163                 /* If there's no fqdn.no-client-update or if it's
00164                    nonzero, don't try to use the client-supplied
00165                    XXX */
00166                 if (!(oc = lookup_option (&fqdn_universe, packet -> options,
00167                                           FQDN_SERVER_UPDATE)) ||
00168                     evaluate_boolean_option_cache(&ignorep, packet, lease,
00169                                                   NULL, packet->options,
00170                                                   options, scope, oc, MDL))
00171                         goto noclient;
00172                 /* Win98 and Win2k will happily claim to be willing to
00173                    update an unqualified domain name. */
00174                 if (!(oc = lookup_option (&fqdn_universe, packet -> options,
00175                                           FQDN_DOMAINNAME)))
00176                         goto noclient;
00177                 if (!(oc = lookup_option (&fqdn_universe, packet -> options,
00178                                           FQDN_FQDN)) ||
00179                     !evaluate_option_cache(&ddns_fwd_name, packet, lease,
00180                                            NULL, packet->options,
00181                                            options, scope, oc, MDL))
00182                         goto noclient;
00183                 ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
00184                 server_updates_a = 0;
00185                 goto client_updates;
00186         }
00187       noclient:
00188         /* If do-forward-updates is disabled, this basically means don't
00189            do an update unless the client is participating, so if we get
00190            here and do-forward-updates is disabled, we can stop. */
00191         if ((oc = lookup_option (&server_universe, options,
00192                                  SV_DO_FORWARD_UPDATES)) &&
00193             !evaluate_boolean_option_cache(&ignorep, packet, lease,
00194                                            NULL, packet->options,
00195                                            options, scope, oc, MDL)) {
00196                 goto out;
00197         }
00198 
00199         /* If it's a static lease, then don't do the DNS update unless we're
00200            specifically configured to do so.   If the client asked to do its
00201            own update and we allowed that, we don't do this test. */
00202         /* XXX: note that we cannot detect static DHCPv6 leases. */
00203         if ((lease != NULL) && (lease->flags & STATIC_LEASE)) {
00204                 if (!(oc = lookup_option(&server_universe, options,
00205                                          SV_UPDATE_STATIC_LEASES)) ||
00206                     !evaluate_boolean_option_cache(&ignorep, packet, lease,
00207                                                    NULL, packet->options,
00208                                                    options, scope, oc, MDL))
00209                         goto out;
00210         }
00211 
00212         /*
00213          * Compute the name for the A record.
00214          */
00215         oc = lookup_option(&server_universe, options, SV_DDNS_HOST_NAME);
00216         if (oc)
00217                 s1 = evaluate_option_cache(&ddns_hostname, packet, lease,
00218                                            NULL, packet->options,
00219                                            options, scope, oc, MDL);
00220         else
00221                 s1 = 0;
00222 
00223         oc = lookup_option(&server_universe, options, SV_DDNS_DOMAIN_NAME);
00224         if (oc)
00225                 s2 = evaluate_option_cache(&ddns_domainname, packet, lease,
00226                                            NULL, packet->options,
00227                                            options, scope, oc, MDL);
00228         else
00229                 s2 = 0;
00230 
00231         if (s1 && s2) {
00232                 if (ddns_hostname.len + ddns_domainname.len > 253) {
00233                         log_error ("ddns_update: host.domain name too long");
00234 
00235                         goto out;
00236                 }
00237 
00238                 buffer_allocate (&ddns_fwd_name.buffer,
00239                                  ddns_hostname.len + ddns_domainname.len + 2,
00240                                  MDL);
00241                 if (ddns_fwd_name.buffer) {
00242                         ddns_fwd_name.data = ddns_fwd_name.buffer->data;
00243                         data_string_append (&ddns_fwd_name, &ddns_hostname);
00244                         ddns_fwd_name.buffer->data[ddns_fwd_name.len] = '.';
00245                         ddns_fwd_name.len++;
00246                         data_string_append (&ddns_fwd_name, &ddns_domainname);
00247                         ddns_fwd_name.buffer->data[ddns_fwd_name.len] ='\0';
00248                         ddns_fwd_name.terminated = 1;
00249                 }
00250         }
00251       client_updates:
00252 
00253         /* See if there's a name already stored on the lease. */
00254         if (find_bound_string(&old_ddns_fwd_name, *scope, "ddns-fwd-name")) {
00255                 /* If there is, see if it's different. */
00256                 if (old_ddns_fwd_name.len != ddns_fwd_name.len ||
00257                     memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data,
00258                             old_ddns_fwd_name.len)) {
00259                         /*
00260                          * If the name is different, mark the old record
00261                          * for deletion and continue getting the new info.
00262                          */
00263                         do_remove = 1;
00264                         goto in;
00265                 }
00266 
00267 #if defined  (DDNS_UPDATE_SLOW_TRANSITION)
00268                 /*
00269                  * If the slow transition code is enabled check to see
00270                  * if the stored type (standard or interim doesn't
00271                  * match the type currently in use.  If it doesn't
00272                  * try to remove and replace the DNS record
00273                  */
00274                 if (((ddns_update_style == DDNS_UPDATE_STYLE_STANDARD) &&
00275                      find_bound_string(&ddns_dhcid, *scope, ddns_interim_tag)) ||
00276                     ((ddns_update_style == DDNS_UPDATE_STYLE_INTERIM) &&
00277                      find_bound_string(&ddns_dhcid, *scope, ddns_standard_tag))) {
00278                         data_string_forget(&ddns_dhcid, MDL);
00279                         do_remove = 1;
00280                         goto in;
00281                 }
00282 #endif
00283                    
00284                 /* See if the administrator wants to do updates even
00285                    in cases where the update already appears to have been
00286                    done. */
00287                 if (!(oc = lookup_option(&server_universe, options,
00288                                          SV_UPDATE_OPTIMIZATION)) ||
00289                     evaluate_boolean_option_cache(&ignorep, packet, lease,
00290                                                   NULL, packet->options,
00291                                                   options, scope, oc, MDL)) {
00292                         result = 1;
00293                         goto noerror;
00294                 }
00295         /* If there's no "ddns-fwd-name" on the lease record, see if
00296          * there's a ddns-client-fqdn indicating a previous client
00297          * update (if it changes, we need to adjust the PTR).
00298          */
00299         } else if (find_bound_string(&old_ddns_fwd_name, *scope,
00300                                      "ddns-client-fqdn")) {
00301                 /* If the name is not different, no need to update
00302                    the PTR record. */
00303                 if (old_ddns_fwd_name.len == ddns_fwd_name.len &&
00304                     !memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data,
00305                              old_ddns_fwd_name.len) &&
00306                     (!(oc = lookup_option(&server_universe, options,
00307                                           SV_UPDATE_OPTIMIZATION)) ||
00308                      evaluate_boolean_option_cache(&ignorep, packet, lease,
00309                                                    NULL, packet->options,
00310                                                    options, scope, oc, MDL))) {
00311                         goto noerror;
00312                 }
00313         }
00314       in:
00315                 
00316         /* If we don't have a name that the client has been assigned, we
00317            can just skip all this. */
00318 
00319         if ((!ddns_fwd_name.len) || (ddns_fwd_name.len > 255)) {
00320                 if (ddns_fwd_name.len > 255) {
00321                         log_error ("client provided fqdn: too long");
00322                 }
00323 
00324                 /* If desired do the removals */
00325                 if (do_remove != 0) {
00326                         (void) ddns_removals(lease, lease6, NULL, ISC_TRUE);
00327                 }
00328                 goto out;
00329         }
00330 
00331         /*
00332          * Compute the RR TTL.
00333          *
00334          * We have two ways of computing the TTL.
00335          * The old behavior was to allow for the customer to set up
00336          * the option or to default things.  For v4 this was 1/2
00337          * of the lease time, for v6 this was DEFAULT_DDNS_TTL.
00338          * The new behavior continues to allow the customer to set
00339          * up an option but the defaults are a little different.
00340          * We now use 1/2 of the (preferred) lease time for both
00341          * v4 and v6 and cap them at a maximum value. 
00342          * If the customer chooses to use an experession that references
00343          * part of the lease the v6 value will be the default as there
00344          * isn't a lease available for v6.
00345          */
00346 
00347         ddns_ttl = DEFAULT_DDNS_TTL;
00348         if (lease != NULL) {
00349                 if (lease->ends <= cur_time) {
00350                         ddns_ttl = 0;
00351                 } else {
00352                         ddns_ttl = (lease->ends - cur_time)/2;
00353                 }
00354         }
00355 #ifndef USE_OLD_DDNS_TTL
00356         else if (lease6 != NULL) {
00357                 ddns_ttl = lease6->prefer/2;
00358         }
00359 
00360         if (ddns_ttl > MAX_DEFAULT_DDNS_TTL) {
00361                 ddns_ttl = MAX_DEFAULT_DDNS_TTL;
00362         }
00363 #endif          
00364 
00365         if ((oc = lookup_option(&server_universe, options, SV_DDNS_TTL))) {
00366                 if (evaluate_option_cache(&d1, packet, lease, NULL,
00367                                           packet->options, options,
00368                                           scope, oc, MDL)) {
00369                         if (d1.len == sizeof (u_int32_t))
00370                                 ddns_ttl = getULong (d1.data);
00371                         data_string_forget (&d1, MDL);
00372                 }
00373         }
00374 
00375         ddns_cb->ttl = ddns_ttl;
00376 
00377         /*
00378          * Compute the reverse IP name, starting with the domain name.
00379          */
00380         oc = lookup_option(&server_universe, options, SV_DDNS_REV_DOMAIN_NAME);
00381         if (oc)
00382                 s1 = evaluate_option_cache(&d1, packet, lease, NULL,
00383                                            packet->options, options,
00384                                            scope, oc, MDL);
00385         else
00386                 s1 = 0;
00387 
00388         /* 
00389          * Figure out the length of the part of the name that depends 
00390          * on the address.
00391          */
00392         if (ddns_cb->address.len == 4) {
00393                 char buf[17];
00394                 /* XXX: WOW this is gross. */
00395                 rev_name_len = snprintf(buf, sizeof(buf), "%u.%u.%u.%u.",
00396                                         ddns_cb->address.iabuf[3] & 0xff,
00397                                         ddns_cb->address.iabuf[2] & 0xff,
00398                                         ddns_cb->address.iabuf[1] & 0xff,
00399                                         ddns_cb->address.iabuf[0] & 0xff) + 1;
00400 
00401                 if (s1) {
00402                         rev_name_len += d1.len;
00403 
00404                         if (rev_name_len > 255) {
00405                                 log_error("ddns_update: Calculated rev domain "
00406                                           "name too long.");
00407                                 s1 = 0;
00408                                 data_string_forget(&d1, MDL);
00409                         }
00410                 }
00411         } else if (ddns_cb->address.len == 16) {
00412                 /* 
00413                  * IPv6 reverse names are always the same length, with 
00414                  * 32 hex characters separated by dots.
00415                  */
00416                 rev_name_len = sizeof("0.1.2.3.4.5.6.7."
00417                                       "8.9.a.b.c.d.e.f."
00418                                       "0.1.2.3.4.5.6.7."
00419                                       "8.9.a.b.c.d.e.f."
00420                                       "ip6.arpa.");
00421 
00422                 /* Set s1 to make sure we gate into updates. */
00423                 s1 = 1;
00424         } else {
00425                 log_fatal("invalid address length %d", ddns_cb->address.len);
00426                 /* Silence compiler warnings. */
00427                 return 0;
00428         }
00429 
00430         /* See if we are configured NOT to do reverse ptr updates */
00431         if ((oc = lookup_option(&server_universe, options,
00432                                 SV_DO_REVERSE_UPDATES)) &&
00433             !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
00434                                            packet->options, options,
00435                                            scope, oc, MDL)) {
00436                 ddns_cb->flags &= ~DDNS_UPDATE_PTR;
00437         }
00438 
00439         if (s1) {
00440                 buffer_allocate(&ddns_cb->rev_name.buffer, rev_name_len, MDL);
00441                 if (ddns_cb->rev_name.buffer != NULL) {
00442                         struct data_string *rname = &ddns_cb->rev_name;
00443                         rname->data = rname->buffer->data;
00444 
00445                         if (ddns_cb->address.len == 4) {
00446                                 rname->len =
00447                                     sprintf((char *)rname->buffer->data,
00448                                             "%u.%u.%u.%u.", 
00449                                             ddns_cb->address.iabuf[3] & 0xff,
00450                                             ddns_cb->address.iabuf[2] & 0xff,
00451                                             ddns_cb->address.iabuf[1] & 0xff,
00452                                             ddns_cb->address.iabuf[0] & 0xff);
00453 
00454                                 /*
00455                                  * d1.data may be opaque, garbage bytes, from
00456                                  * user (mis)configuration.
00457                                  */
00458                                 data_string_append(rname, &d1);
00459                                 rname->buffer->data[rname->len] = '\0';
00460                         } else if (ddns_cb->address.len == 16) {
00461                                 char *p = (char *)&rname->buffer->data;
00462                                 unsigned char *a = ddns_cb->address.iabuf + 15;
00463                                 for (i=0; i<16; i++) {
00464                                         sprintf(p, "%x.%x.", 
00465                                                 (*a & 0xF), ((*a >> 4) & 0xF));
00466                                         p += 4;
00467                                         a -= 1;
00468                                 }
00469                                 strcat(p, "ip6.arpa.");
00470                                 rname->len = strlen((const char *)rname->data);
00471                         }
00472 
00473                         rname->terminated = 1;
00474                 }
00475 
00476                 if (d1.data != NULL)
00477                         data_string_forget(&d1, MDL);
00478         }
00479 
00480         /*
00481          * copy the string now so we can pass it to the dhcid routines
00482          * via the ddns_cb pointer
00483          */
00484         data_string_copy(&ddns_cb->fwd_name, &ddns_fwd_name, MDL);
00485 
00486         /*
00487          * If we are updating the A record, compute the DHCID value.
00488          * We have two options for computing the DHCID value, the older
00489          * interim version and the newer standard version.  The interim
00490          * has some issues but is left as is to avoid compatibility issues.
00491          *
00492          * We select the type of DHCID to construct and the information to
00493          * use for the digest based on 4701 section 3.3
00494          */
00495         if ((ddns_cb->flags & DDNS_UPDATE_ADDR) != 0) {
00496                 int ddns_type;
00497                 int ddns_len;
00498                 if (ddns_update_style == DDNS_UPDATE_STYLE_STANDARD) {
00499                         /* The standard style */
00500                         ddns_cb->lease_tag = ddns_standard_tag;
00501                         ddns_cb->dhcid_class = dns_rdatatype_dhcid;
00502                         ddns_type = 1;
00503                         ddns_len = 4;
00504                 } else {
00505                         /* The older interim style */
00506                         ddns_cb->lease_tag = ddns_interim_tag;
00507                         ddns_cb->dhcid_class = dns_rdatatype_txt;
00508                         /* for backwards compatibility */
00509                         ddns_type = DHO_DHCP_CLIENT_IDENTIFIER;
00510                         /* IAID incorrectly included */
00511                         ddns_len = 0;
00512                 }
00513 
00514 
00515                 if (lease6 != NULL) {
00516                         if (lease6->ia->iaid_duid.len < ddns_len)
00517                                 goto badfqdn;
00518                         result = get_dhcid(ddns_cb, 2,
00519                                            lease6->ia->iaid_duid.data + ddns_len,
00520                                            lease6->ia->iaid_duid.len - ddns_len);
00521                 } else if ((lease != NULL) &&
00522                            (lease->uid != NULL) &&
00523                            (lease->uid_len != 0)) {
00524                         /* If this is standard check for an RFC 4361
00525                          * compliant client identifier
00526                          */
00527                         if ((ddns_update_style == DDNS_UPDATE_STYLE_STANDARD) &&
00528                             (lease->uid[0] == 255)) {
00529                                 if (lease->uid_len < 5)
00530                                         goto badfqdn;
00531                                 result = get_dhcid(ddns_cb, 2,
00532                                                    lease->uid + 5,
00533                                                    lease->uid_len - 5);
00534                         } else {
00535                                 result = get_dhcid(ddns_cb, ddns_type,
00536                                                    lease->uid,
00537                                                    lease->uid_len);
00538                         }
00539                 } else if (lease != NULL)
00540                         result = get_dhcid(ddns_cb, 0,
00541                                            lease->hardware_addr.hbuf,
00542                                            lease->hardware_addr.hlen);
00543                 else
00544                         log_fatal("Impossible condition at %s:%d.", MDL);
00545 
00546                 if (!result)
00547                         goto badfqdn;
00548         }
00549 
00550         /*
00551          * Perform updates.
00552          */
00553 
00554         if (ddns_cb->flags & DDNS_UPDATE_ADDR) {
00555                 oc = lookup_option(&server_universe, options,
00556                                    SV_DDNS_CONFLICT_DETECT);
00557                 if (oc &&
00558                     !evaluate_boolean_option_cache(&ignorep, packet, lease,
00559                                                    NULL, packet->options,
00560                                                    options, scope, oc, MDL))
00561                         ddns_cb->flags |= DDNS_CONFLICT_OVERRIDE;
00562 
00563         }
00564 
00565         /*
00566          * Previously if we failed during the removal operations
00567          * we skipped the fqdn option processing.  I'm not sure
00568          * if we want to continue with that if we fail before sending
00569          * the ddns messages.  Currently we don't.
00570          */
00571         if (do_remove) {
00572                 /*
00573                  * We should log a more specific error closer to the actual
00574                  * error if we want one. ddns_removal failure not logged here.
00575                  */
00576                  (void) ddns_removals(lease, lease6, ddns_cb, ISC_TRUE);
00577         }
00578         else {
00579                 ddns_fwd_srv_connector(lease, lease6, scope, ddns_cb,
00580                                        ISC_R_SUCCESS);
00581         }
00582         ddns_cb = NULL;
00583 
00584       noerror:
00585         /*
00586          * If fqdn-reply option is disabled in dhcpd.conf, then don't
00587          * send the client an FQDN option at all, even if one was requested.
00588          * (WinXP clients allegedly misbehave if the option is present,
00589          * refusing to handle PTR updates themselves).
00590          */
00591         if ((oc = lookup_option (&server_universe, options, SV_FQDN_REPLY)) &&
00592             !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
00593                                            packet->options, options,
00594                                            scope, oc, MDL)) {
00595                 goto badfqdn;
00596 
00597         /* If we're ignoring client updates, then we tell a sort of 'white
00598          * lie'.  We've already updated the name the server wants (per the
00599          * config written by the server admin).  Now let the client do as
00600          * it pleases with the name they supplied (if any).
00601          *
00602          * We only form an FQDN option this way if the client supplied an
00603          * FQDN option that had FQDN_SERVER_UPDATE set false.
00604          */
00605         } else if (client_ignorep &&
00606             (oc = lookup_option(&fqdn_universe, packet->options,
00607                                 FQDN_SERVER_UPDATE)) &&
00608             !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
00609                                            packet->options, options,
00610                                            scope, oc, MDL)) {
00611                 oc = lookup_option(&fqdn_universe, packet->options, FQDN_FQDN);
00612                 if (oc && evaluate_option_cache(&d1, packet, lease, NULL,
00613                                                 packet->options, options,
00614                                                 scope, oc, MDL)) {
00615                         if (d1.len == 0 ||
00616                             !buffer_allocate(&bp, d1.len + 5, MDL))
00617                                 goto badfqdn;
00618 
00619                         /* Server pretends it is not updating. */
00620                         bp->data[0] = 0;
00621                         if (!save_option_buffer(&fqdn_universe, options,
00622                                                 bp, &bp->data[0], 1,
00623                                                 FQDN_SERVER_UPDATE, 0))
00624                                 goto badfqdn;
00625 
00626                         /* Client is encouraged to update. */
00627                         bp->data[1] = 0;
00628                         if (!save_option_buffer(&fqdn_universe, options,
00629                                                 bp, &bp->data[1], 1,
00630                                                 FQDN_NO_CLIENT_UPDATE, 0))
00631                                 goto badfqdn;
00632 
00633                         /* Use the encoding of client's FQDN option. */
00634                         oc = lookup_option(&fqdn_universe, packet->options,
00635                                            FQDN_ENCODED);
00636                         if (oc &&
00637                             evaluate_boolean_option_cache(&ignorep, packet,
00638                                                           lease, NULL,
00639                                                           packet->options,
00640                                                           options, scope,
00641                                                           oc, MDL))
00642                                 bp->data[2] = 1; /* FQDN is encoded. */
00643                         else
00644                                 bp->data[2] = 0; /* FQDN is not encoded. */
00645 
00646                         if (!save_option_buffer(&fqdn_universe, options,
00647                                                 bp, &bp->data[2], 1,
00648                                                 FQDN_ENCODED, 0))
00649                                 goto badfqdn;
00650 
00651                         /* Current FQDN drafts indicate 255 is mandatory. */
00652                         bp->data[3] = 255;
00653                         if (!save_option_buffer(&fqdn_universe, options,
00654                                                 bp, &bp->data[3], 1,
00655                                                 FQDN_RCODE1, 0))
00656                                 goto badfqdn;
00657 
00658                         bp->data[4] = 255;
00659                         if (!save_option_buffer(&fqdn_universe, options,
00660                                                 bp, &bp->data[4], 1,
00661                                                 FQDN_RCODE2, 0))
00662                                 goto badfqdn;
00663 
00664                         /* Copy in the FQDN supplied by the client.  Note well
00665                          * that the format of this option in the cache is going
00666                          * to be in text format.  If the fqdn supplied by the
00667                          * client is encoded, it is decoded into the option
00668                          * cache when parsed out of the packet.  It will be
00669                          * re-encoded when the option is assembled to be
00670                          * transmitted if the client elects that encoding.
00671                          */
00672                         memcpy(&bp->data[5], d1.data, d1.len);
00673                         if (!save_option_buffer(&fqdn_universe, options,
00674                                                 bp, &bp->data[5], d1.len,
00675                                                 FQDN_FQDN, 0))
00676                                 goto badfqdn;
00677 
00678                         data_string_forget(&d1, MDL);
00679                 }
00680         /* Set up the outgoing FQDN option if there was an incoming
00681          * FQDN option.  If there's a valid FQDN option, there MUST
00682          * be an FQDN_SERVER_UPDATES suboption, it's part of the fixed
00683          * length head of the option contents, so we test the latter
00684          * to detect the presence of the former.
00685          */
00686         } else if ((oc = lookup_option(&fqdn_universe, packet->options,
00687                                        FQDN_ENCODED)) &&
00688                    buffer_allocate(&bp, ddns_fwd_name.len + 5, MDL)) {
00689                 bp -> data [0] = server_updates_a;
00690                 if (!save_option_buffer(&fqdn_universe, options,
00691                                         bp, &bp->data [0], 1,
00692                                         FQDN_SERVER_UPDATE, 0))
00693                         goto badfqdn;
00694                 bp -> data [1] = server_updates_a;
00695                 if (!save_option_buffer(&fqdn_universe, options,
00696                                          bp, &bp->data [1], 1,
00697                                          FQDN_NO_CLIENT_UPDATE, 0))
00698                         goto badfqdn;
00699 
00700                 /* Do the same encoding the client did. */
00701                 if (evaluate_boolean_option_cache(&ignorep, packet, lease,
00702                                                   NULL, packet->options,
00703                                                   options, scope, oc, MDL))
00704                         bp -> data [2] = 1;
00705                 else
00706                         bp -> data [2] = 0;
00707                 if (!save_option_buffer(&fqdn_universe, options,
00708                                         bp, &bp->data [2], 1,
00709                                         FQDN_ENCODED, 0))
00710                         goto badfqdn;
00711                 bp -> data [3] = 255;//isc_rcode_to_ns (rcode1);
00712                 if (!save_option_buffer(&fqdn_universe, options,
00713                                         bp, &bp->data [3], 1,
00714                                         FQDN_RCODE1, 0))
00715                         goto badfqdn;
00716                 bp -> data [4] = 255;//isc_rcode_to_ns (rcode2);
00717                 if (!save_option_buffer(&fqdn_universe, options,
00718                                         bp, &bp->data [4], 1,
00719                                         FQDN_RCODE2, 0))
00720                         goto badfqdn;
00721                 if (ddns_fwd_name.len) {
00722                     memcpy (&bp -> data [5],
00723                             ddns_fwd_name.data, ddns_fwd_name.len);
00724                     if (!save_option_buffer(&fqdn_universe, options,
00725                                              bp, &bp->data [5],
00726                                              ddns_fwd_name.len,
00727                                              FQDN_FQDN, 0))
00728                         goto badfqdn;
00729                 }
00730         }
00731 
00732       badfqdn:
00733       out:
00734         /*
00735          * Final cleanup.
00736          */
00737         if (ddns_cb != NULL) {
00738                 ddns_cb_free(ddns_cb, MDL);
00739         }
00740 
00741         data_string_forget(&d1, MDL);
00742         data_string_forget(&ddns_hostname, MDL);
00743         data_string_forget(&ddns_domainname, MDL);
00744         data_string_forget(&old_ddns_fwd_name, MDL);
00745         data_string_forget(&ddns_fwd_name, MDL);
00746         if (bp)
00747                 buffer_dereference(&bp, MDL);
00748 
00749         return result;
00750 }
00751 
00752 /*%<
00753  * Utility function to update text strings within a lease.
00754  *
00755  * The first issue is to find the proper scope.  Sometimes we shall be
00756  * called with a pointer to the scope in other cases we need to find
00757  * the proper lease and then get the scope.  Once we have the scope we update
00758  * the proper strings, as indicated by the state value in the control block.
00759  * Lastly, if we needed to find the scope we write it out, if we used a
00760  * scope that was passed as an argument we don't write it, assuming that
00761  * our caller (or his ...) will do the write.
00762  * 
00763  *\li ddns_cb - the control block for the DDNS request
00764  *
00765  *\li inscope - a pointer to the scope to update.  This may be NULL
00766  *    in which case we use the control block to find the lease and
00767  *    then the scope.
00768  *
00769  * Returns
00770  *\li ISC_R_SUCCESS
00771  *
00772  *\li ISC_R_FAILURE - The routine was unable to find an expected scope.
00773  *    In some cases (static and inactive leases) we don't expect a scope
00774  *    and return success.
00775  */
00776 
00777 isc_result_t
00778 ddns_update_lease_text(dhcp_ddns_cb_t        *ddns_cb,
00779                        struct binding_scope **inscope)
00780 {
00781         struct binding_scope **scope  = NULL;
00782         struct lease          *lease  = NULL;
00783         struct iasubopt       *lease6 = NULL;
00784         struct ipv6_pool      *pool   = NULL;
00785         struct in6_addr        addr;
00786         struct data_string     lease_dhcid;
00787         
00788         /*
00789          * If the lease was static (for a fixed address)
00790          * we don't need to do any work.
00791          */
00792         if (ddns_cb->flags & DDNS_STATIC_LEASE)
00793                 return (ISC_R_SUCCESS);
00794 
00795         /* 
00796          * If we are processing an expired or released v6 lease
00797          * or some types of v4 leases we don't actually have a
00798          * scope to update
00799          */
00800         if ((ddns_cb->flags & DDNS_ACTIVE_LEASE) == 0)
00801                 return (ISC_R_SUCCESS);
00802 
00803         if (inscope != NULL) {
00804                 scope = inscope;
00805         } else if (ddns_cb->address.len == 4) {
00806                 if (find_lease_by_ip_addr(&lease, ddns_cb->address, MDL) != 0){
00807                         scope = &(lease->scope);
00808                 }
00809         } else if (ddns_cb->address.len == 16) {
00810                 memcpy(&addr, &ddns_cb->address.iabuf, 16);
00811                 if ((find_ipv6_pool(&pool, D6O_IA_TA, &addr) ==
00812                      ISC_R_SUCCESS) ||
00813                     (find_ipv6_pool(&pool, D6O_IA_NA, &addr) == 
00814                      ISC_R_SUCCESS)) {
00815                         if (iasubopt_hash_lookup(&lease6,  pool->leases,
00816                                                  &addr, 16, MDL)) {
00817                                 scope = &(lease6->scope);
00818                         }
00819                         ipv6_pool_dereference(&pool, MDL);
00820                 }
00821         } else {
00822                 log_fatal("Impossible condition at %s:%d.", MDL);
00823         }
00824 
00825         if (scope == NULL) {
00826                 /* If necessary get rid of the lease */
00827                 if (lease) {
00828                         lease_dereference(&lease, MDL);
00829                 }
00830                 else if (lease6) {
00831                         iasubopt_dereference(&lease6, MDL);
00832                 }
00833 
00834                 return(ISC_R_FAILURE);
00835         }
00836 
00837         /* We now have a scope and can proceed to update it */
00838         switch(ddns_cb->state) {
00839         case DDNS_STATE_REM_PTR:
00840                 unset(*scope, "ddns-rev-name");
00841                 if ((ddns_cb->flags & DDNS_CLIENT_DID_UPDATE) != 0) {
00842                         unset(*scope, "ddns-client-fqdn");
00843                 }
00844                 break;
00845 
00846         case DDNS_STATE_ADD_PTR:
00847         case DDNS_STATE_CLEANUP:
00848                 bind_ds_value(scope, "ddns-rev-name", &ddns_cb->rev_name);
00849                 if ((ddns_cb->flags & DDNS_UPDATE_ADDR) == 0) {
00850                         bind_ds_value(scope, "ddns-client-fqdn",
00851                                       &ddns_cb->fwd_name);
00852                 }
00853                 break;
00854 
00855         case DDNS_STATE_ADD_FW_YXDHCID:
00856         case DDNS_STATE_ADD_FW_NXDOMAIN:
00857                 bind_ds_value(scope, "ddns-fwd-name", &ddns_cb->fwd_name);
00858 
00859                 if (ddns_cb->lease_tag == ddns_standard_tag) {
00860                         bind_ds_value(scope, ddns_standard_tag, &ddns_cb->dhcid);
00861                 } else {
00862                         /* convert from dns version to lease version of dhcid */
00863                         memset(&lease_dhcid, 0, sizeof(lease_dhcid));
00864                         dhcid_tolease(&ddns_cb->dhcid, &lease_dhcid);
00865                         bind_ds_value(scope, ddns_interim_tag, &lease_dhcid);
00866                         data_string_forget(&lease_dhcid, MDL);
00867                 }
00868                 break;
00869 
00870         case DDNS_STATE_REM_FW_NXRR:
00871         case DDNS_STATE_REM_FW_YXDHCID:
00872                 unset(*scope, "ddns-fwd-name");
00873                 unset(*scope, ddns_cb->lease_tag);
00874                 break;
00875         }
00876                 
00877         /* If necessary write it out and get rid of the lease */
00878         if (lease) {
00879                 write_lease(lease);
00880                 lease_dereference(&lease, MDL);
00881         } else if (lease6) {
00882                 write_ia(lease6->ia);
00883                 iasubopt_dereference(&lease6, MDL);
00884         }
00885 
00886         return(ISC_R_SUCCESS);
00887 }
00888 
00889 /*
00890  * This function should be called when update_lease_ptr function fails.
00891  * It does inform user about the condition, provides some hints how to
00892  * resolve this and dies gracefully. This can happend in at least three
00893  * cases (all are configuration mistakes):
00894  * a) IPv4: user have duplicate fixed-address entries (the same
00895  *    address is defined twice). We may have found wrong lease.
00896  * b) IPv6: user have overlapping pools (we tried to find 
00897  *    a lease in a wrong pool)
00898  * c) IPv6: user have duplicate fixed-address6 entires (the same
00899  *    address is defined twice). We may have found wrong lease.
00900  *
00901  * Comment: while it would be possible to recover from both cases
00902  * by forcibly searching for leases in *all* following pools, that would
00903  * only hide the real problem - a misconfiguration. Proper solution
00904  * is to log the problem, die and let the user fix his config file.
00905  */
00906 void
00907 update_lease_failed(struct lease *lease,
00908                     struct iasubopt *lease6,
00909                     dhcp_ddns_cb_t  *ddns_cb,
00910                     dhcp_ddns_cb_t  *ddns_cb_set,
00911                     const char * file, int line)
00912 {
00913         char lease_address[MAX_ADDRESS_STRING_LEN + 64];
00914         char reason[128]; /* likely reason */
00915 
00916         sprintf(reason, "unknown");
00917         sprintf(lease_address, "unknown");
00918 
00919         /*
00920          * let's pretend that everything is ok, so we can continue for 
00921          * information gathering purposes
00922          */
00923         
00924         if (ddns_cb != NULL) {
00925                 strncpy(lease_address, piaddr(ddns_cb->address), 
00926                         MAX_ADDRESS_STRING_LEN);
00927                 
00928                 if (ddns_cb->address.len == 4) {
00929                         sprintf(reason, "duplicate IPv4 fixed-address entry");
00930                 } else if (ddns_cb->address.len == 16) {
00931                         sprintf(reason, "duplicate IPv6 fixed-address6 entry "
00932                                 "or overlapping pools");
00933                 } else {
00934                         /* 
00935                          * Should not happen. We have non-IPv4, non-IPv6 
00936                          * address. Something is very wrong here.
00937                          */
00938                         sprintf(reason, "corrupted ddns_cb structure (address "
00939                                 "length is %d)", ddns_cb->address.len);
00940                 }
00941         }
00942         
00943         log_error("Failed to properly update internal lease structure with "
00944                   "DDNS");
00945         log_error("control block structures. Tried to update lease for"
00946                   "%s address, ddns_cb=%p.", lease_address, ddns_cb);
00947 
00948         log_error("%s", "");
00949         log_error("This condition can occur, if DHCP server configuration is "
00950                   "inconsistent.");
00951         log_error("In particular, please do check that your configuration:");
00952         log_error("a) does not have overlapping pools (especially containing");
00953         log_error("   %s address).", lease_address);
00954         log_error("b) there are no duplicate fixed-address or fixed-address6");
00955         log_error("entries for the %s address.", lease_address);
00956         log_error("%s", "");
00957         log_error("Possible reason for this failure: %s", reason);
00958 
00959         log_fatal("%s(%d): Failed to update lease database with DDNS info for "
00960                   "address %s. Lease database inconsistent. Unable to recover."
00961                   " Terminating.", file, line, lease_address);
00962 }
00963 
00964 /*
00965  * utility function to update found lease. It does extra checks
00966  * that we are indeed updating the right lease. It may happen
00967  * that user have duplicate fixed-address entries, so we attempt
00968  * to update wrong lease. See also safe_lease6_update.
00969  */
00970 
00971 void
00972 safe_lease_update(struct lease *lease,
00973                   dhcp_ddns_cb_t *oldcb,
00974                   dhcp_ddns_cb_t *newcb,
00975                   const char *file, int line)
00976 {
00977         if (lease == NULL) {
00978                 /* should never get here */
00979                 log_fatal("Impossible condition at %s:%d (called from %s:%d).", 
00980                           MDL, file, line);
00981         }
00982 
00983         if ( (lease->ddns_cb == NULL) && (newcb == NULL) ) {
00984                 /*
00985                  * Trying to clean up pointer that is already null. We
00986                  * are most likely trying to update wrong lease here.
00987                  */
00988 
00989                 /* 
00990                  * Previously this error message popped out during
00991                  * DNS update for fixed leases.  As we no longer
00992                  * try to update the lease for a fixed (static) lease
00993                  * this should not be a problem.
00994                  */
00995                 log_error("%s(%d): Invalid lease update. Tried to "
00996                           "clear already NULL DDNS control block "
00997                           "pointer for lease %s.",
00998                           file, line, piaddr(lease->ip_addr) );
00999 
01000 #if defined (DNS_UPDATES_MEMORY_CHECKS)
01001                 update_lease_failed(lease, NULL, oldcb, newcb, file, line);
01002 #endif
01003                 /* 
01004                  * May not reach this: update_lease_failed calls 
01005                  * log_fatal.
01006                  */ 
01007                 return;
01008         }
01009 
01010         if ( (lease->ddns_cb != NULL) && (lease->ddns_cb != oldcb) ) {
01011                 /* 
01012                  * There is existing cb structure, but it differs from
01013                  * what we expected to see there. Most likely we are 
01014                  * trying to update wrong lease. 
01015                  */
01016                 log_error("%s(%d): Failed to update internal lease "
01017                           "structure with DDNS control block. Existing"
01018                           " ddns_cb structure does not match "
01019                           "expectations.IPv4=%s, old ddns_cb=%p, tried"
01020                           "to update to new ddns_cb=%p", file, line,
01021                           piaddr(lease->ip_addr), oldcb,  newcb);
01022 
01023 #if defined (DNS_UPDATES_MEMORY_CHECKS)
01024                 update_lease_failed(lease, NULL, oldcb, newcb, file, line);
01025 #endif
01026                 /* 
01027                  * May not reach this: update_lease_failed calls 
01028                  * log_fatal.
01029                  */ 
01030                 return; 
01031         }
01032 
01033         /* additional IPv4 specific checks may be added here */
01034 
01035         /* update the lease */
01036         lease->ddns_cb = newcb;
01037 }
01038 
01039 void
01040 safe_lease6_update(struct iasubopt *lease6,
01041                    dhcp_ddns_cb_t *oldcb,
01042                    dhcp_ddns_cb_t *newcb,
01043                    const char *file, int line)
01044 {
01045         char addrbuf[MAX_ADDRESS_STRING_LEN];
01046 
01047         if (lease6 == NULL) {
01048                 /* should never get here */
01049                 log_fatal("Impossible condition at %s:%d (called from %s:%d).", 
01050                           MDL, file, line);
01051         }
01052 
01053         if ( (lease6->ddns_cb == NULL) && (newcb == NULL) ) {
01054                 inet_ntop(AF_INET6, &lease6->addr, addrbuf, 
01055                           MAX_ADDRESS_STRING_LEN);
01056                 /*
01057                  * Trying to clean up pointer that is already null. We
01058                  * are most likely trying to update wrong lease here.
01059                  */
01060                 log_error("%s(%d): Failed to update internal lease "
01061                           "structure. Tried to clear already NULL "
01062                           "DDNS control block pointer for lease %s.",
01063                           file, line, addrbuf);
01064 
01065 #if defined (DNS_UPDATES_MEMORY_CHECKS)
01066                 update_lease_failed(NULL, lease6, oldcb, newcb, file, line);
01067 #endif
01068 
01069                 /* 
01070                  * May not reach this: update_lease_failed calls 
01071                  * log_fatal.
01072                  */ 
01073                 return; 
01074         }
01075 
01076         if ( (lease6->ddns_cb != NULL) && (lease6->ddns_cb != oldcb) ) {
01077                 /* 
01078                  * there is existing cb structure, but it differs from
01079                  * what we expected to see there. Most likely we are 
01080                  * trying to update wrong lease. 
01081                  */
01082                 inet_ntop(AF_INET6, &lease6->addr, addrbuf, 
01083                           MAX_ADDRESS_STRING_LEN);
01084 
01085                 log_error("%s(%d): Failed to update internal lease "
01086                           "structure with DDNS control block. Existing"
01087                           " ddns_cb structure does not match "
01088                           "expectations.IPv6=%s, old ddns_cb=%p, tried"
01089                           "to update to new ddns_cb=%p", file, line,
01090                           addrbuf, oldcb,  newcb);
01091 
01092 #if defined (DNS_UPDATES_MEMORY_CHECKS)
01093                 update_lease_failed(NULL, lease6, oldcb, newcb, file, line);
01094 #endif
01095                 /* 
01096                  * May not reach this: update_lease_failed calls 
01097                  * log_fatal.
01098                  */ 
01099                 return;
01100         }
01101         /* additional IPv6 specific checks may be added here */
01102         
01103         /* update the lease */
01104         lease6->ddns_cb = newcb;
01105 }
01106 
01107 /*
01108  * Utility function to update the pointer to the DDNS control block
01109  * in a lease.
01110  * SUCCESS - able to update the pointer
01111  * FAILURE - lease didn't exist or sanity checks failed
01112  * lease and lease6 may be empty in which case we attempt to find
01113  * the lease from the ddns_cb information.
01114  * ddns_cb is the control block to use if a lookup is necessary
01115  * ddns_cb_set is the pointer to insert into the lease and may be NULL
01116  * The last two arguments may look odd as they will be the same much of the
01117  * time, but I need an argument to tell me if I'm setting or clearing in
01118  * addition to the address information from the cb to look up the lease.
01119  * using the same value twice allows me more flexibility.
01120  */
01121 
01122 isc_result_t 
01123 ddns_update_lease_ptr(struct lease    *lease,
01124                       struct iasubopt *lease6,
01125                       dhcp_ddns_cb_t  *ddns_cb,
01126                       dhcp_ddns_cb_t  *ddns_cb_set,
01127                       const char * file, int line)
01128 {
01129         char ddns_address[MAX_ADDRESS_STRING_LEN];
01130         sprintf(ddns_address, "unknown");
01131         if (ddns_cb == NULL) {
01132                 log_info("%s(%d): No control block for lease update",
01133                          file, line);
01134                 return (ISC_R_FAILURE);
01135         }
01136         else {
01137                 strncpy(ddns_address, piaddr(ddns_cb->address), 
01138                         MAX_ADDRESS_STRING_LEN);
01139         }
01140 #if defined (DEBUG_DNS_UPDATES)
01141         log_info("%s(%d): Updating lease_ptr for ddns_cp=%p (addr=%s)",
01142                  file, line, ddns_cb, ddns_address );
01143 #endif
01144 
01145         /*
01146          * If the lease was static (for a fixed address)
01147          * we don't need to do any work.
01148          */
01149         if (ddns_cb->flags & DDNS_STATIC_LEASE) {
01150 #if defined (DEBUG_DNS_UPDATES)
01151                 log_info("lease is static, returning");
01152 #endif
01153                 return (ISC_R_SUCCESS);
01154         }
01155 
01156         /* 
01157          * If we are processing an expired or released v6 lease
01158          * we don't actually have a lease to update
01159          */
01160         if ((ddns_cb->address.len == 16) &&
01161             ((ddns_cb->flags & DDNS_ACTIVE_LEASE) == 0)) {
01162                 return (ISC_R_SUCCESS);
01163         }
01164 
01165         if (lease != NULL) {
01166                 safe_lease_update(lease, ddns_cb, ddns_cb_set, 
01167                                   file, line);
01168         } else if (lease6 != NULL) {
01169                 safe_lease6_update(lease6, ddns_cb, ddns_cb_set, 
01170                                   file, line);
01171         } else if (ddns_cb->address.len == 4) {
01172                 struct lease *find_lease = NULL;
01173                 if (find_lease_by_ip_addr(&find_lease,
01174                                           ddns_cb->address, MDL) != 0) {
01175 #if defined (DEBUG_DNS_UPDATES)
01176                         log_info("%s(%d): find_lease_by_ip_addr(%s) successful:"
01177                                  "lease=%p", file, line, ddns_address, 
01178                                  find_lease);
01179 #endif
01180                   
01181                         safe_lease_update(find_lease, ddns_cb,
01182                                           ddns_cb_set, file, line);
01183                         lease_dereference(&find_lease, MDL);
01184                 }
01185                 else {
01186                         log_error("%s(%d): ddns_update_lease_ptr failed. "
01187                                   "Lease for %s not found.",
01188                                   file, line, piaddr(ddns_cb->address));
01189 
01190 #if defined (DNS_UPDATES_MEMORY_CHECKS)
01191                         update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set,
01192                                             file, line);
01193 #endif
01194                         /*
01195                          * may not reach this. update_lease_failed 
01196                          * calls log_fatal. 
01197                          */
01198                         return(ISC_R_FAILURE); 
01199                                                   
01200                 }
01201         } else if (ddns_cb->address.len == 16) {
01202                 struct iasubopt *find_lease6 = NULL;
01203                 struct ipv6_pool *pool = NULL;
01204                 struct in6_addr addr;
01205                 char addrbuf[MAX_ADDRESS_STRING_LEN];
01206 
01207                 memcpy(&addr, &ddns_cb->address.iabuf, 16);
01208                 if ((find_ipv6_pool(&pool, D6O_IA_TA, &addr) != 
01209                      ISC_R_SUCCESS) &&
01210                     (find_ipv6_pool(&pool, D6O_IA_NA, &addr) != 
01211                      ISC_R_SUCCESS)) {
01212                         inet_ntop(AF_INET6, &addr, addrbuf,
01213                                   MAX_ADDRESS_STRING_LEN);
01214                         log_error("%s(%d): Pool for lease %s not found.",
01215                                   file, line, addrbuf);
01216 #if defined (DNS_UPDATES_MEMORY_CHECKS)
01217                         update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set,
01218                                             file, line);
01219 #endif
01220                         /*
01221                          * never reached. update_lease_failed 
01222                          * calls log_fatal. 
01223                          */
01224                         return(ISC_R_FAILURE);
01225                 }
01226 
01227                 if (iasubopt_hash_lookup(&find_lease6, pool->leases,
01228                                          &addr, 16, MDL)) {
01229                         find_lease6->ddns_cb = ddns_cb_set;
01230                         iasubopt_dereference(&find_lease6, MDL);
01231                 } else {
01232                         inet_ntop(AF_INET6, &addr, addrbuf,
01233                                   MAX_ADDRESS_STRING_LEN);
01234                         log_error("%s(%d): Lease %s not found within pool.",
01235                                   file, line, addrbuf);
01236 #if defined (DNS_UPDATES_MEMORY_CHECKS)
01237                         update_lease_failed(NULL, NULL, ddns_cb, ddns_cb_set,
01238                                             file, line);
01239 #endif
01240                         /*
01241                          * never reached. update_lease_failed 
01242                          * calls log_fatal. 
01243                          */
01244                         return(ISC_R_FAILURE);
01245                 }
01246                 ipv6_pool_dereference(&pool, MDL);
01247         } else {
01248                 /* shouldn't get here */
01249                 log_fatal("Impossible condition at %s:%d, called from %s:%d.", 
01250                           MDL, file, line);
01251         }
01252 
01253         return(ISC_R_SUCCESS);
01254 }               
01255 
01256 void
01257 ddns_ptr_add(dhcp_ddns_cb_t *ddns_cb,
01258              isc_result_t    eresult)
01259 {
01260         if (eresult == ISC_R_SUCCESS) {
01261                 log_info("Added reverse map from %.*s to %.*s",
01262                          (int)ddns_cb->rev_name.len,
01263                          (const char *)ddns_cb->rev_name.data,
01264                          (int)ddns_cb->fwd_name.len,
01265                          (const char *)ddns_cb->fwd_name.data);
01266 
01267                 ddns_update_lease_text(ddns_cb, NULL);
01268         } else {
01269                 log_error("Unable to add reverse map from %.*s to %.*s: %s",
01270                           (int)ddns_cb->rev_name.len,
01271                           (const char *)ddns_cb->rev_name.data,
01272                           (int)ddns_cb->fwd_name.len,
01273                           (const char *)ddns_cb->fwd_name.data,
01274                           isc_result_totext (eresult));
01275         }
01276 
01277         ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
01278         ddns_cb_free(ddns_cb, MDL);
01279         /*
01280          * A single DDNS operation may require several calls depending on
01281          * the current state as the prerequisites for the first message
01282          * may not succeed requiring a second operation and potentially
01283          * a ptr operation after that.  The commit_leases operation is
01284          * invoked at the end of this set of operations in order to require
01285          * a single write for all of the changes.  We call commit_leases
01286          * here rather than immediately after the call to update the lease
01287          * text in order to save any previously written data.
01288          */
01289         commit_leases();
01290         return;
01291 }
01292 
01293 /*
01294  * action routine when trying to remove a pointer
01295  * this will be called after the ddns queries have completed
01296  * if we succeeded in removing the pointer we go to the next step (if any)
01297  * if not we cleanup and leave.
01298  */
01299 
01300 void
01301 ddns_ptr_remove(dhcp_ddns_cb_t *ddns_cb,
01302                 isc_result_t    eresult)
01303 {
01304         isc_result_t result = eresult;
01305 
01306         switch(eresult) {
01307         case ISC_R_SUCCESS:
01308                 log_info("Removed reverse map on %.*s",
01309                          (int)ddns_cb->rev_name.len,
01310                          (const char *)ddns_cb->rev_name.data);
01311                 /* fall through */
01312         case DNS_R_NXRRSET:
01313         case DNS_R_NXDOMAIN:
01314                 /* No entry is the same as success.
01315                  * Remove the information from the lease and
01316                  * continue with any next step */
01317                 ddns_update_lease_text(ddns_cb, NULL);
01318 
01319                 /* trigger any add operation */
01320                 result = ISC_R_SUCCESS;
01321 #if defined (DEBUG_DNS_UPDATES)
01322                 log_info("DDNS: removed map or no reverse map to remove %.*s",
01323                          (int)ddns_cb->rev_name.len,
01324                          (const char *)ddns_cb->rev_name.data);
01325 #endif
01326                 break;
01327 
01328         default:
01329                 log_error("Can't remove reverse map on %.*s: %s",
01330                           (int)ddns_cb->rev_name.len,
01331                           (const char *)ddns_cb->rev_name.data,
01332                           isc_result_totext (eresult));
01333                 break;
01334         }
01335 
01336         ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
01337         ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, result);
01338         ddns_cb_free(ddns_cb, MDL);
01339         return;
01340 }
01341 
01342 
01343 /*
01344  * If the first query succeeds, the updater can conclude that it
01345  * has added a new name whose only RRs are the A and DHCID RR records.
01346  * The A RR update is now complete (and a client updater is finished,
01347  * while a server might proceed to perform a PTR RR update).
01348  *   -- "Interaction between DHCP and DNS"
01349  *
01350  * If the second query succeeds, the updater can conclude that the current
01351  * client was the last client associated with the domain name, and that
01352  * the name now contains the updated A RR. The A RR update is now
01353  * complete (and a client updater is finished, while a server would
01354  * then proceed to perform a PTR RR update).
01355  *   -- "Interaction between DHCP and DNS"
01356  *
01357  * If the second query fails with NXRRSET, the updater must conclude
01358  * that the client's desired name is in use by another host.  At this
01359  * juncture, the updater can decide (based on some administrative
01360  * configuration outside of the scope of this document) whether to let
01361  * the existing owner of the name keep that name, and to (possibly)
01362  * perform some name disambiguation operation on behalf of the current
01363  * client, or to replace the RRs on the name with RRs that represent
01364  * the current client. If the configured policy allows replacement of
01365  * existing records, the updater submits a query that deletes the
01366  * existing A RR and the existing DHCID RR, adding A and DHCID RRs that
01367  * represent the IP address and client-identity of the new client.
01368  *   -- "Interaction between DHCP and DNS"
01369  */
01370 
01371 void
01372 ddns_fwd_srv_add2(dhcp_ddns_cb_t *ddns_cb,
01373                   isc_result_t    eresult)
01374 {
01375         isc_result_t result;
01376         const char *logstr = NULL;
01377         char ddns_address[MAX_ADDRESS_STRING_LEN];
01378 
01379         /* Construct a printable form of the address for logging */
01380         strcpy(ddns_address, piaddr(ddns_cb->address));
01381 
01382         switch(eresult) {
01383         case ISC_R_SUCCESS:
01384                 log_info("Added new forward map from %.*s to %s",
01385                          (int)ddns_cb->fwd_name.len,
01386                          (const char *)ddns_cb->fwd_name.data,
01387                          ddns_address);
01388 
01389                 ddns_update_lease_text(ddns_cb, NULL);
01390 
01391                 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
01392                         /* if we have zone information get rid of it */
01393                         if (ddns_cb->zone != NULL) {
01394                                 ddns_cb_forget_zone(ddns_cb);
01395                         }
01396 
01397                         ddns_cb->state = DDNS_STATE_ADD_PTR;
01398                         ddns_cb->cur_func = ddns_ptr_add;
01399                         
01400                         result = ddns_modify_ptr(ddns_cb, MDL);
01401                         if (result == ISC_R_SUCCESS) {
01402                                 return;
01403                         }
01404                 }
01405                 break;
01406 
01407         case DNS_R_YXRRSET:
01408         case DNS_R_YXDOMAIN:
01409                 logstr = "DHCID mismatch, belongs to another client.";
01410                 break;
01411 
01412         case DNS_R_NXRRSET:
01413         case DNS_R_NXDOMAIN:
01414                 logstr = "Has an address record but no DHCID, not mine.";
01415                 break;
01416 
01417         default:
01418                 logstr = isc_result_totext(eresult);
01419                 break;
01420         }
01421 
01422         if (logstr != NULL) {
01423                 log_error("Forward map from %.*s to %s FAILED: %s",
01424                           (int)ddns_cb->fwd_name.len,
01425                           (const char *)ddns_cb->fwd_name.data,
01426                           ddns_address, logstr);
01427         }
01428 
01429         ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
01430         ddns_cb_free(ddns_cb, MDL);
01431         /*
01432          * A single DDNS operation may require several calls depending on
01433          * the current state as the prerequisites for the first message
01434          * may not succeed requiring a second operation and potentially
01435          * a ptr operation after that.  The commit_leases operation is
01436          * invoked at the end of this set of operations in order to require
01437          * a single write for all of the changes.  We call commit_leases
01438          * here rather than immediately after the call to update the lease
01439          * text in order to save any previously written data.
01440          */
01441         commit_leases();
01442         return;
01443 }
01444 
01445 void
01446 ddns_fwd_srv_add1(dhcp_ddns_cb_t *ddns_cb,
01447                   isc_result_t    eresult)
01448 {
01449         isc_result_t result;
01450         char ddns_address[MAX_ADDRESS_STRING_LEN];
01451 
01452         /* Construct a printable form of the address for logging */
01453         strcpy(ddns_address, piaddr(ddns_cb->address));
01454 
01455         switch(eresult) {
01456         case ISC_R_SUCCESS:
01457                 log_info ("Added new forward map from %.*s to %s",
01458                           (int)ddns_cb->fwd_name.len,
01459                           (const char *)ddns_cb->fwd_name.data,
01460                           ddns_address);
01461 
01462                 ddns_update_lease_text(ddns_cb, NULL);
01463 
01464                 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
01465                         /* if we have zone information get rid of it */
01466                         if (ddns_cb->zone != NULL) {
01467                                 ddns_cb_forget_zone(ddns_cb);
01468                         }
01469 
01470                         ddns_cb->state = DDNS_STATE_ADD_PTR;
01471                         ddns_cb->cur_func = ddns_ptr_add;
01472                         
01473                         result = ddns_modify_ptr(ddns_cb, MDL);
01474                         if (result == ISC_R_SUCCESS) {
01475                                 return;
01476                         }
01477                 }
01478                 break;
01479 
01480         case DNS_R_YXDOMAIN:
01481                 /* we can reuse the zone information */
01482                 ddns_cb->state = DDNS_STATE_ADD_FW_YXDHCID;
01483                 ddns_cb->cur_func = ddns_fwd_srv_add2;
01484                         
01485                 result = ddns_modify_fwd(ddns_cb, MDL);
01486                 if (result == ISC_R_SUCCESS) {
01487                         return;
01488                 }
01489                 break;
01490 
01491         default:
01492                 log_error ("Unable to add forward map from %.*s to %s: %s",
01493                            (int)ddns_cb->fwd_name.len,
01494                            (const char *)ddns_cb->fwd_name.data,
01495                            ddns_address,
01496                            isc_result_totext (eresult));
01497                 break;
01498         }
01499 
01500         ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
01501         ddns_cb_free(ddns_cb, MDL);
01502         /*
01503          * A single DDNS operation may require several calls depending on
01504          * the current state as the prerequisites for the first message
01505          * may not succeed requiring a second operation and potentially
01506          * a ptr operation after that.  The commit_leases operation is
01507          * invoked at the end of this set of operations in order to require
01508          * a single write for all of the changes.  We call commit_leases
01509          * here rather than immediately after the call to update the lease
01510          * text in order to save any previously written data.
01511          */
01512         commit_leases();
01513         return;
01514 }
01515 
01516 static void
01517 ddns_fwd_srv_connector(struct lease          *lease,
01518                        struct iasubopt       *lease6,
01519                        struct binding_scope **inscope,
01520                        dhcp_ddns_cb_t        *ddns_cb,
01521                        isc_result_t           eresult)
01522 {
01523         isc_result_t result = ISC_R_FAILURE;
01524 
01525         if (ddns_cb == NULL) {
01526                 /* nothing to do */
01527                 return;
01528         }
01529 
01530         if (eresult == ISC_R_SUCCESS) {
01531                 /*
01532                  * If we have updates dispatch as appropriate,
01533                  * if not do FQDN binding if desired.
01534                  */
01535 
01536                 if (ddns_cb->flags & DDNS_UPDATE_ADDR) {
01537                         ddns_cb->state    = DDNS_STATE_ADD_FW_NXDOMAIN;
01538                         ddns_cb->cur_func = ddns_fwd_srv_add1;
01539                         result = ddns_modify_fwd(ddns_cb, MDL);
01540                 } else if ((ddns_cb->flags & DDNS_UPDATE_PTR) &&
01541                          (ddns_cb->rev_name.len != 0)) {
01542                         ddns_cb->state    = DDNS_STATE_ADD_PTR;
01543                         ddns_cb->cur_func = ddns_ptr_add;
01544                         result = ddns_modify_ptr(ddns_cb, MDL);
01545                 } else {
01546                         ddns_update_lease_text(ddns_cb, inscope);
01547                 }
01548         }
01549 
01550         if (result == ISC_R_SUCCESS) {
01551                 ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb, MDL);
01552         } else {
01553                 ddns_cb_free(ddns_cb, MDL);
01554         }
01555 
01556         return;
01557 }
01558 
01559 /*
01560  * If the first query fails, the updater MUST NOT delete the DNS name.  It
01561  * may be that the host whose lease on the server has expired has moved
01562  * to another network and obtained a lease from a different server,
01563  * which has caused the client's A RR to be replaced. It may also be
01564  * that some other client has been configured with a name that matches
01565  * the name of the DHCP client, and the policy was that the last client
01566  * to specify the name would get the name.  In this case, the DHCID RR
01567  * will no longer match the updater's notion of the client-identity of
01568  * the host pointed to by the DNS name.
01569  *   -- "Interaction between DHCP and DNS"
01570  */
01571 
01572 void
01573 ddns_fwd_srv_rem2(dhcp_ddns_cb_t *ddns_cb,
01574                   isc_result_t    eresult)
01575 {
01576         if (eresult == ISC_R_SUCCESS) {
01577                 ddns_update_lease_text(ddns_cb, NULL);
01578 
01579                 /* Do the next operation */
01580                 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
01581                         /* if we have zone information get rid of it */
01582                         if (ddns_cb->zone != NULL) {
01583                                 ddns_cb_forget_zone(ddns_cb);
01584                         }
01585 
01586                         ddns_cb->state = DDNS_STATE_REM_PTR;
01587                         ddns_cb->cur_func = ddns_ptr_remove;
01588                         
01589                         eresult = ddns_modify_ptr(ddns_cb, MDL);
01590                         if (eresult == ISC_R_SUCCESS) {
01591                                 return;
01592                         }
01593                 }
01594         }
01595 
01596         ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
01597         ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult);
01598         ddns_cb_free(ddns_cb, MDL);
01599         return;
01600 }
01601 
01602 
01603 /*
01604  * First action routine when trying to remove a fwd
01605  * this will be called after the ddns queries have completed
01606  * if we succeeded in removing the fwd we go to the next step (if any)
01607  * if not we cleanup and leave.
01608  */
01609 
01610 void
01611 ddns_fwd_srv_rem1(dhcp_ddns_cb_t *ddns_cb,
01612                   isc_result_t    eresult)
01613 {
01614         isc_result_t result = eresult;
01615         char ddns_address[MAX_ADDRESS_STRING_LEN];
01616 
01617         switch(eresult) {
01618         case ISC_R_SUCCESS:
01619                 /* Construct a printable form of the address for logging */
01620                 strcpy(ddns_address, piaddr(ddns_cb->address));
01621                 log_info("Removed forward map from %.*s to %s",
01622                          (int)ddns_cb->fwd_name.len, 
01623                          (const char*)ddns_cb->fwd_name.data,
01624                          ddns_address);
01625 
01626                 /* Do the second step of the FWD removal */
01627                 ddns_cb->state    = DDNS_STATE_REM_FW_NXRR;
01628                 ddns_cb->cur_func = ddns_fwd_srv_rem2;
01629                 result = ddns_modify_fwd(ddns_cb, MDL);
01630                 if (result == ISC_R_SUCCESS) {
01631                         return;
01632                 }
01633                 break;
01634 
01635         case DNS_R_NXRRSET:
01636         case DNS_R_NXDOMAIN:
01637                 ddns_update_lease_text(ddns_cb, NULL);
01638 
01639 #if defined (DEBUG_DNS_UPDATES)
01640                 log_info("DDNS: no forward map to remove. %p", ddns_cb);
01641 #endif
01642 
01643                 /* Do the next operation */
01644                 if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
01645                         /* if we have zone information get rid of it */
01646                         if (ddns_cb->zone != NULL) {
01647                                 ddns_cb_forget_zone(ddns_cb);
01648                         }
01649 
01650                         ddns_cb->state    = DDNS_STATE_REM_PTR;
01651                         ddns_cb->cur_func = ddns_ptr_remove;
01652                         
01653                         result = ddns_modify_ptr(ddns_cb, MDL);
01654                         if (result == ISC_R_SUCCESS) {
01655                                 return;
01656                         }
01657                 }
01658                 else {
01659                         /* Trigger the add operation */
01660                         eresult = ISC_R_SUCCESS;
01661                 }
01662                 break;
01663                         
01664         default:
01665                 break;
01666         }
01667 
01668         ddns_update_lease_ptr(NULL, NULL, ddns_cb, NULL, MDL);
01669         ddns_fwd_srv_connector(NULL, NULL, NULL, ddns_cb->next_op, eresult);
01670         ddns_cb_free(ddns_cb, MDL);
01671 }
01672 
01673 /*%<
01674  * Remove relevant entries from DNS.
01675  *
01676  * \li lease  - lease to start with if this is for v4
01677  * 
01678  * \li lease6 - lease to start with if this is for v6
01679  * 
01680  * \li add_ddns_cb - control block for additional DDNS work.  This
01681  *     is used when the code is going to add a DDNS entry after removing
01682  *     the current entry.
01683  * 
01684  * \li active - indication about the status of the lease. It is
01685  *     ISC_TRUE if the lease is still active, and FALSE if the lease
01686  *     is inactive.  This is used to indicate if the lease is inactive or going
01687  *     to inactive so we can avoid trying to update the lease with cb pointers
01688  *     and text information if it isn't useful.
01689  * 
01690  * Returns
01691  * \li #ISC_R_FAILURE - badness occurred and we weren't able to do what was wanted
01692  * \li #ISC_R_SUCCESS - we were able to do stuff but it's in progress
01693  *
01694  * in both cases any additional block has been passed on to it's handler
01695  */
01696 
01697 isc_result_t
01698 ddns_removals(struct lease    *lease,
01699               struct iasubopt *lease6,
01700               dhcp_ddns_cb_t  *add_ddns_cb,
01701               isc_boolean_t    active)
01702 {
01703         isc_result_t rcode, execute_add = ISC_R_FAILURE;
01704         struct binding_scope **scope = NULL;
01705         isc_result_t result = ISC_R_FAILURE;
01706         dhcp_ddns_cb_t        *ddns_cb = NULL;
01707         struct data_string     leaseid;
01708 
01709         /*
01710          * See if we need to cancel an outstanding request.  Mostly this is
01711          * used to handle the case where this routine is called twice for
01712          * the same release or abandon event.
01713          * 
01714          * When called from the dns code as part of an update request
01715          * (add_ddns_cb != NULL) any outstanding requests will have already
01716          * been cancelled.
01717          * 
01718          * If the new request is just a removal and we have an outstanding
01719          * request we have several options:
01720          *
01721          * - we are doing an update or we are doing a removal and the active
01722          * flag has changed from TRUE to FALSE.  In these cases we  need to
01723          * cancel the old request and start the new one.
01724          *
01725          * - other wise we are doing a removal with the active flag unchanged.
01726          * In this case we can let the current removal continue and do not need
01727          * to start a new one.  If the old request included an update to be
01728          * done after the removal we need to kill the update part of the
01729          * request.
01730          */
01731         
01732         if (add_ddns_cb == NULL) {
01733                 if ((lease != NULL) && (lease->ddns_cb != NULL)) {
01734                         ddns_cb = lease->ddns_cb;
01735 
01736                         /*
01737                          * Is the old request an update or did the 
01738                          * the active flag change?
01739                          */
01740                         if (((ddns_cb->state == DDNS_STATE_ADD_PTR) ||
01741                              (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) ||
01742                              (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) ||
01743                             ((active == ISC_FALSE) &&
01744                              ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) {
01745                                 /* Cancel the current request */
01746                                 ddns_cancel(lease->ddns_cb, MDL);
01747                                 lease->ddns_cb = NULL;
01748                         } else {
01749                                 /* Remvoval, check and remove updates */
01750                                 if (ddns_cb->next_op != NULL) {
01751                                         ddns_cb_free(ddns_cb->next_op, MDL);
01752                                         ddns_cb->next_op = NULL;
01753                                 }
01754 #if defined (DEBUG_DNS_UPDATES)
01755                                 log_info("DDNS %s(%d): removal already in "
01756                                          "progress new ddns_cb=%p",
01757                                          MDL, ddns_cb);
01758 #endif
01759                                 return (ISC_R_SUCCESS);
01760                         }
01761                 } else if ((lease6 != NULL) && (lease6->ddns_cb != NULL)) {
01762                         ddns_cb = lease6->ddns_cb;
01763 
01764                         /*
01765                          * Is the old request an update or did the 
01766                          * the active flag change?
01767                          */
01768                         if (((ddns_cb->state == DDNS_STATE_ADD_PTR) ||
01769                              (ddns_cb->state == DDNS_STATE_ADD_FW_NXDOMAIN) ||
01770                              (ddns_cb->state == DDNS_STATE_ADD_FW_YXDHCID)) ||
01771                             ((active == ISC_FALSE) &&
01772                              ((ddns_cb->flags & DDNS_ACTIVE_LEASE) != 0))) {
01773                                 /* Cancel the current request */
01774                                 ddns_cancel(lease6->ddns_cb, MDL);
01775                                 lease6->ddns_cb = NULL;
01776                         } else {
01777                                 /* Remvoval, check and remove updates */
01778                                 if (ddns_cb->next_op != NULL) {
01779                                         ddns_cb_free(ddns_cb->next_op, MDL);
01780                                         ddns_cb->next_op = NULL;
01781                                 }
01782 #if defined (DEBUG_DNS_UPDATES)
01783                                 log_info("DDNS %s(%d): removal already in "
01784                                          "progress new ddns_cb=%p",
01785                                          MDL, ddns_cb);
01786 #endif
01787                                 return (ISC_R_SUCCESS);
01788                         }
01789                 }
01790                 ddns_cb = NULL;
01791         }
01792 
01793         /* allocate our control block */
01794         ddns_cb = ddns_cb_alloc(MDL);
01795         if (ddns_cb == NULL) {
01796                 goto cleanup;
01797         }
01798 
01799         /*
01800          * For v4 we flag static leases so we don't try
01801          * and manipulate the lease later.  For v6 we don't
01802          * get static leases and don't need to flag them.
01803          */
01804         if (lease != NULL) {
01805                 scope = &(lease->scope);
01806                 ddns_cb->address = lease->ip_addr;
01807                 if (lease->flags & STATIC_LEASE)
01808                         ddns_cb->flags |= DDNS_STATIC_LEASE;
01809         } else if (lease6 != NULL) {
01810                 scope = &(lease6->scope);
01811                 memcpy(&ddns_cb->address.iabuf, lease6->addr.s6_addr, 16);
01812                 ddns_cb->address.len = 16;
01813         } else
01814                 goto cleanup;
01815 
01816         /*
01817          * Set the flag bit if the lease is active, that is it isn't
01818          * expired or released.  This is used to determine if we need
01819          * to update the scope information for both v4 and v6 and
01820          * the lease information for v6 when the response
01821          * from the DNS code is processed.
01822          */
01823         if (active == ISC_TRUE) {
01824                 ddns_cb->flags |= DDNS_ACTIVE_LEASE;
01825         }
01826 
01827         /* No scope implies that DDNS has not been performed for this lease. */
01828         if (*scope == NULL)
01829                 goto cleanup;
01830 
01831         if ((ddns_update_style != DDNS_UPDATE_STYLE_STANDARD) &&
01832             (ddns_update_style != DDNS_UPDATE_STYLE_INTERIM))
01833                 goto cleanup;
01834 
01835         /* Assume that we are removing both records */
01836         ddns_cb->flags |= DDNS_UPDATE_ADDR | DDNS_UPDATE_PTR;
01837 
01838         /* and that we want to do the add call */
01839         execute_add = ISC_R_SUCCESS;
01840 
01841         /*
01842          * Look up stored names.
01843          */
01844 
01845         /*
01846          * Find the fwd name and copy it to the control block.  If we don't
01847          * have it we can't delete the fwd record but we can still try to
01848          * remove the ptr record and cleanup the lease information if the
01849          * client did the fwd update.
01850          */
01851         if (!find_bound_string(&ddns_cb->fwd_name, *scope, "ddns-fwd-name")) {
01852                 /* don't try and delete the A, or do the add */
01853                 ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
01854                 execute_add = ISC_R_FAILURE;
01855 
01856                 /* Check if client did update */
01857                 if (find_bound_string(&ddns_cb->fwd_name, *scope,
01858                                       "ddns-client-fqdn")) {
01859                         ddns_cb->flags |= DDNS_CLIENT_DID_UPDATE;
01860                 }
01861         }
01862 
01863         /*
01864          * Find the txt or dhcid tag and copy it to the control block.  If we don't
01865          * have one this isn't an interim or standard record so we can't delete
01866          * the A record using this mechanism but we can delete the ptr record.
01867          * In this case we will attempt to do any requested next step.
01868          */
01869         memset(&leaseid, 0, sizeof(leaseid));
01870         if (find_bound_string (&leaseid, *scope, ddns_standard_tag)) {
01871                 /* We have a standard tag */
01872                 ddns_cb->lease_tag = ddns_standard_tag;
01873                 ddns_cb->dhcid_class = dns_rdatatype_dhcid;
01874                 data_string_copy(&ddns_cb->dhcid, &leaseid, MDL);
01875                 data_string_forget(&leaseid, MDL);
01876         } else  if (find_bound_string (&leaseid, *scope, ddns_interim_tag)) {
01877                 /* we have an interim tag */
01878                 ddns_cb->lease_tag = ddns_interim_tag;
01879                 ddns_cb->dhcid_class = dns_rdatatype_txt;
01880                 if (dhcid_fromlease(&ddns_cb->dhcid, &leaseid) != 
01881                     ISC_R_SUCCESS) {
01882                         /* We couldn't convert the dhcid from the lease
01883                          * version to the dns version.  We can't delete
01884                          * the A record but can continue to the ptr
01885                          */
01886                         ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
01887                 }
01888                 data_string_forget(&leaseid, MDL);
01889         } else {
01890                 ddns_cb->flags &= ~DDNS_UPDATE_ADDR;
01891         }               
01892 
01893         /*
01894          * Find the rev name and copy it to the control block.  If we don't
01895          * have it we can't get rid of it but we can try to remove the fwd
01896          * pointer if desired.
01897          */
01898         if (!find_bound_string(&ddns_cb->rev_name, *scope, "ddns-rev-name")) {
01899                 ddns_cb->flags &= ~DDNS_UPDATE_PTR;
01900         }
01901         
01902         /*
01903          * If we have a second control block for doing an add
01904          * after the remove finished attach it to our control block.
01905          */
01906         ddns_cb->next_op = add_ddns_cb;
01907 
01908         /*
01909          * Now that we've collected the information we can try to process it.
01910          * If necessary we call an appropriate routine to send a message and
01911          * provide it with an action routine to run on the control block given
01912          * the results of the message.  We have three entry points from here,
01913          * one for removing the A record, the next for removing the PTR and
01914          * the third for doing any requested add.
01915          */
01916         if ((ddns_cb->flags & DDNS_UPDATE_ADDR) != 0) {
01917                 if (ddns_cb->fwd_name.len != 0) {
01918                         ddns_cb->state    = DDNS_STATE_REM_FW_YXDHCID;
01919                         ddns_cb->cur_func = ddns_fwd_srv_rem1;
01920 
01921                         rcode = ddns_modify_fwd(ddns_cb, MDL);
01922                         if (rcode == ISC_R_SUCCESS) {
01923                                 ddns_update_lease_ptr(lease, lease6, ddns_cb,
01924                                                       ddns_cb, MDL);
01925                                 return (ISC_R_SUCCESS);
01926                         }
01927 
01928                         /*
01929                          * We weren't able to process the request tag the
01930                          * add so we won't execute it.
01931                          */
01932                         execute_add = ISC_R_FAILURE;
01933                         goto cleanup;
01934                 }
01935                 else {
01936                         /*remove info from scope */
01937                         unset(*scope, "ddns-fwd-name");
01938                         unset(*scope, ddns_cb->lease_tag);
01939                 }
01940         }
01941 
01942         if ((ddns_cb->flags & DDNS_UPDATE_PTR) != 0) {
01943                 ddns_cb->state      = DDNS_STATE_REM_PTR;
01944                 ddns_cb->cur_func   = ddns_ptr_remove;
01945 
01946                 /*
01947                  * if execute add isn't success remove the control block so
01948                  * it won't be processed when the remove completes.  We
01949                  * also arrange to clean it up and get rid of it.
01950                  */
01951                 if (execute_add != ISC_R_SUCCESS) {
01952                         ddns_cb->next_op = NULL;
01953                         ddns_fwd_srv_connector(lease, lease6, scope, 
01954                                                add_ddns_cb, execute_add);
01955                         add_ddns_cb = NULL;
01956                 }
01957                 else {
01958                         result = ISC_R_SUCCESS;
01959                 }
01960 
01961                 rcode = ddns_modify_ptr(ddns_cb, MDL);
01962                 if (rcode == ISC_R_SUCCESS) {
01963                         ddns_update_lease_ptr(lease, lease6, ddns_cb, ddns_cb,
01964                                               MDL);
01965                         return (result);
01966                 }
01967 
01968                 /* We weren't able to process the request tag the
01969                  * add so we won't execute it */
01970                 execute_add = ISC_R_FAILURE;
01971                 goto cleanup;
01972         }
01973 
01974  cleanup:
01975         /*
01976          * We've gotten here because we didn't need to send a message or
01977          * we failed when trying to do so.  We send the additional cb
01978          * off to handle sending and/or cleanup and cleanup anything
01979          * we allocated here.
01980          */
01981         ddns_fwd_srv_connector(lease, lease6, scope, add_ddns_cb, execute_add);
01982         if (ddns_cb != NULL) 
01983                 ddns_cb_free(ddns_cb, MDL);
01984 
01985         return (result);
01986 }
01987 
01988 #endif /* NSUPDATE */

Generated on 5 Apr 2014 for ISC DHCP by  doxygen 1.6.1