diff options
Diffstat (limited to 'src/lib/dhcpsrv/sanity_checker.cc')
-rw-r--r-- | src/lib/dhcpsrv/sanity_checker.cc | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/src/lib/dhcpsrv/sanity_checker.cc b/src/lib/dhcpsrv/sanity_checker.cc new file mode 100644 index 0000000..e2df498 --- /dev/null +++ b/src/lib/dhcpsrv/sanity_checker.cc @@ -0,0 +1,187 @@ +// Copyright (C) 2018-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 <dhcpsrv/sanity_checker.h> +#include <dhcpsrv/cfg_consistency.h> +#include <dhcpsrv/cfgmgr.h> +#include <dhcpsrv/subnet_id.h> +#include <dhcpsrv/dhcpsrv_log.h> +#include <sstream> + +namespace isc { +namespace dhcp { + +bool SanityChecker::leaseCheckingEnabled(bool current) { + SrvConfigPtr cfg; + if (current) { + cfg = CfgMgr::instance().getCurrentCfg(); + } else { + cfg = CfgMgr::instance().getStagingCfg(); + } + + if (cfg) { + CfgConsistencyPtr sanity = cfg->getConsistency(); + return (sanity && (sanity->getLeaseSanityCheck() != CfgConsistency::LEASE_CHECK_NONE)); + } + + return (false); +} + +void SanityChecker::checkLease(Lease4Ptr& lease, bool current) { + SrvConfigPtr cfg; + if (current) { + cfg = CfgMgr::instance().getCurrentCfg(); + } else { + cfg = CfgMgr::instance().getStagingCfg(); + } + + CfgConsistencyPtr sanity = cfg->getConsistency(); + if (sanity->getLeaseSanityCheck() == CfgConsistency::LEASE_CHECK_NONE) { + // No sense going farther. + return; + } + + CfgSubnets4Ptr subnets = cfg->getCfgSubnets4(); + checkLeaseInternal(lease, sanity, subnets); +} + +void SanityChecker::checkLease(Lease6Ptr& lease, bool current) { + // We only check IA_NAs currently. + if (lease->type_ != Lease::TYPE_NA) { + return; + } + + SrvConfigPtr cfg; + if (current) { + cfg = CfgMgr::instance().getCurrentCfg(); + } else { + cfg = CfgMgr::instance().getStagingCfg(); + } + CfgConsistencyPtr sanity = cfg->getConsistency(); + if (sanity->getLeaseSanityCheck() == CfgConsistency::LEASE_CHECK_NONE) { + // No sense going farther. + return; + } + + CfgSubnets6Ptr subnets = cfg->getCfgSubnets6(); + checkLeaseInternal(lease, sanity, subnets); +} + +template<typename LeasePtrType, typename SubnetsType> +void SanityChecker::checkLeaseInternal(LeasePtrType& lease, const CfgConsistencyPtr& checks, + const SubnetsType& subnets) { + + auto subnet = subnets->getBySubnetId(lease->subnet_id_); + if (subnet && subnet->inRange(lease->addr_)) { + + // If the subnet is defined and the address is in range, we're good. + + return; + } + + // Ok, if we got here, that means that either we did not find a subnet + // of found it, but it wasn't the right subnet. + SubnetID id = findSubnetId(lease, subnets); + + // Prepare a message in the case the check fails. + std::ostringstream msg; + if (id != 0) { + msg << "the lease should have subnet-id " << id; + } else { + msg << "the lease IP address did not belong to a configured subnet"; + } + + switch (checks->getLeaseSanityCheck()) { + case CfgConsistency::LEASE_CHECK_WARN: + if (lease->subnet_id_ != id) { + // Print a warning, but return the lease as is. + LOG_WARN(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FAIL) + .arg(lease->addr_.toText()) + .arg(lease->subnet_id_) + .arg(msg.str()); + } + break; + + case CfgConsistency::LEASE_CHECK_FIX: + if (lease->subnet_id_ != id) { + + // If there is a better subnet, use it. + if (id != 0) { + LOG_INFO(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FIXED) + .arg(lease->addr_.toText()) + .arg(lease->subnet_id_) + .arg(id); + lease->subnet_id_ = id; + } else { + // If not, return the lease as is. + LOG_WARN(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FAIL) + .arg(lease->addr_.toText()) + .arg(lease->subnet_id_) + .arg(msg.str()); + } + } + break; + + case CfgConsistency::LEASE_CHECK_FIX_DEL: + if (lease->subnet_id_ != id) { + + // If there is a better subnet, use it. + if (id != 0) { + LOG_INFO(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FIXED) + .arg(lease->addr_.toText()) + .arg(lease->subnet_id_) + .arg(id); + lease->subnet_id_ = id; + break; + } else { + // If not, delete the lease. + LOG_INFO(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FAIL_DISCARD) + .arg(lease->addr_.toText()) + .arg(lease->subnet_id_) + .arg(msg.str()); + lease.reset(); + } + + } + break; + + case CfgConsistency::LEASE_CHECK_DEL: + if (lease->subnet_id_ != id) { + LOG_INFO(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FAIL_DISCARD) + .arg(lease->addr_.toText()) + .arg(lease->subnet_id_) + .arg(msg.str()); + lease.reset(); + } + break; + + default: + // Shouldn't get here but some compilers and analyzers + // complain. We'll we treat it as NONE and return the + // lease as-is. + break; + + } + + // Additional checks may be implemented in the future here. + + /// @todo: add a check if the address is within specified dynamic pool + /// if not, check if the address is reserved. +} + +template<typename LeaseType, typename SubnetsType> +SubnetID SanityChecker::findSubnetId(const LeaseType& lease, const SubnetsType& subnets) { + auto subnet = subnets->selectSubnet(lease->addr_); + if (!subnet) { + return (0); + } + + return (subnet->getID()); +} + +} +} |