BPv7: Enhance block data and payload data handling

This change improves sequence analysis and subdissector interfaces, adds
payload Decode As support for DTN and IPN services, and add heuristic
dissection for BTSD.
This commit is contained in:
Patricia Lindner 2022-08-23 17:51:39 -04:00 committed by Alexis La Goutte
parent 58cb2d6857
commit ddf0d35516
8 changed files with 489 additions and 176 deletions

View File

@ -316,7 +316,9 @@ static int dissect_block_asb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
}
const gint offset_value = offset;
wscbor_skip_next_item(wmem_packet_scope(), tvb, &offset);
if (!wscbor_skip_next_item(wmem_packet_scope(), tvb, &offset)) {
return 0;
}
tvbuff_t *tvb_value = tvb_new_subset_length(tvb, offset_value, offset - offset_value);
dissector_handle_t value_dissect = NULL;
@ -375,7 +377,9 @@ static int dissect_block_asb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
}
const gint offset_value = offset;
wscbor_skip_next_item(wmem_packet_scope(), tvb, &offset);
if (!wscbor_skip_next_item(wmem_packet_scope(), tvb, &offset)) {
return 0;
}
tvbuff_t *tvb_value = tvb_new_subset_length(tvb, offset_value, offset - offset_value);
dissector_handle_t value_dissect = NULL;
@ -498,14 +502,14 @@ void proto_reg_handoff_bpsec(void) {
/* Packaged extensions */
{
guint64 *key = g_new(guint64, 1);
*key = 11;
dissector_handle_t hdl = create_dissector_handle(dissect_block_bib, proto_bpsec);
*key = BP_BLOCKTYPE_BIB;
dissector_handle_t hdl = create_dissector_handle_with_name(dissect_block_bib, proto_bpsec, "Block Integrity Block");
dissector_add_custom_table_handle("bpv7.block_type", key, hdl);
}
{
guint64 *key = g_new(guint64, 1);
*key = 12;
dissector_handle_t hdl = create_dissector_handle(dissect_block_bcb, proto_bpsec);
*key = BP_BLOCKTYPE_BCB;
dissector_handle_t hdl = create_dissector_handle_with_name(dissect_block_bcb, proto_bpsec, "Block Confidentiality Block");
dissector_add_custom_table_handle("bpv7.block_type", key, hdl);
}

View File

@ -22,6 +22,8 @@
#include <epan/expert.h>
#include <epan/to_str.h>
#include <epan/reassemble.h>
#include <epan/decode_as.h>
#include <epan/proto_data.h>
#include <epan/exceptions.h>
#include <epan/ftypes/ftypes.h>
#include <wsutil/crc16.h>
@ -43,7 +45,9 @@ static gboolean bp_payload_try_heur = FALSE;
/// Protocol handles
static int proto_bp = -1;
static int proto_blocktype = -1;
static int proto_bp_admin = -1;
static int proto_admintype = -1;
/// Protocol-level data
static bp_history_t *bp_history = NULL;
@ -55,6 +59,7 @@ static dissector_handle_t handle_cborseq = NULL;
static dissector_table_t block_dissectors = NULL;
static dissector_table_t payload_dissectors_dtn_wkssp = NULL;
static dissector_table_t payload_dissectors_dtn_serv = NULL;
static dissector_table_t payload_dissectors_ipn_serv = NULL;
static dissector_table_t admin_dissectors = NULL;
/// BTSD heuristic
static heur_dissector_list_t btsd_heur = NULL;
@ -75,16 +80,6 @@ static const val64_string crc_vals[] = {
{0, NULL},
};
static const val64_string blocktype_vals[] = {
{BP_BLOCKTYPE_PAYLOAD, "Payload"},
{BP_BLOCKTYPE_PREV_NODE, "Previous Node"},
{BP_BLOCKTYPE_BUNDLE_AGE, "Bundle Age"},
{BP_BLOCKTYPE_HOP_COUNT, "Hop Count"},
{BP_BLOCKTYPE_BIB, "Block Integrity Block"},
{BP_BLOCKTYPE_BCB, "Block Confidentiality Block"},
{0, NULL},
};
typedef struct {
/// Type of block
guint64 type_code;
@ -116,11 +111,6 @@ static int blocktype_order(const bp_block_canonical_t *block) {
return 0;
}
static const val64_string admin_type_vals[] = {
{BP_ADMINTYPE_BUNDLE_STATUS, "Bundle Status Report"},
{0, NULL},
};
static const val64_string status_report_reason_vals[] = {
{0, "No additional information"},
{1, "Lifetime expired"},
@ -190,8 +180,11 @@ static int hf_primary_frag_offset = -1;
static int hf_primary_total_length = -1;
static int hf_bundle_ident = -1;
static int hf_bundle_seen = -1;
static int hf_bundle_first_seen = -1;
static int hf_bundle_retrans_seen = -1;
static int hf_bundle_seen_time_diff = -1;
static int hf_bundle_dst_dtn_srv = -1;
static int hf_bundle_dst_ipn_srv = -1;
static int hf_bundle_status_ref = -1;
static int hf_canonical_type_code = -1;
@ -201,6 +194,7 @@ static int hf_canonical_block_flags_delete_no_process = -1;
static int hf_canonical_block_flags_status_no_process = -1;
static int hf_canonical_block_flags_remove_no_process = -1;
static int hf_canonical_block_flags_replicate_in_fragment = -1;
static int hf_canonical_data_size = -1;
static int hf_canonical_data = -1;
static int hf_previous_node_nodeid = -1;
@ -292,18 +286,23 @@ static hf_register_info fields[] = {
{&hf_primary_total_length, {"Total Application Data Unit Length", "bpv7.primary.total_len", FT_UINT64, BASE_DEC | BASE_UNIT_STRING, &units_octet_octets, 0x0, NULL, HFILL}},
{&hf_bundle_ident, {"Bundle Identity", "bpv7.bundle.identity", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
{&hf_bundle_seen, {"First Seen", "bpv7.bundle.first_seen", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RETRANS_PREV), 0x0, NULL, HFILL}},
{&hf_bundle_first_seen, {"First Seen", "bpv7.bundle.first_seen", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RETRANS_PREV), 0x0, NULL, HFILL}},
{&hf_bundle_retrans_seen, {"Retransmit Seen", "bpv7.bundle.retransmit_seen", FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RETRANS_NEXT), 0x0, NULL, HFILL}},
{&hf_bundle_seen_time_diff, {"Seen Time", "bpv7.bundle.seen_time_diff", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL}},
{&hf_bundle_dst_dtn_srv, {"Destination Service", "bpv7.bundle.dst_dtn_srv", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL}},
{&hf_bundle_dst_ipn_srv, {"Destination Service", "bpv7.bundle.dst_ipn_srv", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
{&hf_bundle_status_ref, {"Status Bundle", "bpv7.bundle.status_ref", FT_FRAMENUM, BASE_NONE, NULL, 0x0, NULL, HFILL}},
{&hf_canonical_type_code, {"Type Code", "bpv7.canonical.type_code", FT_UINT64, BASE_DEC | BASE_VAL64_STRING, VALS64(blocktype_vals), 0x0, NULL, HFILL}},
{&hf_canonical_type_code, {"Type Code", "bpv7.canonical.type_code", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
{&hf_canonical_block_num, {"Block Number", "bpv7.canonical.block_num", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
{&hf_canonical_block_flags, {"Block Flags", "bpv7.canonical.block_flags", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL}},
{&hf_canonical_block_flags_replicate_in_fragment, {"Replicate block in fragment", "bpv7.canonical.block_flags.replicate_in_fragment", FT_BOOLEAN, 8, TFS(&tfs_set_notset), BP_BLOCK_REPLICATE_IN_FRAGMENT, NULL, HFILL}},
{&hf_canonical_block_flags_status_no_process, {"Status bundle if not processed", "bpv7.canonical.block_flags.status_if_no_process", FT_BOOLEAN, 8, TFS(&tfs_set_notset), BP_BLOCK_STATUS_IF_NO_PROCESS, NULL, HFILL}},
{&hf_canonical_block_flags_delete_no_process, {"Delete bundle if not processed", "bpv7.canonical.block_flags.delete_if_no_process", FT_BOOLEAN, 8, TFS(&tfs_set_notset), BP_BLOCK_DELETE_IF_NO_PROCESS, NULL, HFILL}},
{&hf_canonical_block_flags_remove_no_process, {"Discard block if not processed", "bpv7.canonical.block_flags.discard_if_no_process", FT_BOOLEAN, 8, TFS(&tfs_set_notset), BP_BLOCK_REMOVE_IF_NO_PROCESS, NULL, HFILL}},
{&hf_canonical_data, {"Block Type-Specific Data", "bpv7.canonical.data", FT_UINT64, BASE_DEC | BASE_UNIT_STRING, &units_octet_octets, 0x0, NULL, HFILL}},
{&hf_canonical_data_size, {"Block Type-Specific Data Length", "bpv7.canonical.data_length", FT_UINT64, BASE_DEC | BASE_UNIT_STRING, &units_octet_octets, 0x0, NULL, HFILL}},
{&hf_canonical_data, {"Block Type-Specific Data", "bpv7.canonical.data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL}},
{&hf_payload_fragments,
{"Payload fragments", "bpv7.payload.fragments",
@ -349,7 +348,7 @@ static hf_register_info fields[] = {
{&hf_hop_count_limit, {"Hop Limit", "bpv7.hop_count.limit", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
{&hf_hop_count_current, {"Hop Count", "bpv7.hop_count.current", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
{&hf_admin_record_type, {"Record Type Code", "bpv7.admin_rec.type_code", FT_UINT64, BASE_DEC | BASE_VAL64_STRING, VALS64(admin_type_vals), 0x0, NULL, HFILL}},
{&hf_admin_record_type, {"Record Type Code", "bpv7.admin_rec.type_code", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL}},
{&hf_status_rep, {"Status Report", "bpv7.status_rep", FT_PROTOCOL, BASE_NONE, NULL, 0x0, NULL, HFILL}},
{&hf_status_rep_status_info, {"Status Information", "bpv7.status_rep.status_info", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
@ -397,6 +396,7 @@ static int ett_block = -1;
static int ett_eid = -1;
static int ett_time = -1;
static int ett_create_ts = -1;
static int ett_ident = -1;
static int ett_block_flags = -1;
static int ett_canonical_data = -1;
static int ett_payload = -1;
@ -412,6 +412,7 @@ static int *ett[] = {
&ett_eid,
&ett_time,
&ett_create_ts,
&ett_ident,
&ett_block_flags,
&ett_canonical_data,
&ett_payload,
@ -527,6 +528,7 @@ bp_eid_t * bp_eid_new(wmem_allocator_t *alloc) {
void bp_eid_free(wmem_allocator_t *alloc, bp_eid_t *obj) {
wmem_free(alloc, (char *)(obj->dtn_wkssp));
wmem_free(alloc, (char *)(obj->dtn_serv));
wmem_free(alloc, (void *)(obj->ipn_serv));
wmem_free(alloc, obj);
}
@ -592,6 +594,26 @@ void bp_bundle_free(wmem_allocator_t *alloc, bp_bundle_t *obj) {
wmem_free(alloc, obj);
}
/** Function to match the GCompareFunc signature.
*/
static gint bp_bundle_frameloc_compare(gconstpointer a, gconstpointer b) {
const bp_bundle_t *aobj = a;
const bp_bundle_t *bobj = b;
if (aobj->frame_num < bobj->frame_num) {
return -1;
}
if (aobj->frame_num > bobj->frame_num) {
return 1;
}
if (aobj->layer_num < bobj->layer_num) {
return -1;
}
if (aobj->layer_num > bobj->layer_num) {
return 1;
}
return 0;
}
bp_bundle_ident_t * bp_bundle_ident_new(wmem_allocator_t *alloc, bp_eid_t *src, bp_creation_ts_t *ts, guint64 *off, guint64 *len) {
bp_bundle_ident_t *ident = wmem_new(alloc, bp_bundle_ident_t);
ident->src = src ? wmem_strdup(alloc, src->uri) : NULL;
@ -688,6 +710,7 @@ proto_item * proto_tree_add_cbor_eid(proto_tree *tree, int hfindex, int hfindex_
wmem_strbuf_t *uribuf = wmem_strbuf_new(alloc_eid, NULL);
const char *dtn_wkssp = NULL;
const char *dtn_serv = NULL;
guint64 *ipn_serv = NULL;
switch (*scheme) {
case EID_SCHEME_DTN: {
chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, offset);
@ -747,10 +770,10 @@ proto_item * proto_tree_add_cbor_eid(proto_tree *tree, int hfindex, int hfindex_
proto_tree_add_cbor_uint64(tree_eid, hf_eid_ipn_node, pinfo, tvb, chunk, node);
chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, offset);
const guint64 *service = wscbor_require_uint64(wmem_packet_scope(), chunk);
proto_tree_add_cbor_uint64(tree_eid, hf_eid_ipn_service, pinfo, tvb, chunk, service);
ipn_serv = wscbor_require_uint64(wmem_file_scope(), chunk);
proto_tree_add_cbor_uint64(tree_eid, hf_eid_ipn_service, pinfo, tvb, chunk, ipn_serv);
wmem_strbuf_append_printf(uribuf, "ipn:%" PRIu64 ".%" PRIu64, node ? *node : 0, service ? *service : 0);
wmem_strbuf_append_printf(uribuf, "ipn:%" PRIu64 ".%" PRIu64, node ? *node : 0, ipn_serv ? *ipn_serv : 0);
}
break;
}
@ -784,11 +807,13 @@ proto_item * proto_tree_add_cbor_eid(proto_tree *tree, int hfindex, int hfindex_
eid->uri = uri;
eid->dtn_wkssp = dtn_wkssp;
eid->dtn_serv = dtn_serv;
eid->ipn_serv = ipn_serv;
}
else {
file_scope_delete(uri);
file_scope_delete((char *)dtn_wkssp);
file_scope_delete((char *)dtn_serv);
file_scope_delete(ipn_serv);
}
proto_item_set_len(item_eid, *offset - eid_start);
@ -866,6 +891,29 @@ static void proto_tree_add_cbor_timestamp(proto_tree *tree, int hfindex, packet_
proto_item_set_len(item_ts, *offset - chunk_ts->start);
}
/** Label type-field items with sub-dissector name.
* This is similar to using val64_string labels but based on dissector name.
*
* @param type_code The dissected value, which must not be null.
* @param type_dissect The associated sub-dissector, which may be null.
* @param[in,out] item_type The item associated with the type field.
* @param[in,out] item_parent The parent item to label.
*/
static void label_type_field(const guint64 *type_code, dissector_handle_t type_dissect, proto_item *item_type, proto_item *item_parent) {
if (!item_type || !item_parent) {
return;
}
const char *type_name = dissector_handle_get_dissector_name(type_dissect);
if (type_name) {
proto_item_append_text(item_parent, ": %s", type_name);
}
else {
proto_item_append_text(item_parent, ": Type %" PRIu64, *type_code);
type_name = "Unknown";
}
proto_item_set_text(item_type, "%s: %s (%" PRIu64 ")", PITEM_FINFO(item_type)->hfinfo->name, type_name, *type_code);
}
/** Show read-in and actual CRC information.
*
* @param tvb The single-block data.
@ -921,7 +969,7 @@ static void show_crc_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree_bl
proto_tree_add_checksum(tree_block, crc_field, 0, hf_crc_field, hf_crc_status, &ei_block_failed_crc, pinfo, crc_actual, ENC_BIG_ENDIAN, chksum_flags);
}
static void proto_tree_add_ident(proto_tree *tree, int hfindex, tvbuff_t *tvb, const bp_bundle_ident_t *ident) {
static proto_item * proto_tree_add_ident(proto_tree *tree, int hfindex, tvbuff_t *tvb, const bp_bundle_ident_t *ident) {
wmem_strbuf_t *ident_text = wmem_strbuf_new(wmem_packet_scope(), NULL);
wmem_strbuf_append_printf(
ident_text,
@ -937,9 +985,10 @@ static void proto_tree_add_ident(proto_tree *tree, int hfindex, tvbuff_t *tvb, c
wmem_strbuf_append_printf(ident_text, ", Total Length: %" PRIu64, *(ident->total_len));
}
proto_item *item_subj_ident = proto_tree_add_string(tree, hfindex, tvb, 0, 0, wmem_strbuf_get_str(ident_text));
proto_item_set_generated(item_subj_ident);
proto_item *item_ident = proto_tree_add_string(tree, hfindex, tvb, 0, 0, wmem_strbuf_get_str(ident_text));
proto_item_set_generated(item_ident);
wmem_strbuf_finalize(ident_text);
return item_ident;
}
@ -979,7 +1028,7 @@ static gint dissect_block_primary(tvbuff_t *tvb, packet_info *pinfo, proto_tree
guint64 *crc_type = wscbor_require_uint64(wmem_packet_scope(), chunk);
proto_item *item_crc_type = proto_tree_add_cbor_uint64(tree_block, hf_crc_type, pinfo, tvb, chunk, crc_type);
field_ix++;
block->crc_type = (crc_type ? (BundleCrcType)(*crc_type) : BP_CRC_NONE);
block->crc_type = (crc_type ? *crc_type : BP_CRC_NONE);
if (crc_type) {
proto_item_append_text(item_block, ", CRC Type: %s", val64_to_str(*crc_type, crc_vals, "%" PRIu64));
}
@ -1090,7 +1139,8 @@ static gint dissect_block_canonical(tvbuff_t *tvb, packet_info *pinfo, proto_tre
block->type_code = type_code;
if (type_code) {
proto_item_append_text(item_block, ": %s", val64_to_str(*type_code, blocktype_vals, "Type %" PRIu64));
dissector_handle_t type_dissect = dissector_get_custom_table_handle(block_dissectors, type_code);
label_type_field(type_code, type_dissect, item_type, item_block);
// Check duplicate of this type
guint64 limit = UINT64_MAX;
@ -1142,7 +1192,7 @@ static gint dissect_block_canonical(tvbuff_t *tvb, packet_info *pinfo, proto_tre
guint64 *crc_type = wscbor_require_uint64(wmem_file_scope(), chunk);
proto_item *item_crc_type = proto_tree_add_cbor_uint64(tree_block, hf_crc_type, pinfo, tvb, chunk, crc_type);
field_ix++;
block->crc_type = (crc_type ? (BundleCrcType)(*crc_type) : BP_CRC_NONE);
block->crc_type = (crc_type ? *crc_type : BP_CRC_NONE);
if (crc_type) {
proto_item_append_text(item_block, ", CRC Type: %s", val64_to_str(*crc_type, crc_vals, "%" PRIu64));
}
@ -1152,8 +1202,10 @@ static gint dissect_block_canonical(tvbuff_t *tvb, packet_info *pinfo, proto_tre
field_ix++;
block->data = tvb_data;
const guint tvb_data_len = (tvb_data ? tvb_reported_length(tvb_data) : 0);
proto_item *item_data = proto_tree_add_uint64(tree_block, hf_canonical_data, tvb_data, 0, tvb_data_len, tvb_data_len);
proto_item_set_generated(
proto_tree_add_cbor_strlen(tree_block, hf_canonical_data_size, pinfo, tvb, chunk)
);
proto_item *item_data = proto_tree_add_cbor_bstr(tree_block, hf_canonical_data, pinfo, tvb, chunk);
proto_tree *tree_data = proto_item_add_subtree(item_data, ett_canonical_data);
block->tree_data = tree_data;
@ -1257,10 +1309,10 @@ static void apply_bpsec_mark(const security_mark_t *sec, packet_info *pinfo, pro
* @param tvb Buffer to read from.
* @param pinfo Packet info to update.
* @param tree The tree to write items under.
* @param payload True if this is bundle payload.
* @param type_exp True if the type code is in the private/experimental range.
* @return The number of dissected octets.
*/
static gint dissect_carried_data(dissector_handle_t dissector, void *context, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean payload _U_) {
static gint dissect_carried_data(dissector_handle_t dissector, void *context, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean type_exp) {
int sublen = 0;
if (dissector) {
sublen = call_dissector_only(dissector, tvb, pinfo, tree, context);
@ -1269,7 +1321,7 @@ static gint dissect_carried_data(dissector_handle_t dissector, void *context, tv
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_sub_partial_decode);
}
}
else {
else if (!type_exp) {
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_sub_type_unknown);
}
@ -1291,9 +1343,11 @@ static gint dissect_carried_data(dissector_handle_t dissector, void *context, tv
static void show_status_subj_ref(gpointer key, gpointer val _U_, gpointer data) {
bp_bundle_ident_t *status_ident = key;
proto_tree *tree_bundle = data;
const bp_bundle_t *status_found = wmem_map_lookup(bp_history->bundles, status_ident);
if (status_found) {
proto_item *item_subj_ref = proto_tree_add_uint(tree_bundle, hf_bundle_status_ref, NULL, 0, 0, status_found->frame_num);
const wmem_list_t *subj_list = wmem_map_lookup(bp_history->bundles, status_ident);
const wmem_list_frame_t *subj_it = subj_list ? wmem_list_head(subj_list) : NULL;
const bp_bundle_t *subj_found = subj_it ? wmem_list_frame_data(subj_it) : NULL;
if (subj_found) {
proto_item *item_subj_ref = proto_tree_add_uint(tree_bundle, hf_bundle_status_ref, NULL, 0, 0, subj_found->frame_num);
proto_item_set_generated(item_subj_ref);
}
}
@ -1331,6 +1385,7 @@ static int dissect_bp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
bp_bundle_t *bundle = bp_bundle_new(wmem_file_scope());
bundle->frame_num = pinfo->num;
bundle->layer_num = pinfo->curr_layer_num;
bundle->frame_time = pinfo->abs_ts;
// Read blocks directly from buffer with same addresses as #tvb
@ -1341,7 +1396,7 @@ static int dissect_bp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
proto_item *item_head = proto_tree_add_item(tree_bundle, hf_bundle_head, tvb, chunk->start, chunk->data_length, ENC_NA);
wscbor_require_array(chunk);
if (wscbor_chunk_mark_errors(pinfo, item_head, chunk)) {
return buflen;
return 0;
}
else if (chunk->type_minor != 31) {
expert_add_info_format(pinfo, item_head, &ei_invalid_framing, "Expected indefinite length array");
@ -1373,9 +1428,19 @@ static int dissect_bp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
// Primary block
proto_item_prepend_text(item_block, "Primary ");
bp_block_primary_t *block = bp_block_primary_new(wmem_file_scope());
offset += dissect_block_primary(tvb, pinfo, tree_block, offset, block, bundle);
const gint sublen = dissect_block_primary(tvb, pinfo, tree_block, offset, block, bundle);
if (sublen <= 0) {
break;
}
offset += sublen;
bundle->primary = block;
// identify bundle regardless of payload decoding
col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%s %s %s",
block->src_nodeid->uri,
UTF8_RIGHTWARDS_ARROW,
block->dst_eid->uri);
if (!(bundle->ident)) {
bundle->ident = bp_bundle_ident_new(
wmem_file_scope(),
@ -1384,23 +1449,52 @@ static int dissect_bp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
bundle->primary->frag_offset,
bundle->primary->total_len
);
proto_tree_add_ident(tree_bundle, hf_bundle_ident, tvb, bundle->ident);
proto_item *item_ident = proto_tree_add_ident(tree_bundle, hf_bundle_ident, tvb, bundle->ident);
proto_tree *tree_ident = proto_item_add_subtree(item_ident, ett_ident);
const bp_bundle_t *seen_found = wmem_map_lookup(bp_history->bundles, bundle->ident);
if (seen_found && (seen_found->frame_num != pinfo->num)) {
proto_item *item_seen = proto_tree_add_uint(tree_bundle, hf_bundle_seen, tvb, 0, 0, seen_found->frame_num);
const wmem_list_t *seen_list = wmem_map_lookup(bp_history->bundles, bundle->ident);
wmem_list_frame_t *seen_it = seen_list ? wmem_list_head(seen_list) : NULL;
const bp_bundle_t *seen_first = seen_it ? wmem_list_frame_data(seen_it) : NULL;
// show first occurance if not this one
if (seen_first && (seen_first->frame_num != pinfo->num)) {
proto_item *item_seen = proto_tree_add_uint(tree_ident, hf_bundle_first_seen, tvb, 0, 0, seen_first->frame_num);
proto_item_set_generated(item_seen);
nstime_t td;
nstime_delta(&td, &(bundle->frame_time), &(seen_found->frame_time));
proto_item *item_td = proto_tree_add_time(tree_bundle, hf_bundle_seen_time_diff, tvb, 0, 0, &td);
nstime_delta(&td, &(bundle->frame_time), &(seen_first->frame_time));
proto_item *item_td = proto_tree_add_time(tree_ident, hf_bundle_seen_time_diff, tvb, 0, 0, &td);
proto_item_set_generated(item_td);
}
// show any retransmits
else if (seen_it) {
for (seen_it = wmem_list_frame_next(seen_it); seen_it != NULL; seen_it = wmem_list_frame_next(seen_it)) {
const bp_bundle_t *seen_re = wmem_list_frame_data(seen_it);
if (seen_re && (seen_re->frame_num != pinfo->num)) {
proto_item *item_seen = proto_tree_add_uint(tree_ident, hf_bundle_retrans_seen, tvb, 0, 0, seen_re->frame_num);
proto_item_set_generated(item_seen);
}
}
}
// Indicate related status (may be multiple)
wmem_map_t *status_set = wmem_map_lookup(bp_history->admin_status, bundle->ident);
if (status_set) {
wmem_map_foreach(status_set, show_status_subj_ref, tree_bundle);
wmem_map_foreach(status_set, show_status_subj_ref, tree_ident);
}
}
{
const bp_eid_t *dst = bundle->primary->dst_eid;
if (dst) {
proto_item *item_dst = NULL;
if (dst->dtn_serv) {
item_dst = proto_tree_add_string(tree_bundle, hf_bundle_dst_dtn_srv, tvb, 0, 0, dst->dtn_serv);
}
else if (dst->ipn_serv) {
item_dst = proto_tree_add_uint64(tree_bundle, hf_bundle_dst_ipn_srv, tvb, 0, 0, *(dst->ipn_serv));
}
if (item_dst) {
proto_item_set_generated(item_dst);
}
}
}
}
@ -1408,7 +1502,11 @@ static int dissect_bp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
// Non-primary block
proto_item_prepend_text(item_block, "Canonical ");
bp_block_canonical_t *block = bp_block_canonical_new(wmem_file_scope(), block_ix);
offset += dissect_block_canonical(tvb, pinfo, tree_block, offset, block, bundle);
const gint sublen = dissect_block_canonical(tvb, pinfo, tree_block, offset, block, bundle);
if (sublen <= 0) {
break;
}
offset += sublen;
}
proto_item_set_len(item_block, offset - block_start);
@ -1424,6 +1522,13 @@ static int dissect_bp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
if (wmem_list_frame_next(it)) {
expert_add_info(pinfo, block->item_block, &ei_block_payload_index);
}
if (block->data) {
bundle->pyld_start = wmem_new(wmem_file_scope(), guint);
*(bundle->pyld_start) = tvb_raw_offset(block->data) - tvb_raw_offset(tvb);
bundle->pyld_len = wmem_new(wmem_file_scope(), guint);
*(bundle->pyld_len) = tvb_reported_length(block->data);
}
}
}
@ -1452,14 +1557,16 @@ static int dissect_bp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
// sub-dissect after all is read
dissector_handle_t data_dissect = NULL;
gboolean type_exp = FALSE;
if (block->type_code) {
data_dissect = dissector_get_custom_table_handle(block_dissectors, block->type_code);
type_exp = (*(block->type_code) >= 192) && (*(block->type_code) <= 255);
}
bp_dissector_data_t dissect_data;
dissect_data.bundle = bundle;
dissect_data.block = block;
dissect_carried_data(data_dissect, &dissect_data, block->data, pinfo, block->tree_data, FALSE);
dissect_carried_data(data_dissect, &dissect_data, block->data, pinfo, block->tree_data, type_exp);
}
// Block-data-derived markings
@ -1473,12 +1580,6 @@ static int dissect_bp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
if (bundle->primary) {
const bp_block_primary_t *primary = bundle->primary;
// identify bundle regardless of payload decoding
col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%s %s %s",
primary->src_nodeid->uri,
UTF8_RIGHTWARDS_ARROW,
primary->dst_eid->uri);
const gboolean is_fragment = primary->flags & BP_BUNDLE_IS_FRAGMENT;
const gboolean is_admin = primary->flags & BP_BUNDLE_PAYLOAD_ADMIN;
if (is_admin) {
@ -1496,19 +1597,36 @@ static int dissect_bp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
}
}
if (bundle->pyld_start && bundle->pyld_len) {
// Treat payload as non-protocol data
const guint trailer_start = *(bundle->pyld_start) + *(bundle->pyld_len);
proto_item_set_len(item_bundle, *(bundle->pyld_start));
proto_tree_set_appendix(tree_bundle, tvb, trailer_start, offset - trailer_start);
}
else {
proto_item_set_len(item_bundle, offset);
}
{
// Keep bundle metadata around for the whole file
bp_bundle_t *found = wmem_map_lookup(bp_history->bundles, bundle->ident);
if (!found) {
wmem_map_insert(bp_history->bundles, bundle->ident, bundle);
wmem_list_t *found_list = wmem_map_lookup(bp_history->bundles, bundle->ident);
if (!found_list) {
found_list = wmem_list_new(wmem_file_scope());
wmem_map_insert(bp_history->bundles, bundle->ident, found_list);
}
const wmem_list_frame_t *found_it = wmem_list_find_custom(found_list, bundle, bp_bundle_frameloc_compare);
bp_bundle_t *found_item = found_it ? wmem_list_frame_data(found_it) : NULL;
if (!found_item) {
wmem_list_append(found_list, bundle);
p_add_proto_data(pinfo->pool, pinfo, proto_bp, pinfo->curr_layer_num, bundle);
}
else {
bp_bundle_free(wmem_file_scope(), bundle);
}
}
proto_item_set_len(item_bundle, offset);
return buflen;
return offset;
}
static gboolean proto_tree_add_status_assertion(proto_tree *tree, int hfassert, packet_info *pinfo, tvbuff_t *tvb, gint *offset) {
@ -1560,15 +1678,17 @@ static int dissect_payload_admin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset);
guint64 *type_code = wscbor_require_uint64(wmem_packet_scope(), chunk);
proto_tree_add_cbor_uint64(tree_rec, hf_admin_record_type, pinfo, tvb, chunk, type_code);
proto_item *item_type = proto_tree_add_cbor_uint64(tree_rec, hf_admin_record_type, pinfo, tvb, chunk, type_code);
dissector_handle_t admin_dissect = NULL;
dissector_handle_t type_dissect = NULL;
gboolean type_exp = FALSE;
if (type_code) {
proto_item_append_text(item_rec, ": %s", val64_to_str(*type_code, admin_type_vals, "Type %" PRIu64));
admin_dissect = dissector_get_custom_table_handle(admin_dissectors, type_code);
type_dissect = dissector_get_custom_table_handle(admin_dissectors, type_code);
label_type_field(type_code, type_dissect, item_type, item_rec);
type_exp = (*type_code >= 65536);
}
tvbuff_t *tvb_record = tvb_new_subset_remaining(tvb, offset);
gint sublen = dissect_carried_data(admin_dissect, context, tvb_record, pinfo, tree_rec, TRUE);
gint sublen = dissect_carried_data(type_dissect, context, tvb_record, pinfo, tree_rec, type_exp);
offset += sublen;
}
@ -1593,7 +1713,7 @@ static int dissect_status_report(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
wscbor_chunk_mark_errors(pinfo, item_status, chunk_status);
if (wscbor_skip_if_errors(wmem_packet_scope(), tvb, &offset, chunk_status)) {
proto_item_set_len(item_status, offset - chunk_status->start);
return offset;
return 0;
}
wscbor_chunk_t *chunk;
@ -1653,7 +1773,9 @@ static int dissect_status_report(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
{
// Pointer back to subject
const bp_bundle_t *subj_found = wmem_map_lookup(bp_history->bundles, subj);
const wmem_list_t *subj_list = wmem_map_lookup(bp_history->bundles, subj);
const wmem_list_frame_t *subj_it = subj_list ? wmem_list_head(subj_list) : NULL;
const bp_bundle_t *subj_found = subj_it ? wmem_list_frame_data(subj_it) : NULL;
if (subj_found) {
proto_item *item_subj_ref = proto_tree_add_uint(tree_status, hf_status_rep_subj_ref, tvb, 0, 0, subj_found->frame_num);
proto_item_set_generated(item_subj_ref);
@ -1836,7 +1958,7 @@ static int dissect_block_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
}
}
// an EID shouldn't have both of these set
// an EID shouldn't have multiple of these set
dissector_handle_t payload_dissect = NULL;
if (bundle->primary->dst_eid->dtn_wkssp) {
payload_dissect = dissector_get_string_handle(payload_dissectors_dtn_wkssp, bundle->primary->dst_eid->dtn_wkssp);
@ -1844,8 +1966,12 @@ static int dissect_block_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
else if (bundle->primary->dst_eid->dtn_serv) {
payload_dissect = dissector_get_string_handle(payload_dissectors_dtn_serv, bundle->primary->dst_eid->dtn_serv);
}
else if (bundle->primary->dst_eid->ipn_serv &&
(*(bundle->primary->dst_eid->ipn_serv) <= G_MAXUINT)) {
payload_dissect = dissector_get_uint_handle(payload_dissectors_ipn_serv, (guint)(*(bundle->primary->dst_eid->ipn_serv)));
}
return dissect_carried_data(payload_dissect, &data, tvb_payload, pinfo, tree_top, TRUE);
return dissect_carried_data(payload_dissect, context, tvb_payload, pinfo, tree_top, TRUE);
}
/** Dissector for Previous Node block.
@ -1878,7 +2004,7 @@ static int dissect_block_hop_count(tvbuff_t *tvb, packet_info *pinfo, proto_tree
wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset);
wscbor_require_array_size(chunk, 2, 2);
if (wscbor_skip_if_errors(wmem_packet_scope(), tvb, &offset, chunk)) {
return offset;
return 0;
}
chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset);
@ -1894,22 +2020,33 @@ static int dissect_block_hop_count(tvbuff_t *tvb, packet_info *pinfo, proto_tree
static gboolean btsd_heur_cbor(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
gint offset = 0;
volatile gint count = 0;
// check exactly one item
wscbor_skip_next_item(wmem_packet_scope(), tvb, &offset);
if ((guint)offset == tvb_reported_length(tvb)) {
while ((guint)offset < tvb_reported_length(tvb)) {
volatile gboolean valid = FALSE;
TRY {
valid = wscbor_skip_next_item(wmem_packet_scope(), tvb, &offset);
}
CATCH_BOUNDS_AND_DISSECTOR_ERRORS {}
ENDTRY;
if (!valid) {
break;
}
++count;
}
// Anything went wrong with any part of the data
if ((count == 0) || ((guint)offset != tvb_reported_length(tvb))) {
return FALSE;
}
if (count == 1) {
call_dissector(handle_cbor, tvb, pinfo, tree);
return TRUE;
}
// attempt a multi-item sequence
TRY {
offset = call_dissector(handle_cborseq, tvb, pinfo, tree);
else {
call_dissector(handle_cborseq, tvb, pinfo, tree);
}
CATCH_ALL {}
ENDTRY;
return ((guint)offset == tvb_reported_length(tvb));
return TRUE;
}
/// Clear state when new file scope is entered
@ -1977,6 +2114,52 @@ static const reassembly_table_functions bundle_reassembly_table_functions = {
fragment_bundle_ident_free_persistent_key
};
static void dtn_serv_prompt(packet_info *pinfo, gchar *result) {
const bp_bundle_t *bundle = p_get_proto_data(pinfo->pool, pinfo, proto_bp, pinfo->curr_layer_num);
const char *serv = NULL;
if (bundle && bundle->primary && bundle->primary->dst_eid
&& bundle->primary->dst_eid->dtn_serv) {
serv = bundle->primary->dst_eid->dtn_serv;
}
snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "dst (%s)", serv);
}
static gpointer dtn_serv_value(packet_info *pinfo) {
const bp_bundle_t *bundle = p_get_proto_data(pinfo->pool, pinfo, proto_bp, pinfo->curr_layer_num);
if (bundle && bundle->primary && bundle->primary->dst_eid
&& bundle->primary->dst_eid->dtn_serv) {
const char *serv = bundle->primary->dst_eid->dtn_serv;
return (char *)serv;
}
return 0;
}
static void ipn_serv_prompt(packet_info *pinfo, gchar *result) {
const bp_bundle_t *bundle = p_get_proto_data(pinfo->pool, pinfo, proto_bp, pinfo->curr_layer_num);
guint32 serv = 0;
if (bundle && bundle->primary && bundle->primary->dst_eid
&& bundle->primary->dst_eid->ipn_serv
&& (*(bundle->primary->dst_eid->ipn_serv) <= G_MAXUINT)) {
serv = (unsigned int) *(bundle->primary->dst_eid->ipn_serv);
}
snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "dst (%u)", serv);
}
static gpointer ipn_serv_value(packet_info *pinfo) {
const bp_bundle_t *bundle = p_get_proto_data(pinfo->pool, pinfo, proto_bp, pinfo->curr_layer_num);
if (bundle && bundle->primary && bundle->primary->dst_eid
&& bundle->primary->dst_eid->ipn_serv
&& (*(bundle->primary->dst_eid->ipn_serv) <= G_MAXUINT)) {
guint64 serv = *(bundle->primary->dst_eid->ipn_serv);
return GUINT_TO_POINTER(serv);
}
return 0;
}
/// Overall registration of the protocol
void proto_register_bpv7(void) {
proto_bp = proto_register_protocol(
@ -1994,9 +2177,41 @@ void proto_register_bpv7(void) {
register_dissector("bpv7", dissect_bp, proto_bp);
block_dissectors = register_custom_dissector_table("bpv7.block_type", "BPv7 Block", proto_bp, g_int64_hash, g_int64_equal);
// Blocks don't count as protocol layers
proto_blocktype = proto_register_protocol_in_name_only("BPv7 Block Type", "Block Type", "bpv7.block_type", proto_bp, FT_PROTOCOL);
// case-sensitive string matching
payload_dissectors_dtn_wkssp = register_dissector_table("bpv7.payload.dtn_wkssp", "BPv7 Payload (by well-known SSP)", proto_bp, FT_STRING, FALSE);
payload_dissectors_dtn_serv = register_dissector_table("bpv7.payload.serv", "BPv7 Payload (by service demux)", proto_bp, FT_STRING, FALSE);
payload_dissectors_dtn_wkssp = register_dissector_table("bpv7.payload.dtn_wkssp", "BPv7 DTN-scheme well-known SSP", proto_bp, FT_STRING, FALSE);
payload_dissectors_dtn_serv = register_dissector_table("bpv7.payload.dtn_serv", "BPv7 DTN-scheme service", proto_bp, FT_STRING, FALSE);
dissector_table_allow_decode_as(payload_dissectors_dtn_serv);
static build_valid_func dtn_serv_da_build_value[1] = {dtn_serv_value};
static decode_as_value_t dtn_serv_da_values[1] = {
{dtn_serv_prompt, 1, dtn_serv_da_build_value}
};
static decode_as_t dtn_serv_da = {
"bpv7", "bpv7.payload.dtn_serv",
1, 0, dtn_serv_da_values, NULL, NULL,
decode_as_default_populate_list, decode_as_default_reset,
decode_as_default_change, NULL
};
register_decode_as(&dtn_serv_da);
payload_dissectors_ipn_serv = register_dissector_table("bpv7.payload.ipn_serv", "BPv7 IPN-scheme service", proto_bp, FT_UINT32, BASE_DEC);
dissector_table_allow_decode_as(payload_dissectors_ipn_serv);
static build_valid_func ipn_serv_da_build_value[1] = {ipn_serv_value};
static decode_as_value_t ipn_serv_da_values[1] = {
{ipn_serv_prompt, 1, ipn_serv_da_build_value}
};
static decode_as_t ipn_serv_da = {
"bpv7", "bpv7.payload.ipn_serv",
1, 0, ipn_serv_da_values, NULL, NULL,
decode_as_default_populate_list, decode_as_default_reset,
decode_as_default_change, NULL
};
register_decode_as(&ipn_serv_da);
module_t *module_bp = prefs_register_protocol(proto_bp, bp_reinit_config);
prefs_register_bool_preference(
@ -2035,6 +2250,7 @@ void proto_register_bpv7(void) {
);
handle_admin = create_dissector_handle(dissect_payload_admin, proto_bp_admin);
admin_dissectors = register_custom_dissector_table("bpv7.admin_record_type", "BPv7 Administrative Record Type", proto_bp_admin, g_int64_hash, g_int64_equal);
proto_admintype = proto_register_protocol_in_name_only("BPv7 Administrative Record Type", "Admin Type", "bpv7.admin_record_type", proto_bp, FT_PROTOCOL);
}
void proto_reg_handoff_bpv7(void) {
@ -2048,31 +2264,31 @@ void proto_reg_handoff_bpv7(void) {
{
guint64 *key = g_new(guint64, 1);
*key = BP_BLOCKTYPE_PAYLOAD;
dissector_handle_t hdl = create_dissector_handle(dissect_block_payload, proto_bp);
dissector_handle_t hdl = create_dissector_handle_with_name(dissect_block_payload, proto_blocktype, "Payload");
dissector_add_custom_table_handle("bpv7.block_type", key, hdl);
}
{
guint64 *key = g_new(guint64, 1);
*key = BP_BLOCKTYPE_PREV_NODE;
dissector_handle_t hdl = create_dissector_handle(dissect_block_prev_node, proto_bp);
dissector_handle_t hdl = create_dissector_handle_with_name(dissect_block_prev_node, proto_blocktype, "Previous Node");
dissector_add_custom_table_handle("bpv7.block_type", key, hdl);
}
{
guint64 *key = g_new(guint64, 1);
*key = BP_BLOCKTYPE_BUNDLE_AGE;
dissector_handle_t hdl = create_dissector_handle(dissect_block_bundle_age, proto_bp);
dissector_handle_t hdl = create_dissector_handle_with_name(dissect_block_bundle_age, proto_blocktype, "Bundle Age");
dissector_add_custom_table_handle("bpv7.block_type", key, hdl);
}
{
guint64 *key = g_new(guint64, 1);
*key = BP_BLOCKTYPE_HOP_COUNT;
dissector_handle_t hdl = create_dissector_handle(dissect_block_hop_count, proto_bp);
dissector_handle_t hdl = create_dissector_handle_with_name(dissect_block_hop_count, proto_blocktype, "Hop Count");
dissector_add_custom_table_handle("bpv7.block_type", key, hdl);
}
{
guint64 *key = g_new(guint64, 1);
*key = BP_ADMINTYPE_BUNDLE_STATUS;
dissector_handle_t hdl = create_dissector_handle(dissect_status_report, proto_bp);
dissector_handle_t hdl = create_dissector_handle_with_name(dissect_status_report, proto_admintype, "Bundle Status Report");
dissector_add_custom_table_handle("bpv7.admin_record_type", key, hdl);
}

View File

@ -35,6 +35,20 @@ extern "C" {
*
* There is a BTSD heuristic dissector table "bpv7.btsd" which uses
* bp_dissector_data_t* as dissector user data.
*
* Payload block (block type 1) dissection is additionally handled based on
* bundle flags and destination EID as:
* - If the bundle flags mark it as administrative, it is dissected as such.
* - If the destination is a well-known SSP, the dissector table
* "bpv7.payload.dtn_wkssp" is used with the scheme-specific part.
* - If the destination is "dtn" scheme, the dissector table
* "bpv7.payload.dtn_serv" is used with the service demux (text string).
* There is also Decode As behavior for dtn service demux.
* - If the destination is "ipn" scheme, the dissector table
* "bpv7.payload.ipn_serv" is used with the service number (uint value).
* There is also Decode As behavior for ipn service number.
* - Finally, fall through to BTSD heuristic dissection.
* All payload dissection uses bp_dissector_data_t* as dissector user data.
*/
/** Bundle CRC types.
@ -159,12 +173,12 @@ typedef struct {
/// Derived URI text
const char *uri;
/// Optional DTN well-known SSP
/// Optional DTN-scheme well-known SSP
const char *dtn_wkssp;
/// Optional URI authority part
// const char *node_name;
/// Optional DTN service name
/// Optional DTN-scheme service name
const char *dtn_serv;
/// Optional IPN-scheme service name
guint64 *ipn_serv;
} bp_eid_t;
/** Construct a new timestamp.
@ -211,7 +225,7 @@ typedef struct {
/// Optional bundle total length
guint64 *total_len;
/// CRC type code (assumed zero)
BundleCrcType crc_type;
guint64 crc_type;
/// Raw bytes of CRC field
tvbuff_t *crc_field;
@ -242,7 +256,7 @@ typedef struct {
/// All flags on this block
guint64 flags;
/// CRC type code (assumed zero)
BundleCrcType crc_type;
guint64 crc_type;
/// Raw bytes of CRC field
tvbuff_t *crc_field;
@ -284,7 +298,7 @@ bp_bundle_ident_t * bp_bundle_ident_new(wmem_allocator_t *alloc, bp_eid_t *src,
WS_DLL_PUBLIC
void bp_bundle_ident_free(wmem_allocator_t *alloc, bp_bundle_ident_t *obj);
/** Function to match the GCompareFunc signature.
/** Function to match the GEqualFunc signature.
*/
WS_DLL_PUBLIC
gboolean bp_bundle_ident_equal(gconstpointer a, gconstpointer b);
@ -298,6 +312,8 @@ guint bp_bundle_ident_hash(gconstpointer key);
typedef struct {
/// Index of the frame
guint32 frame_num;
/// Layer within the frame
guint8 layer_num;
/// Timestamp on the frame (end time if reassembled)
nstime_t frame_time;
/// Bundle identity derived from #primary data
@ -312,6 +328,11 @@ typedef struct {
/// Map from block type code (guint64) to sequence (wmem_list_t) of
/// pointers to block of that type (bp_block_canonical_t owned by #blocks)
wmem_map_t *block_types;
/// Payload BTSD start offset in bundle TVB
guint *pyld_start;
/// Payload BTSD length
guint *pyld_len;
} bp_bundle_t;
/** Construct a new object on the file allocator.
@ -341,7 +362,7 @@ proto_item * proto_tree_add_cbor_eid(proto_tree *tree, int hfindex, int hfindex_
/// Metadata for an entire file
typedef struct {
/// Map from a bundle ID (bp_bundle_ident_t) to bundle (bp_bundle_t)
/// Map from a bundle ID (bp_bundle_ident_t) to wmem_list_t of bundle (bp_bundle_t)
wmem_map_t *bundles;
/// Map from subject bundle ID (bp_bundle_ident_t) to
/// map from references (bp_bundle_ident_t) of status bundles to NULL

View File

@ -346,8 +346,9 @@ gboolean cose_param_key_equal(gconstpointer a, gconstpointer b) {
*
* @param dis_table The cose_param_key_t dissector table.
* @param[in,out] ctx The context from other pairs.
* @return True if the pair was dissected (even as opaque CBOR data).
*/
static void dissect_header_pair(dissector_table_t dis_table, cose_header_context_t *ctx, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset) {
static gboolean dissect_header_pair(dissector_table_t dis_table, cose_header_context_t *ctx, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset) {
wscbor_chunk_t *chunk_label = wscbor_chunk_read(wmem_packet_scope(), tvb, offset);
proto_item *item_label = NULL;
@ -400,7 +401,9 @@ static void dissect_header_pair(dissector_table_t dis_table, cose_header_context
// Peek into the value as tvb
const gint offset_value = *offset;
wscbor_skip_next_item(wmem_packet_scope(), tvb, offset);
if (!wscbor_skip_next_item(wmem_packet_scope(), tvb, offset)) {
return FALSE;
}
tvb_value = tvb_new_subset_length(tvb, offset_value, *offset - offset_value);
gint sublen = 0;
@ -422,6 +425,7 @@ static void dissect_header_pair(dissector_table_t dis_table, cose_header_context
CATCH_ALL {}
ENDTRY;
}
return TRUE;
}
/** Dissect an entire header map, either for messages, recipients, or keys.
@ -442,7 +446,9 @@ static void dissect_header_map(dissector_table_t dis_table, tvbuff_t *tvb, packe
cose_header_context_t *ctx = wmem_new0(wmem_packet_scope(), cose_header_context_t);
for (guint64 ix = 0; ix < chunk_hdr_map->head_value; ++ix) {
dissect_header_pair(dis_table, ctx, tvb, pinfo, tree_hdr_map, offset);
if (!dissect_header_pair(dis_table, ctx, tvb, pinfo, tree_hdr_map, offset)) {
break;
}
}
if (ctx->principal) {

View File

@ -234,9 +234,8 @@ wscbor_chunk_t * wscbor_chunk_read(wmem_allocator_t *alloc, tvbuff_t *tvb, gint
// skip over definite data
*offset += datalen;
chunk->data_length += datalen;
if(datalen) {
chunk->_priv->str_value = tvb_new_subset_length(tvb, chunk->start + chunk->head_length, datalen);
}
// allow even zero-length strings
chunk->_priv->str_value = tvb_new_subset_length(tvb, chunk->start + chunk->head_length, datalen);
}
else {
// indefinite length, sequence of definite items
@ -348,8 +347,21 @@ gboolean wscbor_is_indefinite_break(const wscbor_chunk_t *chunk) {
);
}
gboolean wscbor_skip_next_item(wmem_allocator_t *alloc, tvbuff_t *tvb, gint *offset) {
/** Add output parameter to indicate internal state.
* @param alloc The allocator to use.
* @param tvb The data buffer.
* @param[in,out] offset The initial offset to read and skip over.
* @param[out] is_break If non-null, set to true only when the item was
* an indefinite break.
* @return True if the skipped item was fully valid.
*/
static gboolean wscbor_skip_next_item_internal(wmem_allocator_t *alloc, tvbuff_t *tvb, gint *offset, gboolean *is_break) {
wscbor_chunk_t *chunk = wscbor_chunk_read(alloc, tvb, offset);
if (wscbor_has_errors(chunk)) {
*offset = chunk->start;
wscbor_chunk_free(chunk);
return FALSE;
}
switch (chunk->type_major) {
case CBOR_TYPE_UINT:
case CBOR_TYPE_NEGINT:
@ -363,12 +375,20 @@ gboolean wscbor_skip_next_item(wmem_allocator_t *alloc, tvbuff_t *tvb, gint *off
case CBOR_TYPE_ARRAY: {
if (chunk->type_minor == 31) {
// wait for indefinite break
while (!wscbor_skip_next_item(alloc, tvb, offset)) {}
gboolean was_break = FALSE;
do {
if (!wscbor_skip_next_item_internal(alloc, tvb, offset, &was_break)) {
return FALSE;
}
}
while (!was_break);
}
else {
const guint64 count = chunk->head_value;
for (guint64 ix = 0; ix < count; ++ix) {
wscbor_skip_next_item(alloc, tvb, offset);
if (!wscbor_skip_next_item_internal(alloc, tvb, offset, NULL)) {
return FALSE;
}
}
}
break;
@ -376,21 +396,40 @@ gboolean wscbor_skip_next_item(wmem_allocator_t *alloc, tvbuff_t *tvb, gint *off
case CBOR_TYPE_MAP: {
if (chunk->type_minor == 31) {
// wait for indefinite break
while (!wscbor_skip_next_item(alloc, tvb, offset)) {}
gboolean was_break = FALSE;
do {
if (!wscbor_skip_next_item_internal(alloc, tvb, offset, &was_break)) {
return FALSE;
}
}
while (!was_break);
}
else {
const guint64 count = chunk->head_value;
for (guint64 ix = 0; ix < count; ++ix) {
wscbor_skip_next_item(alloc, tvb, offset);
wscbor_skip_next_item(alloc, tvb, offset);
if (!wscbor_skip_next_item_internal(alloc, tvb, offset, NULL)) {
return FALSE;
}
if (!wscbor_skip_next_item_internal(alloc, tvb, offset, NULL)) {
return FALSE;
}
}
}
break;
}
}
const gboolean is_break = wscbor_is_indefinite_break(chunk);
const gboolean got_break = wscbor_is_indefinite_break(chunk);
if (is_break) {
*is_break = got_break;
}
wscbor_chunk_free(chunk);
return is_break;
// RFC 8949 Sec 3.2.1: a break code outside of an indefinite container is
// not valid, and is_break is non-null only in indefinite container.
return is_break || !got_break;
}
gboolean wscbor_skip_next_item(wmem_allocator_t *alloc, tvbuff_t *tvb, gint *offset) {
return wscbor_skip_next_item_internal(alloc, tvb, offset, NULL);
}
gboolean wscbor_skip_if_errors(wmem_allocator_t *alloc, tvbuff_t *tvb, gint *offset, const wscbor_chunk_t *chunk) {
@ -624,22 +663,34 @@ proto_item * proto_tree_add_cbor_bitmask(proto_tree *tree, int hfindex, const gi
return item;
}
proto_item * proto_tree_add_cbor_tstr(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb _U_, const wscbor_chunk_t *chunk) {
proto_item * proto_tree_add_cbor_tstr(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk) {
proto_item *item;
if (chunk->_priv->str_value) {
proto_item *item = proto_tree_add_item(tree, hfindex, chunk->_priv->str_value, 0, tvb_reported_length(chunk->_priv->str_value), 0);
wscbor_chunk_mark_errors(pinfo, item, chunk);
return item;
} else {
return NULL;
item = proto_tree_add_item(tree, hfindex, chunk->_priv->str_value, 0, tvb_reported_length(chunk->_priv->str_value), 0);
}
else {
// still show an empty item with errors
item = proto_tree_add_item(tree, hfindex, tvb, chunk->start, 0, 0);
}
wscbor_chunk_mark_errors(pinfo, item, chunk);
return item;
}
proto_item * proto_tree_add_cbor_bstr(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb _U_, const wscbor_chunk_t *chunk) {
proto_item * proto_tree_add_cbor_bstr(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk) {
proto_item *item;
if (chunk->_priv->str_value) {
proto_item *item = proto_tree_add_item(tree, hfindex, chunk->_priv->str_value, 0, tvb_reported_length(chunk->_priv->str_value), 0);
wscbor_chunk_mark_errors(pinfo, item, chunk);
return item;
} else {
return NULL;
item = proto_tree_add_item(tree, hfindex, chunk->_priv->str_value, 0, tvb_reported_length(chunk->_priv->str_value), 0);
}
else {
// still show an empty item with errors
item = proto_tree_add_item(tree, hfindex, tvb, chunk->start, 0, 0);
}
wscbor_chunk_mark_errors(pinfo, item, chunk);
return item;
}
proto_item * proto_tree_add_cbor_strlen(proto_tree *tree, int hfindex, packet_info *pinfo _U_, tvbuff_t *tvb, const wscbor_chunk_t *chunk) {
const guint str_len = (chunk->_priv->str_value ? tvb_reported_length(chunk->_priv->str_value) : 0);
proto_item *item = proto_tree_add_uint64(tree, hfindex, tvb, chunk->start, chunk->head_length, str_len);
return item;
}

View File

@ -163,7 +163,10 @@ gboolean wscbor_is_indefinite_break(const wscbor_chunk_t *chunk);
* @param alloc The allocator to use.
* @param tvb The data buffer.
* @param[in,out] offset The initial offset to read and skip over.
* @return True if the skipped item was an indefinite break.
* Will be set to one-past the last valid CBOR (possibly nested) present.
* @return True if the skipped item was fully valid.
* @post This can throw ReportedBoundsError or ContainedBoundsError
* if the read itself ran out of data.
*/
WS_DLL_PUBLIC
gboolean wscbor_skip_next_item(wmem_allocator_t *alloc, tvbuff_t *tvb, gint *offset);
@ -305,6 +308,11 @@ proto_item * proto_tree_add_cbor_tstr(proto_tree *tree, int hfindex, packet_info
WS_DLL_PUBLIC
proto_item * proto_tree_add_cbor_bstr(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk);
/** Add an item representing the length of a bstr or tstr value.
*/
WS_DLL_PUBLIC
proto_item * proto_tree_add_cbor_strlen(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk);
#ifdef __cplusplus
}
#endif

View File

@ -85,7 +85,7 @@ wscbor_test_chunk_read_simple(void)
gint offset = 0;
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
g_assert(chunk);
g_assert_nonnull(chunk);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
g_assert_cmpuint(chunk->head_length, ==, ex->head_length);
@ -117,7 +117,7 @@ wscbor_test_chunk_read_simple_tags(void)
gint offset = 0;
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
g_assert(chunk);
g_assert_nonnull(chunk);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
g_assert_cmpuint(chunk->head_length, ==, ex->head_length + 3);
@ -125,19 +125,19 @@ wscbor_test_chunk_read_simple_tags(void)
g_assert_cmpuint(wmem_list_count(chunk->tags), ==, 2);
{
wmem_list_frame_t *frm = wmem_list_head(chunk->tags);
g_assert(frm);
g_assert_nonnull(frm);
{
const wscbor_tag_t *tag = wmem_list_frame_data(frm);
g_assert_cmpuint(tag->value, ==, 1);
}
frm = wmem_list_frame_next(frm);
g_assert(frm);
g_assert_nonnull(frm);
{
const wscbor_tag_t *tag = wmem_list_frame_data(frm);
g_assert_cmpuint(tag->value, ==, 200);
}
frm = wmem_list_frame_next(frm);
g_assert(!frm);
g_assert_null(frm);
}
g_assert_cmpuint(chunk->type_major, ==, ex->type_major);
g_assert_cmpuint(chunk->head_value, ==, ex->head_value);
@ -157,7 +157,7 @@ wscbor_test_chunk_read_invalid(void)
{ // last valid item
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
g_assert(chunk);
g_assert_nonnull(chunk);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
g_assert_cmpuint(chunk->type_major, ==, CBOR_TYPE_UINT);
g_assert_cmpuint(chunk->head_value, ==, 2);
@ -168,7 +168,7 @@ wscbor_test_chunk_read_invalid(void)
volatile gulong caught = 0;
TRY {
wscbor_chunk_read(test_scope, tvb, &offset);
g_assert(FALSE);
g_assert_true(FALSE);
}
CATCH_BOUNDS_ERRORS {
caught = exc->except_id.except_code;
@ -181,7 +181,7 @@ wscbor_test_chunk_read_invalid(void)
volatile gulong caught = 0;
TRY {
wscbor_chunk_read(test_scope, tvb, &offset);
g_assert(FALSE);
g_assert_true(FALSE);
}
CATCH_BOUNDS_ERRORS {
caught = exc->except_id.except_code;
@ -205,17 +205,17 @@ wscbor_test_is_indefinite_break(void)
gint offset = 0;
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
g_assert(chunk);
g_assert_nonnull(chunk);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
// this test never modifies the chunk
const gboolean val = wscbor_is_indefinite_break(chunk);
if (memcmp(ex->enc, "\xFF", 1) == 0) {
g_assert(val);
g_assert_true(val);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
}
else {
g_assert(!val);
g_assert_false(val);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
}
@ -234,7 +234,9 @@ wscbor_test_skip_next_item_simple(void)
tvbuff_t *tvb = tvb_new_real_data(ex->enc, ex->enc_len, ex->enc_len);
gint offset = 0;
wscbor_skip_next_item(test_scope, tvb, &offset);
gboolean valid = wscbor_skip_next_item(test_scope, tvb, &offset);
// break is well-formed but not valid on its own
g_assert_cmpint(valid, ==, (ex != &ex_break));
g_assert_cmpint(offset, ==, ex->data_length);
tvb_free(tvb);
@ -247,19 +249,19 @@ wscbor_test_skip_next_item_multiple(void)
tvbuff_t *tvb = tvb_new_real_data((const guint8 *)"\x00\x01\x02\x03", 4, 4);
gint offset = 2;
gboolean res = wscbor_skip_next_item(test_scope, tvb, &offset);
g_assert(!res);
gboolean valid = wscbor_skip_next_item(test_scope, tvb, &offset);
g_assert_true(valid);
g_assert_cmpint(offset, ==, 3);
res = wscbor_skip_next_item(test_scope, tvb, &offset);
g_assert(!res);
valid = wscbor_skip_next_item(test_scope, tvb, &offset);
g_assert_true(valid);
g_assert_cmpint(offset, ==, 4);
{ // Read past the end
volatile gulong caught = 0;
TRY {
wscbor_skip_next_item(test_scope, tvb, &offset);
g_assert(FALSE);
g_assert_true(FALSE);
}
CATCH_BOUNDS_ERRORS {
caught = exc->except_id.except_code;
@ -283,14 +285,14 @@ wscbor_test_require_major_type(void)
gint offset = 0;
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
g_assert(chunk);
g_assert_nonnull(chunk);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
g_assert(wscbor_require_major_type(chunk, ex->type_major));
g_assert_true(wscbor_require_major_type(chunk, ex->type_major));
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
// any other type
g_assert(!wscbor_require_major_type(chunk, ex->type_major + 1));
g_assert_false(wscbor_require_major_type(chunk, ex->type_major + 1));
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
wscbor_chunk_free(chunk);
@ -309,18 +311,18 @@ wscbor_test_require_boolean_simple(void)
gint offset = 0;
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
g_assert(chunk);
g_assert_nonnull(chunk);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
const gboolean *val = wscbor_require_boolean(test_scope, chunk);
if ((ex->type_major == CBOR_TYPE_FLOAT_CTRL)
&& ((ex->head_value == CBOR_CTRL_FALSE) || (ex->head_value == CBOR_CTRL_TRUE))) {
g_assert(val);
g_assert_nonnull(val);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
g_assert_cmpint(*val, ==, ex->head_value == CBOR_CTRL_TRUE);
}
else {
g_assert(!val);
g_assert_null(val);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
}
@ -340,12 +342,12 @@ wscbor_test_require_int64_simple(void)
gint offset = 0;
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
g_assert(chunk);
g_assert_nonnull(chunk);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
const gint64 *val = wscbor_require_int64(test_scope, chunk);
if (ex->type_major == CBOR_TYPE_UINT) {
g_assert(val);
g_assert_nonnull(val);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
g_assert_cmpint(*val, ==, ex->head_value);
}
@ -355,7 +357,7 @@ wscbor_test_require_int64_simple(void)
g_assert_cmpint(*val, ==, -1 - ex->head_value);
}
else {
g_assert(!val);
g_assert_null(val);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
}
@ -378,24 +380,24 @@ wscbor_test_require_int64_overflow(void)
gint offset = 0;
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
g_assert(chunk);
g_assert_nonnull(chunk);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
g_assert_cmpuint(chunk->type_major, ==, ex->type_major);
g_assert_cmpuint(chunk->head_value, ==, ex->head_value);
const gint64 *val = wscbor_require_int64(test_scope, chunk);
if (ex->type_major == CBOR_TYPE_UINT) {
g_assert(val);
g_assert_nonnull(val);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
g_assert_cmpint(*val, ==, G_MAXINT64);
}
else if (ex->type_major == CBOR_TYPE_NEGINT) {
g_assert(val);
g_assert_nonnull(val);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
g_assert_cmpint(*val, ==, G_MININT64);
}
else {
g_assert(!val);
g_assert_null(val);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
}
@ -415,12 +417,12 @@ wscbor_test_require_tstr_simple(void)
gint offset = 0;
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
g_assert(chunk);
g_assert_nonnull(chunk);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
const char *val = wscbor_require_tstr(test_scope, chunk);
if (ex->type_major == CBOR_TYPE_STRING) {
g_assert(val);
g_assert_nonnull(val);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
if (ex->head_value > 0) {
// only works because this is Latin-1 text
@ -428,7 +430,7 @@ wscbor_test_require_tstr_simple(void)
}
}
else {
g_assert(!val);
g_assert_null(val);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
}
@ -454,7 +456,7 @@ wscbor_test_require_tstr_short(void)
gint offset = 0;
chunk = wscbor_chunk_read(test_scope, tvb, &offset);
g_assert(chunk);
g_assert_nonnull(chunk);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
g_assert_cmpuint(chunk->type_major, ==, ex->type_major);
g_assert_cmpuint(chunk->head_value, ==, ex->head_value);
@ -462,7 +464,7 @@ wscbor_test_require_tstr_short(void)
volatile gulong caught = 0;
TRY {
wscbor_require_tstr(test_scope, chunk);
g_assert(FALSE);
g_assert_true(FALSE);
}
CATCH_BOUNDS_ERRORS {
caught = exc->except_id.except_code;
@ -486,12 +488,12 @@ wscbor_test_require_bstr_simple(void)
gint offset = 0;
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
g_assert(chunk);
g_assert_nonnull(chunk);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
tvbuff_t *val = wscbor_require_bstr(test_scope, chunk);
if (ex->type_major == CBOR_TYPE_BYTESTRING) {
g_assert(val);
g_assert_nonnull(val);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
if (ex->head_value > 0) {
g_assert_cmpint(tvb_reported_length(val), ==, ex->head_value);
@ -499,12 +501,12 @@ wscbor_test_require_bstr_simple(void)
const gint buflen = tvb_reported_length(val);
void *buf = tvb_memdup(test_scope, val, 0, buflen);
g_assert(buf);
g_assert_nonnull(buf);
g_assert_cmpmem(buf, buflen, ex->enc + ex->head_length, ex->head_value);
}
}
else {
g_assert(!val);
g_assert_null(val);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
}
@ -519,22 +521,26 @@ wscbor_test_require_bstr_short(void)
const example_s * examples[] = {
&ex_bstr_short,
};
tvbuff_t *tvb = NULL;
wscbor_chunk_t *chunk = NULL;
tvbuff_t *val = NULL;
for (size_t ex_ix = 0; ex_ix < (sizeof(examples) / sizeof(example_s*)); ++ex_ix) {
const example_s *ex = examples[ex_ix];
printf("simple #%zu\n", ex_ix);
tvbuff_t *tvb = tvb_new_real_data(ex->enc, ex->enc_len, ex->enc_len);
tvb = tvb_new_real_data(ex->enc, ex->enc_len, ex->enc_len);
gint offset = 0;
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
g_assert(chunk);
chunk = wscbor_chunk_read(test_scope, tvb, &offset);
g_assert_nonnull(chunk);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
g_assert_cmpuint(chunk->type_major, ==, ex->type_major);
g_assert_cmpuint(chunk->head_value, ==, ex->head_value);
// no exception, but truncated captured length
tvbuff_t *val = wscbor_require_bstr(test_scope, chunk);
g_assert(val);
val = wscbor_require_bstr(test_scope, chunk);
g_assert_nonnull(val);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0);
g_assert_cmpint(tvb_reported_length(val), ==, ex->head_value);
g_assert_cmpuint(tvb_captured_length(val), <, ex->head_value);
@ -543,7 +549,7 @@ wscbor_test_require_bstr_short(void)
TRY {
const gint buflen = tvb_reported_length(val);
tvb_memdup(test_scope, val, 0, buflen);
g_assert(FALSE);
g_assert_true(FALSE);
}
CATCH_BOUNDS_ERRORS {
caught = exc->except_id.except_code;
@ -570,13 +576,13 @@ wscbor_test_require_bstr_overflow(void)
gint offset = 0;
wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset);
g_assert(chunk);
g_assert_nonnull(chunk);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
g_assert_cmpuint(chunk->type_major, ==, ex->type_major);
g_assert_cmpuint(chunk->head_value, ==, ex->head_value);
const tvbuff_t *val = wscbor_require_bstr(test_scope, chunk);
g_assert(val);
g_assert_nonnull(val);
g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1);
g_assert_cmpuint(tvb_reported_length(val), ==, G_MAXINT);
g_assert_cmpuint(tvb_captured_length(val), ==, 2);

View File

@ -1281,6 +1281,7 @@ libwireshark.so.0 libwireshark0 #MINVER#
proto_tree_add_cbor_ctrl@Base 3.5.1
proto_tree_add_cbor_eid@Base 3.5.1rc0-3265-gb0c69d7db316
proto_tree_add_cbor_int64@Base 3.5.1
proto_tree_add_cbor_strlen@Base 3.7.0
proto_tree_add_cbor_tstr@Base 3.5.1
proto_tree_add_cbor_uint64@Base 3.5.1
proto_tree_add_checksum@Base 2.1.1