2024-03-04 12:19:56 +02:00
|
|
|
// Copyright (C) 2019-2024 Internet Systems Consortium, Inc. ("ISC")
|
2019-03-06 09:10:19 +01:00
|
|
|
//
|
|
|
|
// 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>
|
2021-11-10 11:14:00 -05:00
|
|
|
#include <util/triplet.h>
|
2023-02-08 09:41:57 -05:00
|
|
|
#include <dhcpsrv/dhcpsrv_log.h>
|
2019-03-06 09:10:19 +01:00
|
|
|
#include <dhcpsrv/parsers/base_network_parser.h>
|
|
|
|
#include <util/optional.h>
|
2024-03-04 11:49:45 +02:00
|
|
|
#include <util/str.h>
|
2019-03-06 09:10:19 +01:00
|
|
|
|
|
|
|
using namespace isc::data;
|
|
|
|
using namespace isc::util;
|
|
|
|
|
|
|
|
namespace isc {
|
|
|
|
namespace dhcp {
|
|
|
|
|
2024-10-16 14:09:50 -04:00
|
|
|
|
2019-03-06 09:10:19 +01:00
|
|
|
void
|
2020-03-31 16:17:43 -04:00
|
|
|
BaseNetworkParser::parseCommon(const ConstElementPtr& network_data,
|
|
|
|
NetworkPtr& network) {
|
2020-08-18 15:52:46 +03:00
|
|
|
bool has_renew = network_data->contains("renew-timer");
|
|
|
|
bool has_rebind = network_data->contains("rebind-timer");
|
|
|
|
int64_t renew = -1;
|
|
|
|
int64_t rebind = -1;
|
|
|
|
|
|
|
|
if (has_renew) {
|
|
|
|
renew = getInteger(network_data, "renew-timer");
|
|
|
|
if (renew < 0) {
|
2021-08-10 16:19:41 +03:00
|
|
|
isc_throw(DhcpConfigError, "the value of renew-timer ("
|
2020-08-18 15:52:46 +03:00
|
|
|
<< renew << ") must be a positive number");
|
|
|
|
}
|
|
|
|
network->setT1(renew);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (has_rebind) {
|
|
|
|
rebind = getInteger(network_data, "rebind-timer");
|
|
|
|
if (rebind < 0) {
|
2021-08-10 16:19:41 +03:00
|
|
|
isc_throw(DhcpConfigError, "the value of rebind-timer ("
|
2020-08-18 15:52:46 +03:00
|
|
|
<< rebind << ") must be a positive number");
|
|
|
|
}
|
|
|
|
network->setT2(rebind);
|
2019-03-06 09:10:19 +01:00
|
|
|
}
|
|
|
|
|
2020-08-18 15:52:46 +03:00
|
|
|
if (has_renew && has_rebind && (renew > rebind)) {
|
2023-02-08 09:41:57 -05:00
|
|
|
// The renew-timer value is too large and server logic
|
|
|
|
// later on will end up not sending it. Warn the user but
|
|
|
|
// allow the configuration to pass.
|
|
|
|
LOG_WARN(dhcpsrv_logger, DHCPSRV_CFGMGR_RENEW_GTR_REBIND)
|
|
|
|
.arg(network->getLabel())
|
|
|
|
.arg(renew)
|
|
|
|
.arg(rebind);
|
2019-03-06 09:10:19 +01:00
|
|
|
}
|
|
|
|
|
2021-02-16 13:20:40 -05:00
|
|
|
network->setValid(parseIntTriplet(network_data, "valid-lifetime"));
|
2020-03-31 16:17:43 -04:00
|
|
|
|
|
|
|
if (network_data->contains("store-extended-info")) {
|
|
|
|
network->setStoreExtendedInfo(getBoolean(network_data,
|
|
|
|
"store-extended-info"));
|
|
|
|
}
|
2020-11-11 19:06:06 +02:00
|
|
|
|
|
|
|
if (network_data->contains("reservations-global")) {
|
|
|
|
network->setReservationsGlobal(getBoolean(network_data,
|
|
|
|
"reservations-global"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (network_data->contains("reservations-in-subnet")) {
|
|
|
|
network->setReservationsInSubnet(getBoolean(network_data,
|
|
|
|
"reservations-in-subnet"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (network_data->contains("reservations-out-of-pool")) {
|
|
|
|
network->setReservationsOutOfPool(getBoolean(network_data,
|
|
|
|
"reservations-out-of-pool"));
|
|
|
|
}
|
2019-03-06 09:10:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-03-06 16:44:29 +01:00
|
|
|
BaseNetworkParser::parseTeePercents(const ConstElementPtr& network_data,
|
2019-03-06 09:10:19 +01:00
|
|
|
NetworkPtr& network) {
|
|
|
|
bool calculate_tee_times = network->getCalculateTeeTimes();
|
2019-03-06 16:44:29 +01:00
|
|
|
if (network_data->contains("calculate-tee-times")) {
|
2019-06-05 23:22:33 +02:00
|
|
|
calculate_tee_times = getBoolean(network_data, "calculate-tee-times");
|
2019-03-06 09:10:19 +01:00
|
|
|
network->setCalculateTeeTimes(calculate_tee_times);
|
|
|
|
}
|
|
|
|
|
|
|
|
Optional<double> t2_percent;
|
2019-03-06 16:44:29 +01:00
|
|
|
if (network_data->contains("t2-percent")) {
|
|
|
|
t2_percent = getDouble(network_data, "t2-percent");
|
2019-03-06 09:10:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Optional<double> t1_percent;
|
2019-03-06 16:44:29 +01:00
|
|
|
if (network_data->contains("t1-percent")) {
|
|
|
|
t1_percent = getDouble(network_data, "t1-percent");
|
2019-03-06 09:10:19 +01:00
|
|
|
}
|
|
|
|
if (calculate_tee_times) {
|
|
|
|
if (!t2_percent.unspecified() && ((t2_percent.get() <= 0.0) ||
|
|
|
|
(t2_percent.get() >= 1.0))) {
|
|
|
|
isc_throw(DhcpConfigError, "t2-percent: " << t2_percent.get()
|
|
|
|
<< " is invalid, it must be greater than 0.0 and less than 1.0");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!t1_percent.unspecified() && ((t1_percent.get() <= 0.0) ||
|
|
|
|
(t1_percent.get() >= 1.0))) {
|
|
|
|
isc_throw(DhcpConfigError, "t1-percent: " << t1_percent.get()
|
|
|
|
<< " is invalid it must be greater than 0.0 and less than 1.0");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!t1_percent.unspecified() && !t2_percent.unspecified() &&
|
|
|
|
(t1_percent.get() >= t2_percent.get())) {
|
|
|
|
isc_throw(DhcpConfigError, "t1-percent: " << t1_percent.get()
|
|
|
|
<< " is invalid, it must be less than t2-percent: "
|
|
|
|
<< t2_percent.get());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
network->setT2Percent(t2_percent);
|
|
|
|
network->setT1Percent(t1_percent);
|
|
|
|
}
|
|
|
|
|
2020-09-25 16:48:15 +02:00
|
|
|
void
|
|
|
|
BaseNetworkParser::parseCacheParams(const ConstElementPtr& network_data,
|
|
|
|
NetworkPtr& network) {
|
|
|
|
if (network_data->contains("cache-threshold")) {
|
|
|
|
double cache_threshold = getDouble(network_data, "cache-threshold");
|
|
|
|
if ((cache_threshold <= 0.0) || (cache_threshold >= 1.0)) {
|
|
|
|
isc_throw(DhcpConfigError, "cache-threshold: " << cache_threshold
|
|
|
|
<< " is invalid, it must be greater than 0.0 and less than 1.0");
|
|
|
|
}
|
|
|
|
network->setCacheThreshold(cache_threshold);
|
|
|
|
}
|
|
|
|
|
2020-10-02 17:10:31 +02:00
|
|
|
if (network_data->contains("cache-max-age")) {
|
|
|
|
network->setCacheMaxAge(getInteger(network_data, "cache-max-age"));
|
2020-09-25 16:48:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-26 08:33:41 -04:00
|
|
|
void
|
|
|
|
BaseNetworkParser::parseDdnsParams(const data::ConstElementPtr& network_data,
|
|
|
|
NetworkPtr& network) {
|
|
|
|
|
|
|
|
if (network_data->contains("ddns-send-updates")) {
|
|
|
|
network->setDdnsSendUpdates(getBoolean(network_data, "ddns-send-updates"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (network_data->contains("ddns-override-no-update")) {
|
|
|
|
network->setDdnsOverrideNoUpdate(getBoolean(network_data, "ddns-override-no-update"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (network_data->contains("ddns-override-client-update")) {
|
|
|
|
network->setDdnsOverrideClientUpdate(getBoolean(network_data, "ddns-override-client-update"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (network_data->contains("ddns-replace-client-name")) {
|
|
|
|
network->setDdnsReplaceClientNameMode(getAndConvert<D2ClientConfig::ReplaceClientNameMode,
|
|
|
|
D2ClientConfig::stringToReplaceClientNameMode>
|
2019-09-27 15:52:28 -04:00
|
|
|
(network_data, "ddns-replace-client-name",
|
2019-09-26 08:33:41 -04:00
|
|
|
"ReplaceClientName mode"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (network_data->contains("ddns-generated-prefix")) {
|
|
|
|
network->setDdnsGeneratedPrefix(getString(network_data, "ddns-generated-prefix"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (network_data->contains("ddns-qualifying-suffix")) {
|
|
|
|
network->setDdnsQualifyingSuffix(getString(network_data, "ddns-qualifying-suffix"));
|
|
|
|
}
|
2019-09-27 15:52:28 -04:00
|
|
|
|
|
|
|
std::string hostname_char_set;
|
|
|
|
if (network_data->contains("hostname-char-set")) {
|
|
|
|
hostname_char_set = getString(network_data, "hostname-char-set");
|
|
|
|
network->setHostnameCharSet(hostname_char_set);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string hostname_char_replacement;
|
|
|
|
if (network_data->contains("hostname-char-replacement")) {
|
|
|
|
hostname_char_replacement = getString(network_data, "hostname-char-replacement");
|
|
|
|
network->setHostnameCharReplacement(hostname_char_replacement);
|
|
|
|
}
|
|
|
|
|
2021-01-22 01:36:41 +02:00
|
|
|
// We need to validate sanitizer values here so we can detect problems and
|
2019-10-09 15:08:19 -04:00
|
|
|
// cause a configuration. We don't retain the compilation because it's not
|
2019-09-27 15:52:28 -04:00
|
|
|
// something we can inherit.
|
|
|
|
if (!hostname_char_set.empty()) {
|
|
|
|
try {
|
|
|
|
str::StringSanitizerPtr sanitizer(new str::StringSanitizer(hostname_char_set,
|
|
|
|
hostname_char_replacement));
|
|
|
|
} catch (const std::exception& ex) {
|
|
|
|
isc_throw(BadValue, "hostname-char-set '" << hostname_char_set
|
|
|
|
<< "' is not a valid regular expression");
|
|
|
|
}
|
|
|
|
}
|
2020-10-06 15:21:25 -04:00
|
|
|
|
|
|
|
if (network_data->contains("ddns-update-on-renew")) {
|
|
|
|
network->setDdnsUpdateOnRenew(getBoolean(network_data, "ddns-update-on-renew"));
|
|
|
|
}
|
2020-10-19 11:48:18 -04:00
|
|
|
|
2023-03-21 11:53:32 -04:00
|
|
|
if (network_data->contains("ddns-ttl-percent")) {
|
|
|
|
network->setDdnsTtlPercent(getDouble(network_data, "ddns-ttl-percent"));
|
|
|
|
}
|
2023-05-31 13:51:19 -04:00
|
|
|
|
2023-06-05 10:51:40 -04:00
|
|
|
// For backward compatibility, ddns-conflict-resolution-mode is optional.
|
2023-05-31 13:51:19 -04:00
|
|
|
if (network_data->contains("ddns-conflict-resolution-mode")) {
|
|
|
|
network->setDdnsConflictResolutionMode(getString(network_data,
|
|
|
|
"ddns-conflict-resolution-mode"));
|
|
|
|
}
|
2019-09-26 08:33:41 -04:00
|
|
|
}
|
|
|
|
|
2022-11-21 17:30:31 +01:00
|
|
|
void
|
|
|
|
BaseNetworkParser::parseAllocatorParams(const data::ConstElementPtr& network_data,
|
|
|
|
NetworkPtr& network) {
|
|
|
|
if (network_data->contains("allocator")) {
|
|
|
|
auto allocator_type = getString(network_data, "allocator");
|
2023-03-16 19:09:05 +01:00
|
|
|
if ((allocator_type != "iterative") && (allocator_type != "random") &&
|
|
|
|
(allocator_type != "flq")) {
|
2022-11-21 17:30:31 +01:00
|
|
|
// Unsupported allocator type used.
|
2023-03-16 19:09:05 +01:00
|
|
|
isc_throw(DhcpConfigError, "supported allocators are: iterative, random and flq");
|
2022-11-21 17:30:31 +01:00
|
|
|
}
|
|
|
|
network->setAllocatorType(allocator_type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
BaseNetworkParser::parsePdAllocatorParams(const data::ConstElementPtr& network_data,
|
|
|
|
Network6Ptr& network) {
|
|
|
|
if (network_data->contains("pd-allocator")) {
|
|
|
|
auto allocator_type = getString(network_data, "pd-allocator");
|
2023-03-16 19:09:05 +01:00
|
|
|
if ((allocator_type != "iterative") && (allocator_type != "random") &&
|
|
|
|
(allocator_type != "flq")) {
|
2022-11-21 17:30:31 +01:00
|
|
|
// Unsupported allocator type used.
|
2023-03-16 19:09:05 +01:00
|
|
|
isc_throw(DhcpConfigError, "supported allocators are: iterative, random and flq");
|
2022-11-21 17:30:31 +01:00
|
|
|
}
|
|
|
|
network->setPdAllocatorType(allocator_type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-03 09:56:35 -05:00
|
|
|
void
|
|
|
|
BaseNetworkParser::parseOfferLft(const data::ConstElementPtr& network_data,
|
|
|
|
Network4Ptr& network) {
|
2023-03-06 10:25:24 -05:00
|
|
|
if (network_data->contains("offer-lifetime")) {
|
|
|
|
auto value = getInteger(network_data, "offer-lifetime");
|
2023-03-03 09:56:35 -05:00
|
|
|
if (value < 0) {
|
2023-03-06 10:25:24 -05:00
|
|
|
isc_throw(DhcpConfigError, "the value of offer-lifetime '"
|
2023-03-03 09:56:35 -05:00
|
|
|
<< value << "' must be a positive number ("
|
2023-03-06 10:25:24 -05:00
|
|
|
<< getPosition("offer-lifetime", network_data) << ")");
|
2023-03-03 09:56:35 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
network->setOfferLft(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-16 14:09:50 -04:00
|
|
|
void
|
|
|
|
BaseNetworkParser::getAdditionalClassesElem(ConstElementPtr params,
|
|
|
|
ClassAdderFunc adder_func) {
|
|
|
|
// Try setting up additional lient classes.
|
|
|
|
ConstElementPtr req_class_list = params->get("require-client-classes");
|
|
|
|
ConstElementPtr class_list = params->get("evaluate-additional-classes");
|
|
|
|
if (req_class_list) {
|
|
|
|
if (!class_list) {
|
|
|
|
LOG_WARN(dhcpsrv_logger, DHCPSRV_REQUIRE_CLIENT_CLASSES_DEPRECATED);
|
|
|
|
class_list = req_class_list;
|
|
|
|
} else {
|
|
|
|
isc_throw(isc::dhcp::DhcpConfigError,
|
|
|
|
"cannot specify both 'require-client-classes' and "
|
|
|
|
"'evaluate-additional-classes'. Use only the latter.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (class_list) {
|
|
|
|
const std::vector<data::ElementPtr>& classes = class_list->listValue();
|
|
|
|
for (auto const& cclass : classes) {
|
|
|
|
if ((cclass->getType() != Element::string) ||
|
|
|
|
cclass->stringValue().empty()) {
|
|
|
|
isc_throw(DhcpConfigError, "invalid class name (" << cclass->getPosition() << ")");
|
|
|
|
}
|
|
|
|
|
|
|
|
(adder_func)(cclass->stringValue());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-03-03 09:56:35 -05:00
|
|
|
|
2019-03-06 09:10:19 +01:00
|
|
|
} // end of namespace isc::dhcp
|
|
|
|
} // end of namespace isc
|