Ethereal-dev: [Ethereal-dev] ranges for dfilter

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Ed Warnicke <hagbard@xxxxxxxxxxxxxxxxxxx>
Date: Sat, 30 Dec 2000 21:34:03 -0500 (EST)
Here is a patch to ethereal and a tarball containing two new 
source files that implements generalized ranges for filters and 
extending these ranges from just FT_BYTES to FT_STRINGS as well.  

The mechanism for extending ranges to other sequence types are 
also fairly well generalizes, so applying ranges to other 
types should not be very hard.  

Since this is the first large scale change I've written to something 
in the core of ethereal I would appreciate it if someone would look over 
it for a sanity check and then check it in.

Ed

Attachment: drange-20001230.tar.gz
Description: drange.c and drange.h

? cscope.out
? out
? epan/drange.h
? epan/drange.c
? epan/Makefile.am.new
Index: epan/Makefile.am
===================================================================
RCS file: /cvsroot/ethereal/epan/Makefile.am,v
retrieving revision 1.14
diff -u -r1.14 Makefile.am
--- Makefile.am	2000/11/20 16:18:08	1.14
+++ Makefile.am	2000/12/31 02:16:14
@@ -46,6 +46,8 @@
 	dfilter-scanner.l	\
 	dfilter.c		\
 	dfilter.h		\
+	drange.c		\
+	drange.h		\
 	epan.c			\
 	epan.h			\
 	except.c		\
Index: epan/dfilter-grammar.y
===================================================================
RCS file: /cvsroot/ethereal/epan/dfilter-grammar.y,v
retrieving revision 1.2
diff -u -r1.2 dfilter-grammar.y
--- dfilter-grammar.y	2000/12/22 12:05:36	1.2
+++ dfilter-grammar.y	2000/12/31 02:16:14
@@ -70,6 +70,7 @@
 #endif
 
 #include "dfilter-int.h"
+#include "drange.h"
 
 #ifndef __RESOLV_H__
 #include "resolv.h"
@@ -91,21 +92,37 @@
 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, gboolean to_the_end);
+static GNode* dfilter_mknode_bytes_variable(gint id, drange* range);
 static GNode* dfilter_mknode_string_value(char *s);
-static GNode* dfilter_mknode_string_variable(gint id);
+static GNode* dfilter_mknode_string_variable(gint id, drange* range);
 
 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 guint dfilter_get_range_value_length(GNode* gnode);
 static char* dfilter_get_variable_abbrev(GNode *gnode);
-static int check_bytes_variable_sanity(GNode *gnode);
 
+static drange_node* byte_string_to_drange_node(gchar* s, gboolean *success);
+static drange_node* string_to_drange_node(gchar* s, gboolean *success);
+static gboolean dfilter_is_range_variable(GNode *gnode);
+static gboolean dfilter_is_range_value(GNode *gnode);
+static gboolean dfilter_range_variable_has_total_length(GNode *gnode);
+static gint dfilter_get_range_variable_total_length(GNode *gnode);
+static int check_range_variable_sanity(GNode *gnode);
+static gint dfilter_get_range_variable_field_registered_length(GNode *gnode);
+static drange* null_to_drange(drange* range);
+
+static void check_range_variable_sanity_iterator(gpointer data, gpointer user_data);
+
+typedef struct _check_range_variable_sanity_iterator_arg{
+  gint max_length;
+  gboolean *success;
+  gchar* variable_abbrev;
+} check_range_variable_sanity_iterator_arg;
+
+static gboolean check_range_relation_sanity(GNode* a_gnode, 
+						GNode* b_gnode);
+
 /* This is the dfilter we're currently processing. It's how
  * dfilter_compile communicates with us.
  */
@@ -125,6 +142,7 @@
 		gint	offset;
 		guint	length;
 	} byte_range;
+        drange* range;
 }
 
 %type <node>	statement expression relation
@@ -138,6 +156,8 @@
 %type <node>	variable_name
 %type <node>	bytes_value bytes_variable
 
+%type <range>   range
+
 %type <operand>	numeric_relation
 %type <operand>	equality_relation
 %type <operand>	bytes_relation
@@ -165,10 +185,10 @@
 %token <string>	 	T_VAL_UNQUOTED_STRING
 %token <string>	 	T_VAL_QUOTED_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
+%token <operand>        TOK_BRA TOK_KET TOK_COMMA
 
 %expect 4
 %left TOK_AND
