2 * Routines for the disassembly of Skype
4 * Copyright 2009 Joerg Mayer (see AUTHORS file)
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
14 * Documentation that formed the basis of the packet decoding:
15 * https://github.com/matthiasbock/OpenSkype/wiki/Skype's-UDP-Format
16 * For additional information see:
17 * https://gitlab.com/wireshark/wireshark/-/wikis/Skype
22 * - Conversation stuff (to obtain external IPs for decryption)
23 * - Decryption (with given keys)
24 * - Test CRC check (requires working decryption)
25 * - Heuristics to reliably detect Skype traffic - most likely impossible
26 * to implement in Wireshark (see
27 * https://gitlab.com/wireshark/wireshark/-/wikis/Skype)
33 #include <epan/packet.h>
34 #include <epan/conversation.h>
36 void proto_register_skype(void);
37 void proto_reg_handoff_skype(void);
39 static dissector_handle_t skype_handle
;
41 /* Things we may want to remember for a whole conversation */
42 typedef struct _skype_udp_conv_info_t
{
43 uint32_t global_src_ip
;
44 uint32_t global_dst_ip
;
45 } skype_udp_conv_info_t
;
47 /* protocol handles */
48 static int proto_skype
;
53 #define SKYPE_SOM_UNK_MASK 0xF0
54 #define SKYPE_SOM_TYPE_MASK 0x0F
57 /* Start of Message */
58 static int hf_skype_som_id
;
59 static int hf_skype_som_unk
;
60 static int hf_skype_som_type
;
63 static int hf_skype_unknown_0_unk1
;
65 static int hf_skype_payload_iv
;
66 static int hf_skype_payload_crc
;
67 static int hf_skype_payload_enc_data
;
69 static int hf_skype_ffr_num
;
70 static int hf_skype_ffr_unk1
;
71 static int hf_skype_ffr_iv
;
72 static int hf_skype_ffr_crc
;
73 static int hf_skype_ffr_enc_data
;
75 static int hf_skype_natinfo_srcip
;
76 static int hf_skype_natinfo_dstip
;
78 static int hf_skype_natrequest_srcip
;
79 static int hf_skype_natrequest_dstip
;
81 static int hf_skype_audio_unk1
;
83 static int hf_skype_unknown_f_unk1
;
84 /* Unknown packet type */
85 static int hf_skype_unknown_packet
;
88 #define PROTO_SHORT_NAME "SKYPE"
89 #define PROTO_LONG_NAME "SKYPE"
92 SKYPE_TYPE_UNKNOWN_0
= 0,
93 SKYPE_TYPE_PAYLOAD
= 2,
95 SKYPE_TYPE_NAT_INFO
= 5,
96 SKYPE_TYPE_NAT_REPEAT
= 7,
97 SKYPE_TYPE_AUDIO
= 0xd,
98 SKYPE_TYPE_UNKNOWN_F
= 0xf
102 static const value_string skype_type_vals
[] = {
103 { SKYPE_TYPE_UNKNOWN_0
, "Unknown_0" },
104 { SKYPE_TYPE_PAYLOAD
, "Payload" },
105 { SKYPE_TYPE_FFR
, "Fragment/Forward/Resend" },
106 { SKYPE_TYPE_NAT_INFO
, "NAT info" },
107 { SKYPE_TYPE_NAT_REPEAT
,"NAT repeat" },
108 { SKYPE_TYPE_AUDIO
, "Audio" },
109 { SKYPE_TYPE_UNKNOWN_F
, "Unknown_F" },
116 dissect_skype_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
119 proto_tree
*skype_tree
= NULL
;
121 uint32_t packet_length
;
124 /* XXX: Just until we know how to decode skype over tcp */
127 packet_length
= tvb_captured_length(tvb
);
129 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, PROTO_SHORT_NAME
);
130 col_add_str(pinfo
->cinfo
, COL_INFO
, val_to_str(packet_type
,
131 skype_type_vals
, "Type 0x%1x"));
134 /* Start of message dissection */
135 ti
= proto_tree_add_item(tree
, proto_skype
, tvb
, offset
, -1,
137 skype_tree
= proto_item_add_subtree(ti
, ett_skype
);
139 /* Body dissection */
140 switch (packet_type
) {
143 proto_tree_add_item(skype_tree
, hf_skype_unknown_packet
, tvb
, offset
, -1,
145 offset
= packet_length
;
153 dissect_skype_udp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
156 proto_tree
*skype_tree
= NULL
;
158 uint32_t packet_length
;
159 uint8_t packet_type
, packet_unk
;
161 conversation_t
*conversation
= NULL
;
162 skype_udp_conv_info_t
*skype_udp_info
;
164 /* look up the conversation */
165 conversation
= find_or_create_conversation(pinfo
);
167 /* if conversation found get the data pointer that you stored */
168 skype_udp_info
= (skype_udp_conv_info_t
*)conversation_get_proto_data(conversation
, proto_skype
);
169 if (!skype_udp_info
) {
170 /* new conversation create local data structure */
171 skype_udp_info
= wmem_new(wmem_file_scope(), skype_udp_conv_info_t
);
172 skype_udp_info
->global_src_ip
= 0;
173 skype_udp_info
->global_dst_ip
= 0;
174 conversation_add_proto_data(conversation
, proto_skype
,
177 /* at this point the conversation data is ready */
179 packet_type
= tvb_get_uint8(tvb
, 2) & SKYPE_SOM_TYPE_MASK
;
180 packet_unk
= (tvb_get_uint8(tvb
, 2) & SKYPE_SOM_UNK_MASK
) >> 4;
182 packet_length
= tvb_captured_length(tvb
);
184 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, PROTO_SHORT_NAME
);
185 col_add_str(pinfo
->cinfo
, COL_INFO
, val_to_str(packet_type
,
186 skype_type_vals
, "Type 0x%1x"));
188 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " Unk: %1x", packet_unk
);
192 /* Start of message dissection */
193 ti
= proto_tree_add_item(tree
, proto_skype
, tvb
, offset
, -1,
195 skype_tree
= proto_item_add_subtree(ti
, ett_skype
);
197 proto_tree_add_item(skype_tree
, hf_skype_som_id
, tvb
, offset
, 2,
200 proto_tree_add_item(skype_tree
, hf_skype_som_unk
, tvb
, offset
, 1,
202 proto_tree_add_item(skype_tree
, hf_skype_som_type
, tvb
, offset
, 1,
206 /* Body dissection */
207 switch (packet_type
) {
209 case SKYPE_TYPE_UNKNOWN_0
:
210 proto_tree_add_item(skype_tree
, hf_skype_unknown_0_unk1
, tvb
, offset
, -1,
212 offset
= packet_length
;
214 case SKYPE_TYPE_PAYLOAD
:
215 proto_tree_add_item(skype_tree
, hf_skype_payload_iv
, tvb
, offset
, 4,
218 proto_tree_add_item(skype_tree
, hf_skype_payload_crc
, tvb
, offset
, 4,
221 proto_tree_add_item(skype_tree
, hf_skype_payload_enc_data
, tvb
, offset
, -1,
223 offset
= packet_length
;
226 proto_tree_add_item(skype_tree
, hf_skype_ffr_num
, tvb
, offset
, 1,
229 proto_tree_add_item(skype_tree
, hf_skype_ffr_unk1
, tvb
, offset
, 4,
232 proto_tree_add_item(skype_tree
, hf_skype_ffr_iv
, tvb
, offset
, 4,
235 proto_tree_add_item(skype_tree
, hf_skype_ffr_crc
, tvb
, offset
, 4,
238 proto_tree_add_item(skype_tree
, hf_skype_ffr_enc_data
, tvb
, offset
, -1,
240 offset
= packet_length
;
242 case SKYPE_TYPE_NAT_INFO
:
243 proto_tree_add_item(skype_tree
, hf_skype_natinfo_srcip
, tvb
, offset
, 4,
245 skype_udp_info
->global_src_ip
= tvb_get_ipv4(tvb
, offset
);
247 proto_tree_add_item(skype_tree
, hf_skype_natinfo_dstip
, tvb
, offset
, 4,
249 skype_udp_info
->global_dst_ip
= tvb_get_ipv4(tvb
, offset
);
252 case SKYPE_TYPE_NAT_REPEAT
:
253 proto_tree_add_item(skype_tree
, hf_skype_natrequest_srcip
, tvb
, offset
, 4,
255 skype_udp_info
->global_src_ip
= tvb_get_ipv4(tvb
, offset
);
257 proto_tree_add_item(skype_tree
, hf_skype_natrequest_dstip
, tvb
, offset
, 4,
259 skype_udp_info
->global_dst_ip
= tvb_get_ipv4(tvb
, offset
);
262 case SKYPE_TYPE_AUDIO
:
263 proto_tree_add_item(skype_tree
, hf_skype_audio_unk1
, tvb
, offset
, -1,
265 offset
= packet_length
;
267 case SKYPE_TYPE_UNKNOWN_F
:
268 proto_tree_add_item(skype_tree
, hf_skype_unknown_f_unk1
, tvb
, offset
, -1,
270 offset
= packet_length
;
273 proto_tree_add_item(skype_tree
, hf_skype_unknown_packet
, tvb
, offset
, -1,
275 offset
= packet_length
;
283 test_skype_udp(tvbuff_t
*tvb
)
285 /* Minimum of 3 bytes, check for valid message type */
286 if (tvb_captured_length(tvb
) > 3)
288 uint8_t type
= tvb_get_uint8(tvb
, 2) & 0xF;
290 /* FIXME: Extend this by minimum or exact length per message type */
306 dissect_skype_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
308 if ( !test_skype_udp(tvb
) ) {
312 dissect_skype_udp(tvb
, pinfo
, tree
);
317 dissect_skype_static(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
320 * Don't test for valid packet - we only end here when
321 * the user did a decode-as.
323 if (pinfo
->ptype
== PT_UDP
) {
324 return dissect_skype_udp(tvb
, pinfo
, tree
);
325 } else if (pinfo
->ptype
== PT_TCP
) {
326 return dissect_skype_tcp(tvb
, pinfo
, tree
);
332 proto_register_skype(void)
334 static hf_register_info hf
[] = {
336 /* Start of message fields */
338 { "ID", "skype.som.id", FT_UINT16
, BASE_HEX
, NULL
,
339 0x0, "Message ID", HFILL
}},
342 { "Unknown", "skype.som.unk", FT_UINT8
, BASE_HEX
, NULL
,
343 SKYPE_SOM_UNK_MASK
, NULL
, HFILL
}},
345 { &hf_skype_som_type
,
346 { "Type", "skype.som.type", FT_UINT8
, BASE_HEX
, VALS(skype_type_vals
),
347 SKYPE_SOM_TYPE_MASK
, "Message type", HFILL
}},
352 { &hf_skype_unknown_0_unk1
,
353 { "Unknown1", "skype.unknown_0.unk1", FT_BYTES
, BASE_NONE
, NULL
,
357 { &hf_skype_payload_iv
,
358 { "IV", "skype.payload.iv", FT_UINT32
, BASE_HEX
, NULL
,
361 { &hf_skype_payload_crc
,
362 { "CRC", "skype.payload.crc", FT_UINT32
, BASE_HEX
, NULL
,
365 { &hf_skype_payload_enc_data
,
366 { "Enc Data", "skype.payload.encdata", FT_BYTES
, BASE_NONE
, NULL
,
371 { "Num", "skype.ffr.num", FT_UINT8
, BASE_HEX
, NULL
,
374 { &hf_skype_ffr_unk1
,
375 { "Unk1", "skype.ffr.unk1", FT_UINT32
, BASE_HEX
, NULL
,
379 { "IV", "skype.ffr.iv", FT_UINT32
, BASE_HEX
, NULL
,
383 { "CRC", "skype.ffr.crc", FT_UINT32
, BASE_HEX
, NULL
,
386 { &hf_skype_ffr_enc_data
,
387 { "Enc Data", "skype.ffr.encdata", FT_BYTES
, BASE_NONE
, NULL
,
391 { &hf_skype_natinfo_srcip
,
392 { "Src IP", "skype.natinfo.srcip", FT_IPv4
, BASE_NONE
, NULL
,
393 0x0, "Global source IP", HFILL
}},
395 { &hf_skype_natinfo_dstip
,
396 { "Dst IP", "skype.natinfo.dstip", FT_UINT32
, BASE_HEX
, NULL
,
397 0x0, "Global destination IP", HFILL
}},
400 { &hf_skype_natrequest_srcip
,
401 { "Src IP", "skype.natrequest.srcip", FT_IPv4
, BASE_NONE
, NULL
,
402 0x0, "Global source IP", HFILL
}},
404 { &hf_skype_natrequest_dstip
,
405 { "Dst IP", "skype.natrequest.dstip", FT_UINT32
, BASE_HEX
, NULL
,
409 { &hf_skype_audio_unk1
,
410 { "Unknown1", "skype.audio.unk1", FT_BYTES
, BASE_NONE
, NULL
,
414 { &hf_skype_unknown_f_unk1
,
415 { "Unknown1", "skype.unknown_f.unk1", FT_BYTES
, BASE_NONE
, NULL
,
419 { &hf_skype_unknown_packet
,
420 { "Unknown Packet", "skype.unknown_packet", FT_BYTES
, BASE_NONE
, NULL
,
424 static int *ett
[] = {
428 proto_skype
= proto_register_protocol(PROTO_LONG_NAME
, PROTO_SHORT_NAME
, "skype");
429 proto_register_field_array(proto_skype
, hf
, array_length(hf
));
430 proto_register_subtree_array(ett
, array_length(ett
));
432 skype_handle
= register_dissector("skype", dissect_skype_static
, proto_skype
);
436 proto_reg_handoff_skype(void)
438 dissector_add_for_decode_as_with_preference("tcp.port", skype_handle
);
439 dissector_add_for_decode_as_with_preference("udp.port", skype_handle
);
441 heur_dissector_add("udp", dissect_skype_heur
, "Skype over UDP", "skype_udp", proto_skype
, HEURISTIC_DISABLE
);
445 * Editor modelines - https://www.wireshark.org/tools/modelines.html
450 * indent-tabs-mode: t
453 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
454 * :indentSize=8:tabSize=8:noTabs=false: