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 <pzhukov@redhat.com>
+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 <port>] [-D LL|LLT]\n"
++		  "[-4|-6] [-SNTPI1dvrxi] [-nw] [-p <port>] [-D LL|LLT] \n"
+ #else /* DHCPv6 */
+-		  "[-1dvrx] [-nw] [-p <port>]\n"
++		  "[-I1dvrxi] [-nw] [-p <port>] [-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 <isc/md5.h>
+-
++#include <isc/sha2.h>
+ #include <dns/result.h>
+ 
+ /*
+@@ -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"
+-	 *      <draft-ietf-dhc-dhcp-dns-12.txt>
+-	 *      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 <dns/result.h>
+ 
++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 <bugs@centos.org> - 4.2.5-58.el7.centos.3
-- Roll in CentOS Branding
-
 * Wed Feb 28 2018 Pavel Zhukov <pzhukov@redhat.com> - 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 <pzhukov@redhat.com> - 12:4.2.5-67
+- Resolves #1549998 :CVE-2018-5732  Avoid buffer overflow in options parser
+
+* Thu Dec  7 2017 Pavel Zhukov <pzhukov@redhat.com> - 12:4.2.5-65
+- Resolves: #1519363 - omapi: Close orphaned sockets.
+
+* Mon Oct  2 2017 Pavel Zhukov <pzhukov@redhat.com> - 12:4.2.5-64
+- Resolves: #1497630 - failover hangs with both potential-conflict
+
+* Wed Sep 20 2017 Pavel Zhukov <pzhukov@redhat.com> - 12:4.2.5-63
+- Resolves: #1490782 - Do not override HOSTNAME in client script
+
+* Wed Aug 30 2017 Pavel Zhukov <pzhukov@redhat.com> - 12:4.2.5-62
+- Resolves: #1394727 - Add code to support standard ddns updates
+
+* Wed Aug 16 2017 Pavel Zhukov <pzhukov@redhat.com> - 12:4.2.5-61
+- Resolves: #1396985 - Addes addtional HMAC TSIG algorithms to DDNS
 
-* Wed Feb 28 2018 Pavel Zhukov <pzhukov@redhat.com> - 12:4.2.5-58.2
-- Resolves: #1549979 - CVE-2018-5732  Avoid buffer overflow in options parser
+* Wed Aug 16 2017 Pavel Zhukov <pzhukov@redhat.com> - 12:4.2.5-60
+- Resolves: #1299562 - listen on DDNS port on demand only
 
-* Wed Dec 13 2017 Pavel Zhukov <pzhukov@redhat.com> - 12:4.2.5-58.1
-- Resolves: #1523475 - Fix omapi socket descriptors leak
+* Wed Aug 16 2017 Pavel Zhukov <pzhukov@redhat.com> - 12:4.2.5-59
+- Resolves: 1363791 - dhclient update routing table after the lease expiry
 
 * Tue May 16 2017 Pavel Zhukov <pzhukov@redhat.com> - 12:4.2.5-58
 - Resolves 1374119: Add dns server variable to azure-cloud.sh script