aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/dissectors/packet-bt-dht.c82
1 files changed, 55 insertions, 27 deletions
diff --git a/epan/dissectors/packet-bt-dht.c b/epan/dissectors/packet-bt-dht.c
index 10f2ac2411..b53f89f67a 100644
--- a/epan/dissectors/packet-bt-dht.c
+++ b/epan/dissectors/packet-bt-dht.c
@@ -24,11 +24,14 @@
#include <wsutil/strtoi.h>
+#define DHT_MIN_LEN 5
+
void proto_register_bt_dht(void);
void proto_reg_handoff_bt_dht(void);
-/* Specifications: BEP-0005
- * http://www.bittorrent.org/beps/bep_0005.html
+/* Specifications:
+ * https://www.bittorrent.org/beps/bep_0005.html BEP 5 DHT Protocol
+ * https://www.bittorrent.org/beps/bep_0042.html BEP 42 DHT Security extension
*/
static int proto_bt_dht = -1;
@@ -67,21 +70,21 @@ static gint ett_bt_dht_nodes = -1;
/* some keys use short name in packet */
static const value_string short_key_name_value_string[] = {
- { 'y', "Message type" },
- { 'q', "Request type" },
+ { 'a', "Request arguments" },
{ 'e', "Error" },
+ { 'q', "Request type" },
+ { 'r', "Response values" },
{ 't', "Transaction ID" },
{ 'v', "Version" },
- { 'a', "Request arguments" },
- { 'r', "Response values" },
+ { 'y', "Message type" },
{ 0, NULL }
};
/* some values use short name in packet */
static const value_string short_val_name_value_string[] = {
+ { 'e', "Error" },
{ 'q', "Request" },
{ 'r', "Response" },
- { 'e', "Error" },
{ 0, NULL }
};
@@ -441,20 +444,28 @@ dissect_bencoded_dict_entry(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
else if( strcmp(key,"ip")==0 )
{
/*
- * Not found in BEP 0005 but explained by
- * http://www.rasterbar.com/products/libtorrent/dht_sec.html
+ * BEP 42 DHT Security extension
+ * https://www.bittorrent.org/beps/bep_0042.html
+ * https://www.rasterbar.com/products/libtorrent/dht_sec.html
*/
int len, old_offset;
old_offset = offset;
len = bencoded_string_length(pinfo, tvb, &offset);
- if(len == 4) {
- proto_tree_add_item(sub_tree, hf_ip, tvb, offset, len, ENC_BIG_ENDIAN);
+ if(len == 6) {
+ proto_tree_add_item(sub_tree, hf_ip, tvb, offset, 4, ENC_BIG_ENDIAN);
val = tvb_ip_to_str(pinfo->pool, tvb, offset);
- offset += len;
+ offset += 4;
+ proto_tree_add_item(sub_tree, hf_port, tvb, offset, 2, ENC_BIG_ENDIAN);
+ offset += 2;
}
else {
+ /* XXX: BEP 42 doesn't mention IPv6 and predates the IPv6 DHT;
+ * it doesn't make sense for IPv6 because the purpose is to tell
+ * the requestor its own publicly routable IP address and port
+ * (working around NAT). So any other length than 6 is unexpected.
+ */
offset = dissect_bencoded_string( tvb, pinfo, sub_tree, old_offset, &val, TRUE, "Value" );
}
}
@@ -530,20 +541,35 @@ static gboolean
test_bt_dht(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
{
- /* try dissecting */
- /* Assume dictionary (d) is followed by a one char long (1:) key string. */
-
- if(tvb_captured_length_remaining(tvb, offset) < 4)
- return FALSE;
+ /* The DHT KRPC protocol sends packets that are bencoded dictionaries.
+ * Bencoded dictionaries always have the keys in sorted (raw string)
+ * order. There are three possible message types, query, which has "a" and
+ * "q" keys that map to dictionaries, response, which has an "r" key
+ * that maps to a dictionary, and error, which has an "e" key that maps
+ * to a list.
+ *
+ * Conveniently, those keys appear in sort order before all other possible
+ * top level keys, with the exception of the "ip" key added in BEP-0042.
+ *
+ * Thus, there are only four possible initial sets of bytes, corresponding
+ * to beginning with an "a" dictionary, "r" dictionary, "ip" string, or an
+ * "e" list.
+ */
- if(tvb_memeql(tvb, offset, "d1:", 3) != 0)
+ if (tvb_captured_length_remaining(tvb, offset) < DHT_MIN_LEN)
return FALSE;
- /* Is 'key' a valid key ? */
- if(try_val_to_str(tvb_get_guint8(tvb, offset+3), short_key_name_value_string) == NULL)
- return FALSE;
+ if (tvb_memeql(tvb, offset, "d1:ad", 5) == 0) {
+ return TRUE;
+ } else if (tvb_memeql(tvb, offset, "d1:rd", 5) == 0) {
+ return TRUE;
+ } else if (tvb_memeql(tvb, offset, "d2:ip", 5) == 0) {
+ return TRUE;
+ } else if (tvb_memeql(tvb, offset, "d1:el", 5) == 0) {
+ return TRUE;
+ }
- return TRUE;
+ return FALSE;
}
static int
@@ -562,6 +588,12 @@ dissect_bt_dht(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
col_clear(pinfo->cinfo, COL_INFO);
col_set_str(pinfo->cinfo, COL_INFO, "BitTorrent DHT Protocol");
+ /* XXX: There is a separate "bencode" dissector. Would it be possible
+ * to use it, at least to move some functions into a shared header?
+ * DHT has some keys with special meanings, and some values that
+ * are supposed to be interpreted specially (e.g., IP/port combinations),
+ * so maybe it's more trouble than it's worth.
+ */
return dissect_bencoded_dict(tvb, pinfo, tree, 0, "BitTorrent DHT Protocol");
}
@@ -687,11 +719,7 @@ proto_register_bt_dht(void)
void
proto_reg_handoff_bt_dht(void)
{
- /* "Decode As" is always available;
- * Heuristic dissection in disabled by default since the heuristic is quite weak.
- * XXX - Still too weak?
- */
- heur_dissector_add("udp", dissect_bt_dht_heur, "BitTorrent DHT over UDP", "bittorrent_dht_udp", proto_bt_dht, HEURISTIC_DISABLE);
+ heur_dissector_add("udp", dissect_bt_dht_heur, "BitTorrent DHT over UDP", "bittorrent_dht_udp", proto_bt_dht, HEURISTIC_ENABLE);
bt_dht_handle = create_dissector_handle(dissect_bt_dht, proto_bt_dht);
dissector_add_for_decode_as_with_preference("udp.port", bt_dht_handle);