@@ -232,10 +252,16 @@
 
 	|	string_variable equality_relation string_value
 		{
+		        if(!check_range_relation_sanity($1,$3)){
+			  YYERROR;
+			}
 			$$ = dfilter_mknode_join($1, relation, $2, $3);
 		}
 	|	string_variable equality_relation string_variable
 		{
+		        if(!check_range_relation_sanity($1,$3)){
+			  YYERROR;
+			}
 			$$ = dfilter_mknode_join($1, relation, $2, $3);
 		}
 
@@ -260,57 +286,16 @@
 
 	|	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_range_relation_sanity($1,$3)){
+			  YYERROR;
 			}
-
-			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_range_relation_sanity($1,$3)){
+			  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);
 		}
 
@@ -545,21 +530,90 @@
 ipv6_variable:		T_FT_IPv6	{ $$ = dfilter_mknode_ipv6_variable($1.id); }
 	;
 
-string_variable:	T_FT_STRING	{ $$ = dfilter_mknode_string_variable($1.id); }
+string_variable:	T_FT_STRING TOK_BRA range TOK_KET	
+                        { 
+			  $$ = dfilter_mknode_string_variable($1.id,$3); 
+			}
+        |               T_FT_STRING	{ $$ = dfilter_mknode_string_variable($1.id,NULL); } 
 	;
 
-bytes_variable:		T_FT_BYTES T_VAL_BYTE_RANGE
+bytes_variable:		T_FT_BYTES TOK_BRA range TOK_KET
 		{
-			$$ = dfilter_mknode_bytes_variable($1.id, $2.offset, $2.length, FALSE);
+			$$ = dfilter_mknode_bytes_variable($1.id,$3);
 		}
 
         |               T_FT_BYTES      
                 {
-		        $$ = dfilter_mknode_bytes_variable($1.id, 0, 0, TRUE);
+		        $$ = dfilter_mknode_bytes_variable($1.id, NULL);
 		}
 
 	;
 
+
+range:                  T_VAL_BYTE_STRING
+                {
+		        drange* dr;
+                        drange_node* drnode;
+			gboolean success;
+			dr = drange_new();
+			global_df->list_of_dranges = 
+			  g_slist_prepend(global_df->list_of_dranges, dr);
+			drnode = byte_string_to_drange_node($1,&success);
+			if(success == FALSE){
+			  dfilter_fail("%s is not a range",$1);
+			  YYERROR;
+			}
+			drange_prepend_drange_node(dr,drnode);
+			g_free($1);
+			$$ = dr;
+		}
+        |               T_VAL_BYTE_STRING TOK_COMMA range
+                {
+                        drange_node* drnode;
+			gboolean success;
+			drnode = byte_string_to_drange_node($1,&success);
+			if(success == FALSE){
+			  dfilter_fail("%s is not a range",$1);
+			  YYERROR;
+			}
+			drange_prepend_drange_node($3,drnode);
+			g_free($1);
+			$$ = $3;
+		}
+        |               T_VAL_UNQUOTED_STRING
+                {
+		        drange* dr;
+                        drange_node* drnode;
+			gboolean success;
+
+			dr = drange_new();
+			global_df->list_of_dranges = 
+			  g_slist_prepend(global_df->list_of_dranges, dr);
+			drnode = string_to_drange_node($1,&success);
+			if(success == FALSE){
+			  dfilter_fail("%s is not a range",$1);
+			  YYERROR;
+			}
+			drange_prepend_drange_node(dr,drnode);
+			g_free($1);
+			$$ = dr;
+		}
+        |               T_VAL_UNQUOTED_STRING TOK_COMMA range
+                {
+                        drange_node* drnode;
+			gboolean success;
+			drnode = string_to_drange_node($1,&success);
+
+			if(success == FALSE){
+			  dfilter_fail("%s is not a range",$1);
+			  YYERROR;
+			}
+			drange_prepend_drange_node($3,drnode);
+			g_free($1);
+			$$ = $3;
+		}
+        ;
+
 variable_name:		any_variable_type
                 {
 		GNode	*variable;
@@ -774,10 +828,11 @@
 }
 
 static GNode*
-dfilter_mknode_string_variable(gint id)
+dfilter_mknode_string_variable(gint id, drange* range)
 {
 	dfilter_node	*node;
 	GNode		*gnode;
+	range = null_to_drange(range);
 
 	node = g_mem_chunk_alloc(global_df->node_memchunk);
 	node->ntype = variable;
@@ -786,16 +841,18 @@
 	node->fill_array_value_func = NULL;
 	node->check_relation_func = check_relation_string; 
 	node->value.variable = id;
+	node->range = range;
 	gnode = g_node_new(node);
 
 	return gnode;
 }
 
 static GNode*
