Add tvb_get and proto_tree_add for string-encoded byte arrays

This commit adds tvb_get_string_bytes and proto_tree_add_bytes_item routines for
getting GByteArrays fields from the tvb when they are encoded in ASCII hex string form.

The proto_tree_add_bytes_item routine is also usable for normal
binary encoded byte arrays, and has the advantage of retrieving
the array values even if there's no proto tree.

It also exposes the routines to Lua, both so that a Lua script can take
advantage of this, but also so I can write a testsuite to test the functions.

Change-Id: I112a038653df6482a5d0ebe7c95708f207319e20
Reviewed-on: https://code.wireshark.org/review/1158
Reviewed-by: Hadriel Kaplan <hadrielk@yahoo.com>
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Hadriel Kaplan 2014-04-12 23:20:15 -04:00 committed by Anders Broman
parent c49be78f4e
commit f52626cc83
12 changed files with 802 additions and 37 deletions

View File

@ -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
@ -1097,6 +1107,10 @@ protocol or field labels to the proto_tree:
proto_item *
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, ...);
@ -1108,6 +1122,10 @@ protocol or field labels to the proto_tree:
proto_item *
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

View File

@ -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,12 +121,22 @@ 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; \
} \
} \
}
/** 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) \
@ -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,

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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) {

View File

@ -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

View File

@ -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