diff options
-rw-r--r-- | doc/README.dissector | 46 | ||||
-rw-r--r-- | epan/proto.c | 159 | ||||
-rw-r--r-- | epan/proto.h | 54 | ||||
-rw-r--r-- | epan/strutil.c | 129 | ||||
-rw-r--r-- | epan/strutil.h | 30 | ||||
-rw-r--r-- | epan/tvbuff.c | 30 | ||||
-rw-r--r-- | epan/tvbuff.h | 12 | ||||
-rw-r--r-- | epan/wslua/wslua_field.c | 19 | ||||
-rw-r--r-- | epan/wslua/wslua_tree.c | 22 | ||||
-rw-r--r-- | epan/wslua/wslua_tvb.c | 67 | ||||
-rw-r--r-- | test/lua/tvb.lua | 263 | ||||
-rwxr-xr-x | test/suite-wslua.sh | 8 |
12 files changed, 802 insertions, 37 deletions
diff --git a/doc/README.dissector b/doc/README.dissector index 1ca8107cc0..0d5d9aef66 100644 --- a/doc/README.dissector +++ b/doc/README.dissector @@ -320,6 +320,16 @@ gchar *tvb_bytes_to_str_punct(tvbuff_t *tvb, gint offset, gint len, gchar punct) This function is similar to tvb_bytes_to_str(...) except that 'punct' is inserted between the hex representation of each byte. +GByteArray *tvb_get_string_bytes(tvbuff_t *tvb, const gint offset, const gint length, + const guint encoding, GByteArray* bytes, gint *endoff) + +Given a tvbuff, an offset into the tvbuff, and a length that starts +at that offset (which may be -1 for "all the way to the end of the +tvbuff"), fetch the hex-decoded byte values of the tvbuff into the +passed-in 'bytes' array, based on the passed-in encoding. In other +words, convert from a hex-ascii string in tvbuff, into the supplied +GByteArray. + gchar *tvb_bcd_dig_to_wmem_packet_str(tvbuff_t *tvb, const gint offset, const gint len, dgt_set_t *dgt, gboolean skip_first); Given a tvbuff, an offset into the tvbuff, and a length that starts @@ -1098,6 +1108,10 @@ protocol or field labels to the proto_tree: proto_tree_add_bytes(tree, id, tvb, start, length, start_ptr); proto_item * + proto_tree_add_bytes_item(tree, id, tvb, start, length, encoding, + retval, endoff, err); + + proto_item * proto_tree_add_bytes_format(tree, id, tvb, start, length, start_ptr, format, ...); @@ -1109,6 +1123,10 @@ protocol or field labels to the proto_tree: proto_tree_add_time(tree, id, tvb, start, length, value_ptr); proto_item * + proto_tree_add_time_item(tree, id, tvb, start, length, encoding, + retval, endoff, err); + + proto_item * proto_tree_add_time_format(tree, id, tvb, start, length, value_ptr, format, ...); @@ -1476,6 +1494,34 @@ Subarea Nodes. The user does not have to shift the value of the FID to the high nibble of the byte ("sna.th.fid == 0xf0") as was necessary in the past. +proto_tree_add_XXX_item() +--------------------- +proto_tree_add_XXX_item is used when you wish to do no special formatting, +but also either wish for the retrieved value from the tvbuff to be handed +back (to avoid doing tvb_get_...), and/or wish to have the value be decoded +from the tvbuff in a string-encoded format. + +The item added to the GUI tree will contain the name (as passed in the +proto_register_*() function) and a value. The value will be fetched +from the tvbuff, based on the type of the XXX name and the encoding of +the value as specified by the "encoding" argument. + +This function retrieves the value even if the passed-in tree param is NULL, +so that it can be used by dissectors at all times to both get the value +and set the tree item to it. + +Like other proto_tree_add functions, if there is a tree and the value cannot +be decoded from the tvbuff, then an expert info error is reported. For string +encoding, this means that a failure to decode the hex value from the string +results in an expert info error being added to the tree. + +For string-decoding, the passed-in encoding argument needs to specify the +string encoding (e.g., ENC_ASCII, ENC_UTF_8) as well as the format. For +some XXX types, the format is constrained - for example for the encoding format +for proto_tree_add_time_item() can only be one of the ENC_ISO_8601_* ones +or ENC_RFC_822 or ENC_RFC_1123. For proto_tree_add_bytes_item() it can only +be ENC_STR_HEX bit-or'ed with one or more of the ENC_SEP_* separator types. + proto_tree_add_protocol_format() -------------------------------- proto_tree_add_protocol_format is used to add the top-level item for the diff --git a/epan/proto.c b/epan/proto.c index 2707f056ec..ac73a2604b 100644 --- a/epan/proto.c +++ b/epan/proto.c @@ -87,8 +87,9 @@ struct ptvcursor { @param tree the tree to append this item to @param hfindex field index @param hfinfo header_field + @param free_block a code block to call to free resources if this returns @return the header field matching 'hfinfo' */ -#define TRY_TO_FAKE_THIS_ITEM(tree, hfindex, hfinfo) \ +#define TRY_TO_FAKE_THIS_ITEM_OR_FREE(tree, hfindex, hfinfo, free_block) \ /* If this item is not referenced we dont have to do much work \ at all but we should still return a node so that field items \ below this node (think proto_item_add_subtree()) will still \ @@ -100,10 +101,13 @@ struct ptvcursor { We fake FT_PROTOCOL unless some clients have requested us \ not to do so. \ */ \ - if (!tree) \ + if (!tree) { \ + free_block; \ return NULL; \ + } \ PTREE_DATA(tree)->count++; \ if (PTREE_DATA(tree)->count > MAX_TREE_ITEMS) { \ + free_block; \ if (getenv("WIRESHARK_ABORT_ON_TOO_MANY_ITEMS") != NULL) \ g_error("More than %d items in the tree -- possible infinite loop", MAX_TREE_ITEMS); \ /* Let the exception handler add items to the tree */ \ @@ -117,6 +121,7 @@ struct ptvcursor { if ((hfinfo->ref_type != HF_REF_TYPE_DIRECT) \ && (hfinfo->type != FT_PROTOCOL || \ PTREE_DATA(tree)->fake_protocols)) { \ + free_block; \ /* just return tree back to the caller */\ return tree; \ } \ @@ -124,6 +129,15 @@ struct ptvcursor { } /** See inlined comments. + @param tree the tree to append this item to + @param hfindex field index + @param hfinfo header_field + @return the header field matching 'hfinfo' */ +#define TRY_TO_FAKE_THIS_ITEM(tree, hfindex, hfinfo) \ + TRY_TO_FAKE_THIS_ITEM_OR_FREE(tree, hfindex, hfinfo, ((void)0)) + + +/** See inlined comments. @param pi the created protocol item we're about to return */ #define TRY_TO_FAKE_THIS_REPR(pi) \ g_assert(pi); \ @@ -182,6 +196,8 @@ proto_tree_set_bytes(field_info *fi, const guint8* start_ptr, gint length); static void proto_tree_set_bytes_tvb(field_info *fi, tvbuff_t *tvb, gint offset, gint length); static void +proto_tree_set_bytes_gbytearray(field_info *fi, const GByteArray *value); +static void proto_tree_set_time(field_info *fi, const nstime_t *value_ptr); static void proto_tree_set_string(field_info *fi, const char* value); @@ -1955,6 +1971,133 @@ proto_tree_add_item(proto_tree *tree, int hfindex, tvbuff_t *tvb, return proto_tree_add_item_new(tree, proto_registrar_get_nth(hfindex), tvb, start, length, encoding); } +/* which FT_ types can use proto_tree_add_bytes_item() */ +static inline gboolean +validate_proto_tree_add_bytes_ftype(const enum ftenum type) +{ + return (type == FT_BYTES || + type == FT_UINT_BYTES || + type == FT_OID || + type == FT_REL_OID || + type == FT_SYSTEM_ID ); +} + +/* Note: this does no validation that the byte array of an FT_OID or + FT_REL_OID is actually valid; and neither does proto_tree_add_item(), + so I think it's ok to continue not validating it? + */ +proto_item * +proto_tree_add_bytes_item(proto_tree *tree, int hfindex, tvbuff_t *tvb, + const gint start, gint length, const guint encoding, + GByteArray *retval, gint *endoff, gint *err) +{ + field_info *new_fi; + GByteArray *bytes = retval; + GByteArray *created_bytes = NULL; + gint saved_err = 0; + guint32 n = 0; + header_field_info *hfinfo = proto_registrar_get_nth(hfindex); + gboolean generate = (bytes || tree) ? TRUE : FALSE; + + DISSECTOR_ASSERT_HINT(hfinfo != NULL, "Not passed hfi!"); + + DISSECTOR_ASSERT_HINT(validate_proto_tree_add_bytes_ftype(hfinfo->type), + "Called proto_tree_add_bytes_item but not a bytes-based FT_XXX type"); + + /* length has to be -1 or > 0 regardless of encoding */ + /* invalid FT_UINT_BYTES length is caught in get_uint_value() */ + if (length < -1 || length == 0) { + REPORT_DISSECTOR_BUG(wmem_strdup_printf(wmem_packet_scope(), + "Invalid length %d passed to proto_tree_add_bytes_item for %s", + length, ftype_name(hfinfo->type))); + } + + if (encoding & ENC_STR_NUM) { + REPORT_DISSECTOR_BUG("Decoding number strings for byte arrays is not supported"); + } + + if (generate && (encoding & ENC_STR_HEX)) { + if (hfinfo->type == FT_UINT_BYTES) { + /* can't decode FT_UINT_BYTES from strings */ + REPORT_DISSECTOR_BUG("proto_tree_add_bytes_item called for " + "FT_UINT_BYTES type, but as ENC_STR_HEX"); + } + + if (!bytes) { + /* caller doesn't care about return value, but we need it to + call tvb_get_string_bytes() and set the tree later */ + bytes = created_bytes = g_byte_array_new(); + } + + /* bytes might be NULL after this, but can't add expert error until later */ + bytes = tvb_get_string_bytes(tvb, start, length, encoding, bytes, endoff); + + /* grab the errno now before it gets overwritten */ + saved_err = errno; + } + else if (generate) { + tvb_ensure_bytes_exist(tvb, start, length); + + if (!bytes) { + /* caller doesn't care about return value, but we need it to + call tvb_get_string_bytes() and set the tree later */ + bytes = created_bytes = g_byte_array_new(); + } + + if (hfinfo->type == FT_UINT_BYTES) { + n = length; /* n is now the "header" length */ + length = get_uint_value(tree, tvb, start, n, encoding); + /* length is now the value's length; only store the value in the array */ + g_byte_array_append(bytes, tvb_get_ptr(tvb, start + n, length), length); + } + else if (length > 0) { + g_byte_array_append(bytes, tvb_get_ptr(tvb, start, length), length); + } + + if (endoff) + *endoff = start + n + length; + } + + if (err) *err = saved_err; + + TRY_TO_FAKE_THIS_ITEM_OR_FREE(tree, hfinfo->id, hfinfo, + { + if (created_bytes) + g_byte_array_free(created_bytes, TRUE); + created_bytes = NULL; + bytes = NULL; + } ); + + /* n will be zero except when it's a FT_UINT_BYTES */ + new_fi = new_field_info(tree, hfinfo, tvb, start, n + length); + + if (new_fi == NULL) + return NULL; + + if (encoding & ENC_STRING) { + if (saved_err == ERANGE) + expert_add_info(NULL, tree, &ei_number_string_decoding_erange_error); + else if (!bytes || saved_err != 0) + expert_add_info(NULL, tree, &ei_number_string_decoding_failed_error); + + if (bytes) + proto_tree_set_bytes_gbytearray(new_fi, bytes); + + if (created_bytes) + g_byte_array_free(created_bytes, TRUE); + } + else { + /* n will be zero except when it's a FT_UINT_BYTES */ + proto_tree_set_bytes_tvb(new_fi, tvb, start + n, length); + + FI_SET_FLAG(new_fi, + (encoding & ENC_LITTLE_ENDIAN) ? FI_LITTLE_ENDIAN : FI_BIG_ENDIAN); + } + + return proto_tree_add_node(tree, new_fi); +} + + proto_item * proto_tree_add_time_item(proto_tree *tree, int hfindex, tvbuff_t *tvb, const gint start, gint length, const guint encoding, @@ -2205,6 +2348,18 @@ proto_tree_set_bytes_tvb(field_info *fi, tvbuff_t *tvb, gint offset, gint length proto_tree_set_bytes(fi, tvb_get_ptr(tvb, offset, length), length); } +static void +proto_tree_set_bytes_gbytearray(field_info *fi, const GByteArray *value) +{ + GByteArray *bytes; + + DISSECTOR_ASSERT(value != NULL); + + bytes = byte_array_dup(value); + + fvalue_set_byte_array(&fi->value, bytes); +} + /* Add a FT_*TIME to a proto_tree */ proto_item * proto_tree_add_time(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, diff --git a/epan/proto.h b/epan/proto.h index d17242990e..eac413478a 100644 --- a/epan/proto.h +++ b/epan/proto.h @@ -347,6 +347,22 @@ WS_DLL_PUBLIC WS_MSVC_NORETURN void proto_report_dissector_bug(const char *messa /* mask out ENC_STR_* and related bits - should this replace ENC_CHARENCODING_MASK? */ #define ENC_STR_MASK 0x0000FFFE +/* for cases where the number is allowed to have a leading '+'/'-' */ +/* this can't collide with ENC_SEP_* because they can be used simultaneously */ +#define ENC_NUM_PREF 0x00200000 + +/* For cases where a string encoding contains hex, bit-or one or more + * of these for the allowed separator(s), as well as with ENC_STR_HEX. + * See hex_str_to_bytes_encoding() in epan/strutil.h for details. + */ +#define ENC_SEP_NONE 0x00010000 +#define ENC_SEP_COLON 0x00020000 +#define ENC_SEP_DASH 0x00040000 +#define ENC_SEP_DOT 0x00080000 +#define ENC_SEP_SPACE 0x00100000 +/* a convenience macro for the above */ +#define ENC_SEP_MASK 0x001F0000 + /* For cases where a string encoding contains a timestamp, use one * of these (but only one). These values can collide with above, because * you can't do both at the same time. @@ -905,6 +921,44 @@ WS_DLL_PUBLIC proto_item * proto_tree_add_bytes(proto_tree *tree, int hfindex, tvbuff_t *tvb, gint start, gint length, const guint8* start_ptr); +/** Get and add a byte-array-based FT_* to a proto_tree. + + Supported: FT_BYTES, FT_UINT_BYTES, FT_OID, FT_REL_OID, and FT_SYSTEM_ID. + + The item is extracted from the tvbuff handed to it, based on the ENC_* passed + in for the encoding, and the retrieved byte array is also set to *retval so the + caller gets it back for other uses. + + This function retrieves the value even if the passed-in tree param is NULL, + so that it can be used by dissectors at all times to both get the value + and set the tree item to it. + + Like other proto_tree_add functions, if there is a tree and the value cannot + be decoded from the tvbuff, then an expert info error is reported. For string + encoding, this means that a failure to decode the hex value from the string + results in an expert info error being added to the tree. + + If encoding is string-based, it will convert using tvb_get_string_bytes(); see + that function's comments for details. + + @note The GByteArray retval must be pre-constructed using g_byte_array_new(). + + @param tree the tree to append this item to + @param hfindex field index + @param tvb the tv buffer of the current data + @param start start of data in tvb + @param length length of data in tvb + @param encoding data encoding (e.g, ENC_LITTLE_ENDIAN, or ENC_UTF_8|ENC_STR_HEX) + @param[in,out] retval points to a GByteArray which will be set to the bytes from the Tvb. + @param[in,out] endoff if not NULL, gets set to the character after those consumed. + @param[in,out] err if not NULL, gets set to 0 if no failure, else the errno code (e.g., EDOM, ERANGE). + @return the newly created item, and retval is set to the decoded value + */ +WS_DLL_PUBLIC proto_item * +proto_tree_add_bytes_item(proto_tree *tree, int hfindex, tvbuff_t *tvb, + const gint start, gint length, const guint encoding, + GByteArray *retval, gint *endoff, gint *err); + /** Add a formatted FT_BYTES to a proto_tree, with the format generating the string for the value and with the field name being included automatically. diff --git a/epan/strutil.c b/epan/strutil.c index 567d072abd..d9b8c5a553 100644 --- a/epan/strutil.c +++ b/epan/strutil.c @@ -30,6 +30,7 @@ #include "emem.h" #include <wsutil/str_util.h> +#include <epan/proto.h> #ifdef _WIN32 #include <windows.h> @@ -545,6 +546,132 @@ hex_str_to_bytes(const char *hex_str, GByteArray *bytes, gboolean force_separato return TRUE; } +static inline gchar +get_valid_byte_sep(gchar c, const guint encoding) +{ + gchar retval = -1; /* -1 means failure */ + + switch (c) { + case ':': + if (encoding & ENC_SEP_COLON) + retval = c; + break; + case '-': + if (encoding & ENC_SEP_DASH) + retval = c; + break; + case '.': + if (encoding & ENC_SEP_DOT) + retval = c; + break; + case ' ': + if (encoding & ENC_SEP_SPACE) + retval = c; + break; + case '\0': + /* we were given the end of the string, so it's fine */ + retval = 0; + break; + default: + if (isxdigit(c) && (encoding & ENC_SEP_NONE)) + retval = 0; + /* anything else means we've got a failure */ + break; + } + + return retval; +} + +/* Turn a string of hex digits with optional separators (defined by is_byte_sep()) + * into a byte array. Unlike hex_str_to_bytes(), this will read as many hex-char + * pairs as possible and not error if it hits a non-hex-char; instead it just ends + * there. (i.e., like strtol()/atoi()/etc.) Unless fail_if_partial is TRUE. + * + * The **endptr, if not NULL, is set to the char after the last hex character. + */ +gboolean +hex_str_to_bytes_encoding(const gchar *hex_str, GByteArray *bytes, const gchar **endptr, + const guint encoding, const gboolean fail_if_partial) +{ + gchar c, d; + guint8 val; + const gchar *end = hex_str; + gboolean retval = FALSE; + gchar sep = -1; + + /* a map from ASCII hex chars to their value */ + static const gchar str_to_nibble[256] = { + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + }; + + /* we must see two hex chars at the beginning, or fail */ + if (bytes && *end && isxdigit(*end) && isxdigit(*(end+1))) { + retval = TRUE; + + /* set the separator character we'll allow; if this returns a -1, it means something's + * invalid after the hex, but we'll let the while-loop grab the first hex-pair anyway + */ + sep = get_valid_byte_sep(*(end+2), encoding); + + while (*end) { + c = str_to_nibble[(int)*end]; + if (c < 0) { + if (fail_if_partial) retval = FALSE; + break; + } + ++end; + + d = str_to_nibble[(int)*end]; + if (d < 0) { + if (fail_if_partial) retval = FALSE; + break; + } + val = ((guint8)c * 16) + d; + g_byte_array_append(bytes, &val, 1); + ++end; + + /* check for separator and peek at next char to make sure we should keep going */ + if (sep > 0 && *end == sep && str_to_nibble[(int)*(end+1)] > -1) { + /* yes, it's the right sep and followed by more hex, so skip the sep */ + ++end; + } else if (sep != 0 && *end) { + /* we either need a separator, but we don't see one; or the get_valid_byte_sep() + earlier didn't find a valid one to begin with */ + if (fail_if_partial) retval = FALSE; + break; + } + /* otherwise, either no separator allowed, or *end is null, or *end is an invalid + * sep, or *end is a valid sep but after it is not a hex char - in all those + * cases, just loop back up and let it fail later naturally. + */ + } + } + + if (!retval) { + if (bytes) g_byte_array_set_size(bytes, 0); + end = hex_str; + } + + if (endptr) *endptr = end; + + return retval; +} + /* * Turn an RFC 3986 percent-encoded string into a byte array. * XXX - We don't check for reserved characters. @@ -666,7 +793,7 @@ format_uri(const GByteArray *bytes, const gchar *reserved_chars) * */ GByteArray * -byte_array_dup(GByteArray *ba) { +byte_array_dup(const GByteArray *ba) { GByteArray *new_ba; if (!ba) diff --git a/epan/strutil.h b/epan/strutil.h index b9e8bdfcb7..f92136bbcd 100644 --- a/epan/strutil.h +++ b/epan/strutil.h @@ -112,6 +112,34 @@ WS_DLL_PUBLIC gboolean hex_str_to_bytes(const char *hex_str, GByteArray *bytes, gboolean force_separators); +/* Turn a string of hex digits with optional separators (defined by encoding) + * into a byte array. Unlike hex_str_to_bytes(), this will read as many hex-char + * pairs as possible and not error if it hits a non-hex-char; instead it just ends + * there. (i.e., like strtol()/atoi()/etc.) But it must see two hex chars at the + * beginning or it will return FALSE. + * + * @param hex_str The string of hex digits. + * @param bytes The GByteArray that will receive the bytes. This + * must be initialized by the caller. + * @param endptr if not NULL, is set to the char after the last hex character consumed. + * @param encoding set to one or more bitwise-or'ed ENC_SEP_* (see proto.h) + * @param fail_if_partial If set to TRUE, then the conversion fails if the whole + * hex_str is not consumed. + * @return FALSE only if no bytes were generated; or if fail_if_partial is TRUE + * and the entire hex_str was not consumed. + * + * If no ENC_SEP_* is set, then no separators are allowed. If multiple ENC_SEP_* are + * bit-or'ed, any of them can be a separator, but once the separator is seen then + * only its same type is accepted for the rest of the string. (i.e., it won't convert + * a "01:23-4567" even if ENC_SEP_COLON|ENC_SEP_DASH|ENC_SEP_NONE is passed in) + * + * This is done this way because it's likely a malformed scenario if they're mixed, + * and this routine is used by dissectors via tvb_get_string_XXX routines. + */ +WS_DLL_PUBLIC +gboolean hex_str_to_bytes_encoding(const char *hex_str, GByteArray *bytes, const char **endptr, + const guint encoding, const gboolean fail_if_partial); + /** Turn an RFC 3986 percent-encoded string into a byte array. * * @param uri_str The string of hex digits. @@ -169,7 +197,7 @@ gboolean oid_str_to_bytes(const char *oid_str, GByteArray *bytes); * @todo - Should this be in strutil.c? */ WS_DLL_PUBLIC -GByteArray *byte_array_dup(GByteArray *ba); +GByteArray *byte_array_dup(const GByteArray *ba); /** * Compare the contents of two GByteArrays diff --git a/epan/tvbuff.c b/epan/tvbuff.c index 668d1c0f8b..8612921bd5 100644 --- a/epan/tvbuff.c +++ b/epan/tvbuff.c @@ -1307,6 +1307,36 @@ validate_single_byte_ascii_encoding(const guint encoding) REPORT_DISSECTOR_BUG("No string encoding type passed to tvb_get_string_XXX"); } +GByteArray* +tvb_get_string_bytes(tvbuff_t *tvb, const gint offset, const gint length, + const guint encoding, GByteArray *bytes, gint *endoff) +{ + const gchar *ptr = (gchar*) tvb_get_raw_string(wmem_packet_scope(), tvb, offset, length); + const gchar *begin = ptr; + const gchar *end = NULL; + GByteArray* retval = NULL; + + errno = EDOM; + + validate_single_byte_ascii_encoding(encoding); + + if (endoff) *endoff = 0; + + while (*begin == ' ') begin++; + + if (*begin && bytes) { + if (hex_str_to_bytes_encoding(begin, bytes, &end, encoding, FALSE)) { + if (bytes->len > 0) { + if (endoff) *endoff = offset + (gint)(end - ptr); + errno = 0; + retval = bytes; + } + } + } + + return retval; +} + /* converts a broken down date representation, relative to UTC, * to a timestamp; it uses timegm() if it's available. * Copied from Glib source gtimer.c diff --git a/epan/tvbuff.h b/epan/tvbuff.h index 14789d318b..e68095759a 100644 --- a/epan/tvbuff.h +++ b/epan/tvbuff.h @@ -367,6 +367,18 @@ WS_DLL_PUBLIC struct nstime_t* tvb_get_string_time(tvbuff_t *tvb, const gint offset, const gint length, const guint encoding, struct nstime_t* ns, gint *endoff); +/* Similar to above, but returns a GByteArray based on the case-insensitive + * hex-char strings with optional separators, and with optional leading spaces. + * The separators allowed are based on the ENC_SEP_* passed in the encoding param. + * + * The passed-in bytes is set to the values, and its pointer is also the return + * value or NULL on error. The GByteArray bytes must be pre-constructed with + * g_byte_array_new(). + */ +WS_DLL_PUBLIC +GByteArray* tvb_get_string_bytes(tvbuff_t *tvb, const gint offset, const gint length, + const guint encoding, GByteArray* bytes, gint *endoff); + /** * Fetch an IPv4 address, in network byte order. * We do *not* convert it to host byte order; we leave it in diff --git a/epan/wslua/wslua_field.c b/epan/wslua/wslua_field.c index 0720edf591..72dc551d7f 100644 --- a/epan/wslua/wslua_field.c +++ b/epan/wslua/wslua_field.c @@ -75,7 +75,16 @@ WSLUA_METAMETHOD FieldInfo__unm(lua_State* L) { /* WSLUA_ATTRIBUTE FieldInfo_value RO The value of this field. */ WSLUA_METAMETHOD FieldInfo__call(lua_State* L) { /* - Obtain the Value of the field + Obtain the Value of the field. + + Previous to 1.11.4, this function retrieved the value for most field types, + but for `ftypes.UINT_BYTES` it retrieved the `ByteArray` of the field's entire `TvbRange`. + In other words, it returned a `ByteArray` that included the leading length byte(s), + instead of just the *value* bytes. That was a bug, and has been changed in 1.11.4. + Furthermore, it retrieved an `ftypes.GUID` as a `ByteArray`, which is also incorrect. + + If you wish to still get a `ByteArray` of the `TvbRange`, use `FieldInfo:get_range()` + to get the `TvbRange`, and then use `Tvb:bytes()` to convert it to a `ByteArray`. */ FieldInfo fi = checkFieldInfo(L,1); @@ -165,16 +174,18 @@ WSLUA_METAMETHOD FieldInfo__call(lua_State* L) { /* FALLTHROUGH */ case FT_BYTES: case FT_UINT_BYTES: - case FT_GUID: case FT_PROTOCOL: case FT_REL_OID: case FT_SYSTEM_ID: - case FT_OID: { + case FT_OID: + { ByteArray ba = g_byte_array_new(); - g_byte_array_append(ba, (const guint8 *)tvb_memdup(wmem_packet_scope(),fi->ws_fi->ds_tvb,fi->ws_fi->start,fi->ws_fi->length),fi->ws_fi->length); + g_byte_array_append(ba, (const guint8 *) fvalue_get(&fi->ws_fi->value), + fvalue_length(&fi->ws_fi->value)); pushByteArray(L,ba); return 1; } + case FT_GUID: default: luaL_error(L,"FT_ not yet supported"); return 1; diff --git a/epan/wslua/wslua_tree.c b/epan/wslua/wslua_tree.c index 78c4390e41..afd5feef90 100644 --- a/epan/wslua/wslua_tree.c +++ b/epan/wslua/wslua_tree.c @@ -62,6 +62,25 @@ try_add_packet_field(lua_State *L, TreeItem tree_item, TvbRange tvbr, const int gint endoff = 0; switch(type) { + /* these all generate ByteArrays */ + case FT_BYTES: + case FT_UINT_BYTES: + case FT_OID: + case FT_REL_OID: + case FT_SYSTEM_ID: + { + /* GByteArray and its data will be g_free'd by Lua */ + GByteArray *gba = g_byte_array_new(); + item = proto_tree_add_bytes_item(tree_item->tree, hfid, tvbr->tvb->ws_tvb, + tvbr->offset, tvbr->len, encoding, + gba, &endoff, &err); + if (err == 0) { + pushByteArray(L, gba); + lua_pushinteger(L, endoff); + } + } + break; + case FT_ABSOLUTE_TIME: case FT_RELATIVE_TIME: { @@ -77,6 +96,9 @@ try_add_packet_field(lua_State *L, TreeItem tree_item, TvbRange tvbr, const int } break; + /* XXX: what about these? */ + case FT_NONE: + case FT_PROTOCOL: /* anything else just needs to be done the old fashioned way */ default: item = proto_tree_add_item(tree_item->tree, hfid, tvbr->tvb->ws_tvb, tvbr->offset, tvbr->len, encoding); diff --git a/epan/wslua/wslua_tvb.c b/epan/wslua/wslua_tvb.c index a48e48f32c..d40de58436 100644 --- a/epan/wslua/wslua_tvb.c +++ b/epan/wslua/wslua_tvb.c @@ -106,6 +106,27 @@ WSLUA_METAMETHOD ByteArray__concat(lua_State* L) { WSLUA_RETURN(1); /* The new composite `ByteArray`. */ } +WSLUA_METAMETHOD ByteArray__eq(lua_State* L) { + /* Compares two ByteArray values. + + @since 1.11.4 + */ +#define WSLUA_ARG_ByteArray__eq_FIRST 1 /* First array. */ +#define WSLUA_ARG_ByteArray__eq_SECOND 2 /* Second array. */ + ByteArray ba1 = checkByteArray(L,WSLUA_ARG_ByteArray__eq_FIRST); + ByteArray ba2 = checkByteArray(L,WSLUA_ARG_ByteArray__eq_SECOND); + gboolean result = FALSE; + + if (ba1->len == ba2->len) { + if (memcmp(ba1->data, ba2->data, ba1->len) == 0) + result = TRUE; + } + + lua_pushboolean(L,result); + + return 1; +} + WSLUA_METHOD ByteArray_prepend(lua_State* L) { /* Prepend a `ByteArray` to this `ByteArray`. */ #define WSLUA_ARG_ByteArray_prepend_PREPENDED 2 /* `ByteArray` to be prepended. */ @@ -325,6 +346,7 @@ WSLUA_METHODS ByteArray_methods[] = { WSLUA_META ByteArray_meta[] = { WSLUA_CLASS_MTREG(ByteArray,tostring), WSLUA_CLASS_MTREG(ByteArray,concat), + WSLUA_CLASS_MTREG(ByteArray,eq), {"__call",ByteArray_subset}, { NULL, NULL } }; @@ -1309,9 +1331,25 @@ WSLUA_METHOD TvbRange_le_ustringz(lua_State* L) { } WSLUA_METHOD TvbRange_bytes(lua_State* L) { - /* Obtain a `ByteArray` from a `TvbRange`. */ + /* Obtain a `ByteArray` from a `TvbRange`. + + Starting in 1.11.4, this function also takes an optional `encoding` argument, + which can be set to `ENC_STR_HEX` to decode a hex-string from the `TvbRange` + into the returned `ByteArray`. The `encoding` can be bitwise-or'ed with one + or more separator encodings, such as `ENC_SEP_COLON`, to allow separators + to occur between each pair of hex characters. + + The return value also now returns the number of bytes used as a second return value. + + On failure or error, nil is returned for both return values. + + @note The encoding type of the hex string should also be set, for example + `ENC_ASCII` or `ENC_UTF_8`, along with `ENC_STR_HEX`. + */ +#define WSLUA_OPTARG_TvbRange_bytes_ENCODING 2 /* An optional ENC_* encoding value to use */ TvbRange tvbr = checkTvbRange(L,1); GByteArray* ba; + const guint encoding = luaL_optint(L, WSLUA_OPTARG_TvbRange_bytes_ENCODING, 0); if ( !(tvbr && tvbr->tvb)) return 0; if (tvbr->tvb->expired) { @@ -1320,11 +1358,32 @@ WSLUA_METHOD TvbRange_bytes(lua_State* L) { } ba = g_byte_array_new(); - g_byte_array_append(ba,(const guint8 *)tvb_memdup(wmem_packet_scope(),tvbr->tvb->ws_tvb,tvbr->offset,tvbr->len),tvbr->len); - pushByteArray(L,ba); + if (encoding == 0) { + g_byte_array_append(ba,(const guint8 *)tvb_memdup(wmem_packet_scope(),tvbr->tvb->ws_tvb,tvbr->offset,tvbr->len),tvbr->len); + pushByteArray(L,ba); + lua_pushinteger(L, tvbr->len); + } + else if ((encoding & ENC_STR_HEX) == 0) { + WSLUA_OPTARG_ERROR(TvbRange_nstime, ENCODING, "invalid encoding value"); + } + else { + gint endoff = 0; + GByteArray* retval = tvb_get_string_bytes(tvbr->tvb->ws_tvb, tvbr->offset, tvbr->len, + encoding, ba, &endoff); + if (!retval || endoff == 0) { + g_byte_array_free(ba, TRUE); + /* push nil nstime and offset */ + lua_pushnil(L); + lua_pushnil(L); + } + else { + pushByteArray(L,ba); + lua_pushinteger(L, endoff); + } + } - WSLUA_RETURN(1); /* The `ByteArray` object. */ + WSLUA_RETURN(2); /* The `ByteArray` object or nil, and number of bytes consumed or nil. */ } WSLUA_METHOD TvbRange_bitfield(lua_State* L) { diff --git a/test/lua/tvb.lua b/test/lua/tvb.lua index 52f271b9da..25c0daacf3 100644 --- a/test/lua/tvb.lua +++ b/test/lua/tvb.lua @@ -45,7 +45,7 @@ end -- -- CHANGE THIS TO MATCH HOW MANY TESTS THERE ARE -- -local taptests = { [FRAME]=4, [OTHER]=247 } +local taptests = { [FRAME]=4, [OTHER]=312 } local function getResults() print("\n-----------------------------\n") @@ -132,14 +132,21 @@ end ---------------------------------------- --- a table of all of our Protocol's fields and test input and expected output +-- a table of all of our Protocol's fields local testfield = { basic = { - STRING = ProtoField.string ("test.basic.string", "Basic string"), - BOOLEAN = ProtoField.bool ("test.basic.boolean", "Basic boolean", 16, {"yes","no"}, 0x0001), - UINT16 = ProtoField.uint16 ("test.basic.uint16", "Basic uint16") + STRING = ProtoField.string ("test.basic.string", "Basic string"), + BOOLEAN = ProtoField.bool ("test.basic.boolean", "Basic boolean", 16, {"yes","no"}, 0x0001), + UINT16 = ProtoField.uint16 ("test.basic.uint16", "Basic uint16"), + BYTES = ProtoField.bytes ("test.basic.bytes", "Basic Bytes"), + UINT_BYTES = ProtoField.ubytes ("test.basic.ubytes", "Basic Uint Bytes"), + OID = ProtoField.oid ("test.basic.oid", "Basic OID"), + REL_OID = ProtoField.rel_oid("test.basic.rel_oid", "Basic Relative OID"), + ABSOLUTE_LOCAL = ProtoField.absolute_time("test.basic.absolute.local","Basic absolute local"), + ABSOLUTE_UTC = ProtoField.absolute_time("test.basic.absolute.utc", "Basic absolute utc", 1001), + -- GUID = ProtoField.guid ("test.basic.guid", "Basic GUID"), }, time = @@ -148,6 +155,14 @@ local testfield = ABSOLUTE_UTC = ProtoField.absolute_time("test.time.absolute.utc", "Time absolute utc", 1001), }, + bytes = + { + BYTES = ProtoField.bytes ("test.bytes.bytes", "Bytes"), + UINT_BYTES = ProtoField.ubytes ("test.bytes.ubytes", "Uint Bytes"), + OID = ProtoField.oid ("test.bytes.oid", "OID"), + REL_OID = ProtoField.rel_oid("test.bytes.rel_oid", "Relative OID"), + -- GUID = ProtoField.guid ("test.bytes.guid", "GUID"), + }, } -- create a flat array table of the above that can be registered @@ -168,9 +183,16 @@ local getfield = { basic = { - STRING = Field.new ("test.basic.string"), - BOOLEAN = Field.new ("test.basic.boolean"), - UINT16 = Field.new ("test.basic.uint16") + STRING = Field.new ("test.basic.string"), + BOOLEAN = Field.new ("test.basic.boolean"), + UINT16 = Field.new ("test.basic.uint16"), + BYTES = Field.new ("test.basic.bytes"), + UINT_BYTES = Field.new ("test.basic.ubytes"), + OID = Field.new ("test.basic.oid"), + REL_OID = Field.new ("test.basic.rel_oid"), + ABSOLUTE_LOCAL = Field.new ("test.basic.absolute.local"), + ABSOLUTE_UTC = Field.new ("test.basic.absolute.utc"), + -- GUID = Field.new ("test.basic.guid"), }, time = @@ -179,8 +201,18 @@ local getfield = ABSOLUTE_UTC = Field.new ("test.time.absolute.utc"), }, + bytes = + { + BYTES = Field.new ("test.bytes.bytes"), + UINT_BYTES = Field.new ("test.bytes.ubytes"), + OID = Field.new ("test.bytes.oid"), + REL_OID = Field.new ("test.bytes.rel_oid"), + -- GUID = Field.new ("test.bytes.guid"), + }, } +print("test_proto Fields created") + local function addMatchFields(match_fields, ... ) match_fields[#match_fields + 1] = { ... } end @@ -303,14 +335,14 @@ function test_proto.dissector(tvbuf,pktinfo,root) incPktCount(FRAME) incPktCount(OTHER) - testing(OTHER, "Basic") + testing(OTHER, "Basic string") local tree = root:add(test_proto, tvbuf:range(0,tvbuf:len())) -- create a fake Tvb to use for testing local teststring = "this is the string for the first test" - local bytearray = ByteArray.new(teststring, true) - local tvb = bytearray:tvb("Basic") + local bytearray = ByteArray.new(teststring, true) + local tvb_string = bytearray:tvb("Basic string") local function callTreeAdd(tree,...) tree:add(...) @@ -318,61 +350,242 @@ function test_proto.dissector(tvbuf,pktinfo,root) local string_match_fields = {} - execute ("basic-string", tree:add(testfield.basic.STRING, tvb:range(0,tvb:len())) ~= nil ) + execute ("basic-tvb_get_string", tvb_string:range():string() == teststring ) + + execute ("basic-string", tree:add(testfield.basic.STRING, tvb_string:range(0,tvb_string:len())) ~= nil ) addMatchFields(string_match_fields, teststring) - execute ("basic-string", pcall (callTreeAdd, tree, testfield.basic.STRING, tvb:range() ) ) + execute ("basic-string", pcall (callTreeAdd, tree, testfield.basic.STRING, tvb_string:range() ) ) addMatchFields(string_match_fields, teststring) verifyFields("basic.STRING", string_match_fields) - tvb = ByteArray.new("00FF 0001 8000"):tvb("Basic") +---------------------------------------- + testing(OTHER, "Basic boolean") + + local barray_bytes_hex = "00FF00018000" + local barray_bytes = ByteArray.new(barray_bytes_hex) + local tvb_bytes = barray_bytes:tvb("Basic bytes") local bool_match_fields = {} - execute ("basic-boolean", pcall (callTreeAdd, tree, testfield.basic.BOOLEAN, tvb:range(0,2)) ) + execute ("basic-boolean", pcall (callTreeAdd, tree, testfield.basic.BOOLEAN, tvb_bytes:range(0,2)) ) addMatchFields(bool_match_fields, true) - execute ("basic-boolean", pcall (callTreeAdd, tree, testfield.basic.BOOLEAN, tvb:range(2,2)) ) + execute ("basic-boolean", pcall (callTreeAdd, tree, testfield.basic.BOOLEAN, tvb_bytes:range(2,2)) ) addMatchFields(bool_match_fields, true) - execute ("basic-boolean", pcall (callTreeAdd, tree, testfield.basic.BOOLEAN, tvb:range(4,2)) ) + execute ("basic-boolean", pcall (callTreeAdd, tree, testfield.basic.BOOLEAN, tvb_bytes:range(4,2)) ) addMatchFields(bool_match_fields, false) verifyFields("basic.BOOLEAN", bool_match_fields ) +---------------------------------------- + testing(OTHER, "Basic uint16") + local uint16_match_fields = {} - execute ("basic-uint16", pcall (callTreeAdd, tree, testfield.basic.UINT16, tvb:range(0,2)) ) + execute ("basic-uint16", pcall (callTreeAdd, tree, testfield.basic.UINT16, tvb_bytes:range(0,2)) ) addMatchFields(uint16_match_fields, 255) - execute ("basic-uint16", pcall (callTreeAdd, tree, testfield.basic.UINT16, tvb:range(2,2)) ) + execute ("basic-uint16", pcall (callTreeAdd, tree, testfield.basic.UINT16, tvb_bytes:range(2,2)) ) addMatchFields(uint16_match_fields, 1) - execute ("basic-uint16", pcall (callTreeAdd, tree, testfield.basic.UINT16, tvb:range(4,2)) ) + execute ("basic-uint16", pcall (callTreeAdd, tree, testfield.basic.UINT16, tvb_bytes:range(4,2)) ) addMatchFields(uint16_match_fields, 32768) verifyFields("basic.UINT16", uint16_match_fields) +---------------------------------------- + testing(OTHER, "Basic uint16-le") + local function callTreeAddLE(tree,...) tree:add_le(...) end - execute ("basic-uint16-le", pcall (callTreeAddLE, tree, testfield.basic.UINT16, tvb:range(0,2)) ) + execute ("basic-uint16-le", pcall (callTreeAddLE, tree, testfield.basic.UINT16, tvb_bytes:range(0,2)) ) addMatchFields(uint16_match_fields, 65280) - execute ("basic-uint16-le", pcall (callTreeAddLE, tree, testfield.basic.UINT16, tvb:range(2,2)) ) + execute ("basic-uint16-le", pcall (callTreeAddLE, tree, testfield.basic.UINT16, tvb_bytes:range(2,2)) ) addMatchFields(uint16_match_fields, 256) - execute ("basic-uint16-le", pcall (callTreeAddLE, tree, testfield.basic.UINT16, tvb:range(4,2)) ) + execute ("basic-uint16-le", pcall (callTreeAddLE, tree, testfield.basic.UINT16, tvb_bytes:range(4,2)) ) addMatchFields(uint16_match_fields, 128) verifyFields("basic.UINT16", uint16_match_fields) +---------------------------------------- + testing(OTHER, "Basic bytes") + + local bytes_match_fields = {} + + execute ("basic-tvb_get_string_bytes", + string.lower(tostring(tvb_bytes:range():bytes())) == string.lower(barray_bytes_hex)) + + execute ("basic-bytes", pcall (callTreeAdd, tree, testfield.basic.BYTES, tvb_bytes:range()) ) + addMatchFields(bytes_match_fields, barray_bytes) + + -- TODO: it's silly that tree:add_packet_field() requires an encoding argument + -- need to fix that separately in a bug fix + execute ("add_pfield-bytes", treeAddPField(tree, testfield.basic.BYTES, + tvb_bytes:range(), ENC_BIG_ENDIAN)) + addMatchFields(bytes_match_fields, barray_bytes) + + verifyFields("basic.BYTES", bytes_match_fields) + +---------------------------------------- + testing(OTHER, "Basic uint bytes") + + local len_string = string.format("%02x", barray_bytes:len()) + local barray_uint_bytes = ByteArray.new(len_string) .. barray_bytes + local tvb_uint_bytes = barray_uint_bytes:tvb("Basic UINT_BYTES") + local uint_bytes_match_fields = {} + + execute ("basic-uint-bytes", pcall (callTreeAdd, tree, testfield.basic.UINT_BYTES, + tvb_uint_bytes:range(0,1)) ) + addMatchFields(uint_bytes_match_fields, barray_bytes) + + execute ("add_pfield-uint-bytes", treeAddPField(tree, testfield.basic.UINT_BYTES, + tvb_uint_bytes:range(0,1), ENC_BIG_ENDIAN) ) + addMatchFields(uint_bytes_match_fields, barray_bytes) + + verifyFields("basic.UINT_BYTES", uint_bytes_match_fields) + +---------------------------------------- + testing(OTHER, "Basic OID") + + -- note: the tvb being dissected and compared isn't actually a valid OID. + -- tree:add() and tree:add_packet-field() don't care about its validity right now. + + local oid_match_fields = {} + + execute ("basic-oid", pcall(callTreeAdd, tree, testfield.basic.OID, tvb_bytes:range()) ) + addMatchFields(oid_match_fields, barray_bytes) + + execute ("add_pfield-oid", treeAddPField(tree, testfield.basic.OID, + tvb_bytes:range(), ENC_BIG_ENDIAN) ) + addMatchFields(oid_match_fields, barray_bytes) + + verifyFields("basic.OID", oid_match_fields) + +---------------------------------------- + testing(OTHER, "Basic REL_OID") + + -- note: the tvb being dissected and compared isn't actually a valid OID. + -- tree:add() and tree:add_packet-field() don't care about its validity right now. + + local rel_oid_match_fields = {} + + execute ("basic-rel-oid", pcall(callTreeAdd, tree, testfield.basic.REL_OID, tvb_bytes:range())) + addMatchFields(rel_oid_match_fields, barray_bytes) + + execute ("add_pfield-rel_oid", treeAddPField(tree, testfield.basic.REL_OID, + tvb_bytes:range(), ENC_BIG_ENDIAN) ) + addMatchFields(rel_oid_match_fields, barray_bytes) + + verifyFields("basic.REL_OID", rel_oid_match_fields) + + -- TODO: a FT_GUID is not really a ByteArray, so we can't simply treat it as one + -- local barray_guid = ByteArray.new("00FF0001 80001234 567890AB CDEF00FF") + -- local tvb_guid = barray_guid:tvb("Basic GUID") + -- local guid_match_fields = {} + + -- execute ("basic-guid", pcall(callTreeAdd, tree, testfield.basic.GUID, tvb_guid:range()) ) + -- addMatchFields(guid_match_fields, barray_guid) + + -- execute ("add_pfield-guid", treeAddPField(tree, testfield.basic.GUID, + -- tvb_guid:range(), ENC_BIG_ENDIAN) ) + -- addMatchFields(guid_match_fields, barray_guid) + + -- verifyFields("basic.GUID", guid_match_fields) + + +---------------------------------------- + testing(OTHER, "tree:add_packet_field Bytes") + + resetResults() + bytes_match_fields = {} + local bytes_match_values = {} + + -- something to make this easier to read + local function addMatch(...) + addMatchFieldValues(bytes_match_fields, bytes_match_values, ...) + end + + local bytesstring1 = "deadbeef0123456789DEADBEEFabcdef" + local bytesstring = ByteArray.new(bytesstring1) -- the binary version of above, for comparing + local bytestvb1 = ByteArray.new(bytesstring1, true):tvb("Bytes hex-string 1") + local bytesstring2 = " de:ad:be:ef:01:23:45:67:89:DE:AD:BE:EF:ab:cd:ef" + local bytestvb2 = ByteArray.new(bytesstring2 .. "-f0-00 foobar", true):tvb("Bytes hex-string 2") + + local bytestvb1_decode = bytestvb1:range():bytes(ENC_STR_HEX + ENC_SEP_NONE + ENC_SEP_COLON + ENC_SEP_DASH) + execute ("tvb_get_string_bytes", string.lower(tostring(bytestvb1_decode)) == string.lower(tostring(bytesstring1))) + + execute ("add_pfield-bytes1", treeAddPField(tree, testfield.bytes.BYTES, + bytestvb1:range(), + ENC_STR_HEX + ENC_SEP_NONE + + ENC_SEP_COLON + ENC_SEP_DASH)) + addMatch(bytesstring, string.len(bytesstring1)) + + execute ("add_pfield-bytes2", treeAddPField(tree, testfield.bytes.BYTES, + bytestvb2:range(), + ENC_STR_HEX + ENC_SEP_NONE + + ENC_SEP_COLON + ENC_SEP_DASH)) + addMatch(bytesstring, string.len(bytesstring2)) + + verifyResults("add_pfield-bytes", bytes_match_values) + verifyFields("bytes.BYTES", bytes_match_fields) + + +---------------------------------------- + testing(OTHER, "tree:add_packet_field OID") + + resetResults() + bytes_match_fields = {} + bytes_match_values = {} + + execute ("add_pfield-oid1", treeAddPField(tree, testfield.bytes.OID, + bytestvb1:range(), + ENC_STR_HEX + ENC_SEP_NONE + + ENC_SEP_COLON + ENC_SEP_DASH)) + addMatch(bytesstring, string.len(bytesstring1)) + + execute ("add_pfield-oid2", treeAddPField(tree, testfield.bytes.OID, + bytestvb2:range(), + ENC_STR_HEX + ENC_SEP_NONE + + ENC_SEP_COLON + ENC_SEP_DASH)) + addMatch(bytesstring, string.len(bytesstring2)) + + verifyResults("add_pfield-oid", bytes_match_values) + verifyFields("bytes.OID", bytes_match_fields) + + +---------------------------------------- + testing(OTHER, "tree:add_packet_field REL_OID") + + resetResults() + bytes_match_fields = {} + bytes_match_values = {} + + execute ("add_pfield-rel_oid1", treeAddPField(tree, testfield.bytes.REL_OID, + bytestvb1:range(), + ENC_STR_HEX + ENC_SEP_NONE + + ENC_SEP_COLON + ENC_SEP_DASH)) + addMatch(bytesstring, string.len(bytesstring1)) + + execute ("add_pfield-rel_oid2", treeAddPField(tree, testfield.bytes.REL_OID, + bytestvb2:range(), + ENC_STR_HEX + ENC_SEP_NONE + + ENC_SEP_COLON + ENC_SEP_DASH)) + addMatch(bytesstring, string.len(bytesstring2)) + + verifyResults("add_pfield-rel_oid", bytes_match_values) + verifyFields("bytes.REL_OID", bytes_match_fields) + ---------------------------------------- testing(OTHER, "tree:add Time") - tvb = ByteArray.new("00000000 00000000 0000FF0F 00FF000F"):tvb("Time") + local tvb = ByteArray.new("00000000 00000000 0000FF0F 00FF000F"):tvb("Time") local ALOCAL = testfield.time.ABSOLUTE_LOCAL local alocal_match_fields = {} @@ -414,7 +627,7 @@ function test_proto.dissector(tvbuf,pktinfo,root) local autc_match_values = {} -- something to make this easier to read - local function addMatch(...) + addMatch = function(...) addMatchFieldValues(autc_match_fields, autc_match_values, ...) end diff --git a/test/suite-wslua.sh b/test/suite-wslua.sh index fdeb5f0f2f..04e7a70ca3 100755 --- a/test/suite-wslua.sh +++ b/test/suite-wslua.sh @@ -371,6 +371,14 @@ wslua_step_tvb_test() { fi # Tshark catches lua script failures, so we have to parse the output. + # perform this twice: once with a tree, once without + $TSHARK -r $CAPTURE_DIR/dns_port.pcap -X lua_script:$TESTS_DIR/lua/tvb.lua -V > testout.txt 2>&1 + grep -q "All tests passed!" testout.txt + if [ $? -ne 0 ]; then + cat testout.txt + test_step_failed "lua_args_test test 1 failed" + fi + $TSHARK -r $CAPTURE_DIR/dns_port.pcap -X lua_script:$TESTS_DIR/lua/tvb.lua > testout.txt 2>&1 if grep -q "All tests passed!" testout.txt; then test_step_ok |