dfilter: Add suport for raw addressing with references

Extends raw adressing syntax to wok with references. The syntax
is
    @field1 == ${@field2}

This requires replicating the logic to load field references, but
using raw values instead. We use separate hash tables for that,
namely "references" vs "raw_references".
This commit is contained in:
João Valverde 2022-10-25 13:03:08 +01:00
parent 0853ddd1cb
commit b83658d8a4
8 changed files with 85 additions and 16 deletions

View File

@ -34,6 +34,7 @@ struct epan_dfilter {
GPtrArray *deprecated; GPtrArray *deprecated;
char *expanded_text; char *expanded_text;
GHashTable *references; GHashTable *references;
GHashTable *raw_references;
char *syntax_tree_str; char *syntax_tree_str;
/* Used to pass arguments to functions. List of Lists (list of registers). */ /* Used to pass arguments to functions. List of Lists (list of registers). */
GSList *function_stack; GSList *function_stack;
@ -52,6 +53,7 @@ typedef struct {
int next_register; int next_register;
GPtrArray *deprecated; GPtrArray *deprecated;
GHashTable *references; /* hfinfo -> pointer to array of references */ GHashTable *references; /* hfinfo -> pointer to array of references */
GHashTable *raw_references; /* hfinfo -> pointer to array of references */
char *expanded_text; char *expanded_text;
stloc_t err_loc; stloc_t err_loc;
} dfwork_t; } dfwork_t;
@ -119,7 +121,7 @@ dfilter_fvalue_from_charconst(dfwork_t *dfw, ftenum_t ftype, stnode_t *st);
const char *tokenstr(int token); const char *tokenstr(int token);
df_reference_t * df_reference_t *
reference_new(const field_info *finfo); reference_new(const field_info *finfo, gboolean raw);
void void
reference_free(df_reference_t *ref); reference_free(df_reference_t *ref);

View File

@ -111,6 +111,10 @@ static gboolean start_is_field_reference(const char *start)
/* This violates constness but we will restore the original string. */ /* This violates constness but we will restore the original string. */
*(char *)end = '\0'; *(char *)end = '\0';
/* Search for name in registered fields. */ /* Search for name in registered fields. */
if (start[0] == '@')
start++;
hfinfo = dfilter_resolve_unparsed(NULL, start); hfinfo = dfilter_resolve_unparsed(NULL, start);
/* Restore mangled string. */ /* Restore mangled string. */
*(char *)end = saved_c; *(char *)end = saved_c;

View File

