aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--docbook/release-notes.adoc1
-rw-r--r--epan/dfilter/dfunctions.c29
-rw-r--r--epan/dfilter/dfvm.c32
-rw-r--r--epan/dfilter/dfvm.h1
-rw-r--r--epan/dfilter/gencode.c58
-rw-r--r--epan/dfilter/semcheck.c16
-rw-r--r--test/suite_dfilter/group_slice.py (renamed from test/suite_dfilter/group_range_method.py)16
8 files changed, 117 insertions, 38 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3ab3fcac99..069289fff6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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
diff --git a/docbook/release-notes.adoc b/docbook/release-notes.adoc
index caf8eeaafc..2673f2d959 100644
--- a/docbook/release-notes.adoc
+++ b/docbook/release-notes.adoc
@@ -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`.
diff --git a/epan/dfilter/dfunctions.c b/epan/dfilter/dfunctions.c
index 66099fd9f4..66e83d2d29 100644
--- a/epan/dfilter/dfunctions.c
+++ b/epan/dfilter/dfunctions.c
@@ -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;
}
diff --git a/epan/dfilter/dfvm.c b/epan/dfilter/dfvm.c
index 935a121b97..0403707335 100644
--- a/epan/dfilter/dfvm.c
+++ b/epan/dfilter/dfvm.c
@@ -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;
diff --git a/epan/dfilter/dfvm.h b/epan/dfilter/dfvm.h
index 660b6799a5..d9f81d2e83 100644
--- a/epan/dfilter/dfvm.h
+++ b/epan/dfilter/dfvm.h
@@ -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,
diff --git a/epan/dfilter/gencode.c b/epan/dfilter/gencode.c
index b085ca4bd4..ef996ae8a0 100644
--- a/epan/dfilter/gencode.c
+++ b/epan/dfilter/gencode.c
@@ -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));
@@ -601,6 +631,31 @@ gen_notzero(dfwork_t *dfw, stnode_t *st_node)
}
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)
{
stnode_op_t st_op;
@@ -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();
}
diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c
index 46dc9bda4f..fd267feadb 100644
--- a/epan/dfilter/semcheck.c
+++ b/epan/dfilter/semcheck.c
@@ -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);
}
diff --git a/test/suite_dfilter/group_range_method.py b/test/suite_dfilter/group_slice.py
index 143b223cd0..4aa686c57c 100644
--- a/test/suite_dfilter/group_range_method.py
+++ b/test/suite_dfilter/group_slice.py
@@ -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)