From 52338a3bafa30b1c1ea6759ea14a60c5d3fd35da Mon Sep 17 00:00:00 2001 From: Gilbert Ramirez Date: Wed, 27 Aug 2003 15:23:11 +0000 Subject: [PATCH] Add a "contains" operator for byte-strings, strings, and tvbuffs (protocols). The search uses a naive approach; more work is required to add a Boyer-Moore Search algorithm. svn path=/trunk/; revision=8280 --- doc/ethereal.pod.template | 7 ++- doc/tethereal.pod.template | 7 ++- epan/dfilter/dfvm.c | 7 ++- epan/dfilter/dfvm.h | 3 +- epan/dfilter/gencode.c | 6 ++- epan/dfilter/grammar.lemon | 5 +- epan/dfilter/scanner.l | 4 +- epan/dfilter/semcheck.c | 58 ++++++++++++++-------- epan/dfilter/sttype-test.c | 4 +- epan/dfilter/sttype-test.h | 5 +- epan/ftypes/ftype-bytes.c | 50 +++++++++++++++---- epan/ftypes/ftype-double.c | 6 ++- epan/ftypes/ftype-integer.c | 19 +++++-- epan/ftypes/ftype-ipv4.c | 7 +-- epan/ftypes/ftype-none.c | 3 +- epan/ftypes/ftype-string.c | 56 +++++++++++++++++++-- epan/ftypes/ftype-time.c | 16 ++++-- epan/ftypes/ftype-tvbuff.c | 99 ++++++++++++++++++++++++++++++++++--- epan/ftypes/ftypes-int.h | 5 +- epan/ftypes/ftypes.c | 23 +++++++-- epan/ftypes/ftypes.h | 17 +++++-- epan/strutil.c | 33 ++++++++++++- epan/strutil.h | 5 +- epan/tvbuff.c | 32 +++++++++++- epan/tvbuff.h | 9 +++- gtk/dfilter_expr_dlg.c | 17 +++++-- tools/dfilter-test.py | 75 +++++++++++++++++++++++++++- 27 files changed, 496 insertions(+), 82 deletions(-) diff --git a/doc/ethereal.pod.template b/doc/ethereal.pod.template index ef09184443..8774d88636 100644 --- a/doc/ethereal.pod.template +++ b/doc/ethereal.pod.template @@ -1384,6 +1384,11 @@ abbreviations: ge, >= Greater than or Equal to le, <= Less than or Equal to +An additional operater exists that is expressed only in English, not +punctuation: + + contains Does the protocol, byte-string, or string contain a value + Furthermore, each protocol field is typed. The types are: Unsigned integer (either 8-bit, 16-bit, 24-bit, or 32-bit) @@ -1480,7 +1485,7 @@ Use of octal to look for "HEAD": This means that you must escape backslashes with backslashes inside double quotes: - smb.path == "\\\\SERVER\\SHARE" + smb.path contains "\\\\SERVER\\SHARE" to look for \\SERVER\SHARE in "smb.path". diff --git a/doc/tethereal.pod.template b/doc/tethereal.pod.template index 248ad436e8..7e439c76ee 100644 --- a/doc/tethereal.pod.template +++ b/doc/tethereal.pod.template @@ -599,6 +599,11 @@ abbreviations: ge, >= Greater than or Equal to le, <= Less than or Equal to +An additional operater exists that is expressed only in English, not +punctuation: + + contains Does the protocol, byte-string, or string contain a value + Furthermore, each protocol field is typed. The types are: Unsigned integer (either 8-bit, 16-bit, 24-bit, or 32-bit) @@ -695,7 +700,7 @@ Use of octal to look for "HEAD": This means that you must escape backslashes with backslashes inside double quotes: - smb.path == "\\\\SERVER\\SHARE" + smb.path contains "\\\\SERVER\\SHARE" to look for \\SERVER\SHARE in "smb.path". diff --git a/epan/dfilter/dfvm.c b/epan/dfilter/dfvm.c index 0be9fc692d..85753468f1 100644 --- a/epan/dfilter/dfvm.c +++ b/epan/dfilter/dfvm.c @@ -1,5 +1,5 @@ /* - * $Id: dfvm.c,v 1.9 2002/10/16 16:32:59 gram Exp $ + * $Id: dfvm.c,v 1.10 2003/08/27 15:23:03 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -403,6 +403,11 @@ dfvm_apply(dfilter_t *df, proto_tree *tree) arg1->value.numeric, arg2->value.numeric); break; + case ANY_CONTAINS: + accum = any_test(df, fvalue_contains, + arg1->value.numeric, arg2->value.numeric); + break; + case NOT: accum = !accum; break; diff --git a/epan/dfilter/dfvm.h b/epan/dfilter/dfvm.h index c97faae5fb..efeb478962 100644 --- a/epan/dfilter/dfvm.h +++ b/epan/dfilter/dfvm.h @@ -1,5 +1,5 @@ /* - * $Id: dfvm.h,v 1.8 2002/10/16 16:32:59 gram Exp $ + * $Id: dfvm.h,v 1.9 2003/08/27 15:23:04 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -67,6 +67,7 @@ typedef enum { ANY_GE, ANY_LT, ANY_LE, + ANY_CONTAINS, MK_RANGE } dfvm_opcode_t; diff --git a/epan/dfilter/gencode.c b/epan/dfilter/gencode.c index 1d23d93bc6..333fdacf38 100644 --- a/epan/dfilter/gencode.c +++ b/epan/dfilter/gencode.c @@ -1,5 +1,5 @@ /* - * $Id: gencode.c,v 1.10 2003/06/13 10:03:25 guy Exp $ + * $Id: gencode.c,v 1.11 2003/08/27 15:23:04 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -319,6 +319,10 @@ gen_test(dfwork_t *dfw, stnode_t *st_node) case TEST_OP_LE: gen_relation(dfw, ANY_LE, st_arg1, st_arg2); break; + + case TEST_OP_CONTAINS: + gen_relation(dfw, ANY_CONTAINS, st_arg1, st_arg2); + break; } } diff --git a/epan/dfilter/grammar.lemon b/epan/dfilter/grammar.lemon index 35310adf7d..c114892034 100644 --- a/epan/dfilter/grammar.lemon +++ b/epan/dfilter/grammar.lemon @@ -1,4 +1,4 @@ -/* $Id: grammar.lemon,v 1.5 2003/07/25 03:44:01 gram Exp $ */ +/* $Id: grammar.lemon,v 1.6 2003/08/27 15:23:04 gram Exp $ */ %include { #ifdef HAVE_CONFIG_H @@ -108,7 +108,7 @@ shifting 3 more symbols. */ /* Associativity */ %left TEST_AND. %left TEST_OR. -%nonassoc TEST_EQ TEST_NE TEST_LT TEST_LE TEST_GT TEST_GE. +%nonassoc TEST_EQ TEST_NE TEST_LT TEST_LE TEST_GT TEST_GE TEST_CONTAINS. %right TEST_NOT. /* Top-level targets */ @@ -247,6 +247,7 @@ rel_op2(O) ::= TEST_GT. { O = TEST_OP_GT; } rel_op2(O) ::= TEST_GE. { O = TEST_OP_GE; } rel_op2(O) ::= TEST_LT. { O = TEST_OP_LT; } rel_op2(O) ::= TEST_LE. { O = TEST_OP_LE; } +rel_op2(O) ::= TEST_CONTAINS. { O = TEST_OP_CONTAINS; } diff --git a/epan/dfilter/scanner.l b/epan/dfilter/scanner.l index ca23626457..563c08b855 100644 --- a/epan/dfilter/scanner.l +++ b/epan/dfilter/scanner.l @@ -1,6 +1,6 @@ %{ /* - * $Id: scanner.l,v 1.8 2003/07/25 03:44:01 gram Exp $ + * $Id: scanner.l,v 1.9 2003/08/27 15:23:04 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -77,6 +77,7 @@ GString* quoted_string = NULL; "lt" return simple(TOKEN_TEST_LT); "<=" return simple(TOKEN_TEST_LE); "le" return simple(TOKEN_TEST_LE); +"contains" return simple(TOKEN_TEST_CONTAINS); "!" return simple(TOKEN_TEST_NOT); "not" return simple(TOKEN_TEST_NOT); @@ -221,6 +222,7 @@ simple(int token) case TOKEN_TEST_GE: case TOKEN_TEST_LT: case TOKEN_TEST_LE: + case TOKEN_TEST_CONTAINS: case TOKEN_TEST_NOT: case TOKEN_TEST_AND: case TOKEN_TEST_OR: diff --git a/epan/dfilter/semcheck.c b/epan/dfilter/semcheck.c index faba2942d4..8bcf967d59 100644 --- a/epan/dfilter/semcheck.c +++ b/epan/dfilter/semcheck.c @@ -1,5 +1,5 @@ /* - * $Id: semcheck.c,v 1.18 2003/07/25 03:44:01 gram Exp $ + * $Id: semcheck.c,v 1.19 2003/08/27 15:23:04 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -260,6 +260,7 @@ is_bytes_type(enum ftenum type) * and possibly some modifications of syntax tree nodes. */ static void check_relation_LHS_FIELD(const char *relation_string, FtypeCanFunc can_func, + gboolean allow_partial_value, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { stnode_t *new_st; @@ -318,7 +319,7 @@ check_relation_LHS_FIELD(const char *relation_string, FtypeCanFunc can_func, } else if (type2 == STTYPE_UNPARSED) { s = stnode_data(st_arg2); - fvalue = fvalue_from_unparsed(ftype1, s, dfilter_fail); + fvalue = fvalue_from_unparsed(ftype1, s, allow_partial_value, dfilter_fail); if (!fvalue) { /* check value_string */ fvalue = mk_fvalue_from_val_string(hfinfo1, s); @@ -358,7 +359,8 @@ check_relation_LHS_FIELD(const char *relation_string, FtypeCanFunc can_func, } static void -check_relation_LHS_STRING(FtypeCanFunc can_func _U_, stnode_t *st_node, +check_relation_LHS_STRING(FtypeCanFunc can_func _U_, gboolean allow_partial_value _U_, + stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { stnode_t *new_st; @@ -389,7 +391,7 @@ check_relation_LHS_STRING(FtypeCanFunc can_func _U_, stnode_t *st_node, sttype_test_set2_args(st_node, new_st, st_arg2); stnode_free(st_arg1); } - else if (type2 == STTYPE_STRING) { + else if (type2 == STTYPE_STRING || type2 == STTYPE_UNPARSED) { /* Well now that's silly... */ dfilter_fail("Neither \"%s\" nor \"%s\" are field or protocol names.", stnode_data(st_arg1), @@ -412,7 +414,8 @@ check_relation_LHS_STRING(FtypeCanFunc can_func _U_, stnode_t *st_node, } static void -check_relation_LHS_UNPARSED(FtypeCanFunc can_func _U_, stnode_t *st_node, +check_relation_LHS_UNPARSED(FtypeCanFunc can_func _U_, gboolean allow_partial_value, + stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { stnode_t *new_st; @@ -430,7 +433,7 @@ check_relation_LHS_UNPARSED(FtypeCanFunc can_func _U_, stnode_t *st_node, ftype2 = hfinfo2->type; s = stnode_data(st_arg1); - fvalue = fvalue_from_unparsed(ftype2, s, dfilter_fail); + fvalue = fvalue_from_unparsed(ftype2, s, allow_partial_value, dfilter_fail); if (!fvalue) { /* check value_string */ fvalue = mk_fvalue_from_val_string(hfinfo2, s); @@ -443,7 +446,7 @@ check_relation_LHS_UNPARSED(FtypeCanFunc can_func _U_, stnode_t *st_node, sttype_test_set2_args(st_node, new_st, st_arg2); stnode_free(st_arg1); } - else if (type2 == STTYPE_STRING) { + else if (type2 == STTYPE_STRING || type2 == STTYPE_UNPARSED) { /* Well now that's silly... */ dfilter_fail("Neither \"%s\" nor \"%s\" are field or protocol names.", stnode_data(st_arg1), @@ -451,8 +454,9 @@ check_relation_LHS_UNPARSED(FtypeCanFunc can_func _U_, stnode_t *st_node, THROW(TypeError); } else if (type2 == STTYPE_RANGE) { + /* XXX - is this right? */ s = stnode_data(st_arg1); - fvalue = fvalue_from_unparsed(FT_BYTES, s, dfilter_fail); + fvalue = fvalue_from_unparsed(FT_BYTES, s, allow_partial_value, dfilter_fail); if (!fvalue) { THROW(TypeError); } @@ -529,7 +533,8 @@ check_drange_sanity(stnode_t *st) } static void -check_relation_LHS_RANGE(FtypeCanFunc can_func _U_, stnode_t *st_node, +check_relation_LHS_RANGE(FtypeCanFunc can_func _U_, gboolean allow_partial_value, + stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { stnode_t *new_st; @@ -589,7 +594,7 @@ check_relation_LHS_RANGE(FtypeCanFunc can_func _U_, stnode_t *st_node, } else if (type2 == STTYPE_UNPARSED) { s = stnode_data(st_arg2); - fvalue = fvalue_from_unparsed(FT_BYTES, s, dfilter_fail); + fvalue = fvalue_from_unparsed(FT_BYTES, s, allow_partial_value, dfilter_fail); if (!fvalue) { THROW(TypeError); } @@ -609,21 +614,26 @@ check_relation_LHS_RANGE(FtypeCanFunc can_func _U_, stnode_t *st_node, /* Check the semantics of any relational test. */ static void -check_relation(const char *relation_string, FtypeCanFunc can_func, stnode_t *st_node, +check_relation(const char *relation_string, gboolean allow_partial_value, + FtypeCanFunc can_func, stnode_t *st_node, stnode_t *st_arg1, stnode_t *st_arg2) { switch (stnode_type_id(st_arg1)) { case STTYPE_FIELD: - check_relation_LHS_FIELD(relation_string, can_func, st_node, st_arg1, st_arg2); + check_relation_LHS_FIELD(relation_string, can_func, + allow_partial_value, st_node, st_arg1, st_arg2); break; case STTYPE_STRING: - check_relation_LHS_STRING(can_func, st_node, st_arg1, st_arg2); + check_relation_LHS_STRING(can_func, + allow_partial_value, st_node, st_arg1, st_arg2); break; case STTYPE_RANGE: - check_relation_LHS_RANGE(can_func, st_node, st_arg1, st_arg2); + check_relation_LHS_RANGE(can_func, + allow_partial_value, st_node, st_arg1, st_arg2); break; case STTYPE_UNPARSED: - check_relation_LHS_UNPARSED(can_func, st_node, st_arg1, st_arg2); + check_relation_LHS_UNPARSED(can_func, + allow_partial_value, st_node, st_arg1, st_arg2); break; case STTYPE_UNINITIALIZED: @@ -664,23 +674,29 @@ check_test(stnode_t *st_node) break; case TEST_OP_EQ: - check_relation("==", ftype_can_eq, st_node, st_arg1, st_arg2); + check_relation("==", FALSE, ftype_can_eq, st_node, st_arg1, st_arg2); break; case TEST_OP_NE: - check_relation("!=", ftype_can_ne, st_node, st_arg1, st_arg2); + check_relation("!=", FALSE, ftype_can_ne, st_node, st_arg1, st_arg2); break; case TEST_OP_GT: - check_relation(">", ftype_can_gt, st_node, st_arg1, st_arg2); + check_relation(">", FALSE, ftype_can_gt, st_node, st_arg1, st_arg2); break; case TEST_OP_GE: - check_relation(">=", ftype_can_ge, st_node, st_arg1, st_arg2); + check_relation(">=", FALSE, ftype_can_ge, st_node, st_arg1, st_arg2); break; case TEST_OP_LT: - check_relation("<", ftype_can_lt, st_node, st_arg1, st_arg2); + check_relation("<", FALSE, ftype_can_lt, st_node, st_arg1, st_arg2); break; case TEST_OP_LE: - check_relation("<=", ftype_can_le, st_node, st_arg1, st_arg2); + check_relation("<=", FALSE, ftype_can_le, st_node, st_arg1, st_arg2); break; + case TEST_OP_CONTAINS: + check_relation("contains", TRUE, ftype_can_contains, st_node, st_arg1, st_arg2); + break; + + default: + g_assert_not_reached(); } } diff --git a/epan/dfilter/sttype-test.c b/epan/dfilter/sttype-test.c index d559bff19e..f6f917f1fc 100644 --- a/epan/dfilter/sttype-test.c +++ b/epan/dfilter/sttype-test.c @@ -1,5 +1,5 @@ /* - * $Id: sttype-test.c,v 1.3 2002/08/28 20:40:56 jmayer Exp $ + * $Id: sttype-test.c,v 1.4 2003/08/27 15:23:05 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -90,6 +90,8 @@ num_operands(test_op_t op) return 2; case TEST_OP_LE: return 2; + case TEST_OP_CONTAINS: + return 2; } g_assert_not_reached(); return -1; diff --git a/epan/dfilter/sttype-test.h b/epan/dfilter/sttype-test.h index a4d017f154..f662a5b097 100644 --- a/epan/dfilter/sttype-test.h +++ b/epan/dfilter/sttype-test.h @@ -1,5 +1,5 @@ /* - * $Id: sttype-test.h,v 1.3 2002/08/28 20:40:56 jmayer Exp $ + * $Id: sttype-test.h,v 1.4 2003/08/27 15:23:05 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -35,7 +35,8 @@ typedef enum { TEST_OP_GT, TEST_OP_GE, TEST_OP_LT, - TEST_OP_LE + TEST_OP_LE, + TEST_OP_CONTAINS } test_op_t; void diff --git a/epan/ftypes/ftype-bytes.c b/epan/ftypes/ftype-bytes.c index 25c2f445ec..e0e859fab7 100644 --- a/epan/ftypes/ftype-bytes.c +++ b/epan/ftypes/ftype-bytes.c @@ -1,5 +1,5 @@ /* - * $Id: ftype-bytes.c,v 1.16 2003/07/25 03:44:02 gram Exp $ + * $Id: ftype-bytes.c,v 1.17 2003/08/27 15:23:05 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -28,6 +28,7 @@ #include #include #include +#include #include #define ETHER_LEN 6 @@ -129,7 +130,7 @@ is_byte_sep(guint8 c) } static gboolean -val_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) +bytes_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc) { GByteArray *bytes; guint8 val; @@ -226,7 +227,7 @@ val_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) } static gboolean -ether_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) +ether_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value, LogFunc logfunc) { guint8 *mac; @@ -235,7 +236,18 @@ ether_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) * up as an Ethernet host name if it does, and if that fails, * we'll log a message. */ - if (val_from_unparsed(fv, s, NULL)) { + if (bytes_from_unparsed(fv, s, TRUE, NULL)) { + if (fv->value.bytes->len > ETHER_LEN) { + logfunc("\"%s\" contains too many bytes to be a valid Ethernet address.", + s); + return FALSE; + } + else if (fv->value.bytes->len < ETHER_LEN && !allow_partial_value) { + logfunc("\"%s\" contains too few bytes to be a valid Ethernet address.", + s); + return FALSE; + } + return TRUE; } @@ -251,7 +263,7 @@ ether_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) } static gboolean -ipv6_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) +ipv6_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc) { guint8 buffer[16]; @@ -265,7 +277,7 @@ ipv6_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) } static gboolean -u64_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) +u64_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc) { guint8 buffer[8]; @@ -279,7 +291,7 @@ u64_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) } static gboolean -i64_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) +i64_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc) { guint8 buffer[8]; @@ -577,6 +589,20 @@ cmp_le_i64(fvalue_t *fv_a, fvalue_t *fv_b) return (memcmp(a->data, b->data, a->len) <= 0); } +static gboolean +cmp_contains(fvalue_t *fv_a, fvalue_t *fv_b) +{ + GByteArray *a = fv_a->value.bytes; + GByteArray *b = fv_b->value.bytes; + + if (epan_memmem(a->data, a->len, b->data, b->len)) { + return TRUE; + } + else { + return FALSE; + } +} + void ftype_register_bytes(void) { @@ -587,7 +613,7 @@ ftype_register_bytes(void) 0, /* wire_size */ bytes_fvalue_new, /* new_value */ bytes_fvalue_free, /* free_value */ - val_from_unparsed, /* val_from_unparsed */ + bytes_from_unparsed, /* val_from_unparsed */ NULL, /* val_from_string */ bytes_to_repr, /* val_to_string_repr */ bytes_repr_len, /* len_string_repr */ @@ -606,6 +632,7 @@ ftype_register_bytes(void) cmp_ge, cmp_lt, cmp_le, + cmp_contains, len, slice, @@ -617,7 +644,7 @@ ftype_register_bytes(void) 0, /* wire_size */ bytes_fvalue_new, /* new_value */ bytes_fvalue_free, /* free_value */ - val_from_unparsed, /* val_from_unparsed */ + bytes_from_unparsed, /* val_from_unparsed */ NULL, /* val_from_string */ bytes_to_repr, /* val_to_string_repr */ bytes_repr_len, /* len_string_repr */ @@ -636,6 +663,7 @@ ftype_register_bytes(void) cmp_ge, cmp_lt, cmp_le, + cmp_contains, len, slice, @@ -666,6 +694,7 @@ ftype_register_bytes(void) cmp_ge, cmp_lt, cmp_le, + cmp_contains, len, slice, @@ -696,6 +725,7 @@ ftype_register_bytes(void) cmp_ge, cmp_lt, cmp_le, + cmp_contains, len, slice, @@ -726,6 +756,7 @@ ftype_register_bytes(void) cmp_ge, cmp_lt, cmp_le, + NULL, /* cmp_contains */ len, slice, @@ -756,6 +787,7 @@ ftype_register_bytes(void) cmp_ge_i64, cmp_lt_i64, cmp_le_i64, + NULL, /* cmp_contains */ len, slice, diff --git a/epan/ftypes/ftype-double.c b/epan/ftypes/ftype-double.c index fb1bfcd36f..27fba9aaf4 100644 --- a/epan/ftypes/ftype-double.c +++ b/epan/ftypes/ftype-double.c @@ -1,5 +1,5 @@ /* - * $Id: ftype-double.c,v 1.10 2003/07/31 03:52:43 guy Exp $ + * $Id: ftype-double.c,v 1.11 2003/08/27 15:23:06 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -51,7 +51,7 @@ value_get_floating(fvalue_t *fv) } static gboolean -val_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) +val_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc) { char *endptr = NULL; @@ -181,6 +181,7 @@ ftype_register_double(void) cmp_ge, cmp_lt, cmp_le, + NULL, /* cmp_contains */ NULL, NULL, @@ -211,6 +212,7 @@ ftype_register_double(void) cmp_ge, cmp_lt, cmp_le, + NULL, /* cmp_contains */ NULL, NULL, diff --git a/epan/ftypes/ftype-integer.c b/epan/ftypes/ftype-integer.c index 818b6cce7a..0bba4d218b 100644 --- a/epan/ftypes/ftype-integer.c +++ b/epan/ftypes/ftype-integer.c @@ -1,5 +1,5 @@ /* - * $Id: ftype-integer.c,v 1.14 2003/07/25 03:44:02 gram Exp $ + * $Id: ftype-integer.c,v 1.15 2003/08/27 15:23:06 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -49,7 +49,7 @@ get_integer(fvalue_t *fv) } static gboolean -val_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) +val_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc) { char *endptr; @@ -78,7 +78,7 @@ val_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) } static gboolean -ipxnet_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) +ipxnet_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc) { guint32 val; gboolean known; @@ -88,7 +88,7 @@ ipxnet_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) * up as an IPX network name if it does, and if that fails, * we'll log a message. */ - if (val_from_unparsed(fv, s, NULL)) { + if (val_from_unparsed(fv, s, TRUE, NULL)) { return TRUE; } @@ -242,6 +242,7 @@ ftype_register_integers(void) u_cmp_ge, u_cmp_lt, u_cmp_le, + NULL, /* cmp_contains */ NULL, /* len */ NULL, /* slice */ @@ -271,6 +272,7 @@ ftype_register_integers(void) u_cmp_ge, u_cmp_lt, u_cmp_le, + NULL, /* cmp_contains */ NULL, /* len */ NULL, /* slice */ @@ -300,6 +302,7 @@ ftype_register_integers(void) u_cmp_ge, u_cmp_lt, u_cmp_le, + NULL, /* cmp_contains */ NULL, /* len */ NULL, /* slice */ @@ -329,6 +332,7 @@ ftype_register_integers(void) u_cmp_ge, u_cmp_lt, u_cmp_le, + NULL, /* cmp_contains */ NULL, /* len */ NULL, /* slice */ @@ -358,6 +362,7 @@ ftype_register_integers(void) s_cmp_ge, s_cmp_lt, s_cmp_le, + NULL, /* cmp_contains */ NULL, /* len */ NULL, /* slice */ @@ -387,6 +392,7 @@ ftype_register_integers(void) s_cmp_ge, s_cmp_lt, s_cmp_le, + NULL, /* cmp_contains */ NULL, /* len */ NULL, /* slice */ @@ -416,6 +422,7 @@ ftype_register_integers(void) s_cmp_ge, s_cmp_lt, s_cmp_le, + NULL, /* cmp_contains */ NULL, /* len */ NULL, /* slice */ @@ -445,6 +452,7 @@ ftype_register_integers(void) s_cmp_ge, s_cmp_lt, s_cmp_le, + NULL, /* cmp_contains */ NULL, /* len */ NULL, /* slice */ @@ -474,6 +482,7 @@ ftype_register_integers(void) NULL, /* cmp_ge */ NULL, /* cmp_lt */ NULL, /* cmp_le */ + NULL, /* cmp_contains */ NULL, /* len */ NULL, /* slice */ @@ -504,6 +513,7 @@ ftype_register_integers(void) u_cmp_ge, u_cmp_lt, u_cmp_le, + NULL, /* cmp_contains */ NULL, /* len */ NULL, /* slice */ @@ -534,6 +544,7 @@ ftype_register_integers(void) u_cmp_ge, u_cmp_lt, u_cmp_le, + NULL, /* cmp_contains */ NULL, /* len */ NULL, /* slice */ diff --git a/epan/ftypes/ftype-ipv4.c b/epan/ftypes/ftype-ipv4.c index cad03ef251..c5362bfbca 100644 --- a/epan/ftypes/ftype-ipv4.c +++ b/epan/ftypes/ftype-ipv4.c @@ -1,5 +1,5 @@ /* - * $Id: ftype-ipv4.c,v 1.12 2003/07/31 04:18:01 guy Exp $ + * $Id: ftype-ipv4.c,v 1.13 2003/08/27 15:23:07 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -45,7 +45,7 @@ value_get(fvalue_t *fv) } static gboolean -val_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) +val_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc) { guint32 addr; unsigned int nmask_bits; @@ -99,7 +99,7 @@ val_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) } /* XXX - this is inefficient */ - nmask_fvalue = fvalue_from_unparsed(FT_UINT32, net_str, logfunc); + nmask_fvalue = fvalue_from_unparsed(FT_UINT32, net_str, FALSE, logfunc); g_free(s_copy); if (!nmask_fvalue) { return FALSE; @@ -202,6 +202,7 @@ ftype_register_ipv4(void) cmp_ge, cmp_lt, cmp_le, + NULL, /* cmp_contains */ NULL, NULL, diff --git a/epan/ftypes/ftype-none.c b/epan/ftypes/ftype-none.c index bf6cd400eb..46c1822a80 100644 --- a/epan/ftypes/ftype-none.c +++ b/epan/ftypes/ftype-none.c @@ -1,5 +1,5 @@ /* - * $Id: ftype-none.c,v 1.6 2003/07/25 03:44:03 gram Exp $ + * $Id: ftype-none.c,v 1.7 2003/08/27 15:23:07 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -57,6 +57,7 @@ ftype_register_none(void) NULL, NULL, NULL, + NULL, /* cmp_contains */ NULL, NULL, diff --git a/epan/ftypes/ftype-string.c b/epan/ftypes/ftype-string.c index 5cac0e7966..bb2c088ebe 100644 --- a/epan/ftypes/ftype-string.c +++ b/epan/ftypes/ftype-string.c @@ -1,5 +1,5 @@ /* - * $Id: ftype-string.c,v 1.12 2003/07/30 22:25:35 guy Exp $ + * $Id: ftype-string.c,v 1.13 2003/08/27 15:23:07 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -117,6 +117,32 @@ val_from_string(fvalue_t *fv, char *s, LogFunc logfunc _U_) return TRUE; } +static gboolean +val_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc) +{ + fvalue_t *fv_bytes; + /* Does this look like a byte-string? */ + fv_bytes = fvalue_from_unparsed(FT_BYTES, s, TRUE, NULL); + if (fv_bytes) { + /* Copy the bytes over to a string and terminate it + * with a NUL. XXX - what if the user embeds a NUL + * in the middle of the byte string? */ + int num_bytes = fv_bytes->value.bytes->len; + + fv->value.string = g_malloc(num_bytes + 1); + memcpy(fv->value.string, fv->value.bytes->data, num_bytes); + fv->value.string[num_bytes] = '\0'; + + fvalue_free(fv_bytes); + return TRUE; + } + else { + /* Just turn it into a string */ + return val_from_string(fv, s, logfunc); + } + g_assert_not_reached(); +} + static guint len(fvalue_t *fv) { @@ -170,6 +196,25 @@ cmp_le(fvalue_t *a, fvalue_t *b) return (strcmp(a->value.string, b->value.string) <= 0); } +static gboolean +cmp_contains(fvalue_t *fv_a, fvalue_t *fv_b) +{ + /* According to + * http://www.introl.com/introl-demo/Libraries/C/ANSI_C/string/strstr.html + * strstr() returns a non-NULL value if needle is an empty + * string. We don't that behavior for cmp_contains. */ + if (strlen(fv_b->value.string) == 0) { + return FALSE; + } + + if (strstr(fv_a->value.string, fv_b->value.string)) { + return TRUE; + } + else { + return FALSE; + } +} + void ftype_register_string(void) { @@ -180,7 +225,7 @@ ftype_register_string(void) 0, /* wire_size */ string_fvalue_new, /* new_value */ string_fvalue_free, /* free_value */ - val_from_string, /* val_from_unparsed */ + val_from_unparsed, /* val_from_unparsed */ val_from_string, /* val_from_string */ string_to_repr, /* val_to_string_repr */ string_repr_len, /* len_string_repr */ @@ -199,6 +244,7 @@ ftype_register_string(void) cmp_ge, cmp_lt, cmp_le, + cmp_contains, /* cmp_contains */ len, slice, @@ -209,7 +255,7 @@ ftype_register_string(void) 0, string_fvalue_new, string_fvalue_free, - val_from_string, /* val_from_unparsed */ + val_from_unparsed, /* val_from_unparsed */ val_from_string, /* val_from_string */ NULL, /* val_to_string_repr */ NULL, /* len_string_repr */ @@ -228,6 +274,7 @@ ftype_register_string(void) cmp_ge, cmp_lt, cmp_le, + cmp_contains, /* cmp_contains */ len, slice, @@ -238,7 +285,7 @@ ftype_register_string(void) 0, string_fvalue_new, string_fvalue_free, - val_from_string, /* val_from_unparsed */ + val_from_unparsed, /* val_from_unparsed */ val_from_string, /* val_from_string */ NULL, /* val_to_string_repr */ NULL, /* len_string_repr */ @@ -257,6 +304,7 @@ ftype_register_string(void) cmp_ge, cmp_lt, cmp_le, + cmp_contains, /* cmp_contains */ len, slice, diff --git a/epan/ftypes/ftype-time.c b/epan/ftypes/ftype-time.c index dd04fa6cb9..d926d30365 100644 --- a/epan/ftypes/ftype-time.c +++ b/epan/ftypes/ftype-time.c @@ -1,5 +1,5 @@ /* - * $Id: ftype-time.c,v 1.20 2003/07/30 22:50:39 guy Exp $ + * $Id: ftype-time.c,v 1.21 2003/08/27 15:23:07 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -167,7 +167,7 @@ get_nsecs(char *startp, int *nsecs) } static gboolean -relative_val_from_unparsed(fvalue_t *fv, char *s, LogFunc logfunc) +relative_val_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc) { char *curptr, *endptr; @@ -277,6 +277,12 @@ fail: return FALSE; } +static gboolean +absolute_val_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc) +{ + return absolute_val_from_string(fv, s, logfunc); +} + static void time_fvalue_new(fvalue_t *fv) { @@ -337,7 +343,7 @@ ftype_register_time(void) 0, time_fvalue_new, NULL, - absolute_val_from_string, /* val_from_unparsed */ + absolute_val_from_unparsed, /* val_from_unparsed */ absolute_val_from_string, /* val_from_string */ absolute_val_to_repr, /* val_to_string_repr */ absolute_val_repr_len, /* len_string_repr */ @@ -356,6 +362,8 @@ ftype_register_time(void) cmp_ge, cmp_lt, cmp_le, + NULL, /* cmp_contains */ + NULL, NULL }; @@ -384,6 +392,8 @@ ftype_register_time(void) cmp_ge, cmp_lt, cmp_le, + NULL, /* cmp_contains */ + NULL, NULL }; diff --git a/epan/ftypes/ftype-tvbuff.c b/epan/ftypes/ftype-tvbuff.c index 43050f9f9f..c648086a3f 100644 --- a/epan/ftypes/ftype-tvbuff.c +++ b/epan/ftypes/ftype-tvbuff.c @@ -1,5 +1,5 @@ /* - * $Id: ftype-tvbuff.c,v 1.9 2003/07/25 03:44:03 gram Exp $ + * $Id: ftype-tvbuff.c,v 1.10 2003/08/27 15:23:08 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -27,10 +27,21 @@ #include #include +#define tvb_is_private fvalue_gboolean1 + static void value_new(fvalue_t *fv) { fv->value.tvb = NULL; + fv->tvb_is_private = FALSE; +} + +static void +value_free(fvalue_t *fv) +{ + if (fv->tvb_is_private) { + tvb_free_chain(fv->value.tvb); + } } @@ -41,6 +52,66 @@ value_set(fvalue_t *fv, gpointer value, gboolean already_copied) fv->value.tvb = value; } +static void +free_tvb_data(void *data) +{ + g_free(data); +} + + +static gboolean +val_from_string(fvalue_t *fv, char *s, LogFunc logfunc _U_) +{ + tvbuff_t *new_tvb; + guint8 *private_data; + + /* Make a tvbuff from the string. We can drop the + * terminating NUL. */ + private_data = g_memdup(s, strlen(s)); + new_tvb = tvb_new_real_data(private_data, + strlen(s), strlen(s)); + + /* Let the tvbuff know how to delete the data. */ + tvb_set_free_cb(new_tvb, free_tvb_data); + + /* And let us know that we need to free the tvbuff */ + fv->tvb_is_private = TRUE; + fv->value.tvb = new_tvb; + return TRUE; +} + +static gboolean +val_from_unparsed(fvalue_t *fv, char *s, gboolean allow_partial_value _U_, LogFunc logfunc) +{ + fvalue_t *fv_bytes; + tvbuff_t *new_tvb; + guint8 *private_data; + + /* Does this look like a byte string? */ + fv_bytes = fvalue_from_unparsed(FT_BYTES, s, TRUE, NULL); + if (fv_bytes) { + /* Make a tvbuff from the bytes */ + private_data = g_memdup(fv_bytes->value.bytes->data, + fv_bytes->value.bytes->len); + new_tvb = tvb_new_real_data(private_data, + fv_bytes->value.bytes->len, + fv_bytes->value.bytes->len); + + /* Let the tvbuff know how to delete the data. */ + tvb_set_free_cb(new_tvb, free_tvb_data); + + /* And let us know that we need to free the tvbuff */ + fv->tvb_is_private = TRUE; + fv->value.tvb = new_tvb; + return TRUE; + } + else { + /* Treat it as a string. */ + return val_from_string(fv, s, logfunc); + } + g_assert_not_reached(); +} + static gpointer value_get(fvalue_t *fv) { @@ -74,18 +145,29 @@ slice(fvalue_t *fv, GByteArray *bytes, guint offset, guint length) } } +static gboolean +cmp_contains(fvalue_t *fv_a, fvalue_t *fv_b) +{ + if (tvb_find_tvb(fv_a->value.tvb, fv_b->value.tvb, 0) > -1) { + return TRUE; + } + else { + return FALSE; + } +} + void ftype_register_tvbuff(void) { static ftype_t protocol_type = { - "FT_PROTOCOL", - "protocol", - 0, - value_new, - NULL, - NULL, /* val_from_unparsed */ - NULL, /* val_from_string */ + "FT_PROTOCOL", /* name */ + "protocol", /* pretty_name */ + 0, /* wire_size */ + value_new, /* new_value */ + value_free, /* free_value */ + val_from_unparsed, /* val_from_unparsed */ + val_from_string, /* val_from_string */ NULL, /* val_to_string_repr */ NULL, /* len_string_repr */ @@ -103,6 +185,7 @@ ftype_register_tvbuff(void) NULL, NULL, NULL, + cmp_contains, /* cmp_contains */ len, slice, diff --git a/epan/ftypes/ftypes-int.h b/epan/ftypes/ftypes-int.h index d6922ef7c9..2ba2e2fde3 100644 --- a/epan/ftypes/ftypes-int.h +++ b/epan/ftypes/ftypes-int.h @@ -1,5 +1,5 @@ /* - * $Id: ftypes-int.h,v 1.9 2003/07/25 03:44:03 gram Exp $ + * $Id: ftypes-int.h,v 1.10 2003/08/27 15:23:08 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -29,7 +29,7 @@ typedef void (*FvalueNewFunc)(fvalue_t*); typedef void (*FvalueFreeFunc)(fvalue_t*); -typedef gboolean (*FvalueFromUnparsed)(fvalue_t*, char*, LogFunc); +typedef gboolean (*FvalueFromUnparsed)(fvalue_t*, char*, gboolean, LogFunc); typedef gboolean (*FvalueFromString)(fvalue_t*, char*, LogFunc); typedef void (*FvalueToStringRepr)(fvalue_t*, ftrepr_t, char*); typedef int (*FvalueStringReprLen)(fvalue_t*, ftrepr_t); @@ -74,6 +74,7 @@ struct _ftype_t { FvalueCmp cmp_ge; FvalueCmp cmp_lt; FvalueCmp cmp_le; + FvalueCmp cmp_contains; FvalueLen len; FvalueSlice slice; diff --git a/epan/ftypes/ftypes.c b/epan/ftypes/ftypes.c index aa2239397f..58f4afda60 100644 --- a/epan/ftypes/ftypes.c +++ b/epan/ftypes/ftypes.c @@ -1,5 +1,5 @@ /* - * $Id: ftypes.c,v 1.10 2003/07/25 03:44:03 gram Exp $ + * $Id: ftypes.c,v 1.11 2003/08/27 15:23:08 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -198,6 +198,15 @@ ftype_can_le(enum ftenum ftype) return ft->cmp_le ? TRUE : FALSE; } +gboolean +ftype_can_contains(enum ftenum ftype) +{ + ftype_t *ft; + + ft = ftype_lookup(ftype); + return ft->cmp_contains ? TRUE : FALSE; +} + /* ---------------------------------------------------------- */ /* Allocate and initialize an fvalue_t, given an ftype */ @@ -236,13 +245,13 @@ fvalue_free(fvalue_t *fv) } fvalue_t* -fvalue_from_unparsed(ftenum_t ftype, char *s, LogFunc logfunc) +fvalue_from_unparsed(ftenum_t ftype, char *s, gboolean allow_partial_value, LogFunc logfunc) { fvalue_t *fv; fv = fvalue_new(ftype); if (fv->ftype->val_from_unparsed) { - if (fv->ftype->val_from_unparsed(fv, s, logfunc)) { + if (fv->ftype->val_from_unparsed(fv, s, allow_partial_value, logfunc)) { return fv; } } @@ -507,3 +516,11 @@ fvalue_le(fvalue_t *a, fvalue_t *b) g_assert(a->ftype->cmp_le); return a->ftype->cmp_le(a, b); } + +gboolean +fvalue_contains(fvalue_t *a, fvalue_t *b) +{ + /* XXX - check compatibility of a and b */ + g_assert(a->ftype->cmp_contains); + return a->ftype->cmp_contains(a, b); +} diff --git a/epan/ftypes/ftypes.h b/epan/ftypes/ftypes.h index 1e224cbf53..74f4f2b705 100644 --- a/epan/ftypes/ftypes.h +++ b/epan/ftypes/ftypes.h @@ -1,7 +1,7 @@ /* ftypes.h * Definitions for field types * - * $Id: ftypes.h,v 1.18 2003/07/25 03:44:04 gram Exp $ + * $Id: ftypes.h,v 1.19 2003/08/27 15:23:08 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -120,6 +120,9 @@ ftype_can_lt(enum ftenum ftype); gboolean ftype_can_le(enum ftenum ftype); +gboolean +ftype_can_contains(enum ftenum ftype); + /* ---------------- FVALUE ----------------- */ #include @@ -141,6 +144,11 @@ typedef struct { nstime_t time; tvbuff_t *tvb; } value; + + /* The following is provided for private use + * by the fvalue. */ + gboolean fvalue_gboolean1; + } fvalue_t; fvalue_t* @@ -152,10 +160,10 @@ fvalue_free(fvalue_t *fv); typedef void (*LogFunc)(char*,...); fvalue_t* -fvalue_from_unparsed(ftenum_t ftype, char *s, LogFunc log); +fvalue_from_unparsed(ftenum_t ftype, char *s, gboolean allow_partial_value, LogFunc logfunc); fvalue_t* -fvalue_from_string(ftenum_t ftype, char *s, LogFunc log); +fvalue_from_string(ftenum_t ftype, char *s, LogFunc logfunc); /* Returns the length of the string required to hold the * string representation of the the field value. @@ -213,6 +221,9 @@ fvalue_lt(fvalue_t *a, fvalue_t *b); gboolean fvalue_le(fvalue_t *a, fvalue_t *b); +gboolean +fvalue_contains(fvalue_t *a, fvalue_t *b); + guint fvalue_length(fvalue_t *fv); diff --git a/epan/strutil.c b/epan/strutil.c index 45ea39dbff..93b5b1ef5f 100644 --- a/epan/strutil.c +++ b/epan/strutil.c @@ -1,7 +1,7 @@ /* strutil.c * String utility routines * - * $Id: strutil.c,v 1.11 2003/08/01 01:39:00 guy Exp $ + * $Id: strutil.c,v 1.12 2003/08/27 15:23:02 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -301,3 +301,34 @@ bytes_to_str_punct(const guint8 *bd, int bd_len, gchar punct) { *p = '\0'; return cur; } + +/* Return the first occurrence of needle in haystack. + * If not found, return NULL. + * If either haystack or needle has 0 length, return NULL. + * Algorithm copied from GNU's glibc 2.3.2 memcmp() */ +const guint8 * +epan_memmem(const guint8 *haystack, guint haystack_len, + const guint8 *needle, guint needle_len) +{ + const guint8 *begin; + const guint8 *const last_possible + = haystack + haystack_len - needle_len; + + if (needle_len == 0) { + return NULL; + } + + if (needle_len > haystack_len) { + return NULL; + } + + for (begin = haystack ; begin <= last_possible; ++begin) { + if (begin[0] == needle[0] && + !memcmp(&begin[1], needle + 1, + needle_len - 1)) { + return begin; + } + } + + return NULL; +} diff --git a/epan/strutil.h b/epan/strutil.h index 78aabe3dd2..e9792c6e94 100644 --- a/epan/strutil.h +++ b/epan/strutil.h @@ -1,7 +1,7 @@ /* strutil.h * String utility definitions * - * $Id: strutil.h,v 1.10 2003/07/04 03:41:00 gram Exp $ + * $Id: strutil.h,v 1.11 2003/08/27 15:23:02 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -35,6 +35,9 @@ gchar* format_text(const guchar *line, int len); gchar* bytes_to_str(const guint8 *, int); gchar* bytes_to_str_punct(const guint8 *, int, gchar punct); +const guint8 * epan_memmem(const guint8 *haystack, guint haystack_len, + const guint8 *needle, guint needle_len); + /* Surround a string or a macro, resolved to a string, with double quotes */ #define _STRINGIFY(a) # a #define STRINGIFY(a) _STRINGIFY(a) diff --git a/epan/tvbuff.c b/epan/tvbuff.c index b161a8110e..65997123bc 100644 --- a/epan/tvbuff.c +++ b/epan/tvbuff.c @@ -9,7 +9,7 @@ * the data of a backing tvbuff, or can be a composite of * other tvbuffs. * - * $Id: tvbuff.c,v 1.48 2003/08/08 08:19:50 guy Exp $ + * $Id: tvbuff.c,v 1.49 2003/08/27 15:23:02 gram Exp $ * * Copyright (c) 2000 by Gilbert Ramirez * @@ -2141,3 +2141,33 @@ tvb_get_ds_tvb(tvbuff_t *tvb) { return tvb->ds_tvb; } + +/* Find a needle tvbuff within a haystack tvbuff. */ +gint +tvb_find_tvb(tvbuff_t *haystack_tvb, tvbuff_t *needle_tvb, gint haystack_offset) +{ + guint haystack_abs_offset, haystack_abs_length; + const guint8 *haystack_data; + const guint8 *needle_data; + const guint needle_len = needle_tvb->length; + const guint8 *location; + + /* Get pointers to the tvbuffs' data. */ + haystack_data = tvb_get_ptr(haystack_tvb, 0, -1); + needle_data = tvb_get_ptr(needle_tvb, 0, -1); + + check_offset_length(haystack_tvb, haystack_offset, -1, + &haystack_abs_offset, &haystack_abs_length); + + location = epan_memmem(haystack_data + haystack_abs_offset, haystack_abs_length, + needle_data, needle_len); + + if (location) { + return location - haystack_data; + } + else { + return -1; + } + + return -1; +} diff --git a/epan/tvbuff.h b/epan/tvbuff.h index 6dd756a03c..156de931fa 100644 --- a/epan/tvbuff.h +++ b/epan/tvbuff.h @@ -9,7 +9,7 @@ * the data of a backing tvbuff, or can be a composite of * other tvbuffs. * - * $Id: tvbuff.h,v 1.33 2003/06/12 08:33:31 guy Exp $ + * $Id: tvbuff.h,v 1.34 2003/08/27 15:23:03 gram Exp $ * * Copyright (c) 2000 by Gilbert Ramirez * @@ -435,6 +435,13 @@ extern gchar *tvb_bytes_to_str(tvbuff_t *tvb, gint offset, gint len); extern tvbuff_t *tvb_get_ds_tvb(tvbuff_t *tvb); +/* Locate a sub-tvbuff within another tvbuff, starting at position + * 'haystack_offset'. Returns the index of the beginning of 'needle' within + * 'haystack', or -1 if 'needle' is not found. The index is relative + * to the start of 'haystack', not 'haystack_offset'. */ +extern gint tvb_find_tvb(tvbuff_t *haystack_tvb, tvbuff_t *needle_tvb, + gint haystack_offset); + /************** END OF ACCESSORS ****************/ #endif /* __TVBUFF_H__ */ diff --git a/gtk/dfilter_expr_dlg.c b/gtk/dfilter_expr_dlg.c index a91c8c68e3..20c79e19d9 100644 --- a/gtk/dfilter_expr_dlg.c +++ b/gtk/dfilter_expr_dlg.c @@ -7,7 +7,7 @@ * Copyright 2000, Jeffrey C. Foster and * Guy Harris * - * $Id: dfilter_expr_dlg.c,v 1.35 2003/08/25 00:15:02 guy Exp $ + * $Id: dfilter_expr_dlg.c,v 1.36 2003/08/27 15:23:10 gram Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -280,6 +280,9 @@ show_relations(GtkWidget *relation_label, GtkWidget *relation_list, if (ftype_can_le(ftype) || (ftype_can_slice(ftype) && ftype_can_le(FT_BYTES))) add_relation_list(relation_list, "<="); + if (ftype_can_contains(ftype) || + (ftype_can_slice(ftype) && ftype_can_contains(FT_BYTES))) + add_relation_list(relation_list, "contains"); /* * And show the list. @@ -883,6 +886,8 @@ dfilter_expr_dlg_accept_cb(GtkWidget *w, gpointer filter_te_arg) can_compare = ftype_can_ge(ftype); else if (strcmp(item_str, "<=") == 0) can_compare = ftype_can_le(ftype); + else if (strcmp(item_str, "contains") == 0) + can_compare = ftype_can_contains(ftype); else can_compare = TRUE; /* not a comparison */ if (!can_compare) { @@ -928,8 +933,14 @@ dfilter_expr_dlg_accept_cb(GtkWidget *w, gpointer filter_te_arg) * for the type of the field; if a range string was * specified, must be valid for FT_BYTES. */ - fvalue = fvalue_from_unparsed(ftype, stripped_value_str, - dfilter_report_bad_value); + if (strcmp(item_str, "contains") == 0) { + fvalue = fvalue_from_unparsed(ftype, stripped_value_str, TRUE, + dfilter_report_bad_value); + } + else { + fvalue = fvalue_from_unparsed(ftype, stripped_value_str, FALSE, + dfilter_report_bad_value); + } if (fvalue == NULL) { /* * It's not valid. diff --git a/tools/dfilter-test.py b/tools/dfilter-test.py index 2e801a4e4d..58ca3ccae5 100755 --- a/tools/dfilter-test.py +++ b/tools/dfilter-test.py @@ -4,7 +4,7 @@ Test-suite to test ethereal's dfilter mechanism. """ # -# $Id: dfilter-test.py,v 1.2 2003/07/25 03:44:05 gram Exp $ +# $Id: dfilter-test.py,v 1.3 2003/08/27 15:23:11 gram Exp $ # # Copyright (C) 2003 by Gilbert Ramirez # @@ -454,6 +454,22 @@ class Bytes(Test): return self.DFilterCount(pkt_nfs, "nfs.fattr3.size == 264000", 0) + def ck_contains_1(self): + return self.DFilterCount(pkt_ipx_rip, + "ipx.src.node contains a3", 1) + + def ck_contains_2(self): + return self.DFilterCount(pkt_ipx_rip, + "ipx.src.node contains a3:e3", 1) + + def ck_contains_3(self): + return self.DFilterCount(pkt_ipx_rip, + "ipx.src.node contains 00:aa:00:a3:e3:a4", 1) + + def ck_contains_4(self): + return self.DFilterCount(pkt_ipx_rip, + "ipx.src.node contains aa:e3", 0) + tests = [ ck_eq_1, @@ -482,6 +498,10 @@ class Bytes(Test): ck_bytes_2, ck_uint64_1, ck_uint64_2, + ck_contains_1, + ck_contains_2, + ck_contains_3, + ck_contains_4, ] @@ -967,6 +987,29 @@ class String(Test): return self.DFilterCount(pkt_tftp, 'tftp.type == "junk"', 0) + def ck_contains_1(self): + return self.DFilterCount(pkt_http, + 'http.request.method contains "E"', 1) + + def ck_contains_2(self): + return self.DFilterCount(pkt_http, + 'http.request.method contains "EA"', 1) + + def ck_contains_3(self): + return self.DFilterCount(pkt_http, + 'http.request.method contains "HEAD"', 1) + + def ck_contains_4(self): + return self.DFilterCount(pkt_http, + 'http.request.method contains "POST"', 0) + + def ck_contains_5(self): + return self.DFilterCount(pkt_http, + 'http.request.method contains 50:4f:53:54"', 0) # "POST" + + def ck_contains_6(self): + return self.DFilterCount(pkt_http, + 'http.request.method contains 48:45:41:44"', 1) # "HEAD" tests = [ @@ -995,6 +1038,11 @@ class String(Test): # ck_slice_8, ck_stringz_1, ck_stringz_2, + ck_contains_1, + ck_contains_2, + ck_contains_3, + ck_contains_4, + ck_contains_5, ] @@ -1124,6 +1172,26 @@ class TVB(Test): "ip[-1] == 0x86", 0) + def ck_contains_1(self): + return self.DFilterCount(pkt_http, + "eth contains 6b", 1) + + def ck_contains_2(self): + return self.DFilterCount(pkt_http, + "eth contains 09:6b:88", 1) + + def ck_contains_3(self): + return self.DFilterCount(pkt_http, + "eth contains 00:e0:81:00:b0:28:00:09:6b:88:f5:c9:08:00", 1) + + def ck_contains_4(self): + return self.DFilterCount(pkt_http, + "eth contains ff:ff:ff", 0) + + def ck_contains_5(self): + return self.DFilterCount(pkt_http, + 'http contains "HEAD"', 1) + tests = [ ck_slice_1, @@ -1132,6 +1200,11 @@ class TVB(Test): # XXX # ck_slice_4, # ck_slice_5, + ck_contains_1, + ck_contains_2, + ck_contains_3, + ck_contains_4, + ck_contains_5, ]