1999-07-07 22:52:57 +00:00
|
|
|
/* dfilter.c
|
|
|
|
* Routines for display filters
|
|
|
|
*
|
2000-12-22 12:05:38 +00:00
|
|
|
* $Id: dfilter.c,v 1.3 2000/12/22 12:05:36 gram Exp $
|
1999-07-07 22:52:57 +00:00
|
|
|
*
|
|
|
|
* Ethereal - Network traffic analyzer
|
|
|
|
* By Gerald Combs <gerald@zing.org>
|
|
|
|
* 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 <sys/types.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2000-08-11 13:37:21 +00:00
|
|
|
#include <glib.h>
|
1999-07-07 22:52:57 +00:00
|
|
|
|
1999-08-20 20:45:14 +00:00
|
|
|
#ifdef NEED_SNPRINTF_H
|
|
|
|
# include "snprintf.h"
|
|
|
|
#endif
|
|
|
|
|
1999-07-07 22:52:57 +00:00
|
|
|
#include "proto.h"
|
|
|
|
#include "dfilter.h"
|
1999-08-12 21:16:32 +00:00
|
|
|
#include "dfilter-int.h"
|
1999-07-07 22:52:57 +00:00
|
|
|
#include "dfilter-grammar.h"
|
|
|
|
|
1999-08-14 06:24:27 +00:00
|
|
|
int dfilter_parse(void); /* yacc entry-point */
|
1999-07-07 22:52:57 +00:00
|
|
|
|
|
|
|
#define DFILTER_LEX_ABBREV_OFFSET 2000
|
|
|
|
|
Changed the display filter scanner from GLIB's GScanner to lex. The code
as it standed depends on your lex being flex, but that only matters if you're
a developer. The distribution will include the dfilter-scanner.c file, so
that if the user doesn't modify dfilter-scanner.l, he won't need flex to
re-create the *.c file.
The new lex scanner gives me better syntax checking for ether addresses. I
thought I could get by using GScanner, but it simply wasn't powerful enough.
All operands have English-like abbreviations and C-like syntax:
and, && ; or, || ; eq, == ; ne, != ; , etc.
I removed the ETHER_VENDOR type in favor of letting the user use the [x:y]
notation: ether.src[0:3] == 0:6:29 instead of ether.srcvendor == 00:06:29
I implemented the IPXNET field type; it had been there before, but was
not implemented. I chose to make it use integer values rather than byte
ranges, since an IPX Network is 4 bytes. So a display filter looks like this:
ipx.srcnet == 0xc0a82c00
rather than this:
ipx.srcnet == c0:a8:2c:00
I can supposrt the byte-range type IPXNET in the future, very trivially.
I still have more work to do on the parser though. It needs to check ranges
when extracting byte ranges ([x:y]) from packets. And I need to get rid
of those reduce/reduce errors from yacc!
svn path=/trunk/; revision=414
1999-08-01 04:28:20 +00:00
|
|
|
/* Balanced tree of abbreviations and IDs */
|
|
|
|
GTree *dfilter_tokens = NULL;
|
|
|
|
|
|
|
|
/* Comparision function for tree insertion. A wrapper around strcmp() */
|
|
|
|
static int g_strcmp(gconstpointer a, gconstpointer b);
|
1999-07-07 22:52:57 +00:00
|
|
|
|
|
|
|
/* Silly global variables used to pass parameter to check_relation_bytes() */
|
|
|
|
int bytes_offset = 0;
|
|
|
|
int bytes_length = 0;
|
2000-12-22 12:05:38 +00:00
|
|
|
gboolean bytes_to_the_end = FALSE;
|
1999-07-07 22:52:57 +00:00
|
|
|
|
|
|
|
YYSTYPE yylval;
|
Changed the display filter scanner from GLIB's GScanner to lex. The code
as it standed depends on your lex being flex, but that only matters if you're
a developer. The distribution will include the dfilter-scanner.c file, so
that if the user doesn't modify dfilter-scanner.l, he won't need flex to
re-create the *.c file.
The new lex scanner gives me better syntax checking for ether addresses. I
thought I could get by using GScanner, but it simply wasn't powerful enough.
All operands have English-like abbreviations and C-like syntax:
and, && ; or, || ; eq, == ; ne, != ; , etc.
I removed the ETHER_VENDOR type in favor of letting the user use the [x:y]
notation: ether.src[0:3] == 0:6:29 instead of ether.srcvendor == 00:06:29
I implemented the IPXNET field type; it had been there before, but was
not implemented. I chose to make it use integer values rather than byte
ranges, since an IPX Network is 4 bytes. So a display filter looks like this:
ipx.srcnet == 0xc0a82c00
rather than this:
ipx.srcnet == c0:a8:2c:00
I can supposrt the byte-range type IPXNET in the future, very trivially.
I still have more work to do on the parser though. It needs to check ranges
when extracting byte ranges ([x:y]) from packets. And I need to get rid
of those reduce/reduce errors from yacc!
svn path=/trunk/; revision=414
1999-08-01 04:28:20 +00:00
|
|
|
|
1999-08-20 20:37:47 +00:00
|
|
|
/* Global error message space for dfilter_compile errors */
|
|
|
|
gchar dfilter_error_msg_buf[1024];
|
|
|
|
gchar *dfilter_error_msg; /* NULL when no error resulted */
|
|
|
|
|
1999-10-12 04:21:13 +00:00
|
|
|
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);
|
1999-07-07 22:52:57 +00:00
|
|
|
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);
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
* for type ether.. GArray makes it easy for me to store 6 bytes inside an array
|
|
|
|
* cell, but hard to retrieve it.
|
|
|
|
*/
|
|
|
|
#define g_array_index_ptr(a,s,i) (((guint8*) (a)->data) + (i*s))
|
|
|
|
|
2000-09-13 20:30:48 +00:00
|
|
|
extern int hf_text_only; /* in proto.c */
|
|
|
|
|
1999-07-07 22:52:57 +00:00
|
|
|
void
|
|
|
|
dfilter_init(void)
|
|
|
|
{
|
Changed the display filter scanner from GLIB's GScanner to lex. The code
as it standed depends on your lex being flex, but that only matters if you're
a developer. The distribution will include the dfilter-scanner.c file, so
that if the user doesn't modify dfilter-scanner.l, he won't need flex to
re-create the *.c file.
The new lex scanner gives me better syntax checking for ether addresses. I
thought I could get by using GScanner, but it simply wasn't powerful enough.
All operands have English-like abbreviations and C-like syntax:
and, && ; or, || ; eq, == ; ne, != ; , etc.
I removed the ETHER_VENDOR type in favor of letting the user use the [x:y]
notation: ether.src[0:3] == 0:6:29 instead of ether.srcvendor == 00:06:29
I implemented the IPXNET field type; it had been there before, but was
not implemented. I chose to make it use integer values rather than byte
ranges, since an IPX Network is 4 bytes. So a display filter looks like this:
ipx.srcnet == 0xc0a82c00
rather than this:
ipx.srcnet == c0:a8:2c:00
I can supposrt the byte-range type IPXNET in the future, very trivially.
I still have more work to do on the parser though. It needs to check ranges
when extracting byte ranges ([x:y]) from packets. And I need to get rid
of those reduce/reduce errors from yacc!
svn path=/trunk/; revision=414
1999-08-01 04:28:20 +00:00
|
|
|
int i, num_symbols, symbol;
|
1999-07-07 22:52:57 +00:00
|
|
|
char *s;
|
|
|
|
|
Changed the display filter scanner from GLIB's GScanner to lex. The code
as it standed depends on your lex being flex, but that only matters if you're
a developer. The distribution will include the dfilter-scanner.c file, so
that if the user doesn't modify dfilter-scanner.l, he won't need flex to
re-create the *.c file.
The new lex scanner gives me better syntax checking for ether addresses. I
thought I could get by using GScanner, but it simply wasn't powerful enough.
All operands have English-like abbreviations and C-like syntax:
and, && ; or, || ; eq, == ; ne, != ; , etc.
I removed the ETHER_VENDOR type in favor of letting the user use the [x:y]
notation: ether.src[0:3] == 0:6:29 instead of ether.srcvendor == 00:06:29
I implemented the IPXNET field type; it had been there before, but was
not implemented. I chose to make it use integer values rather than byte
ranges, since an IPX Network is 4 bytes. So a display filter looks like this:
ipx.srcnet == 0xc0a82c00
rather than this:
ipx.srcnet == c0:a8:2c:00
I can supposrt the byte-range type IPXNET in the future, very trivially.
I still have more work to do on the parser though. It needs to check ranges
when extracting byte ranges ([x:y]) from packets. And I need to get rid
of those reduce/reduce errors from yacc!
svn path=/trunk/; revision=414
1999-08-01 04:28:20 +00:00
|
|
|
dfilter_tokens = g_tree_new(g_strcmp);
|
1999-07-07 22:52:57 +00:00
|
|
|
|
|
|
|
/* Add the header field and protocol abbrevs to the symbol table */
|
|
|
|
num_symbols = proto_registrar_n();
|
2000-09-13 20:30:48 +00:00
|
|
|
|
1999-07-07 22:52:57 +00:00
|
|
|
for (i=0; i < num_symbols; i++) {
|
2000-09-13 20:30:48 +00:00
|
|
|
if (i == hf_text_only) {
|
|
|
|
continue;
|
|
|
|
}
|
1999-07-07 22:52:57 +00:00
|
|
|
s = proto_registrar_get_abbrev(i);
|
2000-03-20 22:52:48 +00:00
|
|
|
g_assert(s); /* Not Null */
|
|
|
|
g_assert(s[0] != 0); /* Not empty string */
|
|
|
|
/* Make sure we don't have duplicate abbreviation */
|
|
|
|
if (g_tree_lookup(dfilter_tokens, s)) {
|
|
|
|
g_message("Already have abbreviation \"%s\"", s);
|
|
|
|
g_assert(0);
|
1999-07-07 22:52:57 +00:00
|
|
|
}
|
2000-03-20 22:52:48 +00:00
|
|
|
symbol = DFILTER_LEX_ABBREV_OFFSET + i;
|
|
|
|
g_tree_insert(dfilter_tokens, s, GINT_TO_POINTER(symbol));
|
1999-07-07 22:52:57 +00:00
|
|
|
}
|
|
|
|
}
|
1999-08-26 06:20:50 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
dfilter_cleanup(void)
|
|
|
|
{
|
|
|
|
if (dfilter_tokens)
|
|
|
|
g_tree_destroy(dfilter_tokens);
|
|
|
|
}
|
1999-07-07 22:52:57 +00:00
|
|
|
|
Changed the display filter scanner from GLIB's GScanner to lex. The code
as it standed depends on your lex being flex, but that only matters if you're
a developer. The distribution will include the dfilter-scanner.c file, so
that if the user doesn't modify dfilter-scanner.l, he won't need flex to
re-create the *.c file.
The new lex scanner gives me better syntax checking for ether addresses. I
thought I could get by using GScanner, but it simply wasn't powerful enough.
All operands have English-like abbreviations and C-like syntax:
and, && ; or, || ; eq, == ; ne, != ; , etc.
I removed the ETHER_VENDOR type in favor of letting the user use the [x:y]
notation: ether.src[0:3] == 0:6:29 instead of ether.srcvendor == 00:06:29
I implemented the IPXNET field type; it had been there before, but was
not implemented. I chose to make it use integer values rather than byte
ranges, since an IPX Network is 4 bytes. So a display filter looks like this:
ipx.srcnet == 0xc0a82c00
rather than this:
ipx.srcnet == c0:a8:2c:00
I can supposrt the byte-range type IPXNET in the future, very trivially.
I still have more work to do on the parser though. It needs to check ranges
when extracting byte ranges ([x:y]) from packets. And I need to get rid
of those reduce/reduce errors from yacc!
svn path=/trunk/; revision=414
1999-08-01 04:28:20 +00:00
|
|
|
/* Compiles the textual representation of the display filter into a tree
|
1999-08-13 23:47:43 +00:00
|
|
|
* of operations to perform. Can be called multiple times, compiling a new
|
|
|
|
* display filter each time, without having to clear any memory used, since
|
|
|
|
* dfilter_compile will take care of that automatically.
|
1999-08-20 20:37:47 +00:00
|
|
|
*
|
1999-10-12 05:01:07 +00:00
|
|
|
* Returns 0 on success, non-zero on failure.
|
|
|
|
*
|
|
|
|
* On success, sets the "dfilter *" pointed to by its second argument
|
|
|
|
* either to a null pointer (if the filter is a null filter, as
|
|
|
|
* generated by an all-blank string) or to a pointer to a newly-allocated
|
|
|
|
* dfilter structure (if the filter isn't null).
|
|
|
|
*
|
|
|
|
* On failure, "dfilter_error_msg" points to an appropriate error message.
|
1999-08-20 20:37:47 +00:00
|
|
|
* This error message is a global string, so another invocation of
|
|
|
|
* dfilter_compile will clear it. If the caller needs is stored, he
|
|
|
|
* needs to g_strdup it himself.
|
Changed the display filter scanner from GLIB's GScanner to lex. The code
as it standed depends on your lex being flex, but that only matters if you're
a developer. The distribution will include the dfilter-scanner.c file, so
that if the user doesn't modify dfilter-scanner.l, he won't need flex to
re-create the *.c file.
The new lex scanner gives me better syntax checking for ether addresses. I
thought I could get by using GScanner, but it simply wasn't powerful enough.
All operands have English-like abbreviations and C-like syntax:
and, && ; or, || ; eq, == ; ne, != ; , etc.
I removed the ETHER_VENDOR type in favor of letting the user use the [x:y]
notation: ether.src[0:3] == 0:6:29 instead of ether.srcvendor == 00:06:29
I implemented the IPXNET field type; it had been there before, but was
not implemented. I chose to make it use integer values rather than byte
ranges, since an IPX Network is 4 bytes. So a display filter looks like this:
ipx.srcnet == 0xc0a82c00
rather than this:
ipx.srcnet == c0:a8:2c:00
I can supposrt the byte-range type IPXNET in the future, very trivially.
I still have more work to do on the parser though. It needs to check ranges
when extracting byte ranges ([x:y]) from packets. And I need to get rid
of those reduce/reduce errors from yacc!
svn path=/trunk/; revision=414
1999-08-01 04:28:20 +00:00
|
|
|
*/
|
1999-10-12 05:01:07 +00:00
|
|
|
int
|
|
|
|
dfilter_compile(gchar *dfilter_text, dfilter **dfp)
|
1999-07-07 22:52:57 +00:00
|
|
|
{
|
1999-10-11 06:39:26 +00:00
|
|
|
dfilter *df;
|
1999-07-07 22:52:57 +00:00
|
|
|
int retval;
|
|
|
|
|
|
|
|
g_assert(dfilter_text != NULL);
|
|
|
|
|
1999-10-11 06:39:26 +00:00
|
|
|
df = dfilter_new();
|
1999-07-07 22:52:57 +00:00
|
|
|
|
1999-10-11 06:39:26 +00:00
|
|
|
/* tell the scanner to use the filter string as input */
|
|
|
|
dfilter_scanner_text(dfilter_text);
|
1999-07-07 22:52:57 +00:00
|
|
|
|
1999-08-26 06:20:50 +00:00
|
|
|
/* Assign global variable so dfilter_parse knows which dfilter we're
|
1999-10-11 06:39:26 +00:00
|
|
|
* talking about. Reset the global error message.
|
1999-08-26 06:20:50 +00:00
|
|
|
*/
|
1999-08-13 23:47:43 +00:00
|
|
|
global_df = df;
|
1999-08-20 20:37:47 +00:00
|
|
|
dfilter_error_msg = NULL;
|
1999-07-11 08:40:52 +00:00
|
|
|
|
1999-08-13 23:47:43 +00:00
|
|
|
/* The magic happens right here. */
|
1999-08-14 06:24:27 +00:00
|
|
|
retval = dfilter_parse();
|
1999-08-13 23:47:43 +00:00
|
|
|
|
|
|
|
/* clean up lex */
|
Changed the display filter scanner from GLIB's GScanner to lex. The code
as it standed depends on your lex being flex, but that only matters if you're
a developer. The distribution will include the dfilter-scanner.c file, so
that if the user doesn't modify dfilter-scanner.l, he won't need flex to
re-create the *.c file.
The new lex scanner gives me better syntax checking for ether addresses. I
thought I could get by using GScanner, but it simply wasn't powerful enough.
All operands have English-like abbreviations and C-like syntax:
and, && ; or, || ; eq, == ; ne, != ; , etc.
I removed the ETHER_VENDOR type in favor of letting the user use the [x:y]
notation: ether.src[0:3] == 0:6:29 instead of ether.srcvendor == 00:06:29
I implemented the IPXNET field type; it had been there before, but was
not implemented. I chose to make it use integer values rather than byte
ranges, since an IPX Network is 4 bytes. So a display filter looks like this:
ipx.srcnet == 0xc0a82c00
rather than this:
ipx.srcnet == c0:a8:2c:00
I can supposrt the byte-range type IPXNET in the future, very trivially.
I still have more work to do on the parser though. It needs to check ranges
when extracting byte ranges ([x:y]) from packets. And I need to get rid
of those reduce/reduce errors from yacc!
svn path=/trunk/; revision=414
1999-08-01 04:28:20 +00:00
|
|
|
dfilter_scanner_cleanup();
|
|
|
|
|
Make "dfilter_error()" available to the lexical analyzer.
Get rid of the declaration of the non-existent "dfilter_yyerror()", and
put in some #defines to work around the fact that the #defines to
replace "yy" with "dfilter_" in the names of Flex-generated and
Yacc-generated routines aren't put into a header file, they're put into
".c" files.
Have it remember the error message it was handed (unless it's Yacc's
boring "parse error" message).
When generating the message to be shown to the user on a parse error,
make it be the "Unable to parse filter string" message, and, if a
non-boring error message was supplied to "dfilter_error()", take that
error message onto the end.
Don't panic if a field type we don't yet support in the parser is seen;
generate an error, telling the user we don't support filter on that type
yet.
Don't assume that "global_df" has been set if we see an empty statement
(if the first token was the end-marker, because, say, the first token
the lexical analyzer found was a field of a type not yet supported in
filter expressions, "global_df" won't have been set).
svn path=/trunk/; revision=783
1999-10-07 21:47:20 +00:00
|
|
|
/* Errors not found by the parser may not cause the parse to
|
|
|
|
* fail; if "dfilter_error_msg" is set, it means somebody
|
Have "get_host_ipaddr()" return a Boolean indicating whether it
succeeded or failed, and, if it succeeded, have it fill in the IP
address if found through a pointer passed as the second argument.
Have it first try interpreting its first argument as a dotted-quad IP
address, with "inet_aton()", and, if that fails, have it try to
interpret it as a host name with "gethostbyname()"; don't bother with
"gethostbyaddr()", as we should be allowed to filter on IP addresses
even if there's no host name associated with them (there's no guarantee
that "gethostbyaddr()" will succeed if handed an IP address with no
corresponding name - and it looks as if FreeBSD 3.2, at least, may not
succeed in that case).
Add a "dfilter_fail()" routine that takes "printf()"-like arguments and
uses them to set an error message for the parse; doing so means that
even if the filter expression is syntactically valid, we treat it as
being invalid. (Is there a better way to force a parse to fail from
arbitrary places in routines called by the parser?)
Use that routine in the lexical analyzer.
If that error message was set, use it as is as the failure message,
rather than adding "Unable to parse filter string XXX" to it.
Have the code to handle IP addresses and host names in display filters
check whether "get_host_ipaddr()" succeeded or failed and, if it failed,
arrange that the parse fail with an error message indicating the source
of the problem.
svn path=/trunk/; revision=802
1999-10-11 03:03:12 +00:00
|
|
|
* else called "dfilter_fail()", e.g. the lexical analyzer,
|
Make "dfilter_error()" available to the lexical analyzer.
Get rid of the declaration of the non-existent "dfilter_yyerror()", and
put in some #defines to work around the fact that the #defines to
replace "yy" with "dfilter_" in the names of Flex-generated and
Yacc-generated routines aren't put into a header file, they're put into
".c" files.
Have it remember the error message it was handed (unless it's Yacc's
boring "parse error" message).
When generating the message to be shown to the user on a parse error,
make it be the "Unable to parse filter string" message, and, if a
non-boring error message was supplied to "dfilter_error()", take that
error message onto the end.
Don't panic if a field type we don't yet support in the parser is seen;
generate an error, telling the user we don't support filter on that type
yet.
Don't assume that "global_df" has been set if we see an empty statement
(if the first token was the end-marker, because, say, the first token
the lexical analyzer found was a field of a type not yet supported in
filter expressions, "global_df" won't have been set).
svn path=/trunk/; revision=783
1999-10-07 21:47:20 +00:00
|
|
|
* so treat that as a parse error. */
|
|
|
|
if (dfilter_error_msg != NULL)
|
|
|
|
retval = 1;
|
|
|
|
|
1999-08-20 20:37:47 +00:00
|
|
|
if (retval != 0) {
|
|
|
|
if (dfilter_error_msg == NULL) {
|
Make "dfilter_error()" available to the lexical analyzer.
Get rid of the declaration of the non-existent "dfilter_yyerror()", and
put in some #defines to work around the fact that the #defines to
replace "yy" with "dfilter_" in the names of Flex-generated and
Yacc-generated routines aren't put into a header file, they're put into
".c" files.
Have it remember the error message it was handed (unless it's Yacc's
boring "parse error" message).
When generating the message to be shown to the user on a parse error,
make it be the "Unable to parse filter string" message, and, if a
non-boring error message was supplied to "dfilter_error()", take that
error message onto the end.
Don't panic if a field type we don't yet support in the parser is seen;
generate an error, telling the user we don't support filter on that type
yet.
Don't assume that "global_df" has been set if we see an empty statement
(if the first token was the end-marker, because, say, the first token
the lexical analyzer found was a field of a type not yet supported in
filter expressions, "global_df" won't have been set).
svn path=/trunk/; revision=783
1999-10-07 21:47:20 +00:00
|
|
|
snprintf(dfilter_error_msg_buf, sizeof(dfilter_error_msg_buf),
|
1999-08-20 20:37:47 +00:00
|
|
|
"Unable to parse filter string \"%s\".",
|
|
|
|
dfilter_text);
|
Have "get_host_ipaddr()" return a Boolean indicating whether it
succeeded or failed, and, if it succeeded, have it fill in the IP
address if found through a pointer passed as the second argument.
Have it first try interpreting its first argument as a dotted-quad IP
address, with "inet_aton()", and, if that fails, have it try to
interpret it as a host name with "gethostbyname()"; don't bother with
"gethostbyaddr()", as we should be allowed to filter on IP addresses
even if there's no host name associated with them (there's no guarantee
that "gethostbyaddr()" will succeed if handed an IP address with no
corresponding name - and it looks as if FreeBSD 3.2, at least, may not
succeed in that case).
Add a "dfilter_fail()" routine that takes "printf()"-like arguments and
uses them to set an error message for the parse; doing so means that
even if the filter expression is syntactically valid, we treat it as
being invalid. (Is there a better way to force a parse to fail from
arbitrary places in routines called by the parser?)
Use that routine in the lexical analyzer.
If that error message was set, use it as is as the failure message,
rather than adding "Unable to parse filter string XXX" to it.
Have the code to handle IP addresses and host names in display filters
check whether "get_host_ipaddr()" succeeded or failed and, if it failed,
arrange that the parse fail with an error message indicating the source
of the problem.
svn path=/trunk/; revision=802
1999-10-11 03:03:12 +00:00
|
|
|
dfilter_error_msg = &dfilter_error_msg_buf[0];
|
1999-08-20 20:37:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-10-11 06:39:26 +00:00
|
|
|
/* Set global_df to NULL just to be tidy. */
|
|
|
|
global_df = NULL;
|
1999-08-13 23:47:43 +00:00
|
|
|
|
1999-10-12 05:01:07 +00:00
|
|
|
if (retval == 0) {
|
|
|
|
/* Success. Check if the filter is empty; if so, discard
|
|
|
|
* it and set "*dfp" to NULL, otherwise set "*dfp" to
|
|
|
|
* point to the filter. */
|
|
|
|
if (df->dftree == NULL) {
|
|
|
|
/* The filter is empty. */
|
|
|
|
dfilter_destroy(df);
|
|
|
|
df = NULL;
|
|
|
|
}
|
|
|
|
*dfp = df;
|
|
|
|
} else {
|
|
|
|
/* Failure. Destroy the filter. */
|
1999-10-11 06:39:26 +00:00
|
|
|
dfilter_destroy(df);
|
1999-10-12 05:01:07 +00:00
|
|
|
df = NULL;
|
1999-08-13 23:47:43 +00:00
|
|
|
}
|
1999-10-12 05:01:07 +00:00
|
|
|
return retval;
|
1999-08-13 23:47:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocates new dfilter, initializes values, and returns pointer to dfilter */
|
|
|
|
dfilter*
|
|
|
|
dfilter_new(void)
|
|
|
|
{
|
|
|
|
dfilter *df;
|
|
|
|
|
|
|
|
df = g_malloc(sizeof(dfilter));
|
|
|
|
|
|
|
|
df->dftree = NULL;
|
|
|
|
df->node_memchunk = g_mem_chunk_new("df->node_memchunk",
|
|
|
|
sizeof(dfilter_node), 20 * sizeof(dfilter_node), G_ALLOC_ONLY);
|
|
|
|
df->list_of_byte_arrays = NULL;
|
2000-08-01 18:10:06 +00:00
|
|
|
df->list_of_strings = NULL;
|
1999-08-13 23:47:43 +00:00
|
|
|
|
|
|
|
return df;
|
|
|
|
}
|
|
|
|
|
2000-08-01 18:10:06 +00:00
|
|
|
static void
|
|
|
|
free_string(gpointer data, gpointer user_data)
|
|
|
|
{
|
|
|
|
char *string = data;
|
|
|
|
if (string)
|
|
|
|
g_free(string);
|
|
|
|
}
|
|
|
|
|
1999-08-13 23:47:43 +00:00
|
|
|
/* Frees all memory used by dfilter, and frees dfilter itself */
|
|
|
|
void
|
|
|
|
dfilter_destroy(dfilter *df)
|
|
|
|
{
|
|
|
|
if (!df)
|
|
|
|
return;
|
|
|
|
|
1999-10-11 06:39:26 +00:00
|
|
|
if (df->dftree != NULL)
|
|
|
|
g_node_destroy(df->dftree);
|
|
|
|
|
|
|
|
/* clear the memory that the tree was using for nodes */
|
|
|
|
if (df->node_memchunk)
|
|
|
|
g_mem_chunk_reset(df->node_memchunk);
|
|
|
|
|
|
|
|
/* clear the memory that the tree was using for byte arrays */
|
|
|
|
if (df->list_of_byte_arrays) {
|
|
|
|
g_slist_foreach(df->list_of_byte_arrays, clear_byte_array, NULL);
|
|
|
|
g_slist_free(df->list_of_byte_arrays);
|
|
|
|
}
|
|
|
|
|
2000-08-01 18:10:06 +00:00
|
|
|
/* clear the allocated strings */
|
|
|
|
if (df->list_of_strings) {
|
|
|
|
g_slist_foreach(df->list_of_strings, free_string, NULL);
|
|
|
|
g_slist_free(df->list_of_strings);
|
|
|
|
}
|
|
|
|
|
1999-10-11 06:39:26 +00:00
|
|
|
df->dftree = NULL;
|
|
|
|
df->list_of_byte_arrays = NULL;
|
2000-08-01 18:10:06 +00:00
|
|
|
df->list_of_strings = NULL;
|
1999-08-13 23:47:43 +00:00
|
|
|
|
|
|
|
/* Git rid of memchunk */
|
|
|
|
if (df->node_memchunk)
|
|
|
|
g_mem_chunk_destroy(df->node_memchunk);
|
|
|
|
|
|
|
|
g_free(df);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-07-07 22:52:57 +00:00
|
|
|
static void
|
|
|
|
clear_byte_array(gpointer data, gpointer user_data)
|
|
|
|
{
|
|
|
|
GByteArray *barray = data;
|
1999-08-12 15:10:48 +00:00
|
|
|
if (barray)
|
|
|
|
g_byte_array_free(barray, TRUE);
|
1999-07-07 22:52:57 +00:00
|
|
|
}
|
|
|
|
|
1999-08-26 06:20:50 +00:00
|
|
|
/* Called when the yacc grammar finds a parsing error */
|
1999-07-07 22:52:57 +00:00
|
|
|
void
|
1999-08-14 06:24:27 +00:00
|
|
|
dfilter_error(char *s)
|
1999-07-07 22:52:57 +00:00
|
|
|
{
|
1999-08-26 06:20:50 +00:00
|
|
|
}
|
|
|
|
|
Have "get_host_ipaddr()" return a Boolean indicating whether it
succeeded or failed, and, if it succeeded, have it fill in the IP
address if found through a pointer passed as the second argument.
Have it first try interpreting its first argument as a dotted-quad IP
address, with "inet_aton()", and, if that fails, have it try to
interpret it as a host name with "gethostbyname()"; don't bother with
"gethostbyaddr()", as we should be allowed to filter on IP addresses
even if there's no host name associated with them (there's no guarantee
that "gethostbyaddr()" will succeed if handed an IP address with no
corresponding name - and it looks as if FreeBSD 3.2, at least, may not
succeed in that case).
Add a "dfilter_fail()" routine that takes "printf()"-like arguments and
uses them to set an error message for the parse; doing so means that
even if the filter expression is syntactically valid, we treat it as
being invalid. (Is there a better way to force a parse to fail from
arbitrary places in routines called by the parser?)
Use that routine in the lexical analyzer.
If that error message was set, use it as is as the failure message,
rather than adding "Unable to parse filter string XXX" to it.
Have the code to handle IP addresses and host names in display filters
check whether "get_host_ipaddr()" succeeded or failed and, if it failed,
arrange that the parse fail with an error message indicating the source
of the problem.
svn path=/trunk/; revision=802
1999-10-11 03:03:12 +00:00
|
|
|
/* Called when an error other than a parsing error occurs. */
|
|
|
|
void
|
|
|
|
dfilter_fail(char *format, ...)
|
|
|
|
{
|
1999-10-11 06:39:26 +00:00
|
|
|
va_list ap;
|
Have "get_host_ipaddr()" return a Boolean indicating whether it
succeeded or failed, and, if it succeeded, have it fill in the IP
address if found through a pointer passed as the second argument.
Have it first try interpreting its first argument as a dotted-quad IP
address, with "inet_aton()", and, if that fails, have it try to
interpret it as a host name with "gethostbyname()"; don't bother with
"gethostbyaddr()", as we should be allowed to filter on IP addresses
even if there's no host name associated with them (there's no guarantee
that "gethostbyaddr()" will succeed if handed an IP address with no
corresponding name - and it looks as if FreeBSD 3.2, at least, may not
succeed in that case).
Add a "dfilter_fail()" routine that takes "printf()"-like arguments and
uses them to set an error message for the parse; doing so means that
even if the filter expression is syntactically valid, we treat it as
being invalid. (Is there a better way to force a parse to fail from
arbitrary places in routines called by the parser?)
Use that routine in the lexical analyzer.
If that error message was set, use it as is as the failure message,
rather than adding "Unable to parse filter string XXX" to it.
Have the code to handle IP addresses and host names in display filters
check whether "get_host_ipaddr()" succeeded or failed and, if it failed,
arrange that the parse fail with an error message indicating the source
of the problem.
svn path=/trunk/; revision=802
1999-10-11 03:03:12 +00:00
|
|
|
|
1999-10-11 06:39:26 +00:00
|
|
|
/* If we've already reported one error, don't overwrite it with this
|
|
|
|
* one. */
|
|
|
|
if (dfilter_error_msg != NULL)
|
|
|
|
return;
|
1999-07-07 22:52:57 +00:00
|
|
|
|
1999-10-11 06:39:26 +00:00
|
|
|
va_start(ap, format);
|
|
|
|
vsnprintf(dfilter_error_msg_buf, sizeof dfilter_error_msg_buf, format, ap);
|
|
|
|
dfilter_error_msg = dfilter_error_msg_buf;
|
|
|
|
va_end(ap);
|
1999-08-26 06:20:50 +00:00
|
|
|
}
|
|
|
|
|
Changed the display filter scanner from GLIB's GScanner to lex. The code
as it standed depends on your lex being flex, but that only matters if you're
a developer. The distribution will include the dfilter-scanner.c file, so
that if the user doesn't modify dfilter-scanner.l, he won't need flex to
re-create the *.c file.
The new lex scanner gives me better syntax checking for ether addresses. I
thought I could get by using GScanner, but it simply wasn't powerful enough.
All operands have English-like abbreviations and C-like syntax:
and, && ; or, || ; eq, == ; ne, != ; , etc.
I removed the ETHER_VENDOR type in favor of letting the user use the [x:y]
notation: ether.src[0:3] == 0:6:29 instead of ether.srcvendor == 00:06:29
I implemented the IPXNET field type; it had been there before, but was
not implemented. I chose to make it use integer values rather than byte
ranges, since an IPX Network is 4 bytes. So a display filter looks like this:
ipx.srcnet == 0xc0a82c00
rather than this:
ipx.srcnet == c0:a8:2c:00
I can supposrt the byte-range type IPXNET in the future, very trivially.
I still have more work to do on the parser though. It needs to check ranges
when extracting byte ranges ([x:y]) from packets. And I need to get rid
of those reduce/reduce errors from yacc!
svn path=/trunk/; revision=414
1999-08-01 04:28:20 +00:00
|
|
|
/* lookup an abbreviation in our token tree, returing the ID #
|
1999-10-04 18:53:26 +00:00
|
|
|
* If the abbreviation doesn't exit, returns -1 */
|
Changed the display filter scanner from GLIB's GScanner to lex. The code
as it standed depends on your lex being flex, but that only matters if you're
a developer. The distribution will include the dfilter-scanner.c file, so
that if the user doesn't modify dfilter-scanner.l, he won't need flex to
re-create the *.c file.
The new lex scanner gives me better syntax checking for ether addresses. I
thought I could get by using GScanner, but it simply wasn't powerful enough.
All operands have English-like abbreviations and C-like syntax:
and, && ; or, || ; eq, == ; ne, != ; , etc.
I removed the ETHER_VENDOR type in favor of letting the user use the [x:y]
notation: ether.src[0:3] == 0:6:29 instead of ether.srcvendor == 00:06:29
I implemented the IPXNET field type; it had been there before, but was
not implemented. I chose to make it use integer values rather than byte
ranges, since an IPX Network is 4 bytes. So a display filter looks like this:
ipx.srcnet == 0xc0a82c00
rather than this:
ipx.srcnet == c0:a8:2c:00
I can supposrt the byte-range type IPXNET in the future, very trivially.
I still have more work to do on the parser though. It needs to check ranges
when extracting byte ranges ([x:y]) from packets. And I need to get rid
of those reduce/reduce errors from yacc!
svn path=/trunk/; revision=414
1999-08-01 04:28:20 +00:00
|
|
|
int dfilter_lookup_token(char *abbrev)
|
|
|
|
{
|
|
|
|
int value;
|
|
|
|
|
|
|
|
g_assert(abbrev != NULL);
|
|
|
|
value = GPOINTER_TO_INT(g_tree_lookup(dfilter_tokens, abbrev));
|
|
|
|
|
|
|
|
if (value < DFILTER_LEX_ABBREV_OFFSET) {
|
1999-10-04 18:09:05 +00:00
|
|
|
return -1;
|
Changed the display filter scanner from GLIB's GScanner to lex. The code
as it standed depends on your lex being flex, but that only matters if you're
a developer. The distribution will include the dfilter-scanner.c file, so
that if the user doesn't modify dfilter-scanner.l, he won't need flex to
re-create the *.c file.
The new lex scanner gives me better syntax checking for ether addresses. I
thought I could get by using GScanner, but it simply wasn't powerful enough.
All operands have English-like abbreviations and C-like syntax:
and, && ; or, || ; eq, == ; ne, != ; , etc.
I removed the ETHER_VENDOR type in favor of letting the user use the [x:y]
notation: ether.src[0:3] == 0:6:29 instead of ether.srcvendor == 00:06:29
I implemented the IPXNET field type; it had been there before, but was
not implemented. I chose to make it use integer values rather than byte
ranges, since an IPX Network is 4 bytes. So a display filter looks like this:
ipx.srcnet == 0xc0a82c00
rather than this:
ipx.srcnet == c0:a8:2c:00
I can supposrt the byte-range type IPXNET in the future, very trivially.
I still have more work to do on the parser though. It needs to check ranges
when extracting byte ranges ([x:y]) from packets. And I need to get rid
of those reduce/reduce errors from yacc!
svn path=/trunk/; revision=414
1999-08-01 04:28:20 +00:00
|
|
|
}
|
|
|
|
return value - DFILTER_LEX_ABBREV_OFFSET;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
g_strcmp(gconstpointer a, gconstpointer b)
|
|
|
|
{
|
|
|
|
return strcmp((const char*)a, (const char*)b);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-07-07 22:52:57 +00:00
|
|
|
gboolean
|
2000-04-14 05:39:43 +00:00
|
|
|
dfilter_apply(dfilter *dfcode, proto_tree *ptree, const guint8* pd, guint pd_len)
|
1999-07-07 22:52:57 +00:00
|
|
|
{
|
|
|
|
gboolean retval;
|
1999-09-29 14:41:34 +00:00
|
|
|
if (dfcode == NULL)
|
|
|
|
return FALSE;
|
1999-10-12 04:21:13 +00:00
|
|
|
retval = dfilter_apply_node(dfcode->dftree, ptree, pd);
|
1999-07-07 22:52:57 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
1999-10-12 04:21:13 +00:00
|
|
|
dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8* pd)
|
1999-07-07 22:52:57 +00:00
|
|
|
{
|
|
|
|
GNode *gnode_a, *gnode_b;
|
|
|
|
dfilter_node *dnode = (dfilter_node*) (gnode->data);
|
|
|
|
|
|
|
|
/* We'll get 2 NULLs if we don't have children */
|
|
|
|
gnode_a = g_node_nth_child(gnode, 0);
|
|
|
|
gnode_b = g_node_nth_child(gnode, 1);
|
|
|
|
|
|
|
|
switch(dnode->ntype) {
|
|
|
|
case variable:
|
1999-08-03 15:04:33 +00:00
|
|
|
/* We'll never see this case because if the parser finds the name of
|
|
|
|
* a variable, it will cause it to be an 'existence' operation.
|
|
|
|
*/
|
1999-07-07 22:52:57 +00:00
|
|
|
g_assert_not_reached();
|
|
|
|
|
|
|
|
case logical:
|
1999-09-29 22:11:51 +00:00
|
|
|
g_assert(gnode_a);
|
1999-10-12 04:21:13 +00:00
|
|
|
return check_logical(dnode->value.logical, gnode_a, gnode_b, ptree, pd);
|
1999-07-07 22:52:57 +00:00
|
|
|
|
|
|
|
case relation:
|
|
|
|
g_assert(gnode_a && gnode_b);
|
1999-10-12 04:21:13 +00:00
|
|
|
return check_relation(dnode->value.relation, gnode_a, gnode_b, ptree, pd);
|
1999-07-07 22:52:57 +00:00
|
|
|
|
|
|
|
case alternation:
|
|
|
|
g_assert_not_reached();
|
|
|
|
/* not coded yet */
|
|
|
|
|
|
|
|
case numeric:
|
1999-10-19 05:31:14 +00:00
|
|
|
case floating:
|
1999-07-07 22:52:57 +00:00
|
|
|
case ipv4:
|
1999-10-11 17:05:49 +00:00
|
|
|
case ipv6:
|
1999-07-07 22:52:57 +00:00
|
|
|
case boolean:
|
|
|
|
case ether:
|
|
|
|
case string:
|
|
|
|
case abs_time:
|
|
|
|
case bytes:
|
Changed the display filter scanner from GLIB's GScanner to lex. The code
as it standed depends on your lex being flex, but that only matters if you're
a developer. The distribution will include the dfilter-scanner.c file, so
that if the user doesn't modify dfilter-scanner.l, he won't need flex to
re-create the *.c file.
The new lex scanner gives me better syntax checking for ether addresses. I
thought I could get by using GScanner, but it simply wasn't powerful enough.
All operands have English-like abbreviations and C-like syntax:
and, && ; or, || ; eq, == ; ne, != ; , etc.
I removed the ETHER_VENDOR type in favor of letting the user use the [x:y]
notation: ether.src[0:3] == 0:6:29 instead of ether.srcvendor == 00:06:29
I implemented the IPXNET field type; it had been there before, but was
not implemented. I chose to make it use integer values rather than byte
ranges, since an IPX Network is 4 bytes. So a display filter looks like this:
ipx.srcnet == 0xc0a82c00
rather than this:
ipx.srcnet == c0:a8:2c:00
I can supposrt the byte-range type IPXNET in the future, very trivially.
I still have more work to do on the parser though. It needs to check ranges
when extracting byte ranges ([x:y]) from packets. And I need to get rid
of those reduce/reduce errors from yacc!
svn path=/trunk/; revision=414
1999-08-01 04:28:20 +00:00
|
|
|
case ipxnet:
|
1999-07-07 22:52:57 +00:00
|
|
|
/* the only time we'll see these at this point is if the display filter
|
1999-08-03 15:04:33 +00:00
|
|
|
* is really wacky. (like simply "192.168.1.1"). The parser as it stands
|
|
|
|
* now let these by. Just return TRUE */
|
1999-07-07 22:52:57 +00:00
|
|
|
g_assert(!gnode_a && !gnode_b);
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
case existence: /* checking the existence of a protocol or hf*/
|
|
|
|
g_assert(!gnode_a && !gnode_b);
|
|
|
|
return check_existence_in_ptree(dnode, ptree);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
1999-10-12 04:21:13 +00:00
|
|
|
check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd)
|
1999-07-07 22:52:57 +00:00
|
|
|
{
|
1999-10-12 04:21:13 +00:00
|
|
|
gboolean val_a = dfilter_apply_node(a, ptree, pd);
|
1999-07-08 03:35:30 +00:00
|
|
|
gboolean val_b;
|
|
|
|
|
1999-07-07 22:52:57 +00:00
|
|
|
switch(operand) {
|
|
|
|
case TOK_AND:
|
1999-09-29 22:11:51 +00:00
|
|
|
g_assert(b);
|
1999-10-12 04:21:13 +00:00
|
|
|
return (val_a && dfilter_apply_node(b, ptree, pd));
|
1999-07-07 22:52:57 +00:00
|
|
|
case TOK_OR:
|
1999-09-29 22:11:51 +00:00
|
|
|
g_assert(b);
|
1999-10-12 04:21:13 +00:00
|
|
|
return (val_a || dfilter_apply_node(b, ptree, pd));
|
1999-07-07 22:52:57 +00:00
|
|
|
case TOK_XOR:
|
1999-09-29 22:11:51 +00:00
|
|
|
g_assert(b);
|
1999-10-12 04:21:13 +00:00
|
|
|
val_b = dfilter_apply_node(b, ptree, pd);
|
1999-07-08 03:35:30 +00:00
|
|
|
return ( ( val_a || val_b ) && ! ( val_a && val_b ) );
|
1999-07-07 22:52:57 +00:00
|
|
|
case TOK_NOT:
|
1999-07-08 03:35:30 +00:00
|
|
|
return (!val_a);
|
1999-07-07 22:52:57 +00:00
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
g_assert_not_reached();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
free_array_of_byte_arrays(GArray *array)
|
|
|
|
{
|
|
|
|
int i, len;
|
|
|
|
GByteArray *ba_ptr;
|
|
|
|
|
|
|
|
len = array->len;
|
|
|
|
|
|
|
|
for (i = 0; i < len ; i++) {
|
|
|
|
ba_ptr = g_array_index(array, GByteArray*, i);
|
|
|
|
g_byte_array_free(ba_ptr, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-07-07 22:52:57 +00:00
|
|
|
/* 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
|
|
|
|
* them all. It makes my coding easier in the beginning, but I should change this to make it run
|
|
|
|
* faster.
|
|
|
|
*/
|
|
|
|
static gboolean
|
1999-10-12 04:21:13 +00:00
|
|
|
check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8* pd)
|
1999-07-07 22:52:57 +00:00
|
|
|
{
|
|
|
|
dfilter_node *node_a = (dfilter_node*) (a->data);
|
|
|
|
dfilter_node *node_b = (dfilter_node*) (b->data);
|
|
|
|
GArray *vals_a, *vals_b;
|
|
|
|
gboolean retval;
|
|
|
|
|
|
|
|
|
|
|
|
if (node_a->ntype == variable)
|
1999-10-12 04:21:13 +00:00
|
|
|
vals_a = get_values_from_ptree(node_a, ptree, pd);
|
1999-07-07 22:52:57 +00:00
|
|
|
else
|
|
|
|
vals_a = get_values_from_dfilter(node_a, a);
|
|
|
|
|
|
|
|
if (node_b->ntype == variable)
|
1999-10-12 04:21:13 +00:00
|
|
|
vals_b = get_values_from_ptree(node_b, ptree, pd);
|
1999-07-07 22:52:57 +00:00
|
|
|
else
|
|
|
|
vals_b = get_values_from_dfilter(node_b, b);
|
|
|
|
|
|
|
|
retval = node_a->check_relation_func(operand, vals_a, vals_b);
|
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
/* Free GByteArrays alloated by fill_array_bytes_variable() */
|
|
|
|
if (node_a->fill_array_variable_func == fill_array_bytes_variable) {
|
|
|
|
free_array_of_byte_arrays(vals_a);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node_b->fill_array_variable_func == fill_array_bytes_variable) {
|
|
|
|
free_array_of_byte_arrays(vals_b);
|
|
|
|
}
|
|
|
|
|
1999-07-07 22:52:57 +00:00
|
|
|
g_array_free(vals_a, FALSE);
|
|
|
|
g_array_free(vals_b, FALSE);
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
|
1999-07-07 22:52:57 +00:00
|
|
|
static gboolean
|
|
|
|
check_existence_in_ptree(dfilter_node *dnode, proto_tree *ptree)
|
|
|
|
{
|
1999-08-29 04:06:43 +00:00
|
|
|
int target;
|
1999-07-07 22:52:57 +00:00
|
|
|
|
1999-08-29 04:06:43 +00:00
|
|
|
target = dnode->value.variable;
|
|
|
|
return proto_check_for_protocol_or_field(ptree, target);
|
1999-07-07 22:52:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static GArray*
|
1999-10-12 04:21:13 +00:00
|
|
|
get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd)
|
1999-07-07 22:52:57 +00:00
|
|
|
{
|
2000-07-22 15:58:54 +00:00
|
|
|
GArray *result_array;
|
|
|
|
GPtrArray *finfo_array;
|
|
|
|
int i, len;
|
|
|
|
field_info *finfo;
|
1999-07-07 22:52:57 +00:00
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
/* Prepare the array for results */
|
1999-07-07 22:52:57 +00:00
|
|
|
g_assert(dnode->elem_size > 0);
|
2000-07-22 15:58:54 +00:00
|
|
|
result_array = g_array_new(FALSE, FALSE, dnode->elem_size);
|
1999-07-07 22:52:57 +00:00
|
|
|
|
2000-12-22 12:05:38 +00:00
|
|
|
/* Set bytes_offset, bytes_length, and bytes_to_the_end
|
|
|
|
* for this dnode
|
|
|
|
*/
|
|
|
|
|
|
|
|
bytes_offset = dnode->offset;
|
|
|
|
bytes_length = dnode->length;
|
|
|
|
bytes_to_the_end = dnode->to_the_end;
|
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
/* Cull the finfos from the proto_tree */
|
|
|
|
finfo_array = proto_get_finfo_ptr_array(ptree, dnode->value.variable);
|
|
|
|
if (!finfo_array) {
|
|
|
|
return result_array;
|
1999-07-07 22:52:57 +00:00
|
|
|
}
|
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
len = g_ptr_array_len(finfo_array);
|
1999-07-07 22:52:57 +00:00
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
finfo = g_ptr_array_index(finfo_array, i);
|
|
|
|
dnode->fill_array_variable_func(finfo, result_array, pd);
|
|
|
|
}
|
1999-07-07 22:52:57 +00:00
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
g_ptr_array_free(finfo_array, FALSE);
|
1999-07-07 22:52:57 +00:00
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
return result_array;
|
1999-07-07 22:52:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
void
|
|
|
|
fill_array_numeric_variable(field_info *finfo, GArray *array, const guint8 *pd)
|
|
|
|
{
|
|
|
|
g_array_append_val(array, finfo->value.numeric);
|
1999-07-07 22:52:57 +00:00
|
|
|
}
|
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
void
|
|
|
|
fill_array_floating_variable(field_info *finfo, GArray *array, const guint8 *pd)
|
1999-10-19 05:31:14 +00:00
|
|
|
{
|
2000-07-22 15:58:54 +00:00
|
|
|
g_array_append_val(array, finfo->value.floating);
|
1999-10-19 05:31:14 +00:00
|
|
|
}
|
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
void
|
|
|
|
fill_array_ether_variable(field_info *finfo, GArray *array, const guint8 *pd)
|
1999-07-07 22:52:57 +00:00
|
|
|
{
|
2000-07-22 15:58:54 +00:00
|
|
|
/* hmmm, yes, I *can* copy a pointer instead of memcpy() */
|
|
|
|
g_array_append_val(array, finfo->value.ether);
|
1999-07-07 22:52:57 +00:00
|
|
|
}
|
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
void
|
|
|
|
fill_array_ipv4_variable(field_info *finfo, GArray *array, const guint8 *pd)
|
1999-11-15 06:32:38 +00:00
|
|
|
{
|
2000-07-22 15:58:54 +00:00
|
|
|
/* hmmm, yes, I *can* copy a pointer instead of memcpy() */
|
|
|
|
g_array_append_val(array, finfo->value.ipv4);
|
1999-11-15 06:32:38 +00:00
|
|
|
}
|
1999-10-11 17:05:49 +00:00
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
void
|
|
|
|
fill_array_ipv6_variable(field_info *finfo, GArray *array, const guint8 *pd)
|
|
|
|
{
|
|
|
|
/* hmmm, yes, I *can* copy a pointer instead of memcpy() */
|
|
|
|
g_array_append_val(array, finfo->value.ipv6);
|
1999-10-11 17:05:49 +00:00
|
|
|
}
|
|
|
|
|
2000-08-01 18:10:06 +00:00
|
|
|
void
|
|
|
|
fill_array_string_variable(field_info *finfo, GArray *array, const guint8 *pd)
|
|
|
|
{
|
|
|
|
g_array_append_val(array, finfo->value.string);
|
|
|
|
}
|
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
void
|
|
|
|
fill_array_bytes_variable(field_info *finfo, GArray *array, const guint8 *pd)
|
1999-07-07 22:52:57 +00:00
|
|
|
{
|
|
|
|
GByteArray *barray;
|
2000-12-22 12:05:38 +00:00
|
|
|
guint read_start, pkt_end, read_len;
|
1999-07-07 22:52:57 +00:00
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
if (bytes_offset < 0) {
|
|
|
|
/* Handle negative byte offsets */
|
|
|
|
bytes_offset = finfo->length + bytes_offset;
|
1999-10-12 04:21:13 +00:00
|
|
|
if (bytes_offset < 0) {
|
2000-07-22 15:58:54 +00:00
|
|
|
return;
|
1999-10-12 04:21:13 +00:00
|
|
|
}
|
2000-07-22 15:58:54 +00:00
|
|
|
}
|
1999-10-12 04:21:13 +00:00
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
/* Check to make sure offset exists for this field */
|
|
|
|
if (bytes_offset >= finfo->length) {
|
|
|
|
return;
|
|
|
|
}
|
1999-10-12 04:21:13 +00:00
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
pkt_end = finfo->start + finfo->length;
|
|
|
|
read_start = finfo->start + bytes_offset;
|
2000-12-22 12:05:38 +00:00
|
|
|
if(bytes_to_the_end){
|
|
|
|
read_len = pkt_end - read_start;;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
read_len = bytes_length;
|
|
|
|
}
|
2000-07-22 15:58:54 +00:00
|
|
|
/* Check to make sure entire length requested is inside field */
|
2000-12-22 12:05:38 +00:00
|
|
|
if (pkt_end < read_start + read_len) {
|
2000-07-22 15:58:54 +00:00
|
|
|
return;
|
1999-07-07 22:52:57 +00:00
|
|
|
}
|
|
|
|
|
2000-07-22 15:58:54 +00:00
|
|
|
barray = g_byte_array_new();
|
2000-12-22 12:05:38 +00:00
|
|
|
g_byte_array_append(barray, pd + read_start, read_len);
|
2000-07-22 15:58:54 +00:00
|
|
|
g_array_append_val(array, barray);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GArray*
|
|
|
|
get_values_from_dfilter(dfilter_node *dnode, GNode *gnode)
|
|
|
|
{
|
|
|
|
GArray *array;
|
|
|
|
|
|
|
|
g_assert(dnode->elem_size > 0);
|
|
|
|
array = g_array_new(FALSE, FALSE, dnode->elem_size);
|
|
|
|
|
|
|
|
g_node_traverse(gnode, G_IN_ORDER, G_TRAVERSE_ALL, -1,
|
|
|
|
dnode->fill_array_value_func, array);
|
|
|
|
return array;
|
1999-07-07 22:52:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
gboolean fill_array_numeric_value(GNode *gnode, gpointer data)
|
|
|
|
{
|
|
|
|
GArray *array = (GArray*)data;
|
|
|
|
dfilter_node *dnode = (dfilter_node*) (gnode->data);
|
|
|
|
|
|
|
|
g_array_append_val(array, dnode->value.numeric);
|
|
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
|
|
}
|
|
|
|
|
1999-10-19 05:31:14 +00:00
|
|
|
gboolean fill_array_floating_value(GNode *gnode, gpointer data)
|
|
|
|
{
|
|
|
|
GArray *array = (GArray*)data;
|
|
|
|
dfilter_node *dnode = (dfilter_node*) (gnode->data);
|
|
|
|
|
|
|
|
g_array_append_val(array, dnode->value.floating);
|
|
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
|
|
}
|
|
|
|
|
1999-07-07 22:52:57 +00:00
|
|
|
gboolean fill_array_ether_value(GNode *gnode, gpointer data)
|
|
|
|
{
|
|
|
|
GArray *array = (GArray*)data;
|
|
|
|
dfilter_node *dnode = (dfilter_node*) (gnode->data);
|
|
|
|
|
|
|
|
g_array_append_val(array, dnode->value.ether);
|
|
|
|
|
|
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
|
|
}
|
|
|
|
|
1999-11-15 06:32:38 +00:00
|
|
|
gboolean fill_array_ipv4_value(GNode *gnode, gpointer data)
|
|
|
|
{
|
|
|
|
GArray *array = (GArray*)data;
|
|
|
|
dfilter_node *dnode = (dfilter_node*) (gnode->data);
|
|
|
|
|
|
|
|
g_array_append_val(array, dnode->value.ipv4);
|
|
|
|
|
|
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
|
|
}
|
|
|
|
|
1999-10-11 17:05:49 +00:00
|
|
|
gboolean fill_array_ipv6_value(GNode *gnode, gpointer data)
|
|
|
|
{
|
|
|
|
GArray *array = (GArray*)data;
|
|
|
|
dfilter_node *dnode = (dfilter_node*) (gnode->data);
|
|
|
|
|
|
|
|
g_array_append_val(array, dnode->value.ipv6);
|
|
|
|
|
|
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
|
|
}
|
|
|
|
|
1999-07-07 22:52:57 +00:00
|
|
|
gboolean fill_array_bytes_value(GNode *gnode, gpointer data)
|
|
|
|
{
|
|
|
|
GArray *array = (GArray*)data;
|
|
|
|
dfilter_node *dnode = (dfilter_node*) (gnode->data);
|
|
|
|
GByteArray *barray = dnode->value.bytes;
|
|
|
|
|
|
|
|
g_array_append_val(array, barray);
|
|
|
|
|
|
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
|
|
}
|
|
|
|
|
2000-08-01 18:10:06 +00:00
|
|
|
gboolean fill_array_string_value(GNode *gnode, gpointer data)
|
|
|
|
{
|
|
|
|
GArray *array = (GArray*)data;
|
|
|
|
dfilter_node *dnode = (dfilter_node*) (gnode->data);
|
|
|
|
|
|
|
|
g_array_append_val(array, dnode->value.string);
|
|
|
|
|
|
|
|
return FALSE; /* FALSE = do not end traversal of GNode tree */
|
|
|
|
}
|
|
|
|
|
1999-07-07 22:52:57 +00:00
|
|
|
gboolean check_relation_numeric(gint operand, GArray *a, GArray *b)
|
|
|
|
{
|
|
|
|
int i, j, len_a, len_b;
|
|
|
|
guint32 val_a;
|
|
|
|
|
|
|
|
len_a = a->len;
|
|
|
|
len_b = b->len;
|
|
|
|
|
|
|
|
|
|
|
|
switch(operand) {
|
|
|
|
case TOK_EQ:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
val_a = g_array_index(a, guint32, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
if (val_a == g_array_index(b, guint32, j))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_NE:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
val_a = g_array_index(a, guint32, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
if (val_a != g_array_index(b, guint32, j))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_GT:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
val_a = g_array_index(a, guint32, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
if (val_a > g_array_index(b, guint32, j))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_GE:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
val_a = g_array_index(a, guint32, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
if (val_a >= g_array_index(b, guint32, j))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_LT:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
val_a = g_array_index(a, guint32, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
if (val_a < g_array_index(b, guint32, j))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_LE:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
val_a = g_array_index(a, guint32, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
if (val_a <= g_array_index(b, guint32, j))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
1999-10-19 05:31:14 +00:00
|
|
|
gboolean check_relation_floating(gint operand, GArray *a, GArray *b)
|
|
|
|
{
|
|
|
|
int i, j, len_a, len_b;
|
|
|
|
double val_a;
|
|
|
|
|
|
|
|
len_a = a->len;
|
|
|
|
len_b = b->len;
|
|
|
|
|
|
|
|
|
|
|
|
switch(operand) {
|
|
|
|
case TOK_EQ:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
val_a = g_array_index(a, double, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
if (val_a == g_array_index(b, double, j))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_NE:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
val_a = g_array_index(a, double, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
if (val_a != g_array_index(b, double, j))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_GT:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
val_a = g_array_index(a, double, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
if (val_a > g_array_index(b, double, j))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_GE:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
val_a = g_array_index(a, double, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
if (val_a >= g_array_index(b, double, j))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_LT:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
val_a = g_array_index(a, double, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
if (val_a < g_array_index(b, double, j))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_LE:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
val_a = g_array_index(a, double, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
if (val_a <= g_array_index(b, double, j))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
default:
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
1999-11-15 06:32:38 +00:00
|
|
|
gboolean check_relation_ipv4(gint operand, GArray *a, GArray *b)
|
|
|
|
{
|
|
|
|
int i, j, len_a, len_b;
|
|
|
|
ipv4_addr *ptr_a, *ptr_b;
|
|
|
|
|
|
|
|
len_a = a->len;
|
|
|
|
len_b = b->len;
|
|
|
|
|
|
|
|
|
|
|
|
switch(operand) {
|
|
|
|
case TOK_EQ:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
|
|
|
|
if (ipv4_addr_eq(ptr_a, ptr_b))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_NE:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
|
2000-04-14 05:39:43 +00:00
|
|
|
if (ipv4_addr_ne(ptr_a, ptr_b))
|
1999-11-15 06:32:38 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_GT:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
|
|
|
|
if (ipv4_addr_gt(ptr_a, ptr_b))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_GE:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
|
|
|
|
if (ipv4_addr_ge(ptr_a, ptr_b))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_LT:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
|
|
|
|
if (ipv4_addr_lt(ptr_a, ptr_b))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_LE:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
ptr_a = (ipv4_addr*) g_array_index_ptr(a, sizeof(ipv4_addr), i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
ptr_b = (ipv4_addr*) g_array_index_ptr(b, sizeof(ipv4_addr), j);
|
|
|
|
if (ipv4_addr_le(ptr_a, ptr_b))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
1999-10-11 17:05:49 +00:00
|
|
|
gboolean check_relation_ipv6(gint operand, GArray *a, GArray *b)
|
|
|
|
{
|
|
|
|
int i, j, len_a, len_b;
|
|
|
|
guint8 *ptr_a, *ptr_b;
|
|
|
|
|
|
|
|
len_a = a->len;
|
|
|
|
len_b = b->len;
|
|
|
|
|
|
|
|
|
|
|
|
switch(operand) {
|
|
|
|
case TOK_EQ:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
ptr_a = g_array_index_ptr(a, 16, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
ptr_b = g_array_index_ptr(b, 16, j);
|
|
|
|
if (memcmp(ptr_a, ptr_b, 16) == 0)
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_NE:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
ptr_a = g_array_index_ptr(a, 16, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
ptr_b = g_array_index_ptr(b, 16, j);
|
|
|
|
if (memcmp(ptr_a, ptr_b, 16) != 0)
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
return FALSE;
|
|
|
|
}
|
1999-07-07 22:52:57 +00:00
|
|
|
|
|
|
|
gboolean check_relation_ether(gint operand, GArray *a, GArray *b)
|
|
|
|
{
|
|
|
|
int i, j, len_a, len_b;
|
Changed the display filter scanner from GLIB's GScanner to lex. The code
as it standed depends on your lex being flex, but that only matters if you're
a developer. The distribution will include the dfilter-scanner.c file, so
that if the user doesn't modify dfilter-scanner.l, he won't need flex to
re-create the *.c file.
The new lex scanner gives me better syntax checking for ether addresses. I
thought I could get by using GScanner, but it simply wasn't powerful enough.
All operands have English-like abbreviations and C-like syntax:
and, && ; or, || ; eq, == ; ne, != ; , etc.
I removed the ETHER_VENDOR type in favor of letting the user use the [x:y]
notation: ether.src[0:3] == 0:6:29 instead of ether.srcvendor == 00:06:29
I implemented the IPXNET field type; it had been there before, but was
not implemented. I chose to make it use integer values rather than byte
ranges, since an IPX Network is 4 bytes. So a display filter looks like this:
ipx.srcnet == 0xc0a82c00
rather than this:
ipx.srcnet == c0:a8:2c:00
I can supposrt the byte-range type IPXNET in the future, very trivially.
I still have more work to do on the parser though. It needs to check ranges
when extracting byte ranges ([x:y]) from packets. And I need to get rid
of those reduce/reduce errors from yacc!
svn path=/trunk/; revision=414
1999-08-01 04:28:20 +00:00
|
|
|
guint8 *ptr_a, *ptr_b;
|
1999-07-07 22:52:57 +00:00
|
|
|
|
|
|
|
len_a = a->len;
|
|
|
|
len_b = b->len;
|
|
|
|
|
|
|
|
|
|
|
|
switch(operand) {
|
|
|
|
case TOK_EQ:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
ptr_a = g_array_index_ptr(a, 6, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
Changed the display filter scanner from GLIB's GScanner to lex. The code
as it standed depends on your lex being flex, but that only matters if you're
a developer. The distribution will include the dfilter-scanner.c file, so
that if the user doesn't modify dfilter-scanner.l, he won't need flex to
re-create the *.c file.
The new lex scanner gives me better syntax checking for ether addresses. I
thought I could get by using GScanner, but it simply wasn't powerful enough.
All operands have English-like abbreviations and C-like syntax:
and, && ; or, || ; eq, == ; ne, != ; , etc.
I removed the ETHER_VENDOR type in favor of letting the user use the [x:y]
notation: ether.src[0:3] == 0:6:29 instead of ether.srcvendor == 00:06:29
I implemented the IPXNET field type; it had been there before, but was
not implemented. I chose to make it use integer values rather than byte
ranges, since an IPX Network is 4 bytes. So a display filter looks like this:
ipx.srcnet == 0xc0a82c00
rather than this:
ipx.srcnet == c0:a8:2c:00
I can supposrt the byte-range type IPXNET in the future, very trivially.
I still have more work to do on the parser though. It needs to check ranges
when extracting byte ranges ([x:y]) from packets. And I need to get rid
of those reduce/reduce errors from yacc!
svn path=/trunk/; revision=414
1999-08-01 04:28:20 +00:00
|
|
|
ptr_b = g_array_index_ptr(b, 6, j);
|
|
|
|
if (memcmp(ptr_a, ptr_b, 6) == 0)
|
1999-07-07 22:52:57 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_NE:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
ptr_a = g_array_index_ptr(a, 6, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
Changed the display filter scanner from GLIB's GScanner to lex. The code
as it standed depends on your lex being flex, but that only matters if you're
a developer. The distribution will include the dfilter-scanner.c file, so
that if the user doesn't modify dfilter-scanner.l, he won't need flex to
re-create the *.c file.
The new lex scanner gives me better syntax checking for ether addresses. I
thought I could get by using GScanner, but it simply wasn't powerful enough.
All operands have English-like abbreviations and C-like syntax:
and, && ; or, || ; eq, == ; ne, != ; , etc.
I removed the ETHER_VENDOR type in favor of letting the user use the [x:y]
notation: ether.src[0:3] == 0:6:29 instead of ether.srcvendor == 00:06:29
I implemented the IPXNET field type; it had been there before, but was
not implemented. I chose to make it use integer values rather than byte
ranges, since an IPX Network is 4 bytes. So a display filter looks like this:
ipx.srcnet == 0xc0a82c00
rather than this:
ipx.srcnet == c0:a8:2c:00
I can supposrt the byte-range type IPXNET in the future, very trivially.
I still have more work to do on the parser though. It needs to check ranges
when extracting byte ranges ([x:y]) from packets. And I need to get rid
of those reduce/reduce errors from yacc!
svn path=/trunk/; revision=414
1999-08-01 04:28:20 +00:00
|
|
|
ptr_b = g_array_index_ptr(b, 6, j);
|
|
|
|
if (memcmp(ptr_a, ptr_b, 6) != 0)
|
1999-07-07 22:52:57 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean check_relation_bytes(gint operand, GArray *a, GArray *b)
|
|
|
|
{
|
|
|
|
int i, j, len_a, len_b;
|
|
|
|
GByteArray *ptr_a,*ptr_b;
|
|
|
|
|
|
|
|
len_a = a->len;
|
|
|
|
len_b = b->len;
|
|
|
|
|
|
|
|
|
|
|
|
switch(operand) {
|
|
|
|
case TOK_EQ:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
ptr_a = g_array_index(a, GByteArray*, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
ptr_b = g_array_index(b, GByteArray*, j);
|
2000-12-22 12:05:38 +00:00
|
|
|
if(ptr_a->len != ptr_b->len)
|
|
|
|
return FALSE; if (memcmp(ptr_a->data, ptr_b->data, ptr_a->len) == 0)
|
1999-07-07 22:52:57 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_NE:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
ptr_a = g_array_index(a, GByteArray*, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
ptr_b = g_array_index(b, GByteArray*, j);
|
2000-12-22 12:05:38 +00:00
|
|
|
if(ptr_a->len != ptr_b->len)
|
|
|
|
return TRUE;
|
|
|
|
if (memcmp(ptr_a->data, ptr_b->data, ptr_a->len) != 0)
|
1999-07-07 22:52:57 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_GT:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
ptr_a = g_array_index(a, GByteArray*, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
ptr_b = g_array_index(b, GByteArray*, j);
|
2000-12-22 12:05:38 +00:00
|
|
|
if(ptr_a->len > ptr_b->len)
|
|
|
|
return TRUE;
|
|
|
|
if(ptr_a->len < ptr_b->len)
|
|
|
|
return FALSE;
|
|
|
|
if (memcmp(ptr_a->data, ptr_b->data, ptr_a->len) > 0)
|
1999-07-07 22:52:57 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_LT:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
ptr_a = g_array_index(a, GByteArray*, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
ptr_b = g_array_index(b, GByteArray*, j);
|
2000-12-22 12:05:38 +00:00
|
|
|
if(ptr_a->len < ptr_b->len)
|
|
|
|
return TRUE;
|
|
|
|
if(ptr_a->len > ptr_b->len)
|
|
|
|
return FALSE;
|
|
|
|
if (memcmp(ptr_a->data, ptr_b->data, ptr_a->len) < 0)
|
1999-07-07 22:52:57 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
return FALSE;
|
|
|
|
}
|
2000-08-01 18:10:06 +00:00
|
|
|
|
|
|
|
gboolean check_relation_string(gint operand, GArray *a, GArray *b)
|
|
|
|
{
|
|
|
|
int i, j, len_a, len_b;
|
|
|
|
char *ptr_a, *ptr_b;
|
|
|
|
|
|
|
|
len_a = a->len;
|
|
|
|
len_b = b->len;
|
|
|
|
|
|
|
|
|
|
|
|
switch(operand) {
|
|
|
|
case TOK_EQ:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
ptr_a = g_array_index(a, char*, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
ptr_b = g_array_index(b, char*, j);
|
|
|
|
if (strcmp(ptr_a, ptr_b) == 0)
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
case TOK_NE:
|
|
|
|
for(i = 0; i < len_a; i++) {
|
|
|
|
ptr_a = g_array_index(a, char*, i);
|
|
|
|
for (j = 0; j < len_b; j++) {
|
|
|
|
ptr_b = g_array_index(b, char*, j);
|
|
|
|
if (strcmp(ptr_a, ptr_b) != 0)
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|