diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | docbook/release-notes.adoc | 1 | ||||
-rw-r--r-- | epan/dfilter/dfunctions.c | 29 | ||||
-rw-r--r-- | epan/dfilter/dfvm.c | 32 | ||||
-rw-r--r-- | epan/dfilter/dfvm.h | 1 | ||||
-rw-r--r-- | epan/dfilter/gencode.c | 58 | ||||
-rw-r--r-- | epan/dfilter/semcheck.c | 16 | ||||
-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) |