Re-implemented fix to keep display filter from reading data from outside

the packet boundary. Now the field boundary is honored. The frame boundary
is ignored, but of course we put proper field lengths in the proto_tree,
right? :)

Implemented negative offsets in byte-strings:
	frame[-4:4] will read the last 4 bytes of a frame.

Implemented "offset-only" byte-string comparisons, since the dfilter
compiler knows the length of the byte-string you supplied. These are
now legal:
	frame[-4] == 0.0.0.1
	tr.dst[0] == 00:06:29

Implemented the use of integers if you're comparing one byte. These are
legal:
	llc[0] == 0xaa
	llc[0:1] == 0xaa

All these forms check against the length of the field, so these will be
reported as bad to the user:
	eth.src[5] == 00:06:29      (goes beyond field boundary)
	eth.dst == 1.2.3.4.5.6.7    (too long, goes beyond field boundary)

Thes is also reported as bad:
	eth.dst[0:3] == 1.2          (incorrect number of bytes specified)
	eth.dst[0:1] == eth.src[0:2] (disparate lengths)

I had to add a new function, proto_registrar_get_length() in proto.c, which
reports the length of a field as can be determined at registration time.

There are some shift/reduce errors in the grammar that I need to get rid of.

svn path=/trunk/; revision=811
This commit is contained in:
Gilbert Ramirez 1999-10-12 04:21:13 +00:00
parent 0faf733914
commit 1efcb7b2cf
7 changed files with 294 additions and 36 deletions

View File

