From f37c7c4062db513bd4dc6fffa36a0c90c74a4339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Valverde?= Date: Mon, 2 Jan 2023 01:42:55 +0000 Subject: [PATCH] dfilter: Tweak representation for length-1 byte array Make dfilter byte representation always use ':' for consistency. Make 1 byte be represented as "XX:" with the colon suffix to make it nonambiguous that is is a byte and not other type, like a protocol. The difference is can be seen in the following programs. In the before representation it is not obvious at all that the second "fc" value is a literal bytes value and not the value of the protocol "fc", although it can be inferred from the lack of a READ_TREE instruction. In the After we know that "fc:" must be bytes and not a protocol. Note that a leading colon is a syntactical expedient to say "this value with any type is a literal value and not a protocol field." A terminating colon is just a part of the dfilter literal bytes syntax. Before: Filter: fc == :fc Syntax tree: 0 TEST_ANY_EQ: 1 FIELD(fc ) 1 FVALUE(fc ) Instructions: 00000 READ_TREE fc -> reg#0 00001 IF_FALSE_GOTO 3 00002 ANY_EQ reg#0 == fc After: Filter: fc == :fc Syntax tree: 0 TEST_ANY_EQ: 1 FIELD(fc ) 1 FVALUE(fc: ) Instructions: 00000 READ_TREE fc -> reg#0 00001 IF_FALSE_GOTO 3 00002 ANY_EQ reg#0 == fc: --- epan/dfilter/scanner.l | 2 +- epan/ftypes/ftype-bytes.c | 32 +++++++++++++++++++++++++----- epan/ftypes/ftype-protocol.c | 10 +++++++--- epan/ftypes/ftypes-int.h | 4 ++++ test/suite_dfilter/group_syntax.py | 5 +++++ 5 files changed, 44 insertions(+), 9 deletions(-) diff --git a/epan/dfilter/scanner.l b/epan/dfilter/scanner.l index a273e99d81..1943f2acc4 100644 --- a/epan/dfilter/scanner.l +++ b/epan/dfilter/scanner.l @@ -121,7 +121,7 @@ IPv6Address ({h16}:){6}{ls32}|::({h16}:){5}{ls32}|({h16})?::({h16}:){4}{ls32}|(( V4CidrPrefix \/[[:digit:]]{1,2} V6CidrPrefix \/[[:digit:]]{1,3} -ColonBytes {hex2}(:{hex2})+ +ColonBytes ({hex2}:)|({hex2}(:{hex2})+) DotBytes {hex2}(\.{hex2})+ HyphenBytes {hex2}(-{hex2})+ diff --git a/epan/ftypes/ftype-bytes.c b/epan/ftypes/ftype-bytes.c index 719bae0f25..d3771f519c 100644 --- a/epan/ftypes/ftype-bytes.c +++ b/epan/ftypes/ftype-bytes.c @@ -69,11 +69,38 @@ system_id_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U return print_system_id(scope, fv->value.bytes->data, fv->value.bytes->len); } +char * +bytes_to_dfilter_repr(wmem_allocator_t *scope, + const guint8 *src, size_t src_size) +{ + char *buf; + size_t max_char_size; + char *buf_ptr; + + /* Include space for extra punct and '\0'. */ + max_char_size = src_size * 3 + 1; + + buf = wmem_alloc(scope, max_char_size); + buf_ptr = bytes_to_hexstr_punct(buf, src, src_size, ':'); + if (src_size == 1) + *buf_ptr++ = ':'; + *buf_ptr = '\0'; + return buf; +} + static char * bytes_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display) { char separator; + if (rtype == FTREPR_DFILTER) { + if (fv->value.bytes->len == 0) { + /* An empty byte array in a display filter is represented as "" */ + return wmem_strdup(scope, "\"\""); + } + return bytes_to_dfilter_repr(scope, fv->value.bytes->data, fv->value.bytes->len); + } + switch(FIELD_DISPLAY(field_display)) { case SEP_DOT: @@ -94,11 +121,6 @@ bytes_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int f return bytes_to_str_punct_maxlen(scope, fv->value.bytes->data, fv->value.bytes->len, separator, 0); } - if (rtype == FTREPR_DFILTER) { - /* An empty byte array in a display filter is represented as "" */ - return wmem_strdup(scope, "\"\""); - } - return wmem_strdup(scope, ""); } diff --git a/epan/ftypes/ftype-protocol.c b/epan/ftypes/ftype-protocol.c index 25571e3407..f1274066e1 100644 --- a/epan/ftypes/ftype-protocol.c +++ b/epan/ftypes/ftype-protocol.c @@ -169,7 +169,7 @@ val_from_charconst(fvalue_t *fv, unsigned long num, gchar **err_msg) } static char * -val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int field_display _U_) +val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype, int field_display _U_) { guint length; char *volatile buf = NULL; @@ -183,8 +183,12 @@ val_to_repr(wmem_allocator_t *scope, const fvalue_t *fv, ftrepr_t rtype _U_, int else length = tvb_captured_length(fv->value.protocol.tvb); - if (length) - buf = bytes_to_str_punct_maxlen(scope, tvb_get_ptr(fv->value.protocol.tvb, 0, length), length, ':', 0); + if (length) { + if (rtype == FTREPR_DFILTER) + buf = bytes_to_dfilter_repr(scope, tvb_get_ptr(fv->value.protocol.tvb, 0, length), length); + else + buf = bytes_to_str_punct_maxlen(scope, tvb_get_ptr(fv->value.protocol.tvb, 0, length), length, ':', 0); + } } CATCH_ALL { /* nothing */ diff --git a/epan/ftypes/ftypes-int.h b/epan/ftypes/ftypes-int.h index 713bec3029..f8a0d6ed04 100644 --- a/epan/ftypes/ftypes-int.h +++ b/epan/ftypes/ftypes-int.h @@ -160,6 +160,10 @@ byte_array_from_literal(const char *s, gchar **err_msg); GByteArray * byte_array_from_charconst(unsigned long num, gchar **err_msg); +char * +bytes_to_dfilter_repr(wmem_allocator_t *scope, + const guint8 *src, size_t src_size); + #endif /* FTYPES_INT_H */ /* diff --git a/test/suite_dfilter/group_syntax.py b/test/suite_dfilter/group_syntax.py index 89e442e539..86e351928a 100644 --- a/test/suite_dfilter/group_syntax.py +++ b/test/suite_dfilter/group_syntax.py @@ -188,6 +188,11 @@ class case_equality(unittest.TestCase): dfilter = 'frame[37] == :fc' checkDFilterCount(dfilter, 1) + def test_rhs_bias_3(self, checkDFilterCount): + # Byte 0xFC on the RHS + dfilter = 'frame[37] == fc:' + checkDFilterCount(dfilter, 1) + def test_rhs_literal_bias_4(self, checkDFilterCount): # Protocol "Fibre Channel" on the RHS dfilter = 'frame[37] == .fc'