summaryrefslogtreecommitdiffstats
path: root/src/lib/dhcpsrv/sanity_checker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/dhcpsrv/sanity_checker.cc')
-rw-r--r--src/lib/dhcpsrv/sanity_checker.cc187
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());
+}
+
+}
+}