/src/kea/src/lib/dhcpsrv/sanity_checker.cc
Line | Count | Source |
1 | | // Copyright (C) 2018-2022 Internet Systems Consortium, Inc. ("ISC") |
2 | | // |
3 | | // This Source Code Form is subject to the terms of the Mozilla Public |
4 | | // License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | // file, You can obtain one at http://mozilla.org/MPL/2.0/. |
6 | | #include <config.h> |
7 | | |
8 | | #include <dhcpsrv/sanity_checker.h> |
9 | | #include <dhcpsrv/cfg_consistency.h> |
10 | | #include <dhcpsrv/cfgmgr.h> |
11 | | #include <dhcpsrv/subnet_id.h> |
12 | | #include <dhcpsrv/dhcpsrv_log.h> |
13 | | #include <sstream> |
14 | | |
15 | | namespace isc { |
16 | | namespace dhcp { |
17 | | |
18 | 15.3k | bool SanityChecker::leaseCheckingEnabled(bool current) { |
19 | 15.3k | SrvConfigPtr cfg; |
20 | 15.3k | if (current) { |
21 | 0 | cfg = CfgMgr::instance().getCurrentCfg(); |
22 | 15.3k | } else { |
23 | 15.3k | cfg = CfgMgr::instance().getStagingCfg(); |
24 | 15.3k | } |
25 | | |
26 | 15.3k | if (cfg) { |
27 | 15.3k | CfgConsistencyPtr sanity = cfg->getConsistency(); |
28 | 15.3k | return (sanity && (sanity->getLeaseSanityCheck() != CfgConsistency::LEASE_CHECK_NONE)); |
29 | 15.3k | } |
30 | | |
31 | 0 | return (false); |
32 | 15.3k | } |
33 | | |
34 | 32.6k | void SanityChecker::checkLease(Lease4Ptr& lease, bool current) { |
35 | 32.6k | SrvConfigPtr cfg; |
36 | 32.6k | if (current) { |
37 | 0 | cfg = CfgMgr::instance().getCurrentCfg(); |
38 | 32.6k | } else { |
39 | 32.6k | cfg = CfgMgr::instance().getStagingCfg(); |
40 | 32.6k | } |
41 | | |
42 | 32.6k | CfgConsistencyPtr sanity = cfg->getConsistency(); |
43 | 32.6k | if (sanity->getLeaseSanityCheck() == CfgConsistency::LEASE_CHECK_NONE) { |
44 | | // No sense going farther. |
45 | 0 | return; |
46 | 0 | } |
47 | | |
48 | 32.6k | CfgSubnets4Ptr subnets = cfg->getCfgSubnets4(); |
49 | 32.6k | checkLeaseInternal(lease, sanity, subnets); |
50 | 32.6k | } |
51 | | |
52 | 24.1k | void SanityChecker::checkLease(Lease6Ptr& lease, bool current) { |
53 | | // We only check IA_NAs currently. |
54 | 24.1k | if (lease->type_ != Lease::TYPE_NA) { |
55 | 18.0k | return; |
56 | 18.0k | } |
57 | | |
58 | 6.03k | SrvConfigPtr cfg; |
59 | 6.03k | if (current) { |
60 | 0 | cfg = CfgMgr::instance().getCurrentCfg(); |
61 | 6.03k | } else { |
62 | 6.03k | cfg = CfgMgr::instance().getStagingCfg(); |
63 | 6.03k | } |
64 | 6.03k | CfgConsistencyPtr sanity = cfg->getConsistency(); |
65 | 6.03k | if (sanity->getLeaseSanityCheck() == CfgConsistency::LEASE_CHECK_NONE) { |
66 | | // No sense going farther. |
67 | 0 | return; |
68 | 0 | } |
69 | | |
70 | 6.03k | CfgSubnets6Ptr subnets = cfg->getCfgSubnets6(); |
71 | 6.03k | checkLeaseInternal(lease, sanity, subnets); |
72 | 6.03k | } |
73 | | |
74 | | template<typename LeasePtrType, typename SubnetsType> |
75 | | void SanityChecker::checkLeaseInternal(LeasePtrType& lease, const CfgConsistencyPtr& checks, |
76 | 38.6k | const SubnetsType& subnets) { |
77 | | |
78 | 38.6k | auto subnet = subnets->getBySubnetId(lease->subnet_id_); |
79 | 38.6k | if (subnet && subnet->inRange(lease->addr_)) { |
80 | | |
81 | | // If the subnet is defined and the address is in range, we're good. |
82 | | |
83 | 8.15k | return; |
84 | 8.15k | } |
85 | | |
86 | | // Ok, if we got here, that means that either we did not find a subnet |
87 | | // of found it, but it wasn't the right subnet. |
88 | 30.4k | SubnetID id = findSubnetId(lease, subnets); |
89 | | |
90 | | // Prepare a message in the case the check fails. |
91 | 30.4k | std::ostringstream msg; |
92 | 30.4k | if (id != 0) { |
93 | 24.4k | msg << "the lease should have subnet-id " << id; |
94 | 24.4k | } else { |
95 | 6.03k | msg << "the lease IP address did not belong to a configured subnet"; |
96 | 6.03k | } |
97 | | |
98 | 30.4k | switch (checks->getLeaseSanityCheck()) { |
99 | 30.4k | case CfgConsistency::LEASE_CHECK_WARN: |
100 | 30.4k | if (lease->subnet_id_ != id) { |
101 | | // Print a warning, but return the lease as is. |
102 | 30.4k | LOG_WARN(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FAIL) |
103 | 30.4k | .arg(lease->addr_.toText()) |
104 | 30.4k | .arg(lease->subnet_id_) |
105 | 30.4k | .arg(msg.str()); |
106 | 30.4k | } |
107 | 30.4k | break; |
108 | | |
109 | 0 | case CfgConsistency::LEASE_CHECK_FIX: |
110 | 0 | if (lease->subnet_id_ != id) { |
111 | | |
112 | | // If there is a better subnet, use it. |
113 | 0 | if (id != 0) { |
114 | 0 | LOG_INFO(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FIXED) |
115 | 0 | .arg(lease->addr_.toText()) |
116 | 0 | .arg(lease->subnet_id_) |
117 | 0 | .arg(id); |
118 | 0 | lease->subnet_id_ = id; |
119 | 0 | } else { |
120 | | // If not, return the lease as is. |
121 | 0 | LOG_WARN(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FAIL) |
122 | 0 | .arg(lease->addr_.toText()) |
123 | 0 | .arg(lease->subnet_id_) |
124 | 0 | .arg(msg.str()); |
125 | 0 | } |
126 | 0 | } |
127 | 0 | break; |
128 | | |
129 | 0 | case CfgConsistency::LEASE_CHECK_FIX_DEL: |
130 | 0 | if (lease->subnet_id_ != id) { |
131 | | |
132 | | // If there is a better subnet, use it. |
133 | 0 | if (id != 0) { |
134 | 0 | LOG_INFO(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FIXED) |
135 | 0 | .arg(lease->addr_.toText()) |
136 | 0 | .arg(lease->subnet_id_) |
137 | 0 | .arg(id); |
138 | 0 | lease->subnet_id_ = id; |
139 | 0 | break; |
140 | 0 | } else { |
141 | | // If not, delete the lease. |
142 | 0 | LOG_INFO(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FAIL_DISCARD) |
143 | 0 | .arg(lease->addr_.toText()) |
144 | 0 | .arg(lease->subnet_id_) |
145 | 0 | .arg(msg.str()); |
146 | 0 | lease.reset(); |
147 | 0 | } |
148 | |
|
149 | 0 | } |
150 | 0 | break; |
151 | | |
152 | 0 | case CfgConsistency::LEASE_CHECK_DEL: |
153 | 0 | if (lease->subnet_id_ != id) { |
154 | 0 | LOG_INFO(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FAIL_DISCARD) |
155 | 0 | .arg(lease->addr_.toText()) |
156 | 0 | .arg(lease->subnet_id_) |
157 | 0 | .arg(msg.str()); |
158 | 0 | lease.reset(); |
159 | 0 | } |
160 | 0 | break; |
161 | | |
162 | 0 | default: |
163 | | // Shouldn't get here but some compilers and analyzers |
164 | | // complain. We'll we treat it as NONE and return the |
165 | | // lease as-is. |
166 | 0 | break; |
167 | | |
168 | 30.4k | } |
169 | | |
170 | | // Additional checks may be implemented in the future here. |
171 | | |
172 | | /// @todo: add a check if the address is within specified dynamic pool |
173 | | /// if not, check if the address is reserved. |
174 | 30.4k | } void isc::dhcp::SanityChecker::checkLeaseInternal<boost::shared_ptr<isc::dhcp::Lease4>, boost::shared_ptr<isc::dhcp::CfgSubnets4> >(boost::shared_ptr<isc::dhcp::Lease4>&, boost::shared_ptr<isc::dhcp::CfgConsistency> const&, boost::shared_ptr<isc::dhcp::CfgSubnets4> const&) Line | Count | Source | 76 | 32.6k | const SubnetsType& subnets) { | 77 | | | 78 | 32.6k | auto subnet = subnets->getBySubnetId(lease->subnet_id_); | 79 | 32.6k | if (subnet && subnet->inRange(lease->addr_)) { | 80 | | | 81 | | // If the subnet is defined and the address is in range, we're good. | 82 | | | 83 | 8.15k | return; | 84 | 8.15k | } | 85 | | | 86 | | // Ok, if we got here, that means that either we did not find a subnet | 87 | | // of found it, but it wasn't the right subnet. | 88 | 24.4k | SubnetID id = findSubnetId(lease, subnets); | 89 | | | 90 | | // Prepare a message in the case the check fails. | 91 | 24.4k | std::ostringstream msg; | 92 | 24.4k | if (id != 0) { | 93 | 24.4k | msg << "the lease should have subnet-id " << id; | 94 | 24.4k | } else { | 95 | 0 | msg << "the lease IP address did not belong to a configured subnet"; | 96 | 0 | } | 97 | | | 98 | 24.4k | switch (checks->getLeaseSanityCheck()) { | 99 | 24.4k | case CfgConsistency::LEASE_CHECK_WARN: | 100 | 24.4k | if (lease->subnet_id_ != id) { | 101 | | // Print a warning, but return the lease as is. | 102 | 24.4k | LOG_WARN(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FAIL) | 103 | 24.4k | .arg(lease->addr_.toText()) | 104 | 24.4k | .arg(lease->subnet_id_) | 105 | 24.4k | .arg(msg.str()); | 106 | 24.4k | } | 107 | 24.4k | break; | 108 | | | 109 | 0 | case CfgConsistency::LEASE_CHECK_FIX: | 110 | 0 | if (lease->subnet_id_ != id) { | 111 | | | 112 | | // If there is a better subnet, use it. | 113 | 0 | if (id != 0) { | 114 | 0 | LOG_INFO(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FIXED) | 115 | 0 | .arg(lease->addr_.toText()) | 116 | 0 | .arg(lease->subnet_id_) | 117 | 0 | .arg(id); | 118 | 0 | lease->subnet_id_ = id; | 119 | 0 | } else { | 120 | | // If not, return the lease as is. | 121 | 0 | LOG_WARN(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FAIL) | 122 | 0 | .arg(lease->addr_.toText()) | 123 | 0 | .arg(lease->subnet_id_) | 124 | 0 | .arg(msg.str()); | 125 | 0 | } | 126 | 0 | } | 127 | 0 | break; | 128 | | | 129 | 0 | case CfgConsistency::LEASE_CHECK_FIX_DEL: | 130 | 0 | if (lease->subnet_id_ != id) { | 131 | | | 132 | | // If there is a better subnet, use it. | 133 | 0 | if (id != 0) { | 134 | 0 | LOG_INFO(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FIXED) | 135 | 0 | .arg(lease->addr_.toText()) | 136 | 0 | .arg(lease->subnet_id_) | 137 | 0 | .arg(id); | 138 | 0 | lease->subnet_id_ = id; | 139 | 0 | break; | 140 | 0 | } else { | 141 | | // If not, delete the lease. | 142 | 0 | LOG_INFO(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FAIL_DISCARD) | 143 | 0 | .arg(lease->addr_.toText()) | 144 | 0 | .arg(lease->subnet_id_) | 145 | 0 | .arg(msg.str()); | 146 | 0 | lease.reset(); | 147 | 0 | } | 148 | |
| 149 | 0 | } | 150 | 0 | break; | 151 | | | 152 | 0 | case CfgConsistency::LEASE_CHECK_DEL: | 153 | 0 | if (lease->subnet_id_ != id) { | 154 | 0 | LOG_INFO(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FAIL_DISCARD) | 155 | 0 | .arg(lease->addr_.toText()) | 156 | 0 | .arg(lease->subnet_id_) | 157 | 0 | .arg(msg.str()); | 158 | 0 | lease.reset(); | 159 | 0 | } | 160 | 0 | break; | 161 | | | 162 | 0 | default: | 163 | | // Shouldn't get here but some compilers and analyzers | 164 | | // complain. We'll we treat it as NONE and return the | 165 | | // lease as-is. | 166 | 0 | break; | 167 | | | 168 | 24.4k | } | 169 | | | 170 | | // Additional checks may be implemented in the future here. | 171 | | | 172 | | /// @todo: add a check if the address is within specified dynamic pool | 173 | | /// if not, check if the address is reserved. | 174 | 24.4k | } |
void isc::dhcp::SanityChecker::checkLeaseInternal<boost::shared_ptr<isc::dhcp::Lease6>, boost::shared_ptr<isc::dhcp::CfgSubnets6> >(boost::shared_ptr<isc::dhcp::Lease6>&, boost::shared_ptr<isc::dhcp::CfgConsistency> const&, boost::shared_ptr<isc::dhcp::CfgSubnets6> const&) Line | Count | Source | 76 | 6.03k | const SubnetsType& subnets) { | 77 | | | 78 | 6.03k | auto subnet = subnets->getBySubnetId(lease->subnet_id_); | 79 | 6.03k | if (subnet && subnet->inRange(lease->addr_)) { | 80 | | | 81 | | // If the subnet is defined and the address is in range, we're good. | 82 | |
| 83 | 0 | return; | 84 | 0 | } | 85 | | | 86 | | // Ok, if we got here, that means that either we did not find a subnet | 87 | | // of found it, but it wasn't the right subnet. | 88 | 6.03k | SubnetID id = findSubnetId(lease, subnets); | 89 | | | 90 | | // Prepare a message in the case the check fails. | 91 | 6.03k | std::ostringstream msg; | 92 | 6.03k | if (id != 0) { | 93 | 0 | msg << "the lease should have subnet-id " << id; | 94 | 6.03k | } else { | 95 | 6.03k | msg << "the lease IP address did not belong to a configured subnet"; | 96 | 6.03k | } | 97 | | | 98 | 6.03k | switch (checks->getLeaseSanityCheck()) { | 99 | 6.03k | case CfgConsistency::LEASE_CHECK_WARN: | 100 | 6.03k | if (lease->subnet_id_ != id) { | 101 | | // Print a warning, but return the lease as is. | 102 | 6.03k | LOG_WARN(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FAIL) | 103 | 6.03k | .arg(lease->addr_.toText()) | 104 | 6.03k | .arg(lease->subnet_id_) | 105 | 6.03k | .arg(msg.str()); | 106 | 6.03k | } | 107 | 6.03k | break; | 108 | | | 109 | 0 | case CfgConsistency::LEASE_CHECK_FIX: | 110 | 0 | if (lease->subnet_id_ != id) { | 111 | | | 112 | | // If there is a better subnet, use it. | 113 | 0 | if (id != 0) { | 114 | 0 | LOG_INFO(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FIXED) | 115 | 0 | .arg(lease->addr_.toText()) | 116 | 0 | .arg(lease->subnet_id_) | 117 | 0 | .arg(id); | 118 | 0 | lease->subnet_id_ = id; | 119 | 0 | } else { | 120 | | // If not, return the lease as is. | 121 | 0 | LOG_WARN(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FAIL) | 122 | 0 | .arg(lease->addr_.toText()) | 123 | 0 | .arg(lease->subnet_id_) | 124 | 0 | .arg(msg.str()); | 125 | 0 | } | 126 | 0 | } | 127 | 0 | break; | 128 | | | 129 | 0 | case CfgConsistency::LEASE_CHECK_FIX_DEL: | 130 | 0 | if (lease->subnet_id_ != id) { | 131 | | | 132 | | // If there is a better subnet, use it. | 133 | 0 | if (id != 0) { | 134 | 0 | LOG_INFO(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FIXED) | 135 | 0 | .arg(lease->addr_.toText()) | 136 | 0 | .arg(lease->subnet_id_) | 137 | 0 | .arg(id); | 138 | 0 | lease->subnet_id_ = id; | 139 | 0 | break; | 140 | 0 | } else { | 141 | | // If not, delete the lease. | 142 | 0 | LOG_INFO(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FAIL_DISCARD) | 143 | 0 | .arg(lease->addr_.toText()) | 144 | 0 | .arg(lease->subnet_id_) | 145 | 0 | .arg(msg.str()); | 146 | 0 | lease.reset(); | 147 | 0 | } | 148 | |
| 149 | 0 | } | 150 | 0 | break; | 151 | | | 152 | 0 | case CfgConsistency::LEASE_CHECK_DEL: | 153 | 0 | if (lease->subnet_id_ != id) { | 154 | 0 | LOG_INFO(dhcpsrv_logger, DHCPSRV_LEASE_SANITY_FAIL_DISCARD) | 155 | 0 | .arg(lease->addr_.toText()) | 156 | 0 | .arg(lease->subnet_id_) | 157 | 0 | .arg(msg.str()); | 158 | 0 | lease.reset(); | 159 | 0 | } | 160 | 0 | break; | 161 | | | 162 | 0 | default: | 163 | | // Shouldn't get here but some compilers and analyzers | 164 | | // complain. We'll we treat it as NONE and return the | 165 | | // lease as-is. | 166 | 0 | break; | 167 | | | 168 | 6.03k | } | 169 | | | 170 | | // Additional checks may be implemented in the future here. | 171 | | | 172 | | /// @todo: add a check if the address is within specified dynamic pool | 173 | | /// if not, check if the address is reserved. | 174 | 6.03k | } |
|
175 | | |
176 | | template<typename LeaseType, typename SubnetsType> |
177 | 30.4k | SubnetID SanityChecker::findSubnetId(const LeaseType& lease, const SubnetsType& subnets) { |
178 | 30.4k | auto subnet = subnets->selectSubnet(lease->addr_); |
179 | 30.4k | if (!subnet) { |
180 | 6.03k | return (0); |
181 | 6.03k | } |
182 | | |
183 | 24.4k | return (subnet->getID()); |
184 | 30.4k | } unsigned int isc::dhcp::SanityChecker::findSubnetId<boost::shared_ptr<isc::dhcp::Lease4>, boost::shared_ptr<isc::dhcp::CfgSubnets4> >(boost::shared_ptr<isc::dhcp::Lease4> const&, boost::shared_ptr<isc::dhcp::CfgSubnets4> const&) Line | Count | Source | 177 | 24.4k | SubnetID SanityChecker::findSubnetId(const LeaseType& lease, const SubnetsType& subnets) { | 178 | 24.4k | auto subnet = subnets->selectSubnet(lease->addr_); | 179 | 24.4k | if (!subnet) { | 180 | 0 | return (0); | 181 | 0 | } | 182 | | | 183 | 24.4k | return (subnet->getID()); | 184 | 24.4k | } |
unsigned int isc::dhcp::SanityChecker::findSubnetId<boost::shared_ptr<isc::dhcp::Lease6>, boost::shared_ptr<isc::dhcp::CfgSubnets6> >(boost::shared_ptr<isc::dhcp::Lease6> const&, boost::shared_ptr<isc::dhcp::CfgSubnets6> const&) Line | Count | Source | 177 | 6.03k | SubnetID SanityChecker::findSubnetId(const LeaseType& lease, const SubnetsType& subnets) { | 178 | 6.03k | auto subnet = subnets->selectSubnet(lease->addr_); | 179 | 6.03k | if (!subnet) { | 180 | 6.03k | return (0); | 181 | 6.03k | } | 182 | | | 183 | 0 | return (subnet->getID()); | 184 | 6.03k | } |
|
185 | | |
186 | | } |
187 | | } |