dhcp_parsers.cc 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258
  1. // Copyright (C) 2013-2017 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. #include <config.h>
  7. #include <dhcp/iface_mgr.h>
  8. #include <dhcp/libdhcp++.h>
  9. #include <dhcpsrv/cfgmgr.h>
  10. #include <dhcpsrv/cfg_option.h>
  11. #include <dhcpsrv/dhcpsrv_log.h>
  12. #include <dhcpsrv/parsers/dhcp_parsers.h>
  13. #include <dhcpsrv/parsers/host_reservation_parser.h>
  14. #include <dhcpsrv/parsers/host_reservations_list_parser.h>
  15. #include <dhcpsrv/parsers/option_data_parser.h>
  16. #include <dhcpsrv/cfg_mac_source.h>
  17. #include <util/encode/hex.h>
  18. #include <util/strutil.h>
  19. #include <boost/algorithm/string.hpp>
  20. #include <boost/foreach.hpp>
  21. #include <boost/lexical_cast.hpp>
  22. #include <boost/scoped_ptr.hpp>
  23. #include <map>
  24. #include <string>
  25. #include <vector>
  26. using namespace std;
  27. using namespace isc::asiolink;
  28. using namespace isc::data;
  29. using namespace isc::util;
  30. namespace isc {
  31. namespace dhcp {
  32. // **************************** DebugParser *************************
  33. DebugParser::DebugParser(const std::string& param_name)
  34. :param_name_(param_name) {
  35. }
  36. void
  37. DebugParser::build(ConstElementPtr new_config) {
  38. value_ = new_config;
  39. std::cout << "Build for token: [" << param_name_ << "] = ["
  40. << value_->str() << "]" << std::endl;
  41. }
  42. void
  43. DebugParser::commit() {
  44. // Debug message. The whole DebugParser class is used only for parser
  45. // debugging, and is not used in production code. It is very convenient
  46. // to keep it around. Please do not turn this cout into logger calls.
  47. std::cout << "Commit for token: [" << param_name_ << "] = ["
  48. << value_->str() << "]" << std::endl;
  49. }
  50. // **************************** BooleanParser *************************
  51. template<> void ValueParser<bool>::build(isc::data::ConstElementPtr value) {
  52. // Invoke common code for all specializations of build().
  53. buildCommon(value);
  54. // The Config Manager checks if user specified a
  55. // valid value for a boolean parameter: true or false.
  56. // We should have a boolean Element, use value directly
  57. try {
  58. value_ = value->boolValue();
  59. } catch (const isc::data::TypeError &) {
  60. isc_throw(BadValue, " Wrong value type for " << param_name_
  61. << " : build called with a non-boolean element "
  62. << "(" << value->getPosition() << ").");
  63. }
  64. }
  65. // **************************** Uin32Parser *************************
  66. template<> void ValueParser<uint32_t>::build(ConstElementPtr value) {
  67. // Invoke common code for all specializations of build().
  68. buildCommon(value);
  69. int64_t check;
  70. string x = value->str();
  71. try {
  72. check = boost::lexical_cast<int64_t>(x);
  73. } catch (const boost::bad_lexical_cast &) {
  74. isc_throw(BadValue, "Failed to parse value " << value->str()
  75. << " as unsigned 32-bit integer "
  76. "(" << value->getPosition() << ").");
  77. }
  78. if (check > std::numeric_limits<uint32_t>::max()) {
  79. isc_throw(BadValue, "Value " << value->str() << " is too large"
  80. " for unsigned 32-bit integer "
  81. "(" << value->getPosition() << ").");
  82. }
  83. if (check < 0) {
  84. isc_throw(BadValue, "Value " << value->str() << " is negative."
  85. << " Only 0 or larger are allowed for unsigned 32-bit integer "
  86. "(" << value->getPosition() << ").");
  87. }
  88. // value is small enough to fit
  89. value_ = static_cast<uint32_t>(check);
  90. }
  91. // **************************** StringParser *************************
  92. template <> void ValueParser<std::string>::build(ConstElementPtr value) {
  93. // Invoke common code for all specializations of build().
  94. buildCommon(value);
  95. // For strings we need to use stringValue() rather than str().
  96. // str() returns fully escaped special characters, so
  97. // single backslash would be misrepresented as "\\".
  98. if (value->getType() == Element::string) {
  99. value_ = value->stringValue();
  100. } else {
  101. value_ = value->str();
  102. }
  103. boost::erase_all(value_, "\"");
  104. }
  105. // ******************** MACSourcesListConfigParser *************************
  106. void
  107. MACSourcesListConfigParser::parse(CfgMACSource& mac_sources, ConstElementPtr value) {
  108. CfgIface cfg_iface;
  109. uint32_t source = 0;
  110. size_t cnt = 0;
  111. // By default, there's only one source defined: ANY.
  112. // If user specified anything, we need to get rid of that default.
  113. mac_sources.clear();
  114. BOOST_FOREACH(ConstElementPtr source_elem, value->listValue()) {
  115. std::string source_str = source_elem->stringValue();
  116. try {
  117. source = CfgMACSource::MACSourceFromText(source_str);
  118. mac_sources.add(source);
  119. ++cnt;
  120. } catch (const InvalidParameter& ex) {
  121. isc_throw(DhcpConfigError, "The mac-sources value '" << source_str
  122. << "' was specified twice (" << value->getPosition() << ")");
  123. } catch (const std::exception& ex) {
  124. isc_throw(DhcpConfigError, "Failed to convert '"
  125. << source_str << "' to any recognized MAC source:"
  126. << ex.what() << " (" << value->getPosition() << ")");
  127. }
  128. }
  129. if (!cnt) {
  130. isc_throw(DhcpConfigError, "If specified, MAC Sources cannot be empty");
  131. }
  132. }
  133. // ******************** ControlSocketParser *************************
  134. void ControlSocketParser::parse(SrvConfig& srv_cfg, isc::data::ConstElementPtr value) {
  135. if (!value) {
  136. isc_throw(DhcpConfigError, "Logic error: specified control-socket is null");
  137. }
  138. if (value->getType() != Element::map) {
  139. isc_throw(DhcpConfigError, "Specified control-socket is expected to be a map"
  140. ", i.e. a structure defined within { }");
  141. }
  142. srv_cfg.setControlSocketInfo(value);
  143. }
  144. template<typename SearchKey>
  145. OptionDefinitionPtr
  146. OptionDataParser::findOptionDefinition(const std::string& option_space,
  147. const SearchKey& search_key) const {
  148. OptionDefinitionPtr def = LibDHCP::getOptionDef(option_space, search_key);
  149. if (!def) {
  150. // Check if this is a vendor-option. If it is, get vendor-specific
  151. // definition.
  152. uint32_t vendor_id = LibDHCP::optionSpaceToVendorId(option_space);
  153. if (vendor_id) {
  154. const Option::Universe u = address_family_ == AF_INET ?
  155. Option::V4 : Option::V6;
  156. def = LibDHCP::getVendorOptionDef(u, vendor_id, search_key);
  157. }
  158. }
  159. if (!def) {
  160. // Check if this is an option specified by a user.
  161. def = CfgMgr::instance().getStagingCfg()->getCfgOptionDef()
  162. ->get(option_space, search_key);
  163. }
  164. return (def);
  165. }
  166. // ******************************** OptionDefParser ****************************
  167. std::pair<isc::dhcp::OptionDefinitionPtr, std::string>
  168. OptionDefParser::parse(ConstElementPtr option_def) {
  169. // Get mandatory parameters.
  170. std::string name = getString(option_def, "name");
  171. uint32_t code = getInteger(option_def, "code");
  172. std::string type = getString(option_def, "type");
  173. // Get optional parameters. Whoever called this parser, should have
  174. // called SimpleParser::setDefaults first.
  175. bool array_type = getBoolean(option_def, "array");
  176. std::string record_types = getString(option_def, "record-types");
  177. std::string space = getString(option_def, "space");
  178. std::string encapsulates = getString(option_def, "encapsulate");
  179. if (!OptionSpace::validateName(space)) {
  180. isc_throw(DhcpConfigError, "invalid option space name '"
  181. << space << "' ("
  182. << getPosition("space", option_def) << ")");
  183. }
  184. // Create option definition.
  185. OptionDefinitionPtr def;
  186. // We need to check if user has set encapsulated option space
  187. // name. If so, different constructor will be used.
  188. if (!encapsulates.empty()) {
  189. // Arrays can't be used together with sub-options.
  190. if (array_type) {
  191. isc_throw(DhcpConfigError, "option '" << space << "."
  192. << "name" << "', comprising an array of data"
  193. << " fields may not encapsulate any option space ("
  194. << option_def->getPosition() << ")");
  195. } else if (encapsulates == space) {
  196. isc_throw(DhcpConfigError, "option must not encapsulate"
  197. << " an option space it belongs to: '"
  198. << space << "." << name << "' is set to"
  199. << " encapsulate '" << space << "' ("
  200. << option_def->getPosition() << ")");
  201. } else {
  202. def.reset(new OptionDefinition(name, code, type,
  203. encapsulates.c_str()));
  204. }
  205. } else {
  206. def.reset(new OptionDefinition(name, code, type, array_type));
  207. }
  208. // Split the list of record types into tokens.
  209. std::vector<std::string> record_tokens =
  210. isc::util::str::tokens(record_types, ",");
  211. // Iterate over each token and add a record type into
  212. // option definition.
  213. BOOST_FOREACH(std::string record_type, record_tokens) {
  214. try {
  215. boost::trim(record_type);
  216. if (!record_type.empty()) {
  217. def->addRecordField(record_type);
  218. }
  219. } catch (const Exception& ex) {
  220. isc_throw(DhcpConfigError, "invalid record type values"
  221. << " specified for the option definition: "
  222. << ex.what() << " ("
  223. << getPosition("record-types", option_def) << ")");
  224. }
  225. }
  226. // Validate the definition.
  227. try {
  228. def->validate();
  229. } catch (const std::exception& ex) {
  230. isc_throw(DhcpConfigError, ex.what()
  231. << " (" << option_def->getPosition() << ")");
  232. }
  233. // Option definition has been created successfully.
  234. return make_pair(def, space);
  235. }
  236. // ******************************** OptionDefListParser ************************
  237. void
  238. OptionDefListParser::parse(CfgOptionDefPtr storage, ConstElementPtr option_def_list) {
  239. if (!option_def_list) {
  240. isc_throw(DhcpConfigError, "parser error: a pointer to a list of"
  241. << " option definitions is NULL ("
  242. << option_def_list->getPosition() << ")");
  243. }
  244. OptionDefParser parser;
  245. BOOST_FOREACH(ConstElementPtr option_def, option_def_list->listValue()) {
  246. OptionDefinitionTuple def;
  247. def = parser.parse(option_def);
  248. try {
  249. storage->add(def.first, def.second);
  250. } catch (const std::exception& ex) {
  251. // Append position if there is a failure.
  252. isc_throw(DhcpConfigError, ex.what() << " ("
  253. << option_def->getPosition() << ")");
  254. }
  255. }
  256. // All definitions have been prepared. Put them as runtime options into
  257. // the libdhcp++.
  258. LibDHCP::setRuntimeOptionDefs(storage->getContainer());
  259. }
  260. //****************************** RelayInfoParser ********************************
  261. RelayInfoParser::RelayInfoParser(const Option::Universe& family)
  262. : family_(family) {
  263. };
  264. void
  265. RelayInfoParser::parse(const isc::dhcp::Subnet::RelayInfoPtr& cfg,
  266. ConstElementPtr relay_info) {
  267. // There is only one parameter which is mandatory
  268. IOAddress ip = getAddress(relay_info, "ip-address");
  269. // Check if the address family matches.
  270. if ((ip.isV4() && family_ != Option::V4) ||
  271. (ip.isV6() && family_ != Option::V6) ) {
  272. isc_throw(DhcpConfigError, "ip-address field " << ip.toText()
  273. << " does not have IP address of expected family type: "
  274. << (family_ == Option::V4 ? "IPv4" : "IPv6")
  275. << " (" << getPosition("ip-address", relay_info) << ")");
  276. }
  277. // Ok, we're done with parsing. Let's store the result in the structure
  278. // we were given as configuration storage.
  279. *cfg = isc::dhcp::Subnet::RelayInfo(ip);
  280. }
  281. //****************************** PoolParser ********************************
  282. void
  283. PoolParser::parse(PoolStoragePtr pools,
  284. ConstElementPtr pool_structure,
  285. const uint16_t address_family) {
  286. ConstElementPtr text_pool = pool_structure->get("pool");
  287. if (!text_pool) {
  288. isc_throw(DhcpConfigError, "Mandatory 'pool' entry missing in "
  289. "definition: (" << pool_structure->getPosition() << ")");
  290. }
  291. // That should be a single pool representation. It should contain
  292. // text is form prefix/len or first - last. Note that spaces
  293. // are allowed
  294. string txt = text_pool->stringValue();
  295. // first let's remove any whitespaces
  296. boost::erase_all(txt, " "); // space
  297. boost::erase_all(txt, "\t"); // tabulation
  298. PoolPtr pool;
  299. // Is this prefix/len notation?
  300. size_t pos = txt.find("/");
  301. if (pos != string::npos) {
  302. isc::asiolink::IOAddress addr("::");
  303. uint8_t len = 0;
  304. try {
  305. addr = isc::asiolink::IOAddress(txt.substr(0, pos));
  306. // start with the first character after /
  307. string prefix_len = txt.substr(pos + 1);
  308. // It is lexical cast to int and then downcast to uint8_t.
  309. // Direct cast to uint8_t (which is really an unsigned char)
  310. // will result in interpreting the first digit as output
  311. // value and throwing exception if length is written on two
  312. // digits (because there are extra characters left over).
  313. // No checks for values over 128. Range correctness will
  314. // be checked in Pool4 constructor, here we only check
  315. // the representation fits in an uint8_t as this can't
  316. // be done by a direct lexical cast as explained...
  317. int val_len = boost::lexical_cast<int>(prefix_len);
  318. if ((val_len < std::numeric_limits<uint8_t>::min()) ||
  319. (val_len > std::numeric_limits<uint8_t>::max())) {
  320. // This exception will be handled 4 line later!
  321. isc_throw(OutOfRange, "");
  322. }
  323. len = static_cast<uint8_t>(val_len);
  324. } catch (...) {
  325. isc_throw(DhcpConfigError, "Failed to parse pool "
  326. "definition: " << txt << " ("
  327. << text_pool->getPosition() << ")");
  328. }
  329. try {
  330. pool = poolMaker(addr, len);
  331. pools->push_back(pool);
  332. } catch (const std::exception& ex) {
  333. isc_throw(DhcpConfigError, "Failed to create pool defined by: "
  334. << txt << " (" << text_pool->getPosition() << ")");
  335. }
  336. } else {
  337. isc::asiolink::IOAddress min("::");
  338. isc::asiolink::IOAddress max("::");
  339. // Is this min-max notation?
  340. pos = txt.find("-");
  341. if (pos != string::npos) {
  342. // using min-max notation
  343. try {
  344. min = isc::asiolink::IOAddress(txt.substr(0, pos));
  345. max = isc::asiolink::IOAddress(txt.substr(pos + 1));
  346. } catch (...) {
  347. isc_throw(DhcpConfigError, "Failed to parse pool "
  348. "definition: " << txt << " ("
  349. << text_pool->getPosition() << ")");
  350. }
  351. try {
  352. pool = poolMaker(min, max);
  353. pools->push_back(pool);
  354. } catch (const std::exception& ex) {
  355. isc_throw(DhcpConfigError, "Failed to create pool defined by: "
  356. << txt << " (" << text_pool->getPosition() << ")");
  357. }
  358. }
  359. }
  360. if (!pool) {
  361. isc_throw(DhcpConfigError, "invalid pool definition: "
  362. << text_pool->stringValue() <<
  363. ". There are two acceptable formats <min address-max address>"
  364. " or <prefix/len> ("
  365. << text_pool->getPosition() << ")");
  366. }
  367. // If there's user-context specified, store it.
  368. ConstElementPtr user_context = pool_structure->get("user-context");
  369. if (user_context) {
  370. if (user_context->getType() != Element::map) {
  371. isc_throw(isc::dhcp::DhcpConfigError, "User context has to be a map ("
  372. << user_context->getPosition() << ")");
  373. }
  374. pool->setContext(user_context);
  375. }
  376. // Parser pool specific options.
  377. ConstElementPtr option_data = pool_structure->get("option-data");
  378. if (option_data) {
  379. try {
  380. CfgOptionPtr cfg = pool->getCfgOption();
  381. OptionDataListParser option_parser(address_family);
  382. option_parser.parse(cfg, option_data);
  383. } catch (const std::exception& ex) {
  384. isc_throw(isc::dhcp::DhcpConfigError, ex.what()
  385. << " (" << option_data->getPosition() << ")");
  386. }
  387. }
  388. }
  389. //****************************** Pool4Parser *************************
  390. PoolPtr
  391. Pool4Parser::poolMaker (IOAddress &addr, uint32_t len, int32_t) {
  392. return (PoolPtr(new Pool4(addr, len)));
  393. }
  394. PoolPtr
  395. Pool4Parser::poolMaker (IOAddress &min, IOAddress &max, int32_t) {
  396. return (PoolPtr(new Pool4(min, max)));
  397. }
  398. //****************************** Pool4ListParser *************************
  399. void
  400. Pools4ListParser::parse(PoolStoragePtr pools, ConstElementPtr pools_list) {
  401. BOOST_FOREACH(ConstElementPtr pool, pools_list->listValue()) {
  402. Pool4Parser parser;
  403. parser.parse(pools, pool, AF_INET);
  404. }
  405. }
  406. //****************************** SubnetConfigParser *************************
  407. SubnetConfigParser::SubnetConfigParser(uint16_t family)
  408. : pools_(new PoolStorage()),
  409. address_family_(family),
  410. options_(new CfgOption()) {
  411. string addr = family == AF_INET ? "0.0.0.0" : "::";
  412. relay_info_.reset(new isc::dhcp::Subnet::RelayInfo(IOAddress(addr)));
  413. }
  414. SubnetPtr
  415. SubnetConfigParser::parse(ConstElementPtr subnet) {
  416. ConstElementPtr options_params = subnet->get("option-data");
  417. if (options_params) {
  418. OptionDataListParser opt_parser(address_family_);
  419. opt_parser.parse(options_, options_params);
  420. }
  421. ConstElementPtr relay_params = subnet->get("relay");
  422. if (relay_params) {
  423. Option::Universe u = (address_family_ == AF_INET) ? Option::V4 : Option::V6;
  424. RelayInfoParser parser(u);
  425. parser.parse(relay_info_, relay_params);
  426. }
  427. // Create a subnet.
  428. try {
  429. createSubnet(subnet);
  430. } catch (const std::exception& ex) {
  431. isc_throw(DhcpConfigError,
  432. "subnet configuration failed: " << ex.what());
  433. }
  434. return (subnet_);
  435. }
  436. Subnet::HRMode
  437. SubnetConfigParser::hrModeFromText(const std::string& txt) {
  438. if ( (txt.compare("disabled") == 0) ||
  439. (txt.compare("off") == 0) ) {
  440. return (Subnet::HR_DISABLED);
  441. } else if (txt.compare("out-of-pool") == 0) {
  442. return (Subnet::HR_OUT_OF_POOL);
  443. } else if (txt.compare("all") == 0) {
  444. return (Subnet::HR_ALL);
  445. } else {
  446. isc_throw(BadValue, "Can't convert '" << txt
  447. << "' into any valid reservation-mode values");
  448. }
  449. }
  450. void
  451. SubnetConfigParser::createSubnet(ConstElementPtr params) {
  452. std::string subnet_txt;
  453. try {
  454. subnet_txt = getString(params, "subnet");
  455. } catch (const DhcpConfigError &) {
  456. // rethrow with precise error
  457. isc_throw(DhcpConfigError,
  458. "mandatory 'subnet' parameter is missing for a subnet being"
  459. " configured (" << params->getPosition() << ")");
  460. }
  461. // Remove any spaces or tabs.
  462. boost::erase_all(subnet_txt, " ");
  463. boost::erase_all(subnet_txt, "\t");
  464. // The subnet format is prefix/len. We are going to extract
  465. // the prefix portion of a subnet string to create IOAddress
  466. // object from it. IOAddress will be passed to the Subnet's
  467. // constructor later on. In order to extract the prefix we
  468. // need to get all characters preceding "/".
  469. size_t pos = subnet_txt.find("/");
  470. if (pos == string::npos) {
  471. ConstElementPtr elem = params->get("subnet");
  472. isc_throw(DhcpConfigError,
  473. "Invalid subnet syntax (prefix/len expected):" << subnet_txt
  474. << " (" << elem->getPosition() << ")");
  475. }
  476. // Try to create the address object. It also validates that
  477. // the address syntax is ok.
  478. isc::asiolink::IOAddress addr(subnet_txt.substr(0, pos));
  479. uint8_t len = boost::lexical_cast<unsigned int>(subnet_txt.substr(pos + 1));
  480. // Call the subclass's method to instantiate the subnet
  481. initSubnet(params, addr, len);
  482. // Add pools to it.
  483. for (PoolStorage::iterator it = pools_->begin(); it != pools_->end();
  484. ++it) {
  485. try {
  486. subnet_->addPool(*it);
  487. } catch (const BadValue& ex) {
  488. // addPool() can throw BadValue if the pool is overlapping or
  489. // is out of bounds for the subnet.
  490. isc_throw(DhcpConfigError,
  491. ex.what() << " (" << params->getPosition() << ")");
  492. }
  493. }
  494. // Now configure parameters that are common for v4 and v6:
  495. // Get interface name. If it is defined, then the subnet is available
  496. // directly over specified network interface.
  497. std::string iface = getString(params, "interface");
  498. if (!iface.empty()) {
  499. if (!IfaceMgr::instance().getIface(iface)) {
  500. ConstElementPtr error = params->get("interface");
  501. isc_throw(DhcpConfigError, "Specified network interface name " << iface
  502. << " for subnet " << subnet_->toText()
  503. << " is not present in the system ("
  504. << error->getPosition() << ")");
  505. }
  506. subnet_->setIface(iface);
  507. }
  508. // Let's set host reservation mode. If not specified, the default value of
  509. // all will be used.
  510. try {
  511. std::string hr_mode = getString(params, "reservation-mode");
  512. subnet_->setHostReservationMode(hrModeFromText(hr_mode));
  513. } catch (const BadValue& ex) {
  514. isc_throw(DhcpConfigError, "Failed to process specified value "
  515. " of reservation-mode parameter: " << ex.what()
  516. << "(" << getPosition("reservation-mode", params) << ")");
  517. }
  518. // Try setting up client class.
  519. string client_class = getString(params, "client-class");
  520. if (!client_class.empty()) {
  521. subnet_->allowClientClass(client_class);
  522. }
  523. // If there's user-context specified, store it.
  524. ConstElementPtr user_context = params->get("user-context");
  525. if (user_context) {
  526. if (user_context->getType() != Element::map) {
  527. isc_throw(isc::dhcp::DhcpConfigError, "User context has to be a map ("
  528. << user_context->getPosition() << ")");
  529. }
  530. subnet_->setContext(user_context);
  531. }
  532. // Here globally defined options were merged to the subnet specific
  533. // options but this is no longer the case (they have a different
  534. // and not consecutive priority).
  535. // Copy options to the subnet configuration.
  536. options_->copyTo(*subnet_->getCfgOption());
  537. }
  538. //****************************** Subnet4ConfigParser *************************
  539. Subnet4ConfigParser::Subnet4ConfigParser()
  540. :SubnetConfigParser(AF_INET) {
  541. }
  542. Subnet4Ptr
  543. Subnet4ConfigParser::parse(ConstElementPtr subnet) {
  544. /// Parse Pools first.
  545. ConstElementPtr pools = subnet->get("pools");
  546. if (pools) {
  547. Pools4ListParser parser;
  548. parser.parse(pools_, pools);
  549. }
  550. SubnetPtr generic = SubnetConfigParser::parse(subnet);
  551. if (!generic) {
  552. isc_throw(DhcpConfigError,
  553. "Failed to create an IPv4 subnet (" <<
  554. subnet->getPosition() << ")");
  555. }
  556. Subnet4Ptr sn4ptr = boost::dynamic_pointer_cast<Subnet4>(subnet_);
  557. if (!sn4ptr) {
  558. // If we hit this, it is a programming error.
  559. isc_throw(Unexpected,
  560. "Invalid Subnet4 cast in Subnet4ConfigParser::parse");
  561. }
  562. // Set relay information if it was parsed
  563. if (relay_info_) {
  564. sn4ptr->setRelayInfo(*relay_info_);
  565. }
  566. // Parse Host Reservations for this subnet if any.
  567. ConstElementPtr reservations = subnet->get("reservations");
  568. if (reservations) {
  569. HostCollection hosts;
  570. HostReservationsListParser<HostReservationParser4> parser;
  571. parser.parse(subnet_->getID(), reservations, hosts);
  572. for (auto h = hosts.begin(); h != hosts.end(); ++h) {
  573. CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(*h);
  574. }
  575. }
  576. return (sn4ptr);
  577. }
  578. void
  579. Subnet4ConfigParser::initSubnet(data::ConstElementPtr params,
  580. asiolink::IOAddress addr, uint8_t len) {
  581. // The renew-timer and rebind-timer are optional. If not set, the
  582. // option 58 and 59 will not be sent to a client. In this case the
  583. // client will use default values based on the valid-lifetime.
  584. Triplet<uint32_t> t1 = getInteger(params, "renew-timer");
  585. Triplet<uint32_t> t2 = getInteger(params, "rebind-timer");
  586. // The valid-lifetime is mandatory. It may be specified for a
  587. // particular subnet. If not, the global value should be present.
  588. // If there is no global value, exception is thrown.
  589. Triplet<uint32_t> valid = getInteger(params, "valid-lifetime");
  590. // Subnet ID is optional. If it is not supplied the value of 0 is used,
  591. // which means autogenerate. The value was inserted earlier by calling
  592. // SimpleParser4::setAllDefaults.
  593. SubnetID subnet_id = static_cast<SubnetID>(getInteger(params, "id"));
  594. stringstream s;
  595. s << addr << "/" << static_cast<int>(len) << " with params: ";
  596. // t1 and t2 are optional may be not specified.
  597. if (!t1.unspecified()) {
  598. s << "t1=" << t1 << ", ";
  599. }
  600. if (!t2.unspecified()) {
  601. s << "t2=" << t2 << ", ";
  602. }
  603. s <<"valid-lifetime=" << valid;
  604. LOG_INFO(dhcpsrv_logger, DHCPSRV_CFGMGR_NEW_SUBNET4).arg(s.str());
  605. Subnet4Ptr subnet4(new Subnet4(addr, len, t1, t2, valid, subnet_id));
  606. subnet_ = subnet4;
  607. // Set the match-client-id value for the subnet. It is always present.
  608. // If not explicitly specified, the default value was filled in when
  609. // SimpleParser4::setAllDefaults was called.
  610. bool match_client_id = getBoolean(params, "match-client-id");
  611. subnet4->setMatchClientId(match_client_id);
  612. // Set next-server. The default value is 0.0.0.0. Nevertheless, the
  613. // user could have messed that up by specifying incorrect value.
  614. // To avoid using 0.0.0.0, user can specify "".
  615. string next_server;
  616. try {
  617. next_server = getString(params, "next-server");
  618. if (!next_server.empty()) {
  619. subnet4->setSiaddr(IOAddress(next_server));
  620. }
  621. } catch (...) {
  622. ConstElementPtr next = params->get("next-server");
  623. string pos;
  624. if (next) {
  625. pos = next->getPosition().str();
  626. } else {
  627. pos = params->getPosition().str();
  628. }
  629. isc_throw(DhcpConfigError, "invalid parameter next-server : "
  630. << next_server << "(" << pos << ")");
  631. }
  632. // 4o6 specific parameter: 4o6-interface. If not explicitly specified,
  633. // it will have the default value of "".
  634. string iface4o6 = getString(params, "4o6-interface");
  635. if (!iface4o6.empty()) {
  636. subnet4->get4o6().setIface4o6(iface4o6);
  637. subnet4->get4o6().enabled(true);
  638. }
  639. // 4o6 specific parameter: 4o6-subnet. If not explicitly specified, it
  640. // will have the default value of "".
  641. string subnet4o6 = getString(params, "4o6-subnet");
  642. if (!subnet4o6.empty()) {
  643. size_t slash = subnet4o6.find("/");
  644. if (slash == std::string::npos) {
  645. isc_throw(DhcpConfigError, "Missing / in the 4o6-subnet parameter:"
  646. << subnet4o6 << ", expected format: prefix6/length");
  647. }
  648. string prefix = subnet4o6.substr(0, slash);
  649. string lenstr = subnet4o6.substr(slash + 1);
  650. uint8_t len = 128;
  651. try {
  652. len = boost::lexical_cast<unsigned int>(lenstr.c_str());
  653. } catch (const boost::bad_lexical_cast &) {
  654. isc_throw(DhcpConfigError, "Invalid prefix length specified in "
  655. "4o6-subnet parameter: " << subnet4o6 << ", expected 0..128 value");
  656. }
  657. subnet4->get4o6().setSubnet4o6(IOAddress(prefix), len);
  658. subnet4->get4o6().enabled(true);
  659. }
  660. // Try 4o6 specific parameter: 4o6-interface-id
  661. std::string ifaceid = getString(params, "4o6-interface-id");
  662. if (!ifaceid.empty()) {
  663. OptionBuffer tmp(ifaceid.begin(), ifaceid.end());
  664. OptionPtr opt(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
  665. subnet4->get4o6().setInterfaceId(opt);
  666. subnet4->get4o6().enabled(true);
  667. }
  668. /// client-class processing is now generic and handled in the common
  669. /// code (see isc::data::SubnetConfigParser::createSubnet)
  670. }
  671. //**************************** Subnets4ListConfigParser **********************
  672. size_t
  673. Subnets4ListConfigParser::parse(SrvConfigPtr cfg, ConstElementPtr subnets_list) {
  674. size_t cnt = 0;
  675. BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
  676. Subnet4ConfigParser parser;
  677. Subnet4Ptr subnet = parser.parse(subnet_json);
  678. if (subnet) {
  679. // Adding a subnet to the Configuration Manager may fail if the
  680. // subnet id is invalid (duplicate). Thus, we catch exceptions
  681. // here to append a position in the configuration string.
  682. try {
  683. cfg->getCfgSubnets4()->add(subnet);
  684. cnt++;
  685. } catch (const std::exception& ex) {
  686. isc_throw(DhcpConfigError, ex.what() << " ("
  687. << subnet_json->getPosition() << ")");
  688. }
  689. }
  690. }
  691. return (cnt);
  692. }
  693. //**************************** Pool6Parser *********************************
  694. PoolPtr
  695. Pool6Parser::poolMaker (IOAddress &addr, uint32_t len, int32_t ptype)
  696. {
  697. return (PoolPtr(new Pool6(static_cast<isc::dhcp::Lease::Type>
  698. (ptype), addr, len)));
  699. }
  700. PoolPtr
  701. Pool6Parser::poolMaker (IOAddress &min, IOAddress &max, int32_t ptype)
  702. {
  703. return (PoolPtr(new Pool6(static_cast<isc::dhcp::Lease::Type>
  704. (ptype), min, max)));
  705. }
  706. //**************************** Pool6ListParser ***************************
  707. void
  708. Pools6ListParser::parse(PoolStoragePtr pools, ConstElementPtr pools_list) {
  709. BOOST_FOREACH(ConstElementPtr pool, pools_list->listValue()) {
  710. Pool6Parser parser;
  711. parser.parse(pools, pool, AF_INET6);
  712. }
  713. }
  714. //**************************** PdPoolParser ******************************
  715. PdPoolParser::PdPoolParser() : options_(new CfgOption()) {
  716. }
  717. void
  718. PdPoolParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_) {
  719. std::string addr_str = getString(pd_pool_, "prefix");
  720. uint8_t prefix_len = getUint8(pd_pool_, "prefix-len");
  721. uint8_t delegated_len = getUint8(pd_pool_, "delegated-len");
  722. std::string excluded_prefix_str = "::";
  723. if (pd_pool_->contains("excluded-prefix")) {
  724. excluded_prefix_str = getString(pd_pool_, "excluded-prefix");
  725. }
  726. uint8_t excluded_prefix_len = 0;
  727. if (pd_pool_->contains("excluded-prefix-len")) {
  728. excluded_prefix_len = getUint8(pd_pool_, "excluded-prefix-len");
  729. }
  730. ConstElementPtr option_data = pd_pool_->get("option-data");
  731. if (option_data) {
  732. OptionDataListParser opts_parser(AF_INET6);
  733. opts_parser.parse(options_, option_data);
  734. }
  735. ConstElementPtr user_context = pd_pool_->get("user-context");
  736. if (user_context) {
  737. user_context_ = user_context;
  738. }
  739. // Check the pool parameters. It will throw an exception if any
  740. // of the required parameters are invalid.
  741. try {
  742. // Attempt to construct the local pool.
  743. pool_.reset(new Pool6(IOAddress(addr_str),
  744. prefix_len,
  745. delegated_len,
  746. IOAddress(excluded_prefix_str),
  747. excluded_prefix_len));
  748. // Merge options specified for a pool into pool configuration.
  749. options_->copyTo(*pool_->getCfgOption());
  750. } catch (const std::exception& ex) {
  751. // Some parameters don't exist or are invalid. Since we are not
  752. // aware whether they don't exist or are invalid, let's append
  753. // the position of the pool map element.
  754. isc_throw(isc::dhcp::DhcpConfigError, ex.what()
  755. << " (" << pd_pool_->getPosition() << ")");
  756. }
  757. if (user_context_) {
  758. pool_->setContext(user_context_);
  759. }
  760. // Add the local pool to the external storage ptr.
  761. pools->push_back(pool_);
  762. }
  763. //**************************** PdPoolsListParser ************************
  764. void
  765. PdPoolsListParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_list) {
  766. // Loop through the list of pd pools.
  767. BOOST_FOREACH(ConstElementPtr pd_pool, pd_pool_list->listValue()) {
  768. PdPoolParser parser;
  769. parser.parse(pools, pd_pool);
  770. }
  771. }
  772. //**************************** Subnet6ConfigParser ***********************
  773. Subnet6ConfigParser::Subnet6ConfigParser()
  774. :SubnetConfigParser(AF_INET6) {
  775. }
  776. Subnet6Ptr
  777. Subnet6ConfigParser::parse(ConstElementPtr subnet) {
  778. /// Parse all pools first.
  779. ConstElementPtr pools = subnet->get("pools");
  780. if (pools) {
  781. Pools6ListParser parser;
  782. parser.parse(pools_, pools);
  783. }
  784. ConstElementPtr pd_pools = subnet->get("pd-pools");
  785. if (pd_pools) {
  786. PdPoolsListParser parser;
  787. parser.parse(pools_, pd_pools);
  788. }
  789. SubnetPtr generic = SubnetConfigParser::parse(subnet);
  790. if (!generic) {
  791. isc_throw(DhcpConfigError,
  792. "Failed to create an IPv6 subnet (" <<
  793. subnet->getPosition() << ")");
  794. }
  795. Subnet6Ptr sn6ptr = boost::dynamic_pointer_cast<Subnet6>(subnet_);
  796. if (!sn6ptr) {
  797. // If we hit this, it is a programming error.
  798. isc_throw(Unexpected,
  799. "Invalid Subnet6 cast in Subnet6ConfigParser::parse");
  800. }
  801. // Set relay information if it was provided
  802. if (relay_info_) {
  803. sn6ptr->setRelayInfo(*relay_info_);
  804. }
  805. // Parse Host Reservations for this subnet if any.
  806. ConstElementPtr reservations = subnet->get("reservations");
  807. if (reservations) {
  808. HostCollection hosts;
  809. HostReservationsListParser<HostReservationParser6> parser;
  810. parser.parse(subnet_->getID(), reservations, hosts);
  811. for (auto h = hosts.begin(); h != hosts.end(); ++h) {
  812. CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(*h);
  813. }
  814. }
  815. return (sn6ptr);
  816. }
  817. void
  818. Subnet6ConfigParser::duplicate_option_warning(uint32_t code,
  819. asiolink::IOAddress& addr) {
  820. LOG_WARN(dhcpsrv_logger, DHCPSRV_CFGMGR_OPTION_DUPLICATE)
  821. .arg(code).arg(addr.toText());
  822. }
  823. void
  824. Subnet6ConfigParser::initSubnet(data::ConstElementPtr params,
  825. asiolink::IOAddress addr, uint8_t len) {
  826. // Get all 'time' parameters using inheritance.
  827. // If the subnet-specific value is defined then use it, else
  828. // use the global value. The global value must always be
  829. // present. If it is not, it is an internal error and exception
  830. // is thrown.
  831. Triplet<uint32_t> t1 = getInteger(params, "renew-timer");
  832. Triplet<uint32_t> t2 = getInteger(params, "rebind-timer");
  833. Triplet<uint32_t> pref = getInteger(params, "preferred-lifetime");
  834. Triplet<uint32_t> valid = getInteger(params, "valid-lifetime");
  835. // Subnet ID is optional. If it is not supplied the value of 0 is used,
  836. // which means autogenerate. The value was inserted earlier by calling
  837. // SimpleParser6::setAllDefaults.
  838. SubnetID subnet_id = static_cast<SubnetID>(getInteger(params, "id"));
  839. // We want to log whether rapid-commit is enabled, so we get this
  840. // before the actual subnet creation.
  841. bool rapid_commit = getBoolean(params, "rapid-commit");
  842. std::ostringstream output;
  843. output << addr << "/" << static_cast<int>(len)
  844. << " with params t1=" << t1 << ", t2="
  845. << t2 << ", preferred-lifetime=" << pref
  846. << ", valid-lifetime=" << valid
  847. << ", rapid-commit is " << (rapid_commit ? "enabled" : "disabled");
  848. LOG_INFO(dhcpsrv_logger, DHCPSRV_CFGMGR_NEW_SUBNET4).arg(output.str());
  849. // Create a new subnet.
  850. Subnet6* subnet6 = new Subnet6(addr, len, t1, t2, pref, valid,
  851. subnet_id);
  852. subnet_.reset(subnet6);
  853. // Enable or disable Rapid Commit option support for the subnet.
  854. subnet6->setRapidCommit(rapid_commit);
  855. // Get interface-id option content. For now we support string
  856. // representation only
  857. std::string ifaceid = getString(params, "interface-id");
  858. std::string iface = getString(params, "interface");
  859. // Specifying both interface for locally reachable subnets and
  860. // interface id for relays is mutually exclusive. Need to test for
  861. // this condition.
  862. if (!ifaceid.empty() && !iface.empty()) {
  863. isc_throw(isc::dhcp::DhcpConfigError,
  864. "parser error: interface (defined for locally reachable "
  865. "subnets) and interface-id (defined for subnets reachable"
  866. " via relays) cannot be defined at the same time for "
  867. "subnet " << addr << "/" << (int)len << "("
  868. << params->getPosition() << ")");
  869. }
  870. // Configure interface-id for remote interfaces, if defined
  871. if (!ifaceid.empty()) {
  872. OptionBuffer tmp(ifaceid.begin(), ifaceid.end());
  873. OptionPtr opt(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
  874. subnet6->setInterfaceId(opt);
  875. }
  876. /// client-class processing is now generic and handled in the common
  877. /// code (see isc::data::SubnetConfigParser::createSubnet)
  878. }
  879. //**************************** Subnet6ListConfigParser ********************
  880. size_t
  881. Subnets6ListConfigParser::parse(SrvConfigPtr cfg, ConstElementPtr subnets_list) {
  882. size_t cnt = 0;
  883. BOOST_FOREACH(ConstElementPtr subnet_json, subnets_list->listValue()) {
  884. Subnet6ConfigParser parser;
  885. Subnet6Ptr subnet = parser.parse(subnet_json);
  886. // Adding a subnet to the Configuration Manager may fail if the
  887. // subnet id is invalid (duplicate). Thus, we catch exceptions
  888. // here to append a position in the configuration string.
  889. try {
  890. cfg->getCfgSubnets6()->add(subnet);
  891. cnt++;
  892. } catch (const std::exception& ex) {
  893. isc_throw(DhcpConfigError, ex.what() << " ("
  894. << subnet_json->getPosition() << ")");
  895. }
  896. }
  897. return (cnt);
  898. }
  899. //**************************** D2ClientConfigParser **********************
  900. dhcp_ddns::NameChangeProtocol
  901. D2ClientConfigParser::getProtocol(ConstElementPtr scope,
  902. const std::string& name) {
  903. return (getAndConvert<dhcp_ddns::NameChangeProtocol,
  904. dhcp_ddns::stringToNcrProtocol>
  905. (scope, name, "NameChangeRequest protocol"));
  906. }
  907. dhcp_ddns::NameChangeFormat
  908. D2ClientConfigParser::getFormat(ConstElementPtr scope,
  909. const std::string& name) {
  910. return (getAndConvert<dhcp_ddns::NameChangeFormat,
  911. dhcp_ddns::stringToNcrFormat>
  912. (scope, name, "NameChangeRequest format"));
  913. }
  914. D2ClientConfig::ReplaceClientNameMode
  915. D2ClientConfigParser::getMode(ConstElementPtr scope,
  916. const std::string& name) {
  917. return (getAndConvert<D2ClientConfig::ReplaceClientNameMode,
  918. D2ClientConfig::stringToReplaceClientNameMode>
  919. (scope, name, "ReplaceClientName mode"));
  920. }
  921. D2ClientConfigPtr
  922. D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
  923. D2ClientConfigPtr new_config;
  924. // Get all parameters that are needed to create the D2ClientConfig.
  925. bool enable_updates = getBoolean(client_config, "enable-updates");
  926. IOAddress server_ip = getAddress(client_config, "server-ip");
  927. uint32_t server_port = getUint32(client_config, "server-port");
  928. std::string sender_ip_str = getString(client_config, "sender-ip");
  929. uint32_t sender_port = getUint32(client_config, "sender-port");
  930. uint32_t max_queue_size = getUint32(client_config, "max-queue-size");
  931. dhcp_ddns::NameChangeProtocol ncr_protocol =
  932. getProtocol(client_config, "ncr-protocol");
  933. dhcp_ddns::NameChangeFormat ncr_format =
  934. getFormat(client_config, "ncr-format");
  935. bool always_include_fqdn =
  936. getBoolean(client_config, "always-include-fqdn");
  937. bool override_no_update =
  938. getBoolean(client_config, "override-no-update");
  939. bool override_client_update =
  940. getBoolean(client_config, "override-client-update");
  941. D2ClientConfig::ReplaceClientNameMode replace_client_name_mode =
  942. getMode(client_config, "replace-client-name");
  943. std::string generated_prefix =
  944. getString(client_config, "generated-prefix");
  945. // qualifying-suffix is the only parameter which has no default
  946. std::string qualifying_suffix = "";
  947. bool found_qualifying_suffix = false;
  948. if (client_config->contains("qualifying-suffix")) {
  949. qualifying_suffix = getString(client_config, "qualifying-suffix");
  950. found_qualifying_suffix = true;
  951. }
  952. IOAddress sender_ip(0);
  953. if (sender_ip_str.empty()) {
  954. // The default sender IP depends on the server IP family
  955. sender_ip = (server_ip.isV4() ? IOAddress::IPV4_ZERO_ADDRESS() :
  956. IOAddress::IPV6_ZERO_ADDRESS());
  957. } else {
  958. try {
  959. sender_ip = IOAddress(sender_ip_str);
  960. } catch (const std::exception& ex) {
  961. isc_throw(DhcpConfigError, "invalid address (" << sender_ip_str
  962. << ") specified for parameter 'sender-ip' ("
  963. << getPosition("sender-ip", client_config) << ")");
  964. }
  965. }
  966. // Qualifying-suffix is required when updates are enabled
  967. if (enable_updates && !found_qualifying_suffix) {
  968. isc_throw(DhcpConfigError,
  969. "parameter 'qualifying-suffix' is required when "
  970. "updates are enabled ("
  971. << client_config->getPosition() << ")");
  972. }
  973. // Now we check for logical errors. This repeats what is done in
  974. // D2ClientConfig::validate(), but doing it here permits us to
  975. // emit meaningful parameter position info in the error.
  976. if (ncr_format != dhcp_ddns::FMT_JSON) {
  977. isc_throw(D2ClientError, "D2ClientConfig error: NCR Format: "
  978. << dhcp_ddns::ncrFormatToString(ncr_format)
  979. << " is not supported. ("
  980. << getPosition("ncr-format", client_config) << ")");
  981. }
  982. if (ncr_protocol != dhcp_ddns::NCR_UDP) {
  983. isc_throw(D2ClientError, "D2ClientConfig error: NCR Protocol: "
  984. << dhcp_ddns::ncrProtocolToString(ncr_protocol)
  985. << " is not supported. ("
  986. << getPosition("ncr-protocol", client_config) << ")");
  987. }
  988. if (sender_ip.getFamily() != server_ip.getFamily()) {
  989. isc_throw(D2ClientError,
  990. "D2ClientConfig error: address family mismatch: "
  991. << "server-ip: " << server_ip.toText()
  992. << " is: " << (server_ip.isV4() ? "IPv4" : "IPv6")
  993. << " while sender-ip: " << sender_ip.toText()
  994. << " is: " << (sender_ip.isV4() ? "IPv4" : "IPv6")
  995. << " (" << getPosition("sender-ip", client_config) << ")");
  996. }
  997. if (server_ip == sender_ip && server_port == sender_port) {
  998. isc_throw(D2ClientError,
  999. "D2ClientConfig error: server and sender cannot"
  1000. " share the exact same IP address/port: "
  1001. << server_ip.toText() << "/" << server_port
  1002. << " (" << getPosition("sender-ip", client_config) << ")");
  1003. }
  1004. try {
  1005. // Attempt to create the new client config.
  1006. new_config.reset(new D2ClientConfig(enable_updates,
  1007. server_ip,
  1008. server_port,
  1009. sender_ip,
  1010. sender_port,
  1011. max_queue_size,
  1012. ncr_protocol,
  1013. ncr_format,
  1014. always_include_fqdn,
  1015. override_no_update,
  1016. override_client_update,
  1017. replace_client_name_mode,
  1018. generated_prefix,
  1019. qualifying_suffix));
  1020. } catch (const std::exception& ex) {
  1021. isc_throw(DhcpConfigError, ex.what() << " ("
  1022. << client_config->getPosition() << ")");
  1023. }
  1024. return(new_config);
  1025. }
  1026. /// @brief This table defines default values for D2 client configuration
  1027. const SimpleDefaults D2ClientConfigParser::D2_CLIENT_CONFIG_DEFAULTS = {
  1028. // enable-updates is unconditionally required
  1029. { "server-ip", Element::string, "127.0.0.1" },
  1030. { "server-port", Element::integer, "53001" },
  1031. // default sender-ip depends on server-ip family, so we leave default blank
  1032. // parser knows to use the appropriate ZERO address based on server-ip
  1033. { "sender-ip", Element::string, "" },
  1034. { "sender-port", Element::integer, "0" },
  1035. { "max-queue-size", Element::integer, "1024" },
  1036. { "ncr-protocol", Element::string, "UDP" },
  1037. { "ncr-format", Element::string, "JSON" },
  1038. { "always-include-fqdn", Element::boolean, "false" },
  1039. { "override-no-update", Element::boolean, "false" },
  1040. { "override-client-update", Element::boolean, "false" },
  1041. { "replace-client-name", Element::string, "never" },
  1042. { "generated-prefix", Element::string, "myhost" }
  1043. // qualifying-suffix has no default
  1044. };
  1045. size_t
  1046. D2ClientConfigParser::setAllDefaults(isc::data::ConstElementPtr d2_config) {
  1047. ElementPtr mutable_d2 = boost::const_pointer_cast<Element>(d2_config);
  1048. return (SimpleParser::setDefaults(mutable_d2, D2_CLIENT_CONFIG_DEFAULTS));
  1049. }
  1050. }; // namespace dhcp
  1051. }; // namespace isc