1 // Copyright (C) 2015-2021 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 <dhcp/dhcp6.h>
10 #include <dhcp/option.h>
11 #include <dhcp/option_definition.h>
12 #include <dhcp/libdhcp++.h>
13 #include <dhcp/option_space.h>
14 #include <eval/eval_context.h>
15 #include <eval/parser.h>
16 #include <exceptions/exceptions.h>
17 #include <boost/lexical_cast.hpp>
18 #include <fstream>
19 #include <limits>
20
EvalContext(const Option::Universe & option_universe,CheckDefined check_defined)21 EvalContext::EvalContext(const Option::Universe& option_universe,
22 CheckDefined check_defined)
23 : trace_scanning_(false), trace_parsing_(false),
24 option_universe_(option_universe), check_defined_(check_defined)
25 {
26 }
27
~EvalContext()28 EvalContext::~EvalContext() {
29 }
30
31 bool
acceptAll(const ClientClass &)32 EvalContext::acceptAll(const ClientClass&) {
33 return (true);
34 }
35
36 bool
parseString(const std::string & str,ParserType type)37 EvalContext::parseString(const std::string& str, ParserType type) {
38 file_ = "<string>";
39 string_ = str;
40 scanStringBegin(type);
41 int res = -1;
42 try {
43 isc::eval::EvalParser parser(*this);
44 parser.set_debug_level(trace_parsing_);
45 res = parser.parse();
46 } catch (...) {
47 scanStringEnd();
48 throw;
49 }
50 scanStringEnd();
51 return (res == 0);
52 }
53
54 void
error(const isc::eval::location & loc,const std::string & what)55 EvalContext::error(const isc::eval::location& loc, const std::string& what) {
56 isc_throw(EvalParseError, loc << ": " << what);
57 }
58
59 void
error(const std::string & what)60 EvalContext::error (const std::string& what) {
61 isc_throw(EvalParseError, what);
62 }
63
64 uint16_t
convertOptionCode(const std::string & option_code,const isc::eval::location & loc)65 EvalContext::convertOptionCode(const std::string& option_code,
66 const isc::eval::location& loc) {
67 int n = 0;
68 try {
69 n = boost::lexical_cast<int>(option_code);
70 } catch (const boost::bad_lexical_cast &) {
71 // This can't happen...
72 error(loc, "Option code has invalid value in " + option_code);
73 }
74 if (option_universe_ == Option::V6) {
75 if (n < 0 || n > 65535) {
76 error(loc, "Option code has invalid value in "
77 + option_code + ". Allowed range: 0..65535");
78 }
79 } else {
80 if (n < 0 || n > 255) {
81 error(loc, "Option code has invalid value in "
82 + option_code + ". Allowed range: 0..255");
83 }
84 }
85 return (static_cast<uint16_t>(n));
86 }
87
88 uint16_t
convertOptionName(const std::string & option_name,const isc::eval::location & loc)89 EvalContext::convertOptionName(const std::string& option_name,
90 const isc::eval::location& loc) {
91 const std::string global_space = (option_universe_ == Option::V4) ?
92 DHCP4_OPTION_SPACE : DHCP6_OPTION_SPACE;
93
94 OptionDefinitionPtr option_def = LibDHCP::getOptionDef(global_space,
95 option_name);
96 if (!option_def) {
97 option_def = LibDHCP::getRuntimeOptionDef(global_space, option_name);
98 }
99
100 if (!option_def) {
101 option_def = LibDHCP::getLastResortOptionDef(global_space, option_name);
102 }
103
104 if (!option_def) {
105 error(loc, "option '" + option_name + "' is not defined");
106 }
107
108 return (option_def->getCode());
109 }
110
111 int8_t
convertNestLevelNumber(const std::string & nest_level,const isc::eval::location & loc)112 EvalContext::convertNestLevelNumber(const std::string& nest_level,
113 const isc::eval::location& loc) {
114 int8_t n = convertInt8(nest_level, loc);
115 if (option_universe_ == Option::V6) {
116 if ((n < - HOP_COUNT_LIMIT) || (n >= HOP_COUNT_LIMIT)) {
117 error(loc, "Nest level has invalid value in "
118 + nest_level + ". Allowed range: -32..31");
119 }
120 } else {
121 error(loc, "Nest level invalid for DHCPv4 packets");
122 }
123
124 return (n);
125 }
126
127 uint8_t
convertUint8(const std::string & number,const isc::eval::location & loc)128 EvalContext::convertUint8(const std::string& number,
129 const isc::eval::location& loc) {
130 int64_t n = 0;
131 try {
132 n = boost::lexical_cast<int64_t>(number);
133 } catch (const boost::bad_lexical_cast &) {
134 error(loc, "Invalid integer value in " + number);
135 }
136 if (n < 0 || n > std::numeric_limits<uint8_t>::max()) {
137 error(loc, "Invalid value in "
138 + number + ". Allowed range: 0..255");
139 }
140
141 return (static_cast<uint8_t>(n));
142 }
143
144 int8_t
convertInt8(const std::string & number,const isc::eval::location & loc)145 EvalContext::convertInt8(const std::string& number,
146 const isc::eval::location& loc) {
147 int64_t n = 0;
148 try {
149 n = boost::lexical_cast<int64_t>(number);
150 } catch (const boost::bad_lexical_cast &) {
151 error(loc, "Invalid integer value in " + number);
152 }
153 if (n < std::numeric_limits<int8_t>::min() ||
154 n > std::numeric_limits<int8_t>::max()) {
155 error(loc, "Invalid value in "
156 + number + ". Allowed range: -128..127");
157 }
158
159 return (static_cast<int8_t>(n));
160 }
161
162 uint16_t
convertUint16(const std::string & number,const isc::eval::location & loc)163 EvalContext::convertUint16(const std::string& number,
164 const isc::eval::location& loc) {
165 int64_t n = 0;
166 try {
167 n = boost::lexical_cast<int64_t>(number);
168 } catch (const boost::bad_lexical_cast &) {
169 error(loc, "Invalid value in " + number);
170 }
171 if (n < 0 || n > std::numeric_limits<uint16_t>::max()) {
172 error(loc, "Invalid value in "
173 + number + ". Allowed range: 0..65535");
174 }
175
176 return (static_cast<uint16_t>(n));
177 }
178
179 int16_t
convertInt16(const std::string & number,const isc::eval::location & loc)180 EvalContext::convertInt16(const std::string& number,
181 const isc::eval::location& loc) {
182 uint64_t n = 0;
183 try {
184 n = boost::lexical_cast<int64_t>(number);
185 } catch (const boost::bad_lexical_cast &) {
186 error(loc, "Invalid value in " + number);
187 }
188 if (n > std::numeric_limits<int16_t>::max() ||
189 n < std::numeric_limits<int16_t>::max()) {
190 error(loc, "Invalid value in "
191 + number + ". Allowed range: -32768..32767");
192 }
193
194 return (static_cast<int16_t>(n));
195 }
196
197 uint32_t
convertUint32(const std::string & number,const isc::eval::location & loc)198 EvalContext::convertUint32(const std::string& number,
199 const isc::eval::location& loc) {
200 int64_t n = 0;
201 try {
202 n = boost::lexical_cast<int64_t>(number);
203 } catch (const boost::bad_lexical_cast &) {
204 error(loc, "Invalid value in " + number);
205 }
206 if (n < 0 || n > std::numeric_limits<uint32_t>::max()) {
207 error(loc, "Invalid value in "
208 + number + ". Allowed range: 0..4294967295");
209 }
210
211 return (static_cast<uint32_t>(n));
212 }
213
214 int32_t
convertInt32(const std::string & number,const isc::eval::location & loc)215 EvalContext::convertInt32(const std::string& number,
216 const isc::eval::location& loc) {
217 int64_t n = 0;
218 try {
219 n = boost::lexical_cast<int64_t>(number);
220 } catch (const boost::bad_lexical_cast &) {
221 error(loc, "Invalid value in " + number);
222 }
223 if (n > std::numeric_limits<int32_t>::max() ||
224 n < std::numeric_limits<int32_t>::max()) {
225 error(loc, "Invalid value in "
226 + number + ". Allowed range: -2147483648..2147483647");
227 }
228
229 return (static_cast<int32_t>(n));
230 }
231
232 std::string
fromUint32(const uint32_t integer)233 EvalContext::fromUint32(const uint32_t integer) {
234 std::string tmp(4, 0);
235 tmp[0] = (integer >> 24) & 0xff;
236 tmp[1] = (integer >> 16) & 0xff;
237 tmp[2] = (integer >> 8) & 0xff;
238 tmp[3] = integer & 0xff;
239
240 return (tmp);
241 }
242
243 std::string
fromUint16(const uint16_t integer)244 EvalContext::fromUint16(const uint16_t integer) {
245 std::string tmp(2, 0);
246 tmp[0] = (integer >> 8) & 0xff;
247 tmp[1] = integer & 0xff;
248
249 return (tmp);
250 }
251
252 bool
isClientClassDefined(const ClientClass & client_class)253 EvalContext::isClientClassDefined(const ClientClass& client_class) {
254 return (check_defined_(client_class));
255 }
256
257 void
fatal(const std::string & what)258 EvalContext::fatal(const std::string& what) {
259 isc_throw(Unexpected, what);
260 }
261