dfilter: Try to resolve field reference instead of using a heuristic

Instead of using a heuristic to decide whether the form ${...} is
a macro or not, try to resolve the name to a registered protocol
field and use that instead.

This increases somewhat the surface for clobbering existing macro
names with new field registrations but we'll cross that bridge when
we get to it.

Rejecting protocol field types reduces this probability again but it
may not be intuitive to the user trying to mistakenly use a reference
to a protocol why it is parsed as a macro. The reasons for rejecting
FT_PROTOCOL types as not interesting field references are not
very strong but it seems reasonable.

$ dftest 'frame.number != ${frame.number}'
Filter: frame.number != ${frame.number}

Instructions:
00000 READ_TREE		frame.number -> reg#0
00001 IF_FALSE_GOTO	5
00002 READ_REFERENCE	${frame.number} -> reg#1
00003 IF_FALSE_GOTO	5
00004 ALL_NE		reg#0 != reg#1
00005 RETURN

$ dftest 'frame != ${frame}'
dftest: macro 'frame' does not exist
This commit is contained in:
João Valverde 2022-04-12 13:44:34 +01:00 committed by A Wireshark GitLab Utility
parent 8355e96858
commit 8746eea297
2 changed files with 37 additions and 12 deletions

View File

@ -9,6 +9,7 @@
#include "config.h"
#define WS_LOG_DOMAIN LOG_DOMAIN_DFILTER
#ifdef DUMP_DFILTER_MACRO
#include <stdio.h>
@ -93,6 +94,37 @@ static gchar* dfilter_macro_resolve(gchar* name, gchar** args, gchar** error) {
return ret;
}
/* Start points to the first character after "${" */
static gboolean start_is_field_reference(const char *start)
{
const char *end;
char saved_c;
const header_field_info *hfinfo;
end = strchr(start, '}');
if (end == NULL)
return FALSE;
saved_c = *end;
/* This violates constness but we will restore the original string. */
*(char *)end = '\0';
/* Search for name in registered fields. */
hfinfo = dfilter_resolve_unparsed(NULL, start);
/* Restore mangled string. */
*(char *)end = saved_c;
if (hfinfo == NULL)
return FALSE;
if (hfinfo->type == FT_PROTOCOL || hfinfo->type == FT_NONE) {
/* Ignore these? */
return FALSE;
}
/* It's a field reference so ignore it as a macro. */
ws_noisy("Ignore field reference ${%s}", start);
return TRUE;
}
static gchar* dfilter_macro_apply_recurse(const gchar* text, guint depth, gchar** error) {
enum { OUTSIDE, STARTING, NAME, ARGS } state = OUTSIDE;
@ -147,22 +179,14 @@ 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 */
if (start_is_field_reference(r)) {
/* We have a field reference, preserve the name with ${} and bail. */
g_string_append(out,"${");
state = OUTSIDE;
break;
}
/* We have a macro, continue. */
args = g_ptr_array_new();
arg = g_string_sized_new(32);
name = g_string_sized_new(32);

View File

@ -113,7 +113,8 @@ dfilter_resolve_unparsed(dfwork_t *dfw, const char *name)
hfinfo = proto_registrar_get_byalias(name);
if (hfinfo != NULL) {
/* It's an aliased field name */
add_deprecated_token(dfw, name);
if (dfw)
add_deprecated_token(dfw, name);
return hfinfo;
}