Kea 2.7.5
adaptor_config.cc
Go to the documentation of this file.
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
7#include <config.h>
8
9#include <dhcpsrv/subnet_id.h>
10#include <yang/adaptor_config.h>
11
12using namespace std;
13using namespace isc::data;
14using namespace isc::dhcp;
15
16namespace {
17const string DHCP4_SPACE = "dhcp4";
18const string DHCP6_SPACE = "dhcp6";
19}
20
21namespace isc {
22namespace yang {
23
24bool
26 bool have_ids = true;
27
28 if (!subnets || subnets->empty()) {
29 // There are no subnets defined, so technically there are no ids.
30 // However, the flag is used to determine whether the code later
31 // needs to call assignIDs. Since there is no need to assign
32 // anything, the code returns true here.
33 return (true);
34 }
35
36 // If there are subnets defined, let's go over them one by one and
37 // collect subnet-ids used in them.
38 for (ElementPtr const& subnet : subnets->listValue()) {
39 if (!collectID(subnet, set)) {
40 have_ids = false;
41 }
42 }
43 return (have_ids);
44}
45
46bool
48 SubnetIDSet& set,
49 const string& subsel) {
50 if (!networks || networks->empty()) {
51 // There are no shared networks defined, so technically there are no
52 // ids. However, the flag is used to determine whether the code later
53 // needs to call assignIDs. Since there is no need to assign anything,
54 // the code returns true here.
55 return (true);
56 }
57
58 // This determines if EVERY subnet has subnet-id defined.
59 bool have_ids = true;
60 for (size_t i = 0; i < networks->size(); ++i) {
61 ElementPtr network = networks->getNonConst(i);
62 ConstElementPtr subnets = network->get(subsel);
63 if (subnets) {
64 if (!subnets->empty()) {
65 // If there are subnets, collect their subnet-ids. If any
66 // of them doesn't have a subnet-id, return false.
67 if (!subnetsCollectID(subnets, set)) {
68 have_ids = false;
69 }
70 } else {
71 // There's empty subnets list, so just remove it.
72 network->remove(subsel);
73 }
74 }
75 }
76 return (have_ids);
77}
78
79void
81 SubnetID& next) {
82 if (!subnets || subnets->empty()) {
83 // nothing to do here.
84 return;
85 }
86
87 for (size_t i = 0; i < subnets->size(); ++i) {
88 ElementPtr subnet = subnets->getNonConst(i);
89 assignID(subnet, set, next);
90 }
91}
92
93void
95 SubnetIDSet& set, SubnetID& next,
96 const string& subsel) {
97 if (!networks || networks->empty()) {
98 // nothing to do here.
99 return;
100 }
101
102 for (ElementPtr const& network : networks->listValue()) {
103 ConstElementPtr subnets = network->get(subsel);
104 if (!subnets || subnets->empty()) {
105 continue;
106 }
107
108 for (size_t i = 0; i < subnets->size(); ++i) {
109 ElementPtr subnet = subnets->getNonConst(i);
110 assignID(subnet, set, next);
111 }
112 }
113}
114
115void
117 if (!pools || pools->empty()) {
118 // nothing to do here.
119 return;
120 }
121
122 // Canonize (clean up name, remove extra spaces, add one space where
123 // needed) every pool on the list.
124 for (size_t i = 0; i < pools->size(); ++i) {
125 ElementPtr pool = pools->getNonConst(i);
127 }
128}
129
130void
132 if (!subnets || subnets->empty()) {
133 // nothing to do here.
134 return;
135 }
136
137 for (ElementPtr const& subnet : subnets->listValue()) {
138 sanitizePools(subnet->get("pools"));
139 }
140}
141
142void
144 const string& subsel) {
145 if (!networks || networks->empty()) {
146 // nothing to do here.
147 return;
148 }
149
150 for (ElementPtr const& network : networks->listValue()) {
151 sanitizePoolsInSubnets(network->get(subsel));
152 }
153}
154
155void
157 const string& space,
158 OptionCodes& codes) {
159 if (!defs || defs->empty()) {
160 // nothing to do here.
161 return;
162 }
163
164 // Do sanity checks on every option definition and fill any missing
165 // fields with default values.
166 for (size_t i = 0; i < defs->size(); ++i) {
167 ElementPtr def = defs->getNonConst(i);
168 checkCode(def);
169 checkType(def);
170 setSpace(def, space);
171 collect(def, codes);
172 }
173}
174
175void
177 const string& space,
178 const OptionCodes& codes) {
179 if (!options || options->empty()) {
180 // nothing to do here.
181 return;
182 }
183
184 // Sanitize option-data. The only missing elements we may possibly
185 // need to fill are option space and option code.
186 for (size_t i = 0; i < options->size(); ++i) {
187 ElementPtr option = options->getNonConst(i);
188 setSpace(option, space);
189 setCode(option, codes);
190 }
191}
192
193void
195 const string& space,
196 OptionCodes& codes) {
197 if (!classes || classes->empty()) {
198 // nothing to do here.
199 return;
200 }
201
202 // For every client class defined...
203 for (size_t i = 0; i < classes->size(); ++i) {
204 ElementPtr cclass = classes->getNonConst(i);
205
206 if (space == DHCP4_SPACE) {
207 ConstElementPtr options = cclass->get("option-def");
208 if (options) {
209 if (!options->empty()) {
210 // If present, sanitize it.
211 sanitizeOptionDefList(options, space, codes);
212 } else {
213 // If empty, remove it.
214 cclass->remove("option-def");
215 }
216 }
217 }
218
219 // also sanitize option data.
220 ConstElementPtr options = cclass->get("option-data");
221 if (options) {
222 if (!options->empty()) {
223 // If present, sanitize it.
224 sanitizeOptionDataList(options, space, codes);
225 } else {
226 // If empty, remove it.
227 cclass->remove("option-data");
228 }
229 }
230 }
231}
232
233void
235 const OptionCodes& codes) {
236 if (!pools || pools->empty()) {
237 // nothing to do here.
238 return;
239 }
240
241 for (size_t i = 0; i < pools->size(); ++i) {
242 ElementPtr pool = pools->getNonConst(i);
243 ConstElementPtr options = pool->get("option-data");
244 if (options) {
245 if (!options->empty()) {
246 sanitizeOptionDataList(options, space, codes);
247 } else {
248 pool->remove("option-data");
249 }
250 }
251 }
252}
253
254void
256 const OptionCodes& codes) {
257 if (!hosts || hosts->empty()) {
258 // nothing to do here.
259 return;
260 }
261
262 for (size_t i = 0; i < hosts->size(); ++i) {
263 ElementPtr host = hosts->getNonConst(i);
264 ConstElementPtr options = host->get("option-data");
265 if (options) {
266 if (!options->empty()) {
267 sanitizeOptionDataList(options, space, codes);
268 } else {
269 host->remove("option-data");
270 }
271 }
272 }
273}
274
275void
277 const string& space,
278 const OptionCodes& codes) {
279 if (!subnets || subnets->empty()) {
280 // nothing to do here.
281 return;
282 }
283
284 for (size_t i = 0; i < subnets->size(); ++i) {
285 ElementPtr subnet = subnets->getNonConst(i);
286
287 // Let's try to sanitize option-data first.
288 ConstElementPtr options = subnet->get("option-data");
289 if (options) {
290 if (!options->empty()) {
291 sanitizeOptionDataList(options, space, codes);
292 } else {
293 subnet->remove("option-data");
294 }
295 }
296
297 // Then try to sanitize pools.
298 ConstElementPtr pools = subnet->get("pools");
299 if (pools) {
300 if (!pools->empty()) {
301 sanitizeOptionPools(pools, space, codes);
302 } else {
303 subnet->remove("pools");
304 }
305 }
306
307 // If this is v6, also sanitize pd-pools.
308 if (space == DHCP6_SPACE) {
309 ConstElementPtr pd_pools = subnet->get("pd-pools");
310 if (pd_pools) {
311 if (!pd_pools->empty()) {
312 sanitizeOptionPools(pd_pools, space, codes);
313 } else {
314 subnet->remove("pd-pools");
315 }
316 }
317 }
318
319 // Finally, sanitize host reservations.
320 ConstElementPtr hosts = subnet->get("reservations");
321 if (hosts) {
322 if (!hosts->empty()) {
323 sanitizeOptionHosts(hosts, space, codes);
324 } else {
325 subnet->remove("reservations");
326 }
327 }
328 }
329}
330
331void
333 const string& space,
334 const OptionCodes& codes) {
335 if (!networks || networks->empty()) {
336 // nothing to do here.
337 return;
338 }
339
340 // For every shared network...
341 for (size_t i = 0; i < networks->size(); ++i) {
342 ElementPtr network = networks->getNonConst(i);
343
344 // try to sanitize shared network options first.
345 ConstElementPtr options = network->get("option-data");
346 if (options) {
347 if (!options->empty()) {
348 sanitizeOptionDataList(options, space, codes);
349 } else {
350 network->remove("option-data");
351 }
352 }
353 string subnet = "subnet";
354 if (space == DHCP4_SPACE) {
355 subnet += "4";
356 } else {
357 subnet += "6";
358 }
359
360 // Now try to sanitize subnets.
361 ConstElementPtr subnets = network->get(subnet);
362 if (subnets) {
363 if (!subnets->empty()) {
364 sanitizeOptionSubnets(subnets, space, codes);
365 } else {
366 network->remove(subnet);
367 }
368 }
369 }
370}
371
372void
374 if (!pools || pools->empty()) {
375 // nothing to do here.
376 return;
377 }
378
379 for (size_t i = 0; i < pools->size(); ++i) {
380 ElementPtr pool = pools->getNonConst(i);
381 ConstElementPtr require = pool->get("require-client-classes");
382 if (require && require->empty()) {
383 pool->remove("require-client-classes");
384 }
385 }
386}
387
388void
390 if (!subnets || subnets->empty()) {
391 // nothing to do here.
392 return;
393 }
394
395 for (size_t i = 0; i < subnets->size(); ++i) {
396 ElementPtr subnet = subnets->getNonConst(i);
397 sanitizeRequireClassesPools(subnet->get("pools"));
398 sanitizeRequireClassesPools(subnet->get("pd-pools"));
399 ConstElementPtr require = subnet->get("require-client-classes");
400 if (require && require->empty()) {
401 subnet->remove("require-client-classes");
402 }
403 }
404}
405
406void
408 const string& subsel) {
409 if (!networks || networks->empty()) {
410 // nothing to do here.
411 return;
412 }
413
414 for (size_t i = 0; i < networks->size(); ++i) {
415 ElementPtr network = networks->getNonConst(i);
416 sanitizeRequireClassesSubnets(network->get(subsel));
417 ConstElementPtr require = network->get("require-client-classes");
418 if (require && require->empty()) {
419 network->remove("require-client-classes");
420 }
421 }
422}
423
424void
426
427 if (!hosts || hosts->empty()) {
428 // nothing to do here.
429 return;
430 }
431
432 for (size_t i = 0; i < hosts->size(); ++i) {
433 ElementPtr host = hosts->getNonConst(i);
434 quoteIdentifier(host);
435 }
436}
437
438void
440
441 if (!subnets || subnets->empty()) {
442 // nothing to do here.
443 return;
444 }
445
446 for (ElementPtr const& subnet : subnets->listValue()) {
447 sanitizeHostList(subnet->get("reservations"));
448 }
449}
450
451void
453 const string& space) {
454 if (!networks || networks->empty()) {
455 // nothing to do here.
456 return;
457 }
458
459 for (ElementPtr const& network : networks->listValue()) {
460 if (space == DHCP4_SPACE) {
461 sanitizeHostSubnets(network->get("subnet4"));
462 } else {
463 sanitizeHostSubnets(network->get("subnet6"));
464 }
465 }
466}
467
468void
470 if (!subnets || subnets->empty()) {
471 // nothing to do here.
472 return;
473 }
474
475 for (size_t i = 0; i < subnets->size(); ++i) {
476 ElementPtr subnet = subnets->getNonConst(i);
477 updateRelay(subnet);
478 }
479}
480
481void
483 const string& subsel) {
484 if (!networks || networks->empty()) {
485 // nothing to do here.
486 return;
487 }
488
489 for (size_t i = 0; i < networks->size(); ++i) {
490 ElementPtr network = networks->getNonConst(i);
491 updateRelay(network);
492 sanitizeRelaySubnets(network->get(subsel));
493 }
494}
495
496void
498 ConstElementPtr database = dhcp->get("hosts-database");
499 if (!database) {
500 // nothing to do here.
501 return;
502 }
503
504 dhcp->remove("hosts-database");
506 list->add(copy(database, 0));
507 dhcp->set("hosts-databases", list);
508}
509
510void
512 ConstElementPtr options = dhcp->get("relay-supplied-options");
513 if (!options || !options->empty()) {
514 // nothing to do here.
515 return;
516 }
517 dhcp->remove("relay-supplied-options");
518}
519
520void
521AdaptorConfig::preProcess(ElementPtr dhcp, const string& subsel,
522 const string& space) {
523 if (!dhcp) {
524 isc_throw(BadValue, "preProcess: null DHCP config");
525 }
526 bool have_ids = true;
527 SubnetIDSet set;
528 ConstElementPtr subnets = dhcp->get(subsel);
529 if (subnets) {
530 if (!subnets->empty()) {
531 if (!subnetsCollectID(subnets, set)) {
532 have_ids = false;
533 }
534 } else {
535 dhcp->remove(subsel);
536 }
537 }
538 ConstElementPtr networks = dhcp->get("shared-networks");
539 if (networks) {
540 if (!networks->empty()) {
541 if (!sharedNetworksCollectID(networks, set, subsel)) {
542 have_ids = false;
543 }
544 } else {
545 dhcp->remove("shared-networks");
546 }
547 }
548
549 if (!have_ids) {
550 SubnetID next(1);
551 subnetsAssignID(subnets, set, next);
552 sharedNetworksAssignID(networks, set, next, subsel);
553 }
554
555 OptionCodes codes;
556 initCodes(codes, space);
557 ConstElementPtr defs = dhcp->get("option-def");
558 if (defs) {
559 if (!defs->empty()) {
560 sanitizeOptionDefList(defs, space, codes);
561 } else {
562 dhcp->remove("option-def");
563 }
564 }
565 ConstElementPtr options = dhcp->get("option-data");
566 if (options) {
567 if (!options->empty()) {
568 sanitizeOptionDataList(options, space, codes);
569 } else {
570 dhcp->remove("option-data");
571 }
572 }
573 ConstElementPtr classes = dhcp->get("client-classes");
574 if (classes) {
575 if (!classes->empty()) {
576 sanitizeOptionClasses(classes, space, codes);
577 } else {
578 dhcp->remove("client-classes");
579 }
580 }
581 ConstElementPtr hosts = dhcp->get("reservations");
582 if (hosts) {
583 if (!hosts->empty()) {
584 sanitizeHostList(hosts);
585 sanitizeOptionHosts(hosts, space, codes);
586 } else {
587 dhcp->remove("reservations");
588 }
589 }
590 sanitizeOptionSubnets(subnets, space, codes);
591 sanitizeOptionSharedNetworks(networks, space, codes);
592
593 sanitizePoolsInSubnets(subnets);
594 sanitizePoolsInSharedNetworks(networks, subsel);
595
596 sanitizeHostSubnets(subnets);
597 SanitizeHostsInSharedNetworks(networks, space);
598
599 sanitizeRelaySubnets(subnets);
600 sanitizeRelayInSharedNetworks(networks, subsel);
601
603 requireClassesSharedNetworks(networks, subsel);
604
605 sanitizeDatabase(dhcp);
606
607 if (space == DHCP6_SPACE) {
609 }
610}
611
612void
614 if (!config) {
615 isc_throw(BadValue, "preProcess4: null config");
616 }
617 if (config->getType() != Element::map) {
618 isc_throw(BadValue, "preProcess4: not map: " << config->str());
619 }
620 if (config->contains("Logging")) {
621 isc_throw(BadValue, "preProcess4: got Logging object");
622 }
623 ConstElementPtr dhcp = config->get("Dhcp4");
624 if (!dhcp) {
625 return;
626 }
627 ElementPtr mutable_dhcp(copy(dhcp, 0));
628 preProcess(mutable_dhcp, "subnet4", DHCP4_SPACE);
629 config->set("Dhcp4", mutable_dhcp);
630}
631
632void
634 if (!config) {
635 isc_throw(BadValue, "preProcess6: null config");
636 }
637 if (config->getType() != Element::map) {
638 isc_throw(BadValue, "preProcess6: not map: " << config->str());
639 }
640 if (config->contains("Logging")) {
641 isc_throw(BadValue, "preProcess6: got Logging object");
642 }
643 ConstElementPtr dhcp = config->get("Dhcp6");
644 if (!dhcp) {
645 return;
646 }
647 ElementPtr mutable_dhcp(copy(dhcp, 0));
648 preProcess(mutable_dhcp, "subnet6", DHCP6_SPACE);
649 config->set("Dhcp6", mutable_dhcp);
650}
651
652} // namespace yang
653} // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:299
static void sanitizeRequireClassesPools(isc::data::ConstElementPtr pools)
Process require client classes in a pool list.
static void subnetsAssignID(isc::data::ConstElementPtr subnets, isc::dhcp::SubnetIDSet &set, isc::dhcp::SubnetID &next)
Assigns subnet-id to every subnet in a subnet list.
static void sanitizeOptionSharedNetworks(isc::data::ConstElementPtr networks, const std::string &space, const OptionCodes &codes)
Set missing option codes to a shared network list.
static void sharedNetworksAssignID(isc::data::ConstElementPtr networks, isc::dhcp::SubnetIDSet &set, isc::dhcp::SubnetID &next, const std::string &subsel)
Assigns subnet-id to every subnet in a shared network list.
static void sanitizeRelaySubnets(isc::data::ConstElementPtr subnets)
Sanitizes relay information in subnets in a subnet list.
static void sanitizeHostSubnets(isc::data::ConstElementPtr subnets)
Process host reservations in a subnet list.
static bool subnetsCollectID(isc::data::ConstElementPtr subnets, isc::dhcp::SubnetIDSet &set)
Collects subnet-ids on all subnets.
static void preProcess4(isc::data::ElementPtr config)
Pre process a DHCPv4 configuration.
static void sanitizeOptionPools(isc::data::ConstElementPtr pools, const std::string &space, const OptionCodes &codes)
Set missing option codes to a pool list.
static void preProcess(isc::data::ElementPtr dhcp, const std::string &subsel, const std::string &space)
Pre process a configuration.
static void sanitizePoolsInSubnets(isc::data::ConstElementPtr subnets)
Sanitizes all pools in a subnets list.
static void sanitizeDatabase(isc::data::ElementPtr dhcp)
Update (hosts) database.
static void requireClassesSharedNetworks(isc::data::ConstElementPtr networks, const std::string &subsel)
Process require client classes in a shared network list.
static void sanitizeOptionHosts(isc::data::ConstElementPtr hosts, const std::string &space, const OptionCodes &codes)
Set missing option codes to a host reservation list.
static void sanitizeHostList(isc::data::ConstElementPtr hosts)
Process host reservation list.
static void SanitizeHostsInSharedNetworks(isc::data::ConstElementPtr networks, const std::string &space)
Process host reservations in a shared network list.
static void sanitizeOptionDefList(isc::data::ConstElementPtr defs, const std::string &space, OptionCodes &codes)
Collect option definitions from an option definition list.
static void sanitizeRequireClassesSubnets(isc::data::ConstElementPtr subnets)
Process require client classes in a subnet list.
static void sanitizeOptionSubnets(isc::data::ConstElementPtr subnets, const std::string &space, const OptionCodes &codes)
Set missing option codes to a subnet list.
static void sanitizePools(isc::data::ConstElementPtr pools)
Sanitizes all pools in a pools list.
static void sanitizePoolsInSharedNetworks(isc::data::ConstElementPtr networks, const std::string &subsel)
Sanitizes all pools in all subnets in a shared network list.
static void sanitizeOptionClasses(isc::data::ConstElementPtr classes, const std::string &space, OptionCodes &codes)
Collect option definitions from a client class list and set missing option codes.
static void preProcess6(isc::data::ElementPtr config)
Pre process a DHCPv6 configuration.
static void sanitizeRelaySuppliedOptions(isc::data::ElementPtr dhcp)
Update relay supplied options.
static void sanitizeOptionDataList(isc::data::ConstElementPtr options, const std::string &space, const OptionCodes &codes)
Set missing option codes to an option data list.
static void sanitizeRelayInSharedNetworks(isc::data::ConstElementPtr networks, const std::string &subsel)
Sanitizes relay information in a shared network list.
static bool sharedNetworksCollectID(isc::data::ConstElementPtr networks, isc::dhcp::SubnetIDSet &set, const std::string &subsel)
Collects subnet-ids in all subnets in all shared network list.
static void quoteIdentifier(isc::data::ElementPtr host)
Quote when needed a host identifier.
static void setCode(isc::data::ElementPtr option, const OptionCodes &codes)
Set code from name and definitions.
static void initCodes(OptionCodes &codes, const std::string &space)
Initialize code map.
static void setSpace(isc::data::ElementPtr option, const std::string &space)
Set space.
static void checkType(isc::data::ConstElementPtr option)
Checks if type is specified in option definition.
static void collect(isc::data::ConstElementPtr option, OptionCodes &codes)
Collect definition.
static void checkCode(isc::data::ConstElementPtr option)
Check if code is specified in option defintion.
static void canonizePool(isc::data::ElementPtr pool)
Canonize pool.
static void assignID(isc::data::ElementPtr subnet, isc::dhcp::SubnetIDSet &set, isc::dhcp::SubnetID &next)
Assign subnet ID.
static bool collectID(isc::data::ConstElementPtr subnet, isc::dhcp::SubnetIDSet &set)
Collect a subnet ID.
static void updateRelay(isc::data::ElementPtr subnet)
Update relay.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
Definition data.cc:1420
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
std::set< dhcp::SubnetID > SubnetIDSet
Ordered list aka set of subnetIDs.
Definition subnet_id.h:43
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition subnet_id.h:25
std::unordered_map< std::string, uint16_t > OptionCodes
Map for DHCP option definitions handling code and an index built from space and name.
Defines the logger used by the top-level component of kea-lfc.