-dfilter_mknode_bytes_variable(gint id, gint offset, guint length, gboolean to_the_end)
+dfilter_mknode_bytes_variable(gint id, drange* range)
 {
 	dfilter_node	*node;
 	GNode		*gnode;
+	range = null_to_drange(range);
 
 	node = g_mem_chunk_alloc(global_df->node_memchunk);
 	node->ntype = variable;
@@ -804,62 +861,12 @@
 	node->fill_array_value_func = NULL;
 	node->check_relation_func = check_relation_bytes;
 	node->value.variable = id;
-	node->offset = offset;
-	node->length = length;
-	node->to_the_end = to_the_end;
+	node->range = range;
 	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_variable_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_variable_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_variable_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_variable_func == fill_array_bytes_variable);
-
-	return node->offset;
-}
-
 static char*
 dfilter_get_variable_abbrev(GNode *gnode)
 {
@@ -1021,6 +1028,7 @@
 	node->value.string = g_strdup(s);
 	global_df->list_of_strings = g_slist_append(global_df->list_of_strings, 
 		node->value.string);
+	node->length = strlen(s);
 	gnode = g_node_new(node);
 
 	return gnode;
@@ -1040,7 +1048,6 @@
 	node->fill_array_value_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);
 
@@ -1050,11 +1057,11 @@
 /* Given a node representing a bytes_value, returns
  * the length of the byte array */
 static guint
-dfilter_get_bytes_value_length(GNode* gnode)
+dfilter_get_range_value_length(GNode* gnode)
 {
 	dfilter_node	*node = gnode->data;
 
-	g_assert(node->ntype == bytes);
+	g_assert(dfilter_is_range_value(gnode));
 	return node->length;
 }
 
@@ -1166,26 +1173,286 @@
 }
 
 
+/* We aren't really trying to convert a byte_string into a drange_node,
+ * but the scanner may have mistaken a range like 23:25 for a 
+ * byte string, so we correct for that here ( as the alternative 
+ * involves a MAJOR overhaul of a lot of other code.
+ */
+static drange_node* byte_string_to_drange_node(gchar* s, gboolean *success){
+  drange_node* drnode;
+  gint str_len, offset, length;
+  gboolean is_dash;
+  offset = 0;
+  length = 0;
+  is_dash = FALSE;
+  str_len = strlen(s);
+  drnode = NULL;
+  *success = FALSE;
+  if(str_len < 6){ /* are we any bigger than xx:yy ? */
+    drnode = string_to_drange_node(s,success);
+  }
+  return drnode;
+}
+
+/* convert a string like i:j or i-j into a drange_node */
+
+static drange_node* string_to_drange_node(gchar* s, gboolean *success){
+
+  drange_node* drnode;
+  gchar **str_array,*endptr;
+  gint str_len, offset, length,split_len;
+  gboolean is_dash,to_the_end;
+  offset = 0;
+  length = 0;
+  is_dash = FALSE;
+  to_the_end = FALSE;
+
+  str_len = strlen(s);
+  drnode = NULL;
+  *success = FALSE;
+
+  str_array = g_strsplit(s,":",2);
+  split_len = strlen(str_array[0]);
+  if( ( str_array[0] != NULL ) && ( split_len != str_len )){
+    offset = strtol(str_array[0],&endptr,10);
+    if( *endptr == '\0'){
+      if(str_array[1] != NULL){
+	length = strtol(str_array[1],&endptr,10);
+	if(*endptr == '\0'){
+	  *success = TRUE;
+	}
+      }
+    }
+  }
+  else {
+    g_strfreev(str_array);
+    str_array = g_strsplit(s,"-",2);
+    split_len = strlen(str_array[0]);
+    if( ( str_array[0] != NULL ) && ( split_len != str_len )){
+      is_dash = TRUE;
+      offset = strtol(str_array[0],&endptr,10);
+      if( *endptr == '\0'){
+	if(str_array[1] != NULL){
+	  length = strtol(str_array[1],&endptr,10);
+	  if(*endptr == '\0'){
+	    *success = TRUE;
+	  }
+	}
+	else if(s[str_len-1] == '-'){
+	  to_the_end = TRUE;
+	  *success = TRUE;
+	  is_dash = FALSE;
+	}
+      }
+    }
+    else {
+      offset = strtol(str_array[0],&endptr,10);
+      length = 1;
+      if( *endptr == '\0'){
+	*success = TRUE;
+      }
+    }
+  }
+  g_strfreev(str_array);
+  if(is_dash){
+    length = (length + 1) - offset;
+  }
+  if( *success ) {
+    drnode = drange_node_new();
+    drange_node_set_offset(drnode,offset);
+    drange_node_set_length(drnode,length);
+    drange_node_set_to_the_end(drnode,to_the_end);
+  }
+  return drnode;
+}
+
+static gboolean dfilter_is_range_variable(GNode *gnode){
+	dfilter_node	*node = gnode->data;
+	gboolean rtrn = FALSE;
+	if( node->ntype == variable &&
+	   ((node->fill_array_variable_func == fill_array_bytes_variable) ||
+	    (node->fill_array_variable_func == fill_array_string_variable))){
+	  rtrn = TRUE;
+	}
+	return rtrn;
+}
+
+static gboolean dfilter_is_range_value(GNode *gnode){
+        dfilter_node    *node = gnode->data;
+	gboolean rtrn = FALSE;
+	if(node->ntype == bytes || node->ntype == string){
+	  rtrn = TRUE;
+	}
+	return rtrn;
+}
+
+static gboolean dfilter_range_variable_has_total_length(GNode *gnode){
+  	dfilter_node	*node = gnode->data;
+	return (drange_has_total_length(node->range));
+}
+
+static gint dfilter_get_range_variable_total_length(GNode *gnode){
+  	dfilter_node	*node = gnode->data;
+	return (drange_get_total_length(node->range));
+}
+
+/* Gets length of variable represented by node from proto_register */
+static gint
+dfilter_get_range_variable_field_registered_length(GNode *gnode)
+{
+	dfilter_node	*node = gnode->data;
+
+	/* Is this really a range_variable? */
+	g_assert(dfilter_is_range_variable(gnode));
+
+	return proto_registrar_get_length(node->value.variable);
+}
+
 static int
