18 #include <boost/algorithm/string.hpp>
19 #include <boost/foreach.hpp>
20 #include <boost/lexical_cast.hpp>
21 #include <boost/scoped_ptr.hpp>
48 std::string source_str = source_elem->stringValue();
50 source = CfgMACSource::MACSourceFromText(source_str);
51 mac_sources.
add(source);
55 <<
"' was specified twice (" << value->getPosition() <<
")");
56 }
catch (
const std::exception& ex) {
58 << source_str <<
"' to any recognized MAC source:"
59 << ex.
what() <<
" (" << value->getPosition() <<
")");
75 if (value->getType() != Element::map) {
78 ", i.e. a structure defined within { }");
83 template<
typename SearchKey>
85 OptionDataParser::findOptionDefinition(
const std::string& option_space,
86 const SearchKey& search_key)
const {
92 uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(option_space);
95 Option::V4 : Option::V6;
96 def = LibDHCP::getVendorOptionDef(u, vendor_id, search_key);
102 def = CfgMgr::instance().getStagingCfg()->getCfgOptionDef()
103 ->get(option_space, search_key);
111 std::pair<isc::dhcp::OptionDefinitionPtr, std::string>
115 std::string name = getString(option_def,
"name");
116 uint32_t code = getInteger(option_def,
"code");
117 std::string type = getString(option_def,
"type");
121 bool array_type = getBoolean(option_def,
"array");
122 std::string record_types = getString(option_def,
"record-types");
123 std::string space = getString(option_def,
"space");
124 std::string encapsulates = getString(option_def,
"encapsulate");
127 if (!OptionSpace::validateName(space)) {
130 << getPosition(
"space", option_def) <<
")");
137 if (!encapsulates.empty()) {
141 <<
"name" <<
"', comprising an array of data"
142 <<
" fields may not encapsulate any option space ("
143 << option_def->getPosition() <<
")");
145 }
else if (encapsulates == space) {
147 <<
" an option space it belongs to: '"
148 << space <<
"." << name <<
"' is set to"
149 <<
" encapsulate '" << space <<
"' ("
150 << option_def->getPosition() <<
")");
154 encapsulates.c_str()));
163 def->setContext(user_context);
167 std::vector<std::string> record_tokens =
171 BOOST_FOREACH(std::string record_type, record_tokens) {
174 if (!record_type.empty()) {
175 def->addRecordField(record_type);
179 <<
" specified for the option definition: "
181 << getPosition(
"record-types", option_def) <<
")");
188 }
catch (
const std::exception& ex) {
190 <<
" (" << option_def->getPosition() <<
")");
194 return make_pair(def, space);
200 if (!option_def_list) {
203 <<
" option definitions is NULL ("
204 << option_def_list->getPosition() <<
")");
208 BOOST_FOREACH(
ConstElementPtr option_def, option_def_list->listValue()) {
211 def = parser.
parse(option_def);
213 storage->add(def.first, def.second);
214 }
catch (
const std::exception& ex) {
217 << option_def->getPosition() <<
")");
223 LibDHCP::setRuntimeOptionDefs(storage->getContainer());
235 if (relay_elem->getType() != Element::map) {
242 if (address && addresses) {
244 "specify either ip-address or ip-addresses, not both");
247 if (!address && !addresses) {
256 relay_elem, relay_info);
258 DHCPSRV_CFGMGR_RELAY_IP_ADDRESS_DEPRECATED)
263 if (addresses->getType() != Element::list) {
265 <<
" (" <<
getPosition(
"ip-addresses", relay_elem) <<
")");
268 BOOST_FOREACH(
ConstElementPtr address_element, addresses->listValue()) {
269 addAddress(
"ip-addresses", address_element->stringValue(),
270 relay_elem, relay_info);
276 const std::string& address_str,
279 boost::scoped_ptr<isc::asiolink::IOAddress> ip;
282 }
catch (
const std::exception& ex) {
284 <<
" is not a valid: "
301 relay_info->addAddress(*ip);
302 }
catch (
const std::exception& ex) {
304 <<
"to relay info: " << ex.
what()
314 const uint16_t address_family) {
320 "definition: (" << pool_structure->getPosition() <<
")");
326 string txt = text_pool->stringValue();
329 boost::erase_all(txt,
" ");
330 boost::erase_all(txt,
"\t");
335 size_t pos = txt.find(
"/");
336 if (pos != string::npos) {
343 string prefix_len = txt.substr(pos + 1);
355 int val_len = boost::lexical_cast<int>(prefix_len);
356 if ((val_len < std::numeric_limits<uint8_t>::min()) ||
357 (val_len > std::numeric_limits<uint8_t>::max())) {
361 len =
static_cast<uint8_t
>(val_len);
364 "definition: " << txt <<
" ("
365 << text_pool->getPosition() <<
")");
370 pools->push_back(pool);
371 }
catch (
const std::exception& ex) {
373 << txt <<
" (" << text_pool->getPosition() <<
")");
382 if (pos != string::npos) {
389 "definition: " << txt <<
" ("
390 << text_pool->getPosition() <<
")");
395 pools->push_back(pool);
396 }
catch (
const std::exception& ex) {
398 << txt <<
" (" << text_pool->getPosition() <<
")");
405 << text_pool->stringValue() <<
406 ". There are two acceptable formats <min address-max address>"
408 << text_pool->getPosition() <<
")");
415 if (user_context->getType() != Element::map) {
417 << user_context->getPosition() <<
")");
419 pool->setContext(user_context);
428 option_parser.
parse(cfg, option_data);
429 }
catch (
const std::exception& ex) {
431 <<
" (" << option_data->getPosition() <<
")");
438 string cclass = client_class->stringValue();
439 if (!cclass.empty()) {
440 pool->allowClientClass(cclass);
445 ConstElementPtr class_list = pool_structure->get(
"require-client-classes");
447 const std::vector<data::ElementPtr>& classes = class_list->listValue();
448 for (
auto cclass = classes.cbegin();
449 cclass != classes.cend(); ++cclass) {
450 if (((*cclass)->getType() != Element::string) ||
451 (*cclass)->stringValue().empty()) {
453 << (*cclass)->getPosition() <<
")");
455 pool->requireClientClass((*cclass)->stringValue());
478 parser.
parse(pools, pool, AF_INET);
486 address_family_(family),
495 if (options_params) {
509 createSubnet(subnet);
510 }
catch (
const std::exception& ex) {
512 "subnet configuration failed: " << ex.
what());
520 if ( (txt.compare(
"disabled") == 0) ||
521 (txt.compare(
"off") == 0) ) {
523 }
else if (txt.compare(
"out-of-pool") == 0) {
525 }
else if (txt.compare(
"global") == 0) {
527 }
else if (txt.compare(
"all") == 0) {
532 <<
"' into any valid reservation-mode values");
538 std::string subnet_txt;
540 subnet_txt =
getString(params,
"subnet");
541 }
catch (
const DhcpConfigError &) {
544 "mandatory 'subnet' parameter is missing for a subnet being"
545 " configured (" << params->getPosition() <<
")");
549 boost::erase_all(subnet_txt,
" ");
550 boost::erase_all(subnet_txt,
"\t");
557 size_t pos = subnet_txt.find(
"/");
558 if (pos == string::npos) {
561 "Invalid subnet syntax (prefix/len expected):" << subnet_txt
562 <<
" (" << elem->getPosition() <<
")");
572 len = boost::lexical_cast<unsigned int>(subnet_txt.substr(pos + 1));
573 }
catch (
const boost::bad_lexical_cast&) {
575 isc_throw(DhcpConfigError,
"prefix length: '" <<
576 subnet_txt.substr(pos+1) <<
"' is not an integer ("
577 << elem->getPosition() <<
")");
581 if ((addr.isV6() && len > 128) ||
582 (addr.isV4() && len > 32)) {
585 "Invalid prefix length specified for subnet: " << len
586 <<
" (" << elem->getPosition() <<
")");
593 for (PoolStorage::iterator it =
pools_->begin(); it !=
pools_->end();
597 }
catch (
const BadValue& ex) {
601 ex.what() <<
" (" << params->getPosition() <<
")");
608 if (user_context->getType() != Element::map) {
610 << user_context->getPosition() <<
")");
612 subnet_->setContext(user_context);
637 "Failed to create an IPv4 subnet (" <<
638 subnet->getPosition() <<
")");
645 "Invalid Subnet4 cast in Subnet4ConfigParser::parse");
659 for (
auto h = hosts.begin(); h != hosts.end(); ++h) {
674 if (params->contains(
"renew-timer")) {
679 if (params->contains(
"rebind-timer")) {
694 s << addr <<
"/" <<
static_cast<int>(len) <<
" with params: ";
697 s <<
"t1=" << t1 <<
", ";
700 s <<
"t2=" << t2 <<
", ";
702 s <<
"valid-lifetime=" << valid;
712 bool match_client_id =
getBoolean(params,
"match-client-id");
713 subnet4->setMatchClientId(match_client_id);
718 bool authoritative =
getBoolean(params,
"authoritative");
719 subnet4->setAuthoritative(authoritative);
726 next_server =
getString(params,
"next-server");
727 if (!next_server.empty()) {
728 subnet4->setSiaddr(
IOAddress(next_server));
734 pos = next->getPosition().str();
736 pos = params->getPosition().str();
739 << next_server <<
"(" << pos <<
")");
743 std::string sname =
getString(params,
"server-hostname");
744 if (!sname.empty()) {
749 << sname.length() <<
" ("
750 << error->getPosition() <<
")");
752 subnet4->setSname(sname);
756 std::string filename =
getString(params,
"boot-file-name");
757 if (!filename.empty()) {
762 << filename.length() <<
" ("
763 << error->getPosition() <<
")");
765 subnet4->setFilename(filename);
770 std::string iface =
getString(params,
"interface");
771 if (!iface.empty()) {
775 <<
" for subnet " << subnet4->toText()
776 <<
" is not present in the system ("
777 << error->getPosition() <<
")");
780 subnet4->setIface(iface);
786 std::string hr_mode =
getString(params,
"reservation-mode");
790 " of reservation-mode parameter: " << ex.
what()
791 <<
"(" <<
getPosition(
"reservation-mode", params) <<
")");
795 string client_class =
getString(params,
"client-class");
796 if (!client_class.empty()) {
797 subnet4->allowClientClass(client_class);
803 const std::vector<data::ElementPtr>& classes = class_list->listValue();
804 for (
auto cclass = classes.cbegin();
805 cclass != classes.cend(); ++cclass) {
806 if (((*cclass)->getType() != Element::string) ||
807 (*cclass)->stringValue().empty()) {
809 << (*cclass)->getPosition() <<
")");
811 subnet4->requireClientClass((*cclass)->stringValue());
817 string iface4o6 =
getString(params,
"4o6-interface");
818 if (!iface4o6.empty()) {
819 subnet4->get4o6().setIface4o6(iface4o6);
820 subnet4->get4o6().enabled(
true);
825 string subnet4o6 =
getString(params,
"4o6-subnet");
826 if (!subnet4o6.empty()) {
827 size_t slash = subnet4o6.find(
"/");
828 if (slash == std::string::npos) {
830 << subnet4o6 <<
", expected format: prefix6/length");
832 string prefix = subnet4o6.substr(0, slash);
833 string lenstr = subnet4o6.substr(slash + 1);
837 len = boost::lexical_cast<unsigned int>(lenstr.c_str());
838 }
catch (
const boost::bad_lexical_cast &) {
840 "4o6-subnet parameter: " << subnet4o6 <<
", expected 0..128 value");
842 subnet4->get4o6().setSubnet4o6(
IOAddress(prefix), len);
843 subnet4->get4o6().enabled(
true);
847 std::string ifaceid =
getString(params,
"4o6-interface-id");
848 if (!ifaceid.empty()) {
851 subnet4->get4o6().setInterfaceId(opt);
852 subnet4->get4o6().enabled(
true);
863 options_->copyTo(*subnet4->getCfgOption());
871 BOOST_FOREACH(
ConstElementPtr subnet_json, subnets_list->listValue()) {
881 cfg->getCfgSubnets4()->add(subnet);
883 }
catch (
const std::exception& ex) {
885 << subnet_json->getPosition() <<
")");
896 BOOST_FOREACH(
ConstElementPtr subnet_json, subnets_list->listValue()) {
902 subnets.push_back(subnet);
904 }
catch (
const std::exception& ex) {
906 << subnet_json->getPosition() <<
")");
920 (ptype), addr, len)));
927 (ptype), min, max)));
937 parser.
parse(pools, pool, AF_INET6);
948 std::string addr_str =
getString(pd_pool_,
"prefix");
950 uint8_t prefix_len =
getUint8(pd_pool_,
"prefix-len");
952 uint8_t delegated_len =
getUint8(pd_pool_,
"delegated-len");
954 std::string excluded_prefix_str =
"::";
955 if (pd_pool_->contains(
"excluded-prefix")) {
956 excluded_prefix_str =
getString(pd_pool_,
"excluded-prefix");
959 uint8_t excluded_prefix_len = 0;
960 if (pd_pool_->contains(
"excluded-prefix-len")) {
961 excluded_prefix_len =
getUint8(pd_pool_,
"excluded-prefix-len");
967 opts_parser.
parse(options_, option_data);
972 user_context_ = user_context;
977 client_class_ = client_class;
990 excluded_prefix_len));
992 options_->copyTo(*pool_->getCfgOption());
993 }
catch (
const std::exception& ex) {
998 <<
" (" << pd_pool_->getPosition() <<
")");
1001 if (user_context_) {
1002 pool_->setContext(user_context_);
1005 if (client_class_) {
1006 string cclass = client_class_->stringValue();
1007 if (!cclass.empty()) {
1008 pool_->allowClientClass(cclass);
1013 const std::vector<data::ElementPtr>& classes = class_list->listValue();
1014 for (
auto cclass = classes.cbegin();
1015 cclass != classes.cend(); ++cclass) {
1016 if (((*cclass)->getType() != Element::string) ||
1017 (*cclass)->stringValue().empty()) {
1019 << (*cclass)->getPosition() <<
")");
1021 pool_->requireClientClass((*cclass)->stringValue());
1026 pools->push_back(pool_);
1036 parser.
parse(pools, pd_pool);
1065 "Failed to create an IPv6 subnet (" <<
1066 subnet->getPosition() <<
")");
1073 "Invalid Subnet6 cast in Subnet6ConfigParser::parse");
1087 for (
auto h = hosts.begin(); h != hosts.end(); ++h) {
1100 .arg(code).arg(addr.
toText());
1123 bool rapid_commit =
getBoolean(params,
"rapid-commit");
1125 std::ostringstream output;
1126 output << addr <<
"/" <<
static_cast<int>(len)
1127 <<
" with params t1=" << t1 <<
", t2="
1128 << t2 <<
", preferred-lifetime=" << pref
1129 <<
", valid-lifetime=" << valid
1130 <<
", rapid-commit is " << (rapid_commit ?
"enabled" :
"disabled");
1145 std::string ifaceid =
getString(params,
"interface-id");
1146 std::string iface =
getString(params,
"interface");
1151 if (!ifaceid.empty() && !iface.empty()) {
1153 "parser error: interface (defined for locally reachable "
1154 "subnets) and interface-id (defined for subnets reachable"
1155 " via relays) cannot be defined at the same time for "
1156 "subnet " << addr <<
"/" << (
int)len <<
"("
1157 << params->getPosition() <<
")");
1161 if (!ifaceid.empty()) {
1169 if (!iface.empty()) {
1173 <<
" for subnet " << subnet6->
toText()
1174 <<
" is not present in the system ("
1175 << error->getPosition() <<
")");
1184 std::string hr_mode =
getString(params,
"reservation-mode");
1188 " of reservation-mode parameter: " << ex.
what()
1189 <<
"(" <<
getPosition(
"reservation-mode", params) <<
")");
1193 string client_class =
getString(params,
"client-class");
1194 if (!client_class.empty()) {
1201 const std::vector<data::ElementPtr>& classes = class_list->listValue();
1202 for (
auto cclass = classes.cbegin();
1203 cclass != classes.cend(); ++cclass) {
1204 if (((*cclass)->getType() != Element::string) ||
1205 (*cclass)->stringValue().empty()) {
1207 << (*cclass)->getPosition() <<
")");
1225 BOOST_FOREACH(
ConstElementPtr subnet_json, subnets_list->listValue()) {
1234 cfg->getCfgSubnets6()->add(subnet);
1236 }
catch (
const std::exception& ex) {
1238 << subnet_json->getPosition() <<
")");
1248 BOOST_FOREACH(
ConstElementPtr subnet_json, subnets_list->listValue()) {
1253 subnets.push_back(subnet);
1255 }
catch (
const std::exception& ex) {
1257 << subnet_json->getPosition() <<
")");
1268 const std::string& name) {
1271 (scope, name,
"NameChangeRequest protocol"));
1276 const std::string& name) {
1279 (scope, name,
"NameChangeRequest format"));
1284 const std::string& name) {
1287 (scope, name,
"ReplaceClientName mode"));
1295 bool enable_updates =
getBoolean(client_config,
"enable-updates");
1299 uint32_t server_port =
getUint32(client_config,
"server-port");
1301 std::string sender_ip_str =
getString(client_config,
"sender-ip");
1303 uint32_t sender_port =
getUint32(client_config,
"sender-port");
1305 uint32_t max_queue_size =
getUint32(client_config,
"max-queue-size");
1308 getProtocol(client_config,
"ncr-protocol");
1311 getFormat(client_config,
"ncr-format");
1313 bool override_no_update =
1314 getBoolean(client_config,
"override-no-update");
1316 bool override_client_update =
1317 getBoolean(client_config,
"override-client-update");
1320 getMode(client_config,
"replace-client-name");
1322 std::string generated_prefix =
1323 getString(client_config,
"generated-prefix");
1325 std::string hostname_char_set =
1326 getString(client_config,
"hostname-char-set");
1328 std::string hostname_char_replacement =
1329 getString(client_config,
"hostname-char-replacement");
1332 std::string qualifying_suffix =
"";
1333 bool found_qualifying_suffix =
false;
1334 if (client_config->contains(
"qualifying-suffix")) {
1335 qualifying_suffix =
getString(client_config,
"qualifying-suffix");
1336 found_qualifying_suffix =
true;
1340 if (sender_ip_str.empty()) {
1347 }
catch (
const std::exception& ex) {
1349 <<
") specified for parameter 'sender-ip' ("
1350 <<
getPosition(
"sender-ip", client_config) <<
")");
1355 if (enable_updates && !found_qualifying_suffix) {
1357 "parameter 'qualifying-suffix' is required when "
1358 "updates are enabled ("
1359 << client_config->getPosition() <<
")");
1368 <<
" is not supported. ("
1369 <<
getPosition(
"ncr-format", client_config) <<
")");
1375 <<
" is not supported. ("
1376 <<
getPosition(
"ncr-protocol", client_config) <<
")");
1381 "D2ClientConfig error: address family mismatch: "
1382 <<
"server-ip: " << server_ip.
toText()
1383 <<
" is: " << (server_ip.
isV4() ?
"IPv4" :
"IPv6")
1384 <<
" while sender-ip: " << sender_ip.
toText()
1385 <<
" is: " << (sender_ip.
isV4() ?
"IPv4" :
"IPv6")
1386 <<
" (" <<
getPosition(
"sender-ip", client_config) <<
")");
1389 if (server_ip == sender_ip && server_port == sender_port) {
1391 "D2ClientConfig error: server and sender cannot"
1392 " share the exact same IP address/port: "
1393 << server_ip.
toText() <<
"/" << server_port
1394 <<
" (" <<
getPosition(
"sender-ip", client_config) <<
")");
1408 override_client_update,
1409 replace_client_name_mode,
1413 hostname_char_replacement));
1414 }
catch (
const std::exception& ex) {
1416 << client_config->getPosition() <<
")");
1422 new_config->setContext(user_context);
1431 {
"server-ip", Element::string,
"127.0.0.1" },
1432 {
"server-port", Element::integer,
"53001" },
1435 {
"sender-ip", Element::string,
"" },
1436 {
"sender-port", Element::integer,
"0" },
1437 {
"max-queue-size", Element::integer,
"1024" },
1438 {
"ncr-protocol", Element::string,
"UDP" },
1439 {
"ncr-format", Element::string,
"JSON" },
1440 {
"override-no-update", Element::boolean,
"false" },
1441 {
"override-client-update", Element::boolean,
"false" },
1442 {
"replace-client-name", Element::string,
"never" },
1443 {
"generated-prefix", Element::string,
"myhost" },
1444 {
"hostname-char-set", Element::string,
"" },
1445 {
"hostname-char-replacement", Element::string,
"" }
1451 ElementPtr mutable_d2 = boost::const_pointer_cast<Element>(d2_config);