]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
DDNS implementation rewrite. DDNS should now operate according to
authorDamien Neil <source@isc.org>
Mon, 11 Dec 2000 18:56:45 +0000 (18:56 +0000)
committerDamien Neil <source@isc.org>
Mon, 11 Dec 2000 18:56:45 +0000 (18:56 +0000)
<draft-ietf-dhc-dhcp-dns-12.txt>.

common/options.c, common/tables.c, includes/dhcp.h:
  Split the fqdn.name option into fqdn.hostname and fqdn.domainname.

includes/dhcpd.h, server/Makefile.dist, server/ddns.c, server/dhcp.c,
server/mdb.c, server/stables.c:
  Added a new file (server/ddns.c) containing the DDNS updates code.
  This file exports two functions: ddns_updates() and ddns_removals().
  ddns_updates() is called when a lease is granted, and ddns_removals()
  is called when the lease expires or is released.

server/dhcpd.c:
  Remove the previous DDNS update code, and add default code for the
  ddns-hostname, ddns-domainname, ddns-ttl, and ddns-rev-domainname
  server options.

common/options.c
common/tables.c
includes/dhcp.h
includes/dhcpd.h
server/Makefile.dist
server/ddns.c [new file with mode: 0644]
server/dhcp.c
server/dhcpd.c
server/mdb.c
server/stables.c

index d21e17d9e0a9ec24dc92ba01b2d24a4a5271e8de..bdf9781c028f43f4a670673ebc931e5f7991174b 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: options.c,v 1.71 2000/11/29 13:38:36 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: options.c,v 1.72 2000/12/11 18:56:31 neild Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #define DHCP_OPTION_DATA
@@ -182,6 +182,11 @@ int parse_option_buffer (options, buffer, length, universe)
        return 1;
 }
 
+/* If an option in an option buffer turns out to be an encapsulation,
+   figure out what to do.   If we don't know how to de-encapsulate it,
+   or it's not well-formed, return zero; otherwise, return 1, indicating
+   that we succeeded in de-encapsulating it. */
+
 struct universe *find_option_universe (struct option *eopt, const char *uname)
 {
        int i;
@@ -321,36 +326,72 @@ int fqdn_universe_decode (struct option_state *options,
 
        /* Not encoded using DNS format? */
        if (!bp -> data [0]) {
+               unsigned i;
+
+               /* Determine the length of the hostname component of the
+                  name.  If the name contains no '.' character, it
+                  represents a non-qualified label. */
+               for (i = 3; i < length && buffer [i] != '.'; i++);
+               i -= 3;
+
+               /* Note: If the client sends a FQDN, the first '.' will
+                  be used as a NUL terminator for the hostname. */
                if (!save_option_buffer (&fqdn_universe, options, bp,
-                                        &bp -> data [5], length - 3,
-                                        &fqdn_options [FQDN_NAME], 1))
+                                        &bp -> data[5], i,
+                                        &fqdn_options [FQDN_HOSTNAME], 1))
+                       goto bad;
+               /* Note: If the client sends a single label, the
+                  hostname's terminal NUL will be reused for the
+                  (0-length) domainname. */
+               if (!save_option_buffer (&fqdn_universe, options, bp,
+                                        &bp -> data[5 + i], length - 3 - i,
+                                        &fqdn_options [FQDN_DOMAINNAME], 1))
                        goto bad;
        } else {
-               int len;
-               unsigned char *s, *t, *u;
+               unsigned len;
+               unsigned total_len = 0;
+               unsigned first_len = 0;
+               int terminated = 0;
+               unsigned char *s;
+
+               s = &bp -> data[5];
 
-               u = t = s = &bp -> data [5];
                do {
-                       len = *s++;
+                       len = *s;
                        if (len > 63) {
                                log_info ("fancy bits in fqdn option");
                                return 0;
                        }       
                        if (len == 0) {
-                               *t++ = '.';
+                               terminated = 1;
                                break;
                        }
                        if (s + len > &bp -> data [0] + length + 3) {
                                log_info ("fqdn tag longer than buffer");
                                return 0;
                        }
-                       while (len--)
-                               *t++ = *s++;
-                       *t++ = '.';
-               } while (s + len < &bp -> data [0] + length + 3);
+
+                       if (first_len == 0) {
+                               first_len = len;
+                       }
+
+                       *s = '.';
+                       s += len + 1;
+                       total_len += len;
+               } while (s < &bp -> data[0] + length + 3);
+
+               if (!terminated) {
+                       first_len = total_len;
+               }
+
+               if (!save_option_buffer (&fqdn_universe, options, bp,
+                                        &bp -> data[6], first_len,
+                                        &fqdn_options [FQDN_HOSTNAME], 1))
+                       goto bad;
                if (!save_option_buffer (&fqdn_universe, options, bp,
-                                        &bp -> data [5], (unsigned)(t - u),
-                                        &fqdn_options [FQDN_NAME], 1))
+                                        &bp -> data[6 + first_len],
+                                        total_len - first_len,
+                                        &fqdn_options [FQDN_DOMAINNAME], 1))
                        goto bad;
        }
        return 1;
@@ -1662,7 +1703,7 @@ int fqdn_option_space_encapsulate (result, packet, lease, client_state,
                                       packet, lease, client_state, in_options,
                                       cfg_options, scope,  oc, MDL);
        }
