dfilter: Allow existence check for slices
Allow checking if a slice exists. The result is true if the slice has length greater than zero. The len() function is implemented as a DFVM instruction instead. The semantics are the same.
This commit is contained in:
parent
0fc81c21b2
commit
a877f2d5f3
|
@ -3839,7 +3839,7 @@ set(_test_group_list
|
|||
suite_dfilter.group_integer_1byte
|
||||
suite_dfilter.group_ipv4
|
||||
suite_dfilter.group_membership
|
||||
suite_dfilter.group_range_method
|
||||
suite_dfilter.group_slice
|
||||
suite_dfilter.group_scanner
|
||||
suite_dfilter.group_string_type
|
||||
suite_dfilter.group_stringz
|
||||
|
|
|
@ -141,6 +141,7 @@ They previously shipped with Qt 5.12.2.
|
|||
For example the double-quoted string "\0 is a null byte" is a legal literal value.
|
||||
This may be useful to match byte patterns but note that in general protocol fields with a string type still cannot contain embedded null bytes.
|
||||
** Booleans can be written as True/TRUE or False/FALSE. Previously they could only be written as 1 or 0.
|
||||
** It is now possible to test for the existence of a slice.
|
||||
|
||||
* The `text2pcap` command and the “Import from Hex Dump” feature have been updated and enhanced:
|
||||
** `text2pcap` supports writing the output file in all the capture file formats that wiretap library supports, using the same `-F` option as `editcap`, `mergecap`, and `tshark`.
|
||||
|
|
|
@ -73,30 +73,6 @@ df_func_upper(GSList *args, guint32 arg_count, GSList **retval)
|
|||
return string_walk(args, arg_count, retval, g_ascii_toupper);
|
||||
}
|
||||
|
||||
/* dfilter function: len() */
|
||||
static gboolean
|
||||
df_func_len(GSList *args, guint32 arg_count, GSList **retval)
|
||||
{
|
||||
GSList *arg1;
|
||||
fvalue_t *arg_fvalue;
|
||||
fvalue_t *ft_len;
|
||||
|
||||
ws_assert(arg_count == 1);
|
||||
arg1 = args->data;
|
||||
if (arg1 == NULL)
|
||||
return FALSE;
|
||||
|
||||
while (arg1) {
|
||||
arg_fvalue = (fvalue_t *)arg1->data;
|
||||
ft_len = fvalue_new(FT_UINT32);
|
||||
fvalue_set_uinteger(ft_len, fvalue_length(arg_fvalue));
|
||||
*retval = g_slist_prepend(*retval, ft_len);
|
||||
arg1 = arg1->next;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* dfilter function: count() */
|
||||
static gboolean
|
||||
df_func_count(GSList *args, guint32 arg_count, GSList **retval)
|
||||
|
@ -460,7 +436,8 @@ static df_func_def_t
|
|||
df_functions[] = {
|
||||
{ "lower", df_func_lower, 1, 1, ul_semcheck_is_field_string },
|
||||
{ "upper", df_func_upper, 1, 1, ul_semcheck_is_field_string },
|
||||
{ "len", df_func_len, 1, 1, ul_semcheck_is_field },
|
||||
/* Length function is implemented as a DFVM instruction. */
|
||||
{ "len", NULL, 1, 1, ul_semcheck_is_field },
|
||||
{ "count", df_func_count, 1, 1, ul_semcheck_is_field },
|
||||
{ "string", df_func_string, 1, 1, ul_semcheck_string_param },
|
||||
{ "max", df_func_max, 1, 0, ul_semcheck_compare },
|
||||
|
@ -476,7 +453,7 @@ df_func_lookup(const char *name)
|
|||
df_func_def_t *func_def;
|
||||
|
||||
func_def = df_functions;
|
||||
while (func_def->function != NULL) {
|
||||
while (func_def->name != NULL) {
|
||||
if (strcmp(func_def->name, name) == 0) {
|
||||
return func_def;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ dfvm_opcode_tostr(dfvm_opcode_t code)
|
|||
case DFVM_ALL_IN_RANGE: return "ALL_IN_RANGE";
|
||||
case DFVM_ANY_IN_RANGE: return "ANY_IN_RANGE";
|
||||
case DFVM_SLICE: return "SLICE";
|
||||
case DFVM_LENGTH: return "LENGTH";
|
||||
case DFVM_BITWISE_AND: return "BITWISE_AND";
|
||||
case DFVM_UNARY_MINUS: return "UNARY_MINUS";
|
||||
case DFVM_ADD: return "ADD";
|
||||
|
@ -350,6 +351,11 @@ dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, gboolean print_references)
|
|||
id, opcode_str, arg1_str, arg3_str, arg2_str);
|
||||
break;
|
||||
|
||||
case DFVM_LENGTH:
|
||||
wmem_strbuf_append_printf(buf, "%05d %s\t\t%s -> %s\n",
|
||||
id, opcode_str, arg1_str, arg2_str);
|
||||
break;
|
||||
|
||||
case DFVM_ALL_EQ:
|
||||
case DFVM_ANY_EQ:
|
||||
wmem_strbuf_append_printf(buf, "%05d %s\t\t%s === %s\n",
|
||||
|
@ -998,6 +1004,28 @@ mk_slice(dfilter_t *df, dfvm_value_t *from_arg, dfvm_value_t *to_arg,
|
|||
df->free_registers[to_arg->value.numeric] = (GDestroyNotify)fvalue_free;
|
||||
}
|
||||
|
||||
static void
|
||||
mk_length(dfilter_t *df, dfvm_value_t *from_arg, dfvm_value_t *to_arg)
|
||||
{
|
||||
GSList *from_list, *to_list;
|
||||
fvalue_t *old_fv, *new_fv;
|
||||
|
||||
to_list = NULL;
|
||||
from_list = df->registers[from_arg->value.numeric];
|
||||
|
||||
while (from_list) {
|
||||
old_fv = from_list->data;
|
||||
new_fv = fvalue_new(FT_UINT32);
|
||||
fvalue_set_uinteger(new_fv, fvalue_length(old_fv));
|
||||
to_list = g_slist_prepend(to_list, new_fv);
|
||||
|
||||
from_list = g_slist_next(from_list);
|
||||
}
|
||||
|
||||
df->registers[to_arg->value.numeric] = to_list;
|
||||
df->free_registers[to_arg->value.numeric] = (GDestroyNotify)fvalue_free;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
call_function(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *arg2,
|
||||
dfvm_value_t *arg3)
|
||||
|
@ -1318,6 +1346,10 @@ dfvm_apply(dfilter_t *df, proto_tree *tree)
|
|||
mk_slice(df, arg1, arg2, arg3);
|
||||
break;
|
||||
|
||||
case DFVM_LENGTH:
|
||||
mk_length(df, arg1, arg2);
|
||||
break;
|
||||
|
||||
case DFVM_ALL_EQ:
|
||||
accum = all_test(df, fvalue_eq, arg1, arg2);
|
||||
break;
|
||||
|
|
|
@ -79,6 +79,7 @@ typedef enum {
|
|||
DFVM_ALL_IN_RANGE,
|
||||
DFVM_ANY_IN_RANGE,
|
||||
DFVM_SLICE,
|
||||
DFVM_LENGTH,
|
||||
DFVM_BITWISE_AND,
|
||||
DFVM_UNARY_MINUS,
|
||||
DFVM_ADD,
|
||||
|
|
|
@ -70,6 +70,7 @@ select_opcode(dfvm_opcode_t op, stmatch_t how)
|
|||
case DFVM_READ_REFERENCE_R:
|
||||
case DFVM_PUT_FVALUE:
|
||||
case DFVM_SLICE:
|
||||
case DFVM_LENGTH:
|
||||
case DFVM_BITWISE_AND:
|
||||
case DFVM_UNARY_MINUS:
|
||||
case DFVM_ADD:
|
||||
|
@ -281,6 +282,30 @@ dfw_append_put_fvalue(dfwork_t *dfw, fvalue_t *fv)
|
|||
return reg_val;
|
||||
}
|
||||
|
||||
/* returns register number that the length's result will be in. */
|
||||
static dfvm_value_t *
|
||||
dfw_append_length(dfwork_t *dfw, stnode_t *node, GSList **jumps_ptr)
|
||||
{
|
||||
GSList *params;
|
||||
dfvm_insn_t *insn;
|
||||
dfvm_value_t *reg_val, *val_arg;
|
||||
|
||||
/* Create the new DFVM instruction */
|
||||
insn = dfvm_insn_new(DFVM_LENGTH);
|
||||
/* Create input argument */
|
||||
params = sttype_function_params(node);
|
||||
ws_assert(params);
|
||||
ws_assert(g_slist_length(params) == 1);
|
||||
val_arg = gen_entity(dfw, params->data, jumps_ptr);
|
||||
insn->arg1 = dfvm_value_ref(val_arg);
|
||||
/* Destination. */
|
||||
reg_val = dfvm_value_new_register(dfw->next_register++);
|
||||
insn->arg2 = dfvm_value_ref(reg_val);
|
||||
|
||||
dfw_append_insn(dfw, insn);
|
||||
return reg_val;
|
||||
}
|
||||
|
||||
/* returns register number that the functions's result will be in. */
|
||||
static dfvm_value_t *
|
||||
dfw_append_function(dfwork_t *dfw, stnode_t *node, GSList **jumps_ptr)
|
||||
|
@ -292,6 +317,11 @@ dfw_append_function(dfwork_t *dfw, stnode_t *node, GSList **jumps_ptr)
|
|||
dfvm_value_t *reg_val, *val1, *val3, *val_arg;
|
||||
guint count;
|
||||
|
||||
if (strcmp(sttype_function_name(node), "len") == 0) {
|
||||
/* Replace len() function call with DFVM_LENGTH instruction. */
|
||||
return dfw_append_length(dfw, node, jumps_ptr);
|
||||
}
|
||||
|
||||
/* Create the new DFVM instruction */
|
||||
insn = dfvm_insn_new(DFVM_CALL_FUNCTION);
|
||||
val1 = dfvm_value_new_funcdef(sttype_function_funcdef(node));
|
||||
|
@ -600,6 +630,31 @@ gen_notzero(dfwork_t *dfw, stnode_t *st_node)
|
|||
g_slist_free(jumps);
|
||||
}
|
||||
|
||||
static void
|
||||
gen_exists_slice(dfwork_t *dfw, stnode_t *st_node)
|
||||
{
|
||||
dfvm_insn_t *insn;
|
||||
dfvm_value_t *val1, *reg_val;
|
||||
GSList *jumps = NULL;
|
||||
|
||||
val1 = gen_entity(dfw, st_node, &jumps);
|
||||
/* Compute length. */
|
||||
insn = dfvm_insn_new(DFVM_LENGTH);
|
||||
insn->arg1 = dfvm_value_ref(val1);
|
||||
reg_val = dfvm_value_new_register(dfw->next_register++);
|
||||
insn->arg2 = dfvm_value_ref(reg_val);
|
||||
dfw_append_insn(dfw, insn);
|
||||
/* Check length is not zero. */
|
||||
insn = dfvm_insn_new(DFVM_ALL_ZERO);
|
||||
insn->arg1 = dfvm_value_ref(reg_val);
|
||||
dfw_append_insn(dfw, insn);
|
||||
insn = dfvm_insn_new(DFVM_NOT);
|
||||
dfw_append_insn(dfw, insn);
|
||||
/* Fixup jumps. */
|
||||
g_slist_foreach(jumps, fixup_jumps, dfw);
|
||||
g_slist_free(jumps);
|
||||
}
|
||||
|
||||
static void
|
||||
gen_test(dfwork_t *dfw, stnode_t *st_node)
|
||||
{
|
||||
|
@ -717,6 +772,9 @@ gencode(dfwork_t *dfw, stnode_t *st_node)
|
|||
case STTYPE_ARITHMETIC:
|
||||
gen_notzero(dfw, st_node);
|
||||
break;
|
||||
case STTYPE_SLICE:
|
||||
gen_exists_slice(dfw, st_node);
|
||||
break;
|
||||
default:
|
||||
ws_assert_not_reached();
|
||||
}
|
||||
|
|
|
@ -454,7 +454,6 @@ check_exists(dfwork_t *dfw, stnode_t *st_arg1)
|
|||
|
||||
switch (stnode_type_id(st_arg1)) {
|
||||
case STTYPE_FIELD:
|
||||
case STTYPE_ARITHMETIC:
|
||||
/* This is OK */
|
||||
break;
|
||||
case STTYPE_REFERENCE:
|
||||
|
@ -465,16 +464,6 @@ check_exists(dfwork_t *dfw, stnode_t *st_arg1)
|
|||
stnode_todisplay(st_arg1));
|
||||
break;
|
||||
|
||||
case STTYPE_SLICE:
|
||||
/*
|
||||
* XXX - why not? Shouldn't "eth[3:2]" mean
|
||||
* "check whether the 'eth' field is present and
|
||||
* has at least 2 bytes starting at an offset of
|
||||
* 3"?
|
||||
*/
|
||||
FAIL(dfw, st_arg1, "You cannot test whether a slice is present.");
|
||||
break;
|
||||
|
||||
case STTYPE_FUNCTION:
|
||||
/* XXX - Maybe we should change functions so they can return fields,
|
||||
* in which case the 'exist' should be fine. */
|
||||
|
@ -487,6 +476,8 @@ check_exists(dfwork_t *dfw, stnode_t *st_arg1)
|
|||
case STTYPE_TEST:
|
||||
case STTYPE_FVALUE:
|
||||
case STTYPE_PCRE:
|
||||
case STTYPE_ARITHMETIC:
|
||||
case STTYPE_SLICE:
|
||||
ws_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
@ -1255,6 +1246,9 @@ semcheck(dfwork_t *dfw, stnode_t *st_node)
|
|||
case STTYPE_ARITHMETIC:
|
||||
check_arithmetic_expr(dfw, st_node, FT_NONE);
|
||||
break;
|
||||
case STTYPE_SLICE:
|
||||
check_slice_sanity(dfw, st_node, FT_NONE);
|
||||
break;
|
||||
default:
|
||||
check_exists(dfw, st_node);
|
||||
}
|
||||
|
|
|
@ -78,3 +78,19 @@ class case_range(unittest.TestCase):
|
|||
def test_slice_range_5(self, checkDFilterSucceed):
|
||||
dfilter = "frame[20:] contains :12345678"
|
||||
checkDFilterSucceed(dfilter)
|
||||
|
||||
def test_slice_exists_1(self, checkDFilterCount):
|
||||
dfilter = "frame[59]"
|
||||
checkDFilterCount(dfilter, 1)
|
||||
|
||||
def test_slice_exists_2(self, checkDFilterCount):
|
||||
dfilter = "frame[60]"
|
||||
checkDFilterCount(dfilter, 0)
|
||||
|
||||
def test_slice_exists_3(self, checkDFilterCount):
|
||||
dfilter = "frame[50-59]"
|
||||
checkDFilterCount(dfilter, 1)
|
||||
|
||||
def test_slice_exists_4(self, checkDFilterCount):
|
||||
dfilter = "frame[50-60]"
|
||||
checkDFilterCount(dfilter, 0)
|
Loading…
Reference in New Issue