aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Thacker <johnthacker@gmail.com>2021-10-12 22:34:14 -0400
committerWireshark GitLab Utility <gerald+gitlab-utility@wireshark.org>2021-10-19 18:53:46 +0000
commitdb8e63614ebfab7497bc44532411261256058625 (patch)
tree29e565d11f3e5ec4a4a5a6b835894ed39151ab29
parent9a8feb8abd84366ca009c56ae3aa67a62e03dee7 (diff)
BT-uTP: Hand to bittorrent dissector, dissect multiple PDUs
Handle uTP payload to the bittorrent dissector. Implement dissect PDUs to handle more than one bittorrent PDU in a uTP payload. Implement basic multisegment PDU tracking; not enough to actually desegment, but enough to provide a hint to the start offset of the next PDU when a PDU does span segments. (Provided that they're in order, but OOO handling isn't implemented yet either.) Improves #8792.
-rw-r--r--epan/dissectors/packet-bittorrent.c10
-rw-r--r--epan/dissectors/packet-bt-utp.c554
-rw-r--r--epan/dissectors/packet-bt-utp.h5
3 files changed, 552 insertions, 17 deletions
diff --git a/epan/dissectors/packet-bittorrent.c b/epan/dissectors/packet-bittorrent.c
index 36542cf26c..11d2a859e2 100644
--- a/epan/dissectors/packet-bittorrent.c
+++ b/epan/dissectors/packet-bittorrent.c
@@ -18,6 +18,7 @@
#include <epan/strutil.h>
#include "packet-tcp.h"
+#include "packet-bt-utp.h"
void proto_register_bittorrent(void);
void proto_reg_handoff_bittorrent(void);
@@ -574,6 +575,14 @@ int dissect_bittorrent (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, voi
}
static
+int dissect_bittorrent_utp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
+{
+ utp_dissect_pdus(tvb, pinfo, tree, bittorrent_desegment, BITTORRENT_HEADER_LENGTH,
+ get_bittorrent_pdu_length, dissect_bittorrent_tcp_pdu, data);
+ return tvb_reported_length(tvb);
+}
+
+static
gboolean test_bittorrent_packet (tvbuff_t *tvb, packet_info *pinfo,
proto_tree *tree, void *data)
{
@@ -692,6 +701,7 @@ proto_register_bittorrent(void)
proto_register_subtree_array(ett, array_length(ett));
dissector_handle = register_dissector("bittorrent.tcp", dissect_bittorrent, proto_bittorrent);
+ register_dissector("bittorrent.utp", dissect_bittorrent_utp, proto_bittorrent);
bittorrent_module = prefs_register_protocol(proto_bittorrent, NULL);
prefs_register_bool_preference(bittorrent_module, "desegment",
diff --git a/epan/dissectors/packet-bt-utp.c b/epan/dissectors/packet-bt-utp.c
index 974840695e..d4cda9eb03 100644
--- a/epan/dissectors/packet-bt-utp.c
+++ b/epan/dissectors/packet-bt-utp.c
@@ -14,8 +14,11 @@
#include <epan/packet.h>
#include <epan/conversation.h>
+#include <epan/exceptions.h>
+#include <epan/show_exception.h>
#include <epan/prefs.h>
#include <epan/proto_data.h>
+#include <epan/reassemble.h>
#include "packet-udp.h"
#include "packet-bt-utp.h"
@@ -129,6 +132,7 @@ Fields Types
#define V1_MAX_WINDOW_SIZE 0x380000U
static dissector_handle_t bt_utp_handle;
+static dissector_handle_t bittorrent_handle;
static int hf_bt_utp_ver = -1;
static int hf_bt_utp_type = -1;
@@ -148,23 +152,56 @@ static int hf_bt_utp_wnd_size_v0 = -1;
static int hf_bt_utp_wnd_size_v1 = -1;
static int hf_bt_utp_seq_nr = -1;
static int hf_bt_utp_ack_nr = -1;
+static int hf_bt_utp_len = -1;
static int hf_bt_utp_data = -1;
+static int hf_bt_utp_pdu_size = -1;
+static int hf_bt_utp_continuation_to = -1;
static gint ett_bt_utp = -1;
static gint ett_bt_utp_extension = -1;
static gboolean enable_version0 = FALSE;
static guint max_window_size = V1_MAX_WINDOW_SIZE;
+/* XXX: Desegementation and OOO-reassembly are not supported yet */
+static gboolean utp_desegment = FALSE;
+/*static gboolean utp_reassemble_out_of_order = FALSE;*/
+static gboolean utp_analyze_seq = TRUE;
static guint32 bt_utp_stream_count = 0;
+typedef struct _utp_multisegment_pdu {
+
+ guint16 first_seq;
+ guint16 last_seq;
+ guint first_seq_start_offset;
+ guint last_seq_end_offset;
+ /*gint length;
+ guint32 reassembly_id;*/
+ guint32 first_frame;
+
+} utp_multisegment_pdu;
+
+typedef struct _utp_flow_t {
+#if 0
+ /* XXX: Some other things to add in later. */
+ gboolean base_seq_set;
+ guint16 base_seq;
+ guint32 fin;
+ guint32 window;
+ guint32 maxnextseq;
+#endif
+
+ wmem_tree_t *multisegment_pdus;
+} utp_flow_t;
+
typedef struct {
guint32 stream;
-#if 0
- /* XXX: Some other things to add in later. The flow will contain
- * multisegment PDU handling, base sequence numbers, etc. */
utp_flow_t flow[2];
+ utp_flow_t *fwd;
+ utp_flow_t *rev;
+#if 0
+ /* XXX: Some other things to add in later. */
nstime_t ts_first;
nstime_t ts_prev;
guint8 conversation_completeness;
@@ -180,6 +217,9 @@ typedef struct {
guint16 seq;
guint16 ack;
guint32 seglen; /* reported length remaining */
+ gboolean have_seglen;
+
+ proto_tree *tree; /* For the bittorrent subdissector to access */
} utp_info_t;
static utp_stream_info_t*
@@ -188,6 +228,7 @@ get_utp_stream_info(packet_info *pinfo, utp_info_t *utp_info)
conversation_t* conv;
utp_stream_info_t *stream_info;
guint32 id_up, id_down;
+ int direction;
/* Handle connection ID wrapping correctly. (Mainline libutp source
* does not appear to do this, probably fails to connect if the random
@@ -250,12 +291,327 @@ get_utp_stream_info(packet_info *pinfo, utp_info_t *utp_info)
if (!stream_info) {
stream_info = wmem_new0(wmem_file_scope(), utp_stream_info_t);
stream_info->stream = bt_utp_stream_count++;
+ stream_info->flow[0].multisegment_pdus=wmem_tree_new(wmem_file_scope());
+ stream_info->flow[1].multisegment_pdus=wmem_tree_new(wmem_file_scope());
conversation_add_proto_data(conv, proto_bt_utp, stream_info);
}
+ /* check direction */
+ direction=cmp_address(&pinfo->src, &pinfo->dst);
+ /* if the addresses are equal, match the ports instead. Use
+ * the UDP ports instead of the uTP connection IDs because
+ * we don't know which ID is smaller if we don't have both. */
+ if(direction==0) {
+ direction= (pinfo->srcport > pinfo->destport) ? 1 : -1;
+ }
+ if(direction>=0) {
+ stream_info->fwd=&(stream_info->flow[0]);
+ stream_info->rev=&(stream_info->flow[1]);
+ } else {
+ stream_info->fwd=&(stream_info->flow[1]);
+ stream_info->rev=&(stream_info->flow[0]);
+ }
+
return stream_info;
}
+static void
+print_pdu_tracking_data(packet_info *pinfo, tvbuff_t *tvb, proto_tree *utp_tree, utp_multisegment_pdu *msp)
+{
+ proto_item *item;
+
+ col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, "[Continuation to #%u] ", msp->first_frame);
+ item=proto_tree_add_uint(utp_tree, hf_bt_utp_continuation_to,
+ tvb, 0, 0, msp->first_frame);
+ proto_item_set_generated(item);
+}
+
+static int
+scan_for_next_pdu(tvbuff_t *tvb, proto_tree *utp_tree, packet_info *pinfo, wmem_tree_t *multisegment_pdus)
+{
+ utp_multisegment_pdu *msp;
+ utp_info_t *p_utp_info;
+ guint16 seq, prev_seq;
+
+ p_utp_info = (utp_info_t *)p_get_proto_data(pinfo->pool, pinfo, proto_bt_utp, pinfo->curr_layer_num);
+
+ /* XXX: Wraparound is possible, as is cycling through all 16 bit
+ * sequence numbers in a connection. We only do this path if
+ * "seq analysis" is on; that ought to do something (relative
+ * sequence numbers definitely, maybe extend the width?) to help,
+ * but doesn't yet.
+ */
+ seq = p_utp_info->seq;
+ prev_seq = seq - 1;
+ msp = (utp_multisegment_pdu *)wmem_tree_lookup32_le(multisegment_pdus, prev_seq);
+ if (msp) {
+
+ if(seq>msp->first_seq && seq<=msp->last_seq) {
+ print_pdu_tracking_data(pinfo, tvb, utp_tree, msp);
+ }
+
+ /* If this segment is completely within a previous PDU
+ * then we just skip this packet
+ */
+ if(seq>msp->first_seq && seq<msp->last_seq) {
+ return -1;
+ }
+
+ if(seq>msp->first_seq && seq==msp->last_seq) {
+ if (!PINFO_FD_VISITED(pinfo) && p_utp_info->have_seglen) {
+ /* Unlike TCP, the sequence numbers don't measure bytes, so
+ * we can only really update the end of the MSP when the packets
+ * are in order, and if we have the real segment length (so not
+ * an unreassembled IP fragment).
+ */
+ if (p_utp_info->seglen >= msp->last_seq_end_offset) {
+ return msp->last_seq_end_offset;
+ } else {
+ msp->last_seq++;
+ msp->last_seq_end_offset -= p_utp_info->seglen;
+ return -1;
+ }
+ } else {
+ /* We can still provide a hint to the offset start in some
+ * cases even when we can't update the MSP.
+ */
+ if (msp->last_seq_end_offset < tvb_reported_length(tvb)) {
+ return msp->last_seq_end_offset;
+ } else {
+ return -1;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static utp_multisegment_pdu *
+pdu_store_sequencenumber_of_next_pdu(packet_info *pinfo, guint16 seq, int offset, guint32 bytes_until_next_pdu, wmem_tree_t *multisegment_pdus)
+{
+ utp_multisegment_pdu *msp;
+
+ msp = wmem_new(wmem_file_scope(), utp_multisegment_pdu);
+ msp->first_seq = seq;
+ msp->first_seq_start_offset = offset;
+ msp->last_seq = seq+1;
+ msp->last_seq_end_offset = bytes_until_next_pdu;
+ msp->first_frame = pinfo->num;
+ wmem_tree_insert32(multisegment_pdus, seq, (void *)msp);
+
+ return msp;
+}
+
+#if 0
+static void
+desegment_utp(tvbuff_t *tvb, packet_info *pinfo, int offset,
+ guint32 seq, guint32 nxtseq,
+ proto_tree *tree, proto_tree *utp_tree,
+ utp_stream_info_t *stream_info)
+{
+
+}
+#endif
+
+void
+utp_dissect_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
+ gboolean proto_desegment, guint fixed_len,
+ guint (*get_pdu_len)(packet_info *, tvbuff_t *, int, void*),
+ dissector_t dissect_pdu, void* dissector_data)
+{
+ volatile int offset = 0;
+ int offset_before;
+ guint captured_length_remaining;
+ volatile guint plen;
+ guint length;
+ tvbuff_t *next_tvb;
+ proto_item *item=NULL;
+ const char *saved_proto;
+ guint8 curr_layer_num;
+ wmem_list_frame_t *frame;
+
+ while (tvb_reported_length_remaining(tvb, offset) > 0) {
+ /*
+ * We use "tvb_ensure_captured_length_remaining()" to make
+ * sure there actually *is* data remaining. The protocol
+ * we're handling could conceivably consists of a sequence of
+ * fixed-length PDUs, and therefore the "get_pdu_len" routine
+ * might not actually fetch anything from the tvbuff, and thus
+ * might not cause an exception to be thrown if we've run past
+ * the end of the tvbuff.
+ *
+ * This means we're guaranteed that "captured_length_remaining" is positive.
+ */
+ captured_length_remaining = tvb_ensure_captured_length_remaining(tvb, offset);
+
+ /*
+ * Can we do reassembly?
+ */
+ if (proto_desegment && pinfo->can_desegment) {
+ /*
+ * Yes - is the fixed-length part of the PDU split across segment
+ * boundaries?
+ */
+ if (captured_length_remaining < fixed_len) {
+ /*
+ * Yes. Tell the uTP dissector where the data for this message
+ * starts in the data it handed us and that we need "some more
+ * data." Don't tell it exactly how many bytes we need because
+ * if/when we ask for even more (after the header) that will
+ * break reassembly.
+ */
+ pinfo->desegment_offset = offset;
+ pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
+ return;
+ }
+ }
+
+ /*
+ * Get the length of the PDU.
+ */
+ plen = (*get_pdu_len)(pinfo, tvb, offset, dissector_data);
+ if (plen == 0) {
+ /*
+ * Support protocols which have a variable length which cannot
+ * always be determined within the given fixed_len.
+ */
+ DISSECTOR_ASSERT(proto_desegment && pinfo->can_desegment);
+ pinfo->desegment_offset = offset;
+ pinfo->desegment_len = DESEGMENT_ONE_MORE_SEGMENT;
+ return;
+ }
+ if (plen < fixed_len) {
+ /*
+ * Either:
+ *
+ * 1) the length value extracted from the fixed-length portion
+ * doesn't include the fixed-length portion's length, and
+ * was so large that, when the fixed-length portion's
+ * length was added to it, the total length overflowed;
+ *
+ * 2) the length value extracted from the fixed-length portion
+ * includes the fixed-length portion's length, and the value
+ * was less than the fixed-length portion's length, i.e. it
+ * was bogus.
+ *
+ * Report this as a bounds error.
+ */
+ show_reported_bounds_error(tvb, pinfo, tree);
+ return;
+ }
+
+ /* give a hint to uTP where the next PDU starts
+ * so that it can attempt to find it in case it starts
+ * somewhere in the middle of a segment.
+ */
+ if(!pinfo->fd->visited && utp_analyze_seq) {
+ guint remaining_bytes;
+ remaining_bytes = tvb_reported_length_remaining(tvb, offset);
+ if(plen>remaining_bytes) {
+ pinfo->want_pdu_tracking=2;
+ pinfo->bytes_until_next_pdu=plen-remaining_bytes;
+ }
+ }
+
+ /*
+ * Can we do reassembly?
+ */
+ if (proto_desegment && pinfo->can_desegment) {
+ /*
+ * Yes - is the PDU split across segment boundaries?
+ */
+ if (captured_length_remaining < plen) {
+ /*
+ * Yes. Tell the TCP dissector where the data for this message
+ * starts in the data it handed us, and how many more bytes we
+ * need, and return.
+ */
+ pinfo->desegment_offset = offset;
+ pinfo->desegment_len = plen - captured_length_remaining;
+ return;
+ }
+ }
+
+ curr_layer_num = pinfo->curr_layer_num-1;
+ frame = wmem_list_frame_prev(wmem_list_tail(pinfo->layers));
+ while (frame && (proto_bt_utp != (gint) GPOINTER_TO_UINT(wmem_list_frame_data(frame)))) {
+ frame = wmem_list_frame_prev(frame);
+ curr_layer_num--;
+ }
+#if 0
+ if (captured_length_remaining >= plen || there are more packets)
+ {
+#endif
+ /*
+ * Display the PDU length as a field
+ */
+ item=proto_tree_add_uint(((utp_info_t *)p_get_proto_data(pinfo->pool, pinfo, proto_bt_utp, curr_layer_num))->tree,
+ hf_bt_utp_pdu_size,
+ tvb, offset, plen, plen);
+ proto_item_set_generated(item);
+#if 0
+ } else {
+ item = proto_tree_add_expert_format((proto_tree *)p_get_proto_data(pinfo->pool, pinfo, proto_bt_utp, curr_layer_num),
+ tvb, offset, -1,
+ "PDU Size: %u cut short at %u",plen,captured_length_remaining);
+ proto_item_set_generated(item);
+ }
+#endif
+
+ /*
+ * Construct a tvbuff containing the amount of the payload we have
+ * available. Make its reported length the amount of data in the PDU.
+ */
+ length = captured_length_remaining;
+ if (length > plen) {
+ length = plen;
+ }
+ next_tvb = tvb_new_subset_length_caplen(tvb, offset, length, plen);
+ if (!(proto_desegment && pinfo->can_desegment)) {
+ /* If we can't do reassembly, give a hint that bounds errors
+ * are probably fragment errors. */
+ tvb_set_fragment(next_tvb);
+ }
+
+ /*
+ * Dissect the PDU.
+ *
+ * If it gets an error that means there's no point in
+ * dissecting any more PDUs, rethrow the exception in
+ * question.
+ *
+ * If it gets any other error, report it and continue, as that
+ * means that PDU got an error, but that doesn't mean we should
+ * stop dissecting PDUs within this frame or chunk of reassembled
+ * data.
+ */
+ saved_proto = pinfo->current_proto;
+ TRY {
+ (*dissect_pdu)(next_tvb, pinfo, tree, dissector_data);
+ }
+ CATCH_NONFATAL_ERRORS {
+ show_exception(tvb, pinfo, tree, EXCEPT_CODE, GET_MESSAGE);
+ /*
+ * Restore the saved protocol as well; we do this after
+ * show_exception(), so that the "Malformed packet" indication
+ * shows the protocol for which dissection failed.
+ */
+ pinfo->current_proto = saved_proto;
+ }
+ ENDTRY;
+
+ /*
+ * Step to the next PDU.
+ * Make sure we don't overflow.
+ */
+ offset_before = offset;
+ offset += plen;
+ if (offset <= offset_before)
+ break;
+ }
+}
+
static gint
get_utp_version(tvbuff_t *tvb) {
guint8 v0_flags;
@@ -335,7 +691,7 @@ dissect_utp_header_v0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
p_utp_info = wmem_new(pinfo->pool, utp_info_t);
p_utp_info->v0 = TRUE;
- p_add_proto_data(pinfo->pool, pinfo, proto_bt_utp, 0, p_utp_info);
+ p_add_proto_data(pinfo->pool, pinfo, proto_bt_utp, pinfo->curr_layer_num, p_utp_info);
proto_tree_add_item_ret_uint(tree, hf_bt_utp_connection_id_v0, tvb, offset, 4, ENC_BIG_ENDIAN, &connection);
offset += 4;
@@ -393,7 +749,7 @@ dissect_utp_header_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
p_utp_info = wmem_new(pinfo->pool, utp_info_t);
p_utp_info->v0 = FALSE;
- p_add_proto_data(pinfo->pool, pinfo, proto_bt_utp, 0, p_utp_info);
+ p_add_proto_data(pinfo->pool, pinfo, proto_bt_utp, pinfo->curr_layer_num, p_utp_info);
proto_tree_add_item(tree, hf_bt_utp_ver, tvb, offset, 1, ENC_BIG_ENDIAN);
proto_tree_add_item_ret_uint(tree, hf_bt_utp_type, tvb, offset, 1, ENC_BIG_ENDIAN, &type);
@@ -508,6 +864,158 @@ dissect_utp_extension(tvbuff_t *tvb, packet_info _U_*pinfo, proto_tree *tree, in
return offset;
}
+gboolean
+decode_utp(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree)
+{
+ proto_tree *parent_tree;
+ tvbuff_t *next_tvb;
+ int save_desegment_offset;
+ guint32 save_desegment_len;
+
+ /* XXX: Check for retransmission? */
+
+ next_tvb = tvb_new_subset_remaining(tvb, offset);
+
+ save_desegment_offset = pinfo->desegment_offset;
+ save_desegment_len = pinfo->desegment_len;
+
+ /* The only possible payload is bittorrent */
+
+ parent_tree = proto_tree_get_parent_tree(tree);
+ if (call_dissector_with_data(bittorrent_handle, next_tvb, pinfo, parent_tree, NULL)) {
+ pinfo->want_pdu_tracking -= !!(pinfo->want_pdu_tracking);
+ return TRUE;
+ }
+
+ DISSECTOR_ASSERT(save_desegment_offset == pinfo->desegment_offset &&
+ save_desegment_len == pinfo->desegment_len);
+
+ call_data_dissector(tvb, pinfo, parent_tree);
+ pinfo->want_pdu_tracking -= !!(pinfo->want_pdu_tracking);
+
+ return FALSE;
+}
+
+static void
+process_utp_payload(tvbuff_t *tvb, packet_info *pinfo,
+ proto_tree *tree, guint16 seq, gboolean is_utp_segment,
+ utp_stream_info_t *stream_info)
+{
+ volatile int offset = 0;
+ pinfo->want_pdu_tracking = 0;
+
+ TRY {
+ if (is_utp_segment) {
+ /* See if an unaligned PDU */
+ if (stream_info && utp_analyze_seq && (!utp_desegment)) {
+ offset = scan_for_next_pdu(tvb, tree, pinfo,
+ stream_info->fwd->multisegment_pdus);
+ }
+ }
+
+ if ((offset != -1) && decode_utp(tvb, offset, pinfo, tree)) {
+ /*
+ * We succeeded in handing off to bittorent.
+ *
+ * Is this a segment (so we're not desegmenting for whatever
+ * reason)? Then at least do rudimentary PDU tracking.
+ */
+ if(is_utp_segment) {
+ /* if !visited, check want_pdu_tracking and
+ store it in table */
+ if(stream_info && (!pinfo->fd->visited) &&
+ utp_analyze_seq && pinfo->want_pdu_tracking) {
+ pdu_store_sequencenumber_of_next_pdu(
+ pinfo,
+ seq,
+ offset,
+ pinfo->bytes_until_next_pdu,
+ stream_info->fwd->multisegment_pdus);
+ }
+ }
+ }
+ }
+ CATCH_ALL {
+ /* We got an exception. Before dissection is aborted and execution
+ * is transferred back to (probably) the frame dissector, do PDU
+ * tracking if we need to because this is a segment.
+ */
+ if (is_utp_segment) {
+ if(stream_info && (!pinfo->fd->visited) &&
+ utp_analyze_seq && pinfo->want_pdu_tracking) {
+ pdu_store_sequencenumber_of_next_pdu(
+ pinfo,
+ seq,
+ offset,
+ pinfo->bytes_until_next_pdu,
+ stream_info->fwd->multisegment_pdus);
+ }
+ }
+ RETHROW;
+ }
+ ENDTRY;
+}
+
+static guint
+dissect_utp_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *ti;
+
+ utp_info_t *p_utp_info;
+ guint len_tvb;
+ gboolean save_fragmented;
+
+ p_utp_info = (utp_info_t *)p_get_proto_data(pinfo->pool, pinfo, proto_bt_utp, pinfo->curr_layer_num);
+
+ p_utp_info->tree = tree;
+
+ utp_stream_info_t *stream_info;
+ stream_info = get_utp_stream_info(pinfo, p_utp_info);
+
+ len_tvb = tvb_reported_length(tvb);
+
+ /* As with TCP, if we've been handed an IP fragment, we don't really
+ * know how big the segment is, and we don't really want to do anything
+ * if this is an error packet from ICMP or similar.
+ *
+ * XXX: We don't want to desegment if the UDP checksum is bad either.
+ * Need to add that to the per-packet info that UDP stores and access
+ * it.
+ */
+ pinfo->can_desegment = 0;
+ if (!pinfo->fragmented && !pinfo->flags.in_error_pkt) {
+ p_utp_info->seglen = len_tvb;
+ p_utp_info->have_seglen = TRUE;
+
+ ti = proto_tree_add_uint(tree, hf_bt_utp_len, tvb, 0, 0, len_tvb);
+ proto_item_set_generated(ti);
+ col_append_str_uint(pinfo->cinfo, COL_INFO, "Len", len_tvb, " ");
+
+ if (utp_desegment && tvb_bytes_exist(tvb, 0, len_tvb)) {
+ /* If we actually have the bytes too then we can desegment. */
+ pinfo->can_desegment = 2;
+ }
+ } else {
+ p_utp_info->have_seglen = FALSE;
+ }
+
+ if(tvb_captured_length(tvb)) {
+ proto_tree_add_item(tree, hf_bt_utp_data, tvb, 0, len_tvb, ENC_NA);
+ if (pinfo->can_desegment) {
+ /* XXX: desegment_utp() is not implemented, but we can't get
+ * into this code path yet because utp_desegment is FALSE. */
+ } else {
+ save_fragmented = pinfo->fragmented;
+ pinfo->fragmented = TRUE;
+ process_utp_payload(tvb, pinfo, tree, p_utp_info->seq, TRUE, stream_info);
+ pinfo->fragmented = save_fragmented;
+ }
+ }
+
+ return len_tvb;
+}
+
static int
dissect_bt_utp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
@@ -517,7 +1025,6 @@ dissect_bt_utp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _
/* try dissecting */
if (version >= 0)
{
- guint len_tvb;
proto_tree *sub_tree = NULL;
proto_item *ti;
gint offset = 0;
@@ -542,15 +1049,9 @@ dissect_bt_utp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _
offset = dissect_utp_extension(tvb, pinfo, sub_tree, offset, &extension_type);
- len_tvb = tvb_reported_length_remaining(tvb, offset);
- if(len_tvb > 0) {
- col_append_str_uint(pinfo->cinfo, COL_INFO, "Len", len_tvb, " ");
- proto_tree_add_item(sub_tree, hf_bt_utp_data, tvb, offset, len_tvb, ENC_NA);
- utp_info_t *p_utp_info = (utp_info_t *)p_get_proto_data(pinfo->pool, pinfo, proto_bt_utp, 0);
- p_utp_info->seglen = len_tvb;
- }
+ offset += dissect_utp_payload(tvb_new_subset_remaining(tvb, offset), pinfo, sub_tree);
- return offset+len_tvb;
+ return tvb_reported_length(tvb);
}
return 0;
}
@@ -675,11 +1176,26 @@ proto_register_bt_utp(void)
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
+ { &hf_bt_utp_len,
+ { "uTP Segment Len", "bt-utp.len",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
{ &hf_bt_utp_data,
{ "Data", "bt-utp.data",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
+ { &hf_bt_utp_pdu_size,
+ { "PDU Size", "bt-utp.pdu.size",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "The size of this PDU", HFILL }
+ },
+ { &hf_bt_utp_continuation_to,
+ { "This is a continuation to the PDU in frame",
+ "bt-utp.continuation_to", FT_FRAMENUM, BASE_NONE,
+ NULL, 0x0, "This is a continuation to the PDU in frame #", HFILL }
+ },
};
/* Setup protocol subtree array */
@@ -693,6 +1209,14 @@ proto_register_bt_utp(void)
bt_utp_module = prefs_register_protocol(proto_bt_utp, NULL);
prefs_register_obsolete_preference(bt_utp_module, "enable");
prefs_register_bool_preference(bt_utp_module,
+ "analyze_sequence_numbers",
+ "Analyze uTP sequence numbers",
+ "Make the uTP dissector analyze uTP sequence numbers. Currently this "
+ "just means that it tries to find the correct start offset of a PDU "
+ "if it detected that previous in-order packets spanned multiple "
+ "frames.",
+ &utp_analyze_seq);
+ prefs_register_bool_preference(bt_utp_module,
"enable_version0",
"Dissect prerelease (version 0) packets",
"Whether the dissector should attempt to dissect packets with the "
@@ -726,6 +1250,8 @@ proto_reg_handoff_bt_utp(void)
bt_utp_handle = create_dissector_handle(dissect_bt_utp, proto_bt_utp);
dissector_add_for_decode_as_with_preference("udp.port", bt_utp_handle);
+
+ bittorrent_handle = find_dissector_add_dependency("bittorrent.utp", proto_bt_utp);
}
/*
diff --git a/epan/dissectors/packet-bt-utp.h b/epan/dissectors/packet-bt-utp.h
index e21e62cee4..4074c0742b 100644
--- a/epan/dissectors/packet-bt-utp.h
+++ b/epan/dissectors/packet-bt-utp.h
@@ -19,13 +19,12 @@
extern "C" {
#endif /* __cplusplus */
-#if 0
-WS_DLL_PUBLIC void
+/* bittorent is the only protocol on uTP, so extern not WS_DLL_PUBLIC */
+extern void
utp_dissect_pdus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
gboolean proto_desegment, guint fixed_len,
guint (*get_pdu_len)(packet_info *, tvbuff_t *, int, void*),
dissector_t dissect_pdu, void* dissector_data);
-#endif
#ifdef __cplusplus
}