BPv7: Add proper heuristic block/payload dissection.

This also touches up the INFO column display of bundle src/dst EID.
This commit is contained in:
Brian Sipos 2021-10-22 23:39:37 -04:00 committed by Wireshark GitLab Utility
parent fad8346282
commit 1e42357d19
2 changed files with 69 additions and 21 deletions

View File

@ -23,6 +23,7 @@
#include <epan/ftypes/ftypes.h>
#include <wsutil/crc16.h>
#include <wsutil/crc32.h>
#include <wsutil/utf8_entities.h>
#include <stdio.h>
#include <inttypes.h>
@ -43,13 +44,17 @@ static int proto_bp_admin = -1;
/// Protocol-level data
static bp_history_t *bp_history = NULL;
static dissector_handle_t handle_admin = NULL;
/// Dissect opaque CBOR data
static dissector_handle_t handle_cbor = NULL;
static dissector_handle_t handle_cborseq = NULL;
/// Extension sub-dissectors
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 admin_dissectors = NULL;
/// BTSD heuristic
static heur_dissector_list_t btsd_heur = NULL;
/// Fragment reassembly
static reassembly_table bp_reassembly_table;
@ -876,7 +881,7 @@ static void show_crc_info(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree_bl
chksum_flags |= PROTO_CHECKSUM_NOT_PRESENT;
}
else {
const guint block_len = tvb_captured_length(tvb);
const guint block_len = tvb_reported_length(tvb);
guint8 *crcbuf = tvb_memdup(pinfo->pool, tvb, 0, block_len);
switch (*crc_type) {
case BP_CRC_16:
@ -1129,7 +1134,7 @@ 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_captured_length(tvb_data) : 0);
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_tree *tree_data = proto_item_add_subtree(item_data, ett_canonical_data);
block->tree_data = tree_data;
@ -1237,11 +1242,12 @@ static void apply_bpsec_mark(const security_mark_t *sec, packet_info *pinfo, pro
* @param payload True if this is bundle payload.
* @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) {
static gint dissect_carried_data(dissector_handle_t dissector, void *context, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean payload _U_) {
int sublen = 0;
if (dissector) {
sublen = call_dissector_with_data(dissector, tvb, pinfo, tree, context);
if ((sublen < 0) || ((guint)sublen < tvb_captured_length(tvb))) {
sublen = call_dissector_only(dissector, tvb, pinfo, tree, context);
if ((sublen < 0) ||
((sublen > 0) && ((guint)sublen < tvb_reported_length(tvb)))) {
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_sub_partial_decode);
}
}
@ -1249,15 +1255,11 @@ static gint dissect_carried_data(dissector_handle_t dissector, void *context, tv
expert_add_info(pinfo, proto_tree_get_parent(tree), &ei_sub_type_unknown);
}
if ((sublen == 0) && bp_payload_try_heur) {
if (payload) {
col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Assumed CBOR");
if ((sublen <= 0) && bp_payload_try_heur) {
heur_dtbl_entry_t *entry = NULL;
if (dissector_try_heuristic(btsd_heur, tvb, pinfo, tree, &entry, context)) {
sublen = tvb_reported_length(tvb);
}
TRY {
sublen = call_dissector(handle_cbor, tvb, pinfo, tree);
}
CATCH_ALL {}
ENDTRY;
}
if (sublen == 0) {
sublen = call_data_dissector(tvb, pinfo, tree);
@ -1297,7 +1299,7 @@ static int dissect_bp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
bundle->frame_time = pinfo->abs_ts;
// Read blocks directly from buffer with same addresses as #tvb
const guint buflen = tvb_captured_length(tvb);
const guint buflen = tvb_reported_length(tvb);
// Require indefinite-length array type
wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset);
@ -1466,7 +1468,9 @@ static gboolean proto_tree_add_status_assertion(proto_tree *tree, int hfassert,
return result;
}
static int dissect_payload_admin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, bp_dissector_data_t *context) {
static int dissect_payload_admin(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) {
bp_dissector_data_t *context = (bp_dissector_data_t *)data;
DISSECTOR_ASSERT(context);
{
const gchar *proto_name = col_get_text(pinfo->cinfo, COL_PROTOCOL);
if (g_strcmp0(proto_name, proto_name_bp_admin) != 0) {
@ -1640,7 +1644,11 @@ static int dissect_status_report(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
}
const char *status_buf = wmem_strbuf_finalize(status_text);
proto_item_append_text(item_admin, ", Status: %s", status_buf);
col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "Status: %s", status_buf);
col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%s %s %s Status: %s",
context->bundle->primary->src_nodeid->uri,
UTF8_RIGHTWARDS_ARROW,
context->bundle->primary->dst_eid->uri,
status_buf);
}
if (reason_code) {
proto_item_append_text(item_admin, ", Reason: %s", val64_to_str(*reason_code, status_report_reason_vals, "%" G_GUINT64_FORMAT));
@ -1674,11 +1682,14 @@ static int dissect_block_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
if (is_fragment) {
proto_item_append_text(item_bundle, ", FRAGMENT");
}
const guint payload_len = tvb_captured_length(tvb);
const guint payload_len = tvb_reported_length(tvb);
proto_item_append_text(item_bundle, ", Payload-Size: %d", payload_len);
// identify bundle regardless of payload decoding
col_append_sep_str(pinfo->cinfo, COL_INFO, NULL, "Bundle");
col_append_sep_fstr(pinfo->cinfo, COL_INFO, NULL, "%s %s %s",
bundle->primary->src_nodeid->uri,
UTF8_RIGHTWARDS_ARROW,
bundle->primary->dst_eid->uri);
// Set if the payload is fully defragmented
tvbuff_t *tvb_payload = NULL;
@ -1765,7 +1776,10 @@ static int dissect_block_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *
// Payload is known to be administrative, independent of destination EID
if (is_admin) {
col_append_str(pinfo->cinfo, COL_INFO, " [Admin]");
return dissect_payload_admin(tvb_payload, pinfo, tree_top, context);
const int sublen = call_dissector_only(handle_admin, tvb_payload, pinfo, tree_top, context);
if (sublen > 0) {
return sublen;
}
}
// an EID shouldn't have both of these set
@ -1824,6 +1838,26 @@ static int dissect_block_hop_count(tvbuff_t *tvb, packet_info *pinfo, proto_tree
return offset;
}
static gboolean btsd_heur_cbor(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) {
gint offset = 0;
// check exactly one item
wscbor_skip_next_item(wmem_packet_scope(), tvb, &offset);
if ((guint)offset == tvb_reported_length(tvb)) {
call_dissector(handle_cbor, tvb, pinfo, tree);
return TRUE;
}
// attempt a multi-item sequence
TRY {
offset = call_dissector(handle_cborseq, tvb, pinfo, tree);
}
CATCH_ALL {}
ENDTRY;
return ((guint)offset == tvb_reported_length(tvb));
}
/// Clear state when new file scope is entered
static void bp_init(void) {
bp_history = wmem_new0(wmem_file_scope(), bp_history_t);
@ -1938,17 +1972,23 @@ void proto_register_bpv7(void) {
&bundle_reassembly_table_functions
);
btsd_heur = register_heur_dissector_list("bpv7.btsd", proto_bp);
proto_bp_admin = proto_register_protocol(
"BPv7 Administrative Record", /* name */
"BPv7 Admin", /* short name */
"bpv7.admin_rec" /* abbrev */
);
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);
}
void proto_reg_handoff_bpv7(void) {
const int proto_cbor = proto_get_id_by_filter_name("cbor");
heur_dissector_add("bpv7.btsd", btsd_heur_cbor, "CBOR in Bundle BTSD", "cbor_bpv7", proto_cbor, HEURISTIC_ENABLE);
handle_cbor = find_dissector("cbor");
handle_cborseq = find_dissector("cborseq");
/* Packaged extensions */
{

View File

@ -23,10 +23,18 @@
extern "C" {
#endif
/*
* BPv7 block-type-specific data dissectors are registered with the
/* This dissector defines two layers of protocol:
* - The BPv7 bundle format and its block types.
* - The BPv7 Administrative Record which is a bundle payload as indicated by
* a primary block flag.
*
* BPv7 block-type-specific data (BTSD) dissectors are registered with the
* dissector table "bpv7.block_type" and Administrative Record dissectors
* with the table "bpv7.admin_record_type". Both use guint64* table keys.
* Both use bp_dissector_data_t* as dissector user data.
*
* There is a BTSD heuristic dissector table "bpv7.btsd" which uses
* bp_dissector_data_t* as dissector user data.
*/
/** Bundle CRC types.