-       len = 4 + results [FQDN_NAME].len;
+       len = 6 + results [FQDN_HOSTNAME].len + results [FQDN_DOMAINNAME].len;
        /* Save the contents of the option in a buffer. */
        if (!buffer_allocate (&bp, len, MDL)) {
                log_error ("no memory for option buffer.");
@@ -1684,39 +1725,59 @@ int fqdn_option_space_encapsulate (result, packet, lease, client_state,
        if (results [FQDN_RCODE2].len)
                bp -> data [2] = results [FQDN_RCODE2].data [0];
 
-       if (results [FQDN_ENCODED].len &&
-           results [FQDN_ENCODED].data [0]) {
+       if (results [FQDN_HOSTNAME].len == 0) {
+               /* Can't send just a domainname. */
+               bp -> data[3] = 0;
+               result -> len = 3;
+       } else if (results [FQDN_ENCODED].len &&
+                  results [FQDN_ENCODED].data [0]) {
                unsigned char *out;
                int i;
                bp -> data [0] |= 4;
                out = &bp -> data [3];
-               if (results [FQDN_NAME].len) {
-                       i = 0;
-                       while (i < results [FQDN_NAME].len) {
-                               int j;
-                               for (j = i; ('.' !=
-                                            results [FQDN_NAME].data [j]) &&
-                                            j < results [FQDN_NAME].len; j++)
-                                       ;
-                               *out++ = j - i;
-                               memcpy (out, &results [FQDN_NAME].data [i],
-                                       (unsigned)(j - i));
-                               out += j - i;
-                               i = j;
-                               if (results [FQDN_NAME].data [j] == '.')
-                                       i++;
-                       }
-                       if ((results [FQDN_NAME].data
-                            [results [FQDN_NAME].len - 1] == '.'))
-                               *out++ = 0;
-                       result -> len = out - result -> data;
-                       result -> terminated = 0;
+
+               memcpy (out + 1,
+                       results [FQDN_HOSTNAME].data,
+                       results [FQDN_HOSTNAME].len);
+
+               len = results [FQDN_HOSTNAME].len + 1;
+
+               if (results [FQDN_DOMAINNAME].len) {
+                       out [len] = '.';
+                       memcpy (out + len + 1,
+                               results [FQDN_DOMAINNAME].data,
+                               results [FQDN_DOMAINNAME].len);
+
+                       len += results [FQDN_DOMAINNAME].len + 1;
+
+                       out[len] = '.';
+                       len++;
                }
+
+               for (i = 0; i < len; ) {
+                       int j;
+                       for (j = i + 1; (('.' != out [j]) && (j < len)); j++)
+                               ;
+                       
+                       out[i] = j - i - 1;
+                       i = j;
+               }
+
+               result -> len += len;
+               result -> terminated = 0;
        } else {
-               if (results [FQDN_NAME].len) {
-                       memcpy (&bp -> data [3], results [FQDN_NAME].data,
-                               results [FQDN_NAME].len);
-                       result -> len += results [FQDN_NAME].len;
+               memcpy (&bp -> data[3],
+                       results [FQDN_HOSTNAME].data,
+                       results [FQDN_HOSTNAME].len);
+               result -> len += results [FQDN_HOSTNAME].len;
+
+               if (results [FQDN_DOMAINNAME].len) {
+                       bp -> data[result -> len] = '.';
+                       result -> len++;
+                       memcpy (&bp -> data[result -> len],
+                               results [FQDN_DOMAINNAME].data,
+                               results [FQDN_DOMAINNAME].len);
+                       result -> len += results [FQDN_DOMAINNAME].len;
                        result -> terminated = 0;
                }
        }
index f9a1235d804b833a74623aa45b2d6b016070c277..ba11e7546a4dba5ecf0c996fe30680f9b660d152 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: tables.c,v 1.46 2000/10/10 22:48:20 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: tables.c,v 1.47 2000/12/11 18:56:32 neild Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -615,8 +615,8 @@ struct option fqdn_options [256] = {
        { "encoded", "f",                               &fqdn_universe, 3 },
        { "rcode1", "B",                                &fqdn_universe, 4 },
        { "rcode2", "B",                                &fqdn_universe, 5 },
-       { "name", "t",                                  &fqdn_universe, 6 },
-       { "option-7", "X",                              &fqdn_universe, 7 },
+       { "hostname", "t",                              &fqdn_universe, 6 },
+       { "domainname", "t",                            &fqdn_universe, 7 },
        { "option-8", "X",                              &fqdn_universe, 8 },
        { "option-9", "X",                              &fqdn_universe, 9 },
        { "option-10", "X",                             &fqdn_universe, 10 },
index d4d31138c51bde5da67f2bc8c6ee24d82d4d89da..0602ae1076a4dcb7c4049707696b9502d9bd649a 100644 (file)
@@ -192,5 +192,6 @@ struct dhcp_packet {
 #define FQDN_ENCODED                   3
 #define FQDN_RCODE1                    4
 #define FQDN_RCODE2                    5
-#define FQDN_NAME                      6
-#define FQDN_SUBOPTION_COUNT           6
+#define FQDN_HOSTNAME                  6
+#define FQDN_DOMAINNAME                        7
+#define FQDN_SUBOPTION_COUNT           7
index 1302b4d8587378a3a9aa467146ab1d0adff87fe2..a6c3882c9f76a58e3275e3e6cff31c8458165e58 100644 (file)
@@ -377,6 +377,7 @@ struct lease_state {
 #define SV_LOCAL_ADDRESS               35
 #define SV_OMAPI_KEY                   36
 #define SV_STASH_AGENT_OPTIONS         37
+#define SV_DDNS_TTL                    38
 
 #if !defined (DEFAULT_DEFAULT_LEASE_TIME)
 # define DEFAULT_DEFAULT_LEASE_TIME 43200
@@ -390,6 +391,10 @@ struct lease_state {
 # define DEFAULT_MAX_LEASE_TIME 86400
 #endif
 
+#if !defined (DEFAULT_DDNS_TTL)
+# define DEFAULT_DDNS_TTL 3600
+#endif
+
 /* Client option names */
 
 #define        CL_TIMEOUT              1
@@ -1092,6 +1097,11 @@ int parse_lease_declaration PROTO ((struct lease **, struct parse *));
 void parse_address_range PROTO ((struct parse *,
                                 struct group *, int, struct pool *));
 
+/* ddns.c */
+int ddns_updates PROTO ((struct packet *, struct lease *,
+                        struct lease_state *));
+int ddns_removals PROTO ((struct lease *));
+
 /* parse.c */
 void skip_to_semi PROTO ((struct parse *));
 void skip_to_rbrace PROTO ((struct parse *, int));
index f49b83af60ce882492da043901ee03d93e0c225b..71a19a27096fa6c13afb53062380d4db5f985810 100644 (file)
@@ -20,9 +20,9 @@
 CATMANPAGES = dhcpd.cat8 dhcpd.conf.cat5 dhcpd.leases.cat5
 SEDMANPAGES = dhcpd.man8 dhcpd.conf.man5 dhcpd.leases.man5
 SRCS   = dhcpd.c dhcp.c bootp.c confpars.c db.c class.c failover.c \
-        omapi.c mdb.c stables.c salloc.c
+        omapi.c mdb.c stables.c salloc.c ddns.c
 OBJS   = dhcpd.o dhcp.o bootp.o confpars.o db.o class.o failover.o \
-        omapi.o mdb.o stables.o salloc.o
+        omapi.o mdb.o stables.o salloc.o ddns.o
 PROG   = dhcpd
 MAN    = dhcpd.8 dhcpd.conf.5 dhcpd.leases.5
 
diff --git a/server/ddns.c b/server/ddns.c
new file mode 100644 (file)
index 0000000..c509814
--- /dev/null
@@ -0,0 +1,1000 @@
+/* ddns.c
+
+   Dynamic DNS updates. */
+
+/*
+ * Copyright (c) 1995-2000 Internet Software Consortium.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Internet Software Consortium nor the names
+ *    of its contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
+ * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This software has been written for the Internet Software Consortium
+ * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
+ * To learn more about the Internet Software Consortium, see
+ * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
+ * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
+ * ``http://www.nominum.com''.
+ */
+
+#ifndef lint
+static char copyright[] =
+"$Id: ddns.c,v 1.1 2000/12/11 18:56:41 neild Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
+#endif /* not lint */
+
+#include "dhcpd.h"
+#include "../minires/md5.h"
+
+#ifdef NSUPDATE
+
+/* Have to use TXT records for now. */
+#define T_DHCID T_TXT
+
+static int get_dhcid (unsigned char *, struct lease *);
+
+static struct __res_state resolver_state;
+static int                resolver_inited = 0;
+
+
+static int get_dhcid (unsigned char *dhcid, struct lease *lease) {
+       unsigned char buf[MD5_DIGEST_LENGTH];
+       MD5_CTX md5;
+       int i;
+
+       /*
+        * DHCP clients and servers should use the following forms of client
+        * identification, starting with the most preferable, and finishing
+        * with the least preferable.  If the client does not send any of these
+        * forms of identification, the DHCP/DDNS interaction is not defined by
+        * this specification.  The most preferable form of identification is
+        * the Globally Unique Identifier Option [TBD].  Next is the DHCP
+        * Client Identifier option.  Last is the client's link-layer address,
+        * as conveyed in its DHCPREQUEST message.  Implementors should note
+        * that the link-layer address cannot be used if there are no
+        * significant bytes in the chaddr field of the DHCP client's request,
+        * because this does not constitute a unique identifier.
+        *   -- "Interaction between DHCP and DNS"
+        *      <draft-ietf-dhc-dhcp-dns-12.txt>
+        *      M. Stapp, Y. Rekhter
+        */
+
+       MD5_Init (&md5);
+
+       if (lease -> uid) {
+               /* Use the DHCP Client Identifier option. */
+               MD5_Update (&md5, lease -> uid, lease -> uid_len);
+       } else if (lease -> hardware_addr . hlen) {
+               /* Use the link-layer address. */
+               MD5_Update (&md5,
+                           lease -> hardware_addr.hbuf,
+                           lease -> hardware_addr.hlen);
+       } else {
+               /* Uh-oh.  Something isn't right here. */
+               return 1;
+       }
+
+       MD5_Final (buf, &md5);
+
+       /* Convert into ASCII. */
+       for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
+               dhcid [i*2]   = "0123456789abcdef"[(buf[i]>>4)&0xf];
+               dhcid [i*2+1] = "0123456789abcdef"[ buf[i]    &0xf];
+       }
+        dhcid [MD5_DIGEST_LENGTH*2] = '\0';
+
+       return 0;
+}
+
+
+/* NB: No way of checking that there is enough space in a data_string's
+   buffer.  Be certain to allocate enough! */
+static void data_string_append (struct data_string *ds1,
+                               struct data_string *ds2)
+{
+       memcpy (ds1 -> buffer -> data + ds1 -> len,
+               ds2 -> data,
+               ds2 -> len);
+       ds1 -> len += ds2 -> len;
+}
+
+
+static struct binding *create_binding (struct binding_scope **scope,
+                                      const char *name)
+{
+       struct binding *binding;
+
+       if (!*scope) {
+               if (!binding_scope_allocate (scope, MDL))
+                       return (struct binding *)0;
+       }
+
+       binding = find_binding (*scope, name);
+       if (!binding) {
+               binding = dmalloc (sizeof *binding, MDL);
+               if (!binding)
+                       return (struct binding *)0;
+
+               memset (binding, 0, sizeof *binding);
+               binding -> name = dmalloc (strlen (name) + 1, MDL);
+               if (!binding -> name) {
+                       dfree (binding, MDL);
+                       return (struct binding *)0;
+               }
+               strcpy (binding -> name, name);
+
+               binding -> next = (*scope) -> bindings;
+               (*scope) -> bindings = binding;
+       }
+
+       return binding;
+}
+
+
+static int bind_ds_value (struct binding_scope **scope,
+                         const char *name,
+                         struct data_string *value)
+{
+       struct binding *binding;
+
+       binding = create_binding (scope, name);
+       if (!binding)
+               return 0;
+
+       if (binding -> value)
+               binding_value_dereference (&binding -> value, MDL);
+
+       if (!binding_value_allocate (&binding -> value, MDL))
+               return 0;
+
+       data_string_copy (&binding -> value -> value.data, value, MDL);
+       binding -> value -> type = binding_data;
+
+       return 1;
+}
+
+
+static int find_bound_string (struct data_string *value,
+                             struct binding_scope *scope,
+                             const char *name)
+{
+       struct binding *binding;
+
+       binding = find_binding (scope, name);
+       if (!binding ||
+           !binding -> value ||
+           binding -> value -> type != binding_data)
+               return 0;
+
+       if (binding -> value -> value.data.terminated) {
+               data_string_copy (value, &binding -> value -> value.data, MDL);
+       } else {
+               buffer_allocate (&value -> buffer,
+                                binding -> value -> value.data.len,
+                                MDL);
+               if (!value -> buffer)
+                       return 0;
+
+               memcpy (value -> buffer -> data,
+                       binding -> value -> value.data.data,
+                       binding -> value -> value.data.len);
+               value -> data = value -> buffer -> data;
+               value -> len  = binding -> value -> value.data.len;
+
+               data_string_forget (&binding -> value -> value.data, MDL);
+               data_string_copy (&binding -> value -> value.data, value, MDL);
+       }
+
+       return 1;
+}
+
+
+static ns_rcode ddns_update_a (struct data_string *ddns_fwd_name,
+                              struct data_string *ddns_address,
+                              struct data_string *ddns_dhcid,
+                              unsigned long ttl)
+{
+       ns_updque updque;
+       ns_updrec *updrec;
+       ns_rcode result;
+
+       /*
+        * When a DHCP client or server intends to update an A RR, it first
+        * prepares a DNS UPDATE query which includes as a prerequisite the
+        * assertion that the name does not exist.  The update section of the
+        * query attempts to add the new name and its IP address mapping (an A
+        * RR), and the DHCID RR with its unique client-identity.
+        *   -- "Interaction between DHCP and DNS"
+        */
+
+       ISC_LIST_INIT (updque);
+
+       /*
+        * A RR does not exist.
+        */
+       updrec = minires_mkupdrec (S_PREREQ, ddns_fwd_name -> data,
+                                  C_IN, T_A, 0);
+       if (!updrec) goto error;
+
+       updrec -> r_data   = (unsigned char *)0;
+       updrec -> r_size   = 0;
+       updrec -> r_opcode = NXDOMAIN;
+
+       ISC_LIST_APPEND (updque, updrec, r_link);
+
+
+       /*
+        * Add A RR.
+        */
+       updrec = minires_mkupdrec (S_UPDATE, ddns_fwd_name -> data,
+                                  C_IN, T_A, ttl);
+       if (!updrec) goto error;
+
+       updrec -> r_data = ddns_address -> buffer -> data;
+       updrec -> r_size = ddns_address -> len;
+       updrec -> r_opcode = ADD;
+
+       ISC_LIST_APPEND (updque, updrec, r_link);
+
+
+       /*
+        * Add DHCID RR.
+        */
+       updrec = minires_mkupdrec (S_UPDATE, ddns_fwd_name -> data,
+                                  C_IN, T_DHCID, ttl);
+       if (!updrec) goto error;
+
+       updrec -> r_data = ddns_dhcid -> buffer -> data;
+       updrec -> r_size = ddns_dhcid -> len;
+       updrec -> r_opcode = ADD;
+
+       ISC_LIST_APPEND (updque, updrec, r_link);
+
+
+       /*
+        * Attempt to perform the update.
+        */
+       result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updque));
+
+       while (!ISC_LIST_EMPTY (updque)) {
+               updrec = ISC_LIST_HEAD (updque);
+               ISC_LIST_UNLINK (updque, updrec, r_link);
+               minires_freeupdrec (updrec);
+       }
+
+
+       /*
+        * If this update operation succeeds, the updater can conclude that it
+        * has added a new name whose only RRs are the A and DHCID RR records.
+        * The A RR update is now complete (and a client updater is finished,
+        * while a server might proceed to perform a PTR RR update).
+        *   -- "Interaction between DHCP and DNS"
+        */
+
+       if (result == NOERROR)
+               return result;
+
+
+       /*
+        * If the first update operation fails with YXDOMAIN, the updater can
+        * conclude that the intended name is in use.  The updater then
+        * attempts to confirm that the DNS name is not being used by some
+        * other host. The updater prepares a second UPDATE query in which the
+        * prerequisite is that the desired name has attached to it a DHCID RR
+        * whose contents match the client identity.  The update section of
+        * this query deletes the existing A records on the name, and adds the
+        * A record that matches the DHCP binding and the DHCID RR with the
+        * client identity.
+        *   -- "Interaction between DHCP and DNS"
+        */
+
+       if (result != YXDOMAIN)
+               return result;
+
+
+       /*
+        * DHCID RR exists, and matches client identity.
+        */
+       updrec = minires_mkupdrec (S_PREREQ, ddns_fwd_name -> data,
+                                  C_IN, T_DHCID, 0);
+       if (!updrec) goto error;
+
+       updrec -> r_data = ddns_dhcid -> buffer -> data;
+       updrec -> r_size = ddns_dhcid -> len;
+       updrec -> r_opcode = YXRRSET;
+
+       ISC_LIST_APPEND (updque, updrec, r_link);
+
+
+       /*
+        * Delete A RRset.
+        */
+       updrec = minires_mkupdrec (S_UPDATE, ddns_fwd_name -> data,
+                                  C_IN, T_A, 0);
+       if (!updrec) goto error;
+
+       updrec -> r_data = (unsigned char *)0;
+       updrec -> r_size = 0;
+       updrec -> r_opcode = DELETE;
+
+       ISC_LIST_APPEND (updque, updrec, r_link);
+
+
+       /*
+        * Add A RR.
+        */
+       updrec = minires_mkupdrec (S_UPDATE, ddns_fwd_name -> data,
+                                  C_IN, T_A, ttl);
+       if (!updrec) goto error;
+
+       updrec -> r_data = ddns_address -> buffer -> data;
+       updrec -> r_size = ddns_address -> len;
+       updrec -> r_opcode = ADD;
+
+       ISC_LIST_APPEND (updque, updrec, r_link);
+
+
+       /*
+        * Attempt to perform the update.
+        */
+       result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updque));
+
+       while (!ISC_LIST_EMPTY (updque)) {
+               updrec = ISC_LIST_HEAD (updque);
+               ISC_LIST_UNLINK (updque, updrec, r_link);
+               minires_freeupdrec (updrec);
+       }
+
+
+       /*
+        * If this query succeeds, the updater can conclude that the current
+        * client was the last client associated with the domain name, and that
+        * the name now contains the updated A RR. The A RR update is now
+        * complete (and a client updater is finished, while a server would
+        * then proceed to perform a PTR RR update).
+        *   -- "Interaction between DHCP and DNS"
+        */
+
+       if (result == NOERROR)
+               return result;
+
+
+       /*
+        * If the second query fails with NXRRSET, the updater must conclude
+        * that the client's desired name is in use by another host.  At this
+        * juncture, the updater can decide (based on some administrative
+        * configuration outside of the scope of this document) whether to let
+        * the existing owner of the name keep that name, and to (possibly)
+        * perform some name disambiguation operation on behalf of the current
+        * client, or to replace the RRs on the name with RRs that represent
+        * the current client. If the configured policy allows replacement of
+        * existing records, the updater submits a query that deletes the
+        * existing A RR and the existing DHCID RR, adding A and DHCID RRs that
+        * represent the IP address and client-identity of the new client.
+        *   -- "Interaction between DHCP and DNS"
+        */
+
+       return result;
+
+
+  error:
+       while (!ISC_LIST_EMPTY (updque)) {
+               updrec = ISC_LIST_HEAD (updque);
+               ISC_LIST_UNLINK (updque, updrec, r_link);
+               minires_freeupdrec (updrec);
+       }
+
+       return SERVFAIL;
+}
+
+
+static ns_rcode ddns_update_ptr (struct data_string *ddns_fwd_name,
+                                struct data_string *ddns_rev_name,
+                                struct data_string *ddns_dhcid,
+                                unsigned long ttl)
+{
+       ns_updque updque;
+       ns_updrec *updrec;
+       ns_rcode result = SERVFAIL;
+
+       /*
+        * The DHCP server submits a DNS query which deletes all of the PTR RRs
+        * associated with the lease IP address, and adds a PTR RR whose data
+        * is the client's (possibly disambiguated) host name. The server also
+        * adds a DHCID RR specified in Section 4.3.
+        *   -- "Interaction between DHCP and DNS"
+        */
+
+       ISC_LIST_INIT (updque);
+
+       /*
+        * Delete all PTR RRs.
+        */
+       updrec = minires_mkupdrec (S_UPDATE, ddns_rev_name -> data,
+                                  C_IN, T_PTR, 0);
+       if (!updrec) goto error;
+
+       updrec -> r_data   = (unsigned char *)0;
+       updrec -> r_size   = 0;
+       updrec -> r_opcode = DELETE;
+
+       ISC_LIST_APPEND (updque, updrec, r_link);
+
+
+       /*
+        * Add PTR RR.
+        */
+       updrec = minires_mkupdrec (S_UPDATE, ddns_rev_name -> data,
+                                  C_IN, T_PTR, ttl);
+       if (!updrec) goto error;
+
+       updrec -> r_data   = ddns_fwd_name -> buffer -> data;
+       updrec -> r_size   = ddns_fwd_name -> len;
+       updrec -> r_opcode = ADD;
+
+       ISC_LIST_APPEND (updque, updrec, r_link);
+
+
+       /*
+        * Add DHCID RR.
+        */
+       updrec = minires_mkupdrec (S_UPDATE, ddns_rev_name -> data,
+                                  C_IN, T_DHCID,ttl);
+       if (!updrec) goto error;
+
+       updrec -> r_data = ddns_dhcid -> buffer -> data;
+       updrec -> r_size = ddns_dhcid -> len;
+       updrec -> r_opcode = ADD;
+
+       ISC_LIST_APPEND (updque, updrec, r_link);
+
+
+       /*
+        * Attempt to perform the update.
+        */
+       result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updque));
+
+
+       /* Fall through. */
+  error:
+
+       while (!ISC_LIST_EMPTY (updque)) {
+               updrec = ISC_LIST_HEAD (updque);
+               ISC_LIST_UNLINK (updque, updrec, r_link);
+               minires_freeupdrec (updrec);
+       }
+
+       return result;
+}
+
+
+static ns_rcode ddns_remove_a (struct data_string *ddns_fwd_name,
+                              struct data_string *ddns_address,
+                              struct data_string *ddns_dhcid)
+{
+       ns_updque updque;
+       ns_updrec *updrec;
+       ns_rcode result = SERVFAIL;
+
+       /*
+        * The entity chosen to handle the A record for this client (either the
+        * client or the server) SHOULD delete the A record that was added when
+        * the lease was made to the client.
+        *
+        * In order to perform this delete, the updater prepares an UPDATE
+        * query which contains two prerequisites.  The first prerequisite
+        * asserts that the DHCID RR exists whose data is the client identity
+        * described in Section 4.3. The second prerequisite asserts that the
+        * data in the A RR contains the IP address of the lease that has
+        * expired or been released.
+        *   -- "Interaction between DHCP and DNS"
+        */
+
+       ISC_LIST_INIT (updque);
+
+       /*
+        * DHCID RR exists, and matches client identity.
+        */
+       updrec = minires_mkupdrec (S_PREREQ, ddns_fwd_name -> data,
+                                  C_IN, T_DHCID,0);
+       if (!updrec) goto error;
+
+       updrec -> r_data = ddns_dhcid -> buffer -> data;
+       updrec -> r_size = ddns_dhcid -> len;
+       updrec -> r_opcode = YXRRSET;
+
+       ISC_LIST_APPEND (updque, updrec, r_link);
+
+
+       /*
+        * A RR matches the expiring lease.
+        */
+       updrec = minires_mkupdrec (S_PREREQ, ddns_fwd_name -> data,
+                                  C_IN, T_A, 0);
+       if (!updrec) goto error;
+
+       updrec -> r_data = ddns_address -> buffer -> data;
+       updrec -> r_size = ddns_address -> len;
+       updrec -> r_opcode = YXRRSET;
+
+       ISC_LIST_APPEND (updque, updrec, r_link);
+
+
+       /*
+        * Delete appropriate A RR.
+        */
+       updrec = minires_mkupdrec (S_UPDATE, ddns_fwd_name -> data,
+                                  C_IN, T_A, 0);
+       if (!updrec) goto error;
+
+       updrec -> r_data   = ddns_address -> buffer -> data;
+       updrec -> r_size   = ddns_address -> len;
+       updrec -> r_opcode = DELETE;
+
+       ISC_LIST_APPEND (updque, updrec, r_link);
+
+
+       /*
+        * Delete appropriate DHCID RR.
+        */
+       updrec = minires_mkupdrec (S_UPDATE, ddns_fwd_name -> data,
+                                  C_IN, T_DHCID, 0);
+       if (!updrec) goto error;
+
+       updrec -> r_data   = ddns_dhcid -> buffer -> data;
+       updrec -> r_size   = ddns_dhcid -> len;
+       updrec -> r_opcode = DELETE;
+
+       ISC_LIST_APPEND (updque, updrec, r_link);
+
+
+       /*
+        * Attempt to perform the update.
+        */
+       result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updque));
+
+
+       /*
+        * If the query fails, the updater MUST NOT delete the DNS name.  It
+        * may be that the host whose lease on the server has expired has moved
+        * to another network and obtained a lease from a different server,
+        * which has caused the client's A RR to be replaced. It may also be
+        * that some other client has been configured with a name that matches
+        * the name of the DHCP client, and the policy was that the last client
+        * to specify the name would get the name.  In this case, the DHCID RR
+        * will no longer match the updater's notion of the client-identity of
+        * the host pointed to by the DNS name.
+        *   -- "Interaction between DHCP and DNS"
+        */
+
+
+       /* Fall through. */
+  error:
+
+       while (!ISC_LIST_EMPTY (updque)) {
+               updrec = ISC_LIST_HEAD (updque);
+               ISC_LIST_UNLINK (updque, updrec, r_link);
+               minires_freeupdrec (updrec);
+       }
+
+       return result;
+}
+
+
+static ns_rcode ddns_remove_ptr (struct data_string *ddns_fwd_name,
+                                struct data_string *ddns_rev_name,
+                                struct data_string *ddns_dhcid)
+{
+       ns_updque updque;
+       ns_updrec *updrec;
+       ns_rcode result = SERVFAIL;
+
+       /*
+        * When a lease expires or a DHCP client issues a DHCPRELEASE request,
+        * the DHCP server SHOULD delete the PTR RR that matches the DHCP
+        * binding, if one was successfully added. The server's update query
+        * SHOULD assert that the name in the PTR record matches the name of
+        * the client whose lease has expired or been released.
+        *   -- "Interaction between DHCP and DNS"
+        */
+
+       ISC_LIST_INIT (updque);
+
+       /*
+        * Delete appropriate PTR RR.
+        */
+       updrec = minires_mkupdrec (S_UPDATE, ddns_rev_name -> data,
+                                  C_IN, T_PTR, 0);
+       if (!updrec) goto error;
+
+       updrec -> r_data   = ddns_fwd_name -> buffer -> data;
+       updrec -> r_size   = ddns_fwd_name -> len;
+       updrec -> r_opcode = DELETE;
+
+       ISC_LIST_APPEND (updque, updrec, r_link);
+
+
+       /*
+        * Delete appropriate DHCID RR.
+        */
+       updrec = minires_mkupdrec (S_UPDATE, ddns_rev_name -> data,
+                                  C_IN, T_DHCID, 0);
+       if (!updrec) goto error;
+
+       updrec -> r_data   = ddns_dhcid -> buffer -> data;
+       updrec -> r_size   = ddns_dhcid -> len;
+       updrec -> r_opcode = DELETE;
+
+       ISC_LIST_APPEND (updque, updrec, r_link);
+
+
+       /*
+        * Attempt to perform the update.
+        */
+       result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updque));
+
+
+       /* Fall through. */
+  error:
+
+       while (!ISC_LIST_EMPTY (updque)) {
+               updrec = ISC_LIST_HEAD (updque);
+               ISC_LIST_UNLINK (updque, updrec, r_link);
+               minires_freeupdrec (updrec);
+       }
+
+       return result;
+}
+
+
+int ddns_updates (struct packet *packet,
+                 struct lease *lease,
+                 struct lease_state *state)
+{
+       unsigned long ddns_ttl = DEFAULT_DDNS_TTL;
+       struct data_string ddns_hostname;
+       struct data_string ddns_domainname;
+       struct data_string ddns_fwd_name;
+       struct data_string ddns_rev_name;
+       struct data_string ddns_address;
+       struct data_string ddns_dhcid;
+       unsigned len;
+       unsigned ddns_address_len = 0;
+       struct data_string d1;
+       struct option_cache *oc;
+       int s1, s2;
+       int result = 0;
+       ns_rcode rcode1, rcode2;
+
+       /* Can only cope with IPv4 addrs at the moment. */
+       if (lease -> ip_addr . len != 4)
+               return 0;
+
+
+       memset (&ddns_hostname, 0, sizeof (ddns_hostname));
+       memset (&ddns_domainname, 0, sizeof (ddns_domainname));
+       memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name));
+       memset (&ddns_rev_name, 0, sizeof (ddns_rev_name));
+       memset (&ddns_address, 0, sizeof (ddns_address));
+       memset (&ddns_dhcid, 0, sizeof (ddns_dhcid));
+
+
+       /*
+        * Look up the RR TTL.
+        */
+       ddns_ttl = DEFAULT_DDNS_TTL;
+       if ((oc = lookup_option (&server_universe, state -> options,
+                                SV_DDNS_TTL))) {
+               if (evaluate_option_cache (&d1, packet, lease,
+                                          (struct client_state *)0,
+                                          packet -> options,
+                                          state -> options,
+                                          &lease -> scope, oc, MDL)) {
+                       if (d1.len == sizeof (u_int32_t))
+                               ddns_ttl = getULong (d1.data);
+                       data_string_forget (&d1, MDL);
+               }
+       }
+
+
+       /*
+        * Look up the lease FQDN.
+        */
+       s1 = s2 = 0;
+
+       oc = lookup_option (&server_universe, state -> options,
+                           SV_DDNS_HOST_NAME);
+       if (oc)
+               s1 = evaluate_option_cache (&ddns_hostname, packet, lease,
+                                           (struct client_state *)0,
+                                           packet -> options,
+                                           state -> options,
+                                           &lease -> scope, oc, MDL);
+
+       oc = lookup_option (&server_universe, state -> options,
+                           SV_DDNS_DOMAIN_NAME);
+       if (oc)
+               s2 = evaluate_option_cache (&ddns_domainname, packet, lease,
+                                           (struct client_state *)0,
+                                           packet -> options,
+                                           state -> options,
+                                           &lease -> scope, oc, MDL);
+
+       if (s1 && s2) {
+               buffer_allocate (&ddns_fwd_name.buffer,
+                                ddns_hostname.len + ddns_domainname.len + 2,
+                                MDL);
+               if (ddns_fwd_name.buffer) {
+                       ddns_fwd_name.data = ddns_fwd_name.buffer -> data;
+                       data_string_append (&ddns_fwd_name, &ddns_hostname);
+                       ddns_fwd_name.buffer -> data [ddns_fwd_name.len] = '.';
+                       ddns_fwd_name.len++;
+                       data_string_append (&ddns_fwd_name, &ddns_domainname);
+                       ddns_fwd_name.buffer -> data [ddns_fwd_name.len] ='\0';
+                       ddns_fwd_name.terminated = 1;
+               }
+       }
+
+
+       /*
+        * Look up the lease IP address (as a string).
+        */
+       /* XXX.XXX.XXX.XXX\0 = 16 characters. */
+       buffer_allocate (&ddns_address.buffer, 16, MDL);
+                        
+#ifndef NO_SNPRINTF
+       snprintf (ddns_address.buffer -> data, 16,
+                 "%d.%d.%d.%d",
+                 lease -> ip_addr . iabuf[0],
+                 lease -> ip_addr . iabuf[1],
+                 lease -> ip_addr . iabuf[2],
+                 lease -> ip_addr . iabuf[3]);
+#else
+       sprintf (ddns_address.buffer -> data,
+                "%d.%d.%d.%d",
+                lease -> ip_addr . iabuf[0],
+                lease -> ip_addr . iabuf[1],
+                lease -> ip_addr . iabuf[2],
+                lease -> ip_addr . iabuf[3]);
+#endif
+       ddns_address.data = ddns_address.buffer -> data;
+       ddns_address.len = strlen (ddns_address.data);
+       ddns_address.terminated = 1;
+
+
+       /*
+        * Look up the reverse IP name.
+        */
+       oc = lookup_option (&server_universe, state -> options,
+                           SV_DDNS_REV_DOMAIN_NAME);
+       if (oc)
+               s1 = evaluate_option_cache (&d1, packet, lease,
+                                           (struct client_state *)0,
+                                           packet -> options,
+                                           state -> options,
+                                           &lease -> scope, oc, MDL);
+       
+       if (oc && s1) {
+               /* Buffer length:
+                  XXX.XXX.XXX.XXX.<ddns-rev-domain-name>\0 */
+               buffer_allocate (&ddns_rev_name.buffer,
+                                d1.len + 17, MDL);
+               if (ddns_rev_name.buffer) {
+                       ddns_rev_name.data = ddns_rev_name.buffer -> data;
+#ifndef NO_SNPRINTF
+                       snprintf (ddns_rev_name.buffer -> data, 17,
+                                 "%d.%d.%d.%d.",
+                                 lease -> ip_addr . iabuf[3],
+                                 lease -> ip_addr . iabuf[2],
+                                 lease -> ip_addr . iabuf[1],
+                                 lease -> ip_addr . iabuf[0]);
+#else
+                       sprintf (ddns_rev_name.buffer -> data,
+                                "%d.%d.%d.%d.",
+                                lease -> ip_addr . iabuf[3],
+                                lease -> ip_addr . iabuf[2],
+                                lease -> ip_addr . iabuf[1],
+                                lease -> ip_addr . iabuf[0]);
+#endif
+                       ddns_rev_name.len = strlen (ddns_rev_name.data);
+                       data_string_append (&ddns_rev_name, &d1);
+                       ddns_rev_name.buffer -> data [ddns_rev_name.len] ='\0';
+                       ddns_rev_name.terminated = 1;
+               }
+               
+               data_string_forget (&d1, MDL);
+       }
+
+
+       /*
+        * Look up the DHCID value.  (Should this be cached in the lease?)
+        */
+       buffer_allocate (&ddns_dhcid.buffer, (MD5_DIGEST_LENGTH*2)+1, MDL);
+       if (ddns_dhcid.buffer) {
+               get_dhcid (ddns_dhcid.buffer -> data, lease);
+               ddns_dhcid.data = ddns_dhcid.buffer -> data;
+               ddns_dhcid.len = MD5_DIGEST_LENGTH * 2;
+               ddns_dhcid.terminated = 1;
+       }
+
+
+       /*
+        * Start the resolver, if necessary.
+        */
+       if (!resolver_inited) {
+               minires_ninit (&resolver_state);
+               resolver_inited = 1;
+       }
+
+
+       /*
+        * Perform updates.
+        */
+       if (ddns_fwd_name.len && ddns_address.len && ddns_dhcid.len)
+               rcode1 = ddns_update_a(&ddns_fwd_name, &ddns_address,
+                                      &ddns_dhcid, ddns_ttl);
+       
+       if (ddns_fwd_name.len && ddns_rev_name.len && ddns_dhcid.len)
+               rcode2 = ddns_update_ptr(&ddns_fwd_name, &ddns_rev_name,
+                                        &ddns_dhcid, ddns_ttl);
+
+       /* minires_update() can return -1 under certain circumstances. */
+       if (rcode1 == -1)
+               rcode1 = SERVFAIL;
+       if (rcode2 == -1)
+               rcode2 = SERVFAIL;
+
+       if (rcode1 == NOERROR || rcode2 == NOERROR) {
+               bind_ds_value (&lease -> scope, "ddns-fwd-name",
+                              &ddns_fwd_name);
+               bind_ds_value (&lease -> scope, "ddns-dhcid",
+                              &ddns_dhcid);
+       }
+       if (rcode1 == NOERROR) {
+               bind_ds_value (&lease -> scope, "ddns-address",
+                              &ddns_address);
+       }
+       if (rcode2 == NOERROR) {
+               bind_ds_value (&lease -> scope, "ddns-rev-name",
+                              &ddns_rev_name);
+       }
+
+
+       /*
+        * If the client sent us the FQDN option, respond appropriately.
+        */
+       oc = lookup_option (&fqdn_universe, packet -> options,
+                           FQDN_SERVER_UPDATE);
+       if (oc) {
+               oc -> data.buffer -> data[0] = 1;
+       }
+
+       oc = lookup_option (&fqdn_universe, packet -> options,
+                           FQDN_NO_CLIENT_UPDATE);
+       if (oc) {
+               oc -> data.buffer -> data[0] = 1;
+       }
+
+       oc = lookup_option (&fqdn_universe, packet -> options,
+                           FQDN_RCODE1);
+       if (oc) {
+               oc -> data.buffer -> data[0] = rcode1;
+       }
+
+       oc = lookup_option (&fqdn_universe, packet -> options,
+                           FQDN_RCODE2);
+       if (oc) {
+               oc -> data.buffer -> data[0] = rcode2;
+       }
+
+       oc = lookup_option (&fqdn_universe, packet -> options,
+                           FQDN_HOSTNAME);
+       if (oc && ddns_hostname.buffer) {
+               data_string_forget (&oc -> data, MDL);
+               data_string_copy (&oc -> data, &ddns_hostname, MDL);
+       }
+
+       oc = lookup_option (&fqdn_universe, packet -> options,
+                           FQDN_DOMAINNAME);
+       if (oc && ddns_hostname.buffer) {
+               data_string_forget (&oc -> data, MDL);
+               data_string_copy (&oc -> data, &ddns_domainname, MDL);
+       }
+
+
+       /*
+        * Final cleanup.
+        */
+       data_string_forget (&ddns_hostname, MDL);
+       data_string_forget (&ddns_domainname, MDL);
+       data_string_forget (&ddns_fwd_name, MDL);
+       data_string_forget (&ddns_rev_name, MDL);
+       data_string_forget (&ddns_address, MDL);
+       data_string_forget (&ddns_dhcid, MDL);
+
+       return rcode1 == NOERROR || rcode2 == NOERROR;
+}
+
+
+int ddns_removals(struct lease *lease) {
+       struct data_string ddns_fwd_name;
+       struct data_string ddns_rev_name;
+       struct data_string ddns_address;
+       struct data_string ddns_dhcid;
+       ns_rcode rcode;
+
+       /* No scope implies that DDNS has not been performed for this lease. */
+       if (!lease -> scope)
+               return 1;
+
+
+       /*
+        * Look up stored names.
+        */
+       memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name));
+       memset (&ddns_rev_name, 0, sizeof (ddns_rev_name));
+       memset (&ddns_address, 0, sizeof (ddns_address));
+       memset (&ddns_dhcid, 0, sizeof (ddns_dhcid));
+
+       find_bound_string (&ddns_fwd_name, lease -> scope, "ddns-fwd-name");
+       find_bound_string (&ddns_rev_name, lease -> scope, "ddns-rev-name");
+       find_bound_string (&ddns_address, lease -> scope, "ddns-address");
+       find_bound_string (&ddns_dhcid, lease -> scope, "ddns-dhcid");
+
+
+       /*
+        * Start the resolver, if necessary.
+        */
+       if (!resolver_inited) {
+               minires_ninit (&resolver_state);
+               resolver_inited = 1;
+       }
+
+
+       /*
+        * Perform removals.
+        */
+       if (ddns_fwd_name.len && ddns_address.len && ddns_dhcid.len) {
+               rcode = ddns_remove_a (&ddns_fwd_name, &ddns_address,
+                                      &ddns_dhcid);
+       }
+       if (ddns_fwd_name.len && ddns_rev_name.len && ddns_dhcid.len) {
+               rcode = ddns_remove_ptr(&ddns_fwd_name, &ddns_rev_name,
+                                       &ddns_dhcid);
+       }
+
+
+       data_string_forget (&ddns_fwd_name, MDL);
+       data_string_forget (&ddns_rev_name, MDL);
+       data_string_forget (&ddns_address, MDL);
+       data_string_forget (&ddns_dhcid, MDL);
+
+
+       return 1;
+}
+
+
+#endif /* NSUPDATE */
index de8aa618d2b3b3cb933f77365a64bbc8c6bdcd02..1b57a85ddd8d57836b88eac3d3130cca46f09e2e 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: dhcp.c,v 1.172 2000/12/05 07:21:31 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: dhcp.c,v 1.173 2000/12/11 18:56:42 neild Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -1976,6 +1976,12 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                data_string_forget (&d1, MDL);
        }
 
