2 * Wireshark - Network traffic analyzer
3 * By Gerald Combs <gerald@wireshark.org>
4 * Copyright 2001 Gerald Combs
6 * SPDX-License-Identifier: GPL-2.0-or-later
10 #define WS_LOG_DOMAIN "Dfilter"
15 #include "dfilter-int.h"
16 #include "syntax-tree.h"
20 #include <epan/epan_dissect.h>
22 #include "dfilter-macro.h"
23 #include "scanner_lex.h"
24 #include <wsutil/wslog.h>
27 #define DFILTER_TOKEN_ID_OFFSET 1
29 /* Holds the singular instance of our Lemon parser object */
30 static void* ParserObj = NULL;
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.
39 dfilter_fail(dfwork_t *dfw, const char *format, ...)
43 /* If we've already reported one error, don't overwite it */
44 if (dfw->error_message != NULL)
47 va_start(args, format);
48 dfw->error_message = g_strdup_vprintf(format, args);
52 /* Initialize the dfilter module */
57 ws_message("I expected ParserObj to be NULL\n");
58 /* Free the Lemon Parser object */
59 DfilterFree(ParserObj, g_free);
61 /* Allocate an instance of our Lemon-based parser */
62 ParserObj = DfilterAlloc(g_malloc);
64 /* Enable parser tracing by defining AM_CFLAGS
65 * so that it contains "-DDFTRACE".
69 DfilterTrace(stdout, "lemon> ");
72 /* Initialize the syntax-tree sub-sub-system */
78 /* Clean-up the dfilter module */
82 dfilter_macro_cleanup();
84 /* Free the Lemon Parser object */
86 DfilterFree(ParserObj, g_free);
89 /* Clean up the syntax-tree sub-sub-system */
98 df = g_new0(dfilter_t, 1);
100 df->deprecated = NULL;
105 /* Given a GPtrArray of instructions (dfvm_insn_t),
108 free_insns(GPtrArray *insns)
113 for (i = 0; i < insns->len; i++) {
114 insn = (dfvm_insn_t *)g_ptr_array_index(insns, i);
115 dfvm_insn_free(insn);
117 g_ptr_array_free(insns, TRUE);
121 dfilter_free(dfilter_t *df)
129 free_insns(df->insns);
132 free_insns(df->consts);
135 g_free(df->interesting_fields);
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]);
143 if (df->deprecated) {
144 for (i = 0; i < df->deprecated->len; ++i) {
145 gchar *depr = (gchar *)g_ptr_array_index(df->deprecated, i);
148 g_ptr_array_free(df->deprecated, TRUE);
151 g_free(df->registers);
152 g_free(df->attempted_load);
153 g_free(df->owns_memory);
163 dfw = g_new0(dfwork_t, 1);
164 dfw->first_constant = -1;
170 dfwork_free(dfwork_t *dfw)
173 stnode_free(dfw->st_root);
176 if (dfw->loaded_fields) {
177 g_hash_table_destroy(dfw->loaded_fields);
180 if (dfw->interesting_fields) {
181 g_hash_table_destroy(dfw->interesting_fields);
185 free_insns(dfw->insns);
189 free_insns(dfw->consts);
193 * We don't free the error message string; our caller will return
200 dfilter_compile(const gchar *text, dfilter_t **dfp, gchar **err_msg)
202 gchar *expanded_text;
206 df_scanner_state_t state;
208 YY_BUFFER_STATE in_buffer;
209 gboolean failure = FALSE;
210 const char *depr_test;
212 /* XXX, GHashTable */
213 GPtrArray *deprecated;
220 *err_msg = g_strdup("BUG: NULL text pointer passed to dfilter_compile()");
224 if ( !( expanded_text = dfilter_macro_apply(text, err_msg) ) ) {
229 if (df_lex_init(&scanner) != 0) {
230 wmem_free(NULL, expanded_text);
233 *err_msg = g_strdup_printf("Can't initialize scanner: %s",
238 in_buffer = df__scan_string(expanded_text, scanner);
243 state.quoted_string = NULL;
244 state.in_set = FALSE;
245 state.raw_string = FALSE;
247 df_set_extra(&state, scanner);
249 deprecated = g_ptr_array_new();
252 df_lval = stnode_new(STTYPE_UNINITIALIZED, NULL);
253 token = df_lex(scanner);
255 /* Check for scanner failure */
256 if (token == SCAN_FAILED) {
261 /* Check for end-of-input */
266 /* See if the node is deprecated */
267 depr_test = stnode_deprecated(df_lval);
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 */
279 g_ptr_array_add(deprecated, g_strdup(depr_test));
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 */
287 if (dfw->syntax_error) {
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. */
297 stnode_free(df_lval);
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);
309 /* One last check for syntax error (after EOF) */
310 if (dfw->syntax_error)
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);
322 /* Success, but was it an empty filter? If so, discard
323 * it and set *dfp to NULL */
324 if (dfw->st_root == NULL) {
326 for (i = 0; i < deprecated->len; ++i) {
327 gchar* depr = (gchar*)g_ptr_array_index(deprecated,i);
330 g_ptr_array_free(deprecated, TRUE);
334 /* Check semantics and do necessary type conversion*/
335 if (!dfw_semcheck(dfw, deprecated)) {
339 /* Create bytecode */
342 /* Tuck away the bytecode in the dfilter_t */
343 dfilter = dfilter_new();
344 dfilter->insns = dfw->insns;
345 dfilter->consts = dfw->consts;
348 dfilter->interesting_fields = dfw_interesting_fields(dfw,
349 &dfilter->num_interesting_fields);
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);
358 /* Initialize constants */
359 dfvm_init_const(dfilter);
361 /* Add any deprecated items */
362 dfilter->deprecated = deprecated;
364 /* And give it to the user. */
370 wmem_free(NULL, expanded_text);
376 *err_msg = dfw->error_message;
378 g_free(dfw->error_message);
382 for (i = 0; i < deprecated->len; ++i) {
383 gchar* depr = (gchar*)g_ptr_array_index(deprecated,i);
386 g_ptr_array_free(deprecated, TRUE);
387 if (err_msg != NULL) {
389 * Default error message.
391 * XXX - we should really make sure that this is never the
392 * case for any error.
394 if (*err_msg == NULL)
395 *err_msg = g_strdup_printf("Unable to parse filter string \"%s\".", expanded_text);
397 wmem_free(NULL, expanded_text);
404 dfilter_apply(dfilter_t *df, proto_tree *tree)
406 return dfvm_apply(df, tree);
410 dfilter_apply_edt(dfilter_t *df, epan_dissect_t* edt)
412 return dfvm_apply(df, edt->tree);
417 dfilter_prime_proto_tree(const dfilter_t *df, proto_tree *tree)
421 for (i = 0; i < df->num_interesting_fields; i++) {
422 proto_tree_prime_with_hfid(tree, df->interesting_fields[i]);
427 dfilter_has_interesting_fields(const dfilter_t *df)
429 return (df->num_interesting_fields > 0);
433 dfilter_deprecated_tokens(dfilter_t *df) {
434 if (df->deprecated && df->deprecated->len > 0) {
435 return df->deprecated;
441 dfilter_dump(dfilter_t *df)
444 const gchar *sep = "";
446 dfvm_dump(stdout, df);
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));
459 * Editor modelines - https://www.wireshark.org/tools/modelines.html
464 * indent-tabs-mode: t
467 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
468 * :indentSize=8:tabSize=8:noTabs=false: