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