dfilter: Add layer support for references

This adds support for using the layers filter
with field references.

Before:
    $ dftest 'ip.src != ${ip.src#2}'
    dftest: invalid character in macro name

After:
    $ dftest 'ip.src != ${ip.src#2}'
    Filter: ip.src != ${ip.src#2}

    Syntax tree:
     0 TEST_ALL_NE:
       1 FIELD(ip.src <FT_IPv4>)
       1 REFERENCE(ip.src#[2:1] <FT_IPv4>)

    Instructions:
    00000 READ_TREE		ip.src <FT_IPv4> -> reg#0
    00001 IF_FALSE_GOTO	5
    00002 READ_REFERENCE_R	${ip.src <FT_IPv4>} #[2:1] -> reg#1
    00003 IF_FALSE_GOTO	5
    00004 ALL_NE		reg#0 != reg#1
    00005 RETURN

This requires adding another level of complexity to references.
When loading references we need to copy the 'proto_layer_num'
and add the logic to filter on that.

The "layer" sttype is removed and replace by a new
field sttype with support for a range. This is a nice
cleanup for the semantic check and general simplification.
The grammar is better too with this design.

Range sttype is renamed to slice for clarity.
This commit is contained in:
João Valverde 2022-06-24 00:07:42 +01:00
parent e9e6431d7b
commit aaff0d21ae
24 changed files with 758 additions and 514 deletions

View File

@ -96,7 +96,8 @@ They previously shipped with Qt 5.12.2.
For example the expression "all tcp.port > 1024" is true if and only if all tcp.port fields match the condition.
Previously only the default behaviour to return true if any one field matches was supported.
** Field references, of the form ${some.field}, are now part of the syntax of display filters. Previously they were implemented as macros.
The new implementation is more efficient and allows matching multiple values, like any other protocol field.
The new implementation is more efficient and has the same properties as protocol fields, like matching on multiple values
using quantifiers and support for layer filtering.
** Arithmetic is supported for numeric fields with the usual operators “+”, “-”, “*”, “/”, and “%”.
Arithmetic expressions must be grouped using curly brackets (not parenthesis).
** New display filter functions max(), min() and abs() have been added.

View File

@ -22,10 +22,11 @@ set(DFILTER_HEADER_FILES
drange.h
gencode.h
semcheck.h
sttype-field.h
sttype-function.h
sttype-pointer.h
sttype-range.h
sttype-set.h
sttype-slice.h
sttype-test.h
syntax-tree.h
)
@ -38,10 +39,11 @@ set(DFILTER_NONGENERATED_FILES
drange.c
gencode.c
semcheck.c
sttype-field.c
sttype-function.c
sttype-pointer.c
sttype-range.c
sttype-set.c
sttype-slice.c
sttype-string.c
sttype-test.c
syntax-tree.c

View File

@ -16,6 +16,12 @@
#include <epan/proto.h>
#include <stdio.h>
typedef struct {
const header_field_info *hfinfo;
fvalue_t *value;
int proto_layer_num;
} df_reference_t;
/* Passed back to user */
struct epan_dfilter {
GPtrArray *insns;
@ -44,7 +50,7 @@ typedef struct {
int next_insn_id;
int next_register;
GPtrArray *deprecated;
GHashTable *references; /* hfinfo -> pointer to GSList of fvalues */
GHashTable *references; /* hfinfo -> pointer to array of references */
GHashTable *loaded_references;
char *expanded_text;
stloc_t err_loc;
@ -119,4 +125,10 @@ dfilter_fvalue_from_charconst(dfwork_t *dfw, ftenum_t ftype, stnode_t *st);
const char *tokenstr(int token);
df_reference_t *
reference_new(const field_info *finfo);
void
reference_free(df_reference_t *ref);
#endif

View File

@ -101,7 +101,9 @@ static gboolean start_is_field_reference(const char *start)
char saved_c;
const header_field_info *hfinfo;
end = strchr(start, '}');
end = strchr(start, '#');
if (end == NULL)
end = strchr(start, '}');
if (end == NULL)
return FALSE;

View File

@ -238,13 +238,10 @@ dfilter_free(dfilter_t *df)
g_free(df);
}
static void free_reference(gpointer data)
static void free_refs_array(gpointer data)
{
/* List data must be freed. */
GSList **fvalues_ptr = data;
if (*fvalues_ptr)
g_slist_free_full(*fvalues_ptr, (GDestroyNotify)fvalue_free);
g_free(fvalues_ptr);
/* Array data must be freed. */
(void)g_ptr_array_free(data, TRUE);
}
@ -255,7 +252,7 @@ dfwork_new(void)
dfw->references =
g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, free_reference);
NULL, (GDestroyNotify)free_refs_array);
dfw->loaded_references =
g_hash_table_new_full(g_direct_hash, g_direct_equal,
@ -340,7 +337,7 @@ const char *tokenstr(int token)
case TOKEN_DOTDOT: return "DOTDOT";
case TOKEN_LPAREN: return "LPAREN";
case TOKEN_RPAREN: return "RPAREN";
case TOKEN_REFERENCE: return "REFERENCE";
case TOKEN_DOLLAR: return "DOLLAR";
}
return "<unknown>";
}
@ -675,6 +672,14 @@ dfilter_log_full(const char *domain, enum ws_log_level level,
g_free(str);
}
static int
compare_ref_layer(gconstpointer _a, gconstpointer _b)
{
const df_reference_t *a = *(const df_reference_t **)_a;
const df_reference_t *b = *(const df_reference_t **)_b;
return a->proto_layer_num - b->proto_layer_num;
}
void
dfilter_load_field_references(const dfilter_t *df, proto_tree *tree)
{
@ -682,7 +687,7 @@ dfilter_load_field_references(const dfilter_t *df, proto_tree *tree)
GPtrArray *finfos;
field_info *finfo;
header_field_info *hfinfo;
GSList **fvalues_ptr;
GPtrArray *refs;
int i, len;
if (g_hash_table_size(df->references) == 0) {
@ -691,10 +696,9 @@ dfilter_load_field_references(const dfilter_t *df, proto_tree *tree)
}
g_hash_table_iter_init( &iter, df->references);
while (g_hash_table_iter_next (&iter, (void **)&hfinfo, (void **)&fvalues_ptr)) {
/* If we have a previous list free it and the data too */
g_slist_free_full(*fvalues_ptr, (GDestroyNotify)fvalue_free);
*fvalues_ptr = NULL;
while (g_hash_table_iter_next (&iter, (void **)&hfinfo, (void **)&refs)) {
/* If we have a previous array free the data */
g_ptr_array_set_size(refs, 0);
while (hfinfo) {
finfos = proto_find_finfo(tree, hfinfo->id);
@ -706,15 +710,33 @@ dfilter_load_field_references(const dfilter_t *df, proto_tree *tree)
len = finfos->len;
for (i = 0; i < len; i++) {
finfo = g_ptr_array_index(finfos, i);
*fvalues_ptr = g_slist_prepend(*fvalues_ptr,
fvalue_dup(&finfo->value));
g_ptr_array_add(refs, reference_new(finfo));
}
hfinfo = hfinfo->same_name_next;
}
g_ptr_array_sort(refs, compare_ref_layer);
}
}
df_reference_t *
reference_new(const field_info *finfo)
{
df_reference_t *ref = g_new(df_reference_t, 1);
ref->hfinfo = finfo->hfinfo;
ref->value = fvalue_dup(&finfo->value);
ref->proto_layer_num = finfo->proto_layer_num;
return ref;
}
void
reference_free(df_reference_t *ref)
{
fvalue_free(ref->value);
g_free(ref);
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*

View File

@ -12,7 +12,7 @@
#include "dfilter-int.h"
#include "dfunctions.h"
#include "sttype-pointer.h"
#include "sttype-field.h"
#include "semcheck.h"
#include <string.h>
@ -277,7 +277,7 @@ ul_semcheck_is_field_string(dfwork_t *dfw, const char *func_name, ftenum_t lhs_f
dfw_resolve_unparsed(dfw, st_node);
if (stnode_type_id(st_node) == STTYPE_FIELD) {
hfinfo = stnode_data(st_node);
hfinfo = sttype_field_hfinfo(st_node);
if (IS_FT_STRING(hfinfo->type)) {
return FT_STRING;
}
@ -312,7 +312,7 @@ ul_semcheck_string_param(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftyp
dfw_resolve_unparsed(dfw, st_node);
if (stnode_type_id(st_node) == STTYPE_FIELD) {
hfinfo = stnode_data(st_node);
hfinfo = sttype_field_hfinfo(st_node);
switch (hfinfo->type) {
case FT_UINT8:
case FT_UINT16:
@ -380,7 +380,7 @@ ul_semcheck_compare(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype,
ftype = check_function(dfw, arg, lhs_ftype);
}
else {
ftype = sttype_pointer_ftenum(arg);
ftype = sttype_field_ftenum(arg);
}
if (ftype == FT_NONE) {
@ -404,7 +404,7 @@ ul_semcheck_compare(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ftype,
ft_arg = check_function(dfw, arg, ftype);
}
else {
ft_arg = sttype_pointer_ftenum(arg);
ft_arg = sttype_field_ftenum(arg);
}
if (ft_arg == FT_NONE) {
@ -450,7 +450,7 @@ ul_semcheck_absolute_value(dfwork_t *dfw, const char *func_name, ftenum_t lhs_ft
ftype = check_function(dfw, st_node, lhs_ftype);
}
else {
ftype = sttype_pointer_ftenum(st_node);
ftype = sttype_field_ftenum(st_node);
}
if (ftype == FT_NONE) {

View File

@ -30,6 +30,7 @@ dfvm_opcode_tostr(dfvm_opcode_t code)
case READ_TREE: return "READ_TREE";
case READ_TREE_R: return "READ_TREE_R";
case READ_REFERENCE: return "READ_REFERENCE";
case READ_REFERENCE_R: return "READ_REFERENCE_R";
case PUT_FVALUE: return "PUT_FVALUE";
case ALL_EQ: return "ALL_EQ";
case ANY_EQ: return "ANY_EQ";
@ -299,7 +300,7 @@ dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, gboolean print_references)
break;
case CHECK_EXISTS_R:
wmem_strbuf_append_printf(buf, "%05d CHECK_EXISTS\t%s#[%s]\n",
wmem_strbuf_append_printf(buf, "%05d CHECK_EXISTS_R\t%s #[%s]\n",
id, arg1_str, arg2_str);
break;
@ -309,7 +310,7 @@ dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, gboolean print_references)
break;
case READ_TREE_R:
wmem_strbuf_append_printf(buf, "%05d READ_TREE\t\t%s#[%s] -> %s\n",
wmem_strbuf_append_printf(buf, "%05d READ_TREE_R\t%s #[%s] -> %s\n",
id, arg1_str, arg3_str, arg2_str);
break;
@ -318,6 +319,11 @@ dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, gboolean print_references)
id, arg1_str, arg2_str);
break;
case READ_REFERENCE_R:
wmem_strbuf_append_printf(buf, "%05d READ_REFERENCE_R\t${%s} #[%s] -> %s\n",
id, arg1_str, arg3_str, arg2_str);
break;
case PUT_FVALUE:
wmem_strbuf_append_printf(buf, "%05d PUT_FVALUE\t%s -> %s\n",
id, arg1_str, arg2_str);
@ -485,20 +491,18 @@ dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, gboolean print_references)
g_hash_table_iter_init(&ref_iter, df->references);
while (g_hash_table_iter_next(&ref_iter, &key, &value)) {
const char *abbrev = ((header_field_info *)key)->abbrev;
GSList *fvalues = *(GSList **)value;
GPtrArray *refs_array = value;
df_reference_t *ref;
wmem_strbuf_append_printf(buf, "${%s} = {", abbrev);
if (fvalues != NULL) {
str = fvalue_to_debug_repr(NULL, fvalues->data);
wmem_strbuf_append_printf(buf, "%s <%s>", str, fvalue_type_name(fvalues->data));
g_free(str);
for (fvalues = fvalues->next; fvalues != NULL; fvalues = fvalues->next) {
str = fvalue_to_debug_repr(NULL, fvalues->data);
wmem_strbuf_append_printf(buf, ", %s <%s>", str, fvalue_type_name(fvalues->data));
g_free(str);
for (i = 0; i < refs_array->len; i++) {
if (i != 0) {
wmem_strbuf_append(buf, ", ");
}
ref = refs_array->pdata[i];
str = fvalue_to_debug_repr(NULL, ref->value);
wmem_strbuf_append_printf(buf, "%s <%s>", str, fvalue_type_name(ref->value));
g_free(str);
}
wmem_strbuf_append(buf, "}\n");
}
@ -653,14 +657,58 @@ read_tree(dfilter_t *df, proto_tree *tree,
return TRUE;
}
static gboolean
read_reference(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *arg2)
GSList *
filter_refs_fvalues(GPtrArray *refs_array, drange_t *range)
{
GSList **fvalues_ptr;
int length; /* maximum proto layer number. The numbers are sequential. */
df_reference_t *last_ref, *ref;
int cookie = -1;
gboolean cookie_matches = false;
int layer;
GSList *fvalues = NULL;
/* refs array is sorted. */
last_ref = refs_array->pdata[refs_array->len - 1];
length = last_ref->proto_layer_num;
for (guint i = 0; i < refs_array->len; i++) {
if (range == NULL) {
fvalues = g_slist_prepend(fvalues, fvalue_dup(ref->value));
continue;
}
ref = refs_array->pdata[i];
layer = ref->proto_layer_num;
if (cookie == layer) {
if (cookie_matches) {
fvalues = g_slist_prepend(fvalues, fvalue_dup(ref->value));
}
}
else {
cookie = layer;
cookie_matches = drange_contains_layer(range, layer, length);
if (cookie_matches) {
fvalues = g_slist_prepend(fvalues, fvalue_dup(ref->value));
}
}
}
return fvalues;
}
static gboolean
read_reference(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *arg2,
dfvm_value_t *arg3)
{
GPtrArray *refs;
drange_t *range = NULL;
header_field_info *hfinfo = arg1->value.hfinfo;
int reg = arg2->value.numeric;
if (arg3) {
range = arg3->value.drange;
}
/* Already loaded in this run of the dfilter? */
if (df->attempted_load[reg]) {
if (df->registers[reg]) {
@ -673,16 +721,16 @@ read_reference(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *arg2)
df->attempted_load[reg] = TRUE;
fvalues_ptr = g_hash_table_lookup(df->references, hfinfo);
if (*fvalues_ptr == NULL) {
refs = g_hash_table_lookup(df->references, hfinfo);
if (refs == NULL || refs->len == 0) {
df->registers[reg] = NULL;
return FALSE;
}
/* Shallow copy */
df->registers[reg] = g_slist_copy(*fvalues_ptr);
/* These values are referenced only, do not try to free it later. */
df->free_registers[reg] = NULL;
df->registers[reg] = filter_refs_fvalues(refs, range);
/* Creates new value so own it. */
df->free_registers[reg] = (GDestroyNotify)fvalue_free;
return TRUE;
}
@ -1011,9 +1059,11 @@ debug_register(GSList *reg, guint32 num)
wmem_strbuf_append_printf(buf, "Reg#%"G_GUINT32_FORMAT" = { ", num);
for (l = reg; l != NULL; l = l->next) {
s = fvalue_to_debug_repr(NULL, l->data);
wmem_strbuf_append(buf, s);
wmem_strbuf_append_printf(buf, "%s <%s>", s, fvalue_type_name(l->data));
g_free(s);
wmem_strbuf_append_c(buf, ' ');
if (l->next != NULL) {
wmem_strbuf_append(buf, ", ");
}
}
wmem_strbuf_append_c(buf, '}');
WS_DEBUG_HERE("%s", wmem_strbuf_get_str(buf));
@ -1257,7 +1307,11 @@ dfvm_apply(dfilter_t *df, proto_tree *tree)
break;
case READ_REFERENCE:
accum = read_reference(df, arg1, arg2);
accum = read_reference(df, arg1, arg2, NULL);
break;
case READ_REFERENCE_R:
accum = read_reference(df, arg1, arg2, arg3);
break;
case PUT_FVALUE:

View File

@ -56,6 +56,7 @@ typedef enum {
READ_TREE,
READ_TREE_R,
READ_REFERENCE,
READ_REFERENCE_R,
PUT_FVALUE,
ALL_EQ,
ANY_EQ,

View File

@ -243,7 +243,7 @@ drange_node_set_to_the_end(drange_node* drnode)
/* drange constructor */
drange_t *
drange_new(void)
drange_new(drange_node* drnode)
{
drange_t * new_drange;
new_drange = g_new(drange_t,1);
@ -252,6 +252,10 @@ drange_new(void)
new_drange->total_length = 0;
new_drange->min_start_offset = G_MAXINT;
new_drange->max_start_offset = G_MININT;
if (drnode)
drange_append_drange_node(new_drange, drnode);
return new_drange;
}
@ -269,7 +273,7 @@ drange_new_from_list(GSList *list)
{
drange_t *new_drange;
new_drange = drange_new();
new_drange = drange_new(NULL);
g_slist_foreach(list, drange_append_wrapper, new_drange);
return new_drange;
}
@ -283,7 +287,7 @@ drange_dup(drange_t *org)
if (!org)
return NULL;
new_drange = drange_new();
new_drange = drange_new(NULL);
for (p = org->range_list; p; p = p->next) {
drange_node *drnode = (drange_node *)p->data;
drange_append_drange_node(new_drange, drange_node_dup(drnode));

View File

@ -70,7 +70,7 @@ void drange_node_set_end_offset(drange_node* drnode, gint offset);
void drange_node_set_to_the_end(drange_node* drnode);
/* drange constructor */
drange_t * drange_new(void);
drange_t * drange_new(drange_node* drnode);
drange_t * drange_new_from_list(GSList *list);
drange_t * drange_dup(drange_t *org);

View File

@ -12,7 +12,8 @@
#include "gencode.h"
#include "dfvm.h"
#include "syntax-tree.h"
#include "sttype-range.h"
#include "sttype-field.h"
#include "sttype-slice.h"
#include "sttype-test.h"
#include "sttype-set.h"
#include "sttype-function.h"
@ -66,6 +67,7 @@ select_opcode(dfvm_opcode_t op, test_match_t how)
case READ_TREE:
case READ_TREE_R:
case READ_REFERENCE:
case READ_REFERENCE_R:
case PUT_FVALUE:
case MK_SLICE:
case MK_BITWISE_AND:
@ -187,9 +189,7 @@ dfw_append_read_tree(dfwork_t *dfw, header_field_info *hfinfo,
if (added_new_hfinfo) {
while (hfinfo) {
/* Record the FIELD_ID in hash of interesting fields. */
g_hash_table_insert(dfw->interesting_fields,
GINT_TO_POINTER(hfinfo->id),
GUINT_TO_POINTER(TRUE));
g_hash_table_add(dfw->interesting_fields, &hfinfo->id);
hfinfo = hfinfo->same_name_next;
}
}
@ -199,46 +199,43 @@ dfw_append_read_tree(dfwork_t *dfw, header_field_info *hfinfo,
/* returns register number */
static dfvm_value_t *
dfw_append_read_reference(dfwork_t *dfw, header_field_info *hfinfo)
dfw_append_read_reference(dfwork_t *dfw, header_field_info *hfinfo,
drange_t *range)
{
dfvm_insn_t *insn;
dfvm_value_t *reg_val, *val1;
GSList **fvalues_ptr;
gboolean added_new_hfinfo = FALSE;
dfvm_value_t *reg_val, *val1, *val3;
GPtrArray *refs_array;
/* Rewind to find the first field of this name. */
while (hfinfo->same_name_prev_id != -1) {
hfinfo = proto_registrar_get_nth(hfinfo->same_name_prev_id);
}
/* Keep track of which registers
* were used for which hfinfo's so that we
* can re-use registers. */
reg_val = g_hash_table_lookup(dfw->loaded_references, hfinfo);
if (!reg_val) {
reg_val = dfvm_value_new_register(dfw->next_register++);
g_hash_table_insert(dfw->loaded_references, hfinfo, dfvm_value_ref(reg_val));
added_new_hfinfo = TRUE;
}
insn = dfvm_insn_new(READ_REFERENCE);
/* We can't reuse registers with a filter so just skip
* that optimization and don't reuse them at all. */
val1 = dfvm_value_new_hfinfo(hfinfo);
reg_val = dfvm_value_new_register(dfw->next_register++);
if (range) {
val3 = dfvm_value_new_drange(range);
insn = dfvm_insn_new(READ_REFERENCE_R);
}
else {
val3 = NULL;
insn = dfvm_insn_new(READ_REFERENCE);
}
insn->arg1 = dfvm_value_ref(val1);
insn->arg2 = dfvm_value_ref(reg_val);
insn->arg3 = dfvm_value_ref(val3);
dfw_append_insn(dfw, insn);
fvalues_ptr = g_new(GSList *, 1);
*fvalues_ptr = NULL;
g_hash_table_insert(dfw->references, hfinfo, fvalues_ptr);
refs_array = g_ptr_array_new_with_free_func((GDestroyNotify)reference_free);
g_hash_table_insert(dfw->references, hfinfo, refs_array);
if (added_new_hfinfo) {
while (hfinfo) {
/* Record the FIELD_ID in hash of interesting fields. */
g_hash_table_insert(dfw->interesting_fields,
GINT_TO_POINTER(hfinfo->id),
GUINT_TO_POINTER(TRUE));
hfinfo = hfinfo->same_name_next;
}
/* Record the FIELD_ID in hash of interesting fields. */
while (hfinfo) {
/* Record the FIELD_ID in hash of interesting fields. */
g_hash_table_add(dfw->interesting_fields, &hfinfo->id);
hfinfo = hfinfo->same_name_next;
}
return reg_val;
@ -252,16 +249,16 @@ dfw_append_mk_slice(dfwork_t *dfw, stnode_t *node, GSList **jumps_ptr)
dfvm_insn_t *insn;
dfvm_value_t *reg_val, *val1, *val3;
entity = sttype_range_entity(node);
entity = sttype_slice_entity(node);
insn = dfvm_insn_new(MK_SLICE);
val1 = gen_entity(dfw, entity, jumps_ptr);
insn->arg1 = dfvm_value_ref(val1);
reg_val = dfvm_value_new_register(dfw->next_register++);
insn->arg2 = dfvm_value_ref(reg_val);
val3 = dfvm_value_new_drange(sttype_range_drange_steal(node));
val3 = dfvm_value_new_drange(sttype_slice_drange_steal(node));
insn->arg3 = dfvm_value_ref(val3);
sttype_range_remove_drange(node);
sttype_slice_remove_drange(node);
dfw_append_insn(dfw, insn);
return reg_val;
@ -510,22 +507,19 @@ gen_entity(dfwork_t *dfw, stnode_t *st_arg, GSList **jumps_ptr)
sttype_id_t e_type;
dfvm_value_t *val;
header_field_info *hfinfo;
drange_t *range = NULL;
e_type = stnode_type_id(st_arg);
if (e_type == STTYPE_FIELD) {
hfinfo = stnode_data(st_arg);
val = dfw_append_read_tree(dfw, hfinfo, NULL);
hfinfo = sttype_field_hfinfo(st_arg);
range = sttype_field_drange_steal(st_arg);
val = dfw_append_read_tree(dfw, hfinfo, range);
*jumps_ptr = g_slist_prepend(*jumps_ptr, dfw_append_jump(dfw));
}
else if (e_type == STTYPE_REFERENCE) {
hfinfo = stnode_data(st_arg);
val = dfw_append_read_reference(dfw, hfinfo);
*jumps_ptr = g_slist_prepend(*jumps_ptr, dfw_append_jump(dfw));
}
else if (e_type == STTYPE_LAYER) {
stnode_t *entity = sttype_range_entity(st_arg);
drange_t *range = sttype_range_drange_steal(st_arg);
val = dfw_append_read_tree(dfw, stnode_data(entity), range);
hfinfo = sttype_field_hfinfo(st_arg);
range = sttype_field_drange_steal(st_arg);
val = dfw_append_read_reference(dfw, hfinfo, range);
*jumps_ptr = g_slist_prepend(*jumps_ptr, dfw_append_jump(dfw));
}
else if (e_type == STTYPE_FVALUE) {
@ -556,18 +550,10 @@ gen_exists(dfwork_t *dfw, stnode_t *st_node)
dfvm_insn_t *insn;
dfvm_value_t *val1, *val2 = NULL;
header_field_info *hfinfo;
stnode_t *st_arg;
drange_t *range;
drange_t *range = NULL;
if (stnode_type_id(st_node) == STTYPE_LAYER) {
st_arg = sttype_range_entity(st_node);
range = sttype_range_drange_steal(st_node);
}
else {
st_arg = st_node;
range = NULL;
}
hfinfo = stnode_data(st_arg);
hfinfo = sttype_field_hfinfo(st_node);
range = sttype_field_drange_steal(st_node);
/* Rewind to find the first field of this name. */
while (hfinfo->same_name_prev_id != -1) {
@ -592,9 +578,7 @@ gen_exists(dfwork_t *dfw, stnode_t *st_node)
/* Record the FIELD_ID in hash of interesting fields. */
while (hfinfo) {
g_hash_table_insert(dfw->interesting_fields,
GINT_TO_POINTER(hfinfo->id),
GUINT_TO_POINTER(TRUE));
g_hash_table_add(dfw->interesting_fields, &hfinfo->id);
hfinfo = hfinfo->same_name_next;
}
}
@ -728,7 +712,6 @@ gencode(dfwork_t *dfw, stnode_t *st_node)
gen_test(dfw, st_node);
break;
case STTYPE_FIELD:
case STTYPE_LAYER:
gen_exists(dfw, st_node);
break;
case STTYPE_ARITHMETIC:
@ -791,7 +774,7 @@ dfw_gencode(dfwork_t *dfw)
{
dfw->insns = g_ptr_array_new();
dfw->loaded_fields = g_hash_table_new(g_direct_hash, g_direct_equal);
dfw->interesting_fields = g_hash_table_new(g_direct_hash, g_direct_equal);
dfw->interesting_fields = g_hash_table_new(g_int_hash, g_int_equal);
gencode(dfw, dfw->st_root);
dfw_append_insn(dfw, dfvm_insn_new(RETURN));
optimize(dfw);
@ -806,7 +789,7 @@ typedef struct {
static void
get_hash_key(gpointer key, gpointer value _U_, gpointer user_data)
{
int field_id = GPOINTER_TO_INT(key);
int field_id = *(int *)key;
hash_key_iterator *hki = (hash_key_iterator *)user_data;
hki->fields[hki->i] = field_id;

View File

@ -6,7 +6,8 @@
#include "dfilter-int.h"
#include "syntax-tree.h"
#include "sttype-range.h"
#include "sttype-field.h"
#include "sttype-slice.h"
#include "sttype-test.h"
#include "sttype-function.h"
#include "sttype-set.h"
@ -44,6 +45,9 @@ new_function(dfwork_t *dfw, stnode_t *node);
%type range_node_list {GSList*}
%destructor range_node_list {drange_node_free_list($$);}
%type layer {GSList*}
%destructor layer {drange_node_free_list($$);}
%type function_params {GSList*}
%destructor function_params {st_funcparams_free($$);}
@ -118,31 +122,71 @@ atom(A) ::= STRING(S). { A = S; }
atom(A) ::= CHARCONST(N). { A = N; }
atom(A) ::= UNPARSED(S). { A = S; }
atom(A) ::= LITERAL(S). { A = S; }
atom(A) ::= FIELD(F). { A = F; }
atom(A) ::= REFERENCE(F). { A = F; }
layer(R) ::= atom(F) HASH LBRACKET range_node_list(L) RBRACKET.
layer(R) ::= HASH LBRACKET range_node_list(L) RBRACKET.
{
R = stnode_new(STTYPE_LAYER, NULL, NULL, NULL);
sttype_range_set(R, F, L);
g_slist_free(L);
R = L;
}
layer(R) ::= atom(F) HASH INTEGER(N).
layer(R) ::= HASH INTEGER(N).
{
R = stnode_new(STTYPE_LAYER, NULL, NULL, stnode_location(F));
char *err_msg = sttype_range_set_number(R, F, stnode_token(N));
char *err_msg = NULL;
drange_node *range = drange_node_from_str(stnode_token(N), &err_msg);
if (err_msg != NULL) {
FAIL(dfw, N, "%s", err_msg);
g_free(err_msg);
}
stnode_free(N);
R = g_slist_append(NULL, range);
}
field(R) ::= FIELD(F).
{
R = F;
}
field(R) ::= FIELD(F) layer(L).
{
R = F;
sttype_field_set_range(R, L);
g_slist_free(L);
}
field(R) ::= UNPARSED(U) layer(L).
{
header_field_info *hfinfo = dfilter_resolve_unparsed(dfw, stnode_data(U));
if (hfinfo == NULL) {
FAIL(dfw, U, "%s is not a valid field", stnode_token(U));
}
R = stnode_new(STTYPE_FIELD, hfinfo, NULL, stnode_location(U));
stnode_free(U);
sttype_field_set_range(R, L);
g_slist_free(L);
}
reference(R) ::= DOLLAR LBRACE field(F) RBRACE.
{
/* convert field to reference */
R = stnode_new(STTYPE_REFERENCE, sttype_field_hfinfo(F), NULL, stnode_location(F));
sttype_field_set_drange(R, sttype_field_drange_steal(F));
stnode_free(F);
}
reference(R) ::= DOLLAR LBRACE UNPARSED(U) RBRACE.
{
header_field_info *hfinfo = dfilter_resolve_unparsed(dfw, stnode_data(U));
if (hfinfo == NULL) {
FAIL(dfw, U, "%s is not a valid field", stnode_token(U));
}
R = stnode_new(STTYPE_REFERENCE, hfinfo, NULL, stnode_location(U));
stnode_free(U);
}
entity(E) ::= atom(A). { E = A; }
entity(E) ::= slice(R). { E = R; }
entity(E) ::= function(F). { E = F; }
entity(E) ::= layer(L). { E = L; }
entity(E) ::= field(F). { E = F; }
entity(E) ::= reference(R). { E = R; }
arithmetic_expr(T) ::= entity(N).
{
@ -327,7 +371,7 @@ set_element(N) ::= set_entity(X) DOTDOT set_entity(Y).
slice(R) ::= entity(E) LBRACKET range_node_list(L) RBRACKET.
{
R = stnode_new(STTYPE_SLICE, NULL, NULL, NULL);
sttype_range_set(R, E, L);
sttype_slice_set(R, E, L);
/* Delete the list, but not the drange_nodes that
* the list contains. */

View File

@ -154,6 +154,7 @@ hyphen-bytes {hex2}(-{hex2})+
"{" return simple(TOKEN_LBRACE);
".." return simple(TOKEN_DOTDOT);
"}" return simple(TOKEN_RBRACE);
"$" return simple(TOKEN_DOLLAR);
"any" return simple(TOKEN_ANY);
"all" return simple(TOKEN_ALL);
@ -467,12 +468,6 @@ hyphen-bytes {hex2}(-{hex2})+
return set_lval_str(yyextra, TOKEN_UNPARSED, yytext);
}
"${"{Identifier}"}" {
char *end = strchr(yytext, '}');
*end = '\0';
return set_lval_field(yyextra, TOKEN_REFERENCE, yytext + 2);
}
. {
/* Default */
update_location(yyextra, yytext);
@ -575,9 +570,6 @@ set_lval_field(df_scanner_state_t *state, int token, const char *token_value)
case TOKEN_FIELD:
type_id = STTYPE_FIELD;
break;
case TOKEN_REFERENCE:
type_id = STTYPE_REFERENCE;
break;
default:
ws_assert_not_reached();
}

View File

@ -15,7 +15,8 @@
#include "dfilter-int.h"
#include "semcheck.h"
#include "syntax-tree.h"
#include "sttype-range.h"
#include "sttype-field.h"
#include "sttype-slice.h"
#include "sttype-test.h"
#include "sttype-set.h"
#include "sttype-function.h"
@ -507,7 +508,6 @@ check_exists(dfwork_t *dfw, stnode_t *st_arg1)
switch (stnode_type_id(st_arg1)) {
case STTYPE_FIELD:
case STTYPE_ARITHMETIC:
case STTYPE_LAYER:
/* This is OK */
break;
case STTYPE_REFERENCE:
@ -546,17 +546,6 @@ check_exists(dfwork_t *dfw, stnode_t *st_arg1)
}
}
static void
check_exists_layer(dfwork_t *dfw, stnode_t *st_arg1)
{
stnode_t *entity;
entity = sttype_range_entity(st_arg1);
dfw_resolve_unparsed(dfw, entity);
check_exists(dfw, entity);
/* Nothing to do here? */
}
static void
check_slice_sanity(dfwork_t *dfw, stnode_t *st, ftenum_t lhs_ftype)
{
@ -566,12 +555,12 @@ check_slice_sanity(dfwork_t *dfw, stnode_t *st, ftenum_t lhs_ftype)
LOG_NODE(st);
entity1 = sttype_range_entity(st);
entity1 = sttype_slice_entity(st);
ws_assert(entity1);
dfw_resolve_unparsed(dfw, entity1);
if (stnode_type_id(entity1) == STTYPE_FIELD) {
hfinfo1 = stnode_data(entity1);
hfinfo1 = sttype_field_hfinfo(entity1);
ftype1 = hfinfo1->type;
if (!ftype_can_slice(ftype1)) {
@ -594,51 +583,9 @@ check_slice_sanity(dfwork_t *dfw, stnode_t *st, ftenum_t lhs_ftype)
}
}
static ftenum_t
check_layer_sanity(dfwork_t *dfw, stnode_t *st)
{
stnode_t *entity1;
sttype_id_t e_type;
LOG_NODE(st);
entity1 = sttype_range_entity(st);
ws_assert(entity1);
dfw_resolve_unparsed(dfw, entity1);
e_type = stnode_type_id(entity1);
if (e_type == STTYPE_FIELD) {
return sttype_pointer_ftenum(entity1);
}
else if (e_type == STTYPE_REFERENCE) {
/* TODO: Implement layers with references. */
FAIL(dfw, entity1, "The # operator is not valid with a reference");
}
else {
FAIL(dfw, entity1, "%s is not a valid field value", stnode_todisplay(entity1));
}
}
#define IS_FIELD_ENTITY(ft) \
((ft) == STTYPE_FIELD || \
(ft) == STTYPE_REFERENCE || \
(ft) == STTYPE_LAYER)
static ftenum_t
field_ftenum(stnode_t *st)
{
sttype_id_t e_type;
e_type = stnode_type_id(st);
if (e_type == STTYPE_FIELD || e_type == STTYPE_REFERENCE)
return sttype_pointer_ftenum(st);
else if (e_type == STTYPE_LAYER) {
return sttype_pointer_ftenum(sttype_range_entity(st));
}
else {
ws_assert_not_reached();
}
}
(ft) == STTYPE_REFERENCE)
static void
convert_to_bytes(stnode_t *arg)
@ -652,7 +599,7 @@ convert_to_bytes(stnode_t *arg)
drange_node_set_to_the_end(rn);
stnode_replace(arg, STTYPE_SLICE, NULL);
sttype_range_set1(arg, entity1, rn);
sttype_slice_set1(arg, entity1, rn);
}
ftenum_t
@ -718,7 +665,7 @@ again:
ws_assert(stnode_type_id(st_arg1) == STTYPE_FIELD ||
stnode_type_id(st_arg1) == STTYPE_REFERENCE);
hfinfo1 = stnode_data(st_arg1);
hfinfo1 = sttype_field_hfinfo(st_arg1);
ftype1 = hfinfo1->type;
if (!can_func(ftype1)) {
@ -728,7 +675,7 @@ again:
}
if (IS_FIELD_ENTITY(type2)) {
ftype2 = field_ftenum(st_arg2);
ftype2 = sttype_field_ftenum(st_arg2);
if (!compatible_ftypes(ftype1, ftype2)) {
FAIL(dfw, st_arg2, "%s and %s are not of compatible types.",
@ -817,21 +764,6 @@ again:
}
}
static void
check_relation_LHS_LAYER(dfwork_t *dfw, test_op_t st_op,
FtypeCanFunc can_func,
gboolean allow_partial_value,
stnode_t *st_node,
stnode_t *st_arg1, stnode_t *st_arg2)
{
stnode_t *entity;
check_layer_sanity(dfw, st_arg1);
entity = sttype_range_entity(st_arg1);
ws_assert(stnode_type_id(entity) == STTYPE_FIELD);
check_relation_LHS_FIELD(dfw, st_op, can_func, allow_partial_value, st_node, entity, st_arg2);
}
static void
check_relation_LHS_SLICE(dfwork_t *dfw, test_op_t st_op,
FtypeCanFunc can_func _U_,
@ -851,7 +783,7 @@ again:
type2 = stnode_type_id(st_arg2);
if (IS_FIELD_ENTITY(type2)) {
ftype2 = field_ftenum(st_arg2);
ftype2 = sttype_field_ftenum(st_arg2);
if (!is_bytes_type(ftype2)) {
if (!ftype_can_slice(ftype2)) {
@ -948,7 +880,7 @@ again:
type2 = stnode_type_id(st_arg2);
if (IS_FIELD_ENTITY(type2)) {
ftype2 = field_ftenum(st_arg2);
ftype2 = sttype_field_ftenum(st_arg2);
if (!compatible_ftypes(ftype1, ftype2)) {
FAIL(dfw, st_arg2, "Function %s and %s are not of compatible types.",
@ -1078,10 +1010,6 @@ check_relation(dfwork_t *dfw, test_op_t st_op,
check_relation_LHS_FIELD(dfw, st_op, can_func,
allow_partial_value, st_node, st_arg1, st_arg2);
break;
case STTYPE_LAYER:
check_relation_LHS_LAYER(dfw, st_op, can_func,
allow_partial_value, st_node, st_arg1, st_arg2);
break;
case STTYPE_SLICE:
check_relation_LHS_SLICE(dfw, st_op, can_func,
allow_partial_value, st_node, st_arg1, st_arg2);
@ -1300,7 +1228,7 @@ check_arithmetic_entity(dfwork_t *dfw, stnode_t *st_arg, ftenum_t lhs_ftype)
ftype = fvalue_type_ftenum(fvalue);
}
else if (type == STTYPE_FIELD || type == STTYPE_REFERENCE) {
header_field_info *hfinfo = stnode_data(st_arg);
header_field_info *hfinfo = sttype_field_hfinfo(st_arg);
ftype = hfinfo->type;
}
else if (type == STTYPE_FUNCTION) {
@ -1419,9 +1347,6 @@ semcheck(dfwork_t *dfw, stnode_t *st_node)
case STTYPE_ARITHMETIC:
check_arithmetic_expr(dfw, st_node, FT_NONE);
break;
case STTYPE_LAYER:
check_exists_layer(dfw, st_node);
break;
default:
check_exists(dfw, st_node);
}

202
epan/dfilter/sttype-field.c Normal file
View File

@ -0,0 +1,202 @@
/*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 2001 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
/* The ideas in this code came from Ed Warnicke's original implementation
* of dranges for the old display filter code (Ethereal 0.8.15 and before).
* The code is different, but definitely inspired by his code.
*/
#include "config.h"
#include <glib.h>
#include <epan/proto.h>
#include "sttype-field.h"
#include <wsutil/ws_assert.h>
typedef struct {
guint32 magic;
header_field_info *hfinfo;
drange_t *drange;
} field_t;
#define FIELD_MAGIC 0xfc2002cf
static gpointer
field_new(gpointer hfinfo)
{
field_t *field;
field = g_new(field_t, 1);
field->magic = FIELD_MAGIC;
field->hfinfo = hfinfo;
field->drange = NULL;
return field;
}
static gpointer
field_dup(gconstpointer data)
{
const field_t *org = data;
field_t *field;
ws_assert_magic(org, FIELD_MAGIC);
field = field_new(NULL);
field->hfinfo = org->hfinfo;
field->drange = drange_dup(org->drange);
return field;
}
static void
field_free(gpointer data)
{
field_t *field = data;
ws_assert_magic(field, FIELD_MAGIC);
if (field->drange)
drange_free(field->drange);
g_free(field);
}
static char *
field_tostr(const void *data, gboolean pretty _U_)
{
const field_t *field = data;
ws_assert_magic(field, FIELD_MAGIC);
char *repr, *drange_str;
if (field->drange && (drange_str = drange_tostr(field->drange))) {
repr = ws_strdup_printf("%s#[%s] <%s>",
field->hfinfo->abbrev,
drange_str,
ftype_name(field->hfinfo->type));
g_free(drange_str);
}
else {
repr = ws_strdup_printf("%s <%s>", field->hfinfo->abbrev,
ftype_name(field->hfinfo->type));
}
return repr;
}
header_field_info *
sttype_field_hfinfo(stnode_t *node)
{
field_t *field = node->data;
ws_assert_magic(field, FIELD_MAGIC);
return field->hfinfo;
}
ftenum_t
sttype_field_ftenum(stnode_t *node)
{
field_t *field = node->data;
ws_assert_magic(field, FIELD_MAGIC);
return field->hfinfo->type;
}
drange_t *
sttype_field_drange(stnode_t *node)
{
field_t *field = node->data;
ws_assert_magic(field, FIELD_MAGIC);
return field->drange;
}
drange_t *
sttype_field_drange_steal(stnode_t *node)
{
field_t *field;
drange_t *dr;
field = stnode_data(node);
ws_assert_magic(field, FIELD_MAGIC);
dr = field->drange;
field->drange = NULL;
return dr;
}
/* Set a field */
void
sttype_field_set_range(stnode_t *node, GSList* drange_list)
{
field_t *field = stnode_data(node);
ws_assert_magic(field, FIELD_MAGIC);
ws_assert(field->drange == NULL);
field->drange = drange_new_from_list(drange_list);
}
void
sttype_field_set_range1(stnode_t *node, drange_node *rn)
{
field_t *field = stnode_data(node);
ws_assert_magic(field, FIELD_MAGIC);
ws_assert(field->drange == NULL);
field->drange = drange_new(rn);
}
void
sttype_field_set_drange(stnode_t *node, drange_t *dr)
{
field_t *field = stnode_data(node);
ws_assert_magic(field, FIELD_MAGIC);
ws_assert(field->drange == NULL);
field->drange = dr;
}
char *
sttype_field_set_number(stnode_t *node, const char *number_str)
{
char *err_msg = NULL;
drange_node *rn = drange_node_from_str(number_str, &err_msg);
if (err_msg != NULL)
return err_msg;
sttype_field_set_range1(node, rn);
return NULL;
}
void
sttype_register_field(void)
{
static sttype_t field_type = {
STTYPE_FIELD,
"FIELD",
field_new,
field_free,
field_dup,
field_tostr
};
static sttype_t reference_type = {
STTYPE_REFERENCE,
"REFERENCE",
field_new,
field_free,
field_dup,
field_tostr
};
sttype_register(&field_type);
sttype_register(&reference_type);
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
* :indentSize=8:tabSize=8:noTabs=false:
*/

View File

@ -0,0 +1,48 @@
/** @file
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 2001 Gerald Combs
*
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef STTYPE_FIELD_H
#define STTYPE_FIELD_H
#include "syntax-tree.h"
#include "drange.h"
header_field_info *
sttype_field_hfinfo(stnode_t *node);
ftenum_t
sttype_field_ftenum(stnode_t *node);
drange_t *
sttype_field_drange(stnode_t *node);
drange_t *
sttype_field_drange_steal(stnode_t *node);
/* Set a range */
void
sttype_field_set_range(stnode_t *node, GSList* drange_list);
void
sttype_field_set_range1(stnode_t *node, drange_node *rn);
void
sttype_field_set_drange(stnode_t *node, drange_t *dr);
char *
sttype_field_set_number(stnode_t *node, const char *number_str);
/* Clear the 'drange' variable to remove responsibility for
* freeing it. */
void
sttype_field_remove_drange(stnode_t *node);
#endif

View File

@ -52,14 +52,6 @@ sttype_fvalue_tostr(const void *data, gboolean pretty)
return repr;
}
static char *
field_tostr(const void *data, gboolean pretty _U_)
{
const header_field_info *hfinfo = data;
return ws_strdup_printf("%s <%s>", hfinfo->abbrev, ftype_name(hfinfo->type));
}
static char *
pcre_tostr(const void *data, gboolean pretty _U_)
{
@ -128,25 +120,6 @@ sttype_pointer_ftenum(stnode_t *node)
void
sttype_register_pointer(void)
{
static sttype_t field_type = {
STTYPE_FIELD,
"FIELD",
NULL,
NULL,
NULL,
field_tostr
};
/* A field reference is a *constant* prototocol field value read directly
* from the currently selected frame in the protocol tree when a filter is
* applied to it. */
static sttype_t reference_type = {
STTYPE_REFERENCE,
"REFERENCE",
NULL,
NULL,
NULL,
field_tostr
};
static sttype_t fvalue_type = {
STTYPE_FVALUE,
"FVALUE",
@ -180,8 +153,6 @@ sttype_register_pointer(void)
range_node_tostr
};
sttype_register(&field_type);
sttype_register(&reference_type);
sttype_register(&fvalue_type);
sttype_register(&pcre_type);
sttype_register(&charconst_type);

View File

@ -1,215 +0,0 @@
/*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 2001 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
/* The ideas in this code came from Ed Warnicke's original implementation
* of dranges for the old display filter code (Ethereal 0.8.15 and before).
* The code is different, but definitely inspired by his code.
*/
#include "config.h"
#include <glib.h>
#include <epan/proto.h>
#include "drange.h"
#include "sttype-range.h"
#include <wsutil/ws_assert.h>
typedef struct {
guint32 magic;
stnode_t *entity;
drange_t *drange;
} range_t;
#define RANGE_MAGIC 0xec0990ce
static gpointer
range_new(gpointer junk _U_)
{
range_t *range;
ws_assert(junk == NULL);
range = g_new(range_t, 1);
range->magic = RANGE_MAGIC;
range->entity = NULL;
range->drange = NULL;
return range;
}
static gpointer
range_dup(gconstpointer data)
{
const range_t *org = data;
range_t *range;
range = range_new(NULL);
range->entity = stnode_dup(org->entity);
range->drange = drange_dup(org->drange);
return range;
}
static void
range_free(gpointer value)
{
range_t *range = value;
ws_assert_magic(range, RANGE_MAGIC);
if (range->drange)
drange_free(range->drange);
if (range->entity)
stnode_free(range->entity);
g_free(range);
}
static char *
slice_tostr(const void *data, gboolean pretty)
{
const range_t *range = data;
ws_assert_magic(range, RANGE_MAGIC);
char *repr, *drange_str;
drange_str = drange_tostr(range->drange);
repr = ws_strdup_printf("%s[%s]",
stnode_tostr(range->entity, pretty),
drange_str);
g_free(drange_str);
return repr;
}
static char *
layer_tostr(const void *data, gboolean pretty)
{
const range_t *range = data;
ws_assert_magic(range, RANGE_MAGIC);
char *repr, *drange_str;
drange_str = drange_tostr(range->drange);
repr = ws_strdup_printf("%s#[%s]",
stnode_tostr(range->entity, pretty),
drange_str);
g_free(drange_str);
return repr;
}
void
sttype_range_remove_drange(stnode_t *node)
{
range_t *range;
range = stnode_data(node);
ws_assert_magic(range, RANGE_MAGIC);
range->drange = NULL;
}
drange_t *
sttype_range_drange_steal(stnode_t *node)
{
range_t *range;
drange_t *dr;
range = stnode_data(node);
ws_assert_magic(range, RANGE_MAGIC);
dr = range->drange;
range->drange = NULL;
return dr;
}
/* Set a range */
void
sttype_range_set(stnode_t *node, stnode_t *entity, GSList* drange_list)
{
range_t *range;
range = stnode_data(node);
ws_assert_magic(range, RANGE_MAGIC);
range->entity = entity;
range->drange = drange_new_from_list(drange_list);
}
void
sttype_range_set1(stnode_t *node, stnode_t *entity, drange_node *rn)
{
sttype_range_set(node, entity, g_slist_append(NULL, rn));
}
char *
sttype_range_set_number(stnode_t *node, stnode_t *entity, const char *number_str)
{
char *err_msg = NULL;
drange_node *rn = drange_node_from_str(number_str, &err_msg);
if (err_msg != NULL)
return err_msg;
sttype_range_set1(node, entity, rn);
return NULL;
}
stnode_t *
sttype_range_entity(stnode_t *node)
{
range_t *range = node->data;
ws_assert_magic(range, RANGE_MAGIC);
return range->entity;
}
drange_t *
sttype_range_drange(stnode_t *node)
{
range_t *range = node->data;
ws_assert_magic(range, RANGE_MAGIC);
return range->drange;
}
void
sttype_register_range(void)
{
static sttype_t slice_type = {
STTYPE_SLICE,
"SLICE",
range_new,
range_free,
range_dup,
slice_tostr
};
static sttype_t layer_type = {
STTYPE_LAYER,
"LAYER",
range_new,
range_free,
range_dup,
layer_tostr
};
sttype_register(&slice_type);
sttype_register(&layer_type);
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
* :indentSize=8:tabSize=8:noTabs=false:
*/

View File

@ -1,42 +0,0 @@
/** @file
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 2001 Gerald Combs
*
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef STTYPE_RANGE_H
#define STTYPE_RANGE_H
#include "syntax-tree.h"
#include "drange.h"
stnode_t *
sttype_range_entity(stnode_t *node);
drange_t *
sttype_range_drange(stnode_t *node);
drange_t *
sttype_range_drange_steal(stnode_t *node);
/* Set a range */
void
sttype_range_set(stnode_t *node, stnode_t *field, GSList* drange_list);
void
sttype_range_set1(stnode_t *node, stnode_t *field, drange_node *rn);
char *
sttype_range_set_number(stnode_t *node, stnode_t *entity, const char *number_str);
/* Clear the 'drange' variable to remove responsibility for
* freeing it. */
void
sttype_range_remove_drange(stnode_t *node);
#endif

191
epan/dfilter/sttype-slice.c Normal file
View File

@ -0,0 +1,191 @@
/*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 2001 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
/* The ideas in this code came from Ed Warnicke's original implementation
* of dranges for the old display filter code (Ethereal 0.8.15 and before).
* The code is different, but definitely inspired by his code.
*/
#include "config.h"
#include <glib.h>
#include <epan/proto.h>
#include "drange.h"
#include "sttype-slice.h"
#include <wsutil/ws_assert.h>
typedef struct {
guint32 magic;
stnode_t *entity;
drange_t *drange;
} slice_t;
#define SLICE_MAGIC 0xec0990ce
static gpointer
slice_new(gpointer junk _U_)
{
slice_t *slice;
ws_assert(junk == NULL);
slice = g_new(slice_t, 1);
slice->magic = SLICE_MAGIC;
slice->entity = NULL;
slice->drange = NULL;
return slice;
}
static gpointer
slice_dup(gconstpointer data)
{
const slice_t *org = data;
slice_t *slice;
slice = slice_new(NULL);
slice->entity = stnode_dup(org->entity);
slice->drange = drange_dup(org->drange);
return slice;
}
static void
slice_free(gpointer value)
{
slice_t *slice = value;
ws_assert_magic(slice, SLICE_MAGIC);
if (slice->drange)
drange_free(slice->drange);
if (slice->entity)
stnode_free(slice->entity);
g_free(slice);
}
static char *
slice_tostr(const void *data, gboolean pretty)
{
const slice_t *slice = data;
ws_assert_magic(slice, SLICE_MAGIC);
char *repr, *drange_str;
drange_str = drange_tostr(slice->drange);
repr = ws_strdup_printf("%s[%s]",
stnode_tostr(slice->entity, pretty),
drange_str);
g_free(drange_str);
return repr;
}
void
sttype_slice_remove_drange(stnode_t *node)
{
slice_t *slice;
slice = stnode_data(node);
ws_assert_magic(slice, SLICE_MAGIC);
slice->drange = NULL;
}
drange_t *
sttype_slice_drange_steal(stnode_t *node)
{
slice_t *slice;
drange_t *dr;
slice = stnode_data(node);
ws_assert_magic(slice, SLICE_MAGIC);
dr = slice->drange;
slice->drange = NULL;
return dr;
}
/* Set a slice */
void
sttype_slice_set(stnode_t *node, stnode_t *entity, GSList* drange_list)
{
slice_t *slice;
slice = stnode_data(node);
ws_assert_magic(slice, SLICE_MAGIC);
slice->entity = entity;
slice->drange = drange_new_from_list(drange_list);
}
void
sttype_slice_set1(stnode_t *node, stnode_t *entity, drange_node *rn)
{
sttype_slice_set(node, entity, g_slist_append(NULL, rn));
}
void
sttype_slice_set_drange(stnode_t *node, stnode_t *field, drange_t *dr)
{
slice_t *slice;
slice = stnode_data(node);
ws_assert_magic(slice, SLICE_MAGIC);
slice->entity = field;
slice->drange = dr;
}
stnode_t *
sttype_slice_entity(stnode_t *node)
{
slice_t *slice = node->data;
ws_assert_magic(slice, SLICE_MAGIC);
return slice->entity;
}
drange_t *
sttype_slice_drange(stnode_t *node)
{
slice_t *slice = node->data;
ws_assert_magic(slice, SLICE_MAGIC);
return slice->drange;
}
void
sttype_register_slice(void)
{
static sttype_t slice_type = {
STTYPE_SLICE,
"SLICE",
slice_new,
slice_free,
slice_dup,
slice_tostr
};
sttype_register(&slice_type);
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
* :indentSize=8:tabSize=8:noTabs=false:
*/

View File

@ -0,0 +1,42 @@
/** @file
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 2001 Gerald Combs
*
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef STTYPE_SLICE_H
#define STTYPE_SLICE_H
#include "syntax-tree.h"
#include "drange.h"
stnode_t *
sttype_slice_entity(stnode_t *node);
drange_t *
sttype_slice_drange(stnode_t *node);
drange_t *
sttype_slice_drange_steal(stnode_t *node);
/* Set a range */
void
sttype_slice_set(stnode_t *node, stnode_t *field, GSList* drange_list);
void
sttype_slice_set1(stnode_t *node, stnode_t *field, drange_node *rn);
void
sttype_slice_set_drange(stnode_t *node, stnode_t *field, drange_t *dr);
/* Clear the 'drange' variable to remove responsibility for
* freeing it. */
void
sttype_slice_remove_drange(stnode_t *node);
#endif

View File

@ -28,10 +28,11 @@ static sttype_t* type_list[STTYPE_NUM_TYPES];
void
sttype_init(void)
{
sttype_register_field();
sttype_register_function();
sttype_register_pointer();
sttype_register_range();
sttype_register_set();
sttype_register_slice();
sttype_register_string();
sttype_register_test();
}

View File

@ -31,7 +31,6 @@ typedef enum {
STTYPE_FIELD,
STTYPE_FVALUE,
STTYPE_SLICE,
STTYPE_LAYER,
STTYPE_RANGE_NODE,
STTYPE_FUNCTION,
STTYPE_SET,
@ -104,11 +103,11 @@ typedef struct {
} stnode_t;
/* These are the sttype_t registration function prototypes. */
void sttype_register_field(void);
void sttype_register_function(void);
void sttype_register_integer(void);
void sttype_register_pointer(void);
void sttype_register_range(void);
void sttype_register_set(void);
void sttype_register_slice(void);
void sttype_register_string(void);
void sttype_register_test(void);

View File

@ -282,12 +282,17 @@ class case_arithmetic(unittest.TestCase):
@fixtures.uses_fixtures
class case_field_reference(unittest.TestCase):
trace_file = "dhcp.pcap"
trace_file = "ipoipoip.pcap"
def test_ref_1(self, checkDFilterCountWithSelectedFrame):
dfilter = 'frame.number < ${frame.number}'
# select frame 3, expect 2 frames out of 4.
checkDFilterCountWithSelectedFrame(dfilter, 2, 3)
# select frame 2, expect 1 frames out of 2.
checkDFilterCountWithSelectedFrame(dfilter, 1, 2)
def test_ref_2(self, checkDFilterCountWithSelectedFrame):
dfilter = 'ip.src#3 == ${ip.src#4}'
# select frame 1, expect 1 frames out of 2.
checkDFilterCountWithSelectedFrame(dfilter, 1, 1)
@fixtures.uses_fixtures
class case_field_reference(unittest.TestCase):