aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/README.dissector46
-rw-r--r--epan/proto.c159
-rw-r--r--epan/proto.h54
-rw-r--r--epan/strutil.c129
-rw-r--r--epan/strutil.h30
-rw-r--r--epan/tvbuff.c30
-rw-r--r--epan/tvbuff.h12
-rw-r--r--epan/wslua/wslua_field.c19
-rw-r--r--epan/wslua/wslua_tree.c22
-rw-r--r--epan/wslua/wslua_tvb.c67
-rw-r--r--test/lua/tvb.lua263
-rwxr-xr-xtest/suite-wslua.sh8
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