Bug Summary

File:home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-private/tmp9kmrytkm/../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc
Warning:line 919, 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 -O2 -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=none -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/tmp9kmrytkm -fcoverage-compilation-dir=/home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-private/tmp9kmrytkm -resource-dir /usr/bin/../lib/clang/22 -I src/lib/dhcpsrv/libkea-dhcpsrv.so.152.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/16/../../../../include/c++/16 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../include/c++/16/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../include/c++/16/backward -internal-isystem /usr/bin/../lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -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 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-logs/scanbuild/2026-11-13-234852-4748-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 // Setup client class list.
523 BaseNetworkParser::getClientClassesElem(pool_structure,
524 std::bind(&Pool::allowClientClass,
525 pool, ph::_1));
526
527 // Setup additional class list.
528 BaseNetworkParser::getAdditionalClassesElem(pool_structure,
529 std::bind(&Pool::addAdditionalClass,
530 pool, ph::_1));
531
532 // Parse DDNS behavioral parameters.
533 BaseNetworkParser parser;
534 parser.parseDdnsParameters(pool_structure, pool);
535}
536
537boost::shared_ptr<OptionDataListParser>
538PoolParser::createOptionDataListParser(const uint16_t address_family) const {
539 return (boost::make_shared<OptionDataListParser>(address_family));
540}
541
542//****************************** Pool4Parser *************************
543
544PoolPtr
545Pool4Parser::poolMaker (IOAddress &addr, uint32_t len, int32_t) {
546 return (PoolPtr(new Pool4(addr, len)));
547}
548
549PoolPtr
550Pool4Parser::poolMaker (IOAddress &min, IOAddress &max, int32_t) {
551 return (PoolPtr(new Pool4(min, max)));
552}
553
554//****************************** Pools4ListParser *************************
555
556void
557Pools4ListParser::parse(PoolStoragePtr pools, ConstElementPtr pools_list,
558 bool encapsulate_options) {
559 for (auto const& pool : pools_list->listValue()) {
560 auto const& parser = createPoolConfigParser();
561 parser->parse(pools, pool, AF_INET2, encapsulate_options);
562 }
563}
564
565boost::shared_ptr<PoolParser>
566Pools4ListParser::createPoolConfigParser() const {
567 return (boost::make_shared<Pool4Parser>());
568}
569
570//****************************** SubnetConfigParser *************************
571
572SubnetConfigParser::SubnetConfigParser(uint16_t family, bool check_iface)
573 : pools_(new PoolStorage()),
574 address_family_(family),
575 check_iface_(check_iface) {
576 relay_info_.reset(new isc::dhcp::Network::RelayInfo());
577}
578
579SubnetPtr
580SubnetConfigParser::parse(ConstElementPtr subnet, bool encapsulate_options) {
581
582 ConstElementPtr relay_params = subnet->get("relay");
583 if (relay_params) {
584 Option::Universe u = (address_family_ == AF_INET2) ? Option::V4 : Option::V6;
585 RelayInfoParser parser(u);
586 parser.parse(relay_info_, relay_params);
587 }
588
589 // Create a subnet.
590 try {
591 createSubnet(subnet);
592 } catch (const std::exception& ex) {
593 isc_throw(DhcpConfigError,do { std::ostringstream oss__; oss__ << "subnet configuration failed: "
<< ex.what(); throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 594, oss__.str().c_str()); } while (1)
594 "subnet configuration failed: " << ex.what())do { std::ostringstream oss__; oss__ << "subnet configuration failed: "
<< ex.what(); throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 594, oss__.str().c_str()); } while (1)
;
595 }
596
597 // We create subnet first and then parse the options straight into the subnet's
598 // CfgOption structure. Previously, we first parsed the options and then copied
599 // them into the CfgOption after creating the subnet but it had two issues. First,
600 // it cost performance. Second, copying options reset the isEncapsulated() flag.
601 // If the options have been encapsulated we want to preserve the flag to ensure
602 // they are not encapsulated several times.
603 ConstElementPtr options_params = subnet->get("option-data");
604 if (options_params) {
605 auto opt_parser = createOptionDataListParser();
606 opt_parser->parse(subnet_->getCfgOption(), options_params, encapsulate_options);
607 }
608
609 return (subnet_);
610}
611
612void
613SubnetConfigParser::createSubnet(ConstElementPtr params) {
614 std::string subnet_txt;
615 try {
616 subnet_txt = getString(params, "subnet");
617 } catch (const DhcpConfigError &) {
618 // rethrow with precise error
619 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"
, 621, oss__.str().c_str()); } while (1)
620 "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"
, 621, oss__.str().c_str()); } while (1)
621 " 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"
, 621, oss__.str().c_str()); } while (1)
;
622 }
623
624 // Remove any spaces or tabs.
625 boost::erase_all(subnet_txt, " ");
626 boost::erase_all(subnet_txt, "\t");
627
628 // The subnet format is prefix/len. We are going to extract
629 // the prefix portion of a subnet string to create IOAddress
630 // object from it. IOAddress will be passed to the Subnet's
631 // constructor later on. In order to extract the prefix we
632 // need to get all characters preceding "/".
633 size_t pos = subnet_txt.find("/");
634 if (pos == string::npos) {
635 ConstElementPtr elem = params->get("subnet");
636 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"
, 638, oss__.str().c_str()); } while (1)
637 "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"
, 638, oss__.str().c_str()); } while (1)
638 << " (" << 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"
, 638, oss__.str().c_str()); } while (1)
;
639 }
640
641 // Try to create the address object. It also validates that
642 // the address syntax is ok.
643 isc::asiolink::IOAddress addr(subnet_txt.substr(0, pos));
644
645 // Now parse out the prefix length.
646 unsigned int len;
647 try {
648 len = boost::lexical_cast<unsigned int>(subnet_txt.substr(pos + 1));
649 } catch (const boost::bad_lexical_cast&) {
650 ConstElementPtr elem = params->get("subnet");
651 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", 653, oss__
.str().c_str()); } while (1)
652 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", 653, oss__
.str().c_str()); } while (1)
653 << 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", 653, oss__
.str().c_str()); } while (1)
;
654 }
655
656 // Sanity check the prefix length
657 if ((addr.isV6() && len > 128) ||
658 (addr.isV4() && len > 32)) {
659 ConstElementPtr elem = params->get("subnet");
660 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"
, 662, oss__.str().c_str()); } while (1)
661 "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"
, 662, oss__.str().c_str()); } while (1)
662 << " (" << 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"
, 662, oss__.str().c_str()); } while (1)
;
663 }
664
665 // Call the subclass's method to instantiate the subnet
666 initSubnet(params, addr, len);
667
668 // Add pools to it.
669 for (auto const& pool : *pools_) {
670 try {
671 subnet_->addPool(pool);
672 } catch (const BadValue& ex) {
673 // addPool() can throw BadValue if the pool is overlapping or
674 // is out of bounds for the subnet.
675 isc_throw(DhcpConfigError,do { std::ostringstream oss__; oss__ << ex.what() <<
" (" << params->getPosition() << ")"; throw DhcpConfigError
("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 676, oss__
.str().c_str()); } while (1)
676 ex.what() << " (" << params->getPosition() << ")")do { std::ostringstream oss__; oss__ << ex.what() <<
" (" << params->getPosition() << ")"; throw DhcpConfigError
("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 676, oss__
.str().c_str()); } while (1)
;
677 }
678 }
679 // If there's user-context specified, store it.
680 ConstElementPtr user_context = params->get("user-context");
681 if (user_context) {
682 // The grammar accepts only maps but still check it.
683 if (user_context->getType() != Element::map) {
684 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"
, 685, oss__.str().c_str()); } while (1)
685 << 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"
, 685, oss__.str().c_str()); } while (1)
;
686 }
687 subnet_->setContext(user_context);
688 }
689
690 // In order to take advantage of the dynamic inheritance of global
691 // parameters to a subnet we need to set a callback function for each
692 // subnet to allow for fetching global parameters.
693 subnet_->setFetchGlobalsFn([]() -> ConstCfgGlobalsPtr {
694 return (CfgMgr::instance().getCurrentCfg()->getConfiguredGlobals());
695 });
696}
697
698boost::shared_ptr<OptionDataListParser>
699SubnetConfigParser::createOptionDataListParser() const {
700 return (boost::make_shared<OptionDataListParser>(address_family_));
701}
702
703//****************************** Subnet4ConfigParser *************************
704
705Subnet4ConfigParser::Subnet4ConfigParser(bool check_iface)
706 : SubnetConfigParser(AF_INET2, check_iface) {
707}
708
709Subnet4Ptr
710Subnet4ConfigParser::parse(ConstElementPtr subnet, bool encapsulate_options) {
711 // Check parameters.
712 checkKeywords(SimpleParser4::SUBNET4_PARAMETERS, subnet);
713
714 /// Parse Pools first.
715 ConstElementPtr pools = subnet->get("pools");
716 if (pools) {
717 auto const& parser = createPoolsListParser();
718 parser->parse(pools_, pools, encapsulate_options);
719 }
720
721 SubnetPtr generic = SubnetConfigParser::parse(subnet, encapsulate_options);
722
723 if (!generic) {
724 // Sanity check: not supposed to fail.
725 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", 727, oss__
.str().c_str()); } while (1)
726 "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", 727, oss__
.str().c_str()); } while (1)
727 subnet->getPosition() << ")")do { std::ostringstream oss__; oss__ << "Failed to create an IPv4 subnet ("
<< subnet->getPosition() << ")"; throw DhcpConfigError
("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 727, oss__
.str().c_str()); } while (1)
;
728 }
729
730 Subnet4Ptr sn4ptr = boost::dynamic_pointer_cast<Subnet4>(subnet_);
731 if (!sn4ptr) {
732 // If we hit this, it is a programming error.
733 isc_throw(Unexpected,do { std::ostringstream oss__; oss__ << "Invalid Subnet4 cast in Subnet4ConfigParser::parse"
; throw Unexpected("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 734, oss__.str().c_str()); } while (1)
734 "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"
, 734, oss__.str().c_str()); } while (1)
;
735 }
736
737 // Set relay information if it was parsed
738 if (relay_info_) {
739 sn4ptr->setRelayInfo(*relay_info_);
740 }
741
742 // Parse Host Reservations for this subnet if any.
743 ConstElementPtr reservations = subnet->get("reservations");
744 if (reservations) {
745 HostCollection hosts;
746 HostReservationsListParser<HostReservationParser4> parser;
747 parser.parse(subnet_->getID(), reservations, hosts);
748 for (auto const& h : hosts) {
749 validateResv(sn4ptr, h);
750 CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(h);
751 }
752 }
753
754 // Parse allocator specification.
755 auto network4 = boost::dynamic_pointer_cast<Network>(sn4ptr);
756 parseAllocatorParams(subnet, network4);
757
758 // Instantiate the allocator.
759 sn4ptr->createAllocators();
760
761 return (sn4ptr);
762}
763
764void
765Subnet4ConfigParser::initSubnet(data::ConstElementPtr params,
766 asiolink::IOAddress addr, uint8_t len) {
767 // Subnet ID is required and must be in 1..SUBNET_ID_MAX.
768 int64_t subnet_id_max = static_cast<int64_t>(SUBNET_ID_MAX);
769 SubnetID subnet_id = static_cast<SubnetID>(getInteger(params, "id", 1,
770 subnet_id_max));
771
772 auto subnet4 = Subnet4::create(addr, len, Triplet<uint32_t>(),
773 Triplet<uint32_t>(), Triplet<uint32_t>(),
774 subnet_id);
775 subnet_ = subnet4;
776
777 ElementPtr mutable_params;
778 mutable_params = boost::const_pointer_cast<Element>(params);
779
780 // Parse parameters common to all Network derivations.
781 NetworkPtr network = boost::dynamic_pointer_cast<Network>(subnet4);
782 parseCommon(mutable_params, network);
783
784 std::ostringstream output;
785 output << addr << "/" << static_cast<int>(len) << " with params: ";
786
787 bool has_renew = !subnet4->getT1().unspecified();
788 bool has_rebind = !subnet4->getT2().unspecified();
789 int64_t renew = -1;
790 int64_t rebind = -1;
791
792 // t1 and t2 are optional may be not specified.
793 if (has_renew) {
794 renew = subnet4->getT1().get();
795 output << "t1=" << renew << ", ";
796 }
797 if (has_rebind) {
798 rebind = subnet4->getT2().get();
799 output << "t2=" << rebind << ", ";
800 }
801
802 if (!subnet4->getValid().unspecified()) {
803 output << "valid-lifetime=" << subnet4->getValid().get();
804 }
805
806 LOG_INFO(dhcpsrv_logger, DHCPSRV_CFGMGR_NEW_SUBNET4)if (!(dhcpsrv_logger).isInfoEnabled()) { } else (dhcpsrv_logger
).info((DHCPSRV_CFGMGR_NEW_SUBNET4))
.arg(output.str());
807
808 // Set the match-client-id value for the subnet.
809 if (params->contains("match-client-id")) {
810 bool match_client_id = getBoolean(params, "match-client-id");
811 subnet4->setMatchClientId(match_client_id);
812 }
813
814 // Set the authoritative value for the subnet.
815 if (params->contains("authoritative")) {
816 bool authoritative = getBoolean(params, "authoritative");
817 subnet4->setAuthoritative(authoritative);
818 }
819
820 // Set next-server. The default value is 0.0.0.0. Nevertheless, the
821 // user could have messed that up by specifying incorrect value.
822 // To avoid using 0.0.0.0, user can specify "".
823 if (params->contains("next-server")) {
824 string next_server;
825 try {
826 next_server = getString(params, "next-server");
827 if (!next_server.empty()) {
828 subnet4->setSiaddr(IOAddress(next_server));
829 }
830 } catch (...) {
831 ConstElementPtr next = params->get("next-server");
832 string pos;
833 if (next) {
834 pos = next->getPosition().str();
835 } else {
836 pos = params->getPosition().str();
837 }
838 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"
, 839, oss__.str().c_str()); } while (1)
839 << next_server << "(" << pos << ")")do { std::ostringstream oss__; oss__ << "invalid parameter next-server : "
<< next_server << "(" << pos << ")";
throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 839, oss__.str().c_str()); } while (1)
;
840 }
841 }
842
843 // Set server-hostname.
844 if (params->contains("server-hostname")) {
845 std::string sname = getString(params, "server-hostname");
846 if (!sname.empty()) {
847 if (sname.length() >= Pkt4::MAX_SNAME_LEN) {
848 ConstElementPtr error = params->get("server-hostname");
849 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"
, 852, oss__.str().c_str()); } while (1)
850 << 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"
, 852, oss__.str().c_str()); } while (1)
851 << 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"
, 852, oss__.str().c_str()); } while (1)
852 << 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"
, 852, oss__.str().c_str()); } while (1)
;
853 }
854 subnet4->setSname(sname);
855 }
856 }
857
858 // Set boot-file-name.
859 if (params->contains("boot-file-name")) {
860 std::string filename =getString(params, "boot-file-name");
861 if (!filename.empty()) {
862 if (filename.length() > Pkt4::MAX_FILE_LEN) {
863 ConstElementPtr error = params->get("boot-file-name");
864 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"
, 867, oss__.str().c_str()); } while (1)
865 << 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"
, 867, oss__.str().c_str()); } while (1)
866 << 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"
, 867, oss__.str().c_str()); } while (1)
867 << 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"
, 867, oss__.str().c_str()); } while (1)
;
868 }
869 subnet4->setFilename(filename);
870 }
871 }
872
873 // Get interface name. If it is defined, then the subnet is available
874 // directly over specified network interface.
875 if (params->contains("interface")) {
876 std::string iface = getString(params, "interface");
877 if (!iface.empty()) {
878 if (check_iface_ && !IfaceMgr::instance().getIface(iface)) {
879 ConstElementPtr error = params->get("interface");
880 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"
, 883, oss__.str().c_str()); } while (1)
881 << " 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"
, 883, oss__.str().c_str()); } while (1)
882 << " 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"
, 883, oss__.str().c_str()); } while (1)
883 << 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"
, 883, oss__.str().c_str()); } while (1)
;
884 }
885
886 subnet4->setIface(iface);
887 }
888 }
889
890 // Setup client class list.
891 getClientClassesElem(params, std::bind(&Network::allowClientClass,
892 boost::dynamic_pointer_cast<Network>(subnet4), ph::_1));
893
894 // Setup additional class list.
895 getAdditionalClassesElem(params, std::bind(&Network::addAdditionalClass,
896 boost::dynamic_pointer_cast<Network>(subnet4), ph::_1));
897
898 // 4o6 specific parameter: 4o6-interface.
899 if (params->contains("4o6-interface")) {
900 string iface4o6 = getString(params, "4o6-interface");
901 if (!iface4o6.empty()) {
902 subnet4->get4o6().setIface4o6(iface4o6);
903 subnet4->get4o6().enabled(true);
904 }
905 }
906
907 // 4o6 specific parameter: 4o6-subnet.
908 if (params->contains("4o6-subnet")) {
909 string subnet4o6 = getString(params, "4o6-subnet");
910 if (!subnet4o6.empty()) {
911 size_t slash = subnet4o6.find("/");
912 if (slash == std::string::npos) {
913 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"
, 914, oss__.str().c_str()); } while (1)
914 << 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"
, 914, oss__.str().c_str()); } while (1)
;
915 }
916 string prefix = subnet4o6.substr(0, slash);
917 string lenstr = subnet4o6.substr(slash + 1);
918
919 len = 128;
Value stored to 'len' is never read
920 try {
921 len = boost::lexical_cast<unsigned int>(lenstr.c_str());
922 } catch (const boost::bad_lexical_cast &) {
923 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"
, 924, oss__.str().c_str()); } while (1)
924 "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"
, 924, oss__.str().c_str()); } while (1)
;
925 }
926 subnet4->get4o6().setSubnet4o6(IOAddress(prefix), len);
927 subnet4->get4o6().enabled(true);
928 }
929 }
930
931 // Try 4o6 specific parameter: 4o6-interface-id
932 if (params->contains("4o6-interface-id")) {
933 std::string ifaceid = getString(params, "4o6-interface-id");
934 if (!ifaceid.empty()) {
935 OptionBuffer tmp(ifaceid.begin(), ifaceid.end());
936 OptionPtr opt(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
937 subnet4->get4o6().setInterfaceId(opt);
938 subnet4->get4o6().enabled(true);
939 }
940 }
941
942 /// client-classes processing is now generic and handled in the common
943 /// code (see isc::data::SubnetConfigParser::createSubnet)
944
945 // Here globally defined options were merged to the subnet specific
946 // options but this is no longer the case (they have a different
947 // and not consecutive priority).
948
949 // Parse t1-percent and t2-percent
950 parseTeePercents(params, network);
951
952 // Parse DDNS parameters
953 parseDdnsParams(params, network);
954
955 // Parse lease cache parameters
956 parseCacheParams(params, network);
957
958 // Parse adaptive lease time parameter.
959 parseAdaptiveLeaseTimeParam(params, network);
960
961 // Set the offer_lft value for the subnet.
962 if (params->contains("offer-lifetime")) {
963 uint32_t offer_lft = getInteger(params, "offer-lifetime");
964 subnet4->setOfferLft(offer_lft);
965 }
966
967 // Parse offer-lifetime parameter.
968 Network4Ptr network4 = boost::dynamic_pointer_cast<Network4>(subnet4);
969 parseOfferLft(params, network4);
970
971}
972
973void
974Subnet4ConfigParser::validateResv(const Subnet4Ptr& subnet, ConstHostPtr host) {
975 const IOAddress& address = host->getIPv4Reservation();
976 if (!address.isV4Zero() && !subnet->inRange(address)) {
977 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", 979, oss__
.str().c_str()); } while (1)
978 << "' 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", 979, oss__
.str().c_str()); } while (1)
979 << 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", 979, oss__
.str().c_str()); } while (1)
;
980 }
981}
982
983boost::shared_ptr<PoolsListParser>
984Subnet4ConfigParser::createPoolsListParser() const {
985 return (boost::make_shared<Pools4ListParser>());
986}
987
988//**************************** Subnets4ListConfigParser **********************
989
990Subnets4ListConfigParser::Subnets4ListConfigParser(bool check_iface)
991 : check_iface_(check_iface) {
992}
993
994size_t
995Subnets4ListConfigParser::parse(SrvConfigPtr cfg,
996 ConstElementPtr subnets_list,
997 bool encapsulate_options) {
998 size_t cnt = 0;
999 for (auto const& subnet_json : subnets_list->listValue()) {
1000
1001 auto const& parser = createSubnetConfigParser();
1002 Subnet4Ptr subnet = parser->parse(subnet_json, encapsulate_options);
1003 if (subnet) {
1004
1005 // Adding a subnet to the Configuration Manager may fail if the
1006 // subnet id is invalid (duplicate). Thus, we catch exceptions
1007 // here to append a position in the configuration string.
1008 try {
1009 cfg->getCfgSubnets4()->add(subnet);
1010 cnt++;
1011 } catch (const std::exception& ex) {
1012 isc_throw(DhcpConfigError, ex.what() << " ("do { std::ostringstream oss__; oss__ << ex.what() <<
" (" << subnet_json->getPosition() << ")"; throw
DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 1013, oss__.str().c_str()); } while (1)
1013 << subnet_json->getPosition() << ")")do { std::ostringstream oss__; oss__ << ex.what() <<
" (" << subnet_json->getPosition() << ")"; throw
DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 1013, oss__.str().c_str()); } while (1)
;
1014 }
1015 }
1016 }
1017 return (cnt);
1018}
1019
1020size_t
1021Subnets4ListConfigParser::parse(Subnet4Collection& subnets,
1022 data::ConstElementPtr subnets_list,
1023 bool encapsulate_options) {
1024 size_t cnt = 0;
1025 for (auto const& subnet_json : subnets_list->listValue()) {
1026
1027 auto const& parser = createSubnetConfigParser();
1028 Subnet4Ptr subnet = parser->parse(subnet_json, encapsulate_options);
1029 if (subnet) {
1030 try {
1031 auto ret = subnets.insert(subnet);
1032 if (!ret.second) {
1033 isc_throw(Unexpected,do { std::ostringstream oss__; oss__ << "can't store subnet because of conflict"
; throw Unexpected("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 1034, oss__.str().c_str()); } while (1)
1034 "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"
, 1034, oss__.str().c_str()); } while (1)
;
1035 }
1036 ++cnt;
1037 } catch (const std::exception& ex) {
1038 isc_throw(DhcpConfigError, ex.what() << " ("do { std::ostringstream oss__; oss__ << ex.what() <<
" (" << subnet_json->getPosition() << ")"; throw
DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 1039, oss__.str().c_str()); } while (1)
1039 << subnet_json->getPosition() << ")")do { std::ostringstream oss__; oss__ << ex.what() <<
" (" << subnet_json->getPosition() << ")"; throw
DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 1039, oss__.str().c_str()); } while (1)
;
1040 }
1041 }
1042 }
1043 return (cnt);
1044}
1045
1046boost::shared_ptr<Subnet4ConfigParser>
1047Subnets4ListConfigParser::createSubnetConfigParser() const {
1048 return (boost::make_shared<Subnet4ConfigParser>(check_iface_));
1049}
1050
1051//**************************** Pool6Parser *********************************
1052
1053PoolPtr
1054Pool6Parser::poolMaker(IOAddress &addr, uint32_t len, int32_t ptype)
1055{
1056 return (PoolPtr(new Pool6(static_cast<isc::dhcp::Lease::Type>
1057 (ptype), addr, len)));
1058}
1059
1060PoolPtr
1061Pool6Parser::poolMaker(IOAddress &min, IOAddress &max, int32_t ptype)
1062{
1063 return (PoolPtr(new Pool6(static_cast<isc::dhcp::Lease::Type>
1064 (ptype), min, max)));
1065}
1066
1067
1068//**************************** Pool6ListParser ***************************
1069
1070void
1071Pools6ListParser::parse(PoolStoragePtr pools, ConstElementPtr pools_list,
1072 bool encapsulate_options) {
1073 for (auto const& pool : pools_list->listValue()) {
1074 auto const& parser = createPoolConfigParser();
1075 parser->parse(pools, pool, AF_INET610, encapsulate_options);
1076 }
1077}
1078
1079boost::shared_ptr<PoolParser>
1080Pools6ListParser::createPoolConfigParser() const {
1081 return (boost::make_shared<Pool6Parser>());
1082}
1083
1084//**************************** PdPoolParser ******************************
1085
1086PdPoolParser::PdPoolParser() {
1087}
1088
1089void
1090PdPoolParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool,
1091 bool encapsulate_options) {
1092 checkKeywords(SimpleParser6::PD_POOL6_PARAMETERS, pd_pool);
1093
1094 std::string addr_str = getString(pd_pool, "prefix");
1095
1096 uint8_t prefix_len = getUint8(pd_pool, "prefix-len");
1097
1098 uint8_t delegated_len = getUint8(pd_pool, "delegated-len");
1099
1100 std::string excluded_prefix_str = "::";
1101 if (pd_pool->contains("excluded-prefix")) {
1102 excluded_prefix_str = getString(pd_pool, "excluded-prefix");
1103 }
1104
1105 uint8_t excluded_prefix_len = 0;
1106 if (pd_pool->contains("excluded-prefix-len")) {
1107 excluded_prefix_len = getUint8(pd_pool, "excluded-prefix-len");
1108 }
1109
1110 ConstElementPtr user_context = pd_pool->get("user-context");
1111 if (user_context) {
1112 user_context_ = user_context;
1113 }
1114
1115 // Check the pool parameters. It will throw an exception if any
1116 // of the required parameters are invalid.
1117 try {
1118 // Attempt to construct the local pool.
1119 pool_.reset(new Pool6(IOAddress(addr_str),
1120 prefix_len,
1121 delegated_len,
1122 IOAddress(excluded_prefix_str),
1123 excluded_prefix_len));
1124 } catch (const std::exception& ex) {
1125 // Some parameters don't exist or are invalid. Since we are not
1126 // aware whether they don't exist or are invalid, let's append
1127 // the position of the pool map element.
1128 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"
, 1129, oss__.str().c_str()); } while (1)
1129 << " (" << pd_pool->getPosition() << ")")do { std::ostringstream oss__; oss__ << ex.what() <<
" (" << pd_pool->getPosition() << ")"; throw isc
::dhcp::DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 1129, oss__.str().c_str()); } while (1)
;
1130 }
1131
1132 // If there is a pool-id, store it.
1133 ConstElementPtr pool_id = pd_pool->get("pool-id");
1134 if (pool_id) {
1135 if (pool_id->intValue() <= 0) {
1136 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"
, 1137, oss__.str().c_str()); } while (1)
1137 << " 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"
, 1137, oss__.str().c_str()); } while (1)
;
1138 } else if (pool_id->intValue() > numeric_limits<uint32_t>::max()) {
1139 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"
, 1140, oss__.str().c_str()); } while (1)
1140 << " 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"
, 1140, oss__.str().c_str()); } while (1)
;
1141 }
1142
1143 pool_->setID(pool_id->intValue());
1144 }
1145
1146 // We create subnet first and then parse the options straight into the subnet's
1147 // CfgOption structure. Previously, we first parsed the options and then copied
1148 // them into the CfgOption after creating the subnet but it had two issues. First,
1149 // it cost performance. Second, copying options reset the isEncapsulated() flag.
1150 // If the options have been encapsulated we want to preserve the flag to ensure
1151 // they are not encapsulated several times.
1152 ConstElementPtr option_data = pd_pool->get("option-data");
1153 if (option_data) {
1154 auto opts_parser = createOptionDataListParser();
1155 opts_parser->parse(pool_->getCfgOption(), option_data, encapsulate_options);
1156 }
1157
1158 if (user_context_) {
1159 pool_->setContext(user_context_);
1160 }
1161
1162 // Setup client class list.
1163 BaseNetworkParser::getClientClassesElem(pd_pool,
1164 std::bind(&Pool::allowClientClass,
1165 boost::dynamic_pointer_cast<Pool>(pool_), ph::_1));
1166
1167 // Setup additional class list.
1168 BaseNetworkParser::getAdditionalClassesElem(pd_pool,
1169 std::bind(&Pool::addAdditionalClass,
1170 boost::dynamic_pointer_cast<Pool>(pool_), ph::_1));
1171
1172 // Add the local pool to the external storage ptr.
1173 pools->push_back(pool_);
1174}
1175
1176boost::shared_ptr<OptionDataListParser>
1177PdPoolParser::createOptionDataListParser() const {
1178 return (boost::make_shared<OptionDataListParser>(AF_INET610));
1179}
1180
1181//**************************** PdPoolsListParser ************************
1182
1183void
1184PdPoolsListParser::parse(PoolStoragePtr pools, ConstElementPtr pd_pool_list) {
1185 // Loop through the list of pd pools.
1186 for (auto const& pd_pool : pd_pool_list->listValue()) {
1187 auto const& parser = createPdPoolConfigParser();
1188 parser->parse(pools, pd_pool);
1189 }
1190}
1191
1192boost::shared_ptr<PdPoolParser>
1193PdPoolsListParser::createPdPoolConfigParser() const {
1194 return (boost::make_shared<PdPoolParser>());
1195}
1196
1197//**************************** Subnet6ConfigParser ***********************
1198
1199Subnet6ConfigParser::Subnet6ConfigParser(bool check_iface)
1200 : SubnetConfigParser(AF_INET610, check_iface) {
1201}
1202
1203Subnet6Ptr
1204Subnet6ConfigParser::parse(ConstElementPtr subnet, bool encapsulate_options) {
1205 // Check parameters.
1206 checkKeywords(SimpleParser6::SUBNET6_PARAMETERS, subnet);
1207
1208 /// Parse all pools first.
1209 ConstElementPtr pools = subnet->get("pools");
1210 if (pools) {
1211 auto const& parser = createPoolsListParser();
1212 parser->parse(pools_, pools, encapsulate_options);
1213 }
1214 ConstElementPtr pd_pools = subnet->get("pd-pools");
1215 if (pd_pools) {
1216 auto const& parser = createPdPoolsListParser();
1217 parser->parse(pools_, pd_pools);
1218 }
1219
1220 SubnetPtr generic = SubnetConfigParser::parse(subnet, encapsulate_options);
1221
1222 if (!generic) {
1223 // Sanity check: not supposed to fail.
1224 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", 1226, oss__
.str().c_str()); } while (1)
1225 "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", 1226, oss__
.str().c_str()); } while (1)
1226 subnet->getPosition() << ")")do { std::ostringstream oss__; oss__ << "Failed to create an IPv6 subnet ("
<< subnet->getPosition() << ")"; throw DhcpConfigError
("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc", 1226, oss__
.str().c_str()); } while (1)
;
1227 }
1228
1229 Subnet6Ptr sn6ptr = boost::dynamic_pointer_cast<Subnet6>(subnet_);
1230 if (!sn6ptr) {
1231 // If we hit this, it is a programming error.
1232 isc_throw(Unexpected,do { std::ostringstream oss__; oss__ << "Invalid Subnet6 cast in Subnet6ConfigParser::parse"
; throw Unexpected("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 1233, oss__.str().c_str()); } while (1)
1233 "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"
, 1233, oss__.str().c_str()); } while (1)
;
1234 }
1235
1236 // Set relay information if it was provided
1237 if (relay_info_) {
1238 sn6ptr->setRelayInfo(*relay_info_);
1239 }
1240
1241 // Parse Host Reservations for this subnet if any.
1242 ConstElementPtr reservations = subnet->get("reservations");
1243 if (reservations) {
1244 HostCollection hosts;
1245 HostReservationsListParser<HostReservationParser6> parser;
1246 parser.parse(subnet_->getID(), reservations, hosts);
1247 for (auto const& h : hosts) {
1248 validateResvs(sn6ptr, h);
1249 CfgMgr::instance().getStagingCfg()->getCfgHosts()->add(h);
1250 }
1251 }
1252
1253 // Parse allocator specification.
1254 auto network = boost::dynamic_pointer_cast<Network>(sn6ptr);
1255 parseAllocatorParams(subnet, network);
1256
1257 // Parse pd-allocator specification.
1258 auto network6 = boost::dynamic_pointer_cast<Network6>(sn6ptr);
1259 parsePdAllocatorParams(subnet, network6);
1260
1261 // Instantiate the allocators.
1262 sn6ptr->createAllocators();
1263
1264 return (sn6ptr);
1265}
1266
1267// Unused?
1268void
1269Subnet6ConfigParser::duplicateOptionWarning(uint32_t code,
1270 asiolink::IOAddress& addr) {
1271 LOG_WARN(dhcpsrv_logger, DHCPSRV_CFGMGR_OPTION_DUPLICATE)if (!(dhcpsrv_logger).isWarnEnabled()) { } else (dhcpsrv_logger
).warn((DHCPSRV_CFGMGR_OPTION_DUPLICATE))
1272 .arg(code).arg(addr.toText());
1273}
1274
1275void
1276Subnet6ConfigParser::initSubnet(data::ConstElementPtr params,
1277 asiolink::IOAddress addr, uint8_t len) {
1278 // Subnet ID is required and must be in 1..SUBNET_ID_MAX.
1279 int64_t subnet_id_max = static_cast<int64_t>(SUBNET_ID_MAX);
1280 SubnetID subnet_id = static_cast<SubnetID>(getInteger(params, "id", 1,
1281 subnet_id_max));
1282
1283 // We want to log whether rapid-commit is enabled, so we get this
1284 // before the actual subnet creation.
1285 Optional<bool> rapid_commit;
1286 if (params->contains("rapid-commit")) {
1287 rapid_commit = getBoolean(params, "rapid-commit");
1288 }
1289
1290 // Parse preferred lifetime as it is not parsed by the common function.
1291 Triplet<uint32_t> pref = parseIntTriplet(params, "preferred-lifetime");
1292
1293 // Create a new subnet.
1294 auto subnet6 = Subnet6::create(addr, len, Triplet<uint32_t>(),
1295 Triplet<uint32_t>(),
1296 pref,
1297 Triplet<uint32_t>(),
1298 subnet_id);
1299 subnet_ = subnet6;
1300
1301 ElementPtr mutable_params;
1302 mutable_params = boost::const_pointer_cast<Element>(params);
1303
1304 // Parse parameters common to all Network derivations.
1305 NetworkPtr network = boost::dynamic_pointer_cast<Network>(subnet_);
1306 parseCommon(mutable_params, network);
1307
1308 // Enable or disable Rapid Commit option support for the subnet.
1309 if (!rapid_commit.unspecified()) {
1310 subnet6->setRapidCommit(rapid_commit);
1311 }
1312
1313 std::ostringstream output;
1314 output << addr << "/" << static_cast<int>(len) << " with params: ";
1315 // t1 and t2 are optional may be not specified.
1316
1317 bool has_renew = !subnet6->getT1().unspecified();
1318 bool has_rebind = !subnet6->getT2().unspecified();
1319 int64_t renew = -1;
1320 int64_t rebind = -1;
1321
1322 if (has_renew) {
1323 renew = subnet6->getT1().get();
1324 output << "t1=" << renew << ", ";
1325 }
1326 if (has_rebind) {
1327 rebind = subnet6->getT2().get();
1328 output << "t2=" << rebind << ", ";
1329 }
1330
1331 if (!subnet6->getPreferred().unspecified()) {
1332 output << "preferred-lifetime=" << subnet6->getPreferred().get() << ", ";
1333 }
1334 if (!subnet6->getValid().unspecified()) {
1335 output << "valid-lifetime=" << subnet6->getValid().get();
1336 }
1337 if (!subnet6->getRapidCommit().unspecified()) {
1338 output << ", rapid-commit is "
1339 << boolalpha << subnet6->getRapidCommit().get();
1340 }
1341
1342 LOG_INFO(dhcpsrv_logger, DHCPSRV_CFGMGR_NEW_SUBNET6)if (!(dhcpsrv_logger).isInfoEnabled()) { } else (dhcpsrv_logger
).info((DHCPSRV_CFGMGR_NEW_SUBNET6))
.arg(output.str());
1343
1344 // Get interface-id option content. For now we support string
1345 // representation only
1346 Optional<std::string> ifaceid;
1347 if (params->contains("interface-id")) {
1348 ifaceid = getString(params, "interface-id");
1349 }
1350
1351 Optional<std::string> iface;
1352 if (params->contains("interface")) {
1353 iface = getString(params, "interface");
1354 }
1355
1356 // Specifying both interface for locally reachable subnets and
1357 // interface id for relays is mutually exclusive. Need to test for
1358 // this condition.
1359 if (!ifaceid.unspecified() && !iface.unspecified() && !ifaceid.empty() &&
1360 !iface.empty()) {
1361 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"
, 1366, oss__.str().c_str()); } while (1)
1362 "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"
, 1366, oss__.str().c_str()); } while (1)
1363 "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"
, 1366, oss__.str().c_str()); } while (1)
1364 " 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"
, 1366, oss__.str().c_str()); } while (1)
1365 "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"
, 1366, oss__.str().c_str()); } while (1)
1366 << 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"
, 1366, oss__.str().c_str()); } while (1)
;
1367 }
1368
1369 // Configure interface-id for remote interfaces, if defined
1370 if (!ifaceid.unspecified() && !ifaceid.empty()) {
1371 std::string ifaceid_value = ifaceid.get();
1372 OptionBuffer tmp(ifaceid_value.begin(), ifaceid_value.end());
1373 OptionPtr opt(new Option(Option::V6, D6O_INTERFACE_ID, tmp));
1374 subnet6->setInterfaceId(opt);
1375 }
1376
1377 // Get interface name. If it is defined, then the subnet is available
1378 // directly over specified network interface.
1379 if (!iface.unspecified() && !iface.empty()) {
1380 if (check_iface_ && !IfaceMgr::instance().getIface(iface)) {
1381 ConstElementPtr error = params->get("interface");
1382 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"
, 1385, oss__.str().c_str()); } while (1)
1383 << " 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"
, 1385, oss__.str().c_str()); } while (1)
1384 << " 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"
, 1385, oss__.str().c_str()); } while (1)
1385 << 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"
, 1385, oss__.str().c_str()); } while (1)
;
1386 }
1387
1388 subnet6->setIface(iface);
1389 }
1390
1391 // Setup client class list.
1392 getClientClassesElem(params, std::bind(&Network::allowClientClass,
1393 boost::dynamic_pointer_cast<Network>(subnet6), ph::_1));
1394
1395 // Setup additional class list.
1396 getAdditionalClassesElem(params, std::bind(&Network::addAdditionalClass,
1397 boost::dynamic_pointer_cast<Network>(subnet6), ph::_1));
1398
1399 /// client-classes processing is now generic and handled in the common
1400 /// code (see isc::data::SubnetConfigParser::createSubnet)
1401
1402 // Parse t1-percent and t2-percent
1403 parseTeePercents(params, network);
1404
1405 // Parse DDNS parameters
1406 parseDdnsParams(params, network);
1407
1408 // Parse lease cache parameters
1409 parseCacheParams(params, network);
1410
1411 // Parse adaptive lease time parameter.
1412 parseAdaptiveLeaseTimeParam(params, network);
1413}
1414
1415void
1416Subnet6ConfigParser::validateResvs(const Subnet6Ptr& subnet, ConstHostPtr host) {
1417 const IPv6ResrvRange& range = host->getIPv6Reservations(IPv6Resrv::TYPE_NA);
1418 BOOST_FOREACH(auto const& it, range)if (boost::foreach_detail_::auto_any_t _foreach_col1418 = 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_cur1418
= boost::foreach_detail_::begin( _foreach_col1418 , (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_end1418
= boost::foreach_detail_::end( _foreach_col1418 , (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_continue1418 = true; _foreach_continue1418
&& !boost::foreach_detail_::done( _foreach_cur1418 ,
_foreach_end1418 , (true ? nullptr : boost::foreach_detail_::
encode_type(range, boost::foreach_detail_::is_const_(range)))
); _foreach_continue1418 ? boost::foreach_detail_::next( _foreach_cur1418
, (true ? nullptr : boost::foreach_detail_::encode_type(range
, boost::foreach_detail_::is_const_(range)))) : (void)0) if (
boost::foreach_detail_::set_false(_foreach_continue1418)) {} else
for (auto const& it = boost::foreach_detail_::deref( _foreach_cur1418
, (true ? nullptr : boost::foreach_detail_::encode_type(range
, boost::foreach_detail_::is_const_(range)))); !_foreach_continue1418
; _foreach_continue1418 = true)
{
1419 const IOAddress& address = it.second.getPrefix();
1420 if (!subnet->inRange(address)) {
1421 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", 1423, oss__
.str().c_str()); } while (1)
1422 << "' 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", 1423, oss__
.str().c_str()); } while (1)
1423 << 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", 1423, oss__
.str().c_str()); } while (1)
;
1424 }
1425 }
1426}
1427
1428boost::shared_ptr<PoolsListParser>
1429Subnet6ConfigParser::createPoolsListParser() const {
1430 return (boost::make_shared<Pools6ListParser>());
1431}
1432
1433boost::shared_ptr<PdPoolsListParser>
1434Subnet6ConfigParser::createPdPoolsListParser() const {
1435 return (boost::make_shared<PdPoolsListParser>());
1436}
1437
1438//**************************** Subnet6ListConfigParser ********************
1439
1440Subnets6ListConfigParser::Subnets6ListConfigParser(bool check_iface)
1441 : check_iface_(check_iface) {
1442}
1443
1444size_t
1445Subnets6ListConfigParser::parse(SrvConfigPtr cfg,
1446 ConstElementPtr subnets_list,
1447 bool encapsulate_options) {
1448 size_t cnt = 0;
1449 for (auto const& subnet_json : subnets_list->listValue()) {
1450
1451 auto const& parser = createSubnetConfigParser();
1452 Subnet6Ptr subnet = parser->parse(subnet_json, encapsulate_options);
1453
1454 // Adding a subnet to the Configuration Manager may fail if the
1455 // subnet id is invalid (duplicate). Thus, we catch exceptions
1456 // here to append a position in the configuration string.
1457 try {
1458 cfg->getCfgSubnets6()->add(subnet);
1459 cnt++;
1460 } catch (const std::exception& ex) {
1461 isc_throw(DhcpConfigError, ex.what() << " ("do { std::ostringstream oss__; oss__ << ex.what() <<
" (" << subnet_json->getPosition() << ")"; throw
DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 1462, oss__.str().c_str()); } while (1)
1462 << subnet_json->getPosition() << ")")do { std::ostringstream oss__; oss__ << ex.what() <<
" (" << subnet_json->getPosition() << ")"; throw
DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 1462, oss__.str().c_str()); } while (1)
;
1463 }
1464 }
1465 return (cnt);
1466}
1467
1468size_t
1469Subnets6ListConfigParser::parse(Subnet6Collection& subnets,
1470 ConstElementPtr subnets_list,
1471 bool encapsulate_options) {
1472 size_t cnt = 0;
1473 for (auto const& subnet_json : subnets_list->listValue()) {
1474
1475 auto const& parser = createSubnetConfigParser();
1476 Subnet6Ptr subnet = parser->parse(subnet_json, encapsulate_options);
1477 if (subnet) {
1478 try {
1479 auto ret = subnets.insert(subnet);
1480 if (!ret.second) {
1481 isc_throw(Unexpected,do { std::ostringstream oss__; oss__ << "can't store subnet because of conflict"
; throw Unexpected("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 1482, oss__.str().c_str()); } while (1)
1482 "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"
, 1482, oss__.str().c_str()); } while (1)
;
1483 }
1484 ++cnt;
1485 } catch (const std::exception& ex) {
1486 isc_throw(DhcpConfigError, ex.what() << " ("do { std::ostringstream oss__; oss__ << ex.what() <<
" (" << subnet_json->getPosition() << ")"; throw
DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 1487, oss__.str().c_str()); } while (1)
1487 << subnet_json->getPosition() << ")")do { std::ostringstream oss__; oss__ << ex.what() <<
" (" << subnet_json->getPosition() << ")"; throw
DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 1487, oss__.str().c_str()); } while (1)
;
1488 }
1489 }
1490 }
1491 return (cnt);
1492}
1493
1494boost::shared_ptr<Subnet6ConfigParser>
1495Subnets6ListConfigParser::createSubnetConfigParser() const {
1496 return (boost::make_shared<Subnet6ConfigParser>(check_iface_));
1497}
1498
1499//**************************** D2ClientConfigParser **********************
1500
1501dhcp_ddns::NameChangeProtocol
1502D2ClientConfigParser::getProtocol(ConstElementPtr scope,
1503 const std::string& name) {
1504 return (getAndConvert<dhcp_ddns::NameChangeProtocol,
1505 dhcp_ddns::stringToNcrProtocol>
1506 (scope, name, "NameChangeRequest protocol"));
1507}
1508
1509dhcp_ddns::NameChangeFormat
1510D2ClientConfigParser::getFormat(ConstElementPtr scope,
1511 const std::string& name) {
1512 return (getAndConvert<dhcp_ddns::NameChangeFormat,
1513 dhcp_ddns::stringToNcrFormat>
1514 (scope, name, "NameChangeRequest format"));
1515}
1516
1517D2ClientConfig::ReplaceClientNameMode
1518D2ClientConfigParser::getMode(ConstElementPtr scope,
1519 const std::string& name) {
1520 return (getAndConvert<D2ClientConfig::ReplaceClientNameMode,
1521 D2ClientConfig::stringToReplaceClientNameMode>
1522 (scope, name, "ReplaceClientName mode"));
1523}
1524
1525D2ClientConfigPtr
1526D2ClientConfigParser::parse(isc::data::ConstElementPtr client_config) {
1527 D2ClientConfigPtr new_config;
1528
1529 // Get all parameters that are needed to create the D2ClientConfig.
1530 bool enable_updates = getBoolean(client_config, "enable-updates");
1531
1532 IOAddress server_ip = getAddress(client_config, "server-ip");
1533
1534 uint32_t server_port = getUint32(client_config, "server-port");
1535
1536 std::string sender_ip_str = getString(client_config, "sender-ip");
1537
1538 uint32_t sender_port = getUint32(client_config, "sender-port");
1539
1540 uint32_t max_queue_size = getUint32(client_config, "max-queue-size");
1541
1542 dhcp_ddns::NameChangeProtocol ncr_protocol =
1543 getProtocol(client_config, "ncr-protocol");
1544
1545 dhcp_ddns::NameChangeFormat ncr_format =
1546 getFormat(client_config, "ncr-format");
1547
1548 IOAddress sender_ip(0);
1549 if (sender_ip_str.empty()) {
1550 // The default sender IP depends on the server IP family
1551 sender_ip = (server_ip.isV4() ? IOAddress::IPV4_ZERO_ADDRESS() :
1552 IOAddress::IPV6_ZERO_ADDRESS());
1553 } else {
1554 try {
1555 sender_ip = IOAddress(sender_ip_str);
1556 } catch (const std::exception& ex) {
1557 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"
, 1559, oss__.str().c_str()); } while (1)
1558 << ") 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"
, 1559, oss__.str().c_str()); } while (1)
1559 << 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"
, 1559, oss__.str().c_str()); } while (1)
;
1560 }
1561 }
1562
1563 // Now we check for logical errors. This repeats what is done in
1564 // D2ClientConfig::validate(), but doing it here permits us to
1565 // emit meaningful parameter position info in the error.
1566 if (ncr_format != dhcp_ddns::FMT_JSON) {
1567 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"
, 1570, oss__.str().c_str()); } while (1)
1568 << 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"
, 1570, oss__.str().c_str()); } while (1)
1569 << " 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"
, 1570, oss__.str().c_str()); } while (1)
1570 << 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"
, 1570, oss__.str().c_str()); } while (1)
;
1571 }
1572
1573 if (ncr_protocol != dhcp_ddns::NCR_UDP) {
1574 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"
, 1577, oss__.str().c_str()); } while (1)
1575 << 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"
, 1577, oss__.str().c_str()); } while (1)
1576 << " 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"
, 1577, oss__.str().c_str()); } while (1)
1577 << 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"
, 1577, oss__.str().c_str()); } while (1)
;
1578 }
1579
1580 if (sender_ip.getFamily() != server_ip.getFamily()) {
1581 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", 1587, oss__
.str().c_str()); } while (1)
1582 "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", 1587, oss__
.str().c_str()); } while (1)
1583 << "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", 1587, oss__
.str().c_str()); } while (1)
1584 << " 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", 1587, oss__
.str().c_str()); } while (1)
1585 << " 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", 1587, oss__
.str().c_str()); } while (1)
1586 << " 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", 1587, oss__
.str().c_str()); } while (1)
1587 << " (" << 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", 1587, oss__
.str().c_str()); } while (1)
;
1588 }
1589
1590 if (server_ip == sender_ip && server_port == sender_port) {
1591 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", 1595, oss__
.str().c_str()); } while (1)
1592 "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", 1595, oss__
.str().c_str()); } while (1)
1593 " 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", 1595, oss__
.str().c_str()); } while (1)
1594 << 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", 1595, oss__
.str().c_str()); } while (1)
1595 << " (" << 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", 1595, oss__
.str().c_str()); } while (1)
;
1596 }
1597
1598 try {
1599 // Attempt to create the new client config.
1600 new_config.reset(new D2ClientConfig(enable_updates,
1601 server_ip,
1602 server_port,
1603 sender_ip,
1604 sender_port,
1605 max_queue_size,
1606 ncr_protocol,
1607 ncr_format));
1608 } catch (const std::exception& ex) {
1609 isc_throw(DhcpConfigError, ex.what() << " ("do { std::ostringstream oss__; oss__ << ex.what() <<
" (" << client_config->getPosition() << ")"; throw
DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 1610, oss__.str().c_str()); } while (1)
1610 << client_config->getPosition() << ")")do { std::ostringstream oss__; oss__ << ex.what() <<
" (" << client_config->getPosition() << ")"; throw
DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 1610, oss__.str().c_str()); } while (1)
;
1611 }
1612
1613 // Add user context
1614 ConstElementPtr user_context = client_config->get("user-context");
1615 if (user_context) {
1616 new_config->setContext(user_context);
1617 }
1618
1619 return (new_config);
1620}
1621
1622/// @brief This table defines default values for D2 client configuration
1623const SimpleDefaults D2ClientConfigParser::D2_CLIENT_CONFIG_DEFAULTS = {
1624 // enable-updates is unconditionally required
1625 { "server-ip", Element::string, "127.0.0.1" },
1626 { "server-port", Element::integer, "53001" },
1627 // default sender-ip depends on server-ip family, so we leave default blank
1628 // parser knows to use the appropriate ZERO address based on server-ip
1629 { "sender-ip", Element::string, "" },
1630 { "sender-port", Element::integer, "0" },
1631 { "max-queue-size", Element::integer, "1024" },
1632 { "ncr-protocol", Element::string, "UDP" },
1633 { "ncr-format", Element::string, "JSON" }
1634};
1635
1636size_t
1637D2ClientConfigParser::setAllDefaults(isc::data::ConstElementPtr d2_config) {
1638 ElementPtr mutable_d2 = boost::const_pointer_cast<Element>(d2_config);
1639 return (SimpleParser::setDefaults(mutable_d2, D2_CLIENT_CONFIG_DEFAULTS));
1640}
1641
1642void
1643CompatibilityParser::parse(ConstElementPtr compatibility, SrvConfig& srv_cfg) {
1644 if (compatibility) {
1645 auto family = CfgMgr::instance().getFamily();
1646 for (auto const& kv : compatibility->mapValue()) {
1647 if (!kv.second || (kv.second->getType() != Element::boolean)) {
1648 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", 1651, oss__
.str().c_str()); } while (1)
1649 "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", 1651, oss__
.str().c_str()); } while (1)
1650 << "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", 1651, oss__
.str().c_str()); } while (1)
1651 << 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", 1651, oss__
.str().c_str()); } while (1)
;
1652 }
1653 if (kv.first == "lenient-option-parsing") {
1654 srv_cfg.setLenientOptionParsing(kv.second->boolValue());
1655 } else if (family == AF_INET2) {
1656 if (kv.first == "ignore-dhcp-server-identifier") {
1657 srv_cfg.setIgnoreServerIdentifier(kv.second->boolValue());
1658 } else if (kv.first == "ignore-rai-link-selection") {
1659 srv_cfg.setIgnoreRAILinkSelection(kv.second->boolValue());
1660 } else if (kv.first == "exclude-first-last-24") {
1661 srv_cfg.setExcludeFirstLast24(kv.second->boolValue());
1662 } else {
1663 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"
, 1666, oss__.str().c_str()); } while (1)
1664 "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"
, 1666, oss__.str().c_str()); } while (1)
1665 << 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"
, 1666, oss__.str().c_str()); } while (1)
1666 << ")")do { std::ostringstream oss__; oss__ << "unsupported compatibility parameter: "
<< kv.first << " (" << kv.second->getPosition
() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 1666, oss__.str().c_str()); } while (1)
;
1667 }
1668 } else {
1669 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"
, 1672, oss__.str().c_str()); } while (1)
1670 "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"
, 1672, oss__.str().c_str()); } while (1)
1671 << 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"
, 1672, oss__.str().c_str()); } while (1)
1672 << ")")do { std::ostringstream oss__; oss__ << "unsupported compatibility parameter: "
<< kv.first << " (" << kv.second->getPosition
() << ")"; throw DhcpConfigError("../../../src/lib/dhcpsrv/parsers/dhcp_parsers.cc"
, 1672, oss__.str().c_str()); } while (1)
;
1673 }
1674 }
1675 }
1676}
1677
1678} // namespace dhcp
1679} // namespace isc