1 // Copyright (C) 2019-2021 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 <dhcpsrv/triplet.h>
9 #include <dhcpsrv/parsers/base_network_parser.h>
10 #include <util/optional.h>
11 #include <util/strutil.h>
12
13 using namespace isc::data;
14 using namespace isc::util;
15
16 namespace isc {
17 namespace dhcp {
18
19 void
moveReservationMode(ElementPtr config)20 BaseNetworkParser::moveReservationMode(ElementPtr config) {
21 if (!config->contains("reservation-mode")) {
22 return;
23 }
24 if (config->contains("reservations-global") ||
25 config->contains("reservations-in-subnet") ||
26 config->contains("reservations-out-of-pool")) {
27 isc_throw(DhcpConfigError, "invalid use of both 'reservation-mode'"
28 " and one of 'reservations-global', 'reservations-in-subnet'"
29 " or 'reservations-out-of-pool' parameters");
30 }
31 std::string hr_mode = getString(config, "reservation-mode");
32 if ((hr_mode == "disabled") || (hr_mode == "off")) {
33 config->set("reservations-global", Element::create(false));
34 config->set("reservations-in-subnet", Element::create(false));
35 } else if (hr_mode == "out-of-pool") {
36 config->set("reservations-global", Element::create(false));
37 config->set("reservations-in-subnet", Element::create(true));
38 config->set("reservations-out-of-pool", Element::create(true));
39 } else if (hr_mode == "global") {
40 config->set("reservations-global", Element::create(true));
41 config->set("reservations-in-subnet", Element::create(false));
42 } else if (hr_mode == "all") {
43 config->set("reservations-global", Element::create(false));
44 config->set("reservations-in-subnet", Element::create(true));
45 config->set("reservations-out-of-pool", Element::create(false));
46 } else {
47 isc_throw(DhcpConfigError, "invalid reservation-mode parameter: '"
48 << hr_mode << "' ("
49 << getPosition("reservation-mode", config) << ")");
50 }
51 config->remove("reservation-mode");
52 }
53
54 void
parseCommon(const ConstElementPtr & network_data,NetworkPtr & network)55 BaseNetworkParser::parseCommon(const ConstElementPtr& network_data,
56 NetworkPtr& network) {
57 bool has_renew = network_data->contains("renew-timer");
58 bool has_rebind = network_data->contains("rebind-timer");
59 int64_t renew = -1;
60 int64_t rebind = -1;
61
62 if (has_renew) {
63 renew = getInteger(network_data, "renew-timer");
64 if (renew < 0) {
65 isc_throw(DhcpConfigError, "the value of renew-timer ("
66 << renew << ") must be a positive number");
67 }
68 network->setT1(renew);
69 }
70
71 if (has_rebind) {
72 rebind = getInteger(network_data, "rebind-timer");
73 if (rebind < 0) {
74 isc_throw(DhcpConfigError, "the value of rebind-timer ("
75 << rebind << ") must be a positive number");
76 }
77 network->setT2(rebind);
78 }
79
80 if (has_renew && has_rebind && (renew > rebind)) {
81 isc_throw(DhcpConfigError, "the value of renew-timer (" << renew
82 << ") is greater than the value of rebind-timer ("
83 << rebind << ")");
84 }
85
86 network->setValid(parseIntTriplet(network_data, "valid-lifetime"));
87
88 if (network_data->contains("store-extended-info")) {
89 network->setStoreExtendedInfo(getBoolean(network_data,
90 "store-extended-info"));
91 }
92
93 if (network_data->contains("reservations-global")) {
94 network->setReservationsGlobal(getBoolean(network_data,
95 "reservations-global"));
96 }
97
98 if (network_data->contains("reservations-in-subnet")) {
99 network->setReservationsInSubnet(getBoolean(network_data,
100 "reservations-in-subnet"));
101 }
102
103 if (network_data->contains("reservations-out-of-pool")) {
104 network->setReservationsOutOfPool(getBoolean(network_data,
105 "reservations-out-of-pool"));
106 }
107 }
108
109 void
parseTeePercents(const ConstElementPtr & network_data,NetworkPtr & network)110 BaseNetworkParser::parseTeePercents(const ConstElementPtr& network_data,
111 NetworkPtr& network) {
112 bool calculate_tee_times = network->getCalculateTeeTimes();
113 if (network_data->contains("calculate-tee-times")) {
114 calculate_tee_times = getBoolean(network_data, "calculate-tee-times");
115 network->setCalculateTeeTimes(calculate_tee_times);
116 }
117
118 Optional<double> t2_percent;
119 if (network_data->contains("t2-percent")) {
120 t2_percent = getDouble(network_data, "t2-percent");
121 }
122
123 Optional<double> t1_percent;
124 if (network_data->contains("t1-percent")) {
125 t1_percent = getDouble(network_data, "t1-percent");
126 }
127 if (calculate_tee_times) {
128 if (!t2_percent.unspecified() && ((t2_percent.get() <= 0.0) ||
129 (t2_percent.get() >= 1.0))) {
130 isc_throw(DhcpConfigError, "t2-percent: " << t2_percent.get()
131 << " is invalid, it must be greater than 0.0 and less than 1.0");
132 }
133
134 if (!t1_percent.unspecified() && ((t1_percent.get() <= 0.0) ||
135 (t1_percent.get() >= 1.0))) {
136 isc_throw(DhcpConfigError, "t1-percent: " << t1_percent.get()
137 << " is invalid it must be greater than 0.0 and less than 1.0");
138 }
139
140 if (!t1_percent.unspecified() && !t2_percent.unspecified() &&
141 (t1_percent.get() >= t2_percent.get())) {
142 isc_throw(DhcpConfigError, "t1-percent: " << t1_percent.get()
143 << " is invalid, it must be less than t2-percent: "
144 << t2_percent.get());
145 }
146 }
147
148 network->setT2Percent(t2_percent);
149 network->setT1Percent(t1_percent);
150 }
151
152 void
parseCacheParams(const ConstElementPtr & network_data,NetworkPtr & network)153 BaseNetworkParser::parseCacheParams(const ConstElementPtr& network_data,
154 NetworkPtr& network) {
155 if (network_data->contains("cache-threshold")) {
156 double cache_threshold = getDouble(network_data, "cache-threshold");
157 if ((cache_threshold <= 0.0) || (cache_threshold >= 1.0)) {
158 isc_throw(DhcpConfigError, "cache-threshold: " << cache_threshold
159 << " is invalid, it must be greater than 0.0 and less than 1.0");
160 }
161 network->setCacheThreshold(cache_threshold);
162 }
163
164 if (network_data->contains("cache-max-age")) {
165 network->setCacheMaxAge(getInteger(network_data, "cache-max-age"));
166 }
167 }
168
169 void
parseDdnsParams(const data::ConstElementPtr & network_data,NetworkPtr & network)170 BaseNetworkParser::parseDdnsParams(const data::ConstElementPtr& network_data,
171 NetworkPtr& network) {
172
173 if (network_data->contains("ddns-send-updates")) {
174 network->setDdnsSendUpdates(getBoolean(network_data, "ddns-send-updates"));
175 }
176
177 if (network_data->contains("ddns-override-no-update")) {
178 network->setDdnsOverrideNoUpdate(getBoolean(network_data, "ddns-override-no-update"));
179 }
180
181 if (network_data->contains("ddns-override-client-update")) {
182 network->setDdnsOverrideClientUpdate(getBoolean(network_data, "ddns-override-client-update"));
183 }
184
185 if (network_data->contains("ddns-replace-client-name")) {
186 network->setDdnsReplaceClientNameMode(getAndConvert<D2ClientConfig::ReplaceClientNameMode,
187 D2ClientConfig::stringToReplaceClientNameMode>
188 (network_data, "ddns-replace-client-name",
189 "ReplaceClientName mode"));
190 }
191
192 if (network_data->contains("ddns-generated-prefix")) {
193 network->setDdnsGeneratedPrefix(getString(network_data, "ddns-generated-prefix"));
194 }
195
196 if (network_data->contains("ddns-qualifying-suffix")) {
197 network->setDdnsQualifyingSuffix(getString(network_data, "ddns-qualifying-suffix"));
198 }
199
200 std::string hostname_char_set;
201 if (network_data->contains("hostname-char-set")) {
202 hostname_char_set = getString(network_data, "hostname-char-set");
203 network->setHostnameCharSet(hostname_char_set);
204 }
205
206 std::string hostname_char_replacement;
207 if (network_data->contains("hostname-char-replacement")) {
208 hostname_char_replacement = getString(network_data, "hostname-char-replacement");
209 network->setHostnameCharReplacement(hostname_char_replacement);
210 }
211
212 // We need to validate sanitizer values here so we can detect problems and
213 // cause a configuration. We don't retain the compilation because it's not
214 // something we can inherit.
215 if (!hostname_char_set.empty()) {
216 try {
217 str::StringSanitizerPtr sanitizer(new str::StringSanitizer(hostname_char_set,
218 hostname_char_replacement));
219 } catch (const std::exception& ex) {
220 isc_throw(BadValue, "hostname-char-set '" << hostname_char_set
221 << "' is not a valid regular expression");
222 }
223 }
224
225 if (network_data->contains("ddns-update-on-renew")) {
226 network->setDdnsUpdateOnRenew(getBoolean(network_data, "ddns-update-on-renew"));
227 }
228
229 if (network_data->contains("ddns-use-conflict-resolution")) {
230 network->setDdnsUseConflictResolution(getBoolean(network_data, "ddns-use-conflict-resolution"));
231 }
232 }
233
234 } // end of namespace isc::dhcp
235 } // end of namespace isc
236