diff options
Diffstat (limited to 'src/lib/dhcpsrv/ncr_generator.cc')
-rw-r--r-- | src/lib/dhcpsrv/ncr_generator.cc | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/src/lib/dhcpsrv/ncr_generator.cc b/src/lib/dhcpsrv/ncr_generator.cc new file mode 100644 index 0000000..c8a4a9c --- /dev/null +++ b/src/lib/dhcpsrv/ncr_generator.cc @@ -0,0 +1,158 @@ +// Copyright (C) 2015-2023 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 <dhcp/option_data_types.h> +#include <dhcpsrv/cfgmgr.h> +#include <dhcpsrv/dhcpsrv_log.h> +#include <dhcpsrv/d2_client_mgr.h> +#include <dhcpsrv/ncr_generator.h> +#include <stdint.h> +#include <vector> + +using namespace isc; +using namespace isc::dhcp; +using namespace isc::dhcp_ddns; + +namespace { + +/// @brief Sends name change request to D2 using lease information. +/// +/// This method is exception safe. +/// +/// @param chg_type type of change to create CHG_ADD or CHG_REMOVE +/// @param lease Pointer to a lease for which NCR should be sent. +/// @param identifier Identifier to be used to generate DHCID for +/// the DNS update. For DHCPv4 it will be hardware address or client +/// identifier. For DHCPv6 it will be a DUID. +/// @param label Client identification information in the textual format. +/// This is used for logging purposes. +/// @param subnet subnet to which the lease belongs. +/// +/// @tparam LeasePtrType Pointer to a lease. +/// @tparam IdentifierType HW Address, Client Identifier or DUID. +template<typename LeasePtrType, typename IdentifierType> +void queueNCRCommon(const NameChangeType& chg_type, const LeasePtrType& lease, + const IdentifierType& identifier, const std::string& label, + NetworkPtr subnet) { + // Check if there is a need for update. + if (lease->hostname_.empty() || (!lease->fqdn_fwd_ && !lease->fqdn_rev_) + || !CfgMgr::instance().getD2ClientMgr().ddnsEnabled()) { + LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL, + DHCPSRV_QUEUE_NCR_SKIP) + .arg(label) + .arg(lease->addr_.toText()); + + return; + } + + ConflictResolutionMode conflict_resolution_mode = CHECK_WITH_DHCID; + util::Optional<double> ddns_ttl_percent; + if (subnet) { + auto mode = subnet->getDdnsConflictResolutionMode(); + if (!mode.empty()) { + conflict_resolution_mode = StringToConflictResolutionMode(mode); + } + + ddns_ttl_percent = subnet->getDdnsTtlPercent(); + } + + try { + // Create DHCID + std::vector<uint8_t> hostname_wire; + OptionDataTypeUtil::writeFqdn(lease->hostname_, hostname_wire, true); + D2Dhcid dhcid = D2Dhcid(identifier, hostname_wire); + + // Calculate the TTL based on lease life time. + uint32_t ttl = calculateDdnsTtl(lease->valid_lft_, ddns_ttl_percent); + + // Create name change request. + NameChangeRequestPtr ncr + (new NameChangeRequest(chg_type, lease->fqdn_fwd_, lease->fqdn_rev_, + lease->hostname_, lease->addr_.toText(), + dhcid, lease->cltt_ + ttl, + ttl, conflict_resolution_mode)); + + LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL_DATA, DHCPSRV_QUEUE_NCR) + .arg(label) + .arg(chg_type == CHG_ADD ? "add" : "remove") + .arg(ncr->toText()); + + // Send name change request. + CfgMgr::instance().getD2ClientMgr().sendRequest(ncr); + + } catch (const std::exception& ex) { + LOG_ERROR(dhcpsrv_logger, DHCPSRV_QUEUE_NCR_FAILED) + .arg(label) + .arg(chg_type == CHG_ADD ? "add" : "remove") + .arg(lease->addr_.toText()) + .arg(ex.what()); + } +} + +} // end of anonymous namespace + +namespace isc { +namespace dhcp { + +void queueNCR(const NameChangeType& chg_type, const Lease4Ptr& lease) { + if (lease) { + // Figure out from the lease's subnet if we should use conflict resolution. + // If there's no subnet, something hinky is going on so we'll set it true. + Subnet4Ptr subnet = CfgMgr::instance().getCurrentCfg() + ->getCfgSubnets4()->getSubnet(lease->subnet_id_); + + // Client id takes precedence over HW address. + if (lease->client_id_) { + queueNCRCommon(chg_type, lease, lease->client_id_->getClientId(), + Pkt4::makeLabel(lease->hwaddr_, lease->client_id_), subnet); + } else { + // Client id is not specified for the lease. Use HW address + // instead. + queueNCRCommon(chg_type, lease, lease->hwaddr_, + Pkt4::makeLabel(lease->hwaddr_, lease->client_id_), subnet); + } + } +} + +void queueNCR(const NameChangeType& chg_type, const Lease6Ptr& lease) { + // DUID is required to generate NCR. + if (lease && (lease->type_ != Lease::TYPE_PD) && lease->duid_) { + // Figure out from the lease's subnet if we should use conflict resolution. + // If there's no subnet, something hinky is going on so we'll set it true. + Subnet6Ptr subnet = CfgMgr::instance().getCurrentCfg() + ->getCfgSubnets6()->getSubnet(lease->subnet_id_); + queueNCRCommon(chg_type, lease, *(lease->duid_), + Pkt6::makeLabel(lease->duid_, lease->hwaddr_), subnet); + } +} + +uint32_t calculateDdnsTtl(uint32_t lease_lft, const util::Optional<double>& ddns_ttl_percent) { + // If we have a configured percentage use it to calculate TTL. + if (!ddns_ttl_percent.unspecified() && (ddns_ttl_percent.get() > 0.0)) { + uint32_t new_lft = static_cast<uint32_t>(round(ddns_ttl_percent.get() * lease_lft)); + if (new_lft > 0) { + return (new_lft); + } else { + LOG_DEBUG(dhcpsrv_logger, DHCPSRV_DBG_TRACE_DETAIL_DATA, + DHCPSRV_DDNS_TTL_PERCENT_TOO_SMALL) + .arg(ddns_ttl_percent.get()) + .arg(lease_lft); + } + } + + // Per RFC 4702 DDNS RR TTL should be given by: + // ((lease life time / 3) < 10 minutes) ? 10 minutes : (lease life time / 3) + if (lease_lft < 1800) { + return (600); + } + + return (lease_lft / 3); +} + +} +} |