Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name dhcp_parsers.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-private/tmphs1g5w79 -fcoverage-compilation-dir=/home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-private/tmphs1g5w79 -resource-dir /usr/bin/../lib/clang/20 -I src/lib/dhcpsrv/libkea-dhcpsrv.so.142.0.0.p -I src/lib/dhcpsrv -I ../../../src/lib/dhcpsrv -I . -I ../../.. -I src -I ../../../src -I src/bin -I ../../../src/bin -I src/lib -I ../../../src/lib -I /usr/include -D _GLIBCXX_ASSERTIONS=1 -D _FILE_OFFSET_BITS=64 -D BOOST_ALL_NO_LIB -D DHCP_DATA_DIR="/usr/local/var/lib/kea" -D KEA_LFC_EXECUTABLE="/usr/local/sbin/kea-lfc" -D LEGAL_LOG_DIR="/usr/local/var/log/kea" -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/15/../../../../include/c++/15 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/15/../../../../include/c++/15/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/15/../../../../include/c++/15/backward -internal-isystem /usr/bin/../lib/clang/20/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/15/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wwrite-strings -Wno-missing-field-initializers -fdeprecated-macro -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-logs/scanbuild/2025-10-17-063701-9203-1 -x c++ ../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc
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
39using namespace std;
40using namespace isc::asiolink;
41using namespace isc::config;
42using namespace isc::data;
43using namespace isc::util;
44namespace ph = std::placeholders;
45
46namespace isc {
47namespace dhcp {
48
49// ******************** MACSourcesListConfigParser *************************
50
51void
52MACSourcesListConfigParser::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 *************************
82void 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
136OptionDefParser::OptionDefParser(const uint16_t address_family)
137 : address_family_(address_family) {
138}
139
140OptionDefinitionPtr
141OptionDefParser::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
278OptionDefListParser::OptionDefListParser(const uint16_t address_family)
279 : address_family_(address_family) {
280}
281
282void
283OptionDefListParser::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 ********************************
309RelayInfoParser::RelayInfoParser(const Option::Universe& family)
310 : family_(family) {
311};
312
313void
314RelayInfoParser::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
340void
341RelayInfoParser::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
377void
378PoolParser::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
546boost::shared_ptr<OptionDataListParser>
547PoolParser::createOptionDataListParser(const uint16_t address_family) const {
548 return (boost::make_shared<OptionDataListParser>(address_family));
549}
550
551//****************************** Pool4Parser *************************
552
553PoolPtr
554Pool4Parser::poolMaker (IOAddress &addr, uint32_t len, int32_t) {
555 return (PoolPtr(new Pool4(addr, len)));
556}
557
558PoolPtr
559Pool4Parser::poolMaker (IOAddress &min, IOAddress &max, int32_t) {
560 return (PoolPtr(new Pool4(min, max)));
561}
562
563//****************************** Pools4ListParser *************************
564
565void
566Pools4ListParser::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
574boost::shared_ptr<PoolParser>
575Pools4ListParser::createPoolConfigParser() const {
576 return (boost::make_shared<Pool4Parser>());
577}
578
579//****************************** SubnetConfigParser *************************
580
581SubnetConfigParser::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
588SubnetPtr
589SubnetConfigParser::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
621void
622SubnetConfigParser::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
707boost::shared_ptr<OptionDataListParser>
708SubnetConfigParser::createOptionDataListParser() const {
709 return (boost::make_shared<OptionDataListParser>(address_family_));
710}
711
712//****************************** Subnet4ConfigParser *************************
713
714Subnet4ConfigParser::Subnet4ConfigParser(bool check_iface)
715 : SubnetConfigParser(AF_INET2, check_iface) {
716}
717
718Subnet4Ptr
719Subnet4ConfigParser::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
773void
774Subnet4ConfigParser::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
990void
991Subnet4ConfigParser::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
1000boost::shared_ptr<PoolsListParser>
1001Subnet4ConfigParser::createPoolsListParser() const {
1002 return (boost::make_shared<Pools4ListParser>());
1003}
1004
1005//**************************** Subnets4ListConfigParser **********************
1006
1007Subnets4ListConfigParser::Subnets4ListConfigParser(bool check_iface)
1008 : check_iface_(check_iface) {
1009}
1010
1011size_t
1012Subnets4ListConfigParser::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
1037size_t
1038Subnets4ListConfigParser::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
1063boost::shared_ptr<Subnet4ConfigParser>
1064Subnets4ListConfigParser::createSubnetConfigParser() const {
1065 return (boost::make_shared<Subnet4ConfigParser>(check_iface_));
1066}
1067
1068//**************************** Pool6Parser *********************************
1069
1070PoolPtr
1071Pool6Parser::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
1077PoolPtr
1078Pool6Parser::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
1087void
1088Pools6ListParser::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
1096boost::shared_ptr<PoolParser>
1097Pools6ListParser::createPoolConfigParser() const {
1098 return (boost::make_shared<Pool6Parser>());
1099}
1100
1101//**************************** PdPoolParser ******************************
1102
1103PdPoolParser::PdPoolParser() {
1104}
1105
1106void
1107PdPoolParser::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
1205boost::shared_ptr<OptionDataListParser>
1206PdPoolParser::createOptionDataListParser() const {
1207 return (boost::make_shared<OptionDataListParser>(AF_INET610));
1208}
1209
1210//**************************** PdPoolsListParser ************************
1211
1212void
1213PdPoolsListParser::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
1221boost::shared_ptr<PdPoolParser>
1222PdPoolsListParser::createPdPoolConfigParser() const {
1223 return (boost::make_shared<PdPoolParser>());
1224}
1225
1226//**************************** Subnet6ConfigParser ***********************
1227
1228Subnet6ConfigParser::Subnet6ConfigParser(bool check_iface)
1229 : SubnetConfigParser(AF_INET610, check_iface) {
1230}
1231
1232Subnet6Ptr
1233Subnet6ConfigParser::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?
1297void
1298Subnet6ConfigParser::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
1304void
1305Subnet6ConfigParser::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
1452void
1453Subnet6ConfigParser::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
1465boost::shared_ptr<PoolsListParser>
1466Subnet6ConfigParser::createPoolsListParser() const {
1467 return (boost::make_shared<Pools6ListParser>());
1468}
1469
1470boost::shared_ptr<PdPoolsListParser>
1471Subnet6ConfigParser::createPdPoolsListParser() const {
1472 return (boost::make_shared<PdPoolsListParser>());
1473}
1474
1475//**************************** Subnet6ListConfigParser ********************
1476
1477Subnets6ListConfigParser::Subnets6ListConfigParser(bool check_iface)
1478 : check_iface_(check_iface) {
1479}
1480
1481size_t
1482Subnets6ListConfigParser::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
1505size_t
1506Subnets6ListConfigParser::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
1531boost::shared_ptr<Subnet6ConfigParser>
1532Subnets6ListConfigParser::createSubnetConfigParser() const {
1533 return (boost::make_shared<Subnet6ConfigParser>(check_iface_));
1534}
1535
1536//**************************** D2ClientConfigParser **********************
1537
1538dhcp_ddns::NameChangeProtocol
1539D2ClientConfigParser::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
1546dhcp_ddns::NameChangeFormat
1547D2ClientConfigParser::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
1554D2ClientConfig::ReplaceClientNameMode
1555D2ClientConfigParser::getMode(ConstElementPtr scope,
1556 const std::string& name) {
1557 return (getAndConvert<D2ClientConfig::ReplaceClientNameMode,
1558 D2ClientConfig::stringToReplaceClientNameMode>
1559 (scope, name, "ReplaceClientName mode"));
1560}
1561
1562D2ClientConfigPtr
1563D2ClientConfigParser::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
1660const 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
1673size_t
1674D2ClientConfigParser::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
1679void
1680CompatibilityParser::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