2001-02-01 20:31:21 +00:00
|
|
|
/*
|
2006-05-21 05:12:17 +00:00
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
2001-02-01 20:31:21 +00:00
|
|
|
* Copyright 2001 Gerald Combs
|
|
|
|
*
|
2018-02-08 16:59:17 +00:00
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
2001-02-01 20:31:21 +00:00
|
|
|
*/
|
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
#include "config.h"
|
2022-02-27 14:47:31 +00:00
|
|
|
#define WS_LOG_DOMAIN LOG_DOMAIN_DFILTER
|
2001-02-01 20:21:25 +00:00
|
|
|
|
|
|
|
#include "dfvm.h"
|
|
|
|
|
2021-11-11 00:54:00 +00:00
|
|
|
#include <ftypes/ftypes.h>
|
2021-06-18 18:21:42 +00:00
|
|
|
#include <wsutil/ws_assert.h>
|
2013-11-10 13:14:09 +00:00
|
|
|
|
2022-04-12 15:13:08 +00:00
|
|
|
static void
|
|
|
|
debug_register(GSList *reg, guint32 num);
|
|
|
|
|
2022-04-16 01:42:20 +00:00
|
|
|
const char *
|
|
|
|
dfvm_opcode_tostr(dfvm_opcode_t code)
|
|
|
|
{
|
|
|
|
switch (code) {
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_IF_TRUE_GOTO: return "IF_TRUE_GOTO";
|
|
|
|
case DFVM_IF_FALSE_GOTO: return "IF_FALSE_GOTO";
|
|
|
|
case DFVM_CHECK_EXISTS: return "CHECK_EXISTS";
|
|
|
|
case DFVM_CHECK_EXISTS_R: return "CHECK_EXISTS_R";
|
|
|
|
case DFVM_NOT: return "NOT";
|
|
|
|
case DFVM_RETURN: return "RETURN";
|
|
|
|
case DFVM_READ_TREE: return "READ_TREE";
|
|
|
|
case DFVM_READ_TREE_R: return "READ_TREE_R";
|
|
|
|
case DFVM_READ_REFERENCE: return "READ_REFERENCE";
|
|
|
|
case DFVM_READ_REFERENCE_R: return "READ_REFERENCE_R";
|
|
|
|
case DFVM_PUT_FVALUE: return "PUT_FVALUE";
|
|
|
|
case DFVM_ALL_EQ: return "ALL_EQ";
|
|
|
|
case DFVM_ANY_EQ: return "ANY_EQ";
|
|
|
|
case DFVM_ALL_NE: return "ALL_NE";
|
|
|
|
case DFVM_ANY_NE: return "ANY_NE";
|
|
|
|
case DFVM_ALL_GT: return "ALL_GT";
|
|
|
|
case DFVM_ANY_GT: return "ANY_GT";
|
|
|
|
case DFVM_ALL_GE: return "ALL_GE";
|
|
|
|
case DFVM_ANY_GE: return "ANY_GE";
|
|
|
|
case DFVM_ALL_LT: return "ALL_LT";
|
|
|
|
case DFVM_ANY_LT: return "ANY_LT";
|
|
|
|
case DFVM_ALL_LE: return "ALL_LE";
|
|
|
|
case DFVM_ANY_LE: return "ANY_LE";
|
|
|
|
case DFVM_ALL_CONTAINS: return "ALL_CONTAINS";
|
|
|
|
case DFVM_ANY_CONTAINS: return "ANY_CONTAINS";
|
|
|
|
case DFVM_ALL_MATCHES: return "ALL_MATCHES";
|
|
|
|
case DFVM_ANY_MATCHES: return "ANY_MATCHES";
|
|
|
|
case DFVM_ALL_IN_RANGE: return "ALL_IN_RANGE";
|
|
|
|
case DFVM_ANY_IN_RANGE: return "ANY_IN_RANGE";
|
|
|
|
case DFVM_SLICE: return "SLICE";
|
2022-07-03 22:07:36 +00:00
|
|
|
case DFVM_LENGTH: return "LENGTH";
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_BITWISE_AND: return "BITWISE_AND";
|
|
|
|
case DFVM_UNARY_MINUS: return "UNARY_MINUS";
|
|
|
|
case DFVM_ADD: return "ADD";
|
|
|
|
case DFVM_SUBTRACT: return "SUBTRACT";
|
|
|
|
case DFVM_MULTIPLY: return "MULTIPLY";
|
|
|
|
case DFVM_DIVIDE: return "DIVIDE";
|
|
|
|
case DFVM_MODULO: return "MODULO";
|
|
|
|
case DFVM_CALL_FUNCTION: return "CALL_FUNCTION";
|
|
|
|
case DFVM_STACK_PUSH: return "STACK_PUSH";
|
|
|
|
case DFVM_STACK_POP: return "STACK_POP";
|
2022-07-05 08:51:49 +00:00
|
|
|
case DFVM_NOT_ALL_ZERO: return "NOT_ALL_ZERO";
|
2022-04-16 01:42:20 +00:00
|
|
|
}
|
|
|
|
return "(fix-opcode-string)";
|
|
|
|
}
|
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
dfvm_insn_t*
|
|
|
|
dfvm_insn_new(dfvm_opcode_t op)
|
|
|
|
{
|
|
|
|
dfvm_insn_t *insn;
|
|
|
|
|
|
|
|
insn = g_new(dfvm_insn_t, 1);
|
|
|
|
insn->op = op;
|
|
|
|
insn->arg1 = NULL;
|
|
|
|
insn->arg2 = NULL;
|
|
|
|
insn->arg3 = NULL;
|
|
|
|
return insn;
|
|
|
|
}
|
|
|
|
|
2002-04-08 20:11:31 +00:00
|
|
|
static void
|
|
|
|
dfvm_value_free(dfvm_value_t *v)
|
|
|
|
{
|
|
|
|
switch (v->type) {
|
|
|
|
case FVALUE:
|
2021-11-11 00:54:00 +00:00
|
|
|
fvalue_free(v->value.fvalue);
|
2002-04-08 20:11:31 +00:00
|
|
|
break;
|
|
|
|
case DRANGE:
|
|
|
|
drange_free(v->value.drange);
|
|
|
|
break;
|
2021-03-21 10:06:17 +00:00
|
|
|
case PCRE:
|
2021-11-12 15:55:14 +00:00
|
|
|
ws_regex_free(v->value.pcre);
|
2021-03-21 10:06:17 +00:00
|
|
|
break;
|
2002-04-08 20:11:31 +00:00
|
|
|
default:
|
|
|
|
/* nothing */
|
|
|
|
;
|
|
|
|
}
|
|
|
|
g_free(v);
|
|
|
|
}
|
|
|
|
|
2022-03-21 16:00:17 +00:00
|
|
|
dfvm_value_t*
|
|
|
|
dfvm_value_ref(dfvm_value_t *v)
|
|
|
|
{
|
|
|
|
if (v == NULL)
|
|
|
|
return NULL;
|
|
|
|
v->ref_count++;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dfvm_value_unref(dfvm_value_t *v)
|
|
|
|
{
|
|
|
|
ws_assert(v);
|
|
|
|
v->ref_count--;
|
|
|
|
if (v->ref_count > 0)
|
|
|
|
return;
|
|
|
|
dfvm_value_free(v);
|
|
|
|
}
|
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
void
|
|
|
|
dfvm_insn_free(dfvm_insn_t *insn)
|
|
|
|
{
|
|
|
|
if (insn->arg1) {
|
2022-03-21 16:00:17 +00:00
|
|
|
dfvm_value_unref(insn->arg1);
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
|
|
|
if (insn->arg2) {
|
2022-03-21 16:00:17 +00:00
|
|
|
dfvm_value_unref(insn->arg2);
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
|
|
|
if (insn->arg3) {
|
2022-03-21 16:00:17 +00:00
|
|
|
dfvm_value_unref(insn->arg3);
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
|
|
|
g_free(insn);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
dfvm_value_t*
|
|
|
|
dfvm_value_new(dfvm_value_type_t type)
|
|
|
|
{
|
|
|
|
dfvm_value_t *v;
|
|
|
|
|
|
|
|
v = g_new(dfvm_value_t, 1);
|
|
|
|
v->type = type;
|
2022-03-21 16:00:17 +00:00
|
|
|
v->ref_count = 0;
|
2001-02-01 20:21:25 +00:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2022-03-21 15:38:22 +00:00
|
|
|
dfvm_value_t*
|
|
|
|
dfvm_value_new_fvalue(fvalue_t *fv)
|
|
|
|
{
|
|
|
|
dfvm_value_t *v = dfvm_value_new(FVALUE);
|
|
|
|
v->value.fvalue = fv;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
dfvm_value_t*
|
2022-10-25 03:20:18 +00:00
|
|
|
dfvm_value_new_hfinfo(header_field_info *hfinfo, gboolean raw)
|
2022-03-21 15:38:22 +00:00
|
|
|
{
|
2022-10-25 03:20:18 +00:00
|
|
|
dfvm_value_t *v;
|
|
|
|
|
|
|
|
if (raw)
|
|
|
|
v = dfvm_value_new(RAW_HFINFO);
|
|
|
|
else
|
|
|
|
v = dfvm_value_new(HFINFO);
|
2022-03-21 15:38:22 +00:00
|
|
|
v->value.hfinfo = hfinfo;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
dfvm_value_t*
|
|
|
|
dfvm_value_new_register(int reg)
|
|
|
|
{
|
|
|
|
dfvm_value_t *v = dfvm_value_new(REGISTER);
|
|
|
|
v->value.numeric = reg;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
dfvm_value_t*
|
|
|
|
dfvm_value_new_drange(drange_t *dr)
|
|
|
|
{
|
|
|
|
dfvm_value_t *v = dfvm_value_new(DRANGE);
|
|
|
|
v->value.drange = dr;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
dfvm_value_t*
|
|
|
|
dfvm_value_new_funcdef(df_func_def_t *funcdef)
|
|
|
|
{
|
|
|
|
dfvm_value_t *v = dfvm_value_new(FUNCTION_DEF);
|
|
|
|
v->value.funcdef = funcdef;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
dfvm_value_t*
|
|
|
|
dfvm_value_new_pcre(ws_regex_t *re)
|
|
|
|
{
|
|
|
|
dfvm_value_t *v = dfvm_value_new(PCRE);
|
|
|
|
v->value.pcre = re;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2022-04-16 01:42:20 +00:00
|
|
|
dfvm_value_t*
|
|
|
|
dfvm_value_new_guint(guint num)
|
|
|
|
{
|
|
|
|
dfvm_value_t *v = dfvm_value_new(INTEGER);
|
|
|
|
v->value.numeric = num;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2022-07-13 19:07:27 +00:00
|
|
|
static char *
|
2022-03-21 11:13:02 +00:00
|
|
|
dfvm_value_tostr(dfvm_value_t *v)
|
|
|
|
{
|
2023-01-06 00:33:08 +00:00
|
|
|
char *s;
|
2022-03-21 11:13:02 +00:00
|
|
|
|
|
|
|
if (!v)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
switch (v->type) {
|
|
|
|
case HFINFO:
|
2023-01-06 00:33:08 +00:00
|
|
|
s = ws_strdup(v->value.hfinfo->abbrev);
|
2022-03-21 11:13:02 +00:00
|
|
|
break;
|
2022-10-25 03:20:18 +00:00
|
|
|
case RAW_HFINFO:
|
2023-01-06 00:33:08 +00:00
|
|
|
s = ws_strdup_printf("@%s", v->value.hfinfo->abbrev);
|
2022-10-25 03:20:18 +00:00
|
|
|
break;
|
2022-03-21 11:13:02 +00:00
|
|
|
case FVALUE:
|
2023-01-06 00:33:08 +00:00
|
|
|
s = fvalue_to_debug_repr(NULL, v->value.fvalue);
|
2022-03-21 11:13:02 +00:00
|
|
|
break;
|
|
|
|
case DRANGE:
|
|
|
|
s = drange_tostr(v->value.drange);
|
|
|
|
break;
|
|
|
|
case PCRE:
|
|
|
|
s = ws_strdup(ws_regex_pattern(v->value.pcre));
|
|
|
|
break;
|
|
|
|
case REGISTER:
|
2023-01-06 00:33:08 +00:00
|
|
|
s = ws_strdup_printf("R%"G_GUINT32_FORMAT, v->value.numeric);
|
2022-03-21 11:13:02 +00:00
|
|
|
break;
|
|
|
|
case FUNCTION_DEF:
|
|
|
|
s = ws_strdup(v->value.funcdef->name);
|
|
|
|
break;
|
2022-04-12 15:13:08 +00:00
|
|
|
case INTEGER:
|
|
|
|
s = ws_strdup_printf("%"G_GUINT32_FORMAT, v->value.numeric);
|
|
|
|
break;
|
2022-03-21 11:13:02 +00:00
|
|
|
default:
|
|
|
|
s = ws_strdup("FIXME");
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2023-01-10 15:42:32 +00:00
|
|
|
static char *
|
|
|
|
value_type_tostr(dfvm_value_t *v, gboolean show_ftype)
|
|
|
|
{
|
|
|
|
const char *s;
|
|
|
|
|
|
|
|
if (!v || !show_ftype)
|
|
|
|
return ws_strdup("");
|
|
|
|
|
|
|
|
switch (v->type) {
|
|
|
|
case HFINFO:
|
|
|
|
case RAW_HFINFO:
|
|
|
|
s = ftype_name(v->value.hfinfo->type);
|
|
|
|
break;
|
|
|
|
case FVALUE:
|
|
|
|
s = fvalue_type_name(v->value.fvalue);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return ws_strdup("");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return ws_strdup_printf(" <%s>", s);
|
|
|
|
}
|
|
|
|
|
2022-04-16 01:42:20 +00:00
|
|
|
static GSList *
|
|
|
|
dump_str_stack_push(GSList *stack, const char *str)
|
|
|
|
{
|
|
|
|
return g_slist_prepend(stack, g_strdup(str));
|
|
|
|
}
|
|
|
|
|
|
|
|
static GSList *
|
2023-01-06 02:24:47 +00:00
|
|
|
dump_str_stack_pop(GSList *stack, guint32 count)
|
2022-04-16 01:42:20 +00:00
|
|
|
{
|
2023-01-06 02:24:47 +00:00
|
|
|
while (stack && count-- > 0) {
|
|
|
|
g_free(stack->data);
|
|
|
|
stack = g_slist_delete_link(stack, stack);
|
2022-04-19 17:57:13 +00:00
|
|
|
}
|
2022-04-16 01:42:20 +00:00
|
|
|
return stack;
|
|
|
|
}
|
|
|
|
|
2023-01-05 18:48:16 +00:00
|
|
|
static void
|
2023-01-07 02:40:14 +00:00
|
|
|
append_call_function(wmem_strbuf_t *buf, const char *func, uint32_t nargs,
|
|
|
|
GSList *stack_print)
|
2023-01-05 18:48:16 +00:00
|
|
|
{
|
2023-01-07 02:40:14 +00:00
|
|
|
uint32_t idx;
|
|
|
|
GString *gs;
|
|
|
|
GSList *l;
|
|
|
|
const char *sep = "";
|
|
|
|
|
|
|
|
wmem_strbuf_append_printf(buf, "%s(", func);
|
|
|
|
if (nargs > 0) {
|
|
|
|
gs = g_string_new(NULL);
|
|
|
|
for (l = stack_print, idx = 0; l != NULL && idx < nargs; idx++, l = l->next) {
|
|
|
|
g_string_prepend(gs, sep);
|
|
|
|
g_string_prepend(gs, l->data);
|
|
|
|
sep = ", ";
|
|
|
|
}
|
|
|
|
wmem_strbuf_append(buf, gs->str);
|
|
|
|
g_string_free(gs, TRUE);
|
2023-01-05 18:48:16 +00:00
|
|
|
}
|
2023-01-07 02:40:14 +00:00
|
|
|
wmem_strbuf_append(buf, ")");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
indent(wmem_strbuf_t *buf, size_t offset, size_t start)
|
|
|
|
{
|
|
|
|
size_t pos = buf->len - start;
|
|
|
|
if (pos >= offset)
|
|
|
|
return;
|
|
|
|
wmem_strbuf_append_c_count(buf, ' ', offset - pos);
|
2023-01-05 18:48:16 +00:00
|
|
|
}
|
2023-01-07 02:40:14 +00:00
|
|
|
#define indent1(buf, start) indent(buf, 24, start)
|
|
|
|
#define indent2(buf, start) indent(buf, 16, start)
|
2023-01-05 18:48:16 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
append_to_register(wmem_strbuf_t *buf, const char *reg)
|
|
|
|
{
|
2023-01-10 15:06:01 +00:00
|
|
|
wmem_strbuf_append_printf(buf, " -> %s", reg);
|
2023-01-05 18:48:16 +00:00
|
|
|
}
|
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
static void
|
2023-01-10 15:42:32 +00:00
|
|
|
append_op_args(wmem_strbuf_t *buf, dfvm_insn_t *insn, GSList **stack_print,
|
|
|
|
uint16_t flags)
|
2001-02-01 20:21:25 +00:00
|
|
|
{
|
2022-05-13 12:46:43 +00:00
|
|
|
dfvm_value_t *arg1, *arg2, *arg3;
|
|
|
|
char *arg1_str, *arg2_str, *arg3_str;
|
2023-01-10 15:42:32 +00:00
|
|
|
char *arg1_str_type, *arg2_str_type, *arg3_str_type;
|
2023-01-07 02:40:14 +00:00
|
|
|
size_t col_start;
|
2014-02-25 20:42:35 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
arg1 = insn->arg1;
|
|
|
|
arg2 = insn->arg2;
|
|
|
|
arg3 = insn->arg3;
|
|
|
|
arg1_str = dfvm_value_tostr(arg1);
|
|
|
|
arg2_str = dfvm_value_tostr(arg2);
|
|
|
|
arg3_str = dfvm_value_tostr(arg3);
|
2023-01-10 15:42:32 +00:00
|
|
|
arg1_str_type = value_type_tostr(arg1, flags & DF_DUMP_SHOW_FTYPE);
|
|
|
|
arg2_str_type = value_type_tostr(arg2, flags & DF_DUMP_SHOW_FTYPE);
|
|
|
|
arg3_str_type = value_type_tostr(arg3, flags & DF_DUMP_SHOW_FTYPE);
|
2022-03-27 23:21:53 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
col_start = buf->len;
|
2012-02-29 05:58:45 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
switch (insn->op) {
|
|
|
|
case DFVM_CHECK_EXISTS:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s",
|
|
|
|
arg1_str, arg1_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
break;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2023-01-08 15:09:14 +00:00
|
|
|
case DFVM_CHECK_EXISTS_R:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s#[%s]%s",
|
|
|
|
arg1_str, arg2_str, arg1_str_type);
|
2023-01-08 15:09:14 +00:00
|
|
|
break;
|
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_READ_TREE:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s",
|
|
|
|
arg1_str, arg1_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
indent2(buf, col_start);
|
|
|
|
append_to_register(buf, arg2_str);
|
|
|
|
break;
|
2023-01-05 18:48:16 +00:00
|
|
|
|
2023-01-08 15:09:14 +00:00
|
|
|
case DFVM_READ_TREE_R:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s#[%s]%s",
|
|
|
|
arg1_str, arg3_str, arg1_str_type);
|
2023-01-08 15:09:14 +00:00
|
|
|
indent2(buf, col_start);
|
|
|
|
append_to_register(buf, arg2_str);
|
|
|
|
break;
|
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_READ_REFERENCE:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "${%s}%s",
|
|
|
|
arg1_str, arg1_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
indent2(buf, col_start);
|
|
|
|
append_to_register(buf, arg2_str);
|
|
|
|
break;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2023-01-08 15:09:14 +00:00
|
|
|
case DFVM_READ_REFERENCE_R:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "${%s#[%s]}%s",
|
|
|
|
arg1_str, arg3_str, arg1_str_type);
|
2023-01-08 15:09:14 +00:00
|
|
|
indent2(buf, col_start);
|
|
|
|
append_to_register(buf, arg2_str);
|
|
|
|
break;
|
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_PUT_FVALUE:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s",
|
|
|
|
arg1_str, arg1_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
indent2(buf, col_start);
|
|
|
|
append_to_register(buf, arg2_str);
|
|
|
|
break;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_CALL_FUNCTION:
|
|
|
|
append_call_function(buf, arg1_str, arg3->value.numeric, *stack_print);
|
|
|
|
indent2(buf, col_start);
|
|
|
|
append_to_register(buf, arg2_str);
|
|
|
|
break;
|
2022-04-09 22:03:40 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_STACK_PUSH:
|
|
|
|
wmem_strbuf_append_printf(buf, "%s", arg1_str);
|
|
|
|
*stack_print = dump_str_stack_push(*stack_print, arg1_str);
|
|
|
|
break;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_STACK_POP:
|
|
|
|
wmem_strbuf_append_printf(buf, "%s", arg1_str);
|
|
|
|
*stack_print = dump_str_stack_pop(*stack_print, arg1->value.numeric);
|
|
|
|
break;
|
2022-04-09 22:03:40 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_SLICE:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s[%s]%s",
|
|
|
|
arg1_str, arg3_str, arg1_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
indent2(buf, col_start);
|
|
|
|
append_to_register(buf, arg2_str);
|
|
|
|
break;
|
2022-04-16 01:42:20 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_LENGTH:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s",
|
|
|
|
arg1_str, arg1_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
indent2(buf, col_start);
|
|
|
|
append_to_register(buf, arg2_str);
|
|
|
|
break;
|
2022-04-16 01:42:20 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_ALL_EQ:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s === %s%s",
|
|
|
|
arg1_str, arg1_str_type, arg2_str, arg2_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
break;
|
2021-12-13 01:06:01 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_ANY_EQ:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s == %s%s",
|
|
|
|
arg1_str, arg1_str_type, arg2_str, arg2_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
break;
|
2022-07-03 22:07:36 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_ALL_NE:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s != %s%s",
|
|
|
|
arg1_str, arg1_str_type, arg2_str, arg2_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
break;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_ANY_NE:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s !== %s%s",
|
|
|
|
arg1_str, arg1_str_type, arg2_str, arg2_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
break;
|
2022-07-12 23:37:12 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_ALL_GT:
|
|
|
|
case DFVM_ANY_GT:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s > %s%s",
|
|
|
|
arg1_str, arg1_str_type, arg2_str, arg2_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
break;
|
2022-07-12 23:37:12 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_ALL_GE:
|
|
|
|
case DFVM_ANY_GE:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s >= %s%s",
|
|
|
|
arg1_str, arg1_str_type, arg2_str, arg2_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
break;
|
dfilter: Fix "!=" relation to be free of contradictions
Wireshark defines the relation of equality A == B as
A any_eq B <=> An == Bn for at least one An, Bn.
More accurately I think this is (formally) an equivalence
relation, not true equality.
Whichever definition for "==" we choose we must keep the
definition of "!=" as !(A == B), otherwise it will
lead to logical contradictions like (A == B) AND (A != B)
being true.
Fix the '!=' relation to match the definition of equality:
A != B <=> !(A == B) <=> A all_ne B <=> An != Bn, for
every n.
This has been the recomended way to write "not equal" for a
long time in the documentation, even to the point where != was
deprecated, but it just wasn't implemented consistently in the
language, which has understandably been a persistent source
of confusion. Even a field that is normally well-behaved
with "!=" like "ip.src" or "ip.dst" will produce unexpected
results with encapsulations like IP-over-IP.
The opcode ALL_NE could have been implemented in the compiler
instead using NOT and ANY_EQ but I chose to implement it in
bytecode. It just seemed more elegant and efficient
but the difference was not very significant.
Keep around "~=" for any_ne relation, in case someone depends
on that, and because we don't have an operator for true equality:
A strict_equal B <=> A all_eq B <=> !(A any_ne B).
If there is only one value then any_ne and all_ne are the same
comparison operation.
Implementing this change did not require fixing any tests so it
is unlikely the relation "~=" (any_ne) will be very useful.
Note that the behaviour of the '<' (less than) comparison relation
is a separate, more subtle issue. In the general case the definition
of '<' that is used is only a partial order.
2021-10-18 20:07:06 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_ALL_LT:
|
|
|
|
case DFVM_ANY_LT:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s < %s%s",
|
|
|
|
arg1_str, arg1_str_type, arg2_str, arg2_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
break;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_ALL_LE:
|
|
|
|
case DFVM_ANY_LE:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s <= %s%s",
|
|
|
|
arg1_str, arg1_str_type, arg2_str, arg2_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
break;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_NOT_ALL_ZERO:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s",
|
|
|
|
arg1_str, arg1_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
break;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_ALL_CONTAINS:
|
|
|
|
case DFVM_ANY_CONTAINS:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s contains %s%s",
|
|
|
|
arg1_str, arg1_str_type, arg2_str, arg2_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
break;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_ALL_MATCHES:
|
|
|
|
case DFVM_ANY_MATCHES:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s matches %s%s",
|
|
|
|
arg1_str, arg1_str_type, arg2_str, arg2_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
break;
|
2022-02-25 19:37:53 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_ALL_IN_RANGE:
|
|
|
|
case DFVM_ANY_IN_RANGE:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s in { %s%s .. %s%s }",
|
|
|
|
arg1_str, arg1_str_type, arg2_str, arg2_str_type, arg3_str, arg3_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
break;
|
2004-02-27 12:00:32 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_BITWISE_AND:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s & %s%s",
|
|
|
|
arg1_str, arg1_str_type, arg2_str, arg2_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
indent2(buf, col_start);
|
|
|
|
append_to_register(buf, arg3_str);
|
|
|
|
break;
|
2022-02-27 14:47:31 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_UNARY_MINUS:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "-%s%s",
|
|
|
|
arg1_str, arg1_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
indent2(buf, col_start);
|
|
|
|
append_to_register(buf, arg2_str);
|
|
|
|
break;
|
2022-02-27 14:47:31 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_ADD:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s + %s%s",
|
|
|
|
arg1_str, arg1_str_type, arg2_str, arg2_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
indent2(buf, col_start);
|
|
|
|
append_to_register(buf, arg3_str);
|
|
|
|
break;
|
2022-03-31 13:50:20 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_SUBTRACT:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s - %s%s",
|
|
|
|
arg1_str, arg1_str_type, arg2_str, arg2_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
indent2(buf, col_start);
|
|
|
|
append_to_register(buf, arg3_str);
|
|
|
|
break;
|
2022-03-31 13:50:20 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_MULTIPLY:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s * %s%s",
|
|
|
|
arg1_str, arg1_str_type, arg2_str, arg2_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
indent2(buf, col_start);
|
|
|
|
append_to_register(buf, arg3_str);
|
|
|
|
break;
|
2022-03-31 13:50:20 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_DIVIDE:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s / %s%s",
|
|
|
|
arg1_str, arg1_str_type, arg2_str, arg2_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
indent2(buf, col_start);
|
|
|
|
append_to_register(buf, arg3_str);
|
|
|
|
break;
|
2003-12-19 04:40:24 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_MODULO:
|
2023-01-10 15:42:32 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s%s %% %s%s",
|
|
|
|
arg1_str, arg1_str_type, arg2_str, arg2_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
indent2(buf, col_start);
|
|
|
|
append_to_register(buf, arg3_str);
|
|
|
|
break;
|
2003-12-19 04:40:24 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_IF_TRUE_GOTO:
|
|
|
|
case DFVM_IF_FALSE_GOTO:
|
|
|
|
wmem_strbuf_append_printf(buf, "%u", arg1->value.numeric);
|
|
|
|
break;
|
2018-04-14 16:07:22 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
case DFVM_NOT:
|
|
|
|
case DFVM_RETURN:
|
|
|
|
ws_assert_not_reached();
|
|
|
|
}
|
2022-02-27 09:56:41 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
g_free(arg1_str);
|
|
|
|
g_free(arg2_str);
|
|
|
|
g_free(arg3_str);
|
2023-01-10 15:42:32 +00:00
|
|
|
g_free(arg1_str_type);
|
|
|
|
g_free(arg2_str_type);
|
|
|
|
g_free(arg3_str_type);
|
2023-01-07 02:40:14 +00:00
|
|
|
}
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
static void
|
|
|
|
append_references(wmem_strbuf_t *buf, GHashTable *references, gboolean raw)
|
|
|
|
{
|
|
|
|
GHashTableIter ref_iter;
|
|
|
|
gpointer key, value;
|
|
|
|
char *str;
|
|
|
|
guint i;
|
2022-03-21 11:13:02 +00:00
|
|
|
|
2023-01-07 02:40:14 +00:00
|
|
|
g_hash_table_iter_init(&ref_iter, references);
|
|
|
|
while (g_hash_table_iter_next(&ref_iter, &key, &value)) {
|
|
|
|
const char *abbrev = ((header_field_info *)key)->abbrev;
|
|
|
|
GPtrArray *refs_array = value;
|
|
|
|
df_reference_t *ref;
|
|
|
|
|
|
|
|
if (raw)
|
|
|
|
wmem_strbuf_append_printf(buf, " ${@%s} = {", abbrev);
|
|
|
|
else
|
|
|
|
wmem_strbuf_append_printf(buf, " ${%s} = {", abbrev);
|
|
|
|
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");
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
2023-01-07 02:40:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
2023-01-10 15:42:32 +00:00
|
|
|
dfvm_dump_str(wmem_allocator_t *alloc, dfilter_t *df, uint16_t flags)
|
2023-01-07 02:40:14 +00:00
|
|
|
{
|
|
|
|
int id, length;
|
|
|
|
dfvm_insn_t *insn;
|
|
|
|
wmem_strbuf_t *buf;
|
|
|
|
GSList *stack_print = NULL;
|
|
|
|
size_t col_start;
|
|
|
|
|
|
|
|
buf = wmem_strbuf_new(alloc, NULL);
|
2022-03-27 15:38:39 +00:00
|
|
|
|
2023-01-10 15:42:32 +00:00
|
|
|
if ((flags & DF_DUMP_REFERENCES) && g_hash_table_size(df->references) > 0) {
|
2023-01-07 02:40:14 +00:00
|
|
|
wmem_strbuf_append(buf, "References:\n");
|
|
|
|
append_references(buf, df->references, FALSE);
|
|
|
|
wmem_strbuf_append_c(buf, '\n');
|
2022-03-27 14:26:46 +00:00
|
|
|
}
|
|
|
|
|
2023-01-10 15:42:32 +00:00
|
|
|
if ((flags & DF_DUMP_REFERENCES) && g_hash_table_size(df->raw_references) > 0) {
|
2023-01-07 02:40:14 +00:00
|
|
|
wmem_strbuf_append(buf, "Raw references:\n");
|
|
|
|
append_references(buf, df->raw_references, TRUE);
|
|
|
|
wmem_strbuf_append_c(buf, '\n');
|
|
|
|
}
|
|
|
|
|
|
|
|
wmem_strbuf_append(buf, "Instructions:");
|
|
|
|
|
|
|
|
length = df->insns->len;
|
|
|
|
for (id = 0; id < length; id++) {
|
|
|
|
insn = g_ptr_array_index(df->insns, id);
|
|
|
|
col_start = buf->len;
|
|
|
|
wmem_strbuf_append_printf(buf, "\n %04d %s", id, dfvm_opcode_tostr(insn->op));
|
|
|
|
|
|
|
|
switch (insn->op) {
|
|
|
|
case DFVM_NOT:
|
|
|
|
case DFVM_RETURN:
|
|
|
|
/* Nothing here */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
indent1(buf, col_start);
|
2023-01-10 15:42:32 +00:00
|
|
|
append_op_args(buf, insn, &stack_print, flags);
|
2023-01-07 02:40:14 +00:00
|
|
|
break;
|
2022-10-25 12:03:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-27 15:38:39 +00:00
|
|
|
return wmem_strbuf_finalize(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2023-01-10 15:42:32 +00:00
|
|
|
dfvm_dump(FILE *f, dfilter_t *df, uint16_t flags)
|
2022-03-27 15:38:39 +00:00
|
|
|
{
|
2023-01-10 15:42:32 +00:00
|
|
|
char *str = dfvm_dump_str(NULL, df, flags);
|
2022-03-27 15:38:39 +00:00
|
|
|
fputs(str, f);
|
2023-01-07 19:55:06 +00:00
|
|
|
fputc('\n', f);
|
2022-03-27 15:38:39 +00:00
|
|
|
wmem_free(NULL, str);
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
|
|
|
|
2022-04-09 22:03:40 +00:00
|
|
|
static int
|
|
|
|
compare_finfo_layer(gconstpointer _a, gconstpointer _b)
|
|
|
|
{
|
|
|
|
const field_info *a = *(const field_info **)_a;
|
|
|
|
const field_info *b = *(const field_info **)_b;
|
|
|
|
return a->proto_layer_num - b->proto_layer_num;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
drange_contains_layer(drange_t *dr, int num, int length)
|
|
|
|
{
|
|
|
|
drange_node *rn;
|
|
|
|
GSList *list = dr->range_list;
|
|
|
|
int lower, upper;
|
|
|
|
|
|
|
|
while (list) {
|
|
|
|
rn = list->data;
|
|
|
|
lower = rn->start_offset;
|
|
|
|
if (lower < 0) {
|
|
|
|
lower += length + 1;
|
|
|
|
}
|
|
|
|
if (rn->ending == DRANGE_NODE_END_T_LENGTH) {
|
|
|
|
upper = lower + rn->length - 1;
|
|
|
|
}
|
|
|
|
else if (rn->ending == DRANGE_NODE_END_T_OFFSET) {
|
|
|
|
upper = rn->end_offset;
|
|
|
|
}
|
|
|
|
else if (rn->ending == DRANGE_NODE_END_T_TO_THE_END) {
|
|
|
|
upper = INT_MAX;
|
|
|
|
}
|
2022-05-13 12:22:29 +00:00
|
|
|
else {
|
|
|
|
ws_assert_not_reached();
|
|
|
|
}
|
2022-04-09 22:03:40 +00:00
|
|
|
|
|
|
|
if (num >= lower && num <= upper) { /* inclusive */
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
list = g_slist_next(list);
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2022-10-25 12:03:08 +00:00
|
|
|
fvalue_t *
|
|
|
|
dfvm_get_raw_fvalue(const field_info *fi)
|
2022-10-25 03:20:18 +00:00
|
|
|
{
|
|
|
|
GByteArray *bytes;
|
|
|
|
fvalue_t *fv;
|
|
|
|
int length, tvb_length;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX - a field can have a length that runs past
|
|
|
|
* the end of the tvbuff. Ideally, that should
|
|
|
|
* be fixed when adding an item to the protocol
|
|
|
|
* tree, but checking the length when doing
|
|
|
|
* that could be expensive. Until we fix that,
|
|
|
|
* we'll do the check here.
|
|
|
|
*/
|
|
|
|
tvb_length = tvb_captured_length_remaining(fi->ds_tvb, fi->start);
|
|
|
|
if (tvb_length < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
length = fi->length;
|
|
|
|
if (length > tvb_length)
|
|
|
|
length = tvb_length;
|
|
|
|
|
|
|
|
bytes = g_byte_array_new();
|
|
|
|
g_byte_array_append(bytes, tvb_get_ptr(fi->ds_tvb, fi->start, length), length);
|
|
|
|
|
|
|
|
fv = fvalue_new(FT_BYTES);
|
|
|
|
fvalue_set_byte_array(fv, bytes);
|
|
|
|
return fv;
|
|
|
|
}
|
|
|
|
|
2022-07-13 19:07:27 +00:00
|
|
|
static GSList *
|
2022-10-25 03:20:18 +00:00
|
|
|
filter_finfo_fvalues(GSList *fvalues, GPtrArray *finfos, drange_t *range, gboolean raw)
|
2022-04-09 22:03:40 +00:00
|
|
|
{
|
|
|
|
int length; /* maximum proto layer number. The numbers are sequential. */
|
|
|
|
field_info *last_finfo, *finfo;
|
2022-10-25 03:20:18 +00:00
|
|
|
fvalue_t *fv;
|
2022-04-09 22:03:40 +00:00
|
|
|
int cookie = -1;
|
2022-04-27 06:46:21 +00:00
|
|
|
gboolean cookie_matches = false;
|
2022-04-09 22:03:40 +00:00
|
|
|
int layer;
|
|
|
|
|
|
|
|
g_ptr_array_sort(finfos, compare_finfo_layer);
|
|
|
|
last_finfo = finfos->pdata[finfos->len - 1];
|
|
|
|
length = last_finfo->proto_layer_num;
|
|
|
|
|
|
|
|
for (guint i = 0; i < finfos->len; i++) {
|
|
|
|
finfo = finfos->pdata[i];
|
|
|
|
layer = finfo->proto_layer_num;
|
|
|
|
if (cookie == layer) {
|
|
|
|
if (cookie_matches) {
|
2022-10-25 03:20:18 +00:00
|
|
|
if (raw)
|
2022-10-25 12:03:08 +00:00
|
|
|
fv = dfvm_get_raw_fvalue(finfo);
|
2022-10-25 03:20:18 +00:00
|
|
|
else
|
|
|
|
fv = &finfo->value;
|
|
|
|
fvalues = g_slist_prepend(fvalues, fv);
|
2022-04-09 22:03:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cookie = layer;
|
|
|
|
cookie_matches = drange_contains_layer(range, layer, length);
|
|
|
|
if (cookie_matches) {
|
2022-10-25 03:20:18 +00:00
|
|
|
if (raw)
|
2022-10-25 12:03:08 +00:00
|
|
|
fv = dfvm_get_raw_fvalue(finfo);
|
2022-10-25 03:20:18 +00:00
|
|
|
else
|
|
|
|
fv = &finfo->value;
|
|
|
|
fvalues = g_slist_prepend(fvalues, fv);
|
2022-04-09 22:03:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return fvalues;
|
|
|
|
}
|
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
/* Reads a field from the proto_tree and loads the fvalues into a register,
|
|
|
|
* if that field has not already been read. */
|
|
|
|
static gboolean
|
2022-03-21 12:19:54 +00:00
|
|
|
read_tree(dfilter_t *df, proto_tree *tree,
|
2022-04-09 22:03:40 +00:00
|
|
|
dfvm_value_t *arg1, dfvm_value_t *arg2,
|
|
|
|
dfvm_value_t *arg3)
|
2001-02-01 20:21:25 +00:00
|
|
|
{
|
|
|
|
GPtrArray *finfos;
|
|
|
|
field_info *finfo;
|
|
|
|
int i, len;
|
2022-03-21 11:43:28 +00:00
|
|
|
GSList *fvalues = NULL;
|
2022-10-25 03:20:18 +00:00
|
|
|
fvalue_t *fv;
|
2022-04-09 22:03:40 +00:00
|
|
|
drange_t *range = NULL;
|
2022-10-25 03:20:18 +00:00
|
|
|
gboolean raw;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2022-03-21 12:19:54 +00:00
|
|
|
header_field_info *hfinfo = arg1->value.hfinfo;
|
2022-10-25 03:20:18 +00:00
|
|
|
raw = arg1->type == RAW_HFINFO;
|
|
|
|
|
2022-03-21 12:19:54 +00:00
|
|
|
int reg = arg2->value.numeric;
|
|
|
|
|
2022-04-09 22:03:40 +00:00
|
|
|
if (arg3) {
|
|
|
|
range = arg3->value.drange;
|
|
|
|
}
|
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
/* Already loaded in this run of the dfilter? */
|
|
|
|
if (df->attempted_load[reg]) {
|
|
|
|
if (df->registers[reg]) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
df->attempted_load[reg] = TRUE;
|
|
|
|
|
2002-10-16 16:32:59 +00:00
|
|
|
while (hfinfo) {
|
|
|
|
finfos = proto_get_finfo_ptr_array(tree, hfinfo->id);
|
2012-06-11 02:09:48 +00:00
|
|
|
if ((finfos == NULL) || (g_ptr_array_len(finfos) == 0)) {
|
2002-10-16 16:32:59 +00:00
|
|
|
hfinfo = hfinfo->same_name_next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-04-09 22:03:40 +00:00
|
|
|
if (range) {
|
2022-10-25 03:20:18 +00:00
|
|
|
fvalues = filter_finfo_fvalues(fvalues, finfos, range, raw);
|
2022-04-09 22:03:40 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
len = finfos->len;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
finfo = g_ptr_array_index(finfos, i);
|
2022-10-25 03:20:18 +00:00
|
|
|
if (raw)
|
2022-10-25 12:03:08 +00:00
|
|
|
fv = dfvm_get_raw_fvalue(finfo);
|
2022-10-25 03:20:18 +00:00
|
|
|
else
|
|
|
|
fv = &finfo->value;
|
|
|
|
fvalues = g_slist_prepend(fvalues, fv);
|
2022-04-09 22:03:40 +00:00
|
|
|
}
|
2002-10-16 16:32:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
hfinfo = hfinfo->same_name_next;
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
2002-10-16 16:32:59 +00:00
|
|
|
|
2022-04-09 22:03:40 +00:00
|
|
|
if (fvalues == NULL) {
|
2002-10-16 16:32:59 +00:00
|
|
|
return FALSE;
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
df->registers[reg] = fvalues;
|
2022-10-25 03:20:18 +00:00
|
|
|
if (raw) {
|
|
|
|
df->free_registers[reg] = (GDestroyNotify)fvalue_free;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// These values are referenced only, do not try to free it later.
|
|
|
|
df->free_registers[reg] = NULL;
|
|
|
|
}
|
2001-02-01 20:21:25 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2022-07-13 19:07:27 +00:00
|
|
|
static GSList *
|
2022-06-23 23:07:42 +00:00
|
|
|
filter_refs_fvalues(GPtrArray *refs_array, drange_t *range)
|
|
|
|
{
|
|
|
|
int length; /* maximum proto layer number. The numbers are sequential. */
|
2022-06-27 08:52:18 +00:00
|
|
|
df_reference_t *last_ref = NULL;
|
2022-06-23 23:07:42 +00:00
|
|
|
int cookie = -1;
|
|
|
|
gboolean cookie_matches = false;
|
|
|
|
GSList *fvalues = NULL;
|
|
|
|
|
2022-06-27 08:52:18 +00:00
|
|
|
if (!refs_array || refs_array->len == 0) {
|
|
|
|
return fvalues;
|
|
|
|
}
|
|
|
|
|
2022-06-23 23:07:42 +00:00
|
|
|
/* 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++) {
|
2022-06-27 08:52:18 +00:00
|
|
|
df_reference_t *ref = refs_array->pdata[i];
|
|
|
|
int layer = ref->proto_layer_num;
|
|
|
|
|
2022-06-23 23:07:42 +00:00
|
|
|
if (range == NULL) {
|
2022-10-28 14:44:30 +00:00
|
|
|
fvalues = g_slist_prepend(fvalues, ref->value);
|
2022-06-23 23:07:42 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cookie == layer) {
|
|
|
|
if (cookie_matches) {
|
2022-10-28 14:44:30 +00:00
|
|
|
fvalues = g_slist_prepend(fvalues, ref->value);
|
2022-06-23 23:07:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
cookie = layer;
|
|
|
|
cookie_matches = drange_contains_layer(range, layer, length);
|
|
|
|
if (cookie_matches) {
|
2022-10-28 14:44:30 +00:00
|
|
|
fvalues = g_slist_prepend(fvalues, ref->value);
|
2022-06-23 23:07:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return fvalues;
|
|
|
|
}
|
|
|
|
|
2022-03-27 14:26:46 +00:00
|
|
|
static gboolean
|
2022-06-23 23:07:42 +00:00
|
|
|
read_reference(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *arg2,
|
|
|
|
dfvm_value_t *arg3)
|
2022-03-27 14:26:46 +00:00
|
|
|
{
|
2022-06-23 23:07:42 +00:00
|
|
|
GPtrArray *refs;
|
|
|
|
drange_t *range = NULL;
|
2022-10-25 12:03:08 +00:00
|
|
|
gboolean raw;
|
2022-03-27 14:26:46 +00:00
|
|
|
|
|
|
|
header_field_info *hfinfo = arg1->value.hfinfo;
|
2022-10-25 12:03:08 +00:00
|
|
|
raw = arg1->type == RAW_HFINFO;
|
|
|
|
|
2022-03-27 14:26:46 +00:00
|
|
|
int reg = arg2->value.numeric;
|
|
|
|
|
2022-06-23 23:07:42 +00:00
|
|
|
if (arg3) {
|
|
|
|
range = arg3->value.drange;
|
|
|
|
}
|
|
|
|
|
2022-03-27 14:26:46 +00:00
|
|
|
/* Already loaded in this run of the dfilter? */
|
|
|
|
if (df->attempted_load[reg]) {
|
|
|
|
if (df->registers[reg]) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
df->attempted_load[reg] = TRUE;
|
|
|
|
|
2022-10-25 12:03:08 +00:00
|
|
|
if (raw)
|
|
|
|
refs = g_hash_table_lookup(df->raw_references, hfinfo);
|
|
|
|
else
|
|
|
|
refs = g_hash_table_lookup(df->references, hfinfo);
|
2022-06-23 23:07:42 +00:00
|
|
|
if (refs == NULL || refs->len == 0) {
|
2022-03-27 14:26:46 +00:00
|
|
|
df->registers[reg] = NULL;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2022-06-23 23:07:42 +00:00
|
|
|
df->registers[reg] = filter_refs_fvalues(refs, range);
|
2022-10-28 14:44:30 +00:00
|
|
|
// These values are referenced only, do not try to free it later.
|
|
|
|
df->free_registers[reg] = NULL;
|
2022-03-27 14:26:46 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
dfilter: Fix "!=" relation to be free of contradictions
Wireshark defines the relation of equality A == B as
A any_eq B <=> An == Bn for at least one An, Bn.
More accurately I think this is (formally) an equivalence
relation, not true equality.
Whichever definition for "==" we choose we must keep the
definition of "!=" as !(A == B), otherwise it will
lead to logical contradictions like (A == B) AND (A != B)
being true.
Fix the '!=' relation to match the definition of equality:
A != B <=> !(A == B) <=> A all_ne B <=> An != Bn, for
every n.
This has been the recomended way to write "not equal" for a
long time in the documentation, even to the point where != was
deprecated, but it just wasn't implemented consistently in the
language, which has understandably been a persistent source
of confusion. Even a field that is normally well-behaved
with "!=" like "ip.src" or "ip.dst" will produce unexpected
results with encapsulations like IP-over-IP.
The opcode ALL_NE could have been implemented in the compiler
instead using NOT and ANY_EQ but I chose to implement it in
bytecode. It just seemed more elegant and efficient
but the difference was not very significant.
Keep around "~=" for any_ne relation, in case someone depends
on that, and because we don't have an operator for true equality:
A strict_equal B <=> A all_eq B <=> !(A any_ne B).
If there is only one value then any_ne and all_ne are the same
comparison operation.
Implementing this change did not require fixing any tests so it
is unlikely the relation "~=" (any_ne) will be very useful.
Note that the behaviour of the '<' (less than) comparison relation
is a separate, more subtle issue. In the general case the definition
of '<' that is used is only a partial order.
2021-10-18 20:07:06 +00:00
|
|
|
enum match_how {
|
|
|
|
MATCH_ANY,
|
|
|
|
MATCH_ALL
|
|
|
|
};
|
|
|
|
|
2022-07-05 19:24:30 +00:00
|
|
|
typedef ft_bool_t (*DFVMCompareFunc)(const fvalue_t*, const fvalue_t*);
|
|
|
|
typedef ft_bool_t (*DFVMTestFunc)(const fvalue_t*);
|
2001-02-01 20:21:25 +00:00
|
|
|
|
|
|
|
static gboolean
|
2022-12-25 19:46:07 +00:00
|
|
|
cmp_test_internal(enum match_how how, DFVMCompareFunc match_func,
|
2022-03-20 20:32:39 +00:00
|
|
|
GSList *arg1, GSList *arg2)
|
2001-02-01 20:21:25 +00:00
|
|
|
{
|
2022-03-20 20:32:39 +00:00
|
|
|
GSList *list1, *list2;
|
dfilter: Fix "!=" relation to be free of contradictions
Wireshark defines the relation of equality A == B as
A any_eq B <=> An == Bn for at least one An, Bn.
More accurately I think this is (formally) an equivalence
relation, not true equality.
Whichever definition for "==" we choose we must keep the
definition of "!=" as !(A == B), otherwise it will
lead to logical contradictions like (A == B) AND (A != B)
being true.
Fix the '!=' relation to match the definition of equality:
A != B <=> !(A == B) <=> A all_ne B <=> An != Bn, for
every n.
This has been the recomended way to write "not equal" for a
long time in the documentation, even to the point where != was
deprecated, but it just wasn't implemented consistently in the
language, which has understandably been a persistent source
of confusion. Even a field that is normally well-behaved
with "!=" like "ip.src" or "ip.dst" will produce unexpected
results with encapsulations like IP-over-IP.
The opcode ALL_NE could have been implemented in the compiler
instead using NOT and ANY_EQ but I chose to implement it in
bytecode. It just seemed more elegant and efficient
but the difference was not very significant.
Keep around "~=" for any_ne relation, in case someone depends
on that, and because we don't have an operator for true equality:
A strict_equal B <=> A all_eq B <=> !(A any_ne B).
If there is only one value then any_ne and all_ne are the same
comparison operation.
Implementing this change did not require fixing any tests so it
is unlikely the relation "~=" (any_ne) will be very useful.
Note that the behaviour of the '<' (less than) comparison relation
is a separate, more subtle issue. In the general case the definition
of '<' that is used is only a partial order.
2021-10-18 20:07:06 +00:00
|
|
|
gboolean want_all = (how == MATCH_ALL);
|
|
|
|
gboolean want_any = (how == MATCH_ANY);
|
2022-07-05 19:24:30 +00:00
|
|
|
ft_bool_t have_match;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2022-03-20 20:32:39 +00:00
|
|
|
list1 = arg1;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2022-03-20 20:32:39 +00:00
|
|
|
while (list1) {
|
|
|
|
list2 = arg2;
|
|
|
|
while (list2) {
|
|
|
|
have_match = match_func(list1->data, list2->data);
|
2022-07-05 19:24:30 +00:00
|
|
|
if (want_all && have_match == FT_FALSE) {
|
dfilter: Fix "!=" relation to be free of contradictions
Wireshark defines the relation of equality A == B as
A any_eq B <=> An == Bn for at least one An, Bn.
More accurately I think this is (formally) an equivalence
relation, not true equality.
Whichever definition for "==" we choose we must keep the
definition of "!=" as !(A == B), otherwise it will
lead to logical contradictions like (A == B) AND (A != B)
being true.
Fix the '!=' relation to match the definition of equality:
A != B <=> !(A == B) <=> A all_ne B <=> An != Bn, for
every n.
This has been the recomended way to write "not equal" for a
long time in the documentation, even to the point where != was
deprecated, but it just wasn't implemented consistently in the
language, which has understandably been a persistent source
of confusion. Even a field that is normally well-behaved
with "!=" like "ip.src" or "ip.dst" will produce unexpected
results with encapsulations like IP-over-IP.
The opcode ALL_NE could have been implemented in the compiler
instead using NOT and ANY_EQ but I chose to implement it in
bytecode. It just seemed more elegant and efficient
but the difference was not very significant.
Keep around "~=" for any_ne relation, in case someone depends
on that, and because we don't have an operator for true equality:
A strict_equal B <=> A all_eq B <=> !(A any_ne B).
If there is only one value then any_ne and all_ne are the same
comparison operation.
Implementing this change did not require fixing any tests so it
is unlikely the relation "~=" (any_ne) will be very useful.
Note that the behaviour of the '<' (less than) comparison relation
is a separate, more subtle issue. In the general case the definition
of '<' that is used is only a partial order.
2021-10-18 20:07:06 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2022-07-05 19:24:30 +00:00
|
|
|
else if (want_any && have_match == FT_TRUE) {
|
2001-02-01 20:21:25 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
2022-03-20 20:32:39 +00:00
|
|
|
list2 = g_slist_next(list2);
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
2022-03-20 20:32:39 +00:00
|
|
|
list1 = g_slist_next(list1);
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
dfilter: Fix "!=" relation to be free of contradictions
Wireshark defines the relation of equality A == B as
A any_eq B <=> An == Bn for at least one An, Bn.
More accurately I think this is (formally) an equivalence
relation, not true equality.
Whichever definition for "==" we choose we must keep the
definition of "!=" as !(A == B), otherwise it will
lead to logical contradictions like (A == B) AND (A != B)
being true.
Fix the '!=' relation to match the definition of equality:
A != B <=> !(A == B) <=> A all_ne B <=> An != Bn, for
every n.
This has been the recomended way to write "not equal" for a
long time in the documentation, even to the point where != was
deprecated, but it just wasn't implemented consistently in the
language, which has understandably been a persistent source
of confusion. Even a field that is normally well-behaved
with "!=" like "ip.src" or "ip.dst" will produce unexpected
results with encapsulations like IP-over-IP.
The opcode ALL_NE could have been implemented in the compiler
instead using NOT and ANY_EQ but I chose to implement it in
bytecode. It just seemed more elegant and efficient
but the difference was not very significant.
Keep around "~=" for any_ne relation, in case someone depends
on that, and because we don't have an operator for true equality:
A strict_equal B <=> A all_eq B <=> !(A any_ne B).
If there is only one value then any_ne and all_ne are the same
comparison operation.
Implementing this change did not require fixing any tests so it
is unlikely the relation "~=" (any_ne) will be very useful.
Note that the behaviour of the '<' (less than) comparison relation
is a separate, more subtle issue. In the general case the definition
of '<' that is used is only a partial order.
2021-10-18 20:07:06 +00:00
|
|
|
/* want_all || !want_any */
|
|
|
|
return want_all;
|
|
|
|
}
|
|
|
|
|
2022-02-25 19:37:53 +00:00
|
|
|
static gboolean
|
|
|
|
cmp_test_unary(enum match_how how, DFVMTestFunc test_func, GSList *arg1)
|
|
|
|
{
|
|
|
|
GSList *list1;
|
|
|
|
gboolean want_all = (how == MATCH_ALL);
|
|
|
|
gboolean want_any = (how == MATCH_ANY);
|
2022-07-05 19:24:30 +00:00
|
|
|
ft_bool_t have_match;
|
2022-02-25 19:37:53 +00:00
|
|
|
|
|
|
|
list1 = arg1;
|
|
|
|
|
|
|
|
while (list1) {
|
|
|
|
have_match = test_func(list1->data);
|
2022-07-05 19:24:30 +00:00
|
|
|
if (want_all && have_match == FT_FALSE) {
|
2022-02-25 19:37:53 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2022-07-05 19:24:30 +00:00
|
|
|
else if (want_any && have_match == FT_TRUE) {
|
2022-02-25 19:37:53 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
list1 = g_slist_next(list1);
|
|
|
|
}
|
|
|
|
/* want_all || !want_any */
|
|
|
|
return want_all;
|
|
|
|
}
|
|
|
|
|
2022-03-23 00:50:24 +00:00
|
|
|
static gboolean
|
|
|
|
all_test_unary(dfilter_t *df, DFVMTestFunc func, dfvm_value_t *arg1)
|
|
|
|
{
|
|
|
|
ws_assert(arg1->type == REGISTER);
|
|
|
|
GSList *list1 = df->registers[arg1->value.numeric];
|
|
|
|
return cmp_test_unary(MATCH_ALL, func, list1);
|
|
|
|
}
|
|
|
|
|
2022-03-20 20:32:39 +00:00
|
|
|
static gboolean
|
2022-12-25 19:46:07 +00:00
|
|
|
cmp_test(dfilter_t *df, DFVMCompareFunc cmp,
|
|
|
|
dfvm_value_t *arg1, dfvm_value_t *arg2,
|
|
|
|
enum match_how how)
|
dfilter: Fix "!=" relation to be free of contradictions
Wireshark defines the relation of equality A == B as
A any_eq B <=> An == Bn for at least one An, Bn.
More accurately I think this is (formally) an equivalence
relation, not true equality.
Whichever definition for "==" we choose we must keep the
definition of "!=" as !(A == B), otherwise it will
lead to logical contradictions like (A == B) AND (A != B)
being true.
Fix the '!=' relation to match the definition of equality:
A != B <=> !(A == B) <=> A all_ne B <=> An != Bn, for
every n.
This has been the recomended way to write "not equal" for a
long time in the documentation, even to the point where != was
deprecated, but it just wasn't implemented consistently in the
language, which has understandably been a persistent source
of confusion. Even a field that is normally well-behaved
with "!=" like "ip.src" or "ip.dst" will produce unexpected
results with encapsulations like IP-over-IP.
The opcode ALL_NE could have been implemented in the compiler
instead using NOT and ANY_EQ but I chose to implement it in
bytecode. It just seemed more elegant and efficient
but the difference was not very significant.
Keep around "~=" for any_ne relation, in case someone depends
on that, and because we don't have an operator for true equality:
A strict_equal B <=> A all_eq B <=> !(A any_ne B).
If there is only one value then any_ne and all_ne are the same
comparison operation.
Implementing this change did not require fixing any tests so it
is unlikely the relation "~=" (any_ne) will be very useful.
Note that the behaviour of the '<' (less than) comparison relation
is a separate, more subtle issue. In the general case the definition
of '<' that is used is only a partial order.
2021-10-18 20:07:06 +00:00
|
|
|
{
|
2022-12-25 19:46:07 +00:00
|
|
|
GSList list1, list2, *l1, *l2;
|
dfilter: Fix "!=" relation to be free of contradictions
Wireshark defines the relation of equality A == B as
A any_eq B <=> An == Bn for at least one An, Bn.
More accurately I think this is (formally) an equivalence
relation, not true equality.
Whichever definition for "==" we choose we must keep the
definition of "!=" as !(A == B), otherwise it will
lead to logical contradictions like (A == B) AND (A != B)
being true.
Fix the '!=' relation to match the definition of equality:
A != B <=> !(A == B) <=> A all_ne B <=> An != Bn, for
every n.
This has been the recomended way to write "not equal" for a
long time in the documentation, even to the point where != was
deprecated, but it just wasn't implemented consistently in the
language, which has understandably been a persistent source
of confusion. Even a field that is normally well-behaved
with "!=" like "ip.src" or "ip.dst" will produce unexpected
results with encapsulations like IP-over-IP.
The opcode ALL_NE could have been implemented in the compiler
instead using NOT and ANY_EQ but I chose to implement it in
bytecode. It just seemed more elegant and efficient
but the difference was not very significant.
Keep around "~=" for any_ne relation, in case someone depends
on that, and because we don't have an operator for true equality:
A strict_equal B <=> A all_eq B <=> !(A any_ne B).
If there is only one value then any_ne and all_ne are the same
comparison operation.
Implementing this change did not require fixing any tests so it
is unlikely the relation "~=" (any_ne) will be very useful.
Note that the behaviour of the '<' (less than) comparison relation
is a separate, more subtle issue. In the general case the definition
of '<' that is used is only a partial order.
2021-10-18 20:07:06 +00:00
|
|
|
|
2022-12-25 19:46:07 +00:00
|
|
|
if (arg1->type == REGISTER) {
|
|
|
|
l1 = df->registers[arg1->value.numeric];
|
|
|
|
}
|
|
|
|
else if (arg1->type == FVALUE) {
|
|
|
|
list1.data = arg1->value.fvalue;
|
|
|
|
list1.next = NULL;
|
|
|
|
l1 = &list1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ws_assert_not_reached();
|
2022-03-20 20:32:39 +00:00
|
|
|
}
|
|
|
|
|
2022-12-25 19:46:07 +00:00
|
|
|
if (arg2->type == REGISTER) {
|
|
|
|
l2 = df->registers[arg2->value.numeric];
|
|
|
|
}
|
|
|
|
else if (arg2->type == FVALUE) {
|
2022-03-20 20:32:39 +00:00
|
|
|
list2.data = arg2->value.fvalue;
|
|
|
|
list2.next = NULL;
|
2022-12-25 19:46:07 +00:00
|
|
|
l2 = &list2;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ws_assert_not_reached();
|
2022-03-20 20:32:39 +00:00
|
|
|
}
|
2022-12-25 19:46:07 +00:00
|
|
|
|
|
|
|
return cmp_test_internal(how, cmp, l1, l2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* cmp(A) <=> cmp(a1) OR cmp(a2) OR cmp(a3) OR ... */
|
|
|
|
static inline gboolean
|
|
|
|
any_test(dfilter_t *df, DFVMCompareFunc cmp,
|
|
|
|
dfvm_value_t *arg1, dfvm_value_t *arg2)
|
|
|
|
{
|
|
|
|
return cmp_test(df, cmp, arg1, arg2, MATCH_ANY);
|
dfilter: Fix "!=" relation to be free of contradictions
Wireshark defines the relation of equality A == B as
A any_eq B <=> An == Bn for at least one An, Bn.
More accurately I think this is (formally) an equivalence
relation, not true equality.
Whichever definition for "==" we choose we must keep the
definition of "!=" as !(A == B), otherwise it will
lead to logical contradictions like (A == B) AND (A != B)
being true.
Fix the '!=' relation to match the definition of equality:
A != B <=> !(A == B) <=> A all_ne B <=> An != Bn, for
every n.
This has been the recomended way to write "not equal" for a
long time in the documentation, even to the point where != was
deprecated, but it just wasn't implemented consistently in the
language, which has understandably been a persistent source
of confusion. Even a field that is normally well-behaved
with "!=" like "ip.src" or "ip.dst" will produce unexpected
results with encapsulations like IP-over-IP.
The opcode ALL_NE could have been implemented in the compiler
instead using NOT and ANY_EQ but I chose to implement it in
bytecode. It just seemed more elegant and efficient
but the difference was not very significant.
Keep around "~=" for any_ne relation, in case someone depends
on that, and because we don't have an operator for true equality:
A strict_equal B <=> A all_eq B <=> !(A any_ne B).
If there is only one value then any_ne and all_ne are the same
comparison operation.
Implementing this change did not require fixing any tests so it
is unlikely the relation "~=" (any_ne) will be very useful.
Note that the behaviour of the '<' (less than) comparison relation
is a separate, more subtle issue. In the general case the definition
of '<' that is used is only a partial order.
2021-10-18 20:07:06 +00:00
|
|
|
}
|
|
|
|
|
2022-03-21 12:19:54 +00:00
|
|
|
/* cmp(A) <=> cmp(a1) AND cmp(a2) AND cmp(a3) AND ... */
|
2022-03-20 20:32:39 +00:00
|
|
|
static gboolean
|
2022-03-21 12:19:54 +00:00
|
|
|
all_test(dfilter_t *df, DFVMCompareFunc cmp,
|
|
|
|
dfvm_value_t *arg1, dfvm_value_t *arg2)
|
2021-12-13 01:06:01 +00:00
|
|
|
{
|
2022-12-25 19:46:07 +00:00
|
|
|
return cmp_test(df, cmp, arg1, arg2, MATCH_ALL);
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
|
|
|
|
2021-03-21 10:06:17 +00:00
|
|
|
static gboolean
|
2022-03-21 12:19:54 +00:00
|
|
|
any_matches(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *arg2)
|
2021-03-21 10:06:17 +00:00
|
|
|
{
|
2022-03-20 20:32:39 +00:00
|
|
|
GSList *list1 = df->registers[arg1->value.numeric];
|
|
|
|
ws_regex_t *re = arg2->value.pcre;
|
2021-03-21 10:06:17 +00:00
|
|
|
|
2022-03-20 20:32:39 +00:00
|
|
|
while (list1) {
|
2022-07-05 19:24:30 +00:00
|
|
|
if (fvalue_matches(list1->data, re) == FT_TRUE) {
|
2022-03-20 20:32:39 +00:00
|
|
|
return TRUE;
|
2021-03-21 10:06:17 +00:00
|
|
|
}
|
2022-03-20 20:32:39 +00:00
|
|
|
list1 = g_slist_next(list1);
|
2021-03-21 10:06:17 +00:00
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2022-04-19 23:04:05 +00:00
|
|
|
static gboolean
|
|
|
|
all_matches(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *arg2)
|
|
|
|
{
|
|
|
|
GSList *list1 = df->registers[arg1->value.numeric];
|
|
|
|
ws_regex_t *re = arg2->value.pcre;
|
|
|
|
|
|
|
|
while (list1) {
|
2022-07-05 19:24:30 +00:00
|
|
|
if (fvalue_matches(list1->data, re) == FT_FALSE) {
|
2022-04-19 23:04:05 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
list1 = g_slist_next(list1);
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2018-04-14 16:07:22 +00:00
|
|
|
static gboolean
|
2022-04-16 01:42:20 +00:00
|
|
|
any_in_range_internal(GSList *list1, fvalue_t *low, fvalue_t *high)
|
2018-04-14 16:07:22 +00:00
|
|
|
{
|
|
|
|
while (list1) {
|
2022-07-05 19:24:30 +00:00
|
|
|
if (fvalue_ge(list1->data, low) == FT_TRUE &&
|
|
|
|
fvalue_le(list1->data, high) == FT_TRUE) {
|
2018-04-14 16:07:22 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
2022-03-21 11:43:28 +00:00
|
|
|
list1 = g_slist_next(list1);
|
2018-04-14 16:07:22 +00:00
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2022-04-16 01:42:20 +00:00
|
|
|
static gboolean
|
2022-04-19 23:04:05 +00:00
|
|
|
all_in_range_internal(GSList *list1, fvalue_t *low, fvalue_t *high)
|
|
|
|
{
|
|
|
|
while (list1) {
|
2022-07-05 19:24:30 +00:00
|
|
|
if (fvalue_ge(list1->data, low) == FT_FALSE ||
|
|
|
|
fvalue_le(list1->data, high) == FT_FALSE) {
|
2022-04-19 23:04:05 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
list1 = g_slist_next(list1);
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
match_in_range(dfilter_t *df, enum match_how how, dfvm_value_t *arg1,
|
2022-04-16 01:42:20 +00:00
|
|
|
dfvm_value_t *arg_low, dfvm_value_t *arg_high)
|
|
|
|
{
|
|
|
|
GSList *list1 = df->registers[arg1->value.numeric];
|
|
|
|
GSList *_low, *_high;
|
|
|
|
fvalue_t *low, *high;
|
|
|
|
|
|
|
|
if (arg_low->type == REGISTER) {
|
|
|
|
_low = df->registers[arg_low->value.numeric];
|
|
|
|
ws_assert(g_slist_length(_low) == 1);
|
|
|
|
low = _low->data;
|
|
|
|
}
|
|
|
|
else if (arg_low->type == FVALUE) {
|
|
|
|
low = arg_low->value.fvalue;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ws_assert_not_reached();
|
|
|
|
}
|
|
|
|
if (arg_high->type == REGISTER) {
|
|
|
|
_high = df->registers[arg_high->value.numeric];
|
|
|
|
ws_assert(g_slist_length(_high) == 1);
|
|
|
|
high = _high->data;
|
|
|
|
}
|
|
|
|
else if (arg_high->type == FVALUE) {
|
|
|
|
high = arg_high->value.fvalue;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ws_assert_not_reached();
|
|
|
|
}
|
2022-04-19 23:04:05 +00:00
|
|
|
|
|
|
|
if (how == MATCH_ALL)
|
|
|
|
return all_in_range_internal(list1, low, high);
|
|
|
|
else if (how == MATCH_ANY)
|
|
|
|
return any_in_range_internal(list1, low, high);
|
|
|
|
else
|
|
|
|
ws_assert_not_reached();
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
any_in_range(dfilter_t *df, dfvm_value_t *arg1,
|
|
|
|
dfvm_value_t *arg_low, dfvm_value_t *arg_high)
|
|
|
|
{
|
|
|
|
return match_in_range(df, MATCH_ANY, arg1, arg_low, arg_high);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
all_in_range(dfilter_t *df, dfvm_value_t *arg1,
|
|
|
|
dfvm_value_t *arg_low, dfvm_value_t *arg_high)
|
|
|
|
{
|
|
|
|
return match_in_range(df, MATCH_ALL, arg1, arg_low, arg_high);
|
2022-04-16 01:42:20 +00:00
|
|
|
}
|
|
|
|
|
2022-03-21 16:48:06 +00:00
|
|
|
/* Clear registers that were populated during evaluation.
|
|
|
|
* If we created the values, then these will be freed as well. */
|
2001-02-01 20:21:25 +00:00
|
|
|
static void
|
|
|
|
free_register_overhead(dfilter_t* df)
|
|
|
|
{
|
2009-10-18 23:25:33 +00:00
|
|
|
guint i;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
|
|
|
for (i = 0; i < df->num_registers; i++) {
|
2007-11-28 22:13:50 +00:00
|
|
|
df->attempted_load[i] = FALSE;
|
2001-02-01 20:21:25 +00:00
|
|
|
if (df->registers[i]) {
|
2022-03-18 12:47:29 +00:00
|
|
|
if (df->free_registers[i]) {
|
|
|
|
for (GSList *l = df->registers[i]; l != NULL; l = l->next) {
|
|
|
|
df->free_registers[i](l->data);
|
|
|
|
}
|
|
|
|
df->free_registers[i] = NULL;
|
2018-04-24 20:34:26 +00:00
|
|
|
}
|
2022-03-21 11:43:28 +00:00
|
|
|
g_slist_free(df->registers[i]);
|
2007-11-28 22:13:50 +00:00
|
|
|
df->registers[i] = NULL;
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Takes the list of fvalue_t's in a register, uses fvalue_slice()
|
2022-04-11 19:06:49 +00:00
|
|
|
* to make a new list of fvalue_t's (which are byte-slices),
|
2001-02-01 20:21:25 +00:00
|
|
|
* and puts the new list into a new register. */
|
|
|
|
static void
|
2022-04-11 19:06:49 +00:00
|
|
|
mk_slice(dfilter_t *df, dfvm_value_t *from_arg, dfvm_value_t *to_arg,
|
2022-03-21 12:19:54 +00:00
|
|
|
dfvm_value_t *drange_arg)
|
2001-02-01 20:21:25 +00:00
|
|
|
{
|
2022-03-21 11:43:28 +00:00
|
|
|
GSList *from_list, *to_list;
|
2001-02-01 20:21:25 +00:00
|
|
|
fvalue_t *old_fv, *new_fv;
|
|
|
|
|
|
|
|
to_list = NULL;
|
2022-03-21 12:19:54 +00:00
|
|
|
from_list = df->registers[from_arg->value.numeric];
|
|
|
|
drange_t *drange = drange_arg->value.drange;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
|
|
|
while (from_list) {
|
2022-03-21 12:19:54 +00:00
|
|
|
old_fv = from_list->data;
|
|
|
|
new_fv = fvalue_slice(old_fv, drange);
|
2001-02-27 19:23:30 +00:00
|
|
|
/* Assert here because semcheck.c should have
|
2001-02-01 20:21:25 +00:00
|
|
|
* already caught the cases in which a slice
|
|
|
|
* cannot be made. */
|
2021-06-18 18:21:42 +00:00
|
|
|
ws_assert(new_fv);
|
2022-03-21 11:43:28 +00:00
|
|
|
to_list = g_slist_prepend(to_list, new_fv);
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2022-03-21 11:43:28 +00:00
|
|
|
from_list = g_slist_next(from_list);
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
|
|
|
|
2022-03-21 12:19:54 +00:00
|
|
|
df->registers[to_arg->value.numeric] = to_list;
|
2022-03-18 12:47:29 +00:00
|
|
|
df->free_registers[to_arg->value.numeric] = (GDestroyNotify)fvalue_free;
|
2001-02-01 20:21:25 +00:00
|
|
|
}
|
|
|
|
|
2022-07-03 22:07:36 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-03-21 12:19:54 +00:00
|
|
|
static gboolean
|
|
|
|
call_function(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *arg2,
|
2022-04-16 01:42:20 +00:00
|
|
|
dfvm_value_t *arg3)
|
2022-03-21 12:19:54 +00:00
|
|
|
{
|
|
|
|
df_func_def_t *funcdef;
|
|
|
|
GSList *retval = NULL;
|
|
|
|
gboolean accum;
|
2022-04-16 01:42:20 +00:00
|
|
|
guint32 reg_return, arg_count;
|
2022-03-21 12:19:54 +00:00
|
|
|
|
|
|
|
funcdef = arg1->value.funcdef;
|
2022-04-12 15:13:08 +00:00
|
|
|
reg_return = arg2->value.numeric;
|
2022-04-16 01:42:20 +00:00
|
|
|
arg_count = arg3->value.numeric;
|
2022-04-12 15:13:08 +00:00
|
|
|
|
2022-04-16 01:42:20 +00:00
|
|
|
accum = funcdef->function(df->function_stack, arg_count, &retval);
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2022-04-12 15:13:08 +00:00
|
|
|
/* Write return registers. */
|
|
|
|
df->registers[reg_return] = retval;
|
2022-03-21 12:19:54 +00:00
|
|
|
// functions create a new value, so own it.
|
2022-04-12 15:13:08 +00:00
|
|
|
df->free_registers[reg_return] = (GDestroyNotify)fvalue_free;
|
2022-03-21 12:19:54 +00:00
|
|
|
return accum;
|
|
|
|
}
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2022-02-25 19:37:53 +00:00
|
|
|
static void debug_op_error(fvalue_t *v1, fvalue_t *v2, const char *op, const char *msg)
|
|
|
|
{
|
|
|
|
char *s1 = fvalue_to_debug_repr(NULL, v1);
|
|
|
|
char *s2 = fvalue_to_debug_repr(NULL, v2);
|
|
|
|
ws_noisy("Error: %s %s %s: %s", s1, op, s2, msg);
|
|
|
|
g_free(s1);
|
|
|
|
g_free(s2);
|
|
|
|
}
|
|
|
|
|
2022-04-12 15:13:08 +00:00
|
|
|
/* Used for temporary debugging only, don't leave in production code (at
|
|
|
|
* a minimum WS_DEBUG_HERE must be replaced by another log level). */
|
2022-02-27 14:47:31 +00:00
|
|
|
static void _U_
|
|
|
|
debug_register(GSList *reg, guint32 num)
|
|
|
|
{
|
|
|
|
wmem_strbuf_t *buf;
|
|
|
|
GSList *l;
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
buf = wmem_strbuf_new(NULL, NULL);
|
|
|
|
|
|
|
|
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);
|
2022-06-23 23:07:42 +00:00
|
|
|
wmem_strbuf_append_printf(buf, "%s <%s>", s, fvalue_type_name(l->data));
|
2022-02-27 14:47:31 +00:00
|
|
|
g_free(s);
|
2022-06-23 23:07:42 +00:00
|
|
|
if (l->next != NULL) {
|
|
|
|
wmem_strbuf_append(buf, ", ");
|
|
|
|
}
|
2022-02-27 14:47:31 +00:00
|
|
|
}
|
|
|
|
wmem_strbuf_append_c(buf, '}');
|
2022-04-12 15:13:08 +00:00
|
|
|
WS_DEBUG_HERE("%s", wmem_strbuf_get_str(buf));
|
2022-02-27 14:47:31 +00:00
|
|
|
wmem_strbuf_destroy(buf);
|
|
|
|
}
|
|
|
|
|
2022-02-25 19:37:53 +00:00
|
|
|
|
2022-02-27 14:47:31 +00:00
|
|
|
typedef fvalue_t* (*DFVMBinaryFunc)(const fvalue_t*, const fvalue_t*, char **);
|
2022-02-25 19:37:53 +00:00
|
|
|
|
|
|
|
static void
|
2022-02-27 14:47:31 +00:00
|
|
|
mk_binary_internal(DFVMBinaryFunc func,
|
2022-02-25 19:37:53 +00:00
|
|
|
GSList *arg1, GSList *arg2, GSList **retval)
|
|
|
|
{
|
|
|
|
GSList *list1, *list2;
|
|
|
|
GSList *to_list = NULL;
|
|
|
|
fvalue_t *val1, *val2;
|
|
|
|
fvalue_t *result;
|
|
|
|
char *err_msg = NULL;
|
|
|
|
|
|
|
|
list1 = arg1;
|
|
|
|
while (list1) {
|
|
|
|
list2 = arg2;
|
|
|
|
while (list2) {
|
|
|
|
val1 = list1->data;
|
|
|
|
val2 = list2->data;
|
|
|
|
result = func(val1, val2, &err_msg);
|
|
|
|
if (result == NULL) {
|
|
|
|
debug_op_error(val1, val2, "&", err_msg);
|
|
|
|
g_free(err_msg);
|
|
|
|
err_msg = NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
to_list = g_slist_prepend(to_list, result);
|
|
|
|
}
|
|
|
|
list2 = g_slist_next(list2);
|
|
|
|
}
|
|
|
|
list1 = g_slist_next(list1);
|
|
|
|
}
|
|
|
|
*retval = to_list;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2022-02-27 14:47:31 +00:00
|
|
|
mk_binary(dfilter_t *df, DFVMBinaryFunc func,
|
2022-02-25 19:37:53 +00:00
|
|
|
dfvm_value_t *arg1, dfvm_value_t *arg2, dfvm_value_t *to_arg)
|
|
|
|
{
|
2022-02-27 14:47:31 +00:00
|
|
|
GSList ls1, ls2;
|
|
|
|
GSList *list1, *list2;
|
2022-02-25 19:37:53 +00:00
|
|
|
GSList *result = NULL;
|
|
|
|
|
2022-02-27 14:47:31 +00:00
|
|
|
if (arg1->type == REGISTER) {
|
|
|
|
list1 = df->registers[arg1->value.numeric];
|
|
|
|
}
|
|
|
|
else if (arg1->type == FVALUE) {
|
|
|
|
ls1.data = arg1->value.fvalue;
|
|
|
|
ls1.next = NULL;
|
|
|
|
list1 = &ls1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ws_assert_not_reached();
|
|
|
|
}
|
2022-02-25 19:37:53 +00:00
|
|
|
|
2022-02-27 14:47:31 +00:00
|
|
|
if (arg2->type == REGISTER) {
|
|
|
|
list2 = df->registers[arg2->value.numeric];
|
2022-02-25 19:37:53 +00:00
|
|
|
}
|
|
|
|
else if (arg2->type == FVALUE) {
|
2022-02-27 14:47:31 +00:00
|
|
|
ls2.data = arg2->value.fvalue;
|
|
|
|
ls2.next = NULL;
|
|
|
|
list2 = &ls2;
|
2022-02-25 19:37:53 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
ws_assert_not_reached();
|
|
|
|
}
|
2022-02-27 14:47:31 +00:00
|
|
|
|
|
|
|
mk_binary_internal(func, list1, list2, &result);
|
|
|
|
//debug_register(result, to_arg->value.numeric);
|
|
|
|
|
2022-02-25 19:37:53 +00:00
|
|
|
df->registers[to_arg->value.numeric] = result;
|
|
|
|
df->free_registers[to_arg->value.numeric] = (GDestroyNotify)fvalue_free;
|
|
|
|
}
|
|
|
|
|
2022-02-27 09:56:41 +00:00
|
|
|
static void
|
|
|
|
mk_minus_internal(GSList *arg1, GSList **retval)
|
|
|
|
{
|
|
|
|
GSList *list1;
|
|
|
|
GSList *to_list = NULL;
|
|
|
|
fvalue_t *val1;
|
|
|
|
fvalue_t *result;
|
|
|
|
char *err_msg = NULL;
|
|
|
|
|
|
|
|
list1 = arg1;
|
|
|
|
while (list1) {
|
|
|
|
val1 = list1->data;
|
|
|
|
result = fvalue_unary_minus(val1, &err_msg);
|
|
|
|
if (result == NULL) {
|
|
|
|
ws_noisy("unary_minus: %s", err_msg);
|
|
|
|
g_free(err_msg);
|
|
|
|
err_msg = NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
to_list = g_slist_prepend(to_list, result);
|
|
|
|
}
|
|
|
|
list1 = g_slist_next(list1);
|
|
|
|
}
|
|
|
|
*retval = to_list;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
mk_minus(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *to_arg)
|
|
|
|
{
|
2022-12-25 19:46:07 +00:00
|
|
|
GSList ls1;
|
|
|
|
GSList *list1;
|
2022-02-27 09:56:41 +00:00
|
|
|
GSList *result = NULL;
|
|
|
|
|
2022-12-25 19:46:07 +00:00
|
|
|
if (arg1->type == REGISTER) {
|
|
|
|
list1 = df->registers[arg1->value.numeric];
|
|
|
|
}
|
|
|
|
else if (arg1->type == FVALUE) {
|
|
|
|
ls1.data = arg1->value.fvalue;
|
|
|
|
ls1.next = NULL;
|
|
|
|
list1 = &ls1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ws_assert_not_reached();
|
|
|
|
}
|
|
|
|
|
2022-02-27 09:56:41 +00:00
|
|
|
mk_minus_internal(list1, &result);
|
|
|
|
|
|
|
|
df->registers[to_arg->value.numeric] = result;
|
|
|
|
df->free_registers[to_arg->value.numeric] = (GDestroyNotify)fvalue_free;
|
|
|
|
}
|
|
|
|
|
2022-04-12 15:13:08 +00:00
|
|
|
static void
|
|
|
|
put_fvalue(dfilter_t *df, dfvm_value_t *arg1, dfvm_value_t *to_arg)
|
|
|
|
{
|
|
|
|
fvalue_t *fv = arg1->value.fvalue;
|
|
|
|
df->registers[to_arg->value.numeric] = g_slist_append(NULL, fv);
|
|
|
|
|
|
|
|
/* Memory is owned by the dfvm_value_t. */
|
|
|
|
df->free_registers[to_arg->value.numeric] = NULL;
|
|
|
|
}
|
|
|
|
|
2022-04-16 01:42:20 +00:00
|
|
|
static void
|
|
|
|
stack_push(dfilter_t *df, dfvm_value_t *arg1)
|
|
|
|
{
|
|
|
|
GSList *arg;
|
|
|
|
|
|
|
|
if (arg1->type == FVALUE) {
|
|
|
|
arg = g_slist_prepend(NULL, arg1->value.fvalue);
|
|
|
|
}
|
|
|
|
else if (arg1->type == REGISTER) {
|
|
|
|
arg = g_slist_copy(df->registers[arg1->value.numeric]);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ws_assert_not_reached();
|
|
|
|
}
|
|
|
|
df->function_stack = g_slist_prepend(df->function_stack, arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
stack_pop(dfilter_t *df, dfvm_value_t *arg1)
|
|
|
|
{
|
|
|
|
guint count;
|
|
|
|
GSList *reg;
|
|
|
|
|
|
|
|
count = arg1->value.numeric;
|
|
|
|
|
|
|
|
for (guint i = 0; i < count; i++) {
|
|
|
|
/* Free top of stack and register contained there. The register
|
|
|
|
* contentes are not owned by us. */
|
|
|
|
reg = df->function_stack->data;
|
|
|
|
/* Free the list but not the data it contains. */
|
|
|
|
g_slist_free(reg);
|
|
|
|
/* remove top of stack */
|
|
|
|
df->function_stack = g_slist_delete_link(df->function_stack, df->function_stack);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-09 22:03:40 +00:00
|
|
|
static gboolean
|
|
|
|
check_exists(proto_tree *tree, dfvm_value_t *arg1, dfvm_value_t *arg2)
|
|
|
|
{
|
|
|
|
GPtrArray *finfos;
|
|
|
|
header_field_info *hfinfo;
|
|
|
|
drange_t *range = NULL;
|
|
|
|
gboolean exists;
|
|
|
|
GSList *fvalues;
|
|
|
|
|
|
|
|
hfinfo = arg1->value.hfinfo;
|
|
|
|
if (arg2)
|
|
|
|
range = arg2->value.drange;
|
|
|
|
|
|
|
|
while (hfinfo) {
|
|
|
|
finfos = proto_get_finfo_ptr_array(tree, hfinfo->id);
|
|
|
|
if ((finfos == NULL) || (g_ptr_array_len(finfos) == 0)) {
|
|
|
|
hfinfo = hfinfo->same_name_next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (range == NULL) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2022-10-25 03:20:18 +00:00
|
|
|
fvalues = filter_finfo_fvalues(NULL, finfos, range, FALSE);
|
2022-04-09 22:03:40 +00:00
|
|
|
exists = (fvalues != NULL);
|
|
|
|
g_slist_free(fvalues);
|
|
|
|
if (exists) {
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
hfinfo = hfinfo->same_name_next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
gboolean
|
2002-05-09 23:50:34 +00:00
|
|
|
dfvm_apply(dfilter_t *df, proto_tree *tree)
|
2001-02-01 20:21:25 +00:00
|
|
|
{
|
2007-11-28 22:13:50 +00:00
|
|
|
int id, length;
|
2001-02-01 20:21:25 +00:00
|
|
|
gboolean accum = TRUE;
|
|
|
|
dfvm_insn_t *insn;
|
|
|
|
dfvm_value_t *arg1;
|
|
|
|
dfvm_value_t *arg2;
|
2006-05-02 14:26:17 +00:00
|
|
|
dfvm_value_t *arg3 = NULL;
|
2001-02-01 20:21:25 +00:00
|
|
|
|
2021-06-18 18:21:42 +00:00
|
|
|
ws_assert(tree);
|
2001-02-01 20:21:25 +00:00
|
|
|
|
|
|
|
length = df->insns->len;
|
|
|
|
|
|
|
|
for (id = 0; id < length; id++) {
|
|
|
|
|
|
|
|
AGAIN:
|
2022-03-21 12:19:54 +00:00
|
|
|
insn = g_ptr_array_index(df->insns, id);
|
2001-02-01 20:21:25 +00:00
|
|
|
arg1 = insn->arg1;
|
|
|
|
arg2 = insn->arg2;
|
2022-03-21 12:19:54 +00:00
|
|
|
arg3 = insn->arg3;
|
2022-04-16 01:42:20 +00:00
|
|
|
|
2001-02-01 20:21:25 +00:00
|
|
|
switch (insn->op) {
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_CHECK_EXISTS:
|
2022-04-09 22:03:40 +00:00
|
|
|
accum = check_exists(tree, arg1, NULL);
|
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_CHECK_EXISTS_R:
|
2022-04-09 22:03:40 +00:00
|
|
|
accum = check_exists(tree, arg1, arg2);
|
2001-02-01 20:21:25 +00:00
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_READ_TREE:
|
2022-04-09 22:03:40 +00:00
|
|
|
accum = read_tree(df, tree, arg1, arg2, NULL);
|
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_READ_TREE_R:
|
2022-04-09 22:03:40 +00:00
|
|
|
accum = read_tree(df, tree, arg1, arg2, arg3);
|
2001-02-01 20:21:25 +00:00
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_READ_REFERENCE:
|
2022-06-23 23:07:42 +00:00
|
|
|
accum = read_reference(df, arg1, arg2, NULL);
|
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_READ_REFERENCE_R:
|
2022-06-23 23:07:42 +00:00
|
|
|
accum = read_reference(df, arg1, arg2, arg3);
|
2022-03-27 14:26:46 +00:00
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_PUT_FVALUE:
|
2022-04-12 15:13:08 +00:00
|
|
|
put_fvalue(df, arg1, arg2);
|
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_CALL_FUNCTION:
|
2022-04-16 01:42:20 +00:00
|
|
|
accum = call_function(df, arg1, arg2, arg3);
|
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_STACK_PUSH:
|
2022-04-16 01:42:20 +00:00
|
|
|
stack_push(df, arg1);
|
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_STACK_POP:
|
2022-04-16 01:42:20 +00:00
|
|
|
stack_pop(df, arg1);
|
2006-05-02 14:26:17 +00:00
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_SLICE:
|
2022-04-11 19:06:49 +00:00
|
|
|
mk_slice(df, arg1, arg2, arg3);
|
2001-02-01 20:21:25 +00:00
|
|
|
break;
|
|
|
|
|
2022-07-03 22:07:36 +00:00
|
|
|
case DFVM_LENGTH:
|
|
|
|
mk_length(df, arg1, arg2);
|
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ALL_EQ:
|
2022-03-21 12:19:54 +00:00
|
|
|
accum = all_test(df, fvalue_eq, arg1, arg2);
|
2021-12-13 01:06:01 +00:00
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ANY_EQ:
|
2022-03-21 12:19:54 +00:00
|
|
|
accum = any_test(df, fvalue_eq, arg1, arg2);
|
dfilter: Fix "!=" relation to be free of contradictions
Wireshark defines the relation of equality A == B as
A any_eq B <=> An == Bn for at least one An, Bn.
More accurately I think this is (formally) an equivalence
relation, not true equality.
Whichever definition for "==" we choose we must keep the
definition of "!=" as !(A == B), otherwise it will
lead to logical contradictions like (A == B) AND (A != B)
being true.
Fix the '!=' relation to match the definition of equality:
A != B <=> !(A == B) <=> A all_ne B <=> An != Bn, for
every n.
This has been the recomended way to write "not equal" for a
long time in the documentation, even to the point where != was
deprecated, but it just wasn't implemented consistently in the
language, which has understandably been a persistent source
of confusion. Even a field that is normally well-behaved
with "!=" like "ip.src" or "ip.dst" will produce unexpected
results with encapsulations like IP-over-IP.
The opcode ALL_NE could have been implemented in the compiler
instead using NOT and ANY_EQ but I chose to implement it in
bytecode. It just seemed more elegant and efficient
but the difference was not very significant.
Keep around "~=" for any_ne relation, in case someone depends
on that, and because we don't have an operator for true equality:
A strict_equal B <=> A all_eq B <=> !(A any_ne B).
If there is only one value then any_ne and all_ne are the same
comparison operation.
Implementing this change did not require fixing any tests so it
is unlikely the relation "~=" (any_ne) will be very useful.
Note that the behaviour of the '<' (less than) comparison relation
is a separate, more subtle issue. In the general case the definition
of '<' that is used is only a partial order.
2021-10-18 20:07:06 +00:00
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ALL_NE:
|
2022-03-21 12:19:54 +00:00
|
|
|
accum = all_test(df, fvalue_ne, arg1, arg2);
|
2001-02-01 20:21:25 +00:00
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ANY_NE:
|
2022-03-21 12:19:54 +00:00
|
|
|
accum = any_test(df, fvalue_ne, arg1, arg2);
|
2001-02-01 20:21:25 +00:00
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ALL_GT:
|
2022-04-19 23:04:05 +00:00
|
|
|
accum = all_test(df, fvalue_gt, arg1, arg2);
|
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ANY_GT:
|
2022-03-21 12:19:54 +00:00
|
|
|
accum = any_test(df, fvalue_gt, arg1, arg2);
|
2001-02-01 20:21:25 +00:00
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ALL_GE:
|
2022-04-19 23:04:05 +00:00
|
|
|
accum = all_test(df, fvalue_ge, arg1, arg2);
|
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ANY_GE:
|
2022-03-21 12:19:54 +00:00
|
|
|
accum = any_test(df, fvalue_ge, arg1, arg2);
|
2001-02-01 20:21:25 +00:00
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ALL_LT:
|
2022-04-19 23:04:05 +00:00
|
|
|
accum = all_test(df, fvalue_lt, arg1, arg2);
|
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ANY_LT:
|
2022-03-21 12:19:54 +00:00
|
|
|
accum = any_test(df, fvalue_lt, arg1, arg2);
|
2001-02-01 20:21:25 +00:00
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ALL_LE:
|
2022-04-19 23:04:05 +00:00
|
|
|
accum = all_test(df, fvalue_le, arg1, arg2);
|
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ANY_LE:
|
2022-03-21 12:19:54 +00:00
|
|
|
accum = any_test(df, fvalue_le, arg1, arg2);
|
2001-02-01 20:21:25 +00:00
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_BITWISE_AND:
|
2022-02-27 14:47:31 +00:00
|
|
|
mk_binary(df, fvalue_bitwise_and, arg1, arg2, arg3);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DFVM_ADD:
|
|
|
|
mk_binary(df, fvalue_add, arg1, arg2, arg3);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DFVM_SUBTRACT:
|
|
|
|
mk_binary(df, fvalue_subtract, arg1, arg2, arg3);
|
2022-02-25 19:37:53 +00:00
|
|
|
break;
|
|
|
|
|
2022-03-31 13:50:20 +00:00
|
|
|
case DFVM_MULTIPLY:
|
|
|
|
mk_binary(df, fvalue_multiply, arg1, arg2, arg3);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DFVM_DIVIDE:
|
|
|
|
mk_binary(df, fvalue_divide, arg1, arg2, arg3);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DFVM_MODULO:
|
|
|
|
mk_binary(df, fvalue_modulo, arg1, arg2, arg3);
|
|
|
|
break;
|
|
|
|
|
2022-07-05 08:51:49 +00:00
|
|
|
case DFVM_NOT_ALL_ZERO:
|
|
|
|
accum = !all_test_unary(df, fvalue_is_zero, arg1);
|
2022-03-23 00:50:24 +00:00
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ALL_CONTAINS:
|
2022-04-19 23:04:05 +00:00
|
|
|
accum = all_test(df, fvalue_contains, arg1, arg2);
|
2004-02-27 12:00:32 +00:00
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ANY_CONTAINS:
|
2022-03-21 12:19:54 +00:00
|
|
|
accum = any_test(df, fvalue_contains, arg1, arg2);
|
2003-08-27 15:23:11 +00:00
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ALL_MATCHES:
|
2022-04-19 23:04:05 +00:00
|
|
|
accum = all_matches(df, arg1, arg2);
|
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ANY_MATCHES:
|
2022-03-21 12:19:54 +00:00
|
|
|
accum = any_matches(df, arg1, arg2);
|
2003-12-06 16:35:20 +00:00
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ALL_IN_RANGE:
|
2022-04-19 23:04:05 +00:00
|
|
|
accum = all_in_range(df, arg1, arg2, arg3);
|
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_ANY_IN_RANGE:
|
2022-03-21 12:19:54 +00:00
|
|
|
accum = any_in_range(df, arg1, arg2, arg3);
|
2018-04-14 16:07:22 +00:00
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_UNARY_MINUS:
|
2022-02-27 09:56:41 +00:00
|
|
|
mk_minus(df, arg1, arg2);
|
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_NOT:
|
2001-02-01 20:21:25 +00:00
|
|
|
accum = !accum;
|
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_RETURN:
|
2001-02-01 20:21:25 +00:00
|
|
|
free_register_overhead(df);
|
|
|
|
return accum;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_IF_TRUE_GOTO:
|
2001-02-01 20:21:25 +00:00
|
|
|
if (accum) {
|
|
|
|
id = arg1->value.numeric;
|
|
|
|
goto AGAIN;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2022-06-27 06:28:00 +00:00
|
|
|
case DFVM_IF_FALSE_GOTO:
|
2001-02-01 20:21:25 +00:00
|
|
|
if (!accum) {
|
|
|
|
id = arg1->value.numeric;
|
|
|
|
goto AGAIN;
|
|
|
|
}
|
|
|
|
break;
|
2007-11-28 22:44:37 +00:00
|
|
|
}
|
|
|
|
}
|
2022-03-21 16:48:06 +00:00
|
|
|
|
|
|
|
ws_assert_not_reached();
|
2007-11-28 22:44:37 +00:00
|
|
|
}
|
2015-02-13 19:02:43 +00:00
|
|
|
|
|
|
|
/*
|
2019-07-26 18:43:17 +00:00
|
|
|
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
2015-02-13 19:02:43 +00:00
|
|
|
*
|
|
|
|
* 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:
|
|
|
|
*/
|