File: | home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-private/tmphs1g5w79/../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc |
Warning: | line 936, column 13 Value stored to 'len' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | // Copyright (C) 2013-2025 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 <config/http_command_config.h> |
10 | #include <config/unix_command_config.h> |
11 | #include <dhcp/iface_mgr.h> |
12 | #include <dhcp/dhcp4.h> |
13 | #include <dhcp/libdhcp++.h> |
14 | #include <dhcpsrv/cfgmgr.h> |
15 | #include <dhcpsrv/cfg_option.h> |
16 | #include <dhcpsrv/dhcpsrv_log.h> |
17 | #include <dhcpsrv/parsers/dhcp_parsers.h> |
18 | #include <dhcpsrv/parsers/host_reservation_parser.h> |
19 | #include <dhcpsrv/parsers/host_reservations_list_parser.h> |
20 | #include <dhcpsrv/parsers/option_data_parser.h> |
21 | #include <dhcpsrv/parsers/simple_parser4.h> |
22 | #include <dhcpsrv/parsers/simple_parser6.h> |
23 | #include <dhcpsrv/cfg_mac_source.h> |
24 | #include <util/encode/encode.h> |
25 | #include <util/str.h> |
26 | |
27 | #include <boost/algorithm/string.hpp> |
28 | #include <boost/foreach.hpp> |
29 | #include <boost/lexical_cast.hpp> |
30 | #include <boost/make_shared.hpp> |
31 | #include <boost/scoped_ptr.hpp> |
32 | |
33 | #include <limits> |
34 | #include <map> |
35 | #include <string> |
36 | #include <vector> |
37 | #include <iomanip> |
38 | |
39 | using namespace std; |
40 | using namespace isc::asiolink; |
41 | using namespace isc::config; |
42 | using namespace isc::data; |
43 | using namespace isc::util; |
44 | namespace ph = std::placeholders; |
45 | |
46 | namespace isc { |
47 | namespace dhcp { |
48 | |
49 | // ******************** MACSourcesListConfigParser ************************* |
50 | |
51 | void |
52 | MACSourcesListConfigParser::parse(CfgMACSource& mac_sources, ConstElementPtr value) { |
53 | uint32_t source = 0; |
54 | size_t cnt = 0; |
55 | |
56 | // By default, there's only one source defined: ANY. |
57 | // If user specified anything, we need to get rid of that default. |
58 | mac_sources.clear(); |
59 | |
60 | for (auto const& source_elem : value->listValue()) { |
61 | std::string source_str = source_elem->stringValue(); |
62 | try { |
63 | source = CfgMACSource::MACSourceFromText(source_str); |
64 | mac_sources.add(source); |
65 | ++cnt; |
66 | } catch (const InvalidParameter& ex) { |
67 | isc_throw(DhcpConfigError, "The mac-sources value '" << source_strdo { std::ostringstream oss__; oss__ << "The mac-sources value '" << source_str << "' was specified twice (" << value->getPosition() << ")"; throw DhcpConfigError( "../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 68, oss__ .str().c_str()); } while (1) |
68 | << "' was specified twice (" << value->getPosition() << ")")do { std::ostringstream oss__; oss__ << "The mac-sources value '" << source_str << "' was specified twice (" << value->getPosition() << ")"; throw DhcpConfigError( "../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 68, oss__ .str().c_str()); } while (1); |
69 | } catch (const std::exception& ex) { |
70 | isc_throw(DhcpConfigError, "Failed to convert '"do { std::ostringstream oss__; oss__ << "Failed to convert '" << source_str << "' to any recognized MAC source:" << ex.what() << " (" << value->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 72, oss__.str().c_str()); } while (1) |
71 | << source_str << "' to any recognized MAC source:"do { std::ostringstream oss__; oss__ << "Failed to convert '" << source_str << "' to any recognized MAC source:" << ex.what() << " (" << value->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 72, oss__.str().c_str()); } while (1) |
72 | << ex.what() << " (" << value->getPosition() << ")")do { std::ostringstream oss__; oss__ << "Failed to convert '" << source_str << "' to any recognized MAC source:" << ex.what() << " (" << value->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 72, oss__.str().c_str()); } while (1); |
73 | } |
74 | } |
75 | |
76 | if (!cnt) { |
77 | isc_throw(DhcpConfigError, "If specified, MAC Sources cannot be empty")do { std::ostringstream oss__; oss__ << "If specified, MAC Sources cannot be empty" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 77, oss__.str().c_str()); } while (1); |
78 | } |
79 | } |
80 | |
81 | // ******************** ControlSocketsParser ************************* |
82 | void ControlSocketsParser::parse(SrvConfig& srv_cfg, ConstElementPtr value) { |
83 | if (value->getType() != Element::list) { |
84 | // Sanity check: not supposed to fail. |
85 | isc_throw(DhcpConfigError,do { std::ostringstream oss__; oss__ << "Specified control-sockets is expected to be a list" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 86, oss__.str().c_str()); } while (1) |
86 | "Specified control-sockets is expected to be a list")do { std::ostringstream oss__; oss__ << "Specified control-sockets is expected to be a list" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 86, oss__.str().c_str()); } while (1); |
87 | } |
88 | bool seen_unix(false); |
89 | ElementPtr unix_config = Element::createList(); |
90 | ElementPtr http_config = Element::createList(); |
91 | for (ElementPtr socket : value->listValue()) { |
92 | if (socket->getType() != Element::map) { |
93 | // Sanity check: not supposed to fail. |
94 | isc_throw(DhcpConfigError,do { std::ostringstream oss__; oss__ << "Specified control-sockets is expected to be a list of maps" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 95, oss__.str().c_str()); } while (1) |
95 | "Specified control-sockets is expected to be a list of maps")do { std::ostringstream oss__; oss__ << "Specified control-sockets is expected to be a list of maps" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 95, oss__.str().c_str()); } while (1); |
96 | } |
97 | ConstElementPtr socket_type = socket->get("socket-type"); |
98 | if (!socket_type) { |
99 | isc_throw(DhcpConfigError,do { std::ostringstream oss__; oss__ << "'socket-type' parameter is mandatory in control-sockets items" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 100, oss__.str().c_str()); } while (1) |
100 | "'socket-type' parameter is mandatory in control-sockets items")do { std::ostringstream oss__; oss__ << "'socket-type' parameter is mandatory in control-sockets items" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 100, oss__.str().c_str()); } while (1); |
101 | } |
102 | if (socket_type->getType() != Element::string) { |
103 | // Sanity check: not supposed to fail. |
104 | isc_throw(DhcpConfigError,do { std::ostringstream oss__; oss__ << "'socket-type' parameter is expected to be a string" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 105, oss__.str().c_str()); } while (1) |
105 | "'socket-type' parameter is expected to be a string")do { std::ostringstream oss__; oss__ << "'socket-type' parameter is expected to be a string" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 105, oss__.str().c_str()); } while (1); |
106 | } |
107 | string type = socket_type->stringValue(); |
108 | if (type == "unix") { |
109 | if (seen_unix) { |
110 | isc_throw(DhcpConfigError,do { std::ostringstream oss__; oss__ << "control socket of type 'unix' already configured" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 111, oss__.str().c_str()); } while (1) |
111 | "control socket of type 'unix' already configured")do { std::ostringstream oss__; oss__ << "control socket of type 'unix' already configured" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 111, oss__.str().c_str()); } while (1); |
112 | } |
113 | UnixCommandConfig cmd_config(socket); |
114 | seen_unix = true; |
115 | unix_config->add(socket); |
116 | } else if ((type == "http") || (type == "https")) { |
117 | HttpCommandConfig cmd_config(socket); |
118 | http_config->add(socket); |
119 | } else { |
120 | // Sanity check: not supposed to fail. |
121 | isc_throw(DhcpConfigError,do { std::ostringstream oss__; oss__ << "unsupported 'socket-type': '" << type << "' not 'unix', 'http' or 'https'"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 123, oss__.str().c_str()); } while (1) |
122 | "unsupported 'socket-type': '" << typedo { std::ostringstream oss__; oss__ << "unsupported 'socket-type': '" << type << "' not 'unix', 'http' or 'https'"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 123, oss__.str().c_str()); } while (1) |
123 | << "' not 'unix', 'http' or 'https'")do { std::ostringstream oss__; oss__ << "unsupported 'socket-type': '" << type << "' not 'unix', 'http' or 'https'"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 123, oss__.str().c_str()); } while (1); |
124 | } |
125 | } |
126 | if (unix_config->size()) { |
127 | srv_cfg.setUnixControlSocketInfo(unix_config); |
128 | } |
129 | if (http_config->size()) { |
130 | srv_cfg.setHttpControlSocketInfo(http_config); |
131 | } |
132 | } |
133 | |
134 | // ******************************** OptionDefParser **************************** |
135 | |
136 | OptionDefParser::OptionDefParser(const uint16_t address_family) |
137 | : address_family_(address_family) { |
138 | } |
139 | |
140 | OptionDefinitionPtr |
141 | OptionDefParser::parse(ConstElementPtr option_def) { |
142 | |
143 | // Check parameters. |
144 | if (address_family_ == AF_INET2) { |
145 | checkKeywords(SimpleParser4::OPTION4_DEF_PARAMETERS, option_def); |
146 | } else { |
147 | checkKeywords(SimpleParser6::OPTION6_DEF_PARAMETERS, option_def); |
148 | } |
149 | |
150 | // Get mandatory parameters. |
151 | std::string name = getString(option_def, "name"); |
152 | int64_t code64 = getInteger(option_def, "code"); |
153 | std::string type = getString(option_def, "type"); |
154 | |
155 | // Get optional parameters. Whoever called this parser, should have |
156 | // called SimpleParser::setDefaults first. |
157 | bool array_type = getBoolean(option_def, "array"); |
158 | std::string record_types = getString(option_def, "record-types"); |
159 | std::string space = getString(option_def, "space"); |
160 | std::string encapsulates = getString(option_def, "encapsulate"); |
161 | ConstElementPtr user_context = option_def->get("user-context"); |
162 | |
163 | // Check code value. |
164 | if (code64 < 0) { |
165 | isc_throw(DhcpConfigError, "option code must not be negative "do { std::ostringstream oss__; oss__ << "option code must not be negative " "(" << getPosition("code", option_def) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 166, oss__.str().c_str()); } while (1) |
166 | "(" << getPosition("code", option_def) << ")")do { std::ostringstream oss__; oss__ << "option code must not be negative " "(" << getPosition("code", option_def) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 166, oss__.str().c_str()); } while (1); |
167 | } else if (address_family_ == AF_INET2 && |
168 | code64 > std::numeric_limits<uint8_t>::max()) { |
169 | isc_throw(DhcpConfigError, "invalid option code '" << code64do { std::ostringstream oss__; oss__ << "invalid option code '" << code64 << "', it must not be greater than '" << static_cast<int>(std::numeric_limits<uint8_t>::max ()) << "' (" << getPosition("code", option_def) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 172, oss__.str().c_str()); } while (1) |
170 | << "', it must not be greater than '"do { std::ostringstream oss__; oss__ << "invalid option code '" << code64 << "', it must not be greater than '" << static_cast<int>(std::numeric_limits<uint8_t>::max ()) << "' (" << getPosition("code", option_def) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 172, oss__.str().c_str()); } while (1) |
171 | << static_cast<int>(std::numeric_limits<uint8_t>::max())do { std::ostringstream oss__; oss__ << "invalid option code '" << code64 << "', it must not be greater than '" << static_cast<int>(std::numeric_limits<uint8_t>::max ()) << "' (" << getPosition("code", option_def) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 172, oss__.str().c_str()); } while (1) |
172 | << "' (" << getPosition("code", option_def) << ")")do { std::ostringstream oss__; oss__ << "invalid option code '" << code64 << "', it must not be greater than '" << static_cast<int>(std::numeric_limits<uint8_t>::max ()) << "' (" << getPosition("code", option_def) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 172, oss__.str().c_str()); } while (1); |
173 | } else if (address_family_ == AF_INET610 && |
174 | code64 > std::numeric_limits<uint16_t>::max()) { |
175 | isc_throw(DhcpConfigError, "invalid option code '" << code64do { std::ostringstream oss__; oss__ << "invalid option code '" << code64 << "', it must not be greater than '" << std::numeric_limits<uint16_t>::max() << "' (" << getPosition("code", option_def) << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 178, oss__ .str().c_str()); } while (1) |
176 | << "', it must not be greater than '"do { std::ostringstream oss__; oss__ << "invalid option code '" << code64 << "', it must not be greater than '" << std::numeric_limits<uint16_t>::max() << "' (" << getPosition("code", option_def) << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 178, oss__ .str().c_str()); } while (1) |
177 | << std::numeric_limits<uint16_t>::max()do { std::ostringstream oss__; oss__ << "invalid option code '" << code64 << "', it must not be greater than '" << std::numeric_limits<uint16_t>::max() << "' (" << getPosition("code", option_def) << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 178, oss__ .str().c_str()); } while (1) |
178 | << "' (" << getPosition("code", option_def) << ")")do { std::ostringstream oss__; oss__ << "invalid option code '" << code64 << "', it must not be greater than '" << std::numeric_limits<uint16_t>::max() << "' (" << getPosition("code", option_def) << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 178, oss__ .str().c_str()); } while (1); |
179 | } |
180 | uint32_t code = static_cast<uint32_t>(code64); |
181 | |
182 | // Validate space name. |
183 | if (!OptionSpace::validateName(space)) { |
184 | isc_throw(DhcpConfigError, "invalid option space name '"do { std::ostringstream oss__; oss__ << "invalid option space name '" << space << "' (" << getPosition("space", option_def ) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 186, oss__.str().c_str()); } while (1) |
185 | << space << "' ("do { std::ostringstream oss__; oss__ << "invalid option space name '" << space << "' (" << getPosition("space", option_def ) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 186, oss__.str().c_str()); } while (1) |
186 | << getPosition("space", option_def) << ")")do { std::ostringstream oss__; oss__ << "invalid option space name '" << space << "' (" << getPosition("space", option_def ) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 186, oss__.str().c_str()); } while (1); |
187 | } |
188 | |
189 | // Protect against definition of options 0 (PAD) or 255 (END) |
190 | // in (and only in) the dhcp4 space. |
191 | if (space == DHCP4_OPTION_SPACE"dhcp4") { |
192 | if (code == DHO_PAD) { |
193 | isc_throw(DhcpConfigError, "invalid option code '0': "do { std::ostringstream oss__; oss__ << "invalid option code '0': " << "reserved for PAD (" << getPosition("code", option_def ) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 195, oss__.str().c_str()); } while (1) |
194 | << "reserved for PAD ("do { std::ostringstream oss__; oss__ << "invalid option code '0': " << "reserved for PAD (" << getPosition("code", option_def ) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 195, oss__.str().c_str()); } while (1) |
195 | << getPosition("code", option_def) << ")")do { std::ostringstream oss__; oss__ << "invalid option code '0': " << "reserved for PAD (" << getPosition("code", option_def ) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 195, oss__.str().c_str()); } while (1); |
196 | } else if (code == DHO_END) { |
197 | isc_throw(DhcpConfigError, "invalid option code '255': "do { std::ostringstream oss__; oss__ << "invalid option code '255': " << "reserved for END (" << getPosition("code", option_def ) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 199, oss__.str().c_str()); } while (1) |
198 | << "reserved for END ("do { std::ostringstream oss__; oss__ << "invalid option code '255': " << "reserved for END (" << getPosition("code", option_def ) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 199, oss__.str().c_str()); } while (1) |
199 | << getPosition("code", option_def) << ")")do { std::ostringstream oss__; oss__ << "invalid option code '255': " << "reserved for END (" << getPosition("code", option_def ) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 199, oss__.str().c_str()); } while (1); |
200 | } |
201 | } |
202 | |
203 | // For dhcp6 space the value 0 is reserved. |
204 | if (space == DHCP6_OPTION_SPACE"dhcp6") { |
205 | if (code == 0) { |
206 | isc_throw(DhcpConfigError, "invalid option code '0': "do { std::ostringstream oss__; oss__ << "invalid option code '0': " << "reserved value (" << getPosition("code", option_def ) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 208, oss__.str().c_str()); } while (1) |
207 | << "reserved value ("do { std::ostringstream oss__; oss__ << "invalid option code '0': " << "reserved value (" << getPosition("code", option_def ) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 208, oss__.str().c_str()); } while (1) |
208 | << getPosition("code", option_def) << ")")do { std::ostringstream oss__; oss__ << "invalid option code '0': " << "reserved value (" << getPosition("code", option_def ) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 208, oss__.str().c_str()); } while (1); |
209 | } |
210 | } |
211 | |
212 | // Create option definition. |
213 | OptionDefinitionPtr def; |
214 | // We need to check if user has set encapsulated option space |
215 | // name. If so, different constructor will be used. |
216 | if (!encapsulates.empty()) { |
217 | // Arrays can't be used together with sub-options. |
218 | if (array_type) { |
219 | isc_throw(DhcpConfigError, "option '" << space << "."do { std::ostringstream oss__; oss__ << "option '" << space << "." << name << "', comprising an array of data" << " fields may not encapsulate any option space (" << option_def->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 222, oss__ .str().c_str()); } while (1) |
220 | << name << "', comprising an array of data"do { std::ostringstream oss__; oss__ << "option '" << space << "." << name << "', comprising an array of data" << " fields may not encapsulate any option space (" << option_def->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 222, oss__ .str().c_str()); } while (1) |
221 | << " fields may not encapsulate any option space ("do { std::ostringstream oss__; oss__ << "option '" << space << "." << name << "', comprising an array of data" << " fields may not encapsulate any option space (" << option_def->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 222, oss__ .str().c_str()); } while (1) |
222 | << option_def->getPosition() << ")")do { std::ostringstream oss__; oss__ << "option '" << space << "." << name << "', comprising an array of data" << " fields may not encapsulate any option space (" << option_def->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 222, oss__ .str().c_str()); } while (1); |
223 | |
224 | } else if (encapsulates == space) { |
225 | isc_throw(DhcpConfigError, "option must not encapsulate"do { std::ostringstream oss__; oss__ << "option must not encapsulate" << " an option space it belongs to: '" << space << "." << name << "' is set to" << " encapsulate '" << space << "' (" << option_def->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 229, oss__.str().c_str()); } while (1) |
226 | << " an option space it belongs to: '"do { std::ostringstream oss__; oss__ << "option must not encapsulate" << " an option space it belongs to: '" << space << "." << name << "' is set to" << " encapsulate '" << space << "' (" << option_def->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 229, oss__.str().c_str()); } while (1) |
227 | << space << "." << name << "' is set to"do { std::ostringstream oss__; oss__ << "option must not encapsulate" << " an option space it belongs to: '" << space << "." << name << "' is set to" << " encapsulate '" << space << "' (" << option_def->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 229, oss__.str().c_str()); } while (1) |
228 | << " encapsulate '" << space << "' ("do { std::ostringstream oss__; oss__ << "option must not encapsulate" << " an option space it belongs to: '" << space << "." << name << "' is set to" << " encapsulate '" << space << "' (" << option_def->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 229, oss__.str().c_str()); } while (1) |
229 | << option_def->getPosition() << ")")do { std::ostringstream oss__; oss__ << "option must not encapsulate" << " an option space it belongs to: '" << space << "." << name << "' is set to" << " encapsulate '" << space << "' (" << option_def->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 229, oss__.str().c_str()); } while (1); |
230 | |
231 | } else { |
232 | def.reset(new OptionDefinition(name, code, space, type, |
233 | encapsulates.c_str())); |
234 | } |
235 | |
236 | } else { |
237 | def.reset(new OptionDefinition(name, code, space, type, array_type)); |
238 | |
239 | } |
240 | |
241 | if (user_context) { |
242 | def->setContext(user_context); |
243 | } |
244 | |
245 | // Split the list of record types into tokens. |
246 | std::vector<std::string> record_tokens = |
247 | isc::util::str::tokens(record_types, ","); |
248 | // Iterate over each token and add a record type into |
249 | // option definition. |
250 | for (auto const& record_type : record_tokens) { |
251 | try { |
252 | auto const trim_rec = boost::trim_copy(record_type); |
253 | if (!trim_rec.empty()) { |
254 | def->addRecordField(trim_rec); |
255 | } |
256 | } catch (const Exception& ex) { |
257 | isc_throw(DhcpConfigError, "invalid record type values"do { std::ostringstream oss__; oss__ << "invalid record type values" << " specified for the option definition: " << ex .what() << " (" << getPosition("record-types", option_def ) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 260, oss__.str().c_str()); } while (1) |
258 | << " specified for the option definition: "do { std::ostringstream oss__; oss__ << "invalid record type values" << " specified for the option definition: " << ex .what() << " (" << getPosition("record-types", option_def ) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 260, oss__.str().c_str()); } while (1) |
259 | << ex.what() << " ("do { std::ostringstream oss__; oss__ << "invalid record type values" << " specified for the option definition: " << ex .what() << " (" << getPosition("record-types", option_def ) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 260, oss__.str().c_str()); } while (1) |
260 | << getPosition("record-types", option_def) << ")")do { std::ostringstream oss__; oss__ << "invalid record type values" << " specified for the option definition: " << ex .what() << " (" << getPosition("record-types", option_def ) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 260, oss__.str().c_str()); } while (1); |
261 | } |
262 | } |
263 | |
264 | // Validate the definition. |
265 | try { |
266 | def->validate(); |
267 | } catch (const std::exception& ex) { |
268 | isc_throw(DhcpConfigError, ex.what()do { std::ostringstream oss__; oss__ << ex.what() << " (" << option_def->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 269, oss__.str().c_str()); } while (1) |
269 | << " (" << option_def->getPosition() << ")")do { std::ostringstream oss__; oss__ << ex.what() << " (" << option_def->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 269, oss__.str().c_str()); } while (1); |
270 | } |
271 | |
272 | // Option definition has been created successfully. |
273 | return (def); |
274 | } |
275 | |
276 | // ******************************** OptionDefListParser ************************ |
277 | |
278 | OptionDefListParser::OptionDefListParser(const uint16_t address_family) |
279 | : address_family_(address_family) { |
280 | } |
281 | |
282 | void |
283 | OptionDefListParser::parse(CfgOptionDefPtr storage, ConstElementPtr option_def_list) { |
284 | if (!option_def_list) { |
285 | // Sanity check: not supposed to fail. |
286 | isc_throw(DhcpConfigError, "parser error: a pointer to a list of"do { std::ostringstream oss__; oss__ << "parser error: a pointer to a list of" << " option definitions is NULL (" << option_def_list ->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 288, oss__.str().c_str()); } while (1) |
287 | << " option definitions is NULL ("do { std::ostringstream oss__; oss__ << "parser error: a pointer to a list of" << " option definitions is NULL (" << option_def_list ->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 288, oss__.str().c_str()); } while (1) |
288 | << option_def_list->getPosition() << ")")do { std::ostringstream oss__; oss__ << "parser error: a pointer to a list of" << " option definitions is NULL (" << option_def_list ->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 288, oss__.str().c_str()); } while (1); |
289 | } |
290 | |
291 | OptionDefParser parser(address_family_); |
292 | for (auto const& option_def : option_def_list->listValue()) { |
293 | OptionDefinitionPtr def = parser.parse(option_def); |
294 | try { |
295 | storage->add(def); |
296 | } catch (const std::exception& ex) { |
297 | // Append position if there is a failure. |
298 | isc_throw(DhcpConfigError, ex.what() << " ("do { std::ostringstream oss__; oss__ << ex.what() << " (" << option_def->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 299, oss__.str().c_str()); } while (1) |
299 | << option_def->getPosition() << ")")do { std::ostringstream oss__; oss__ << ex.what() << " (" << option_def->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 299, oss__.str().c_str()); } while (1); |
300 | } |
301 | } |
302 | |
303 | // All definitions have been prepared. Put them as runtime options into |
304 | // the libdhcp++. |
305 | LibDHCP::setRuntimeOptionDefs(storage->getContainer()); |
306 | } |
307 | |
308 | //****************************** RelayInfoParser ******************************** |
309 | RelayInfoParser::RelayInfoParser(const Option::Universe& family) |
310 | : family_(family) { |
311 | }; |
312 | |
313 | void |
314 | RelayInfoParser::parse(const isc::dhcp::Network::RelayInfoPtr& relay_info, |
315 | ConstElementPtr relay_elem) { |
316 | |
317 | if (relay_elem->getType() != Element::map) { |
318 | isc_throw(DhcpConfigError, "relay must be a map")do { std::ostringstream oss__; oss__ << "relay must be a map" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 318, oss__.str().c_str()); } while (1); |
319 | } |
320 | |
321 | ConstElementPtr addresses = relay_elem->get("ip-addresses"); |
322 | if (!addresses) { |
323 | isc_throw(DhcpConfigError, "ip-addresses is required")do { std::ostringstream oss__; oss__ << "ip-addresses is required" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 323, oss__.str().c_str()); } while (1); |
324 | } |
325 | |
326 | // Create our resultant RelayInfo structure |
327 | *relay_info = isc::dhcp::Network::RelayInfo(); |
328 | |
329 | if (addresses->getType() != Element::list) { |
330 | isc_throw(DhcpConfigError, "ip-addresses must be a list "do { std::ostringstream oss__; oss__ << "ip-addresses must be a list " "(" << getPosition("ip-addresses", relay_elem) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 331, oss__.str().c_str()); } while (1) |
331 | "(" << getPosition("ip-addresses", relay_elem) << ")")do { std::ostringstream oss__; oss__ << "ip-addresses must be a list " "(" << getPosition("ip-addresses", relay_elem) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 331, oss__.str().c_str()); } while (1); |
332 | } |
333 | |
334 | for (auto const& address_element : addresses->listValue()) { |
335 | addAddress("ip-addresses", address_element->stringValue(), |
336 | relay_elem, relay_info); |
337 | } |
338 | } |
339 | |
340 | void |
341 | RelayInfoParser::addAddress(const std::string& name, |
342 | const std::string& address_str, |
343 | ConstElementPtr relay_elem, |
344 | const isc::dhcp::Network::RelayInfoPtr& relay_info) { |
345 | boost::scoped_ptr<isc::asiolink::IOAddress> ip; |
346 | try { |
347 | ip.reset(new isc::asiolink::IOAddress(address_str)); |
348 | } catch (const std::exception& ex) { |
349 | isc_throw(DhcpConfigError, "address " << address_strdo { std::ostringstream oss__; oss__ << "address " << address_str << " is not a valid: " << (family_ == Option::V4 ? "IPv4" : "IPv6") << "address" << " (" << getPosition(name, relay_elem) << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 353, oss__ .str().c_str()); } while (1) |
350 | << " is not a valid: "do { std::ostringstream oss__; oss__ << "address " << address_str << " is not a valid: " << (family_ == Option::V4 ? "IPv4" : "IPv6") << "address" << " (" << getPosition(name, relay_elem) << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 353, oss__ .str().c_str()); } while (1) |
351 | << (family_ == Option::V4 ? "IPv4" : "IPv6")do { std::ostringstream oss__; oss__ << "address " << address_str << " is not a valid: " << (family_ == Option::V4 ? "IPv4" : "IPv6") << "address" << " (" << getPosition(name, relay_elem) << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 353, oss__ .str().c_str()); } while (1) |
352 | << "address"do { std::ostringstream oss__; oss__ << "address " << address_str << " is not a valid: " << (family_ == Option::V4 ? "IPv4" : "IPv6") << "address" << " (" << getPosition(name, relay_elem) << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 353, oss__ .str().c_str()); } while (1) |
353 | << " (" << getPosition(name, relay_elem) << ")")do { std::ostringstream oss__; oss__ << "address " << address_str << " is not a valid: " << (family_ == Option::V4 ? "IPv4" : "IPv6") << "address" << " (" << getPosition(name, relay_elem) << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 353, oss__ .str().c_str()); } while (1); |
354 | } |
355 | |
356 | // Check if the address family matches. |
357 | if ((ip->isV4() && family_ != Option::V4) || |
358 | (ip->isV6() && family_ != Option::V6) ) { |
359 | isc_throw(DhcpConfigError, "address " << address_strdo { std::ostringstream oss__; oss__ << "address " << address_str << " is not a: " << (family_ == Option ::V4 ? "IPv4" : "IPv6") << "address" << " (" << getPosition(name, relay_elem) << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 363, oss__ .str().c_str()); } while (1) |
360 | << " is not a: "do { std::ostringstream oss__; oss__ << "address " << address_str << " is not a: " << (family_ == Option ::V4 ? "IPv4" : "IPv6") << "address" << " (" << getPosition(name, relay_elem) << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 363, oss__ .str().c_str()); } while (1) |
361 | << (family_ == Option::V4 ? "IPv4" : "IPv6")do { std::ostringstream oss__; oss__ << "address " << address_str << " is not a: " << (family_ == Option ::V4 ? "IPv4" : "IPv6") << "address" << " (" << getPosition(name, relay_elem) << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 363, oss__ .str().c_str()); } while (1) |
362 | << "address"do { std::ostringstream oss__; oss__ << "address " << address_str << " is not a: " << (family_ == Option ::V4 ? "IPv4" : "IPv6") << "address" << " (" << getPosition(name, relay_elem) << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 363, oss__ .str().c_str()); } while (1) |
363 | << " (" << getPosition(name, relay_elem) << ")")do { std::ostringstream oss__; oss__ << "address " << address_str << " is not a: " << (family_ == Option ::V4 ? "IPv4" : "IPv6") << "address" << " (" << getPosition(name, relay_elem) << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 363, oss__ .str().c_str()); } while (1); |
364 | } |
365 | |
366 | try { |
367 | relay_info->addAddress(*ip); |
368 | } catch (const std::exception& ex) { |
369 | isc_throw(DhcpConfigError, "cannot add address: " << address_strdo { std::ostringstream oss__; oss__ << "cannot add address: " << address_str << " to relay info: " << ex .what() << " (" << getPosition(name, relay_elem) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 371, oss__.str().c_str()); } while (1) |
370 | << " to relay info: " << ex.what()do { std::ostringstream oss__; oss__ << "cannot add address: " << address_str << " to relay info: " << ex .what() << " (" << getPosition(name, relay_elem) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 371, oss__.str().c_str()); } while (1) |
371 | << " (" << getPosition(name, relay_elem) << ")")do { std::ostringstream oss__; oss__ << "cannot add address: " << address_str << " to relay info: " << ex .what() << " (" << getPosition(name, relay_elem) << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 371, oss__.str().c_str()); } while (1); |
372 | } |
373 | } |
374 | |
375 | //****************************** PoolParser ******************************** |
376 | |
377 | void |
378 | PoolParser::parse(PoolStoragePtr pools, |
379 | ConstElementPtr pool_structure, |
380 | const uint16_t address_family, |
381 | bool encapsulate_options) { |
382 | |
383 | if (address_family == AF_INET2) { |
384 | checkKeywords(SimpleParser4::POOL4_PARAMETERS, pool_structure); |
385 | } else { |
386 | checkKeywords(SimpleParser6::POOL6_PARAMETERS, pool_structure); |
387 | } |
388 | |
389 | ConstElementPtr text_pool = pool_structure->get("pool"); |
390 | |
391 | if (!text_pool) { |
392 | isc_throw(DhcpConfigError, "Mandatory 'pool' entry missing in "do { std::ostringstream oss__; oss__ << "Mandatory 'pool' entry missing in " "definition: (" << pool_structure->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 393, oss__.str().c_str()); } while (1) |
393 | "definition: (" << pool_structure->getPosition() << ")")do { std::ostringstream oss__; oss__ << "Mandatory 'pool' entry missing in " "definition: (" << pool_structure->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 393, oss__.str().c_str()); } while (1); |
394 | } |
395 | |
396 | // That should be a single pool representation. It should contain |
397 | // text is form prefix/len or first - last. Note that spaces |
398 | // are allowed |
399 | string txt = text_pool->stringValue(); |
400 | |
401 | // first let's remove any whitespaces |
402 | boost::erase_all(txt, " "); // space |
403 | boost::erase_all(txt, "\t"); // tabulation |
404 | |
405 | PoolPtr pool; |
406 | |
407 | // Is this prefix/len notation? |
408 | size_t pos = txt.find("/"); |
409 | if (pos != string::npos) { |
410 | isc::asiolink::IOAddress addr("::"); |
411 | uint8_t len = 0; |
412 | try { |
413 | addr = isc::asiolink::IOAddress(txt.substr(0, pos)); |
414 | |
415 | // start with the first character after / |
416 | string prefix_len = txt.substr(pos + 1); |
417 | |
418 | // It is lexical cast to int and then downcast to uint8_t. |
419 | // Direct cast to uint8_t (which is really an unsigned char) |
420 | // will result in interpreting the first digit as output |
421 | // value and throwing exception if length is written on two |
422 | // digits (because there are extra characters left over). |
423 | |
424 | // No checks for values over 128. Range correctness will |
425 | // be checked in Pool4 constructor, here we only check |
426 | // the representation fits in an uint8_t as this can't |
427 | // be done by a direct lexical cast as explained... |
428 | int val_len = boost::lexical_cast<int>(prefix_len); |
429 | if ((val_len < std::numeric_limits<uint8_t>::min()) || |
430 | (val_len > std::numeric_limits<uint8_t>::max())) { |
431 | // This exception will be handled 4 line later! |
432 | isc_throw(OutOfRange, "")do { std::ostringstream oss__; oss__ << ""; throw OutOfRange ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 432, oss__ .str().c_str()); } while (1); |
433 | } |
434 | len = static_cast<uint8_t>(val_len); |
435 | } catch (...) { |
436 | isc_throw(DhcpConfigError, "Failed to parse pool "do { std::ostringstream oss__; oss__ << "Failed to parse pool " "definition: " << txt << " (" << text_pool ->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 438, oss__.str().c_str()); } while (1) |
437 | "definition: " << txt << " ("do { std::ostringstream oss__; oss__ << "Failed to parse pool " "definition: " << txt << " (" << text_pool ->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 438, oss__.str().c_str()); } while (1) |
438 | << text_pool->getPosition() << ")")do { std::ostringstream oss__; oss__ << "Failed to parse pool " "definition: " << txt << " (" << text_pool ->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 438, oss__.str().c_str()); } while (1); |
439 | } |
440 | |
441 | try { |
442 | pool = poolMaker(addr, len); |
443 | pools->push_back(pool); |
444 | } catch (const std::exception& ex) { |
445 | isc_throw(DhcpConfigError, "Failed to create pool defined by: "do { std::ostringstream oss__; oss__ << "Failed to create pool defined by: " << txt << " (" << text_pool->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 446, oss__.str().c_str()); } while (1) |
446 | << txt << " (" << text_pool->getPosition() << ")")do { std::ostringstream oss__; oss__ << "Failed to create pool defined by: " << txt << " (" << text_pool->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 446, oss__.str().c_str()); } while (1); |
447 | } |
448 | |
449 | } else { |
450 | isc::asiolink::IOAddress min("::"); |
451 | isc::asiolink::IOAddress max("::"); |
452 | |
453 | // Is this min-max notation? |
454 | pos = txt.find("-"); |
455 | if (pos != string::npos) { |
456 | // using min-max notation |
457 | try { |
458 | min = isc::asiolink::IOAddress(txt.substr(0, pos)); |
459 | max = isc::asiolink::IOAddress(txt.substr(pos + 1)); |
460 | } catch (...) { |
461 | isc_throw(DhcpConfigError, "Failed to parse pool "do { std::ostringstream oss__; oss__ << "Failed to parse pool " "definition: " << txt << " (" << text_pool ->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 463, oss__.str().c_str()); } while (1) |
462 | "definition: " << txt << " ("do { std::ostringstream oss__; oss__ << "Failed to parse pool " "definition: " << txt << " (" << text_pool ->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 463, oss__.str().c_str()); } while (1) |
463 | << text_pool->getPosition() << ")")do { std::ostringstream oss__; oss__ << "Failed to parse pool " "definition: " << txt << " (" << text_pool ->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 463, oss__.str().c_str()); } while (1); |
464 | } |
465 | |
466 | try { |
467 | pool = poolMaker(min, max); |
468 | pools->push_back(pool); |
469 | } catch (const std::exception& ex) { |
470 | isc_throw(DhcpConfigError, "Failed to create pool defined by: "do { std::ostringstream oss__; oss__ << "Failed to create pool defined by: " << txt << " (" << text_pool->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 471, oss__.str().c_str()); } while (1) |
471 | << txt << " (" << text_pool->getPosition() << ")")do { std::ostringstream oss__; oss__ << "Failed to create pool defined by: " << txt << " (" << text_pool->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 471, oss__.str().c_str()); } while (1); |
472 | } |
473 | } |
474 | } |
475 | |
476 | if (!pool) { |
477 | isc_throw(DhcpConfigError, "invalid pool definition: "do { std::ostringstream oss__; oss__ << "invalid pool definition: " << text_pool->stringValue() << ". There are two acceptable formats <min address-max address>" " or <prefix/len> (" << text_pool->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 481, oss__.str().c_str()); } while (1) |
478 | << text_pool->stringValue() <<do { std::ostringstream oss__; oss__ << "invalid pool definition: " << text_pool->stringValue() << ". There are two acceptable formats <min address-max address>" " or <prefix/len> (" << text_pool->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 481, oss__.str().c_str()); } while (1) |
479 | ". There are two acceptable formats <min address-max address>"do { std::ostringstream oss__; oss__ << "invalid pool definition: " << text_pool->stringValue() << ". There are two acceptable formats <min address-max address>" " or <prefix/len> (" << text_pool->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 481, oss__.str().c_str()); } while (1) |
480 | " or <prefix/len> ("do { std::ostringstream oss__; oss__ << "invalid pool definition: " << text_pool->stringValue() << ". There are two acceptable formats <min address-max address>" " or <prefix/len> (" << text_pool->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 481, oss__.str().c_str()); } while (1) |
481 | << text_pool->getPosition() << ")")do { std::ostringstream oss__; oss__ << "invalid pool definition: " << text_pool->stringValue() << ". There are two acceptable formats <min address-max address>" " or <prefix/len> (" << text_pool->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 481, oss__.str().c_str()); } while (1); |
482 | } |
483 | |
484 | // If there is a pool-id, store it. |
485 | ConstElementPtr pool_id = pool_structure->get("pool-id"); |
486 | if (pool_id) { |
487 | if (pool_id->intValue() <= 0) { |
488 | isc_throw(BadValue, "pool-id " << pool_id->intValue() << " is not"do { std::ostringstream oss__; oss__ << "pool-id " << pool_id->intValue() << " is not" << " a positive integer greater than 0" ; throw BadValue("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 489, oss__.str().c_str()); } while (1) |
489 | << " a positive integer greater than 0")do { std::ostringstream oss__; oss__ << "pool-id " << pool_id->intValue() << " is not" << " a positive integer greater than 0" ; throw BadValue("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 489, oss__.str().c_str()); } while (1); |
490 | } else if (pool_id->intValue() > numeric_limits<uint32_t>::max()) { |
491 | isc_throw(BadValue, "pool-id " << pool_id->intValue() << " is not"do { std::ostringstream oss__; oss__ << "pool-id " << pool_id->intValue() << " is not" << " a 32 bit unsigned integer" ; throw BadValue("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 492, oss__.str().c_str()); } while (1) |
492 | << " a 32 bit unsigned integer")do { std::ostringstream oss__; oss__ << "pool-id " << pool_id->intValue() << " is not" << " a 32 bit unsigned integer" ; throw BadValue("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 492, oss__.str().c_str()); } while (1); |
493 | } |
494 | |
495 | pool->setID(pool_id->intValue()); |
496 | } |
497 | |
498 | // If there's user-context specified, store it. |
499 | ConstElementPtr user_context = pool_structure->get("user-context"); |
500 | if (user_context) { |
501 | // The grammar accepts only maps but still check it. |
502 | if (user_context->getType() != Element::map) { |
503 | isc_throw(isc::dhcp::DhcpConfigError, "User context has to be a map ("do { std::ostringstream oss__; oss__ << "User context has to be a map (" << user_context->getPosition() << ")"; throw isc ::dhcp::DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 504, oss__.str().c_str()); } while (1) |
504 | << user_context->getPosition() << ")")do { std::ostringstream oss__; oss__ << "User context has to be a map (" << user_context->getPosition() << ")"; throw isc ::dhcp::DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 504, oss__.str().c_str()); } while (1); |
505 | } |
506 | pool->setContext(user_context); |
507 | } |
508 | |
509 | // Parser pool specific options. |
510 | ConstElementPtr option_data = pool_structure->get("option-data"); |
511 | if (option_data) { |
512 | try { |
513 | CfgOptionPtr cfg = pool->getCfgOption(); |
514 | auto option_parser = createOptionDataListParser(address_family); |
515 | option_parser->parse(cfg, option_data, encapsulate_options); |
516 | } catch (const std::exception& ex) { |
517 | isc_throw(isc::dhcp::DhcpConfigError, ex.what()do { std::ostringstream oss__; oss__ << ex.what() << " (" << option_data->getPosition() << ")"; throw isc::dhcp::DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 518, oss__.str().c_str()); } while (1) |
518 | << " (" << option_data->getPosition() << ")")do { std::ostringstream oss__; oss__ << ex.what() << " (" << option_data->getPosition() << ")"; throw isc::dhcp::DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 518, oss__.str().c_str()); } while (1); |
519 | } |
520 | } |
521 | |
522 | // Client-class. |
523 | ConstElementPtr client_class = pool_structure->get("client-class"); |
524 | if (client_class) { |
525 | string cclass = client_class->stringValue(); |
526 | if (!cclass.empty()) { |
527 | pool->allowClientClass(cclass); |
528 | } |
529 | } |
530 | |
531 | // Setup client class list. |
532 | BaseNetworkParser::getClientClassesElem(pool_structure, |
533 | std::bind(&Pool::allowClientClass, |
534 | pool, ph::_1)); |
535 | |
536 | // Setup additional class list. |
537 | BaseNetworkParser::getAdditionalClassesElem(pool_structure, |
538 | std::bind(&Pool::addAdditionalClass, |
539 | pool, ph::_1)); |
540 | |
541 | // Parse DDNS behavioral parameters. |
542 | BaseNetworkParser parser; |
543 | parser.parseDdnsParameters(pool_structure, pool); |
544 | } |
545 | |
546 | boost::shared_ptr<OptionDataListParser> |
547 | PoolParser::createOptionDataListParser(const uint16_t address_family) const { |
548 | return (boost::make_shared<OptionDataListParser>(address_family)); |
549 | } |
550 | |
551 | //****************************** Pool4Parser ************************* |
552 | |
553 | PoolPtr |
554 | Pool4Parser::poolMaker (IOAddress &addr, uint32_t len, int32_t) { |
555 | return (PoolPtr(new Pool4(addr, len))); |
556 | } |
557 | |
558 | PoolPtr |
559 | Pool4Parser::poolMaker (IOAddress &min, IOAddress &max, int32_t) { |
560 | return (PoolPtr(new Pool4(min, max))); |
561 | } |
562 | |
563 | //****************************** Pools4ListParser ************************* |
564 | |
565 | void |
566 | Pools4ListParser::parse(PoolStoragePtr pools, ConstElementPtr pools_list, |
567 | bool encapsulate_options) { |
568 | for (auto const& pool : pools_list->listValue()) { |
569 | auto const& parser = createPoolConfigParser(); |
570 | parser->parse(pools, pool, AF_INET2, encapsulate_options); |
571 | } |
572 | } |
573 | |
574 | boost::shared_ptr<PoolParser> |
575 | Pools4ListParser::createPoolConfigParser() const { |
576 | return (boost::make_shared<Pool4Parser>()); |
577 | } |
578 | |
579 | //****************************** SubnetConfigParser ************************* |
580 | |
581 | SubnetConfigParser::SubnetConfigParser(uint16_t family, bool check_iface) |
582 | : pools_(new PoolStorage()), |
583 | address_family_(family), |
584 | check_iface_(check_iface) { |
585 | relay_info_.reset(new isc::dhcp::Network::RelayInfo()); |
586 | } |
587 | |
588 | SubnetPtr |
589 | SubnetConfigParser::parse(ConstElementPtr subnet, bool encapsulate_options) { |
590 | |
591 | ConstElementPtr relay_params = subnet->get("relay"); |
592 | if (relay_params) { |
593 | Option::Universe u = (address_family_ == AF_INET2) ? Option::V4 : Option::V6; |
594 | RelayInfoParser parser(u); |
595 | parser.parse(relay_info_, relay_params); |
596 | } |
597 | |
598 | // Create a subnet. |
599 | try { |
600 | createSubnet(subnet); |
601 | } catch (const std::exception& ex) { |
602 | isc_throw(DhcpConfigError,do { std::ostringstream oss__; oss__ << "subnet configuration failed: " << ex.what(); throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 603, oss__.str().c_str()); } while (1) |
603 | "subnet configuration failed: " << ex.what())do { std::ostringstream oss__; oss__ << "subnet configuration failed: " << ex.what(); throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 603, oss__.str().c_str()); } while (1); |
604 | } |
605 | |
606 | // We create subnet first and then parse the options straight into the subnet's |
607 | // CfgOption structure. Previously, we first parsed the options and then copied |
608 | // them into the CfgOption after creating the subnet but it had two issues. First, |
609 | // it cost performance. Second, copying options reset the isEncapsulated() flag. |
610 | // If the options have been encapsulated we want to preserve the flag to ensure |
611 | // they are not encapsulated several times. |
612 | ConstElementPtr options_params = subnet->get("option-data"); |
613 | if (options_params) { |
614 | auto opt_parser = createOptionDataListParser(); |
615 | opt_parser->parse(subnet_->getCfgOption(), options_params, encapsulate_options); |
616 | } |
617 | |
618 | return (subnet_); |
619 | } |
620 | |
621 | void |
622 | SubnetConfigParser::createSubnet(ConstElementPtr params) { |
623 | std::string subnet_txt; |
624 | try { |
625 | subnet_txt = getString(params, "subnet"); |
626 | } catch (const DhcpConfigError &) { |
627 | // rethrow with precise error |
628 | isc_throw(DhcpConfigError,do { std::ostringstream oss__; oss__ << "mandatory 'subnet' parameter is missing for a subnet being" " configured (" << params->getPosition() << ")" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 630, oss__.str().c_str()); } while (1) |
629 | "mandatory 'subnet' parameter is missing for a subnet being"do { std::ostringstream oss__; oss__ << "mandatory 'subnet' parameter is missing for a subnet being" " configured (" << params->getPosition() << ")" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 630, oss__.str().c_str()); } while (1) |
630 | " configured (" << params->getPosition() << ")")do { std::ostringstream oss__; oss__ << "mandatory 'subnet' parameter is missing for a subnet being" " configured (" << params->getPosition() << ")" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 630, oss__.str().c_str()); } while (1); |
631 | } |
632 | |
633 | // Remove any spaces or tabs. |
634 | boost::erase_all(subnet_txt, " "); |
635 | boost::erase_all(subnet_txt, "\t"); |
636 | |
637 | // The subnet format is prefix/len. We are going to extract |
638 | // the prefix portion of a subnet string to create IOAddress |
639 | // object from it. IOAddress will be passed to the Subnet's |
640 | // constructor later on. In order to extract the prefix we |
641 | // need to get all characters preceding "/". |
642 | size_t pos = subnet_txt.find("/"); |
643 | if (pos == string::npos) { |
644 | ConstElementPtr elem = params->get("subnet"); |
645 | isc_throw(DhcpConfigError,do { std::ostringstream oss__; oss__ << "Invalid subnet syntax (prefix/len expected):" << subnet_txt << " (" << elem->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 647, oss__.str().c_str()); } while (1) |
646 | "Invalid subnet syntax (prefix/len expected):" << subnet_txtdo { std::ostringstream oss__; oss__ << "Invalid subnet syntax (prefix/len expected):" << subnet_txt << " (" << elem->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 647, oss__.str().c_str()); } while (1) |
647 | << " (" << elem->getPosition() << ")")do { std::ostringstream oss__; oss__ << "Invalid subnet syntax (prefix/len expected):" << subnet_txt << " (" << elem->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 647, oss__.str().c_str()); } while (1); |
648 | } |
649 | |
650 | // Try to create the address object. It also validates that |
651 | // the address syntax is ok. |
652 | isc::asiolink::IOAddress addr(subnet_txt.substr(0, pos)); |
653 | |
654 | // Now parse out the prefix length. |
655 | unsigned int len; |
656 | try { |
657 | len = boost::lexical_cast<unsigned int>(subnet_txt.substr(pos + 1)); |
658 | } catch (const boost::bad_lexical_cast&) { |
659 | ConstElementPtr elem = params->get("subnet"); |
660 | isc_throw(DhcpConfigError, "prefix length: '" <<do { std::ostringstream oss__; oss__ << "prefix length: '" << subnet_txt.substr(pos+1) << "' is not an integer (" << elem->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 662, oss__ .str().c_str()); } while (1) |
661 | subnet_txt.substr(pos+1) << "' is not an integer ("do { std::ostringstream oss__; oss__ << "prefix length: '" << subnet_txt.substr(pos+1) << "' is not an integer (" << elem->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 662, oss__ .str().c_str()); } while (1) |
662 | << elem->getPosition() << ")")do { std::ostringstream oss__; oss__ << "prefix length: '" << subnet_txt.substr(pos+1) << "' is not an integer (" << elem->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 662, oss__ .str().c_str()); } while (1); |
663 | } |
664 | |
665 | // Sanity check the prefix length |
666 | if ((addr.isV6() && len > 128) || |
667 | (addr.isV4() && len > 32)) { |
668 | ConstElementPtr elem = params->get("subnet"); |
669 | isc_throw(BadValue,do { std::ostringstream oss__; oss__ << "Invalid prefix length specified for subnet: " << len << " (" << elem->getPosition() << ")"; throw BadValue("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 671, oss__.str().c_str()); } while (1) |
670 | "Invalid prefix length specified for subnet: " << lendo { std::ostringstream oss__; oss__ << "Invalid prefix length specified for subnet: " << len << " (" << elem->getPosition() << ")"; throw BadValue("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 671, oss__.str().c_str()); } while (1) |
671 | << " (" << elem->getPosition() << ")")do { std::ostringstream oss__; oss__ << "Invalid prefix length specified for subnet: " << len << " (" << elem->getPosition() << ")"; throw BadValue("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 671, oss__.str().c_str()); } while (1); |
672 | } |
673 | |
674 | // Call the subclass's method to instantiate the subnet |
675 | initSubnet(params, addr, len); |
676 | |
677 | // Add pools to it. |
678 | for (auto const& pool : *pools_) { |
679 | try { |
680 | subnet_->addPool(pool); |
681 | } catch (const BadValue& ex) { |
682 | // addPool() can throw BadValue if the pool is overlapping or |
683 | // is out of bounds for the subnet. |
684 | isc_throw(DhcpConfigError,do { std::ostringstream oss__; oss__ << ex.what() << " (" << params->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 685, oss__ .str().c_str()); } while (1) |
685 | ex.what() << " (" << params->getPosition() << ")")do { std::ostringstream oss__; oss__ << ex.what() << " (" << params->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 685, oss__ .str().c_str()); } while (1); |
686 | } |
687 | } |
688 | // If there's user-context specified, store it. |
689 | ConstElementPtr user_context = params->get("user-context"); |
690 | if (user_context) { |
691 | // The grammar accepts only maps but still check it. |
692 | if (user_context->getType() != Element::map) { |
693 | isc_throw(isc::dhcp::DhcpConfigError, "User context has to be a map ("do { std::ostringstream oss__; oss__ << "User context has to be a map (" << user_context->getPosition() << ")"; throw isc ::dhcp::DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 694, oss__.str().c_str()); } while (1) |
694 | << user_context->getPosition() << ")")do { std::ostringstream oss__; oss__ << "User context has to be a map (" << user_context->getPosition() << ")"; throw isc ::dhcp::DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 694, oss__.str().c_str()); } while (1); |
695 | } |
696 | subnet_->setContext(user_context); |
697 | } |
698 | |
699 | // In order to take advantage of the dynamic inheritance of global |
700 | // parameters to a subnet we need to set a callback function for each |
701 | // subnet to allow for fetching global parameters. |
702 | subnet_->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr { |
703 | return (CfgMgr::instance().getCurrentCfg()->getConfiguredGlobals()); |
704 | }); |
705 | } |
706 | |
707 | boost::shared_ptr<OptionDataListParser> |
708 | SubnetConfigParser::createOptionDataListParser() const { |
709 | return (boost::make_shared<OptionDataListParser>(address_family_)); |
710 | } |
711 | |
712 | //****************************** Subnet4ConfigParser ************************* |
713 | |
714 | Subnet4ConfigParser::Subnet4ConfigParser(bool check_iface) |
715 | : SubnetConfigParser(AF_INET2, check_iface) { |
716 | } |
717 | |
718 | Subnet4Ptr |
719 | Subnet4ConfigParser::parse(ConstElementPtr subnet, bool encapsulate_options) { |
720 | // Check parameters. |
721 | checkKeywords(SimpleParser4::SUBNET4_PARAMETERS, subnet); |
722 | |
723 | /// Parse Pools first. |
724 | ConstElementPtr pools = subnet->get("pools"); |
725 | if (pools) { |
726 | auto const& parser = createPoolsListParser(); |
727 | parser->parse(pools_, pools, encapsulate_options); |
728 | } |
729 | |
730 | SubnetPtr generic = SubnetConfigParser::parse(subnet, encapsulate_options); |
731 | |
732 | if (!generic) { |
733 | // Sanity check: not supposed to fail. |
734 | isc_throw(DhcpConfigError,do { std::ostringstream oss__; oss__ << "Failed to create an IPv4 subnet (" << subnet->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 736, oss__ .str().c_str()); } while (1) |
735 | "Failed to create an IPv4 subnet (" <<do { std::ostringstream oss__; oss__ << "Failed to create an IPv4 subnet (" << subnet->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 736, oss__ .str().c_str()); } while (1) |
736 | subnet->getPosition() << ")")do { std::ostringstream oss__; oss__ << "Failed to create an IPv4 subnet (" << subnet->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 736, oss__ .str().c_str()); } while (1); |
737 | } |
738 | |
739 | Subnet4Ptr sn4ptr = boost::dynamic_pointer_cast<Subnet4>(subnet_); |
740 | if (!sn4ptr) { |
741 | // If we hit this, it is a programming error. |
742 | isc_throw(Unexpected,do { std::ostringstream oss__; oss__ << "Invalid Subnet4 cast in Subnet4ConfigParser::parse" ; throw Unexpected("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 743, oss__.str().c_str()); } while (1) |
743 | "Invalid Subnet4 cast in Subnet4ConfigParser::parse")do { std::ostringstream oss__; oss__ << "Invalid Subnet4 cast in Subnet4ConfigParser::parse" ; throw Unexpected("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 743, oss__.str().c_str()); } while (1); |
744 | } |
745 | |
746 | // Set relay information if it was parsed |
747 | if (relay_info_) { |
748 | sn4ptr->setRelayInfo(*relay_info_); |
749 | } |
750 | |
751 | // Parse Host Reservations for this subnet if any. |
752 | ConstElementPtr reservations = subnet->get("reservations"); |
753 | if (reservations) { |
754 | HostCollection hosts; |
755 | HostReservationsListParser<HostReservationParser4> parser; |
756 | parser.parse(subnet_->getID(), reservations, hosts); |
757 | for (auto const& h : hosts) { |
758 | validateResv(sn4ptr, h); |
759 | CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(h); |
760 | } |
761 | } |
762 | |
763 | // Parse allocator specification. |
764 | auto network4 = boost::dynamic_pointer_cast<Network>(sn4ptr); |
765 | parseAllocatorParams(subnet, network4); |
766 | |
767 | // Instantiate the allocator. |
768 | sn4ptr->createAllocators(); |
769 | |
770 | return (sn4ptr); |
771 | } |
772 | |
773 | void |
774 | Subnet4ConfigParser::initSubnet(data::ConstElementPtr params, |
775 | asiolink::IOAddress addr, uint8_t len) { |
776 | // Subnet ID is required and must be in 1..SUBNET_ID_MAX. |
777 | int64_t subnet_id_max = static_cast<int64_t>(SUBNET_ID_MAX); |
778 | SubnetID subnet_id = static_cast<SubnetID>(getInteger(params, "id", 1, |
779 | subnet_id_max)); |
780 | |
781 | auto subnet4 = Subnet4::create(addr, len, Triplet<uint32_t>(), |
782 | Triplet<uint32_t>(), Triplet<uint32_t>(), |
783 | subnet_id); |
784 | subnet_ = subnet4; |
785 | |
786 | ElementPtr mutable_params; |
787 | mutable_params = boost::const_pointer_cast<Element>(params); |
788 | |
789 | // Parse parameters common to all Network derivations. |
790 | NetworkPtr network = boost::dynamic_pointer_cast<Network>(subnet4); |
791 | parseCommon(mutable_params, network); |
792 | |
793 | std::ostringstream output; |
794 | output << addr << "/" << static_cast<int>(len) << " with params: "; |
795 | |
796 | bool has_renew = !subnet4->getT1().unspecified(); |
797 | bool has_rebind = !subnet4->getT2().unspecified(); |
798 | int64_t renew = -1; |
799 | int64_t rebind = -1; |
800 | |
801 | // t1 and t2 are optional may be not specified. |
802 | if (has_renew) { |
803 | renew = subnet4->getT1().get(); |
804 | output << "t1=" << renew << ", "; |
805 | } |
806 | if (has_rebind) { |
807 | rebind = subnet4->getT2().get(); |
808 | output << "t2=" << rebind << ", "; |
809 | } |
810 | |
811 | if (!subnet4->getValid().unspecified()) { |
812 | output << "valid-lifetime=" << subnet4->getValid().get(); |
813 | } |
814 | |
815 | LOG_INFO(dhcpsrv_logger, DHCPSRV_CFGMGR_NEW_SUBNET4)if (!(dhcpsrv_logger).isInfoEnabled()) { } else (dhcpsrv_logger ).info((DHCPSRV_CFGMGR_NEW_SUBNET4)).arg(output.str()); |
816 | |
817 | // Set the match-client-id value for the subnet. |
818 | if (params->contains("match-client-id")) { |
819 | bool match_client_id = getBoolean(params, "match-client-id"); |
820 | subnet4->setMatchClientId(match_client_id); |
821 | } |
822 | |
823 | // Set the authoritative value for the subnet. |
824 | if (params->contains("authoritative")) { |
825 | bool authoritative = getBoolean(params, "authoritative"); |
826 | subnet4->setAuthoritative(authoritative); |
827 | } |
828 | |
829 | // Set next-server. The default value is 0.0.0.0. Nevertheless, the |
830 | // user could have messed that up by specifying incorrect value. |
831 | // To avoid using 0.0.0.0, user can specify "". |
832 | if (params->contains("next-server")) { |
833 | string next_server; |
834 | try { |
835 | next_server = getString(params, "next-server"); |
836 | if (!next_server.empty()) { |
837 | subnet4->setSiaddr(IOAddress(next_server)); |
838 | } |
839 | } catch (...) { |
840 | ConstElementPtr next = params->get("next-server"); |
841 | string pos; |
842 | if (next) { |
843 | pos = next->getPosition().str(); |
844 | } else { |
845 | pos = params->getPosition().str(); |
846 | } |
847 | isc_throw(DhcpConfigError, "invalid parameter next-server : "do { std::ostringstream oss__; oss__ << "invalid parameter next-server : " << next_server << "(" << pos << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 848, oss__.str().c_str()); } while (1) |
848 | << next_server << "(" << pos << ")")do { std::ostringstream oss__; oss__ << "invalid parameter next-server : " << next_server << "(" << pos << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 848, oss__.str().c_str()); } while (1); |
849 | } |
850 | } |
851 | |
852 | // Set server-hostname. |
853 | if (params->contains("server-hostname")) { |
854 | std::string sname = getString(params, "server-hostname"); |
855 | if (!sname.empty()) { |
856 | if (sname.length() >= Pkt4::MAX_SNAME_LEN) { |
857 | ConstElementPtr error = params->get("server-hostname"); |
858 | isc_throw(DhcpConfigError, "server-hostname must be at most "do { std::ostringstream oss__; oss__ << "server-hostname must be at most " << Pkt4::MAX_SNAME_LEN - 1 << " bytes long, it is " << sname.length() << " (" << error->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 861, oss__.str().c_str()); } while (1) |
859 | << Pkt4::MAX_SNAME_LEN - 1 << " bytes long, it is "do { std::ostringstream oss__; oss__ << "server-hostname must be at most " << Pkt4::MAX_SNAME_LEN - 1 << " bytes long, it is " << sname.length() << " (" << error->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 861, oss__.str().c_str()); } while (1) |
860 | << sname.length() << " ("do { std::ostringstream oss__; oss__ << "server-hostname must be at most " << Pkt4::MAX_SNAME_LEN - 1 << " bytes long, it is " << sname.length() << " (" << error->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 861, oss__.str().c_str()); } while (1) |
861 | << error->getPosition() << ")")do { std::ostringstream oss__; oss__ << "server-hostname must be at most " << Pkt4::MAX_SNAME_LEN - 1 << " bytes long, it is " << sname.length() << " (" << error->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 861, oss__.str().c_str()); } while (1); |
862 | } |
863 | subnet4->setSname(sname); |
864 | } |
865 | } |
866 | |
867 | // Set boot-file-name. |
868 | if (params->contains("boot-file-name")) { |
869 | std::string filename =getString(params, "boot-file-name"); |
870 | if (!filename.empty()) { |
871 | if (filename.length() > Pkt4::MAX_FILE_LEN) { |
872 | ConstElementPtr error = params->get("boot-file-name"); |
873 | isc_throw(DhcpConfigError, "boot-file-name must be at most "do { std::ostringstream oss__; oss__ << "boot-file-name must be at most " << Pkt4::MAX_FILE_LEN - 1 << " bytes long, it is " << filename.length() << " (" << error-> getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 876, oss__.str().c_str()); } while (1) |
874 | << Pkt4::MAX_FILE_LEN - 1 << " bytes long, it is "do { std::ostringstream oss__; oss__ << "boot-file-name must be at most " << Pkt4::MAX_FILE_LEN - 1 << " bytes long, it is " << filename.length() << " (" << error-> getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 876, oss__.str().c_str()); } while (1) |
875 | << filename.length() << " ("do { std::ostringstream oss__; oss__ << "boot-file-name must be at most " << Pkt4::MAX_FILE_LEN - 1 << " bytes long, it is " << filename.length() << " (" << error-> getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 876, oss__.str().c_str()); } while (1) |
876 | << error->getPosition() << ")")do { std::ostringstream oss__; oss__ << "boot-file-name must be at most " << Pkt4::MAX_FILE_LEN - 1 << " bytes long, it is " << filename.length() << " (" << error-> getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 876, oss__.str().c_str()); } while (1); |
877 | } |
878 | subnet4->setFilename(filename); |
879 | } |
880 | } |
881 | |
882 | // Get interface name. If it is defined, then the subnet is available |
883 | // directly over specified network interface. |
884 | if (params->contains("interface")) { |
885 | std::string iface = getString(params, "interface"); |
886 | if (!iface.empty()) { |
887 | if (check_iface_ && !IfaceMgr::instance().getIface(iface)) { |
888 | ConstElementPtr error = params->get("interface"); |
889 | isc_throw(DhcpConfigError, "Specified network interface name " << ifacedo { std::ostringstream oss__; oss__ << "Specified network interface name " << iface << " for subnet " << subnet4-> toText() << " is not present in the system (" << error ->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 892, oss__.str().c_str()); } while (1) |
890 | << " for subnet " << subnet4->toText()do { std::ostringstream oss__; oss__ << "Specified network interface name " << iface << " for subnet " << subnet4-> toText() << " is not present in the system (" << error ->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 892, oss__.str().c_str()); } while (1) |
891 | << " is not present in the system ("do { std::ostringstream oss__; oss__ << "Specified network interface name " << iface << " for subnet " << subnet4-> toText() << " is not present in the system (" << error ->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 892, oss__.str().c_str()); } while (1) |
892 | << error->getPosition() << ")")do { std::ostringstream oss__; oss__ << "Specified network interface name " << iface << " for subnet " << subnet4-> toText() << " is not present in the system (" << error ->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 892, oss__.str().c_str()); } while (1); |
893 | } |
894 | |
895 | subnet4->setIface(iface); |
896 | } |
897 | } |
898 | |
899 | // Try setting up client class. |
900 | if (params->contains("client-class")) { |
901 | string client_class = getString(params, "client-class"); |
902 | if (!client_class.empty()) { |
903 | subnet4->allowClientClass(client_class); |
904 | } |
905 | } |
906 | |
907 | // Setup client class list. |
908 | getClientClassesElem(params, std::bind(&Network::allowClientClass, |
909 | boost::dynamic_pointer_cast<Network>(subnet4), ph::_1)); |
910 | |
911 | // Setup additional class list. |
912 | getAdditionalClassesElem(params, std::bind(&Network::addAdditionalClass, |
913 | boost::dynamic_pointer_cast<Network>(subnet4), ph::_1)); |
914 | |
915 | // 4o6 specific parameter: 4o6-interface. |
916 | if (params->contains("4o6-interface")) { |
917 | string iface4o6 = getString(params, "4o6-interface"); |
918 | if (!iface4o6.empty()) { |
919 | subnet4->get4o6().setIface4o6(iface4o6); |
920 | subnet4->get4o6().enabled(true); |
921 | } |
922 | } |
923 | |
924 | // 4o6 specific parameter: 4o6-subnet. |
925 | if (params->contains("4o6-subnet")) { |
926 | string subnet4o6 = getString(params, "4o6-subnet"); |
927 | if (!subnet4o6.empty()) { |
928 | size_t slash = subnet4o6.find("/"); |
929 | if (slash == std::string::npos) { |
930 | isc_throw(DhcpConfigError, "Missing / in the 4o6-subnet parameter:"do { std::ostringstream oss__; oss__ << "Missing / in the 4o6-subnet parameter:" << subnet4o6 << ", expected format: prefix6/length" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 931, oss__.str().c_str()); } while (1) |
931 | << subnet4o6 << ", expected format: prefix6/length")do { std::ostringstream oss__; oss__ << "Missing / in the 4o6-subnet parameter:" << subnet4o6 << ", expected format: prefix6/length" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 931, oss__.str().c_str()); } while (1); |
932 | } |
933 | string prefix = subnet4o6.substr(0, slash); |
934 | string lenstr = subnet4o6.substr(slash + 1); |
935 | |
936 | len = 128; |
Value stored to 'len' is never read | |
937 | try { |
938 | len = boost::lexical_cast<unsigned int>(lenstr.c_str()); |
939 | } catch (const boost::bad_lexical_cast &) { |
940 | isc_throw(DhcpConfigError, "Invalid prefix length specified in "do { std::ostringstream oss__; oss__ << "Invalid prefix length specified in " "4o6-subnet parameter: " << subnet4o6 << ", expected 0..128 value" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 941, oss__.str().c_str()); } while (1) |
941 | "4o6-subnet parameter: " << subnet4o6 << ", expected 0..128 value")do { std::ostringstream oss__; oss__ << "Invalid prefix length specified in " "4o6-subnet parameter: " << subnet4o6 << ", expected 0..128 value" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 941, oss__.str().c_str()); } while (1); |
942 | } |
943 | subnet4->get4o6().setSubnet4o6(IOAddress(prefix), len); |
944 | subnet4->get4o6().enabled(true); |
945 | } |
946 | } |
947 | |
948 | // Try 4o6 specific parameter: 4o6-interface-id |
949 | if (params->contains("4o6-interface-id")) { |
950 | std::string ifaceid = getString(params, "4o6-interface-id"); |
951 | if (!ifaceid.empty()) { |
952 | OptionBuffer tmp(ifaceid.begin(), ifaceid.end()); |
953 | OptionPtr opt(new Option(Option::V6, D6O_INTERFACE_ID, tmp)); |
954 | subnet4->get4o6().setInterfaceId(opt); |
955 | subnet4->get4o6().enabled(true); |
956 | } |
957 | } |
958 | |
959 | /// client-class processing is now generic and handled in the common |
960 | /// code (see isc::data::SubnetConfigParser::createSubnet) |
961 | |
962 | // Here globally defined options were merged to the subnet specific |
963 | // options but this is no longer the case (they have a different |
964 | // and not consecutive priority). |
965 | |
966 | // Parse t1-percent and t2-percent |
967 | parseTeePercents(params, network); |
968 | |
969 | // Parse DDNS parameters |
970 | parseDdnsParams(params, network); |
971 | |
972 | // Parse lease cache parameters |
973 | parseCacheParams(params, network); |
974 | |
975 | // Parse adaptive lease time parameter. |
976 | parseAdaptiveLeaseTimeParam(params, network); |
977 | |
978 | // Set the offer_lft value for the subnet. |
979 | if (params->contains("offer-lifetime")) { |
980 | uint32_t offer_lft = getInteger(params, "offer-lifetime"); |
981 | subnet4->setOfferLft(offer_lft); |
982 | } |
983 | |
984 | // Parse offer-lifetime parameter. |
985 | Network4Ptr network4 = boost::dynamic_pointer_cast<Network4>(subnet4); |
986 | parseOfferLft(params, network4); |
987 | |
988 | } |
989 | |
990 | void |
991 | Subnet4ConfigParser::validateResv(const Subnet4Ptr& subnet, ConstHostPtr host) { |
992 | const IOAddress& address = host->getIPv4Reservation(); |
993 | if (!address.isV4Zero() && !subnet->inRange(address)) { |
994 | isc_throw(DhcpConfigError, "specified reservation '" << addressdo { std::ostringstream oss__; oss__ << "specified reservation '" << address << "' is not within the IPv4 subnet '" << subnet->toText() << "'"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 996, oss__ .str().c_str()); } while (1) |
995 | << "' is not within the IPv4 subnet '"do { std::ostringstream oss__; oss__ << "specified reservation '" << address << "' is not within the IPv4 subnet '" << subnet->toText() << "'"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 996, oss__ .str().c_str()); } while (1) |
996 | << subnet->toText() << "'")do { std::ostringstream oss__; oss__ << "specified reservation '" << address << "' is not within the IPv4 subnet '" << subnet->toText() << "'"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 996, oss__ .str().c_str()); } while (1); |
997 | } |
998 | } |
999 | |
1000 | boost::shared_ptr<PoolsListParser> |
1001 | Subnet4ConfigParser::createPoolsListParser() const { |
1002 | return (boost::make_shared<Pools4ListParser>()); |
1003 | } |
1004 | |
1005 | //**************************** Subnets4ListConfigParser ********************** |
1006 | |
1007 | Subnets4ListConfigParser::Subnets4ListConfigParser(bool check_iface) |
1008 | : check_iface_(check_iface) { |
1009 | } |
1010 | |
1011 | size_t |
1012 | Subnets4ListConfigParser::parse(SrvConfigPtr cfg, |
1013 | ConstElementPtr subnets_list, |
1014 | bool encapsulate_options) { |
1015 | size_t cnt = 0; |
1016 | for (auto const& subnet_json : subnets_list->listValue()) { |
1017 | |
1018 | auto const& parser = createSubnetConfigParser(); |
1019 | Subnet4Ptr subnet = parser->parse(subnet_json, encapsulate_options); |
1020 | if (subnet) { |
1021 | |
1022 | // Adding a subnet to the Configuration Manager may fail if the |
1023 | // subnet id is invalid (duplicate). Thus, we catch exceptions |
1024 | // here to append a position in the configuration string. |
1025 | try { |
1026 | cfg->getCfgSubnets4()->add(subnet); |
1027 | cnt++; |
1028 | } catch (const std::exception& ex) { |
1029 | isc_throw(DhcpConfigError, ex.what() << " ("do { std::ostringstream oss__; oss__ << ex.what() << " (" << subnet_json->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1030, oss__.str().c_str()); } while (1) |
1030 | << subnet_json->getPosition() << ")")do { std::ostringstream oss__; oss__ << ex.what() << " (" << subnet_json->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1030, oss__.str().c_str()); } while (1); |
1031 | } |
1032 | } |
1033 | } |
1034 | return (cnt); |
1035 | } |
1036 | |
1037 | size_t |
1038 | Subnets4ListConfigParser::parse(Subnet4Collection& subnets, |
1039 | data::ConstElementPtr subnets_list, |
1040 | bool encapsulate_options) { |
1041 | size_t cnt = 0; |
1042 | for (auto const& subnet_json : subnets_list->listValue()) { |
1043 | |
1044 | auto const& parser = createSubnetConfigParser(); |
1045 | Subnet4Ptr subnet = parser->parse(subnet_json, encapsulate_options); |
1046 | if (subnet) { |
1047 | try { |
1048 | auto ret = subnets.insert(subnet); |
1049 | if (!ret.second) { |
1050 | isc_throw(Unexpected,do { std::ostringstream oss__; oss__ << "can't store subnet because of conflict" ; throw Unexpected("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1051, oss__.str().c_str()); } while (1) |
1051 | "can't store subnet because of conflict")do { std::ostringstream oss__; oss__ << "can't store subnet because of conflict" ; throw Unexpected("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1051, oss__.str().c_str()); } while (1); |
1052 | } |
1053 | ++cnt; |
1054 | } catch (const std::exception& ex) { |
1055 | isc_throw(DhcpConfigError, ex.what() << " ("do { std::ostringstream oss__; oss__ << ex.what() << " (" << subnet_json->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1056, oss__.str().c_str()); } while (1) |
1056 | << subnet_json->getPosition() << ")")do { std::ostringstream oss__; oss__ << ex.what() << " (" << subnet_json->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1056, oss__.str().c_str()); } while (1); |
1057 | } |
1058 | } |
1059 | } |
1060 | return (cnt); |
1061 | } |
1062 | |
1063 | boost::shared_ptr<Subnet4ConfigParser> |
1064 | Subnets4ListConfigParser::createSubnetConfigParser() const { |
1065 | return (boost::make_shared<Subnet4ConfigParser>(check_iface_)); |
1066 | } |
1067 | |
1068 | //**************************** Pool6Parser ********************************* |
1069 | |
1070 | PoolPtr |
1071 | Pool6Parser::poolMaker(IOAddress &addr, uint32_t len, int32_t ptype) |
1072 | { |
1073 | return (PoolPtr(new Pool6(static_cast<isc::dhcp::Lease::Type> |
1074 | (ptype), addr, len))); |
1075 | } |
1076 | |
1077 | PoolPtr |
1078 | Pool6Parser::poolMaker(IOAddress &min, IOAddress &max, int32_t ptype) |
1079 | { |
1080 | return (PoolPtr(new Pool6(static_cast<isc::dhcp::Lease::Type> |
1081 | (ptype), min, max))); |
1082 | } |
1083 | |
1084 | |
1085 | //**************************** Pool6ListParser *************************** |
1086 | |
1087 | void |
1088 | Pools6ListParser::parse(PoolStoragePtr pools, ConstElementPtr pools_list, |
1089 | bool encapsulate_options) { |
1090 | for (auto const& pool : pools_list->listValue()) { |
1091 | auto const& parser = createPoolConfigParser(); |
1092 | parser->parse(pools, pool, AF_INET610, encapsulate_options); |
1093 | } |
1094 | } |
1095 | |
1096 | boost::shared_ptr<PoolParser> |
1097 | Pools6ListParser::createPoolConfigParser() const { |
1098 | return (boost::make_shared<Pool6Parser>()); |
1099 | } |
1100 | |
1101 | //**************************** PdPoolParser ****************************** |
1102 | |
1103 | PdPoolParser::PdPoolParser() { |
1104 | } |
1105 | |
1106 | void |
1107 | PdPoolParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool, |
1108 | bool encapsulate_options) { |
1109 | checkKeywords(SimpleParser6::PD_POOL6_PARAMETERS, pd_pool); |
1110 | |
1111 | std::string addr_str = getString(pd_pool, "prefix"); |
1112 | |
1113 | uint8_t prefix_len = getUint8(pd_pool, "prefix-len"); |
1114 | |
1115 | uint8_t delegated_len = getUint8(pd_pool, "delegated-len"); |
1116 | |
1117 | std::string excluded_prefix_str = "::"; |
1118 | if (pd_pool->contains("excluded-prefix")) { |
1119 | excluded_prefix_str = getString(pd_pool, "excluded-prefix"); |
1120 | } |
1121 | |
1122 | uint8_t excluded_prefix_len = 0; |
1123 | if (pd_pool->contains("excluded-prefix-len")) { |
1124 | excluded_prefix_len = getUint8(pd_pool, "excluded-prefix-len"); |
1125 | } |
1126 | |
1127 | ConstElementPtr user_context = pd_pool->get("user-context"); |
1128 | if (user_context) { |
1129 | user_context_ = user_context; |
1130 | } |
1131 | |
1132 | ConstElementPtr client_class = pd_pool->get("client-class"); |
1133 | if (client_class) { |
1134 | client_class_ = client_class; |
1135 | } |
1136 | |
1137 | // Check the pool parameters. It will throw an exception if any |
1138 | // of the required parameters are invalid. |
1139 | try { |
1140 | // Attempt to construct the local pool. |
1141 | pool_.reset(new Pool6(IOAddress(addr_str), |
1142 | prefix_len, |
1143 | delegated_len, |
1144 | IOAddress(excluded_prefix_str), |
1145 | excluded_prefix_len)); |
1146 | } catch (const std::exception& ex) { |
1147 | // Some parameters don't exist or are invalid. Since we are not |
1148 | // aware whether they don't exist or are invalid, let's append |
1149 | // the position of the pool map element. |
1150 | isc_throw(isc::dhcp::DhcpConfigError, ex.what()do { std::ostringstream oss__; oss__ << ex.what() << " (" << pd_pool->getPosition() << ")"; throw isc ::dhcp::DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1151, oss__.str().c_str()); } while (1) |
1151 | << " (" << pd_pool->getPosition() << ")")do { std::ostringstream oss__; oss__ << ex.what() << " (" << pd_pool->getPosition() << ")"; throw isc ::dhcp::DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1151, oss__.str().c_str()); } while (1); |
1152 | } |
1153 | |
1154 | // If there is a pool-id, store it. |
1155 | ConstElementPtr pool_id = pd_pool->get("pool-id"); |
1156 | if (pool_id) { |
1157 | if (pool_id->intValue() <= 0) { |
1158 | isc_throw(BadValue, "pool-id " << pool_id->intValue() << " is not"do { std::ostringstream oss__; oss__ << "pool-id " << pool_id->intValue() << " is not" << " a positive integer greater than 0" ; throw BadValue("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1159, oss__.str().c_str()); } while (1) |
1159 | << " a positive integer greater than 0")do { std::ostringstream oss__; oss__ << "pool-id " << pool_id->intValue() << " is not" << " a positive integer greater than 0" ; throw BadValue("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1159, oss__.str().c_str()); } while (1); |
1160 | } else if (pool_id->intValue() > numeric_limits<uint32_t>::max()) { |
1161 | isc_throw(BadValue, "pool-id " << pool_id->intValue() << " is not"do { std::ostringstream oss__; oss__ << "pool-id " << pool_id->intValue() << " is not" << " a 32 bit unsigned integer" ; throw BadValue("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1162, oss__.str().c_str()); } while (1) |
1162 | << " a 32 bit unsigned integer")do { std::ostringstream oss__; oss__ << "pool-id " << pool_id->intValue() << " is not" << " a 32 bit unsigned integer" ; throw BadValue("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1162, oss__.str().c_str()); } while (1); |
1163 | } |
1164 | |
1165 | pool_->setID(pool_id->intValue()); |
1166 | } |
1167 | |
1168 | // We create subnet first and then parse the options straight into the subnet's |
1169 | // CfgOption structure. Previously, we first parsed the options and then copied |
1170 | // them into the CfgOption after creating the subnet but it had two issues. First, |
1171 | // it cost performance. Second, copying options reset the isEncapsulated() flag. |
1172 | // If the options have been encapsulated we want to preserve the flag to ensure |
1173 | // they are not encapsulated several times. |
1174 | ConstElementPtr option_data = pd_pool->get("option-data"); |
1175 | if (option_data) { |
1176 | auto opts_parser = createOptionDataListParser(); |
1177 | opts_parser->parse(pool_->getCfgOption(), option_data, encapsulate_options); |
1178 | } |
1179 | |
1180 | if (user_context_) { |
1181 | pool_->setContext(user_context_); |
1182 | } |
1183 | |
1184 | if (client_class_) { |
1185 | string cclass = client_class_->stringValue(); |
1186 | if (!cclass.empty()) { |
1187 | pool_->allowClientClass(cclass); |
1188 | } |
1189 | } |
1190 | |
1191 | // Setup client class list. |
1192 | BaseNetworkParser::getClientClassesElem(pd_pool, |
1193 | std::bind(&Pool::allowClientClass, |
1194 | boost::dynamic_pointer_cast<Pool>(pool_), ph::_1)); |
1195 | |
1196 | // Setup additional class list. |
1197 | BaseNetworkParser::getAdditionalClassesElem(pd_pool, |
1198 | std::bind(&Pool::addAdditionalClass, |
1199 | boost::dynamic_pointer_cast<Pool>(pool_), ph::_1)); |
1200 | |
1201 | // Add the local pool to the external storage ptr. |
1202 | pools->push_back(pool_); |
1203 | } |
1204 | |
1205 | boost::shared_ptr<OptionDataListParser> |
1206 | PdPoolParser::createOptionDataListParser() const { |
1207 | return (boost::make_shared<OptionDataListParser>(AF_INET610)); |
1208 | } |
1209 | |
1210 | //**************************** PdPoolsListParser ************************ |
1211 | |
1212 | void |
1213 | PdPoolsListParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_list) { |
1214 | // Loop through the list of pd pools. |
1215 | for (auto const& pd_pool : pd_pool_list->listValue()) { |
1216 | auto const& parser = createPdPoolConfigParser(); |
1217 | parser->parse(pools, pd_pool); |
1218 | } |
1219 | } |
1220 | |
1221 | boost::shared_ptr<PdPoolParser> |
1222 | PdPoolsListParser::createPdPoolConfigParser() const { |
1223 | return (boost::make_shared<PdPoolParser>()); |
1224 | } |
1225 | |
1226 | //**************************** Subnet6ConfigParser *********************** |
1227 | |
1228 | Subnet6ConfigParser::Subnet6ConfigParser(bool check_iface) |
1229 | : SubnetConfigParser(AF_INET610, check_iface) { |
1230 | } |
1231 | |
1232 | Subnet6Ptr |
1233 | Subnet6ConfigParser::parse(ConstElementPtr subnet, bool encapsulate_options) { |
1234 | // Check parameters. |
1235 | checkKeywords(SimpleParser6::SUBNET6_PARAMETERS, subnet); |
1236 | |
1237 | /// Parse all pools first. |
1238 | ConstElementPtr pools = subnet->get("pools"); |
1239 | if (pools) { |
1240 | auto const& parser = createPoolsListParser(); |
1241 | parser->parse(pools_, pools, encapsulate_options); |
1242 | } |
1243 | ConstElementPtr pd_pools = subnet->get("pd-pools"); |
1244 | if (pd_pools) { |
1245 | auto const& parser = createPdPoolsListParser(); |
1246 | parser->parse(pools_, pd_pools); |
1247 | } |
1248 | |
1249 | SubnetPtr generic = SubnetConfigParser::parse(subnet, encapsulate_options); |
1250 | |
1251 | if (!generic) { |
1252 | // Sanity check: not supposed to fail. |
1253 | isc_throw(DhcpConfigError,do { std::ostringstream oss__; oss__ << "Failed to create an IPv6 subnet (" << subnet->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1255, oss__ .str().c_str()); } while (1) |
1254 | "Failed to create an IPv6 subnet (" <<do { std::ostringstream oss__; oss__ << "Failed to create an IPv6 subnet (" << subnet->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1255, oss__ .str().c_str()); } while (1) |
1255 | subnet->getPosition() << ")")do { std::ostringstream oss__; oss__ << "Failed to create an IPv6 subnet (" << subnet->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1255, oss__ .str().c_str()); } while (1); |
1256 | } |
1257 | |
1258 | Subnet6Ptr sn6ptr = boost::dynamic_pointer_cast<Subnet6>(subnet_); |
1259 | if (!sn6ptr) { |
1260 | // If we hit this, it is a programming error. |
1261 | isc_throw(Unexpected,do { std::ostringstream oss__; oss__ << "Invalid Subnet6 cast in Subnet6ConfigParser::parse" ; throw Unexpected("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1262, oss__.str().c_str()); } while (1) |
1262 | "Invalid Subnet6 cast in Subnet6ConfigParser::parse")do { std::ostringstream oss__; oss__ << "Invalid Subnet6 cast in Subnet6ConfigParser::parse" ; throw Unexpected("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1262, oss__.str().c_str()); } while (1); |
1263 | } |
1264 | |
1265 | // Set relay information if it was provided |
1266 | if (relay_info_) { |
1267 | sn6ptr->setRelayInfo(*relay_info_); |
1268 | } |
1269 | |
1270 | // Parse Host Reservations for this subnet if any. |
1271 | ConstElementPtr reservations = subnet->get("reservations"); |
1272 | if (reservations) { |
1273 | HostCollection hosts; |
1274 | HostReservationsListParser<HostReservationParser6> parser; |
1275 | parser.parse(subnet_->getID(), reservations, hosts); |
1276 | for (auto const& h : hosts) { |
1277 | validateResvs(sn6ptr, h); |
1278 | CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(h); |
1279 | } |
1280 | } |
1281 | |
1282 | // Parse allocator specification. |
1283 | auto network = boost::dynamic_pointer_cast<Network>(sn6ptr); |
1284 | parseAllocatorParams(subnet, network); |
1285 | |
1286 | // Parse pd-allocator specification. |
1287 | auto network6 = boost::dynamic_pointer_cast<Network6>(sn6ptr); |
1288 | parsePdAllocatorParams(subnet, network6); |
1289 | |
1290 | // Instantiate the allocators. |
1291 | sn6ptr->createAllocators(); |
1292 | |
1293 | return (sn6ptr); |
1294 | } |
1295 | |
1296 | // Unused? |
1297 | void |
1298 | Subnet6ConfigParser::duplicateOptionWarning(uint32_t code, |
1299 | asiolink::IOAddress& addr) { |
1300 | LOG_WARN(dhcpsrv_logger, DHCPSRV_CFGMGR_OPTION_DUPLICATE)if (!(dhcpsrv_logger).isWarnEnabled()) { } else (dhcpsrv_logger ).warn((DHCPSRV_CFGMGR_OPTION_DUPLICATE)) |
1301 | .arg(code).arg(addr.toText()); |
1302 | } |
1303 | |
1304 | void |
1305 | Subnet6ConfigParser::initSubnet(data::ConstElementPtr params, |
1306 | asiolink::IOAddress addr, uint8_t len) { |
1307 | // Subnet ID is required and must be in 1..SUBNET_ID_MAX. |
1308 | int64_t subnet_id_max = static_cast<int64_t>(SUBNET_ID_MAX); |
1309 | SubnetID subnet_id = static_cast<SubnetID>(getInteger(params, "id", 1, |
1310 | subnet_id_max)); |
1311 | |
1312 | // We want to log whether rapid-commit is enabled, so we get this |
1313 | // before the actual subnet creation. |
1314 | Optional<bool> rapid_commit; |
1315 | if (params->contains("rapid-commit")) { |
1316 | rapid_commit = getBoolean(params, "rapid-commit"); |
1317 | } |
1318 | |
1319 | // Parse preferred lifetime as it is not parsed by the common function. |
1320 | Triplet<uint32_t> pref = parseIntTriplet(params, "preferred-lifetime"); |
1321 | |
1322 | // Create a new subnet. |
1323 | auto subnet6 = Subnet6::create(addr, len, Triplet<uint32_t>(), |
1324 | Triplet<uint32_t>(), |
1325 | pref, |
1326 | Triplet<uint32_t>(), |
1327 | subnet_id); |
1328 | subnet_ = subnet6; |
1329 | |
1330 | ElementPtr mutable_params; |
1331 | mutable_params = boost::const_pointer_cast<Element>(params); |
1332 | |
1333 | // Parse parameters common to all Network derivations. |
1334 | NetworkPtr network = boost::dynamic_pointer_cast<Network>(subnet_); |
1335 | parseCommon(mutable_params, network); |
1336 | |
1337 | // Enable or disable Rapid Commit option support for the subnet. |
1338 | if (!rapid_commit.unspecified()) { |
1339 | subnet6->setRapidCommit(rapid_commit); |
1340 | } |
1341 | |
1342 | std::ostringstream output; |
1343 | output << addr << "/" << static_cast<int>(len) << " with params: "; |
1344 | // t1 and t2 are optional may be not specified. |
1345 | |
1346 | bool has_renew = !subnet6->getT1().unspecified(); |
1347 | bool has_rebind = !subnet6->getT2().unspecified(); |
1348 | int64_t renew = -1; |
1349 | int64_t rebind = -1; |
1350 | |
1351 | if (has_renew) { |
1352 | renew = subnet6->getT1().get(); |
1353 | output << "t1=" << renew << ", "; |
1354 | } |
1355 | if (has_rebind) { |
1356 | rebind = subnet6->getT2().get(); |
1357 | output << "t2=" << rebind << ", "; |
1358 | } |
1359 | |
1360 | if (!subnet6->getPreferred().unspecified()) { |
1361 | output << "preferred-lifetime=" << subnet6->getPreferred().get() << ", "; |
1362 | } |
1363 | if (!subnet6->getValid().unspecified()) { |
1364 | output << "valid-lifetime=" << subnet6->getValid().get(); |
1365 | } |
1366 | if (!subnet6->getRapidCommit().unspecified()) { |
1367 | output << ", rapid-commit is " |
1368 | << boolalpha << subnet6->getRapidCommit().get(); |
1369 | } |
1370 | |
1371 | LOG_INFO(dhcpsrv_logger, DHCPSRV_CFGMGR_NEW_SUBNET6)if (!(dhcpsrv_logger).isInfoEnabled()) { } else (dhcpsrv_logger ).info((DHCPSRV_CFGMGR_NEW_SUBNET6)).arg(output.str()); |
1372 | |
1373 | // Get interface-id option content. For now we support string |
1374 | // representation only |
1375 | Optional<std::string> ifaceid; |
1376 | if (params->contains("interface-id")) { |
1377 | ifaceid = getString(params, "interface-id"); |
1378 | } |
1379 | |
1380 | Optional<std::string> iface; |
1381 | if (params->contains("interface")) { |
1382 | iface = getString(params, "interface"); |
1383 | } |
1384 | |
1385 | // Specifying both interface for locally reachable subnets and |
1386 | // interface id for relays is mutually exclusive. Need to test for |
1387 | // this condition. |
1388 | if (!ifaceid.unspecified() && !iface.unspecified() && !ifaceid.empty() && |
1389 | !iface.empty()) { |
1390 | isc_throw(isc::dhcp::DhcpConfigError,do { std::ostringstream oss__; oss__ << "parser error: interface (defined for locally reachable " "subnets) and interface-id (defined for subnets reachable" " via relays) cannot be defined at the same time for " "subnet " << addr << "/" << (int)len << "(" << params->getPosition() << ")"; throw isc ::dhcp::DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1395, oss__.str().c_str()); } while (1) |
1391 | "parser error: interface (defined for locally reachable "do { std::ostringstream oss__; oss__ << "parser error: interface (defined for locally reachable " "subnets) and interface-id (defined for subnets reachable" " via relays) cannot be defined at the same time for " "subnet " << addr << "/" << (int)len << "(" << params->getPosition() << ")"; throw isc ::dhcp::DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1395, oss__.str().c_str()); } while (1) |
1392 | "subnets) and interface-id (defined for subnets reachable"do { std::ostringstream oss__; oss__ << "parser error: interface (defined for locally reachable " "subnets) and interface-id (defined for subnets reachable" " via relays) cannot be defined at the same time for " "subnet " << addr << "/" << (int)len << "(" << params->getPosition() << ")"; throw isc ::dhcp::DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1395, oss__.str().c_str()); } while (1) |
1393 | " via relays) cannot be defined at the same time for "do { std::ostringstream oss__; oss__ << "parser error: interface (defined for locally reachable " "subnets) and interface-id (defined for subnets reachable" " via relays) cannot be defined at the same time for " "subnet " << addr << "/" << (int)len << "(" << params->getPosition() << ")"; throw isc ::dhcp::DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1395, oss__.str().c_str()); } while (1) |
1394 | "subnet " << addr << "/" << (int)len << "("do { std::ostringstream oss__; oss__ << "parser error: interface (defined for locally reachable " "subnets) and interface-id (defined for subnets reachable" " via relays) cannot be defined at the same time for " "subnet " << addr << "/" << (int)len << "(" << params->getPosition() << ")"; throw isc ::dhcp::DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1395, oss__.str().c_str()); } while (1) |
1395 | << params->getPosition() << ")")do { std::ostringstream oss__; oss__ << "parser error: interface (defined for locally reachable " "subnets) and interface-id (defined for subnets reachable" " via relays) cannot be defined at the same time for " "subnet " << addr << "/" << (int)len << "(" << params->getPosition() << ")"; throw isc ::dhcp::DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1395, oss__.str().c_str()); } while (1); |
1396 | } |
1397 | |
1398 | // Configure interface-id for remote interfaces, if defined |
1399 | if (!ifaceid.unspecified() && !ifaceid.empty()) { |
1400 | std::string ifaceid_value = ifaceid.get(); |
1401 | OptionBuffer tmp(ifaceid_value.begin(), ifaceid_value.end()); |
1402 | OptionPtr opt(new Option(Option::V6, D6O_INTERFACE_ID, tmp)); |
1403 | subnet6->setInterfaceId(opt); |
1404 | } |
1405 | |
1406 | // Get interface name. If it is defined, then the subnet is available |
1407 | // directly over specified network interface. |
1408 | if (!iface.unspecified() && !iface.empty()) { |
1409 | if (check_iface_ && !IfaceMgr::instance().getIface(iface)) { |
1410 | ConstElementPtr error = params->get("interface"); |
1411 | isc_throw(DhcpConfigError, "Specified network interface name " << ifacedo { std::ostringstream oss__; oss__ << "Specified network interface name " << iface << " for subnet " << subnet6-> toText() << " is not present in the system (" << error ->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1414, oss__.str().c_str()); } while (1) |
1412 | << " for subnet " << subnet6->toText()do { std::ostringstream oss__; oss__ << "Specified network interface name " << iface << " for subnet " << subnet6-> toText() << " is not present in the system (" << error ->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1414, oss__.str().c_str()); } while (1) |
1413 | << " is not present in the system ("do { std::ostringstream oss__; oss__ << "Specified network interface name " << iface << " for subnet " << subnet6-> toText() << " is not present in the system (" << error ->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1414, oss__.str().c_str()); } while (1) |
1414 | << error->getPosition() << ")")do { std::ostringstream oss__; oss__ << "Specified network interface name " << iface << " for subnet " << subnet6-> toText() << " is not present in the system (" << error ->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1414, oss__.str().c_str()); } while (1); |
1415 | } |
1416 | |
1417 | subnet6->setIface(iface); |
1418 | } |
1419 | |
1420 | // Try setting up client class. |
1421 | if (params->contains("client-class")) { |
1422 | string client_class = getString(params, "client-class"); |
1423 | if (!client_class.empty()) { |
1424 | subnet6->allowClientClass(client_class); |
1425 | } |
1426 | } |
1427 | |
1428 | // Setup client class list. |
1429 | getClientClassesElem(params, std::bind(&Network::allowClientClass, |
1430 | boost::dynamic_pointer_cast<Network>(subnet6), ph::_1)); |
1431 | |
1432 | // Setup additional class list. |
1433 | getAdditionalClassesElem(params, std::bind(&Network::addAdditionalClass, |
1434 | boost::dynamic_pointer_cast<Network>(subnet6), ph::_1)); |
1435 | |
1436 | /// client-class processing is now generic and handled in the common |
1437 | /// code (see isc::data::SubnetConfigParser::createSubnet) |
1438 | |
1439 | // Parse t1-percent and t2-percent |
1440 | parseTeePercents(params, network); |
1441 | |
1442 | // Parse DDNS parameters |
1443 | parseDdnsParams(params, network); |
1444 | |
1445 | // Parse lease cache parameters |
1446 | parseCacheParams(params, network); |
1447 | |
1448 | // Parse adaptive lease time parameter. |
1449 | parseAdaptiveLeaseTimeParam(params, network); |
1450 | } |
1451 | |
1452 | void |
1453 | Subnet6ConfigParser::validateResvs(const Subnet6Ptr& subnet, ConstHostPtr host) { |
1454 | const IPv6ResrvRange& range = host->getIPv6Reservations(IPv6Resrv::TYPE_NA); |
1455 | BOOST_FOREACH(auto const& it, range)if (boost::foreach_detail_::auto_any_t _foreach_col1455 = boost ::foreach_detail_::contain( (range) , (true ? nullptr : boost ::foreach_detail_::or_( boost::foreach_detail_::is_rvalue_((range ), 0) , boost::foreach_detail_::and_( boost::foreach_detail_:: not_(boost_foreach_is_noncopyable( boost::foreach_detail_::to_ptr (range) , boost_foreach_argument_dependent_lookup_hack_value) ) , boost_foreach_is_lightweight_proxy( boost::foreach_detail_ ::to_ptr(range) , boost_foreach_argument_dependent_lookup_hack_value )))))) {} else if (boost::foreach_detail_::auto_any_t _foreach_cur1455 = boost::foreach_detail_::begin( _foreach_col1455 , (true ? nullptr : boost::foreach_detail_::encode_type(range, boost::foreach_detail_ ::is_const_(range))) , (true ? nullptr : boost::foreach_detail_ ::or_( boost::foreach_detail_::is_rvalue_((range), 0) , boost ::foreach_detail_::and_( boost::foreach_detail_::not_(boost_foreach_is_noncopyable ( boost::foreach_detail_::to_ptr(range) , boost_foreach_argument_dependent_lookup_hack_value )) , boost_foreach_is_lightweight_proxy( boost::foreach_detail_ ::to_ptr(range) , boost_foreach_argument_dependent_lookup_hack_value )))))) {} else if (boost::foreach_detail_::auto_any_t _foreach_end1455 = boost::foreach_detail_::end( _foreach_col1455 , (true ? nullptr : boost::foreach_detail_::encode_type(range, boost::foreach_detail_ ::is_const_(range))) , (true ? nullptr : boost::foreach_detail_ ::or_( boost::foreach_detail_::is_rvalue_((range), 0) , boost ::foreach_detail_::and_( boost::foreach_detail_::not_(boost_foreach_is_noncopyable ( boost::foreach_detail_::to_ptr(range) , boost_foreach_argument_dependent_lookup_hack_value )) , boost_foreach_is_lightweight_proxy( boost::foreach_detail_ ::to_ptr(range) , boost_foreach_argument_dependent_lookup_hack_value )))))) {} else for (bool _foreach_continue1455 = true; _foreach_continue1455 && !boost::foreach_detail_::done( _foreach_cur1455 , _foreach_end1455 , (true ? nullptr : boost::foreach_detail_:: encode_type(range, boost::foreach_detail_::is_const_(range))) ); _foreach_continue1455 ? boost::foreach_detail_::next( _foreach_cur1455 , (true ? nullptr : boost::foreach_detail_::encode_type(range , boost::foreach_detail_::is_const_(range)))) : (void)0) if ( boost::foreach_detail_::set_false(_foreach_continue1455)) {} else for (auto const& it = boost::foreach_detail_::deref( _foreach_cur1455 , (true ? nullptr : boost::foreach_detail_::encode_type(range , boost::foreach_detail_::is_const_(range)))); !_foreach_continue1455 ; _foreach_continue1455 = true) { |
1456 | const IOAddress& address = it.second.getPrefix(); |
1457 | if (!subnet->inRange(address)) { |
1458 | isc_throw(DhcpConfigError, "specified reservation '" << addressdo { std::ostringstream oss__; oss__ << "specified reservation '" << address << "' is not within the IPv6 subnet '" << subnet->toText() << "'"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1460, oss__ .str().c_str()); } while (1) |
1459 | << "' is not within the IPv6 subnet '"do { std::ostringstream oss__; oss__ << "specified reservation '" << address << "' is not within the IPv6 subnet '" << subnet->toText() << "'"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1460, oss__ .str().c_str()); } while (1) |
1460 | << subnet->toText() << "'")do { std::ostringstream oss__; oss__ << "specified reservation '" << address << "' is not within the IPv6 subnet '" << subnet->toText() << "'"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1460, oss__ .str().c_str()); } while (1); |
1461 | } |
1462 | } |
1463 | } |
1464 | |
1465 | boost::shared_ptr<PoolsListParser> |
1466 | Subnet6ConfigParser::createPoolsListParser() const { |
1467 | return (boost::make_shared<Pools6ListParser>()); |
1468 | } |
1469 | |
1470 | boost::shared_ptr<PdPoolsListParser> |
1471 | Subnet6ConfigParser::createPdPoolsListParser() const { |
1472 | return (boost::make_shared<PdPoolsListParser>()); |
1473 | } |
1474 | |
1475 | //**************************** Subnet6ListConfigParser ******************** |
1476 | |
1477 | Subnets6ListConfigParser::Subnets6ListConfigParser(bool check_iface) |
1478 | : check_iface_(check_iface) { |
1479 | } |
1480 | |
1481 | size_t |
1482 | Subnets6ListConfigParser::parse(SrvConfigPtr cfg, |
1483 | ConstElementPtr subnets_list, |
1484 | bool encapsulate_options) { |
1485 | size_t cnt = 0; |
1486 | for (auto const& subnet_json : subnets_list->listValue()) { |
1487 | |
1488 | auto const& parser = createSubnetConfigParser(); |
1489 | Subnet6Ptr subnet = parser->parse(subnet_json, encapsulate_options); |
1490 | |
1491 | // Adding a subnet to the Configuration Manager may fail if the |
1492 | // subnet id is invalid (duplicate). Thus, we catch exceptions |
1493 | // here to append a position in the configuration string. |
1494 | try { |
1495 | cfg->getCfgSubnets6()->add(subnet); |
1496 | cnt++; |
1497 | } catch (const std::exception& ex) { |
1498 | isc_throw(DhcpConfigError, ex.what() << " ("do { std::ostringstream oss__; oss__ << ex.what() << " (" << subnet_json->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1499, oss__.str().c_str()); } while (1) |
1499 | << subnet_json->getPosition() << ")")do { std::ostringstream oss__; oss__ << ex.what() << " (" << subnet_json->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1499, oss__.str().c_str()); } while (1); |
1500 | } |
1501 | } |
1502 | return (cnt); |
1503 | } |
1504 | |
1505 | size_t |
1506 | Subnets6ListConfigParser::parse(Subnet6Collection& subnets, |
1507 | ConstElementPtr subnets_list, |
1508 | bool encapsulate_options) { |
1509 | size_t cnt = 0; |
1510 | for (auto const& subnet_json : subnets_list->listValue()) { |
1511 | |
1512 | auto const& parser = createSubnetConfigParser(); |
1513 | Subnet6Ptr subnet = parser->parse(subnet_json, encapsulate_options); |
1514 | if (subnet) { |
1515 | try { |
1516 | auto ret = subnets.insert(subnet); |
1517 | if (!ret.second) { |
1518 | isc_throw(Unexpected,do { std::ostringstream oss__; oss__ << "can't store subnet because of conflict" ; throw Unexpected("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1519, oss__.str().c_str()); } while (1) |
1519 | "can't store subnet because of conflict")do { std::ostringstream oss__; oss__ << "can't store subnet because of conflict" ; throw Unexpected("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1519, oss__.str().c_str()); } while (1); |
1520 | } |
1521 | ++cnt; |
1522 | } catch (const std::exception& ex) { |
1523 | isc_throw(DhcpConfigError, ex.what() << " ("do { std::ostringstream oss__; oss__ << ex.what() << " (" << subnet_json->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1524, oss__.str().c_str()); } while (1) |
1524 | << subnet_json->getPosition() << ")")do { std::ostringstream oss__; oss__ << ex.what() << " (" << subnet_json->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1524, oss__.str().c_str()); } while (1); |
1525 | } |
1526 | } |
1527 | } |
1528 | return (cnt); |
1529 | } |
1530 | |
1531 | boost::shared_ptr<Subnet6ConfigParser> |
1532 | Subnets6ListConfigParser::createSubnetConfigParser() const { |
1533 | return (boost::make_shared<Subnet6ConfigParser>(check_iface_)); |
1534 | } |
1535 | |
1536 | //**************************** D2ClientConfigParser ********************** |
1537 | |
1538 | dhcp_ddns::NameChangeProtocol |
1539 | D2ClientConfigParser::getProtocol(ConstElementPtr scope, |
1540 | const std::string& name) { |
1541 | return (getAndConvert<dhcp_ddns::NameChangeProtocol, |
1542 | dhcp_ddns::stringToNcrProtocol> |
1543 | (scope, name, "NameChangeRequest protocol")); |
1544 | } |
1545 | |
1546 | dhcp_ddns::NameChangeFormat |
1547 | D2ClientConfigParser::getFormat(ConstElementPtr scope, |
1548 | const std::string& name) { |
1549 | return (getAndConvert<dhcp_ddns::NameChangeFormat, |
1550 | dhcp_ddns::stringToNcrFormat> |
1551 | (scope, name, "NameChangeRequest format")); |
1552 | } |
1553 | |
1554 | D2ClientConfig::ReplaceClientNameMode |
1555 | D2ClientConfigParser::getMode(ConstElementPtr scope, |
1556 | const std::string& name) { |
1557 | return (getAndConvert<D2ClientConfig::ReplaceClientNameMode, |
1558 | D2ClientConfig::stringToReplaceClientNameMode> |
1559 | (scope, name, "ReplaceClientName mode")); |
1560 | } |
1561 | |
1562 | D2ClientConfigPtr |
1563 | D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) { |
1564 | D2ClientConfigPtr new_config; |
1565 | |
1566 | // Get all parameters that are needed to create the D2ClientConfig. |
1567 | bool enable_updates = getBoolean(client_config, "enable-updates"); |
1568 | |
1569 | IOAddress server_ip = getAddress(client_config, "server-ip"); |
1570 | |
1571 | uint32_t server_port = getUint32(client_config, "server-port"); |
1572 | |
1573 | std::string sender_ip_str = getString(client_config, "sender-ip"); |
1574 | |
1575 | uint32_t sender_port = getUint32(client_config, "sender-port"); |
1576 | |
1577 | uint32_t max_queue_size = getUint32(client_config, "max-queue-size"); |
1578 | |
1579 | dhcp_ddns::NameChangeProtocol ncr_protocol = |
1580 | getProtocol(client_config, "ncr-protocol"); |
1581 | |
1582 | dhcp_ddns::NameChangeFormat ncr_format = |
1583 | getFormat(client_config, "ncr-format"); |
1584 | |
1585 | IOAddress sender_ip(0); |
1586 | if (sender_ip_str.empty()) { |
1587 | // The default sender IP depends on the server IP family |
1588 | sender_ip = (server_ip.isV4() ? IOAddress::IPV4_ZERO_ADDRESS() : |
1589 | IOAddress::IPV6_ZERO_ADDRESS()); |
1590 | } else { |
1591 | try { |
1592 | sender_ip = IOAddress(sender_ip_str); |
1593 | } catch (const std::exception& ex) { |
1594 | isc_throw(DhcpConfigError, "invalid address (" << sender_ip_strdo { std::ostringstream oss__; oss__ << "invalid address (" << sender_ip_str << ") specified for parameter 'sender-ip' (" << getPosition("sender-ip", client_config) << ")" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1596, oss__.str().c_str()); } while (1) |
1595 | << ") specified for parameter 'sender-ip' ("do { std::ostringstream oss__; oss__ << "invalid address (" << sender_ip_str << ") specified for parameter 'sender-ip' (" << getPosition("sender-ip", client_config) << ")" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1596, oss__.str().c_str()); } while (1) |
1596 | << getPosition("sender-ip", client_config) << ")")do { std::ostringstream oss__; oss__ << "invalid address (" << sender_ip_str << ") specified for parameter 'sender-ip' (" << getPosition("sender-ip", client_config) << ")" ; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1596, oss__.str().c_str()); } while (1); |
1597 | } |
1598 | } |
1599 | |
1600 | // Now we check for logical errors. This repeats what is done in |
1601 | // D2ClientConfig::validate(), but doing it here permits us to |
1602 | // emit meaningful parameter position info in the error. |
1603 | if (ncr_format != dhcp_ddns::FMT_JSON) { |
1604 | isc_throw(D2ClientError, "D2ClientConfig error: NCR Format: "do { std::ostringstream oss__; oss__ << "D2ClientConfig error: NCR Format: " << dhcp_ddns::ncrFormatToString(ncr_format) << " is not supported. (" << getPosition("ncr-format", client_config) << ")" ; throw D2ClientError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1607, oss__.str().c_str()); } while (1) |
1605 | << dhcp_ddns::ncrFormatToString(ncr_format)do { std::ostringstream oss__; oss__ << "D2ClientConfig error: NCR Format: " << dhcp_ddns::ncrFormatToString(ncr_format) << " is not supported. (" << getPosition("ncr-format", client_config) << ")" ; throw D2ClientError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1607, oss__.str().c_str()); } while (1) |
1606 | << " is not supported. ("do { std::ostringstream oss__; oss__ << "D2ClientConfig error: NCR Format: " << dhcp_ddns::ncrFormatToString(ncr_format) << " is not supported. (" << getPosition("ncr-format", client_config) << ")" ; throw D2ClientError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1607, oss__.str().c_str()); } while (1) |
1607 | << getPosition("ncr-format", client_config) << ")")do { std::ostringstream oss__; oss__ << "D2ClientConfig error: NCR Format: " << dhcp_ddns::ncrFormatToString(ncr_format) << " is not supported. (" << getPosition("ncr-format", client_config) << ")" ; throw D2ClientError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1607, oss__.str().c_str()); } while (1); |
1608 | } |
1609 | |
1610 | if (ncr_protocol != dhcp_ddns::NCR_UDP) { |
1611 | isc_throw(D2ClientError, "D2ClientConfig error: NCR Protocol: "do { std::ostringstream oss__; oss__ << "D2ClientConfig error: NCR Protocol: " << dhcp_ddns::ncrProtocolToString(ncr_protocol) << " is not supported. (" << getPosition("ncr-protocol", client_config ) << ")"; throw D2ClientError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1614, oss__.str().c_str()); } while (1) |
1612 | << dhcp_ddns::ncrProtocolToString(ncr_protocol)do { std::ostringstream oss__; oss__ << "D2ClientConfig error: NCR Protocol: " << dhcp_ddns::ncrProtocolToString(ncr_protocol) << " is not supported. (" << getPosition("ncr-protocol", client_config ) << ")"; throw D2ClientError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1614, oss__.str().c_str()); } while (1) |
1613 | << " is not supported. ("do { std::ostringstream oss__; oss__ << "D2ClientConfig error: NCR Protocol: " << dhcp_ddns::ncrProtocolToString(ncr_protocol) << " is not supported. (" << getPosition("ncr-protocol", client_config ) << ")"; throw D2ClientError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1614, oss__.str().c_str()); } while (1) |
1614 | << getPosition("ncr-protocol", client_config) << ")")do { std::ostringstream oss__; oss__ << "D2ClientConfig error: NCR Protocol: " << dhcp_ddns::ncrProtocolToString(ncr_protocol) << " is not supported. (" << getPosition("ncr-protocol", client_config ) << ")"; throw D2ClientError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1614, oss__.str().c_str()); } while (1); |
1615 | } |
1616 | |
1617 | if (sender_ip.getFamily() != server_ip.getFamily()) { |
1618 | isc_throw(D2ClientError,do { std::ostringstream oss__; oss__ << "D2ClientConfig error: address family mismatch: " << "server-ip: " << server_ip.toText() << " is: " << (server_ip.isV4() ? "IPv4" : "IPv6") << " while sender-ip: " << sender_ip.toText() << " is: " << (sender_ip .isV4() ? "IPv4" : "IPv6") << " (" << getPosition ("sender-ip", client_config) << ")"; throw D2ClientError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1624, oss__ .str().c_str()); } while (1) |
1619 | "D2ClientConfig error: address family mismatch: "do { std::ostringstream oss__; oss__ << "D2ClientConfig error: address family mismatch: " << "server-ip: " << server_ip.toText() << " is: " << (server_ip.isV4() ? "IPv4" : "IPv6") << " while sender-ip: " << sender_ip.toText() << " is: " << (sender_ip .isV4() ? "IPv4" : "IPv6") << " (" << getPosition ("sender-ip", client_config) << ")"; throw D2ClientError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1624, oss__ .str().c_str()); } while (1) |
1620 | << "server-ip: " << server_ip.toText()do { std::ostringstream oss__; oss__ << "D2ClientConfig error: address family mismatch: " << "server-ip: " << server_ip.toText() << " is: " << (server_ip.isV4() ? "IPv4" : "IPv6") << " while sender-ip: " << sender_ip.toText() << " is: " << (sender_ip .isV4() ? "IPv4" : "IPv6") << " (" << getPosition ("sender-ip", client_config) << ")"; throw D2ClientError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1624, oss__ .str().c_str()); } while (1) |
1621 | << " is: " << (server_ip.isV4() ? "IPv4" : "IPv6")do { std::ostringstream oss__; oss__ << "D2ClientConfig error: address family mismatch: " << "server-ip: " << server_ip.toText() << " is: " << (server_ip.isV4() ? "IPv4" : "IPv6") << " while sender-ip: " << sender_ip.toText() << " is: " << (sender_ip .isV4() ? "IPv4" : "IPv6") << " (" << getPosition ("sender-ip", client_config) << ")"; throw D2ClientError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1624, oss__ .str().c_str()); } while (1) |
1622 | << " while sender-ip: " << sender_ip.toText()do { std::ostringstream oss__; oss__ << "D2ClientConfig error: address family mismatch: " << "server-ip: " << server_ip.toText() << " is: " << (server_ip.isV4() ? "IPv4" : "IPv6") << " while sender-ip: " << sender_ip.toText() << " is: " << (sender_ip .isV4() ? "IPv4" : "IPv6") << " (" << getPosition ("sender-ip", client_config) << ")"; throw D2ClientError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1624, oss__ .str().c_str()); } while (1) |
1623 | << " is: " << (sender_ip.isV4() ? "IPv4" : "IPv6")do { std::ostringstream oss__; oss__ << "D2ClientConfig error: address family mismatch: " << "server-ip: " << server_ip.toText() << " is: " << (server_ip.isV4() ? "IPv4" : "IPv6") << " while sender-ip: " << sender_ip.toText() << " is: " << (sender_ip .isV4() ? "IPv4" : "IPv6") << " (" << getPosition ("sender-ip", client_config) << ")"; throw D2ClientError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1624, oss__ .str().c_str()); } while (1) |
1624 | << " (" << getPosition("sender-ip", client_config) << ")")do { std::ostringstream oss__; oss__ << "D2ClientConfig error: address family mismatch: " << "server-ip: " << server_ip.toText() << " is: " << (server_ip.isV4() ? "IPv4" : "IPv6") << " while sender-ip: " << sender_ip.toText() << " is: " << (sender_ip .isV4() ? "IPv4" : "IPv6") << " (" << getPosition ("sender-ip", client_config) << ")"; throw D2ClientError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1624, oss__ .str().c_str()); } while (1); |
1625 | } |
1626 | |
1627 | if (server_ip == sender_ip && server_port == sender_port) { |
1628 | isc_throw(D2ClientError,do { std::ostringstream oss__; oss__ << "D2ClientConfig error: server and sender cannot" " share the exact same IP address/port: " << server_ip .toText() << "/" << server_port << " (" << getPosition("sender-ip", client_config) << ")"; throw D2ClientError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1632, oss__ .str().c_str()); } while (1) |
1629 | "D2ClientConfig error: server and sender cannot"do { std::ostringstream oss__; oss__ << "D2ClientConfig error: server and sender cannot" " share the exact same IP address/port: " << server_ip .toText() << "/" << server_port << " (" << getPosition("sender-ip", client_config) << ")"; throw D2ClientError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1632, oss__ .str().c_str()); } while (1) |
1630 | " share the exact same IP address/port: "do { std::ostringstream oss__; oss__ << "D2ClientConfig error: server and sender cannot" " share the exact same IP address/port: " << server_ip .toText() << "/" << server_port << " (" << getPosition("sender-ip", client_config) << ")"; throw D2ClientError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1632, oss__ .str().c_str()); } while (1) |
1631 | << server_ip.toText() << "/" << server_portdo { std::ostringstream oss__; oss__ << "D2ClientConfig error: server and sender cannot" " share the exact same IP address/port: " << server_ip .toText() << "/" << server_port << " (" << getPosition("sender-ip", client_config) << ")"; throw D2ClientError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1632, oss__ .str().c_str()); } while (1) |
1632 | << " (" << getPosition("sender-ip", client_config) << ")")do { std::ostringstream oss__; oss__ << "D2ClientConfig error: server and sender cannot" " share the exact same IP address/port: " << server_ip .toText() << "/" << server_port << " (" << getPosition("sender-ip", client_config) << ")"; throw D2ClientError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1632, oss__ .str().c_str()); } while (1); |
1633 | } |
1634 | |
1635 | try { |
1636 | // Attempt to create the new client config. |
1637 | new_config.reset(new D2ClientConfig(enable_updates, |
1638 | server_ip, |
1639 | server_port, |
1640 | sender_ip, |
1641 | sender_port, |
1642 | max_queue_size, |
1643 | ncr_protocol, |
1644 | ncr_format)); |
1645 | } catch (const std::exception& ex) { |
1646 | isc_throw(DhcpConfigError, ex.what() << " ("do { std::ostringstream oss__; oss__ << ex.what() << " (" << client_config->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1647, oss__.str().c_str()); } while (1) |
1647 | << client_config->getPosition() << ")")do { std::ostringstream oss__; oss__ << ex.what() << " (" << client_config->getPosition() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1647, oss__.str().c_str()); } while (1); |
1648 | } |
1649 | |
1650 | // Add user context |
1651 | ConstElementPtr user_context = client_config->get("user-context"); |
1652 | if (user_context) { |
1653 | new_config->setContext(user_context); |
1654 | } |
1655 | |
1656 | return (new_config); |
1657 | } |
1658 | |
1659 | /// @brief This table defines default values for D2 client configuration |
1660 | const SimpleDefaults D2ClientConfigParser::D2_CLIENT_CONFIG_DEFAULTS = { |
1661 | // enable-updates is unconditionally required |
1662 | { "server-ip", Element::string, "127.0.0.1" }, |
1663 | { "server-port", Element::integer, "53001" }, |
1664 | // default sender-ip depends on server-ip family, so we leave default blank |
1665 | // parser knows to use the appropriate ZERO address based on server-ip |
1666 | { "sender-ip", Element::string, "" }, |
1667 | { "sender-port", Element::integer, "0" }, |
1668 | { "max-queue-size", Element::integer, "1024" }, |
1669 | { "ncr-protocol", Element::string, "UDP" }, |
1670 | { "ncr-format", Element::string, "JSON" } |
1671 | }; |
1672 | |
1673 | size_t |
1674 | D2ClientConfigParser::setAllDefaults(isc::data::ConstElementPtr d2_config) { |
1675 | ElementPtr mutable_d2 = boost::const_pointer_cast<Element>(d2_config); |
1676 | return (SimpleParser::setDefaults(mutable_d2, D2_CLIENT_CONFIG_DEFAULTS)); |
1677 | } |
1678 | |
1679 | void |
1680 | CompatibilityParser::parse(ConstElementPtr compatibility, SrvConfig& srv_cfg) { |
1681 | if (compatibility) { |
1682 | auto family = CfgMgr::instance().getFamily(); |
1683 | for (auto const& kv : compatibility->mapValue()) { |
1684 | if (!kv.second || (kv.second->getType() != Element::boolean)) { |
1685 | isc_throw(DhcpConfigError,do { std::ostringstream oss__; oss__ << "compatibility parameter values must be " << "boolean (" << kv.first << " at " << kv.second->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1688, oss__ .str().c_str()); } while (1) |
1686 | "compatibility parameter values must be "do { std::ostringstream oss__; oss__ << "compatibility parameter values must be " << "boolean (" << kv.first << " at " << kv.second->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1688, oss__ .str().c_str()); } while (1) |
1687 | << "boolean (" << kv.first << " at "do { std::ostringstream oss__; oss__ << "compatibility parameter values must be " << "boolean (" << kv.first << " at " << kv.second->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1688, oss__ .str().c_str()); } while (1) |
1688 | << kv.second->getPosition() << ")")do { std::ostringstream oss__; oss__ << "compatibility parameter values must be " << "boolean (" << kv.first << " at " << kv.second->getPosition() << ")"; throw DhcpConfigError ("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1688, oss__ .str().c_str()); } while (1); |
1689 | } |
1690 | if (kv.first == "lenient-option-parsing") { |
1691 | srv_cfg.setLenientOptionParsing(kv.second->boolValue()); |
1692 | } else if (family == AF_INET2) { |
1693 | if (kv.first == "ignore-dhcp-server-identifier") { |
1694 | srv_cfg.setIgnoreServerIdentifier(kv.second->boolValue()); |
1695 | } else if (kv.first == "ignore-rai-link-selection") { |
1696 | srv_cfg.setIgnoreRAILinkSelection(kv.second->boolValue()); |
1697 | } else if (kv.first == "exclude-first-last-24") { |
1698 | srv_cfg.setExcludeFirstLast24(kv.second->boolValue()); |
1699 | } else { |
1700 | isc_throw(DhcpConfigError,do { std::ostringstream oss__; oss__ << "unsupported compatibility parameter: " << kv.first << " (" << kv.second->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1703, oss__.str().c_str()); } while (1) |
1701 | "unsupported compatibility parameter: "do { std::ostringstream oss__; oss__ << "unsupported compatibility parameter: " << kv.first << " (" << kv.second->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1703, oss__.str().c_str()); } while (1) |
1702 | << kv.first << " (" << kv.second->getPosition()do { std::ostringstream oss__; oss__ << "unsupported compatibility parameter: " << kv.first << " (" << kv.second->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1703, oss__.str().c_str()); } while (1) |
1703 | << ")")do { std::ostringstream oss__; oss__ << "unsupported compatibility parameter: " << kv.first << " (" << kv.second->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1703, oss__.str().c_str()); } while (1); |
1704 | } |
1705 | } else { |
1706 | isc_throw(DhcpConfigError,do { std::ostringstream oss__; oss__ << "unsupported compatibility parameter: " << kv.first << " (" << kv.second->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1709, oss__.str().c_str()); } while (1) |
1707 | "unsupported compatibility parameter: "do { std::ostringstream oss__; oss__ << "unsupported compatibility parameter: " << kv.first << " (" << kv.second->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1709, oss__.str().c_str()); } while (1) |
1708 | << kv.first << " (" << kv.second->getPosition()do { std::ostringstream oss__; oss__ << "unsupported compatibility parameter: " << kv.first << " (" << kv.second->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1709, oss__.str().c_str()); } while (1) |
1709 | << ")")do { std::ostringstream oss__; oss__ << "unsupported compatibility parameter: " << kv.first << " (" << kv.second->getPosition () << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc" , 1709, oss__.str().c_str()); } while (1); |
1710 | } |
1711 | } |
1712 | } |
1713 | } |
1714 | |
1715 | } // namespace dhcp |
1716 | } // namespace isc |