Kea 2.2.0
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
10#include <cc/data.h>
11#include <dhcpsrv/cfgmgr.h>
12#include <dhcpsrv/cfg_option.h>
18#include <boost/make_shared.hpp>
19#include <boost/pointer_cast.hpp>
20#include <string>
21
22using namespace isc::asiolink;
23using namespace isc::data;
24using namespace isc::util;
25
26namespace isc {
27namespace dhcp {
28
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) {
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
218boost::shared_ptr<OptionDataListParser>
220 auto parser = boost::make_shared<OptionDataListParser>(AF_INET);
221 return (parser);
222}
223
224boost::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
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) {
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
395boost::shared_ptr<OptionDataListParser>
397 auto parser = boost::make_shared<OptionDataListParser>(AF_INET6);
398 return (parser);
399}
400
401boost::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
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
static void checkKeywords(const SimpleKeywords &keywords, isc::data::ConstElementPtr scope)
Checks acceptable keywords with their expected type.
static std::string getString(isc::data::ConstElementPtr scope, const std::string &name)
Returns a string parameter from a scope.
const isc::util::Triplet< uint32_t > parseIntTriplet(const data::ConstElementPtr &scope, const std::string &name)
Parses an integer triplet.
static bool getBoolean(isc::data::ConstElementPtr scope, const std::string &name)
Returns a boolean parameter from a scope.
void parseCacheParams(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses parameters related to lease cache settings.
void parseDdnsParams(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses parameters pertaining to DDNS behavior.
void parseCommon(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses common parameters.
static void moveReservationMode(isc::data::ElementPtr config)
Moves deprecated reservation-mode parameter to new reservations flags.
void parseTeePercents(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses parameters related to "percent" timers settings.
static CfgMgr & instance()
returns a single instance of Configuration Manager
Definition: cfgmgr.cc:25
To be removed. Please use ConfigError instead.
static IfaceMgr & instance()
IfaceMgr is a singleton class.
Definition: iface_mgr.cc:53
Holds optional information about relay.
Definition: network.h:133
boost::shared_ptr< Network::RelayInfo > RelayInfoPtr
Pointer to the RelayInfo structure.
Definition: network.h:181
static const size_t MAX_SNAME_LEN
length of the SNAME field in DHCPv4 message
Definition: pkt4.h:44
static const size_t MAX_FILE_LEN
length of the FILE field in DHCPv4 message
Definition: pkt4.h:47
parser for additional relay information
Definition: dhcp_parsers.h:440
void parse(const isc::dhcp::Network::RelayInfoPtr &relay_info, isc::data::ConstElementPtr relay_elem)
parses the actual relay parameters
virtual boost::shared_ptr< Subnets4ListConfigParser > createSubnetsListParser() const
Returns an instance of the Subnets4ListConfigParser to be used for parsing the subnets within the sha...
SharedNetwork4Parser(bool check_iface=true)
Constructor.
virtual boost::shared_ptr< OptionDataListParser > createOptionDataListParser() const
Returns an instance of the OptionDataListParser to be used in parsing the option-data structure.
SharedNetwork4Ptr parse(const data::ConstElementPtr &shared_network_data)
Parses shared configuration information for IPv4 shared network.
bool check_iface_
Check if the specified interface exists in the system.
Shared network holding IPv4 subnets.
SharedNetwork6Parser(bool check_iface=true)
Constructor.
virtual boost::shared_ptr< Subnets6ListConfigParser > createSubnetsListParser() const
Returns an instance of the Subnets6ListConfigParser to be used for parsing the subnets within the sha...
SharedNetwork6Ptr parse(const data::ConstElementPtr &shared_network_data)
Parses shared configuration information for IPv6 shared network.
bool check_iface_
Check if the specified interface exists in the system.
virtual boost::shared_ptr< OptionDataListParser > createOptionDataListParser() const
Returns an instance of the OptionDataListParser to be used in parsing the option-data structure.
Shared network holding IPv6 subnets.
static const isc::data::SimpleKeywords SHARED_NETWORK4_PARAMETERS
This table defines all shared network parameters for DHCPv4.
static const isc::data::SimpleKeywords SHARED_NETWORK6_PARAMETERS
This table defines all shared network parameters for DHCPv6.
T get() const
Retrieves the encapsulated value.
Definition: optional.h:114
bool empty() const
Checks if the encapsulated value is empty.
Definition: optional.h:153
void unspecified(bool unspecified)
Modifies the flag that indicates whether the value is specified or unspecified.
Definition: optional.h:136
@ D6O_INTERFACE_ID
Definition: dhcp6.h:38
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:27
boost::shared_ptr< Element > ElementPtr
Definition: data.h:24
@ error
Definition: db_log.h:115
boost::shared_ptr< const CfgGlobals > ConstCfgGlobalsPtr
Const shared pointer to a CfgGlobals instance.
Definition: cfg_globals.h:159
boost::shared_ptr< CfgOption > CfgOptionPtr
Non-const pointer.
Definition: cfg_option.h:706
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:964
boost::shared_ptr< SharedNetwork6 > SharedNetwork6Ptr
Pointer to SharedNetwork6 object.
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:893
boost::shared_ptr< Network > NetworkPtr
Pointer to the Network object.
Definition: network.h:41
std::vector< uint8_t > OptionBuffer
buffer types used in DHCP code.
Definition: option.h:24
boost::shared_ptr< SharedNetwork4 > SharedNetwork4Ptr
Pointer to SharedNetwork4 object.
boost::shared_ptr< Option > OptionPtr
Definition: option.h:36
Definition: edns.h:19
Defines the logger used by the top-level component of kea-lfc.