diff options
Diffstat (limited to 'epan/dfilter')
-rw-r--r-- | epan/dfilter/dfilter-int.h | 3 | ||||
-rw-r--r-- | epan/dfilter/dfilter-macro.c | 83 | ||||
-rw-r--r-- | epan/dfilter/dfilter-macro.h | 3 | ||||
-rw-r--r-- | epan/dfilter/dfilter.c | 77 | ||||
-rw-r--r-- | epan/dfilter/dfilter.h | 5 | ||||
-rw-r--r-- | epan/dfilter/dfvm.c | 73 | ||||
-rw-r--r-- | epan/dfilter/dfvm.h | 3 | ||||
-rw-r--r-- | epan/dfilter/gencode.c | 57 | ||||
-rw-r--r-- | epan/dfilter/grammar.lemon | 10 | ||||
-rw-r--r-- | epan/dfilter/scanner.l | 20 | ||||
-rw-r--r-- | epan/dfilter/semcheck.c | 19 | ||||
-rw-r--r-- | epan/dfilter/sttype-pointer.c | 12 | ||||
-rw-r--r-- | epan/dfilter/syntax-tree.h | 1 |
13 files changed, 287 insertions, 79 deletions
diff --git a/epan/dfilter/dfilter-int.h b/epan/dfilter/dfilter-int.h index aaaf4b0f53..6ff14f43f1 100644 --- a/epan/dfilter/dfilter-int.h +++ b/epan/dfilter/dfilter-int.h @@ -27,6 +27,7 @@ struct epan_dfilter { int num_interesting_fields; GPtrArray *deprecated; char *expanded_text; + GHashTable *references; }; typedef struct { @@ -40,6 +41,8 @@ typedef struct { int next_insn_id; int next_register; GPtrArray *deprecated; + GHashTable *references; /* hfinfo -> pointer to GSList of const fvalues */ + GHashTable *loaded_references; } dfwork_t; /* diff --git a/epan/dfilter/dfilter-macro.c b/epan/dfilter/dfilter-macro.c index 16f5ff2bfc..3ce0f668cf 100644 --- a/epan/dfilter/dfilter-macro.c +++ b/epan/dfilter/dfilter-macro.c @@ -23,16 +23,10 @@ #include <epan/proto.h> #include <wsutil/glib-compat.h> -typedef struct { - const char* name; - gboolean usable; - char* repr; -} fvt_cache_entry_t; static uat_t* dfilter_macro_uat = NULL; static dfilter_macro_t* macros = NULL; static guint num_macros; -static GHashTable* fvt_cache = NULL; /* #define DUMP_DFILTER_MACRO */ #ifdef DUMP_DFILTER_MACRO @@ -42,51 +36,10 @@ void dump_dfilter_macro_t(const dfilter_macro_t *m, const char *function, const #define DUMP_MACRO(m) #endif -static gboolean fvt_cache_cb(proto_node * node, gpointer data _U_) { - field_info* finfo = PNODE_FINFO(node); - fvt_cache_entry_t* e; - - if (!finfo) return FALSE; - - if ((e = (fvt_cache_entry_t*)g_hash_table_lookup(fvt_cache,finfo->hfinfo->abbrev))) { - e->usable = FALSE; - } else { - switch (finfo->hfinfo->type) { - case FT_NONE: - case FT_PROTOCOL: - return FALSE; - default: - break; - } - char *repr = fvalue_to_string_repr(NULL, &(finfo->value), FTREPR_DFILTER, finfo->hfinfo->display); - if (repr) { - e = g_new(fvt_cache_entry_t,1); - e->name = finfo->hfinfo->abbrev; - e->repr = repr; - e->usable = TRUE; - g_hash_table_insert(fvt_cache,(void*)finfo->hfinfo->abbrev,e); - } - } - return FALSE; -} - -static void dfilter_free_fvt_entry(gpointer v) -{ - fvt_cache_entry_t* e = (fvt_cache_entry_t*)v; - wmem_free(NULL, e->repr); - g_free(e); -} - -void dfilter_macro_build_ftv_cache(void* tree_root) { - g_hash_table_remove_all(fvt_cache); - proto_tree_traverse_post_order((proto_tree *)tree_root, fvt_cache_cb, NULL); -} - static gchar* dfilter_macro_resolve(gchar* name, gchar** args, gchar** error) { GString* text; int argc = 0; dfilter_macro_t* m = NULL; - fvt_cache_entry_t* e; int* arg_pos_p; gchar** parts; gchar* ret; @@ -101,20 +54,9 @@ static gchar* dfilter_macro_resolve(gchar* name, gchar** args, gchar** error) { } if (!m) { - if (fvt_cache && - (e = (fvt_cache_entry_t *)g_hash_table_lookup(fvt_cache,name)) != NULL) { - if(e->usable) { - return wmem_strdup(NULL, e->repr); - } else { - if (error != NULL) - *error = ws_strdup_printf("macro '%s' is unusable", name); - return NULL; - } - } else { - if (error != NULL) - *error = ws_strdup_printf("macro '%s' does not exist", name); - return NULL; - } + if (error != NULL) + *error = g_strdup_printf("macro '%s' does not exist", name); + return NULL; } DUMP_MACRO(m); @@ -205,6 +147,22 @@ static gchar* dfilter_macro_apply_recurse(const gchar* text, guint depth, gchar* } case STARTING: { switch (c) { case '{': { + /* If the name has a dot it's a field reference, + * and conversely if it doesn't have a dot it's a macro. */ + const char *sep = r; + char cc; + while ((cc = *sep++) != '\0') { + if (cc == '.' || cc == ':' || cc == '}') { + break; + } + } + if (cc == '.') { + /* Field reference, preserve */ + g_string_append(out,"${"); + state = OUTSIDE; + break; + } + args = g_ptr_array_new(); arg = g_string_sized_new(32); name = g_string_sized_new(32); @@ -575,8 +533,6 @@ void dfilter_macro_init(void) { NULL, /* Note: This is set in macros_init () */ NULL, uat_fields); - - fvt_cache = g_hash_table_new_full(g_str_hash,g_str_equal, NULL, dfilter_free_fvt_entry); } void dfilter_macro_get_uat(uat_t **dfmu_ptr_ptr) { @@ -680,7 +636,6 @@ void dump_dfilter_macro_t(const dfilter_macro_t *m, const char *function, const void dfilter_macro_cleanup(void) { - g_hash_table_destroy(fvt_cache); } /* diff --git a/epan/dfilter/dfilter-macro.h b/epan/dfilter/dfilter-macro.h index 2a9bee3494..24fd429c92 100644 --- a/epan/dfilter/dfilter-macro.h +++ b/epan/dfilter/dfilter-macro.h @@ -39,9 +39,6 @@ struct epan_uat; WS_DLL_PUBLIC void dfilter_macro_get_uat(struct epan_uat **dfmu_ptr_ptr); -WS_DLL_PUBLIC -void dfilter_macro_build_ftv_cache(void* tree_root); - void dfilter_macro_cleanup(void); #ifdef __cplusplus diff --git a/epan/dfilter/dfilter.c b/epan/dfilter/dfilter.c index a185956b12..987653cfdc 100644 --- a/epan/dfilter/dfilter.c +++ b/epan/dfilter/dfilter.c @@ -199,6 +199,8 @@ dfilter_free(dfilter_t *df) g_free(df->interesting_fields); + g_hash_table_destroy(df->references); + if (df->deprecated) g_ptr_array_unref(df->deprecated); @@ -209,11 +211,30 @@ dfilter_free(dfilter_t *df) g_free(df); } +static void free_reference(gpointer data) +{ + /* List data is not owned by us. */ + GSList **fvalues_ptr = data; + if (*fvalues_ptr) + g_slist_free(*fvalues_ptr); + g_free(fvalues_ptr); +} + static dfwork_t* dfwork_new(void) { - return g_new0(dfwork_t, 1); + dfwork_t *dfw = g_new0(dfwork_t, 1); + + dfw->references = + g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, free_reference); + + dfw->loaded_references = + g_hash_table_new_full(g_direct_hash, g_direct_equal, + NULL, (GDestroyNotify)dfvm_value_unref); + + return dfw; } static void @@ -231,6 +252,14 @@ dfwork_free(dfwork_t *dfw) g_hash_table_destroy(dfw->interesting_fields); } + if (dfw->references) { + g_hash_table_destroy(dfw->references); + } + + if (dfw->loaded_references) { + g_hash_table_destroy(dfw->loaded_references); + } + if (dfw->insns) { free_insns(dfw->insns); } @@ -279,6 +308,9 @@ const char *tokenstr(int token) case TOKEN_DOTDOT: return "DOTDOT"; case TOKEN_LPAREN: return "LPAREN"; case TOKEN_RPAREN: return "RPAREN"; + case TOKEN_REFERENCE: return "REFERENCE"; + case TOKEN_REF_OPEN: return "REF_OPEN"; + case TOKEN_REF_CLOSE: return "REF_CLOSE"; } return "<unknown>"; } @@ -446,6 +478,8 @@ dfilter_compile_real(const gchar *text, dfilter_t **dfp, dfilter->interesting_fields = dfw_interesting_fields(dfw, &dfilter->num_interesting_fields); dfilter->expanded_text = ws_strdup(expanded_text); + dfilter->references = dfw->references; + dfw->references = NULL; /* Initialize run-time space */ dfilter->num_registers = dfw->next_register; @@ -559,7 +593,7 @@ dfilter_log_full(const char *domain, enum ws_log_level level, return; } - char *str = dfvm_dump_str(NULL, df); + char *str = dfvm_dump_str(NULL, df, TRUE); if (G_UNLIKELY(msg == NULL)) ws_log_write_always_full(domain, level, file, line, func, "\n%s", str); else @@ -567,6 +601,45 @@ dfilter_log_full(const char *domain, enum ws_log_level level, g_free(str); } +void +dfilter_load_field_references(const dfilter_t *df, proto_tree *tree) +{ + GHashTableIter iter; + GPtrArray *finfos; + field_info *finfo; + header_field_info *hfinfo; + GSList **fvalues_ptr; + int i, len; + + if (g_hash_table_size(df->references) == 0) { + /* Nothing to do. */ + return; + } + + g_hash_table_iter_init( &iter, df->references); + while (g_hash_table_iter_next (&iter, (void **)&hfinfo, (void **)&fvalues_ptr)) { + /* If we have a previous list free it leaving the data alone */ + g_slist_free(*fvalues_ptr); + *fvalues_ptr = NULL; + + while (hfinfo) { + finfos = proto_find_finfo(tree, hfinfo->id); + if ((finfos == NULL) || (g_ptr_array_len(finfos) == 0)) { + hfinfo = hfinfo->same_name_next; + continue; + } + + len = finfos->len; + for (i = 0; i < len; i++) { + finfo = g_ptr_array_index(finfos, i); + *fvalues_ptr = g_slist_prepend(*fvalues_ptr, &finfo->value); + } + + hfinfo = hfinfo->same_name_next; + } + } +} + /* * Editor modelines - https://www.wireshark.org/tools/modelines.html * diff --git a/epan/dfilter/dfilter.h b/epan/dfilter/dfilter.h index 3c4286bd33..03c7d924d4 100644 --- a/epan/dfilter/dfilter.h +++ b/epan/dfilter/dfilter.h @@ -73,6 +73,11 @@ dfilter_apply(dfilter_t *df, proto_tree *tree); void dfilter_prime_proto_tree(const dfilter_t *df, proto_tree *tree); +/* Refresh references in a compiled display filter. */ +WS_DLL_PUBLIC +void +dfilter_load_field_references(const dfilter_t *df, proto_tree *tree); + /* Check if dfilter has interesting fields */ gboolean dfilter_has_interesting_fields(const dfilter_t *df); diff --git a/epan/dfilter/dfvm.c b/epan/dfilter/dfvm.c index dcd03cd444..0f2a3dc823 100644 --- a/epan/dfilter/dfvm.c +++ b/epan/dfilter/dfvm.c @@ -181,13 +181,16 @@ dfvm_value_tostr(dfvm_value_t *v) } char * -dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df) +dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, gboolean print_references) { int id, length; dfvm_insn_t *insn; dfvm_value_t *arg1, *arg2, *arg3, *arg4; char *arg1_str, *arg2_str, *arg3_str, *arg4_str; wmem_strbuf_t *buf; + GHashTableIter ref_iter; + gpointer key, value; + char *str; buf = wmem_strbuf_new(alloc, NULL); @@ -219,6 +222,11 @@ dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df) id, arg1_str, arg2_str); break; + case READ_REFERENCE: + wmem_strbuf_append_printf(buf, "%05d READ_REFERENCE\t${%s} -> %s\n", + id, arg1_str, arg2_str); + break; + case CALL_FUNCTION: wmem_strbuf_append_printf(buf, "%05d CALL_FUNCTION\t%s(", id, arg1_str); @@ -337,13 +345,37 @@ dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df) g_free(arg4_str); } + if (print_references && g_hash_table_size(df->references) > 0) { + wmem_strbuf_append(buf, "\nReferences:\n"); + g_hash_table_iter_init(&ref_iter, df->references); + while (g_hash_table_iter_next(&ref_iter, &key, &value)) { + const char *abbrev = ((header_field_info *)key)->abbrev; + GSList *fvalues = *(GSList **)value; + + wmem_strbuf_append_printf(buf, "${%s} = {", abbrev); + + if (fvalues != NULL) { + str = fvalue_to_debug_repr(NULL, fvalues->data); + wmem_strbuf_append_printf(buf, "%s <%s>", str, fvalue_type_name(fvalues->data)); + g_free(str); + + for (fvalues = fvalues->next; fvalues != NULL; fvalues = fvalues->next) { + str = fvalue_to_debug_repr(NULL, fvalues->data); + wmem_strbuf_append_printf(buf, ", %s <%s>", str, fvalue_type_name(fvalues->data)); + g_free(str); + } + } + wmem_strbuf_append(buf, "}\n"); + } + } + return wmem_strbuf_finalize(buf); } void dfvm_dump(FILE *f, dfilter_t *df) { - char *str = dfvm_dump_str(NULL, df); + char *str = dfvm_dump_str(NULL, df, FALSE); fputs(str, f); wmem_free(NULL, str); } @@ -404,6 +436,39 @@ read_tree(dfilter_t *df, proto_tree *tree, return TRUE; } +static gboolean +read_reference(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *arg2) +{ + GSList **fvalues_ptr; + + header_field_info *hfinfo = arg1->value.hfinfo; + int reg = arg2->value.numeric; + + /* Already loaded in this run of the dfilter? */ + if (df->attempted_load[reg]) { + if (df->registers[reg]) { + return TRUE; + } + else { + return FALSE; + } + } + + df->attempted_load[reg] = TRUE; + + fvalues_ptr = g_hash_table_lookup(df->references, hfinfo); + if (*fvalues_ptr == NULL) { + df->registers[reg] = NULL; + return FALSE; + } + + /* Shallow copy */ + df->registers[reg] = g_slist_copy(*fvalues_ptr); + /* These values are referenced only, do not try to free it later. */ + df->free_registers[reg] = NULL; + return TRUE; +} + enum match_how { MATCH_ANY, MATCH_ALL @@ -787,6 +852,10 @@ dfvm_apply(dfilter_t *df, proto_tree *tree) accum = read_tree(df, tree, arg1, arg2); break; + case READ_REFERENCE: + accum = read_reference(df, arg1, arg2); + break; + case CALL_FUNCTION: accum = call_function(df, arg1, arg2, arg3, arg4); break; diff --git a/epan/dfilter/dfvm.h b/epan/dfilter/dfvm.h index 7056f7847c..d5507c0830 100644 --- a/epan/dfilter/dfvm.h +++ b/epan/dfilter/dfvm.h @@ -53,6 +53,7 @@ typedef enum { NOT, RETURN, READ_TREE, + READ_REFERENCE, ALL_EQ, ANY_EQ, ALL_NE, @@ -119,7 +120,7 @@ void dfvm_dump(FILE *f, dfilter_t *df); char * -dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df); +dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, gboolean print_references); gboolean dfvm_apply(dfilter_t *df, proto_tree *tree); diff --git a/epan/dfilter/gencode.c b/epan/dfilter/gencode.c index bdfb0fe42d..3c8c0c995a 100644 --- a/epan/dfilter/gencode.c +++ b/epan/dfilter/gencode.c @@ -92,6 +92,53 @@ dfw_append_read_tree(dfwork_t *dfw, header_field_info *hfinfo) /* returns register number */ static dfvm_value_t * +dfw_append_read_reference(dfwork_t *dfw, header_field_info *hfinfo) +{ + dfvm_insn_t *insn; + dfvm_value_t *reg_val, *val1; + GSList **fvalues_ptr; + gboolean added_new_hfinfo = FALSE; + + /* Rewind to find the first field of this name. */ + while (hfinfo->same_name_prev_id != -1) { + hfinfo = proto_registrar_get_nth(hfinfo->same_name_prev_id); + } + + /* Keep track of which registers + * were used for which hfinfo's so that we + * can re-use registers. */ + reg_val = g_hash_table_lookup(dfw->loaded_references, hfinfo); + if (!reg_val) { + reg_val = dfvm_value_new_register(dfw->next_register++); + g_hash_table_insert(dfw->loaded_references, hfinfo, dfvm_value_ref(reg_val)); + added_new_hfinfo = TRUE; + } + + insn = dfvm_insn_new(READ_REFERENCE); + val1 = dfvm_value_new_hfinfo(hfinfo); + insn->arg1 = dfvm_value_ref(val1); + insn->arg2 = dfvm_value_ref(reg_val); + dfw_append_insn(dfw, insn); + + fvalues_ptr = g_new(GSList *, 1); + *fvalues_ptr = NULL; + g_hash_table_insert(dfw->references, hfinfo, fvalues_ptr); + + if (added_new_hfinfo) { + while (hfinfo) { + /* Record the FIELD_ID in hash of interesting fields. */ + g_hash_table_insert(dfw->interesting_fields, + GINT_TO_POINTER(hfinfo->id), + GUINT_TO_POINTER(TRUE)); + hfinfo = hfinfo->same_name_next; + } + } + + return reg_val; +} + +/* returns register number */ +static dfvm_value_t * dfw_append_mk_range(dfwork_t *dfw, stnode_t *node, GSList **jumps_ptr) { stnode_t *entity; @@ -352,6 +399,16 @@ gen_entity(dfwork_t *dfw, stnode_t *st_arg, GSList **jumps_ptr) dfw_append_insn(dfw, insn); *jumps_ptr = g_slist_prepend(*jumps_ptr, jmp); } + else if (e_type == STTYPE_REFERENCE) { + hfinfo = stnode_data(st_arg); + val = dfw_append_read_reference(dfw, hfinfo); + + insn = dfvm_insn_new(IF_FALSE_GOTO); + jmp = dfvm_value_new(INSN_NUMBER); + insn->arg1 = dfvm_value_ref(jmp); + dfw_append_insn(dfw, insn); + *jumps_ptr = g_slist_prepend(*jumps_ptr, jmp); + } else if (e_type == STTYPE_FVALUE) { val = dfvm_value_new_fvalue(stnode_steal_data(st_arg)); } diff --git a/epan/dfilter/grammar.lemon b/epan/dfilter/grammar.lemon index 8e4a3ed331..d0b7315f11 100644 --- a/epan/dfilter/grammar.lemon +++ b/epan/dfilter/grammar.lemon @@ -166,6 +166,16 @@ atom(E) ::= IDENTIFIER(F). df_lval_free(F, FALSE); } entity(E) ::= atom(A). { E = A; } +entity(E) ::= REF_OPEN REFERENCE(F) REF_CLOSE. +{ + char *name = df_lval_value(F); + header_field_info *hfinfo = dfilter_resolve_unparsed(dfw, name); + if (hfinfo == NULL) { + dfilter_fail(dfw, "\"%s\" is not a valid protocol or protocol field.", name); + } + E = stnode_new(STTYPE_REFERENCE, hfinfo, df_lval_value(F)); + df_lval_free(F, FALSE); +} entity(E) ::= range(R). { E = R; } entity(E) ::= function(F). { E = F; } diff --git a/epan/dfilter/scanner.l b/epan/dfilter/scanner.l index 626a19a068..494a1e0dc1 100644 --- a/epan/dfilter/scanner.l +++ b/epan/dfilter/scanner.l @@ -103,6 +103,7 @@ WORD_CHAR [[:alnum:]_:/+-] %x RANGE %x DQUOTE %x SQUOTE +%x REFERENCE %% @@ -153,6 +154,25 @@ WORD_CHAR [[:alnum:]_:/+-] "&" return simple(TOKEN_BITWISE_AND); "bitwise_and" return simple(TOKEN_BITWISE_AND); +"${" { + BEGIN(REFERENCE); + return simple(TOKEN_REF_OPEN); +} + +<REFERENCE>[^}]+ { + return set_lval_str(TOKEN_REFERENCE, yytext); +} + +<REFERENCE>"}" { + BEGIN(INITIAL); + return simple(TOKEN_REF_CLOSE); +} + +<REFERENCE><<EOF>> { + dfilter_fail(yyextra->dfw, "Right brace missing from field reference."); + return SCAN_FAILED; +} + "[" { BEGIN(RANGE); return simple(TOKEN_LBRACKET); diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c index 210d78c547..968e46827f 100644 --- a/epan/dfilter/semcheck.c +++ b/epan/dfilter/semcheck.c @@ -464,6 +464,7 @@ check_exists(dfwork_t *dfw, stnode_t *st_arg1) case STTYPE_FIELD: /* This is OK */ break; + case STTYPE_REFERENCE: case STTYPE_STRING: case STTYPE_UNPARSED: case STTYPE_LITERAL: @@ -623,7 +624,7 @@ again: stnode_todisplay(st_node)); } - if (type2 == STTYPE_FIELD) { + if (type2 == STTYPE_FIELD || type2 == STTYPE_REFERENCE) { hfinfo2 = stnode_data(st_arg2); ftype2 = hfinfo2->type; @@ -747,7 +748,7 @@ check_relation_LHS_RANGE(dfwork_t *dfw, test_op_t st_op, again: type2 = stnode_type_id(st_arg2); - if (type2 == STTYPE_FIELD) { + if (type2 == STTYPE_FIELD || type2 == STTYPE_REFERENCE) { hfinfo2 = stnode_data(st_arg2); ftype2 = hfinfo2->type; @@ -865,7 +866,7 @@ check_relation_LHS_FUNCTION(dfwork_t *dfw, test_op_t st_op, again: type2 = stnode_type_id(st_arg2); - if (type2 == STTYPE_FIELD) { + if (type2 == STTYPE_FIELD || type2 == STTYPE_REFERENCE) { hfinfo2 = stnode_data(st_arg2); ftype2 = hfinfo2->type; @@ -980,7 +981,8 @@ check_relation_LHS_BITWISE(dfwork_t *dfw, test_op_t st_op _U_, sttype_test_get(st_arg1, NULL, &bitwise_entity, NULL); bitwise_entity_type = stnode_type_id(bitwise_entity); - if (bitwise_entity_type == STTYPE_FIELD) { + if (bitwise_entity_type == STTYPE_FIELD || + bitwise_entity_type == STTYPE_REFERENCE) { check_relation_LHS_FIELD(dfw, st_op, can_func, allow_partial_value, st_node, bitwise_entity, st_arg2); } else if (bitwise_entity_type == STTYPE_RANGE) { @@ -1008,7 +1010,7 @@ check_relation_LHS_ARITHMETIC(dfwork_t *dfw, test_op_t st_op _U_, sttype_test_get(st_arg1, NULL, &entity, NULL); entity_type = stnode_type_id(entity); - if (entity_type == STTYPE_FIELD) { + if (entity_type == STTYPE_FIELD || entity_type == STTYPE_REFERENCE) { check_arithmetic_operation(dfw, st_arg1, FT_NONE); check_relation_LHS_FIELD(dfw, st_op, can_func, allow_partial_value, st_node, entity, st_arg2); @@ -1036,6 +1038,7 @@ check_relation(dfwork_t *dfw, test_op_t st_op, switch (stnode_type_id(st_arg1)) { case STTYPE_FIELD: + case STTYPE_REFERENCE: check_relation_LHS_FIELD(dfw, st_op, can_func, allow_partial_value, st_node, st_arg1, st_arg2); break; @@ -1071,6 +1074,7 @@ check_relation_contains(dfwork_t *dfw, stnode_t *st_node, switch (stnode_type_id(st_arg1)) { case STTYPE_FIELD: + case STTYPE_REFERENCE: check_relation_LHS_FIELD(dfw, TEST_OP_CONTAINS, ftype_can_contains, TRUE, st_node, st_arg1, st_arg2); break; @@ -1119,6 +1123,7 @@ check_relation_matches(dfwork_t *dfw, stnode_t *st_node, switch (stnode_type_id(st_arg1)) { case STTYPE_FIELD: + case STTYPE_REFERENCE: check_relation_LHS_FIELD(dfw, TEST_OP_MATCHES, ftype_can_matches, TRUE, st_node, st_arg1, st_arg2); break; @@ -1259,7 +1264,7 @@ check_bitwise_entity(dfwork_t *dfw, stnode_t *st_node, stnode_t *st_arg, ftenum_ resolve_unparsed(dfw, st_arg); type = stnode_type_id(st_arg); - if (type == STTYPE_FIELD) { + if (type == STTYPE_FIELD || type == STTYPE_REFERENCE) { hfinfo = stnode_data(st_arg); ftype = hfinfo->type; @@ -1381,7 +1386,7 @@ check_arithmetic_operation(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype) stnode_replace(st_node, STTYPE_FVALUE, new_fv); } } - else if (type == STTYPE_FIELD) { + else if (type == STTYPE_FIELD || type == STTYPE_REFERENCE) { header_field_info *hfinfo = stnode_data(st_arg); ftype = hfinfo->type; diff --git a/epan/dfilter/sttype-pointer.c b/epan/dfilter/sttype-pointer.c index f97c76bd53..8f51d9cfd4 100644 --- a/epan/dfilter/sttype-pointer.c +++ b/epan/dfilter/sttype-pointer.c @@ -105,6 +105,17 @@ sttype_register_pointer(void) NULL, field_tostr }; + /* A field reference is a *constant* prototocol field value read directly + * from the currently selected frame in the protocol tree when a filter is + * applied to it. */ + static sttype_t reference_type = { + STTYPE_REFERENCE, + "REFERENCE", + NULL, + NULL, + NULL, + field_tostr + }; static sttype_t fvalue_type = { STTYPE_FVALUE, "FVALUE", @@ -131,6 +142,7 @@ sttype_register_pointer(void) }; sttype_register(&field_type); + sttype_register(&reference_type); sttype_register(&fvalue_type); sttype_register(&pcre_type); sttype_register(&charconst_type); diff --git a/epan/dfilter/syntax-tree.h b/epan/dfilter/syntax-tree.h index 8b3b0b6971..2993ea1882 100644 --- a/epan/dfilter/syntax-tree.h +++ b/epan/dfilter/syntax-tree.h @@ -24,6 +24,7 @@ typedef enum { STTYPE_TEST, STTYPE_LITERAL, STTYPE_UNPARSED, + STTYPE_REFERENCE, STTYPE_STRING, STTYPE_CHARCONST, STTYPE_FIELD, |