Replace g_log() calls with ws_log()
[metze/wireshark/wip.git] / epan / dfilter / dfilter.c
1 /*
2  * Wireshark - Network traffic analyzer
3  * By Gerald Combs <gerald@wireshark.org>
4  * Copyright 2001 Gerald Combs
5  *
6  * SPDX-License-Identifier: GPL-2.0-or-later
7  */
8
9 #include "config.h"
10 #define WS_LOG_DOMAIN "Dfilter"
11
12 #include <stdio.h>
13 #include <string.h>
14
15 #include "dfilter-int.h"
16 #include "syntax-tree.h"
17 #include "gencode.h"
18 #include "semcheck.h"
19 #include "dfvm.h"
20 #include <epan/epan_dissect.h>
21 #include "dfilter.h"
22 #include "dfilter-macro.h"
23 #include "scanner_lex.h"
24 #include <wsutil/wslog.h>
25
26
27 #define DFILTER_TOKEN_ID_OFFSET 1
28
29 /* Holds the singular instance of our Lemon parser object */
30 static void*    ParserObj = NULL;
31
32 /*
33  * XXX - if we're using a version of Flex that supports reentrant lexical
34  * analyzers, we should put this into the lexical analyzer's state.
35  */
36 dfwork_t *global_dfw;
37
38 void
39 dfilter_fail(dfwork_t *dfw, const char *format, ...)
40 {
41         va_list args;
42
43         /* If we've already reported one error, don't overwite it */
44         if (dfw->error_message != NULL)
45                 return;
46
47         va_start(args, format);
48         dfw->error_message = g_strdup_vprintf(format, args);
49         va_end(args);
50 }
51
52 /* Initialize the dfilter module */
53 void
54 dfilter_init(void)
55 {
56         if (ParserObj) {
57                 ws_message("I expected ParserObj to be NULL\n");
58                 /* Free the Lemon Parser object */
59                 DfilterFree(ParserObj, g_free);
60         }
61         /* Allocate an instance of our Lemon-based parser */
62         ParserObj = DfilterAlloc(g_malloc);
63
64 /* Enable parser tracing by defining AM_CFLAGS
65  * so that it contains "-DDFTRACE".
66  */
67 #ifdef DFTRACE
68         /* Trace parser */
69         DfilterTrace(stdout, "lemon> ");
70 #endif
71
72         /* Initialize the syntax-tree sub-sub-system */
73         sttype_init();
74
75         dfilter_macro_init();
76 }
77
78 /* Clean-up the dfilter module */
79 void
80 dfilter_cleanup(void)
81 {
82         dfilter_macro_cleanup();
83
84         /* Free the Lemon Parser object */
85         if (ParserObj) {
86                 DfilterFree(ParserObj, g_free);
87         }
88
89         /* Clean up the syntax-tree sub-sub-system */
90         sttype_cleanup();
91 }
92
93 static dfilter_t*
94 dfilter_new(void)
95 {
96         dfilter_t       *df;
97
98         df = g_new0(dfilter_t, 1);
99         df->insns = NULL;
100         df->deprecated = NULL;
101
102         return df;
103 }
104
105 /* Given a GPtrArray of instructions (dfvm_insn_t),
106  * free them. */
107 static void
108 free_insns(GPtrArray *insns)
109 {
110         unsigned int    i;
111         dfvm_insn_t     *insn;
112
113         for (i = 0; i < insns->len; i++) {
114                 insn = (dfvm_insn_t     *)g_ptr_array_index(insns, i);
115                 dfvm_insn_free(insn);
116         }
117         g_ptr_array_free(insns, TRUE);
118 }
119
120 void
121 dfilter_free(dfilter_t *df)
122 {
123         guint i;
124
125         if (!df)
126                 return;
127
128         if (df->insns) {
129                 free_insns(df->insns);
130         }
131         if (df->consts) {
132                 free_insns(df->consts);
133         }
134
135         g_free(df->interesting_fields);
136
137         /* Clear registers with constant values (as set by dfvm_init_const).
138          * Other registers were cleared on RETURN by free_register_overhead. */
139         for (i = df->num_registers; i < df->max_registers; i++) {
140                 g_list_free(df->registers[i]);
141         }
142
143         if (df->deprecated) {
144                 for (i = 0; i < df->deprecated->len; ++i) {
145                         gchar *depr = (gchar *)g_ptr_array_index(df->deprecated, i);
146                         g_free(depr);
147                 }
148                 g_ptr_array_free(df->deprecated, TRUE);
149         }
150
151         g_free(df->registers);
152         g_free(df->attempted_load);
153         g_free(df->owns_memory);
154         g_free(df);
155 }
156
157
158 static dfwork_t*
159 dfwork_new(void)
160 {
161         dfwork_t        *dfw;
162
163         dfw = g_new0(dfwork_t, 1);
164         dfw->first_constant = -1;
165
166         return dfw;
167 }
168
169 static void
170 dfwork_free(dfwork_t *dfw)
171 {
172         if (dfw->st_root) {
173                 stnode_free(dfw->st_root);
174         }
175
176         if (dfw->loaded_fields) {
177                 g_hash_table_destroy(dfw->loaded_fields);
178         }
179
180         if (dfw->interesting_fields) {
181                 g_hash_table_destroy(dfw->interesting_fields);
182         }
183
184         if (dfw->insns) {
185                 free_insns(dfw->insns);
186         }
187
188         if (dfw->consts) {
189                 free_insns(dfw->consts);
190         }
191
192         /*
193          * We don't free the error message string; our caller will return
194          * it to its caller.
195          */
196         g_free(dfw);
197 }
198
199 gboolean
200 dfilter_compile(const gchar *text, dfilter_t **dfp, gchar **err_msg)
201 {
202         gchar           *expanded_text;
203         int             token;
204         dfilter_t       *dfilter;
205         dfwork_t        *dfw;
206         df_scanner_state_t state;
207         yyscan_t        scanner;
208         YY_BUFFER_STATE in_buffer;
209         gboolean failure = FALSE;
210         const char      *depr_test;
211         guint           i;
212         /* XXX, GHashTable */
213         GPtrArray       *deprecated;
214
215         g_assert(dfp);
216
217         if (!text) {
218                 *dfp = NULL;
219                 if (err_msg != NULL)
220                         *err_msg = g_strdup("BUG: NULL text pointer passed to dfilter_compile()");
221                 return FALSE;
222         }
223
224         if ( !( expanded_text = dfilter_macro_apply(text, err_msg) ) ) {
225                 *dfp = NULL;
226                 return FALSE;
227         }
228
229         if (df_lex_init(&scanner) != 0) {
230                 wmem_free(NULL, expanded_text);
231                 *dfp = NULL;
232                 if (err_msg != NULL)
233                         *err_msg = g_strdup_printf("Can't initialize scanner: %s",
234                             g_strerror(errno));
235                 return FALSE;
236         }
237
238         in_buffer = df__scan_string(expanded_text, scanner);
239
240         dfw = dfwork_new();
241
242         state.dfw = dfw;
243         state.quoted_string = NULL;
244         state.in_set = FALSE;
245         state.raw_string = FALSE;
246
247         df_set_extra(&state, scanner);
248
249         deprecated = g_ptr_array_new();
250
251         while (1) {
252                 df_lval = stnode_new(STTYPE_UNINITIALIZED, NULL);
253                 token = df_lex(scanner);
254
255                 /* Check for scanner failure */
256                 if (token == SCAN_FAILED) {
257                         failure = TRUE;
258                         break;
259                 }
260
261                 /* Check for end-of-input */
262                 if (token == 0) {
263                         break;
264                 }
265
266                 /* See if the node is deprecated */
267                 depr_test = stnode_deprecated(df_lval);
268
269                 if (depr_test) {
270                         for (i = 0; i < deprecated->len; i++) {
271                                 if (g_ascii_strcasecmp(depr_test, (const gchar *)g_ptr_array_index(deprecated, i)) == 0) {
272                                         /* It's already in our list */
273                                         depr_test = NULL;
274                                 }
275                         }
276                 }
277
278                 if (depr_test) {
279                         g_ptr_array_add(deprecated, g_strdup(depr_test));
280                 }
281
282                 /* Give the token to the parser */
283                 Dfilter(ParserObj, token, df_lval, dfw);
284                 /* We've used the stnode_t, so we don't want to free it */
285                 df_lval = NULL;
286
287                 if (dfw->syntax_error) {
288                         failure = TRUE;
289                         break;
290                 }
291
292         } /* while (1) */
293
294         /* If we created an stnode_t but didn't use it, free it; the
295          * parser doesn't know about it and won't free it for us. */
296         if (df_lval) {
297                 stnode_free(df_lval);
298                 df_lval = NULL;
299         }
300
301         /* Tell the parser that we have reached the end of input; that
302          * way, it'll reset its state for the next compile.  (We want
303          * to do that even if we got a syntax error, to make sure the
304          * parser state is cleaned up; we don't create a new parser
305          * object when we start a new parse, and don't destroy it when
306          * the parse finishes.) */
307         Dfilter(ParserObj, 0, NULL, dfw);
308
309         /* One last check for syntax error (after EOF) */
310         if (dfw->syntax_error)
311                 failure = TRUE;
312
313         /* Free scanner state */
314         if (state.quoted_string != NULL)
315                 g_string_free(state.quoted_string, TRUE);
316         df__delete_buffer(in_buffer, scanner);
317         df_lex_destroy(scanner);
318
319         if (failure)
320                 goto FAILURE;
321
322         /* Success, but was it an empty filter? If so, discard
323          * it and set *dfp to NULL */
324         if (dfw->st_root == NULL) {
325                 *dfp = NULL;
326                 for (i = 0; i < deprecated->len; ++i) {
327                         gchar* depr = (gchar*)g_ptr_array_index(deprecated,i);
328                         g_free(depr);
329                 }
330                 g_ptr_array_free(deprecated, TRUE);
331         }
332         else {
333
334                 /* Check semantics and do necessary type conversion*/
335                 if (!dfw_semcheck(dfw, deprecated)) {
336                         goto FAILURE;
337                 }
338
339                 /* Create bytecode */
340                 dfw_gencode(dfw);
341
342                 /* Tuck away the bytecode in the dfilter_t */
343                 dfilter = dfilter_new();
344                 dfilter->insns = dfw->insns;
345                 dfilter->consts = dfw->consts;
346                 dfw->insns = NULL;
347                 dfw->consts = NULL;
348                 dfilter->interesting_fields = dfw_interesting_fields(dfw,
349                         &dfilter->num_interesting_fields);
350
351                 /* Initialize run-time space */
352                 dfilter->num_registers = dfw->first_constant;
353                 dfilter->max_registers = dfw->next_register;
354                 dfilter->registers = g_new0(GList*, dfilter->max_registers);
355                 dfilter->attempted_load = g_new0(gboolean, dfilter->max_registers);
356                 dfilter->owns_memory = g_new0(gboolean, dfilter->max_registers);
357
358                 /* Initialize constants */
359                 dfvm_init_const(dfilter);
360
361                 /* Add any deprecated items */
362                 dfilter->deprecated = deprecated;
363
364                 /* And give it to the user. */
365                 *dfp = dfilter;
366         }
367         /* SUCCESS */
368         global_dfw = NULL;
369         dfwork_free(dfw);
370         wmem_free(NULL, expanded_text);
371         return TRUE;
372
373 FAILURE:
374         if (dfw) {
375                 if (err_msg != NULL)
376                         *err_msg = dfw->error_message;
377                 else
378                         g_free(dfw->error_message);
379                 global_dfw = NULL;
380                 dfwork_free(dfw);
381         }
382         for (i = 0; i < deprecated->len; ++i) {
383                 gchar* depr = (gchar*)g_ptr_array_index(deprecated,i);
384                 g_free(depr);
385         }
386         g_ptr_array_free(deprecated, TRUE);
387         if (err_msg != NULL) {
388                 /*
389                  * Default error message.
390                  *
391                  * XXX - we should really make sure that this is never the
392                  * case for any error.
393                  */
394                 if (*err_msg == NULL)
395                         *err_msg = g_strdup_printf("Unable to parse filter string \"%s\".", expanded_text);
396         }
397         wmem_free(NULL, expanded_text);
398         *dfp = NULL;
399         return FALSE;
400 }
401
402
403 gboolean
404 dfilter_apply(dfilter_t *df, proto_tree *tree)
405 {
406         return dfvm_apply(df, tree);
407 }
408
409 gboolean
410 dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt)
411 {
412         return dfvm_apply(df, edt->tree);
413 }
414
415
416 void
417 dfilter_prime_proto_tree(const dfilter_t *df, proto_tree *tree)
418 {
419         int i;
420
421         for (i = 0; i < df->num_interesting_fields; i++) {
422                 proto_tree_prime_with_hfid(tree, df->interesting_fields[i]);
423         }
424 }
425
426 gboolean
427 dfilter_has_interesting_fields(const dfilter_t *df)
428 {
429         return (df->num_interesting_fields > 0);
430 }
431
432 GPtrArray *
433 dfilter_deprecated_tokens(dfilter_t *df) {
434         if (df->deprecated && df->deprecated->len > 0) {
435                 return df->deprecated;
436         }
437         return NULL;
438 }
439
440 void
441 dfilter_dump(dfilter_t *df)
442 {
443         guint i;
444         const gchar *sep = "";
445
446         dfvm_dump(stdout, df);
447
448         if (df->deprecated && df->deprecated->len) {
449                 printf("\nDeprecated tokens: ");
450                 for (i = 0; i < df->deprecated->len; i++) {
451                         printf("%s\"%s\"", sep, (char *) g_ptr_array_index(df->deprecated, i));
452                         sep = ", ";
453                 }
454                 printf("\n");
455         }
456 }
457
458 /*
459  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
460  *
461  * Local variables:
462  * c-basic-offset: 8
463  * tab-width: 8
464  * indent-tabs-mode: t
465  * End:
466  *
467  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
468  * :indentSize=8:tabSize=8:noTabs=false:
469  */