%{ /* dfilter-grammar.y * Parser for display filters * * $Id: dfilter-grammar.y,v 1.14 1999/08/20 21:19:27 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs * 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 #endif #ifdef HAVE_NETINET_IN_H # include #endif #ifdef NEED_SNPRINTF_H # ifdef HAVE_STDARG_H # include # else # include # endif # include "snprintf.h" #endif #ifndef __GLIB_H__ #include #endif #include #ifndef _STDLIB_H #include #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_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); static GNode* dfilter_mknode_ipv4_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 GNode* dfilter_mknode_boolean_value(gint truth_value); static GNode* dfilter_mknode_boolean_variable(gint id); static guint32 string_to_value(char *s); static int ether_str_to_guint8_array(const char *s, guint8 *mac); /* 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 */ gint variable; GNode* node; gchar* string; struct { gint offset; guint length; } byte_range; } %type statement expression relation %type numeric_value numeric_variable %type ether_value ether_variable %type ipxnet_value ipxnet_variable %type ipv4_value ipv4_variable %type variable_name %type bytes_value bytes_variable %type boolean_value boolean_variable %type numeric_relation %type equality_relation %type bytes_relation %type any_variable_type %token T_FT_UINT8 %token T_FT_UINT16 %token T_FT_UINT32 %token T_FT_ETHER %token T_FT_IPv4 %token T_FT_NONE %token T_FT_BYTES %token T_FT_BOOLEAN %token T_FT_STRING %token T_FT_IPXNET %token T_VAL_UNQUOTED_STRING %token T_VAL_BYTE_STRING %token T_VAL_NUMBER_STRING %token T_VAL_BYTE_RANGE %token TOK_AND TOK_OR TOK_NOT TOK_XOR %token TOK_EQ TOK_NE TOK_GT TOK_GE TOK_LT TOK_LE %token TOK_TRUE TOK_FALSE %left TOK_AND %left TOK_OR %left TOK_XOR %nonassoc TOK_NOT %% statement: expression { global_df->dftree = $1; } | /* 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; } ; 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); } | 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); } | bytes_variable bytes_relation bytes_value { $$ = dfilter_mknode_join($1, relation, $2, $3); } | bytes_variable bytes_relation bytes_variable { $$ = dfilter_mknode_join($1, relation, $2, $3); } | boolean_variable equality_relation boolean_value { $$ = dfilter_mknode_join($1, relation, $2, $3); } | boolean_variable equality_relation boolean_variable { $$ = dfilter_mknode_join($1, relation, $2, $3); } ; numeric_value: T_VAL_NUMBER_STRING { $$ = dfilter_mknode_numeric_value(string_to_value($1)); g_free($1); } ; ether_value: T_VAL_BYTE_STRING { $$ = dfilter_mknode_ether_value($1); g_free($1); if ($$ == NULL) { YYERROR; } } ; ipxnet_value: T_VAL_NUMBER_STRING { $$ = dfilter_mknode_ipxnet_value(string_to_value($1)); g_free($1); } ; ipv4_value: T_VAL_UNQUOTED_STRING { $$ = dfilter_mknode_ipv4_value($1); g_free($1); } | T_VAL_BYTE_STRING { $$ = dfilter_mknode_ipv4_value($1); g_free($1); } ; 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); } ; boolean_value: TOK_TRUE { $$ = dfilter_mknode_boolean_value($1); } | TOK_FALSE { $$ = dfilter_mknode_boolean_value($1); } ; numeric_variable: T_FT_UINT8 { $$ = dfilter_mknode_numeric_variable($1); } | T_FT_UINT16 { $$ = dfilter_mknode_numeric_variable($1); } | T_FT_UINT32 { $$ = dfilter_mknode_numeric_variable($1); } ; ether_variable: T_FT_ETHER { $$ = dfilter_mknode_ether_variable($1); } ; ipxnet_variable: T_FT_IPXNET { $$ = dfilter_mknode_ipxnet_variable($1); } ; ipv4_variable: T_FT_IPv4 { $$ = dfilter_mknode_ipv4_variable($1); } ; variable_name: any_variable_type { $$ = dfilter_mknode_existence($1); } ; bytes_variable: any_variable_type T_VAL_BYTE_RANGE { $$ = dfilter_mknode_bytes_variable($1, $2.offset, $2.length); } ; boolean_variable: T_FT_BOOLEAN { $$ = dfilter_mknode_boolean_variable($1); } ; any_variable_type: T_FT_UINT8 { $$ = $1; } | T_FT_UINT16 { $$ = $1; } | T_FT_UINT32 { $$ = $1; } | T_FT_ETHER { $$ = $1; } | T_FT_IPv4 { $$ = $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_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(guint32); 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_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; } static GNode* dfilter_mknode_boolean_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_boolean_variable; /* cheating ! */ node->check_relation_func = check_relation_boolean; /* cheating ! */ node->value.variable = id; gnode = g_node_new(node); return gnode; } 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; } /* 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 in the next call to * dfilter_clear() */ dfilter_error_msg = &dfilter_error_msg_buf[0]; snprintf(dfilter_error_msg, sizeof(dfilter_error_msg_buf), "\"%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; } static GNode* dfilter_mknode_ipv4_value(char *host) { 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; /* cheating ! */ node->check_relation_func = check_relation_numeric; /* cheating ! */ node->value.numeric = get_host_ipaddr(host); node->value.numeric = htonl(node->value.numeric); 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; } static GNode* dfilter_mknode_boolean_value(gint truth_value) { 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_boolean_value; node->check_relation_func = check_relation_boolean; node->value.boolean = truth_value == TOK_TRUE ? TRUE : FALSE; gnode = g_node_new(node); return gnode; } static guint32 string_to_value(char *s) { char *endptr; guint32 val; val = strtoul(s, &endptr, 0); /* I should probably check errno here */ return (guint32)val; } 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 */ }