-check_bytes_variable_sanity(GNode *gnode)
+check_range_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;
+	dfilter_node* node;
+	gboolean success;
+	check_range_variable_sanity_iterator_arg* arg;
+
+	arg = g_malloc(sizeof(check_range_variable_sanity_iterator_arg));
+
+	node = gnode->data;
+	arg->max_length = dfilter_get_range_variable_field_registered_length(gnode);
+	success = TRUE;
+	arg->success = &success;
+	arg->variable_abbrev = dfilter_get_variable_abbrev(gnode);
+	drange_foreach_drange_node(node->range,check_range_variable_sanity_iterator, arg);
+	g_free(arg);
+	return ( success );
+}
+
+static void check_range_variable_sanity_iterator(gpointer data, gpointer user_data){
+  check_range_variable_sanity_iterator_arg* arg;
+  drange_node* drnode;
+  gboolean *success_ptr;
+  gint a_off, a_len, a_to_the_end,t_off;
+  arg = (check_range_variable_sanity_iterator_arg*)user_data;
+
+  success_ptr = arg->success;
+  if(*(success_ptr) == TRUE){    
+    drnode = (drange_node*)data;
+    a_off = drange_node_get_offset(drnode);
+    a_len = drange_node_get_length(drnode);
+    a_to_the_end = drange_node_get_to_the_end(drnode);
+    if(arg->max_length > 0){
+      t_off = a_off >= 0 ? a_off : arg->max_length + a_off;
+      if( a_to_the_end == FALSE && ( t_off + a_len > arg->max_length ) ){
+	dfilter_fail("The \"%s\" field is only %u byte%s wide, but "
+		     "%u byte%s %s supplied.",
+		     arg->variable_abbrev,
+		     arg->max_length, plurality(arg->max_length, "", "s"),
+		     a_len, plurality(a_len, "", "s"),
+		     plurality(a_len, "was", "were"));
+	*(success_ptr) = FALSE;
+      }
+    }
+  }
+}
+
+static drange* null_to_drange(drange* range){
+  drange*         dr;
+  drange_node*    drnode;
+  dr = range;
+  if(dr == NULL){
+    drnode = drange_node_new();
+    drange_node_set_offset(drnode,0);
+    drange_node_set_to_the_end(drnode,TRUE);
+    dr = drange_new();
+    global_df->list_of_dranges = 
+      g_slist_prepend(global_df->list_of_dranges, dr);
+    drange_prepend_drange_node(dr,drnode);
+  }  
+  return dr;
+}
+
+static gboolean check_range_relation_sanity(GNode* a_gnode, 
+						GNode* b_gnode){
+  int a_len, b_len;
+  gboolean a_has_length, b_has_length, a_is_var, a_is_val, b_is_var, rtrn;
+  gboolean b_is_val;
+
+  a_len = b_len = 0;
+
+  rtrn = FALSE;
+  a_has_length = TRUE;
+  b_has_length = TRUE;
+
+  a_is_var = dfilter_is_range_variable(a_gnode);
+  b_is_var = dfilter_is_range_variable(b_gnode);
+  a_is_val = dfilter_is_range_value(a_gnode);
+  b_is_val = dfilter_is_range_value(b_gnode);
+  
+  if( ( a_is_var || a_is_val ) && ( b_is_var || b_is_val ) ){ 
+    if( a_is_var ){
+      a_has_length = dfilter_range_variable_has_total_length(a_gnode);
+      if(a_has_length)
+	a_len = dfilter_get_range_variable_total_length(a_gnode);
+    }
+    else {
+      a_len = dfilter_get_range_value_length(a_gnode);;
+    }
+ 
+    if( b_is_var ) {
+      b_has_length = dfilter_range_variable_has_total_length(b_gnode);
+      if(b_has_length)
+	b_len = dfilter_get_range_variable_total_length(b_gnode);
+    }
+    else {
+      b_len = dfilter_get_range_value_length(b_gnode);
+    }
+    
+    if (a_is_var && check_range_variable_sanity(a_gnode)) {
+      rtrn = TRUE;
+    }
+    
+    if (rtrn && b_is_var && !check_range_variable_sanity(b_gnode)) {
+      rtrn = FALSE;
+    }
+  
+    if (rtrn && a_has_length && b_has_length && 
+	a_len != b_len) {
+      if(a_is_var && b_is_var){
+	dfilter_fail("Fields \"%s\" and \"%s\" are being compared with "
+		     "disparate lengths of %u byte%s and %u byte%s.",
+		     dfilter_get_variable_abbrev(a_gnode),
+		     dfilter_get_variable_abbrev(b_gnode),
+		     a_len, plurality(a_len, "", "s"),
+		     b_len, plurality(b_len, "", "s"));
+	rtrn = FALSE;;
+      } 
+      else if ( a_is_var && b_is_val ) {
+	dfilter_fail("Field \"%s\" has %u byte%s being compared, but %u byte%s "
+		     "%s supplied.",
+		     dfilter_get_variable_abbrev(a_gnode),
+		     a_len, plurality(a_len, "", "s"),
+		     b_len, plurality(b_len, "", "s"),
+		     plurality(b_len, "was", "were"));
+	rtrn = FALSE;
+      }
+      else if ( a_is_val && b_is_var ){
+		dfilter_fail("Field \"%s\" has %u byte%s being compared, but %u byte%s "
+		     "%s supplied.",
+		     dfilter_get_variable_abbrev(b_gnode),
+		     b_len, plurality(b_len, "", "s"),
+		     a_len, plurality(a_len, "", "s"),
+		     plurality(a_len, "was", "were"));
+	rtrn = FALSE;
+      }
+      else if ( a_is_val && b_is_val ){
+	rtrn = FALSE;
+      }
+    }
+  }
+  return rtrn;
 }
