wireshark/epan/dissectors/packet-bt-utp.c
Michael Mann 2eb7b05b8c Convert most UDP dissectors to use "auto" preferences.
Similar to the "tcp.port" changes in I99604f95d426ad345f4b494598d94178b886eb67,
convert dissectors that use "udp.port".

More cleanup done on dissectors that use both TCP and UDP dissector
tables, so that less preference callbacks exist.

Change-Id: If07be9b9e850c244336a7069599cd554ce312dd3
Reviewed-on: https://code.wireshark.org/review/18120
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Michael Mann <mmann78@netscape.net>
2016-10-13 02:51:18 +00:00

501 lines
16 KiB
C

/* packet-bt-utp.c
* Routines for BT-UTP dissection
* Copyright 2011, Xiao Xiangquan <xiaoxiangquan@gmail.com>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1999 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <epan/packet.h>
#include <epan/conversation.h>
#include <epan/prefs.h>
void proto_register_bt_utp(void);
void proto_reg_handoff_bt_utp(void);
enum {
ST_DATA = 0,
ST_FIN = 1,
ST_STATE = 2,
ST_RESET = 3,
ST_SYN = 4,
ST_NUM_STATES
};
/* V0 hdr: "flags"; V1 hdr: "type" */
static const value_string bt_utp_type_vals[] = {
{ ST_DATA, "Data" },
{ ST_FIN, "Fin" },
{ ST_STATE, "State" },
{ ST_RESET, "Reset" },
{ ST_SYN, "Syn" },
{ 0, NULL }
};
enum {
EXT_NO_EXTENSION = 0,
EXT_SELECTION_ACKS = 1,
EXT_EXTENSION_BITS = 2,
EXT_NUM_EXT
};
static const value_string bt_utp_extension_type_vals[] = {
{ EXT_NO_EXTENSION, "No Extension" },
{ EXT_SELECTION_ACKS, "Selective ACKs" },
{ EXT_EXTENSION_BITS, "Extension bits" },
{ 0, NULL }
};
static int proto_bt_utp = -1;
/* --- "Original" uTP Header ("version 0" ?) --------------
See utp.cpp source code @ https://github.com/bittorrent/libutp
-- Fixed Header --
0 4 8 16 24 32
+-------+-------+---------------+---------------+---------------+
| connection_id |
+-------+-------+---------------+---------------+---------------+
| timestamp_seconds |
+---------------+---------------+---------------+---------------+
| timestamp_microseconds |
+---------------+---------------+---------------+---------------+
| timestamp_difference_microseconds |
+---------------+---------------+---------------+---------------+
| wnd_size | ext | flags | seq_nr [ho] |
+---------------+---------------+---------------+---------------+
| seq_nr [lo] | ack_nr |
+---------------+---------------+---------------+
-- Extension Field(s) --
0 8 16
+---------------+---------------+---------------+---------------+
| extension | len | bitmask
+---------------+---------------+---------------+---------------+
|
+---------------+---------------+....
*/
/* --- Version 1 Header ----------------
Specifications: BEP-0029
http://www.bittorrent.org/beps/bep_0029.html
-- Fixed Header --
Fields Types
0 4 8 16 24 32
+-------+-------+---------------+---------------+---------------+
| type | ver | extension | connection_id |
+-------+-------+---------------+---------------+---------------+
| timestamp_microseconds |
+---------------+---------------+---------------+---------------+
| timestamp_difference_microseconds |
+---------------+---------------+---------------+---------------+
| wnd_size |
+---------------+---------------+---------------+---------------+
| seq_nr | ack_nr |
+---------------+---------------+---------------+---------------+
-- Extension Field(s) --
0 8 16
+---------------+---------------+---------------+---------------+
| extension | len | bitmask
+---------------+---------------+---------------+---------------+
|
+---------------+---------------+....
*/
#define V0_FIXED_HDR_SIZE 23
#define V1_FIXED_HDR_SIZE 20
static dissector_handle_t bt_utp_handle;
static int hf_bt_utp_ver = -1;
static int hf_bt_utp_type = -1;
static int hf_bt_utp_flags = -1;
static int hf_bt_utp_extension = -1;
static int hf_bt_utp_next_extension_type = -1;
static int hf_bt_utp_extension_len = -1;
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_timestamp_sec = -1;
static int hf_bt_utp_timestamp_us = -1;
static int hf_bt_utp_timestamp_diff_us = -1;
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_data = -1;
static gint ett_bt_utp = -1;
static gint ett_bt_utp_extension = -1;
static gint
get_utp_version(tvbuff_t *tvb) {
guint8 v0_flags, v0_ext;
guint8 v1_ver_type, v1_ext;
guint len;
/* Simple heuristics inspired by code from utp.cpp */
len = tvb_captured_length(tvb);
/* Version 1? */
if (len < V1_FIXED_HDR_SIZE) {
return -1;
}
v1_ver_type = tvb_get_guint8(tvb, 0);
v1_ext = tvb_get_guint8(tvb, 1);
if (((v1_ver_type & 0x0f) == 1) && ((v1_ver_type>>4) < ST_NUM_STATES) &&
(v1_ext < EXT_NUM_EXT)) {
return 1;
}
/* Version 0? */
if (len < V0_FIXED_HDR_SIZE) {
return -1;
}
v0_flags = tvb_get_guint8(tvb, 18);
v0_ext = tvb_get_guint8(tvb, 17);
if ((v0_flags < ST_NUM_STATES) || (v0_ext < EXT_NUM_EXT)) {
return 0;
}
return -1;
}
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);
offset += 4;
proto_tree_add_item(tree, hf_bt_utp_timestamp_sec, tvb, offset, 4, ENC_BIG_ENDIAN);
offset += 4;
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_v0, tvb, offset, 1, ENC_BIG_ENDIAN);
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"));
offset += 1;
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;
return offset;
}
static int
dissect_utp_header_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint8 *extension_type)
{
/* V1 */
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"));
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);
offset += 2;
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);
offset += 4;
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;
return offset;
}
static int
dissect_utp_extension(tvbuff_t *tvb, packet_info _U_*pinfo, proto_tree *tree, int offset, guint8 *extension_type)
{
proto_item *ti;
proto_tree *ext_tree;
guint8 extension_length;
/* display the extension tree */
while(*extension_type != EXT_NO_EXTENSION && offset < (int)tvb_reported_length(tvb))
{
switch(*extension_type){
case EXT_SELECTION_ACKS: /* 1 */
{
ti = proto_tree_add_item(tree, hf_bt_utp_extension, tvb, offset, -1, ENC_NA);
ext_tree = proto_item_add_subtree(ti, ett_bt_utp_extension);
proto_tree_add_item(ext_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(ext_tree, hf_bt_utp_extension_len, tvb, offset, 1, ENC_BIG_ENDIAN);
extension_length = tvb_get_guint8(tvb, offset);
proto_item_append_text(ti, " Selection ACKs, Len=%d", extension_length);
offset += 1;
proto_tree_add_item(ext_tree, hf_bt_utp_extension_bitmask, tvb, offset, extension_length, ENC_NA);
offset += extension_length;
proto_item_set_len(ti, 1 + 1 + extension_length);
break;
}
case EXT_EXTENSION_BITS: /* 2 */
{
ti = proto_tree_add_item(tree, hf_bt_utp_extension, tvb, offset, -1, ENC_NA);
ext_tree = proto_item_add_subtree(ti, ett_bt_utp_extension);
proto_tree_add_item(ext_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(ext_tree, hf_bt_utp_extension_len, tvb, offset, 1, ENC_BIG_ENDIAN);
extension_length = tvb_get_guint8(tvb, offset);
proto_item_append_text(ti, " Extension Bits, Len=%d", extension_length);
offset += 1;
proto_tree_add_item(ext_tree, hf_bt_utp_extension_bitmask, tvb, offset, extension_length, ENC_NA);
offset += extension_length;
proto_item_set_len(ti, 1 + 1 + extension_length);
break;
}
default:
ti = proto_tree_add_item(tree, hf_bt_utp_extension, tvb, offset, -1, ENC_NA);
ext_tree = proto_item_add_subtree(ti, ett_bt_utp_extension);
proto_tree_add_item(ext_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(ext_tree, hf_bt_utp_extension_len, tvb, offset, 1, ENC_BIG_ENDIAN);
extension_length = tvb_get_guint8(tvb, offset);
proto_item_append_text(ti, " Unknown, Len=%d", extension_length);
offset += 1;
proto_tree_add_item(ext_tree, hf_bt_utp_extension_unknown, tvb, offset, extension_length, ENC_NA);
offset += extension_length;
proto_item_set_len(ti, 1 + 1 + extension_length);
break;
}
}
return offset;
}
static int
dissect_bt_utp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
{
gint version;
version = get_utp_version(tvb);
/* try dissecting */
if (version >= 0)
{
conversation_t *conversation;
guint len_tvb;
proto_tree *sub_tree = NULL;
proto_item *ti;
gint offset = 0;
guint8 extension_type;
conversation = find_or_create_conversation(pinfo);
conversation_set_dissector(conversation, bt_utp_handle);
/* 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);
ti = proto_tree_add_protocol_format(tree, proto_bt_utp, tvb, 0, -1,
"uTorrent Transport Protocol V%d (%d bytes)",
version, len_tvb);
sub_tree = proto_item_add_subtree(ti, ett_bt_utp);
/* Determine header version */
if (version == 0) {
offset = dissect_utp_header_v0(tvb, pinfo, sub_tree, offset, &extension_type);
} else {
offset = dissect_utp_header_v1(tvb, pinfo, sub_tree, offset, &extension_type);
}
offset = dissect_utp_extension(tvb, pinfo, sub_tree, offset, &extension_type);
len_tvb = tvb_captured_length_remaining(tvb, offset);
if(len_tvb > 0)
proto_tree_add_item(sub_tree, hf_bt_utp_data, tvb, offset, len_tvb, ENC_NA);
return offset+len_tvb;
}
return 0;
}
void
proto_register_bt_utp(void)
{
static hf_register_info hf[] = {
{ &hf_bt_utp_ver,
{ "Version", "bt-utp.ver",
FT_UINT8, BASE_DEC, NULL, 0x0F,
NULL, HFILL }
},
{ &hf_bt_utp_flags,
{ "Flags", "bt-utp.flags",
FT_UINT8, BASE_DEC, VALS(bt_utp_type_vals), 0x0,
NULL, HFILL }
},
{ &hf_bt_utp_type,
{ "Type", "bt-utp.type",
FT_UINT8, BASE_DEC, VALS(bt_utp_type_vals), 0xF0,
NULL, HFILL }
},
{ &hf_bt_utp_extension,
{ "Extension", "bt-utp.extension",
FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_bt_utp_next_extension_type,
{ "Next Extension Type", "bt-utp.next_extension_type",
FT_UINT8, BASE_DEC, VALS(bt_utp_extension_type_vals), 0x0,
NULL, HFILL }
},
{ &hf_bt_utp_extension_len,
{ "Extension Length", "bt-utp.extension_len",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_bt_utp_extension_bitmask,
{ "Extension Bitmask", "bt-utp.extension_bitmask",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_bt_utp_extension_unknown,
{ "Extension Unknown", "bt-utp.extension_unknown",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{ &hf_bt_utp_connection_id_v0,
{ "Connection ID", "bt-utp.connection_id",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_bt_utp_connection_id_v1,
{ "Connection ID", "bt-utp.connection_id",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_bt_utp_timestamp_sec,
{ "Timestamp seconds", "bt-utp.timestamp_sec",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_bt_utp_timestamp_us,
{ "Timestamp Microseconds", "bt-utp.timestamp_us",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_bt_utp_timestamp_diff_us,
{ "Timestamp Difference Microseconds", "bt-utp.timestamp_diff_us",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_bt_utp_wnd_size_v0,
{ "Windows Size", "bt-utp.wnd_size",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_bt_utp_wnd_size_v1,
{ "Windows Size", "bt-utp.wnd_size",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_bt_utp_seq_nr,
{ "Sequence number", "bt-utp.seq_nr",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_bt_utp_ack_nr,
{ "ACK number", "bt-utp.ack_nr",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL }
},
{ &hf_bt_utp_data,
{ "Data", "bt-utp.data",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
};
/* Setup protocol subtree array */
static gint *ett[] = { &ett_bt_utp, &ett_bt_utp_extension };
module_t *bt_utp_module;
/* Register protocol */
proto_bt_utp = proto_register_protocol ("uTorrent Transport Protocol", "BT-uTP", "bt-utp");
bt_utp_module = prefs_register_protocol(proto_bt_utp, NULL);
prefs_register_obsolete_preference(bt_utp_module, "enable");
proto_register_field_array(proto_bt_utp, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
}
void
proto_reg_handoff_bt_utp(void)
{
/* disabled by default since heuristic is weak */
heur_dissector_add("udp", dissect_bt_utp, "BitTorrent UTP over UDP", "bt_utp_udp", proto_bt_utp, HEURISTIC_DISABLE);
bt_utp_handle = create_dissector_handle(dissect_bt_utp, proto_bt_utp);
dissector_add_for_decode_as_with_preference("udp.port", bt_utp_handle);
}
/*
* Editor modelines
*
* Local Variables:
* c-basic-offset: 2
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* ex: set shiftwidth=2 tabstop=8 expandtab:
* :indentSize=2:tabSize=8:noTabs=true:
*/