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