Kea  2.3.5-git
network.cc
Go to the documentation of this file.
1 // Copyright (C) 2017-2023 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 
9 #include <dhcp/dhcp4.h>
10 #include <dhcp/option_custom.h>
11 #include <dhcp/option_space.h>
12 #include <dhcpsrv/network.h>
13 #include <boost/pointer_cast.hpp>
14 
15 using namespace isc::asiolink;
16 using namespace isc::data;
17 using namespace isc::util;
18 
19 namespace isc {
20 namespace dhcp {
21 
22 void
23 Network::RelayInfo::addAddress(const asiolink::IOAddress& addr) {
24  if (containsAddress(addr)) {
25  isc_throw (BadValue, "RelayInfo already contains address: "
26  << addr.toText());
27  }
28 
29  addresses_.push_back(addr);
30 }
31 
32 bool
33 Network::RelayInfo::hasAddresses() const {
34  return (!addresses_.empty());
35 }
36 
37 bool
38 Network::RelayInfo::containsAddress(const asiolink::IOAddress& addr) const {
39  auto const& index = addresses_.get<IOAddressListSetTag>();
40  return (index.find(addr) != index.end());
41 }
42 
43 const IOAddressList&
44 Network::RelayInfo::getAddresses() const {
45  return (addresses_);
46 }
47 
48 void
49 Network::addRelayAddress(const asiolink::IOAddress& addr) {
50  relay_.addAddress(addr);
51 }
52 
53 bool
54 Network::hasRelays() const {
55  return (relay_.hasAddresses());
56 }
57 
58 bool
59 Network::hasRelayAddress(const asiolink::IOAddress& addr) const {
60  return (relay_.containsAddress(addr));
61 }
62 
63 const IOAddressList&
64 Network::getRelayAddresses() const {
65  return (relay_.getAddresses());
66 }
67 
68 bool
69 Network::clientSupported(const isc::dhcp::ClientClasses& classes) const {
70  if (client_class_.empty()) {
71  // There is no class defined for this network, so we do
72  // support everyone.
73  return (true);
74  }
75 
76  return (classes.contains(client_class_));
77 }
78 
79 void
80 Network::allowClientClass(const isc::dhcp::ClientClass& class_name) {
81  client_class_ = class_name;
82 }
83 
84 void
85 Network::requireClientClass(const isc::dhcp::ClientClass& class_name) {
86  if (!required_classes_.contains(class_name)) {
87  required_classes_.insert(class_name);
88  }
89 }
90 
91 const ClientClasses&
92 Network::getRequiredClasses() const {
93  return (required_classes_);
94 }
95 
97 Network::getGlobalProperty(Optional<IOAddress> property,
98  const int global_index,
99  const int /*min_index*/,
100  const int /*max_index*/) const {
101  if ((global_index >= 0) && fetch_globals_fn_) {
102  ConstCfgGlobalsPtr globals = fetch_globals_fn_();
103  if (globals) {
104  ConstElementPtr global_param = globals->get(global_index);
105  if (global_param) {
106  std::string global_str = global_param->stringValue();
107  if (!global_str.empty()) {
108  return (IOAddress(global_str));
109  }
110  }
111  }
112  }
113  return (property);
114 }
115 
117 Network::toElement() const {
118  ElementPtr map = Element::createMap();
119 
120  // Set user-context
121  contextToElement(map);
122 
123  // Set interface
124  if (!iface_name_.unspecified()) {
125  map->set("interface", Element::create(iface_name_.get()));
126  }
127 
128  ElementPtr relay_map = Element::createMap();
129  ElementPtr address_list = Element::createList();
130  const IOAddressList addresses = getRelayAddresses();
131  for (auto address = addresses.begin(); address != addresses.end(); ++address) {
132  address_list->add(Element::create((*address).toText()));
133  }
134 
135  relay_map->set("ip-addresses", address_list);
136  map->set("relay", relay_map);
137 
138  // Set client-class
139  if (!client_class_.unspecified()) {
140  map->set("client-class", Element::create(client_class_.get()));
141  }
142 
143  // Set require-client-classes
144  const ClientClasses& classes = getRequiredClasses();
145  if (!classes.empty()) {
146  ElementPtr class_list = Element::createList();
147  for (ClientClasses::const_iterator it = classes.cbegin();
148  it != classes.cend(); ++it) {
149  class_list->add(Element::create(*it));
150  }
151  map->set("require-client-classes", class_list);
152  }
153 
154  // T1, T2, and Valid are optional for SharedNetworks, and
155  // T1 and T2 are optional for Subnet4 thus we will only
156  // output them if they are marked as specified.
157  if (!t1_.unspecified()) {
158  map->set("renew-timer",
159  Element::create(static_cast<long long>(t1_.get())));
160  }
161 
162  // Set rebind-timer
163  if (!t2_.unspecified()) {
164  map->set("rebind-timer",
165  Element::create(static_cast<long long>(t2_.get())));
166  }
167 
168  // Set valid-lifetime
169  if (!valid_.unspecified()) {
170  map->set("valid-lifetime",
171  Element::create(static_cast<long long>(valid_.get())));
172  map->set("min-valid-lifetime",
173  Element::create(static_cast<long long>(valid_.getMin())));
174  map->set("max-valid-lifetime",
175  Element::create(static_cast<long long>(valid_.getMax())));
176  }
177 
178  // Set reservations-global
179  if (!reservations_global_.unspecified()) {
180  map->set("reservations-global",
181  Element::create(reservations_global_.get()));
182  }
183 
184  // Set reservations-in-subnet
185  if (!reservations_in_subnet_.unspecified()) {
186  map->set("reservations-in-subnet",
187  Element::create(reservations_in_subnet_.get()));
188  }
189 
190  // Set reservations-out-of-pool
191  if (!reservations_out_of_pool_.unspecified()) {
192  map->set("reservations-out-of-pool",
193  Element::create(reservations_out_of_pool_.get()));
194  }
195 
196  // Set options
197  ConstCfgOptionPtr opts = getCfgOption();
198  map->set("option-data", opts->toElement());
199 
200  // Output calculate-tee-times and percentages if calculation is enabled.
201  if (!calculate_tee_times_.unspecified()) {
202  map->set("calculate-tee-times", Element::create(calculate_tee_times_));
203  }
204 
205  if (!t1_percent_.unspecified()) {
206  map->set("t1-percent", Element::create(t1_percent_));
207  }
208 
209  if (!t2_percent_.unspecified()) {
210  map->set("t2-percent", Element::create(t2_percent_));
211  }
212 
213  if (!ddns_send_updates_.unspecified()) {
214  map->set("ddns-send-updates", Element::create(ddns_send_updates_));
215  }
216 
217  if (!ddns_override_no_update_.unspecified()) {
218  map->set("ddns-override-no-update", Element::create(ddns_override_no_update_));
219  }
220 
221  if (!ddns_override_client_update_.unspecified()) {
222  map->set("ddns-override-client-update", Element::create(ddns_override_client_update_));
223  }
224 
225  if (!ddns_replace_client_name_mode_.unspecified()) {
226  map->set("ddns-replace-client-name",
227  Element::create(D2ClientConfig::
228  replaceClientNameModeToString(ddns_replace_client_name_mode_)));
229  }
230 
231  if (!ddns_generated_prefix_.unspecified()) {
232  map->set("ddns-generated-prefix", Element::create(ddns_generated_prefix_));
233  }
234 
235  if (!ddns_qualifying_suffix_.unspecified()) {
236  map->set("ddns-qualifying-suffix", Element::create(ddns_qualifying_suffix_));
237  }
238 
239  if (!hostname_char_set_.unspecified()) {
240  map->set("hostname-char-set", Element::create(hostname_char_set_));
241  }
242 
243  if (!hostname_char_replacement_.unspecified()) {
244  map->set("hostname-char-replacement", Element::create(hostname_char_replacement_));
245  }
246 
247  if (!store_extended_info_.unspecified()) {
248  map->set("store-extended-info", Element::create(store_extended_info_));
249  }
250 
251  if (!cache_threshold_.unspecified()) {
252  map->set("cache-threshold", Element::create(cache_threshold_));
253  }
254 
255  if (!cache_max_age_.unspecified()) {
256  map->set("cache-max-age",
257  Element::create(static_cast<long long>(cache_max_age_)));
258  }
259 
260  if (!ddns_update_on_renew_.unspecified()) {
261  map->set("ddns-update-on-renew", Element::create(ddns_update_on_renew_));
262  }
263 
264  if (!ddns_use_conflict_resolution_.unspecified()) {
265  map->set("ddns-use-conflict-resolution", Element::create(ddns_use_conflict_resolution_));
266  }
267 
268  if (!allocator_type_.unspecified()) {
269  map->set("allocator", Element::create(allocator_type_));
270  }
271 
272  return (map);
273 }
274 
275 void
276 Network4::setSiaddr(const Optional<IOAddress>& siaddr) {
277  if (!siaddr.get().isV4()) {
278  isc_throw(BadValue, "Can't set siaddr to non-IPv4 address "
279  << siaddr);
280  }
281  siaddr_ = siaddr;
282 }
283 
284 void
285 Network4::setSname(const Optional<std::string>& sname) {
286  sname_ = sname;
287 }
288 
289 void
290 Network4::setFilename(const Optional<std::string>& filename) {
291  filename_ = filename;
292 }
293 
295 Network4::toElement() const {
296  ElementPtr map = Network::toElement();
297 
298  // Set match-client-id
299  if (!match_client_id_.unspecified()) {
300  map->set("match-client-id", Element::create(match_client_id_.get()));
301  }
302 
303  // Set authoritative
304  if (!authoritative_.unspecified()) {
305  map->set("authoritative", Element::create(authoritative_.get()));
306  }
307 
308  // Set next-server
309  if (!siaddr_.unspecified()) {
310  map->set("next-server", Element::create(siaddr_.get().toText()));
311  }
312 
313  // Set server-hostname
314  if (!sname_.unspecified()) {
315  map->set("server-hostname", Element::create(sname_.get()));
316  }
317 
318  // Set boot-file-name
319  if (!filename_.unspecified()) {
320  map->set("boot-file-name",Element::create(filename_.get()));
321  }
322 
323  return (map);
324 }
325 
326 IOAddress
327 Network4::getServerId() const {
328  try {
329  OptionCustomPtr opt_server_id = boost::dynamic_pointer_cast<OptionCustom>
330  (cfg_option_->get(DHCP4_OPTION_SPACE, DHO_DHCP_SERVER_IDENTIFIER).option_);
331  if (opt_server_id) {
332  return (opt_server_id->readAddress());
333  }
334  } catch (const std::exception&) {
335  // Ignore any exceptions and simply return empty buffer.
336  }
337 
338  return (IOAddress::IPV4_ZERO_ADDRESS());
339 }
340 
342 Network6::toElement() const {
343  ElementPtr map = Network::toElement();
344 
345  // Set preferred-lifetime
346  if (!preferred_.unspecified()) {
347  map->set("preferred-lifetime",
348  Element::create(static_cast<long long>(preferred_.get())));
349  map->set("min-preferred-lifetime",
350  Element::create(static_cast<long long>(preferred_.getMin())));
351  map->set("max-preferred-lifetime",
352  Element::create(static_cast<long long>(preferred_.getMax())));
353  }
354 
355  // Set interface-id
356  if (interface_id_) {
357  std::vector<uint8_t> bin = interface_id_->getData();
358  std::string ifid;
359  ifid.resize(bin.size());
360  if (!bin.empty()) {
361  std::memcpy(&ifid[0], &bin[0], bin.size());
362  }
363  map->set("interface-id", Element::create(ifid));
364  }
365 
366  // Set rapid-commit
367  if (!rapid_commit_.unspecified()) {
368  map->set("rapid-commit", Element::create(rapid_commit_.get()));
369  }
370 
371  // Set pd-allocator
372  if (!pd_allocator_type_.unspecified()) {
373  map->set("pd-allocator", Element::create(pd_allocator_type_));
374  }
375 
376  return (map);
377 }
378 
379 } // end of namespace isc::dhcp
380 } // end of namespace isc
boost::shared_ptr< OptionCustom > OptionCustomPtr
A pointer to the OptionCustom object.
bool contains(const ClientClass &x) const
returns if class x belongs to the defined classes
Definition: classify.cc:49
boost::shared_ptr< const CfgOption > ConstCfgOptionPtr
Const pointer.
Definition: cfg_option.h:748
boost::shared_ptr< const CfgGlobals > ConstCfgGlobalsPtr
Const shared pointer to a CfgGlobals instance.
Definition: cfg_globals.h:161
T get() const
Retrieves the encapsulated value.
Definition: optional.h:114
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
const_iterator cbegin() const
Iterators to the first element.
Definition: classify.h:152
#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...
ClientClassContainer::const_iterator const_iterator
Type of iterators.
Definition: classify.h:112
Definition: edns.h:19
Acts as a storage vault for D2 client configuration.
Definition: d2_client_cfg.h:57
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
bool empty() const
Check if classes is empty.
Definition: classify.h:138
boost::multi_index_container< asiolink::IOAddress, boost::multi_index::indexed_by< boost::multi_index::sequenced< boost::multi_index::tag< IOAddressListListTag > >, boost::multi_index::hashed_unique< boost::multi_index::tag< IOAddressListSetTag >, boost::multi_index::identity< asiolink::IOAddress > > >> IOAddressList
List of IO addresses.
Definition: network.h:67
Defines the logger used by the top-level component of kea-lfc.
#define DHCP4_OPTION_SPACE
global std option spaces
Tag for the list of IO addresses as a set.
Definition: network.h:49
const_iterator cend() const
Iterators to the past the end element.
Definition: classify.h:165
std::string ClientClass
Defines a single class name.
Definition: classify.h:42
Option with defined data fields represented as buffers that can be accessed using data field index...
Definition: option_custom.h:32
A template representing an optional value.
Definition: optional.h:36
Container for storing client class names.
Definition: classify.h:108