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;
char *expanded_text;
GHashTable *references;
GHashTable *raw_references;
char *syntax_tree_str;
/* Used to pass arguments to functions. List of Lists (list of registers). */
GSList *function_stack;
@ -52,6 +53,7 @@ typedef struct {
int next_register;
GPtrArray *deprecated;
GHashTable *references; /* hfinfo -> pointer to array of references */
GHashTable *raw_references; /* hfinfo -> pointer to array of references */
char *expanded_text;
stloc_t err_loc;
} dfwork_t;
@ -119,7 +121,7 @@ dfilter_fvalue_from_charconst(dfwork_t *dfw, ftenum_t ftype, stnode_t *st);
const char *tokenstr(int token);
df_reference_t *
reference_new(const field_info *finfo);
reference_new(const field_info *finfo, gboolean raw);
void
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. */
*(char *)end = '\0';
/* Search for name in registered fields. */
if (start[0] == '@')
start++;
hfinfo = dfilter_resolve_unparsed(NULL, start);
/* Restore mangled string. */
*(char *)end = saved_c;

View File

@ -202,6 +202,7 @@ dfilter_free(dfilter_t *df)
g_free(df->interesting_fields);
g_hash_table_destroy(df->references);
g_hash_table_destroy(df->raw_references);
if (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,
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;
}
@ -261,6 +266,10 @@ dfwork_free(dfwork_t *dfw)
g_hash_table_destroy(dfw->references);
}
if (dfw->raw_references) {
g_hash_table_destroy(dfw->raw_references);
}
if (dfw->insns) {
free_insns(dfw->insns);
}
@ -504,6 +513,8 @@ dfilter_compile_real(const gchar *text, dfilter_t **dfp,
dfw->expanded_text = NULL;
dfilter->references = dfw->references;
dfw->references = NULL;
dfilter->raw_references = dfw->raw_references;
dfw->raw_references = NULL;
if (save_tree) {
ws_assert(tree_str);
@ -658,8 +669,8 @@ compare_ref_layer(gconstpointer _a, gconstpointer _b)
return a->proto_layer_num - b->proto_layer_num;
}
void
dfilter_load_field_references(const dfilter_t *df, proto_tree *tree)
static void
load_references(GHashTable *table, proto_tree *tree, gboolean raw)
{
GHashTableIter iter;
GPtrArray *finfos;
@ -668,13 +679,13 @@ dfilter_load_field_references(const dfilter_t *df, proto_tree *tree)
GPtrArray *refs;
int i, len;
if (g_hash_table_size(df->references) == 0) {
if (g_hash_table_size(table) == 0) {
/* Nothing to do. */
return;
}
g_hash_table_iter_init( &iter, df->references);
while (g_hash_table_iter_next (&iter, (void **)&hfinfo, (void **)&refs)) {
g_hash_table_iter_init(&iter, table);
while (g_hash_table_iter_next(&iter, (void **)&hfinfo, (void **)&refs)) {
/* If we have a previous array free the data */
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;
for (i = 0; i < len; 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;
@ -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 *
reference_new(const field_info *finfo)
reference_new(const field_info *finfo, gboolean raw)
{
df_reference_t *ref = g_new(df_reference_t, 1);
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;
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);
}
@ -563,8 +585,8 @@ drange_contains_layer(drange_t *dr, int num, int length)
return FALSE;
}
static fvalue_t *
get_raw_fvalue(field_info *fi)
fvalue_t *
dfvm_get_raw_fvalue(const field_info *fi)
{
GByteArray *bytes;
fvalue_t *fv;
@ -614,7 +636,7 @@ filter_finfo_fvalues(GSList *fvalues, GPtrArray *finfos, drange_t *range, gboole
if (cookie == layer) {
if (cookie_matches) {
if (raw)
fv = get_raw_fvalue(finfo);
fv = dfvm_get_raw_fvalue(finfo);
else
fv = &finfo->value;
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);
if (cookie_matches) {
if (raw)
fv = get_raw_fvalue(finfo);
fv = dfvm_get_raw_fvalue(finfo);
else
fv = &finfo->value;
fvalues = g_slist_prepend(fvalues, fv);
@ -686,7 +708,7 @@ read_tree(dfilter_t *df, proto_tree *tree,
for (i = 0; i < len; i++) {
finfo = g_ptr_array_index(finfos, i);
if (raw)
fv = get_raw_fvalue(finfo);
fv = dfvm_get_raw_fvalue(finfo);
else
fv = &finfo->value;
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;
drange_t *range = NULL;
gboolean raw;
header_field_info *hfinfo = arg1->value.hfinfo;
raw = arg1->type == RAW_HFINFO;
int reg = arg2->value.numeric;
if (arg3) {
@ -779,7 +804,10 @@ read_reference(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *arg2,
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) {
df->registers[reg] = NULL;
return FALSE;

View File

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

View File

@ -237,7 +237,10 @@ dfw_append_read_reference(dfwork_t *dfw, header_field_info *hfinfo,
dfw_append_insn(dfw, insn);
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. */
while (hfinfo) {

View File

@ -192,6 +192,7 @@ reference(R) ::= DOLLAR LBRACE field(F) RBRACE.
/* convert field to reference */
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_raw(R, sttype_field_raw(F));
stnode_free(F);
}

View File

@ -348,3 +348,8 @@ class case_raw_modifier(unittest.TestCase):
def test_raw2(self, checkDFilterCount):
dfilter = '@s7comm.blockinfo.blocktype == 30:fe'
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)