pcapng (dissector): don't assume the endianness doesn't change.

Keep the endianness (as an ENC_ value) in the info structure we use
while dissecting.

When dissecting an SPB, peek ahead at the byte-order magic before
dissecting the block length, to determine the byte order of all fields
in that block *and* all other blocks in that section.  Report an error
and stop dissecting if the byte-order magic isn't valid.

Change-Id: I6d94d4fad10d60f327f4a486e180cdcee2f6be2d
Reviewed-on: https://code.wireshark.org/review/37138
Petri-Dish: Guy Harris <gharris@sonic.net>
Tested-by: Petri Dish Buildbot
Reviewed-by: Guy Harris <gharris@sonic.net>
This commit is contained in:
Guy Harris 2020-05-04 18:03:26 -07:00 committed by Guy Harris
parent 432cb20707
commit b99a0c95d8
1 changed files with 424 additions and 370 deletions

View File

@ -135,6 +135,7 @@ static int hf_pcapng_option_data_packet_darwin_dpeb_id = -1;
static int hf_pcapng_option_data_packet_darwin_svc_class = -1;
static int hf_pcapng_option_data_packet_darwin_edpeb_id = -1;
static expert_field ei_invalid_byte_order_magic = EI_INIT;
static expert_field ei_block_length_too_short = EI_INIT;
static expert_field ei_block_length_not_multiple_of_4 = EI_INIT;
static expert_field ei_invalid_option_length = EI_INIT;
@ -188,6 +189,7 @@ struct info {
guint32 interface_number;
guint32 darwin_process_event_number;
guint32 frame_number;
guint encoding;
wmem_array_t *interfaces;
wmem_array_t *darwin_process_events;
};
@ -551,6 +553,15 @@ static const value_string dsb_secrets_types_vals[] = {
void proto_register_pcapng(void);
void proto_reg_handoff_pcapng(void);
#define BYTE_ORDER_MAGIC_SIZE 4
static const guint8 pcapng_big_endian_magic[BYTE_ORDER_MAGIC_SIZE] = {
0x1A, 0x2B, 0x3C, 0x4D
};
static const guint8 pcapng_little_endian_magic[BYTE_ORDER_MAGIC_SIZE] = {
0x4D, 0x3C, 0x2B, 0x1A
};
static gint dissect_options(proto_tree *tree, packet_info *pinfo,
guint32 block_type, tvbuff_t *tvb, guint encoding, void *user_data)
{
@ -1266,14 +1277,52 @@ get_interface_description(struct info *info, guint interface_id,
return (struct interface_description *) wmem_array_index(info->interfaces, interface_id);
}
/*
* This is tricky - for most blocks, we can dissect this first, but, for
* a Section Header Block, we must dissect it *after* determining the
* byte order.
*
* So we extract it into a routine and call it at the appropriate time.
*/
static proto_tree *
dissect_block_length(proto_tree *block_tree, packet_info *pinfo,
tvbuff_t *tvb, int offset, guint32 *block_data_length_p,
guint encoding)
{
proto_item *block_length_item;
proto_item *block_data_item;
block_length_item = proto_tree_add_item_ret_uint(block_tree, hf_pcapng_block_length, tvb, offset, 4, encoding, block_data_length_p);
if (*block_data_length_p < 3*4)
expert_add_info(pinfo, block_length_item, &ei_block_length_too_short);
/*
* To quote the current pcapng spec, "Block Total Length (32 bits) ...
* This value MUST be a multiple of 4."
*/
if ((*block_data_length_p % 4) != 0)
expert_add_info(pinfo, block_length_item, &ei_block_length_not_multiple_of_4);
/*
* Subtract the per-block overhead (block type, block length, trailing
* block length).
*/
*block_data_length_p -= 3*4;
/*
* Now that we know the block data length, create an item for its
* tree.
*/
offset += 4;
block_data_item = proto_tree_add_item(block_tree, hf_pcapng_block_data, tvb, offset, *block_data_length_p, ENC_NA);
return proto_item_add_subtree(block_data_item, ett_pcapng_block_data);
}
static gint dissect_block(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb,
guint encoding, struct info *info)
struct info *info)
{
proto_tree *block_tree;
proto_item *block_item;
proto_item *block_length_item;
proto_tree *block_data_tree;
proto_item *block_data_item;
proto_item *byte_order_magic_item;
proto_item *packet_data_item;
gint offset = 0;
@ -1285,38 +1334,20 @@ static gint dissect_block(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb,
guint32 interface_id;
tvbuff_t *next_tvb;
block_type = tvb_get_guint32(tvb, offset + 0, encoding);
length = tvb_get_guint32(tvb, offset + 4, encoding);
block_type = tvb_get_guint32(tvb, offset + 0, info->encoding);
length = tvb_get_guint32(tvb, offset + 4, info->encoding);
block_item = proto_tree_add_item(tree, hf_pcapng_block, tvb, offset, length, ENC_NA);
block_tree = proto_item_add_subtree(block_item, ett_pcapng_section_header_block);
proto_item_append_text(block_item, ": %s", val_to_str_const(block_type, block_type_vals, "Unknown"));
proto_tree_add_bitmask_with_flags(block_tree, tvb, offset, hf_pcapng_block_type, ett_pcapng_option, hfx_pcapng_block_type, encoding, BMT_NO_APPEND);
proto_tree_add_bitmask_with_flags(block_tree, tvb, offset, hf_pcapng_block_type, ett_pcapng_option, hfx_pcapng_block_type, info->encoding, BMT_NO_APPEND);
offset += 4;
block_length_item = proto_tree_add_item_ret_uint(block_tree, hf_pcapng_block_length, tvb, offset, 4, encoding, &block_data_length);
if (block_data_length < 3*4)
expert_add_info(pinfo, block_length_item, &ei_block_length_too_short);
/*
* To quote the current pcapng spec, "Block Total Length (32 bits) ...
* This value MUST be a multiple of 4."
*/
if ((block_data_length % 4) != 0)
expert_add_info(pinfo, block_length_item, &ei_block_length_not_multiple_of_4);
if (block_type == BLOCK_SECTION_HEADER) {
/* Section Header Block - this needs special byte-order handling */
gboolean byte_order_magic_bad = FALSE;
/*
* Subtract the per-block overhead (block type, block length, trailing
* block length).
*/
block_data_length -= 3*4;
offset += 4;
block_data_item = proto_tree_add_item(block_tree, hf_pcapng_block_data, tvb, offset, block_data_length, ENC_NA);
block_data_tree = proto_item_add_subtree(block_data_item, ett_pcapng_block_data);
switch (block_type) {
case BLOCK_SECTION_HEADER: /* Section Header Block */
proto_item_append_text(block_item, " %u", info->section_number);
info->section_number += 1;
info->interface_number = 0;
@ -1327,385 +1358,406 @@ static gint dissect_block(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb,
}
info->interfaces = wmem_array_new(wmem_packet_scope(), sizeof(struct interface_description));
if (tvb_memeql(tvb, 8, pcapng_big_endian_magic, BYTE_ORDER_MAGIC_SIZE) == 0) {
info->encoding = ENC_BIG_ENDIAN;
} else if (tvb_memeql(tvb, 8, pcapng_little_endian_magic, BYTE_ORDER_MAGIC_SIZE) == 0) {
info->encoding = ENC_LITTLE_ENDIAN;
} else {
byte_order_magic_bad = TRUE;
}
block_data_tree = dissect_block_length(block_tree, pinfo, tvb, offset, &block_data_length, info->encoding);
offset += 4;
byte_order_magic_item = proto_tree_add_item(block_data_tree, hf_pcapng_section_header_byte_order_magic, tvb, offset, 4, ENC_NA);
if (encoding == ENC_BIG_ENDIAN)
if (byte_order_magic_bad) {
expert_add_info(pinfo, byte_order_magic_item, &ei_invalid_byte_order_magic);
return -1;
}
if (info->encoding == ENC_BIG_ENDIAN)
proto_item_append_text(byte_order_magic_item, " (Big-endian)");
else
proto_item_append_text(byte_order_magic_item, " (Little-endian)");
offset += 4;
proto_tree_add_item(block_data_tree, hf_pcapng_section_header_major_version, tvb, offset, 2, encoding);
proto_tree_add_item(block_data_tree, hf_pcapng_section_header_major_version, tvb, offset, 2, info->encoding);
offset += 2;
proto_tree_add_item(block_data_tree, hf_pcapng_section_header_minor_version, tvb, offset, 2, encoding);
proto_tree_add_item(block_data_tree, hf_pcapng_section_header_minor_version, tvb, offset, 2, info->encoding);
offset += 2;
proto_tree_add_item(block_data_tree, hf_pcapng_section_header_section_length, tvb, offset, 8, encoding);
proto_tree_add_item(block_data_tree, hf_pcapng_section_header_section_length, tvb, offset, 8, info->encoding);
offset += 8;
next_tvb = tvb_new_subset_length(tvb, offset, block_data_length - 4 - 2 - 2 - 8);
offset += dissect_options(block_data_tree, pinfo, block_type, next_tvb, encoding, NULL);
break;
case BLOCK_INTERFACE_DESCRIPTION: {
struct interface_description interface_description;
memset(&interface_description, 0, sizeof(struct interface_description));
interface_description.timestamp_resolution = 1000000; /* 1 microsecond resolution is the default */
proto_item_append_text(block_item, " %u", info->interface_number);
info->interface_number += 1;
proto_tree_add_item(block_data_tree, hf_pcapng_interface_description_link_type, tvb, offset, 2, encoding);
interface_description.link_type = tvb_get_guint16(tvb, offset, encoding);
offset += 2;
proto_tree_add_item(block_data_tree, hf_pcapng_interface_description_reserved, tvb, offset, 2, encoding);
offset += 2;
proto_tree_add_item(block_data_tree, hf_pcapng_interface_description_snap_length, tvb, offset, 4, encoding);
interface_description.snap_len = tvb_get_guint32(tvb, offset, encoding);
offset += dissect_options(block_data_tree, pinfo, block_type, next_tvb, info->encoding, NULL);
} else {
/*
* Not an SHB, so we know the byte order.
*/
block_data_tree = dissect_block_length(block_tree, pinfo, tvb, offset, &block_data_length, info->encoding);
offset += 4;
next_tvb = tvb_new_subset_length(tvb, offset, block_data_length - 2 - 2 - 4);
offset += dissect_options(block_data_tree, pinfo, block_type, next_tvb, encoding, &interface_description);
switch (block_type) {
case BLOCK_INTERFACE_DESCRIPTION: {
struct interface_description interface_description;
wmem_array_append_one(info->interfaces, interface_description);
}
break;
case BLOCK_PACKET: {
struct interface_description *interface_description;
memset(&interface_description, 0, sizeof(struct interface_description));
interface_description.timestamp_resolution = 1000000; /* 1 microsecond resolution is the default */
proto_item_append_text(block_item, " %u", info->frame_number);
proto_item_append_text(block_item, " %u", info->interface_number);
info->interface_number += 1;
proto_tree_add_item(block_data_tree, hf_pcapng_packet_block_interface_id, tvb, offset, 2, encoding);
interface_id = tvb_get_guint16(tvb, offset, encoding);
offset += 2;
interface_description = get_interface_description(info, interface_id,
pinfo, block_tree);
proto_tree_add_item(block_data_tree, hf_pcapng_packet_block_drops_count, tvb, offset, 2, encoding);
offset += 2;
pcapng_add_timestamp(block_data_tree, pinfo, tvb, offset, encoding, interface_description);
offset += 8;
proto_tree_add_item_ret_uint(block_data_tree, hf_pcapng_captured_length, tvb, offset, 4, encoding, &captured_length);
offset += 4;
proto_tree_add_item_ret_uint(block_data_tree, hf_pcapng_packet_length, tvb, offset, 4, encoding, &reported_length);
offset += 4;
packet_data_item = proto_tree_add_item(block_data_tree, hf_pcapng_packet_data, tvb, offset, captured_length, encoding);
if (pref_dissect_next_layer && interface_description != NULL) {
proto_tree *packet_data_tree = proto_item_add_subtree(packet_data_item, ett_pcapng_packet_data);
pinfo->num = info->frame_number;
TRY {
call_dissector_with_data(pcap_pktdata_handle, tvb_new_subset_length_caplen(tvb, offset, captured_length, reported_length),
pinfo, packet_data_tree, &interface_description->link_type);
}
CATCH_BOUNDS_ERRORS {
show_exception(tvb, pinfo, packet_data_tree, EXCEPT_CODE, GET_MESSAGE);
}
ENDTRY;
}
info->frame_number += 1;
offset += captured_length;
if (captured_length % 4) {
proto_tree_add_item(block_data_tree, hf_pcapng_packet_padding, tvb, offset, ((captured_length % 4) ? (4 - (captured_length % 4)) : 0), ENC_NA);
offset += ((captured_length % 4) ?(4 - (captured_length % 4)):0);
}
next_tvb = tvb_new_subset_length(tvb, offset, block_data_length - 2 - 2 - 8 - 4 - 4 - captured_length - ((captured_length % 4)?(4 - (captured_length % 4)):0));
offset += dissect_options(block_data_tree, pinfo, block_type, next_tvb, encoding, NULL);
}
break;
case BLOCK_SIMPLE_PACKET: {
struct interface_description *interface_description;
proto_item *ti;
interface_description = get_interface_description(info, 0,
pinfo, block_tree);
proto_item_append_text(block_item, " %u", info->frame_number);
proto_tree_add_item_ret_uint(block_data_tree, hf_pcapng_packet_length, tvb, offset, 4, encoding, &reported_length);
offset += 4;
captured_length = reported_length;
if (interface_description && interface_description->snap_len != 0) {
captured_length = MIN(reported_length, interface_description->snap_len);
}
ti = proto_tree_add_uint(block_data_tree, hf_pcapng_captured_length, tvb, 0, 0, captured_length);
proto_item_set_generated(ti);
packet_data_item = proto_tree_add_item(block_data_tree, hf_pcapng_packet_data, tvb, offset, captured_length, encoding);
if (pref_dissect_next_layer && interface_description != NULL) {
proto_tree *packet_data_tree = proto_item_add_subtree(packet_data_item, ett_pcapng_packet_data);
pinfo->num = info->frame_number;
TRY {
call_dissector_with_data(pcap_pktdata_handle, tvb_new_subset_length(tvb, offset, captured_length),
pinfo, packet_data_tree, &interface_description->link_type);
}
CATCH_BOUNDS_ERRORS {
show_exception(tvb, pinfo, packet_data_tree, EXCEPT_CODE, GET_MESSAGE);
}
ENDTRY;
}
info->frame_number += 1;
offset += captured_length;
if (captured_length % 4) {
proto_tree_add_item(block_data_tree, hf_pcapng_packet_padding, tvb, offset, ((captured_length % 4)?(4 - (captured_length % 4)):0), ENC_NA);
offset += ((captured_length % 4) ? (4 - (captured_length % 4)):0);
}
}
break;
case BLOCK_NAME_RESOLUTION:
{
proto_tree *records_tree;
proto_item *records_item;
proto_tree *record_tree;
proto_item *record_item;
proto_item *record_length_item;
gint offset_record_start;
gint offset_string_start;
guint32 record_code;
guint32 record_length;
gint string_length;
gchar *str = NULL;
address addr;
records_item = proto_tree_add_item(block_data_tree, hf_pcapng_records, tvb, offset, block_data_length, ENC_NA);
records_tree = proto_item_add_subtree(records_item, ett_pcapng_records);
offset_record_start = offset;
while (block_data_length - (offset_record_start - offset) > 0) {
record_item = proto_tree_add_item(records_tree, hf_pcapng_record, tvb, offset, -1, ENC_NA);
record_tree = proto_item_add_subtree(record_item, ett_pcapng_record);
proto_tree_add_item_ret_uint(record_tree, hf_pcapng_record_code, tvb, offset, 2, encoding, &record_code);
proto_item_append_text(record_item, ": %s", val_to_str_const(record_code, record_code_vals, "Unknown"));
proto_tree_add_item(block_data_tree, hf_pcapng_interface_description_link_type, tvb, offset, 2, info->encoding);
interface_description.link_type = tvb_get_guint16(tvb, offset, info->encoding);
offset += 2;
record_length_item = proto_tree_add_item_ret_uint(record_tree, hf_pcapng_record_length, tvb, offset, 2, encoding, &record_length);
proto_tree_add_item(block_data_tree, hf_pcapng_interface_description_reserved, tvb, offset, 2, info->encoding);
offset += 2;
if (record_code == 0) {
if (record_length != 0)
expert_add_info(pinfo, record_length_item, &ei_invalid_record_length);
proto_item_set_len(record_item, record_length + 2 * 2);
break;
} else switch (record_code) {
case 0x0001: /* IPv4 Record */
if (record_length < 5) {
expert_add_info(pinfo, record_length_item, &ei_invalid_record_length);
offset += record_length;
proto_tree_add_item(block_data_tree, hf_pcapng_interface_description_snap_length, tvb, offset, 4, info->encoding);
interface_description.snap_len = tvb_get_guint32(tvb, offset, info->encoding);
offset += 4;
next_tvb = tvb_new_subset_length(tvb, offset, block_data_length - 2 - 2 - 4);
offset += dissect_options(block_data_tree, pinfo, block_type, next_tvb, info->encoding, &interface_description);
wmem_array_append_one(info->interfaces, interface_description);
}
break;
case BLOCK_PACKET: {
struct interface_description *interface_description;
proto_item_append_text(block_item, " %u", info->frame_number);
proto_tree_add_item(block_data_tree, hf_pcapng_packet_block_interface_id, tvb, offset, 2, info->encoding);
interface_id = tvb_get_guint16(tvb, offset, info->encoding);
offset += 2;
interface_description = get_interface_description(info, interface_id,
pinfo, block_tree);
proto_tree_add_item(block_data_tree, hf_pcapng_packet_block_drops_count, tvb, offset, 2, info->encoding);
offset += 2;
pcapng_add_timestamp(block_data_tree, pinfo, tvb, offset, info->encoding, interface_description);
offset += 8;
proto_tree_add_item_ret_uint(block_data_tree, hf_pcapng_captured_length, tvb, offset, 4, info->encoding, &captured_length);
offset += 4;
proto_tree_add_item_ret_uint(block_data_tree, hf_pcapng_packet_length, tvb, offset, 4, info->encoding, &reported_length);
offset += 4;
packet_data_item = proto_tree_add_item(block_data_tree, hf_pcapng_packet_data, tvb, offset, captured_length, info->encoding);
if (pref_dissect_next_layer && interface_description != NULL) {
proto_tree *packet_data_tree = proto_item_add_subtree(packet_data_item, ett_pcapng_packet_data);
pinfo->num = info->frame_number;
TRY {
call_dissector_with_data(pcap_pktdata_handle, tvb_new_subset_length_caplen(tvb, offset, captured_length, reported_length),
pinfo, packet_data_tree, &interface_description->link_type);
}
CATCH_BOUNDS_ERRORS {
show_exception(tvb, pinfo, packet_data_tree, EXCEPT_CODE, GET_MESSAGE);
}
ENDTRY;
}
info->frame_number += 1;
offset += captured_length;
if (captured_length % 4) {
proto_tree_add_item(block_data_tree, hf_pcapng_packet_padding, tvb, offset, ((captured_length % 4) ? (4 - (captured_length % 4)) : 0), ENC_NA);
offset += ((captured_length % 4) ?(4 - (captured_length % 4)):0);
}
next_tvb = tvb_new_subset_length(tvb, offset, block_data_length - 2 - 2 - 8 - 4 - 4 - captured_length - ((captured_length % 4)?(4 - (captured_length % 4)):0));
offset += dissect_options(block_data_tree, pinfo, block_type, next_tvb, info->encoding, NULL);
}
break;
case BLOCK_SIMPLE_PACKET: {
struct interface_description *interface_description;
proto_item *ti;
interface_description = get_interface_description(info, 0,
pinfo, block_tree);
proto_item_append_text(block_item, " %u", info->frame_number);
proto_tree_add_item_ret_uint(block_data_tree, hf_pcapng_packet_length, tvb, offset, 4, info->encoding, &reported_length);
offset += 4;
captured_length = reported_length;
if (interface_description && interface_description->snap_len != 0) {
captured_length = MIN(reported_length, interface_description->snap_len);
}
ti = proto_tree_add_uint(block_data_tree, hf_pcapng_captured_length, tvb, 0, 0, captured_length);
proto_item_set_generated(ti);
packet_data_item = proto_tree_add_item(block_data_tree, hf_pcapng_packet_data, tvb, offset, captured_length, info->encoding);
if (pref_dissect_next_layer && interface_description != NULL) {
proto_tree *packet_data_tree = proto_item_add_subtree(packet_data_item, ett_pcapng_packet_data);
pinfo->num = info->frame_number;
TRY {
call_dissector_with_data(pcap_pktdata_handle, tvb_new_subset_length(tvb, offset, captured_length),
pinfo, packet_data_tree, &interface_description->link_type);
}
CATCH_BOUNDS_ERRORS {
show_exception(tvb, pinfo, packet_data_tree, EXCEPT_CODE, GET_MESSAGE);
}
ENDTRY;
}
info->frame_number += 1;
offset += captured_length;
if (captured_length % 4) {
proto_tree_add_item(block_data_tree, hf_pcapng_packet_padding, tvb, offset, ((captured_length % 4)?(4 - (captured_length % 4)):0), ENC_NA);
offset += ((captured_length % 4) ? (4 - (captured_length % 4)):0);
}
}
break;
case BLOCK_NAME_RESOLUTION:
{
proto_tree *records_tree;
proto_item *records_item;
proto_tree *record_tree;
proto_item *record_item;
proto_item *record_length_item;
gint offset_record_start;
gint offset_string_start;
guint32 record_code;
guint32 record_length;
gint string_length;
gchar *str = NULL;
address addr;
records_item = proto_tree_add_item(block_data_tree, hf_pcapng_records, tvb, offset, block_data_length, ENC_NA);
records_tree = proto_item_add_subtree(records_item, ett_pcapng_records);
offset_record_start = offset;
while (block_data_length - (offset_record_start - offset) > 0) {
record_item = proto_tree_add_item(records_tree, hf_pcapng_record, tvb, offset, -1, ENC_NA);
record_tree = proto_item_add_subtree(record_item, ett_pcapng_record);
proto_tree_add_item_ret_uint(record_tree, hf_pcapng_record_code, tvb, offset, 2, info->encoding, &record_code);
proto_item_append_text(record_item, ": %s", val_to_str_const(record_code, record_code_vals, "Unknown"));
offset += 2;
record_length_item = proto_tree_add_item_ret_uint(record_tree, hf_pcapng_record_length, tvb, offset, 2, info->encoding, &record_length);
offset += 2;
if (record_code == 0) {
if (record_length != 0)
expert_add_info(pinfo, record_length_item, &ei_invalid_record_length);
proto_item_set_len(record_item, record_length + 2 * 2);
break;
}
proto_tree_add_item(record_tree, hf_pcapng_record_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
set_address_tvb(&addr, AT_IPv4, 4, tvb, offset);
offset += 4;
offset_string_start = offset;
while ((guint)(offset - offset_string_start) < record_length - 4) {
string_length = tvb_strnlen(tvb, offset, (offset - offset_string_start) + record_length - 4);
if (string_length >= 0) {
proto_tree_add_item(record_tree, hf_pcapng_record_name, tvb, offset, string_length + 1, encoding);
offset += string_length + 1;
} else {
/*
* XXX - flag with an error, as this means we didn't
* see a terminating NUL, but the spec says "zero
* or more zero-terminated UTF-8 strings containing
* the DNS entries for that address".
*/
proto_tree_add_item(record_tree, hf_pcapng_record_data, tvb, offset, (record_length - 4) - (offset - offset_string_start), encoding);
offset += (record_length - 4) - (offset - offset_string_start);
} else switch (record_code) {
case 0x0001: /* IPv4 Record */
if (record_length < 5) {
expert_add_info(pinfo, record_length_item, &ei_invalid_record_length);
offset += record_length;
break;
}
}
str = address_to_display(wmem_packet_scope(), &addr);
break;
case 0x0002: /* IPv6 Record */
if (record_length < 17) {
expert_add_info(pinfo, record_length_item, &ei_invalid_record_length);
offset += record_length;
proto_tree_add_item(record_tree, hf_pcapng_record_ipv4, tvb, offset, 4, ENC_BIG_ENDIAN);
set_address_tvb(&addr, AT_IPv4, 4, tvb, offset);
offset += 4;
offset_string_start = offset;
while ((guint)(offset - offset_string_start) < record_length - 4) {
string_length = tvb_strnlen(tvb, offset, (offset - offset_string_start) + record_length - 4);
if (string_length >= 0) {
proto_tree_add_item(record_tree, hf_pcapng_record_name, tvb, offset, string_length + 1, info->encoding);
offset += string_length + 1;
} else {
/*
* XXX - flag with an error, as this means we didn't
* see a terminating NUL, but the spec says "zero
* or more zero-terminated UTF-8 strings containing
* the DNS entries for that address".
*/
proto_tree_add_item(record_tree, hf_pcapng_record_data, tvb, offset, (record_length - 4) - (offset - offset_string_start), info->encoding);
offset += (record_length - 4) - (offset - offset_string_start);
}
}
str = address_to_display(wmem_packet_scope(), &addr);
break;
}
proto_tree_add_item(record_tree, hf_pcapng_record_ipv6, tvb, offset, 16, ENC_NA);
set_address_tvb(&addr, AT_IPv6, 16, tvb, offset);
offset += 16;
offset_string_start = offset;
while ((guint)(offset - offset_string_start) < record_length - 16) {
string_length = tvb_strnlen(tvb, offset, (offset - offset_string_start) + record_length - 16);
if (string_length >= 0) {
proto_tree_add_item(record_tree, hf_pcapng_record_name, tvb, offset, string_length + 1, encoding);
offset += string_length + 1;
} else {
/*
* XXX - flag with an error, as this means we didn't
* see a terminating NUL, but the spec says "zero
* or more zero-terminated UTF-8 strings containing
* the DNS entries for that address".
*/
proto_tree_add_item(record_tree, hf_pcapng_record_data, tvb, offset, (record_length - 16) - (offset - offset_string_start), encoding);
offset += (record_length - 16) - (offset - offset_string_start);
case 0x0002: /* IPv6 Record */
if (record_length < 17) {
expert_add_info(pinfo, record_length_item, &ei_invalid_record_length);
offset += record_length;
break;
}
proto_tree_add_item(record_tree, hf_pcapng_record_ipv6, tvb, offset, 16, ENC_NA);
set_address_tvb(&addr, AT_IPv6, 16, tvb, offset);
offset += 16;
offset_string_start = offset;
while ((guint)(offset - offset_string_start) < record_length - 16) {
string_length = tvb_strnlen(tvb, offset, (offset - offset_string_start) + record_length - 16);
if (string_length >= 0) {
proto_tree_add_item(record_tree, hf_pcapng_record_name, tvb, offset, string_length + 1, info->encoding);
offset += string_length + 1;
} else {
/*
* XXX - flag with an error, as this means we didn't
* see a terminating NUL, but the spec says "zero
* or more zero-terminated UTF-8 strings containing
* the DNS entries for that address".
*/
proto_tree_add_item(record_tree, hf_pcapng_record_data, tvb, offset, (record_length - 16) - (offset - offset_string_start), info->encoding);
offset += (record_length - 16) - (offset - offset_string_start);
}
}
str = address_to_display(wmem_packet_scope(), &addr);
break;
default:
proto_tree_add_item(record_tree, hf_pcapng_record_data, tvb, offset, record_length, ENC_NA);
offset += record_length;
}
str = address_to_display(wmem_packet_scope(), &addr);
if (record_code != 0 && record_length % 4) {
proto_item_set_len(record_item, record_length + 2 * 2 + (4 - record_length % 4));
record_length = 4 - record_length % 4;
proto_tree_add_item(record_tree, hf_pcapng_record_padding, tvb, offset, record_length, ENC_NA);
offset += record_length;
} else
proto_item_set_len(record_item, record_length + 2 * 2);
break;
default:
proto_tree_add_item(record_tree, hf_pcapng_record_data, tvb, offset, record_length, ENC_NA);
offset += record_length;
if (str)
proto_item_append_text(record_item, " = %s", str);
}
if (record_code != 0 && record_length % 4) {
proto_item_set_len(record_item, record_length + 2 * 2 + (4 - record_length % 4));
record_length = 4 - record_length % 4;
proto_tree_add_item(record_tree, hf_pcapng_record_padding, tvb, offset, record_length, ENC_NA);
offset += record_length;
} else
proto_item_set_len(record_item, record_length + 2 * 2);
if (str)
proto_item_append_text(record_item, " = %s", str);
}
next_tvb = tvb_new_subset_length(tvb, offset, block_data_length - (offset - offset_record_start));
offset += dissect_options(block_data_tree, pinfo, block_type, next_tvb, encoding, NULL);
}
break;
case BLOCK_INTERFACE_STATISTICS: {
struct interface_description *interface_description;
proto_tree_add_item(block_data_tree, hf_pcapng_interface_id, tvb, offset, 4, encoding);
interface_id = tvb_get_guint32(tvb, offset, encoding);
offset += 4;
interface_description = get_interface_description(info, interface_id,
pinfo, block_tree);
pcapng_add_timestamp(block_data_tree, pinfo, tvb, offset, encoding, interface_description);
offset += 8;
next_tvb = tvb_new_subset_length(tvb, offset, block_data_length - 4 - 8);
offset += dissect_options(block_data_tree, pinfo, block_type, next_tvb, encoding, NULL);
}
break;
case BLOCK_ENHANCED_PACKET: {
struct interface_description *interface_description;
proto_item_append_text(block_item, " %u", info->frame_number);
proto_tree_add_item(block_data_tree, hf_pcapng_interface_id, tvb, offset, 4, encoding);
interface_id = tvb_get_guint32(tvb, offset, encoding);
offset += 4;
interface_description = get_interface_description(info, interface_id,
pinfo, block_tree);
pcapng_add_timestamp(block_data_tree, pinfo, tvb, offset, encoding, interface_description);
offset += 8;
proto_tree_add_item_ret_uint(block_data_tree, hf_pcapng_captured_length, tvb, offset, 4, encoding, &captured_length);
offset += 4;
proto_tree_add_item_ret_uint(block_data_tree, hf_pcapng_packet_length, tvb, offset, 4, encoding, &reported_length);
offset += 4;
packet_data_item = proto_tree_add_item(block_data_tree, hf_pcapng_packet_data, tvb, offset, captured_length, encoding);
if (pref_dissect_next_layer && interface_description != NULL) {
proto_tree *packet_data_tree = proto_item_add_subtree(packet_data_item, ett_pcapng_packet_data);
pinfo->num = info->frame_number;
TRY {
call_dissector_with_data(pcap_pktdata_handle, tvb_new_subset_length_caplen(tvb, offset, captured_length, reported_length),
pinfo, packet_data_tree, &interface_description->link_type);
next_tvb = tvb_new_subset_length(tvb, offset, block_data_length - (offset - offset_record_start));
offset += dissect_options(block_data_tree, pinfo, block_type, next_tvb, info->encoding, NULL);
}
CATCH_BOUNDS_ERRORS {
show_exception(tvb, pinfo, packet_data_tree, EXCEPT_CODE, GET_MESSAGE);
break;
case BLOCK_INTERFACE_STATISTICS: {
struct interface_description *interface_description;
proto_tree_add_item(block_data_tree, hf_pcapng_interface_id, tvb, offset, 4, info->encoding);
interface_id = tvb_get_guint32(tvb, offset, info->encoding);
offset += 4;
interface_description = get_interface_description(info, interface_id,
pinfo, block_tree);
pcapng_add_timestamp(block_data_tree, pinfo, tvb, offset, info->encoding, interface_description);
offset += 8;
next_tvb = tvb_new_subset_length(tvb, offset, block_data_length - 4 - 8);
offset += dissect_options(block_data_tree, pinfo, block_type, next_tvb, info->encoding, NULL);
}
ENDTRY;
break;
case BLOCK_ENHANCED_PACKET: {
struct interface_description *interface_description;
proto_item_append_text(block_item, " %u", info->frame_number);
proto_tree_add_item(block_data_tree, hf_pcapng_interface_id, tvb, offset, 4, info->encoding);
interface_id = tvb_get_guint32(tvb, offset, info->encoding);
offset += 4;
interface_description = get_interface_description(info, interface_id,
pinfo, block_tree);
pcapng_add_timestamp(block_data_tree, pinfo, tvb, offset, info->encoding, interface_description);
offset += 8;
proto_tree_add_item_ret_uint(block_data_tree, hf_pcapng_captured_length, tvb, offset, 4, info->encoding, &captured_length);
offset += 4;
proto_tree_add_item_ret_uint(block_data_tree, hf_pcapng_packet_length, tvb, offset, 4, info->encoding, &reported_length);
offset += 4;
packet_data_item = proto_tree_add_item(block_data_tree, hf_pcapng_packet_data, tvb, offset, captured_length, info->encoding);
if (pref_dissect_next_layer && interface_description != NULL) {
proto_tree *packet_data_tree = proto_item_add_subtree(packet_data_item, ett_pcapng_packet_data);
pinfo->num = info->frame_number;
TRY {
call_dissector_with_data(pcap_pktdata_handle, tvb_new_subset_length_caplen(tvb, offset, captured_length, reported_length),
pinfo, packet_data_tree, &interface_description->link_type);
}
CATCH_BOUNDS_ERRORS {
show_exception(tvb, pinfo, packet_data_tree, EXCEPT_CODE, GET_MESSAGE);
}
ENDTRY;
}
info->frame_number += 1;
offset += captured_length;
if (captured_length % 4) {
proto_tree_add_item(block_data_tree, hf_pcapng_packet_padding, tvb, offset, ((captured_length % 4)? (4 - (captured_length % 4)):0), ENC_NA);
offset += ((captured_length % 4) ?(4 - (captured_length % 4)):0);
}
next_tvb = tvb_new_subset_length(tvb, offset, block_data_length - 4 - 8 - 4 - 4 - captured_length - ((captured_length % 4)?(4 - (captured_length % 4)):0));
offset += dissect_options(block_data_tree, pinfo, block_type, next_tvb, info->encoding, NULL);
}
break;
case BLOCK_DSB:
{
guint32 secrets_length;
proto_tree_add_item(block_data_tree, hf_pcapng_dsb_secrets_type, tvb, offset, 4, info->encoding);
offset += 4;
proto_tree_add_item_ret_uint(block_data_tree, hf_pcapng_dsb_secrets_length, tvb, offset, 4, info->encoding, &secrets_length);
offset += 4;
proto_tree_add_item(block_data_tree, hf_pcapng_dsb_secrets_data, tvb, offset, secrets_length, info->encoding);
offset += secrets_length;
guint32 padlen = (4 - (secrets_length & 3)) & 3;
if (padlen) {
proto_tree_add_item(block_data_tree, hf_pcapng_record_padding, tvb, offset, padlen, ENC_NA);
offset += padlen;
}
if (block_data_length > 4 + 4 + secrets_length + padlen) {
next_tvb = tvb_new_subset_length(tvb, offset, block_data_length - 4 - 4 - secrets_length - padlen);
offset += dissect_options(block_data_tree, pinfo, block_type, next_tvb, info->encoding, NULL);
}
}
break;
case BLOCK_DARWIN_PROCESS:
proto_item_append_text(block_item, " %u", info->darwin_process_event_number);
info->darwin_process_event_number += 1;
proto_tree_add_item(block_data_tree, hf_pcapng_darwin_process_id, tvb, offset, 4, info->encoding);
offset += 4;
next_tvb = tvb_new_subset_length(tvb, offset, block_data_length - 4);
offset += dissect_options(block_data_tree, pinfo, block_type, next_tvb, info->encoding, NULL);
break;
case BLOCK_IRIG_TIMESTAMP:
case BLOCK_ARINC_429:
default:
offset += block_data_length;
}
info->frame_number += 1;
offset += captured_length;
if (captured_length % 4) {
proto_tree_add_item(block_data_tree, hf_pcapng_packet_padding, tvb, offset, ((captured_length % 4)? (4 - (captured_length % 4)):0), ENC_NA);
offset += ((captured_length % 4) ?(4 - (captured_length % 4)):0);
}
next_tvb = tvb_new_subset_length(tvb, offset, block_data_length - 4 - 8 - 4 - 4 - captured_length - ((captured_length % 4)?(4 - (captured_length % 4)):0));
offset += dissect_options(block_data_tree, pinfo, block_type, next_tvb, encoding, NULL);
}
break;
case BLOCK_DSB:
{
guint32 secrets_length;
proto_tree_add_item(block_data_tree, hf_pcapng_dsb_secrets_type, tvb, offset, 4, encoding);
offset += 4;
proto_tree_add_item_ret_uint(block_data_tree, hf_pcapng_dsb_secrets_length, tvb, offset, 4, encoding, &secrets_length);
offset += 4;
proto_tree_add_item(block_data_tree, hf_pcapng_dsb_secrets_data, tvb, offset, secrets_length, encoding);
offset += secrets_length;
guint32 padlen = (4 - (secrets_length & 3)) & 3;
if (padlen) {
proto_tree_add_item(block_data_tree, hf_pcapng_record_padding, tvb, offset, padlen, ENC_NA);
offset += padlen;
}
if (block_data_length > 4 + 4 + secrets_length + padlen) {
next_tvb = tvb_new_subset_length(tvb, offset, block_data_length - 4 - 4 - secrets_length - padlen);
offset += dissect_options(block_data_tree, pinfo, block_type, next_tvb, encoding, NULL);
}
}
break;
case BLOCK_DARWIN_PROCESS:
proto_item_append_text(block_item, " %u", info->darwin_process_event_number);
info->darwin_process_event_number += 1;
proto_tree_add_item(block_data_tree, hf_pcapng_darwin_process_id, tvb, offset, 4, encoding);
offset += 4;
next_tvb = tvb_new_subset_length(tvb, offset, block_data_length - 4);
offset += dissect_options(block_data_tree, pinfo, block_type, next_tvb, encoding, NULL);
break;
case BLOCK_IRIG_TIMESTAMP:
case BLOCK_ARINC_429:
default:
offset += block_data_length;
}
proto_tree_add_item(block_tree, hf_pcapng_block_length, tvb, offset, 4, encoding);
proto_tree_add_item(block_tree, hf_pcapng_block_length, tvb, offset, 4, info->encoding);
offset += 4;
return offset;
}
#define BLOCK_TYPE_SIZE 4
#define BYTE_ORDER_MAGIC_SIZE 4
static int
dissect_pcapng(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
@ -1713,12 +1765,6 @@ dissect_pcapng(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _
static const guint8 pcapng_premagic[BLOCK_TYPE_SIZE] = {
0x0A, 0x0D, 0x0D, 0x0A
};
static const guint8 pcapng_big_endian_magic[BYTE_ORDER_MAGIC_SIZE] = {
0x1A, 0x2B, 0x3C, 0x4D
};
static const guint8 pcapng_little_endian_magic[BYTE_ORDER_MAGIC_SIZE] = {
0x4D, 0x3C, 0x2B, 0x1A
};
gint offset = 0;
guint32 length;
guint32 encoding;
@ -1741,6 +1787,7 @@ dissect_pcapng(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _
info.interface_number = 0;
info.darwin_process_event_number = 0;
info.frame_number = 1;
info.encoding = encoding;
info.interfaces = wmem_array_new(wmem_packet_scope(), sizeof(struct interface_description));
info.darwin_process_events = wmem_array_new(wmem_packet_scope(), sizeof(struct darwin_process_event_description));
@ -1749,11 +1796,17 @@ dissect_pcapng(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _
while (tvb_captured_length_remaining(tvb, offset)) {
tvbuff_t *next_tvb;
int block_length;
length = tvb_get_guint32(tvb, offset + 4, encoding);
next_tvb = tvb_new_subset_length(tvb, offset, length);
offset += dissect_block(main_tree, pinfo, next_tvb, encoding, &info);
block_length = dissect_block(main_tree, pinfo, next_tvb, &info);
if (block_length == -1) {
/* Fatal error. */
break;
}
offset += block_length;
}
return offset;
@ -2285,6 +2338,7 @@ proto_register_pcapng(void)
};
static ei_register_info ei[] = {
{ &ei_invalid_byte_order_magic, { "pcapng.invalid_byte_order_magic", PI_PROTOCOL, PI_ERROR, "The byte-order magic number is not valid", EXPFILL }},
{ &ei_block_length_too_short, { "pcapng.block_length_too_short", PI_PROTOCOL, PI_ERROR, "Block length is < 12 bytes", EXPFILL }},
{ &ei_block_length_not_multiple_of_4, { "pcapng.block_length_too_short", PI_PROTOCOL, PI_ERROR, "Block length is not a multiple of 4", EXPFILL }},
{ &ei_invalid_option_length, { "pcapng.invalid_option_length", PI_PROTOCOL, PI_ERROR, "Invalid Option Length", EXPFILL }},