Kea 1.9.11
dhcp_parsers.cc
Go to the documentation of this file.
1// Copyright (C) 2013-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 <dhcp/iface_mgr.h>
9#include <dhcp/dhcp4.h>
10#include <dhcp/libdhcp++.h>
11#include <dhcpsrv/cfgmgr.h>
12#include <dhcpsrv/cfg_option.h>
13#include <dhcpsrv/dhcpsrv_log.h>
21#include <util/encode/hex.h>
22#include <util/strutil.h>
23
24#include <boost/algorithm/string.hpp>
25#include <boost/foreach.hpp>
26#include <boost/lexical_cast.hpp>
27#include <boost/scoped_ptr.hpp>
28
29#include <map>
30#include <string>
31#include <vector>
32#include <iomanip>
33
34using namespace std;
35using namespace isc::asiolink;
36using namespace isc::data;
37using namespace isc::util;
38
39namespace isc {
40namespace dhcp {
41
42// ******************** MACSourcesListConfigParser *************************
43
44void
46 CfgIface cfg_iface;
47 uint32_t source = 0;
48 size_t cnt = 0;
49
50 // By default, there's only one source defined: ANY.
51 // If user specified anything, we need to get rid of that default.
52 mac_sources.clear();
53
54 BOOST_FOREACH(ConstElementPtr source_elem, value->listValue()) {
55 std::string source_str = source_elem->stringValue();
56 try {
57 source = CfgMACSource::MACSourceFromText(source_str);
58 mac_sources.add(source);
59 ++cnt;
60 } catch (const InvalidParameter& ex) {
61 isc_throw(DhcpConfigError, "The mac-sources value '" << source_str
62 << "' was specified twice (" << value->getPosition() << ")");
63 } catch (const std::exception& ex) {
64 isc_throw(DhcpConfigError, "Failed to convert '"
65 << source_str << "' to any recognized MAC source:"
66 << ex.what() << " (" << value->getPosition() << ")");
67 }
68 }
69
70 if (!cnt) {
71 isc_throw(DhcpConfigError, "If specified, MAC Sources cannot be empty");
72 }
73}
74
75// ******************** ControlSocketParser *************************
77 if (!value) {
78 // Sanity check: not supposed to fail.
79 isc_throw(DhcpConfigError, "Logic error: specified control-socket is null");
80 }
81
82 if (value->getType() != Element::map) {
83 // Sanity check: not supposed to fail.
84 isc_throw(DhcpConfigError, "Specified control-socket is expected to be a map"
85 ", i.e. a structure defined within { }");
86 }
87 srv_cfg.setControlSocketInfo(value);
88}
89
90template<typename SearchKey>
92OptionDataParser::findOptionDefinition(const std::string& option_space,
93 const SearchKey& search_key) const {
94 OptionDefinitionPtr def = LibDHCP::getOptionDef(option_space, search_key);
95
96 if (!def) {
97 // Check if this is a vendor-option. If it is, get vendor-specific
98 // definition.
99 uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(option_space);
100 if (vendor_id) {
101 const Option::Universe u = address_family_ == AF_INET ?
103 def = LibDHCP::getVendorOptionDef(u, vendor_id, search_key);
104 }
105 }
106
107 if (!def) {
108 // Check if this is an option specified by a user.
109 def = CfgMgr::instance().getStagingCfg()->getCfgOptionDef()
110 ->get(option_space, search_key);
111 }
112
113 return (def);
114}
115
116// ******************************** OptionDefParser ****************************
117
118OptionDefParser::OptionDefParser(const uint16_t address_family)
119 : address_family_(address_family) {
120}
121
124
125 // Check parameters.
126 if (address_family_ == AF_INET) {
128 } else {
130 }
131
132 // Get mandatory parameters.
133 std::string name = getString(option_def, "name");
134 int64_t code64 = getInteger(option_def, "code");
135 std::string type = getString(option_def, "type");
136
137 // Get optional parameters. Whoever called this parser, should have
138 // called SimpleParser::setDefaults first.
139 bool array_type = getBoolean(option_def, "array");
140 std::string record_types = getString(option_def, "record-types");
141 std::string space = getString(option_def, "space");
142 std::string encapsulates = getString(option_def, "encapsulate");
143 ConstElementPtr user_context = option_def->get("user-context");
144
145 // Check code value.
146 if (code64 < 0) {
147 isc_throw(DhcpConfigError, "option code must not be negative "
148 "(" << getPosition("code", option_def) << ")");
149 } else if (address_family_ == AF_INET &&
150 code64 > std::numeric_limits<uint8_t>::max()) {
151 isc_throw(DhcpConfigError, "invalid option code '" << code64
152 << "', it must not be greater than '"
153 << static_cast<int>(std::numeric_limits<uint8_t>::max())
154 << "' (" << getPosition("code", option_def) << ")");
155 } else if (address_family_ == AF_INET6 &&
156 code64 > std::numeric_limits<uint16_t>::max()) {
157 isc_throw(DhcpConfigError, "invalid option code '" << code64
158 << "', it must not be greater than '"
159 << std::numeric_limits<uint16_t>::max()
160 << "' (" << getPosition("code", option_def) << ")");
161 }
162 uint32_t code = static_cast<uint32_t>(code64);
163
164 // Validate space name.
165 if (!OptionSpace::validateName(space)) {
166 isc_throw(DhcpConfigError, "invalid option space name '"
167 << space << "' ("
168 << getPosition("space", option_def) << ")");
169 }
170
171 // Protect against definition of options 0 (PAD) or 255 (END)
172 // in (and only in) the dhcp4 space.
173 if (space == DHCP4_OPTION_SPACE) {
174 if (code == DHO_PAD) {
175 isc_throw(DhcpConfigError, "invalid option code '0': "
176 << "reserved for PAD ("
177 << getPosition("code", option_def) << ")");
178 } else if (code == DHO_END) {
179 isc_throw(DhcpConfigError, "invalid option code '255': "
180 << "reserved for END ("
181 << getPosition("code", option_def) << ")");
182 }
183 }
184
185 // For dhcp6 space the value 0 is reserved.
186 if (space == DHCP6_OPTION_SPACE) {
187 if (code == 0) {
188 isc_throw(DhcpConfigError, "invalid option code '0': "
189 << "reserved value ("
190 << getPosition("code", option_def) << ")");
191 }
192 }
193
194 // Create option definition.
196 // We need to check if user has set encapsulated option space
197 // name. If so, different constructor will be used.
198 if (!encapsulates.empty()) {
199 // Arrays can't be used together with sub-options.
200 if (array_type) {
201 isc_throw(DhcpConfigError, "option '" << space << "."
202 << name << "', comprising an array of data"
203 << " fields may not encapsulate any option space ("
204 << option_def->getPosition() << ")");
205
206 } else if (encapsulates == space) {
207 isc_throw(DhcpConfigError, "option must not encapsulate"
208 << " an option space it belongs to: '"
209 << space << "." << name << "' is set to"
210 << " encapsulate '" << space << "' ("
211 << option_def->getPosition() << ")");
212
213 } else {
214 def.reset(new OptionDefinition(name, code, space, type,
215 encapsulates.c_str()));
216 }
217
218 } else {
219 def.reset(new OptionDefinition(name, code, space, type, array_type));
220
221 }
222
223 if (user_context) {
224 def->setContext(user_context);
225 }
226
227 // Split the list of record types into tokens.
228 std::vector<std::string> record_tokens =
229 isc::util::str::tokens(record_types, ",");
230 // Iterate over each token and add a record type into
231 // option definition.
232 BOOST_FOREACH(std::string record_type, record_tokens) {
233 try {
234 boost::trim(record_type);
235 if (!record_type.empty()) {
236 def->addRecordField(record_type);
237 }
238 } catch (const Exception& ex) {
239 isc_throw(DhcpConfigError, "invalid record type values"
240 << " specified for the option definition: "
241 << ex.what() << " ("
242 << getPosition("record-types", option_def) << ")");
243 }
244 }
245
246 // Validate the definition.
247 try {
248 def->validate();
249 } catch (const std::exception& ex) {
251 << " (" << option_def->getPosition() << ")");
252 }
253
254 // Option definition has been created successfully.
255 return (def);
256}
257
258// ******************************** OptionDefListParser ************************
259
260OptionDefListParser::OptionDefListParser(const uint16_t address_family)
261 : address_family_(address_family) {
262}
263
264void
266 if (!option_def_list) {
267 // Sanity check: not supposed to fail.
268 isc_throw(DhcpConfigError, "parser error: a pointer to a list of"
269 << " option definitions is NULL ("
270 << option_def_list->getPosition() << ")");
271 }
272
273 OptionDefParser parser(address_family_);
274 BOOST_FOREACH(ConstElementPtr option_def, option_def_list->listValue()) {
275 OptionDefinitionPtr def = parser.parse(option_def);
276 try {
277 storage->add(def);
278 } catch (const std::exception& ex) {
279 // Append position if there is a failure.
280 isc_throw(DhcpConfigError, ex.what() << " ("
281 << option_def->getPosition() << ")");
282 }
283 }
284
285 // All definitions have been prepared. Put them as runtime options into
286 // the libdhcp++.
287 LibDHCP::setRuntimeOptionDefs(storage->getContainer());
288}
289
290//****************************** RelayInfoParser ********************************
292 : family_(family) {
293};
294
295void
297 ConstElementPtr relay_elem) {
298
299 if (relay_elem->getType() != Element::map) {
300 isc_throw(DhcpConfigError, "relay must be a map");
301 }
302
303 ConstElementPtr address = relay_elem->get("ip-address");
304 ConstElementPtr addresses = relay_elem->get("ip-addresses");
305
306 if (address && addresses) {
308 "specify either ip-address or ip-addresses, not both");
309 }
310
311 if (!address && !addresses) {
312 isc_throw(DhcpConfigError, "ip-addresses is required");
313 }
314
315 // Create our resultant RelayInfo structure
316 *relay_info = isc::dhcp::Network::RelayInfo();
317
318 if (address) {
319 addAddress("ip-address", getString(relay_elem, "ip-address"),
320 relay_elem, relay_info);
323 .arg(getPosition("ip-address", relay_elem));
324 return;
325 }
326
327 if (addresses->getType() != Element::list) {
328 isc_throw(DhcpConfigError, "ip-addresses must be a list "
329 "(" << getPosition("ip-addresses", relay_elem) << ")");
330 }
331
332 BOOST_FOREACH(ConstElementPtr address_element, addresses->listValue()) {
333 addAddress("ip-addresses", address_element->stringValue(),
334 relay_elem, relay_info);
335 }
336}
337
338void
339RelayInfoParser::addAddress(const std::string& name,
340 const std::string& address_str,
341 ConstElementPtr relay_elem,
342 const isc::dhcp::Network::RelayInfoPtr& relay_info) {
343 boost::scoped_ptr<isc::asiolink::IOAddress> ip;
344 try {
345 ip.reset(new isc::asiolink::IOAddress(address_str));
346 } catch (const std::exception& ex) {
347 isc_throw(DhcpConfigError, "address " << address_str
348 << " is not a valid: "
349 << (family_ == Option::V4 ? "IPv4" : "IPv6")
350 << "address"
351 << " (" << getPosition(name, relay_elem) << ")");
352 }
353
354 // Check if the address family matches.
355 if ((ip->isV4() && family_ != Option::V4) ||
356 (ip->isV6() && family_ != Option::V6) ) {
357 isc_throw(DhcpConfigError, "address " << address_str
358 << " is not a: "
359 << (family_ == Option::V4 ? "IPv4" : "IPv6")
360 << "address"
361 << " (" << getPosition(name, relay_elem) << ")");
362 }
363
364 try {
365 relay_info->addAddress(*ip);
366 } catch (const std::exception& ex) {
367 isc_throw(DhcpConfigError, "cannot add address: " << address_str
368 << "to relay info: " << ex.what()
369 << " (" << getPosition(name, relay_elem) << ")");
370 }
371}
372
373//****************************** PoolParser ********************************
374
375void
377 ConstElementPtr pool_structure,
378 const uint16_t address_family) {
379
380 if (address_family == AF_INET) {
382 } else {
384 }
385
386 ConstElementPtr text_pool = pool_structure->get("pool");
387
388 if (!text_pool) {
389 isc_throw(DhcpConfigError, "Mandatory 'pool' entry missing in "
390 "definition: (" << pool_structure->getPosition() << ")");
391 }
392
393 // That should be a single pool representation. It should contain
394 // text is form prefix/len or first - last. Note that spaces
395 // are allowed
396 string txt = text_pool->stringValue();
397
398 // first let's remove any whitespaces
399 boost::erase_all(txt, " "); // space
400 boost::erase_all(txt, "\t"); // tabulation
401
402 PoolPtr pool;
403
404 // Is this prefix/len notation?
405 size_t pos = txt.find("/");
406 if (pos != string::npos) {
407 isc::asiolink::IOAddress addr("::");
408 uint8_t len = 0;
409 try {
410 addr = isc::asiolink::IOAddress(txt.substr(0, pos));
411
412 // start with the first character after /
413 string prefix_len = txt.substr(pos + 1);
414
415 // It is lexical cast to int and then downcast to uint8_t.
416 // Direct cast to uint8_t (which is really an unsigned char)
417 // will result in interpreting the first digit as output
418 // value and throwing exception if length is written on two
419 // digits (because there are extra characters left over).
420
421 // No checks for values over 128. Range correctness will
422 // be checked in Pool4 constructor, here we only check
423 // the representation fits in an uint8_t as this can't
424 // be done by a direct lexical cast as explained...
425 int val_len = boost::lexical_cast<int>(prefix_len);
426 if ((val_len < std::numeric_limits<uint8_t>::min()) ||
427 (val_len > std::numeric_limits<uint8_t>::max())) {
428 // This exception will be handled 4 line later!
430 }
431 len = static_cast<uint8_t>(val_len);
432 } catch (...) {
433 isc_throw(DhcpConfigError, "Failed to parse pool "
434 "definition: " << txt << " ("
435 << text_pool->getPosition() << ")");
436 }
437
438 try {
439 pool = poolMaker(addr, len);
440 pools->push_back(pool);
441 } catch (const std::exception& ex) {
442 isc_throw(DhcpConfigError, "Failed to create pool defined by: "
443 << txt << " (" << text_pool->getPosition() << ")");
444 }
445
446 } else {
447 isc::asiolink::IOAddress min("::");
448 isc::asiolink::IOAddress max("::");
449
450 // Is this min-max notation?
451 pos = txt.find("-");
452 if (pos != string::npos) {
453 // using min-max notation
454 try {
455 min = isc::asiolink::IOAddress(txt.substr(0, pos));
456 max = isc::asiolink::IOAddress(txt.substr(pos + 1));
457 } catch (...) {
458 isc_throw(DhcpConfigError, "Failed to parse pool "
459 "definition: " << txt << " ("
460 << text_pool->getPosition() << ")");
461 }
462
463 try {
464 pool = poolMaker(min, max);
465 pools->push_back(pool);
466 } catch (const std::exception& ex) {
467 isc_throw(DhcpConfigError, "Failed to create pool defined by: "
468 << txt << " (" << text_pool->getPosition() << ")");
469 }
470 }
471 }
472
473 if (!pool) {
474 isc_throw(DhcpConfigError, "invalid pool definition: "
475 << text_pool->stringValue() <<
476 ". There are two acceptable formats <min address-max address>"
477 " or <prefix/len> ("
478 << text_pool->getPosition() << ")");
479 }
480
481 // If there's user-context specified, store it.
482 ConstElementPtr user_context = pool_structure->get("user-context");
483 if (user_context) {
484 // The grammar accepts only maps but still check it.
485 if (user_context->getType() != Element::map) {
486 isc_throw(isc::dhcp::DhcpConfigError, "User context has to be a map ("
487 << user_context->getPosition() << ")");
488 }
489 pool->setContext(user_context);
490 }
491
492 // Parser pool specific options.
493 ConstElementPtr option_data = pool_structure->get("option-data");
494 if (option_data) {
495 try {
496 CfgOptionPtr cfg = pool->getCfgOption();
497 OptionDataListParser option_parser(address_family);
498 option_parser.parse(cfg, option_data);
499 } catch (const std::exception& ex) {
501 << " (" << option_data->getPosition() << ")");
502 }
503 }
504
505 // Client-class.
506 ConstElementPtr client_class = pool_structure->get("client-class");
507 if (client_class) {
508 string cclass = client_class->stringValue();
509 if (!cclass.empty()) {
510 pool->allowClientClass(cclass);
511 }
512 }
513
514 // Try setting up required client classes.
515 ConstElementPtr class_list = pool_structure->get("require-client-classes");
516 if (class_list) {
517 const std::vector<data::ElementPtr>& classes = class_list->listValue();
518 for (auto cclass = classes.cbegin();
519 cclass != classes.cend(); ++cclass) {
520 if (((*cclass)->getType() != Element::string) ||
521 (*cclass)->stringValue().empty()) {
522 isc_throw(DhcpConfigError, "invalid class name ("
523 << (*cclass)->getPosition() << ")");
524 }
525 pool->requireClientClass((*cclass)->stringValue());
526 }
527 }
528}
529
530//****************************** Pool4Parser *************************
531
533Pool4Parser::poolMaker (IOAddress &addr, uint32_t len, int32_t) {
534 return (PoolPtr(new Pool4(addr, len)));
535}
536
539 return (PoolPtr(new Pool4(min, max)));
540}
541
542//****************************** Pool4ListParser *************************
543
544void
546 BOOST_FOREACH(ConstElementPtr pool, pools_list->listValue()) {
547 Pool4Parser parser;
548 parser.parse(pools, pool, AF_INET);
549 }
550}
551
552//****************************** SubnetConfigParser *************************
553
554SubnetConfigParser::SubnetConfigParser(uint16_t family, bool check_iface)
555 : pools_(new PoolStorage()),
556 address_family_(family),
557 options_(new CfgOption()),
558 check_iface_(check_iface) {
560}
561
564
565 ConstElementPtr options_params = subnet->get("option-data");
566 if (options_params) {
568 opt_parser.parse(options_, options_params);
569 }
570
571 ConstElementPtr relay_params = subnet->get("relay");
572 if (relay_params) {
574 RelayInfoParser parser(u);
575 parser.parse(relay_info_, relay_params);
576 }
577
578 // Create a subnet.
579 try {
580 createSubnet(subnet);
581 } catch (const std::exception& ex) {
583 "subnet configuration failed: " << ex.what());
584 }
585
586 return (subnet_);
587}
588
589void
590SubnetConfigParser::createSubnet(ConstElementPtr params) {
591 std::string subnet_txt;
592 try {
593 subnet_txt = getString(params, "subnet");
594 } catch (const DhcpConfigError &) {
595 // rethrow with precise error
596 isc_throw(DhcpConfigError,
597 "mandatory 'subnet' parameter is missing for a subnet being"
598 " configured (" << params->getPosition() << ")");
599 }
600
601 // Remove any spaces or tabs.
602 boost::erase_all(subnet_txt, " ");
603 boost::erase_all(subnet_txt, "\t");
604
605 // The subnet format is prefix/len. We are going to extract
606 // the prefix portion of a subnet string to create IOAddress
607 // object from it. IOAddress will be passed to the Subnet's
608 // constructor later on. In order to extract the prefix we
609 // need to get all characters preceding "/".
610 size_t pos = subnet_txt.find("/");
611 if (pos == string::npos) {
612 ConstElementPtr elem = params->get("subnet");
613 isc_throw(DhcpConfigError,
614 "Invalid subnet syntax (prefix/len expected):" << subnet_txt
615 << " (" << elem->getPosition() << ")");
616 }
617
618 // Try to create the address object. It also validates that
619 // the address syntax is ok.
620 isc::asiolink::IOAddress addr(subnet_txt.substr(0, pos));
621
622 // Now parse out the prefix length.
623 unsigned int len;
624 try {
625 len = boost::lexical_cast<unsigned int>(subnet_txt.substr(pos + 1));
626 } catch (const boost::bad_lexical_cast&) {
627 ConstElementPtr elem = params->get("subnet");
628 isc_throw(DhcpConfigError, "prefix length: '" <<
629 subnet_txt.substr(pos+1) << "' is not an integer ("
630 << elem->getPosition() << ")");
631 }
632
633 // Sanity check the prefix length
634 if ((addr.isV6() && len > 128) ||
635 (addr.isV4() && len > 32)) {
636 ConstElementPtr elem = params->get("subnet");
637 isc_throw(BadValue,
638 "Invalid prefix length specified for subnet: " << len
639 << " (" << elem->getPosition() << ")");
640 }
641
642 // Call the subclass's method to instantiate the subnet
643 initSubnet(params, addr, len);
644
645 // Add pools to it.
646 for (PoolStorage::iterator it = pools_->begin(); it != pools_->end();
647 ++it) {
648 try {
649 subnet_->addPool(*it);
650 } catch (const BadValue& ex) {
651 // addPool() can throw BadValue if the pool is overlapping or
652 // is out of bounds for the subnet.
653 isc_throw(DhcpConfigError,
654 ex.what() << " (" << params->getPosition() << ")");
655 }
656 }
657 // If there's user-context specified, store it.
658 ConstElementPtr user_context = params->get("user-context");
659 if (user_context) {
660 // The grammar accepts only maps but still check it.
661 if (user_context->getType() != Element::map) {
662 isc_throw(isc::dhcp::DhcpConfigError, "User context has to be a map ("
663 << user_context->getPosition() << ")");
664 }
665 subnet_->setContext(user_context);
666 }
667
668 // In order to take advantage of the dynamic inheritance of global
669 // parameters to a subnet we need to set a callback function for each
670 // subnet to allow for fetching global parameters.
671 subnet_->setFetchGlobalsFn([]() -> ConstElementPtr {
672 return (CfgMgr::instance().getCurrentCfg()->getConfiguredGlobals());
673 });
674
675}
676
677//****************************** Subnet4ConfigParser *************************
678
680 : SubnetConfigParser(AF_INET, check_iface) {
681}
682
685 // Check parameters.
687
689 ConstElementPtr pools = subnet->get("pools");
690 if (pools) {
691 Pools4ListParser parser;
692 parser.parse(pools_, pools);
693 }
694
695 SubnetPtr generic = SubnetConfigParser::parse(subnet);
696
697 if (!generic) {
698 // Sanity check: not supposed to fail.
700 "Failed to create an IPv4 subnet (" <<
701 subnet->getPosition() << ")");
702 }
703
704 Subnet4Ptr sn4ptr = boost::dynamic_pointer_cast<Subnet4>(subnet_);
705 if (!sn4ptr) {
706 // If we hit this, it is a programming error.
708 "Invalid Subnet4 cast in Subnet4ConfigParser::parse");
709 }
710
711 // Set relay information if it was parsed
712 if (relay_info_) {
713 sn4ptr->setRelayInfo(*relay_info_);
714 }
715
716 // Parse Host Reservations for this subnet if any.
717 ConstElementPtr reservations = subnet->get("reservations");
718 if (reservations) {
719 HostCollection hosts;
721 parser.parse(subnet_->getID(), reservations, hosts);
722 for (auto h = hosts.begin(); h != hosts.end(); ++h) {
723 validateResv(sn4ptr, *h);
724 CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(*h);
725 }
726 }
727
728 return (sn4ptr);
729}
730
731void
733 asiolink::IOAddress addr, uint8_t len) {
734 // Subnet ID is optional. If it is not supplied the value of 0 is used,
735 // which means autogenerate. The value was inserted earlier by calling
736 // SimpleParser4::setAllDefaults.
737 SubnetID subnet_id = static_cast<SubnetID>(getInteger(params, "id"));
738
739 Subnet4Ptr subnet4(new Subnet4(addr, len, Triplet<uint32_t>(),
741 subnet_id));
742 subnet_ = subnet4;
743
744 // Move from reservation mode to new reservations flags.
745 ElementPtr mutable_params;
746 mutable_params = boost::const_pointer_cast<Element>(params);
747 // @todo add warning
749
750 // Parse parameters common to all Network derivations.
751 NetworkPtr network = boost::dynamic_pointer_cast<Network>(subnet4);
752 parseCommon(mutable_params, network);
753
754 std::ostringstream output;
755 output << addr << "/" << static_cast<int>(len) << " with params: ";
756
757 bool has_renew = !subnet4->getT1().unspecified();
758 bool has_rebind = !subnet4->getT2().unspecified();
759 int64_t renew = -1;
760 int64_t rebind = -1;
761
762 // t1 and t2 are optional may be not specified.
763 if (has_renew) {
764 renew = subnet4->getT1().get();
765 output << "t1=" << renew << ", ";
766 }
767 if (has_rebind) {
768 rebind = subnet4->getT2().get();
769 output << "t2=" << rebind << ", ";
770 }
771
772 if (has_renew && has_rebind && (renew > rebind)) {
773 isc_throw(DhcpConfigError, "the value of renew-timer (" << renew
774 << ") is greater than the value of rebind-timer ("
775 << rebind << ")");
776 }
777
778 if (!subnet4->getValid().unspecified()) {
779 output << "valid-lifetime=" << subnet4->getValid().get();
780 }
781
783
784 // Set the match-client-id value for the subnet.
785 if (params->contains("match-client-id")) {
786 bool match_client_id = getBoolean(params, "match-client-id");
787 subnet4->setMatchClientId(match_client_id);
788 }
789
790 // Set the authoritative value for the subnet.
791 if (params->contains("authoritative")) {
792 bool authoritative = getBoolean(params, "authoritative");
793 subnet4->setAuthoritative(authoritative);
794 }
795
796 // Set next-server. The default value is 0.0.0.0. Nevertheless, the
797 // user could have messed that up by specifying incorrect value.
798 // To avoid using 0.0.0.0, user can specify "".
799 if (params->contains("next-server")) {
800 string next_server;
801 try {
802 next_server = getString(params, "next-server");
803 if (!next_server.empty()) {
804 subnet4->setSiaddr(IOAddress(next_server));
805 }
806 } catch (...) {
807 ConstElementPtr next = params->get("next-server");
808 string pos;
809 if (next) {
810 pos = next->getPosition().str();
811 } else {
812 pos = params->getPosition().str();
813 }
814 isc_throw(DhcpConfigError, "invalid parameter next-server : "
815 << next_server << "(" << pos << ")");
816 }
817 }
818
819 // Set server-hostname.
820 if (params->contains("server-hostname")) {
821 std::string sname = getString(params, "server-hostname");
822 if (!sname.empty()) {
823 if (sname.length() >= Pkt4::MAX_SNAME_LEN) {
824 ConstElementPtr error = params->get("server-hostname");
825 isc_throw(DhcpConfigError, "server-hostname must be at most "
826 << Pkt4::MAX_SNAME_LEN - 1 << " bytes long, it is "
827 << sname.length() << " ("
828 << error->getPosition() << ")");
829 }
830 subnet4->setSname(sname);
831 }
832 }
833
834 // Set boot-file-name.
835 if (params->contains("boot-file-name")) {
836 std::string filename =getString(params, "boot-file-name");
837 if (!filename.empty()) {
838 if (filename.length() > Pkt4::MAX_FILE_LEN) {
839 ConstElementPtr error = params->get("boot-file-name");
840 isc_throw(DhcpConfigError, "boot-file-name must be at most "
841 << Pkt4::MAX_FILE_LEN - 1 << " bytes long, it is "
842 << filename.length() << " ("
843 << error->getPosition() << ")");
844 }
845 subnet4->setFilename(filename);
846 }
847 }
848
849 // Get interface name. If it is defined, then the subnet is available
850 // directly over specified network interface.
851 if (params->contains("interface")) {
852 std::string iface = getString(params, "interface");
853 if (!iface.empty()) {
854 if (check_iface_ && !IfaceMgr::instance().getIface(iface)) {
855 ConstElementPtr error = params->get("interface");
856 isc_throw(DhcpConfigError, "Specified network interface name " << iface
857 << " for subnet " << subnet4->toText()
858 << " is not present in the system ("
859 << error->getPosition() << ")");
860 }
861
862 subnet4->setIface(iface);
863 }
864 }
865
866 // Try setting up client class.
867 if (params->contains("client-class")) {
868 string client_class = getString(params, "client-class");
869 if (!client_class.empty()) {
870 subnet4->allowClientClass(client_class);
871 }
872 }
873
874 // Try setting up required client classes.
875 ConstElementPtr class_list = params->get("require-client-classes");
876 if (class_list) {
877 const std::vector<data::ElementPtr>& classes = class_list->listValue();
878 for (auto cclass = classes.cbegin();
879 cclass != classes.cend(); ++cclass) {
880 if (((*cclass)->getType() != Element::string) ||
881 (*cclass)->stringValue().empty()) {
882 isc_throw(DhcpConfigError, "invalid class name ("
883 << (*cclass)->getPosition() << ")");
884 }
885 subnet4->requireClientClass((*cclass)->stringValue());
886 }
887 }
888
889 // 4o6 specific parameter: 4o6-interface.
890 if (params->contains("4o6-interface")) {
891 string iface4o6 = getString(params, "4o6-interface");
892 if (!iface4o6.empty()) {
893 subnet4->get4o6().setIface4o6(iface4o6);
894 subnet4->get4o6().enabled(true);
895 }
896 }
897
898 // 4o6 specific parameter: 4o6-subnet.
899 if (params->contains("4o6-subnet")) {
900 string subnet4o6 = getString(params, "4o6-subnet");
901 if (!subnet4o6.empty()) {
902 size_t slash = subnet4o6.find("/");
903 if (slash == std::string::npos) {
904 isc_throw(DhcpConfigError, "Missing / in the 4o6-subnet parameter:"
905 << subnet4o6 << ", expected format: prefix6/length");
906 }
907 string prefix = subnet4o6.substr(0, slash);
908 string lenstr = subnet4o6.substr(slash + 1);
909
910 uint8_t len = 128;
911 try {
912 len = boost::lexical_cast<unsigned int>(lenstr.c_str());
913 } catch (const boost::bad_lexical_cast &) {
914 isc_throw(DhcpConfigError, "Invalid prefix length specified in "
915 "4o6-subnet parameter: " << subnet4o6 << ", expected 0..128 value");
916 }
917 subnet4->get4o6().setSubnet4o6(IOAddress(prefix), len);
918 subnet4->get4o6().enabled(true);
919 }
920 }
921
922 // Try 4o6 specific parameter: 4o6-interface-id
923 if (params->contains("4o6-interface-id")) {
924 std::string ifaceid = getString(params, "4o6-interface-id");
925 if (!ifaceid.empty()) {
926 OptionBuffer tmp(ifaceid.begin(), ifaceid.end());
928 subnet4->get4o6().setInterfaceId(opt);
929 subnet4->get4o6().enabled(true);
930 }
931 }
932
935
936 // Here globally defined options were merged to the subnet specific
937 // options but this is no longer the case (they have a different
938 // and not consecutive priority).
939
940 // Copy options to the subnet configuration.
941 options_->copyTo(*subnet4->getCfgOption());
942
943 // Parse t1-percent and t2-percent
944 parseTeePercents(params, network);
945
946 // Parse DDNS parameters
947 parseDdnsParams(params, network);
948
949 // Parse lease cache parameters
950 parseCacheParams(params, network);
951}
952
953void
955 const IOAddress& address = host->getIPv4Reservation();
956 if (!address.isV4Zero() && !subnet->inRange(address)) {
957 isc_throw(DhcpConfigError, "specified reservation '" << address
958 << "' is not within the IPv4 subnet '"
959 << subnet->toText() << "'");
960 }
961}
962
963//**************************** Subnets4ListConfigParser **********************
964
966 : check_iface_(check_iface) {
967}
968
969size_t
971 ConstElementPtr subnets_list) {
972 size_t cnt = 0;
973 BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
974
976 Subnet4Ptr subnet = parser.parse(subnet_json);
977 if (subnet) {
978
979 // Adding a subnet to the Configuration Manager may fail if the
980 // subnet id is invalid (duplicate). Thus, we catch exceptions
981 // here to append a position in the configuration string.
982 try {
983 cfg->getCfgSubnets4()->add(subnet);
984 cnt++;
985 } catch (const std::exception& ex) {
986 isc_throw(DhcpConfigError, ex.what() << " ("
987 << subnet_json->getPosition() << ")");
988 }
989 }
990 }
991 return (cnt);
992}
993
994size_t
996 data::ConstElementPtr subnets_list) {
997 size_t cnt = 0;
998 BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
999
1001 Subnet4Ptr subnet = parser.parse(subnet_json);
1002 if (subnet) {
1003 try {
1004 auto ret = subnets.insert(subnet);
1005 if (!ret.second) {
1007 "can't store subnet because of conflict");
1008 }
1009 ++cnt;
1010 } catch (const std::exception& ex) {
1011 isc_throw(DhcpConfigError, ex.what() << " ("
1012 << subnet_json->getPosition() << ")");
1013 }
1014 }
1015 }
1016 return (cnt);
1017}
1018
1019
1020//**************************** Pool6Parser *********************************
1021
1022PoolPtr
1023Pool6Parser::poolMaker (IOAddress &addr, uint32_t len, int32_t ptype)
1024{
1025 return (PoolPtr(new Pool6(static_cast<isc::dhcp::Lease::Type>
1026 (ptype), addr, len)));
1027}
1028
1029PoolPtr
1030Pool6Parser::poolMaker (IOAddress &min, IOAddress &max, int32_t ptype)
1031{
1032 return (PoolPtr(new Pool6(static_cast<isc::dhcp::Lease::Type>
1033 (ptype), min, max)));
1034}
1035
1036
1037//**************************** Pool6ListParser ***************************
1038
1039void
1041 BOOST_FOREACH(ConstElementPtr pool, pools_list->listValue()) {
1042 Pool6Parser parser;
1043 parser.parse(pools, pool, AF_INET6);
1044 }
1045}
1046
1047//**************************** PdPoolParser ******************************
1048
1050}
1051
1052void
1055
1056 std::string addr_str = getString(pd_pool_, "prefix");
1057
1058 uint8_t prefix_len = getUint8(pd_pool_, "prefix-len");
1059
1060 uint8_t delegated_len = getUint8(pd_pool_, "delegated-len");
1061
1062 std::string excluded_prefix_str = "::";
1063 if (pd_pool_->contains("excluded-prefix")) {
1064 excluded_prefix_str = getString(pd_pool_, "excluded-prefix");
1065 }
1066
1067 uint8_t excluded_prefix_len = 0;
1068 if (pd_pool_->contains("excluded-prefix-len")) {
1069 excluded_prefix_len = getUint8(pd_pool_, "excluded-prefix-len");
1070 }
1071
1072 ConstElementPtr option_data = pd_pool_->get("option-data");
1073 if (option_data) {
1074 OptionDataListParser opts_parser(AF_INET6);
1075 opts_parser.parse(options_, option_data);
1076 }
1077
1078 ConstElementPtr user_context = pd_pool_->get("user-context");
1079 if (user_context) {
1080 user_context_ = user_context;
1081 }
1082
1083 ConstElementPtr client_class = pd_pool_->get("client-class");
1084 if (client_class) {
1085 client_class_ = client_class;
1086 }
1087
1088 ConstElementPtr class_list = pd_pool_->get("require-client-classes");
1089
1090 // Check the pool parameters. It will throw an exception if any
1091 // of the required parameters are invalid.
1092 try {
1093 // Attempt to construct the local pool.
1094 pool_.reset(new Pool6(IOAddress(addr_str),
1095 prefix_len,
1096 delegated_len,
1097 IOAddress(excluded_prefix_str),
1098 excluded_prefix_len));
1099 // Merge options specified for a pool into pool configuration.
1100 options_->copyTo(*pool_->getCfgOption());
1101 } catch (const std::exception& ex) {
1102 // Some parameters don't exist or are invalid. Since we are not
1103 // aware whether they don't exist or are invalid, let's append
1104 // the position of the pool map element.
1106 << " (" << pd_pool_->getPosition() << ")");
1107 }
1108
1109 if (user_context_) {
1110 pool_->setContext(user_context_);
1111 }
1112
1113 if (client_class_) {
1114 string cclass = client_class_->stringValue();
1115 if (!cclass.empty()) {
1116 pool_->allowClientClass(cclass);
1117 }
1118 }
1119
1120 if (class_list) {
1121 const std::vector<data::ElementPtr>& classes = class_list->listValue();
1122 for (auto cclass = classes.cbegin();
1123 cclass != classes.cend(); ++cclass) {
1124 if (((*cclass)->getType() != Element::string) ||
1125 (*cclass)->stringValue().empty()) {
1126 isc_throw(DhcpConfigError, "invalid class name ("
1127 << (*cclass)->getPosition() << ")");
1128 }
1129 pool_->requireClientClass((*cclass)->stringValue());
1130 }
1131 }
1132
1133 // Add the local pool to the external storage ptr.
1134 pools->push_back(pool_);
1135}
1136
1137//**************************** PdPoolsListParser ************************
1138
1139void
1141 // Loop through the list of pd pools.
1142 BOOST_FOREACH(ConstElementPtr pd_pool, pd_pool_list->listValue()) {
1143 PdPoolParser parser;
1144 parser.parse(pools, pd_pool);
1145 }
1146}
1147
1148//**************************** Subnet6ConfigParser ***********************
1149
1151 : SubnetConfigParser(AF_INET6, check_iface) {
1152}
1153
1156 // Check parameters.
1158
1160 ConstElementPtr pools = subnet->get("pools");
1161 if (pools) {
1162 Pools6ListParser parser;
1163 parser.parse(pools_, pools);
1164 }
1165 ConstElementPtr pd_pools = subnet->get("pd-pools");
1166 if (pd_pools) {
1167 PdPoolsListParser parser;
1168 parser.parse(pools_, pd_pools);
1169 }
1170
1171 SubnetPtr generic = SubnetConfigParser::parse(subnet);
1172
1173 if (!generic) {
1174 // Sanity check: not supposed to fail.
1176 "Failed to create an IPv6 subnet (" <<
1177 subnet->getPosition() << ")");
1178 }
1179
1180 Subnet6Ptr sn6ptr = boost::dynamic_pointer_cast<Subnet6>(subnet_);
1181 if (!sn6ptr) {
1182 // If we hit this, it is a programming error.
1184 "Invalid Subnet6 cast in Subnet6ConfigParser::parse");
1185 }
1186
1187 // Set relay information if it was provided
1188 if (relay_info_) {
1189 sn6ptr->setRelayInfo(*relay_info_);
1190 }
1191
1192 // Parse Host Reservations for this subnet if any.
1193 ConstElementPtr reservations = subnet->get("reservations");
1194 if (reservations) {
1195 HostCollection hosts;
1197 parser.parse(subnet_->getID(), reservations, hosts);
1198 for (auto h = hosts.begin(); h != hosts.end(); ++h) {
1199 validateResvs(sn6ptr, *h);
1200 CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(*h);
1201 }
1202 }
1203
1204 return (sn6ptr);
1205}
1206
1207// Unused?
1208void
1210 asiolink::IOAddress& addr) {
1212 .arg(code).arg(addr.toText());
1213}
1214
1215void
1217 asiolink::IOAddress addr, uint8_t len) {
1218 // Subnet ID is optional. If it is not supplied the value of 0 is used,
1219 // which means autogenerate. The value was inserted earlier by calling
1220 // SimpleParser6::setAllDefaults.
1221 SubnetID subnet_id = static_cast<SubnetID>(getInteger(params, "id"));
1222
1223 // We want to log whether rapid-commit is enabled, so we get this
1224 // before the actual subnet creation.
1225 Optional<bool> rapid_commit;
1226 if (params->contains("rapid-commit")) {
1227 rapid_commit = getBoolean(params, "rapid-commit");
1228 }
1229
1230 // Parse preferred lifetime as it is not parsed by the common function.
1231 Triplet<uint32_t> pref = parseIntTriplet(params, "preferred-lifetime");
1232
1233 // Create a new subnet.
1234 Subnet6* subnet6 = new Subnet6(addr, len, Triplet<uint32_t>(),
1236 pref,
1238 subnet_id);
1239 subnet_.reset(subnet6);
1240
1241 // Move from reservation mode to new reservations flags.
1242 ElementPtr mutable_params;
1243 mutable_params = boost::const_pointer_cast<Element>(params);
1244 // @todo add warning
1246
1247 // Parse parameters common to all Network derivations.
1248 NetworkPtr network = boost::dynamic_pointer_cast<Network>(subnet_);
1249 parseCommon(mutable_params, network);
1250
1251 // Enable or disable Rapid Commit option support for the subnet.
1252 if (!rapid_commit.unspecified()) {
1253 subnet6->setRapidCommit(rapid_commit);
1254 }
1255
1256 std::ostringstream output;
1257 output << addr << "/" << static_cast<int>(len) << " with params: ";
1258 // t1 and t2 are optional may be not specified.
1259
1260 bool has_renew = !subnet6->getT1().unspecified();
1261 bool has_rebind = !subnet6->getT2().unspecified();
1262 int64_t renew = -1;
1263 int64_t rebind = -1;
1264
1265 if (has_renew) {
1266 renew = subnet6->getT1().get();
1267 output << "t1=" << renew << ", ";
1268 }
1269 if (has_rebind) {
1270 rebind = subnet6->getT2().get();
1271 output << "t2=" << rebind << ", ";
1272 }
1273
1274 if (has_renew && has_rebind && (renew > rebind)) {
1275 isc_throw(DhcpConfigError, "the value of renew-timer (" << renew
1276 << ") is greater than the value of rebind-timer ("
1277 << rebind << ")");
1278 }
1279
1280 if (!subnet6->getPreferred().unspecified()) {
1281 output << "preferred-lifetime=" << subnet6->getPreferred().get() << ", ";
1282 }
1283 if (!subnet6->getValid().unspecified()) {
1284 output << "valid-lifetime=" << subnet6->getValid().get();
1285 }
1286 if (!subnet6->getRapidCommit().unspecified()) {
1287 output << ", rapid-commit is "
1288 << boolalpha << subnet6->getRapidCommit().get();
1289 }
1290
1292
1293 // Get interface-id option content. For now we support string
1294 // representation only
1295 Optional<std::string> ifaceid;
1296 if (params->contains("interface-id")) {
1297 ifaceid = getString(params, "interface-id");
1298 }
1299
1301 if (params->contains("interface")) {
1302 iface = getString(params, "interface");
1303 }
1304
1305 // Specifying both interface for locally reachable subnets and
1306 // interface id for relays is mutually exclusive. Need to test for
1307 // this condition.
1308 if (!ifaceid.unspecified() && !iface.unspecified() && !ifaceid.empty() &&
1309 !iface.empty()) {
1311 "parser error: interface (defined for locally reachable "
1312 "subnets) and interface-id (defined for subnets reachable"
1313 " via relays) cannot be defined at the same time for "
1314 "subnet " << addr << "/" << (int)len << "("
1315 << params->getPosition() << ")");
1316 }
1317
1318 // Configure interface-id for remote interfaces, if defined
1319 if (!ifaceid.unspecified() && !ifaceid.empty()) {
1320 std::string ifaceid_value = ifaceid.get();
1321 OptionBuffer tmp(ifaceid_value.begin(), ifaceid_value.end());
1323 subnet6->setInterfaceId(opt);
1324 }
1325
1326 // Get interface name. If it is defined, then the subnet is available
1327 // directly over specified network interface.
1328 if (!iface.unspecified() && !iface.empty()) {
1329 if (check_iface_ && !IfaceMgr::instance().getIface(iface)) {
1330 ConstElementPtr error = params->get("interface");
1331 isc_throw(DhcpConfigError, "Specified network interface name " << iface
1332 << " for subnet " << subnet6->toText()
1333 << " is not present in the system ("
1334 << error->getPosition() << ")");
1335 }
1336
1337 subnet6->setIface(iface);
1338 }
1339
1340 // Try setting up client class.
1341 if (params->contains("client-class")) {
1342 string client_class = getString(params, "client-class");
1343 if (!client_class.empty()) {
1344 subnet6->allowClientClass(client_class);
1345 }
1346 }
1347
1348 if (params->contains("require-client-classes")) {
1349 // Try setting up required client classes.
1350 ConstElementPtr class_list = params->get("require-client-classes");
1351 if (class_list) {
1352 const std::vector<data::ElementPtr>& classes = class_list->listValue();
1353 for (auto cclass = classes.cbegin();
1354 cclass != classes.cend(); ++cclass) {
1355 if (((*cclass)->getType() != Element::string) ||
1356 (*cclass)->stringValue().empty()) {
1357 isc_throw(DhcpConfigError, "invalid class name ("
1358 << (*cclass)->getPosition() << ")");
1359 }
1360 subnet6->requireClientClass((*cclass)->stringValue());
1361 }
1362 }
1363 }
1364
1367
1368 // Copy options to the subnet configuration.
1369 options_->copyTo(*subnet6->getCfgOption());
1370
1371 // Parse t1-percent and t2-percent
1372 parseTeePercents(params, network);
1373
1374 // Parse DDNS parameters
1375 parseDdnsParams(params, network);
1376
1377 // Parse lease cache parameters
1378 parseCacheParams(params, network);
1379}
1380
1381void
1383 IPv6ResrvRange range = host->getIPv6Reservations(IPv6Resrv::TYPE_NA);
1384 for (auto it = range.first; it != range.second; ++it) {
1385 const IOAddress& address = it->second.getPrefix();
1386 if (!subnet->inRange(address)) {
1387 isc_throw(DhcpConfigError, "specified reservation '" << address
1388 << "' is not within the IPv6 subnet '"
1389 << subnet->toText() << "'");
1390 }
1391 }
1392}
1393
1394//**************************** Subnet6ListConfigParser ********************
1395
1397 : check_iface_(check_iface) {
1398}
1399
1400size_t
1402 ConstElementPtr subnets_list) {
1403 size_t cnt = 0;
1404 BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
1405
1407 Subnet6Ptr subnet = parser.parse(subnet_json);
1408
1409 // Adding a subnet to the Configuration Manager may fail if the
1410 // subnet id is invalid (duplicate). Thus, we catch exceptions
1411 // here to append a position in the configuration string.
1412 try {
1413 cfg->getCfgSubnets6()->add(subnet);
1414 cnt++;
1415 } catch (const std::exception& ex) {
1416 isc_throw(DhcpConfigError, ex.what() << " ("
1417 << subnet_json->getPosition() << ")");
1418 }
1419 }
1420 return (cnt);
1421}
1422
1423size_t
1425 ConstElementPtr subnets_list) {
1426 size_t cnt = 0;
1427 BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
1428
1430 Subnet6Ptr subnet = parser.parse(subnet_json);
1431 if (subnet) {
1432 try {
1433 auto ret = subnets.insert(subnet);
1434 if (!ret.second) {
1436 "can't store subnet because of conflict");
1437 }
1438 ++cnt;
1439 } catch (const std::exception& ex) {
1440 isc_throw(DhcpConfigError, ex.what() << " ("
1441 << subnet_json->getPosition() << ")");
1442 }
1443 }
1444 }
1445 return (cnt);
1446}
1447
1448
1449//**************************** D2ClientConfigParser **********************
1450
1452D2ClientConfigParser::getProtocol(ConstElementPtr scope,
1453 const std::string& name) {
1456 (scope, name, "NameChangeRequest protocol"));
1457}
1458
1460D2ClientConfigParser::getFormat(ConstElementPtr scope,
1461 const std::string& name) {
1464 (scope, name, "NameChangeRequest format"));
1465}
1466
1468D2ClientConfigParser::getMode(ConstElementPtr scope,
1469 const std::string& name) {
1472 (scope, name, "ReplaceClientName mode"));
1473}
1474
1477 D2ClientConfigPtr new_config;
1478
1479 // Get all parameters that are needed to create the D2ClientConfig.
1480 bool enable_updates = getBoolean(client_config, "enable-updates");
1481
1482 IOAddress server_ip = getAddress(client_config, "server-ip");
1483
1484 uint32_t server_port = getUint32(client_config, "server-port");
1485
1486 std::string sender_ip_str = getString(client_config, "sender-ip");
1487
1488 uint32_t sender_port = getUint32(client_config, "sender-port");
1489
1490 uint32_t max_queue_size = getUint32(client_config, "max-queue-size");
1491
1492 dhcp_ddns::NameChangeProtocol ncr_protocol =
1493 getProtocol(client_config, "ncr-protocol");
1494
1495 dhcp_ddns::NameChangeFormat ncr_format =
1496 getFormat(client_config, "ncr-format");
1497
1498 IOAddress sender_ip(0);
1499 if (sender_ip_str.empty()) {
1500 // The default sender IP depends on the server IP family
1501 sender_ip = (server_ip.isV4() ? IOAddress::IPV4_ZERO_ADDRESS() :
1503 } else {
1504 try {
1505 sender_ip = IOAddress(sender_ip_str);
1506 } catch (const std::exception& ex) {
1507 isc_throw(DhcpConfigError, "invalid address (" << sender_ip_str
1508 << ") specified for parameter 'sender-ip' ("
1509 << getPosition("sender-ip", client_config) << ")");
1510 }
1511 }
1512
1513 // Now we check for logical errors. This repeats what is done in
1514 // D2ClientConfig::validate(), but doing it here permits us to
1515 // emit meaningful parameter position info in the error.
1516 if (ncr_format != dhcp_ddns::FMT_JSON) {
1517 isc_throw(D2ClientError, "D2ClientConfig error: NCR Format: "
1518 << dhcp_ddns::ncrFormatToString(ncr_format)
1519 << " is not supported. ("
1520 << getPosition("ncr-format", client_config) << ")");
1521 }
1522
1523 if (ncr_protocol != dhcp_ddns::NCR_UDP) {
1524 isc_throw(D2ClientError, "D2ClientConfig error: NCR Protocol: "
1525 << dhcp_ddns::ncrProtocolToString(ncr_protocol)
1526 << " is not supported. ("
1527 << getPosition("ncr-protocol", client_config) << ")");
1528 }
1529
1530 if (sender_ip.getFamily() != server_ip.getFamily()) {
1532 "D2ClientConfig error: address family mismatch: "
1533 << "server-ip: " << server_ip.toText()
1534 << " is: " << (server_ip.isV4() ? "IPv4" : "IPv6")
1535 << " while sender-ip: " << sender_ip.toText()
1536 << " is: " << (sender_ip.isV4() ? "IPv4" : "IPv6")
1537 << " (" << getPosition("sender-ip", client_config) << ")");
1538 }
1539
1540 if (server_ip == sender_ip && server_port == sender_port) {
1542 "D2ClientConfig error: server and sender cannot"
1543 " share the exact same IP address/port: "
1544 << server_ip.toText() << "/" << server_port
1545 << " (" << getPosition("sender-ip", client_config) << ")");
1546 }
1547
1548 try {
1549 // Attempt to create the new client config.
1550 new_config.reset(new D2ClientConfig(enable_updates,
1551 server_ip,
1552 server_port,
1553 sender_ip,
1554 sender_port,
1555 max_queue_size,
1556 ncr_protocol,
1557 ncr_format));
1558 } catch (const std::exception& ex) {
1559 isc_throw(DhcpConfigError, ex.what() << " ("
1560 << client_config->getPosition() << ")");
1561 }
1562
1563 // Add user context
1564 ConstElementPtr user_context = client_config->get("user-context");
1565 if (user_context) {
1566 new_config->setContext(user_context);
1567 }
1568
1569 return(new_config);
1570}
1571
1574 // enable-updates is unconditionally required
1575 { "server-ip", Element::string, "127.0.0.1" },
1576 { "server-port", Element::integer, "53001" },
1577 // default sender-ip depends on server-ip family, so we leave default blank
1578 // parser knows to use the appropriate ZERO address based on server-ip
1579 { "sender-ip", Element::string, "" },
1580 { "sender-port", Element::integer, "0" },
1581 { "max-queue-size", Element::integer, "1024" },
1582 { "ncr-protocol", Element::string, "UDP" },
1583 { "ncr-format", Element::string, "JSON" }
1584};
1585
1586size_t
1588 ElementPtr mutable_d2 = boost::const_pointer_cast<Element>(d2_config);
1589 return (SimpleParser::setDefaults(mutable_d2, D2_CLIENT_CONFIG_DEFAULTS));
1590}
1591
1592} // namespace dhcp
1593} // namespace isc
This is a base class for exceptions thrown from the DNS library module.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
A generic exception that is thrown when an unexpected error condition occurs.
static void checkKeywords(const SimpleKeywords &keywords, isc::data::ConstElementPtr scope)
Checks acceptable keywords with their expected type.
const dhcp::Triplet< uint32_t > parseIntTriplet(const data::ConstElementPtr &scope, const std::string &name)
Parses an integer triplet.
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.
uint8_t getUint8(ConstElementPtr scope, const std::string &name)
Get an uint8_t value.
static isc::asiolink::IOAddress getAddress(const ConstElementPtr &scope, const std::string &name)
Returns a IOAddress parameter from a scope.
static std::string getString(isc::data::ConstElementPtr scope, const std::string &name)
Returns a string parameter from a scope.
uint32_t getUint32(isc::data::ConstElementPtr scope, const std::string &name)
Returns a value converted to uint32_t.
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 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.
static void moveReservationMode(isc::data::ElementPtr config)
Moves deprecated reservation-mode parameter to new reservations flags.
void parseTeePercents(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses parameters related to "percent" timers settings.
Represents selection of interfaces for DHCP server.
Definition: cfg_iface.h:130
Wrapper class that holds MAC/hardware address sources.
void add(uint32_t source)
Adds additional MAC/hardware address acquisition.
void clear()
Removes any configured MAC/Hardware address sources.
static uint32_t MACSourceFromText(const std::string &name)
Attempts to convert known hardware address sources to uint32_t.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
SrvConfigPtr getStagingCfg()
Returns a pointer to the staging configuration.
Definition: cfgmgr.cc:167
Represents option data configuration for the DHCP server.
Definition: cfg_option.h:314
void parse(SrvConfig &srv_cfg, isc::data::ConstElementPtr value)
"Parses" control-socket structure
Definition: dhcp_parsers.cc:76
D2ClientConfigPtr parse(isc::data::ConstElementPtr d2_client_cfg)
Parses a given dhcp-ddns element into D2ClientConfig.
static const isc::data::SimpleDefaults D2_CLIENT_CONFIG_DEFAULTS
Defaults for the D2 client configuration.
Definition: dhcp_parsers.h:854
static size_t setAllDefaults(isc::data::ConstElementPtr d2_config)
Sets all defaults for D2 client configuration.
Acts as a storage vault for D2 client configuration.
Definition: d2_client_cfg.h:56
static ReplaceClientNameMode stringToReplaceClientNameMode(const std::string &mode_str)
Converts labels to ReplaceClientNameMode enum values.
ReplaceClientNameMode
Defines the client name replacement modes.
Definition: d2_client_cfg.h:75
An exception that is thrown if an error occurs while configuring the D2 DHCP DDNS client.
Definition: d2_client_cfg.h:33
To be removed. Please use ConfigError instead.
Parser for a list of host reservations for a subnet.
void parse(const SubnetID &subnet_id, isc::data::ConstElementPtr hr_list, HostCollection &hosts_list)
Parses a list of host reservation entries for a subnet.
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition: iface_mgr.cc:53
static void setRuntimeOptionDefs(const OptionDefSpaceContainer &defs)
Copies option definitions created at runtime.
Definition: libdhcp++.cc:214
static OptionDefinitionPtr getOptionDef(const std::string &space, const uint16_t code)
Return the first option definition matching a particular option code.
Definition: libdhcp++.cc:122
static OptionDefinitionPtr getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id, const uint16_t code)
Returns vendor option definition for a given vendor-id and code.
Definition: libdhcp++.cc:164
static uint32_t optionSpaceToVendorId(const std::string &option_space)
Converts option space name to vendor id.
Definition: libdhcp++.cc:925
void parse(CfgMACSource &mac_sources, isc::data::ConstElementPtr value)
parses parameters value
Definition: dhcp_parsers.cc:45
void setRapidCommit(const util::Optional< bool > &rapid_commit)
Enables or disables Rapid Commit option support for the subnet.
Definition: network.h:1326
util::Optional< bool > getRapidCommit(const Inheritance &inheritance=Inheritance::ALL) const
Returns boolean value indicating that the Rapid Commit option is supported or unsupported for the sub...
Definition: network.h:1316
void setInterfaceId(const OptionPtr &ifaceid)
sets interface-id option (if defined)
Definition: network.h:1306
Triplet< uint32_t > getPreferred(const Inheritance &inheritance=Inheritance::ALL) const
Returns preferred lifetime (in seconds)
Definition: network.h:1280
Holds optional information about relay.
Definition: network.h:132
boost::shared_ptr< Network::RelayInfo > RelayInfoPtr
Pointer to the RelayInfo structure.
Definition: network.h:180
void requireClientClass(const isc::dhcp::ClientClass &class_name)
Adds class class_name to classes required to be evaluated.
Definition: network.cc:91
void allowClientClass(const isc::dhcp::ClientClass &class_name)
Sets the supported class to class class_name.
Definition: network.cc:86
void setIface(const util::Optional< std::string > &iface_name)
Sets local name of the interface for which this network is selected.
Definition: network.h:224
Triplet< uint32_t > getValid(const Inheritance &inheritance=Inheritance::ALL) const
Return valid-lifetime for addresses in that prefix.
Definition: network.h:340
Triplet< uint32_t > getT2(const Inheritance &inheritance=Inheritance::ALL) const
Returns T2 (rebind timer), expressed in seconds.
Definition: network.h:370
CfgOptionPtr getCfgOption()
Returns pointer to the option data configuration for this network.
Definition: network.h:436
Triplet< uint32_t > getT1(const Inheritance &inheritance=Inheritance::ALL) const
Returns T1 (renew timer), expressed in seconds.
Definition: network.h:356
Parser for option data values within a subnet.
void parse(const CfgOptionPtr &cfg, isc::data::ConstElementPtr option_data_list)
Parses a list of options, instantiates them and stores in cfg.
OptionDefListParser(const uint16_t address_family)
Constructor.
void parse(CfgOptionDefPtr cfg, isc::data::ConstElementPtr def_list)
Parses a list of option definitions, create them and store in cfg.
Parser for a single option definition.
Definition: dhcp_parsers.h:227
OptionDefinitionPtr parse(isc::data::ConstElementPtr option_def)
Parses an entry that describes single option definition.
OptionDefParser(const uint16_t address_family)
Constructor.
Base class representing a DHCP option definition.
static bool validateName(const std::string &name)
Checks that the provided option space name is valid.
Definition: option_space.cc:26
Universe
defines option universe DHCPv4 or DHCPv6
Definition: option.h:82
Parser for IPv6 prefix delegation definitions.
Definition: dhcp_parsers.h:676
PdPoolParser()
Constructor.
void parse(PoolStoragePtr pools, data::ConstElementPtr pd_pool_)
Builds a prefix delegation pool from the given configuration.
Parser for a list of prefix delegation pools.
Definition: dhcp_parsers.h:719
void parse(PoolStoragePtr pools, data::ConstElementPtr pd_pool_list)
Parse configuration entries.
static const size_t MAX_SNAME_LEN
length of the SNAME field in DHCPv4 message
Definition: pkt4.h:44
static const size_t MAX_FILE_LEN
length of the FILE field in DHCPv4 message
Definition: pkt4.h:47
Parser for IPv4 pool definitions.
Definition: dhcp_parsers.h:338
PoolPtr poolMaker(asiolink::IOAddress &addr, uint32_t len, int32_t ignored)
Creates a Pool4 object given a IPv4 prefix and the prefix length.
Pool information for IPv4 addresses.
Definition: pool.h:262
Parser for IPv6 pool definitions.
Definition: dhcp_parsers.h:621
PoolPtr poolMaker(asiolink::IOAddress &addr, uint32_t len, int32_t ptype)
Creates a Pool6 object given a IPv6 prefix and the prefix length.
Pool information for IPv6 addresses and prefixes.
Definition: pool.h:321
virtual void parse(PoolStoragePtr pools, isc::data::ConstElementPtr pool_structure, const uint16_t address_family)
parses the actual structure
virtual PoolPtr poolMaker(isc::asiolink::IOAddress &addr, uint32_t len, int32_t ptype=0)=0
Creates a Pool object given a IPv4 prefix and the prefix length.
Specialization of the pool list parser for DHCPv4.
Definition: dhcp_parsers.h:385
void parse(PoolStoragePtr pools, data::ConstElementPtr pools_list)
parses the actual structure
Specialization of the pool list parser for DHCPv6.
Definition: dhcp_parsers.h:646
void parse(PoolStoragePtr pools, data::ConstElementPtr pools_list)
parses the actual structure
parser for additional relay information
Definition: dhcp_parsers.h:405
RelayInfoParser(const isc::dhcp::Option::Universe &family)
constructor
void addAddress(const std::string &name, const std::string &address_str, isc::data::ConstElementPtr relay_elem, const isc::dhcp::Network::RelayInfoPtr &relay_info)
Attempts to add an IP address to list of relay addresses.
void parse(const isc::dhcp::Network::RelayInfoPtr &relay_info, isc::data::ConstElementPtr relay_elem)
parses the actual relay parameters
static const isc::data::SimpleKeywords SUBNET4_PARAMETERS
This table defines all subnet parameters for DHCPv4.
static const isc::data::SimpleKeywords OPTION4_DEF_PARAMETERS
This table defines all option definition parameters.
static const isc::data::SimpleKeywords POOL4_PARAMETERS
This table defines all pool parameters.
static const isc::data::SimpleKeywords POOL6_PARAMETERS
This table defines all pool parameters.
static const isc::data::SimpleKeywords SUBNET6_PARAMETERS
This table defines all subnet parameters for DHCPv6.
static const isc::data::SimpleKeywords OPTION6_DEF_PARAMETERS
This table defines all option definition parameters.
static const isc::data::SimpleKeywords PD_POOL6_PARAMETERS
This table defines all prefix delegation pool parameters.
Specifies current DHCP configuration.
Definition: srv_config.h:167
void setControlSocketInfo(const isc::data::ConstElementPtr &control_socket)
Sets information about the control socket.
Definition: srv_config.h:482
Subnet4ConfigParser(bool check_iface=true)
Constructor.
void validateResv(const Subnet4Ptr &subnet, ConstHostPtr host)
Verifies the host reservation address is in the subnet range.
void initSubnet(data::ConstElementPtr params, asiolink::IOAddress addr, uint8_t len)
Instantiates the IPv4 Subnet based on a given IPv4 address and prefix length.
Subnet4Ptr parse(data::ConstElementPtr subnet)
Parses a single IPv4 subnet configuration and adds to the Configuration Manager.
A configuration holder for IPv4 subnet.
Definition: subnet.h:529
virtual void duplicate_option_warning(uint32_t code, asiolink::IOAddress &addr)
Issues a DHCP6 server specific warning regarding duplicate subnet options.
Subnet6Ptr parse(data::ConstElementPtr subnet)
Parses a single IPv6 subnet configuration and adds to the Configuration Manager.
void initSubnet(isc::data::ConstElementPtr params, isc::asiolink::IOAddress addr, uint8_t len)
Instantiates the IPv6 Subnet based on a given IPv6 address and prefix length.
void validateResvs(const Subnet6Ptr &subnet, ConstHostPtr host)
Verifies host reservation addresses are in the subnet range.
Subnet6ConfigParser(bool check_iface=true)
Constructor.
A configuration holder for IPv6 subnet.
Definition: subnet.h:677
this class parses a single subnet
Definition: dhcp_parsers.h:468
SubnetConfigParser(uint16_t family, bool check_iface=true)
constructor
isc::dhcp::SubnetPtr subnet_
Pointer to the created subnet object.
Definition: dhcp_parsers.h:517
CfgOptionPtr options_
Pointer to the options configuration.
Definition: dhcp_parsers.h:526
virtual void initSubnet(isc::data::ConstElementPtr params, isc::asiolink::IOAddress addr, uint8_t len)=0
Instantiates the subnet based on a given IP prefix and prefix length.
SubnetPtr parse(isc::data::ConstElementPtr subnet)
parses a subnet description and returns Subnet{4,6} structure
isc::dhcp::Network::RelayInfoPtr relay_info_
Pointer to relay information.
Definition: dhcp_parsers.h:523
uint16_t address_family_
Address family: AF_INET or AF_INET6.
Definition: dhcp_parsers.h:520
bool check_iface_
Check if the specified interface exists in the system.
Definition: dhcp_parsers.h:529
PoolStoragePtr pools_
Storage for pools belonging to this subnet.
Definition: dhcp_parsers.h:514
virtual std::string toText() const
Returns textual representation of the subnet (e.g.
Definition: subnet.cc:174
bool check_iface_
Check if the specified interface exists in the system.
Definition: dhcp_parsers.h:610
Subnets4ListConfigParser(bool check_iface=true)
constructor
size_t parse(SrvConfigPtr cfg, data::ConstElementPtr subnets_list)
parses contents of the list
Subnets6ListConfigParser(bool check_iface=true)
constructor
size_t parse(SrvConfigPtr cfg, data::ConstElementPtr subnets_list)
parses contents of the list
bool check_iface_
Check if the specified interface exists in the system.
Definition: dhcp_parsers.h:824
This template specifies a parameter value.
Definition: triplet.h:37
A template representing an optional value.
Definition: optional.h:36
T get() const
Retrieves the encapsulated value.
Definition: optional.h:112
bool empty() const
Checks if the encapsulated value is empty.
Definition: optional.h:138
void unspecified(bool unspecified)
Modifies the flag that indicates whether the value is specified or unspecified.
Definition: optional.h:121
@ D6O_INTERFACE_ID
Definition: dhcp6.h:38
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
std::vector< SimpleDefault > SimpleDefaults
This specifies all default values in a given scope (e.g. a subnet).
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
@ error
Definition: db_log.h:118
NameChangeProtocol stringToNcrProtocol(const std::string &protocol_str)
Function which converts text labels to NameChangeProtocol enums.
Definition: ncr_io.cc:23
NameChangeFormat
Defines the list of data wire formats supported.
Definition: ncr_msg.h:60
NameChangeProtocol
Defines the list of socket protocols supported.
Definition: ncr_io.h:68
std::string ncrProtocolToString(NameChangeProtocol protocol)
Function which converts NameChangeProtocol enums to text labels.
Definition: ncr_io.cc:36
NameChangeFormat stringToNcrFormat(const std::string &fmt_str)
Function which converts labels to NameChangeFormat enum values.
Definition: ncr_msg.cc:26
std::string ncrFormatToString(NameChangeFormat format)
Function which converts NameChangeFormat enums to text labels.
Definition: ncr_msg.cc:35
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
boost::shared_ptr< Subnet > SubnetPtr
A generic pointer to either Subnet4 or Subnet6 object.
Definition: subnet.h:513
const isc::log::MessageID DHCPSRV_CFGMGR_NEW_SUBNET6
boost::shared_ptr< Subnet4 > Subnet4Ptr
A pointer to a Subnet4 object.
Definition: subnet.h:522
std::vector< PoolPtr > PoolStorage
a collection of pools
Definition: dhcp_parsers.h:279
boost::shared_ptr< D2ClientConfig > D2ClientConfigPtr
Defines a pointer for D2ClientConfig instances.
boost::shared_ptr< CfgOption > CfgOptionPtr
Non-const pointer.
Definition: cfg_option.h:706
@ DHO_END
Definition: dhcp4.h:224
@ DHO_PAD
Definition: dhcp4.h:69
boost::shared_ptr< CfgOptionDef > CfgOptionDefPtr
Non-const pointer.
const isc::log::MessageID DHCPSRV_CFGMGR_OPTION_DUPLICATE
boost::shared_ptr< Subnet6 > Subnet6Ptr
A pointer to a Subnet6 object.
Definition: subnet.h:670
boost::multi_index_container< Subnet6Ptr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetSubnetIdIndexTag >, boost::multi_index::const_mem_fun< Subnet, SubnetID, &Subnet::getID > >, boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetPrefixIndexTag >, boost::multi_index::const_mem_fun< Subnet, std::string, &Subnet::toText > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SubnetModificationTimeIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, boost::posix_time::ptime, &data::BaseStampedElement::getModificationTime > > > > Subnet6Collection
A collection of Subnet6 objects.
Definition: subnet.h:914
const isc::log::MessageID DHCPSRV_CFGMGR_RELAY_IP_ADDRESS_DEPRECATED
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
Definition: srv_config.h:1044
std::pair< IPv6ResrvIterator, IPv6ResrvIterator > IPv6ResrvRange
Definition: host.h:243
std::vector< HostPtr > HostCollection
Collection of the Host objects.
Definition: host.h:794
const int DHCPSRV_DBG_TRACE_DETAIL
Additional information.
Definition: dhcpsrv_log.h:38
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
boost::shared_ptr< PoolStorage > PoolStoragePtr
Definition: dhcp_parsers.h:280
boost::shared_ptr< Pool > PoolPtr
a pointer to either IPv4 or IPv6 Pool
Definition: pool.h:505
boost::multi_index_container< Subnet4Ptr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetSubnetIdIndexTag >, boost::multi_index::const_mem_fun< Subnet, SubnetID, &Subnet::getID > >, boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetPrefixIndexTag >, boost::multi_index::const_mem_fun< Subnet, std::string, &Subnet::toText > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SubnetServerIdIndexTag >, boost::multi_index::const_mem_fun< Network4, asiolink::IOAddress, &Network4::getServerId > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SubnetModificationTimeIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, boost::posix_time::ptime, &data::BaseStampedElement::getModificationTime > > > > Subnet4Collection
A collection of Subnet4 objects.
Definition: subnet.h:867
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
Definition: lease.h:24
const isc::log::MessageID DHCPSRV_CFGMGR_NEW_SUBNET4
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
Definition: host.h:788
boost::shared_ptr< Network > NetworkPtr
Pointer to the Network object.
Definition: network.h:40
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:24
boost::shared_ptr< Option > OptionPtr
Definition: option.h:36
string trim(const string &instring)
Trim Leading and Trailing Spaces.
Definition: strutil.cc:53
vector< string > tokens(const std::string &text, const std::string &delim, bool escape)
Split String into Tokens.
Definition: strutil.cc:77
Definition: edns.h:19
Defines the logger used by the top-level component of kea-lfc.
#define DHCP4_OPTION_SPACE
global std option spaces
#define DHCP6_OPTION_SPACE
Type
Type of lease or pool.
Definition: lease.h:50