+
+
+
+
Index: epan/dfilter-int.h
===================================================================
RCS file: /cvsroot/ethereal/epan/dfilter-int.h,v
retrieving revision 1.2
diff -u -r1.2 dfilter-int.h
--- dfilter-int.h	2000/12/22 12:05:36	1.2
+++ dfilter-int.h	2000/12/31 02:16:14
@@ -31,6 +31,8 @@
 #include "ipv4.h"
 #endif
 
+#include "drange.h"
+
 /* in dfilter-scanner.l */
 GByteArray *byte_str_to_guint8_array(const char *s);
 void dfilter_scanner_text(char*);
@@ -134,12 +136,11 @@
 		GByteArray	*bytes;
 	}				value;
 
-	/* used for byte-ranges */
-	gint				offset;
+	/* used for value lengths */
 	guint				length;
 
-        /* used to indicate range should go to end of sequence */
-        gboolean                        to_the_end;
+        /* used to handle many ranges */
+        drange* range;
 } dfilter_node;
 
 /* lookup an abbreviation in our token hash, returing the ID # */
Index: epan/dfilter-scanner.l
===================================================================
RCS file: /cvsroot/ethereal/epan/dfilter-scanner.l,v
retrieving revision 1.1
diff -u -r1.1 dfilter-scanner.l
--- dfilter-scanner.l	2000/09/27 04:54:48	1.1
+++ dfilter-scanner.l	2000/12/31 02:16:15
@@ -115,54 +115,10 @@
 ge|\>\=		{ dfilter_lval.operand = TOK_GE; return TOK_GE; }
 lt|\<		{ dfilter_lval.operand = TOK_LT; return TOK_LT; }
 le|\<\=		{ dfilter_lval.operand = TOK_LE; return TOK_LE; }