@ -202,6 +202,7 @@ dfilter_free(dfilter_t *df)
g_free(df->interesting_fields); g_free(df->interesting_fields);
g_hash_table_destroy(df->references); g_hash_table_destroy(df->references);
g_hash_table_destroy(df->raw_references);
if (df->deprecated) if (df->deprecated)
g_ptr_array_unref(df->deprecated); g_ptr_array_unref(df->deprecated);
@ -235,6 +236,10 @@ dfwork_new(void)
g_hash_table_new_full(g_direct_hash, g_direct_equal, g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, (GDestroyNotify)free_refs_array); NULL, (GDestroyNotify)free_refs_array);
dfw->raw_references =
g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, (GDestroyNotify)free_refs_array);
return dfw; return dfw;
} }
@ -261,6 +266,10 @@ dfwork_free(dfwork_t *dfw)
g_hash_table_destroy(dfw->references); g_hash_table_destroy(dfw->references);
} }
if (dfw->raw_references) {
g_hash_table_destroy(dfw->raw_references);
}
if (dfw->insns) { if (dfw->insns) {
free_insns(dfw->insns); free_insns(dfw->insns);
} }
@ -504,6 +513,8 @@ dfilter_compile_real(const gchar *text, dfilter_t **dfp,
dfw->expanded_text = NULL; dfw->expanded_text = NULL;
dfilter->references = dfw->references; dfilter->references = dfw->references;
dfw->references = NULL; dfw->references = NULL;
dfilter->raw_references = dfw->raw_references;
dfw->raw_references = NULL;
if (save_tree) { if (save_tree) {
ws_assert(tree_str); ws_assert(tree_str);
@ -658,8 +669,8 @@ compare_ref_layer(gconstpointer _a, gconstpointer _b)
return a->proto_layer_num - b->proto_layer_num; return a->proto_layer_num - b->proto_layer_num;
} }
void static void
dfilter_load_field_references(const dfilter_t *df, proto_tree *tree) load_references(GHashTable *table, proto_tree *tree, gboolean raw)
{ {
GHashTableIter iter; GHashTableIter iter;
GPtrArray *finfos; GPtrArray *finfos;
@ -668,13 +679,13 @@ dfilter_load_field_references(const dfilter_t *df, proto_tree *tree)
GPtrArray *refs; GPtrArray *refs;
int i, len; int i, len;
if (g_hash_table_size(df->references) == 0) { if (g_hash_table_size(table) == 0) {
/* Nothing to do. */ /* Nothing to do. */
return; return;
} }
g_hash_table_iter_init( &iter, df->references); g_hash_table_iter_init(&iter, table);
while (g_hash_table_iter_next (&iter, (void **)&hfinfo, (void **)&refs)) { while (g_hash_table_iter_next(&iter, (void **)&hfinfo, (void **)&refs)) {
/* If we have a previous array free the data */ /* If we have a previous array free the data */
g_ptr_array_set_size(refs, 0); g_ptr_array_set_size(refs, 0);
@ -688,7 +699,7 @@ dfilter_load_field_references(const dfilter_t *df, proto_tree *tree)
len = finfos->len; len = finfos->len;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
finfo = g_ptr_array_index(finfos, i); finfo = g_ptr_array_index(finfos, i);
g_ptr_array_add(refs, reference_new(finfo)); g_ptr_array_add(refs, reference_new(finfo, raw));
} }
hfinfo = hfinfo->same_name_next; hfinfo = hfinfo->same_name_next;
@ -698,12 +709,24 @@ dfilter_load_field_references(const dfilter_t *df, proto_tree *tree)
} }
} }
void
dfilter_load_field_references(const dfilter_t *df, proto_tree *tree)
{
load_references(df->references, tree, FALSE);
load_references(df->raw_references, tree, TRUE);
}
df_reference_t * df_reference_t *
reference_new(const field_info *finfo) reference_new(const field_info *finfo, gboolean raw)
{ {
df_reference_t *ref = g_new(df_reference_t, 1); df_reference_t *ref = g_new(df_reference_t, 1);
ref->hfinfo = finfo->hfinfo; ref->hfinfo = finfo->hfinfo;
ref->value = fvalue_dup(&finfo->value); if (raw) {
ref->value = dfvm_get_raw_fvalue(finfo);
}
else {
ref->value = fvalue_dup(&finfo->value);
}
ref->proto_layer_num = finfo->proto_layer_num; ref->proto_layer_num = finfo->proto_layer_num;
return ref; return ref;
} }

View File