+       /* Record the hardware address, if given... */
+       lt -> hardware_addr.hlen = packet -> raw -> hlen + 1;
+       lt -> hardware_addr.hbuf [0] = packet -> raw -> htype;
+       memcpy (&lt -> hardware_addr.hbuf [1], packet -> raw -> chaddr,
+               sizeof packet -> raw -> chaddr);
+
        lt -> flags = lease -> flags & ~PERSISTENT_FLAGS;
 
        /* If there are statements to execute when the lease is
@@ -1991,6 +1997,19 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                                                          MDL);
        }
 
+#ifdef NSUPDATE
+       /* Perform DDNS updates, if configured to. */
+       if ((!offer || offer == DHCPACK) &&
+           (oc = lookup_option (&server_universe, state -> options,
+                                SV_DDNS_UPDATES)) &&
+           evaluate_boolean_option_cache (&ignorep, packet, lt,
+                                          (struct client_state *)0,
+                                          packet -> options, state -> options,
+                                          &lt -> scope, oc, MDL)) {
+               ddns_updates (packet, lt, state);
+       }
+#endif /* NSUPDATE */
+
        /* Don't call supersede_lease on a mocked-up lease. */
        if (lease -> flags & STATIC_LEASE) {
                /* Copy the hardware address into the static lease
@@ -2001,12 +2020,6 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp)
                        packet -> raw -> chaddr,
                        sizeof packet -> raw -> chaddr); /* XXX */
        } else {
-               /* Record the hardware address, if given... */
-               lt -> hardware_addr.hlen = packet -> raw -> hlen + 1;
-               lt -> hardware_addr.hbuf [0] = packet -> raw -> htype;
-               memcpy (&lt -> hardware_addr.hbuf [1], packet -> raw -> chaddr,
-                       sizeof packet -> raw -> chaddr);
-
                /* Install the new information about this lease in the
                   database.  If this is a DHCPACK or a dynamic BOOTREPLY
                   and we can't write the lease, don't ACK it (or BOOTREPLY
index 2a5eb9909acbab2cb60712393d3c3d3ccd93868a..b6f888ceb2dd220379d8b68fd506ff0d0f7db291 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char ocopyright[] =
-"$Id: dhcpd.c,v 1.104 2000/12/05 07:30:37 mellon Exp $ Copyright 1995-2000 Internet Software Consortium.";
+"$Id: dhcpd.c,v 1.105 2000/12/11 18:56:43 neild Exp $ Copyright 1995-2000 Internet Software Consortium.";
 #endif
 
   static char copyright[] =
@@ -63,86 +63,15 @@ TIME cur_time;
 struct iaddr server_identifier;
 int server_identifier_matched;
 
-/* This is the standard name service updater that is executed whenever a
-   lease is committed.   Right now it's not following the DHCP-DNS draft
-   at all, but as soon as I fix the resolver it should try to. */
-
 #if defined (NSUPDATE)
 char std_nsupdate [] = "                                                   \n\
-on commit {                                                                \n\
-  if (not static and                                                       \n\
-      ((config-option server.ddns-updates = null) or                       \n\
-       (config-option server.ddns-updates != 0))) {                        \n\
-    set new-ddns-fwd-name =                                                \n\
-      concat (pick (config-option server.ddns-hostname,                            \n\
-                   option host-name), \".\",                               \n\
-             pick (config-option server.ddns-domainname,                   \n\
-                   config-option domain-name));                            \n\
-    if (defined (ddns-fwd-name) and ddns-fwd-name != new-ddns-fwd-name) {   \n\
-      switch (ns-update (delete (IN, A, ddns-fwd-name, leased-address))) {  \n\
-      case NOERROR:                                                        \n\
-       unset ddns-fwd-name;                                                \n\
-       on expiry or release {                                              \n\
-       }                                                                   \n\
-      }                                                                            \n\
-    }                                                                      \n\
-                                                                           \n\
-    if (not defined (ddns-fwd-name)) {                                     \n\
-      set ddns-fwd-name = new-ddns-fwd-name;                               \n\
-      if defined (ddns-fwd-name) {                                         \n\
-       switch (ns-update (not exists (IN, A, ddns-fwd-name, null),         \n\
-                          add (IN, A, ddns-fwd-name, leased-address,       \n\
-                               lease-time / 2))) {                         \n\
-       default:                                                            \n\
-         unset ddns-fwd-name;                                              \n\
-         break;                                                            \n\
-                                                                           \n\
-       case NOERROR:                                                       \n\
-         set ddns-rev-name =                                               \n\
-           concat (binary-to-ascii (10, 8, \".\",                          \n\
-                                    reverse (1,                            \n\
-                                             leased-address)), \".\",      \n\
-                   pick (config-option server.ddns-rev-domainname,         \n\
-                         \"in-addr.arpa.\"));                              \n\
-         switch (ns-update (delete (IN, PTR, ddns-rev-name, null),         \n\
-                            add (IN, PTR, ddns-rev-name, ddns-fwd-name,    \n\
-                                 lease-time / 2)))                         \n\
-           {                                                               \n\
-           default:                                                        \n\
-             unset ddns-rev-name;                                          \n\
-             on release or expiry {                                        \n\
-               switch (ns-update (delete (IN, A, ddns-fwd-name,            \n\
-                                          leased-address))) {              \n\
-               case NOERROR:                                               \n\
-                 unset ddns-fwd-name;                                      \n\
-                 break;                                                    \n\
-               }                                                           \n\
-               on release or expiry;                                       \n\
-             }                                                             \n\
-             break;                                                        \n\
-                                                                           \n\
-           case NOERROR:                                                   \n\
-             on release or expiry {                                        \n\
-               switch (ns-update (delete (IN, PTR, ddns-rev-name, null))) {\n\
-               case NOERROR:                                               \n\
-                 unset ddns-rev-name;                                      \n\
-                 break;                                                    \n\
-               }                                                           \n\
-               switch (ns-update (delete (IN, A, ddns-fwd-name,            \n\
-                                          leased-address))) {              \n\
-               case NOERROR:                                               \n\
-                 unset ddns-fwd-name;                                      \n\
-                 break;                                                    \n\
-               }                                                           \n\
-               on release or expiry;                                       \n\
-             }                                                             \n\
-           }                                                               \n\
-       }                                                                   \n\
-      }                                                                            \n\
-    }                                                                      \n\
-    unset new-ddns-fwd-name;                                               \n\
-  }                                                                        \n\
-}";
+option server.ddns-hostname =                                               \n\
+  pick (option fqdn.hostname, option host-name);                            \n\
+option server.ddns-domainname =                                             \n\
+  pick (option fqdn.domainname, option domain-name);                        \n\
+option server.ddns-ttl = encode-int(lease-time / 2, 32);                    \n\
+option server.ddns-rev-domainname = \"in-addr.arpa.\";                      \n\
+";
 #endif /* NSUPDATE */
 
 const char *path_dhcpd_conf = _PATH_DHCPD_CONF;
index 0b0b08b35bdea80d595e3f5ffba0ea631b31e0f5..eb5f222a9c61ccec8f8958aefb4d75a9d1513b82 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: mdb.c,v 1.45 2000/12/05 07:32:26 mellon Exp $ Copyright (c) 1996-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: mdb.c,v 1.46 2000/12/11 18:56:44 neild Exp $ Copyright (c) 1996-2000 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -1063,6 +1063,7 @@ void process_state_transition (struct lease *lease)
             lease -> binding_state == FTS_RESERVED) &&
            lease -> next_binding_state != FTS_RELEASED) {
                if (lease -> on_expiry) {
+                       ddns_removals (lease);
                        execute_statements ((struct binding_value **)0,
                                            (struct packet *)0, lease,
                                            (struct client_state *)0,
@@ -1090,6 +1091,7 @@ void process_state_transition (struct lease *lease)
             lease -> binding_state == FTS_RESERVED) &&
            lease -> next_binding_state == FTS_RELEASED) {
                if (lease -> on_release) {
+                       ddns_removals (lease);
                        execute_statements ((struct binding_value **)0,
                                            (struct packet *)0, lease,
                                            (struct client_state *)0,
@@ -1211,6 +1213,7 @@ void release_lease (lease, packet)
        /* If there are statements to execute when the lease is
           released, execute them. */
        if (lease -> on_release) {
+               ddns_removals (lease);
                execute_statements ((struct binding_value **)0,
                                    packet, lease, (struct client_state *)0,
                                    packet -> options,
index 4d8f894b1a748c3341ab63cce090f54dae885597..56c430fefa5658904d32791621bb0ffb41d4c35c 100644 (file)
@@ -43,7 +43,7 @@
 
 #ifndef lint
 static char copyright[] =
-"$Id: stables.c,v 1.19 2000/11/28 23:27:24 mellon Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
+"$Id: stables.c,v 1.20 2000/12/11 18:56:45 neild Exp $ Copyright (c) 1995-2000 The Internet Software Consortium.  All rights reserved.\n";
 #endif /* not lint */
 
 #include "dhcpd.h"
@@ -483,7 +483,7 @@ struct option server_options [256] = {
        { "local-address", "I",                 &server_universe, 35 },
        { "omapi-key", "t",                     &server_universe, 36 },
        { "stash-agent-options", "f",           &server_universe, 37 },
-       { "option-38", "X",                     &server_universe, 38 },
+       { "ddns-ttl", "T",                      &server_universe, 38 },
        { "option-39", "X",                     &server_universe, 39 },
        { "option-40", "X",                     &server_universe, 40 },
        { "option-41", "X",                     &server_universe, 41 },