AMQP: Add field table values as fields

Add the name, type, and values of field tables and arrays as
fields under the FT_NONE header. This makes them filterable
and show up in JSON export.

Fix #18385
This commit is contained in:
John Thacker 2022-10-30 07:00:36 -04:00 committed by AndersBroman
parent cabe0e0239
commit 1293f15897
1 changed files with 152 additions and 98 deletions

View File

@ -1451,6 +1451,20 @@ static int hf_amqp_method_dtx_start_dtx_identifier = -1;
static int hf_amqp_method_tunnel_request_meta_data = -1;
static int hf_amqp_method_confirm_select_nowait = -1;
static int hf_amqp_field = -1;
static int hf_amqp_field_name = -1;
static int hf_amqp_field_type = -1;
static int hf_amqp_field_integer = -1;
static int hf_amqp_field_unsigned_integer = -1;
static int hf_amqp_field_string = -1;
static int hf_amqp_field_boolean = -1;
static int hf_amqp_field_byte = -1;
static int hf_amqp_field_unsigned_byte = -1;
static int hf_amqp_field_short_int = -1;
static int hf_amqp_field_short_uint = -1;
static int hf_amqp_field_long_int = -1;
static int hf_amqp_field_float = -1;
static int hf_amqp_field_double = -1;
static int hf_amqp_field_decimal = -1;
static int hf_amqp_field_timestamp = -1;
static int hf_amqp_field_byte_array = -1;
static int hf_amqp_header_class_id = -1;
@ -1525,6 +1539,7 @@ static gint ett_args = -1;
static gint ett_props = -1;
static gint ett_field_table = -1;
static gint ett_amqp_init = -1;
static gint ett_amqp_0_9_field = -1;
static gint ett_amqp_0_10_map = -1;
static gint ett_amqp_0_10_array = -1;
static gint ett_amqp_0_10_struct = -1;
@ -2381,25 +2396,30 @@ get_amqp_0_9_message_len(packet_info *pinfo _U_, tvbuff_t *tvb,
static void
dissect_amqp_0_9_field_table(tvbuff_t *tvb, packet_info *pinfo, int offset, guint length, proto_item *item)
{
proto_tree *field_table_tree;
proto_tree *field_table_tree, *field_item_tree;
proto_item *field_item;
guint namelen, vallen;
const char *name;
const guint8 *name;
int field_start;
field_table_tree = proto_item_add_subtree(item, ett_amqp);
while (length != 0) {
field_start = offset;
field_item = proto_tree_add_item(field_table_tree, hf_amqp_field, tvb,
offset, 1, ENC_NA);
namelen = tvb_get_guint8(tvb, offset);
offset += 1;
length -= 1;
if (length < namelen)
goto too_short;
name = (char*) tvb_get_string_enc(wmem_packet_scope(), tvb, offset, namelen, ENC_UTF_8|ENC_NA);
field_item_tree = proto_item_add_subtree(field_item, ett_amqp_0_9_field);
proto_tree_add_item_ret_string(field_item_tree, hf_amqp_field_name, tvb, offset, namelen, ENC_UTF_8, pinfo->pool, &name);
proto_item_set_text(field_item, "%s", name);
offset += namelen;
length -= namelen;
vallen = dissect_amqp_0_9_field_value(tvb, pinfo, offset, length, name, field_table_tree);
vallen = dissect_amqp_0_9_field_value(tvb, pinfo, offset, length, name, field_item_tree);
if(vallen == 0)
goto too_short;
offset += vallen;
@ -2417,7 +2437,8 @@ too_short:
static void
dissect_amqp_0_9_field_array(tvbuff_t *tvb, packet_info *pinfo, int offset, guint length, proto_item *item)
{
proto_tree *field_table_tree;
proto_tree *field_table_tree, *field_item_tree;
proto_item *field_item;
int field_start, idx;
guint vallen;
const char *name;
@ -2427,9 +2448,12 @@ dissect_amqp_0_9_field_array(tvbuff_t *tvb, packet_info *pinfo, int offset, guin
while (length != 0) {
field_start = offset;
name = wmem_strdup_printf(wmem_packet_scope(), "[%i]", idx);
field_item = proto_tree_add_none_format(field_table_tree, hf_amqp_field, tvb,
offset, 0, "[%i]", idx);
field_item_tree = proto_item_add_subtree(field_item, ett_amqp_0_9_field);
name = wmem_strdup_printf(pinfo->pool, "[%i]", idx);
vallen = dissect_amqp_0_9_field_value(tvb, pinfo, offset, length, name, field_table_tree);
vallen = dissect_amqp_0_9_field_value(tvb, pinfo, offset, length, name, field_item_tree);
if(vallen == 0)
goto too_short;
offset += vallen;
@ -2477,67 +2501,77 @@ too_short:
* who follows the 0-9-1 spec for this bit.
*/
static const value_string amqp_0_9_field_type_vals[] = {
{ 'A', "array" },
{ 'B', "unsigned byte" },
{ 'D', "decimal" },
{ 'F', "field table" },
{ 'I', "integer" },
{ 'S', "string" },
{ 'T', "timestamp" },
{ 'V', "void" },
{ 'b', "byte" },
{ 'd', "double" },
{ 'f', "float" },
{ 'i', "unsigned integer" },
{ 'l', "long int" },
{ 's', "short int" },
{ 't', "boolean" },
{ 'u', "short uint" },
{ 'x', "byte array" },
{ 0, NULL },
};
static guint
dissect_amqp_0_9_field_value(tvbuff_t *tvb, packet_info *pinfo, int offset, guint length,
const char *name, proto_tree *field_table_tree)
const char *name _U_, proto_tree *field_tree)
{
proto_item *ti;
proto_item *field_item, *type_item, *ti = NULL;
guint vallen;
guint8 type;
char type_buf[7] = { 0 };
const char *amqp_typename;
const char *value;
nstime_t tv;
int value_start;
value_start = offset;
if (length < 1)
return 0; /* too short */
type = tvb_get_guint8(tvb, offset);
amqp_typename = char_val_to_str(type, amqp_0_9_field_type_vals, "unknown type");
field_item = proto_tree_get_parent(field_tree);
proto_item_append_text(field_item, " (%s)", amqp_typename);
type_item = proto_tree_add_item(field_tree, hf_amqp_field_type, tvb, offset, 1, ENC_NA);
offset += 1;
length -= 1;
switch (type) {
case 'I': /* signed 32-bit */
amqp_typename = "integer";
if (length < 4)
return 0; /* too short */
value = wmem_strdup_printf(wmem_packet_scope(), "%" PRIi32,
tvb_get_ntohil(tvb, offset));
ti = proto_tree_add_item(field_tree, hf_amqp_field_integer, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
break;
case 'D':
amqp_typename = "decimal";
case 'D': /* 40-bit decimal floating point, biased towards small numbers */
{
if (length < 5)
return 0; /* too short */
value = wmem_strdup_printf(wmem_packet_scope(), "%f",
tvb_get_ntohl(tvb, offset+1) / pow(10, tvb_get_guint8(tvb, offset)));
double decimal = tvb_get_ntohl(tvb, offset + 1) / pow(10, tvb_get_guint8(tvb, offset));
ti = proto_tree_add_double(field_tree, hf_amqp_field_decimal, tvb, offset, 5, decimal);
offset += 5;
break;
}
case 'S': /* long string, UTF-8 encoded */
amqp_typename = "string";
if (length < 4)
return 0; /* too short */
vallen = tvb_get_ntohl(tvb, offset);
offset += 4;
length -= 4;
if (length < vallen)
return 0; /* too short */
value = (char*) tvb_get_string_enc(wmem_packet_scope(), tvb, offset, vallen, ENC_UTF_8|ENC_NA);
ti = proto_tree_add_item_ret_length(field_tree, hf_amqp_field_string, tvb, offset, 4, ENC_BIG_ENDIAN|ENC_UTF_8, &vallen);
offset += vallen;
break;
case 'T': /* timestamp (u64) */
if (length < 8)
return 0; /* too short */
tv.secs = (time_t)tvb_get_ntoh64(tvb, offset);
tv.nsecs = 0;
ti = proto_tree_add_item(field_tree, hf_amqp_field_timestamp, tvb,
offset, 8, ENC_TIME_SECS|ENC_BIG_ENDIAN);
offset += 8;
ti = proto_tree_add_time(field_table_tree, hf_amqp_field_timestamp, tvb,
value_start, offset - value_start, &tv);
proto_item_prepend_text(ti, "%s ", name);
return offset - value_start;
break;
case 'F': /* nested table */
amqp_typename = "field table";
if (length < 4)
return 0; /* too short */
vallen = tvb_get_ntohl(tvb, offset);
@ -2545,90 +2579,67 @@ dissect_amqp_0_9_field_value(tvbuff_t *tvb, packet_info *pinfo, int offset, guin
length -= 4;
if (length < vallen)
return 0; /* too short */
ti = proto_tree_add_item(field_table_tree, hf_amqp_field, tvb,
value_start, offset+vallen - value_start, ENC_NA);
proto_item_set_text(ti, "%s (%s)", name, amqp_typename);
dissect_amqp_0_9_field_table(tvb, pinfo, offset, vallen, ti);
dissect_amqp_0_9_field_table(tvb, pinfo, offset, vallen, field_tree);
offset += vallen;
return offset - value_start;
break;
case 'V':
amqp_typename = "void";
value = "";
break;
/* AMQP 0-9-1 types */
case 't': /* boolean */
amqp_typename = "boolean";
if (length < 1)
return 0; /* too short */
value = tvb_get_guint8(tvb, offset) ? "true" : "false";
ti = proto_tree_add_item(field_tree, hf_amqp_field_boolean, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 'b': /* signed 8-bit */
amqp_typename = "byte";
if (length < 1)
return 0; /* too short */
value = wmem_strdup_printf(wmem_packet_scope(), "%d",
tvb_get_gint8(tvb, offset));
ti = proto_tree_add_item(field_tree, hf_amqp_field_byte, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 'B': /* unsigned 8-bit */
amqp_typename = "unsigned byte";
if (length < 1)
return 0; /* too short */
value = wmem_strdup_printf(wmem_packet_scope(), "%u",
tvb_get_guint8(tvb, offset));
ti = proto_tree_add_item(field_tree, hf_amqp_field_unsigned_byte, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 's': /* signed 16-bit */
amqp_typename = "short int";
if (length < 2)
return 0; /* too short */
value = wmem_strdup_printf(wmem_packet_scope(), "%" PRIi16,
tvb_get_ntohis(tvb, offset));
ti = proto_tree_add_item(field_tree, hf_amqp_field_short_int, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
break;
case 'u': /* unsigned 16-bit */
amqp_typename = "short uint";
if (length < 2)
return 0; /* too short */
value = wmem_strdup_printf(wmem_packet_scope(), "%" PRIu16,
tvb_get_ntohs(tvb, offset));
ti = proto_tree_add_item(field_tree, hf_amqp_field_short_uint, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
break;
case 'i': /* unsigned 32-bit */
amqp_typename = "unsigned integer";
if (length < 4)
return 0; /* too short */
value = wmem_strdup_printf(wmem_packet_scope(), "%" PRIu32,
tvb_get_ntohl(tvb, offset));
ti = proto_tree_add_item(field_tree, hf_amqp_field_unsigned_integer, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
break;
case 'l': /* signed 64-bit */
amqp_typename = "long int";
if (length < 8)
return 0; /* too short */
value = wmem_strdup_printf(wmem_packet_scope(), "%" PRIi64,
tvb_get_ntohi64(tvb, offset));
ti = proto_tree_add_item(field_tree, hf_amqp_field_long_int, tvb, offset, 8, ENC_BIG_ENDIAN);
offset += 8;
break;
case 'f': /* 32-bit float */
amqp_typename = "float";
if (length < 4)
return 0; /* too short */
value = wmem_strdup_printf(wmem_packet_scope(), "%f",
tvb_get_ntohieee_float(tvb, offset));
ti = proto_tree_add_item(field_tree, hf_amqp_field_float, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
break;
case 'd': /* 64-bit float */
amqp_typename = "double";
if (length < 8)
return 0; /* too short */
value = wmem_strdup_printf(wmem_packet_scope(), "%f",
tvb_get_ntohieee_double(tvb, offset));
ti = proto_tree_add_item(field_tree, hf_amqp_field_double, tvb, offset, 8, ENC_BIG_ENDIAN);
offset += 8;
break;
case 'A': /* array */
amqp_typename = "array";
if (length < 4)
return 0; /* too short */
vallen = tvb_get_ntohl(tvb, offset);
@ -2636,41 +2647,27 @@ dissect_amqp_0_9_field_value(tvbuff_t *tvb, packet_info *pinfo, int offset, guin
length -= 4;
if (length < vallen)
return 0; /* too short */
ti = proto_tree_add_item(field_table_tree, hf_amqp_field, tvb,
value_start, offset+vallen - value_start, ENC_NA);
proto_item_set_text(ti, "%s (%s)", name, amqp_typename);
dissect_amqp_0_9_field_array(tvb, pinfo, offset, vallen, ti);
offset += vallen;
return offset - value_start;
break;
case 'x': /* byte array */
if (length < 4)
return 0; /* too short */
vallen = tvb_get_ntohl(tvb, offset);
offset += 4;
length -= 4;
if (length < vallen)
return 0; /* too short */
ti = proto_tree_add_item(field_table_tree, hf_amqp_field_byte_array, tvb,
offset, vallen, ENC_NA);
proto_item_prepend_text(ti, "%s ", name);
ti = proto_tree_add_item_ret_length(field_tree, hf_amqp_field_byte_array, tvb,
offset, 4, ENC_NA, &vallen);
offset += vallen;
return offset - value_start;
default:
amqp_typename = "";
value = NULL;
break;
default:
expert_add_info(pinfo, type_item, &ei_amqp_array_type_unknown);
/* Without knowing the type, we don't know how much to increment
* the offset, so break out. */
return 0;
}
if (value != NULL)
proto_tree_add_none_format(field_table_tree, hf_amqp_field, tvb,
value_start, offset - value_start,
"%s (%s): %s", name, amqp_typename, value);
else
proto_tree_add_none_format(field_table_tree, hf_amqp_field, tvb,
value_start, offset - value_start,
"%s: unknown type %s",
name,
hfinfo_char_value_format_display(BASE_HEX, type_buf, type));
proto_item_set_end(field_item, tvb, offset);
if (ti != NULL) {
proto_item_append_text(field_item, ": %s", proto_item_get_display_repr(pinfo->pool, ti));
}
return offset - value_start;
}
@ -13270,16 +13267,72 @@ proto_register_amqp(void)
FT_BOOLEAN, 8, NULL, 0x01,
NULL, HFILL}},
{&hf_amqp_field, {
"AMQP", "amqp.field",
"Field", "amqp.field",
FT_NONE, BASE_NONE, NULL, 0,
NULL, HFILL}},
{&hf_amqp_field_name, {
"Name", "amqp.field.name",
FT_STRING, BASE_NONE, NULL, 0,
NULL, HFILL}},
{&hf_amqp_field_type, {
"Type", "amqp.field.type",
FT_CHAR, BASE_HEX, VALS(amqp_0_9_field_type_vals), 0,
NULL, HFILL}},
{&hf_amqp_field_integer, {
"Value", "amqp.field.integer",
FT_INT32, BASE_DEC, NULL, 0,
NULL, HFILL}},
{&hf_amqp_field_unsigned_integer, {
"Value", "amqp.field.unsigned_integer",
FT_UINT32, BASE_DEC, NULL, 0,
NULL, HFILL}},
{&hf_amqp_field_string, {
"Value", "amqp.field.string",
FT_UINT_STRING, BASE_NONE, NULL, 0,
NULL, HFILL}},
{&hf_amqp_field_boolean, {
"Value", "amqp.field.boolean",
FT_BOOLEAN, BASE_NONE, NULL, 0,
NULL, HFILL}},
{&hf_amqp_field_byte, {
"Value", "amqp.field.byte",
FT_INT8, BASE_DEC, NULL, 0,
NULL, HFILL}},
{&hf_amqp_field_unsigned_byte, {
"Value", "amqp.field.unsigned_byte",
FT_UINT8, BASE_DEC, NULL, 0,
NULL, HFILL}},
{&hf_amqp_field_short_int, {
"Value", "amqp.field.short_int",
FT_INT16, BASE_DEC, NULL, 0,
NULL, HFILL}},
{&hf_amqp_field_short_uint, {
"Value", "amqp.field.short_uint",
FT_UINT16, BASE_DEC, NULL, 0,
NULL, HFILL}},
{&hf_amqp_field_long_int, {
"Value", "amqp.field.long_int",
FT_INT64, BASE_DEC, NULL, 0,
NULL, HFILL}},
{&hf_amqp_field_float, {
"Value", "amqp.field.float",
FT_FLOAT, BASE_NONE, NULL, 0,
NULL, HFILL}},
{&hf_amqp_field_double, {
"Value", "amqp.field.double",
FT_DOUBLE, BASE_NONE, NULL, 0,
NULL, HFILL}},
{&hf_amqp_field_decimal, {
"Value", "amqp.field.decimal",
FT_DOUBLE, BASE_NONE, NULL, 0,
NULL, HFILL}},
{&hf_amqp_field_timestamp, {
"(timestamp)", "amqp.field.timestamp",
"Value", "amqp.field.timestamp",
FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0x0,
NULL, HFILL}},
{&hf_amqp_field_byte_array, {
"(byte array)", "amqp.field.byte_array",
FT_BYTES, BASE_NONE, NULL, 0,
"Value", "amqp.field.byte_array",
FT_UINT_BYTES, BASE_NONE, NULL, 0,
NULL, HFILL}},
{&hf_amqp_header_class_id, {
"Class ID", "amqp.header.class",
@ -13552,6 +13605,7 @@ proto_register_amqp(void)
&ett_props,
&ett_field_table,
&ett_amqp_init,
&ett_amqp_0_9_field,
&ett_amqp_0_10_map,
&ett_amqp_0_10_array,
&ett_amqp_0_10_struct,