Kea 2.7.6
base_network_parser.cc
Go to the documentation of this file.
1// Copyright (C) 2019-2024 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
7#include <config.h>
8#include <util/triplet.h>
11#include <util/optional.h>
12#include <util/str.h>
13
14using namespace isc::data;
15using namespace isc::util;
16
17namespace isc {
18namespace dhcp {
19
20
21void
23 NetworkPtr& network) {
24 bool has_renew = network_data->contains("renew-timer");
25 bool has_rebind = network_data->contains("rebind-timer");
26 int64_t renew = -1;
27 int64_t rebind = -1;
28
29 if (has_renew) {
30 renew = getInteger(network_data, "renew-timer");
31 if (renew < 0) {
32 isc_throw(DhcpConfigError, "the value of renew-timer ("
33 << renew << ") must be a positive number");
34 }
35 network->setT1(renew);
36 }
37
38 if (has_rebind) {
39 rebind = getInteger(network_data, "rebind-timer");
40 if (rebind < 0) {
41 isc_throw(DhcpConfigError, "the value of rebind-timer ("
42 << rebind << ") must be a positive number");
43 }
44 network->setT2(rebind);
45 }
46
47 if (has_renew && has_rebind && (renew > rebind)) {
48 // The renew-timer value is too large and server logic
49 // later on will end up not sending it. Warn the user but
50 // allow the configuration to pass.
52 .arg(network->getLabel())
53 .arg(renew)
54 .arg(rebind);
55 }
56
57 network->setValid(parseIntTriplet(network_data, "valid-lifetime"));
58
59 if (network_data->contains("store-extended-info")) {
60 network->setStoreExtendedInfo(getBoolean(network_data,
61 "store-extended-info"));
62 }
63
64 if (network_data->contains("reservations-global")) {
65 network->setReservationsGlobal(getBoolean(network_data,
66 "reservations-global"));
67 }
68
69 if (network_data->contains("reservations-in-subnet")) {
70 network->setReservationsInSubnet(getBoolean(network_data,
71 "reservations-in-subnet"));
72 }
73
74 if (network_data->contains("reservations-out-of-pool")) {
75 network->setReservationsOutOfPool(getBoolean(network_data,
76 "reservations-out-of-pool"));
77 }
78}
79
80void
82 NetworkPtr& network) {
83 bool calculate_tee_times = network->getCalculateTeeTimes();
84 if (network_data->contains("calculate-tee-times")) {
85 calculate_tee_times = getBoolean(network_data, "calculate-tee-times");
86 network->setCalculateTeeTimes(calculate_tee_times);
87 }
88
89 Optional<double> t2_percent;
90 if (network_data->contains("t2-percent")) {
91 t2_percent = getDouble(network_data, "t2-percent");
92 }
93
94 Optional<double> t1_percent;
95 if (network_data->contains("t1-percent")) {
96 t1_percent = getDouble(network_data, "t1-percent");
97 }
98 if (calculate_tee_times) {
99 if (!t2_percent.unspecified() && ((t2_percent.get() <= 0.0) ||
100 (t2_percent.get() >= 1.0))) {
101 isc_throw(DhcpConfigError, "t2-percent: " << t2_percent.get()
102 << " is invalid, it must be greater than 0.0 and less than 1.0");
103 }
104
105 if (!t1_percent.unspecified() && ((t1_percent.get() <= 0.0) ||
106 (t1_percent.get() >= 1.0))) {
107 isc_throw(DhcpConfigError, "t1-percent: " << t1_percent.get()
108 << " is invalid it must be greater than 0.0 and less than 1.0");
109 }
110
111 if (!t1_percent.unspecified() && !t2_percent.unspecified() &&
112 (t1_percent.get() >= t2_percent.get())) {
113 isc_throw(DhcpConfigError, "t1-percent: " << t1_percent.get()
114 << " is invalid, it must be less than t2-percent: "
115 << t2_percent.get());
116 }
117 }
118
119 network->setT2Percent(t2_percent);
120 network->setT1Percent(t1_percent);
121}
122
123void
125 NetworkPtr& network) {
126 if (network_data->contains("cache-threshold")) {
127 double cache_threshold = getDouble(network_data, "cache-threshold");
128 if ((cache_threshold <= 0.0) || (cache_threshold >= 1.0)) {
129 isc_throw(DhcpConfigError, "cache-threshold: " << cache_threshold
130 << " is invalid, it must be greater than 0.0 and less than 1.0");
131 }
132 network->setCacheThreshold(cache_threshold);
133 }
134
135 if (network_data->contains("cache-max-age")) {
136 network->setCacheMaxAge(getInteger(network_data, "cache-max-age"));
137 }
138}
139
140void
142 NetworkPtr& network) {
143
144 if (network_data->contains("ddns-send-updates")) {
145 network->setDdnsSendUpdates(getBoolean(network_data, "ddns-send-updates"));
146 }
147
148 if (network_data->contains("ddns-override-no-update")) {
149 network->setDdnsOverrideNoUpdate(getBoolean(network_data, "ddns-override-no-update"));
150 }
151
152 if (network_data->contains("ddns-override-client-update")) {
153 network->setDdnsOverrideClientUpdate(getBoolean(network_data, "ddns-override-client-update"));
154 }
155
156 if (network_data->contains("ddns-replace-client-name")) {
157 network->setDdnsReplaceClientNameMode(getAndConvert<D2ClientConfig::ReplaceClientNameMode,
159 (network_data, "ddns-replace-client-name",
160 "ReplaceClientName mode"));
161 }
162
163 if (network_data->contains("ddns-generated-prefix")) {
164 network->setDdnsGeneratedPrefix(getString(network_data, "ddns-generated-prefix"));
165 }
166
167 if (network_data->contains("ddns-qualifying-suffix")) {
168 network->setDdnsQualifyingSuffix(getString(network_data, "ddns-qualifying-suffix"));
169 }
170
171 std::string hostname_char_set;
172 if (network_data->contains("hostname-char-set")) {
173 hostname_char_set = getString(network_data, "hostname-char-set");
174 network->setHostnameCharSet(hostname_char_set);
175 }
176
177 std::string hostname_char_replacement;
178 if (network_data->contains("hostname-char-replacement")) {
179 hostname_char_replacement = getString(network_data, "hostname-char-replacement");
180 network->setHostnameCharReplacement(hostname_char_replacement);
181 }
182
183 // We need to validate sanitizer values here so we can detect problems and
184 // cause a configuration. We don't retain the compilation because it's not
185 // something we can inherit.
186 if (!hostname_char_set.empty()) {
187 try {
188 str::StringSanitizerPtr sanitizer(new str::StringSanitizer(hostname_char_set,
189 hostname_char_replacement));
190 } catch (const std::exception& ex) {
191 isc_throw(BadValue, "hostname-char-set '" << hostname_char_set
192 << "' is not a valid regular expression");
193 }
194 }
195
196 if (network_data->contains("ddns-update-on-renew")) {
197 network->setDdnsUpdateOnRenew(getBoolean(network_data, "ddns-update-on-renew"));
198 }
199
200 bool has_ddns_ttl = false;
201 uint32_t ddns_ttl = 0;
202 if (network_data->contains("ddns-ttl")) {
203 ddns_ttl = getInteger(network_data, "ddns-ttl");
204 network->setDdnsTtl(ddns_ttl);
205 has_ddns_ttl = true;
206 }
207
208 if (network_data->contains("ddns-ttl-percent")) {
209 if (has_ddns_ttl) {
210 isc_throw(BadValue, "cannot specify both ddns-ttl-percent and ddns-ttl");
211 }
212
213 network->setDdnsTtlPercent(getDouble(network_data, "ddns-ttl-percent"));
214 }
215
216 uint32_t ddns_ttl_min = 0;
217 if (network_data->contains("ddns-ttl-min")) {
218 if (has_ddns_ttl) {
219 isc_throw(BadValue, "cannot specify both ddns-ttl-min and ddns-ttl");
220 }
221
222 ddns_ttl_min = getInteger(network_data, "ddns-ttl-min");
223 network->setDdnsTtlMin(ddns_ttl_min);
224 }
225
226 if (network_data->contains("ddns-ttl-max")) {
227 if (has_ddns_ttl) {
228 isc_throw(BadValue, "cannot specify both ddns-ttl-max and ddns-ttl");
229 }
230
231 uint32_t ddns_ttl_max = getInteger(network_data, "ddns-ttl-max");
232 if (ddns_ttl_max < ddns_ttl_min) {
233 isc_throw(BadValue, "ddns-ttl-max: " << ddns_ttl_max
234 << " must be greater than ddns-ttl-min: " << ddns_ttl_min);
235 }
236
237 network->setDdnsTtlMax(ddns_ttl_max);
238 }
239
240 // For backward compatibility, ddns-conflict-resolution-mode is optional.
241 if (network_data->contains("ddns-conflict-resolution-mode")) {
242 network->setDdnsConflictResolutionMode(getString(network_data,
243 "ddns-conflict-resolution-mode"));
244 }
245}
246
247void
249 NetworkPtr& network) {
250 if (network_data->contains("allocator")) {
251 auto allocator_type = getString(network_data, "allocator");
252 if ((allocator_type != "iterative") && (allocator_type != "random") &&
253 (allocator_type != "flq")) {
254 // Unsupported allocator type used.
255 isc_throw(DhcpConfigError, "supported allocators are: iterative, random and flq");
256 }
257 network->setAllocatorType(allocator_type);
258 }
259}
260
261void
263 Network6Ptr& network) {
264 if (network_data->contains("pd-allocator")) {
265 auto allocator_type = getString(network_data, "pd-allocator");
266 if ((allocator_type != "iterative") && (allocator_type != "random") &&
267 (allocator_type != "flq")) {
268 // Unsupported allocator type used.
269 isc_throw(DhcpConfigError, "supported allocators are: iterative, random and flq");
270 }
271 network->setPdAllocatorType(allocator_type);
272 }
273}
274
275void
277 Network4Ptr& network) {
278 if (network_data->contains("offer-lifetime")) {
279 auto value = getInteger(network_data, "offer-lifetime");
280 if (value < 0) {
281 isc_throw(DhcpConfigError, "the value of offer-lifetime '"
282 << value << "' must be a positive number ("
283 << getPosition("offer-lifetime", network_data) << ")");
284 }
285
286 network->setOfferLft(value);
287 }
288}
289
290void
292 ClassAdderFunc adder_func) {
293 // Try setting up additional client classes.
294 ConstElementPtr req_class_list = params->get("require-client-classes");
295 ConstElementPtr class_list = params->get("evaluate-additional-classes");
296 if (req_class_list) {
297 if (!class_list) {
299 class_list = req_class_list;
300 } else {
302 "cannot specify both 'require-client-classes' and "
303 "'evaluate-additional-classes'. Use only the latter.");
304 }
305 }
306
307 if (class_list) {
308 const std::vector<data::ElementPtr>& classes = class_list->listValue();
309 for (auto const& cclass : classes) {
310 if ((cclass->getType() != Element::string) ||
311 cclass->stringValue().empty()) {
312 isc_throw(DhcpConfigError, "invalid class name (" << cclass->getPosition() << ")");
313 }
314
315 (adder_func)(cclass->stringValue());
316 }
317 }
318}
319
320void
322 ClassAdderFunc adder_func) {
323 // Try setting up client client classes.
324 ConstElementPtr class_elem = params->get("client-class");
325 ConstElementPtr class_list = params->get("client-classes");
326 if (class_elem) {
327 if (!class_list) {
329 if (class_elem->getType() != Element::string) {
330 isc_throw(DhcpConfigError, "invalid class name (" << class_elem->getPosition() << ")");
331 }
332
333 if (!class_elem->stringValue().empty()) {
334 (adder_func)(class_elem->stringValue());
335 }
336 } else {
338 "cannot specify both 'client-class' and "
339 "'client-classes'. Use only the latter.");
340 }
341 }
342
343 if (class_list) {
344 for (auto const& cclass : class_list->listValue()) {
345 if ((cclass->getType() != Element::string) ||
346 cclass->stringValue().empty()) {
347 isc_throw(DhcpConfigError, "invalid class name (" << cclass->getPosition() << ")");
348 }
349
350 (adder_func)(cclass->stringValue());
351 }
352 }
353}
354
355
356} // end of namespace isc::dhcp
357} // end of namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
target_type getAndConvert(isc::data::ConstElementPtr scope, const std::string &name, const std::string &type_name)
Returns a converted value from a scope.
static const data::Element::Position & getPosition(const std::string &name, const data::ConstElementPtr parent)
Utility method that returns position of an element.
static double getDouble(const ConstElementPtr &scope, const std::string &name)
Returns a floating point parameter from a scope.
static std::string getString(isc::data::ConstElementPtr scope, const std::string &name)
Returns a string parameter from a scope.
const isc::util::Triplet< uint32_t > parseIntTriplet(const data::ConstElementPtr &scope, const std::string &name)
Parses an integer triplet.
static bool getBoolean(isc::data::ConstElementPtr scope, const std::string &name)
Returns a boolean parameter from a scope.
static int64_t getInteger(isc::data::ConstElementPtr scope, const std::string &name)
Returns an integer parameter from a scope.
void parseCacheParams(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses parameters related to lease cache settings.
void parseAllocatorParams(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses parameters pertaining to allocator selection.
static void getClientClassesElem(data::ConstElementPtr params, ClassAdderFunc adder_func)
Fetches the element for either 'client-classes' or deprecated 'client-class'.
void parseDdnsParams(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses parameters pertaining to DDNS behavior.
void parseCommon(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses common parameters.
std::function< void(const isc::dhcp::ClientClass &)> ClassAdderFunc
static void getAdditionalClassesElem(data::ConstElementPtr params, ClassAdderFunc adder_func)
Fetches the element for either 'evaluate-additional-classes' or deprecated 'require-client-classes'.
void parseTeePercents(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses parameters related to "percent" timers settings.
void parsePdAllocatorParams(const data::ConstElementPtr &network_data, Network6Ptr &network)
Parses parameters pertaining to prefix delegation allocator selection.
void parseOfferLft(const data::ConstElementPtr &network_data, Network4Ptr &network)
Parses offer-lifetime parameter (v4 only)
static ReplaceClientNameMode stringToReplaceClientNameMode(const std::string &mode_str)
Converts labels to ReplaceClientNameMode enum values.
ReplaceClientNameMode
Defines the client name replacement modes.
To be removed. Please use ConfigError instead.
A template representing an optional value.
Definition optional.h:36
T get() const
Retrieves the encapsulated value.
Definition optional.h:114
void unspecified(bool unspecified)
Modifies the flag that indicates whether the value is specified or unspecified.
Definition optional.h:136
Implements a regular expression based string scrubber.
Definition str.h:222
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition macros.h:26
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition dhcpsrv_log.h:56
boost::shared_ptr< Network4 > Network4Ptr
Pointer to the Network4 object.
Definition network.h:1479
const isc::log::MessageID DHCPSRV_CFGMGR_RENEW_GTR_REBIND
boost::shared_ptr< Network6 > Network6Ptr
Pointer to the Network6 object.
Definition network.h:1484
const isc::log::MessageID DHCPSRV_CLIENT_CLASS_DEPRECATED
const isc::log::MessageID DHCPSRV_REQUIRE_CLIENT_CLASSES_DEPRECATED
boost::shared_ptr< Network > NetworkPtr
Pointer to the Network object.
Definition network.h:73
std::unique_ptr< StringSanitizer > StringSanitizerPtr
Type representing the pointer to the StringSanitizer.
Definition str.h:263
Defines the logger used by the top-level component of kea-lfc.