1012 lines
24 KiB
C
1012 lines
24 KiB
C
/* dfilter.c
|
|
* Routines for display filters
|
|
*
|
|
* $Id: dfilter.c,v 1.32 1999/11/15 06:32:13 gram Exp $
|
|
*
|
|
* Ethereal - Network traffic analyzer
|
|
* By Gerald Combs <gerald@zing.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
# include <sys/types.h>
|
|
#endif
|
|
|
|
#ifndef _STDIO_H
|
|
#include <stdio.h>
|
|
#endif
|
|
|
|
#ifndef _STRING_H
|
|
#include <string.h>
|
|
#endif
|
|
|
|
#ifdef NEED_SNPRINTF_H
|
|
# ifdef HAVE_STDARG_H
|
|
# include <stdarg.h>
|
|
# else
|
|
# include <varargs.h>
|
|
# endif
|
|
# include "snprintf.h"
|
|
#endif
|
|
|
|
#ifndef __G_LIB_H__
|
|
#include <glib.h>
|
|
#endif
|
|
|
|
#ifndef __PROTO_H__
|
|
#include "proto.h"
|
|
#endif
|
|
|
|
#ifndef __DFILTER_H__
|
|
#include "dfilter.h"
|
|
#endif
|
|
|
|
#ifndef __UTIL_H__
|
|
#include "util.h"
|
|
#endif
|
|
|
|
#include "dfilter-int.h"
|
|
#include "dfilter-grammar.h"
|
|
|
|
int dfilter_parse(void); /* yacc entry-point */
|
|
|
|
#define DFILTER_LEX_ABBREV_OFFSET 2000
|
|
|
|
/* Balanced tree of abbreviations and IDs */
|
|
GTree *dfilter_tokens = NULL;
|
|
|
|
/* Comparision function for tree insertion. A wrapper around strcmp() */
|
|
static int g_strcmp(gconstpointer a, gconstpointer b);
|
|
|
|
/* Silly global variables used to pass parameter to check_relation_bytes() */
|
|
int bytes_offset = 0;
|
|
int bytes_length = 0;
|
|
|
|
YYSTYPE yylval;
|
|
|
|
/* Global error message space for dfilter_compile errors */
|
|
gchar dfilter_error_msg_buf[1024];
|
|
gchar *dfilter_error_msg; /* NULL when no error resulted */
|
|
|
|
static gboolean dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8 *pd);
|
|
static gboolean check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd);
|
|
static gboolean check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd);
|
|
static GArray* get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd);
|
|
static GArray* get_values_from_dfilter(dfilter_node *dnode, GNode *gnode);
|
|
static gboolean check_existence_in_ptree(dfilter_node *dnode, proto_tree *ptree);
|
|
static void clear_byte_array(gpointer data, gpointer user_data);
|
|
|
|
/* this is not so pretty. I need my own g_array "function" (macro) to
|
|
* retreive the pointer to the data stored in an array cell. I need this
|
|
* for type ether.. GArray makes it easy for me to store 6 bytes inside an array
|
|
* cell, but hard to retrieve it.
|
|
*/
|
|
#define g_array_index_ptr(a,s,i) (((guint8*) (a)->data) + (i*s))
|
|
|
|
void
|
|
dfilter_init(void)
|
|
{
|
|
int i, num_symbols, symbol;
|
|
char *s;
|
|
|
|
dfilter_tokens = g_tree_new(g_strcmp);
|
|
|
|
/* Add the header field and protocol abbrevs to the symbol table */
|
|
num_symbols = proto_registrar_n();
|
|
for (i=0; i < num_symbols; i++) {
|
|
s = proto_registrar_get_abbrev(i);
|
|
if (s) {
|
|
symbol = DFILTER_LEX_ABBREV_OFFSET + i;
|
|
g_tree_insert(dfilter_tokens, s, GINT_TO_POINTER(symbol));
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
dfilter_cleanup(void)
|
|
{
|
|
if (dfilter_tokens)
|
|
g_tree_destroy(dfilter_tokens);
|
|
}
|
|
|
|
/* Compiles the textual representation of the display filter into a tree
|
|
* of operations to perform. Can be called multiple times, compiling a new
|
|
* display filter each time, without having to clear any memory used, since
|
|
* dfilter_compile will take care of that automatically.
|
|
*
|
|
* Returns 0 on success, non-zero on failure.
|
|
*
|
|
* On success, sets the "dfilter *" pointed to by its second argument
|
|
* either to a null pointer (if the filter is a null filter, as
|
|
* generated by an all-blank string) or to a pointer to a newly-allocated
|
|
* dfilter structure (if the filter isn't null).
|
|
*
|
|
* On failure, "dfilter_error_msg" points to an appropriate error message.
|
|
* This error message is a global string, so another invocation of
|
|
* dfilter_compile will clear it. If the caller needs is stored, he
|
|
* needs to g_strdup it himself.
|
|
*/
|
|
int
|
|
dfilter_compile(gchar *dfilter_text, dfilter **dfp)
|
|
{
|
|
dfilter *df;
|
|
int retval;
|
|
|
|
g_assert(dfilter_text != NULL);
|
|
|
|
df = dfilter_new();
|
|
|
|
/* tell the scanner to use the filter string as input */
|
|
dfilter_scanner_text(dfilter_text);
|
|
|
|
/* Assign global variable so dfilter_parse knows which dfilter we're
|
|
* talking about. Reset the global error message.
|
|
*/
|
|
global_df = df;
|
|
dfilter_error_msg = NULL;
|
|
|
|
/* The magic happens right here. */
|
|
retval = dfilter_parse();
|
|
|
|
/* clean up lex */
|
|
dfilter_scanner_cleanup();
|
|
|
|
/* Errors not found by the parser may not cause the parse to
|
|
* fail; if "dfilter_error_msg" is set, it means somebody
|
|
* else called "dfilter_fail()", e.g. the lexical analyzer,
|
|
* so treat that as a parse error. */
|
|
if (dfilter_error_msg != NULL)
|
|
retval = 1;
|
|
|
|
if (retval != 0) {
|
|
if (dfilter_error_msg == NULL) {
|
|
snprintf(dfilter_error_msg_buf, sizeof(dfilter_error_msg_buf),
|
|
"Unable to parse filter string \"%s\".",
|
|
dfilter_text);
|
|
dfilter_error_msg = &dfilter_error_msg_buf[0];
|
|
}
|
|
}
|
|
|
|
/* Set global_df to NULL just to be tidy. */
|
|
global_df = NULL;
|
|
|
|
if (retval == 0) {
|
|
/* Success. Check if the filter is empty; if so, discard
|
|
* it and set "*dfp" to NULL, otherwise set "*dfp" to
|
|
* point to the filter. */
|
|
if (df->dftree == NULL) {
|
|
/* The filter is empty. */
|
|
dfilter_destroy(df);
|
|
df = NULL;
|
|
}
|
|
*dfp = df;
|
|
} else {
|
|
/* Failure. Destroy the filter. */
|
|
dfilter_destroy(df);
|
|
df = NULL;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/* Allocates new dfilter, initializes values, and returns pointer to dfilter */
|
|
dfilter*
|
|
dfilter_new(void)
|
|
{
|
|
dfilter *df;
|
|
|
|
df = g_malloc(sizeof(dfilter));
|
|
|
|
df->dftree = NULL;
|
|
df->node_memchunk = g_mem_chunk_new("df->node_memchunk",
|
|
sizeof(dfilter_node), 20 * sizeof(dfilter_node), G_ALLOC_ONLY);
|
|
df->list_of_byte_arrays = NULL;
|
|
|
|
return df;
|
|
}
|
|
|
|
/* Frees all memory used by dfilter, and frees dfilter itself */
|
|
void
|
|
dfilter_destroy(dfilter *df)
|
|
{
|
|
if (!df)
|
|
return;
|
|
|
|
if (df->dftree != NULL)
|
|
g_node_destroy(df->dftree);
|
|
|
|
/* clear the memory that the tree was using for nodes */
|
|
if (df->node_memchunk)
|
|
g_mem_chunk_reset(df->node_memchunk);
|
|
|
|
/* clear the memory that the tree was using for byte arrays */
|
|
if (df->list_of_byte_arrays) {
|
|
g_slist_foreach(df->list_of_byte_arrays, clear_byte_array, NULL);
|
|
g_slist_free(df->list_of_byte_arrays);
|
|
}
|
|
|
|
df->dftree = NULL;
|
|
df->list_of_byte_arrays = NULL;
|
|
|
|
/* Git rid of memchunk */
|
|
if (df->node_memchunk)
|
|
g_mem_chunk_destroy(df->node_memchunk);
|
|
|
|
g_free(df);
|
|
}
|
|
|
|
|
|
static void
|
|
clear_byte_array(gpointer data, gpointer user_data)
|
|
{
|
|
GByteArray *barray = data;
|
|
if (barray)
|
|
g_byte_array_free(barray, TRUE);
|
|
}
|
|
|
|
/* Called when the yacc grammar finds a parsing error */
|
|
void
|
|
dfilter_error(char *s)
|
|
{
|
|
}
|
|
|
|
/* Called when an error other than a parsing error occurs. */
|
|
void
|
|
dfilter_fail(char *format, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
/* If we've already reported one error, don't overwrite it with this
|
|
* one. */
|
|
if (dfilter_error_msg != NULL)
|
|
return;
|
|
|
|
va_start(ap, format);
|
|
vsnprintf(dfilter_error_msg_buf, sizeof dfilter_error_msg_buf, format, ap);
|
|
dfilter_error_msg = dfilter_error_msg_buf;
|
|
va_end(ap);
|
|
}
|
|
|
|
/* lookup an abbreviation in our token tree, returing the ID #
|
|
* If the abbreviation doesn't exit, returns -1 */
|
|
int dfilter_lookup_token(char *abbrev)
|
|
{
|
|
int value;
|
|
|
|
g_assert(abbrev != NULL);
|
|
value = GPOINTER_TO_INT(g_tree_lookup(dfilter_tokens, abbrev));
|
|
|
|
if (value < DFILTER_LEX_ABBREV_OFFSET) {
|
|
return -1;
|
|
}
|
|
return value - DFILTER_LEX_ABBREV_OFFSET;
|
|
}
|
|
|
|
static int
|
|
g_strcmp(gconstpointer a, gconstpointer b)
|
|
{
|
|
return strcmp((const char*)a, (const char*)b);
|
|
}
|
|
|
|
|
|
gboolean
|
|
dfilter_apply(dfilter *dfcode, proto_tree *ptree, const guint8* pd)
|
|
{
|
|
gboolean retval;
|
|
if (dfcode == NULL)
|
|
return FALSE;
|
|
retval = dfilter_apply_node(dfcode->dftree, ptree, pd);
|
|
return retval;
|
|
}
|
|
|
|
static gboolean
|
|
dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8* pd)
|
|
{
|
|
GNode *gnode_a, *gnode_b;
|
|
dfilter_node *dnode = (dfilter_node*) (gnode->data);
|
|
|
|
/* We'll get 2 NULLs if we don't have children */
|
|
gnode_a = g_node_nth_child(gnode, 0);
|
|
gnode_b = g_node_nth_child(gnode, 1);
|
|
|
|
switch(dnode->ntype) {
|
|
case variable:
|
|
/* We'll never see this case because if the parser finds the name of
|
|
* a variable, it will cause it to be an 'existence' operation.
|
|
*/
|
|
g_assert_not_reached();
|
|
|
|
case logical:
|
|
g_assert(gnode_a);
|
|
return check_logical(dnode->value.logical, gnode_a, gnode_b, ptree, pd);
|
|
|
|
case relation:
|
|
g_assert(gnode_a && gnode_b);
|
|
return check_relation(dnode->value.relation, gnode_a, gnode_b, ptree, pd);
|
|
|
|
case alternation:
|
|
g_assert_not_reached();
|
|
/* not coded yet */
|
|
|
|
case numeric:
|
|
case floating:
|
|
case ipv4:
|
|
case ipv6:
|
|
case boolean:
|
|
case ether:
|
|
case string:
|
|
case abs_time:
|
|
case bytes:
|
|
case ipxnet:
|
|
/* the only time we'll see these at this point is if the display filter
|
|
* is really wacky. (like simply "192.168.1.1"). The parser as it stands
|
|
* now let these by. Just return TRUE */
|
|
g_assert(!gnode_a && !gnode_b);
|
|
return TRUE;
|
|
|
|
case existence: /* checking the existence of a protocol or hf*/
|
|
g_assert(!gnode_a && !gnode_b);
|
|
return check_existence_in_ptree(dnode, ptree);
|
|
}
|
|
|
|
g_assert_not_reached();
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd)
|
|
{
|
|
gboolean val_a = dfilter_apply_node(a, ptree, pd);
|
|
gboolean val_b;
|
|
|
|
switch(operand) {
|
|
case TOK_AND:
|
|
g_assert(b);
|
|
return (val_a && dfilter_apply_node(b, ptree, pd));
|
|
case TOK_OR:
|
|
g_assert(b);
|
|
return (val_a || dfilter_apply_node(b, ptree, pd));
|
|
case TOK_XOR:
|
|
g_assert(b);
|
|
val_b = dfilter_apply_node(b, ptree, pd);
|
|
return ( ( val_a || val_b ) && ! ( val_a && val_b ) );
|
|
case TOK_NOT:
|
|
return (!val_a);
|
|
default:
|
|
g_assert_not_reached();
|
|
}
|
|
g_assert_not_reached();
|
|
return FALSE;
|
|
}
|
|
|
|
/* this is inefficient. I get arrays for both a and b that represent all the values present. That is,
|
|
* if a is bootp.option, e.g., i'll get an array showing all the bootp.option values in the protocol
|
|
* tree. Then I'll get an array for b, which more than likely is a single int, and then I'll compare
|
|
* them all. It makes my coding easier in the beginning, but I should change this to make it run
|
|
* faster.
|
|
*/
|
|
static gboolean
|
|
check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8* pd)
|
|
{
|
|
dfilter_node *node_a = (dfilter_node*) (a->data);
|
|
dfilter_node *node_b = (dfilter_node*) (b->data);
|
|
GArray *vals_a, *vals_b;
|
|
gboolean retval;
|
|
|
|
|
|
bytes_length = MIN(node_a->length, node_b->length);
|
|
bytes_offset = MIN(node_a->offset, node_b->offset);
|
|
if (node_a->ntype == variable)
|
|
vals_a = get_values_from_ptree(node_a, ptree, pd);
|
|
else
|
|
vals_a = get_values_from_dfilter(node_a, a);
|
|
|
|
if (node_b->ntype == variable)
|
|
vals_b = get_values_from_ptree(node_b, ptree, pd);
|
|
else
|
|
vals_b = get_values_from_dfilter(node_b, b);
|
|
|
|
retval = node_a->check_relation_func(operand, vals_a, vals_b);
|
|
|
|
g_array_free(vals_a, FALSE);
|
|
g_array_free(vals_b, FALSE);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static gboolean
|
|
check_existence_in_ptree(dfilter_node *dnode, proto_tree *ptree)
|
|
{
|
|
int target;
|
|
|
|
target = dnode->value.variable;
|
|
return proto_check_for_protocol_or_field(ptree, target);
|
|
}
|
|
|
|
static GArray*
|
|
get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd)
|
|
{
|
|
GArray *array;
|
|
int parent_protocol;
|
|
proto_tree_search_info sinfo;
|
|
|
|
g_assert(dnode->elem_size > 0);
|
|
array = g_array_new(FALSE, FALSE, dnode->elem_size);
|
|
|
|
sinfo.target = dnode->value.variable;
|
|
sinfo.result.array = array;
|
|
sinfo.packet_data = pd;
|
|
sinfo.traverse_func = dnode->fill_array_func;
|
|
|
|
/* Find the proto_tree subtree where we should start searching.*/
|
|
if (proto_registrar_is_protocol(sinfo.target)) {
|
|
proto_find_protocol_multi(ptree, sinfo.target,
|
|
(GNodeTraverseFunc)proto_get_field_values, &sinfo);
|
|
}
|
|
else {
|
|
parent_protocol = proto_registrar_get_parent(sinfo.target);
|
|
if (parent_protocol >= 0) {
|
|
proto_find_protocol_multi(ptree, parent_protocol,
|
|
(GNodeTraverseFunc)proto_get_field_values, &sinfo);
|
|
}
|
|
}
|
|
|
|
return array;
|
|
}
|
|
|
|
static GArray*
|
|
get_values_from_dfilter(dfilter_node *dnode, GNode *gnode)
|
|
{
|
|
GArray *array;
|
|
|
|
g_assert(dnode->elem_size > 0);
|
|
array = g_array_new(FALSE, FALSE, dnode->elem_size);
|
|
|
|
g_node_traverse(gnode, G_IN_ORDER, G_TRAVERSE_ALL, -1, dnode->fill_array_func, array);
|
|
return array;
|
|
}
|
|
|
|
gboolean fill_array_numeric_variable(GNode *gnode, gpointer data)
|
|
{
|
|
proto_tree_search_info *sinfo = (proto_tree_search_info*)data;
|
|
field_info *fi = (field_info*) (gnode->data);
|
|
|
|
if (fi->hfinfo->id == sinfo->target) {
|
|
g_array_append_val(sinfo->result.array, fi->value.numeric);
|
|
}
|
|
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
}
|
|
|
|
gboolean fill_array_floating_variable(GNode *gnode, gpointer data)
|
|
{
|
|
proto_tree_search_info *sinfo = (proto_tree_search_info*)data;
|
|
field_info *fi = (field_info*) (gnode->data);
|
|
|
|
if (fi->hfinfo->id == sinfo->target) {
|
|
g_array_append_val(sinfo->result.array, fi->value.floating);
|
|
}
|
|
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
}
|
|
|
|
gboolean fill_array_ether_variable(GNode *gnode, gpointer data)
|
|
{
|
|
proto_tree_search_info *sinfo = (proto_tree_search_info*)data;
|
|
field_info *fi = (field_info*) (gnode->data);
|
|
|
|
if (fi->hfinfo->id == sinfo->target) {
|
|
g_array_append_val(sinfo->result.array, fi->value.ether);
|
|
}
|
|
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
}
|
|
|
|
gboolean fill_array_ipv4_variable(GNode *gnode, gpointer data)
|
|
{
|
|
proto_tree_search_info *sinfo = (proto_tree_search_info*)data;
|
|
field_info *fi = (field_info*) (gnode->data);
|
|
|
|
if (fi->hfinfo->id == sinfo->target) {
|
|
g_array_append_val(sinfo->result.array, fi->value.ipv4);
|
|
}
|
|
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
}
|
|
gboolean fill_array_ipv6_variable(GNode *gnode, gpointer data)
|
|
{
|
|
proto_tree_search_info *sinfo = (proto_tree_search_info*)data;
|
|
field_info *fi = (field_info*) (gnode->data);
|
|
|
|
if (fi->hfinfo->id == sinfo->target) {
|
|
g_array_append_val(sinfo->result.array, fi->value.ipv6);
|
|
}
|
|
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
}
|
|
|
|
gboolean fill_array_bytes_variable(GNode *gnode, gpointer data)
|
|
{
|
|
proto_tree_search_info *sinfo = (proto_tree_search_info*)data;
|
|
field_info *fi = (field_info*) (gnode->data);
|
|
GByteArray *barray;
|
|
guint read_start, pkt_end;
|
|
|
|
if (fi->hfinfo->id == sinfo->target) {
|
|
if (bytes_offset < 0) {
|
|
/* Handle negative byte offsets */
|
|
bytes_offset = fi->length + bytes_offset;
|
|
if (bytes_offset < 0) {
|
|
goto FAIL;
|
|
}
|
|
}
|
|
|
|
/* Check to make sure offset exists for this field */
|
|
if (bytes_offset >= fi->length) {
|
|
goto FAIL;
|
|
}
|
|
|
|
pkt_end = fi->start + fi->length;
|
|
read_start = fi->start + bytes_offset;
|
|
|
|
/* Check to make sure entire length requested is inside field */
|
|
if (pkt_end < read_start + bytes_length) {
|
|
goto FAIL;
|
|
}
|
|
|
|
barray = g_byte_array_new();
|
|
g_byte_array_append(barray, sinfo->packet_data + read_start, bytes_length);
|
|
g_array_append_val(sinfo->result.array, barray);
|
|
}
|
|
|
|
FAIL:
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
}
|
|
|
|
gboolean fill_array_numeric_value(GNode *gnode, gpointer data)
|
|
{
|
|
GArray *array = (GArray*)data;
|
|
dfilter_node *dnode = (dfilter_node*) (gnode->data);
|
|
|
|
g_array_append_val(array, dnode->value.numeric);
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
}
|
|
|
|
gboolean fill_array_floating_value(GNode *gnode, gpointer data)
|
|
{
|
|
GArray *array = (GArray*)data;
|
|
dfilter_node *dnode = (dfilter_node*) (gnode->data);
|
|
|
|
g_array_append_val(array, dnode->value.floating);
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
}
|
|
|
|
gboolean fill_array_ether_value(GNode *gnode, gpointer data)
|
|
{
|
|
GArray *array = (GArray*)data;
|
|
dfilter_node *dnode = (dfilter_node*) (gnode->data);
|
|
|
|
g_array_append_val(array, dnode->value.ether);
|
|
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
}
|
|
|
|
gboolean fill_array_ipv4_value(GNode *gnode, gpointer data)
|
|
{
|
|
GArray *array = (GArray*)data;
|
|
dfilter_node *dnode = (dfilter_node*) (gnode->data);
|
|
|
|
g_array_append_val(array, dnode->value.ipv4);
|
|
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
}
|
|
|
|
gboolean fill_array_ipv6_value(GNode *gnode, gpointer data)
|
|
{
|
|
GArray *array = (GArray*)data;
|
|
dfilter_node *dnode = (dfilter_node*) (gnode->data);
|
|
|
|
g_array_append_val(array, dnode->value.ipv6);
|
|
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
}
|
|
|
|
gboolean fill_array_bytes_value(GNode *gnode, gpointer data)
|
|
{
|
|
GArray *array = (GArray*)data;
|
|
dfilter_node *dnode = (dfilter_node*) (gnode->data);
|
|
GByteArray *barray = dnode->value.bytes;
|
|
|
|
g_array_append_val(array, barray);
|
|
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
}
|
|
|
|
gboolean check_relation_numeric(gint operand, GArray *a, GArray *b)
|
|
{
|
|
int i, j, len_a, len_b;
|
|
guint32 val_a;
|
|
|
|
len_a = a->len;
|
|
len_b = b->len;
|
|
|
|
|
|
switch(operand) {
|
|
case TOK_EQ:
|
|
for(i = 0; i < len_a; i++) {
|
|
val_a = g_array_index(a, guint32, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
if (val_a == g_array_index(b, guint32, j))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_NE:
|
|
for(i = 0; i < len_a; i++) {
|
|
val_a = g_array_index(a, guint32, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
if (val_a != g_array_index(b, guint32, j))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_GT:
|
|
for(i = 0; i < len_a; i++) {
|
|
val_a = g_array_index(a, guint32, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
if (val_a > g_array_index(b, guint32, j))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_GE:
|
|
for(i = 0; i < len_a; i++) {
|
|
val_a = g_array_index(a, guint32, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
if (val_a >= g_array_index(b, guint32, j))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_LT:
|
|
for(i = 0; i < len_a; i++) {
|
|
val_a = g_array_index(a, guint32, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
if (val_a < g_array_index(b, guint32, j))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_LE:
|
|
for(i = 0; i < len_a; i++) {
|
|
val_a = g_array_index(a, guint32, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
if (val_a <= g_array_index(b, guint32, j))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
default:
|
|
g_assert_not_reached();
|
|
}
|
|
|
|
g_assert_not_reached();
|
|
return FALSE;
|
|
}
|
|
|
|
gboolean check_relation_floating(gint operand, GArray *a, GArray *b)
|
|
{
|
|
int i, j, len_a, len_b;
|
|
double val_a;
|
|
|
|
len_a = a->len;
|
|
len_b = b->len;
|
|
|
|
|
|
switch(operand) {
|
|
case TOK_EQ:
|
|
for(i = 0; i < len_a; i++) {
|
|
val_a = g_array_index(a, double, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
if (val_a == g_array_index(b, double, j))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_NE:
|
|
for(i = 0; i < len_a; i++) {
|
|
val_a = g_array_index(a, double, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
if (val_a != g_array_index(b, double, j))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_GT:
|
|
for(i = 0; i < len_a; i++) {
|
|
val_a = g_array_index(a, double, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
if (val_a > g_array_index(b, double, j))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_GE:
|
|
for(i = 0; i < len_a; i++) {
|
|
val_a = g_array_index(a, double, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
if (val_a >= g_array_index(b, double, j))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_LT:
|
|
for(i = 0; i < len_a; i++) {
|
|
val_a = g_array_index(a, double, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
if (val_a < g_array_index(b, double, j))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_LE:
|
|
for(i = 0; i < len_a; i++) {
|
|
val_a = g_array_index(a, double, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
if (val_a <= g_array_index(b, double, j))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
default:
|
|
g_assert_not_reached();
|
|
}
|
|
|
|
g_assert_not_reached();
|
|
return FALSE;
|
|
}
|
|
|
|
gboolean check_relation_ipv4(gint operand, GArray *a, GArray *b)
|
|
{
|
|
int i, j, len_a, len_b;
|
|
ipv4_addr *ptr_a, *ptr_b;
|
|
|
|
len_a = a->len;
|
|
len_b = b->len;
|
|
|
|
|
|
switch(operand) {
|
|
case TOK_EQ:
|
|
for(i = 0; i < len_a; i++) {
|
|
ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
|
|
for (j = 0; j < len_b; j++) {
|
|
ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
|
|
if (ipv4_addr_eq(ptr_a, ptr_b))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_NE:
|
|
for(i = 0; i < len_a; i++) {
|
|
ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
|
|
for (j = 0; j < len_b; j++) {
|
|
ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
|
|
if (!ipv4_addr_eq(ptr_a, ptr_b))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_GT:
|
|
for(i = 0; i < len_a; i++) {
|
|
ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
|
|
for (j = 0; j < len_b; j++) {
|
|
ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
|
|
if (ipv4_addr_gt(ptr_a, ptr_b))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_GE:
|
|
for(i = 0; i < len_a; i++) {
|
|
ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
|
|
for (j = 0; j < len_b; j++) {
|
|
ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
|
|
if (ipv4_addr_ge(ptr_a, ptr_b))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_LT:
|
|
for(i = 0; i < len_a; i++) {
|
|
ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
|
|
for (j = 0; j < len_b; j++) {
|
|
ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
|
|
if (ipv4_addr_lt(ptr_a, ptr_b))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_LE:
|
|
for(i = 0; i < len_a; i++) {
|
|
ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
|
|
for (j = 0; j < len_b; j++) {
|
|
ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
|
|
if (ipv4_addr_le(ptr_a, ptr_b))
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
g_assert_not_reached();
|
|
return FALSE;
|
|
}
|
|
|
|
gboolean check_relation_ipv6(gint operand, GArray *a, GArray *b)
|
|
{
|
|
int i, j, len_a, len_b;
|
|
guint8 *ptr_a, *ptr_b;
|
|
|
|
len_a = a->len;
|
|
len_b = b->len;
|
|
|
|
|
|
switch(operand) {
|
|
case TOK_EQ:
|
|
for(i = 0; i < len_a; i++) {
|
|
ptr_a = g_array_index_ptr(a, 16, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
ptr_b = g_array_index_ptr(b, 16, j);
|
|
if (memcmp(ptr_a, ptr_b, 16) == 0)
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_NE:
|
|
for(i = 0; i < len_a; i++) {
|
|
ptr_a = g_array_index_ptr(a, 16, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
ptr_b = g_array_index_ptr(b, 16, j);
|
|
if (memcmp(ptr_a, ptr_b, 16) != 0)
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
g_assert_not_reached();
|
|
return FALSE;
|
|
}
|
|
|
|
gboolean check_relation_ether(gint operand, GArray *a, GArray *b)
|
|
{
|
|
int i, j, len_a, len_b;
|
|
guint8 *ptr_a, *ptr_b;
|
|
|
|
len_a = a->len;
|
|
len_b = b->len;
|
|
|
|
|
|
switch(operand) {
|
|
case TOK_EQ:
|
|
for(i = 0; i < len_a; i++) {
|
|
ptr_a = g_array_index_ptr(a, 6, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
ptr_b = g_array_index_ptr(b, 6, j);
|
|
if (memcmp(ptr_a, ptr_b, 6) == 0)
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_NE:
|
|
for(i = 0; i < len_a; i++) {
|
|
ptr_a = g_array_index_ptr(a, 6, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
ptr_b = g_array_index_ptr(b, 6, j);
|
|
if (memcmp(ptr_a, ptr_b, 6) != 0)
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
g_assert_not_reached();
|
|
return FALSE;
|
|
}
|
|
|
|
gboolean check_relation_bytes(gint operand, GArray *a, GArray *b)
|
|
{
|
|
int i, j, len_a, len_b;
|
|
GByteArray *ptr_a,*ptr_b;
|
|
|
|
len_a = a->len;
|
|
len_b = b->len;
|
|
|
|
|
|
switch(operand) {
|
|
case TOK_EQ:
|
|
for(i = 0; i < len_a; i++) {
|
|
ptr_a = g_array_index(a, GByteArray*, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
ptr_b = g_array_index(b, GByteArray*, j);
|
|
if (memcmp(ptr_a->data, ptr_b->data, bytes_length) == 0)
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_NE:
|
|
for(i = 0; i < len_a; i++) {
|
|
ptr_a = g_array_index(a, GByteArray*, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
ptr_b = g_array_index(b, GByteArray*, j);
|
|
if (memcmp(ptr_a->data, ptr_b->data, bytes_length) != 0)
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_GT:
|
|
for(i = 0; i < len_a; i++) {
|
|
ptr_a = g_array_index(a, GByteArray*, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
ptr_b = g_array_index(b, GByteArray*, j);
|
|
if (memcmp(ptr_a->data, ptr_b->data, bytes_length) > 0)
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
case TOK_LT:
|
|
for(i = 0; i < len_a; i++) {
|
|
ptr_a = g_array_index(a, GByteArray*, i);
|
|
for (j = 0; j < len_b; j++) {
|
|
ptr_b = g_array_index(b, GByteArray*, j);
|
|
if (memcmp(ptr_a->data, ptr_b->data, bytes_length) < 0)
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
g_assert_not_reached();
|
|
return FALSE;
|
|
}
|