Kea  1.9.9-git
srv_config.cc
Go to the documentation of this file.
1 // Copyright (C) 2014-2021 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
9 #include <dhcpsrv/cfgmgr.h>
12 #include <dhcpsrv/srv_config.h>
14 #include <dhcpsrv/dhcpsrv_log.h>
15 #include <dhcpsrv/cfg_hosts_util.h>
16 #include <process/logging_info.h>
17 #include <log/logger_manager.h>
19 #include <dhcp/pkt.h> // Needed for HWADDR_SOURCE_*
20 #include <stats/stats_mgr.h>
21 #include <util/strutil.h>
22 
23 #include <list>
24 #include <sstream>
25 
26 using namespace isc::log;
27 using namespace isc::data;
28 using namespace isc::process;
29 
30 namespace isc {
31 namespace dhcp {
32 
33 SrvConfig::SrvConfig()
34  : sequence_(0), cfg_iface_(new CfgIface()),
35  cfg_option_def_(new CfgOptionDef()), cfg_option_(new CfgOption()),
36  cfg_subnets4_(new CfgSubnets4()), cfg_subnets6_(new CfgSubnets6()),
37  cfg_shared_networks4_(new CfgSharedNetworks4()),
38  cfg_shared_networks6_(new CfgSharedNetworks6()),
39  cfg_hosts_(new CfgHosts()), cfg_rsoo_(new CfgRSOO()),
40  cfg_expiration_(new CfgExpiration()), cfg_duid_(new CfgDUID()),
41  cfg_db_access_(new CfgDbAccess()),
42  cfg_host_operations4_(CfgHostOperations::createConfig4()),
43  cfg_host_operations6_(CfgHostOperations::createConfig6()),
44  class_dictionary_(new ClientClassDictionary()),
45  decline_timer_(0), echo_v4_client_id_(true), dhcp4o6_port_(0),
46  d2_client_config_(new D2ClientConfig()),
47  configured_globals_(Element::createMap()),
48  cfg_consist_(new CfgConsistency()),
49  lenient_option_parsing_(false) {
50 }
51 
52 SrvConfig::SrvConfig(const uint32_t sequence)
53  : sequence_(sequence), cfg_iface_(new CfgIface()),
54  cfg_option_def_(new CfgOptionDef()), cfg_option_(new CfgOption()),
55  cfg_subnets4_(new CfgSubnets4()), cfg_subnets6_(new CfgSubnets6()),
56  cfg_shared_networks4_(new CfgSharedNetworks4()),
57  cfg_shared_networks6_(new CfgSharedNetworks6()),
58  cfg_hosts_(new CfgHosts()), cfg_rsoo_(new CfgRSOO()),
59  cfg_expiration_(new CfgExpiration()), cfg_duid_(new CfgDUID()),
60  cfg_db_access_(new CfgDbAccess()),
61  cfg_host_operations4_(CfgHostOperations::createConfig4()),
62  cfg_host_operations6_(CfgHostOperations::createConfig6()),
63  class_dictionary_(new ClientClassDictionary()),
64  decline_timer_(0), echo_v4_client_id_(true), dhcp4o6_port_(0),
65  d2_client_config_(new D2ClientConfig()),
66  configured_globals_(Element::createMap()),
67  cfg_consist_(new CfgConsistency()),
68  lenient_option_parsing_(false) {
69 }
70 
71 std::string
72 SrvConfig::getConfigSummary(const uint32_t selection) const {
73  std::ostringstream s;
74  size_t subnets_num;
75  if ((selection & CFGSEL_SUBNET4) == CFGSEL_SUBNET4) {
76  subnets_num = getCfgSubnets4()->getAll()->size();
77  if (subnets_num > 0) {
78  s << "added IPv4 subnets: " << subnets_num;
79  } else {
80  s << "no IPv4 subnets!";
81  }
82  s << "; ";
83  }
84 
85  if ((selection & CFGSEL_SUBNET6) == CFGSEL_SUBNET6) {
86  subnets_num = getCfgSubnets6()->getAll()->size();
87  if (subnets_num > 0) {
88  s << "added IPv6 subnets: " << subnets_num;
89  } else {
90  s << "no IPv6 subnets!";
91  }
92  s << "; ";
93  }
94 
95  if ((selection & CFGSEL_DDNS) == CFGSEL_DDNS) {
96  bool ddns_enabled = getD2ClientConfig()->getEnableUpdates();
97  s << "DDNS: " << (ddns_enabled ? "enabled" : "disabled") << "; ";
98  }
99 
100  if (s.tellp() == static_cast<std::streampos>(0)) {
101  s << "no config details available";
102  }
103 
104  std::string summary = s.str();
105  size_t last_separator_pos = summary.find_last_of(";");
106  if (last_separator_pos == summary.length() - 2) {
107  summary.erase(last_separator_pos);
108  }
109  return (summary);
110 }
111 
112 bool
114  return (getSequence() == other.getSequence());
115 }
116 
117 void
118 SrvConfig::copy(SrvConfig& new_config) const {
119  ConfigBase::copy(new_config);
120 
121  // Replace interface configuration.
122  new_config.cfg_iface_.reset(new CfgIface(*cfg_iface_));
123  // Replace option definitions.
124  cfg_option_def_->copyTo(*new_config.cfg_option_def_);
125  cfg_option_->copyTo(*new_config.cfg_option_);
126  // Replace the client class dictionary
127  new_config.class_dictionary_.reset(new ClientClassDictionary(*class_dictionary_));
128  // Replace the D2 client configuration
129  new_config.setD2ClientConfig(getD2ClientConfig());
130  // Replace configured hooks libraries.
131  new_config.hooks_config_.clear();
132  using namespace isc::hooks;
133  for (HookLibsCollection::const_iterator it =
134  hooks_config_.get().begin();
135  it != hooks_config_.get().end(); ++it) {
136  new_config.hooks_config_.add(it->first, it->second);
137  }
138 }
139 
140 bool
141 SrvConfig::equals(const SrvConfig& other) const {
142 
143  // Checks common elements: logging & config control
144  if (!ConfigBase::equals(other)) {
145  return (false);
146  }
147 
148  // Common information is equal between objects, so check other values.
149  if ((*cfg_iface_ != *other.cfg_iface_) ||
150  (*cfg_option_def_ != *other.cfg_option_def_) ||
151  (*cfg_option_ != *other.cfg_option_) ||
152  (*class_dictionary_ != *other.class_dictionary_) ||
153  (*d2_client_config_ != *other.d2_client_config_)) {
154  return (false);
155  }
156  // Now only configured hooks libraries can differ.
157  // If number of configured hooks libraries are different, then
158  // configurations aren't equal.
159  if (hooks_config_.get().size() != other.hooks_config_.get().size()) {
160  return (false);
161  }
162  // Pass through all configured hooks libraries.
163  return (hooks_config_.equal(other.hooks_config_));
164 }
165 
166 void
168  ConfigBase::merge(other);
169  try {
170  SrvConfig& other_srv_config = dynamic_cast<SrvConfig&>(other);
171  // We merge objects in order of dependency (real or theoretical).
172  // First we merge the common stuff.
173 
174  // Merge globals.
175  mergeGlobals(other_srv_config);
176 
177  // Merge option defs. We need to do this next so we
178  // pass these into subsequent merges so option instances
179  // at each level can be created based on the merged
180  // definitions.
181  cfg_option_def_->merge((*other_srv_config.getCfgOptionDef()));
182 
183  // Merge options.
184  cfg_option_->merge(cfg_option_def_, (*other_srv_config.getCfgOption()));
185 
186  if (CfgMgr::instance().getFamily() == AF_INET) {
187  merge4(other_srv_config);
188  } else {
189  merge6(other_srv_config);
190  }
191  } catch (const std::bad_cast&) {
192  isc_throw(InvalidOperation, "internal server error: must use derivation"
193  " of the SrvConfig as an argument of the call to"
194  " SrvConfig::merge()");
195  }
196 }
197 
198 void
199 SrvConfig::merge4(SrvConfig& other) {
200  // Merge shared networks.
201  cfg_shared_networks4_->merge(cfg_option_def_, *(other.getCfgSharedNetworks4()));
202 
203  // Merge subnets.
204  cfg_subnets4_->merge(cfg_option_def_, getCfgSharedNetworks4(),
205  *(other.getCfgSubnets4()));
206 
208 }
209 
210 void
211 SrvConfig::merge6(SrvConfig& other) {
212  // Merge shared networks.
213  cfg_shared_networks6_->merge(cfg_option_def_, *(other.getCfgSharedNetworks6()));
214 
215  // Merge subnets.
216  cfg_subnets6_->merge(cfg_option_def_, getCfgSharedNetworks6(),
217  *(other.getCfgSubnets6()));
218 
220 }
221 
222 void
223 SrvConfig::mergeGlobals(SrvConfig& other) {
224  auto config_set = getConfiguredGlobals();
225  ElementPtr mutable_cfg = boost::const_pointer_cast<Element>(config_set);
226  // If the deprecated reservation-mode is found in database, overwrite other
227  // reservation flags so there is no conflict when merging to new flags.
228  if (other.getConfiguredGlobals()->find("reservation-mode")) {
229  mutable_cfg->remove("reservations-global");
230  mutable_cfg->remove("reservations-in-subnet");
231  mutable_cfg->remove("reservations-out-of-pool");
232  }
233  // Iterate over the "other" globals, adding/overwriting them into
234  // this config's list of globals.
235  for (auto other_global : other.getConfiguredGlobals()->mapValue()) {
236  addConfiguredGlobal(other_global.first, other_global.second);
237  }
238 
239  // Merge the reservation-mode to new reservation flags.
241 
242  // A handful of values are stored as members in SrvConfig. So we'll
243  // iterate over the merged globals, setting appropriate members.
244  for (auto merged_global : config_set->mapValue()) {
245  std::string name = merged_global.first;
246  ConstElementPtr element = merged_global.second;
247  try {
248  if (name == "decline-probation-period") {
249  setDeclinePeriod(element->intValue());
250  } else if (name == "echo-client-id") {
251  // echo-client-id is v4 only, but we'll let upstream
252  // worry about that.
253  setEchoClientId(element->boolValue());
254  } else if (name == "dhcp4o6-port") {
255  setDhcp4o6Port(element->intValue());
256  } else if (name == "server-tag") {
257  setServerTag(element->stringValue());
258  } else if (name == "ip-reservations-unique") {
259  setIPReservationsUnique(element->boolValue());
260  }
261  } catch(const std::exception& ex) {
262  isc_throw (BadValue, "Invalid value:" << element->str()
263  << " explicit global:" << name);
264  }
265  }
266 }
267 
268 void
270  // Removes statistics for v4 and v6 subnets
271  getCfgSubnets4()->removeStatistics();
272 
273  getCfgSubnets6()->removeStatistics();
274 }
275 
276 void
278  // Update default sample limits.
280  ConstElementPtr samples =
281  getConfiguredGlobal("statistic-default-sample-count");
282  uint32_t max_samples = 0;
283  if (samples) {
284  max_samples = samples->intValue();
285  stats_mgr.setMaxSampleCountDefault(max_samples);
286  if (max_samples != 0) {
287  stats_mgr.setMaxSampleCountAll(max_samples);
288  }
289  }
290  ConstElementPtr duration =
291  getConfiguredGlobal("statistic-default-sample-age");
292  if (duration) {
293  int64_t time_duration = duration->intValue();
294  auto max_age = std::chrono::seconds(time_duration);
295  stats_mgr.setMaxSampleAgeDefault(max_age);
296  if (max_samples == 0) {
297  stats_mgr.setMaxSampleAgeAll(max_age);
298  }
299  }
300 
301  // Updating subnet statistics involves updating lease statistics, which
302  // is done by the LeaseMgr. Since servers with subnets, must have a
303  // LeaseMgr, we do not bother updating subnet stats for servers without
304  // a lease manager, such as D2. @todo We should probably examine why
305  // "SrvConfig" is being used by D2.
307  // Updates statistics for v4 and v6 subnets
308  getCfgSubnets4()->updateStatistics();
309 
310  getCfgSubnets6()->updateStatistics();
311  }
312 }
313 
315 SrvConfig::getConfiguredGlobal(std::string name) const {
317  if (configured_globals_->contains(name)) {
318  global = configured_globals_->get(name);
319  }
320 
321  return (global);
322 }
323 
324 void
326  configured_globals_ = isc::data::Element::createMap();
327 }
328 
329 void
331  // Code from SimpleParser::setDefaults
332  // This is the position representing a default value. As the values
333  // we're inserting here are not present in whatever the config file
334  // came from, we need to make sure it's clearly labeled as default.
335  const Element::Position pos("<default-value>", 0, 0);
337 
338  // Let's go over all parameters we have defaults for.
339  for (auto def_value : defaults) {
340 
341  // Try if such a parameter is there. If it is, let's
342  // skip it, because user knows best *cough*.
343  ConstElementPtr x = globals->get(def_value.name_);
344  if (x) {
345  // There is such a value already, skip it.
346  continue;
347  }
348 
349  // There isn't such a value defined, let's create the default
350  // value...
351  switch (def_value.type_) {
352  case Element::string: {
353  x.reset(new StringElement(def_value.value_, pos));
354  break;
355  }
356  case Element::integer: {
357  try {
358  int int_value = boost::lexical_cast<int>(def_value.value_);
359  x.reset(new IntElement(int_value, pos));
360  }
361  catch (const std::exception& ex) {
363  "Internal error. Integer value expected for: "
364  << def_value.name_ << ", value is: "
365  << def_value.value_ );
366  }
367 
368  break;
369  }
370  case Element::boolean: {
371  bool bool_value;
372  if (def_value.value_ == std::string("true")) {
373  bool_value = true;
374  } else if (def_value.value_ == std::string("false")) {
375  bool_value = false;
376  } else {
378  "Internal error. Boolean value for "
379  << def_value.name_ << " specified as "
380  << def_value.value_ << ", expected true or false");
381  }
382  x.reset(new BoolElement(bool_value, pos));
383  break;
384  }
385  case Element::real: {
386  double dbl_value = boost::lexical_cast<double>(def_value.value_);
387  x.reset(new DoubleElement(dbl_value, pos));
388  break;
389  }
390  default:
391  // No default values for null, list or map
393  "Internal error. Incorrect default value type for "
394  << def_value.name_);
395  }
396  addConfiguredGlobal(def_value.name_, x);
397  }
398 }
399 
400 void
402  if (config->getType() != Element::map) {
403  isc_throw(BadValue, "extractConfiguredGlobals must be given a map element");
404  }
405 
406  const std::map<std::string, ConstElementPtr>& values = config->mapValue();
407  for (auto value = values.begin(); value != values.end(); ++value) {
408  if (value->second->getType() != Element::list &&
409  value->second->getType() != Element::map) {
410  addConfiguredGlobal(value->first, value->second);
411  }
412  }
413 }
414 
415 void
416 SrvConfig::sanityChecksLifetime(const std::string& name) const {
417  // Initialize as some compilers complain otherwise.
418  uint32_t value = 0;
419  ConstElementPtr has_value = getConfiguredGlobal(name);
420  if (has_value) {
421  value = has_value->intValue();
422  }
423 
424  uint32_t min_value = 0;
425  ConstElementPtr has_min = getConfiguredGlobal("min-" + name);
426  if (has_min) {
427  min_value = has_min->intValue();
428  }
429 
430  uint32_t max_value = 0;
431  ConstElementPtr has_max = getConfiguredGlobal("max-" + name);
432  if (has_max) {
433  max_value = has_max->intValue();
434  }
435 
436  if (!has_value && !has_min && !has_max) {
437  return;
438  }
439  if (has_value) {
440  if (!has_min && !has_max) {
441  // default only.
442  return;
443  } else if (!has_min) {
444  // default and max.
445  min_value = value;
446  } else if (!has_max) {
447  // default and min.
448  max_value = value;
449  }
450  } else if (has_min) {
451  if (!has_max) {
452  // min only.
453  return;
454  } else {
455  // min and max.
456  isc_throw(BadValue, "have min-" << name << " and max-"
457  << name << " but no " << name << " (default)");
458  }
459  } else {
460  // max only.
461  return;
462  }
463 
464  // Check that min <= max.
465  if (min_value > max_value) {
466  if (has_min && has_max) {
467  isc_throw(BadValue, "the value of min-" << name << " ("
468  << min_value << ") is not less than max-" << name << " ("
469  << max_value << ")");
470  } else if (has_min) {
471  // Only min and default so min > default.
472  isc_throw(BadValue, "the value of min-" << name << " ("
473  << min_value << ") is not less than (default) " << name
474  << " (" << value << ")");
475  } else {
476  // Only default and max so default > max.
477  isc_throw(BadValue, "the value of (default) " << name
478  << " (" << value << ") is not less than max-" << name
479  << " (" << max_value << ")");
480  }
481  }
482 
483  // Check that value is between min and max.
484  if ((value < min_value) || (value > max_value)) {
485  isc_throw(BadValue, "the value of (default) " << name << " ("
486  << value << ") is not between min-" << name << " ("
487  << min_value << ") and max-" << name << " ("
488  << max_value << ")");
489  }
490 }
491 
492 void
494  const std::string& name) const {
495  // Three cases:
496  // - the external/source config has the parameter: use it.
497  // - only the target config has the parameter: use this one.
498  // - no config has the parameter.
499  uint32_t value = 0;
500  ConstElementPtr has_value = getConfiguredGlobal(name);
501  bool new_value = true;
502  if (!has_value) {
503  has_value = target_config.getConfiguredGlobal(name);
504  new_value = false;
505  }
506  if (has_value) {
507  value = has_value->intValue();
508  }
509 
510  uint32_t min_value = 0;
511  ConstElementPtr has_min = getConfiguredGlobal("min-" + name);
512  bool new_min = true;
513  if (!has_min) {
514  has_min = target_config.getConfiguredGlobal("min-" + name);
515  new_min = false;
516  }
517  if (has_min) {
518  min_value = has_min->intValue();
519  }
520 
521  uint32_t max_value = 0;
522  ConstElementPtr has_max = getConfiguredGlobal("max-" + name);
523  bool new_max = true;
524  if (!has_max) {
525  has_max = target_config.getConfiguredGlobal("max-" + name);
526  new_max = false;
527  }
528  if (has_max) {
529  max_value = has_max->intValue();
530  }
531 
532  if (!has_value && !has_min && !has_max) {
533  return;
534  }
535  if (has_value) {
536  if (!has_min && !has_max) {
537  // default only.
538  return;
539  } else if (!has_min) {
540  // default and max.
541  min_value = value;
542  } else if (!has_max) {
543  // default and min.
544  max_value = value;
545  }
546  } else if (has_min) {
547  if (!has_max) {
548  // min only.
549  return;
550  } else {
551  // min and max.
552  isc_throw(BadValue, "have min-" << name << " and max-"
553  << name << " but no " << name << " (default)");
554  }
555  } else {
556  // max only.
557  return;
558  }
559 
560  // Check that min <= max.
561  if (min_value > max_value) {
562  if (has_min && has_max) {
563  std::string from_min = (new_min ? "new" : "previous");
564  std::string from_max = (new_max ? "new" : "previous");
565  isc_throw(BadValue, "the value of " << from_min
566  << " min-" << name << " ("
567  << min_value << ") is not less than "
568  << from_max << " max-" << name
569  << " (" << max_value << ")");
570  } else if (has_min) {
571  // Only min and default so min > default.
572  std::string from_min = (new_min ? "new" : "previous");
573  std::string from_value = (new_value ? "new" : "previous");
574  isc_throw(BadValue, "the value of " << from_min
575  << " min-" << name << " ("
576  << min_value << ") is not less than " << from_value
577  << " (default) " << name
578  << " (" << value << ")");
579  } else {
580  // Only default and max so default > max.
581  std::string from_max = (new_max ? "new" : "previous");
582  std::string from_value = (new_value ? "new" : "previous");
583  isc_throw(BadValue, "the value of " << from_value
584  << " (default) " << name
585  << " (" << value << ") is not less than " << from_max
586  << " max-" << name << " (" << max_value << ")");
587  }
588  }
589 
590  // Check that value is between min and max.
591  if ((value < min_value) || (value > max_value)) {
592  std::string from_value = (new_value ? "new" : "previous");
593  std::string from_min = (new_min ? "new" : "previous");
594  std::string from_max = (new_max ? "new" : "previous");
595  isc_throw(BadValue, "the value of " << from_value
596  <<" (default) " << name << " ("
597  << value << ") is not between " << from_min
598  << " min-" << name << " (" << min_value
599  << ") and " << from_max << " max-"
600  << name << " (" << max_value << ")");
601  }
602 }
603 
606  // Toplevel map
607  ElementPtr result = Element::createMap();
608 
609  // Get family for the configuration manager
610  uint16_t family = CfgMgr::instance().getFamily();
611  // DhcpX global map
612  ElementPtr dhcp = ConfigBase::toElement();
613 
614  // Add in explicitly configured globals.
615  dhcp->setValue(configured_globals_->mapValue());
616 
617  // Set user-context
618  contextToElement(dhcp);
619 
620  // Set data directory if DHCPv6 and specified.
621  if (family == AF_INET6) {
622  const util::Optional<std::string>& datadir =
624  if (!datadir.unspecified()) {
625  dhcp->set("data-directory", Element::create(datadir));
626  }
627  }
628 
629  // Set decline-probation-period
630  dhcp->set("decline-probation-period",
631  Element::create(static_cast<long long>(decline_timer_)));
632  // Set echo-client-id (DHCPv4)
633  if (family == AF_INET) {
634  dhcp->set("echo-client-id", Element::create(echo_v4_client_id_));
635  }
636  // Set dhcp4o6-port
637  dhcp->set("dhcp4o6-port",
638  Element::create(static_cast<int>(dhcp4o6_port_)));
639  // Set dhcp-ddns
640  dhcp->set("dhcp-ddns", d2_client_config_->toElement());
641  // Set interfaces-config
642  dhcp->set("interfaces-config", cfg_iface_->toElement());
643  // Set option-def
644  dhcp->set("option-def", cfg_option_def_->toElement());
645  // Set option-data
646  dhcp->set("option-data", cfg_option_->toElement());
647 
648  // Set subnets and shared networks.
649 
650  // We have two problems to solve:
651  // - a subnet is unparsed once:
652  // * if it is a plain subnet in the global subnet list
653  // * if it is a member of a shared network in the shared network
654  // subnet list
655  // - unparsed subnets must be kept to add host reservations in them.
656  // Of course this can be done only when subnets are unparsed.
657 
658  // The list of all unparsed subnets
659  std::vector<ElementPtr> sn_list;
660 
661  if (family == AF_INET) {
662  // Get plain subnets
663  ElementPtr plain_subnets = Element::createList();
664  const Subnet4Collection* subnets = cfg_subnets4_->getAll();
665  for (Subnet4Collection::const_iterator subnet = subnets->cbegin();
666  subnet != subnets->cend(); ++subnet) {
667  // Skip subnets which are in a shared-network
668  SharedNetwork4Ptr network;
669  (*subnet)->getSharedNetwork(network);
670  if (network) {
671  continue;
672  }
673  ElementPtr subnet_cfg = (*subnet)->toElement();
674  sn_list.push_back(subnet_cfg);
675  plain_subnets->add(subnet_cfg);
676  }
677  dhcp->set("subnet4", plain_subnets);
678 
679  // Get shared networks
680  ElementPtr shared_networks = cfg_shared_networks4_->toElement();
681  dhcp->set("shared-networks", shared_networks);
682 
683  // Get subnets in shared network subnet lists
684  const std::vector<ElementPtr> networks = shared_networks->listValue();
685  for (auto network = networks.cbegin();
686  network != networks.cend(); ++network) {
687  const std::vector<ElementPtr> sh_list =
688  (*network)->get("subnet4")->listValue();
689  for (auto subnet = sh_list.cbegin();
690  subnet != sh_list.cend(); ++subnet) {
691  sn_list.push_back(*subnet);
692  }
693  }
694 
695  } else {
696  // Get plain subnets
697  ElementPtr plain_subnets = Element::createList();
698  const Subnet6Collection* subnets = cfg_subnets6_->getAll();
699  for (Subnet6Collection::const_iterator subnet = subnets->cbegin();
700  subnet != subnets->cend(); ++subnet) {
701  // Skip subnets which are in a shared-network
702  SharedNetwork6Ptr network;
703  (*subnet)->getSharedNetwork(network);
704  if (network) {
705  continue;
706  }
707  ElementPtr subnet_cfg = (*subnet)->toElement();
708  sn_list.push_back(subnet_cfg);
709  plain_subnets->add(subnet_cfg);
710  }
711  dhcp->set("subnet6", plain_subnets);
712 
713  // Get shared networks
714  ElementPtr shared_networks = cfg_shared_networks6_->toElement();
715  dhcp->set("shared-networks", shared_networks);
716 
717  // Get subnets in shared network subnet lists
718  const std::vector<ElementPtr> networks = shared_networks->listValue();
719  for (auto network = networks.cbegin();
720  network != networks.cend(); ++network) {
721  const std::vector<ElementPtr> sh_list =
722  (*network)->get("subnet6")->listValue();
723  for (auto subnet = sh_list.cbegin();
724  subnet != sh_list.cend(); ++subnet) {
725  sn_list.push_back(*subnet);
726  }
727  }
728  }
729 
730  // Host reservations
731  CfgHostsList resv_list;
732  resv_list.internalize(cfg_hosts_->toElement());
733 
734  // Insert global reservations
735  ConstElementPtr global_resvs = resv_list.get(SUBNET_ID_GLOBAL);
736  if (global_resvs->size() > 0) {
737  dhcp->set("reservations", global_resvs);
738  }
739 
740  // Insert subnet reservations
741  for (std::vector<ElementPtr>::const_iterator subnet = sn_list.cbegin();
742  subnet != sn_list.cend(); ++subnet) {
743  ConstElementPtr id = (*subnet)->get("id");
744  if (isNull(id)) {
745  isc_throw(ToElementError, "subnet has no id");
746  }
747  SubnetID subnet_id = id->intValue();
748  ConstElementPtr resvs = resv_list.get(subnet_id);
749  (*subnet)->set("reservations", resvs);
750  }
751 
752  // Set expired-leases-processing
753  ConstElementPtr expired = cfg_expiration_->toElement();
754  dhcp->set("expired-leases-processing", expired);
755  if (family == AF_INET6) {
756  // Set server-id (DHCPv6)
757  dhcp->set("server-id", cfg_duid_->toElement());
758 
759  // Set relay-supplied-options (DHCPv6)
760  dhcp->set("relay-supplied-options", cfg_rsoo_->toElement());
761  }
762  // Set lease-database
763  CfgLeaseDbAccess lease_db(*cfg_db_access_);
764  dhcp->set("lease-database", lease_db.toElement());
765  // Set hosts-databases
766  CfgHostDbAccess host_db(*cfg_db_access_);
767  ConstElementPtr hosts_databases = host_db.toElement();
768  if (hosts_databases->size() > 0) {
769  dhcp->set("hosts-databases", hosts_databases);
770  }
771  // Set host-reservation-identifiers
772  ConstElementPtr host_ids;
773  if (family == AF_INET) {
774  host_ids = cfg_host_operations4_->toElement();
775  } else {
776  host_ids = cfg_host_operations6_->toElement();
777  }
778  dhcp->set("host-reservation-identifiers", host_ids);
779  // Set mac-sources (DHCPv6)
780  if (family == AF_INET6) {
781  dhcp->set("mac-sources", cfg_mac_source_.toElement());
782  }
783  // Set control-socket (skip if null as empty is not legal)
784  if (!isNull(control_socket_)) {
785  dhcp->set("control-socket", UserContext::toElement(control_socket_));
786  }
787  // Set client-classes
788  ConstElementPtr client_classes = class_dictionary_->toElement();
790  if (!client_classes->empty()) {
791  dhcp->set("client-classes", client_classes);
792  }
793  // Set hooks-libraries
794  ConstElementPtr hooks_libs = hooks_config_.toElement();
795  dhcp->set("hooks-libraries", hooks_libs);
796  // Set DhcpX
797  result->set(family == AF_INET ? "Dhcp4" : "Dhcp6", dhcp);
798 
799  ConstElementPtr cfg_consist = cfg_consist_->toElement();
800  dhcp->set("sanity-checks", cfg_consist);
801 
802  // Set config-control (if it exists)
804  if (info) {
805  ConstElementPtr info_elem = info->toElement();
806  dhcp->set("config-control", info_elem);
807  }
808 
809  // Set dhcp-packet-control (if it exists)
810  data::ConstElementPtr dhcp_queue_control = getDHCPQueueControl();
811  if (dhcp_queue_control) {
812  dhcp->set("dhcp-queue-control", dhcp_queue_control);
813  }
814 
815  // Set multi-threading (if it exists)
816  data::ConstElementPtr dhcp_multi_threading = getDHCPMultiThreading();
817  if (dhcp_multi_threading) {
818  dhcp->set("multi-threading", dhcp_multi_threading);
819  }
820 
821  return (result);
822 }
823 
825 SrvConfig::getDdnsParams(const Subnet4Ptr& subnet) const {
826  return (DdnsParamsPtr(new DdnsParams(subnet,
827  getD2ClientConfig()->getEnableUpdates())));
828 }
829 
831 SrvConfig::getDdnsParams(const Subnet6Ptr& subnet) const {
832  return(DdnsParamsPtr(new DdnsParams(subnet,
833  getD2ClientConfig()->getEnableUpdates())));
834 }
835 
836 void
838  if (!srv_elem || (srv_elem->getType() != Element::map)) {
839  isc_throw(BadValue, "moveDdnsParams server config must be given a map element");
840  }
841 
842  if (!srv_elem->contains("dhcp-ddns")) {
843  /* nothing to do */
844  return;
845  }
846 
847  ElementPtr d2_elem = boost::const_pointer_cast<Element>(srv_elem->get("dhcp-ddns"));
848  if (!d2_elem || (d2_elem->getType() != Element::map)) {
849  isc_throw(BadValue, "moveDdnsParams dhcp-ddns is not a map");
850  }
851 
852  struct Param {
853  std::string from_name;
854  std::string to_name;
855  };
856 
857  std::vector<Param> params {
858  { "override-no-update", "ddns-override-no-update" },
859  { "override-client-update", "ddns-override-client-update" },
860  { "replace-client-name", "ddns-replace-client-name" },
861  { "generated-prefix", "ddns-generated-prefix" },
862  { "qualifying-suffix", "ddns-qualifying-suffix" },
863  { "hostname-char-set", "hostname-char-set" },
864  { "hostname-char-replacement", "hostname-char-replacement" }
865  };
866 
867  for (auto param : params) {
868  if (d2_elem->contains(param.from_name)) {
869  if (!srv_elem->contains(param.to_name)) {
870  // No global value for it already, so let's add it.
871  srv_elem->set(param.to_name, d2_elem->get(param.from_name));
873  .arg(param.from_name).arg(param.to_name);
874  } else {
875  // Already a global value, we'll use it and ignore this one.
877  .arg(param.from_name).arg(param.to_name);
878  }
879 
880  // Now remove it from d2_data, so D2ClientCfg won't complain.
881  d2_elem->remove(param.from_name);
882  }
883  }
884 }
885 
886 void
888  if (!getCfgDbAccess()->getIPReservationsUnique() && unique) {
890  }
891  getCfgHosts()->setIPReservationsUnique(unique);
892  getCfgDbAccess()->setIPReservationsUnique(unique);
893 }
894 
895 void
897  Option::lenient_parsing_ = lenient_option_parsing_;
898 }
899 
900 bool
902  if (!subnet_) {
903  return (false);
904  }
905 
906  return (d2_client_enabled_ && subnet_->getDdnsSendUpdates().get());
907 }
908 
909 bool
911  if (!subnet_) {
912  return (false);
913  }
914 
915  return (subnet_->getDdnsOverrideNoUpdate().get());
916 }
917 
919  if (!subnet_) {
920  return (false);
921  }
922 
923  return (subnet_->getDdnsOverrideClientUpdate().get());
924 }
925 
928  if (!subnet_) {
929  return (D2ClientConfig::RCM_NEVER);
930  }
931 
932  return (subnet_->getDdnsReplaceClientNameMode().get());
933 }
934 
935 std::string
937  if (!subnet_) {
938  return ("");
939  }
940 
941  return (subnet_->getDdnsGeneratedPrefix().get());
942 }
943 
944 std::string
946  if (!subnet_) {
947  return ("");
948  }
949 
950  return (subnet_->getDdnsQualifyingSuffix().get());
951 }
952 
953 std::string
955  if (!subnet_) {
956  return ("");
957  }
958 
959  return (subnet_->getHostnameCharSet().get());
960 }
961 
962 std::string
964  if (!subnet_) {
965  return ("");
966  }
967 
968  return (subnet_->getHostnameCharReplacement().get());
969 }
970 
974  if (subnet_) {
975  std::string char_set = getHostnameCharSet();
976  if (!char_set.empty()) {
977  try {
978  sanitizer.reset(new util::str::StringSanitizer(char_set,
979  getHostnameCharReplacement()));
980  } catch (const std::exception& ex) {
981  isc_throw(BadValue, "hostname_char_set_: '" << char_set <<
982  "' is not a valid regular expression");
983  }
984  }
985  }
986 
987  return (sanitizer);
988 }
989 
990 bool
992  if (!subnet_) {
993  return (false);
994  }
995 
996  return (subnet_->getDdnsUpdateOnRenew().get());
997 }
998 
999 bool
1001  if (!subnet_) {
1002  return (true);
1003  }
1004 
1005  return (subnet_->getDdnsUseConflictResolution().get());
1006 }
1007 
1008 } // namespace dhcp
1009 } // namespace isc
const isc::log::MessageID DHCPSRV_CFGMGR_IP_RESERVATIONS_UNIQUE_DUPLICATES_POSSIBLE
#define LOG_WARN(LOGGER, MESSAGE)
Macro to conveniently test warn output and log it.
Definition: macros.h:26
Represents configuration of the RSOO options for the DHCP server.
Definition: cfg_rsoo.h:25
D2ClientConfigPtr getD2ClientConfig()
Returns pointer to the D2 client configuration.
Definition: srv_config.h:749
void unspecified(bool unspecified)
Modifies the flag that indicates whether the value is specified or unspecified.
Definition: optional.h:121
void internalize(isc::data::ConstElementPtr list)
Internalize a list Element.
D2ClientConfig::ReplaceClientNameMode getReplaceClientNameMode() const
Returns how Kea should handle the domain-name supplied by the client.
Definition: srv_config.cc:927
SrvConfig()
Default constructor.
Definition: srv_config.cc:33
const isc::hooks::HookLibsCollection & get() const
Provides access to the configured hooks libraries.
Definition: hooks_config.h:54
isc::data::ConstElementPtr getConfiguredGlobal(std::string name) const
Returns pointer to a given configured global parameter.
Definition: srv_config.cc:315
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
Utility class to represent host reservation configurations internally as a map keyed by subnet IDs...
Holds subnets configured for the DHCPv6 server.
Definition: cfg_subnets6.h:34
void setMaxSampleCountDefault(uint32_t max_samples)
Set default count limit.
std::vector< SimpleDefault > SimpleDefaults
This specifies all default values in a given scope (e.g. a subnet).
static void moveDdnsParams(isc::data::ElementPtr srv_elem)
Moves deprecated parameters from dhcp-ddns element to global element.
Definition: srv_config.cc:837
process::ConstConfigControlInfoPtr getConfigControlInfo() const
Fetches a read-only copy of the configuration control information.
Definition: config_base.h:106
isc::data::ConstElementPtr get(SubnetID id) const
Return the host reservations for a subnet ID.
virtual isc::data::ElementPtr toElement() const
Unparse a configuration object.
Definition: srv_config.cc:605
Represents configuration of IPv4 shared networks.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
Base class for all configurations.
Definition: config_base.h:33
Cannot unparse error.
void removeStatistics()
Removes statistics.
Definition: srv_config.cc:269
boost::shared_ptr< Subnet4 > Subnet4Ptr
A pointer to a Subnet4 object.
Definition: subnet.h:522
void copy(SrvConfig &new_config) const
Copies the current configuration to a new configuration.
Definition: srv_config.cc:118
boost::shared_ptr< Element > ElementPtr
Definition: data.h:20
uint32_t getSequence() const
Returns configuration sequence number.
Definition: srv_config.h:229
void setMaxSampleCountAll(uint32_t max_samples)
Set count limit for all collected statistics.
CfgSubnets6Ptr getCfgSubnets6()
Returns pointer to non-const object holding subnets configuration for DHCPv6.
Definition: srv_config.h:345
Holds configuration parameters pertaining to lease expiration and lease affinity. ...
bool getUpdateOnRenew() const
Returns whether or not DNS should be updated when leases renew.
Definition: srv_config.cc:991
bool isNull(ConstElementPtr p)
Checks whether the given ElementPtr is a NULL pointer.
Definition: data.cc:1028
void updateStatistics()
Updates statistics.
Definition: srv_config.cc:277
static ElementPtr createMap(const Position &pos=ZERO_POSITION())
Creates an empty MapElement type ElementPtr.
Definition: data.cc:267
bool equals(const SrvConfig &other) const
Compares two objects for equality.
Definition: srv_config.cc:141
void setIPReservationsUnique(const bool unique)
Configures the server to allow or disallow specifying multiple hosts with the same IP address/subnet...
Definition: srv_config.cc:887
void contextToElement(data::ElementPtr map) const
Merge unparse a user_context object.
Definition: user_context.cc:15
Maintains a list of ClientClassDef's.
static StatsMgr & instance()
Statistics Manager accessor method.
Statistics Manager class.
boost::shared_ptr< DdnsParams > DdnsParamsPtr
Defines a pointer for DdnsParams instances.
Definition: srv_config.h:162
void clear()
Removes all configured hooks libraries.
Definition: hooks_config.h:59
void setMaxSampleAgeAll(const StatsDuration &duration)
Set duration limit for all collected statistics.
CfgOptionDefPtr getCfgOptionDef()
Return pointer to non-const object representing user-defined option definitions.
Definition: srv_config.h:272
void setEchoClientId(const bool echo)
Sets whether server should send back client-id in DHCPv4.
Definition: srv_config.h:720
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual isc::data::ElementPtr toElement() const
Unparse a configuration object.
Parameters for various consistency checks.
util::Optional< std::string > getDataDir() const
returns path do the data directory
Definition: cfgmgr.cc:31
Represents option data configuration for the DHCP server.
Definition: cfg_option.h:314
boost::multi_index_container< Subnet4Ptr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetSubnetIdIndexTag >, boost::multi_index::const_mem_fun< Subnet, SubnetID,&Subnet::getID > >, boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetPrefixIndexTag >, boost::multi_index::const_mem_fun< Subnet, std::string,&Subnet::toText > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SubnetServerIdIndexTag >, boost::multi_index::const_mem_fun< Network4, asiolink::IOAddress,&Network4::getServerId > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SubnetModificationTimeIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, boost::posix_time::ptime,&data::BaseStampedElement::getModificationTime > > >> Subnet4Collection
A collection of Subnet4 objects.
Definition: subnet.h:867
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
Definition: data.cc:1097
bool getEnableUpdates() const
Returns whether or not DHCP DDNS updating is enabled.
Definition: srv_config.cc:901
void setDeclinePeriod(const uint32_t decline_timer)
Sets decline probation-period.
Definition: srv_config.h:702
Acts as a storage vault for D2 client configuration.
Definition: d2_client_cfg.h:56
isc::data::ElementPtr toElement() const
Unparse a configuration object.
Notes: IntElement type is changed to int64_t.
Definition: data.h:544
const isc::data::ConstElementPtr getDHCPQueueControl() const
Returns DHCP queue control information.
Definition: srv_config.h:488
void addConfiguredGlobal(const std::string &name, isc::data::ConstElementPtr value)
Adds a parameter to the collection configured globals.
Definition: srv_config.h:792
uint16_t getFamily() const
Returns address family.
Definition: cfgmgr.h:280
static void moveReservationMode(isc::data::ElementPtr config)
Moves deprecated reservation-mode parameter to new reservations flags.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:23
Represents option definitions used by the DHCP server.
Holds access parameters and the configuration of the lease and hosts database connection.
Definition: cfg_db_access.h:25
CfgDbAccessPtr getCfgDbAccess()
Returns pointer to the object holding configuration of the lease and host database connection paramet...
Definition: srv_config.h:417
Represents global configuration for host reservations.
Holds subnets configured for the DHCPv4 server.
Definition: cfg_subnets4.h:33
isc::util::str::StringSanitizerPtr getHostnameSanitizer() const
Returns a regular expression string sanitizer.
Definition: srv_config.cc:972
boost::shared_ptr< SharedNetwork6 > SharedNetwork6Ptr
Pointer to SharedNetwork6 object.
Convenience container for conveying DDNS behavioral parameters It is intended to be created per Packe...
Definition: srv_config.h:46
Implements a regular expression based string scrubber.
Definition: strutil.h:303
boost::shared_ptr< SharedNetwork4 > SharedNetwork4Ptr
Pointer to SharedNetwork4 object.
DdnsParamsPtr getDdnsParams(const Subnet4Ptr &subnet) const
Fetches the DDNS parameters for a given DHCPv4 subnet.
Definition: srv_config.cc:825
Represents the position of the data element within a configuration string.
Definition: data.h:88
boost::multi_index_container< Subnet6Ptr, boost::multi_index::indexed_by< boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetSubnetIdIndexTag >, boost::multi_index::const_mem_fun< Subnet, SubnetID,&Subnet::getID > >, boost::multi_index::ordered_unique< boost::multi_index::tag< SubnetPrefixIndexTag >, boost::multi_index::const_mem_fun< Subnet, std::string,&Subnet::toText > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< SubnetModificationTimeIndexTag >, boost::multi_index::const_mem_fun< data::BaseStampedElement, boost::posix_time::ptime,&data::BaseStampedElement::getModificationTime > > >> Subnet6Collection
A collection of Subnet6 objects.
Definition: subnet.h:914
utility class for unparsing
Represents configuration of IPv6 shared networks.
Specifies current DHCP configuration.
Definition: srv_config.h:167
Defines the logger used by the top-level component of kea-dhcp-ddns.
void add(std::string libname, isc::data::ConstElementPtr parameters)
Adds additional hooks libraries.
Definition: hooks_config.h:46
CfgSharedNetworks4Ptr getCfgSharedNetworks4() const
Returns pointer to non-const object holding configuration of shared networks in DHCPv4;.
Definition: srv_config.h:320
virtual void merge(ConfigBase &other)
Merges the configuration specified as a parameter into this configuration.
Definition: srv_config.cc:167
std::string getHostnameCharSet() const
Returns the regular expression describing invalid characters for client hostnames.
Definition: srv_config.cc:954
void clearConfiguredGlobals()
Removes all configured global parameters.
Definition: srv_config.cc:325
void merge(ElementPtr element, ConstElementPtr other)
Merges the data from other into element.
Definition: data.cc:1079
const isc::log::MessageID DHCPSRV_CFGMGR_DDNS_PARAMETER_MOVED
const isc::log::MessageID DHCPSRV_CFGMGR_DDNS_PARAMETER_IGNORED
ReplaceClientNameMode
Defines the client name replacement modes.
Definition: d2_client_cfg.h:75
static const uint32_t CFGSEL_SUBNET4
Number of IPv4 subnets.
Definition: srv_config.h:175
bool getOverrideClientUpdate() const
Returns whether or not Kea should perform updates, even if client requested delegation.
Definition: srv_config.cc:918
void setServerTag(const util::Optional< std::string > &server_tag)
Sets the server's logical name.
Definition: config_base.h:127
std::string getConfigSummary(const uint32_t selection) const
Returns summary of the configuration in the textual format.
Definition: srv_config.cc:72
A generic exception that is thrown if a function is called in a prohibited way.
bool sequenceEquals(const SrvConfig &other)
Compares configuration sequence with other sequence.
Definition: srv_config.cc:113
void extractConfiguredGlobals(isc::data::ConstElementPtr config)
Saves scalar elements from the global scope of a configuration.
Definition: srv_config.cc:401
The Element class represents a piece of data, used by the command channel and configuration parts...
Definition: data.h:66
Represents the host reservations specified in the configuration file.
Definition: cfg_hosts.h:37
static const uint32_t CFGSEL_DDNS
DDNS enabled/disabled.
Definition: srv_config.h:183
void setMaxSampleAgeDefault(const StatsDuration &duration)
Set default duration limit.
virtual isc::data::ElementPtr toElement() const
Unparse.
void sanityChecksLifetime(const std::string &name) const
Conducts sanity checks on global lifetime parameters.
Definition: srv_config.cc:416
CfgSharedNetworks6Ptr getCfgSharedNetworks6() const
Returns pointer to non-const object holding configuration of shared networks in DHCPv6.
Definition: srv_config.h:329
std::string getGeneratedPrefix() const
Returns the Prefix Kea should use when generating domain-names.
Definition: srv_config.cc:936
isc::data::ConstElementPtr getConfiguredGlobals() const
Returns pointer to configured global parameters.
Definition: srv_config.h:765
static bool haveInstance()
Indicates if the lease manager has been instantiated.
CfgHostsPtr getCfgHosts()
Returns pointer to the non-const objects representing host reservations for different IPv4 and IPv6 s...
Definition: srv_config.h:361
CfgSubnets4Ptr getCfgSubnets4()
Returns pointer to non-const object holding subnets configuration for DHCPv4.
Definition: srv_config.h:311
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition: dhcpsrv_log.h:56
boost::shared_ptr< Subnet6 > Subnet6Ptr
A pointer to a Subnet6 object.
Definition: subnet.h:670
bool getOverrideNoUpdate() const
Returns whether or not Kea should perform updates, even if client requested no updates.
Definition: srv_config.cc:910
boost::shared_ptr< StringSanitizer > StringSanitizerPtr
Definition: strutil.h:348
bool getUseConflictResolution() const
Returns whether or not keah-dhcp-ddns should use conflict resolution.
Definition: srv_config.cc:1000
virtual void remove(const int i)
Removes the element at the given position.
Definition: data.cc:150
const isc::data::ConstElementPtr getDHCPMultiThreading() const
Returns DHCP multi threading information.
Definition: srv_config.h:500
CfgOptionPtr getCfgOption()
Returns pointer to the non-const object holding options.
Definition: srv_config.h:293
static const uint32_t CFGSEL_SUBNET6
Number of IPv6 subnets.
Definition: srv_config.h:177
void applyDefaultsConfiguredGlobals(const isc::data::SimpleDefaults &defaults)
Applies defaults to global parameters.
Definition: srv_config.cc:330
void setDhcp4o6Port(uint16_t port)
Sets DHCP4o6 IPC port.
Definition: srv_config.h:736
static bool lenient_parsing_
Governs whether options should be parsed less strictly.
Definition: option.h:464
std::string getQualifyingSuffix() const
Returns the suffix Kea should use when to qualify partial domain-names.
Definition: srv_config.cc:945
std::string getHostnameCharReplacement() const
Returns the string to replace invalid characters when scrubbing hostnames.
Definition: srv_config.cc:963
void configureLowerLevelLibraries() const
Convenience method to propagate configuration parameters through inversion of control.
Definition: srv_config.cc:896
Holds manual configuration of the server identifier (DUID).
Definition: cfg_duid.h:30
void setD2ClientConfig(const D2ClientConfigPtr &d2_client_config)
Sets the D2 client configuration.
Definition: srv_config.h:760
virtual isc::data::ElementPtr toElement() const
Unparse.
bool equal(const HooksConfig &other) const
Compares two Hooks Config classes for equality.
Definition: hooks_config.cc:67
uint32_t SubnetID
Unique identifier for a subnet (both v4 and v6)
Definition: lease.h:24
boost::shared_ptr< const ConfigControlInfo > ConstConfigControlInfoPtr
Defines a pointer to a const ConfigControlInfo.