Kea 2.7.1
dhcp_parsers.cc
Go to the documentation of this file.
1// Copyright (C) 2013-2024 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8#include <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/encode.h>
22#include <util/str.h>
23
24#include <boost/algorithm/string.hpp>
25#include <boost/foreach.hpp>
26#include <boost/lexical_cast.hpp>
27#include <boost/make_shared.hpp>
28#include <boost/scoped_ptr.hpp>
29
30#include <limits>
31#include <map>
32#include <string>
33#include <vector>
34#include <iomanip>
35
36using namespace std;
37using namespace isc::asiolink;
38using namespace isc::data;
39using namespace isc::util;
40
41namespace isc {
42namespace dhcp {
43
44// ******************** MACSourcesListConfigParser *************************
45
46void
48 uint32_t source = 0;
49 size_t cnt = 0;
50
51 // By default, there's only one source defined: ANY.
52 // If user specified anything, we need to get rid of that default.
53 mac_sources.clear();
54
55 for (auto const& source_elem : value->listValue()) {
56 std::string source_str = source_elem->stringValue();
57 try {
58 source = CfgMACSource::MACSourceFromText(source_str);
59 mac_sources.add(source);
60 ++cnt;
61 } catch (const InvalidParameter& ex) {
62 isc_throw(DhcpConfigError, "The mac-sources value '" << source_str
63 << "' was specified twice (" << value->getPosition() << ")");
64 } catch (const std::exception& ex) {
65 isc_throw(DhcpConfigError, "Failed to convert '"
66 << source_str << "' to any recognized MAC source:"
67 << ex.what() << " (" << value->getPosition() << ")");
68 }
69 }
70
71 if (!cnt) {
72 isc_throw(DhcpConfigError, "If specified, MAC Sources cannot be empty");
73 }
74}
75
76// ******************** ControlSocketParser *************************
78 if (!value) {
79 // Sanity check: not supposed to fail.
80 isc_throw(DhcpConfigError, "Logic error: specified control-socket is null");
81 }
82
83 if (value->getType() != Element::map) {
84 // Sanity check: not supposed to fail.
85 isc_throw(DhcpConfigError, "Specified control-socket is expected to be a map"
86 ", i.e. a structure defined within { }");
87 }
88 srv_cfg.setControlSocketInfo(value);
89}
90
91// ******************************** OptionDefParser ****************************
92
93OptionDefParser::OptionDefParser(const uint16_t address_family)
94 : address_family_(address_family) {
95}
96
99
100 // Check parameters.
101 if (address_family_ == AF_INET) {
103 } else {
105 }
106
107 // Get mandatory parameters.
108 std::string name = getString(option_def, "name");
109 int64_t code64 = getInteger(option_def, "code");
110 std::string type = getString(option_def, "type");
111
112 // Get optional parameters. Whoever called this parser, should have
113 // called SimpleParser::setDefaults first.
114 bool array_type = getBoolean(option_def, "array");
115 std::string record_types = getString(option_def, "record-types");
116 std::string space = getString(option_def, "space");
117 std::string encapsulates = getString(option_def, "encapsulate");
118 ConstElementPtr user_context = option_def->get("user-context");
119
120 // Check code value.
121 if (code64 < 0) {
122 isc_throw(DhcpConfigError, "option code must not be negative "
123 "(" << getPosition("code", option_def) << ")");
124 } else if (address_family_ == AF_INET &&
125 code64 > std::numeric_limits<uint8_t>::max()) {
126 isc_throw(DhcpConfigError, "invalid option code '" << code64
127 << "', it must not be greater than '"
128 << static_cast<int>(std::numeric_limits<uint8_t>::max())
129 << "' (" << getPosition("code", option_def) << ")");
130 } else if (address_family_ == AF_INET6 &&
131 code64 > std::numeric_limits<uint16_t>::max()) {
132 isc_throw(DhcpConfigError, "invalid option code '" << code64
133 << "', it must not be greater than '"
134 << std::numeric_limits<uint16_t>::max()
135 << "' (" << getPosition("code", option_def) << ")");
136 }
137 uint32_t code = static_cast<uint32_t>(code64);
138
139 // Validate space name.
140 if (!OptionSpace::validateName(space)) {
141 isc_throw(DhcpConfigError, "invalid option space name '"
142 << space << "' ("
143 << getPosition("space", option_def) << ")");
144 }
145
146 // Protect against definition of options 0 (PAD) or 255 (END)
147 // in (and only in) the dhcp4 space.
148 if (space == DHCP4_OPTION_SPACE) {
149 if (code == DHO_PAD) {
150 isc_throw(DhcpConfigError, "invalid option code '0': "
151 << "reserved for PAD ("
152 << getPosition("code", option_def) << ")");
153 } else if (code == DHO_END) {
154 isc_throw(DhcpConfigError, "invalid option code '255': "
155 << "reserved for END ("
156 << getPosition("code", option_def) << ")");
157 }
158 }
159
160 // For dhcp6 space the value 0 is reserved.
161 if (space == DHCP6_OPTION_SPACE) {
162 if (code == 0) {
163 isc_throw(DhcpConfigError, "invalid option code '0': "
164 << "reserved value ("
165 << getPosition("code", option_def) << ")");
166 }
167 }
168
169 // Create option definition.
171 // We need to check if user has set encapsulated option space
172 // name. If so, different constructor will be used.
173 if (!encapsulates.empty()) {
174 // Arrays can't be used together with sub-options.
175 if (array_type) {
176 isc_throw(DhcpConfigError, "option '" << space << "."
177 << name << "', comprising an array of data"
178 << " fields may not encapsulate any option space ("
179 << option_def->getPosition() << ")");
180
181 } else if (encapsulates == space) {
182 isc_throw(DhcpConfigError, "option must not encapsulate"
183 << " an option space it belongs to: '"
184 << space << "." << name << "' is set to"
185 << " encapsulate '" << space << "' ("
186 << option_def->getPosition() << ")");
187
188 } else {
189 def.reset(new OptionDefinition(name, code, space, type,
190 encapsulates.c_str()));
191 }
192
193 } else {
194 def.reset(new OptionDefinition(name, code, space, type, array_type));
195
196 }
197
198 if (user_context) {
199 def->setContext(user_context);
200 }
201
202 // Split the list of record types into tokens.
203 std::vector<std::string> record_tokens =
204 isc::util::str::tokens(record_types, ",");
205 // Iterate over each token and add a record type into
206 // option definition.
207 for (auto const& record_type : record_tokens) {
208 try {
209 auto const trim_rec = boost::trim_copy(record_type);
210 if (!trim_rec.empty()) {
211 def->addRecordField(trim_rec);
212 }
213 } catch (const Exception& ex) {
214 isc_throw(DhcpConfigError, "invalid record type values"
215 << " specified for the option definition: "
216 << ex.what() << " ("
217 << getPosition("record-types", option_def) << ")");
218 }
219 }
220
221 // Validate the definition.
222 try {
223 def->validate();
224 } catch (const std::exception& ex) {
226 << " (" << option_def->getPosition() << ")");
227 }
228
229 // Option definition has been created successfully.
230 return (def);
231}
232
233// ******************************** OptionDefListParser ************************
234
235OptionDefListParser::OptionDefListParser(const uint16_t address_family)
236 : address_family_(address_family) {
237}
238
239void
241 if (!option_def_list) {
242 // Sanity check: not supposed to fail.
243 isc_throw(DhcpConfigError, "parser error: a pointer to a list of"
244 << " option definitions is NULL ("
245 << option_def_list->getPosition() << ")");
246 }
247
248 OptionDefParser parser(address_family_);
249 for (auto const& option_def : option_def_list->listValue()) {
250 OptionDefinitionPtr def = parser.parse(option_def);
251 try {
252 storage->add(def);
253 } catch (const std::exception& ex) {
254 // Append position if there is a failure.
255 isc_throw(DhcpConfigError, ex.what() << " ("
256 << option_def->getPosition() << ")");
257 }
258 }
259
260 // All definitions have been prepared. Put them as runtime options into
261 // the libdhcp++.
262 LibDHCP::setRuntimeOptionDefs(storage->getContainer());
263}
264
265//****************************** RelayInfoParser ********************************
267 : family_(family) {
268};
269
270void
272 ConstElementPtr relay_elem) {
273
274 if (relay_elem->getType() != Element::map) {
275 isc_throw(DhcpConfigError, "relay must be a map");
276 }
277
278 ConstElementPtr addresses = relay_elem->get("ip-addresses");
279 if (!addresses) {
280 isc_throw(DhcpConfigError, "ip-addresses is required");
281 }
282
283 // Create our resultant RelayInfo structure
284 *relay_info = isc::dhcp::Network::RelayInfo();
285
286 if (addresses->getType() != Element::list) {
287 isc_throw(DhcpConfigError, "ip-addresses must be a list "
288 "(" << getPosition("ip-addresses", relay_elem) << ")");
289 }
290
291 for (auto const& address_element : addresses->listValue()) {
292 addAddress("ip-addresses", address_element->stringValue(),
293 relay_elem, relay_info);
294 }
295}
296
297void
298RelayInfoParser::addAddress(const std::string& name,
299 const std::string& address_str,
300 ConstElementPtr relay_elem,
301 const isc::dhcp::Network::RelayInfoPtr& relay_info) {
302 boost::scoped_ptr<isc::asiolink::IOAddress> ip;
303 try {
304 ip.reset(new isc::asiolink::IOAddress(address_str));
305 } catch (const std::exception& ex) {
306 isc_throw(DhcpConfigError, "address " << address_str
307 << " is not a valid: "
308 << (family_ == Option::V4 ? "IPv4" : "IPv6")
309 << "address"
310 << " (" << getPosition(name, relay_elem) << ")");
311 }
312
313 // Check if the address family matches.
314 if ((ip->isV4() && family_ != Option::V4) ||
315 (ip->isV6() && family_ != Option::V6) ) {
316 isc_throw(DhcpConfigError, "address " << address_str
317 << " is not a: "
318 << (family_ == Option::V4 ? "IPv4" : "IPv6")
319 << "address"
320 << " (" << getPosition(name, relay_elem) << ")");
321 }
322
323 try {
324 relay_info->addAddress(*ip);
325 } catch (const std::exception& ex) {
326 isc_throw(DhcpConfigError, "cannot add address: " << address_str
327 << " to relay info: " << ex.what()
328 << " (" << getPosition(name, relay_elem) << ")");
329 }
330}
331
332//****************************** PoolParser ********************************
333
334void
336 ConstElementPtr pool_structure,
337 const uint16_t address_family,
338 bool encapsulate_options) {
339
340 if (address_family == AF_INET) {
342 } else {
344 }
345
346 ConstElementPtr text_pool = pool_structure->get("pool");
347
348 if (!text_pool) {
349 isc_throw(DhcpConfigError, "Mandatory 'pool' entry missing in "
350 "definition: (" << pool_structure->getPosition() << ")");
351 }
352
353 // That should be a single pool representation. It should contain
354 // text is form prefix/len or first - last. Note that spaces
355 // are allowed
356 string txt = text_pool->stringValue();
357
358 // first let's remove any whitespaces
359 boost::erase_all(txt, " "); // space
360 boost::erase_all(txt, "\t"); // tabulation
361
362 PoolPtr pool;
363
364 // Is this prefix/len notation?
365 size_t pos = txt.find("/");
366 if (pos != string::npos) {
367 isc::asiolink::IOAddress addr("::");
368 uint8_t len = 0;
369 try {
370 addr = isc::asiolink::IOAddress(txt.substr(0, pos));
371
372 // start with the first character after /
373 string prefix_len = txt.substr(pos + 1);
374
375 // It is lexical cast to int and then downcast to uint8_t.
376 // Direct cast to uint8_t (which is really an unsigned char)
377 // will result in interpreting the first digit as output
378 // value and throwing exception if length is written on two
379 // digits (because there are extra characters left over).
380
381 // No checks for values over 128. Range correctness will
382 // be checked in Pool4 constructor, here we only check
383 // the representation fits in an uint8_t as this can't
384 // be done by a direct lexical cast as explained...
385 int val_len = boost::lexical_cast<int>(prefix_len);
386 if ((val_len < std::numeric_limits<uint8_t>::min()) ||
387 (val_len > std::numeric_limits<uint8_t>::max())) {
388 // This exception will be handled 4 line later!
390 }
391 len = static_cast<uint8_t>(val_len);
392 } catch (...) {
393 isc_throw(DhcpConfigError, "Failed to parse pool "
394 "definition: " << txt << " ("
395 << text_pool->getPosition() << ")");
396 }
397
398 try {
399 pool = poolMaker(addr, len);
400 pools->push_back(pool);
401 } catch (const std::exception& ex) {
402 isc_throw(DhcpConfigError, "Failed to create pool defined by: "
403 << txt << " (" << text_pool->getPosition() << ")");
404 }
405
406 } else {
407 isc::asiolink::IOAddress min("::");
408 isc::asiolink::IOAddress max("::");
409
410 // Is this min-max notation?
411 pos = txt.find("-");
412 if (pos != string::npos) {
413 // using min-max notation
414 try {
415 min = isc::asiolink::IOAddress(txt.substr(0, pos));
416 max = isc::asiolink::IOAddress(txt.substr(pos + 1));
417 } catch (...) {
418 isc_throw(DhcpConfigError, "Failed to parse pool "
419 "definition: " << txt << " ("
420 << text_pool->getPosition() << ")");
421 }
422
423 try {
424 pool = poolMaker(min, max);
425 pools->push_back(pool);
426 } catch (const std::exception& ex) {
427 isc_throw(DhcpConfigError, "Failed to create pool defined by: "
428 << txt << " (" << text_pool->getPosition() << ")");
429 }
430 }
431 }
432
433 if (!pool) {
434 isc_throw(DhcpConfigError, "invalid pool definition: "
435 << text_pool->stringValue() <<
436 ". There are two acceptable formats <min address-max address>"
437 " or <prefix/len> ("
438 << text_pool->getPosition() << ")");
439 }
440
441 // If there is a pool-id, store it.
442 ConstElementPtr pool_id = pool_structure->get("pool-id");
443 if (pool_id) {
444 if (pool_id->intValue() <= 0) {
445 isc_throw(BadValue, "pool-id " << pool_id->intValue() << " is not"
446 << " a positive integer greater than 0");
447 } else if (pool_id->intValue() > numeric_limits<uint32_t>::max()) {
448 isc_throw(BadValue, "pool-id " << pool_id->intValue() << " is not"
449 << " a 32 bit unsigned integer");
450 }
451
452 pool->setID(pool_id->intValue());
453 }
454
455 // If there's user-context specified, store it.
456 ConstElementPtr user_context = pool_structure->get("user-context");
457 if (user_context) {
458 // The grammar accepts only maps but still check it.
459 if (user_context->getType() != Element::map) {
460 isc_throw(isc::dhcp::DhcpConfigError, "User context has to be a map ("
461 << user_context->getPosition() << ")");
462 }
463 pool->setContext(user_context);
464 }
465
466 // Parser pool specific options.
467 ConstElementPtr option_data = pool_structure->get("option-data");
468 if (option_data) {
469 try {
470 CfgOptionPtr cfg = pool->getCfgOption();
471 auto option_parser = createOptionDataListParser(address_family);
472 option_parser->parse(cfg, option_data, encapsulate_options);
473 } catch (const std::exception& ex) {
475 << " (" << option_data->getPosition() << ")");
476 }
477 }
478
479 // Client-class.
480 ConstElementPtr client_class = pool_structure->get("client-class");
481 if (client_class) {
482 string cclass = client_class->stringValue();
483 if (!cclass.empty()) {
484 pool->allowClientClass(cclass);
485 }
486 }
487
488 // Try setting up required client classes.
489 ConstElementPtr class_list = pool_structure->get("require-client-classes");
490 if (class_list) {
491 const std::vector<data::ElementPtr>& classes = class_list->listValue();
492 for (auto const& cclass : classes) {
493 if ((cclass->getType() != Element::string) ||
494 cclass->stringValue().empty()) {
495 isc_throw(DhcpConfigError, "invalid class name ("
496 << cclass->getPosition() << ")");
497 }
498 pool->requireClientClass(cclass->stringValue());
499 }
500 }
501}
502
503boost::shared_ptr<OptionDataListParser>
504PoolParser::createOptionDataListParser(const uint16_t address_family) const {
505 return (boost::make_shared<OptionDataListParser>(address_family));
506}
507
508//****************************** Pool4Parser *************************
509
511Pool4Parser::poolMaker (IOAddress &addr, uint32_t len, int32_t) {
512 return (PoolPtr(new Pool4(addr, len)));
513}
514
517 return (PoolPtr(new Pool4(min, max)));
518}
519
520//****************************** Pools4ListParser *************************
521
522void
524 bool encapsulate_options) {
525 for (auto const& pool : pools_list->listValue()) {
526 auto const& parser = createPoolConfigParser();
527 parser->parse(pools, pool, AF_INET, encapsulate_options);
528 }
529}
530
531boost::shared_ptr<PoolParser>
533 return (boost::make_shared<Pool4Parser>());
534}
535
536//****************************** SubnetConfigParser *************************
537
538SubnetConfigParser::SubnetConfigParser(uint16_t family, bool check_iface)
539 : pools_(new PoolStorage()),
540 address_family_(family),
541 check_iface_(check_iface) {
543}
544
546SubnetConfigParser::parse(ConstElementPtr subnet, bool encapsulate_options) {
547
548 ConstElementPtr relay_params = subnet->get("relay");
549 if (relay_params) {
551 RelayInfoParser parser(u);
552 parser.parse(relay_info_, relay_params);
553 }
554
555 // Create a subnet.
556 try {
557 createSubnet(subnet);
558 } catch (const std::exception& ex) {
560 "subnet configuration failed: " << ex.what());
561 }
562
563 // We create subnet first and then parse the options straight into the subnet's
564 // CfgOption structure. Previously, we first parsed the options and then copied
565 // them into the CfgOption after creating the subnet but it had two issues. First,
566 // it cost performance. Second, copying options reset the isEncapsulated() flag.
567 // If the options have been encapsulated we want to preserve the flag to ensure
568 // they are not encapsulated several times.
569 ConstElementPtr options_params = subnet->get("option-data");
570 if (options_params) {
571 auto opt_parser = createOptionDataListParser();
572 opt_parser->parse(subnet_->getCfgOption(), options_params, encapsulate_options);
573 }
574
575 return (subnet_);
576}
577
578void
580 std::string subnet_txt;
581 try {
582 subnet_txt = getString(params, "subnet");
583 } catch (const DhcpConfigError &) {
584 // rethrow with precise error
586 "mandatory 'subnet' parameter is missing for a subnet being"
587 " configured (" << params->getPosition() << ")");
588 }
589
590 // Remove any spaces or tabs.
591 boost::erase_all(subnet_txt, " ");
592 boost::erase_all(subnet_txt, "\t");
593
594 // The subnet format is prefix/len. We are going to extract
595 // the prefix portion of a subnet string to create IOAddress
596 // object from it. IOAddress will be passed to the Subnet's
597 // constructor later on. In order to extract the prefix we
598 // need to get all characters preceding "/".
599 size_t pos = subnet_txt.find("/");
600 if (pos == string::npos) {
601 ConstElementPtr elem = params->get("subnet");
603 "Invalid subnet syntax (prefix/len expected):" << subnet_txt
604 << " (" << elem->getPosition() << ")");
605 }
606
607 // Try to create the address object. It also validates that
608 // the address syntax is ok.
609 isc::asiolink::IOAddress addr(subnet_txt.substr(0, pos));
610
611 // Now parse out the prefix length.
612 unsigned int len;
613 try {
614 len = boost::lexical_cast<unsigned int>(subnet_txt.substr(pos + 1));
615 } catch (const boost::bad_lexical_cast&) {
616 ConstElementPtr elem = params->get("subnet");
617 isc_throw(DhcpConfigError, "prefix length: '" <<
618 subnet_txt.substr(pos+1) << "' is not an integer ("
619 << elem->getPosition() << ")");
620 }
621
622 // Sanity check the prefix length
623 if ((addr.isV6() && len > 128) ||
624 (addr.isV4() && len > 32)) {
625 ConstElementPtr elem = params->get("subnet");
627 "Invalid prefix length specified for subnet: " << len
628 << " (" << elem->getPosition() << ")");
629 }
630
631 // Call the subclass's method to instantiate the subnet
632 initSubnet(params, addr, len);
633
634 // Add pools to it.
635 for (auto const& pool : *pools_) {
636 try {
637 subnet_->addPool(pool);
638 } catch (const BadValue& ex) {
639 // addPool() can throw BadValue if the pool is overlapping or
640 // is out of bounds for the subnet.
642 ex.what() << " (" << params->getPosition() << ")");
643 }
644 }
645 // If there's user-context specified, store it.
646 ConstElementPtr user_context = params->get("user-context");
647 if (user_context) {
648 // The grammar accepts only maps but still check it.
649 if (user_context->getType() != Element::map) {
650 isc_throw(isc::dhcp::DhcpConfigError, "User context has to be a map ("
651 << user_context->getPosition() << ")");
652 }
653 subnet_->setContext(user_context);
654 }
655
656 // In order to take advantage of the dynamic inheritance of global
657 // parameters to a subnet we need to set a callback function for each
658 // subnet to allow for fetching global parameters.
659 subnet_->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr {
660 return (CfgMgr::instance().getCurrentCfg()->getConfiguredGlobals());
661 });
662}
663
664boost::shared_ptr<OptionDataListParser>
666 return (boost::make_shared<OptionDataListParser>(address_family_));
667}
668
669//****************************** Subnet4ConfigParser *************************
670
672 : SubnetConfigParser(AF_INET, check_iface) {
673}
674
676Subnet4ConfigParser::parse(ConstElementPtr subnet, bool encapsulate_options) {
677 // Check parameters.
679
681 ConstElementPtr pools = subnet->get("pools");
682 if (pools) {
683 auto const& parser = createPoolsListParser();
684 parser->parse(pools_, pools, encapsulate_options);
685 }
686
687 SubnetPtr generic = SubnetConfigParser::parse(subnet, encapsulate_options);
688
689 if (!generic) {
690 // Sanity check: not supposed to fail.
692 "Failed to create an IPv4 subnet (" <<
693 subnet->getPosition() << ")");
694 }
695
696 Subnet4Ptr sn4ptr = boost::dynamic_pointer_cast<Subnet4>(subnet_);
697 if (!sn4ptr) {
698 // If we hit this, it is a programming error.
700 "Invalid Subnet4 cast in Subnet4ConfigParser::parse");
701 }
702
703 // Set relay information if it was parsed
704 if (relay_info_) {
705 sn4ptr->setRelayInfo(*relay_info_);
706 }
707
708 // Parse Host Reservations for this subnet if any.
709 ConstElementPtr reservations = subnet->get("reservations");
710 if (reservations) {
711 HostCollection hosts;
712 HostReservationsListParser<HostReservationParser4> parser;
713 parser.parse(subnet_->getID(), reservations, hosts);
714 for (auto const& h : hosts) {
715 validateResv(sn4ptr, h);
716 CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(h);
717 }
718 }
719
720 // Parse allocator specification.
721 auto network4 = boost::dynamic_pointer_cast<Network>(sn4ptr);
722 parseAllocatorParams(subnet, network4);
723
724 // Instantiate the allocator.
725 sn4ptr->createAllocators();
726
727 return (sn4ptr);
728}
729
730void
732 asiolink::IOAddress addr, uint8_t len) {
733 // Subnet ID is required and must be in 1..SUBNET_ID_MAX.
734 int64_t subnet_id_max = static_cast<int64_t>(SUBNET_ID_MAX);
735 SubnetID subnet_id = static_cast<SubnetID>(getInteger(params, "id", 1,
736 subnet_id_max));
737
738 auto subnet4 = Subnet4::create(addr, len, Triplet<uint32_t>(),
739 Triplet<uint32_t>(), Triplet<uint32_t>(),
740 subnet_id);
741 subnet_ = subnet4;
742
743 ElementPtr mutable_params;
744 mutable_params = boost::const_pointer_cast<Element>(params);
745
746 // Parse parameters common to all Network derivations.
747 NetworkPtr network = boost::dynamic_pointer_cast<Network>(subnet4);
748 parseCommon(mutable_params, network);
749
750 std::ostringstream output;
751 output << addr << "/" << static_cast<int>(len) << " with params: ";
752
753 bool has_renew = !subnet4->getT1().unspecified();
754 bool has_rebind = !subnet4->getT2().unspecified();
755 int64_t renew = -1;
756 int64_t rebind = -1;
757
758 // t1 and t2 are optional may be not specified.
759 if (has_renew) {
760 renew = subnet4->getT1().get();
761 output << "t1=" << renew << ", ";
762 }
763 if (has_rebind) {
764 rebind = subnet4->getT2().get();
765 output << "t2=" << rebind << ", ";
766 }
767
768 if (!subnet4->getValid().unspecified()) {
769 output << "valid-lifetime=" << subnet4->getValid().get();
770 }
771
773
774 // Set the match-client-id value for the subnet.
775 if (params->contains("match-client-id")) {
776 bool match_client_id = getBoolean(params, "match-client-id");
777 subnet4->setMatchClientId(match_client_id);
778 }
779
780 // Set the authoritative value for the subnet.
781 if (params->contains("authoritative")) {
782 bool authoritative = getBoolean(params, "authoritative");
783 subnet4->setAuthoritative(authoritative);
784 }
785
786 // Set next-server. The default value is 0.0.0.0. Nevertheless, the
787 // user could have messed that up by specifying incorrect value.
788 // To avoid using 0.0.0.0, user can specify "".
789 if (params->contains("next-server")) {
790 string next_server;
791 try {
792 next_server = getString(params, "next-server");
793 if (!next_server.empty()) {
794 subnet4->setSiaddr(IOAddress(next_server));
795 }
796 } catch (...) {
797 ConstElementPtr next = params->get("next-server");
798 string pos;
799 if (next) {
800 pos = next->getPosition().str();
801 } else {
802 pos = params->getPosition().str();
803 }
804 isc_throw(DhcpConfigError, "invalid parameter next-server : "
805 << next_server << "(" << pos << ")");
806 }
807 }
808
809 // Set server-hostname.
810 if (params->contains("server-hostname")) {
811 std::string sname = getString(params, "server-hostname");
812 if (!sname.empty()) {
813 if (sname.length() >= Pkt4::MAX_SNAME_LEN) {
814 ConstElementPtr error = params->get("server-hostname");
815 isc_throw(DhcpConfigError, "server-hostname must be at most "
816 << Pkt4::MAX_SNAME_LEN - 1 << " bytes long, it is "
817 << sname.length() << " ("
818 << error->getPosition() << ")");
819 }
820 subnet4->setSname(sname);
821 }
822 }
823
824 // Set boot-file-name.
825 if (params->contains("boot-file-name")) {
826 std::string filename =getString(params, "boot-file-name");
827 if (!filename.empty()) {
828 if (filename.length() > Pkt4::MAX_FILE_LEN) {
829 ConstElementPtr error = params->get("boot-file-name");
830 isc_throw(DhcpConfigError, "boot-file-name must be at most "
831 << Pkt4::MAX_FILE_LEN - 1 << " bytes long, it is "
832 << filename.length() << " ("
833 << error->getPosition() << ")");
834 }
835 subnet4->setFilename(filename);
836 }
837 }
838
839 // Get interface name. If it is defined, then the subnet is available
840 // directly over specified network interface.
841 if (params->contains("interface")) {
842 std::string iface = getString(params, "interface");
843 if (!iface.empty()) {
844 if (check_iface_ && !IfaceMgr::instance().getIface(iface)) {
845 ConstElementPtr error = params->get("interface");
846 isc_throw(DhcpConfigError, "Specified network interface name " << iface
847 << " for subnet " << subnet4->toText()
848 << " is not present in the system ("
849 << error->getPosition() << ")");
850 }
851
852 subnet4->setIface(iface);
853 }
854 }
855
856 // Try setting up client class.
857 if (params->contains("client-class")) {
858 string client_class = getString(params, "client-class");
859 if (!client_class.empty()) {
860 subnet4->allowClientClass(client_class);
861 }
862 }
863
864 // Try setting up required client classes.
865 ConstElementPtr class_list = params->get("require-client-classes");
866 if (class_list) {
867 const std::vector<data::ElementPtr>& classes = class_list->listValue();
868 for (auto const& cclass : classes) {
869 if ((cclass->getType() != Element::string) ||
870 cclass->stringValue().empty()) {
871 isc_throw(DhcpConfigError, "invalid class name ("
872 << cclass->getPosition() << ")");
873 }
874 subnet4->requireClientClass(cclass->stringValue());
875 }
876 }
877
878 // 4o6 specific parameter: 4o6-interface.
879 if (params->contains("4o6-interface")) {
880 string iface4o6 = getString(params, "4o6-interface");
881 if (!iface4o6.empty()) {
882 subnet4->get4o6().setIface4o6(iface4o6);
883 subnet4->get4o6().enabled(true);
884 }
885 }
886
887 // 4o6 specific parameter: 4o6-subnet.
888 if (params->contains("4o6-subnet")) {
889 string subnet4o6 = getString(params, "4o6-subnet");
890 if (!subnet4o6.empty()) {
891 size_t slash = subnet4o6.find("/");
892 if (slash == std::string::npos) {
893 isc_throw(DhcpConfigError, "Missing / in the 4o6-subnet parameter:"
894 << subnet4o6 << ", expected format: prefix6/length");
895 }
896 string prefix = subnet4o6.substr(0, slash);
897 string lenstr = subnet4o6.substr(slash + 1);
898
899 len = 128;
900 try {
901 len = boost::lexical_cast<unsigned int>(lenstr.c_str());
902 } catch (const boost::bad_lexical_cast &) {
903 isc_throw(DhcpConfigError, "Invalid prefix length specified in "
904 "4o6-subnet parameter: " << subnet4o6 << ", expected 0..128 value");
905 }
906 subnet4->get4o6().setSubnet4o6(IOAddress(prefix), len);
907 subnet4->get4o6().enabled(true);
908 }
909 }
910
911 // Try 4o6 specific parameter: 4o6-interface-id
912 if (params->contains("4o6-interface-id")) {
913 std::string ifaceid = getString(params, "4o6-interface-id");
914 if (!ifaceid.empty()) {
915 OptionBuffer tmp(ifaceid.begin(), ifaceid.end());
917 subnet4->get4o6().setInterfaceId(opt);
918 subnet4->get4o6().enabled(true);
919 }
920 }
921
924
925 // Here globally defined options were merged to the subnet specific
926 // options but this is no longer the case (they have a different
927 // and not consecutive priority).
928
929 // Parse t1-percent and t2-percent
930 parseTeePercents(params, network);
931
932 // Parse DDNS parameters
933 parseDdnsParams(params, network);
934
935 // Parse lease cache parameters
936 parseCacheParams(params, network);
937
938 // Set the offer_lft value for the subnet.
939 if (params->contains("offer-lifetime")) {
940 uint32_t offer_lft = getInteger(params, "offer-lifetime");
941 subnet4->setOfferLft(offer_lft);
942 }
943
944 // Parse offer-lifetime parameter.
945 Network4Ptr network4 = boost::dynamic_pointer_cast<Network4>(subnet4);
946 parseOfferLft(params, network4);
947
948}
949
950void
952 const IOAddress& address = host->getIPv4Reservation();
953 if (!address.isV4Zero() && !subnet->inRange(address)) {
954 isc_throw(DhcpConfigError, "specified reservation '" << address
955 << "' is not within the IPv4 subnet '"
956 << subnet->toText() << "'");
957 }
958}
959
960boost::shared_ptr<PoolsListParser>
962 return (boost::make_shared<Pools4ListParser>());
963}
964
965//**************************** Subnets4ListConfigParser **********************
966
968 : check_iface_(check_iface) {
969}
970
971size_t
973 ConstElementPtr subnets_list,
974 bool encapsulate_options) {
975 size_t cnt = 0;
976 for (auto const& subnet_json : subnets_list->listValue()) {
977
978 auto const& parser = createSubnetConfigParser();
979 Subnet4Ptr subnet = parser->parse(subnet_json, encapsulate_options);
980 if (subnet) {
981
982 // Adding a subnet to the Configuration Manager may fail if the
983 // subnet id is invalid (duplicate). Thus, we catch exceptions
984 // here to append a position in the configuration string.
985 try {
986 cfg->getCfgSubnets4()->add(subnet);
987 cnt++;
988 } catch (const std::exception& ex) {
989 isc_throw(DhcpConfigError, ex.what() << " ("
990 << subnet_json->getPosition() << ")");
991 }
992 }
993 }
994 return (cnt);
995}
996
997size_t
999 data::ConstElementPtr subnets_list,
1000 bool encapsulate_options) {
1001 size_t cnt = 0;
1002 for (auto const& subnet_json : subnets_list->listValue()) {
1003
1004 auto const& parser = createSubnetConfigParser();
1005 Subnet4Ptr subnet = parser->parse(subnet_json, encapsulate_options);
1006 if (subnet) {
1007 try {
1008 auto ret = subnets.insert(subnet);
1009 if (!ret.second) {
1011 "can't store subnet because of conflict");
1012 }
1013 ++cnt;
1014 } catch (const std::exception& ex) {
1015 isc_throw(DhcpConfigError, ex.what() << " ("
1016 << subnet_json->getPosition() << ")");
1017 }
1018 }
1019 }
1020 return (cnt);
1021}
1022
1023boost::shared_ptr<Subnet4ConfigParser>
1025 return (boost::make_shared<Subnet4ConfigParser>(check_iface_));
1026}
1027
1028//**************************** Pool6Parser *********************************
1029
1030PoolPtr
1031Pool6Parser::poolMaker(IOAddress &addr, uint32_t len, int32_t ptype)
1032{
1033 return (PoolPtr(new Pool6(static_cast<isc::dhcp::Lease::Type>
1034 (ptype), addr, len)));
1035}
1036
1037PoolPtr
1039{
1040 return (PoolPtr(new Pool6(static_cast<isc::dhcp::Lease::Type>
1041 (ptype), min, max)));
1042}
1043
1044
1045//**************************** Pool6ListParser ***************************
1046
1047void
1049 bool encapsulate_options) {
1050 for (auto const& pool : pools_list->listValue()) {
1051 auto const& parser = createPoolConfigParser();
1052 parser->parse(pools, pool, AF_INET6, encapsulate_options);
1053 }
1054}
1055
1056boost::shared_ptr<PoolParser>
1058 return (boost::make_shared<Pool6Parser>());
1059}
1060
1061//**************************** PdPoolParser ******************************
1062
1065
1066void
1068 bool encapsulate_options) {
1070
1071 std::string addr_str = getString(pd_pool, "prefix");
1072
1073 uint8_t prefix_len = getUint8(pd_pool, "prefix-len");
1074
1075 uint8_t delegated_len = getUint8(pd_pool, "delegated-len");
1076
1077 std::string excluded_prefix_str = "::";
1078 if (pd_pool->contains("excluded-prefix")) {
1079 excluded_prefix_str = getString(pd_pool, "excluded-prefix");
1080 }
1081
1082 uint8_t excluded_prefix_len = 0;
1083 if (pd_pool->contains("excluded-prefix-len")) {
1084 excluded_prefix_len = getUint8(pd_pool, "excluded-prefix-len");
1085 }
1086
1087 ConstElementPtr user_context = pd_pool->get("user-context");
1088 if (user_context) {
1089 user_context_ = user_context;
1090 }
1091
1092 ConstElementPtr client_class = pd_pool->get("client-class");
1093 if (client_class) {
1094 client_class_ = client_class;
1095 }
1096
1097 ConstElementPtr class_list = pd_pool->get("require-client-classes");
1098
1099 // Check the pool parameters. It will throw an exception if any
1100 // of the required parameters are invalid.
1101 try {
1102 // Attempt to construct the local pool.
1103 pool_.reset(new Pool6(IOAddress(addr_str),
1104 prefix_len,
1105 delegated_len,
1106 IOAddress(excluded_prefix_str),
1107 excluded_prefix_len));
1108 } catch (const std::exception& ex) {
1109 // Some parameters don't exist or are invalid. Since we are not
1110 // aware whether they don't exist or are invalid, let's append
1111 // the position of the pool map element.
1113 << " (" << pd_pool->getPosition() << ")");
1114 }
1115
1116 // If there is a pool-id, store it.
1117 ConstElementPtr pool_id = pd_pool->get("pool-id");
1118 if (pool_id) {
1119 if (pool_id->intValue() <= 0) {
1120 isc_throw(BadValue, "pool-id " << pool_id->intValue() << " is not"
1121 << " a positive integer greater than 0");
1122 } else if (pool_id->intValue() > numeric_limits<uint32_t>::max()) {
1123 isc_throw(BadValue, "pool-id " << pool_id->intValue() << " is not"
1124 << " a 32 bit unsigned integer");
1125 }
1126
1127 pool_->setID(pool_id->intValue());
1128 }
1129
1130 // We create subnet first and then parse the options straight into the subnet's
1131 // CfgOption structure. Previously, we first parsed the options and then copied
1132 // them into the CfgOption after creating the subnet but it had two issues. First,
1133 // it cost performance. Second, copying options reset the isEncapsulated() flag.
1134 // If the options have been encapsulated we want to preserve the flag to ensure
1135 // they are not encapsulated several times.
1136 ConstElementPtr option_data = pd_pool->get("option-data");
1137 if (option_data) {
1138 auto opts_parser = createOptionDataListParser();
1139 opts_parser->parse(pool_->getCfgOption(), option_data, encapsulate_options);
1140 }
1141
1142 if (user_context_) {
1143 pool_->setContext(user_context_);
1144 }
1145
1146 if (client_class_) {
1147 string cclass = client_class_->stringValue();
1148 if (!cclass.empty()) {
1149 pool_->allowClientClass(cclass);
1150 }
1151 }
1152
1153 if (class_list) {
1154 const std::vector<data::ElementPtr>& classes = class_list->listValue();
1155 for (auto const& cclass : classes) {
1156 if ((cclass->getType() != Element::string) ||
1157 cclass->stringValue().empty()) {
1158 isc_throw(DhcpConfigError, "invalid class name ("
1159 << cclass->getPosition() << ")");
1160 }
1161 pool_->requireClientClass(cclass->stringValue());
1162 }
1163 }
1164
1165 // Add the local pool to the external storage ptr.
1166 pools->push_back(pool_);
1167}
1168
1169boost::shared_ptr<OptionDataListParser>
1171 return (boost::make_shared<OptionDataListParser>(AF_INET6));
1172}
1173
1174//**************************** PdPoolsListParser ************************
1175
1176void
1178 // Loop through the list of pd pools.
1179 for (auto const& pd_pool : pd_pool_list->listValue()) {
1180 auto const& parser = createPdPoolConfigParser();
1181 parser->parse(pools, pd_pool);
1182 }
1183}
1184
1185boost::shared_ptr<PdPoolParser>
1187 return (boost::make_shared<PdPoolParser>());
1188}
1189
1190//**************************** Subnet6ConfigParser ***********************
1191
1193 : SubnetConfigParser(AF_INET6, check_iface) {
1194}
1195
1197Subnet6ConfigParser::parse(ConstElementPtr subnet, bool encapsulate_options) {
1198 // Check parameters.
1200
1202 ConstElementPtr pools = subnet->get("pools");
1203 if (pools) {
1204 auto const& parser = createPoolsListParser();
1205 parser->parse(pools_, pools, encapsulate_options);
1206 }
1207 ConstElementPtr pd_pools = subnet->get("pd-pools");
1208 if (pd_pools) {
1209 auto const& parser = createPdPoolsListParser();
1210 parser->parse(pools_, pd_pools);
1211 }
1212
1213 SubnetPtr generic = SubnetConfigParser::parse(subnet, encapsulate_options);
1214
1215 if (!generic) {
1216 // Sanity check: not supposed to fail.
1218 "Failed to create an IPv6 subnet (" <<
1219 subnet->getPosition() << ")");
1220 }
1221
1222 Subnet6Ptr sn6ptr = boost::dynamic_pointer_cast<Subnet6>(subnet_);
1223 if (!sn6ptr) {
1224 // If we hit this, it is a programming error.
1226 "Invalid Subnet6 cast in Subnet6ConfigParser::parse");
1227 }
1228
1229 // Set relay information if it was provided
1230 if (relay_info_) {
1231 sn6ptr->setRelayInfo(*relay_info_);
1232 }
1233
1234 // Parse Host Reservations for this subnet if any.
1235 ConstElementPtr reservations = subnet->get("reservations");
1236 if (reservations) {
1237 HostCollection hosts;
1238 HostReservationsListParser<HostReservationParser6> parser;
1239 parser.parse(subnet_->getID(), reservations, hosts);
1240 for (auto const& h : hosts) {
1241 validateResvs(sn6ptr, h);
1242 CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(h);
1243 }
1244 }
1245
1246 // Parse allocator specification.
1247 auto network = boost::dynamic_pointer_cast<Network>(sn6ptr);
1248 parseAllocatorParams(subnet, network);
1249
1250 // Parse pd-allocator specification.
1251 auto network6 = boost::dynamic_pointer_cast<Network6>(sn6ptr);
1252 parsePdAllocatorParams(subnet, network6);
1253
1254 // Instantiate the allocators.
1255 sn6ptr->createAllocators();
1256
1257 return (sn6ptr);
1258}
1259
1260// Unused?
1261void
1267
1268void
1270 asiolink::IOAddress addr, uint8_t len) {
1271 // Subnet ID is required and must be in 1..SUBNET_ID_MAX.
1272 int64_t subnet_id_max = static_cast<int64_t>(SUBNET_ID_MAX);
1273 SubnetID subnet_id = static_cast<SubnetID>(getInteger(params, "id", 1,
1274 subnet_id_max));
1275
1276 // We want to log whether rapid-commit is enabled, so we get this
1277 // before the actual subnet creation.
1278 Optional<bool> rapid_commit;
1279 if (params->contains("rapid-commit")) {
1280 rapid_commit = getBoolean(params, "rapid-commit");
1281 }
1282
1283 // Parse preferred lifetime as it is not parsed by the common function.
1284 Triplet<uint32_t> pref = parseIntTriplet(params, "preferred-lifetime");
1285
1286 // Create a new subnet.
1287 auto subnet6 = Subnet6::create(addr, len, Triplet<uint32_t>(),
1288 Triplet<uint32_t>(),
1289 pref,
1290 Triplet<uint32_t>(),
1291 subnet_id);
1292 subnet_ = subnet6;
1293
1294 ElementPtr mutable_params;
1295 mutable_params = boost::const_pointer_cast<Element>(params);
1296
1297 // Parse parameters common to all Network derivations.
1298 NetworkPtr network = boost::dynamic_pointer_cast<Network>(subnet_);
1299 parseCommon(mutable_params, network);
1300
1301 // Enable or disable Rapid Commit option support for the subnet.
1302 if (!rapid_commit.unspecified()) {
1303 subnet6->setRapidCommit(rapid_commit);
1304 }
1305
1306 std::ostringstream output;
1307 output << addr << "/" << static_cast<int>(len) << " with params: ";
1308 // t1 and t2 are optional may be not specified.
1309
1310 bool has_renew = !subnet6->getT1().unspecified();
1311 bool has_rebind = !subnet6->getT2().unspecified();
1312 int64_t renew = -1;
1313 int64_t rebind = -1;
1314
1315 if (has_renew) {
1316 renew = subnet6->getT1().get();
1317 output << "t1=" << renew << ", ";
1318 }
1319 if (has_rebind) {
1320 rebind = subnet6->getT2().get();
1321 output << "t2=" << rebind << ", ";
1322 }
1323
1324 if (!subnet6->getPreferred().unspecified()) {
1325 output << "preferred-lifetime=" << subnet6->getPreferred().get() << ", ";
1326 }
1327 if (!subnet6->getValid().unspecified()) {
1328 output << "valid-lifetime=" << subnet6->getValid().get();
1329 }
1330 if (!subnet6->getRapidCommit().unspecified()) {
1331 output << ", rapid-commit is "
1332 << boolalpha << subnet6->getRapidCommit().get();
1333 }
1334
1336
1337 // Get interface-id option content. For now we support string
1338 // representation only
1339 Optional<std::string> ifaceid;
1340 if (params->contains("interface-id")) {
1341 ifaceid = getString(params, "interface-id");
1342 }
1343
1344 Optional<std::string> iface;
1345 if (params->contains("interface")) {
1346 iface = getString(params, "interface");
1347 }
1348
1349 // Specifying both interface for locally reachable subnets and
1350 // interface id for relays is mutually exclusive. Need to test for
1351 // this condition.
1352 if (!ifaceid.unspecified() && !iface.unspecified() && !ifaceid.empty() &&
1353 !iface.empty()) {
1355 "parser error: interface (defined for locally reachable "
1356 "subnets) and interface-id (defined for subnets reachable"
1357 " via relays) cannot be defined at the same time for "
1358 "subnet " << addr << "/" << (int)len << "("
1359 << params->getPosition() << ")");
1360 }
1361
1362 // Configure interface-id for remote interfaces, if defined
1363 if (!ifaceid.unspecified() && !ifaceid.empty()) {
1364 std::string ifaceid_value = ifaceid.get();
1365 OptionBuffer tmp(ifaceid_value.begin(), ifaceid_value.end());
1367 subnet6->setInterfaceId(opt);
1368 }
1369
1370 // Get interface name. If it is defined, then the subnet is available
1371 // directly over specified network interface.
1372 if (!iface.unspecified() && !iface.empty()) {
1373 if (check_iface_ && !IfaceMgr::instance().getIface(iface)) {
1374 ConstElementPtr error = params->get("interface");
1375 isc_throw(DhcpConfigError, "Specified network interface name " << iface
1376 << " for subnet " << subnet6->toText()
1377 << " is not present in the system ("
1378 << error->getPosition() << ")");
1379 }
1380
1381 subnet6->setIface(iface);
1382 }
1383
1384 // Try setting up client class.
1385 if (params->contains("client-class")) {
1386 string client_class = getString(params, "client-class");
1387 if (!client_class.empty()) {
1388 subnet6->allowClientClass(client_class);
1389 }
1390 }
1391
1392 if (params->contains("require-client-classes")) {
1393 // Try setting up required client classes.
1394 ConstElementPtr class_list = params->get("require-client-classes");
1395 if (class_list) {
1396 const std::vector<data::ElementPtr>& classes = class_list->listValue();
1397 for (auto const& cclass : classes) {
1398 if ((cclass->getType() != Element::string) ||
1399 cclass->stringValue().empty()) {
1400 isc_throw(DhcpConfigError, "invalid class name ("
1401 << cclass->getPosition() << ")");
1402 }
1403 subnet6->requireClientClass(cclass->stringValue());
1404 }
1405 }
1406 }
1407
1410
1411 // Parse t1-percent and t2-percent
1412 parseTeePercents(params, network);
1413
1414 // Parse DDNS parameters
1415 parseDdnsParams(params, network);
1416
1417 // Parse lease cache parameters
1418 parseCacheParams(params, network);
1419}
1420
1421void
1423 const IPv6ResrvRange& range = host->getIPv6Reservations(IPv6Resrv::TYPE_NA);
1424 BOOST_FOREACH(auto const& it, range) {
1425 const IOAddress& address = it.second.getPrefix();
1426 if (!subnet->inRange(address)) {
1427 isc_throw(DhcpConfigError, "specified reservation '" << address
1428 << "' is not within the IPv6 subnet '"
1429 << subnet->toText() << "'");
1430 }
1431 }
1432}
1433
1434boost::shared_ptr<PoolsListParser>
1436 return (boost::make_shared<Pools6ListParser>());
1437}
1438
1439boost::shared_ptr<PdPoolsListParser>
1441 return (boost::make_shared<PdPoolsListParser>());
1442}
1443
1444//**************************** Subnet6ListConfigParser ********************
1445
1447 : check_iface_(check_iface) {
1448}
1449
1450size_t
1452 ConstElementPtr subnets_list,
1453 bool encapsulate_options) {
1454 size_t cnt = 0;
1455 for (auto const& subnet_json : subnets_list->listValue()) {
1456
1457 auto const& parser = createSubnetConfigParser();
1458 Subnet6Ptr subnet = parser->parse(subnet_json, encapsulate_options);
1459
1460 // Adding a subnet to the Configuration Manager may fail if the
1461 // subnet id is invalid (duplicate). Thus, we catch exceptions
1462 // here to append a position in the configuration string.
1463 try {
1464 cfg->getCfgSubnets6()->add(subnet);
1465 cnt++;
1466 } catch (const std::exception& ex) {
1467 isc_throw(DhcpConfigError, ex.what() << " ("
1468 << subnet_json->getPosition() << ")");
1469 }
1470 }
1471 return (cnt);
1472}
1473
1474size_t
1476 ConstElementPtr subnets_list,
1477 bool encapsulate_options) {
1478 size_t cnt = 0;
1479 for (auto const& subnet_json : subnets_list->listValue()) {
1480
1481 auto const& parser = createSubnetConfigParser();
1482 Subnet6Ptr subnet = parser->parse(subnet_json, encapsulate_options);
1483 if (subnet) {
1484 try {
1485 auto ret = subnets.insert(subnet);
1486 if (!ret.second) {
1488 "can't store subnet because of conflict");
1489 }
1490 ++cnt;
1491 } catch (const std::exception& ex) {
1492 isc_throw(DhcpConfigError, ex.what() << " ("
1493 << subnet_json->getPosition() << ")");
1494 }
1495 }
1496 }
1497 return (cnt);
1498}
1499
1500boost::shared_ptr<Subnet6ConfigParser>
1502 return (boost::make_shared<Subnet6ConfigParser>(check_iface_));
1503}
1504
1505//**************************** D2ClientConfigParser **********************
1506
1508D2ClientConfigParser::getProtocol(ConstElementPtr scope,
1509 const std::string& name) {
1512 (scope, name, "NameChangeRequest protocol"));
1513}
1514
1516D2ClientConfigParser::getFormat(ConstElementPtr scope,
1517 const std::string& name) {
1520 (scope, name, "NameChangeRequest format"));
1521}
1522
1524D2ClientConfigParser::getMode(ConstElementPtr scope,
1525 const std::string& name) {
1528 (scope, name, "ReplaceClientName mode"));
1529}
1530
1533 D2ClientConfigPtr new_config;
1534
1535 // Get all parameters that are needed to create the D2ClientConfig.
1536 bool enable_updates = getBoolean(client_config, "enable-updates");
1537
1538 IOAddress server_ip = getAddress(client_config, "server-ip");
1539
1540 uint32_t server_port = getUint32(client_config, "server-port");
1541
1542 std::string sender_ip_str = getString(client_config, "sender-ip");
1543
1544 uint32_t sender_port = getUint32(client_config, "sender-port");
1545
1546 uint32_t max_queue_size = getUint32(client_config, "max-queue-size");
1547
1548 dhcp_ddns::NameChangeProtocol ncr_protocol =
1549 getProtocol(client_config, "ncr-protocol");
1550
1551 dhcp_ddns::NameChangeFormat ncr_format =
1552 getFormat(client_config, "ncr-format");
1553
1554 IOAddress sender_ip(0);
1555 if (sender_ip_str.empty()) {
1556 // The default sender IP depends on the server IP family
1557 sender_ip = (server_ip.isV4() ? IOAddress::IPV4_ZERO_ADDRESS() :
1559 } else {
1560 try {
1561 sender_ip = IOAddress(sender_ip_str);
1562 } catch (const std::exception& ex) {
1563 isc_throw(DhcpConfigError, "invalid address (" << sender_ip_str
1564 << ") specified for parameter 'sender-ip' ("
1565 << getPosition("sender-ip", client_config) << ")");
1566 }
1567 }
1568
1569 // Now we check for logical errors. This repeats what is done in
1570 // D2ClientConfig::validate(), but doing it here permits us to
1571 // emit meaningful parameter position info in the error.
1572 if (ncr_format != dhcp_ddns::FMT_JSON) {
1573 isc_throw(D2ClientError, "D2ClientConfig error: NCR Format: "
1574 << dhcp_ddns::ncrFormatToString(ncr_format)
1575 << " is not supported. ("
1576 << getPosition("ncr-format", client_config) << ")");
1577 }
1578
1579 if (ncr_protocol != dhcp_ddns::NCR_UDP) {
1580 isc_throw(D2ClientError, "D2ClientConfig error: NCR Protocol: "
1581 << dhcp_ddns::ncrProtocolToString(ncr_protocol)
1582 << " is not supported. ("
1583 << getPosition("ncr-protocol", client_config) << ")");
1584 }
1585
1586 if (sender_ip.getFamily() != server_ip.getFamily()) {
1588 "D2ClientConfig error: address family mismatch: "
1589 << "server-ip: " << server_ip.toText()
1590 << " is: " << (server_ip.isV4() ? "IPv4" : "IPv6")
1591 << " while sender-ip: " << sender_ip.toText()
1592 << " is: " << (sender_ip.isV4() ? "IPv4" : "IPv6")
1593 << " (" << getPosition("sender-ip", client_config) << ")");
1594 }
1595
1596 if (server_ip == sender_ip && server_port == sender_port) {
1598 "D2ClientConfig error: server and sender cannot"
1599 " share the exact same IP address/port: "
1600 << server_ip.toText() << "/" << server_port
1601 << " (" << getPosition("sender-ip", client_config) << ")");
1602 }
1603
1604 try {
1605 // Attempt to create the new client config.
1606 new_config.reset(new D2ClientConfig(enable_updates,
1607 server_ip,
1608 server_port,
1609 sender_ip,
1610 sender_port,
1611 max_queue_size,
1612 ncr_protocol,
1613 ncr_format));
1614 } catch (const std::exception& ex) {
1615 isc_throw(DhcpConfigError, ex.what() << " ("
1616 << client_config->getPosition() << ")");
1617 }
1618
1619 // Add user context
1620 ConstElementPtr user_context = client_config->get("user-context");
1621 if (user_context) {
1622 new_config->setContext(user_context);
1623 }
1624
1625 return (new_config);
1626}
1627
1630 // enable-updates is unconditionally required
1631 { "server-ip", Element::string, "127.0.0.1" },
1632 { "server-port", Element::integer, "53001" },
1633 // default sender-ip depends on server-ip family, so we leave default blank
1634 // parser knows to use the appropriate ZERO address based on server-ip
1635 { "sender-ip", Element::string, "" },
1636 { "sender-port", Element::integer, "0" },
1637 { "max-queue-size", Element::integer, "1024" },
1638 { "ncr-protocol", Element::string, "UDP" },
1639 { "ncr-format", Element::string, "JSON" }
1640};
1641
1642size_t
1644 ElementPtr mutable_d2 = boost::const_pointer_cast<Element>(d2_config);
1646}
1647
1648void
1650 if (compatibility) {
1651 auto family = CfgMgr::instance().getFamily();
1652 for (auto const& kv : compatibility->mapValue()) {
1653 if (!kv.second || (kv.second->getType() != Element::boolean)) {
1655 "compatibility parameter values must be "
1656 << "boolean (" << kv.first << " at "
1657 << kv.second->getPosition() << ")");
1658 }
1659 if (kv.first == "lenient-option-parsing") {
1660 srv_cfg.setLenientOptionParsing(kv.second->boolValue());
1661 } else if (family == AF_INET) {
1662 if (kv.first == "ignore-dhcp-server-identifier") {
1663 srv_cfg.setIgnoreServerIdentifier(kv.second->boolValue());
1664 } else if (kv.first == "ignore-rai-link-selection") {
1665 srv_cfg.setIgnoreRAILinkSelection(kv.second->boolValue());
1666 } else if (kv.first == "exclude-first-last-24") {
1667 srv_cfg.setExcludeFirstLast24(kv.second->boolValue());
1668 } else {
1670 "unsupported compatibility parameter: "
1671 << kv.first << " (" << kv.second->getPosition()
1672 << ")");
1673 }
1674 } else {
1676 "unsupported compatibility parameter: "
1677 << kv.first << " (" << kv.second->getPosition()
1678 << ")");
1679 }
1680 }
1681 }
1682}
1683
1684} // namespace dhcp
1685} // namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
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.
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.
const isc::util::Triplet< uint32_t > parseIntTriplet(const data::ConstElementPtr &scope, const std::string &name)
Parses an integer triplet.
static bool getBoolean(isc::data::ConstElementPtr scope, const std::string &name)
Returns a boolean parameter from a scope.
static int64_t getInteger(isc::data::ConstElementPtr scope, const std::string &name)
Returns an integer parameter from a scope.
static size_t setDefaults(isc::data::ElementPtr scope, const SimpleDefaults &default_values)
Sets the default values.
void parseCacheParams(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses parameters related to lease cache settings.
void parseAllocatorParams(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses parameters pertaining to allocator selection.
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.
void parseTeePercents(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses parameters related to "percent" timers settings.
void parsePdAllocatorParams(const data::ConstElementPtr &network_data, Network6Ptr &network)
Parses parameters pertaining to prefix delegation allocator selection.
void parseOfferLft(const data::ConstElementPtr &network_data, Network4Ptr &network)
Parses offer-lifetime parameter (v4 only)
Wrapper class that holds 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
void parse(isc::data::ConstElementPtr cfg, isc::dhcp::SrvConfig &srv_cfg)
Parse compatibility flags.
void parse(SrvConfig &srv_cfg, isc::data::ConstElementPtr value)
"Parses" control-socket structure
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.
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.
static ReplaceClientNameMode stringToReplaceClientNameMode(const std::string &mode_str)
Converts labels to ReplaceClientNameMode enum values.
ReplaceClientNameMode
Defines the client name replacement modes.
An exception that is thrown if an error occurs while configuring the D2 DHCP DDNS client.
To be removed. Please use ConfigError instead.
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition iface_mgr.cc:54
static void setRuntimeOptionDefs(const OptionDefSpaceContainer &defs)
Copies option definitions created at runtime.
Definition libdhcp++.cc:220
void parse(CfgMACSource &mac_sources, isc::data::ConstElementPtr value)
parses parameters value
Holds optional information about relay.
Definition network.h:162
boost::shared_ptr< Network::RelayInfo > RelayInfoPtr
Pointer to the RelayInfo structure.
Definition network.h:210
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.
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.
Universe
defines option universe DHCPv4 or DHCPv6
Definition option.h:83
virtual boost::shared_ptr< OptionDataListParser > createOptionDataListParser() const
Returns an instance of the OptionDataListParser to be used in parsing the option-data structure.
isc::data::ConstElementPtr user_context_
User context (optional, may be null)
void parse(PoolStoragePtr pools, data::ConstElementPtr pd_pool_, bool encapsulate_options=true)
Builds a prefix delegation pool from the given configuration.
isc::dhcp::Pool6Ptr pool_
Pointer to the created pool object.
isc::data::ConstElementPtr client_class_
Client class (a client has to belong to to use this pd-pool)
virtual boost::shared_ptr< PdPoolParser > createPdPoolConfigParser() const
Returns an instance of the PdPoolParser to be used in parsing the prefix delegation pools.
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
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:240
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:299
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.
virtual void parse(PoolStoragePtr pools, isc::data::ConstElementPtr pool_structure, const uint16_t address_family, bool encapsulate_options=true)
parses the actual structure
virtual boost::shared_ptr< OptionDataListParser > createOptionDataListParser(const uint16_t address_family) const
Returns an instance of the OptionDataListParser to be used in parsing the option-data structure.
void parse(PoolStoragePtr pools, data::ConstElementPtr pools_list, bool encapsulate_options=true)
parses the actual structure
virtual boost::shared_ptr< PoolParser > createPoolConfigParser() const
Returns an instance of the Pool4Parser to be used in parsing the address pools.
void parse(PoolStoragePtr pools, data::ConstElementPtr pools_list, bool encapsulate_options=true)
parses the actual structure
virtual boost::shared_ptr< PoolParser > createPoolConfigParser() const
Returns an instance of the Pool6Parser to be used in parsing the address pools.
parser for additional relay information
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:184
Subnet4ConfigParser(bool check_iface=true)
Constructor.
virtual boost::shared_ptr< PoolsListParser > createPoolsListParser() const
Returns an instance of the Pools4ListParser to be used in parsing the address pools.
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, bool encapsulate_options=true)
Parses a single IPv4 subnet configuration and adds to the Configuration Manager.
static Subnet4Ptr create(const isc::asiolink::IOAddress &prefix, uint8_t length, const util::Triplet< uint32_t > &t1, const util::Triplet< uint32_t > &t2, const util::Triplet< uint32_t > &valid_lifetime, const SubnetID id)
Factory function creating an instance of the Subnet4.
Definition subnet.cc:263
virtual boost::shared_ptr< PoolsListParser > createPoolsListParser() const
Returns an instance of the Pools6ListParser to be used in parsing the address pools.
virtual boost::shared_ptr< PdPoolsListParser > createPdPoolsListParser() const
Returns an instance of the PdPools6ListParser to be used in parsing the prefix delegation pools.
Subnet6Ptr parse(data::ConstElementPtr subnet, bool encapsulate_options=true)
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.
virtual void duplicateOptionWarning(uint32_t code, asiolink::IOAddress &addr)
Issues a DHCP6 server specific warning regarding duplicate subnet options.
void validateResvs(const Subnet6Ptr &subnet, ConstHostPtr host)
Verifies host reservation addresses are in the subnet range.
Subnet6ConfigParser(bool check_iface=true)
Constructor.
static Subnet6Ptr create(const isc::asiolink::IOAddress &prefix, uint8_t length, const util::Triplet< uint32_t > &t1, const util::Triplet< uint32_t > &t2, const util::Triplet< uint32_t > &preferred_lifetime, const util::Triplet< uint32_t > &valid_lifetime, const SubnetID id)
Factory function creating an instance of the Subnet4.
Definition subnet.cc:651
this class parses a single subnet
SubnetConfigParser(uint16_t family, bool check_iface=true)
constructor
isc::dhcp::SubnetPtr subnet_
Pointer to the created subnet object.
void createSubnet(isc::data::ConstElementPtr data)
Create a new subnet using a data from child parsers.
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.
isc::dhcp::Network::RelayInfoPtr relay_info_
Pointer to relay information.
uint16_t address_family_
Address family: AF_INET or AF_INET6.
SubnetPtr parse(isc::data::ConstElementPtr subnet, bool encapsulate_options)
parses a subnet description and returns Subnet{4,6} structure
bool check_iface_
Check if the specified interface exists in the system.
virtual boost::shared_ptr< OptionDataListParser > createOptionDataListParser() const
Returns an instance of the OptionDataListParser to be used in parsing the option-data structure.
PoolStoragePtr pools_
Storage for pools belonging to this subnet.
bool check_iface_
Check if the specified interface exists in the system.
size_t parse(SrvConfigPtr cfg, data::ConstElementPtr subnets_list, bool encapsulate_options=true)
parses contents of the list
Subnets4ListConfigParser(bool check_iface=true)
constructor
virtual boost::shared_ptr< Subnet4ConfigParser > createSubnetConfigParser() const
Returns an instance of the Subnet4ConfigParser to be used in parsing the subnets.
virtual boost::shared_ptr< Subnet6ConfigParser > createSubnetConfigParser() const
Returns an instance of the Subnet6ConfigParser to be used in parsing the subnets.
Subnets6ListConfigParser(bool check_iface=true)
constructor
bool check_iface_
Check if the specified interface exists in the system.
size_t parse(SrvConfigPtr cfg, data::ConstElementPtr subnets_list, bool encapsulate_options=true)
parses contents of the list
@ 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
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
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:28
@ 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:59
NameChangeProtocol
Defines the list of socket protocols supported.
Definition ncr_io.h:69
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< const CfgGlobals > ConstCfgGlobalsPtr
Const shared pointer to a CfgGlobals instance.
boost::shared_ptr< Subnet > SubnetPtr
A generic pointer to either Subnet4 or Subnet6 object.
Definition subnet.h:449
const isc::log::MessageID DHCPSRV_CFGMGR_NEW_SUBNET6
boost::shared_ptr< Subnet4 > Subnet4Ptr
A pointer to a Subnet4 object.
Definition subnet.h:458
boost::shared_ptr< Network4 > Network4Ptr
Pointer to the Network4 object.
Definition network.h:1413
std::vector< PoolPtr > PoolStorage
a collection of pools
boost::shared_ptr< D2ClientConfig > D2ClientConfigPtr
Defines a pointer for D2ClientConfig instances.
boost::shared_ptr< CfgOption > CfgOptionPtr
Non-const pointer.
Definition cfg_option.h:803
@ DHO_END
Definition dhcp4.h:229
@ 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:623
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:934
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
std::pair< IPv6ResrvIterator, IPv6ResrvIterator > IPv6ResrvRange
Definition host.h:243
std::vector< HostPtr > HostCollection
Collection of the Host objects.
Definition host.h:816
boost::shared_ptr< OptionDefinition > OptionDefinitionPtr
Pointer to option definition object.
boost::shared_ptr< PoolStorage > PoolStoragePtr
boost::shared_ptr< Pool > PoolPtr
a pointer to either IPv4 or IPv6 Pool
Definition pool.h:483
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:863
uint32_t SubnetID
Defines unique IPv4 or IPv6 subnet identifier.
Definition subnet_id.h:25
const isc::log::MessageID DHCPSRV_CFGMGR_NEW_SUBNET4
boost::shared_ptr< const Host > ConstHostPtr
Const pointer to the Host object.
Definition host.h:810
boost::shared_ptr< Network > NetworkPtr
Pointer to the Network object.
Definition network.h:73
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition option.h:24
boost::shared_ptr< Option > OptionPtr
Definition option.h:37
vector< string > tokens(const string &text, const string &delim, bool escape)
Split string into tokens.
Definition str.cc:52
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:46