diff --git a/dfilter-grammar.y b/dfilter-grammar.y index b49ac0b9ff..9a966985d0 100644 --- a/dfilter-grammar.y +++ b/dfilter-grammar.y @@ -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 @@ -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; +} diff --git a/dfilter-scanner.l b/dfilter-scanner.l index b6bab0d9e2..1bf22ac53b 100644 --- a/dfilter-scanner.l +++ b/dfilter-scanner.l @@ -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 @@ -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); diff --git a/dfilter.c b/dfilter.c index 56ac93d336..4f0486239a 100644 --- a/dfilter.c +++ b/dfilter.c @@ -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 @@ -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 */ } diff --git a/dfilter.h b/dfilter.h index c5ad3c4055..bb4d5d868e 100644 --- a/dfilter.h +++ b/dfilter.h @@ -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 @@ -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__ */ diff --git a/file.c b/file.c index 0d87394374..1b7abe7e2a 100644 --- a/file.c +++ b/file.c @@ -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 @@ -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); } } diff --git a/proto.c b/proto.c index cefed2863f..4550814078 100644 --- a/proto.c +++ b/proto.c @@ -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 @@ -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 diff --git a/proto.h b/proto.h index f60466a9e4..13d627a8b9 100644 --- a/proto.h +++ b/proto.h @@ -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 @@ -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);