+\[              { dfilter_lval.operand = TOK_BRA; return TOK_BRA; }
+\]              { dfilter_lval.operand = TOK_KET; return TOK_KET; }
+\,              { dfilter_lval.operand = TOK_COMMA; return TOK_COMMA; }
 
-\[{whitespace}*-?[0-9]+{whitespace}*:{whitespace}*[0-9]+{whitespace}*\] { /* range [ x : y ] */
-
-	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;
-	}
-
-	/* Get the Length from the string */
-	if ((p = strtok(NULL, "]"))) {
-		dfilter_lval.byte_range.length = strtoul(p, NULL, 10);
-	}
-	else {
-		g_free(byterange_string);
-		return 0;
-	}
-	g_free(byterange_string);
-	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);
 	return T_VAL_BYTE_STRING;
@@ -174,7 +130,7 @@
 	return T_VAL_UNQUOTED_STRING;
 }
 
-[A-Za-z0-9\:][A-Za-z0-9\.\_\-\:]+ {
+[A-Za-z0-9\:][A-Za-z0-9\.\_\-\:]* {
 	/* looks like a protocol, field name, or hostname */
 
 	int retval = 0;
Index: epan/dfilter.c
===================================================================
RCS file: /cvsroot/ethereal/epan/dfilter.c,v
retrieving revision 1.3
diff -u -r1.3 dfilter.c
--- dfilter.c	2000/12/22 12:05:36	1.3
+++ dfilter.c	2000/12/31 02:16:16
@@ -44,6 +44,9 @@
 #include "dfilter-int.h"
 #include "dfilter-grammar.h"
 
+/* This should eventually be removed */
+#include "strutil.h"
+
 int dfilter_parse(void); /* yacc entry-point */
 
 #define DFILTER_LEX_ABBREV_OFFSET	2000
@@ -54,10 +57,8 @@
 /* Comparision function for tree insertion. A wrapper around strcmp() */
 static int g_strcmp(gconstpointer a, gconstpointer b);
 
-/* Silly global variables used to pass parameter to check_relation_bytes() */
-int bytes_offset = 0;
-int bytes_length = 0;
-gboolean bytes_to_the_end = FALSE;
+/* Silly global variable used for ranges */
+drange* current_range = NULL;
 
 YYSTYPE yylval;
 
@@ -72,6 +73,25 @@
 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);
+static void pack_byte_array(gpointer data, gpointer user_data);
+
+typedef struct _pack_byte_array_arg {
+  GByteArray* barray;
+  drange* dr;
+  field_info* finfo;
+  const guint8* pd;
+  gboolean success;
+} pack_byte_array_arg;
+
+static void pack_string(gpointer data, gpointer user_data);
+
+typedef struct _pack_string_arg {
+  GString* str;;
+  drange* dr;
+  field_info* finfo;
+  const guint8* pd;
+  gboolean success;
+} pack_string_arg;
 
 /* this is not so pretty. I need my own g_array "function" (macro) to
  * retreive the pointer to the data stored in an array cell. I need this
@@ -139,7 +159,6 @@
 {
 	dfilter *df;
 	int retval;
-
 	g_assert(dfilter_text != NULL);
 
 	df = dfilter_new();
@@ -165,7 +184,6 @@
 	 * so treat that as a parse error. */
 	if (dfilter_error_msg != NULL)
 		retval = 1;
-
 	if (retval != 0) {
 		if (dfilter_error_msg == NULL) {
 			snprintf(dfilter_error_msg_buf, sizeof(dfilter_error_msg_buf),
@@ -174,7 +192,6 @@
 			dfilter_error_msg = &dfilter_error_msg_buf[0];
 		}
 	}
-
 	/* Set global_df to NULL just to be tidy. */
 	global_df = NULL;
 
@@ -209,6 +226,7 @@
 		sizeof(dfilter_node), 20 * sizeof(dfilter_node), G_ALLOC_ONLY);
 	df->list_of_byte_arrays = NULL;
 	df->list_of_strings = NULL;
+	df->list_of_dranges = NULL;
 
 	return df;
 }
@@ -221,6 +239,14 @@
 		g_free(string);
 }
 
