diff --git a/epan/dissectors/file-pcapng.c b/epan/dissectors/file-pcapng.c index 1792047de9..7a008722f5 100644 --- a/epan/dissectors/file-pcapng.c +++ b/epan/dissectors/file-pcapng.c @@ -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 }},