![Gilbert Ramirez](/assets/img/avatar_default.png)
We now store IPv4 addresses in host order, allowing non-equivalence comparisons. That is, display filters with lt, le, gt, and ge will work on big-endian and little-endian machines. CIDR notation is now supported for IPv4 addresses in display filters. You can test to see if an IPv4 address is on a certain subnet by using this notation. For example, to test for IPv4 packets on a Class-C network: ip.addr == 192.168.1.0/24 svn path=/trunk/; revision=1032
1090 lines
25 KiB
Text
1090 lines
25 KiB
Text
%{
|
|
|
|
/* dfilter-grammar.y
|
|
* Parser for display filters
|
|
*
|
|
* $Id: dfilter-grammar.y,v 1.37 1999/11/15 06:32:11 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
|
|
|
|
#ifdef HAVE_NETINET_IN_H
|
|
# include <netinet/in.h>
|
|
#endif
|
|
|
|
#ifdef NEED_SNPRINTF_H
|
|
# ifdef HAVE_STDARG_H
|
|
# include <stdarg.h>
|
|
# else
|
|
# include <varargs.h>
|
|
# endif
|
|
# include "snprintf.h"
|
|
#endif
|
|
|
|
#ifndef __GLIB_H__
|
|
#include <glib.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <math.h>
|
|
|
|
#ifndef _STDLIB_H
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
#ifndef __PROTO_H__
|
|
#include "proto.h"
|
|
#endif
|
|
|
|
#ifndef __PACKET_H__
|
|
#include "packet.h"
|
|
#endif
|
|
|
|
#ifndef __DFILTER_H__
|
|
#include "dfilter.h"
|
|
#endif
|
|
|
|
#include "dfilter-int.h"
|
|
|
|
#ifndef __RESOLV_H__
|
|
#include "resolv.h"
|
|
#endif
|
|
|
|
static GNode* dfilter_mknode_join(GNode *n1, enum node_type ntype, int operand, GNode *n2);
|
|
static GNode* dfilter_mknode_unary(int operand, GNode *n2);
|
|
static GNode* dfilter_mknode_numeric_variable(gint id);
|
|
static GNode* dfilter_mknode_numeric_value(guint32 val);
|
|
static GNode* dfilter_mknode_floating_variable(gint id);
|
|
static GNode* dfilter_mknode_floating_value(double val);
|
|
static GNode* dfilter_mknode_ether_value(gchar*);
|
|
static GNode* dfilter_mknode_ether_variable(gint id);
|
|
static GNode* dfilter_mknode_ipxnet_value(guint32);
|
|
static GNode* dfilter_mknode_ipxnet_variable(gint id);
|
|
static GNode* dfilter_mknode_ipv4_value(char *host, int nmask_bits);
|
|
static GNode* dfilter_mknode_ipv4_variable(gint id);
|
|
static GNode* dfilter_mknode_ipv6_value(char *host);
|
|
static GNode* dfilter_mknode_ipv6_variable(gint id);
|
|
static GNode* dfilter_mknode_existence(gint id);
|
|
static GNode* dfilter_mknode_bytes_value(GByteArray *barray);
|
|
static GNode* dfilter_mknode_bytes_variable(gint id, gint offset, guint length);
|
|
|
|
static guint32 string_to_guint32(char *s, gboolean *success);
|
|
static double string_to_double(char *s, gboolean *success);
|
|
static int ether_str_to_guint8_array(const char *s, guint8 *mac);
|
|
static guint dfilter_get_bytes_variable_offset(GNode *gnode);
|
|
static guint dfilter_get_bytes_value_length(GNode* gnode);
|
|
static void dfilter_set_bytes_variable_length(GNode *gnode, guint length);
|
|
static guint dfilter_get_bytes_variable_length(GNode *gnode);
|
|
static gint dfilter_get_bytes_variable_field_registered_length(GNode *gnode);
|
|
static char* dfilter_get_variable_abbrev(GNode *gnode);
|
|
static int check_bytes_variable_sanity(GNode *gnode);
|
|
|
|
/* This is the dfilter we're currently processing. It's how
|
|
* dfilter_compile communicates with us.
|
|
*/
|
|
dfilter *global_df = NULL;
|
|
|
|
%}
|
|
|
|
%union {
|
|
gint operand; /* logical, relation, alternation */
|
|
struct {
|
|
gint id;
|
|
gint type; /* using macros defined below, in this yacc grammar */
|
|
} variable;
|
|
GNode* node;
|
|
gchar* string;
|
|
struct {
|
|
gint offset;
|
|
guint length;
|
|
} byte_range;
|
|
}
|
|
|
|
%type <node> statement expression relation
|
|
%type <node> numeric_value numeric_variable
|
|
%type <node> floating_value floating_variable
|
|
%type <node> ether_value ether_variable
|
|
%type <node> ipxnet_value ipxnet_variable
|
|
%type <node> ipv4_value ipv4_variable
|
|
%type <node> ipv6_value ipv6_variable
|
|
%type <node> variable_name
|
|
%type <node> bytes_value bytes_variable
|
|
|
|
%type <operand> numeric_relation
|
|
%type <operand> equality_relation
|
|
%type <operand> bytes_relation
|
|
|
|
%type <variable> any_variable_type
|
|
|
|
%token <variable> T_FT_UINT8
|
|
%token <variable> T_FT_UINT16
|
|
%token <variable> T_FT_UINT32
|
|
%token <variable> T_FT_INT8
|
|
%token <variable> T_FT_INT16
|
|
%token <variable> T_FT_INT32
|
|
%token <variable> T_FT_ETHER
|
|
%token <variable> T_FT_IPv4
|
|
%token <variable> T_FT_IPv6
|
|
%token <variable> T_FT_NONE
|
|
%token <variable> T_FT_BYTES
|
|
%token <variable> T_FT_BOOLEAN
|
|
%token <variable> T_FT_STRING
|
|
%token <variable> T_FT_IPXNET
|
|
%token <variable> T_FT_DOUBLE
|
|
|
|
%token <string> T_VAL_UNQUOTED_STRING
|
|
%token <string> T_VAL_BYTE_STRING
|
|
%token <byte_range> T_VAL_BYTE_RANGE
|
|
|
|
%token <operand> TOK_AND TOK_OR TOK_NOT TOK_XOR
|
|
%token <operand> TOK_EQ TOK_NE TOK_GT TOK_GE TOK_LT TOK_LE
|
|
|
|
%expect 4
|
|
%left TOK_AND
|
|
%left TOK_OR TOK_XOR
|
|
%nonassoc TOK_NOT
|
|
|
|
%%
|
|
|
|
statement: expression
|
|
{
|
|
global_df->dftree = $1;
|
|
}
|
|
| /* NULL */ { if (global_df != NULL) global_df->dftree = NULL; }
|
|
;
|
|
|
|
expression: '(' expression ')' { $$ = $2; }
|
|
| expression TOK_AND expression { $$ = dfilter_mknode_join($1, logical, $2, $3); }
|
|
| expression TOK_OR expression { $$ = dfilter_mknode_join($1, logical, $2, $3); }
|
|
| expression TOK_XOR expression { $$ = dfilter_mknode_join($1, logical, $2, $3); }
|
|
| TOK_NOT expression { $$ = dfilter_mknode_unary(TOK_NOT, $2); }
|
|
| relation { $$ = $1; }
|
|
| variable_name { $$ = $1; }
|
|
| expression error { YYABORT; }
|
|
;
|
|
|
|
relation: numeric_variable numeric_relation numeric_value
|
|
{
|
|
$$ = dfilter_mknode_join($1, relation, $2, $3);
|
|
}
|
|
| numeric_variable numeric_relation numeric_variable
|
|
{
|
|
$$ = dfilter_mknode_join($1, relation, $2, $3);
|
|
}
|
|
|
|
| floating_variable numeric_relation floating_value
|
|
{
|
|
$$ = dfilter_mknode_join($1, relation, $2, $3);
|
|
}
|
|
| floating_variable numeric_relation floating_variable
|
|
{
|
|
$$ = dfilter_mknode_join($1, relation, $2, $3);
|
|
}
|
|
|
|
| ether_variable equality_relation ether_value
|
|
{
|
|
$$ = dfilter_mknode_join($1, relation, $2, $3);
|
|
}
|
|
| ether_variable equality_relation ether_variable
|
|
{
|
|
$$ = dfilter_mknode_join($1, relation, $2, $3);
|
|
}
|
|
|
|
| ipxnet_variable equality_relation ipxnet_value
|
|
{
|
|
$$ = dfilter_mknode_join($1, relation, $2, $3);
|
|
}
|
|
| ipxnet_variable equality_relation ipxnet_variable
|
|
{
|
|
$$ = dfilter_mknode_join($1, relation, $2, $3);
|
|
}
|
|
|
|
|
|
| ipv4_variable numeric_relation ipv4_value
|
|
{
|
|
$$ = dfilter_mknode_join($1, relation, $2, $3);
|
|
}
|
|
| ipv4_variable numeric_relation ipv4_variable
|
|
{
|
|
$$ = dfilter_mknode_join($1, relation, $2, $3);
|
|
}
|
|
|
|
| ipv6_variable equality_relation ipv6_value
|
|
{
|
|
$$ = dfilter_mknode_join($1, relation, $2, $3);
|
|
}
|
|
| ipv6_variable equality_relation ipv6_variable
|
|
{
|
|
$$ = dfilter_mknode_join($1, relation, $2, $3);
|
|
}
|
|
|
|
| bytes_variable bytes_relation bytes_value
|
|
{
|
|
int a_len, b_len;
|
|
|
|
a_len = dfilter_get_bytes_variable_length($1);
|
|
b_len = dfilter_get_bytes_value_length($3);
|
|
|
|
if (a_len == 0) {
|
|
dfilter_set_bytes_variable_length($1, b_len);
|
|
a_len = b_len;
|
|
}
|
|
|
|
if (!check_bytes_variable_sanity($1)) {
|
|
YYERROR;
|
|
}
|
|
|
|
if (a_len != b_len) {
|
|
dfilter_fail("Field \"%s\" has %u byte%s being compared, but %u byte%s "
|
|
"%s supplied.",
|
|
dfilter_get_variable_abbrev($1),
|
|
a_len, plurality(a_len, "", "s"),
|
|
b_len, plurality(b_len, "", "s"),
|
|
plurality(b_len, "was", "were"));
|
|
YYERROR;
|
|
}
|
|
|
|
$$ = dfilter_mknode_join($1, relation, $2, $3);
|
|
}
|
|
| bytes_variable bytes_relation bytes_variable
|
|
{
|
|
int a_len, b_len;
|
|
|
|
a_len = dfilter_get_bytes_variable_length($1);
|
|
b_len = dfilter_get_bytes_variable_length($3);
|
|
|
|
if (!check_bytes_variable_sanity($1)) {
|
|
YYERROR;
|
|
}
|
|
|
|
if (!check_bytes_variable_sanity($3)) {
|
|
YYERROR;
|
|
}
|
|
|
|
if (a_len != b_len) {
|
|
dfilter_fail("Fields \"%s\" and \"%s\" are being compared with "
|
|
"disparate lengths of %u byte%s and %u byte%s.",
|
|
dfilter_get_variable_abbrev($1),
|
|
dfilter_get_variable_abbrev($3),
|
|
a_len, plurality(a_len, "", "s"),
|
|
b_len, plurality(b_len, "", "s"));
|
|
YYERROR;
|
|
}
|
|
|
|
$$ = dfilter_mknode_join($1, relation, $2, $3);
|
|
}
|
|
|
|
;
|
|
|
|
|
|
numeric_value: T_VAL_UNQUOTED_STRING
|
|
{
|
|
gboolean success;
|
|
$$ = dfilter_mknode_numeric_value(string_to_guint32($1, &success));
|
|
g_free($1);
|
|
if (!success) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
;
|
|
|
|
ether_value: T_VAL_BYTE_STRING
|
|
{
|
|
$$ = dfilter_mknode_ether_value($1);
|
|
g_free($1);
|
|
if ($$ == NULL) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
;
|
|
|
|
ipxnet_value: T_VAL_UNQUOTED_STRING
|
|
{
|
|
gboolean success;
|
|
$$ = dfilter_mknode_ipxnet_value(string_to_guint32($1, &success));
|
|
g_free($1);
|
|
if (!success) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
;
|
|
|
|
floating_value: T_VAL_UNQUOTED_STRING
|
|
{
|
|
gboolean success;
|
|
$$ = dfilter_mknode_floating_value(string_to_double($1, &success));
|
|
g_free($1);
|
|
if (!success) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
|
|
| T_VAL_BYTE_STRING
|
|
{
|
|
/* e.g., 0.0, 0.1, 0.01 ... */
|
|
gboolean success;
|
|
$$ = dfilter_mknode_floating_value(string_to_double($1, &success));
|
|
g_free($1);
|
|
if (!success) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
;
|
|
|
|
ipv4_value: T_VAL_UNQUOTED_STRING
|
|
{
|
|
$$ = dfilter_mknode_ipv4_value($1, 32);
|
|
g_free($1);
|
|
if ($$ == NULL) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
|
|
| T_VAL_BYTE_STRING
|
|
{
|
|
$$ = dfilter_mknode_ipv4_value($1, 32);
|
|
g_free($1);
|
|
if ($$ == NULL) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
|
|
| T_VAL_UNQUOTED_STRING '/' T_VAL_UNQUOTED_STRING
|
|
{
|
|
gboolean success;
|
|
guint32 nmask_bits;
|
|
|
|
nmask_bits = string_to_guint32($3, &success);
|
|
if (!success) {
|
|
g_free($1);
|
|
g_free($3);
|
|
YYERROR;
|
|
}
|
|
|
|
if (nmask_bits > 32) {
|
|
dfilter_fail("The number of netmask bits in \"%s/%s\" should "
|
|
"be between 0 and 32.", $1, $3);
|
|
g_free($1);
|
|
g_free($3);
|
|
YYERROR;
|
|
}
|
|
|
|
$$ = dfilter_mknode_ipv4_value($1, nmask_bits);
|
|
g_free($1);
|
|
g_free($3);
|
|
if ($$ == NULL) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
|
|
| T_VAL_BYTE_STRING '/' T_VAL_UNQUOTED_STRING
|
|
{
|
|
gboolean success;
|
|
guint32 nmask_bits;
|
|
|
|
nmask_bits = string_to_guint32($3, &success);
|
|
if (!success) {
|
|
g_free($1);
|
|
g_free($3);
|
|
YYERROR;
|
|
}
|
|
|
|
if (nmask_bits > 32) {
|
|
dfilter_fail("The number of netmask bits in \"%s/%s\" should "
|
|
"be between 0 and 32.", $1, $3);
|
|
g_free($1);
|
|
g_free($3);
|
|
YYERROR;
|
|
}
|
|
$$ = dfilter_mknode_ipv4_value($1, nmask_bits);
|
|
g_free($1);
|
|
g_free($3);
|
|
if ($$ == NULL) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
;
|
|
|
|
ipv6_value: T_VAL_UNQUOTED_STRING
|
|
{
|
|
$$ = dfilter_mknode_ipv6_value($1);
|
|
g_free($1);
|
|
if ($$ == NULL) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
|
|
| T_VAL_BYTE_STRING
|
|
{
|
|
$$ = dfilter_mknode_ipv6_value($1);
|
|
g_free($1);
|
|
if ($$ == NULL) {
|
|
YYERROR;
|
|
}
|
|
}
|
|
;
|
|
|
|
bytes_value: T_VAL_BYTE_STRING
|
|
{
|
|
GByteArray *barray;
|
|
|
|
/* the next function appends to list_of_byte_arrays for me */
|
|
barray = byte_str_to_guint8_array($1);
|
|
$$ = dfilter_mknode_bytes_value(barray);
|
|
g_free($1);
|
|
}
|
|
|
|
| T_VAL_UNQUOTED_STRING
|
|
{
|
|
gboolean success;
|
|
guint32 val32;
|
|
guint8 val8;
|
|
GByteArray *barray;
|
|
|
|
val32 = string_to_guint32($1, &success);
|
|
if (!success) {
|
|
g_free($1);
|
|
YYERROR;
|
|
}
|
|
if (val32 > 0xff) {
|
|
dfilter_fail("The value \"%s\" cannot be stored in a single-byte byte-string. "
|
|
"Use the multi-byte \"xx:yy\" representation.", $1);
|
|
g_free($1);
|
|
YYERROR;
|
|
}
|
|
val8 = (guint8) val32;
|
|
barray = g_byte_array_new();
|
|
global_df->list_of_byte_arrays = g_slist_append(global_df->list_of_byte_arrays, barray);
|
|
g_byte_array_append(barray, &val8, 1);
|
|
|
|
$$ = dfilter_mknode_bytes_value(barray);
|
|
g_free($1);
|
|
}
|
|
;
|
|
|
|
numeric_variable: T_FT_UINT8 { $$ = dfilter_mknode_numeric_variable($1.id); }
|
|
| T_FT_UINT16 { $$ = dfilter_mknode_numeric_variable($1.id); }
|
|
| T_FT_UINT32 { $$ = dfilter_mknode_numeric_variable($1.id); }
|
|
| T_FT_INT8 { $$ = dfilter_mknode_numeric_variable($1.id); }
|
|
| T_FT_INT16 { $$ = dfilter_mknode_numeric_variable($1.id); }
|
|
| T_FT_INT32 { $$ = dfilter_mknode_numeric_variable($1.id); }
|
|
;
|
|
|
|
ether_variable: T_FT_ETHER { $$ = dfilter_mknode_ether_variable($1.id); }
|
|
;
|
|
|
|
floating_variable: T_FT_DOUBLE { $$ = dfilter_mknode_floating_variable($1.id); }
|
|
;
|
|
|
|
ipxnet_variable: T_FT_IPXNET { $$ = dfilter_mknode_ipxnet_variable($1.id); }
|
|
;
|
|
|
|
ipv4_variable: T_FT_IPv4 { $$ = dfilter_mknode_ipv4_variable($1.id); }
|
|
;
|
|
|
|
ipv6_variable: T_FT_IPv6 { $$ = dfilter_mknode_ipv6_variable($1.id); }
|
|
;
|
|
|
|
variable_name: any_variable_type
|
|
{
|
|
GNode *variable;
|
|
GNode *value;
|
|
|
|
if ($1.type == T_FT_BOOLEAN) {
|
|
/* Make "variable == TRUE" for BOOLEAN variable */
|
|
variable = dfilter_mknode_numeric_variable($1.id);
|
|
value = dfilter_mknode_numeric_value(TRUE);
|
|
$$ = dfilter_mknode_join(variable, relation, TOK_EQ, value);
|
|
}
|
|
else {
|
|
$$ = dfilter_mknode_existence($1.id);
|
|
}
|
|
}
|
|
;
|
|
|
|
bytes_variable: any_variable_type T_VAL_BYTE_RANGE
|
|
{
|
|
$$ = dfilter_mknode_bytes_variable($1.id, $2.offset, $2.length);
|
|
}
|
|
;
|
|
|
|
any_variable_type: T_FT_UINT8 { $$ = $1; }
|
|
| T_FT_UINT16 { $$ = $1; }
|
|
| T_FT_UINT32 { $$ = $1; }
|
|
| T_FT_INT8 { $$ = $1; }
|
|
| T_FT_INT16 { $$ = $1; }
|
|
| T_FT_INT32 { $$ = $1; }
|
|
| T_FT_DOUBLE { $$ = $1; }
|
|
| T_FT_ETHER { $$ = $1; }
|
|
| T_FT_IPv4 { $$ = $1; }
|
|
| T_FT_IPv6 { $$ = $1; }
|
|
| T_FT_IPXNET { $$ = $1; }
|
|
| T_FT_NONE { $$ = $1; }
|
|
| T_FT_BYTES { $$ = $1; }
|
|
| T_FT_BOOLEAN { $$ = $1; }
|
|
| T_FT_STRING { $$ = $1; }
|
|
;
|
|
|
|
numeric_relation: TOK_EQ { $$ = TOK_EQ; }
|
|
| TOK_NE { $$ = TOK_NE; }
|
|
| TOK_GT { $$ = TOK_GT; }
|
|
| TOK_GE { $$ = TOK_GE; }
|
|
| TOK_LT { $$ = TOK_LT; }
|
|
| TOK_LE { $$ = TOK_LE; }
|
|
;
|
|
|
|
equality_relation: TOK_EQ { $$ = TOK_EQ; }
|
|
| TOK_NE { $$ = TOK_NE; }
|
|
;
|
|
|
|
bytes_relation: TOK_EQ { $$ = TOK_EQ; }
|
|
| TOK_NE { $$ = TOK_NE; }
|
|
| TOK_GT { $$ = TOK_GT; }
|
|
| TOK_LT { $$ = TOK_LT; }
|
|
;
|
|
|
|
%%
|
|
|
|
static GNode*
|
|
dfilter_mknode_join(GNode *n1, enum node_type ntype, int operand, GNode *n2)
|
|
{
|
|
dfilter_node *node_root;
|
|
GNode *gnode_root;
|
|
|
|
node_root = g_mem_chunk_alloc(global_df->node_memchunk);
|
|
node_root->ntype = ntype;
|
|
node_root->elem_size = 0;
|
|
node_root->fill_array_func = NULL;
|
|
node_root->check_relation_func = NULL;
|
|
if (ntype == relation) {
|
|
node_root->value.relation = operand;
|
|
}
|
|
else if (ntype == logical) {
|
|
node_root->value.logical = operand;
|
|
}
|
|
else {
|
|
g_assert_not_reached();
|
|
}
|
|
|
|
gnode_root = g_node_new(node_root);
|
|
g_node_append(gnode_root, n1);
|
|
g_node_append(gnode_root, n2);
|
|
|
|
return gnode_root;
|
|
}
|
|
|
|
static GNode*
|
|
dfilter_mknode_unary(int operand, GNode *n2)
|
|
{
|
|
dfilter_node *node_root;
|
|
GNode *gnode_root;
|
|
|
|
node_root = g_mem_chunk_alloc(global_df->node_memchunk);
|
|
node_root->ntype = logical;
|
|
node_root->value.logical = operand;
|
|
node_root->elem_size = 0;
|
|
node_root->fill_array_func = NULL;
|
|
node_root->check_relation_func = NULL;
|
|
|
|
gnode_root = g_node_new(node_root);
|
|
g_node_append(gnode_root, n2);
|
|
|
|
return gnode_root;
|
|
}
|
|
|
|
|
|
static GNode*
|
|
dfilter_mknode_numeric_variable(gint id)
|
|
{
|
|
dfilter_node *node;
|
|
GNode *gnode;
|
|
|
|
node = g_mem_chunk_alloc(global_df->node_memchunk);
|
|
node->ntype = variable;
|
|
node->elem_size = sizeof(guint32);
|
|
node->fill_array_func = fill_array_numeric_variable;
|
|
node->check_relation_func = check_relation_numeric;
|
|
node->value.variable = id;
|
|
gnode = g_node_new(node);
|
|
|
|
return gnode;
|
|
}
|
|
|
|
static GNode*
|
|
dfilter_mknode_ether_variable(gint id)
|
|
{
|
|
dfilter_node *node;
|
|
GNode *gnode;
|
|
|
|
node = g_mem_chunk_alloc(global_df->node_memchunk);
|
|
node->ntype = variable;
|
|
node->elem_size = sizeof(guint8) * 6;
|
|
node->fill_array_func = fill_array_ether_variable;
|
|
node->check_relation_func = check_relation_ether;
|
|
node->value.variable = id;
|
|
gnode = g_node_new(node);
|
|
|
|
return gnode;
|
|
}
|
|
|
|
static GNode*
|
|
dfilter_mknode_floating_variable(gint id)
|
|
{
|
|
dfilter_node *node;
|
|
GNode *gnode;
|
|
|
|
node = g_mem_chunk_alloc(global_df->node_memchunk);
|
|
node->ntype = variable;
|
|
node->elem_size = sizeof(double);
|
|
node->fill_array_func = fill_array_floating_variable;
|
|
node->check_relation_func = check_relation_floating;
|
|
node->value.variable = id;
|
|
gnode = g_node_new(node);
|
|
|
|
return gnode;
|
|
}
|
|
|
|
static GNode*
|
|
dfilter_mknode_ipxnet_variable(gint id)
|
|
{
|
|
dfilter_node *node;
|
|
GNode *gnode;
|
|
|
|
node = g_mem_chunk_alloc(global_df->node_memchunk);
|
|
node->ntype = variable;
|
|
node->elem_size = sizeof(guint8) * 4;
|
|
node->fill_array_func = fill_array_numeric_variable; /* cheating ! */
|
|
node->check_relation_func = check_relation_numeric; /* cheating ! */
|
|
node->value.variable = id;
|
|
gnode = g_node_new(node);
|
|
|
|
return gnode;
|
|
}
|
|
|
|
static GNode*
|
|
dfilter_mknode_ipv4_variable(gint id)
|
|
{
|
|
dfilter_node *node;
|
|
GNode *gnode;
|
|
|
|
node = g_mem_chunk_alloc(global_df->node_memchunk);
|
|
node->ntype = variable;
|
|
node->elem_size = sizeof(ipv4_addr);
|
|
node->fill_array_func = fill_array_ipv4_variable;
|
|
node->check_relation_func = check_relation_ipv4;
|
|
node->value.variable = id;
|
|
gnode = g_node_new(node);
|
|
|
|
return gnode;
|
|
}
|
|
|
|
static GNode*
|
|
dfilter_mknode_ipv6_variable(gint id)
|
|
{
|
|
dfilter_node *node;
|
|
GNode *gnode;
|
|
|
|
node = g_mem_chunk_alloc(global_df->node_memchunk);
|
|
node->ntype = variable;
|
|
node->elem_size = 16;
|
|
node->fill_array_func = fill_array_ipv6_variable;
|
|
node->check_relation_func = check_relation_ipv6;
|
|
node->value.variable = id;
|
|
gnode = g_node_new(node);
|
|
|
|
return gnode;
|
|
}
|
|
|
|
static GNode*
|
|
dfilter_mknode_bytes_variable(gint id, gint offset, guint length)
|
|
{
|
|
dfilter_node *node;
|
|
GNode *gnode;
|
|
|
|
node = g_mem_chunk_alloc(global_df->node_memchunk);
|
|
node->ntype = variable;
|
|
node->elem_size = sizeof(GByteArray*);
|
|
node->fill_array_func = fill_array_bytes_variable;
|
|
node->check_relation_func = check_relation_bytes;
|
|
node->value.variable = id;
|
|
node->offset = offset;
|
|
node->length = length;
|
|
gnode = g_node_new(node);
|
|
|
|
return gnode;
|
|
}
|
|
|
|
/* Gets length of variable represented by node from proto_register */
|
|
static gint
|
|
dfilter_get_bytes_variable_field_registered_length(GNode *gnode)
|
|
{
|
|
dfilter_node *node = gnode->data;
|
|
|
|
/* Is this really a bytes_variable? */
|
|
g_assert(node->fill_array_func = fill_array_bytes_variable);
|
|
|
|
return proto_registrar_get_length(node->value.variable);
|
|
}
|
|
|
|
/* Sets the length of a bytes_variable node */
|
|
static void
|
|
dfilter_set_bytes_variable_length(GNode *gnode, guint length)
|
|
{
|
|
dfilter_node *node = gnode->data;
|
|
|
|
/* Is this really a bytes_variable? */
|
|
g_assert(node->fill_array_func = fill_array_bytes_variable);
|
|
|
|
node->length = length;
|
|
}
|
|
|
|
/* Gets the length of a bytes_variable node */
|
|
static guint
|
|
dfilter_get_bytes_variable_length(GNode *gnode)
|
|
{
|
|
dfilter_node *node = gnode->data;
|
|
|
|
/* Is this really a bytes_variable? */
|
|
g_assert(node->fill_array_func = fill_array_bytes_variable);
|
|
|
|
return node->length;
|
|
}
|
|
|
|
/* Gets the offset of a bytes_variable node */
|
|
static guint
|
|
dfilter_get_bytes_variable_offset(GNode *gnode)
|
|
{
|
|
dfilter_node *node = gnode->data;
|
|
|
|
/* Is this really a bytes_variable? */
|
|
g_assert(node->fill_array_func = fill_array_bytes_variable);
|
|
|
|
return node->offset;
|
|
}
|
|
|
|
static char*
|
|
dfilter_get_variable_abbrev(GNode *gnode)
|
|
{
|
|
dfilter_node *node = gnode->data;
|
|
|
|
return proto_registrar_get_abbrev(node->value.variable);
|
|
}
|
|
|
|
static GNode*
|
|
dfilter_mknode_numeric_value(guint32 val)
|
|
{
|
|
dfilter_node *node;
|
|
GNode *gnode;
|
|
|
|
node = g_mem_chunk_alloc(global_df->node_memchunk);
|
|
node->ntype = numeric;
|
|
node->elem_size = sizeof(guint32);
|
|
node->fill_array_func = fill_array_numeric_value;
|
|
node->check_relation_func = check_relation_numeric;
|
|
node->value.numeric = val;
|
|
gnode = g_node_new(node);
|
|
|
|
return gnode;
|
|
}
|
|
|
|
static GNode*
|
|
dfilter_mknode_floating_value(double val)
|
|
{
|
|
dfilter_node *node;
|
|
GNode *gnode;
|
|
|
|
node = g_mem_chunk_alloc(global_df->node_memchunk);
|
|
node->ntype = floating;
|
|
node->elem_size = sizeof(double);
|
|
node->fill_array_func = fill_array_floating_value;
|
|
node->check_relation_func = check_relation_floating;
|
|
node->value.floating = val;
|
|
gnode = g_node_new(node);
|
|
|
|
return gnode;
|
|
}
|
|
|
|
/* Returns NULL on bad parse of ETHER value */
|
|
static GNode*
|
|
dfilter_mknode_ether_value(gchar *byte_string)
|
|
{
|
|
dfilter_node *node;
|
|
GNode *gnode;
|
|
|
|
node = g_mem_chunk_alloc(global_df->node_memchunk);
|
|
node->ntype = ether;
|
|
node->elem_size = sizeof(guint8) * 6;
|
|
node->fill_array_func = fill_array_ether_value;
|
|
node->check_relation_func = check_relation_ether;
|
|
|
|
if (!ether_str_to_guint8_array(byte_string, &node->value.ether[0])) {
|
|
/* Rather than free the mem_chunk allocation, let it
|
|
* stay. It will be cleaned up when "dfilter_compile()"
|
|
* calls "dfilter_destroy()". */
|
|
dfilter_fail("\"%s\" is not a valid hardware address.",
|
|
byte_string);
|
|
return NULL;
|
|
}
|
|
|
|
gnode = g_node_new(node);
|
|
return gnode;
|
|
}
|
|
|
|
static GNode*
|
|
dfilter_mknode_ipxnet_value(guint32 ipx_net_val)
|
|
{
|
|
dfilter_node *node;
|
|
GNode *gnode;
|
|
|
|
node = g_mem_chunk_alloc(global_df->node_memchunk);
|
|
node->ntype = ipxnet;
|
|
node->elem_size = sizeof(guint8) * 4;
|
|
node->fill_array_func = fill_array_numeric_value; /* cheating ! */
|
|
node->check_relation_func = check_relation_numeric; /* cheating ! */
|
|
node->value.numeric = ipx_net_val;
|
|
gnode = g_node_new(node);
|
|
|
|
return gnode;
|
|
}
|
|
|
|
/* Returns NULL on bad parse of IP value */
|
|
static GNode*
|
|
dfilter_mknode_ipv4_value(char *host, int nmask_bits)
|
|
{
|
|
dfilter_node *node;
|
|
GNode *gnode;
|
|
guint32 addr;
|
|
|
|
node = g_mem_chunk_alloc(global_df->node_memchunk);
|
|
node->ntype = numeric;
|
|
node->elem_size = sizeof(ipv4_addr);
|
|
node->fill_array_func = fill_array_ipv4_value;
|
|
node->check_relation_func = check_relation_ipv4;
|
|
if (!get_host_ipaddr(host, &addr)) {
|
|
/* Rather than free the mem_chunk allocation, let it
|
|
* stay. It will be cleaned up when "dfilter_compile()"
|
|
* calls "dfilter_destroy()". */
|
|
dfilter_fail("\"%s\" isn't a valid host name or IP address.",
|
|
host);
|
|
return NULL;
|
|
}
|
|
ipv4_addr_set_host_order_addr(&node->value.ipv4, addr);
|
|
ipv4_addr_set_netmask_bits(&node->value.ipv4, nmask_bits);
|
|
|
|
gnode = g_node_new(node);
|
|
return gnode;
|
|
}
|
|
|
|
/* Returns NULL on bad parse of IPv6 value */
|
|
static GNode*
|
|
dfilter_mknode_ipv6_value(char *host)
|
|
{
|
|
dfilter_node *node;
|
|
GNode *gnode;
|
|
|
|
node = g_mem_chunk_alloc(global_df->node_memchunk);
|
|
node->ntype = ipv6;
|
|
node->elem_size = 16;
|
|
node->fill_array_func = fill_array_ipv6_value;
|
|
node->check_relation_func = check_relation_ipv6;
|
|
|
|
if (!get_host_ipaddr6(host, (struct e_in6_addr*)&node->value.ipv6[0])) {
|
|
/* Rather than free the mem_chunk allocation, let it
|
|
* stay. It will be cleaned up when "dfilter_compile()"
|
|
* calls "dfilter_destroy()". */
|
|
dfilter_fail("\"%s\" isn't a valid IPv6 address.",
|
|
host);
|
|
return NULL;
|
|
}
|
|
|
|
gnode = g_node_new(node);
|
|
return gnode;
|
|
}
|
|
|
|
static GNode*
|
|
dfilter_mknode_bytes_value(GByteArray *barray)
|
|
{
|
|
dfilter_node *node;
|
|
GNode *gnode;
|
|
|
|
node = g_mem_chunk_alloc(global_df->node_memchunk);
|
|
node->ntype = bytes;
|
|
node->elem_size = sizeof(GByteArray*);
|
|
node->fill_array_func = fill_array_bytes_value;
|
|
node->check_relation_func = check_relation_bytes;
|
|
node->value.bytes = barray;
|
|
node->offset = G_MAXINT;
|
|
node->length = barray->len;
|
|
gnode = g_node_new(node);
|
|
|
|
return gnode;
|
|
}
|
|
|
|
/* Given a node representing a bytes_value, returns
|
|
* the length of the byte array */
|
|
static guint
|
|
dfilter_get_bytes_value_length(GNode* gnode)
|
|
{
|
|
dfilter_node *node = gnode->data;
|
|
|
|
g_assert(node->ntype == bytes);
|
|
return node->length;
|
|
}
|
|
|
|
static guint32
|
|
string_to_guint32(char *s, gboolean *success)
|
|
{
|
|
char *endptr;
|
|
guint32 val;
|
|
|
|
val = strtoul(s, &endptr, 0);
|
|
*success = TRUE;
|
|
if (endptr == s || *endptr != '\0') {
|
|
/* This isn't a valid number. */
|
|
dfilter_fail("\"%s\" is not a valid number.", s);
|
|
*success = FALSE;
|
|
}
|
|
if (errno == ERANGE) {
|
|
*success = FALSE;
|
|
if (val == ULONG_MAX) {
|
|
dfilter_fail("\"%s\" causes an integer overflow.", s);
|
|
}
|
|
else {
|
|
dfilter_fail("\"%s\" is not an integer.", s);
|
|
}
|
|
}
|
|
|
|
return (guint32)val;
|
|
}
|
|
|
|
static double
|
|
string_to_double(char *s, gboolean *success)
|
|
{
|
|
char *endptr = NULL;
|
|
double retval;
|
|
|
|
retval = strtod(s, &endptr);
|
|
*success = TRUE;
|
|
|
|
if (endptr == s) {
|
|
dfilter_fail("\"%s\" is not a valid floating-point number.", s);
|
|
*success = FALSE;
|
|
}
|
|
|
|
if (errno == ERANGE) {
|
|
*success = FALSE;
|
|
if (retval == 0) {
|
|
dfilter_fail("\"%s\" causes a floating-point underflow.", s);
|
|
}
|
|
else if (retval == HUGE_VAL) {
|
|
dfilter_fail("\"%s\" causes a floating-point overflow.", s);
|
|
}
|
|
else {
|
|
dfilter_fail("\"%s\" is not a valid floating-point.", s);
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
static GNode*
|
|
dfilter_mknode_existence(gint id)
|
|
{
|
|
dfilter_node *node;
|
|
GNode *gnode;
|
|
|
|
node = g_mem_chunk_alloc(global_df->node_memchunk);
|
|
node->ntype = existence;
|
|
node->elem_size = sizeof(guint32);
|
|
node->fill_array_func = NULL;
|
|
node->check_relation_func = NULL;
|
|
node->value.variable = id;
|
|
gnode = g_node_new(node);
|
|
|
|
return gnode;
|
|
}
|
|
|
|
|
|
/* converts a string representing an ether HW address
|
|
* to a guint8 array.
|
|
*
|
|
* Returns 0 on failure, 1 on success.
|
|
*/
|
|
static int
|
|
ether_str_to_guint8_array(const char *s, guint8 *mac)
|
|
{
|
|
char ether_str[18]; /* 2+1+2+1+2+1+2+1+2+1+2 + 1 */
|
|
char *p, *str;
|
|
int i = 0;
|
|
|
|
if (strlen(s) > 17) {
|
|
return 0;
|
|
}
|
|
strcpy(ether_str, s); /* local copy of string */
|
|
str = ether_str;
|
|
while ((p = strtok(str, "-:."))) {
|
|
/* catch short strings with too many hex bytes: 0.0.0.0.0.0.0 */
|
|
if (i > 5) {
|
|
return 0;
|
|
}
|
|
mac[i] = (guint8) strtoul(p, NULL, 16);
|
|
i++;
|
|
/* subsequent calls to strtok() require NULL as arg 1 */
|
|
str = NULL;
|
|
}
|
|
if (i != 6)
|
|
return 0; /* failed to read 6 hex pairs */
|
|
else
|
|
return 1; /* read exactly 6 hex pairs */
|
|
}
|
|
|
|
|
|
static int
|
|
check_bytes_variable_sanity(GNode *gnode)
|
|
{
|
|
int a_off, a_len, reg_len, t_off;
|
|
|
|
a_off = dfilter_get_bytes_variable_offset(gnode);
|
|
a_len = dfilter_get_bytes_variable_length(gnode);
|
|
reg_len = dfilter_get_bytes_variable_field_registered_length(gnode);
|
|
|
|
if (reg_len > 0) {
|
|
t_off = a_off >= 0 ? a_off : reg_len + a_off;
|
|
if (t_off + a_len > reg_len) {
|
|
dfilter_fail("The \"%s\" field is only %u byte%s wide, but "
|
|
"%u byte%s %s supplied.",
|
|
dfilter_get_variable_abbrev(gnode),
|
|
reg_len, plurality(reg_len, "", "s"),
|
|
a_len, plurality(a_len, "", "s"),
|
|
plurality(a_len, "was", "were"));
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|