+static void
+free_drange(gpointer data, gpointer user_data)
+{
+	drange* dr = (drange*)data;
+	if (dr)
+		drange_free(dr);
+}
+
 /* Frees all memory used by dfilter, and frees dfilter itself */
 void
 dfilter_destroy(dfilter *df)
@@ -247,9 +273,16 @@
 		g_slist_free(df->list_of_strings);
 	}
 
+	/* clear the allocated dranges */
+	if (df->list_of_dranges) {
+		g_slist_foreach(df->list_of_dranges, free_drange, NULL);
+		g_slist_free(df->list_of_dranges);
+	}
+
 	df->dftree = NULL;
 	df->list_of_byte_arrays = NULL;
 	df->list_of_strings = NULL;
+	df->list_of_dranges = NULL;
 
 	/* Git rid of memchunk */
 	if (df->node_memchunk)
@@ -417,6 +450,20 @@
 	}
 }
 
+static void
+free_array_of_strings(GArray *array)
+{
+	int		i, len;
+	gchar	        *str_ptr;
+
+	len = array->len;
+
+	for (i = 0; i < len ; i++) {
+		str_ptr = g_array_index(array, gchar*, i);
+		g_free(str_ptr);
+	}
+}
+
 /* this is inefficient. I get arrays for both a and b that represent all the values present. That is,
  * if a is bootp.option, e.g., i'll get an array showing all the bootp.option values in the protocol
  * tree. Then I'll get an array for b, which more than likely is a single int, and then I'll compare
@@ -430,8 +477,7 @@
 	dfilter_node	*node_b = (dfilter_node*) (b->data);
 	GArray		*vals_a, *vals_b;
 	gboolean	retval;
-
-
+	
 	if (node_a->ntype == variable)
 		vals_a = get_values_from_ptree(node_a, ptree, pd);
 	else
@@ -453,9 +499,17 @@
 		free_array_of_byte_arrays(vals_b);
 	}
 
+	/* Free strings allocated by fill_array_string_variable */
+	if (node_a->fill_array_variable_func == fill_array_string_variable) {
+		free_array_of_strings(vals_a);
+	}
+
+	if (node_b->fill_array_variable_func == fill_array_string_variable) {
+		free_array_of_strings(vals_b);
+	}	
+
 	g_array_free(vals_a, FALSE);
 	g_array_free(vals_b, FALSE);
-
 	return retval;
 }
 
@@ -485,9 +539,7 @@
 	 * for this dnode
 	 */
 
-	bytes_offset = dnode->offset;
-	bytes_length = dnode->length;
-	bytes_to_the_end = dnode->to_the_end;
+	current_range = dnode->range;
 
 	/* Cull the finfos from the proto_tree */
 	finfo_array = proto_get_finfo_ptr_array(ptree, dnode->value.variable);
