Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-skype.c
blobcdcffd124dea349eed89ee17e64c419533d6d6f5
1 /* packet-skype.c
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
19 * TODO:
20 * - Authentication
21 * - TCP
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)
28 * - Improve tests
31 #include "config.h"
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;
50 /* ett handles */
51 static int ett_skype;
53 #define SKYPE_SOM_UNK_MASK 0xF0
54 #define SKYPE_SOM_TYPE_MASK 0x0F
56 /* hf elements */
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;
61 /* Message body */
62 /* Unknown_0 */
63 static int hf_skype_unknown_0_unk1;
64 /* Payload */
65 static int hf_skype_payload_iv;
66 static int hf_skype_payload_crc;
67 static int hf_skype_payload_enc_data;
68 /* Resend */
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;
74 /* Nat info */
75 static int hf_skype_natinfo_srcip;
76 static int hf_skype_natinfo_dstip;
77 /* Nat request */
78 static int hf_skype_natrequest_srcip;
79 static int hf_skype_natrequest_dstip;
80 /* Audio */
81 static int hf_skype_audio_unk1;
82 /* Unknown_f */
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"
91 typedef enum {
92 SKYPE_TYPE_UNKNOWN_0 = 0,
93 SKYPE_TYPE_PAYLOAD = 2,
94 SKYPE_TYPE_FFR = 3,
95 SKYPE_TYPE_NAT_INFO = 5,
96 SKYPE_TYPE_NAT_REPEAT = 7,
97 SKYPE_TYPE_AUDIO = 0xd,
98 SKYPE_TYPE_UNKNOWN_F = 0xf
99 } skype_type_t;
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" },
111 { 0, NULL }
115 static int
116 dissect_skype_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
118 proto_item *ti;
119 proto_tree *skype_tree = NULL;
120 uint32_t offset = 0;
121 uint32_t packet_length;
122 uint8_t packet_type;
124 /* XXX: Just until we know how to decode skype over tcp */
125 packet_type = 255;
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"));
133 if (tree) {
134 /* Start of message dissection */
135 ti = proto_tree_add_item(tree, proto_skype, tvb, offset, -1,
136 ENC_NA);
137 skype_tree = proto_item_add_subtree(ti, ett_skype);
139 /* Body dissection */
140 switch (packet_type) {
142 default:
143 proto_tree_add_item(skype_tree, hf_skype_unknown_packet, tvb, offset, -1,
144 ENC_NA);
145 offset = packet_length;
146 break;
149 return offset;
152 static int
153 dissect_skype_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
155 proto_item *ti;
156 proto_tree *skype_tree = NULL;
157 uint32_t offset = 0;
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,
175 skype_udp_info);
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"));
187 if (packet_unk) {
188 col_append_fstr(pinfo->cinfo, COL_INFO, " Unk: %1x", packet_unk);
191 if (tree) {
192 /* Start of message dissection */
193 ti = proto_tree_add_item(tree, proto_skype, tvb, offset, -1,
194 ENC_NA);
195 skype_tree = proto_item_add_subtree(ti, ett_skype);
197 proto_tree_add_item(skype_tree, hf_skype_som_id, tvb, offset, 2,
198 ENC_BIG_ENDIAN);
199 offset += 2;
200 proto_tree_add_item(skype_tree, hf_skype_som_unk, tvb, offset, 1,
201 ENC_BIG_ENDIAN);
202 proto_tree_add_item(skype_tree, hf_skype_som_type, tvb, offset, 1,
203 ENC_BIG_ENDIAN);
204 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,
211 ENC_NA);
212 offset = packet_length;
213 break;
214 case SKYPE_TYPE_PAYLOAD:
215 proto_tree_add_item(skype_tree, hf_skype_payload_iv, tvb, offset, 4,
216 ENC_BIG_ENDIAN);
217 offset += 4;
218 proto_tree_add_item(skype_tree, hf_skype_payload_crc, tvb, offset, 4,
219 ENC_BIG_ENDIAN);
220 offset += 4;
221 proto_tree_add_item(skype_tree, hf_skype_payload_enc_data, tvb, offset, -1,
222 ENC_NA);
223 offset = packet_length;
224 break;
225 case SKYPE_TYPE_FFR:
226 proto_tree_add_item(skype_tree, hf_skype_ffr_num, tvb, offset, 1,
227 ENC_BIG_ENDIAN);
228 offset += 1;
229 proto_tree_add_item(skype_tree, hf_skype_ffr_unk1, tvb, offset, 4,
230 ENC_BIG_ENDIAN);
231 offset += 4;
232 proto_tree_add_item(skype_tree, hf_skype_ffr_iv, tvb, offset, 4,
233 ENC_BIG_ENDIAN);
234 offset += 4;
235 proto_tree_add_item(skype_tree, hf_skype_ffr_crc, tvb, offset, 4,
236 ENC_BIG_ENDIAN);
237 offset += 4;
238 proto_tree_add_item(skype_tree, hf_skype_ffr_enc_data, tvb, offset, -1,
239 ENC_NA);
240 offset = packet_length;
241 break;
242 case SKYPE_TYPE_NAT_INFO:
243 proto_tree_add_item(skype_tree, hf_skype_natinfo_srcip, tvb, offset, 4,
244 ENC_BIG_ENDIAN);
245 skype_udp_info->global_src_ip = tvb_get_ipv4(tvb, offset);
246 offset += 4;
247 proto_tree_add_item(skype_tree, hf_skype_natinfo_dstip, tvb, offset, 4,
248 ENC_BIG_ENDIAN);
249 skype_udp_info->global_dst_ip = tvb_get_ipv4(tvb, offset);
250 offset += 4;
251 break;
252 case SKYPE_TYPE_NAT_REPEAT:
253 proto_tree_add_item(skype_tree, hf_skype_natrequest_srcip, tvb, offset, 4,
254 ENC_BIG_ENDIAN);
255 skype_udp_info->global_src_ip = tvb_get_ipv4(tvb, offset);
256 offset += 4;
257 proto_tree_add_item(skype_tree, hf_skype_natrequest_dstip, tvb, offset, 4,
258 ENC_BIG_ENDIAN);
259 skype_udp_info->global_dst_ip = tvb_get_ipv4(tvb, offset);
260 offset += 4;
261 break;
262 case SKYPE_TYPE_AUDIO:
263 proto_tree_add_item(skype_tree, hf_skype_audio_unk1, tvb, offset, -1,
264 ENC_NA);
265 offset = packet_length;
266 break;
267 case SKYPE_TYPE_UNKNOWN_F:
268 proto_tree_add_item(skype_tree, hf_skype_unknown_f_unk1, tvb, offset, -1,
269 ENC_NA);
270 offset = packet_length;
271 break;
272 default:
273 proto_tree_add_item(skype_tree, hf_skype_unknown_packet, tvb, offset, -1,
274 ENC_NA);
275 offset = packet_length;
276 break;
279 return offset;
282 static bool
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;
289 if ( type == 0 ||
290 /* FIXME: Extend this by minimum or exact length per message type */
291 type == 2 ||
292 type == 3 ||
293 type == 5 ||
294 type == 7 ||
295 type == 0xd ||
296 type == 0xf
299 return true;
302 return false;
305 static bool
306 dissect_skype_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
308 if ( !test_skype_udp(tvb) ) {
309 return false;
312 dissect_skype_udp(tvb, pinfo, tree);
313 return true;
316 static int
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);
328 return 0;
331 void
332 proto_register_skype(void)
334 static hf_register_info hf[] = {
336 /* Start of message fields */
337 { &hf_skype_som_id,
338 { "ID", "skype.som.id", FT_UINT16, BASE_HEX, NULL,
339 0x0, "Message ID", HFILL }},
341 { &hf_skype_som_unk,
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 }},
349 /* Message body */
351 /* Unknown_0 */
352 { &hf_skype_unknown_0_unk1,
353 { "Unknown1", "skype.unknown_0.unk1", FT_BYTES, BASE_NONE, NULL,
354 0x0, NULL, HFILL }},
356 /* Payload */
357 { &hf_skype_payload_iv,
358 { "IV", "skype.payload.iv", FT_UINT32, BASE_HEX, NULL,
359 0x0, NULL, HFILL }},
361 { &hf_skype_payload_crc,
362 { "CRC", "skype.payload.crc", FT_UINT32, BASE_HEX, NULL,
363 0x0, NULL, HFILL }},
365 { &hf_skype_payload_enc_data,
366 { "Enc Data", "skype.payload.encdata", FT_BYTES, BASE_NONE, NULL,
367 0x0, NULL, HFILL }},
369 /* Resend */
370 { &hf_skype_ffr_num,
371 { "Num", "skype.ffr.num", FT_UINT8, BASE_HEX, NULL,
372 0x0, NULL, HFILL }},
374 { &hf_skype_ffr_unk1,
375 { "Unk1", "skype.ffr.unk1", FT_UINT32, BASE_HEX, NULL,
376 0x0, NULL, HFILL }},
378 { &hf_skype_ffr_iv,
379 { "IV", "skype.ffr.iv", FT_UINT32, BASE_HEX, NULL,
380 0x0, NULL, HFILL }},
382 { &hf_skype_ffr_crc,
383 { "CRC", "skype.ffr.crc", FT_UINT32, BASE_HEX, NULL,
384 0x0, NULL, HFILL }},
386 { &hf_skype_ffr_enc_data,
387 { "Enc Data", "skype.ffr.encdata", FT_BYTES, BASE_NONE, NULL,
388 0x0, NULL, HFILL }},
390 /* Nat info */
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 }},
399 /* Nat request */
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,
406 0x0, NULL, HFILL }},
408 /* Audio */
409 { &hf_skype_audio_unk1,
410 { "Unknown1", "skype.audio.unk1", FT_BYTES, BASE_NONE, NULL,
411 0x0, NULL, HFILL }},
413 /* Unknown_F */
414 { &hf_skype_unknown_f_unk1,
415 { "Unknown1", "skype.unknown_f.unk1", FT_BYTES, BASE_NONE, NULL,
416 0x0, NULL, HFILL }},
418 /* Unknown packet */
419 { &hf_skype_unknown_packet,
420 { "Unknown Packet", "skype.unknown_packet", FT_BYTES, BASE_NONE, NULL,
421 0x0, NULL, HFILL }},
424 static int *ett[] = {
425 &ett_skype,
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);
435 void
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
447 * Local variables:
448 * c-basic-offset: 8
449 * tab-width: 8
450 * indent-tabs-mode: t
451 * End:
453 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
454 * :indentSize=8:tabSize=8:noTabs=false: