Kea  2.1.6-git
shared_network_parser.cc
Go to the documentation of this file.
1 // Copyright (C) 2017-2022 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 <asiolink/io_address.h>
10 #include <cc/data.h>
11 #include <dhcpsrv/cfgmgr.h>
12 #include <dhcpsrv/cfg_option.h>
17 #include <dhcpsrv/shared_network.h>
18 #include <boost/make_shared.hpp>
19 #include <boost/pointer_cast.hpp>
20 #include <string>
21 
22 using namespace isc::asiolink;
23 using namespace isc::data;
24 using namespace isc::util;
25 
26 namespace isc {
27 namespace dhcp {
28 
29 SharedNetwork4Parser::SharedNetwork4Parser(bool check_iface)
30  : check_iface_(check_iface) {
31 }
32 
35  SharedNetwork4Ptr shared_network;
36  try {
37 
38  // Check parameters.
40  shared_network_data);
41 
42  // Make sure that the network name has been specified. The name is required
43  // to create a SharedNetwork4 object.
44  std::string name = getString(shared_network_data, "name");
45  shared_network.reset(new SharedNetwork4(name));
46 
47  // Move from reservation mode to new reservations flags.
48  ElementPtr mutable_params;
49  mutable_params = boost::const_pointer_cast<Element>(shared_network_data);
51 
52  // Parse parameters common to all Network derivations.
53  NetworkPtr network = boost::dynamic_pointer_cast<Network>(shared_network);
54  parseCommon(mutable_params, network);
55 
56  // interface is an optional parameter
57  if (shared_network_data->contains("interface")) {
58  std::string iface = getString(shared_network_data, "interface");
59  if (!iface.empty()) {
60  if (check_iface_ && !IfaceMgr::instance().getIface(iface)) {
62  shared_network_data->get("interface");
64  "Specified network interface name " << iface
65  << " for shared network " << name
66  << " is not present in the system ("
67  << error->getPosition() << ")");
68  }
69  shared_network->setIface(iface);
70  }
71  }
72 
73  if (shared_network_data->contains("option-data")) {
74  auto json = shared_network_data->get("option-data");
75  // Create parser instance for option-data.
76  CfgOptionPtr cfg_option = shared_network->getCfgOption();
77  auto parser = createOptionDataListParser();
78  parser->parse(cfg_option, json);
79  }
80 
81  if (shared_network_data->contains("subnet4")) {
82  auto json = shared_network_data->get("subnet4");
83 
84  // Create parser instance of subnet4.
85  auto parser = createSubnetsListParser();
86  Subnet4Collection subnets;
87  parser->parse(subnets, json);
88 
89  // Add all returned subnets into shared network.
90  for (auto subnet = subnets.cbegin(); subnet != subnets.cend();
91  ++subnet) {
92  shared_network->add(*subnet);
93  }
94  }
95 
96  if (shared_network_data->contains("match-client-id")) {
97  shared_network->setMatchClientId(getBoolean(shared_network_data,
98  "match-client-id"));
99  }
100 
101  if (shared_network_data->contains("authoritative")) {
102  shared_network->setAuthoritative(getBoolean(shared_network_data,
103  "authoritative"));
104  }
105 
106  // Set next-server
107  if (shared_network_data->contains("next-server")) {
108  std::string next_server;
109  try {
110  next_server = getString(shared_network_data, "next-server");
111  if (!next_server.empty()) {
112  shared_network->setSiaddr(IOAddress(next_server));
113  }
114  } catch (...) {
115  ConstElementPtr next = shared_network_data->get("next-server");
116  std::string pos;
117  if (next) {
118  pos = next->getPosition().str();
119  } else {
120  pos = shared_network_data->getPosition().str();
121  }
122  isc_throw(DhcpConfigError, "invalid parameter next-server : "
123  << next_server << "(" << pos << ")");
124  }
125  }
126 
127  // Set server-hostname.
128  if (shared_network_data->contains("server-hostname")) {
129  std::string sname = getString(shared_network_data, "server-hostname");
130  if (!sname.empty()) {
131  if (sname.length() >= Pkt4::MAX_SNAME_LEN) {
132  ConstElementPtr error = shared_network_data->get("server-hostname");
133  isc_throw(DhcpConfigError, "server-hostname must be at most "
134  << Pkt4::MAX_SNAME_LEN - 1 << " bytes long, it is "
135  << sname.length() << " ("
136  << error->getPosition() << ")");
137  }
138  shared_network->setSname(sname);
139  }
140  }
141 
142  // Set boot-file-name.
143  if (shared_network_data->contains("boot-file-name")) {
144  std::string filename = getString(shared_network_data, "boot-file-name");
145  if (!filename.empty()) {
146  if (filename.length() > Pkt4::MAX_FILE_LEN) {
147  ConstElementPtr error = shared_network_data->get("boot-file-name");
148  isc_throw(DhcpConfigError, "boot-file-name must be at most "
149  << Pkt4::MAX_FILE_LEN - 1 << " bytes long, it is "
150  << filename.length() << " ("
151  << error->getPosition() << ")");
152  }
153  shared_network->setFilename(filename);
154  }
155  }
156 
157  if (shared_network_data->contains("client-class")) {
158  std::string client_class = getString(shared_network_data, "client-class");
159  if (!client_class.empty()) {
160  shared_network->allowClientClass(client_class);
161  }
162  }
163 
164  ConstElementPtr user_context = shared_network_data->get("user-context");
165  if (user_context) {
166  shared_network->setContext(user_context);
167  }
168 
169  if (shared_network_data->contains("require-client-classes")) {
170  const std::vector<data::ElementPtr>& class_list =
171  shared_network_data->get("require-client-classes")->listValue();
172  for (auto cclass = class_list.cbegin();
173  cclass != class_list.cend(); ++cclass) {
174  if (((*cclass)->getType() != Element::string) ||
175  (*cclass)->stringValue().empty()) {
176  isc_throw(DhcpConfigError, "invalid class name ("
177  << (*cclass)->getPosition() << ")");
178  }
179  shared_network->requireClientClass((*cclass)->stringValue());
180  }
181  }
182 
183  if (shared_network_data->contains("relay")) {
184  auto relay_parms = shared_network_data->get("relay");
185  if (relay_parms) {
186  RelayInfoParser parser(Option::V4);
187  Network::RelayInfoPtr relay_info(new Network::RelayInfo());
188  parser.parse(relay_info, relay_parms);
189  shared_network->setRelayInfo(*relay_info);
190  }
191  }
192 
193  parseTeePercents(shared_network_data, network);
194 
195  // Parse DDNS parameters
196  parseDdnsParams(shared_network_data, network);
197 
198  // Parse lease cache parameters
199  parseCacheParams(shared_network_data, network);
200  } catch (const DhcpConfigError&) {
201  // Position was already added
202  throw;
203  } catch (const std::exception& ex) {
204  isc_throw(DhcpConfigError, ex.what() << " ("
205  << shared_network_data->getPosition() << ")");
206  }
207 
208  // In order to take advantage of the dynamic inheritance of global
209  // parameters to a shared network we need to set a callback function
210  // for each shared network to allow for fetching global parameters.
211  shared_network->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr {
212  return (CfgMgr::instance().getCurrentCfg()->getConfiguredGlobals());
213  });
214 
215  return (shared_network);
216 }
217 
218 boost::shared_ptr<OptionDataListParser>
220  auto parser = boost::make_shared<OptionDataListParser>(AF_INET);
221  return (parser);
222 }
223 
224 boost::shared_ptr<Subnets4ListConfigParser>
226  auto parser = boost::make_shared<Subnets4ListConfigParser>(check_iface_);
227  return (parser);
228 }
229 
231  : check_iface_(check_iface) {
232 }
233 
236  SharedNetwork6Ptr shared_network;
237  std::string name;
238  try {
239  // Check parameters.
241  shared_network_data);
242 
243  // Make sure that the network name has been specified. The name is required
244  // to create a SharedNetwork6 object.
245  std::string name = getString(shared_network_data, "name");
246  shared_network.reset(new SharedNetwork6(name));
247 
248  // Move from reservation mode to new reservations flags.
249  ElementPtr mutable_params;
250  mutable_params = boost::const_pointer_cast<Element>(shared_network_data);
252 
253  // Parse parameters common to all Network derivations.
254  NetworkPtr network = boost::dynamic_pointer_cast<Network>(shared_network);
255  parseCommon(mutable_params, network);
256 
257  // preferred-lifetime
258  shared_network->setPreferred(parseIntTriplet(shared_network_data,
259  "preferred-lifetime"));
260 
261  // Get interface-id option content. For now we support string
262  // representation only
263  Optional<std::string> ifaceid;
264  if (shared_network_data->contains("interface-id")) {
265  ifaceid = getString(shared_network_data, "interface-id");
266  }
267 
268  // Interface is an optional parameter
269  Optional<std::string> iface;
270  if (shared_network_data->contains("interface")) {
271  iface = getString(shared_network_data, "interface");
272  }
273 
274  // Specifying both interface for locally reachable subnets and
275  // interface id for relays is mutually exclusive. Need to test for
276  // this condition.
277  if (!ifaceid.unspecified() && !iface.unspecified() && !ifaceid.empty() &&
278  !iface.empty()) {
280  "parser error: interface (defined for locally reachable "
281  "subnets) and interface-id (defined for subnets reachable"
282  " via relays) cannot be defined at the same time for "
283  "shared network " << name << "("
284  << shared_network_data->getPosition() << ")");
285  }
286 
287  // Configure interface-id for remote interfaces, if defined
288  if (!ifaceid.unspecified() && !ifaceid.empty()) {
289  std::string ifaceid_value = ifaceid.get();
290  OptionBuffer tmp(ifaceid_value.begin(), ifaceid_value.end());
292  shared_network->setInterfaceId(opt);
293  }
294 
295  // Set interface name. If it is defined, then subnets are available
296  // directly over specified network interface.
297  if (!iface.unspecified() && !iface.empty()) {
298  if (check_iface_ && !IfaceMgr::instance().getIface(iface)) {
299  ConstElementPtr error = shared_network_data->get("interface");
301  "Specified network interface name " << iface
302  << " for shared network " << name
303  << " is not present in the system ("
304  << error->getPosition() << ")");
305  }
306  shared_network->setIface(iface);
307  }
308 
309  if (shared_network_data->contains("rapid-commit")) {
310  shared_network->setRapidCommit(getBoolean(shared_network_data,
311  "rapid-commit"));
312  }
313 
314  if (shared_network_data->contains("option-data")) {
315  auto json = shared_network_data->get("option-data");
316  // Create parser instance for option-data.
317  CfgOptionPtr cfg_option = shared_network->getCfgOption();
318  auto parser = createOptionDataListParser();
319  parser->parse(cfg_option, json);
320  }
321 
322  if (shared_network_data->contains("client-class")) {
323  std::string client_class = getString(shared_network_data, "client-class");
324  if (!client_class.empty()) {
325  shared_network->allowClientClass(client_class);
326  }
327  }
328 
329  ConstElementPtr user_context = shared_network_data->get("user-context");
330  if (user_context) {
331  shared_network->setContext(user_context);
332  }
333 
334  if (shared_network_data->contains("require-client-classes")) {
335  const std::vector<data::ElementPtr>& class_list =
336  shared_network_data->get("require-client-classes")->listValue();
337  for (auto cclass = class_list.cbegin();
338  cclass != class_list.cend(); ++cclass) {
339  if (((*cclass)->getType() != Element::string) ||
340  (*cclass)->stringValue().empty()) {
341  isc_throw(DhcpConfigError, "invalid class name ("
342  << (*cclass)->getPosition() << ")");
343  }
344  shared_network->requireClientClass((*cclass)->stringValue());
345  }
346  }
347 
348  if (shared_network_data->contains("subnet6")) {
349  auto json = shared_network_data->get("subnet6");
350 
351  // Create parser instance of subnet6.
352  auto parser = createSubnetsListParser();
353  Subnet6Collection subnets;
354  parser->parse(subnets, json);
355 
356  // Add all returned subnets into shared network.
357  for (auto subnet = subnets.cbegin(); subnet != subnets.cend();
358  ++subnet) {
359  shared_network->add(*subnet);
360  }
361  }
362 
363  if (shared_network_data->contains("relay")) {
364  auto relay_parms = shared_network_data->get("relay");
365  if (relay_parms) {
366  RelayInfoParser parser(Option::V6);
367  Network::RelayInfoPtr relay_info(new Network::RelayInfo());
368  parser.parse(relay_info, relay_parms);
369  shared_network->setRelayInfo(*relay_info);
370  }
371  }
372 
373  parseTeePercents(shared_network_data, network);
374 
375  // Parse DDNS parameters
376  parseDdnsParams(shared_network_data, network);
377 
378  // Parse lease cache parameters
379  parseCacheParams(shared_network_data, network);
380  } catch (const std::exception& ex) {
381  isc_throw(DhcpConfigError, ex.what() << " ("
382  << shared_network_data->getPosition() << ")");
383  }
384 
385  // In order to take advantage of the dynamic inheritance of global
386  // parameters to a shared network we need to set a callback function
387  // for each shared network which can be used to fetch global parameters.
388  shared_network->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr {
389  return (CfgMgr::instance().getCurrentCfg()->getConfiguredGlobals());
390  });
391 
392  return (shared_network);
393 }
394 
395 boost::shared_ptr<OptionDataListParser>
397  auto parser = boost::make_shared<OptionDataListParser>(AF_INET6);
398  return (parser);
399 }
400 
401 boost::shared_ptr<Subnets6ListConfigParser>
403  auto parser = boost::make_shared<Subnets6ListConfigParser>(check_iface_);
404  return (parser);
405 }
406 
407 } // end of namespace isc::dhcp
408 } // end of namespace isc
void parseDdnsParams(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses parameters pertaining to DDNS behavior.
static const size_t MAX_SNAME_LEN
length of the SNAME field in DHCPv4 message
Definition: pkt4.h:44
IfacePtr getIface(int ifindex)
Returns interface specified interface index.
Definition: iface_mgr.cc:894
static bool getBoolean(isc::data::ConstElementPtr scope, const std::string &name)
Returns a boolean parameter from a scope.
void unspecified(bool unspecified)
Modifies the flag that indicates whether the value is specified or unspecified.
Definition: optional.h:136
boost::shared_ptr< CfgOption > CfgOptionPtr
Non-const pointer.
Definition: cfg_option.h:706
bool check_iface_
Check if the specified interface exists in the system.
boost::shared_ptr< Network > NetworkPtr
Pointer to the Network object.
Definition: network.h:41
static const isc::data::SimpleKeywords SHARED_NETWORK6_PARAMETERS
This table defines all shared network parameters for DHCPv6.
boost::shared_ptr< Network::RelayInfo > RelayInfoPtr
Pointer to the RelayInfo structure.
Definition: network.h:181
void parseCommon(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses common parameters.
static const size_t MAX_FILE_LEN
length of the FILE field in DHCPv4 message
Definition: pkt4.h:47
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
static const isc::data::SimpleKeywords SHARED_NETWORK4_PARAMETERS
This table defines all shared network parameters for DHCPv4.
boost::shared_ptr< Option > OptionPtr
Definition: option.h:36
virtual boost::shared_ptr< OptionDataListParser > createOptionDataListParser() const
Returns an instance of the OptionDataListParser to be used in parsing the option-data structure...
boost::shared_ptr< const CfgGlobals > ConstCfgGlobalsPtr
Const shared pointer to a CfgGlobals instance.
Definition: cfg_globals.h:159
T get() const
Retrieves the encapsulated value.
Definition: optional.h:114
void parseCacheParams(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses parameters related to lease cache settings.
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
bool check_iface_
Check if the specified interface exists in the system.
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:24
Shared network holding IPv4 subnets.
Holds optional information about relay.
Definition: network.h:133
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
SharedNetwork6Ptr parse(const data::ConstElementPtr &shared_network_data)
Parses shared configuration information for IPv6 shared network.
Definition: edns.h:19
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:890
parser for additional relay information
Definition: dhcp_parsers.h:440
To be removed. Please use ConfigError instead.
void parseTeePercents(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses parameters related to "percent" timers settings.
Common interface representing a network to which the DHCP clients are connected.
Definition: network.h:123
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:27
static std::string getString(isc::data::ConstElementPtr scope, const std::string &name)
Returns a string parameter from a scope.
boost::shared_ptr< SharedNetwork6 > SharedNetwork6Ptr
Pointer to SharedNetwork6 object.
virtual boost::shared_ptr< Subnets4ListConfigParser > createSubnetsListParser() const
Returns an instance of the Subnets4ListConfigParser to be used for parsing the subnets within the sha...
boost::shared_ptr< SharedNetwork4 > SharedNetwork4Ptr
Pointer to SharedNetwork4 object.
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:961
virtual boost::shared_ptr< OptionDataListParser > createOptionDataListParser() const
Returns an instance of the OptionDataListParser to be used in parsing the option-data structure...
Defines the logger used by the top-level component of kea-lfc.
SharedNetwork6Parser(bool check_iface=true)
Constructor.
void parse(const isc::dhcp::Network::RelayInfoPtr &relay_info, isc::data::ConstElementPtr relay_elem)
parses the actual relay parameters
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition: iface_mgr.cc:53
static void checkKeywords(const SimpleKeywords &keywords, isc::data::ConstElementPtr scope)
Checks acceptable keywords with their expected type.
The Element class represents a piece of data, used by the command channel and configuration parts...
Definition: data.h:70
Shared network holding IPv6 subnets.
const isc::util::Triplet< uint32_t > parseIntTriplet(const data::ConstElementPtr &scope, const std::string &name)
Parses an integer triplet.
virtual boost::shared_ptr< Subnets6ListConfigParser > createSubnetsListParser() const
Returns an instance of the Subnets6ListConfigParser to be used for parsing the subnets within the sha...
bool empty() const
Checks if the encapsulated value is empty.
Definition: optional.h:153
SharedNetwork4Ptr parse(const data::ConstElementPtr &shared_network_data)
Parses shared configuration information for IPv4 shared network.