@ -3,7 +3,7 @@
/* dfilter-grammar.y
* Parser for display filters
*
* $Id: dfilter-grammar.y,v 1.25 1999/10/11 19:39:29 guy Exp $
* $Id: dfilter-grammar.y,v 1.26 1999/10/12 04:21:09 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -93,6 +93,13 @@ static GNode* dfilter_mknode_bytes_variable(gint id, gint offset, guint length);
static guint32 string_to_value(char *s);
static int ether_str_to_guint8_array(const char *s, guint8 *mac);
static int ipv6_str_to_guint8_array(const char *s, guint8 *ipv6);
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.
@ -223,10 +230,56 @@ relation: numeric_variable numeric_relation numeric_value
| 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 "
"were supplied.",
dfilter_get_variable_abbrev($1),
a_len, plurality(a_len, "", "s"),
b_len, plurality(b_len, "", "s"));
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);
}
@ -304,8 +357,27 @@ bytes_value: T_VAL_BYTE_STRING
$$ = dfilter_mknode_bytes_value(barray);
g_free($1);
}
;
| T_VAL_NUMBER_STRING
{
guint32 val32 = string_to_value($1);
guint8 val8;
GByteArray *barray;
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);
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); }
@ -532,6 +604,62 @@ dfilter_mknode_bytes_variable(gint id, gint offset, guint length)
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)
{
@ -664,6 +792,17 @@ dfilter_mknode_bytes_value(GByteArray *barray)
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_value(char *s)
{
@ -764,3 +903,26 @@ ipv6_str_to_guint8_array(const char *s, guint8 *ipv6)
return 1; /* read exactly 16 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 were supplied.",
dfilter_get_variable_abbrev(gnode),
reg_len, plurality(reg_len, "", "s"),
a_len, plurality(a_len, "", "s"));
return 0;
}
}
return 1;
}

View File

@ -3,7 +3,7 @@
/* dfilter-scanner.l
* Scanner for display filters
*
* $Id: dfilter-scanner.l,v 1.18 1999/10/11 17:04:33 deniel Exp $
* $Id: dfilter-scanner.l,v 1.19 1999/10/12 04:21:10 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -132,6 +132,25 @@ le|\<\= { dfilter_lval.operand = TOK_LE; return TOK_LE; }
return T_VAL_BYTE_RANGE;
}
\[{whitespace}*-?[0-9]+{whitespace}*\] { /* range [ x ] */
char *byterange_string = g_strdup(yytext);
char *s = byterange_string + 1; /* I don't want the first '[' */
char *p;
/* Get the offset from the string */
if ((p = strtok(s, "]"))) {
dfilter_lval.byte_range.offset = strtol(p, NULL, 10);
}
else {
g_free(byterange_string);
return 0;
}
dfilter_lval.byte_range.length = 0;
g_free(byterange_string);
return T_VAL_BYTE_RANGE;
}
{hex}({hexsep}{hex})+ { /* byte string, any length */
dfilter_lval.string = g_strdup(yytext);

View File

@ -1,7 +1,7 @@
/* dfilter.c
* Routines for display filters
*
* $Id: dfilter.c,v 1.28 1999/10/11 17:04:34 deniel Exp $
* $Id: dfilter.c,v 1.29 1999/10/12 04:21:10 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -87,10 +87,10 @@ YYSTYPE yylval;
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, guint len);
static gboolean check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd, guint len);
static gboolean check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd, guint len);
static GArray* get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd, guint len);
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);
@ -293,17 +293,17 @@ g_strcmp(gconstpointer a, gconstpointer b)
gboolean
dfilter_apply(dfilter *dfcode, proto_tree *ptree, const guint8* pd, guint len)
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, len);
retval = dfilter_apply_node(dfcode->dftree, ptree, pd);
return retval;
}
static gboolean
dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8* pd, guint len)
dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8* pd)
{
GNode *gnode_a, *gnode_b;
dfilter_node *dnode = (dfilter_node*) (gnode->data);
@ -321,11 +321,11 @@ dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8* pd, guint len)
case logical:
g_assert(gnode_a);
return check_logical(dnode->value.logical, gnode_a, gnode_b, ptree, pd, len);
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, len);
return check_relation(dnode->value.relation, gnode_a, gnode_b, ptree, pd);
case alternation:
g_assert_not_reached();
@ -356,21 +356,21 @@ dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8* pd, guint len)
}
static gboolean
check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd, guint len)
check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd)
{
gboolean val_a = dfilter_apply_node(a, ptree, pd, len);
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, len));
return (val_a && dfilter_apply_node(b, ptree, pd));
case TOK_OR:
g_assert(b);
return (val_a || dfilter_apply_node(b, ptree, pd, len));
return (val_a || dfilter_apply_node(b, ptree, pd));
case TOK_XOR:
g_assert(b);
val_b = dfilter_apply_node(b, ptree, pd, len);
val_b = dfilter_apply_node(b, ptree, pd);
return ( ( val_a || val_b ) && ! ( val_a && val_b ) );
case TOK_NOT:
return (!val_a);
@ -388,7 +388,7 @@ check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8
* faster.
*/
static gboolean
check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8* pd, guint len)
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);
@ -399,12 +399,12 @@ check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8
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, len);
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, len);
vals_b = get_values_from_ptree(node_b, ptree, pd);
else
vals_b = get_values_from_dfilter(node_b, b);
@ -426,7 +426,7 @@ check_existence_in_ptree(dfilter_node *dnode, proto_tree *ptree)
}
static GArray*
get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd, guint len)
get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd)
{
GArray *array;
int parent_protocol;
@ -438,7 +438,6 @@ get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd,
sinfo.target = dnode->value.variable;
sinfo.result.array = array;
sinfo.packet_data = pd;
sinfo.packet_len = len;
sinfo.traverse_func = dnode->fill_array_func;
/* Find the proto_tree subtree where we should start searching.*/
@ -511,16 +510,36 @@ 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 start_of_data = fi->start + bytes_offset;
guint read_start, pkt_end;
if (fi->hfinfo->id == sinfo->target) {
if (sinfo->packet_len >= start_of_data + bytes_length) {
barray = g_byte_array_new();
g_byte_array_append(barray, sinfo->packet_data + start_of_data, bytes_length);
g_array_append_val(sinfo->result.array, barray);
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 */
}

View File

@ -1,7 +1,7 @@
/* dfilter.h
* Definitions for display filters
*
* $Id: dfilter.h,v 1.12 1999/10/11 14:58:01 gram Exp $
* $Id: dfilter.h,v 1.13 1999/10/12 04:21:11 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -61,6 +61,6 @@ void dfilter_destroy(dfilter *df);
dfilter* dfilter_compile(gchar* dfilter_text);
/* Apply compiled dfilter to a proto_tree */
gboolean dfilter_apply(dfilter *df, proto_tree *ptree, const guint8* pd, guint len);
gboolean dfilter_apply(dfilter *df, proto_tree *ptree, const guint8* pd);
#endif /* ! __DFILTER_H__ */

8
file.c
View File

@ -1,7 +1,7 @@
/* file.c
* File I/O routines
*
* $Id: file.c,v 1.106 1999/10/11 14:58:02 gram Exp $
* $Id: file.c,v 1.107 1999/10/12 04:21:11 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -627,7 +627,7 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf
protocol_tree = proto_tree_create_root();
dissect_packet(buf, fdata, protocol_tree);
if( DFILTER_CONTAINS_FILTER(cf->dfcode) )
fdata->passed_dfilter = dfilter_apply(cf->dfcode, protocol_tree, cf->pd, fdata->cap_len);
fdata->passed_dfilter = dfilter_apply(cf->dfcode, protocol_tree, cf->pd);
else
fdata->passed_dfilter = TRUE;
/* Apply color filters. */
@ -639,7 +639,7 @@ add_packet_to_packet_list(frame_data *fdata, capture_file *cf, const u_char *buf
continue;
}
if(dfilter_apply(color_filter(cf,crow)->c_colorfilter, protocol_tree,
cf->pd, fdata->cap_len)){
cf->pd)){
color = crow;
break;
}
@ -752,7 +752,7 @@ wtap_dispatch_cb(u_char *user, const struct wtap_pkthdr *phdr, int offset,
if (DFILTER_CONTAINS_FILTER(cf->rfcode)) {
protocol_tree = proto_tree_create_root();
dissect_packet(buf, fdata, protocol_tree);
passed = dfilter_apply(cf->rfcode, protocol_tree, cf->pd, fdata->cap_len);
passed = dfilter_apply(cf->rfcode, protocol_tree, cf->pd);
proto_tree_free(protocol_tree);
}
}

55
proto.c
View File

@ -1,7 +1,7 @@
/* proto.c
* Routines for protocol tree
*
* $Id: proto.c,v 1.33 1999/10/11 17:02:06 deniel Exp $
* $Id: proto.c,v 1.34 1999/10/12 04:21:12 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -725,6 +725,59 @@ proto_registrar_is_protocol(int n)
return FALSE;
}
/* Returns length of field.
* 0 means undeterminable at time of registration
* -1 means the field is not registered. */
gint
proto_registrar_get_length(int n)
{
struct header_field_info *hfinfo;
hfinfo = find_hfinfo_record(n);
if (!hfinfo)
return -1;
switch (hfinfo->type) {
case FT_TEXT_ONLY: /* not filterable */
case NUM_FIELD_TYPES: /* satisfy picky compilers */
return -1;
case FT_NONE:
case FT_BYTES:
case FT_BOOLEAN:
case FT_STRING:
case FT_DOUBLE:
case FT_ABSOLUTE_TIME:
case FT_RELATIVE_TIME:
return 0;
case FT_UINT8:
case FT_VALS_UINT8:
return 1;
case FT_UINT16:
case FT_VALS_UINT16:
return 2;
case FT_VALS_UINT24:
return 3;
case FT_UINT32:
case FT_VALS_UINT32:
case FT_IPXNET:
case FT_IPv4:
return 4;
case FT_ETHER:
return 6;
case FT_IPv6:
return 128;
}
g_assert_not_reached();
return -1;
}
/* Looks for a protocol or a field in a proto_tree. Returns TRUE if
* it exists anywhere, or FALSE if it exists nowhere. */
gboolean

View File

@ -1,7 +1,7 @@
/* proto.h
* Definitions for protocol display
*
* $Id: proto.h,v 1.15 1999/10/11 17:02:08 deniel Exp $
* $Id: proto.h,v 1.16 1999/10/12 04:21:13 gram Exp $
*
* Ethereal - Network traffic analyzer
* By Gerald Combs <gerald@zing.org>
@ -183,6 +183,11 @@ int proto_registrar_get_parent(int n);
/* Is item #n a protocol? */
gboolean proto_registrar_is_protocol(int n);
/* Get length of registered field according to field type.
* 0 means undeterminable at registration time.
* -1 means unknown field */
gint proto_registrar_get_length(int n);
/* Checks for existence any protocol or field within a tree.
* TRUE = found, FALSE = not found */
gboolean proto_check_for_protocol_or_field(proto_tree* tree, int id);