2 * Wireshark - Network traffic analyzer
4 * Copyright 2006 Gilbert Ramirez <gram@alumni.rice.edu>
6 * SPDX-License-Identifier: GPL-2.0-or-later
10 #define WS_LOG_DOMAIN LOG_DOMAIN_DFILTER
12 #include <wireshark.h>
14 #include "dfilter-int.h"
15 #include "dfunctions.h"
16 #include "dfilter-plugin.h"
17 #include "sttype-field.h"
18 #include "sttype-pointer.h"
23 #include <ftypes/ftypes.h>
24 #include <epan/exceptions.h>
25 #include <wsutil/ws_assert.h>
28 static GHashTable
*registered_functions
;
30 static GPtrArray
*registered_names
;
32 /* Convert an FT_STRING using a callback function */
34 string_walk(GSList
*stack
, uint32_t arg_count _U_
, df_cell_t
*retval
, char(*conv_func
)(char))
38 fvalue_t
*new_ft_string
;
39 const wmem_strbuf_t
*src
;
42 ws_assert(arg_count
== 1);
47 for (unsigned i
= 0; i
< arg1
->len
; i
++) {
48 arg_fvalue
= arg1
->pdata
[i
];
49 /* XXX - it would be nice to handle FT_TVBUFF, too */
50 if (FT_IS_STRING(fvalue_type_ftenum(arg_fvalue
))) {
51 src
= fvalue_get_strbuf(arg_fvalue
);
52 dst
= wmem_strbuf_new_sized(NULL
, src
->len
);
53 for (size_t j
= 0; j
< src
->len
; j
++) {
54 wmem_strbuf_append_c(dst
, conv_func(src
->str
[j
]));
56 new_ft_string
= fvalue_new(FT_STRING
);
57 fvalue_set_strbuf(new_ft_string
, dst
);
58 df_cell_append(retval
, new_ft_string
);
65 /* dfilter function: lower() */
67 df_func_lower(GSList
*stack
, uint32_t arg_count
, df_cell_t
*retval
)
69 return string_walk(stack
, arg_count
, retval
, g_ascii_tolower
);
72 /* dfilter function: upper() */
74 df_func_upper(GSList
*stack
, uint32_t arg_count
, df_cell_t
*retval
)
76 return string_walk(stack
, arg_count
, retval
, g_ascii_toupper
);
79 /* dfilter function: count() */
81 df_func_count(GSList
*stack
, uint32_t arg_count _U_
, df_cell_t
*retval
)
87 ws_assert(arg_count
== 1);
92 num_items
= arg1
->len
;
93 ft_ret
= fvalue_new(FT_UINT32
);
94 fvalue_set_uinteger(ft_ret
, num_items
);
95 df_cell_append(retval
, ft_ret
);
100 /* dfilter function: string() */
102 df_func_string(GSList
*stack
, uint32_t arg_count _U_
, df_cell_t
*retval
)
105 fvalue_t
*arg_fvalue
;
106 fvalue_t
*new_ft_string
;
109 ws_assert(arg_count
== 1);
114 for (unsigned i
= 0; i
< arg1
->len
; i
++) {
115 arg_fvalue
= arg1
->pdata
[i
];
116 switch (fvalue_type_ftenum(arg_fvalue
))
148 case FT_IEEE_11073_SFLOAT
:
149 case FT_IEEE_11073_FLOAT
:
150 s
= fvalue_to_string_repr(NULL
, arg_fvalue
, FTREPR_DFILTER
, BASE_NONE
);
151 /* Ensure we have an allocated string here */
153 s
= wmem_strdup(NULL
, "");
159 new_ft_string
= fvalue_new(FT_STRING
);
160 fvalue_set_string(new_ft_string
, s
);
162 df_cell_append(retval
, new_ft_string
);
168 /* dfilter function: double() */
170 df_func_double(GSList
*stack
, uint32_t arg_count _U_
, df_cell_t
*retval
)
173 fvalue_t
*arg_fvalue
;
174 fvalue_t
*new_ft_double
;
177 ws_assert(arg_count
== 1);
182 for (unsigned i
= 0; i
< arg1
->len
; i
++) {
183 arg_fvalue
= arg1
->pdata
[i
];
185 if (fvalue_to_double(arg_fvalue
, &res
) == FT_OK
) {
186 new_ft_double
= fvalue_new(FT_DOUBLE
);
187 fvalue_set_floating(new_ft_double
, res
);
188 df_cell_append(retval
, new_ft_double
);
192 if (df_cell_size(retval
) == 0) {
199 /* dfilter function: float() */
201 df_func_float(GSList
*stack
, uint32_t arg_count _U_
, df_cell_t
*retval
)
204 fvalue_t
*arg_fvalue
;
205 fvalue_t
*new_ft_double
;
208 ws_assert(arg_count
== 1);
213 for (unsigned i
= 0; i
< arg1
->len
; i
++) {
214 arg_fvalue
= arg1
->pdata
[i
];
216 if (fvalue_to_double(arg_fvalue
, &res
) == FT_OK
) {
217 new_ft_double
= fvalue_new(FT_FLOAT
);
218 fvalue_set_floating(new_ft_double
, (float)res
);
219 df_cell_append(retval
, new_ft_double
);
223 if (df_cell_size(retval
) == 0) {
230 /* dfilter functions: dec(), hex(), */
232 df_func_base(GSList
*stack
, uint32_t arg_count _U_
, df_cell_t
*retval
, int base
)
235 fvalue_t
*arg_fvalue
;
236 fvalue_t
*new_ft_string
;
239 ws_assert(arg_count
== 1);
244 for (unsigned i
= 0; i
< arg1
->len
; i
++) {
245 arg_fvalue
= arg1
->pdata
[i
];
247 if (FT_IS_UINT(fvalue_type_ftenum(arg_fvalue
))) {
248 s
= fvalue_to_string_repr(NULL
, arg_fvalue
, FTREPR_DFILTER
, base
);
249 /* Ensure we have an allocated string here */
251 s
= wmem_strdup(NULL
, "");
253 /* XXX - We have, unfortunately, some field abbreviations which are
254 * re-used with incompatible types, some of which support different
255 * bases and some which don't.
257 s
= wmem_strdup(NULL
, "");
260 new_ft_string
= fvalue_new(FT_STRING
);
261 fvalue_set_string(new_ft_string
, s
);
263 df_cell_append(retval
, new_ft_string
);
270 df_func_hex(GSList
*stack
, uint32_t arg_count _U_
, df_cell_t
*retval
)
272 return df_func_base(stack
, arg_count
, retval
, BASE_HEX
);
276 df_func_dec(GSList
*stack
, uint32_t arg_count _U_
, df_cell_t
*retval
)
278 return df_func_base(stack
, arg_count
, retval
, BASE_DEC
);
282 // XXX - BASE_OCT isn't handled by fvalue_to_string_repr; it probably
283 // should at least for FTREPR_DISPLAY (the filter language doesn't
284 // support it due to possible notation confusion, I assume.)
285 // Add that first before offering it.
287 df_func_oct(GSList
*stack
, uint32_t arg_count _U_
, df_cell_t
*retval
)
289 return df_func_base(stack
, arg_count
, retval
, BASE_OCT
);
294 df_func_compare(GSList
*stack
, uint32_t arg_count
, df_cell_t
*retval
,
295 ft_bool_t (*fv_cmp
)(const fvalue_t
*a
, const fvalue_t
*b
))
297 fvalue_t
*fv_ret
= NULL
;
300 fvalue_t
*arg_fvalue
;
303 for (args
= stack
, i
= 0; i
< arg_count
; args
= args
->next
, i
++) {
306 for (unsigned j
= 0; j
< arg1
->len
; j
++) {
307 arg_fvalue
= arg1
->pdata
[j
];
308 if (fv_ret
== NULL
|| (fv_cmp(arg_fvalue
, fv_ret
) == FT_TRUE
)) {
318 df_cell_append(retval
, fvalue_dup(fv_ret
));
323 /* Find maximum value. */
325 df_func_max(GSList
*stack
, uint32_t arg_count
, df_cell_t
*retval
)
327 return df_func_compare(stack
, arg_count
, retval
, fvalue_gt
);
330 /* Find minimum value. */
332 df_func_min(GSList
*stack
, uint32_t arg_count
, df_cell_t
*retval
)
334 return df_func_compare(stack
, arg_count
, retval
, fvalue_lt
);
338 df_func_abs(GSList
*stack
, uint32_t arg_count _U_
, df_cell_t
*retval
)
341 fvalue_t
*fv_arg
, *new_fv
;
342 char *err_msg
= NULL
;
344 ws_assert(arg_count
== 1);
349 for (unsigned i
= 0; i
< arg1
->len
; i
++) {
350 fv_arg
= arg1
->pdata
[i
];
351 if (fvalue_is_negative(fv_arg
)) {
352 new_fv
= fvalue_unary_minus(fv_arg
, &err_msg
);
353 if (new_fv
== NULL
) {
354 ws_debug("abs: %s", err_msg
);
360 new_fv
= fvalue_dup(fv_arg
);
362 df_cell_append(retval
, new_fv
);
365 return !df_cell_is_empty(retval
);
369 df_semcheck_param(dfwork_t
*dfw
, const char *func_name _U_
, ftenum_t logical_ftype
,
370 stnode_t
*param
, df_loc_t func_loc _U_
)
372 ftenum_t ftype
= FT_NONE
;
374 resolve_unparsed(dfw
, param
, false);
376 switch (stnode_type_id(param
)) {
377 case STTYPE_ARITHMETIC
:
378 ftype
= check_arithmetic(dfw
, param
, logical_ftype
);
382 dfilter_fvalue_from_literal(dfw
, logical_ftype
, param
, false, NULL
);
383 ftype
= sttype_pointer_ftenum(param
);
387 dfilter_fvalue_from_string(dfw
, logical_ftype
, param
, NULL
);
388 ftype
= sttype_pointer_ftenum(param
);
391 case STTYPE_CHARCONST
:
392 dfilter_fvalue_from_charconst(dfw
, logical_ftype
, param
);
393 ftype
= sttype_pointer_ftenum(param
);
397 dfilter_fvalue_from_number(dfw
, logical_ftype
, param
);
398 ftype
= sttype_pointer_ftenum(param
);
401 case STTYPE_FUNCTION
:
402 ftype
= check_function(dfw
, param
, logical_ftype
);
408 case STTYPE_REFERENCE
:
409 ftype
= sttype_field_ftenum(param
);
413 ftype
= check_slice(dfw
, param
, logical_ftype
);
416 case STTYPE_UNPARSED
:
421 case STTYPE_UNINITIALIZED
:
422 case STTYPE_NUM_TYPES
:
423 ASSERT_STTYPE_NOT_REACHED(stnode_type_id(param
));
429 /* For upper() and lower() checks that the parameter passed to
430 * it is an FT_STRING */
432 ul_semcheck_is_string(dfwork_t
*dfw
, const char *func_name
, ftenum_t logical_ftype _U_
,
433 GSList
*param_list
, df_loc_t func_loc _U_
)
435 ws_assert(g_slist_length(param_list
) == 1);
436 stnode_t
*param
= param_list
->data
;
439 resolve_unparsed(dfw
, param
, true);
441 ftype
= df_semcheck_param(dfw
, func_name
, logical_ftype
, param
, func_loc
);
442 if (!FT_IS_STRING(ftype
)) {
443 dfunc_fail(dfw
, param
, "Only string type fields can be used as parameter for %s()", func_name
);
449 ul_semcheck_is_field(dfwork_t
*dfw
, const char *func_name
, ftenum_t logical_ftype _U_
,
450 GSList
*param_list
, df_loc_t func_loc _U_
)
452 ws_assert(g_slist_length(param_list
) == 1);
453 stnode_t
*param
= param_list
->data
;
455 resolve_unparsed(dfw
, param
, true);
457 if (stnode_type_id(param
) != STTYPE_FIELD
) {
458 dfunc_fail(dfw
, param
, "Only fields can be used as parameter for %s()", func_name
);
460 df_semcheck_param(dfw
, func_name
, logical_ftype
, param
, func_loc
);
465 ul_semcheck_can_length(dfwork_t
*dfw
, const char *func_name
, ftenum_t logical_ftype
,
466 GSList
*param_list
, df_loc_t func_loc
)
468 ws_assert(g_slist_length(param_list
) == 1);
469 stnode_t
*param
= param_list
->data
;
472 ftype
= df_semcheck_param(dfw
, func_name
, logical_ftype
, param
, func_loc
);
473 if (!ftype_can_length(ftype
)) {
474 dfunc_fail(dfw
, param
, "Argument does not support the %s() function", func_name
);
480 ul_semcheck_string(dfwork_t
*dfw
, const char *func_name
, ftenum_t logical_ftype _U_
,
481 GSList
*param_list
, df_loc_t func_loc _U_
)
483 header_field_info
*hfinfo
;
485 ws_assert(g_slist_length(param_list
) == 1);
486 stnode_t
*param
= param_list
->data
;
488 resolve_unparsed(dfw
, param
, true);
490 if (stnode_type_id(param
) == STTYPE_FIELD
) {
492 hfinfo
= sttype_field_hfinfo(param
);
493 switch (hfinfo
->type
) {
524 case FT_IEEE_11073_SFLOAT
:
525 case FT_IEEE_11073_FLOAT
:
530 dfunc_fail(dfw
, param
, "String conversion for field \"%s\" is not supported", hfinfo
->abbrev
);
532 dfunc_fail(dfw
, param
, "Only fields can be used as parameter for %s()", func_name
);
536 ul_semcheck_double(dfwork_t
*dfw
, const char *func_name
, ftenum_t logical_ftype
,
537 GSList
*param_list
, df_loc_t func_loc
)
539 ws_assert(g_slist_length(param_list
) == 1);
540 stnode_t
*param
= param_list
->data
;
543 ftype
= df_semcheck_param(dfw
, func_name
, logical_ftype
, param
, func_loc
);
544 if (!ftype_can_val_to_double(ftype
)) {
545 dfunc_fail(dfw
, param
, "Argument does not support the %s() function", func_name
);
551 ul_semcheck_base(dfwork_t
*dfw
, const char *func_name
, ftenum_t logical_ftype _U_
,
552 GSList
*param_list
, df_loc_t func_loc _U_
)
554 header_field_info
*hfinfo
;
556 ws_assert(g_slist_length(param_list
) == 1);
557 stnode_t
*param
= param_list
->data
;
559 resolve_unparsed(dfw
, param
, true);
561 if (stnode_type_id(param
) == STTYPE_FIELD
) {
563 hfinfo
= sttype_field_hfinfo(param
);
564 /* FT_CHAR also supports BASE_, but for what sort of escaped
565 * values to use for non-printable ASCII. BASE_HEX uses hex,
566 * all other bases will use octal.
567 * That's a little confusing, so don't support it for now.
568 * More useful might be to display all possible values as
569 * HEX or DEC, i.e. convert to a FT_UINT8 first. */
570 if (FT_IS_UINT(hfinfo
->type
)) {
573 dfunc_fail(dfw
, param
, "Base conversion for field \"%s\" is not supported", hfinfo
->abbrev
);
575 dfunc_fail(dfw
, param
, "Only fields can be used as parameter for %s()", func_name
);
579 ul_semcheck_value_string(dfwork_t
*dfw
, const char *func_name
, ftenum_t logical_ftype _U_
,
580 GSList
*param_list
, df_loc_t func_loc _U_
)
582 header_field_info
*hfinfo
;
584 ws_assert(g_slist_length(param_list
) == 1);
585 stnode_t
*param
= param_list
->data
;
587 resolve_unparsed(dfw
, param
, true);
589 if (stnode_type_id(param
) == STTYPE_FIELD
) {
591 hfinfo
= sttype_field_hfinfo(param
);
592 /* XXX - We should check all fields with the same abbreviation. */
593 if (hfinfo
->strings
!= NULL
&& hfinfo
->type
!= FT_FRAMENUM
&& hfinfo
->type
!= FT_PROTOCOL
) {
594 sttype_field_set_value_string(param
, true);
597 dfunc_fail(dfw
, param
, "Field \"%s\" does not have a value string.",
600 dfunc_fail(dfw
, param
, "Only fields can be used as parameter for %s()", func_name
);
603 /* Check arguments are all the same type and they can be compared. */
605 ul_semcheck_compare(dfwork_t
*dfw
, const char *func_name
, ftenum_t logical_ftype
,
606 GSList
*param_list
, df_loc_t func_loc
)
612 for (l
= param_list
; l
!= NULL
; l
= l
->next
) {
614 ftype
= df_semcheck_param(dfw
, func_name
, logical_ftype
, param
, func_loc
);
616 if (!compatible_ftypes(ftype
, logical_ftype
)) {
617 dfunc_fail(dfw
, param
, "Arguments to '%s' must be of compatible type (expected %s, got %s)",
618 func_name
, ftype_pretty_name(logical_ftype
), ftype_pretty_name(ftype
));
620 if (!ftype_can_cmp(ftype
)) {
621 dfunc_fail(dfw
, param
, "Argument '%s' to '%s' cannot be ordered",
622 stnode_todisplay(param
), func_name
);
626 return logical_ftype
;
630 ul_semcheck_absolute_value(dfwork_t
*dfw
, const char *func_name
, ftenum_t logical_ftype
,
631 GSList
*param_list
, df_loc_t func_loc
)
633 ws_assert(g_slist_length(param_list
) == 1);
634 stnode_t
*param
= param_list
->data
;
637 ftype
= df_semcheck_param(dfw
, func_name
, logical_ftype
, param
, func_loc
);
638 if (!ftype_can_is_negative(ftype
) || !ftype_can_unary_minus(ftype
)) {
639 dfunc_fail(dfw
, param
, "Argument cannot be negated");
644 /* The table of all display-filter functions */
647 { "lower", df_func_lower
, 1, 1, FT_STRING
, ul_semcheck_is_string
},
648 { "upper", df_func_upper
, 1, 1, FT_STRING
, ul_semcheck_is_string
},
649 /* Length function is implemented as a DFVM instruction. */
650 { "len", NULL
, 1, 1, FT_UINT32
, ul_semcheck_can_length
},
651 { "count", df_func_count
, 1, 1, FT_UINT32
, ul_semcheck_is_field
},
652 { "string", df_func_string
, 1, 1, FT_STRING
, ul_semcheck_string
},
653 { "float", df_func_float
, 1, 1, FT_FLOAT
, ul_semcheck_double
},
654 { "double", df_func_double
, 1, 1, FT_DOUBLE
, ul_semcheck_double
},
655 { "dec", df_func_dec
, 1, 1, FT_STRING
, ul_semcheck_base
},
656 { "hex", df_func_hex
, 1, 1, FT_STRING
, ul_semcheck_base
},
657 //{ "oct", df_func_oct, 1, 1, FT_STRING, ul_semcheck_base },
658 /* VALUE STRING function is implemented as a DFVM instruction. */
659 { "vals", NULL
, 1, 1, FT_STRING
, ul_semcheck_value_string
},
660 { "max", df_func_max
, 1, 0, FT_NONE
, ul_semcheck_compare
},
661 { "min", df_func_min
, 1, 0, FT_NONE
, ul_semcheck_compare
},
662 { "abs", df_func_abs
, 1, 1, FT_NONE
, ul_semcheck_absolute_value
},
663 { NULL
, NULL
, 0, 0, FT_NONE
, NULL
}
666 /* Returns NULL for success. */
668 check_valid_func_name(const char *name
)
670 if (!g_ascii_isalpha(name
[0]) && name
[0] != '_') {
671 return "first character must be a letter or underscore";
673 for (int i
= 1; name
[i
] != '\0'; i
++) {
674 if (!g_ascii_isalnum(name
[0]) && name
[0] != '_') {
675 return "function names must be alphanumeric plus underscore";
686 registered_functions
= g_hash_table_new(g_str_hash
, g_str_equal
);
687 registered_names
= g_ptr_array_new();
689 /* Register built-in functions. */
690 for (func
= df_functions
; func
->name
!= NULL
; func
++) {
691 df_func_register(func
);
696 df_func_register(df_func_def_t
*func
)
698 ws_assert(registered_functions
);
699 ws_assert(registered_names
);
701 if ((err
= check_valid_func_name(func
->name
)) != NULL
) {
702 ws_critical("Function name \"%s\" is invalid: %s",
706 if (g_hash_table_contains(registered_functions
, func
->name
)) {
707 ws_critical("Trying to register display filter function \"%s\" but "
708 "it already exists", func
->name
);
712 g_ptr_array_add(registered_names
, (gpointer
)func
->name
);
713 return g_hash_table_insert(registered_functions
, (gpointer
)func
->name
, func
);
717 df_func_deregister(df_func_def_t
*func
)
719 ws_assert(registered_functions
);
720 df_func_def_t
*value
;
722 value
= g_hash_table_lookup(registered_functions
, func
->name
);
724 ws_critical("Trying to deregister display filter function name \"%s\" but "
725 "it doesn't match the existing function", func
->name
);
729 g_ptr_array_remove_fast(registered_names
, (void *)func
->name
);
730 return g_hash_table_remove(registered_functions
, func
->name
);
733 /* Lookup a display filter function record by name */
735 df_func_lookup(const char *name
)
737 return g_hash_table_lookup(registered_functions
, name
);
741 df_func_name_list(void)
743 return g_ptr_array_ref(registered_names
);
747 df_func_cleanup(void)
749 g_hash_table_destroy(registered_functions
);
750 registered_functions
= NULL
;
751 g_ptr_array_unref(registered_names
);
752 registered_names
= NULL
;
756 * Editor modelines - https://www.wireshark.org/tools/modelines.html
761 * indent-tabs-mode: nil
764 * vi: set shiftwidth=4 tabstop=8 expandtab:
765 * :indentSize=4:tabSize=8:noTabs=true: