2 * Routines for the disassembly of Skype
6 * Copyright 2009 Joerg Mayer (see AUTHORS file)
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 * Documentation that formed the basis of the packet decoding:
29 * https://github.com/matthiasbock/OpenSkype/wiki/Skype's-UDP-Format
30 * For additional information see: http://wiki.wireshark.org/Skype
35 * - Conversation stuff (to obtain external IPs for decryption)
36 * - Decryption (with given keys)
37 * - Test CRC check (requires working decryption)
38 * - Heuristics to reliably detect Skype traffic - most likely impossible
39 * to implement in Wireshark (see http://en.wikipedia.org/wiki/Skype)
46 #include <epan/wmem/wmem.h>
47 #include <epan/packet.h>
48 #include <epan/conversation.h>
50 /* Things we may want to remember for a whole conversation */
51 typedef struct _skype_udp_conv_info_t
{
52 guint32 global_src_ip
;
53 guint32 global_dst_ip
;
54 } skype_udp_conv_info_t
;
56 /* protocol handles */
57 static int proto_skype
= -1;
60 static int ett_skype
= -1;
62 #define SKYPE_SOM_UNK_MASK 0xF0
63 #define SKYPE_SOM_TYPE_MASK 0x0F
66 /* Start of Message */
67 static int hf_skype_som_id
= -1;
68 static int hf_skype_som_unk
= -1;
69 static int hf_skype_som_type
= -1;
72 static int hf_skype_unknown_0_unk1
= -1;
74 static int hf_skype_payload_iv
= -1;
75 static int hf_skype_payload_crc
= -1;
76 static int hf_skype_payload_enc_data
= -1;
78 static int hf_skype_ffr_num
= -1;
79 static int hf_skype_ffr_unk1
= -1;
80 static int hf_skype_ffr_iv
= -1;
81 static int hf_skype_ffr_crc
= -1;
82 static int hf_skype_ffr_enc_data
= -1;
84 static int hf_skype_natinfo_srcip
= -1;
85 static int hf_skype_natinfo_dstip
= -1;
87 static int hf_skype_natrequest_srcip
= -1;
88 static int hf_skype_natrequest_dstip
= -1;
90 static int hf_skype_audio_unk1
= -1;
92 static int hf_skype_unknown_f_unk1
= -1;
93 /* Unknown packet type */
94 static int hf_skype_unknown_packet
= -1;
97 #define PROTO_SHORT_NAME "SKYPE"
98 #define PROTO_LONG_NAME "SKYPE"
101 SKYPE_TYPE_UNKNOWN_0
= 0,
102 SKYPE_TYPE_PAYLOAD
= 2,
104 SKYPE_TYPE_NAT_INFO
= 5,
105 SKYPE_TYPE_NAT_REPEAT
= 7,
106 SKYPE_TYPE_AUDIO
= 0xd,
107 SKYPE_TYPE_UNKNOWN_F
= 0xf
111 static const value_string skype_type_vals
[] = {
112 { SKYPE_TYPE_UNKNOWN_0
, "Unknown_0" },
113 { SKYPE_TYPE_PAYLOAD
, "Payload" },
114 { SKYPE_TYPE_FFR
, "Fragment/Forward/Resend" },
115 { SKYPE_TYPE_NAT_INFO
, "NAT info" },
116 { SKYPE_TYPE_NAT_REPEAT
,"NAT repeat" },
117 { SKYPE_TYPE_AUDIO
, "Audio" },
118 { SKYPE_TYPE_UNKNOWN_F
, "Unknown_F" },
125 dissect_skype_tcp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
128 proto_tree
*skype_tree
= NULL
;
130 guint32 packet_length
;
133 /* XXX: Just until we know how to decode skype over tcp */
136 packet_length
= tvb_length(tvb
);
138 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, PROTO_SHORT_NAME
);
139 col_add_str(pinfo
->cinfo
, COL_INFO
, val_to_str(packet_type
,
140 skype_type_vals
, "Type 0x%1x"));
143 /* Start of message dissection */
144 ti
= proto_tree_add_item(tree
, proto_skype
, tvb
, offset
, -1,
146 skype_tree
= proto_item_add_subtree(ti
, ett_skype
);
148 /* Body dissection */
149 switch (packet_type
) {
152 proto_tree_add_item(skype_tree
, hf_skype_unknown_packet
, tvb
, offset
, -1,
154 offset
= packet_length
;
162 dissect_skype_udp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
165 proto_tree
*skype_tree
= NULL
;
167 guint32 packet_length
;
168 guint8 packet_type
, packet_unk
;
170 conversation_t
*conversation
= NULL
;
171 skype_udp_conv_info_t
*skype_udp_info
;
173 /* look up the conversation */
174 conversation
= find_or_create_conversation(pinfo
);
176 /* if conversation found get the data pointer that you stored */
177 skype_udp_info
= (skype_udp_conv_info_t
*)conversation_get_proto_data(conversation
, proto_skype
);
178 if (!skype_udp_info
) {
179 /* new conversation create local data structure */
180 skype_udp_info
= wmem_new(wmem_file_scope(), skype_udp_conv_info_t
);
181 skype_udp_info
->global_src_ip
= 0;
182 skype_udp_info
->global_dst_ip
= 0;
183 conversation_add_proto_data(conversation
, proto_skype
,
186 /* at this point the conversation data is ready */
188 packet_type
= tvb_get_guint8(tvb
, 2) & SKYPE_SOM_TYPE_MASK
;
189 packet_unk
= (tvb_get_guint8(tvb
, 2) & SKYPE_SOM_UNK_MASK
) >> 4;
191 packet_length
= tvb_length(tvb
);
193 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, PROTO_SHORT_NAME
);
194 col_add_str(pinfo
->cinfo
, COL_INFO
, val_to_str(packet_type
,
195 skype_type_vals
, "Type 0x%1x"));
197 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " Unk: %1x", packet_unk
);
201 /* Start of message dissection */
202 ti
= proto_tree_add_item(tree
, proto_skype
, tvb
, offset
, -1,
204 skype_tree
= proto_item_add_subtree(ti
, ett_skype
);
206 proto_tree_add_item(skype_tree
, hf_skype_som_id
, tvb
, offset
, 2,
209 proto_tree_add_item(skype_tree
, hf_skype_som_unk
, tvb
, offset
, 1,
211 proto_tree_add_item(skype_tree
, hf_skype_som_type
, tvb
, offset
, 1,
215 /* Body dissection */
216 switch (packet_type
) {
218 case SKYPE_TYPE_UNKNOWN_0
:
219 proto_tree_add_item(skype_tree
, hf_skype_unknown_0_unk1
, tvb
, offset
, -1,
221 offset
= packet_length
;
223 case SKYPE_TYPE_PAYLOAD
:
224 proto_tree_add_item(skype_tree
, hf_skype_payload_iv
, tvb
, offset
, 4,
227 proto_tree_add_item(skype_tree
, hf_skype_payload_crc
, tvb
, offset
, 4,
230 proto_tree_add_item(skype_tree
, hf_skype_payload_enc_data
, tvb
, offset
, -1,
232 offset
= packet_length
;
235 proto_tree_add_item(skype_tree
, hf_skype_ffr_num
, tvb
, offset
, 1,
238 proto_tree_add_item(skype_tree
, hf_skype_ffr_unk1
, tvb
, offset
, 4,
241 proto_tree_add_item(skype_tree
, hf_skype_ffr_iv
, tvb
, offset
, 4,
244 proto_tree_add_item(skype_tree
, hf_skype_ffr_crc
, tvb
, offset
, 4,
247 proto_tree_add_item(skype_tree
, hf_skype_ffr_enc_data
, tvb
, offset
, -1,
249 offset
= packet_length
;
251 case SKYPE_TYPE_NAT_INFO
:
252 proto_tree_add_item(skype_tree
, hf_skype_natinfo_srcip
, tvb
, offset
, 4,
254 skype_udp_info
->global_src_ip
= tvb_get_ipv4(tvb
, offset
);
256 proto_tree_add_item(skype_tree
, hf_skype_natinfo_dstip
, tvb
, offset
, 4,
258 skype_udp_info
->global_dst_ip
= tvb_get_ipv4(tvb
, offset
);
261 case SKYPE_TYPE_NAT_REPEAT
:
262 proto_tree_add_item(skype_tree
, hf_skype_natrequest_srcip
, tvb
, offset
, 4,
264 skype_udp_info
->global_src_ip
= tvb_get_ipv4(tvb
, offset
);
266 proto_tree_add_item(skype_tree
, hf_skype_natrequest_dstip
, tvb
, offset
, 4,
268 skype_udp_info
->global_dst_ip
= tvb_get_ipv4(tvb
, offset
);
271 case SKYPE_TYPE_AUDIO
:
272 proto_tree_add_item(skype_tree
, hf_skype_audio_unk1
, tvb
, offset
, -1,
274 offset
= packet_length
;
276 case SKYPE_TYPE_UNKNOWN_F
:
277 proto_tree_add_item(skype_tree
, hf_skype_unknown_f_unk1
, tvb
, offset
, -1,
279 offset
= packet_length
;
282 proto_tree_add_item(skype_tree
, hf_skype_unknown_packet
, tvb
, offset
, -1,
284 offset
= packet_length
;
293 test_skype_udp(tvbuff_t
*tvb
)
295 /* Minimum of 3 bytes, check for valid message type */
296 guint length
= tvb_length(tvb
);
297 guint8 type
= tvb_get_guint8(tvb
, 2) & 0xF;
300 /* FIXME: Extend this by minimum or exact length per message type */
315 dissect_skype_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
317 if (pinfo
->ptype
== PT_UDP
) {
318 if ( !test_skype_udp(tvb
) ) {
321 dissect_skype_udp(tvb
, pinfo
, tree
);
328 dissect_skype_static(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
331 * Don't test for valid packet - we only end here when
332 * the user did a decode-as.
334 if (pinfo
->ptype
== PT_UDP
) {
335 return dissect_skype_udp(tvb
, pinfo
, tree
);
336 } else if (pinfo
->ptype
== PT_UDP
) {
337 return dissect_skype_tcp(tvb
, pinfo
, tree
);
343 proto_register_skype(void)
345 static hf_register_info hf
[] = {
347 /* Start of message fields */
349 { "ID", "skype.som.id", FT_UINT16
, BASE_HEX
, NULL
,
350 0x0, "Message ID", HFILL
}},
353 { "Unknown", "skype.som.unk", FT_UINT8
, BASE_HEX
, NULL
,
354 SKYPE_SOM_UNK_MASK
, NULL
, HFILL
}},
356 { &hf_skype_som_type
,
357 { "Type", "skype.som.type", FT_UINT8
, BASE_HEX
, VALS(skype_type_vals
),
358 SKYPE_SOM_TYPE_MASK
, "Message type", HFILL
}},
363 { &hf_skype_unknown_0_unk1
,
364 { "Unknown1", "skype.unknown_0.unk1", FT_BYTES
, BASE_NONE
, NULL
,
368 { &hf_skype_payload_iv
,
369 { "IV", "skype.payload.iv", FT_UINT32
, BASE_HEX
, NULL
,
372 { &hf_skype_payload_crc
,
373 { "CRC", "skype.payload.crc", FT_UINT32
, BASE_HEX
, NULL
,
376 { &hf_skype_payload_enc_data
,
377 { "Enc Data", "skype.payload.encdata", FT_BYTES
, BASE_NONE
, NULL
,
382 { "Num", "skype.ffr.num", FT_UINT8
, BASE_HEX
, NULL
,
385 { &hf_skype_ffr_unk1
,
386 { "Unk1", "skype.ffr.unk1", FT_UINT32
, BASE_HEX
, NULL
,
390 { "IV", "skype.ffr.iv", FT_UINT32
, BASE_HEX
, NULL
,
394 { "CRC", "skype.ffr.crc", FT_UINT32
, BASE_HEX
, NULL
,
397 { &hf_skype_ffr_enc_data
,
398 { "Enc Data", "skype.ffr.encdata", FT_BYTES
, BASE_NONE
, NULL
,
402 { &hf_skype_natinfo_srcip
,
403 { "Src IP", "skype.natinfo.srcip", FT_IPv4
, BASE_NONE
, NULL
,
404 0x0, "Global source IP", HFILL
}},
406 { &hf_skype_natinfo_dstip
,
407 { "Dst IP", "skype.natinfo.dstip", FT_UINT32
, BASE_HEX
, NULL
,
408 0x0, "Global destination IP", HFILL
}},
411 { &hf_skype_natrequest_srcip
,
412 { "Src IP", "skype.natrequest.srcip", FT_IPv4
, BASE_NONE
, NULL
,
413 0x0, "Global source IP", HFILL
}},
415 { &hf_skype_natrequest_dstip
,
416 { "Dst IP", "skype.natrequest.dstip", FT_UINT32
, BASE_HEX
, NULL
,
420 { &hf_skype_audio_unk1
,
421 { "Unknown1", "skype.audio.unk1", FT_BYTES
, BASE_NONE
, NULL
,
425 { &hf_skype_unknown_f_unk1
,
426 { "Unknown1", "skype.unknown_f.unk1", FT_BYTES
, BASE_NONE
, NULL
,
430 { &hf_skype_unknown_packet
,
431 { "Unknown Packet", "skype.unknown_packet", FT_BYTES
, BASE_NONE
, NULL
,
435 static gint
*ett
[] = {
439 proto_skype
= proto_register_protocol(PROTO_LONG_NAME
, PROTO_SHORT_NAME
, "skype");
440 proto_register_field_array(proto_skype
, hf
, array_length(hf
));
441 proto_register_subtree_array(ett
, array_length(ett
));
445 proto_reg_handoff_skype(void)
447 dissector_handle_t skype_handle
;
449 skype_handle
= new_create_dissector_handle(dissect_skype_static
, proto_skype
);
450 dissector_add_handle("tcp.port", skype_handle
);
451 dissector_add_handle("udp.port", skype_handle
);
453 heur_dissector_add("tcp", dissect_skype_heur
, proto_skype
);
454 heur_dissector_add("udp", dissect_skype_heur
, proto_skype
);