aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Thacker <johnthacker@gmail.com>2021-10-12 19:47:34 -0400
committerWireshark GitLab Utility <gerald+gitlab-utility@wireshark.org>2021-10-13 04:37:21 +0000
commitc6e44fb00c6e94e5037fbc1b54eacc202b432e0c (patch)
treebaa4ee0101178409bc59fe74e4258c93f93d7763
parentabcadce44fab895afc4aa01531122972c9ef9ede (diff)
BT-uTP: Track conversations
Add endpoint type for uTP connection IDs. Manage uTP conversations, creating generated stream ID to filter on both sides of a conversation. Display more information in INFO column, similar to TCP. This is some progress towards #8792.
-rw-r--r--epan/conversation.h4
-rw-r--r--epan/dissectors/packet-bt-utp.c213
-rw-r--r--epan/dissectors/packet-bt-utp.h34
3 files changed, 232 insertions, 19 deletions
diff --git a/epan/conversation.h b/epan/conversation.h
index c920e09ee1..991d99f66b 100644
--- a/epan/conversation.h
+++ b/epan/conversation.h
@@ -80,7 +80,9 @@ typedef enum {
ENDPOINT_GSMTAP,
ENDPOINT_IUUP,
ENDPOINT_DVBBBF, /* DVB Base Band Frame ISI/PLP_ID */
- ENDPOINT_IWARP_MPA /* iWarp MPA */
+ ENDPOINT_IWARP_MPA, /* iWarp MPA */
+ ENDPOINT_BT_UTP, /* BitTorrent uTP Connection ID */
+
} endpoint_type;
/**
diff --git a/epan/dissectors/packet-bt-utp.c b/epan/dissectors/packet-bt-utp.c
index b231c7087c..974840695e 100644
--- a/epan/dissectors/packet-bt-utp.c
+++ b/epan/dissectors/packet-bt-utp.c
@@ -1,6 +1,7 @@
/* packet-bt-utp.c
* Routines for BT-UTP dissection
* Copyright 2011, Xiao Xiangquan <xiaoxiangquan@gmail.com>
+ * Copyright 2021, John Thacker <johnthacker@gmail.com>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
@@ -14,6 +15,10 @@
#include <epan/packet.h>
#include <epan/conversation.h>
#include <epan/prefs.h>
+#include <epan/proto_data.h>
+
+#include "packet-udp.h"
+#include "packet-bt-utp.h"
void proto_register_bt_utp(void);
void proto_reg_handoff_bt_utp(void);
@@ -135,6 +140,7 @@ static int hf_bt_utp_extension_bitmask = -1;
static int hf_bt_utp_extension_unknown = -1;
static int hf_bt_utp_connection_id_v0 = -1;
static int hf_bt_utp_connection_id_v1 = -1;
+static int hf_bt_utp_stream = -1;
static int hf_bt_utp_timestamp_sec = -1;
static int hf_bt_utp_timestamp_us = -1;
static int hf_bt_utp_timestamp_diff_us = -1;
@@ -150,6 +156,106 @@ static gint ett_bt_utp_extension = -1;
static gboolean enable_version0 = FALSE;
static guint max_window_size = V1_MAX_WINDOW_SIZE;
+static guint32 bt_utp_stream_count = 0;
+
+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];
+ nstime_t ts_first;
+ nstime_t ts_prev;
+ guint8 conversation_completeness;
+#endif
+} utp_stream_info_t;
+
+/* Per-packet header information. */
+typedef struct {
+ guint8 type;
+ gboolean v0;
+ guint32 connection; /* The prelease "V0" version is 32 bit */
+ guint32 stream;
+ guint16 seq;
+ guint16 ack;
+ guint32 seglen; /* reported length remaining */
+} utp_info_t;
+
+static utp_stream_info_t*
+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;
+
+ /* Handle connection ID wrapping correctly. (Mainline libutp source
+ * does not appear to do this, probably fails to connect if the random
+ * connection ID is GMAX_UINT16 and tries again.)
+ */
+ if (utp_info->v0) {
+ id_up = utp_info->connection+1;
+ id_down = utp_info->connection-1;
+ } else {
+ id_up = (guint16)(utp_info->connection+1);
+ id_down = (guint16)(utp_info->connection-1);
+ }
+
+ if (utp_info->type == ST_SYN) {
+ /* SYN packets are special, they have the connection ID for the other
+ * side, and allow us to know both.
+ */
+ conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, ENDPOINT_BT_UTP,
+ id_up, utp_info->connection, 0);
+ if (!conv) {
+ /* XXX: A SYN for between the same pair of hosts with a duplicate
+ * connection ID in the same direction is almost surely a retransmission
+ * (unless there's a client that doesn't actually generate random IDs.)
+ * We could check to see if we've gotten a FIN or RST on that same
+ * connection, and also could do like TCP and see if the initial sequence
+ * number matches. (The latter still doesn't help if the client also
+ * doesn't start with random sequence numbers.)
+ */
+ conv = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst, ENDPOINT_BT_UTP, id_up, utp_info->connection, 0);
+ }
+ } else {
+ /* For non-SYN packets, we know our connection ID, but we don't know if
+ * the other side has our ID+1 (src initiated the connection) or our ID-1
+ * (dst initiated). We also don't want find_conversation() to accidentally
+ * call conversation_set_port2() with the wrong ID. So first we see if
+ * we have a wildcarded conversation around (if we've seen previous
+ * non-SYN packets from our current direction but none in the other.)
+ */
+ conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, ENDPOINT_BT_UTP, utp_info->connection, 0, NO_PORT_B);
+ if (!conv) {
+ /* Do we have a complete conversation originated by our src, or
+ * possibly a wildcarded conversation originated in this direction
+ * (but we saw a non-SYN for the non-initiating side first)? */
+ conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, ENDPOINT_BT_UTP, utp_info->connection, id_up, 0);
+ if (!conv) {
+ /* As above, but dst initiated? */
+ conv = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, ENDPOINT_BT_UTP, utp_info->connection, id_down, 0);
+ if (!conv) {
+ /* Didn't find it, so create a new wildcarded conversation. When we
+ * get a packet for the other direction, find_conversation() above
+ * will set port2 with the other connection ID.
+ */
+ conv = conversation_new(pinfo->num, &pinfo->src, &pinfo->dst, ENDPOINT_BT_UTP, utp_info->connection, 0, NO_PORT2);
+ }
+ }
+ }
+ }
+
+ stream_info = (utp_stream_info_t *)conversation_get_proto_data(conv, proto_bt_utp);
+ if (!stream_info) {
+ stream_info = wmem_new0(wmem_file_scope(), utp_stream_info_t);
+ stream_info->stream = bt_utp_stream_count++;
+ conversation_add_proto_data(conv, proto_bt_utp, stream_info);
+ }
+
+ return stream_info;
+}
+
static gint
get_utp_version(tvbuff_t *tvb) {
guint8 v0_flags;
@@ -220,8 +326,18 @@ get_utp_version(tvbuff_t *tvb) {
static int
dissect_utp_header_v0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint8 *extension_type)
{
- /* "Original" (V0) */
- proto_tree_add_item(tree, hf_bt_utp_connection_id_v0, tvb, offset, 4, ENC_BIG_ENDIAN);
+ /* "Original" (V0) */
+ utp_info_t *p_utp_info = NULL;
+ utp_stream_info_t *stream_info = NULL;
+
+ proto_item *ti;
+ guint32 type, connection, win, seq, ack;
+
+ 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);
+
+ proto_tree_add_item_ret_uint(tree, hf_bt_utp_connection_id_v0, tvb, offset, 4, ENC_BIG_ENDIAN, &connection);
offset += 4;
proto_tree_add_item(tree, hf_bt_utp_timestamp_sec, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
@@ -229,20 +345,38 @@ dissect_utp_header_v0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int o
offset += 4;
proto_tree_add_item(tree, hf_bt_utp_timestamp_diff_us, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
- proto_tree_add_item(tree, hf_bt_utp_wnd_size_v0, tvb, offset, 1, ENC_BIG_ENDIAN);
+ proto_tree_add_item_ret_uint(tree, hf_bt_utp_wnd_size_v0, tvb, offset, 1, ENC_BIG_ENDIAN, &win);
offset += 1;
proto_tree_add_item(tree, hf_bt_utp_next_extension_type, tvb, offset, 1, ENC_BIG_ENDIAN);
-
*extension_type = tvb_get_guint8(tvb, offset);
offset += 1;
- proto_tree_add_item(tree, hf_bt_utp_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
- col_append_fstr(pinfo->cinfo, COL_INFO, " Type: %s", val_to_str(tvb_get_guint8(tvb, offset), bt_utp_type_vals, "Unknown %d"));
+ proto_tree_add_item_ret_uint(tree, hf_bt_utp_flags, tvb, offset, 1, ENC_BIG_ENDIAN, &type);
offset += 1;
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, "Connection ID:%d [%s]", connection, val_to_str(type, bt_utp_type_vals, "Unknown %d"));
+ p_utp_info->type = type;
+ p_utp_info->connection = connection;
+
proto_tree_add_item(tree, hf_bt_utp_seq_nr, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_bt_utp_ack_nr, tvb, offset, 2, ENC_BIG_ENDIAN);
offset += 2;
+ proto_tree_add_item_ret_uint(tree, hf_bt_utp_seq_nr, tvb, offset, 2, ENC_BIG_ENDIAN, &seq);
+ col_append_str_uint(pinfo->cinfo, COL_INFO, "Seq", seq, " ");
+ p_utp_info->seq = seq;
+ offset += 2;
+ proto_tree_add_item_ret_uint(tree, hf_bt_utp_ack_nr, tvb, offset, 2, ENC_BIG_ENDIAN, &ack);
+ col_append_str_uint(pinfo->cinfo, COL_INFO, "Ack", ack, " ");
+ p_utp_info->ack = ack;
+ offset += 2;
+ col_append_str_uint(pinfo->cinfo, COL_INFO, "Win", win, " ");
+
+ stream_info = get_utp_stream_info(pinfo, p_utp_info);
+ ti = proto_tree_add_uint(tree, hf_bt_utp_stream, tvb, offset, 0, stream_info->stream);
+ p_utp_info->stream = stream_info->stream;
+ proto_item_set_generated(ti);
+
return offset;
}
@@ -250,26 +384,55 @@ static int
dissect_utp_header_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint8 *extension_type)
{
/* V1 */
+ utp_info_t *p_utp_info = NULL;
+ utp_stream_info_t *stream_info = NULL;
+
+ proto_item *ti;
+
+ guint32 type, connection, win, seq, ack;
+
+ 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);
+
proto_tree_add_item(tree, hf_bt_utp_ver, tvb, offset, 1, ENC_BIG_ENDIAN);
- proto_tree_add_item(tree, hf_bt_utp_type, tvb, offset, 1, ENC_BIG_ENDIAN);
- col_append_fstr(pinfo->cinfo, COL_INFO, " Type: %s", val_to_str((tvb_get_guint8(tvb, offset) >> 4), bt_utp_type_vals, "Unknown %d"));
+ proto_tree_add_item_ret_uint(tree, hf_bt_utp_type, tvb, offset, 1, ENC_BIG_ENDIAN, &type);
offset += 1;
proto_tree_add_item(tree, hf_bt_utp_next_extension_type, tvb, offset, 1, ENC_BIG_ENDIAN);
*extension_type = tvb_get_guint8(tvb, offset);
offset += 1;
- proto_tree_add_item(tree, hf_bt_utp_connection_id_v1, tvb, offset, 2, ENC_BIG_ENDIAN);
+ proto_tree_add_item_ret_uint(tree, hf_bt_utp_connection_id_v1, tvb, offset, 2, ENC_BIG_ENDIAN, &connection);
offset += 2;
+
+ col_append_fstr(pinfo->cinfo, COL_INFO, "Connection ID:%d [%s]", connection, val_to_str(type, bt_utp_type_vals, "Unknown %d"));
+ p_utp_info->type = type;
+ p_utp_info->connection = connection;
+
proto_tree_add_item(tree, hf_bt_utp_timestamp_us, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
proto_tree_add_item(tree, hf_bt_utp_timestamp_diff_us, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
- proto_tree_add_item(tree, hf_bt_utp_wnd_size_v1, tvb, offset, 4, ENC_BIG_ENDIAN);
+ proto_tree_add_item_ret_uint(tree, hf_bt_utp_wnd_size_v1, tvb, offset, 4, ENC_BIG_ENDIAN, &win);
offset += 4;
- proto_tree_add_item(tree, hf_bt_utp_seq_nr, tvb, offset, 2, ENC_BIG_ENDIAN);
+ proto_tree_add_item_ret_uint(tree, hf_bt_utp_seq_nr, tvb, offset, 2, ENC_BIG_ENDIAN, &seq);
+ col_append_str_uint(pinfo->cinfo, COL_INFO, "Seq", seq, " ");
+ p_utp_info->seq = seq;
offset += 2;
- proto_tree_add_item(tree, hf_bt_utp_ack_nr, tvb, offset, 2, ENC_BIG_ENDIAN);
+ proto_tree_add_item_ret_uint(tree, hf_bt_utp_ack_nr, tvb, offset, 2, ENC_BIG_ENDIAN, &ack);
+ col_append_str_uint(pinfo->cinfo, COL_INFO, "Ack", ack, " ");
+ p_utp_info->ack = ack;
offset += 2;
+ col_append_str_uint(pinfo->cinfo, COL_INFO, "Win", win, " ");
+ stream_info = get_utp_stream_info(pinfo, p_utp_info);
+ ti = proto_tree_add_uint(tree, hf_bt_utp_stream, tvb, offset, 0, stream_info->stream);
+ p_utp_info->stream = stream_info->stream;
+ proto_item_set_generated(ti);
+
+ /* XXX: Multisegment PDUs are the top priority to add, but a number of
+ * other features in the TCP dissector would be useful- relative sequence
+ * numbers, conversation completeness, maybe even tracking SACKs.
+ */
return offset;
}
@@ -362,10 +525,7 @@ dissect_bt_utp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _
/* set the protocol column */
col_set_str(pinfo->cinfo, COL_PROTOCOL, "BT-uTP");
- /* set the info column */
- col_set_str( pinfo->cinfo, COL_INFO, "uTorrent Transport Protocol" );
-
- len_tvb = tvb_reported_length(tvb);
+ col_clear(pinfo->cinfo, COL_INFO);
/* Determine header version */
@@ -382,9 +542,13 @@ 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_captured_length_remaining(tvb, offset);
- if(len_tvb > 0)
+ 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;
+ }
return offset+len_tvb;
}
@@ -411,6 +575,12 @@ dissect_bt_utp_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *d
return FALSE;
}
+static void
+utp_init(void)
+{
+ bt_utp_stream_count = 0;
+}
+
void
proto_register_bt_utp(void)
{
@@ -465,6 +635,11 @@ proto_register_bt_utp(void)
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
+ { &hf_bt_utp_stream,
+ { "Stream index", "bt-utp.stream",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ NULL, HFILL }
+ },
{ &hf_bt_utp_timestamp_sec,
{ "Timestamp seconds", "bt-utp.timestamp_sec",
FT_UINT32, BASE_DEC, NULL, 0x0,
@@ -535,6 +710,8 @@ proto_register_bt_utp(void)
proto_register_field_array(proto_bt_utp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
+
+ register_init_routine(utp_init);
}
void
diff --git a/epan/dissectors/packet-bt-utp.h b/epan/dissectors/packet-bt-utp.h
new file mode 100644
index 0000000000..e21e62cee4
--- /dev/null
+++ b/epan/dissectors/packet-bt-utp.h
@@ -0,0 +1,34 @@
+/* packet-bt-utp.h
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef __PACKET_BT_UTP_H__
+#define __PACKET_BT_UTP_H__
+
+#include "ws_symbol_export.h"
+
+#include <epan/conversation.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#if 0
+WS_DLL_PUBLIC 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
+}
+#endif /* __cplusplus */
+
+#endif