Commit b10db887 authored by João Valverde's avatar João Valverde
Browse files

dfilter: Remove unparsed syntax type and RHS literal bias

This removes unparsed name resolution during the semantic
check because it feels like a hack to work around limitations
in the language syntax, that should be solved at the lexical
level instead.

We were interpreting unparsed differently on the LHS and RHS.
Now an unparsed value is always a field if it matches a
registered field name (this matches the implementation in 3.6
and before).

This requires tightening a bit the allowed filter names for
protocols to avoid some common and potentially weird conflicting
cases.

Incidentally this extends set grammar to accept all entities.
That is experimental and may be reverted in the future.
parent 190404d6
Pipeline #578516135 passed with stages
in 75 minutes and 10 seconds
......@@ -869,36 +869,36 @@ to “dhcp.type” but Wireshark will show the warning “"bootp" is deprecated
when you use it. Support for the deprecated fields may be removed in the future.
==== Some protocol names can be ambiguous
In some uncommon cases relational display filter expressions (equal, less than, etc.)
In some particular cases relational expressions (equal, less than, etc.)
can be ambiguous. The filter name of a protocol or protocol field can contain
any letter and digit in any order, possibly separated by dots. That can be
indistinguishable from a literal value (usually numerical values in hexadecimal).
For example the semantic value of `fc` can be the protocol Fibre Channel or the
number 0xfc in hexadecimal. The 0x prefix is optional for literal values and
furthermore "0xfc" would be a syntactically valid filter name for a protocol.
Wireshark will use a heuristic for parsing those expressions. A value on the
right hand side of the expression is treated as literal value first. If that
fails it is treated as a protocol or protocol field (if one exists with that
name). If that fails it is a syntactical error. On the left hand side values
are always treated as protocol fields. Literal values are not considered on the
LHS. So the expression `fc == fc` is parsed as
"Byte array of protocol with name 'fc' equals byte array { 0xfc } of length 1".
Sometimes this may not be the intended meaning and there is additional syntax
to resolve the ambiguity. Lexical tokens in-between angle brackets are always
and only treated as literal values. Bytes arrays can also be prefixed with a
colon. Tokens prefixed with a dot are always treated as a protocol name (the
dot stands for the root of the protocol namespace and is optional).
number 0xFC in hexadecimal because the 0x prefix is optional for hexadecimal numbers.
Any value that matches a registered protocol or protocol field filter name is
interpreted semantically as such. If it doesn't match a protocol name the normal
rules for parsing literal values apply.
So in the case of 'fc' the lexical token is interpreted as "Fibre Channel" and
not 0xFC. In the case of 'fd' it would be interpreted as 0xFD because it is a
well-formed hexadecimal literal value (according to the rules of display filter
language syntax) and there is no protocol registered with the filter name 'fd'.
How ambiguous values are interpreted may change in the future. To avoid this
problem and resolve the ambiguity there is additional syntax available.
Values in-between angle brackets are always and only treated as literal
values. Bytes arrays and numeric values can also be prefixed with a colon to
force interpretation as a literal value. Values prefixed with a dot are always
treated as a protocol name. The dot stands for the root of the protocol namespace
and is optional)
----
frame[10:] contains .fc or frame[10] == :fc and not frame contains <cafe.face>
----
The most common use case for a display filter relational expression is to compare
a field with a constant value on the right hand side and in that case the heuristic
method used will parse the expression correctly. In the not-so-common case, or
if you are writing a script, or you think your expression may not be giving the
expected results it is advisable to use the explicit syntax to resolve any
possible ambiguity in the meaning of filter expression.
If you are writing a script, or you think your expression may not be giving the
expected results because of the syntactical ambiguity of some filter expression
it is advisable to use the explicit syntax to indicate the correct meaning for
that expression.
[#ChWorkFilterAddExpressionSection]
......
......@@ -105,13 +105,6 @@ DfilterTrace(FILE *TraceFILE, char *zTracePrompt);
header_field_info *
dfilter_resolve_unparsed(dfwork_t *dfw, const char *name);
gboolean
dfw_resolve_unparsed(dfwork_t *dfw, stnode_t *st);
fvalue_t *
dfilter_fvalue_from_unparsed(dfwork_t *dfw, ftenum_t ftype, stnode_t *st,
gboolean allow_partial_value, header_field_info *hfinfo_value_string);
WS_RETNONNULL fvalue_t*
dfilter_fvalue_from_literal(dfwork_t *dfw, ftenum_t ftype, stnode_t *st,
gboolean allow_partial_value, header_field_info *hfinfo_value_string);
......
......@@ -94,10 +94,6 @@ dfw_set_error_location(dfwork_t *dfw, stloc_t *loc)
dfw->err_loc = *loc;
}
/*
* Tries to convert an STTYPE_UNPARSED to a STTYPE_FIELD. If it's not registered as
* a field pass UNPARSED to the semantic check.
*/
header_field_info *
dfilter_resolve_unparsed(dfwork_t *dfw, const char *name)
{
......@@ -121,21 +117,6 @@ dfilter_resolve_unparsed(dfwork_t *dfw, const char *name)
return NULL;
}
gboolean
dfw_resolve_unparsed(dfwork_t *dfw, stnode_t *st)
{
if (stnode_type_id(st) != STTYPE_UNPARSED)
return FALSE;
header_field_info *hfinfo = dfilter_resolve_unparsed(dfw, stnode_data(st));
if (hfinfo != NULL) {
stnode_replace(st, STTYPE_FIELD, hfinfo);
return TRUE;
}
stnode_replace(st, STTYPE_LITERAL, g_strdup(stnode_data(st)));
return FALSE;
}
/* Initialize the dfilter module */
void
dfilter_init(void)
......
......@@ -274,8 +274,6 @@ ul_semcheck_is_field_string(dfwork_t *dfw, const char *func_name, ftenum_t lhs_f
ws_assert(g_slist_length(param_list) == 1);
stnode_t *st_node = param_list->data;
dfw_resolve_unparsed(dfw, st_node);
if (stnode_type_id(st_node) == STTYPE_FIELD) {
hfinfo = sttype_field_hfinfo(st_node);
if (IS_FT_STRING(hfinfo->type)) {
......@@ -292,8 +290,6 @@ ul_semcheck_is_field(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype _U
ws_assert(g_slist_length(param_list) == 1);
stnode_t *st_node = param_list->data;
dfw_resolve_unparsed(dfw, st_node);
if (stnode_type_id(st_node) == STTYPE_FIELD)
return FT_UINT32;
......@@ -309,8 +305,6 @@ ul_semcheck_string_param(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftyp
ws_assert(g_slist_length(param_list) == 1);
stnode_t *st_node = param_list->data;
dfw_resolve_unparsed(dfw, st_node);
if (stnode_type_id(st_node) == STTYPE_FIELD) {
hfinfo = sttype_field_hfinfo(st_node);
switch (hfinfo->type) {
......@@ -366,7 +360,6 @@ ul_semcheck_compare(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype,
fvalue_t *fv;
arg = param_list->data;
dfw_resolve_unparsed(dfw, arg);
if (stnode_type_id(arg) == STTYPE_ARITHMETIC) {
ftype = check_arithmetic_expr(dfw, arg, lhs_ftype);
......@@ -390,7 +383,6 @@ ul_semcheck_compare(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype,
for (l = param_list->next; l != NULL; l = l->next) {
arg = l->data;
dfw_resolve_unparsed(dfw, arg);
if (stnode_type_id(arg) == STTYPE_ARITHMETIC) {
ft_arg = check_arithmetic_expr(dfw, arg, ftype);
......@@ -436,7 +428,6 @@ ul_semcheck_absolute_value(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ft
fvalue_t *fv;
st_node = param_list->data;
dfw_resolve_unparsed(dfw, st_node);
if (stnode_type_id(st_node) == STTYPE_ARITHMETIC) {
ftype = check_arithmetic_expr(dfw, st_node, lhs_ftype);
......
......@@ -120,7 +120,6 @@ expr(X) ::= LPAREN expr(Y) RPAREN. { X = Y; }
/* Entities, or things that can be compared/tested/checked */
atom(A) ::= STRING(S). { A = S; }
atom(A) ::= CHARCONST(N). { A = N; }
atom(A) ::= UNPARSED(S). { A = S; }
atom(A) ::= LITERAL(S). { A = S; }
layer(R) ::= HASH LBRACKET range_node_list(L) RBRACKET.
......@@ -154,7 +153,7 @@ field(R) ::= FIELD(F) layer(L).
field(R) ::= UNPARSED(U) layer(L).
{
header_field_info *hfinfo = dfilter_resolve_unparsed(dfw, stnode_data(U));
header_field_info *hfinfo = dfilter_resolve_unparsed(dfw, stnode_token(U));
if (hfinfo == NULL) {
FAIL(dfw, U, "%s is not a valid field", stnode_token(U));
}
......@@ -174,7 +173,7 @@ reference(R) ::= DOLLAR LBRACE field(F) RBRACE.
reference(R) ::= DOLLAR LBRACE UNPARSED(U) RBRACE.
{
header_field_info *hfinfo = dfilter_resolve_unparsed(dfw, stnode_data(U));
header_field_info *hfinfo = dfilter_resolve_unparsed(dfw, stnode_token(U));
if (hfinfo == NULL) {
FAIL(dfw, U, "%s is not a valid field", stnode_token(U));
}
......@@ -187,6 +186,19 @@ entity(E) ::= slice(R). { E = R; }
entity(E) ::= function(F). { E = F; }
entity(E) ::= field(F). { E = F; }
entity(E) ::= reference(R). { E = R; }
entity(E) ::= UNPARSED(U).
{
const char *token = stnode_token(U);
const stloc_t *loc = stnode_location(U);
header_field_info *hfinfo = dfilter_resolve_unparsed(dfw, token);
if (hfinfo != NULL) {
E = stnode_new(STTYPE_FIELD, hfinfo, g_strdup(token), loc);
}
else {
E = stnode_new(STTYPE_LITERAL, g_strdup(token), g_strdup(token), loc);
}
stnode_free(U);
}
arithmetic_expr(T) ::= entity(N).
{
......@@ -338,20 +350,20 @@ set_list(L) ::= set_list(P) COMMA set_element(N).
L = g_slist_concat(P, N);
}
set_entity(N) ::= atom(X).
set_entity(N) ::= entity(E).
{
N = X;
N = E;
}
set_entity(N) ::= MINUS(M) atom(X).
set_entity(N) ::= MINUS(M) entity(E).
{
N = M;
sttype_test_set1(N, OP_UNARY_MINUS, X);
sttype_test_set1(N, OP_UNARY_MINUS, E);
}
set_entity(N) ::= PLUS atom(X).
set_entity(N) ::= PLUS entity(E).
{
N = X;
N = E;
}
set_element(N) ::= set_entity(X).
......@@ -408,7 +420,7 @@ range_node_list(L) ::= range_node_list(P) COMMA RANGE_NODE(N).
static stnode_t *
new_function(dfwork_t *dfw, stnode_t *node)
{
const char *name = stnode_data(node);
const char *name = stnode_token(node);
df_func_def_t *def = df_func_lookup(name);
if (!def) {
......
......@@ -419,19 +419,19 @@ hyphen-bytes {hex2}(-{hex2})+
{MacAddress}|{QuadMacAddress} {
/* MAC Address. */
update_location(yyextra, yytext);
return set_lval_str(yyextra, TOKEN_UNPARSED, yytext);
return set_lval_simple(yyextra, TOKEN_UNPARSED, yytext, STTYPE_UNINITIALIZED);
}
{IPv4address}{v4-cidr-prefix}? {
/* IPv4 with or without prefix. */
update_location(yyextra, yytext);
return set_lval_str(yyextra, TOKEN_UNPARSED, yytext);
return set_lval_simple(yyextra, TOKEN_UNPARSED, yytext, STTYPE_UNINITIALIZED);
}
{IPv6address}{v6-cidr-prefix}? {
/* IPv6 with or without prefix. */
update_location(yyextra, yytext);
return set_lval_str(yyextra, TOKEN_UNPARSED, yytext);
return set_lval_simple(yyextra, TOKEN_UNPARSED, yytext, STTYPE_UNINITIALIZED);
}
:?({colon-bytes}|{dot-bytes}|{hyphen-bytes}) {
......@@ -439,7 +439,7 @@ hyphen-bytes {hex2}(-{hex2})+
update_location(yyextra, yytext);
if (yytext[0] == ':')
return set_lval_str(yyextra, TOKEN_LITERAL, yytext); /* Keep leading colon. */
return set_lval_str(yyextra, TOKEN_UNPARSED, yytext);
return set_lval_simple(yyextra, TOKEN_UNPARSED, yytext, STTYPE_UNINITIALIZED);
}
:[[:xdigit:]]+ {
......@@ -464,7 +464,7 @@ hyphen-bytes {hex2}(-{hex2})+
/* Skip leading dot. */
return set_lval_field(yyextra, TOKEN_FIELD, yytext + 1);
}
return set_lval_str(yyextra, TOKEN_UNPARSED, yytext);
return set_lval_simple(yyextra, TOKEN_UNPARSED, yytext, STTYPE_UNINITIALIZED);
}
. {
......@@ -522,9 +522,6 @@ set_lval_str(df_scanner_state_t *state, int token, const char *token_value)
case TOKEN_LITERAL:
type_id = STTYPE_LITERAL;
break;
case TOKEN_UNPARSED:
type_id = STTYPE_UNPARSED;
break;
default:
ws_assert_not_reached();
}
......
......@@ -184,57 +184,6 @@ dfilter_fvalue_from_literal(dfwork_t *dfw, ftenum_t ftype, stnode_t *st,
return fv;
}
fvalue_t *
dfilter_fvalue_from_unparsed(dfwork_t *dfw, ftenum_t ftype, stnode_t *st,
gboolean allow_partial_value, header_field_info *hfinfo_value_string)
{
fvalue_t *fv;
const char *s = stnode_data(st);
/* Don't set the error message if it's already set. */
fv = fvalue_from_literal(ftype, s, allow_partial_value,
dfw->error_message == NULL ? &dfw->error_message : NULL);
if (fv != NULL) {
/* converted to fvalue successfully. */
return fv;
}
if (hfinfo_value_string) {
/* check value_string */
fv = mk_fvalue_from_val_string(dfw, hfinfo_value_string, s);
if (fv != NULL) {
/*
* Ignore previous errors if this can be mapped
* to an item from value_string.
*/
g_free(dfw->error_message);
dfw->error_message = NULL;
return fv;
}
}
header_field_info *hfinfo = dfilter_resolve_unparsed(dfw, s);
if (hfinfo == NULL) {
/* This node is neither a valid fvalue nor a valid field. */
/* The parse failed. Error message is already set. */
dfw_set_error_location(dfw, stnode_location(st));
THROW(TypeError);
}
/* Successfully resolved to a field. */
/* Free the error message for the failed fvalue_from_literal() attempt. */
g_free(dfw->error_message);
dfw->error_message = NULL;
stnode_replace(st, STTYPE_FIELD, hfinfo);
/* Return NULL to signal we have a field. */
return NULL;
}
/* Gets an fvalue from a string, and sets the error message on failure. */
WS_RETNONNULL
fvalue_t *
......@@ -503,8 +452,6 @@ check_exists(dfwork_t *dfw, stnode_t *st_arg1)
{
LOG_NODE(st_arg1);
dfw_resolve_unparsed(dfw, st_arg1);
switch (stnode_type_id(st_arg1)) {
case STTYPE_FIELD:
case STTYPE_ARITHMETIC:
......@@ -535,7 +482,6 @@ check_exists(dfwork_t *dfw, stnode_t *st_arg1)
break;
case STTYPE_SET:
case STTYPE_UNPARSED:
case STTYPE_UNINITIALIZED:
case STTYPE_NUM_TYPES:
case STTYPE_TEST:
......@@ -556,7 +502,6 @@ check_slice_sanity(dfwork_t *dfw, stnode_t *st, ftenum_t lhs_ftype)
entity1 = sttype_slice_entity(st);
ws_assert(entity1);
dfw_resolve_unparsed(dfw, entity1);
if (stnode_type_id(entity1) == STTYPE_FIELD) {
hfinfo1 = sttype_field_hfinfo(entity1);
......@@ -659,7 +604,6 @@ check_relation_LHS_FIELD(dfwork_t *dfw, test_op_t st_op,
LOG_NODE(st_node);
again:
type2 = stnode_type_id(st_arg2);
ws_assert(stnode_type_id(st_arg1) == STTYPE_FIELD ||
......@@ -687,7 +631,7 @@ again:
stnode_todisplay(st_arg2), ftype_pretty_name(ftype2));
}
}
else if (type2 == STTYPE_STRING || type2 == STTYPE_LITERAL || type2 == STTYPE_UNPARSED) {
else if (type2 == STTYPE_STRING || type2 == STTYPE_LITERAL) {
/* Skip incompatible fields */
while (hfinfo1->same_name_prev_id != -1 &&
((type2 == STTYPE_STRING && ftype1 != FT_STRING && ftype1!= FT_STRINGZ) ||
......@@ -696,14 +640,7 @@ again:
ftype1 = hfinfo1->type;
}
if (type2 == STTYPE_UNPARSED) {
fvalue = dfilter_fvalue_from_unparsed(dfw, ftype1, st_arg2, allow_partial_value, hfinfo1);
if (fvalue == NULL) {
/* We have a protocol or protocol field. */
goto again;
}
}
else if (type2 == STTYPE_STRING) {
if (type2 == STTYPE_STRING) {
fvalue = dfilter_fvalue_from_string(dfw, ftype1, st_arg2, hfinfo1);
}
else {
......@@ -778,7 +715,6 @@ check_relation_LHS_SLICE(dfwork_t *dfw, test_op_t st_op,
check_slice_sanity(dfw, st_arg1, FT_NONE);
again:
type2 = stnode_type_id(st_arg2);
if (IS_FIELD_ENTITY(type2)) {
......@@ -799,14 +735,6 @@ again:
fvalue = dfilter_fvalue_from_string(dfw, FT_BYTES, st_arg2, NULL);
stnode_replace(st_arg2, STTYPE_FVALUE, fvalue);
}
else if (type2 == STTYPE_UNPARSED) {
fvalue = dfilter_fvalue_from_unparsed(dfw, FT_BYTES, st_arg2, allow_partial_value, NULL);
if (fvalue == NULL) {
/* We have a protocol or protocol field. */
goto again;
}
stnode_replace(st_arg2, STTYPE_FVALUE, fvalue);
}
else if (type2 == STTYPE_LITERAL) {
fvalue = dfilter_fvalue_from_literal(dfw, FT_BYTES, st_arg2, allow_partial_value, NULL);
stnode_replace(st_arg2, STTYPE_FVALUE, fvalue);
......@@ -875,7 +803,6 @@ check_relation_LHS_FUNCTION(dfwork_t *dfw, test_op_t st_op,
stnode_todisplay(st_node));
}
again:
type2 = stnode_type_id(st_arg2);
if (IS_FIELD_ENTITY(type2)) {
......@@ -896,14 +823,6 @@ again:
fvalue = dfilter_fvalue_from_string(dfw, ftype1, st_arg2, NULL);
stnode_replace(st_arg2, STTYPE_FVALUE, fvalue);
}
else if (type2 == STTYPE_UNPARSED) {
fvalue = dfilter_fvalue_from_unparsed(dfw, ftype1, st_arg2, allow_partial_value, NULL);
if (fvalue == NULL) {
/* We have a protocol or protocol field. */
goto again;
}
stnode_replace(st_arg2, STTYPE_FVALUE, fvalue);
}
else if (type2 == STTYPE_LITERAL) {
fvalue = dfilter_fvalue_from_literal(dfw, ftype1, st_arg2, allow_partial_value, NULL);
stnode_replace(st_arg2, STTYPE_FVALUE, fvalue);
......@@ -1001,8 +920,6 @@ check_relation(dfwork_t *dfw, test_op_t st_op,
{
LOG_NODE(st_node);
dfw_resolve_unparsed(dfw, st_arg1);
switch (stnode_type_id(st_arg1)) {
case STTYPE_FIELD:
case STTYPE_REFERENCE:
......@@ -1033,8 +950,6 @@ check_relation_contains(dfwork_t *dfw, stnode_t *st_node,
{
LOG_NODE(st_node);
dfw_resolve_unparsed(dfw, st_arg1);
switch (stnode_type_id(st_arg1)) {
case STTYPE_FIELD:
case STTYPE_REFERENCE:
......@@ -1066,8 +981,6 @@ check_relation_matches(dfwork_t *dfw, stnode_t *st_node,
LOG_NODE(st_node);
dfw_resolve_unparsed(dfw, st_arg1);
if (stnode_type_id(st_arg2) != STTYPE_STRING) {
FAIL(dfw, st_arg2, "Matches requires a double quoted string on the right side.");
}
......@@ -1113,8 +1026,6 @@ check_relation_in(dfwork_t *dfw, stnode_t *st_node _U_,
LOG_NODE(st_node);
dfw_resolve_unparsed(dfw, st_arg1);
if (stnode_type_id(st_arg1) != STTYPE_FIELD) {
FAIL(dfw, st_arg1, "Only a field may be tested for membership in a set.");
}
......@@ -1216,7 +1127,6 @@ check_arithmetic_entity(dfwork_t *dfw, stnode_t *st_arg, ftenum_t lhs_ftype)
* is none we must have been passed an entity with a definite type
* (field, function, etc). */
dfw_resolve_unparsed(dfw, st_arg);
type = stnode_type_id(st_arg);
if (type == STTYPE_LITERAL) {
......@@ -1264,7 +1174,6 @@ check_arithmetic_expr(dfwork_t *dfw, stnode_t *st_node, ftenum_t lhs_ftype)
}
sttype_test_get(st_node, &st_op, &st_arg1, &st_arg2);
dfw_resolve_unparsed(dfw, st_arg1);
/* On the LHS we require a field-like value as the first term. */
if (lhs_ftype == FT_NONE && node_is_constant(st_arg1)) {
......
......@@ -61,15 +61,6 @@ sttype_register_string(void)
gstring_tostr
};
static sttype_t unparsed_type = {
STTYPE_UNPARSED,
"UNPARSED",
NULL,
string_free,
string_dup,
string_tostr
};
static sttype_t literal_type = {
STTYPE_LITERAL,
"LITERAL",
......@@ -80,7 +71,6 @@ sttype_register_string(void)
};
sttype_register(&string_type);
sttype_register(&unparsed_type);
sttype_register(&literal_type);
}
......
......@@ -102,7 +102,7 @@ stnode_clear(stnode_t *node)
}
void
stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data, char *token, stloc_t *loc)
stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data, char *token, const stloc_t *loc)
{
sttype_t *type;
......@@ -149,7 +149,7 @@ stnode_replace(stnode_t *node, sttype_id_t type_id, gpointer data)
}
stnode_t*
stnode_new(sttype_id_t type_id, gpointer data, char *token, stloc_t *loc)
stnode_new(sttype_id_t type_id, gpointer data, char *token, const stloc_t *loc)
{
stnode_t *node;
......
......@@ -24,7 +24,6 @@ typedef enum {
STTYPE_UNINITIALIZED,
STTYPE_TEST,
STTYPE_LITERAL,
STTYPE_UNPARSED,
STTYPE_REFERENCE,
STTYPE_STRING,
STTYPE_CHARCONST,
......@@ -120,7 +119,7 @@ void
sttype_register(sttype_t *type);
stnode_t*
stnode_new(sttype_id_t type_id, gpointer data, char *token, stloc_t *loc);
stnode_new(sttype_id_t type_id, gpointer data, char *token, const stloc_t *loc);
stnode_t*
stnode_dup(const stnode_t *org);
......@@ -129,7 +128,7 @@ void
stnode_clear(stnode_t *node);
void
stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data, char *token, stloc_t *loc);
stnode_init(stnode_t *node, sttype_id_t type_id, gpointer data, char *token, const stloc_t *loc);
void
stnode_replace(stnode_t *node, sttype_id_t type_id, gpointer data);
......
......@@ -7425,12 +7425,38 @@ proto_tree_set_appendix(proto_tree *tree, tvbuff_t *tvb, gint start,
static void
check_protocol_filter_name_or_fail(const char *filter_name)
{
/* Require at least two characters. */
if (filter_name[0] == '\0' || filter_name[1] == '\0') {
REPORT_DISSECTOR_BUG("Protocol filter name \"%s\" cannot have length less than two.", filter_name);
}
if (proto_check_field_name(filter_name) != '\0') {
REPORT_DISSECTOR_BUG("Protocol filter name \"%s\" has one or more invalid characters."
" Allowed are letters, digits, '-', '_' and non-repeating '.'."
" This might be caused by an inappropriate plugin or a development error.", filter_name);
}
/* Check that it doesn't match some very common numeric forms. */
if (filter_name[0] == '0' &&
(filter_name[1] == 'x' || filter_name[1] == 'X' ||
filter_name[1] == 'b' || filter_name[1] == 'B')) {
REPORT_DISSECTOR_BUG("Protocol filter name \"%s\" cannot start with \"%c%c\".",
filter_name, filter_name[0], filter_name[1]);
}
/* Check that it doesn't have all decimal digits. */
bool all_digits = true;
for (const char *s = filter_name; *s != '\0'; s++) {
if (!g_ascii_isdigit(*s)) {
all_digits = false;
break;
}
}
if (all_digits) {
REPORT_DISSECTOR_BUG("Protocol filter name \"%s\" cannot be composed of all decimal digits.",
filter_name);
}
/* Check for reserved keywords. */
if (g_hash_table_contains(proto_reserved_filter_names, filter_name)) {
REPORT_DISSECTOR_BUG("Protocol filter name \"%s\" is invalid because it is a reserved keyword."
......
......@@ -167,20 +167,23 @@ class case_equality(unittest.TestCase):
dfilter = "frame[0:10] contains :00-01-6c"
checkDFilterCount(dfilter, 1)
def test_rhs_literal_bias_1(self, checkDFilterCount):
def test_rhs_bias_1(self, checkDFilterCount):
# Protocol "Fibre Channel" on the RHS
dfilter = 'frame[37] == fc'
checkDFilterCount(dfilter, 1)
checkDFilterCount(dfilter, 0)
def test_rhs_literal_bias_2(self, checkDFilterCount):
def test_rhs_bias_2(self, checkDFilterCount):
# Byte 0xFC on the RHS
dfilter = 'frame[37] == :fc'
checkDFilterCount(dfilter, 1)
def test_rhs_literal_bias_3(self, checkDFilterCount):
# Byte 0xFC on the RHS
dfilter = 'frame[37] == <fc>'
checkDFilterCount(dfilter, 1)
def test_rhs_literal_bias_4(self, checkDFilterCount):