2 * Routines for display filters
4 * $Id: dfilter.c,v 1.14 1999/08/20 21:19:28 gram Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
8 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
42 #ifdef NEED_SNPRINTF_H
48 # include "snprintf.h"
67 #include "dfilter-int.h"
68 #include "dfilter-grammar.h"
70 int dfilter_parse(void); /* yacc entry-point */
72 #define DFILTER_LEX_ABBREV_OFFSET 2000
74 /* Balanced tree of abbreviations and IDs */
75 GTree *dfilter_tokens = NULL;
77 /* Comparision function for tree insertion. A wrapper around strcmp() */
78 static int g_strcmp(gconstpointer a, gconstpointer b);
80 /* Silly global variables used to pass parameter to check_relation_bytes() */
86 /* Global error message space for dfilter_compile errors */
87 gchar dfilter_error_msg_buf[1024];
88 gchar *dfilter_error_msg; /* NULL when no error resulted */
90 static gboolean dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8 *pd);
91 static gboolean check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd);
92 static gboolean check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd);
93 static GArray* get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd);
94 static GArray* get_values_from_dfilter(dfilter_node *dnode, GNode *gnode);
95 static gboolean check_existence_in_ptree(dfilter_node *dnode, proto_tree *ptree);
96 static void clear_byte_array(gpointer data, gpointer user_data);
98 /* this is not so pretty. I need my own g_array "function" (macro) to
99 * retreive the pointer to the data stored in an array cell. I need this
100 * for type ether.. GArray makes it easy for me to store 6 bytes inside an array
101 * cell, but hard to retrieve it.
103 #define g_array_index_ptr(a,s,i) (((guint8*) (a)->data) + (i*s))
108 int i, num_symbols, symbol;
111 dfilter_tokens = g_tree_new(g_strcmp);
113 /* Add the header field and protocol abbrevs to the symbol table */
114 num_symbols = proto_registrar_n();
115 for (i=0; i < num_symbols; i++) {
116 s = proto_registrar_get_abbrev(i);
118 symbol = DFILTER_LEX_ABBREV_OFFSET + i;
119 g_tree_insert(dfilter_tokens, s, GINT_TO_POINTER(symbol));
123 /* XXX - I should eventually g_tree_destroy(dfilter_tokens), when ethereal shuts down */
125 /* Compiles the textual representation of the display filter into a tree
126 * of operations to perform. Can be called multiple times, compiling a new
127 * display filter each time, without having to clear any memory used, since
128 * dfilter_compile will take care of that automatically.
130 * Returns 0 on success, non-zero on failure.
131 * If a failure, dfilter_error_msg points to an appropriate error message.
132 * This error message is a global string, so another invocation of
133 * dfilter_compile will clear it. If the caller needs is stored, he
134 * needs to g_strdup it himself.
137 dfilter_compile(dfilter *df, gchar *dfilter_text)
141 g_assert(dfilter_text != NULL);
143 dfilter_clear_filter(df);
144 df->dftext = g_strdup(dfilter_text);
146 /* tell the scanner to use this string as input */
147 dfilter_scanner_text(df->dftext);
149 /* Assign global variable so yyparse knows which dfilter we're talking about */
151 dfilter_error_msg = NULL;
153 /* The magic happens right here. */
154 retval = dfilter_parse();
157 dfilter_scanner_cleanup();
159 /* If a parse error occurred, fill in a generic error message
160 * if one was not created during parsing. */
162 if (dfilter_error_msg == NULL) {
163 dfilter_error_msg = &dfilter_error_msg_buf[0];
164 snprintf(dfilter_error_msg, sizeof(dfilter_error_msg_buf),
165 "Unable to parse filter string \"%s\".",
173 /* clear the current filter, w/o clearing memchunk area which is where we'll
174 * put new nodes in a future filter */
176 dfilter_clear_filter(dfilter *df)
184 if (df->dftree != NULL)
185 g_node_destroy(df->dftree);
187 /* clear the memory that the tree was using for nodes */
188 if (df->node_memchunk)
189 g_mem_chunk_reset(df->node_memchunk);
191 /* clear the memory that the tree was using for byte arrays */
192 if (df->list_of_byte_arrays) {
193 g_slist_foreach(df->list_of_byte_arrays, clear_byte_array, NULL);
194 g_slist_free(df->list_of_byte_arrays);
199 df->list_of_byte_arrays = NULL;
202 /* Allocates new dfilter, initializes values, and returns pointer to dfilter */
208 df = g_malloc(sizeof(dfilter));
212 df->node_memchunk = g_mem_chunk_new("df->node_memchunk",
213 sizeof(dfilter_node), 20 * sizeof(dfilter_node), G_ALLOC_ONLY);
214 df->list_of_byte_arrays = NULL;
219 /* Frees all memory used by dfilter, and frees dfilter itself */
221 dfilter_destroy(dfilter *df)
226 dfilter_clear_filter(df);
228 /* Git rid of memchunk */
229 if (df->node_memchunk)
230 g_mem_chunk_destroy(df->node_memchunk);
240 clear_byte_array(gpointer data, gpointer user_data)
242 GByteArray *barray = data;
244 g_byte_array_free(barray, TRUE);
248 dfilter_error(char *s)
250 /* fprintf(stderr, "%s\n", s);
251 Do not report the error, just let yyparse() return 1 */
255 dfilter_yyerror(char *fmt, ...)
257 /* XXX - is this cool? check for mem leak */
258 global_df->dftree = NULL;
262 /* lookup an abbreviation in our token tree, returing the ID #
263 * If the abbreviation doesn't exit, returns 0 */
264 int dfilter_lookup_token(char *abbrev)
268 g_assert(abbrev != NULL);
269 value = GPOINTER_TO_INT(g_tree_lookup(dfilter_tokens, abbrev));
271 if (value < DFILTER_LEX_ABBREV_OFFSET) {
274 return value - DFILTER_LEX_ABBREV_OFFSET;
278 g_strcmp(gconstpointer a, gconstpointer b)
280 return strcmp((const char*)a, (const char*)b);
285 dfilter_apply(dfilter *dfcode, proto_tree *ptree, const guint8* pd)
288 retval = dfilter_apply_node(dfcode->dftree, ptree, pd);
293 dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8* pd)
295 GNode *gnode_a, *gnode_b;
296 dfilter_node *dnode = (dfilter_node*) (gnode->data);
298 /* We'll get 2 NULLs if we don't have children */
299 gnode_a = g_node_nth_child(gnode, 0);
300 gnode_b = g_node_nth_child(gnode, 1);
302 switch(dnode->ntype) {
304 /* We'll never see this case because if the parser finds the name of
305 * a variable, it will cause it to be an 'existence' operation.
307 g_assert_not_reached();
310 return check_logical(dnode->value.logical, gnode_a, gnode_b, ptree, pd);
313 g_assert(gnode_a && gnode_b);
314 return check_relation(dnode->value.relation, gnode_a, gnode_b, ptree, pd);
317 g_assert_not_reached();
328 /* the only time we'll see these at this point is if the display filter
329 * is really wacky. (like simply "192.168.1.1"). The parser as it stands
330 * now let these by. Just return TRUE */
331 g_assert(!gnode_a && !gnode_b);
334 case existence: /* checking the existence of a protocol or hf*/
335 g_assert(!gnode_a && !gnode_b);
336 return check_existence_in_ptree(dnode, ptree);
339 g_assert_not_reached();
344 check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd)
346 gboolean val_a = dfilter_apply_node(a, ptree, pd);
351 return (val_a && dfilter_apply_node(b, ptree, pd));
353 return (val_a || dfilter_apply_node(b, ptree, pd));
355 val_b = dfilter_apply_node(b, ptree, pd);
356 return ( ( val_a || val_b ) && ! ( val_a && val_b ) );
360 g_assert_not_reached();
362 g_assert_not_reached();
366 /* this is inefficient. I get arrays for both a and b that represent all the values present. That is,
367 * if a is bootp.option, e.g., i'll get an array showing all the bootp.option values in the protocol
368 * tree. Then I'll get an array for b, which more than likely is a single int, and then I'll compare
369 * them all. It makes my coding easier in the beginning, but I should change this to make it run
373 check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8* pd)
375 dfilter_node *node_a = (dfilter_node*) (a->data);
376 dfilter_node *node_b = (dfilter_node*) (b->data);
377 GArray *vals_a, *vals_b;
381 bytes_length = MIN(node_a->length, node_b->length);
382 bytes_offset = MIN(node_a->offset, node_b->offset);
383 if (node_a->ntype == variable)
384 vals_a = get_values_from_ptree(node_a, ptree, pd);
386 vals_a = get_values_from_dfilter(node_a, a);
388 if (node_b->ntype == variable)
389 vals_b = get_values_from_ptree(node_b, ptree, pd);
391 vals_b = get_values_from_dfilter(node_b, b);
393 retval = node_a->check_relation_func(operand, vals_a, vals_b);
395 g_array_free(vals_a, FALSE);
396 g_array_free(vals_b, FALSE);
402 check_existence_in_ptree(dfilter_node *dnode, proto_tree *ptree)
407 target_field = dnode->value.variable;
408 subtree = proto_find_field(ptree, target_field);
417 get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd)
422 proto_tree *subtree = NULL; /* where the parent protocol's sub-tree starts */
423 proto_tree_search_info sinfo;
425 g_assert(dnode->elem_size > 0);
426 array = g_array_new(FALSE, FALSE, dnode->elem_size);
428 target_field = dnode->value.variable;
430 /* Find the proto_tree subtree where we should start searching.*/
431 if (proto_registrar_is_protocol(target_field)) {
432 subtree = proto_find_protocol(ptree, target_field);
435 parent_protocol = proto_registrar_get_parent(target_field);
436 if (parent_protocol >= 0) {
437 subtree = proto_find_protocol(ptree, parent_protocol);
442 sinfo.target_field = target_field;
443 sinfo.result_array = array;
444 sinfo.packet_data = pd;
445 proto_get_field_values(subtree, dnode->fill_array_func, &sinfo);
452 get_values_from_dfilter(dfilter_node *dnode, GNode *gnode)
456 g_assert(dnode->elem_size > 0);
457 array = g_array_new(FALSE, FALSE, dnode->elem_size);
459 g_node_traverse(gnode, G_IN_ORDER, G_TRAVERSE_ALL, -1, dnode->fill_array_func, array);
460 /* dnode->fill_array_func(gnode, array);*/
464 gboolean fill_array_numeric_variable(GNode *gnode, gpointer data)
466 proto_tree_search_info *sinfo = (proto_tree_search_info*)data;
467 field_info *fi = (field_info*) (gnode->data);
469 if (fi->hfinfo->id == sinfo->target_field) {
470 g_array_append_val(sinfo->result_array, fi->value.numeric);
473 return FALSE; /* FALSE = do not end traversal of GNode tree */
476 gboolean fill_array_ether_variable(GNode *gnode, gpointer data)
478 proto_tree_search_info *sinfo = (proto_tree_search_info*)data;
479 field_info *fi = (field_info*) (gnode->data);
481 if (fi->hfinfo->id == sinfo->target_field) {
482 g_array_append_val(sinfo->result_array, fi->value.ether);
485 return FALSE; /* FALSE = do not end traversal of GNode tree */
488 gboolean fill_array_bytes_variable(GNode *gnode, gpointer data)
490 proto_tree_search_info *sinfo = (proto_tree_search_info*)data;
491 field_info *fi = (field_info*) (gnode->data);
494 if (fi->hfinfo->id == sinfo->target_field) {
495 barray = g_byte_array_new();
496 /*list_of_byte_arrays = g_slist_append(list_of_byte_arrays, barray);*/
497 g_byte_array_append(barray, sinfo->packet_data + fi->start + bytes_offset, bytes_length);
498 g_array_append_val(sinfo->result_array, barray);
501 return FALSE; /* FALSE = do not end traversal of GNode tree */
504 gboolean fill_array_boolean_variable(GNode *gnode, gpointer data)
506 proto_tree_search_info *sinfo = (proto_tree_search_info*)data;
507 field_info *fi = (field_info*) (gnode->data);
509 if (fi->hfinfo->id == sinfo->target_field) {
510 g_array_append_val(sinfo->result_array, fi->value.boolean);
513 return FALSE; /* FALSE = do not end traversal of GNode tree */
516 gboolean fill_array_numeric_value(GNode *gnode, gpointer data)
518 GArray *array = (GArray*)data;
519 dfilter_node *dnode = (dfilter_node*) (gnode->data);
521 g_array_append_val(array, dnode->value.numeric);
523 return FALSE; /* FALSE = do not end traversal of GNode tree */
526 gboolean fill_array_ether_value(GNode *gnode, gpointer data)
528 GArray *array = (GArray*)data;
529 dfilter_node *dnode = (dfilter_node*) (gnode->data);
531 g_array_append_val(array, dnode->value.ether);
533 return FALSE; /* FALSE = do not end traversal of GNode tree */
536 gboolean fill_array_bytes_value(GNode *gnode, gpointer data)
538 GArray *array = (GArray*)data;
539 dfilter_node *dnode = (dfilter_node*) (gnode->data);
540 GByteArray *barray = dnode->value.bytes;
542 g_array_append_val(array, barray);
544 return FALSE; /* FALSE = do not end traversal of GNode tree */
547 gboolean fill_array_boolean_value(GNode *gnode, gpointer data)
549 GArray *array = (GArray*)data;
550 dfilter_node *dnode = (dfilter_node*) (gnode->data);
552 g_array_append_val(array, dnode->value.boolean);
554 return FALSE; /* FALSE = do not end traversal of GNode tree */
558 gboolean check_relation_numeric(gint operand, GArray *a, GArray *b)
560 int i, j, len_a, len_b;
569 for(i = 0; i < len_a; i++) {
570 val_a = g_array_index(a, guint32, i);
571 for (j = 0; j < len_b; j++) {
572 if (val_a == g_array_index(b, guint32, j))
579 for(i = 0; i < len_a; i++) {
580 val_a = g_array_index(a, guint32, i);
581 for (j = 0; j < len_b; j++) {
582 if (val_a != g_array_index(b, guint32, j))
589 for(i = 0; i < len_a; i++) {
590 val_a = g_array_index(a, guint32, i);
591 for (j = 0; j < len_b; j++) {
592 if (val_a > g_array_index(b, guint32, j))
599 for(i = 0; i < len_a; i++) {
600 val_a = g_array_index(a, guint32, i);
601 for (j = 0; j < len_b; j++) {
602 if (val_a >= g_array_index(b, guint32, j))
609 for(i = 0; i < len_a; i++) {
610 val_a = g_array_index(a, guint32, i);
611 for (j = 0; j < len_b; j++) {
612 if (val_a < g_array_index(b, guint32, j))
619 for(i = 0; i < len_a; i++) {
620 val_a = g_array_index(a, guint32, i);
621 for (j = 0; j < len_b; j++) {
622 if (val_a <= g_array_index(b, guint32, j))
629 g_assert_not_reached();
632 g_assert_not_reached();
637 gboolean check_relation_ether(gint operand, GArray *a, GArray *b)
639 int i, j, len_a, len_b;
640 guint8 *ptr_a, *ptr_b;
648 for(i = 0; i < len_a; i++) {
649 ptr_a = g_array_index_ptr(a, 6, i);
650 for (j = 0; j < len_b; j++) {
651 ptr_b = g_array_index_ptr(b, 6, j);
652 if (memcmp(ptr_a, ptr_b, 6) == 0)
659 for(i = 0; i < len_a; i++) {
660 ptr_a = g_array_index_ptr(a, 6, i);
661 for (j = 0; j < len_b; j++) {
662 ptr_b = g_array_index_ptr(b, 6, j);
663 if (memcmp(ptr_a, ptr_b, 6) != 0)
670 g_assert_not_reached();
674 gboolean check_relation_bytes(gint operand, GArray *a, GArray *b)
676 int i, j, len_a, len_b;
677 GByteArray *ptr_a,*ptr_b;
685 for(i = 0; i < len_a; i++) {
686 ptr_a = g_array_index(a, GByteArray*, i);
687 for (j = 0; j < len_b; j++) {
688 ptr_b = g_array_index(b, GByteArray*, j);
689 if (memcmp(ptr_a->data, ptr_b->data, bytes_length) == 0)
696 for(i = 0; i < len_a; i++) {
697 ptr_a = g_array_index(a, GByteArray*, i);
698 for (j = 0; j < len_b; j++) {
699 ptr_b = g_array_index(b, GByteArray*, j);
700 if (memcmp(ptr_a->data, ptr_b->data, bytes_length) != 0)
707 for(i = 0; i < len_a; i++) {
708 ptr_a = g_array_index(a, GByteArray*, i);
709 for (j = 0; j < len_b; j++) {
710 ptr_b = g_array_index(b, GByteArray*, j);
711 if (memcmp(ptr_a->data, ptr_b->data, bytes_length) > 0)
718 for(i = 0; i < len_a; i++) {
719 ptr_a = g_array_index(a, GByteArray*, i);
720 for (j = 0; j < len_b; j++) {
721 ptr_b = g_array_index(b, GByteArray*, j);
722 if (memcmp(ptr_a->data, ptr_b->data, bytes_length) < 0)
729 g_assert_not_reached();
733 gboolean check_relation_boolean(gint operand, GArray *a, GArray *b)
735 int i, j, len_a, len_b;
744 for(i = 0; i < len_a; i++) {
745 val_a = g_array_index(a, guint32, i);
746 for (j = 0; j < len_b; j++) {
747 if (val_a == g_array_index(b, guint32, j))
754 for(i = 0; i < len_a; i++) {
755 val_a = g_array_index(a, guint32, i);
756 for (j = 0; j < len_b; j++) {
757 if (val_a != g_array_index(b, guint32, j))
764 g_assert_not_reached();
767 g_assert_not_reached();