From b992d7e23d870ada9317330b0b2b08e5823255d2 Mon Sep 17 00:00:00 2001 From: Damien Neil Date: Mon, 11 Dec 2000 18:56:45 +0000 Subject: [PATCH] DDNS implementation rewrite. DDNS should now operate according to . 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 | 145 ++++-- common/tables.c | 6 +- includes/dhcp.h | 5 +- includes/dhcpd.h | 10 + server/Makefile.dist | 4 +- server/ddns.c | 1000 ++++++++++++++++++++++++++++++++++++++++++ server/dhcp.c | 27 +- server/dhcpd.c | 87 +--- server/mdb.c | 5 +- server/stables.c | 4 +- 10 files changed, 1155 insertions(+), 138 deletions(-) create mode 100644 server/ddns.c diff --git a/common/options.c b/common/options.c index d21e17d9e..bdf9781c0 100644 --- a/common/options.c +++ b/common/options.c @@ -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; } } diff --git a/common/tables.c b/common/tables.c index f9a1235d8..ba11e7546 100644 --- a/common/tables.c +++ b/common/tables.c @@ -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 }, diff --git a/includes/dhcp.h b/includes/dhcp.h index d4d31138c..0602ae107 100644 --- a/includes/dhcp.h +++ b/includes/dhcp.h @@ -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 diff --git a/includes/dhcpd.h b/includes/dhcpd.h index 1302b4d85..a6c3882c9 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -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)); diff --git a/server/Makefile.dist b/server/Makefile.dist index f49b83af6..71a19a270 100644 --- a/server/Makefile.dist +++ b/server/Makefile.dist @@ -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 index 000000000..c50981437 --- /dev/null +++ b/server/ddns.c @@ -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" + * + * 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.\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 */ diff --git a/server/dhcp.c b/server/dhcp.c index de8aa618d..1b57a85dd 100644 --- a/server/dhcp.c +++ b/server/dhcp.c @@ -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 (< -> 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, + < -> 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 (< -> 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 diff --git a/server/dhcpd.c b/server/dhcpd.c index 2a5eb9909..b6f888ceb 100644 --- a/server/dhcpd.c +++ b/server/dhcpd.c @@ -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; diff --git a/server/mdb.c b/server/mdb.c index 0b0b08b35..eb5f222a9 100644 --- a/server/mdb.c +++ b/server/mdb.c @@ -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, diff --git a/server/stables.c b/server/stables.c index 4d8f894b1..56c430fef 100644 --- a/server/stables.c +++ b/server/stables.c @@ -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 }, -- 2.47.2