Kea 2.7.1
shared_network_parser.cc
Go to the documentation of this file.
1// Copyright (C) 2017-2024 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 bool encapsulate_options) {
36 SharedNetwork4Ptr shared_network;
37 try {
38
39 // Check parameters.
41 shared_network_data);
42
43 // Make sure that the network name has been specified. The name is required
44 // to create a SharedNetwork4 object.
45 std::string name = getString(shared_network_data, "name");
46 shared_network.reset(new SharedNetwork4(name));
47
48 ElementPtr mutable_params;
49 mutable_params = boost::const_pointer_cast<Element>(shared_network_data);
50
51 // Parse parameters common to all Network derivations.
52 NetworkPtr network = boost::dynamic_pointer_cast<Network>(shared_network);
53 parseCommon(mutable_params, network);
54
55 // interface is an optional parameter
56 if (shared_network_data->contains("interface")) {
57 std::string iface = getString(shared_network_data, "interface");
58 if (!iface.empty()) {
59 if (check_iface_ && !IfaceMgr::instance().getIface(iface)) {
61 shared_network_data->get("interface");
63 "Specified network interface name " << iface
64 << " for shared network " << name
65 << " is not present in the system ("
66 << error->getPosition() << ")");
67 }
68 shared_network->setIface(iface);
69 }
70 }
71
72 if (shared_network_data->contains("option-data")) {
73 auto json = shared_network_data->get("option-data");
74 // Create parser instance for option-data.
75 CfgOptionPtr cfg_option = shared_network->getCfgOption();
76 auto parser = createOptionDataListParser();
77 parser->parse(cfg_option, json, encapsulate_options);
78 }
79
80 if (shared_network_data->contains("subnet4")) {
81 auto json = shared_network_data->get("subnet4");
82
83 // Create parser instance of subnet4.
84 auto parser = createSubnetsListParser();
85 Subnet4Collection subnets;
86 parser->parse(subnets, json);
87
88 // Add all returned subnets into shared network.
89 for (auto const& subnet : subnets) {
90 shared_network->add(subnet);
91 }
92 }
93
94 if (shared_network_data->contains("match-client-id")) {
95 shared_network->setMatchClientId(getBoolean(shared_network_data,
96 "match-client-id"));
97 }
98
99 if (shared_network_data->contains("authoritative")) {
100 shared_network->setAuthoritative(getBoolean(shared_network_data,
101 "authoritative"));
102 }
103
104 // Set next-server
105 if (shared_network_data->contains("next-server")) {
106 std::string next_server;
107 try {
108 next_server = getString(shared_network_data, "next-server");
109 if (!next_server.empty()) {
110 shared_network->setSiaddr(IOAddress(next_server));
111 }
112 } catch (...) {
113 ConstElementPtr next = shared_network_data->get("next-server");
114 std::string pos;
115 if (next) {
116 pos = next->getPosition().str();
117 } else {
118 pos = shared_network_data->getPosition().str();
119 }
120 isc_throw(DhcpConfigError, "invalid parameter next-server : "
121 << next_server << "(" << pos << ")");
122 }
123 }
124
125 // Set server-hostname.
126 if (shared_network_data->contains("server-hostname")) {
127 std::string sname = getString(shared_network_data, "server-hostname");
128 if (!sname.empty()) {
129 if (sname.length() >= Pkt4::MAX_SNAME_LEN) {
130 ConstElementPtr error = shared_network_data->get("server-hostname");
131 isc_throw(DhcpConfigError, "server-hostname must be at most "
132 << Pkt4::MAX_SNAME_LEN - 1 << " bytes long, it is "
133 << sname.length() << " ("
134 << error->getPosition() << ")");
135 }
136 shared_network->setSname(sname);
137 }
138 }
139
140 // Set boot-file-name.
141 if (shared_network_data->contains("boot-file-name")) {
142 std::string filename = getString(shared_network_data, "boot-file-name");
143 if (!filename.empty()) {
144 if (filename.length() > Pkt4::MAX_FILE_LEN) {
145 ConstElementPtr error = shared_network_data->get("boot-file-name");
146 isc_throw(DhcpConfigError, "boot-file-name must be at most "
147 << Pkt4::MAX_FILE_LEN - 1 << " bytes long, it is "
148 << filename.length() << " ("
149 << error->getPosition() << ")");
150 }
151 shared_network->setFilename(filename);
152 }
153 }
154
155 if (shared_network_data->contains("client-class")) {
156 std::string client_class = getString(shared_network_data, "client-class");
157 if (!client_class.empty()) {
158 shared_network->allowClientClass(client_class);
159 }
160 }
161
162 ConstElementPtr user_context = shared_network_data->get("user-context");
163 if (user_context) {
164 shared_network->setContext(user_context);
165 }
166
167 if (shared_network_data->contains("require-client-classes")) {
168 const std::vector<data::ElementPtr>& class_list =
169 shared_network_data->get("require-client-classes")->listValue();
170 for (auto const& cclass : class_list) {
171 if ((cclass->getType() != Element::string) ||
172 cclass->stringValue().empty()) {
173 isc_throw(DhcpConfigError, "invalid class name ("
174 << cclass->getPosition() << ")");
175 }
176 shared_network->requireClientClass(cclass->stringValue());
177 }
178 }
179
180 if (shared_network_data->contains("relay")) {
181 auto relay_parms = shared_network_data->get("relay");
182 if (relay_parms) {
185 parser.parse(relay_info, relay_parms);
186 shared_network->setRelayInfo(*relay_info);
187 }
188 }
189
190 parseTeePercents(shared_network_data, network);
191
192 // Parse DDNS parameters
193 parseDdnsParams(shared_network_data, network);
194
195 // Parse lease cache parameters
196 parseCacheParams(shared_network_data, network);
197
198 // Parse allocator params.
199 parseAllocatorParams(shared_network_data, network);
200
201 // Parse offer-lifetime parameter.
202 Network4Ptr network4 = boost::dynamic_pointer_cast<Network4>(shared_network);
203 parseOfferLft(shared_network_data, network4);
204
205 } catch (const DhcpConfigError&) {
206 // Position was already added
207 throw;
208 } catch (const std::exception& ex) {
209 isc_throw(DhcpConfigError, ex.what() << " ("
210 << shared_network_data->getPosition() << ")");
211 }
212
213 // In order to take advantage of the dynamic inheritance of global
214 // parameters to a shared network we need to set a callback function
215 // for each shared network to allow for fetching global parameters.
216 shared_network->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr {
217 return (CfgMgr::instance().getCurrentCfg()->getConfiguredGlobals());
218 });
219
220 return (shared_network);
221}
222
223boost::shared_ptr<OptionDataListParser>
225 auto parser = boost::make_shared<OptionDataListParser>(AF_INET);
226 return (parser);
227}
228
229boost::shared_ptr<Subnets4ListConfigParser>
231 auto parser = boost::make_shared<Subnets4ListConfigParser>(check_iface_);
232 return (parser);
233}
234
236 : check_iface_(check_iface) {
237}
238
241 bool encapsulate_options) {
242 SharedNetwork6Ptr shared_network;
243 std::string name;
244 try {
245 // Check parameters.
247 shared_network_data);
248
249 // Make sure that the network name has been specified. The name is required
250 // to create a SharedNetwork6 object.
251 name = getString(shared_network_data, "name");
252 shared_network.reset(new SharedNetwork6(name));
253
254 ElementPtr mutable_params;
255 mutable_params = boost::const_pointer_cast<Element>(shared_network_data);
256
257 // Parse parameters common to all Network derivations.
258 NetworkPtr network = boost::dynamic_pointer_cast<Network>(shared_network);
259 parseCommon(mutable_params, network);
260
261 // preferred-lifetime
262 shared_network->setPreferred(parseIntTriplet(shared_network_data,
263 "preferred-lifetime"));
264
265 // Get interface-id option content. For now we support string
266 // representation only
267 Optional<std::string> ifaceid;
268 if (shared_network_data->contains("interface-id")) {
269 ifaceid = getString(shared_network_data, "interface-id");
270 }
271
272 // Interface is an optional parameter
273 Optional<std::string> iface;
274 if (shared_network_data->contains("interface")) {
275 iface = getString(shared_network_data, "interface");
276 }
277
278 // Specifying both interface for locally reachable subnets and
279 // interface id for relays is mutually exclusive. Need to test for
280 // this condition.
281 if (!ifaceid.unspecified() && !iface.unspecified() && !ifaceid.empty() &&
282 !iface.empty()) {
284 "parser error: interface (defined for locally reachable "
285 "subnets) and interface-id (defined for subnets reachable"
286 " via relays) cannot be defined at the same time for "
287 "shared network " << name << "("
288 << shared_network_data->getPosition() << ")");
289 }
290
291 // Configure interface-id for remote interfaces, if defined
292 if (!ifaceid.unspecified() && !ifaceid.empty()) {
293 std::string ifaceid_value = ifaceid.get();
294 OptionBuffer tmp(ifaceid_value.begin(), ifaceid_value.end());
296 shared_network->setInterfaceId(opt);
297 }
298
299 // Set interface name. If it is defined, then subnets are available
300 // directly over specified network interface.
301 if (!iface.unspecified() && !iface.empty()) {
302 if (check_iface_ && !IfaceMgr::instance().getIface(iface)) {
303 ConstElementPtr error = shared_network_data->get("interface");
305 "Specified network interface name " << iface
306 << " for shared network " << name
307 << " is not present in the system ("
308 << error->getPosition() << ")");
309 }
310 shared_network->setIface(iface);
311 }
312
313 if (shared_network_data->contains("rapid-commit")) {
314 shared_network->setRapidCommit(getBoolean(shared_network_data,
315 "rapid-commit"));
316 }
317
318 if (shared_network_data->contains("option-data")) {
319 auto json = shared_network_data->get("option-data");
320 // Create parser instance for option-data.
321 CfgOptionPtr cfg_option = shared_network->getCfgOption();
322 auto parser = createOptionDataListParser();
323 parser->parse(cfg_option, json, encapsulate_options);
324 }
325
326 if (shared_network_data->contains("client-class")) {
327 std::string client_class = getString(shared_network_data, "client-class");
328 if (!client_class.empty()) {
329 shared_network->allowClientClass(client_class);
330 }
331 }
332
333 ConstElementPtr user_context = shared_network_data->get("user-context");
334 if (user_context) {
335 shared_network->setContext(user_context);
336 }
337
338 if (shared_network_data->contains("require-client-classes")) {
339 const std::vector<data::ElementPtr>& class_list =
340 shared_network_data->get("require-client-classes")->listValue();
341 for (auto const& cclass : class_list) {
342 if ((cclass->getType() != Element::string) ||
343 cclass->stringValue().empty()) {
344 isc_throw(DhcpConfigError, "invalid class name ("
345 << cclass->getPosition() << ")");
346 }
347 shared_network->requireClientClass(cclass->stringValue());
348 }
349 }
350
351 if (shared_network_data->contains("subnet6")) {
352 auto json = shared_network_data->get("subnet6");
353
354 // Create parser instance of subnet6.
355 auto parser = createSubnetsListParser();
356 Subnet6Collection subnets;
357 parser->parse(subnets, json);
358
359 // Add all returned subnets into shared network.
360 for (auto const& subnet : subnets) {
361 shared_network->add(subnet);
362 }
363 }
364
365 if (shared_network_data->contains("relay")) {
366 auto relay_parms = shared_network_data->get("relay");
367 if (relay_parms) {
370 parser.parse(relay_info, relay_parms);
371 shared_network->setRelayInfo(*relay_info);
372 }
373 }
374
375 parseTeePercents(shared_network_data, network);
376
377 // Parse DDNS parameters
378 parseDdnsParams(shared_network_data, network);
379
380 // Parse lease cache parameters
381 parseCacheParams(shared_network_data, network);
382
383 // Parse allocator params.
384 parseAllocatorParams(shared_network_data, network);
385 if (network->getAllocatorType() == "flq") {
386 isc_throw(BadValue, "Free Lease Queue allocator is not supported for IPv6 address pools");
387 }
388
389 // Parse prefix delegation allocator params.
390 auto network6 = boost::dynamic_pointer_cast<Network6>(shared_network);
391 parsePdAllocatorParams(shared_network_data, network6);
392
393 } catch (const std::exception& ex) {
394 isc_throw(DhcpConfigError, ex.what() << " ("
395 << shared_network_data->getPosition() << ")");
396 }
397
398 // In order to take advantage of the dynamic inheritance of global
399 // parameters to a shared network we need to set a callback function
400 // for each shared network which can be used to fetch global parameters.
401 shared_network->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr {
402 return (CfgMgr::instance().getCurrentCfg()->getConfiguredGlobals());
403 });
404
405 return (shared_network);
406}
407
408boost::shared_ptr<OptionDataListParser>
410 auto parser = boost::make_shared<OptionDataListParser>(AF_INET6);
411 return (parser);
412}
413
414boost::shared_ptr<Subnets6ListConfigParser>
416 auto parser = boost::make_shared<Subnets6ListConfigParser>(check_iface_);
417 return (parser);
418}
419
420} // end of namespace isc::dhcp
421} // end of namespace isc
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
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 parseAllocatorParams(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses parameters pertaining to allocator selection.
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.
void parseTeePercents(const data::ConstElementPtr &network_data, NetworkPtr &network)
Parses parameters related to "percent" timers settings.
void parsePdAllocatorParams(const data::ConstElementPtr &network_data, Network6Ptr &network)
Parses parameters pertaining to prefix delegation allocator selection.
void parseOfferLft(const data::ConstElementPtr &network_data, Network4Ptr &network)
Parses offer-lifetime parameter (v4 only)
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:54
Holds optional information about relay.
Definition network.h:162
boost::shared_ptr< Network::RelayInfo > RelayInfoPtr
Pointer to the RelayInfo structure.
Definition network.h:210
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
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.
bool check_iface_
Check if the specified interface exists in the system.
SharedNetwork4Ptr parse(const data::ConstElementPtr &shared_network_data, bool encapsulate_options=true)
Parses shared configuration information for IPv4 shared network.
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...
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.
SharedNetwork6Ptr parse(const data::ConstElementPtr &shared_network_data, bool encapsulate_options=true)
Parses shared configuration information for IPv6 shared network.
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.
@ 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:29
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
@ error
Definition db_log.h:118
boost::shared_ptr< const CfgGlobals > ConstCfgGlobalsPtr
Const shared pointer to a CfgGlobals instance.
boost::shared_ptr< Network4 > Network4Ptr
Pointer to the Network4 object.
Definition network.h:1413
boost::shared_ptr< CfgOption > CfgOptionPtr
Non-const pointer.
Definition cfg_option.h:803
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:934
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:863
boost::shared_ptr< Network > NetworkPtr
Pointer to the Network object.
Definition network.h:73
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:37
Defines the logger used by the top-level component of kea-lfc.