diff --git a/SOURCES/dhclient-script b/SOURCES/dhclient-script index 9f725a0..87bad65 100644 --- a/SOURCES/dhclient-script +++ b/SOURCES/dhclient-script @@ -56,6 +56,7 @@ eventually_add_hostnames_domain_to_search() { search="${1}" if need_hostname; then status=1 + OLD_HOSTNAME=${HOSTNAME} if [ -n "${new_ip_address}" ]; then eval $(/bin/ipcalc --silent --hostname ${new_ip_address} ; echo "status=$?") elif [ -n "${new_ip6_address}" ]; then @@ -65,6 +66,7 @@ eventually_add_hostnames_domain_to_search() { if [ ${status} -eq 0 ]; then domain=$(echo $HOSTNAME | cut -s -d "." -f 2-) fi + HOSTNAME=${OLD_HOSTNAME} else domain=$(hostname 2>/dev/null | cut -s -d "." -f 2-) fi @@ -352,6 +354,8 @@ dhconfig() { if [ "${reason}" = "BOUND" ] || [ "${reason}" = "REBOOT" ] || + [ ! "${old_classless_static_routes}" = "${new_classless_static_routes}" ] || + [ ! "${old_static_routes}" = "${new_static_routes}" ] || [ ! "${old_ip_address}" = "${new_ip_address}" ] || [ ! "${old_subnet_mask}" = "${new_subnet_mask}" ] || [ ! "${old_network_number}" = "${new_network_number}" ] || @@ -368,6 +372,32 @@ dhconfig() { ip link set dev ${interface} mtu ${new_interface_mtu} fi + # Remove old static routes if no new static routes are provided + if [ -n "${old_classless_static_routes}" ] || + [ -n "${old_static_routes}" ]; then + remove_routes=0 + if [ -n "${old_classless_static_routes}" ]; then + if [ -z "${new_classless_static_routes}" ]; then + IFS=', |' old_static_routes=(${old_classless_static_routes}) + remove_routes=1 + fi + else + if [ -z "${new_static_routes}" ]; then + IFS=', |' old_static_routes=(${old_static_routes}) + remove_routes=1 + fi + fi + if [ $remove_routes = "1" ] ; then + for((i=0; i<${#old_static_routes[@]}; i+=2)); do + old_target=${old_static_routes[$i]} + old_prefix=$(echo ${old_target} | cut -d "." -f 1) + old_target=$(echo ${old_target} | cut -d "." -f 2-) + old_gateway=${old_static_routes[$i+1]} + ip -4 route del ${old_target}/${old_prefix} proto static via ${old_gateway} dev ${interface} + done + fi + fi + # static routes if [ -n "${new_classless_static_routes}" ] || [ -n "${new_static_routes}" ]; then @@ -381,6 +411,31 @@ dhconfig() { fi route_targets=() + # Remove old static routes if no matching target is provided in the new static routes + if [ -n "${old_classless_static_routes}" ] || + [ -n "${old_static_routes}" ]; then + if [ -n "${old_classless_static_routes}" ]; then + IFS=', |' old_static_routes=(${old_classless_static_routes}) + else + IFS=', |' old_static_routes=(${old_static_routes}) + fi + for((i=0; i<${#old_static_routes[@]}; i+=2)); do + old_target=${old_static_routes[$i]} + remove_route=1 + for((j=0; j<${#static_routes[@]}; j+=2)); do + if [ $old_target = ${static_routes[$j]} ]; then + remove_route=0 + fi + done + old_prefix=$(echo ${old_target} | cut -d "." -f 1) + old_target=$(echo ${old_target} | cut -d "." -f 2-) + old_gateway=${old_static_routes[$i+1]} + if [ $remove_route = "1" ]; then + ip -4 route del ${old_target}/${old_prefix} proto static via ${old_gateway} dev ${interface} + fi + done + fi + for((i=0; i<${#static_routes[@]}; i+=2)); do target=${static_routes[$i]} if [ -n "${new_classless_static_routes}" ]; then diff --git a/SOURCES/dhcp-4.2.5-additional_hmac_tsig.patch b/SOURCES/dhcp-4.2.5-additional_hmac_tsig.patch new file mode 100644 index 0000000..a90b48e --- /dev/null +++ b/SOURCES/dhcp-4.2.5-additional_hmac_tsig.patch @@ -0,0 +1,87 @@ +commit 71c56235c6fbdeed3ba5a75bb379a34394106619 +Author: Pavel Zhukov +Date: Mon Apr 10 12:59:07 2017 +0200 + + Backported upstream commit e4a2cb79b2679738f56b3803a44c9899f6982c09 + +diff --git a/includes/omapip/isclib.h b/includes/omapip/isclib.h +index ddefeb5..4dffcb9 100644 +--- a/includes/omapip/isclib.h ++++ b/includes/omapip/isclib.h +@@ -104,6 +104,11 @@ extern dhcp_context_t dhcp_gbl_ctx; + #define DHCP_MAXDNS_WIRE 256 + #define DHCP_MAXNS 3 + #define DHCP_HMAC_MD5_NAME "HMAC-MD5.SIG-ALG.REG.INT." ++#define DHCP_HMAC_SHA1_NAME "HMAC-SHA1.SIG-ALG.REG.INT." ++#define DHCP_HMAC_SHA224_NAME "HMAC-SHA224.SIG-ALG.REG.INT." ++#define DHCP_HMAC_SHA256_NAME "HMAC-SHA256.SIG-ALG.REG.INT." ++#define DHCP_HMAC_SHA384_NAME "HMAC-SHA384.SIG-ALG.REG.INT." ++#define DHCP_HMAC_SHA512_NAME "HMAC-SHA512.SIG-ALG.REG.INT." + + isc_result_t dhcp_isc_name(unsigned char *namestr, + dns_fixedname_t *namefix, +diff --git a/omapip/isclib.c b/omapip/isclib.c +index 1534dde..be1982e 100644 +--- a/omapip/isclib.c ++++ b/omapip/isclib.c +@@ -198,21 +198,34 @@ isclib_make_dst_key(char *inname, + dns_name_t *name; + dns_fixedname_t name0; + isc_buffer_t b; ++ unsigned int algorithm_code; + + isc_buffer_init(&b, secret, length); + isc_buffer_add(&b, length); + +- /* We only support HMAC_MD5 currently */ +- if (strcasecmp(algorithm, DHCP_HMAC_MD5_NAME) != 0) { ++ if (strcasecmp(algorithm, DHCP_HMAC_MD5_NAME) == 0) { ++ algorithm_code = DST_ALG_HMACMD5; ++ } else if (strcasecmp(algorithm, DHCP_HMAC_SHA1_NAME) == 0) { ++ algorithm_code = DST_ALG_HMACSHA1; ++ } else if (strcasecmp(algorithm, DHCP_HMAC_SHA224_NAME) == 0) { ++ algorithm_code = DST_ALG_HMACSHA224; ++ } else if (strcasecmp(algorithm, DHCP_HMAC_SHA256_NAME) == 0) { ++ algorithm_code = DST_ALG_HMACSHA256; ++ } else if (strcasecmp(algorithm, DHCP_HMAC_SHA384_NAME) == 0) { ++ algorithm_code = DST_ALG_HMACSHA384; ++ } else if (strcasecmp(algorithm, DHCP_HMAC_SHA512_NAME) == 0) { ++ algorithm_code = DST_ALG_HMACSHA512; ++ } else { + return(DHCP_R_INVALIDARG); + } + ++ + result = dhcp_isc_name((unsigned char *)inname, &name0, &name); + if (result != ISC_R_SUCCESS) { + return(result); + } + +- return(dst_key_frombuffer(name, DST_ALG_HMACMD5, DNS_KEYOWNER_ENTITY, ++ return(dst_key_frombuffer(name, algorithm_code, DNS_KEYOWNER_ENTITY, + DNS_KEYPROTO_DNSSEC, dns_rdataclass_in, + &b, dhcp_gbl_ctx.mctx, dstkey)); + } +diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5 +index 0cb50a6..74393c2 100644 +--- a/server/dhcpd.conf.5 ++++ b/server/dhcpd.conf.5 +@@ -1398,6 +1398,18 @@ generate a key as seen above: + dnskeygen -H 128 -u -c -n DHCP_UPDATER + .fi + .PP ++The key name, algorithm, and secret must match that being used by the DNS ++server. The DHCP server currently supports the following algorithms: ++.nf ++ ++ HMAC-MD5 ++ HMAC-SHA1 ++ HMAC-SHA224 ++ HMAC-SHA256 ++ HMAC-SHA384 ++ HMAC-SHA512 ++.fi ++.PP + You may wish to enable logging of DNS updates on your DNS server. + To do so, you might write a logging statement like the following: + .PP diff --git a/SOURCES/dhcp-4.2.5-centos-branding.patch b/SOURCES/dhcp-4.2.5-centos-branding.patch deleted file mode 100644 index f3e7113..0000000 --- a/SOURCES/dhcp-4.2.5-centos-branding.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff -uNrp dhcp-4.1.1-P1.orig/omapip/errwarn.c dhcp-4.1.1-P1/omapip/errwarn.c ---- dhcp-4.1.1-P1.orig/omapip/errwarn.c 2012-08-15 14:04:33.149141000 +0000 -+++ dhcp-4.1.1-P1/omapip/errwarn.c 2012-08-15 14:13:05.582416057 +0000 -@@ -81,8 +81,8 @@ void log_fatal (const char * fmt, ... ) - log_error ("have been made to the base software release in order to make"); - log_error ("it work better with this distribution."); - log_error ("%s", ""); -- log_error ("Please report for this software via the Red Hat Bugzilla site:"); -- log_error (" http://bugzilla.redhat.com"); -+ log_error ("Please report for this software via the CentOS Bugs Database:"); -+ log_error (" http://bugs.centos.org/"); - log_error ("%s", ""); - log_error ("exiting."); - #endif diff --git a/SOURCES/dhcp-4.2.5-ddns_port_lazy_init.patch b/SOURCES/dhcp-4.2.5-ddns_port_lazy_init.patch new file mode 100644 index 0000000..fb4fd7f --- /dev/null +++ b/SOURCES/dhcp-4.2.5-ddns_port_lazy_init.patch @@ -0,0 +1,70 @@ +--- a/common/dns.c ++++ a/common/dns.c +@@ -1381,6 +1381,24 @@ void ddns_interlude(isc_task_t *taskp, + } + + /* ++ * Moved here from omapip/isclib.c, function dhcp_context_create. ++ * Create dnsclient only before the first use. ++ */ ++static isc_result_t ++dns_client_lazy() { ++ if (dhcp_gbl_ctx.dnsclient == NULL) ++ return dns_client_createx(dhcp_gbl_ctx.mctx, ++ dhcp_gbl_ctx.actx, ++ dhcp_gbl_ctx.taskmgr, ++ dhcp_gbl_ctx.socketmgr, ++ dhcp_gbl_ctx.timermgr, ++ 0, ++ &dhcp_gbl_ctx.dnsclient); ++ else ++ return ISC_R_SUCCESS; ++} ++ ++/* + * This routine does the generic work for sending a ddns message to + * modify the forward record (A or AAAA) and calls one of a set of + * routines to build the specific message. +@@ -1403,6 +1421,10 @@ ddns_modify_fwd(dhcp_ddns_cb_t *ddns_cb, const char *file, int line) + /* Get a pointer to the clientname to make things easier. */ + clientname = (unsigned char *)ddns_cb->fwd_name.data; + ++ result = dns_client_lazy(); ++ if (result != ISC_R_SUCCESS) ++ return result; ++ + /* Extract and validate the type of the address. */ + if (ddns_cb->address.len == 4) { + ddns_cb->address_type = dns_rdatatype_a; +@@ -1586,6 +1608,10 @@ ddns_modify_ptr(dhcp_ddns_cb_t *ddns_cb, const char *file, int line) + unsigned char buf[256]; + int buflen; + ++ result = dns_client_lazy(); ++ if (result != ISC_R_SUCCESS) ++ return result; ++ + /* + * Try to lookup the zone in the zone cache. As with the forward + * case it's okay if we don't have one, the DNS code will try to +--- a/omapip/isclib.c ++++ a/omapip/isclib.c +@@ -130,17 +130,7 @@ dhcp_context_create(void) { + if (result != ISC_R_SUCCESS) + goto cleanup; + +-#if defined (NSUPDATE) +- result = dns_client_createx(dhcp_gbl_ctx.mctx, +- dhcp_gbl_ctx.actx, +- dhcp_gbl_ctx.taskmgr, +- dhcp_gbl_ctx.socketmgr, +- dhcp_gbl_ctx.timermgr, +- 0, +- &dhcp_gbl_ctx.dnsclient); +- if (result != ISC_R_SUCCESS) +- goto cleanup; +-#else ++#if !defined (NSUPDATE) + /* The dst library is inited as part of dns_lib_init, we don't + * need it if NSUPDATE is enabled */ + result = dst_lib_init(dhcp_gbl_ctx.mctx, NULL, 0); diff --git a/SOURCES/dhcp-4.2.5-failover-potential-conflict.patch b/SOURCES/dhcp-4.2.5-failover-potential-conflict.patch new file mode 100644 index 0000000..d1f6861 --- /dev/null +++ b/SOURCES/dhcp-4.2.5-failover-potential-conflict.patch @@ -0,0 +1,255 @@ +diff --git a/includes/dhcpd.h b/includes/dhcpd.h +index 7e756e0..52ba677 100644 +--- a/includes/dhcpd.h ++++ b/includes/dhcpd.h +@@ -3347,6 +3347,7 @@ isc_result_t dhcp_failover_state_signal (omapi_object_t *, + isc_result_t dhcp_failover_state_transition (dhcp_failover_state_t *, + const char *); + isc_result_t dhcp_failover_set_service_state (dhcp_failover_state_t *state); ++void dhcp_failover_rescind_updates (dhcp_failover_state_t *); + isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *, + enum failover_state); + isc_result_t dhcp_failover_peer_state_changed (dhcp_failover_state_t *, +diff --git a/server/failover.c b/server/failover.c +index 8944102..6083672 100644 +--- a/server/failover.c ++++ b/server/failover.c +@@ -1520,8 +1520,16 @@ isc_result_t dhcp_failover_state_transition (dhcp_failover_state_t *state, + /* In these situations, we remain in the current + * state, or if in startup enter those states. + */ +- case communications_interrupted: + case conflict_done: ++ /* As the peer may not have received or may have ++ * lost track of updates we sent previously we ++ * rescind them, causing us to retransmit them ++ * on an update request. ++ */ ++ dhcp_failover_rescind_updates(state); ++ /* fall through */ ++ ++ case communications_interrupted: + case partner_down: + case paused: + case recover: +@@ -1704,6 +1712,52 @@ isc_result_t dhcp_failover_set_service_state (dhcp_failover_state_t *state) + return ISC_R_SUCCESS; + } + ++/*! ++ * \brief Return any leases on the ack queue back to the update queue ++ * ++ * Re-schedule any pending updates by moving them from the ack queue ++ * (update sent awaiting response) back to the update queue (need to ++ * send an update for this lease). This will result in a retransmission ++ * of the update. ++ * ++ * \param state is the state block for the failover connection we are ++ * updating. ++ */ ++ ++void dhcp_failover_rescind_updates (dhcp_failover_state_t *state) ++{ ++ struct lease *lp; ++ ++ if (state->ack_queue_tail == NULL) ++ return; ++ ++ /* Zap the flags. */ ++ for (lp = state->ack_queue_head; lp; lp = lp->next_pending) ++ lp->flags = ((lp->flags & ~ON_ACK_QUEUE) | ON_UPDATE_QUEUE); ++ ++ /* Now hook the ack queue to the beginning of the update queue. */ ++ if (state->update_queue_head) { ++ lease_reference(&state->ack_queue_tail->next_pending, ++ state->update_queue_head, MDL); ++ lease_dereference(&state->update_queue_head, MDL); ++ } ++ lease_reference(&state->update_queue_head, state->ack_queue_head, MDL); ++ ++ if (!state->update_queue_tail) { ++#if defined (POINTER_DEBUG) ++ if (state->ack_queue_tail->next_pending) { ++ log_error("next pending on ack queue tail."); ++ abort(); ++ } ++#endif ++ lease_reference(&state->update_queue_tail, ++ state->ack_queue_tail, MDL); ++ } ++ lease_dereference(&state->ack_queue_tail, MDL); ++ lease_dereference(&state->ack_queue_head, MDL); ++ state->cur_unacked_updates = 0; ++} ++ + isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *state, + enum failover_state new_state) + { +@@ -1724,37 +1778,9 @@ isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *state, + case normal: + case potential_conflict: + case partner_down: +- if (state -> ack_queue_tail) { +- struct lease *lp; +- +- /* Zap the flags. */ +- for (lp = state -> ack_queue_head; lp; lp = lp -> next_pending) +- lp -> flags = ((lp -> flags & ~ON_ACK_QUEUE) | +- ON_UPDATE_QUEUE); +- +- /* Now hook the ack queue to the beginning of the update +- queue. */ +- if (state -> update_queue_head) { +- lease_reference (&state -> ack_queue_tail -> next_pending, +- state -> update_queue_head, MDL); +- lease_dereference (&state -> update_queue_head, MDL); +- } +- lease_reference (&state -> update_queue_head, +- state -> ack_queue_head, MDL); +- if (!state -> update_queue_tail) { +-#if defined (POINTER_DEBUG) +- if (state -> ack_queue_tail -> next_pending) { +- log_error ("next pending on ack queue tail."); +- abort (); +- } +-#endif +- lease_reference (&state -> update_queue_tail, +- state -> ack_queue_tail, MDL); +- } +- lease_dereference (&state -> ack_queue_tail, MDL); +- lease_dereference (&state -> ack_queue_head, MDL); +- state -> cur_unacked_updates = 0; +- } ++ /* Move the ack queue to the update queue */ ++ dhcp_failover_rescind_updates(state); ++ + /* We will re-queue a timeout later, if applicable. */ + cancel_timeout (dhcp_failover_keepalive, state); + break; +@@ -1858,7 +1884,9 @@ isc_result_t dhcp_failover_set_state (dhcp_failover_state_t *state, + break; + + case potential_conflict: +- if (state -> i_am == primary) ++ if ((state->i_am == primary) || ++ ((state->i_am == secondary) && ++ (state->partner.state == conflict_done))) + dhcp_failover_send_update_request (state); + break; + +@@ -1961,7 +1989,18 @@ isc_result_t dhcp_failover_peer_state_changed (dhcp_failover_state_t *state, + if (state -> partner.state == new_state && state -> me.state) { + switch (state -> me.state) { + case startup: +- dhcp_failover_set_state (state, state -> saved_state); ++ /* ++ * If we have a peer state we must be connected. ++ * If so we should move to potential_conflict ++ * instead of resolution_interrupted, otherwise ++ * back to whereever we were before we stopped. ++ */ ++ if (state->saved_state == resolution_interrupted) ++ dhcp_failover_set_state(state, ++ potential_conflict); ++ else ++ dhcp_failover_set_state(state, ++ state->saved_state); + return ISC_R_SUCCESS; + + case unknown_state: +@@ -2179,6 +2218,17 @@ isc_result_t dhcp_failover_peer_state_changed (dhcp_failover_state_t *state, + dhcp_failover_set_state(state, new_state); + break; + ++ case potential_conflict: ++ case resolution_interrupted: ++ /* ++ * This can happen when the connection is lost and ++ * recovered after the primary has moved to ++ * conflict-done but the secondary is still in ++ * potential-conflict. In that case, we have to ++ * remain in conflict-done. ++ */ ++ break; ++ + default: + log_fatal("Peer %s: Invalid attempt to move from %s " + "to %s while local state is conflict-done.", +@@ -4867,16 +4917,17 @@ isc_result_t dhcp_failover_send_update_request (dhcp_failover_state_t *state) + if (!link -> outer || link -> outer -> type != omapi_type_connection) + return DHCP_R_INVALIDARG; + +- if (state -> curUPD) +- return ISC_R_ALREADYRUNNING; ++ /* We allow an update to be restarted in case we requested an update ++ * and were interrupted by something. If we had an ALL going we need ++ * to restart that. Otherwise we simply continue with the request */ ++ if (state -> curUPD == FTM_UPDREQALL) { ++ return (dhcp_failover_send_update_request_all(state)); ++ } + +- status = (dhcp_failover_put_message +- (link, link -> outer, +- FTM_UPDREQ, link->xid++, +- (failover_option_t *)0)); ++ status = (dhcp_failover_put_message(link, link -> outer, FTM_UPDREQ, ++ link -> xid++, NULL)); + +- if (status == ISC_R_SUCCESS) +- state -> curUPD = FTM_UPDREQ; ++ state -> curUPD = FTM_UPDREQ; + + #if defined (DEBUG_FAILOVER_MESSAGES) + if (status != ISC_R_SUCCESS) +@@ -4886,7 +4937,12 @@ isc_result_t dhcp_failover_send_update_request (dhcp_failover_state_t *state) + log_debug ("%s", obuf); + } + #endif +- log_info ("Sent update request message to %s", state -> name); ++ if (status == ISC_R_SUCCESS) { ++ log_info("Sent update request message to %s", state -> name); ++ } else { ++ log_error("Failed to send update request all message to %s: %s", ++ state -> name, isc_result_totext(status)); ++ } + return status; + } + +@@ -4913,17 +4969,14 @@ isc_result_t dhcp_failover_send_update_request_all (dhcp_failover_state_t + if (!link -> outer || link -> outer -> type != omapi_type_connection) + return DHCP_R_INVALIDARG; + +- /* If there is an UPDREQ in progress, then upgrade to UPDREQALL. */ +- if (state -> curUPD && (state -> curUPD != FTM_UPDREQ)) +- return ISC_R_ALREADYRUNNING; ++ /* We allow an update to be restarted in case we requested an update ++ * and were interrupted by something. ++ */ + +- status = (dhcp_failover_put_message +- (link, link -> outer, +- FTM_UPDREQALL, link->xid++, +- (failover_option_t *)0)); ++ status = (dhcp_failover_put_message(link, link -> outer, FTM_UPDREQALL, ++ link -> xid++, NULL)); + +- if (status == ISC_R_SUCCESS) +- state -> curUPD = FTM_UPDREQALL; ++ state -> curUPD = FTM_UPDREQALL; + + #if defined (DEBUG_FAILOVER_MESSAGES) + if (status != ISC_R_SUCCESS) +@@ -4933,7 +4986,12 @@ isc_result_t dhcp_failover_send_update_request_all (dhcp_failover_state_t + log_debug ("%s", obuf); + } + #endif +- log_info ("Sent update request all message to %s", state -> name); ++ if (status == ISC_R_SUCCESS) { ++ log_info("Sent update request all message to %s", state -> name); ++ } else { ++ log_error("Failed to send update request all message to %s: %s", ++ state -> name, isc_result_totext(status)); ++ } + return status; + } + diff --git a/SOURCES/dhcp-4.2.5-standard_ddns.patch b/SOURCES/dhcp-4.2.5-standard_ddns.patch new file mode 100644 index 0000000..39107a7 --- /dev/null +++ b/SOURCES/dhcp-4.2.5-standard_ddns.patch @@ -0,0 +1,2774 @@ +diff --git a/client/dhclient.8 b/client/dhclient.8 +index a29757a..c66a912 100644 +--- a/client/dhclient.8 ++++ b/client/dhclient.8 +@@ -56,6 +56,12 @@ dhclient - Dynamic Host Configuration Protocol Client + ] + ] + [ ++.B -i ++] ++[ ++.B -I ++] ++[ + .B -D + .I LL|LLT + ] +@@ -441,6 +447,17 @@ Set the giaddr field of all packets to the \fIrelay\fR IP address + simulating a relay agent. This is for testing pruposes only and + should not be expected to work in any consistent or useful way. + .TP ++.BI \-i ++Use a DUID with DHCPv4 clients. If no DUID is available in the ++lease file one will be constructed and saved. The DUID will be ++used to contstuct a RFC4361 style client id that will be included ++in the client's messages. This client id can be overridden by ++setting a client id in the configuration file. Overridding the ++client id in this fashion is discouraged. ++.TP ++.BI \-I ++Use the standard DDNS scheme from RFCs 4701 & 4702. ++.TP + .BI \--version + Print version number and exit. + .PP +@@ -470,8 +487,10 @@ DHCPv6 \fBdhclient\fR creates an identifier based on the link-layer address + (DUID-LL) if it is running in stateless mode (with \fB\-S\fR, not + requesting an address), or it creates an identifier based on the + link-layer address plus a timestamp (DUID-LLT) if it is running in +-stateful mode (without \fB\-S\fR, requesting an address). \fB\-D\fR +-overrides this default, with a value of either \fILL\fR or \fILLT\fR. ++stateful mode (without \fB\-S\fR, requesting an address). When DHCPv4 ++is configued to use a DUID using \fB\-i\fR option the default is to use ++a DUID-LLT. \fB\-D\fR ++overrides these default, with a value of either \fILL\fR or \fILLT\fR. + .TP + .BI \-N + .\" TODO: is this for telling an already running dhclient? +diff --git a/client/dhclient.c b/client/dhclient.c +index 0db4703..6403754 100644 +--- a/client/dhclient.c ++++ b/client/dhclient.c +@@ -79,6 +79,8 @@ struct sockaddr_in sockaddr_broadcast; + struct in_addr giaddr; + struct data_string default_duid; + int duid_type = 0; ++int duid_v4 = 0; ++int std_dhcid = 0; + + /* ASSERT_STATE() does nothing now; it used to be + assert (state_is == state_shouldbe). */ +@@ -325,12 +327,9 @@ main(int argc, char **argv) { + wanted_ia_na = 0; + } + wanted_ia_pd++; ++#endif /* DHCPv6 */ + } else if (!strcmp(argv[i], "-D")) { +- if (local_family_set && (local_family == AF_INET)) { +- usage(); +- } +- local_family_set = 1; +- local_family = AF_INET6; ++ duid_v4 = 1; + if (++i == argc) + usage(); + if (!strcasecmp(argv[i], "LL")) { +@@ -340,7 +339,12 @@ main(int argc, char **argv) { + } else { + usage(); + } +-#endif /* DHCPv6 */ ++ } else if (!strcmp(argv[i], "-i")) { ++ /* enable DUID support for DHCPv4 clients */ ++ duid_v4 = 1; ++ } else if (!strcmp(argv[i], "-I")) { ++ /* enable standard DHCID support for DDNS updates */ ++ std_dhcid = 1; + } else if (!strcmp(argv[i], "-v")) { + quiet = 0; + } else if (!strcmp(argv[i], "--version")) { +@@ -970,12 +974,13 @@ main(int argc, char **argv) { + } + } + +- /* Start a configuration state machine for each interface. */ +-#ifdef DHCPv6 +- if (local_family == AF_INET6) { +- /* Establish a default DUID. This may be moved to the +- * DHCPv4 area later. +- */ ++ ++ /* ++ * Establish a default DUID. We always do so for v6 and ++ * do so if desired for v4 via the -D or -i options ++ */ ++ if ((local_family == AF_INET6) || ++ ((local_family == AF_INET) && (duid_v4 == 1))) { + if (default_duid.len == 0) { + if (default_duid.buffer != NULL) + data_string_forget(&default_duid, MDL); +@@ -983,7 +988,11 @@ main(int argc, char **argv) { + if (form_duid(&default_duid, MDL) == ISC_R_SUCCESS) + write_duid(&default_duid); + } ++ } + ++ /* Start a configuration state machine for each interface. */ ++#ifdef DHCPv6 ++ if (local_family == AF_INET6) { + for (ip = interfaces ; ip != NULL ; ip = ip->next) { + for (client = ip->client ; client != NULL ; + client = client->next) { +@@ -1115,9 +1124,9 @@ static void usage() + + log_fatal("Usage: dhclient " + #ifdef DHCPv6 +- "[-4|-6] [-SNTP1dvrx] [-nw] [-p ] [-D LL|LLT]\n" ++ "[-4|-6] [-SNTPI1dvrxi] [-nw] [-p ] [-D LL|LLT] \n" + #else /* DHCPv6 */ +- "[-1dvrx] [-nw] [-p ]\n" ++ "[-I1dvrxi] [-nw] [-p ] [-D LL|LLT] \n" + #endif /* DHCPv6 */ + " [-s server-addr] [-cf config-file] " + "[-lf lease-file]\n" +@@ -2823,24 +2832,24 @@ make_client_options(struct client_state *client, struct client_lease *lease, + unsigned i; + struct option_cache *oc; + struct option *option = NULL; +- struct buffer *bp = (struct buffer *)0; ++ struct buffer *bp = NULL; + + /* If there are any leftover options, get rid of them. */ + if (*op) +- option_state_dereference (op, MDL); ++ option_state_dereference(op, MDL); + + /* Allocate space for options. */ +- option_state_allocate (op, MDL); ++ option_state_allocate(op, MDL); + + /* Send the server identifier if provided. */ + if (sid) +- save_option (&dhcp_universe, *op, sid); ++ save_option(&dhcp_universe, *op, sid); + +- oc = (struct option_cache *)0; ++ oc = NULL; + + /* Send the requested address if provided. */ + if (rip) { +- client -> requested_address = *rip; ++ client->requested_address = *rip; + i = DHO_DHCP_REQUESTED_ADDRESS; + if (!(option_code_hash_lookup(&option, dhcp_universe.code_hash, + &i, 0, MDL) && +@@ -2848,22 +2857,22 @@ make_client_options(struct client_state *client, struct client_lease *lease, + option, MDL))) + log_error ("can't make requested address cache."); + else { +- save_option (&dhcp_universe, *op, oc); +- option_cache_dereference (&oc, MDL); ++ save_option(&dhcp_universe, *op, oc); ++ option_cache_dereference(&oc, MDL); + } + option_dereference(&option, MDL); + } else { +- client -> requested_address.len = 0; ++ client->requested_address.len = 0; + } + + i = DHO_DHCP_MESSAGE_TYPE; + if (!(option_code_hash_lookup(&option, dhcp_universe.code_hash, &i, 0, + MDL) && + make_const_option_cache(&oc, NULL, type, 1, option, MDL))) +- log_error ("can't make message type."); ++ log_error("can't make message type."); + else { +- save_option (&dhcp_universe, *op, oc); +- option_cache_dereference (&oc, MDL); ++ save_option(&dhcp_universe, *op, oc); ++ option_cache_dereference(&oc, MDL); + } + option_dereference(&option, MDL); + +@@ -2876,8 +2885,8 @@ make_client_options(struct client_state *client, struct client_lease *lease, + if (prl[i]->universe == &dhcp_universe) + len++; + +- if (!buffer_allocate (&bp, len, MDL)) +- log_error ("can't make parameter list buffer."); ++ if (!buffer_allocate(&bp, len, MDL)) ++ log_error("can't make parameter list buffer."); + else { + unsigned code = DHO_DHCP_PARAMETER_REQUEST_LIST; + +@@ -2891,15 +2900,69 @@ make_client_options(struct client_state *client, struct client_lease *lease, + &code, 0, MDL) && + make_const_option_cache(&oc, &bp, NULL, len, + option, MDL))) +- log_error ("can't make option cache"); ++ log_error("can't make option cache"); + else { +- save_option (&dhcp_universe, *op, oc); +- option_cache_dereference (&oc, MDL); ++ save_option(&dhcp_universe, *op, oc); ++ option_cache_dereference(&oc, MDL); + } + option_dereference(&option, MDL); + } + } + ++ /* ++ * If requested (duid_v4 == 1) add an RFC4361 compliant client-identifier ++ * This can be overridden by including a client id in the configuration ++ * file. ++ */ ++ if (duid_v4 == 1) { ++ struct data_string client_identifier; ++ int hw_idx, hw_len; ++ ++ memset(&client_identifier, 0, sizeof(client_identifier)); ++ client_identifier.len = 1 + 4 + default_duid.len; ++ if (!buffer_allocate(&client_identifier.buffer, ++ client_identifier.len, MDL)) ++ log_fatal("no memory for default DUID!"); ++ client_identifier.data = client_identifier.buffer->data; ++ ++ i = DHO_DHCP_CLIENT_IDENTIFIER; ++ ++ /* Client-identifier type : 1 byte */ ++ *client_identifier.buffer->data = 255; ++ ++ /* IAID : 4 bytes ++ * we use the low 4 bytes from the interface address ++ */ ++ if (client->interface->hw_address.hlen > 4) { ++ hw_idx = client->interface->hw_address.hlen - 4; ++ hw_len = 4; ++ } else { ++ hw_idx = 0; ++ hw_len = client->interface->hw_address.hlen; ++ } ++ memcpy(&client_identifier.buffer->data + 5 - hw_len, ++ client->interface->hw_address.hbuf + hw_idx, ++ hw_len); ++ ++ /* Add the default duid */ ++ memcpy(&client_identifier.buffer->data+(1+4), ++ default_duid.data, default_duid.len); ++ ++ /* And save the option */ ++ if (!(option_code_hash_lookup(&option, dhcp_universe.code_hash, ++ &i, 0, MDL) && ++ make_const_option_cache(&oc, NULL, ++ (u_int8_t *)client_identifier.data, ++ client_identifier.len, ++ option, MDL))) ++ log_error ("can't make requested client id cache.."); ++ else { ++ save_option (&dhcp_universe, *op, oc); ++ option_cache_dereference (&oc, MDL); ++ } ++ option_dereference(&option, MDL); ++ } ++ + /* Run statements that need to be run on transmission. */ + if (client -> config -> on_transmission) + execute_statements_in_scope +@@ -4522,6 +4585,7 @@ client_dns_update(struct client_state *client, dhcp_ddns_cb_t *ddns_cb) + struct option_cache *oc; + int ignorep; + int result; ++ int ddns_v4_type; + isc_result_t rcode; + + /* If we didn't send an FQDN option, we certainly aren't going to +@@ -4564,47 +4628,82 @@ client_dns_update(struct client_state *client, dhcp_ddns_cb_t *ddns_cb) + &global_scope, oc, MDL)) + return ISC_R_SUCCESS; + +- /* If this is a DHCPv6 client update, make a dhcid string out of +- * the DUID. If this is a DHCPv4 client update, choose either +- * the client identifier, if there is one, or the interface's +- * MAC address. ++ /* ++ * Construct the DHCID value for use in the DDNS update process ++ * We have the newer standard version and the older interim version ++ * chosen by the '-I' option. The interim version is left as is ++ * for backwards compatibility. The standard version is based on ++ * RFC 4701 section 3.3 + */ ++ + result = 0; + memset(&client_identifier, 0, sizeof(client_identifier)); +- if (client->active_lease != NULL) { +- if (((oc = +- lookup_option(&dhcpv6_universe, client->sent_options, +- D6O_CLIENTID)) != NULL) && +- evaluate_option_cache(&client_identifier, NULL, NULL, +- client, client->sent_options, NULL, ++ ++ if (std_dhcid == 1) { ++ /* standard style */ ++ ddns_cb->dhcid_class = dns_rdatatype_dhcid; ++ ddns_v4_type = 1; ++ } else { ++ /* interim style */ ++ ddns_cb->dhcid_class = dns_rdatatype_txt; ++ /* for backwards compatibility */ ++ ddns_v4_type = DHO_DHCP_CLIENT_IDENTIFIER; ++ } ++ ++ if (client->active_lease != NULL) { ++ /* V6 request, get the client identifier, then ++ * construct the dhcid for either standard ++ * or interim */ ++ if (((oc = lookup_option(&dhcpv6_universe, ++ client->sent_options, ++ D6O_CLIENTID)) != NULL) && ++ evaluate_option_cache(&client_identifier, NULL, ++ NULL, client, ++ client->sent_options, NULL, + &global_scope, oc, MDL)) { +- /* RFC4701 defines type '2' as being for the DUID +- * field. We aren't using RFC4701 DHCID RR's yet, +- * but this is as good a value as any. +- */ +- result = get_dhcid(&ddns_cb->dhcid, 2, ++ result = get_dhcid(ddns_cb, 2, + client_identifier.data, + client_identifier.len); + data_string_forget(&client_identifier, MDL); + } else + log_fatal("Impossible condition at %s:%d.", MDL); + } else { +- if (((oc = +- lookup_option(&dhcp_universe, client->sent_options, +- DHO_DHCP_CLIENT_IDENTIFIER)) != NULL) && +- evaluate_option_cache(&client_identifier, NULL, NULL, +- client, client->sent_options, NULL, ++ /* ++ * V4 request, use the client id if there is one or the ++ * mac address if there isn't. If we have a client id ++ * we check to see if it is an embedded DUID. ++ */ ++ if (((oc = lookup_option(&dhcp_universe, ++ client->sent_options, ++ DHO_DHCP_CLIENT_IDENTIFIER)) != NULL) && ++ evaluate_option_cache(&client_identifier, NULL, ++ NULL, client, ++ client->sent_options, NULL, + &global_scope, oc, MDL)) { +- result = get_dhcid(&ddns_cb->dhcid, +- DHO_DHCP_CLIENT_IDENTIFIER, +- client_identifier.data, +- client_identifier.len); ++ if ((std_dhcid == 1) && (duid_v4 == 1) && ++ (client_identifier.data[0] == 255)) { ++ /* ++ * This appears to be an embedded DUID, ++ * extract it and treat it as such ++ */ ++ if (client_identifier.len <= 5) ++ log_fatal("Impossible condition at %s:%d.", ++ MDL); ++ result = get_dhcid(ddns_cb, 2, ++ client_identifier.data + 5, ++ client_identifier.len - 5); ++ } else { ++ result = get_dhcid(ddns_cb, ddns_v4_type, ++ client_identifier.data, ++ client_identifier.len); ++ } + data_string_forget(&client_identifier, MDL); + } else +- result = get_dhcid(&ddns_cb->dhcid, 0, ++ result = get_dhcid(ddns_cb, 0, + client->interface->hw_address.hbuf, + client->interface->hw_address.hlen); + } ++ + if (!result) { + return ISC_R_SUCCESS; + } +@@ -4886,3 +4985,4 @@ dhclient_ddns_cb_free(dhcp_ddns_cb_t *ddns_cb, char* file, int line) { + ddns_cb_free(ddns_cb, file, line); + } + } ++ +diff --git a/common/conflex.c b/common/conflex.c +index 4611616..c99732e 100644 +--- a/common/conflex.c ++++ b/common/conflex.c +@@ -879,10 +879,6 @@ intern(char *atom, enum dhcp_token dfv) { + case 'd': + if (!strcasecmp(atom + 1, "b-time-format")) + return DB_TIME_FORMAT; +- if (!strcasecmp (atom + 1, "ns-update")) +- return DNS_UPDATE; +- if (!strcasecmp (atom + 1, "ns-delete")) +- return DNS_DELETE; + if (!strcasecmp (atom + 1, "omain")) + return DOMAIN; + if (!strncasecmp (atom + 1, "omain-", 6)) { +@@ -1178,8 +1174,6 @@ intern(char *atom, enum dhcp_token dfv) { + return TOKEN_NOT; + if (!strcasecmp (atom + 1, "o")) + return TOKEN_NO; +- if (!strcasecmp (atom + 1, "s-update")) +- return NS_UPDATE; + if (!strcasecmp (atom + 1, "oerror")) + return NS_NOERROR; + if (!strcasecmp (atom + 1, "otauth")) +@@ -1496,8 +1490,6 @@ intern(char *atom, enum dhcp_token dfv) { + } + if (!strcasecmp (atom + 1, "nauthenticated")) + return UNAUTHENTICATED; +- if (!strcasecmp (atom + 1, "pdated-dns-rr")) +- return UPDATED_DNS_RR; + if (!strcasecmp (atom + 1, "pdate")) + return UPDATE; + break; +diff --git a/common/dns.c b/common/dns.c +index d3ac966..a04c61d 100644 +--- a/common/dns.c ++++ b/common/dns.c +@@ -30,10 +30,12 @@ + * asynchronous DNS routines. + */ + ++/*! \file common/dns.c ++ */ + #include "dhcpd.h" + #include "arpa/nameser.h" + #include +- ++#include + #include + + /* +@@ -823,45 +825,123 @@ void repudiate_zone (struct dns_zone **zone) + dns_zone_dereference (zone, MDL); + } + +-/* Have to use TXT records for now. */ +-#define T_DHCID T_TXT ++/*! ++ * \brief Create an id for a client ++ * ++ * This function is used to create an id for a client to use with DDNS ++ * This version of the function is for the standard style, RFC 4701 ++ * ++ * This function takes information from the type and data fields and ++ * mangles it into a dhcid string which it places in ddns_cb. It also ++ * sets a field in ddns_cb to specify the class that should be used ++ * when sending the dhcid, in this case it is a DHCID record so we use ++ * dns_rdatatype_dhcid ++ * ++ * The DHCID we construct is: ++ * 2 bytes - identifier type (see 4701 and IANA) ++ * 1 byte - digest type, currently only SHA256 (1) ++ * n bytes - digest, length depends on digest type, currently 32 for ++ * SHA256 ++ * ++ * What we base the digest on is up to the calling code for an id type of ++ * 0 - 1 octet htype followed by hlen octets of chaddr from v4 client request ++ * 1 - data octets from a dhcpv4 client's client identifier option ++ * 2 - the client DUID from a v4 or v6 client's client id option ++ * This identifier is concatenated with the fqdn and the result is digested. ++ */ ++int get_std_dhcid(dhcp_ddns_cb_t *ddns_cb, ++ int type, ++ const u_int8_t *identifier, ++ unsigned id_len) ++{ ++ struct data_string *id = &ddns_cb->dhcid; ++ isc_sha256_t sha256; ++ unsigned char buf[ISC_SHA256_DIGESTLENGTH]; ++ unsigned char fwd_buf[256]; ++ unsigned fwd_buflen = 0; ++ ++ /* Types can only be 0..(2^16)-1. */ ++ if (type < 0 || type > 65535) ++ return (0); ++ ++ /* We need to convert the fwd name to wire representation */ ++ if (MRns_name_pton((char *)ddns_cb->fwd_name.data, fwd_buf, 256) == -1) ++ return (0); ++ while(fwd_buf[fwd_buflen] != 0) { ++ fwd_buflen += fwd_buf[fwd_buflen] + 1; ++ } ++ fwd_buflen++; ++ ++ if (!buffer_allocate(&id->buffer, ++ ISC_SHA256_DIGESTLENGTH + 2 + 1, ++ MDL)) ++ return (0); ++ id->data = id->buffer->data; ++ ++ /* The two first bytes contain the type identifier. */ ++ putUShort(id->buffer->data, (unsigned)type); ++ ++ /* The next is the digest type, SHA-256 is 1 */ ++ putUChar(id->buffer->data + 2, 1u); ++ ++ /* Computing the digest */ ++ isc_sha256_init(&sha256); ++ isc_sha256_update(&sha256, identifier, id_len); ++ isc_sha256_update(&sha256, fwd_buf, fwd_buflen); ++ isc_sha256_final(buf, &sha256); + +-int get_dhcid (struct data_string *id, +- int type, const u_int8_t *data, unsigned len) ++ memcpy(id->buffer->data + 3, &buf, ISC_SHA256_DIGESTLENGTH); ++ ++ id->len = ISC_SHA256_DIGESTLENGTH + 2 + 1; ++ ++ return (1); ++} ++ ++/*! ++ * ++ * \brief Create an id for a client ++ * ++ * This function is used to create an id for a client to use with DDNS ++ * This version of the function is for the interim style. It is retained ++ * to allow users to continue using the interim style but they should ++ * switch to the standard style (which uses get_std_dhcid) for better ++ * interoperability. ++ * ++ * This function takes information from the type and data fields and ++ * mangles it into a dhcid string which it places in ddns_cb. It also ++ * sets a field in ddns_cb to specify the class that should be used ++ * when sending the dhcid, in this case it is a txt record so we use ++ * dns_rdata_type_txt ++ * ++ * NOTE WELL: this function has issues with how it calculates the ++ * dhcid, they can't be changed now as that would break the records ++ * already in use. ++ */ ++ ++int get_int_dhcid (dhcp_ddns_cb_t *ddns_cb, ++ int type, ++ const u_int8_t *data, ++ unsigned len) + { ++ struct data_string *id = &ddns_cb->dhcid; + unsigned char buf[ISC_MD5_DIGESTLENGTH]; + isc_md5_t md5; + int i; + + /* Types can only be 0..(2^16)-1. */ + if (type < 0 || type > 65535) +- return 0; ++ return (0); + + /* + * Hexadecimal MD5 digest plus two byte type, NUL, + * and one byte for length for dns. + */ +- if (!buffer_allocate (&id -> buffer, +- (ISC_MD5_DIGESTLENGTH * 2) + 4, MDL)) +- return 0; +- id -> data = id -> buffer -> data; ++ if (!buffer_allocate(&id -> buffer, ++ (ISC_MD5_DIGESTLENGTH * 2) + 4, MDL)) ++ return (0); ++ id->data = id->buffer->data; + + /* +- * 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 +- * + * We put the length into the first byte to turn + * this into a dns text string. This avoid needing to + * copy the string to add the byte later. +@@ -893,7 +973,18 @@ int get_dhcid (struct data_string *id, + id->buffer->data[id->len] = 0; + id->terminated = 1; + +- return 1; ++ return (1); ++} ++ ++int get_dhcid(dhcp_ddns_cb_t *ddns_cb, ++ int type, ++ const u_int8_t *identifier, ++ unsigned id_len) ++{ ++ if (ddns_cb->dhcid_class == dns_rdatatype_dhcid) ++ return get_std_dhcid(ddns_cb, type, identifier, id_len); ++ else ++ return get_int_dhcid(ddns_cb, type, identifier, id_len); + } + + /* +@@ -1015,12 +1106,12 @@ make_dns_dataset(dns_rdataclass_t dataclass, + * For the server the first step will have a request of: + * The name is not in use + * Add an A RR +- * Add a DHCID RR (currently txt) ++ * Add a DHCID RR + * + * For the client the first step will have a request of: + * The A RR does not exist + * Add an A RR +- * Add a DHCID RR (currently txt) ++ * Add a DHCID RR + */ + + static isc_result_t +@@ -1062,7 +1153,7 @@ ddns_modify_fwd_add1(dhcp_ddns_cb_t *ddns_cb, + dataspace++; + + /* Add the DHCID RR */ +- result = make_dns_dataset(dns_rdataclass_in, dns_rdatatype_txt, ++ result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class, + dataspace, + (unsigned char *)ddns_cb->dhcid.data, + ddns_cb->dhcid.len, ddns_cb->ttl); +@@ -1108,7 +1199,7 @@ ddns_modify_fwd_add2(dhcp_ddns_cb_t *ddns_cb, + dns_name_t *pname, + dns_name_t *uname) + { +- isc_result_t result; ++ isc_result_t result = ISC_R_SUCCESS; + + /* + * If we are doing conflict resolution (unset) we use a prereq list. +@@ -1117,7 +1208,7 @@ ddns_modify_fwd_add2(dhcp_ddns_cb_t *ddns_cb, + if ((ddns_cb->flags & DDNS_CONFLICT_OVERRIDE) == 0) { + /* Construct the prereq list */ + /* The DHCID RR exists and matches the client identity */ +- result = make_dns_dataset(dns_rdataclass_in, dns_rdatatype_txt, ++ result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class, + dataspace, + (unsigned char *)ddns_cb->dhcid.data, + ddns_cb->dhcid.len, 0); +@@ -1130,7 +1221,7 @@ ddns_modify_fwd_add2(dhcp_ddns_cb_t *ddns_cb, + /* Start constructing the update list. + * Conflict detection override: delete DHCID RRs */ + result = make_dns_dataset(dns_rdataclass_any, +- dns_rdatatype_txt, ++ ddns_cb->dhcid_class, + dataspace, NULL, 0, 0); + if (result != ISC_R_SUCCESS) { + return(result); +@@ -1139,7 +1230,7 @@ ddns_modify_fwd_add2(dhcp_ddns_cb_t *ddns_cb, + dataspace++; + + /* Add current DHCID RR */ +- result = make_dns_dataset(dns_rdataclass_in, dns_rdatatype_txt, ++ result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class, + dataspace, + (unsigned char *)ddns_cb->dhcid.data, + ddns_cb->dhcid.len, ddns_cb->ttl); +@@ -1201,11 +1292,11 @@ ddns_modify_fwd_rem1(dhcp_ddns_cb_t *ddns_cb, + dns_name_t *pname, + dns_name_t *uname) + { +- isc_result_t result; ++ isc_result_t result = ISC_R_SUCCESS; + + /* Consruct the prereq list */ + /* The DHCID RR exists and matches the client identity */ +- result = make_dns_dataset(dns_rdataclass_in, dns_rdatatype_txt, ++ result = make_dns_dataset(dns_rdataclass_in, ddns_cb->dhcid_class, + dataspace, + (unsigned char *)ddns_cb->dhcid.data, + ddns_cb->dhcid.len, 0); +@@ -1271,7 +1362,7 @@ ddns_modify_fwd_rem2(dhcp_ddns_cb_t *ddns_cb, + + /* Construct the update list */ + /* Delete DHCID RR */ +- result = make_dns_dataset(dns_rdataclass_none, dns_rdatatype_txt, ++ result = make_dns_dataset(dns_rdataclass_none, ddns_cb->dhcid_class, + dataspace, + (unsigned char *)ddns_cb->dhcid.data, + ddns_cb->dhcid.len, 0); +diff --git a/common/parse.c b/common/parse.c +index fc51327..7477543 100644 +--- a/common/parse.c ++++ b/common/parse.c +@@ -3558,42 +3558,7 @@ int parse_numeric_expression (expr, cfile, lose) + } + return 1; + } +-#if defined (NSUPDATE_OLD) +-/* +- * dns-expression :== +- * UPDATE LPAREN ns-class COMMA ns-type COMMA data-expression COMMA +- * data-expression COMMA numeric-expression RPAREN +- * DELETE LPAREN ns-class COMMA ns-type COMMA data-expression COMMA +- * data-expression RPAREN +- * EXISTS LPAREN ns-class COMMA ns-type COMMA data-expression COMMA +- * data-expression RPAREN +- * NOT EXISTS LPAREN ns-class COMMA ns-type COMMA data-expression COMMA +- * data-expression RPAREN +- * ns-class :== IN | CHAOS | HS | NUMBER +- * ns-type :== A | PTR | MX | TXT | NUMBER +- */ +- +-int parse_dns_expression (expr, cfile, lose) +- struct expression **expr; +- struct parse *cfile; +- int *lose; +-{ +- /* Parse an expression... */ +- if (!parse_expression (expr, cfile, lose, context_dns, +- (struct expression **)0, expr_none)) +- return 0; + +- if (!is_dns_expression (*expr) && +- (*expr) -> op != expr_variable_reference && +- (*expr) -> op != expr_funcall) { +- expression_dereference (expr, MDL); +- parse_warn (cfile, "Expecting a dns update subexpression."); +- *lose = 1; +- return 0; +- } +- return 1; +-} +-#endif /* NSUPDATE_OLD */ + /* Parse a subexpression that does not contain a binary operator. */ + + int parse_non_binary (expr, cfile, lose, context) +@@ -3608,11 +3573,6 @@ int parse_non_binary (expr, cfile, lose, context) + struct expression *nexp, **ep; + int known; + char *cptr; +-#if defined (NSUPDATE_OLD) +- enum expr_op opcode; +- const char *s; +- unsigned long u; +-#endif + isc_result_t status; + unsigned len; + +@@ -3645,12 +3605,7 @@ int parse_non_binary (expr, cfile, lose, context) + + case TOKEN_NOT: + token = next_token (&val, (unsigned *)0, cfile); +-#if defined(NSUPDATE_OLD) +- if (context == context_dns) { +- token = peek_token (&val, (unsigned *)0, cfile); +- goto not_exists; +- } +-#endif ++ + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); + (*expr) -> op = expr_not; +@@ -3662,7 +3617,7 @@ int parse_non_binary (expr, cfile, lose, context) + } + *lose = 1; + expression_dereference (expr, MDL); +- return 0; ++ return (0); + } + if (!is_boolean_expression ((*expr) -> data.not)) { + *lose = 1; +@@ -3694,10 +3649,6 @@ int parse_non_binary (expr, cfile, lose, context) + break; + + case EXISTS: +-#if defined(NSUPDATE_OLD) +- if (context == context_dns) +- goto ns_exists; +-#endif + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) + log_fatal ("can't allocate expression"); +@@ -3710,7 +3661,7 @@ int parse_non_binary (expr, cfile, lose, context) + (*expr)->data.option == NULL) { + *lose = 1; + expression_dereference (expr, MDL); +- return 0; ++ return (0); + } + break; + +@@ -4011,285 +3962,7 @@ int parse_non_binary (expr, cfile, lose, context) + goto norparen; + break; + +-#if defined(NSUPDATE_OLD) +- /* dns-update and dns-delete are present for historical +- purposes, but are deprecated in favor of ns-update +- in combination with update, delete, exists and not +- exists. */ +- case DNS_UPDATE: +- case DNS_DELETE: +-#if !defined (NSUPDATE) +- parse_warn (cfile, +- "Please rebuild dhcpd with --with-nsupdate."); +-#endif +- token = next_token (&val, (unsigned *)0, cfile); +- if (token == DNS_UPDATE) +- opcode = expr_ns_add; +- else +- opcode = expr_ns_delete; +- +- token = next_token (&val, (unsigned *)0, cfile); +- if (token != LPAREN) +- goto nolparen; +- +- token = next_token (&val, (unsigned *)0, cfile); +- if (token != STRING) { +- parse_warn (cfile, +- "parse_expression: expecting string."); +- badnsupdate: +- skip_to_semi (cfile); +- *lose = 1; +- return 0; +- } +- +- if (!strcasecmp (val, "a")) +- u = T_A; +- else if (!strcasecmp (val, "aaaa")) +- u = T_AAAA; +- else if (!strcasecmp (val, "ptr")) +- u = T_PTR; +- else if (!strcasecmp (val, "mx")) +- u = T_MX; +- else if (!strcasecmp (val, "cname")) +- u = T_CNAME; +- else if (!strcasecmp (val, "TXT")) +- u = T_TXT; +- else { +- parse_warn (cfile, "unexpected rrtype: %s", val); +- goto badnsupdate; +- } +- +- s = (opcode == expr_ns_add +- ? "old-dns-update" +- : "old-dns-delete"); +- cptr = dmalloc (strlen (s) + 1, MDL); +- if (!cptr) +- log_fatal ("can't allocate name for %s", s); +- strcpy (cptr, s); +- if (!expression_allocate (expr, MDL)) +- log_fatal ("can't allocate expression"); +- (*expr) -> op = expr_funcall; +- (*expr) -> data.funcall.name = cptr; +- +- /* Fake up a function call. */ +- ep = &(*expr) -> data.funcall.arglist; +- if (!expression_allocate (ep, MDL)) +- log_fatal ("can't allocate expression"); +- (*ep) -> op = expr_arg; +- if (!make_const_int (&(*ep) -> data.arg.val, u)) +- log_fatal ("can't allocate rrtype value."); +- +- token = next_token (&val, (unsigned *)0, cfile); +- if (token != COMMA) +- goto nocomma; +- ep = &((*ep) -> data.arg.next); +- if (!expression_allocate (ep, MDL)) +- log_fatal ("can't allocate expression"); +- (*ep) -> op = expr_arg; +- if (!(parse_data_expression (&(*ep) -> data.arg.val, +- cfile, lose))) +- goto nodata; +- +- token = next_token (&val, (unsigned *)0, cfile); +- if (token != COMMA) +- goto nocomma; +- +- ep = &((*ep) -> data.arg.next); +- if (!expression_allocate (ep, MDL)) +- log_fatal ("can't allocate expression"); +- (*ep) -> op = expr_arg; +- if (!(parse_data_expression (&(*ep) -> data.arg.val, +- cfile, lose))) +- goto nodata; +- +- if (opcode == expr_ns_add) { +- token = next_token (&val, (unsigned *)0, cfile); +- if (token != COMMA) +- goto nocomma; +- +- ep = &((*ep) -> data.arg.next); +- if (!expression_allocate (ep, MDL)) +- log_fatal ("can't allocate expression"); +- (*ep) -> op = expr_arg; +- if (!(parse_numeric_expression (&(*ep) -> data.arg.val, +- cfile, lose))) { +- parse_warn (cfile, +- "expecting numeric expression."); +- goto badnsupdate; +- } +- } +- +- token = next_token (&val, (unsigned *)0, cfile); +- if (token != RPAREN) +- goto norparen; +- break; +- +- case NS_UPDATE: +-#if !defined (NSUPDATE) +- parse_warn (cfile, +- "Please rebuild dhcpd with --with-nsupdate."); +-#endif +- token = next_token (&val, (unsigned *)0, cfile); +- if (!expression_allocate (expr, MDL)) +- log_fatal ("can't allocate expression"); +- +- token = next_token (&val, (unsigned *)0, cfile); +- if (token != LPAREN) +- goto nolparen; +- +- nexp = *expr; +- do { +- nexp -> op = expr_dns_transaction; +- if (!(parse_dns_expression +- (&nexp -> data.dns_transaction.car, +- cfile, lose))) +- { +- if (!*lose) +- parse_warn +- (cfile, +- "expecting dns expression."); +- expression_dereference (expr, MDL); +- *lose = 1; +- return 0; +- } +- +- token = next_token (&val, (unsigned *)0, cfile); +- +- if (token == COMMA) { +- if (!(expression_allocate +- (&nexp -> data.dns_transaction.cdr, +- MDL))) +- log_fatal +- ("can't allocate expression"); +- nexp = nexp -> data.dns_transaction.cdr; +- } +- } while (token == COMMA); +- +- if (token != RPAREN) +- goto norparen; +- break; +- +- /* NOT EXISTS is special cased above... */ +- not_exists: +- token = peek_token (&val, (unsigned *)0, cfile); +- if (token != EXISTS) { +- parse_warn (cfile, "expecting DNS prerequisite."); +- *lose = 1; +- return 0; +- } +- opcode = expr_ns_not_exists; +- goto nsupdatecode; +- case TOKEN_ADD: +- opcode = expr_ns_add; +- goto nsupdatecode; +- case TOKEN_DELETE: +- opcode = expr_ns_delete; +- goto nsupdatecode; +- ns_exists: +- opcode = expr_ns_exists; +- nsupdatecode: +- token = next_token (&val, (unsigned *)0, cfile); +- +-#if !defined (NSUPDATE) +- parse_warn (cfile, +- "Please rebuild dhcpd with --with-nsupdate."); +-#endif +- if (!expression_allocate (expr, MDL)) +- log_fatal ("can't allocate expression"); +- (*expr) -> op = opcode; +- +- token = next_token (&val, (unsigned *)0, cfile); +- if (token != LPAREN) +- goto nolparen; +- +- token = next_token (&val, (unsigned *)0, cfile); +- if (!is_identifier (token) && token != NUMBER) { +- parse_warn (cfile, "expecting identifier or number."); +- badnsop: +- expression_dereference (expr, MDL); +- skip_to_semi (cfile); +- *lose = 1; +- return 0; +- } +- +- if (token == NUMBER) +- (*expr) -> data.ns_add.rrclass = atoi (val); +- else if (!strcasecmp (val, "in")) +- (*expr) -> data.ns_add.rrclass = C_IN; +- else if (!strcasecmp (val, "chaos")) +- (*expr) -> data.ns_add.rrclass = C_CHAOS; +- else if (!strcasecmp (val, "hs")) +- (*expr) -> data.ns_add.rrclass = C_HS; +- else { +- parse_warn (cfile, "unexpected rrclass: %s", val); +- goto badnsop; +- } +- +- token = next_token (&val, (unsigned *)0, cfile); +- if (token != COMMA) +- goto nocomma; + +- token = next_token (&val, (unsigned *)0, cfile); +- if (!is_identifier (token) && token != NUMBER) { +- parse_warn (cfile, "expecting identifier or number."); +- goto badnsop; +- } +- +- if (token == NUMBER) +- (*expr) -> data.ns_add.rrtype = atoi (val); +- else if (!strcasecmp (val, "a")) +- (*expr) -> data.ns_add.rrtype = T_A; +- else if (!strcasecmp (val, "aaaa")) +- (*expr) -> data.ns_add.rrtype = T_AAAA; +- else if (!strcasecmp (val, "ptr")) +- (*expr) -> data.ns_add.rrtype = T_PTR; +- else if (!strcasecmp (val, "mx")) +- (*expr) -> data.ns_add.rrtype = T_MX; +- else if (!strcasecmp (val, "cname")) +- (*expr) -> data.ns_add.rrtype = T_CNAME; +- else if (!strcasecmp (val, "TXT")) +- (*expr) -> data.ns_add.rrtype = T_TXT; +- else { +- parse_warn (cfile, "unexpected rrtype: %s", val); +- goto badnsop; +- } +- +- token = next_token (&val, (unsigned *)0, cfile); +- if (token != COMMA) +- goto nocomma; +- +- if (!(parse_data_expression +- (&(*expr) -> data.ns_add.rrname, cfile, lose))) +- goto nodata; +- +- token = next_token (&val, (unsigned *)0, cfile); +- if (token != COMMA) +- goto nocomma; +- +- if (!(parse_data_expression +- (&(*expr) -> data.ns_add.rrdata, cfile, lose))) +- goto nodata; +- +- if (opcode == expr_ns_add) { +- token = next_token (&val, (unsigned *)0, cfile); +- if (token != COMMA) +- goto nocomma; +- +- if (!(parse_numeric_expression +- (&(*expr) -> data.ns_add.ttl, cfile, +- lose))) { +- if (!*lose) +- parse_warn (cfile, +- "expecting numeric expression."); +- goto badnsupdate; +- } +- } +- +- token = next_token (&val, (unsigned *)0, cfile); +- if (token != RPAREN) +- goto norparen; +- break; +-#endif /* NSUPDATE_OLD */ + case OPTION: + case CONFIG_OPTION: + if (!expression_allocate (expr, MDL)) +@@ -4366,44 +4039,7 @@ int parse_non_binary (expr, cfile, lose, context) + (*expr) -> op = expr_host_decl_name; + break; + +-#if defined(NSUPDATE_OLD) +- case UPDATED_DNS_RR: +- token = next_token (&val, (unsigned *)0, cfile); +- +- token = next_token (&val, (unsigned *)0, cfile); +- if (token != LPAREN) +- goto nolparen; + +- token = next_token (&val, (unsigned *)0, cfile); +- if (token != STRING) { +- parse_warn (cfile, "expecting string."); +- bad_rrtype: +- *lose = 1; +- return 0; +- } +- if (!strcasecmp (val, "a")) +- s = "ddns-fwd-name"; +- else if (!strcasecmp (val, "ptr")) +- s = "ddns-rev-name"; +- else { +- parse_warn (cfile, "invalid DNS rrtype: %s", val); +- goto bad_rrtype; +- } +- +- token = next_token (&val, (unsigned *)0, cfile); +- if (token != RPAREN) +- goto norparen; +- +- if (!expression_allocate (expr, MDL)) +- log_fatal ("can't allocate expression"); +- (*expr) -> op = expr_variable_reference; +- (*expr) -> data.variable = +- dmalloc (strlen (s) + 1, MDL); +- if (!(*expr) -> data.variable) +- log_fatal ("can't allocate variable name."); +- strcpy ((*expr) -> data.variable, s); +- break; +-#endif /* NSUPDATE_OLD */ + case PACKET: + token = next_token (&val, (unsigned *)0, cfile); + if (!expression_allocate (expr, MDL)) +diff --git a/common/tree.c b/common/tree.c +index 8c2056c..26e0add 100644 +--- a/common/tree.c ++++ b/common/tree.c +@@ -645,15 +645,6 @@ int evaluate_expression (result, packet, lease, client_state, + status = (evaluate_data_expression + (&bv -> value.data, packet, lease, client_state, + in_options, cfg_options, scope, expr, MDL)); +-#if defined (NSUPDATE_OLD) +- } else if (is_dns_expression (expr)) { +- if (!binding_value_allocate (&bv, MDL)) +- return 0; +- bv -> type = binding_dns; +- status = (evaluate_dns_expression +- (&bv -> value.dns, packet, lease, client_state, +- in_options, cfg_options, scope, expr)); +-#endif + } else { + log_error ("%s: invalid expression type: %d", + "evaluate_expression", expr -> op); +@@ -699,19 +690,6 @@ int binding_value_dereference (struct binding_value **v, + if (bv -> value.data.buffer) + data_string_forget (&bv -> value.data, file, line); + break; +- case binding_dns: +-#if defined (NSUPDATE_OLD) +- if (bv -> value.dns) { +- if (bv -> value.dns -> r_data) { +- dfree (bv -> value.dns -> r_data_ephem, MDL); +- bv -> value.dns -> r_data = (unsigned char *)0; +- bv -> value.dns -> r_data_ephem = +- (unsigned char *)0; +- } +- minires_freeupdrec (bv -> value.dns); +- } +- break; +-#endif + default: + log_error ("%s(%d): invalid binding type: %d", + file, line, bv -> type); +@@ -721,270 +699,6 @@ int binding_value_dereference (struct binding_value **v, + return 1; + } + +-#if defined (NSUPDATE_OLD) +-int evaluate_dns_expression (result, packet, lease, client_state, in_options, +- cfg_options, scope, expr) +- ns_updrec **result; +- struct packet *packet; +- struct lease *lease; +- struct client_state *client_state; +- struct option_state *in_options; +- struct option_state *cfg_options; +- struct binding_scope **scope; +- struct expression *expr; +-{ +- unsigned long ttl = 0; +- char *tname; +- struct data_string name, data; +- int r0, r1, r2; +- +- if (!result || *result) { +- log_error ("evaluate_dns_expression called with non-null %s", +- "result pointer"); +-#if defined (POINTER_DEBUG) +- abort (); +-#else +- return 0; +-#endif +- } +- +- switch (expr -> op) { +-#if defined (NSUPDATE) +- case expr_ns_add: +- r0 = evaluate_numeric_expression (&ttl, packet, lease, +- client_state, +- in_options, cfg_options, +- scope, +- expr -> data.ns_add.ttl); +- goto nsfinish; +- +- case expr_ns_exists: +- ttl = 1; +- +- case expr_ns_delete: +- case expr_ns_not_exists: +- r0 = 1; +- nsfinish: +- memset (&name, 0, sizeof name); +- r1 = evaluate_data_expression (&name, packet, lease, +- client_state, +- in_options, cfg_options, scope, +- expr -> data.ns_add.rrname, +- MDL); +- if (r1) { +- /* The result of the evaluation may or may not +- be NUL-terminated, but we need it +- terminated for sure, so we have to allocate +- a buffer and terminate it. */ +- tname = dmalloc (name.len + 1, MDL); +- if (!tname) { +- r2 = 0; +- r1 = 0; +- data_string_forget (&name, MDL); +- } else { +- memcpy (tname, name.data, name.len); +- tname [name.len] = 0; +- memset (&data, 0, sizeof data); +- r2 = evaluate_data_expression +- (&data, packet, lease, client_state, +- in_options, cfg_options, scope, +- expr -> data.ns_add.rrdata, MDL); +- } +- } else { +- r2 = 0; +- tname = NULL; +- } +- if (r0 && r1 && (r2 || expr -> op != expr_ns_add)) { +- *result = minires_mkupdrec (((expr -> op == expr_ns_add || +- expr -> op == expr_ns_delete) +- ? S_UPDATE : S_PREREQ), +- tname, +- expr -> data.ns_add.rrclass, +- expr -> data.ns_add.rrtype, +- ttl); +- if (!*result) { +- ngood: +- if (r2) { +- data_string_forget (&data, MDL); +- r2 = 0; +- } +- } else { +- if (data.len) { +- /* As a special case, if we get exactly +- four bytes of data, it's an IP address +- represented as a 32-bit quantity, which +- is actually what we *should* be getting +- here. Because res_mkupdrec is currently +- broken and expects a dotted quad, convert +- it. This should be fixed when the new +- resolver is merged. */ +- if (data.len == 4) { +- (*result) -> r_data_ephem = +- dmalloc (16, MDL); +- if (!(*result) -> r_data_ephem) +- goto dpngood; +- (*result) -> r_data = +- (*result) -> r_data_ephem; +- /*%Audit% 16 bytes max. %2004.06.17,Safe%*/ +- sprintf ((char *)(*result) -> r_data_ephem, +- "%u.%u.%u.%u", +- data.data [0] & 0xff, +- data.data [1] & 0xff, +- data.data [2] & 0xff, +- data.data [3] & 0xff); +- (*result) -> r_size = +- strlen ((const char *) +- (*result) -> r_data); +- } else { +- (*result) -> r_size = data.len; +- (*result) -> r_data_ephem = +- dmalloc (data.len, MDL); +- if (!(*result) -> r_data_ephem) { +- dpngood: /* double plus ungood. */ +- minires_freeupdrec (*result); +- *result = 0; +- goto ngood; +- } +- (*result) -> r_data = +- (*result) -> r_data_ephem; +- memcpy ((*result) -> r_data_ephem, +- data.data, data.len); +- } +- } else { +- (*result) -> r_data = 0; +- (*result) -> r_size = 0; +- } +- switch (expr -> op) { +- case expr_ns_add: +- (*result) -> r_opcode = ADD; +- break; +- case expr_ns_delete: +- (*result) -> r_opcode = DELETE; +- break; +- case expr_ns_exists: +- (*result) -> r_opcode = YXRRSET; +- break; +- case expr_ns_not_exists: +- (*result) -> r_opcode = NXRRSET; +- break; +- +- /* Can't happen, but satisfy gcc. */ +- default: +- break; +- } +- } +- } +- if (r1) { +- data_string_forget (&name, MDL); +- dfree (tname, MDL); +- } +- if (r2) +- data_string_forget (&data, MDL); +- /* One flaw in the thinking here: an IP address and an +- ASCII string both look like data expressions, but +- for A records, we want an ASCII string, not a +- binary IP address. Do I need to turn binary IP +- addresses into a separate type? */ +- return (r0 && r1 && +- (r2 || expr -> op != expr_ns_add) && *result); +- +-#else +- case expr_ns_add: +- case expr_ns_delete: +- case expr_ns_exists: +- case expr_ns_not_exists: +- return 0; +-#endif +- case expr_funcall: +- log_error ("%s: dns values for functions not supported.", +- expr -> data.funcall.name); +- break; +- +- case expr_variable_reference: +- log_error ("%s: dns values for variables not supported.", +- expr -> data.variable); +- break; +- +- case expr_check: +- case expr_equal: +- case expr_not_equal: +- case expr_regex_match: +- case expr_iregex_match: +- case expr_and: +- case expr_or: +- case expr_not: +- case expr_match: +- case expr_static: +- case expr_known: +- case expr_exists: +- case expr_variable_exists: +- log_error ("Boolean opcode in evaluate_dns_expression: %d", +- expr -> op); +- return 0; +- +- case expr_none: +- case expr_substring: +- case expr_suffix: +- case expr_lcase: +- case expr_ucase: +- case expr_option: +- case expr_hardware: +- case expr_const_data: +- case expr_packet: +- case expr_concat: +- case expr_encapsulate: +- case expr_host_lookup: +- case expr_encode_int8: +- case expr_encode_int16: +- case expr_encode_int32: +- case expr_binary_to_ascii: +- case expr_reverse: +- case expr_filename: +- case expr_sname: +- case expr_pick_first_value: +- case expr_host_decl_name: +- case expr_config_option: +- case expr_leased_address: +- case expr_null: +- case expr_gethostname: +- log_error ("Data opcode in evaluate_dns_expression: %d", +- expr -> op); +- return 0; +- +- case expr_extract_int8: +- case expr_extract_int16: +- case expr_extract_int32: +- case expr_const_int: +- case expr_lease_time: +- case expr_dns_transaction: +- case expr_add: +- case expr_subtract: +- case expr_multiply: +- case expr_divide: +- case expr_remainder: +- case expr_binary_and: +- case expr_binary_or: +- case expr_binary_xor: +- case expr_client_state: +- log_error ("Numeric opcode in evaluate_dns_expression: %d", +- expr -> op); +- return 0; +- +- case expr_function: +- log_error ("Function opcode in evaluate_dns_expression: %d", +- expr -> op); +- return 0; +- +- case expr_arg: +- break; +- } +- +- log_error ("Bogus opcode in evaluate_dns_expression: %d", +- expr -> op); +- return 0; +-} +-#endif /* defined (NSUPDATE_OLD) */ +- + int evaluate_boolean_expression (result, packet, lease, client_state, + in_options, cfg_options, scope, expr) + int *result; +@@ -1056,20 +770,7 @@ int evaluate_boolean_expression (result, packet, lease, client_state, + else + *result = expr -> op == expr_not_equal; + break; +-#if defined (NSUPDATE_OLD) +- case binding_dns: +-#if defined (NSUPDATE) +- /* XXX This should be a comparison for equal +- XXX values, not for identity. */ +- if (bv -> value.dns == obv -> value.dns) +- *result = expr -> op == expr_equal; +- else +- *result = expr -> op == expr_not_equal; +-#else +- *result = expr -> op == expr_not_equal; +-#endif +- break; +-#endif /* NSUPDATE_OLD */ ++ + case binding_function: + if (bv -> value.fundef == obv -> value.fundef) + *result = expr -> op == expr_equal; +@@ -2369,7 +2070,7 @@ int evaluate_data_expression (result, packet, lease, client_state, + case expr_ns_delete: + case expr_ns_exists: + case expr_ns_not_exists: +- log_error ("dns update opcode in evaluate_data_expression: %d", ++ log_error ("dns opcode in evaluate_boolean_expression: %d", + expr -> op); + return 0; + +@@ -2398,11 +2099,6 @@ int evaluate_numeric_expression (result, packet, lease, client_state, + { + struct data_string data; + int status, sleft, sright; +-#if defined (NSUPDATE_OLD) +- ns_updrec *nut; +- ns_updque uq; +- struct expression *cur, *next; +-#endif + + struct binding *binding; + struct binding_value *bv; +@@ -2541,53 +2237,6 @@ int evaluate_numeric_expression (result, packet, lease, client_state, + #endif + return (1); + +- case expr_dns_transaction: +-#if !defined (NSUPDATE_OLD) +- return 0; +-#else +- if (!resolver_inited) { +- minires_ninit (&resolver_state); +- resolver_inited = 1; +- resolver_state.retrans = 1; +- resolver_state.retry = 1; +- } +- ISC_LIST_INIT (uq); +- cur = expr; +- do { +- next = cur -> data.dns_transaction.cdr; +- nut = 0; +- status = (evaluate_dns_expression +- (&nut, packet, +- lease, client_state, in_options, cfg_options, +- scope, cur -> data.dns_transaction.car)); +- if (!status) +- goto dns_bad; +- ISC_LIST_APPEND (uq, nut, r_link); +- cur = next; +- } while (next); +- +- /* Do the update and record the error code, if there was +- an error; otherwise set it to NOERROR. */ +- *result = minires_nupdate (&resolver_state, +- ISC_LIST_HEAD (uq)); +- status = 1; +- +- print_dns_status ((int)*result, &uq); +- +- dns_bad: +- while (!ISC_LIST_EMPTY (uq)) { +- ns_updrec *tmp = ISC_LIST_HEAD (uq); +- ISC_LIST_UNLINK (uq, tmp, r_link); +- if (tmp -> r_data_ephem) { +- dfree (tmp -> r_data_ephem, MDL); +- tmp -> r_data = (unsigned char *)0; +- tmp -> r_data_ephem = (unsigned char *)0; +- } +- minires_freeupdrec (tmp); +- } +- return status; +-#endif /* NSUPDATE_OLD */ +- + case expr_variable_reference: + if (scope && *scope) { + binding = find_binding (*scope, expr -> data.variable); +@@ -2877,14 +2526,6 @@ int evaluate_numeric_expression (result, packet, lease, client_state, + return 0; + } + +- case expr_ns_add: +- case expr_ns_delete: +- case expr_ns_exists: +- case expr_ns_not_exists: +- log_error ("dns opcode in evaluate_numeric_expression: %d", +- expr -> op); +- return 0; +- + case expr_function: + log_error ("function definition in evaluate_numeric_expr"); + return 0; +@@ -3182,38 +2823,6 @@ void expression_dereference (eptr, file, line) + (&expr -> data.reverse.buffer, file, line); + break; + +- case expr_dns_transaction: +- if (expr -> data.dns_transaction.car) +- expression_dereference (&expr -> data.dns_transaction.car, +- file, line); +- if (expr -> data.dns_transaction.cdr) +- expression_dereference (&expr -> data.dns_transaction.cdr, +- file, line); +- break; +- +- case expr_ns_add: +- if (expr -> data.ns_add.rrname) +- expression_dereference (&expr -> data.ns_add.rrname, +- file, line); +- if (expr -> data.ns_add.rrdata) +- expression_dereference (&expr -> data.ns_add.rrdata, +- file, line); +- if (expr -> data.ns_add.ttl) +- expression_dereference (&expr -> data.ns_add.ttl, +- file, line); +- break; +- +- case expr_ns_delete: +- case expr_ns_exists: +- case expr_ns_not_exists: +- if (expr -> data.ns_delete.rrname) +- expression_dereference (&expr -> data.ns_delete.rrname, +- file, line); +- if (expr -> data.ns_delete.rrdata) +- expression_dereference (&expr -> data.ns_delete.rrdata, +- file, line); +- break; +- + case expr_variable_reference: + case expr_variable_exists: + if (expr -> data.variable) +@@ -3262,15 +2871,6 @@ void expression_dereference (eptr, file, line) + free_expression (expr, MDL); + } + +-int is_dns_expression (expr) +- struct expression *expr; +-{ +- return (expr -> op == expr_ns_add || +- expr -> op == expr_ns_delete || +- expr -> op == expr_ns_exists || +- expr -> op == expr_ns_not_exists); +-} +- + int is_boolean_expression (expr) + struct expression *expr; + { +@@ -3325,7 +2925,6 @@ int is_numeric_expression (expr) + expr -> op == expr_extract_int32 || + expr -> op == expr_const_int || + expr -> op == expr_lease_time || +- expr -> op == expr_dns_transaction || + expr -> op == expr_add || + expr -> op == expr_subtract || + expr -> op == expr_multiply || +@@ -3340,11 +2939,7 @@ int is_numeric_expression (expr) + int is_compound_expression (expr) + struct expression *expr; + { +- return (expr -> op == expr_ns_add || +- expr -> op == expr_ns_delete || +- expr -> op == expr_ns_exists || +- expr -> op == expr_ns_not_exists || +- expr -> op == expr_substring || ++ return (expr -> op == expr_substring || + expr -> op == expr_suffix || + expr -> op == expr_option || + expr -> op == expr_concat || +@@ -3357,8 +2952,7 @@ int is_compound_expression (expr) + expr -> op == expr_config_option || + expr -> op == expr_extract_int8 || + expr -> op == expr_extract_int16 || +- expr -> op == expr_extract_int32 || +- expr -> op == expr_dns_transaction); ++ expr -> op == expr_extract_int32); + } + + static int op_val (enum expr_op); +@@ -3456,8 +3050,6 @@ enum expression_context expression_context (struct expression *expr) + return context_numeric; + if (is_boolean_expression (expr)) + return context_boolean; +- if (is_dns_expression (expr)) +- return context_dns; + return context_any; + } + +@@ -3928,99 +3520,6 @@ int write_expression (file, expr, col, indent, firstp) + "lease-time"); + break; + +- case expr_dns_transaction: +- col = token_print_indent (file, col, indent, "", "", +- "ns-update"); +- col = token_print_indent (file, col, indent, " ", "", +- "("); +- scol = 0; +- for (e = expr; +- e && e -> op == expr_dns_transaction; +- e = e -> data.dns_transaction.cdr) { +- if (!scol) { +- scol = col; +- firstp = 1; +- } else +- firstp = 0; +- col = write_expression (file, +- e -> data.dns_transaction.car, +- col, scol, firstp); +- if (e -> data.dns_transaction.cdr) +- col = token_print_indent (file, col, scol, +- "", " ", ","); +- } +- if (e) +- col = write_expression (file, e, col, scol, 0); +- col = token_print_indent (file, col, indent, "", "", ")"); +- break; +- +- case expr_ns_add: +- col = token_print_indent (file, col, indent, "", "", +- "update"); +- col = token_print_indent (file, col, indent, " ", "", +- "("); +- scol = col; +- sprintf (obuf, "%d", expr -> data.ns_add.rrclass); +- col = token_print_indent (file, col, scol, "", "", obuf); +- col = token_print_indent (file, col, scol, "", " ", +- ","); +- sprintf (obuf, "%d", expr -> data.ns_add.rrtype); +- col = token_print_indent (file, col, scol, "", "", obuf); +- col = token_print_indent (file, col, scol, "", " ", +- ","); +- col = write_expression (file, expr -> data.ns_add.rrname, +- col, scol, 0); +- col = token_print_indent (file, col, scol, "", " ", +- ","); +- col = write_expression (file, expr -> data.ns_add.rrdata, +- col, scol, 0); +- col = token_print_indent (file, col, scol, "", " ", +- ","); +- col = write_expression (file, expr -> data.ns_add.ttl, +- col, scol, 0); +- col = token_print_indent (file, col, indent, "", "", +- ")"); +- break; +- +- case expr_ns_delete: +- col = token_print_indent (file, col, indent, "", "", +- "delete"); +- col = token_print_indent (file, col, indent, " ", "", +- "("); +- finish_ns_small: +- scol = col; +- sprintf (obuf, "%d", expr -> data.ns_add.rrclass); +- col = token_print_indent (file, col, scol, "", "", obuf); +- col = token_print_indent (file, col, scol, "", " ", +- ","); +- sprintf (obuf, "%d", expr -> data.ns_add.rrtype); +- col = token_print_indent (file, col, scol, "", "", obuf); +- col = token_print_indent (file, col, scol, "", " ", +- ","); +- col = write_expression (file, expr -> data.ns_add.rrname, +- col, scol, 0); +- col = token_print_indent (file, col, scol, "", " ", +- ","); +- col = write_expression (file, expr -> data.ns_add.rrdata, +- col, scol, 0); +- col = token_print_indent (file, col, indent, "", "", +- ")"); +- break; +- +- case expr_ns_exists: +- col = token_print_indent (file, col, indent, "", "", +- "exists"); +- col = token_print_indent (file, col, indent, " ", "", +- "("); +- goto finish_ns_small; +- +- case expr_ns_not_exists: +- col = token_print_indent (file, col, indent, "", "", +- "not exists"); +- col = token_print_indent (file, col, indent, " ", "", +- "("); +- goto finish_ns_small; +- + case expr_static: + col = token_print_indent (file, col, indent, "", "", + "static"); +@@ -4293,12 +3792,7 @@ int data_subexpression_length (int *rv, + case expr_const_int: + case expr_exists: + case expr_known: +- case expr_dns_transaction: + case expr_static: +- case expr_ns_add: +- case expr_ns_delete: +- case expr_ns_exists: +- case expr_ns_not_exists: + case expr_not_equal: + case expr_null: + case expr_variable_exists: +@@ -4349,12 +3843,6 @@ int expr_valid_for_context (struct expression *expr, + return 1; + return 0; + +- case context_dns: +- if (is_dns_expression (expr)) { +- return 1; +- } +- return 0; +- + case context_data_or_numeric: + if (is_numeric_expression (expr) || + is_data_expression (expr)) { +diff --git a/includes/dhcpd.h b/includes/dhcpd.h +index 1d2bf2c..7e756e0 100644 +--- a/includes/dhcpd.h ++++ b/includes/dhcpd.h +@@ -638,6 +638,7 @@ struct lease_state { + #define DDNS_UPDATE_STYLE_NONE 0 + #define DDNS_UPDATE_STYLE_AD_HOC 1 + #define DDNS_UPDATE_STYLE_INTERIM 2 ++#define DDNS_UPDATE_STYLE_STANDARD 3 + + /* Server option names. */ + +@@ -1627,6 +1628,9 @@ typedef struct dhcp_ddns_cb { + + void *transaction; + void *dataspace; ++ ++ dns_rdataclass_t dhcid_class; ++ char *lease_tag; + } dhcp_ddns_cb_t; + + extern struct ipv6_pool **pools; +@@ -2047,11 +2051,6 @@ struct expression *parse_domain_list(struct parse *cfile, int); + + + /* tree.c */ +-#if defined (NSUPDATE) +-extern struct __res_state resolver_state; +-extern int resolver_inited; +-#endif +- + extern struct binding_scope *global_scope; + pair cons (caddr_t, pair); + int make_const_option_cache (struct option_cache **, struct buffer **, +@@ -2079,15 +2078,6 @@ int evaluate_expression (struct binding_value **, struct packet *, + struct binding_scope **, struct expression *, + const char *, int); + int binding_value_dereference (struct binding_value **, const char *, int); +-#if defined (NSUPDATE_OLD) +-int evaluate_dns_expression (ns_updrec **, struct packet *, +- struct lease *, +- struct client_state *, +- struct option_state *, +- struct option_state *, +- struct binding_scope **, +- struct expression *); +-#endif + int evaluate_boolean_expression (int *, + struct packet *, struct lease *, + struct client_state *, +@@ -2913,21 +2903,18 @@ int icmp_echorequest (struct iaddr *); + isc_result_t icmp_echoreply (omapi_object_t *); + + /* dns.c */ +-#if defined (NSUPDATE) +-isc_result_t find_tsig_key (ns_tsig_key **, const char *, struct dns_zone *); +-void tkey_free (ns_tsig_key **); +-#endif + isc_result_t enter_dns_zone (struct dns_zone *); + isc_result_t dns_zone_lookup (struct dns_zone **, const char *); + int dns_zone_dereference (struct dns_zone **, const char *, int); + #if defined (NSUPDATE) + #define FIND_FORWARD 0 + #define FIND_REVERSE 1 ++isc_result_t find_tsig_key (ns_tsig_key **, const char *, struct dns_zone *); ++void tkey_free (ns_tsig_key **); + isc_result_t find_cached_zone (dhcp_ddns_cb_t *, int); + void forget_zone (struct dns_zone **); + void repudiate_zone (struct dns_zone **); +-//void cache_found_zone (ns_class, char *, struct in_addr *, int); +-int get_dhcid (struct data_string *, int, const u_int8_t *, unsigned); ++int get_dhcid (dhcp_ddns_cb_t *, int, const u_int8_t *, unsigned); + void dhcid_tolease (struct data_string *, struct data_string *); + isc_result_t dhcid_fromlease (struct data_string *, struct data_string *); + isc_result_t ddns_update_fwd(struct data_string *, struct iaddr, +@@ -2937,6 +2924,16 @@ isc_result_t ddns_remove_fwd(struct data_string *, + struct iaddr, struct data_string *); + #endif /* NSUPDATE */ + ++dhcp_ddns_cb_t *ddns_cb_alloc(const char *file, int line); ++void ddns_cb_free (dhcp_ddns_cb_t *ddns_cb, const char *file, int line); ++void ddns_cb_forget_zone (dhcp_ddns_cb_t *ddns_cb); ++isc_result_t ++ddns_modify_fwd(dhcp_ddns_cb_t *ddns_cb, const char *file, int line); ++isc_result_t ++ddns_modify_ptr(dhcp_ddns_cb_t *ddns_cb, const char *file, int line); ++void ++ddns_cancel(dhcp_ddns_cb_t *ddns_cb, const char *file, int line); ++ + /* resolv.c */ + extern char path_resolv_conf []; + extern struct name_server *name_servers; +@@ -3302,21 +3299,6 @@ void dump_subnets (void); + void free_everything (void); + #endif + +-/* nsupdate.c */ +-char *ddns_rev_name (struct lease *, struct lease_state *, struct packet *); +-char *ddns_fwd_name (struct lease *, struct lease_state *, struct packet *); +-int nsupdateA (const char *, const unsigned char *, u_int32_t, int); +-int nsupdatePTR (const char *, const unsigned char *, u_int32_t, int); +-void nsupdate (struct lease *, struct lease_state *, struct packet *, int); +-int updateA (const struct data_string *, const struct data_string *, +- unsigned int, struct lease *); +-int updatePTR (const struct data_string *, const struct data_string *, +- unsigned int, struct lease *); +-int deleteA (const struct data_string *, const struct data_string *, +- struct lease *); +-int deletePTR (const struct data_string *, const struct data_string *, +- struct lease *); +- + /* failover.c */ + #if defined (FAILOVER_PROTOCOL) + extern dhcp_failover_state_t *failover_states; +@@ -3576,20 +3558,5 @@ void mark_hosts_unavailable(void); + void mark_phosts_unavailable(void); + void mark_interfaces_unavailable(void); + +-dhcp_ddns_cb_t *ddns_cb_alloc(const char *file, int line); +-void ddns_cb_free (dhcp_ddns_cb_t *ddns_cb, const char *file, int line); +-void ddns_cb_forget_zone (dhcp_ddns_cb_t *ddns_cb); +- +-//void *key_from_zone(struct dns_zone *zone); +- +-isc_result_t +-ddns_modify_fwd(dhcp_ddns_cb_t *ddns_cb, const char *file, int line); +- +-isc_result_t +-ddns_modify_ptr(dhcp_ddns_cb_t *ddns_cb, const char *file, int line); +- +-void +-ddns_cancel(dhcp_ddns_cb_t *ddns_cb, const char *file, int line); +- + #define MAX_ADDRESS_STRING_LEN \ + (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")) +diff --git a/includes/dhctoken.h b/includes/dhctoken.h +index 3d9a21d..a75eb97 100644 +--- a/includes/dhctoken.h ++++ b/includes/dhctoken.h +@@ -32,6 +32,11 @@ + * ``http://www.nominum.com''. + */ + ++/* ++ * The following tokens have been deprecated and aren't in use anymore. ++ * They have been left in place to avoid disturbing the code. ++ * DNS_UPDATE, DNS_DELETE, NS_UPDATE, UPDATED_DNS_RR ++ */ + enum dhcp_token { + SEMI = ';', + DOT = '.', +diff --git a/includes/site.h b/includes/site.h +index 8ff2834..1c7ec96 100644 +--- a/includes/site.h ++++ b/includes/site.h +@@ -281,3 +281,17 @@ + limit the number of TCP connections that the server will + allow at one time. A value of 0 means there is no limit.*/ + #define MAX_FD_VALUE 200 ++ ++ ++/* Include code to do a slow transition of DDNS records ++ from the interim to the standard version, or backwards. ++ The normal code will handle removing an old style record ++ when the name on a lease is being changed. This adds code ++ to handle the case where the name isn't being changed but ++ the old record should be removed to allow a new record to ++ be added. This is the slow transition as leases are only ++ updated as a client touches them. A fast transition would ++ entail updating all the records at once, probably at start ++ up. */ ++#define DDNS_UPDATE_SLOW_TRANSITION ++ +diff --git a/includes/tree.h b/includes/tree.h +index 291c0f6..746d31c 100644 +--- a/includes/tree.h ++++ b/includes/tree.h +@@ -116,9 +116,6 @@ struct binding_value { + struct data_string data; + unsigned long intval; + int boolean; +-#if defined (NSUPDATE_OLD) +- ns_updrec *dns; +-#endif + struct fundef *fundef; + struct binding_value *bv; + } value; +diff --git a/server/ddns.c b/server/ddns.c +index 2a64bc9..3cf15ce 100644 +--- a/server/ddns.c ++++ b/server/ddns.c +@@ -36,6 +36,9 @@ + #include "dhcpd.h" + #include + ++char *ddns_standard_tag = "ddns-dhcid"; ++char *ddns_interim_tag = "ddns-txt"; ++ + #ifdef NSUPDATE + + static void ddns_fwd_srv_connector(struct lease *lease, +@@ -71,16 +74,13 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, + struct data_string ddns_domainname; + struct data_string old_ddns_fwd_name; + struct data_string ddns_fwd_name; +- //struct data_string ddns_rev_name; + struct data_string ddns_dhcid; + struct binding_scope **scope = NULL; +- //struct iaddr addr; + struct data_string d1; + struct option_cache *oc; + int s1, s2; + int result = 0; + int server_updates_a = 1; +- //int server_updates_ptr = 1; + struct buffer *bp = (struct buffer *)0; + int ignorep = 0, client_ignorep = 0; + int rev_name_len; +@@ -89,8 +89,9 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, + dhcp_ddns_cb_t *ddns_cb; + int do_remove = 0; + +- if (ddns_update_style != 2) +- return 0; ++ if ((ddns_update_style != DDNS_UPDATE_STYLE_STANDARD) && ++ (ddns_update_style != DDNS_UPDATE_STYLE_INTERIM)) ++ return (0); + + /* + * sigh, I want to cancel any previous udpates before we do anything +@@ -149,7 +150,6 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, + memset (&ddns_domainname, 0, sizeof (ddns_domainname)); + memset (&old_ddns_fwd_name, 0, sizeof (ddns_fwd_name)); + memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name)); +- //memset (&ddns_rev_name, 0, sizeof (ddns_rev_name)); + memset (&ddns_dhcid, 0, sizeof (ddns_dhcid)); + + /* If we are allowed to accept the client's update of its own A +@@ -263,31 +263,22 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, + goto in; + } + +- /* See if there's a DHCID on the lease, and if not +- * then potentially look for 'on events' for ad-hoc ddns. ++#if defined (DDNS_UPDATE_SLOW_TRANSITION) ++ /* ++ * If the slow transition code is enabled check to see ++ * if the stored type (standard or interim doesn't ++ * match the type currently in use. If it doesn't ++ * try to remove and replace the DNS record + */ +- if (!find_bound_string(&ddns_dhcid, *scope, "ddns-txt") && +- (old != NULL)) { +- /* If there's no DHCID, the update was probably +- done with the old-style ad-hoc DDNS updates. +- So if the expiry and release events look like +- they're the same, run them. This should delete +- the old DDNS data. */ +- if (old -> on_expiry == old -> on_release) { +- execute_statements(NULL, NULL, lease, NULL, +- NULL, NULL, scope, +- old->on_expiry); +- if (old -> on_expiry) +- executable_statement_dereference +- (&old -> on_expiry, MDL); +- if (old -> on_release) +- executable_statement_dereference +- (&old -> on_release, MDL); +- /* Now, install the DDNS data the new way. */ +- goto in; +- } +- } else ++ if (((ddns_update_style == DDNS_UPDATE_STYLE_STANDARD) && ++ find_bound_string(&ddns_dhcid, *scope, ddns_interim_tag)) || ++ ((ddns_update_style == DDNS_UPDATE_STYLE_INTERIM) && ++ find_bound_string(&ddns_dhcid, *scope, ddns_standard_tag))) { + data_string_forget(&ddns_dhcid, MDL); ++ do_remove = 1; ++ goto in; ++ } ++#endif + + /* See if the administrator wants to do updates even + in cases where the update already appears to have been +@@ -486,22 +477,68 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, + } + + /* ++ * copy the string now so we can pass it to the dhcid routines ++ * via the ddns_cb pointer ++ */ ++ data_string_copy(&ddns_cb->fwd_name, &ddns_fwd_name, MDL); ++ ++ /* + * If we are updating the A record, compute the DHCID value. ++ * We have two options for computing the DHCID value, the older ++ * interim version and the newer standard version. The interim ++ * has some issues but is left as is to avoid compatibility issues. ++ * ++ * We select the type of DHCID to construct and the information to ++ * use for the digest based on 4701 section 3.3 + */ + if ((ddns_cb->flags & DDNS_UPDATE_ADDR) != 0) { +- if (lease6 != NULL) +- result = get_dhcid(&ddns_cb->dhcid, 2, +- lease6->ia->iaid_duid.data, +- lease6->ia->iaid_duid.len); +- else if ((lease != NULL) && (lease->uid != NULL) && +- (lease->uid_len != 0)) +- result = get_dhcid (&ddns_cb->dhcid, +- DHO_DHCP_CLIENT_IDENTIFIER, +- lease -> uid, lease -> uid_len); +- else if (lease != NULL) +- result = get_dhcid (&ddns_cb->dhcid, 0, +- lease -> hardware_addr.hbuf, +- lease -> hardware_addr.hlen); ++ int ddns_type; ++ int ddns_len; ++ if (ddns_update_style == DDNS_UPDATE_STYLE_STANDARD) { ++ /* The standard style */ ++ ddns_cb->lease_tag = ddns_standard_tag; ++ ddns_cb->dhcid_class = dns_rdatatype_dhcid; ++ ddns_type = 1; ++ ddns_len = 4; ++ } else { ++ /* The older interim style */ ++ ddns_cb->lease_tag = ddns_interim_tag; ++ ddns_cb->dhcid_class = dns_rdatatype_txt; ++ /* for backwards compatibility */ ++ ddns_type = DHO_DHCP_CLIENT_IDENTIFIER; ++ /* IAID incorrectly included */ ++ ddns_len = 0; ++ } ++ ++ ++ if (lease6 != NULL) { ++ if (lease6->ia->iaid_duid.len < ddns_len) ++ goto badfqdn; ++ result = get_dhcid(ddns_cb, 2, ++ lease6->ia->iaid_duid.data + ddns_len, ++ lease6->ia->iaid_duid.len - ddns_len); ++ } else if ((lease != NULL) && ++ (lease->uid != NULL) && ++ (lease->uid_len != 0)) { ++ /* If this is standard check for an RFC 4361 ++ * compliant client identifier ++ */ ++ if ((ddns_update_style == DDNS_UPDATE_STYLE_STANDARD) && ++ (lease->uid[0] == 255)) { ++ if (lease->uid_len < 5) ++ goto badfqdn; ++ result = get_dhcid(ddns_cb, 2, ++ lease->uid + 5, ++ lease->uid_len - 5); ++ } else { ++ result = get_dhcid(ddns_cb, ddns_type, ++ lease->uid, ++ lease->uid_len); ++ } ++ } else if (lease != NULL) ++ result = get_dhcid(ddns_cb, 0, ++ lease->hardware_addr.hbuf, ++ lease->hardware_addr.hlen); + else + log_fatal("Impossible condition at %s:%d.", MDL); + +@@ -513,8 +550,6 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, + * Perform updates. + */ + +- data_string_copy(&ddns_cb->fwd_name, &ddns_fwd_name, MDL); +- + if (ddns_cb->flags && DDNS_UPDATE_ADDR) { + oc = lookup_option(&server_universe, options, + SV_DDNS_CONFLICT_DETECT); +@@ -707,8 +742,6 @@ ddns_updates(struct packet *packet, struct lease *lease, struct lease *old, + data_string_forget(&ddns_domainname, MDL); + data_string_forget(&old_ddns_fwd_name, MDL); + data_string_forget(&ddns_fwd_name, MDL); +- //data_string_forget(&ddns_rev_name, MDL); +- //data_string_forget(&ddns_dhcid, MDL); + if (bp) + buffer_dereference(&bp, MDL); + +@@ -822,18 +855,21 @@ ddns_update_lease_text(dhcp_ddns_cb_t *ddns_cb, + case DDNS_STATE_ADD_FW_NXDOMAIN: + bind_ds_value(scope, "ddns-fwd-name", &ddns_cb->fwd_name); + +- /* convert from dns version to lease version of dhcid */ +- memset(&lease_dhcid, 0, sizeof(lease_dhcid)); +- dhcid_tolease(&ddns_cb->dhcid, &lease_dhcid); +- bind_ds_value(scope, "ddns-txt", &lease_dhcid); +- data_string_forget(&lease_dhcid, MDL); +- ++ if (ddns_cb->lease_tag == ddns_standard_tag) { ++ bind_ds_value(scope, ddns_standard_tag, &ddns_cb->dhcid); ++ } else { ++ /* convert from dns version to lease version of dhcid */ ++ memset(&lease_dhcid, 0, sizeof(lease_dhcid)); ++ dhcid_tolease(&ddns_cb->dhcid, &lease_dhcid); ++ bind_ds_value(scope, ddns_interim_tag, &lease_dhcid); ++ data_string_forget(&lease_dhcid, MDL); ++ } + break; + + case DDNS_STATE_REM_FW_NXRR: + case DDNS_STATE_REM_FW_YXDHCID: + unset(*scope, "ddns-fwd-name"); +- unset(*scope, "ddns-txt"); ++ unset(*scope, ddns_cb->lease_tag); + break; + } + +@@ -1791,7 +1827,8 @@ ddns_removals(struct lease *lease, + if (*scope == NULL) + goto cleanup; + +- if (ddns_update_style != 2) ++ if ((ddns_update_style != DDNS_UPDATE_STYLE_STANDARD) && ++ (ddns_update_style != DDNS_UPDATE_STYLE_INTERIM)) + goto cleanup; + + /* Assume that we are removing both records */ +@@ -1823,15 +1860,22 @@ ddns_removals(struct lease *lease, + } + + /* +- * Find the ptr name and copy it to the control block. If we don't +- * have it this isn't an interim or rfc3??? record so we can't delete ++ * Find the txt or dhcid tag and copy it to the control block. If we don't ++ * have one this isn't an interim or standard record so we can't delete + * the A record using this mechanism but we can delete the ptr record. + * In this case we will attempt to do any requested next step. + */ + memset(&leaseid, 0, sizeof(leaseid)); +- if (!find_bound_string (&leaseid, *scope, "ddns-txt")) { +- ddns_cb->flags &= ~DDNS_UPDATE_ADDR; +- } else { ++ if (find_bound_string (&leaseid, *scope, ddns_standard_tag)) { ++ /* We have a standard tag */ ++ ddns_cb->lease_tag = ddns_standard_tag; ++ ddns_cb->dhcid_class = dns_rdatatype_dhcid; ++ data_string_copy(&ddns_cb->dhcid, &leaseid, MDL); ++ data_string_forget(&leaseid, MDL); ++ } else if (find_bound_string (&leaseid, *scope, ddns_interim_tag)) { ++ /* we have an interim tag */ ++ ddns_cb->lease_tag = ddns_interim_tag; ++ ddns_cb->dhcid_class = dns_rdatatype_txt; + if (dhcid_fromlease(&ddns_cb->dhcid, &leaseid) != + ISC_R_SUCCESS) { + /* We couldn't convert the dhcid from the lease +@@ -1841,7 +1885,9 @@ ddns_removals(struct lease *lease, + ddns_cb->flags &= ~DDNS_UPDATE_ADDR; + } + data_string_forget(&leaseid, MDL); +- } ++ } else { ++ ddns_cb->flags &= ~DDNS_UPDATE_ADDR; ++ } + + /* + * Find the rev name and copy it to the control block. If we don't +@@ -1888,7 +1934,7 @@ ddns_removals(struct lease *lease, + else { + /*remove info from scope */ + unset(*scope, "ddns-fwd-name"); +- unset(*scope, "ddns-txt"); ++ unset(*scope, ddns_cb->lease_tag); + } + } + +diff --git a/server/dhcpd.c b/server/dhcpd.c +index 67fec83..9617d75 100644 +--- a/server/dhcpd.c ++++ b/server/dhcpd.c +@@ -82,86 +82,6 @@ option server.ddns-hostname = \n\ + option server.ddns-domainname = config-option domain-name; \n\ + option server.ddns-rev-domainname = \"in-addr.arpa.\";"; + +-/* This is the old-style name service updater that is executed +- whenever a lease is committed. It does not follow the DHCP-DNS +- draft at all. */ +- +-char old_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\ +-}"; +- + #endif /* NSUPDATE */ + int ddns_update_style; + +@@ -897,9 +817,6 @@ void postconf_initialization (int quiet) + struct option_cache *oc; + char *s; + isc_result_t result; +-#if defined (NSUPDATE) +- struct parse *parse; +-#endif + int tmp; + + /* Now try to get the lease file name. */ +@@ -1160,49 +1077,6 @@ void postconf_initialization (int quiet) + + /* Don't need the options anymore. */ + option_state_dereference (&options, MDL); +- +-#if defined (NSUPDATE) +- /* If old-style ddns updates have been requested, parse the +- old-style ddns updater. */ +- if (ddns_update_style == 1) { +- struct executable_statement **e, *s; +- +- if (root_group -> statements) { +- s = (struct executable_statement *)0; +- if (!executable_statement_allocate (&s, MDL)) +- log_fatal ("no memory for ddns updater"); +- executable_statement_reference +- (&s -> next, root_group -> statements, MDL); +- executable_statement_dereference +- (&root_group -> statements, MDL); +- executable_statement_reference +- (&root_group -> statements, s, MDL); +- s -> op = statements_statement; +- e = &s -> data.statements; +- executable_statement_dereference (&s, MDL); +- } else { +- e = &root_group -> statements; +- } +- +- /* Set up the standard name service updater routine. */ +- parse = NULL; +- result = new_parse(&parse, -1, old_nsupdate, +- sizeof(old_nsupdate) - 1, +- "old name service update routine", 0); +- if (result != ISC_R_SUCCESS) +- log_fatal ("can't begin parsing old ddns updater!"); +- +- if (parse != NULL) { +- tmp = 0; +- if (!(parse_executable_statements(e, parse, &tmp, +- context_any))) { +- end_parse(&parse); +- log_fatal("can't parse standard ddns updater!"); +- } +- } +- end_parse(&parse); +- } +-#endif + } + + void postdb_startup (void) +diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5 +index 74393c2..2351e21 100644 +--- a/server/dhcpd.conf.5 ++++ b/server/dhcpd.conf.5 +@@ -1076,115 +1076,24 @@ the Domain Name System to be updated. These updates are RFC 2136 + compliant so any DNS server supporting RFC 2136 should be able to + accept updates from the DHCP server. + .PP +-Two DNS update schemes are currently implemented, and another is +-planned. The two that are currently implemented are the ad-hoc DNS +-update mode and the interim DHCP-DNS interaction draft update mode. +-In the future we plan to add a third mode which will be the standard +-DNS update method based on the RFCS for DHCP-DNS interaction and DHCID +-The DHCP server must be configured to use one of the two +-currently-supported methods, or not to do dns updates. +-This can be done with the ++There are two DNS schemes implemented. The interim option is ++based on draft revisions of the DDNS documents while the standard ++option is based on the RFCs for DHCP-DNS interaction and DHCIDs. ++A third option, ad-hoc, was deprecated and has now been removed ++from the code base. The DHCP server must be configured to use ++one of the two currently-supported methods, or not to do DNS updates. ++.PP ++New installations should use the standard option. Older ++installations may want to continue using the interim option for ++backwards compatibility with the DNS database until the database ++can be updated. This can be done with the + .I ddns-update-style + configuration parameter. +-.SH THE AD-HOC DNS UPDATE SCHEME +-The ad-hoc Dynamic DNS update scheme is +-.B now deprecated +-and +-.B +-does not work. +-In future releases of the ISC DHCP server, this scheme will not likely be +-available. The interim scheme works, allows for failover, and should now be +-used. The following description is left here for informational purposes +-only. +-.PP +-The ad-hoc Dynamic DNS update scheme implemented in this version of +-the ISC DHCP server is a prototype design, which does not +-have much to do with the standard update method that is being +-standardized in the IETF DHC working group, but rather implements some +-very basic, yet useful, update capabilities. This mode +-.B does not work +-with the +-.I failover protocol +-because it does not account for the possibility of two different DHCP +-servers updating the same set of DNS records. +-.PP +-For the ad-hoc DNS update method, the client's FQDN is derived in two +-parts. First, the hostname is determined. Then, the domain name is +-determined, and appended to the hostname. +-.PP +-The DHCP server determines the client's hostname by first looking for +-a \fIddns-hostname\fR configuration option, and using that if it is +-present. If no such option is present, the server looks for a +-valid hostname in the FQDN option sent by the client. If one is +-found, it is used; otherwise, if the client sent a host-name option, +-that is used. Otherwise, if there is a host declaration that applies +-to the client, the name from that declaration will be used. If none +-of these applies, the server will not have a hostname for the client, +-and will not be able to do a DNS update. +-.PP +-The domain name is determined from the +-.I ddns-domainname +-configuration option. The default configuration for this option is: +-.nf +-.sp 1 +- option server.ddns-domainname = config-option domain-name; +- +-.fi +-So if this configuration option is not configured to a different +-value (over-riding the above default), or if a domain-name option +-has not been configured for the client's scope, then the server will +-not attempt to perform a DNS update. +-.PP +-The client's fully-qualified domain name, derived as we have +-described, is used as the name on which an "A" record will be stored. +-The A record will contain the IP address that the client was assigned +-in its lease. If there is already an A record with the same name in +-the DNS server, no update of either the A or PTR records will occur - +-this prevents a client from claiming that its hostname is the name of +-some network server. For example, if you have a fileserver called +-"fs.sneedville.edu", and the client claims its hostname is "fs", no +-DNS update will be done for that client, and an error message will be +-logged. +-.PP +-If the A record update succeeds, a PTR record update for the assigned +-IP address will be done, pointing to the A record. This update is +-unconditional - it will be done even if another PTR record of the same +-name exists. Since the IP address has been assigned to the DHCP +-server, this should be safe. +-.PP +-Please note that the current implementation assumes clients only have +-a single network interface. A client with two network interfaces +-will see unpredictable behavior. This is considered a bug, and will +-be fixed in a later release. It may be helpful to enable the +-.I one-lease-per-client +-parameter so that roaming clients do not trigger this same behavior. +-.PP +-The DHCP protocol normally involves a four-packet exchange - first the +-client sends a DHCPDISCOVER message, then the server sends a +-DHCPOFFER, then the client sends a DHCPREQUEST, then the server sends +-a DHCPACK. In the current version of the server, the server will do +-a DNS update after it has received the DHCPREQUEST, and before it has +-sent the DHCPACK. It only sends the DNS update if it has not sent +-one for the client's address before, in order to minimize the impact +-on the DHCP server. +-.PP +-When the client's lease expires, the DHCP server (if it is operating +-at the time, or when next it operates) will remove the client's A and +-PTR records from the DNS database. If the client releases its lease +-by sending a DHCPRELEASE message, the server will likewise remove the +-A and PTR records. +-.SH THE INTERIM DNS UPDATE SCHEME +-The interim DNS update scheme operates mostly according to several +-drafts considered by the IETF. While the drafts have since become +-RFCs the code was written before they were finalized and there are +-some differences between our code and the final RFCs. We plan to +-update our code, probably adding a standard DNS update option, at +-some time. The basic framework is similar with the main material +-difference being that a DHCID RR was assigned in the RFCs whereas +-our code continues to use an experimental TXT record. The format +-of the TXT record bears a resemblance to the DHCID RR but it is not +-equivalent (MD5 vs SHA1, field length differences etc). +-The standard RFCs are: ++.SH THE DNS UPDATE SCHEME ++the interim and standard DNS update schemes operate mostly according ++to work from the IETF. The interim version was based on the drafts ++in progress at the time while the standard is based on the completed ++RFCs. The standard RFCs are: + .PP + .nf + .ce 3 +@@ -1202,15 +1111,17 @@ draft-ietf-dhc-fqdn-option-??.txt + draft-ietf-dhc-ddns-resolution-??.txt + .fi + .PP +-Because our implementation is slightly different than the standard, we +-will briefly document the operation of this update style here. ++The basic framework for the two schemes is similar with the main ++material difference being that a DHCID RR is used in the standard ++version while the interim versions uses a TXT RR. The format ++of the TXT record bears a resemblance to the DHCID RR but it is not ++equivalent (MD5 vs SHA2, field length differences etc). + .PP +-The first point to understand about this style of DNS update is that +-unlike the ad-hoc style, the DHCP server does not necessarily ++In these two schemes the DHCP server does not necessarily + always update both the A and the PTR records. The FQDN option + includes a flag which, when sent by the client, indicates that the + client wishes to update its own A record. In that case, the server +-can be configured either to honor the client's intentions or ignore ++can be configured either to honor the client\'s intentions or ignore + them. This is done with the statement \fIallow client-updates;\fR or + the statement \fIignore client-updates;\fR. By default, client + updates are allowed. +@@ -1230,15 +1141,14 @@ IP address, it can update its own A record, assuming that the + "radish.org" DNS server will allow it to do so. + .PP + If the server is configured not to allow client updates, or if the +-client doesn't want to do its own update, the server will simply ++client doesn\'t want to do its own update, the server will simply + choose a name for the client from either the fqdn option (if present) + or the hostname option (if present). It will use its own +-domain name for the client, just as in the ad-hoc update scheme. +-It will then update both the A and PTR record, using the name that it +-chose for the client. If the client sends a fully-qualified domain +-name in the fqdn option, the server uses only the leftmost part of the +-domain name - in the example above, "jschmoe" instead of +-"jschmoe.radish.org". ++domain name for the client. It will then update both the A and PTR ++record, using the name that it chose for the client. If the client ++sends a fully-qualified domain name in the \fBfqdn\fR option, the ++server uses only the leftmost part of the domain name - in the ++example above, "jschmoe" instead of "jschmoe.radish.org". + .PP + Further, if the \fIignore client-updates;\fR directive is used, then + the server will in addition send a response in the DHCP packet, using +@@ -1248,49 +1158,41 @@ response is sent which indicates the client may not perform updates. + .PP + Also, if the + .I use-host-decl-names +-configuration option is enabled, then the host declaration's ++configuration option is enabled, then the host declaration\'s + .I hostname + will be used in place of the + .I hostname + option, and the same rules will apply as described above. + .PP +-The other difference between the ad-hoc scheme and the interim +-scheme is that with the interim scheme, a method is used that +-allows more than one DHCP server to update the DNS database without +-accidentally deleting A records that shouldn't be deleted nor failing +-to add A records that should be added. The scheme works as follows: ++Both the standard and interim options also include a method to ++allow more than one DHCP server to update the DNS database without ++accidentally deleting A records that shouldn\'t be deleted nor failing ++to add A records that should be added. For the standard option the ++method works as follows: + .PP + When the DHCP server issues a client a new lease, it creates a text +-string that is an MD5 hash over the DHCP client's identification (see +-draft-ietf-dnsext-dhcid-rr-??.txt for details). The update adds an A +-record with the name the server chose and a TXT record containing the ++string that is an SHA hash over the DHCP client\'s identification (see ++RFCs 4701 & 4702 for details). The update attempts to add an A ++record with the name the server chose and a DHCID record containing the + hashed identifier string (hashid). If this update succeeds, the + server is done. + .PP + If the update fails because the A record already exists, then the DHCP + server attempts to add the A record with the prerequisite that there +-must be a TXT record in the same name as the new A record, and that +-TXT record's contents must be equal to hashid. If this update ++must be a DHCID record in the same name as the new A record, and that ++DHCID record\'s contents must be equal to hashid. If this update + succeeds, then the client has its A record and PTR record. If it + fails, then the name the client has been assigned (or requested) is in +-use, and can't be used by the client. At this point the DHCP server ++use, and can\'t be used by the client. At this point the DHCP server + gives up trying to do a DNS update for the client until the client + chooses a new name. + .PP +-The interim DNS update scheme is called interim for two reasons. +-First, it does not quite follow the RFCs. The RFCs call for a +-new DHCID RRtype while he interim DNS update scheme uses a TXT record. +-The ddns-resolution draft called for the DHCP server to put a DHCID RR +-on the PTR record, but the \fIinterim\fR update method does not do this. +-In the final RFC this requirement was relaxed such that a server may +-add a DHCID RR to the PTR record. +-.PP +-In addition to these differences, the server also does not update very +-aggressively. Because each DNS update involves a round trip to the +-DNS server, there is a cost associated with doing updates even if they +-do not actually modify the DNS database. So the DHCP server tracks +-whether or not it has updated the record in the past (this information +-is stored on the lease) and does not attempt to update records that it ++The server also does not update very aggressively. Because each ++DNS update involves a round trip to the DNS server, there is a cost ++associated with doing updates even if they do not actually modify ++the DNS database. So the DHCP server tracks whether or not it has ++updated the record in the past (this information is stored on the ++lease) and does not attempt to update records that it + thinks it has already updated. + .PP + This can lead to cases where the DHCP server adds a record, and then +@@ -1299,6 +1201,15 @@ never again updates the DNS because it thinks the data is already + there. In this case the data can be removed from the lease through + operator intervention, and once this has been done, the DNS will be + updated the next time the client renews. ++.PP ++The interim DNS update scheme was written before the RFCs were finalized ++and does not quite follow them. The RFCs call for a new DHCID RRtype ++while he interim DNS update scheme uses a TXT record. In addition ++the ddns-resolution draft called for the DHCP server to put a DHCID RR ++on the PTR record, but the \fIinterim\fR update method does not do this. ++In the final RFC this requirement was relaxed such that a server may ++add a DHCID RR to the PTR record. ++.PP + .SH DYNAMIC DNS UPDATE SECURITY + .PP + When you set your DNS server up to allow updates from the DHCP server, +@@ -1380,24 +1291,15 @@ Also keep in mind that zone names in your DHCP configuration should end in a + configuration, zone names are not encapsulated in quotes where there are in + the DNS configuration. + .PP +-You should choose your own secret key, of course. The ISC BIND 8 and +-9 distributions come with a program for generating secret keys called +-dnssec-keygen. The version that comes with BIND 9 is likely to produce a +-substantially more random key, so we recommend you use that one even +-if you are not using BIND 9 as your DNS server. If you are using BIND 9's ++You should choose your own secret key, of course. The ISC BIND 9 ++distribution comes with a program for generating secret keys called ++dnssec-keygen. If you are using BIND 9\'s + dnssec-keygen, the above key would be created as follows: + .PP + .nf + dnssec-keygen -a HMAC-MD5 -b 128 -n USER DHCP_UPDATER + .fi + .PP +-If you are using the BIND 8 dnskeygen program, the following command will +-generate a key as seen above: +-.PP +-.nf +- dnskeygen -H 128 -u -c -n DHCP_UPDATER +-.fi +-.PP + The key name, algorithm, and secret must match that being used by the DNS + server. The DHCP server currently supports the following algorithms: + .nf +@@ -1451,15 +1353,7 @@ and the expiry event, when the commitment expires. + To declare a set of statements to execute when an event happens, you + must use the \fBon\fR statement, followed by the name of the event, + followed by a series of statements to execute when the event happens, +-enclosed in braces. Events are used to implement DNS +-updates, so you should not define your own event handlers if you are +-using the built-in DNS update mechanism. +-.PP +-The built-in version of the DNS update mechanism is in a text +-string towards the top of server/dhcpd.c. If you want to use events +-for things other than DNS updates, and you also want DNS updates, you +-will have to start out by copying this code into your dhcpd.conf file +-and modifying it. ++enclosed in braces. + .SH REFERENCE: DECLARATIONS + .PP + .B The +@@ -2109,7 +2003,7 @@ The \fIddns-update-style\fR parameter + .PP + The + .I style +-parameter must be one of \fBad-hoc\fR, \fBinterim\fR or \fBnone\fR. ++parameter must be one of \fBstandard\fR, \fBinterim\fR or \fBnone\fR. + The \fIddns-update-style\fR statement is only meaningful in the outer + scope - it is evaluated once after reading the dhcpd.conf file, rather + than each time a client is assigned an IP address, so there is no way +@@ -2186,16 +2080,15 @@ statement + .B do-forward-updates \fIflag\fB;\fR + .PP + The \fIdo-forward-updates\fR statement instructs the DHCP server as +-to whether it should attempt to update a DHCP client's A record ++to whether it should attempt to update a DHCP client\'s A record + when the client acquires or renews a lease. This statement has no +-effect unless DNS updates are enabled and \fBddns-update-style\fR is +-set to \fBinterim\fR. Forward updates are enabled by default. If +-this statement is used to disable forward updates, the DHCP server +-will never attempt to update the client's A record, and will only ever +-attempt to update the client's PTR record if the client supplies an +-FQDN that should be placed in the PTR record using the fqdn option. +-If forward updates are enabled, the DHCP server will still honor the +-setting of the \fBclient-updates\fR flag. ++effect unless DNS updates are enabled. Forward updates are enabled ++by default. If this statement is used to disable forward updates, ++the DHCP server will never attempt to update the client\'s A record, ++and will only ever attempt to update the client\'s PTR record if the ++client supplies an FQDN that should be placed in the PTR record using ++the \fBfqdn\fR option. If forward updates are enabled, the DHCP server ++will still honor the setting of the \fBclient-updates\fR flag. + .RE + .PP + The +@@ -2747,7 +2640,7 @@ on which the request arrived. + The usual case where the + \fIserver-identifier\fR statement needs to be sent is when a physical + interface has more than one IP address, and the one being sent by default +-isn't appropriate for some or all clients served by that interface. ++isn\'t appropriate for some or all clients served by that interface. + Another common case is when an alias is defined for the purpose of + having a consistent IP address for the DHCP server, and it is desired + that the clients use this IP address when contacting the server. +diff --git a/server/stables.c b/server/stables.c +index 6a900c8..8ef8bf2 100644 +--- a/server/stables.c ++++ b/server/stables.c +@@ -3,7 +3,7 @@ + Tables of information only used by server... */ + + /* +- * Copyright (c) 2004-2011 by Internet Systems Consortium, Inc. ("ISC") ++ * Copyright (c) 2004-2011,2013 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 1995-2003 by Internet Software Consortium + * + * Permission to use, copy, modify, and distribute this software for any +@@ -330,6 +330,7 @@ struct enumeration_value ddns_styles_values [] = { + { "none", 0 }, + { "ad-hoc", 1 }, + { "interim", 2 }, ++ { "standard", 3 }, + { (char *)0, 0 } + }; + diff --git a/SPECS/dhcp.spec b/SPECS/dhcp.spec index de80f84..e104c1a 100644 --- a/SPECS/dhcp.spec +++ b/SPECS/dhcp.spec @@ -18,7 +18,7 @@ Summary: Dynamic host configuration protocol software Name: dhcp Version: 4.2.5 -Release: 58%{?dist}.3 +Release: 68%{?dist} # NEVER CHANGE THE EPOCH on this package. The previous maintainer (prior to # dcantrell maintaining the package) made incorrect use of the epoch and # that's why it is at 12 now. It should have never been used, but it was. @@ -97,12 +97,18 @@ Patch61: dhcp-addignore.patch Patch62: dhcp-max-fd-value.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1355827 Patch63: dhcp-4.2.5-rh1355827.patch -Patch64: dhcp-4.2.5-reap_orphan_sockets.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1299562 +# Upstream: ca22af89996483efd820de0084c964fc336ee7c1 +Patch64: dhcp-4.2.5-ddns_port_lazy_init.patch +Patch65: dhcp-4.2.5-additional_hmac_tsig.patch +Patch66: dhcp-4.2.5-standard_ddns.patch +Patch67: dhcp-4.2.5-failover-potential-conflict.patch +Patch68: dhcp-4.2.5-reap_orphan_sockets.patch # CVE-2018-5732 -Patch65: dhcp-4.2.5-options_overflow.patch +Patch69: dhcp-4.2.5-options_overflow.patch # CVE-2018-5733 -Patch66: dhcp-4.2.5-reference_count_overflow.patch -Patch67: dhcp-4.2.5-centos-branding.patch +Patch70: dhcp-4.2.5-reference_count_overflow.patch + BuildRequires: autoconf BuildRequires: automake @@ -413,11 +419,23 @@ rm -rf includes/isc-dhcp # https://bugzilla.redhat.com/show_bug.cgi?id=1355827 %patch63 -p1 -%patch64 -p1 -b .omapi_sd_leak +# https://bugzilla.redhat.com/show_bug.cgi?id=1299562 +%patch64 -p1 -b .ddns_lazy_init + +# https://bugzilla.redhat.com/show_bug.cgi?id=1396985 +%patch65 -p1 -b .hmac_alg + +# https://bugzilla.redhat.com/1394727 +%patch66 -p1 -b .stddns -%patch65 -p1 -b .options_overflow -%patch66 -p1 -b .reference_overflow -%patch67 -p1 +# https://bugzilla.redhat.com/1497630 +%patch67 -p1 -b .failover_conflict + +# https://bugzilla.redhat.com/1519363 +%patch68 -p1 -b .orhan_socketts + +%patch69 -p1 -b .options_overflow +%patch70 -p1 -b .reference_overflow # Update paths in all man pages for page in client/dhclient.conf.5 client/dhclient.leases.5 \ @@ -699,17 +717,32 @@ done %changelog -* Mon Mar 12 2018 CentOS Sources - 4.2.5-58.el7.centos.3 -- Roll in CentOS Branding - * Wed Feb 28 2018 Pavel Zhukov - 12:4.2.5-68 -- Resolves: #1550000 - CVE-2018-5733 Avoid buffer overflow reference counter +- Resolves: #1549999 - CVE-2018-5733 Avoid buffer overflow reference counter + +* Wed Feb 28 2018 Pavel Zhukov - 12:4.2.5-67 +- Resolves #1549998 :CVE-2018-5732 Avoid buffer overflow in options parser + +* Thu Dec 7 2017 Pavel Zhukov - 12:4.2.5-65 +- Resolves: #1519363 - omapi: Close orphaned sockets. + +* Mon Oct 2 2017 Pavel Zhukov - 12:4.2.5-64 +- Resolves: #1497630 - failover hangs with both potential-conflict + +* Wed Sep 20 2017 Pavel Zhukov - 12:4.2.5-63 +- Resolves: #1490782 - Do not override HOSTNAME in client script + +* Wed Aug 30 2017 Pavel Zhukov - 12:4.2.5-62 +- Resolves: #1394727 - Add code to support standard ddns updates + +* Wed Aug 16 2017 Pavel Zhukov - 12:4.2.5-61 +- Resolves: #1396985 - Addes addtional HMAC TSIG algorithms to DDNS -* Wed Feb 28 2018 Pavel Zhukov - 12:4.2.5-58.2 -- Resolves: #1549979 - CVE-2018-5732 Avoid buffer overflow in options parser +* Wed Aug 16 2017 Pavel Zhukov - 12:4.2.5-60 +- Resolves: #1299562 - listen on DDNS port on demand only -* Wed Dec 13 2017 Pavel Zhukov - 12:4.2.5-58.1 -- Resolves: #1523475 - Fix omapi socket descriptors leak +* Wed Aug 16 2017 Pavel Zhukov - 12:4.2.5-59 +- Resolves: 1363791 - dhclient update routing table after the lease expiry * Tue May 16 2017 Pavel Zhukov - 12:4.2.5-58 - Resolves 1374119: Add dns server variable to azure-cloud.sh script