dfilter: Add functions to override field base

Add field expression functions to convert unsigned integer
and char fields to hex or decimal. (BASE_OCT is handled
somewhat different currently now, presumably because it
can't be used in filters, so leave that commented until
it is handled as a display representation.)

Currently string() always converts unsigned integers to their
decimal representation so it is the same as dec(), but possibly in
the future string() might use the native base.

These can be used in columns thanks to the fix for #15990

Fix #5308
This commit is contained in:
John Thacker 2024-02-22 10:22:07 -05:00
parent ac90d8c834
commit e5168435b5
4 changed files with 106 additions and 0 deletions

View File

@ -77,6 +77,9 @@ The following features are new (or have been significantly updated) since versio
** Added new display filter functions to test various IP address properties.
Check the wireshark-filter(5) manpage for more information.
** Added new display filter functions to convert unsigned integer types to
decimal or hexadecimal. Check the wireshark-filter(5) manpage for more information.
** Display filter macros can be written with a semicolon after the macro
name before the argument list, e.g. `${mymacro;arg1;...;argN}`, instead
of `${mymacro:arg1;...;argN}`. The version with semicolons works better

View File

@ -138,6 +138,8 @@ The filter language has the following functions:
len(field) - returns the byte length of a string or bytes field
count(field) - returns the number of field occurrences in a frame
string(field) - converts a non-string field to string
dec(field) - converts an unsigned integer to a decimal string
hex(field) - converts an unsigned integer to a hexadecimal string
max(f1,...,fn) - return the maximum value
min(f1,...,fn) - return the minimum value
abs(field) - return the absolute value of numeric fields
@ -157,6 +159,11 @@ byte fields. For example:
gives you all the odd packets.
dec() and hex() convert unsigned integer fields to decimal or hexadecimal
representation. Currently dec() and string() give same result for an unsigned
integer, but it is possible that in the future string() will use the native
base of the field.
max() and min() take any number of arguments and returns one value, respectively
the largest/smallest. The arguments must all have the same type.

View File

@ -956,6 +956,8 @@ The display filter language has a number of functions to convert fields, see
|len |Returns the byte length of a string or bytes field.
|count |Returns the number of field occurrences in a frame.
|string |Converts a non-string field to a string.
|dec |Converts an unsigned integer field to a decimal string.
|hex |Converts an unsigned integer field to a hexadecimal string.
|max |Return the maximum value for the arguments.
|min |Return the minimum value for the arguments.
|abs |Return the absolute value for the argument.

View File

@ -165,6 +165,69 @@ df_func_string(GSList *stack, uint32_t arg_count _U_, df_cell_t *retval)
return true;
}
/* dfilter functions: dec(), hex(), */
static bool
df_func_base(GSList *stack, uint32_t arg_count _U_, df_cell_t *retval, int base)
{
GPtrArray *arg1;
fvalue_t *arg_fvalue;
fvalue_t *new_ft_string;
char *s;
ws_assert(arg_count == 1);
arg1 = stack->data;
if (arg1 == NULL)
return false;
for (unsigned i = 0; i < arg1->len; i++) {
arg_fvalue = arg1->pdata[i];
if (FT_IS_UINT(fvalue_type_ftenum(arg_fvalue))) {
s = fvalue_to_string_repr(NULL, arg_fvalue, FTREPR_DFILTER, base);
/* Ensure we have an allocated string here */
if (!s)
s = wmem_strdup(NULL, "");
} else {
/* XXX - We have, unfortunately, some field abbreviations which are
* re-used with incompatible types, some of which support different
* bases and some which don't.
*/
s = wmem_strdup(NULL, "");
}
new_ft_string = fvalue_new(FT_STRING);
fvalue_set_string(new_ft_string, s);
wmem_free(NULL, s);
df_cell_append(retval, new_ft_string);
}
return true;
}
static bool
df_func_hex(GSList *stack, uint32_t arg_count _U_, df_cell_t *retval)
{
return df_func_base(stack, arg_count, retval, BASE_HEX);
}
static bool
df_func_dec(GSList *stack, uint32_t arg_count _U_, df_cell_t *retval)
{
return df_func_base(stack, arg_count, retval, BASE_DEC);
}
#if 0
// XXX - BASE_OCT isn't handled by fvalue_to_string_repr; it probably
// should at least for FTREPR_DISPLAY (the filter language doesn't
// support it due to possible notation confusion, I assume.)
// Add that first before offering it.
static bool
df_func_oct(GSList *stack, uint32_t arg_count _U_, df_cell_t *retval)
{
return df_func_base(stack, arg_count, retval, BASE_OCT);
}
#endif
static bool
df_func_compare(GSList *stack, uint32_t arg_count, df_cell_t *retval,
bool (*fv_cmp)(const fvalue_t *a, const fvalue_t *b))
@ -410,6 +473,34 @@ ul_semcheck_string(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype
dfunc_fail(dfw, param, "Only fields can be used as parameter for %s()", func_name);
}
static ftenum_t
ul_semcheck_base(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype _U_,
GSList *param_list, df_loc_t func_loc _U_)
{
header_field_info *hfinfo;
ws_assert(g_slist_length(param_list) == 1);
stnode_t *param = param_list->data;
resolve_unparsed(dfw, param, true);
if (stnode_type_id(param) == STTYPE_FIELD) {
dfw->field_count++;
hfinfo = sttype_field_hfinfo(param);
/* FT_CHAR also supports BASE_, but for what sort of escaped
* values to use for non-printable ASCII. BASE_HEX uses hex,
* all other bases will use octal.
* That's a little confusing, so don't support it for now.
* More useful might be to display all possible values as
* HEX or DEC, i.e. convert to a FT_UINT8 first. */
if (FT_IS_UINT(hfinfo->type)) {
return FT_STRING;
}
dfunc_fail(dfw, param, "Base conversion for field \"%s\" is not supported", hfinfo->abbrev);
}
dfunc_fail(dfw, param, "Only fields can be used as parameter for %s()", func_name);
}
/* Check arguments are all the same type and they can be compared. */
static ftenum_t
ul_semcheck_compare(dfwork_t *dfw, const char *func_name, ftenum_t logical_ftype,
@ -460,6 +551,9 @@ df_functions[] = {
{ "len", NULL, 1, 1, FT_UINT32, ul_semcheck_can_length },
{ "count", df_func_count, 1, 1, FT_UINT32, ul_semcheck_is_field },
{ "string", df_func_string, 1, 1, FT_STRING, ul_semcheck_string },
{ "dec", df_func_dec, 1, 1, FT_STRING, ul_semcheck_base },
{ "hex", df_func_hex, 1, 1, FT_STRING, ul_semcheck_base },
//{ "oct", df_func_oct, 1, 1, FT_STRING, ul_semcheck_base },
{ "max", df_func_max, 1, 0, FT_NONE, ul_semcheck_compare },
{ "min", df_func_min, 1, 0, FT_NONE, ul_semcheck_compare },
{ "abs", df_func_abs, 1, 1, FT_NONE, ul_semcheck_absolute_value },