@@ -544,44 +596,39 @@
 void
 fill_array_string_variable(field_info *finfo, GArray *array, const guint8 *pd)
 {
-	g_array_append_val(array, finfo->value.string);
+	pack_string_arg*  arg;
+	arg = g_malloc(sizeof(pack_string_arg));
+	arg->str = g_string_new("\0");
+	arg->dr = current_range;
+	arg->finfo = finfo;
+	arg->pd = pd;
+	arg->success = TRUE;
+	drange_foreach_drange_node(arg->dr,pack_string,arg);
+	if(arg->success){
+	  g_array_append_val(array, arg->str->str);
+	}
+	g_string_free(arg->str,FALSE);
+	g_free(arg);
 }
 
 void
 fill_array_bytes_variable(field_info *finfo, GArray *array, const guint8 *pd)
 {
-	GByteArray		*barray;
-	guint			read_start, pkt_end, read_len;
-
-	if (bytes_offset < 0) {
-		/* Handle negative byte offsets */
-		bytes_offset = finfo->length + bytes_offset;
-		if (bytes_offset < 0) {
-			return;
-		}
+	pack_byte_array_arg*  arg;
+	arg = g_malloc(sizeof(pack_byte_array_arg));
+	arg->barray = g_byte_array_new();
+	arg->dr = current_range;
+	arg->finfo = finfo;
+	arg->pd = pd;
+	arg->success = TRUE;
+	drange_foreach_drange_node(arg->dr,pack_byte_array,arg);
+	if(arg->success){
+	  g_array_append_val(array,arg->barray);
 	}
-
-	/* Check to make sure offset exists for this field */
-	if (bytes_offset >= finfo->length) {
-		return;
+	else{
+	  g_byte_array_free(arg->barray,TRUE);
 	}
-
-	pkt_end = finfo->start + finfo->length;
-	read_start = finfo->start + bytes_offset;
-	if(bytes_to_the_end){
-	        read_len = pkt_end - read_start;;
-	}
-	else {
-	        read_len = bytes_length;
-	}
-	/* Check to make sure entire length requested is inside field */
-	if (pkt_end < read_start + read_len) {
-		return;
-	}
-
-	barray = g_byte_array_new();
-	g_byte_array_append(barray, pd + read_start, read_len);
-	g_array_append_val(array, barray);
+	g_free(arg);
 }
 
 static GArray*
@@ -985,7 +1032,6 @@
 	len_a = a->len;
 	len_b = b->len;
 
-
 	switch(operand) {
 	case TOK_EQ:
 		for(i = 0; i < len_a; i++) {
@@ -1083,4 +1129,111 @@
 	g_assert_not_reached();
 	return FALSE;
 }
+
+static void pack_byte_array(gpointer data, gpointer user_data){
+  pack_byte_array_arg* arg;
+  drange_node* drnode;
+  guint			read_start, pkt_end, read_len;
+  gboolean to_the_end;
+  gint offset, length;
+
+  arg = (pack_byte_array_arg*)user_data;
+  drnode = (drange_node*)data;
+
+  if(arg->success == FALSE){
+    return;
+  }
+  
+  offset = drange_node_get_offset(drnode);
+  length = drange_node_get_length(drnode);
+  to_the_end = drange_node_get_to_the_end(drnode);
+
+  if (offset < 0) {
+    /* Handle negative byte offsets */
+    offset = arg->finfo->length + offset;
+    if (offset < 0) {
+      arg->success = FALSE;
+      return;
+    }
+  }
+  
+  /* Check to make sure offset exists for this field */
+  if (offset >= arg->finfo->length) {
+    arg->success = FALSE;
+    return;
+  }
+  
+  pkt_end = arg->finfo->start + arg->finfo->length;
+  read_start = arg->finfo->start + offset;
+  if(to_the_end){
+    read_len = pkt_end - read_start;;
+  }
+  else {
+    read_len = length;
+  }
+  /* Check to make sure entire length requested is inside field */
+  if (pkt_end < read_start + read_len) {
+    arg->success = FALSE;
+    return;
+  }
+  
+  arg->barray = g_byte_array_append(arg->barray, arg->pd + read_start, read_len);
+  return;
+}  
+
+static void pack_string(gpointer data, gpointer user_data){
+  pack_string_arg* arg;
+  drange_node* drnode;
+  guint			read_start, pkt_end, read_len;
+  gboolean to_the_end;
+  gint offset, length,value_length;
+  gchar* substr;
+
+  arg = (pack_string_arg*)user_data;
+  drnode = (drange_node*)data;
+
+  if(arg->success == FALSE){
+    return;
+  }
+  
+  offset = drange_node_get_offset(drnode);
+  length = drange_node_get_length(drnode);
+  to_the_end = drange_node_get_to_the_end(drnode);
+  value_length = strlen(arg->finfo->value.string);
+  if (offset < 0) {
+    /* Handle negative byte offsets */
+    offset = value_length + offset;
+    if (offset < 0) {
+      arg->success = FALSE;
+      return;
+    }
+  }
+  
+  /* Check to make sure offset exists for this field */
+  if (offset >= value_length) {
+    arg->success = FALSE;
+    return;
+  }
+  
+  pkt_end = value_length;
+  read_start = offset;
+  if(to_the_end){
+    read_len = pkt_end - read_start;;
+  }
+  else {
+    read_len = length;
+  }
+  /* Check to make sure entire length requested is inside field */
+  if (pkt_end < read_start + read_len) {
+    arg->success = FALSE;
+    return;
+  }
+  substr = g_strndup(arg->finfo->value.string + read_start, read_len);  
+  arg->str = g_string_append(arg->str, substr);
+  g_free(substr);
+  return;
+}  
+
+
+
 
Index: epan/dfilter.h
===================================================================
RCS file: /cvsroot/ethereal/epan/dfilter.h,v
retrieving revision 1.1
diff -u -r1.1 dfilter.h
--- dfilter.h	2000/09/27 04:54:49	1.1
+++ dfilter.h	2000/12/31 02:16:16
@@ -47,6 +47,9 @@
 	/* List of strings allocated during parse. */
 	GSList *list_of_strings;
 
+        /* List of dranges allocated during parse */
+        GSList *list_of_dranges;
+
 } dfilter;
 
 /* Initialization of the symbol table. Called once during program startup */