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 #ifndef PARSER_CONTEXT_H
8 #define PARSER_CONTEXT_H
9 #include <string>
10 #include <map>
11 #include <vector>
12 #include <dhcp6/dhcp6_parser.h>
13 #include <dhcp6/parser_context_decl.h>
14 #include <exceptions/exceptions.h>
15 
16 // Tell Flex the lexer's prototype ...
17 #define YY_DECL isc::dhcp::Dhcp6Parser::symbol_type parser6_lex (Parser6Context& driver)
18 
19 // ... and declare it for the parser's sake.
20 YY_DECL;
21 
22 namespace isc {
23 namespace dhcp {
24 
25 /// @brief Evaluation error exception raised when trying to parse.
26 ///
27 /// @todo: This probably should be common for Dhcp4 and Dhcp6.
28 class Dhcp6ParseError : public isc::Exception {
29 public:
Dhcp6ParseError(const char * file,size_t line,const char * what)30     Dhcp6ParseError(const char* file, size_t line, const char* what) :
31         isc::Exception(file, line, what) { };
32 };
33 
34 /// @brief Evaluation context, an interface to the expression evaluation.
35 class Parser6Context
36 {
37 public:
38 
39     /// @brief Defines currently supported scopes
40     ///
41     /// Dhcp6Parser is able to parse several types of scope. Usually,
42     /// when it parses a config file, it expects the data to have a map
43     /// with Dhcp6 in it and all the parameters within that Dhcp6 map.
44     /// However, sometimes the parser is expected to parse only a subset
45     /// of that information. For example, it may be asked to parse
46     /// a structure that is host-reservation only, without the global
47     /// 'Dhcp6' or 'reservations' around it. In such case the parser
48     /// is being told to start parsing as PARSER_HOST_RESERVATION6.
49     typedef enum {
50         /// This parser will parse the content as generic JSON.
51         PARSER_JSON,
52 
53         /// This parser will parse the content as Dhcp6 config wrapped in a map
54         /// (that's the regular config file)
55         PARSER_DHCP6,
56 
57         /// This parser will parse the content of Dhcp6 (without outer { } and
58         /// without "Dhcp6"). It is mostly used in unit-tests as most of the
59         /// unit-tests do not define the outer map and Dhcp6 entity, just the
60         /// contents of it.
61         SUBPARSER_DHCP6,
62 
63         /// This will parse the input as interfaces content.
64         PARSER_INTERFACES,
65 
66         /// This will parse the input as Subnet6 content.
67         PARSER_SUBNET6,
68 
69         /// This will parse the input as pool6 content.
70         PARSER_POOL6,
71 
72         /// This will parse the input as pd-pool content.
73         PARSER_PD_POOL,
74 
75         /// This will parse the input as host-reservation.
76         PARSER_HOST_RESERVATION,
77 
78         /// This will parse the input option definitions (for tests).
79         PARSER_OPTION_DEFS,
80 
81         /// This will parse the input as option definition.
82         PARSER_OPTION_DEF,
83 
84         /// This will parse the input as option data.
85         PARSER_OPTION_DATA,
86 
87         /// This will parse the input as hooks-library.
88         PARSER_HOOKS_LIBRARY,
89 
90         /// This will parse the input as dhcp-ddns. (D2 client config)
91         PARSER_DHCP_DDNS,
92 
93         /// This will parse the input as config-control.
94         PARSER_CONFIG_CONTROL,
95     } ParserType;
96 
97     /// @brief Default constructor.
98     Parser6Context();
99 
100     /// @brief destructor
101     virtual ~Parser6Context();
102 
103     /// @brief JSON elements being parsed.
104     std::vector<isc::data::ElementPtr> stack_;
105 
106     /// @brief Method called before scanning starts on a string.
107     ///
108     /// @param str string to be parsed
109     /// @param type specifies expected content
110     void scanStringBegin(const std::string& str, ParserType type);
111 
112     /// @brief Method called before scanning starts on a file.
113     ///
114     /// @param f stdio FILE pointer
115     /// @param filename file to be parsed
116     /// @param type specifies expected content
117     void scanFileBegin(FILE* f, const std::string& filename, ParserType type);
118 
119     /// @brief Method called after the last tokens are scanned.
120     void scanEnd();
121 
122     /// @brief Divert input to an include file.
123     ///
124     /// @param filename file to be included
125     void includeFile(const std::string& filename);
126 
127     /// @brief Run the parser on the string specified.
128     ///
129     /// This method parses specified string. Depending on the value of
130     /// parser_type, parser may either check only that the input is valid
131     /// JSON, or may do more specific syntax checking. See @ref ParserType
132     /// for supported syntax checkers.
133     ///
134     /// @param str string to be parsed
135     /// @param parser_type specifies expected content (usually DHCP6 or generic JSON)
136     /// @return Element structure representing parsed text.
137     isc::data::ElementPtr parseString(const std::string& str,
138                                       ParserType parser_type);
139 
140     /// @brief Run the parser on the file specified.
141     ///
142     /// This method parses specified file. Depending on the value of
143     /// parser_type, parser may either check only that the input is valid
144     /// JSON, or may do more specific syntax checking. See @ref ParserType
145     /// for supported syntax checkers.
146     ///
147     /// @param filename file to be parsed
148     /// @param parser_type specifies expected content (usually DHCP6 or generic JSON)
149     /// @return Element structure representing parsed text.
150     isc::data::ElementPtr parseFile(const std::string& filename,
151                                     ParserType parser_type);
152 
153     /// @brief Error handler
154     ///
155     /// @note The optional position for an error in a string begins by 1
156     /// so the caller should add 1 to the position of the C++ string.
157     ///
158     /// @param loc location within the parsed file when experienced a problem.
159     /// @param what string explaining the nature of the error.
160     /// @param pos optional position for in string errors.
161     /// @throw Dhcp6ParseError
162     void error(const isc::dhcp::location& loc,
163                const std::string& what,
164                size_t pos = 0);
165 
166     /// @brief Error handler
167     ///
168     /// This is a simplified error reporting tool for possible future
169     /// cases when the Dhcp6Parser is not able to handle the packet.
170     ///
171     /// @param what string explaining the nature of the error.
172     /// @throw Dhcp6ParseError
173     void error(const std::string& what);
174 
175     /// @brief Fatal error handler
176     ///
177     /// This is for should not happen but fatal errors.
178     /// Used by YY_FATAL_ERROR macro so required to be static.
179     ///
180     /// @param what string explaining the nature of the error.
181     /// @throw Dhcp6ParseError
182     static void fatal(const std::string& what);
183 
184     /// @brief Converts bison's position to one understandable by isc::data::Element
185     ///
186     /// Convert a bison location into an element position
187     /// (take the begin, the end is lost)
188     ///
189     /// @param loc location in bison format
190     /// @return Position in format accepted by Element
191     isc::data::Element::Position loc2pos(isc::dhcp::location& loc);
192 
193     /// @brief Check if a required parameter is present
194     ///
195     /// Check if a required parameter is present in the map at the top
196     /// of the stack and raise an error when it is not.
197     ///
198     /// @param name name of the parameter expected to be present
199     /// @param open_loc location of the opening curly bracket
200     /// @param close_loc location of the closing curly bracket
201     /// @throw Dhcp6ParseError
202     void require(const std::string& name,
203                  isc::data::Element::Position open_loc,
204                  isc::data::Element::Position close_loc);
205 
206     /// @brief Check if a parameter is already present
207     ///
208     /// Check if a parameter is already present in the map at the top
209     /// of the stack and raise an error when it is.
210     ///
211     /// @param name name of the parameter to check
212     /// @param loc location of the current parameter
213     /// @throw Dhcp6ParseError
214     void unique(const std::string& name,
215                 isc::data::Element::Position loc);
216 
217     /// @brief Defines syntactic contexts for lexical tie-ins
218     typedef enum {
219         ///< This one is used in pure JSON mode.
220         NO_KEYWORD,
221 
222         ///< Used while parsing top level (that contains Dhcp6)
223         CONFIG,
224 
225         ///< Used while parsing content of Dhcp6.
226         DHCP6,
227 
228         /// Used while parsing Dhcp6/interfaces structures.
229         INTERFACES_CONFIG,
230 
231         /// Sanity checks.
232         SANITY_CHECKS,
233 
234         /// Used while parsing Dhcp6/lease-database structures.
235         LEASE_DATABASE,
236 
237         /// Used while parsing Dhcp6/hosts-database[s] structures.
238         HOSTS_DATABASE,
239 
240         /// Used while parsing Dhcp6/*-database/type.
241         DATABASE_TYPE,
242 
243         /// Used while parsing Dhcp6/*-database/on-fail.
244         DATABASE_ON_FAIL,
245 
246         /// Used while parsing Dhcp6/mac-sources structures.
247         MAC_SOURCES,
248 
249         /// Used while parsing Dhcp6/host-reservation-identifiers.
250         HOST_RESERVATION_IDENTIFIERS,
251 
252         /// Used while parsing Dhcp6/hooks-libraries.
253         HOOKS_LIBRARIES,
254 
255         /// Used while parsing Dhcp6/Subnet6 structures.
256         SUBNET6,
257 
258         /// Used while parsing shared-networks structures.
259         SHARED_NETWORK,
260 
261         /// Used while parsing Dhcp6/reservation-mode.
262         RESERVATION_MODE,
263 
264         /// Used while parsing Dhcp6/option-def structures.
265         OPTION_DEF,
266 
267         /// Used while parsing Dhcp6/option-data, Dhcp6/subnet6/option-data
268         /// or anywhere option-data is present (client classes, host
269         /// reservations and possibly others).
270         OPTION_DATA,
271 
272         /// Used while parsing Dhcp6/client-classes structures.
273         CLIENT_CLASSES,
274 
275         /// Used while parsing Dhcp6/expired-leases-processing.
276         EXPIRED_LEASES_PROCESSING,
277 
278         /// Used while parsing Dhcp6/server-id structures.
279         SERVER_ID,
280 
281         /// Used while parsing Dhcp6/server-id/type structures.
282         DUID_TYPE,
283 
284         /// Used while parsing Dhcp6/control-socket structures.
285         CONTROL_SOCKET,
286 
287         /// Used while parsing Dhcp6/dhcp-queue-control structures.
288         DHCP_QUEUE_CONTROL,
289 
290         /// Used while parsing Dhcp6/multi-threading structures.
291         DHCP_MULTI_THREADING,
292 
293         /// Used while parsing Dhcp6/subnet6/pools structures.
294         POOLS,
295 
296         /// Used while parsing Dhcp6/subnet6/pd-pools structures.
297         PD_POOLS,
298 
299         /// Used while parsing Dhcp6/reservations structures.
300         RESERVATIONS,
301 
302         /// Used while parsing Dhcp6/subnet6/relay structures.
303         RELAY,
304 
305         /// Used while parsing Dhcp6/loggers structures.
306         LOGGERS,
307 
308         /// Used while parsing Dhcp6/loggers/output_options structures.
309         OUTPUT_OPTIONS,
310 
311         /// Used while parsing Dhcp6/dhcp-ddns.
312         DHCP_DDNS,
313 
314         /// Used while parsing Dhcp6/dhcp-ddns/ncr-protocol
315         NCR_PROTOCOL,
316 
317         /// Used while parsing Dhcp6/dhcp-ddns/ncr-format
318         NCR_FORMAT,
319 
320         /// Used while parsing Dhcp6/dhcp-ddns/replace-client-name.
321         REPLACE_CLIENT_NAME,
322 
323         /// Used while parsing Dhcp6/config-control
324         CONFIG_CONTROL,
325 
326         /// Used while parsing config-control/config-databases
327         CONFIG_DATABASE,
328 
329         /// Used while parsing compatibility parameters
330         COMPATIBILITY,
331 
332     } ParserContext;
333 
334     /// @brief File name
335     std::string file_;
336 
337     /// @brief File name stack
338     std::vector<std::string> files_;
339 
340     /// @brief Location of the current token
341     ///
342     /// The lexer will keep updating it. This variable will be useful
343     /// for logging errors.
344     isc::dhcp::location loc_;
345 
346     /// @brief Location stack
347     std::vector<isc::dhcp::location> locs_;
348 
349     /// @brief Lexer state stack
350     std::vector<struct yy_buffer_state*> states_;
351 
352     /// @brief sFile (aka FILE)
353     FILE* sfile_;
354 
355     /// @brief sFile (aka FILE) stack
356     ///
357     /// This is a stack of files. Typically there's only one file (the
358     /// one being currently parsed), but there may be more if one
359     /// file includes another.
360     std::vector<FILE*> sfiles_;
361 
362     /// @brief Current syntactic context
363     ParserContext ctx_;
364 
365     /// @brief Enter a new syntactic context
366     ///
367     /// Entering a new syntactic context is useful in several ways.
368     /// First, it allows the parser to avoid conflicts. Second, it
369     /// allows the lexer to return different tokens depending on
370     /// context (e.g. if "renew-timer" string is detected, the lexer
371     /// will return STRING token if in JSON mode or RENEW_TIMER if
372     /// in DHCP6 mode. Finally, the syntactic context allows the
373     /// error message to be more descriptive if the input string
374     /// does not parse properly.
375     ///
376     /// @param ctx the syntactic context to enter into
377     void enter(const ParserContext& ctx);
378 
379     /// @brief Leave a syntactic context
380     ///
381     /// @throw isc::Unexpected if unbalanced
382     void leave();
383 
384     /// @brief Get the syntactic context name
385     ///
386     /// @return printable name of the context.
387     const std::string contextName();
388 
389  private:
390     /// @brief Flag determining scanner debugging.
391     bool trace_scanning_;
392 
393     /// @brief Flag determining parser debugging.
394     bool trace_parsing_;
395 
396     /// @brief Syntactic context stack
397     std::vector<ParserContext> cstack_;
398 
399     /// @brief Common part of parseXXX
400     ///
401     /// @return Element structure representing parsed text.
402     isc::data::ElementPtr parseCommon();
403 };
404 
405 }; // end of isc::eval namespace
406 }; // end of isc namespace
407 
408 #endif
409