summaryrefslogtreecommitdiffstats
path: root/src/bin/d2/nc_add.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/d2/nc_add.cc')
-rw-r--r--src/bin/d2/nc_add.cc707
1 files changed, 707 insertions, 0 deletions
diff --git a/src/bin/d2/nc_add.cc b/src/bin/d2/nc_add.cc
new file mode 100644
index 0000000..79f4647
--- /dev/null
+++ b/src/bin/d2/nc_add.cc
@@ -0,0 +1,707 @@
+// Copyright (C) 2013-2022 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <d2/nc_add.h>
+#include <d2srv/d2_cfg_mgr.h>
+#include <d2srv/d2_log.h>
+
+#include <util/buffer.h>
+#include <dns/rdataclass.h>
+
+#include <functional>
+
+namespace isc {
+namespace d2 {
+
+// NameAddTransaction states
+const int NameAddTransaction::ADDING_FWD_ADDRS_ST;
+const int NameAddTransaction::REPLACING_FWD_ADDRS_ST;
+const int NameAddTransaction::REPLACING_REV_PTRS_ST;
+
+// NameAddTransaction events
+const int NameAddTransaction::FQDN_IN_USE_EVT;
+const int NameAddTransaction::FQDN_NOT_IN_USE_EVT;
+
+NameAddTransaction::
+NameAddTransaction(asiolink::IOServicePtr& io_service,
+ dhcp_ddns::NameChangeRequestPtr& ncr,
+ DdnsDomainPtr& forward_domain,
+ DdnsDomainPtr& reverse_domain,
+ D2CfgMgrPtr& cfg_mgr)
+ : NameChangeTransaction(io_service, ncr, forward_domain, reverse_domain,
+ cfg_mgr) {
+ if (ncr->getChangeType() != isc::dhcp_ddns::CHG_ADD) {
+ isc_throw (NameAddTransactionError,
+ "NameAddTransaction, request type must be CHG_ADD");
+ }
+}
+
+NameAddTransaction::~NameAddTransaction(){
+}
+
+void
+NameAddTransaction::defineEvents() {
+ // Call superclass impl first.
+ NameChangeTransaction::defineEvents();
+
+ // Define NameAddTransaction events.
+ defineEvent(FQDN_IN_USE_EVT, "FQDN_IN_USE_EVT");
+ defineEvent(FQDN_NOT_IN_USE_EVT, "FQDN_NOT_IN_USE_EVT");
+}
+
+void
+NameAddTransaction::verifyEvents() {
+ // Call superclass implementation first to verify its events. These are
+ // events common to all transactions, and they must be defined.
+ // SELECT_SERVER_EVT
+ // SERVER_SELECTED_EVT
+ // SERVER_IO_ERROR_EVT
+ // NO_MORE_SERVERS_EVT
+ // IO_COMPLETED_EVT
+ // UPDATE_OK_EVT
+ // UPDATE_FAILED_EVT
+ NameChangeTransaction::verifyEvents();
+
+ // Verify NameAddTransaction events by attempting to fetch them.
+ getEvent(FQDN_IN_USE_EVT);
+ getEvent(FQDN_NOT_IN_USE_EVT);
+}
+
+void
+NameAddTransaction::defineStates() {
+ // Call superclass impl first.
+ NameChangeTransaction::defineStates();
+
+ // Define NameAddTransaction states.
+ defineState(READY_ST, "READY_ST",
+ std::bind(&NameAddTransaction::readyHandler, this));
+
+ defineState(SELECTING_FWD_SERVER_ST, "SELECTING_FWD_SERVER_ST",
+ std::bind(&NameAddTransaction::selectingFwdServerHandler, this));
+
+ defineState(SELECTING_REV_SERVER_ST, "SELECTING_REV_SERVER_ST",
+ std::bind(&NameAddTransaction::selectingRevServerHandler, this));
+
+ defineState(ADDING_FWD_ADDRS_ST, "ADDING_FWD_ADDRS_ST",
+ std::bind(&NameAddTransaction::addingFwdAddrsHandler, this));
+
+ defineState(REPLACING_FWD_ADDRS_ST, "REPLACING_FWD_ADDRS_ST",
+ std::bind(&NameAddTransaction::replacingFwdAddrsHandler, this));
+
+ defineState(REPLACING_REV_PTRS_ST, "REPLACING_REV_PTRS_ST",
+ std::bind(&NameAddTransaction::replacingRevPtrsHandler, this));
+
+ defineState(PROCESS_TRANS_OK_ST, "PROCESS_TRANS_OK_ST",
+ std::bind(&NameAddTransaction::processAddOkHandler, this));
+
+ defineState(PROCESS_TRANS_FAILED_ST, "PROCESS_TRANS_FAILED_ST",
+ std::bind(&NameAddTransaction::processAddFailedHandler, this));
+}
+
+void
+NameAddTransaction::verifyStates() {
+ // Call superclass implementation first to verify its states. These are
+ // states common to all transactions, and they must be defined.
+ // READY_ST
+ // SELECTING_FWD_SERVER_ST
+ // SELECTING_REV_SERVER_ST
+ // PROCESS_TRANS_OK_ST
+ // PROCESS_TRANS_FAILED_ST
+ NameChangeTransaction::verifyStates();
+
+ // Verify NameAddTransaction states by attempting to fetch them.
+ getStateInternal(ADDING_FWD_ADDRS_ST);
+ getStateInternal(REPLACING_FWD_ADDRS_ST);
+ getStateInternal(REPLACING_REV_PTRS_ST);
+}
+
+void
+NameAddTransaction::readyHandler() {
+ switch(getNextEvent()) {
+ case START_EVT:
+ if (getForwardDomain()) {
+ // Request includes a forward change, do that first.
+ transition(SELECTING_FWD_SERVER_ST, SELECT_SERVER_EVT);
+ } else {
+ // Reverse change only, transition accordingly.
+ transition(SELECTING_REV_SERVER_ST, SELECT_SERVER_EVT);
+ }
+
+ break;
+ default:
+ // Event is invalid.
+ isc_throw(NameAddTransactionError,
+ "Wrong event for context: " << getContextStr());
+ }
+}
+
+void
+NameAddTransaction::selectingFwdServerHandler() {
+ switch(getNextEvent()) {
+ case SELECT_SERVER_EVT:
+ // First time through for this transaction, so initialize server
+ // selection.
+ initServerSelection(getForwardDomain());
+ break;
+ case SERVER_IO_ERROR_EVT:
+ // We failed to communicate with current server. Attempt to select
+ // another one below.
+ break;
+ default:
+ // Event is invalid.
+ isc_throw(NameAddTransactionError,
+ "Wrong event for context: " << getContextStr());
+ }
+
+ // Select the next server from the list of forward servers.
+ if (selectNextServer()) {
+ // We have a server to try.
+ transition(ADDING_FWD_ADDRS_ST, SERVER_SELECTED_EVT);
+ } else {
+ // Server list is exhausted, so fail the transaction.
+ transition(PROCESS_TRANS_FAILED_ST, NO_MORE_SERVERS_EVT);
+ }
+}
+
+void
+NameAddTransaction::addingFwdAddrsHandler() {
+ if (doOnEntry()) {
+ // Clear the update attempts count on initial transition.
+ clearUpdateAttempts();
+ }
+
+ switch(getNextEvent()) {
+ case SERVER_SELECTED_EVT:
+ try {
+ clearDnsUpdateRequest();
+ buildAddFwdAddressRequest();
+ } catch (const std::exception& ex) {
+ // While unlikely, the build might fail if we have invalid
+ // data. Should that be the case, we need to fail the
+ // transaction.
+ LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_ADD_BUILD_FAILURE)
+ .arg(getRequestId())
+ .arg(getNcr()->toText())
+ .arg(ex.what());
+ transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+ break;
+ }
+
+ // Call sendUpdate() to initiate the async send. Note it also sets
+ // next event to NOP_EVT.
+ sendUpdate("Forward Add");
+ break;
+
+ case IO_COMPLETED_EVT: {
+ switch (getDnsUpdateStatus()) {
+ case DNSClient::SUCCESS: {
+ // We successfully received a response packet from the server.
+ const dns::Rcode& rcode = getDnsUpdateResponse()->getRcode();
+ if (rcode == dns::Rcode::NOERROR()) {
+ // We were able to add it. Mark it as done.
+ setForwardChangeCompleted(true);
+
+ // If request calls for reverse update then do that next,
+ // otherwise we can process ok.
+ if (getReverseDomain()) {
+ transition(SELECTING_REV_SERVER_ST, SELECT_SERVER_EVT);
+ } else {
+ transition(PROCESS_TRANS_OK_ST, UPDATE_OK_EVT);
+ }
+ } else if (rcode == dns::Rcode::YXDOMAIN()) {
+ // FQDN is in use so we need to attempt to replace
+ // forward address.
+ transition(REPLACING_FWD_ADDRS_ST, FQDN_IN_USE_EVT);
+ } else {
+ // Per RFC4703 any other value means cease.
+ // If we get not authorized should we try the next server in
+ // the list? @todo This needs some discussion perhaps.
+ LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_ADD_REJECTED)
+ .arg(getRequestId())
+ .arg(getCurrentServer()->toText())
+ .arg(getNcr()->getFqdn())
+ .arg(rcode.getCode());
+ transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+ }
+
+ break;
+ }
+
+ case DNSClient::TIMEOUT:
+ case DNSClient::OTHER:
+ // We couldn't send to the current server, log it and set up
+ // to select the next server for a retry.
+ // @note For now we treat OTHER as an IO error like TIMEOUT. It
+ // is not entirely clear if this is accurate.
+ LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_ADD_IO_ERROR)
+ .arg(getRequestId())
+ .arg(getNcr()->getFqdn())
+ .arg(getCurrentServer()->toText());
+
+ retryTransition(SELECTING_FWD_SERVER_ST);
+ break;
+
+ case DNSClient::INVALID_RESPONSE:
+ // A response was received but was corrupt. Retry it like an IO
+ // error.
+ LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_ADD_RESP_CORRUPT)
+ .arg(getRequestId())
+ .arg(getCurrentServer()->toText())
+ .arg(getNcr()->getFqdn());
+
+ retryTransition(SELECTING_FWD_SERVER_ST);
+ break;
+
+ default:
+ // Any other value and we will fail this transaction, something
+ // bigger is wrong.
+ LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_ADD_BAD_DNSCLIENT_STATUS)
+ .arg(getRequestId())
+ .arg(getDnsUpdateStatus())
+ .arg(getNcr()->getFqdn())
+ .arg(getCurrentServer()->toText());
+
+ transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+ break;
+ } // end switch on dns_status
+
+ break;
+ } // end case IO_COMPLETE_EVT
+
+ default:
+ // Event is invalid.
+ isc_throw(NameAddTransactionError,
+ "Wrong event for context: " << getContextStr());
+ }
+}
+
+void
+NameAddTransaction::replacingFwdAddrsHandler() {
+ if (doOnEntry()) {
+ // Clear the update attempts count on initial transition.
+ clearUpdateAttempts();
+ }
+
+ switch(getNextEvent()) {
+ case FQDN_IN_USE_EVT:
+ case SERVER_SELECTED_EVT:
+ try {
+ clearDnsUpdateRequest();
+ buildReplaceFwdAddressRequest();
+ } catch (const std::exception& ex) {
+ // While unlikely, the build might fail if we have invalid
+ // data. Should that be the case, we need to fail the
+ // transaction.
+ LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_REPLACE_BUILD_FAILURE)
+ .arg(getRequestId())
+ .arg(getNcr()->toText())
+ .arg(ex.what());
+ transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+ break;
+ }
+
+ // Call sendUpdate() to initiate the async send. Note it also sets
+ // next event to NOP_EVT.
+ sendUpdate("Forward Replace");
+ break;
+
+ case IO_COMPLETED_EVT: {
+ switch (getDnsUpdateStatus()) {
+ case DNSClient::SUCCESS: {
+ // We successfully received a response packet from the server.
+ const dns::Rcode& rcode = getDnsUpdateResponse()->getRcode();
+ if (rcode == dns::Rcode::NOERROR()) {
+ // We were able to replace the forward mapping. Mark it as done.
+ setForwardChangeCompleted(true);
+
+ // If request calls for reverse update then do that next,
+ // otherwise we can process ok.
+ if (getReverseDomain()) {
+ transition(SELECTING_REV_SERVER_ST, SELECT_SERVER_EVT);
+ } else {
+ transition(PROCESS_TRANS_OK_ST, UPDATE_OK_EVT);
+ }
+ } else if (rcode == dns::Rcode::NXDOMAIN()) {
+ // FQDN is NOT in use so go back and do the forward add address.
+ // Covers the case that it was there when we tried to add it,
+ // but has since been removed per RFC 4703.
+ transition(ADDING_FWD_ADDRS_ST, SERVER_SELECTED_EVT);
+ } else {
+ // Per RFC4703 any other value means cease.
+ // If we get not authorized should try the next server in
+ // the list? @todo This needs some discussion perhaps.
+ LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_REPLACE_REJECTED)
+ .arg(getRequestId())
+ .arg(getCurrentServer()->toText())
+ .arg(getNcr()->getFqdn())
+ .arg(rcode.getCode());
+ transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+ }
+
+ break;
+ }
+
+ case DNSClient::TIMEOUT:
+ case DNSClient::OTHER:
+ // We couldn't send to the current server, log it and set up
+ // to select the next server for a retry.
+ // @note For now we treat OTHER as an IO error like TIMEOUT. It
+ // is not entirely clear if this is accurate.
+ LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_REPLACE_IO_ERROR)
+ .arg(getRequestId())
+ .arg(getNcr()->getFqdn())
+ .arg(getCurrentServer()->toText());
+
+ // If we are out of retries on this server, we go back and start
+ // all over on a new server.
+ retryTransition(SELECTING_FWD_SERVER_ST);
+ break;
+
+ case DNSClient::INVALID_RESPONSE:
+ // A response was received but was corrupt. Retry it like an IO
+ // error.
+ LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_FORWARD_REPLACE_RESP_CORRUPT)
+ .arg(getRequestId())
+ .arg(getCurrentServer()->toText())
+ .arg(getNcr()->getFqdn());
+
+ // If we are out of retries on this server, we go back and start
+ // all over on a new server.
+ retryTransition(SELECTING_FWD_SERVER_ST);
+ break;
+
+ default:
+ // Any other value and we will fail this transaction, something
+ // bigger is wrong.
+ LOG_ERROR(d2_to_dns_logger,
+ DHCP_DDNS_FORWARD_REPLACE_BAD_DNSCLIENT_STATUS)
+ .arg(getRequestId())
+ .arg(getDnsUpdateStatus())
+ .arg(getNcr()->getFqdn())
+ .arg(getCurrentServer()->toText());
+
+ transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+ break;
+ } // end switch on dns_status
+
+ break;
+ } // end case IO_COMPLETE_EVT
+
+ default:
+ // Event is invalid.
+ isc_throw(NameAddTransactionError,
+ "Wrong event for context: " << getContextStr());
+ }
+}
+
+void
+NameAddTransaction::selectingRevServerHandler() {
+ switch(getNextEvent()) {
+ case SELECT_SERVER_EVT:
+ // First time through for this transaction, so initialize server
+ // selection.
+ initServerSelection(getReverseDomain());
+ break;
+ case SERVER_IO_ERROR_EVT:
+ // We failed to communicate with current server. Attempt to select
+ // another one below.
+ break;
+ default:
+ // Event is invalid.
+ isc_throw(NameAddTransactionError,
+ "Wrong event for context: " << getContextStr());
+ }
+
+ // Select the next server from the list of forward servers.
+ if (selectNextServer()) {
+ // We have a server to try.
+ transition(REPLACING_REV_PTRS_ST, SERVER_SELECTED_EVT);
+ } else {
+ // Server list is exhausted, so fail the transaction.
+ transition(PROCESS_TRANS_FAILED_ST, NO_MORE_SERVERS_EVT);
+ }
+}
+
+
+void
+NameAddTransaction::replacingRevPtrsHandler() {
+ if (doOnEntry()) {
+ // Clear the update attempts count on initial transition.
+ clearUpdateAttempts();
+ }
+
+ switch(getNextEvent()) {
+ case SERVER_SELECTED_EVT:
+ try {
+ clearDnsUpdateRequest();
+ buildReplaceRevPtrsRequest();
+ } catch (const std::exception& ex) {
+ // While unlikely, the build might fail if we have invalid
+ // data. Should that be the case, we need to fail the
+ // transaction.
+ LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_REVERSE_REPLACE_BUILD_FAILURE)
+ .arg(getRequestId())
+ .arg(getNcr()->toText())
+ .arg(ex.what());
+ transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+ break;
+ }
+
+ // Call sendUpdate() to initiate the async send. Note it also sets
+ // next event to NOP_EVT.
+ sendUpdate("Reverse Replace");
+ break;
+
+ case IO_COMPLETED_EVT: {
+ switch (getDnsUpdateStatus()) {
+ case DNSClient::SUCCESS: {
+ // We successfully received a response packet from the server.
+ const dns::Rcode& rcode = getDnsUpdateResponse()->getRcode();
+ if (rcode == dns::Rcode::NOERROR()) {
+ // We were able to update the reverse mapping. Mark it as done.
+ setReverseChangeCompleted(true);
+ transition(PROCESS_TRANS_OK_ST, UPDATE_OK_EVT);
+ } else {
+ // Per RFC4703 any other value means cease.
+ // If we get not authorized should try the next server in
+ // the list? @todo This needs some discussion perhaps.
+ LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_REVERSE_REPLACE_REJECTED)
+ .arg(getRequestId())
+ .arg(getCurrentServer()->toText())
+ .arg(getNcr()->getFqdn())
+ .arg(rcode.getCode());
+ transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+ }
+
+ break;
+ }
+
+ case DNSClient::TIMEOUT:
+ case DNSClient::OTHER:
+ // We couldn't send to the current server, log it and set up
+ // to select the next server for a retry.
+ // @note For now we treat OTHER as an IO error like TIMEOUT. It
+ // is not entirely clear if this is accurate.
+ LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_REVERSE_REPLACE_IO_ERROR)
+ .arg(getRequestId())
+ .arg(getNcr()->getFqdn())
+ .arg(getCurrentServer()->toText());
+
+ // If we are out of retries on this server, we go back and start
+ // all over on a new server.
+ retryTransition(SELECTING_REV_SERVER_ST);
+ break;
+
+ case DNSClient::INVALID_RESPONSE:
+ // A response was received but was corrupt. Retry it like an IO
+ // error.
+ LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_REVERSE_REPLACE_RESP_CORRUPT)
+ .arg(getRequestId())
+ .arg(getCurrentServer()->toText())
+ .arg(getNcr()->getFqdn());
+
+ // If we are out of retries on this server, we go back and start
+ // all over on a new server.
+ retryTransition(SELECTING_REV_SERVER_ST);
+ break;
+
+ default:
+ // Any other value and we will fail this transaction, something
+ // bigger is wrong.
+ LOG_ERROR(d2_to_dns_logger,
+ DHCP_DDNS_REVERSE_REPLACE_BAD_DNSCLIENT_STATUS)
+ .arg(getRequestId())
+ .arg(getDnsUpdateStatus())
+ .arg(getNcr()->getFqdn())
+ .arg(getCurrentServer()->toText());
+
+ transition(PROCESS_TRANS_FAILED_ST, UPDATE_FAILED_EVT);
+ break;
+ } // end switch on dns_status
+
+ break;
+ } // end case IO_COMPLETE_EVT
+
+ default:
+ // Event is invalid.
+ isc_throw(NameAddTransactionError,
+ "Wrong event for context: " << getContextStr());
+ }
+}
+
+void
+NameAddTransaction::processAddOkHandler() {
+ switch(getNextEvent()) {
+ case UPDATE_OK_EVT:
+ LOG_INFO(d2_to_dns_logger, DHCP_DDNS_ADD_SUCCEEDED)
+ .arg(getRequestId())
+ .arg(getNcr()->toText());
+ setNcrStatus(dhcp_ddns::ST_COMPLETED);
+ endModel();
+ break;
+ default:
+ // Event is invalid.
+ isc_throw(NameAddTransactionError,
+ "Wrong event for context: " << getContextStr());
+ }
+}
+
+void
+NameAddTransaction::processAddFailedHandler() {
+ switch(getNextEvent()) {
+ case UPDATE_FAILED_EVT:
+ case NO_MORE_SERVERS_EVT:
+ setNcrStatus(dhcp_ddns::ST_FAILED);
+ LOG_ERROR(d2_to_dns_logger, DHCP_DDNS_ADD_FAILED)
+ .arg(getRequestId())
+ .arg(transactionOutcomeString());
+ endModel();
+ break;
+ default:
+ // Event is invalid.
+ isc_throw(NameAddTransactionError,
+ "Wrong event for context: " << getContextStr());
+ }
+}
+
+void
+NameAddTransaction::buildAddFwdAddressRequest() {
+ // Construct an empty request.
+ D2UpdateMessagePtr request = prepNewRequest(getForwardDomain());
+
+ // Construct dns::Name from NCR fqdn.
+ dns::Name fqdn(dns::Name(getNcr()->getFqdn()));
+
+ // Content on this request is based on RFC 4703, section 5.3.1
+ // First build the Prerequisite Section.
+
+ // Create 'FQDN Is Not In Use' prerequisite and add it to the
+ // prerequisite section.
+ // Based on RFC 2136, section 2.4.5
+ dns::RRsetPtr prereq(new dns::RRset(fqdn, dns::RRClass::NONE(),
+ dns::RRType::ANY(), dns::RRTTL(0)));
+ request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq);
+
+ // Next build the Update Section.
+
+ // Create the TTL based on lease length.
+ dns::RRTTL lease_ttl(getNcr()->getLeaseLength());
+
+ // Create the FQDN/IP 'add' RR and add it to the to update section.
+ // Based on RFC 2136, section 2.5.1
+ dns::RRsetPtr update(new dns::RRset(fqdn, dns::RRClass::IN(),
+ getAddressRRType(), lease_ttl));
+
+ addLeaseAddressRdata(update);
+ request->addRRset(D2UpdateMessage::SECTION_UPDATE, update);
+
+ // Now create the FQDN/DHCID 'add' RR and add it to update section.
+ // Based on RFC 2136, section 2.5.1
+ update.reset(new dns::RRset(fqdn, dns::RRClass::IN(),
+ dns::RRType::DHCID(), lease_ttl));
+ addDhcidRdata(update);
+ request->addRRset(D2UpdateMessage::SECTION_UPDATE, update);
+
+ // Set the transaction's update request to the new request.
+ setDnsUpdateRequest(request);
+}
+
+void
+NameAddTransaction::buildReplaceFwdAddressRequest() {
+ // Construct an empty request.
+ D2UpdateMessagePtr request = prepNewRequest(getForwardDomain());
+
+ // Construct dns::Name from NCR fqdn.
+ dns::Name fqdn(dns::Name(getNcr()->getFqdn()));
+
+ // Content on this request is based on RFC 4703, section 5.3.2
+ // First build the Prerequisite Section.
+
+ // Create an 'FQDN Is In Use' prerequisite and add it to the
+ // pre-requisite section.
+ // Based on RFC 2136, section 2.4.4
+ dns::RRsetPtr prereq(new dns::RRset(fqdn, dns::RRClass::ANY(),
+ dns::RRType::ANY(), dns::RRTTL(0)));
+ request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq);
+
+ // Create an DHCID matches prerequisite RR and add it to the
+ // pre-requisite section.
+ // Based on RFC 2136, section 2.4.2.
+ prereq.reset(new dns::RRset(fqdn, dns::RRClass::IN(),
+ dns::RRType::DHCID(), dns::RRTTL(0)));
+ addDhcidRdata(prereq);
+ request->addRRset(D2UpdateMessage::SECTION_PREREQUISITE, prereq);
+
+ // Next build the Update Section.
+
+ // Create the TTL based on lease length.
+ dns::RRTTL lease_ttl(getNcr()->getLeaseLength());
+
+ // Create the FQDN/IP 'delete' RR and add it to the update section.
+ // Based on RFC 2136, section 2.5.2
+ dns::RRsetPtr update(new dns::RRset(fqdn, dns::RRClass::ANY(),
+ getAddressRRType(), dns::RRTTL(0)));
+ request->addRRset(D2UpdateMessage::SECTION_UPDATE, update);
+
+ // Create the FQDN/IP 'add' RR and add it to the update section.
+ // Based on RFC 2136, section 2.5.1
+ update.reset(new dns::RRset(fqdn, dns::RRClass::IN(),
+ getAddressRRType(), lease_ttl));
+ addLeaseAddressRdata(update);
+ request->addRRset(D2UpdateMessage::SECTION_UPDATE, update);
+
+ // Set the transaction's update request to the new request.
+ setDnsUpdateRequest(request);
+}
+
+void
+NameAddTransaction::buildReplaceRevPtrsRequest() {
+ // Construct an empty request.
+ D2UpdateMessagePtr request = prepNewRequest(getReverseDomain());
+
+ // Create the reverse IP address "FQDN".
+ std::string rev_addr = D2CfgMgr::reverseIpAddress(getNcr()->getIpAddress());
+ dns::Name rev_ip(rev_addr);
+
+ // Create the TTL based on lease length.
+ dns::RRTTL lease_ttl(getNcr()->getLeaseLength());
+
+ // Content on this request is based on RFC 4703, section 5.4
+ // Reverse replacement has no prerequisites so straight on to
+ // building the Update section.
+
+ // Create the PTR 'delete' RR and add it to update section.
+ dns::RRsetPtr update(new dns::RRset(rev_ip, dns::RRClass::ANY(),
+ dns::RRType::PTR(), dns::RRTTL(0)));
+ request->addRRset(D2UpdateMessage::SECTION_UPDATE, update);
+
+ // Create the DHCID 'delete' RR and add it to the update section.
+ update.reset(new dns::RRset(rev_ip, dns::RRClass::ANY(),
+ dns::RRType::DHCID(), dns::RRTTL(0)));
+ request->addRRset(D2UpdateMessage::SECTION_UPDATE, update);
+
+ // Create the FQDN/IP PTR 'add' RR, add the FQDN as the PTR Rdata
+ // then add it to update section.
+ update.reset(new dns::RRset(rev_ip, dns::RRClass::IN(),
+ dns::RRType::PTR(), lease_ttl));
+ addPtrRdata(update);
+ request->addRRset(D2UpdateMessage::SECTION_UPDATE, update);
+
+ // Create the FQDN/IP PTR 'add' RR, add the DHCID Rdata
+ // then add it to update section.
+ update.reset(new dns::RRset(rev_ip, dns::RRClass::IN(),
+ dns::RRType::DHCID(), lease_ttl));
+ addDhcidRdata(update);
+ request->addRRset(D2UpdateMessage::SECTION_UPDATE, update);
+
+ // Set the transaction's update request to the new request.
+ setDnsUpdateRequest(request);
+}
+
+} // namespace isc::d2
+} // namespace isc