2 * Routines for BitTorrent Tracker over UDP dissection
3 * Copyright 2023, Ivan Nardi <nardi.ivan@gmail.com>
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1999 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include <epan/packet.h>
15 #include <epan/conversation.h>
16 #include <epan/to_str.h>
17 #include <epan/prefs.h>
18 #include <epan/unit_strings.h>
20 void proto_register_bt_tracker(void);
21 void proto_reg_handoff_bt_tracker(void);
24 * https://www.bittorrent.org/beps/bep_0015.html BEP 15 UDP Tracker Protocol for BitTorrent
25 * https://www.bittorrent.org/beps/bep_0041.html BEP 41 UDP Tracker Protocol Extensions
36 MSG_TYPE_CONNECT_REQUEST
,
37 MSG_TYPE_CONNECT_RESPONSE
,
38 MSG_TYPE_ANNOUNCE_REQUEST
,
39 MSG_TYPE_ANNOUNCE_RESPONSE
,
40 MSG_TYPE_SCRAPE_REQUEST
,
41 MSG_TYPE_SCRAPE_RESPONSE
,
42 MSG_TYPE_ERROR_RESPONSE
,
47 static const value_string bt_tracker_msg_type_vals
[] = {
48 { MSG_TYPE_CONNECT_REQUEST
, "Connection Request" },
49 { MSG_TYPE_CONNECT_RESPONSE
, "Connection Response" },
50 { MSG_TYPE_ANNOUNCE_REQUEST
, "Announce Request" },
51 { MSG_TYPE_ANNOUNCE_RESPONSE
, "Announce Response" },
52 { MSG_TYPE_SCRAPE_REQUEST
, "Scrape Request" },
53 { MSG_TYPE_SCRAPE_RESPONSE
, "Scrape Response" },
54 { MSG_TYPE_ERROR_RESPONSE
, "Error Response" },
58 static const value_string bt_tracker_event_vals
[] = {
66 static const value_string bt_tracker_action_vals
[] = {
67 { ACTION_CONNECT
, "Connect" },
68 { ACTION_ANNOUNCE
, "Announce" },
69 { ACTION_SCRAPE
, "Scrape" },
70 { ACTION_ERROR
, "Error" },
75 EXT_END_OF_OPTIONS
= 0,
81 static const value_string bt_tracker_extension_type_vals
[] = {
82 { EXT_END_OF_OPTIONS
, "End of Options" },
84 { EXT_URLDATA
, "URL Data" },
88 static int proto_bt_tracker
;
89 static dissector_handle_t bt_tracker_handle
;
91 static int hf_bt_tracker_msg_type
;
92 static int hf_bt_tracker_protocol_id
;
93 static int hf_bt_tracker_action
;
94 static int hf_bt_tracker_transaction_id
;
95 static int hf_bt_tracker_connection_id
;
96 static int hf_bt_tracker_info_hash
;
97 static int hf_bt_tracker_peer_id
;
98 static int hf_bt_tracker_downloaded
;
99 static int hf_bt_tracker_left
;
100 static int hf_bt_tracker_uploaded
;
101 static int hf_bt_tracker_event
;
102 static int hf_bt_tracker_ip_address
;
103 static int hf_bt_tracker_key
;
104 static int hf_bt_tracker_num_want
;
105 static int hf_bt_tracker_port
;
106 static int hf_bt_tracker_interval
;
107 static int hf_bt_tracker_leechers
;
108 static int hf_bt_tracker_seeders
;
109 static int hf_bt_tracker_trackers
;
110 static int hf_bt_tracker_tracker
;
111 static int hf_bt_tracker_tr_ip
;
112 static int hf_bt_tracker_tr_ip6
;
113 static int hf_bt_tracker_tr_port
;
114 static int hf_bt_tracker_completed
;
115 static int hf_bt_tracker_error_msg
;
116 static int hf_bt_tracker_extension
;
117 static int hf_bt_tracker_extension_type
;
118 static int hf_bt_tracker_extension_len
;
119 static int hf_bt_tracker_extension_unknown
;
120 static int hf_bt_tracker_extension_urldata
;
122 static int ett_bt_tracker
;
123 static int ett_bt_tracker_trackers
;
124 static int ett_bt_tracker_extension
;
126 #define MAGIC_CONSTANT 0x41727101980
129 get_message_type(tvbuff_t
*tvb
)
131 if (tvb_get_ntoh64(tvb
, 0) == MAGIC_CONSTANT
&&
132 tvb_get_ntohl(tvb
, 8) == ACTION_CONNECT
)
133 return MSG_TYPE_CONNECT_REQUEST
;
134 if (tvb_get_ntohl(tvb
, 0) == ACTION_CONNECT
)
135 return MSG_TYPE_CONNECT_RESPONSE
;
136 if (tvb_get_ntohl(tvb
, 8) == ACTION_ANNOUNCE
)
137 return MSG_TYPE_ANNOUNCE_REQUEST
;
138 if (tvb_get_ntohl(tvb
, 0) == ACTION_ANNOUNCE
)
139 return MSG_TYPE_ANNOUNCE_RESPONSE
;
140 if (tvb_get_ntohl(tvb
, 8) == ACTION_SCRAPE
)
141 return MSG_TYPE_SCRAPE_REQUEST
;
142 if (tvb_get_ntohl(tvb
, 0) == ACTION_SCRAPE
)
143 return MSG_TYPE_SCRAPE_RESPONSE
;
144 if (tvb_get_ntohl(tvb
, 0) == ACTION_ERROR
)
145 return MSG_TYPE_ERROR_RESPONSE
;
147 return MSG_TYPE_UNKNOWN
;
151 is_ipv4_format(packet_info
*pinfo
)
153 wmem_list_frame_t
*cur
;
155 const char *cur_name
;
157 /* Format of Announce Response message depends on IPv4 vs IPv6
158 "Which format is used is determined by the address family of the underlying UDP packet.
159 I.e. packets from a v4 address use the v4 format, those from a v6 address use the v6 format."
160 Check the innermost IP layer, to take into account tunnels
163 cur
= wmem_list_frame_prev(wmem_list_tail(pinfo
->layers
));
164 while (cur
!= NULL
) {
165 cur_proto
= (int)GPOINTER_TO_UINT(wmem_list_frame_data(cur
));
166 cur_name
= proto_get_protocol_filter_name(cur_proto
);
167 if (!strcmp(cur_name
, "ip"))
169 if (!strcmp(cur_name
, "ipv6"))
171 cur
= wmem_list_frame_prev(cur
);
176 dissect_bt_tracker_extension(tvbuff_t
*tvb
, packet_info _U_
*pinfo
, proto_tree
*tree
, int offset
)
179 proto_tree
*ext_tree
;
180 uint8_t extension_type
;
181 uint32_t extension_length
;
184 while (offset
< (int)tvb_reported_length(tvb
)) {
185 extension_type
= tvb_get_uint8(tvb
, offset
);
188 if (extension_type
== EXT_URLDATA
) {
189 tot_length
+= 1 + tvb_get_uint8(tvb
, offset
+ 1);
190 } else if (extension_type
>= EXT_MAX
) {
194 ti
= proto_tree_add_none_format(tree
, hf_bt_tracker_extension
, tvb
, offset
, tot_length
, "Extension: %s", val_to_str_const(extension_type
, bt_tracker_extension_type_vals
, "Unknown"));
195 ext_tree
= proto_item_add_subtree(ti
, ett_bt_tracker_extension
);
196 proto_tree_add_item(ext_tree
, hf_bt_tracker_extension_type
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
199 switch (extension_type
) {
200 case EXT_END_OF_OPTIONS
:
201 /* Option parsing continues until either the end of the packet is reached, or an EndOfOptions option is encountered, whichever happens first */
204 /* A special case option that has a fixed-length of one byte. It is not followed by a length field, or associated data.
205 A NOP has no affect on option parsing. It is used only if optional padding is necessary in the future. */
208 proto_tree_add_item_ret_uint(ext_tree
, hf_bt_tracker_extension_len
, tvb
, offset
, 1, ENC_BIG_ENDIAN
, &extension_length
);
210 proto_tree_add_item(ext_tree
, hf_bt_tracker_extension_urldata
, tvb
, offset
, extension_length
, ENC_ASCII
);
211 offset
+= extension_length
;
214 proto_tree_add_item(ext_tree
, hf_bt_tracker_extension_unknown
, tvb
, offset
, -1, ENC_NA
);
222 dissect_bt_tracker_msg(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, unsigned offset
, unsigned msg_type
)
224 unsigned node_index
= 0;
227 proto_tree
*sub_tree
;
230 ti
= proto_tree_add_uint(tree
, hf_bt_tracker_msg_type
, tvb
, 0, 0, msg_type
);
231 proto_item_set_generated(ti
);
234 case MSG_TYPE_CONNECT_REQUEST
:
235 proto_tree_add_item(tree
, hf_bt_tracker_protocol_id
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
237 proto_tree_add_item(tree
, hf_bt_tracker_action
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
239 proto_tree_add_item(tree
, hf_bt_tracker_transaction_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
243 case MSG_TYPE_CONNECT_RESPONSE
:
244 proto_tree_add_item(tree
, hf_bt_tracker_action
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
246 proto_tree_add_item(tree
, hf_bt_tracker_transaction_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
248 proto_tree_add_item(tree
, hf_bt_tracker_connection_id
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
252 case MSG_TYPE_ANNOUNCE_REQUEST
:
253 proto_tree_add_item(tree
, hf_bt_tracker_connection_id
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
255 proto_tree_add_item(tree
, hf_bt_tracker_action
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
257 proto_tree_add_item(tree
, hf_bt_tracker_transaction_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
259 proto_tree_add_item(tree
, hf_bt_tracker_info_hash
, tvb
, offset
, 20, ENC_NA
);
261 proto_tree_add_item(tree
, hf_bt_tracker_peer_id
, tvb
, offset
, 20, ENC_NA
);
263 proto_tree_add_item(tree
, hf_bt_tracker_downloaded
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
265 proto_tree_add_item(tree
, hf_bt_tracker_left
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
267 proto_tree_add_item(tree
, hf_bt_tracker_uploaded
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
269 proto_tree_add_item(tree
, hf_bt_tracker_event
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
271 proto_tree_add_item(tree
, hf_bt_tracker_ip_address
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
273 proto_tree_add_item(tree
, hf_bt_tracker_key
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
275 proto_tree_add_item(tree
, hf_bt_tracker_num_want
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
277 proto_tree_add_item(tree
, hf_bt_tracker_port
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
280 offset
= dissect_bt_tracker_extension(tvb
, pinfo
, tree
, offset
);
283 case MSG_TYPE_ANNOUNCE_RESPONSE
:
284 proto_tree_add_item(tree
, hf_bt_tracker_action
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
286 proto_tree_add_item(tree
, hf_bt_tracker_transaction_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
288 proto_tree_add_item(tree
, hf_bt_tracker_interval
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
290 proto_tree_add_item(tree
, hf_bt_tracker_leechers
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
292 proto_tree_add_item(tree
, hf_bt_tracker_seeders
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
295 if (tvb_captured_length_remaining(tvb
, offset
) > 0)
298 is_ipv6
= !is_ipv4_format(pinfo
);
301 ti
= proto_tree_add_item(tree
, hf_bt_tracker_trackers
, tvb
, offset
, -1, ENC_NA
);
302 sub_tree
= proto_item_add_subtree(ti
, ett_bt_tracker_trackers
);
304 while (tvb_captured_length_remaining(tvb
, offset
) >= stride_length
)
307 proto_tree
*node_tree
;
311 node_ti
= proto_tree_add_item(sub_tree
, hf_bt_tracker_tracker
, tvb
, offset
, stride_length
, ENC_NA
);
312 proto_item_append_text(node_ti
, " %d", node_index
);
313 node_tree
= proto_item_add_subtree(node_ti
, ett_bt_tracker_trackers
);
317 proto_tree_add_item( node_tree
, hf_bt_tracker_tr_ip6
, tvb
, offset
, 16, ENC_NA
);
318 proto_item_append_text(node_ti
, ", IPv6/Port: [%s]", tvb_ip6_to_str(pinfo
->pool
, tvb
, offset
));
320 proto_tree_add_item( node_tree
, hf_bt_tracker_tr_port
, tvb
, offset
+ 16, 2, ENC_BIG_ENDIAN
);
321 proto_item_append_text(node_ti
, ":%u", tvb_get_ntohs( tvb
, offset
+ 16 ));
325 proto_tree_add_item( node_tree
, hf_bt_tracker_tr_ip
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
326 proto_item_append_text(node_ti
, ", IPv4/Port: %s", tvb_ip_to_str(pinfo
->pool
, tvb
, offset
));
328 proto_tree_add_item( node_tree
, hf_bt_tracker_tr_port
, tvb
, offset
+ 4, 2, ENC_BIG_ENDIAN
);
329 proto_item_append_text(node_ti
, ":%u", tvb_get_ntohs( tvb
, offset
+ 4 ));
332 offset
+= stride_length
;
334 proto_item_set_text(ti
, "Trackers: %d trackers", node_index
);
335 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ": %d trackers", node_index
);
340 case MSG_TYPE_SCRAPE_REQUEST
:
341 proto_tree_add_item(tree
, hf_bt_tracker_connection_id
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
343 proto_tree_add_item(tree
, hf_bt_tracker_action
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
345 proto_tree_add_item(tree
, hf_bt_tracker_transaction_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
348 while (tvb_captured_length_remaining(tvb
, offset
) >= 20)
350 proto_tree_add_item(tree
, hf_bt_tracker_info_hash
, tvb
, offset
, 20, ENC_NA
);
355 case MSG_TYPE_SCRAPE_RESPONSE
:
356 proto_tree_add_item(tree
, hf_bt_tracker_action
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
358 proto_tree_add_item(tree
, hf_bt_tracker_transaction_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
361 while (tvb_captured_length_remaining(tvb
, offset
) >= 12)
363 proto_tree_add_item(tree
, hf_bt_tracker_seeders
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
365 proto_tree_add_item(tree
, hf_bt_tracker_completed
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
367 proto_tree_add_item(tree
, hf_bt_tracker_leechers
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
373 case MSG_TYPE_ERROR_RESPONSE
:
374 proto_tree_add_item(tree
, hf_bt_tracker_action
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
376 proto_tree_add_item(tree
, hf_bt_tracker_transaction_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
378 proto_tree_add_item(tree
, hf_bt_tracker_error_msg
, tvb
, offset
, -1, ENC_ASCII
);
379 offset
= tvb_captured_length(tvb
);
388 dissect_bt_tracker(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
392 proto_tree
*sub_tree
;
394 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "BT-Tracker");
395 col_clear(pinfo
->cinfo
, COL_INFO
);
397 msg_type
= get_message_type(tvb
);
399 col_append_str(pinfo
->cinfo
, COL_INFO
, val_to_str_const(msg_type
, bt_tracker_msg_type_vals
, " Unknown Msg Type"));
401 ti
= proto_tree_add_item(tree
, proto_bt_tracker
, tvb
, 0, -1, ENC_NA
);
402 sub_tree
= proto_item_add_subtree(ti
, ett_bt_tracker
);
404 return dissect_bt_tracker_msg(tvb
, pinfo
, sub_tree
, 0, msg_type
);
409 dissect_bt_tracker_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
411 conversation_t
*conversation
;
413 /* Look for a Connect Request */
414 if (tvb_captured_length_remaining(tvb
, 0) < 16)
416 if (tvb_get_ntoh64(tvb
, 0) != MAGIC_CONSTANT
)
418 if (tvb_get_ntohl(tvb
, 8) != ACTION_CONNECT
)
421 conversation
= find_or_create_conversation(pinfo
);
422 conversation_set_dissector_from_frame_number(conversation
, pinfo
->num
, bt_tracker_handle
);
424 dissect_bt_tracker(tvb
, pinfo
, tree
, data
);
429 proto_register_bt_tracker(void)
431 static hf_register_info hf
[] = {
432 { &hf_bt_tracker_protocol_id
,
433 { "Protocol", "bt-tracker.proto_id",
434 FT_UINT64
, BASE_HEX
, NULL
, 0x00,
437 { &hf_bt_tracker_action
,
438 { "Action", "bt-tracker.action",
439 FT_UINT32
, BASE_DEC
, VALS(bt_tracker_action_vals
), 0x0,
442 { &hf_bt_tracker_transaction_id
,
443 { "Transaction Id", "bt-tracker.transaction_id",
444 FT_UINT32
, BASE_DEC
, NULL
, 0x00,
447 { &hf_bt_tracker_connection_id
,
448 { "Connection Id", "bt-tracker.connection_id",
449 FT_UINT64
, BASE_DEC
, NULL
, 0x00,
452 { &hf_bt_tracker_msg_type
,
453 { "Message Type", "bt-tracker.msg_type",
454 FT_UINT8
, BASE_DEC
, VALS(bt_tracker_msg_type_vals
), 0x0,
457 { &hf_bt_tracker_info_hash
,
458 { "Info Hash", "bt-tracker.info_hash",
459 FT_BYTES
, BASE_NONE
, NULL
, 0x00,
462 { &hf_bt_tracker_peer_id
,
463 { "Peer Id", "bt-tracker.peer_id",
464 FT_BYTES
, BASE_NONE
, NULL
, 0x00,
467 { &hf_bt_tracker_downloaded
,
468 { "Downloaded", "bt-tracker.downloaded",
469 FT_UINT64
, BASE_DEC
, NULL
, 0x00,
472 { &hf_bt_tracker_left
,
473 { "Left", "bt-tracker.left",
474 FT_UINT64
, BASE_DEC
, NULL
, 0x00,
477 { &hf_bt_tracker_uploaded
,
478 { "Uploaded", "bt-tracker.uploaded",
479 FT_UINT64
, BASE_DEC
, NULL
, 0x00,
482 { &hf_bt_tracker_event
,
483 { "Event", "bt-tracker.event",
484 FT_UINT32
, BASE_DEC
, VALS(bt_tracker_event_vals
), 0x00,
487 { &hf_bt_tracker_ip_address
,
488 { "IP Address", "bt-tracker.ip_address",
489 FT_IPv4
, BASE_NONE
, NULL
, 0x00,
492 { &hf_bt_tracker_key
,
493 { "Key", "bt-tracker.key",
494 FT_UINT32
, BASE_DEC
, NULL
, 0x00,
497 { &hf_bt_tracker_num_want
,
498 { "Num Want", "bt-tracker.num_want",
499 FT_INT32
, BASE_DEC
, NULL
, 0x00,
502 { &hf_bt_tracker_port
,
503 { "Port", "bt-tracker.port",
504 FT_UINT16
, BASE_DEC
, NULL
, 0x00,
507 { &hf_bt_tracker_interval
,
508 { "Interval", "bt-tracker.interval",
509 FT_INT32
, BASE_DEC
, NULL
, 0x00,
512 { &hf_bt_tracker_leechers
,
513 { "Leechers", "bt-tracker.leechers",
514 FT_INT32
, BASE_DEC
, NULL
, 0x00,
517 { &hf_bt_tracker_seeders
,
518 { "Seeders", "bt-tracker.seeders",
519 FT_INT32
, BASE_DEC
, NULL
, 0x00,
522 { &hf_bt_tracker_trackers
,
523 { "Trackers", "bt-tracker.trackers",
524 FT_NONE
, BASE_NONE
, NULL
, 0x0,
527 { &hf_bt_tracker_tracker
,
528 { "Tracker", "bt-tracker.tracker",
529 FT_NONE
, BASE_NONE
, NULL
, 0x0,
532 { &hf_bt_tracker_tr_ip
,
533 { "IP", "bt-tracker.tracker.ip",
534 FT_IPv4
, BASE_NONE
, NULL
, 0x00,
537 { &hf_bt_tracker_tr_ip6
,
538 { "IPv6", "bt-tracker.tracker.ip6",
539 FT_IPv6
, BASE_NONE
, NULL
, 0x00,
542 { &hf_bt_tracker_tr_port
,
543 { "(TCP) Port", "bt-tracker.tracker.port",
544 FT_UINT16
, BASE_DEC
, NULL
, 0x00,
547 { &hf_bt_tracker_completed
,
548 { "Completed", "bt-tracker.completed",
549 FT_INT32
, BASE_DEC
, NULL
, 0x00,
552 { &hf_bt_tracker_error_msg
,
553 { "Error message", "bt-tracker.error_msg",
554 FT_STRING
, BASE_NONE
, NULL
, 0x00,
557 { &hf_bt_tracker_extension
,
558 { "Extension", "bt-tracker.extension",
559 FT_NONE
, BASE_NONE
, NULL
, 0x0,
562 { &hf_bt_tracker_extension_type
,
563 { "Extension Type", "bt-tracker.extension_type",
564 FT_UINT8
, BASE_HEX
, VALS(bt_tracker_extension_type_vals
), 0x0,
567 { &hf_bt_tracker_extension_len
,
568 { "Extension Length", "bt-tracker.extension_len",
569 FT_UINT8
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_byte_bytes
), 0x0,
572 { &hf_bt_tracker_extension_unknown
,
573 { "Extension Unknown", "bt-tracker.extension_unknown",
574 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
577 { &hf_bt_tracker_extension_urldata
,
578 { "URL Data", "bt-tracker.extension.urldata",
579 FT_STRING
, BASE_NONE
, NULL
, 0x00,
584 /* Setup protocol subtree array */
585 static int *ett
[] = { &ett_bt_tracker
, &ett_bt_tracker_trackers
, &ett_bt_tracker_extension
};
586 module_t
*bt_tracker_module
;
588 /* Register protocol */
589 proto_bt_tracker
= proto_register_protocol ("BitTorrent Tracker", "BT-Tracker", "bt-tracker");
591 bt_tracker_module
= prefs_register_protocol(proto_bt_tracker
, NULL
);
592 prefs_register_obsolete_preference(bt_tracker_module
, "enable");
594 proto_register_field_array(proto_bt_tracker
, hf
, array_length(hf
));
595 proto_register_subtree_array(ett
, array_length(ett
));
599 proto_reg_handoff_bt_tracker(void)
601 heur_dissector_add("udp", dissect_bt_tracker_heur
, "BitTorrent Tracker over UDP", "bt_tracker_udp", proto_bt_tracker
, HEURISTIC_ENABLE
);
603 bt_tracker_handle
= create_dissector_handle(dissect_bt_tracker
, proto_bt_tracker
);
604 dissector_add_for_decode_as_with_preference("udp.port", bt_tracker_handle
);