@ -509,6 +509,28 @@ dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, gboolean print_references)
} }
} }
if (print_references && g_hash_table_size(df->raw_references) > 0) {
wmem_strbuf_append(buf, "\nRaw references:\n");
g_hash_table_iter_init(&ref_iter, df->raw_references);
while (g_hash_table_iter_next(&ref_iter, &key, &value)) {
const char *abbrev = ((header_field_info *)key)->abbrev;
GPtrArray *refs_array = value;
df_reference_t *ref;
wmem_strbuf_append_printf(buf, "${@%s} = {", abbrev);
for (i = 0; i < refs_array->len; i++) {
if (i != 0) {
wmem_strbuf_append(buf, ", ");
}
ref = refs_array->pdata[i];
str = fvalue_to_debug_repr(NULL, ref->value);
wmem_strbuf_append_printf(buf, "%s <%s>", str, fvalue_type_name(ref->value));
g_free(str);
}
wmem_strbuf_append(buf, "}\n");
}
}
return wmem_strbuf_finalize(buf); return wmem_strbuf_finalize(buf);
} }
@ -563,8 +585,8 @@ drange_contains_layer(drange_t *dr, int num, int length)
return FALSE; return FALSE;
} }
static fvalue_t * fvalue_t *
get_raw_fvalue(field_info *fi) dfvm_get_raw_fvalue(const field_info *fi)
{ {
GByteArray *bytes; GByteArray *bytes;
fvalue_t *fv; fvalue_t *fv;
@ -614,7 +636,7 @@ filter_finfo_fvalues(GSList *fvalues, GPtrArray *finfos, drange_t *range, gboole
if (cookie == layer) { if (cookie == layer) {
if (cookie_matches) { if (cookie_matches) {
if (raw) if (raw)
fv = get_raw_fvalue(finfo); fv = dfvm_get_raw_fvalue(finfo);
else else
fv = &finfo->value; fv = &finfo->value;
fvalues = g_slist_prepend(fvalues, fv); fvalues = g_slist_prepend(fvalues, fv);
@ -625,7 +647,7 @@ filter_finfo_fvalues(GSList *fvalues, GPtrArray *finfos, drange_t *range, gboole
cookie_matches = drange_contains_layer(range, layer, length); cookie_matches = drange_contains_layer(range, layer, length);
if (cookie_matches) { if (cookie_matches) {
if (raw) if (raw)
fv = get_raw_fvalue(finfo); fv = dfvm_get_raw_fvalue(finfo);
else else
fv = &finfo->value; fv = &finfo->value;
fvalues = g_slist_prepend(fvalues, fv); fvalues = g_slist_prepend(fvalues, fv);
@ -686,7 +708,7 @@ read_tree(dfilter_t *df, proto_tree *tree,
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
finfo = g_ptr_array_index(finfos, i); finfo = g_ptr_array_index(finfos, i);
if (raw) if (raw)
fv = get_raw_fvalue(finfo); fv = dfvm_get_raw_fvalue(finfo);
else else
fv = &finfo->value; fv = &finfo->value;
fvalues = g_slist_prepend(fvalues, fv); fvalues = g_slist_prepend(fvalues, fv);
@ -759,8 +781,11 @@ read_reference(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *arg2,
{ {
GPtrArray *refs; GPtrArray *refs;
drange_t *range = NULL; drange_t *range = NULL;
gboolean raw;
header_field_info *hfinfo = arg1->value.hfinfo; header_field_info *hfinfo = arg1->value.hfinfo;
raw = arg1->type == RAW_HFINFO;
int reg = arg2->value.numeric; int reg = arg2->value.numeric;
if (arg3) { if (arg3) {
@ -779,7 +804,10 @@ read_reference(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *arg2,
df->attempted_load[reg] = TRUE; df->attempted_load[reg] = TRUE;
refs = g_hash_table_lookup(df->references, hfinfo); if (raw)
refs = g_hash_table_lookup(df->raw_references, hfinfo);
else
refs = g_hash_table_lookup(df->references, hfinfo);
if (refs == NULL || refs->len == 0) { if (refs == NULL || refs->len == 0) {
df->registers[reg] = NULL; df->registers[reg] = NULL;
return FALSE; return FALSE;

View File

@ -148,4 +148,7 @@ dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, gboolean print_references)
gboolean gboolean
dfvm_apply(dfilter_t *df, proto_tree *tree); dfvm_apply(dfilter_t *df, proto_tree *tree);
fvalue_t *
dfvm_get_raw_fvalue(const field_info *fi);
#endif #endif

View File

@ -237,7 +237,10 @@ dfw_append_read_reference(dfwork_t *dfw, header_field_info *hfinfo,
dfw_append_insn(dfw, insn); dfw_append_insn(dfw, insn);
refs_array = g_ptr_array_new_with_free_func((GDestroyNotify)reference_free); refs_array = g_ptr_array_new_with_free_func((GDestroyNotify)reference_free);
g_hash_table_insert(dfw->references, hfinfo, refs_array); if (raw)
g_hash_table_insert(dfw->raw_references, hfinfo, refs_array);
else
g_hash_table_insert(dfw->references, hfinfo, refs_array);
/* Record the FIELD_ID in hash of interesting fields. */ /* Record the FIELD_ID in hash of interesting fields. */
while (hfinfo) { while (hfinfo) {

View File

@ -192,6 +192,7 @@ reference(R) ::= DOLLAR LBRACE field(F) RBRACE.
/* convert field to reference */ /* convert field to reference */
R = stnode_new(STTYPE_REFERENCE, sttype_field_hfinfo(F), NULL, stnode_location(F)); R = stnode_new(STTYPE_REFERENCE, sttype_field_hfinfo(F), NULL, stnode_location(F));
sttype_field_set_drange(R, sttype_field_drange_steal(F)); sttype_field_set_drange(R, sttype_field_drange_steal(F));
sttype_field_set_raw(R, sttype_field_raw(F));
stnode_free(F); stnode_free(F);
} }

View File

@ -348,3 +348,8 @@ class case_raw_modifier(unittest.TestCase):
def test_raw2(self, checkDFilterCount): def test_raw2(self, checkDFilterCount):
dfilter = '@s7comm.blockinfo.blocktype == 30:fe' dfilter = '@s7comm.blockinfo.blocktype == 30:fe'
checkDFilterCount(dfilter, 1) checkDFilterCount(dfilter, 1)
def test_raw_ref(self, checkDFilterCountWithSelectedFrame):
dfilter = '@s7comm.blockinfo.blocktype == ${@s7comm.blockinfo.blocktype}'
# select frame 3, expect 2 frames out of 3.
checkDFilterCountWithSelectedFrame(dfilter, 2, 3)