Coverage Report

Created: 2025-12-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-skype.c
Line
Count
Source
1
/* packet-skype.c
2
 * Routines for the disassembly of Skype
3
 *
4
 * Copyright 2009 Joerg Mayer (see AUTHORS file)
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
/*
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
18
 *
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
29
 */
30
31
#include "config.h"
32
33
#include <epan/packet.h>
34
#include <epan/conversation.h>
35
36
void proto_register_skype(void);
37
void proto_reg_handoff_skype(void);
38
39
static dissector_handle_t skype_handle;
40
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;
46
47
/* protocol handles */
48
static int proto_skype;
49
50
/* ett handles */
51
static int ett_skype;
52
53
14
#define SKYPE_SOM_UNK_MASK  0xF0
54
14
#define SKYPE_SOM_TYPE_MASK 0x0F
55
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;
86
87
88
14
#define PROTO_SHORT_NAME "SKYPE"
89
14
#define PROTO_LONG_NAME "SKYPE"
90
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;
100
101
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" },
110
111
  { 0,  NULL }
112
};
113
114
115
static int
116
dissect_skype_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
117
0
{
118
0
  proto_item *ti;
119
0
  proto_tree *skype_tree = NULL;
120
0
  uint32_t offset = 0;
121
0
  uint32_t packet_length;
122
0
  uint8_t packet_type;
123
124
  /* XXX: Just until we know how to decode skype over tcp */
125
0
  packet_type = 255;
126
127
0
  packet_length = tvb_captured_length(tvb);
128
129
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_SHORT_NAME);
130
0
  col_add_str(pinfo->cinfo, COL_INFO, val_to_str(pinfo->pool, packet_type,
131
0
    skype_type_vals, "Type 0x%1x"));
132
133
0
  if (tree) {
134
    /* Start of message dissection */
135
0
    ti = proto_tree_add_item(tree, proto_skype, tvb, offset, -1,
136
0
        ENC_NA);
137
0
    skype_tree = proto_item_add_subtree(ti, ett_skype);
138
139
    /* Body dissection */
140
0
    switch (packet_type) {
141
142
0
    default:
143
0
      proto_tree_add_item(skype_tree, hf_skype_unknown_packet, tvb, offset, -1,
144
0
        ENC_NA);
145
0
      offset = packet_length;
146
0
      break;
147
0
    }
148
0
  }
149
0
  return offset;
150
0
}
151
152
static int
153
dissect_skype_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
154
0
{
155
0
  proto_item *ti;
156
0
  proto_tree *skype_tree = NULL;
157
0
  uint32_t offset = 0;
158
0
  uint32_t packet_length;
159
0
  uint8_t packet_type, packet_unk;
160
161
0
  conversation_t   *conversation = NULL;
162
0
  skype_udp_conv_info_t *skype_udp_info;
163
164
  /* look up the conversation */
165
0
  conversation = find_or_create_conversation(pinfo);
166
167
  /* if conversation found get the data pointer that you stored */
168
0
  skype_udp_info = (skype_udp_conv_info_t *)conversation_get_proto_data(conversation, proto_skype);
169
0
  if (!skype_udp_info) {
170
    /* new conversation create local data structure */
171
0
    skype_udp_info = wmem_new(wmem_file_scope(), skype_udp_conv_info_t);
172
0
    skype_udp_info->global_src_ip = 0;
173
0
    skype_udp_info->global_dst_ip = 0;
174
0
    conversation_add_proto_data(conversation, proto_skype,
175
0
      skype_udp_info);
176
0
  }
177
  /* at this point the conversation data is ready */
178
179
0
  packet_type = tvb_get_uint8(tvb, 2) & SKYPE_SOM_TYPE_MASK;
180
0
  packet_unk = (tvb_get_uint8(tvb, 2) & SKYPE_SOM_UNK_MASK) >> 4;
181
182
0
  packet_length = tvb_captured_length(tvb);
183
184
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_SHORT_NAME);
185
0
  col_add_str(pinfo->cinfo, COL_INFO, val_to_str(pinfo->pool, packet_type,
186
0
    skype_type_vals, "Type 0x%1x"));
187
0
  if (packet_unk) {
188
0
    col_append_fstr(pinfo->cinfo, COL_INFO, " Unk: %1x", packet_unk);
189
0
  }
190
191
0
  if (tree) {
192
    /* Start of message dissection */
193
0
    ti = proto_tree_add_item(tree, proto_skype, tvb, offset, -1,
194
0
        ENC_NA);
195
0
    skype_tree = proto_item_add_subtree(ti, ett_skype);
196
197
0
    proto_tree_add_item(skype_tree, hf_skype_som_id, tvb, offset, 2,
198
0
      ENC_BIG_ENDIAN);
199
0
    offset += 2;
200
0
    proto_tree_add_item(skype_tree, hf_skype_som_unk, tvb, offset, 1,
201
0
      ENC_BIG_ENDIAN);
202
0
    proto_tree_add_item(skype_tree, hf_skype_som_type, tvb, offset, 1,
203
0
      ENC_BIG_ENDIAN);
204
0
    offset += 1;
205
206
    /* Body dissection */
207
0
    switch (packet_type) {
208
209
0
    case SKYPE_TYPE_UNKNOWN_0:
210
0
      proto_tree_add_item(skype_tree, hf_skype_unknown_0_unk1, tvb, offset, -1,
211
0
        ENC_NA);
212
0
      offset = packet_length;
213
0
      break;
214
0
    case SKYPE_TYPE_PAYLOAD:
215
0
      proto_tree_add_item(skype_tree, hf_skype_payload_iv, tvb, offset, 4,
216
0
        ENC_BIG_ENDIAN);
217
0
      offset += 4;
218
0
      proto_tree_add_item(skype_tree, hf_skype_payload_crc, tvb, offset, 4,
219
0
        ENC_BIG_ENDIAN);
220
0
      offset += 4;
221
0
      proto_tree_add_item(skype_tree, hf_skype_payload_enc_data, tvb, offset, -1,
222
0
        ENC_NA);
223
0
      offset = packet_length;
224
0
      break;
225
0
    case SKYPE_TYPE_FFR:
226
0
      proto_tree_add_item(skype_tree, hf_skype_ffr_num, tvb, offset, 1,
227
0
        ENC_BIG_ENDIAN);
228
0
      offset += 1;
229
0
      proto_tree_add_item(skype_tree, hf_skype_ffr_unk1, tvb, offset, 4,
230
0
        ENC_BIG_ENDIAN);
231
0
      offset += 4;
232
0
      proto_tree_add_item(skype_tree, hf_skype_ffr_iv, tvb, offset, 4,
233
0
        ENC_BIG_ENDIAN);
234
0
      offset += 4;
235
0
      proto_tree_add_item(skype_tree, hf_skype_ffr_crc, tvb, offset, 4,
236
0
        ENC_BIG_ENDIAN);
237
0
      offset += 4;
238
0
      proto_tree_add_item(skype_tree, hf_skype_ffr_enc_data, tvb, offset, -1,
239
0
        ENC_NA);
240
0
      offset = packet_length;
241
0
      break;
242
0
    case SKYPE_TYPE_NAT_INFO:
243
0
      proto_tree_add_item(skype_tree, hf_skype_natinfo_srcip, tvb, offset, 4,
244
0
        ENC_BIG_ENDIAN);
245
0
      skype_udp_info->global_src_ip = tvb_get_ipv4(tvb, offset);
246
0
      offset += 4;
247
0
      proto_tree_add_item(skype_tree, hf_skype_natinfo_dstip, tvb, offset, 4,
248
0
        ENC_BIG_ENDIAN);
249
0
      skype_udp_info->global_dst_ip = tvb_get_ipv4(tvb, offset);
250
0
      offset += 4;
251
0
      break;
252
0
    case SKYPE_TYPE_NAT_REPEAT:
253
0
      proto_tree_add_item(skype_tree, hf_skype_natrequest_srcip, tvb, offset, 4,
254
0
        ENC_BIG_ENDIAN);
255
0
      skype_udp_info->global_src_ip = tvb_get_ipv4(tvb, offset);
256
0
      offset += 4;
257
0
      proto_tree_add_item(skype_tree, hf_skype_natrequest_dstip, tvb, offset, 4,
258
0
        ENC_BIG_ENDIAN);
259
0
      skype_udp_info->global_dst_ip = tvb_get_ipv4(tvb, offset);
260
0
      offset += 4;
261
0
      break;
262
0
    case SKYPE_TYPE_AUDIO:
263
0
      proto_tree_add_item(skype_tree, hf_skype_audio_unk1, tvb, offset, -1,
264
0
        ENC_NA);
265
0
      offset = packet_length;
266
0
      break;
267
0
    case SKYPE_TYPE_UNKNOWN_F:
268
0
      proto_tree_add_item(skype_tree, hf_skype_unknown_f_unk1, tvb, offset, -1,
269
0
        ENC_NA);
270
0
      offset = packet_length;
271
0
      break;
272
0
    default:
273
0
      proto_tree_add_item(skype_tree, hf_skype_unknown_packet, tvb, offset, -1,
274
0
        ENC_NA);
275
0
      offset = packet_length;
276
0
      break;
277
0
    }
278
0
  }
279
0
  return offset;
280
0
}
281
282
static bool
283
test_skype_udp(tvbuff_t *tvb)
284
0
{
285
  /* Minimum of 3 bytes, check for valid message type */
286
0
  if (tvb_captured_length(tvb) > 3)
287
0
  {
288
0
    uint8_t type = tvb_get_uint8(tvb, 2) & 0xF;
289
0
    if ( type == 0   ||
290
      /* FIXME: Extend this by minimum or exact length per message type */
291
0
      type == 2   ||
292
0
      type == 3   ||
293
0
      type == 5   ||
294
0
      type == 7   ||
295
0
      type == 0xd ||
296
0
      type == 0xf
297
0
      )
298
0
    {
299
0
      return true;
300
0
    }
301
0
  }
302
0
  return false;
303
0
}
304
305
static bool
306
dissect_skype_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
307
0
{
308
0
  if ( !test_skype_udp(tvb) ) {
309
0
    return false;
310
0
  }
311
312
0
  dissect_skype_udp(tvb, pinfo, tree);
313
0
  return true;
314
0
}
315
316
static int
317
dissect_skype_static(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
318
0
{
319
  /*
320
   * Don't test for valid packet - we only end here when
321
   * the user did a decode-as.
322
   */
323
0
  if (pinfo->ptype == PT_UDP) {
324
0
    return dissect_skype_udp(tvb, pinfo, tree);
325
0
  } else if (pinfo->ptype == PT_TCP) {
326
0
    return dissect_skype_tcp(tvb, pinfo, tree);
327
0
  }
328
0
  return 0;
329
0
}
330
331
void
332
proto_register_skype(void)
333
14
{
334
14
  static hf_register_info hf[] = {
335
336
  /* Start of message fields */
337
14
    { &hf_skype_som_id,
338
14
    { "ID", "skype.som.id", FT_UINT16, BASE_HEX, NULL,
339
14
      0x0, "Message ID", HFILL }},
340
341
14
    { &hf_skype_som_unk,
342
14
    { "Unknown",  "skype.som.unk", FT_UINT8, BASE_HEX, NULL,
343
14
      SKYPE_SOM_UNK_MASK, NULL, HFILL }},
344
345
14
    { &hf_skype_som_type,
346
14
    { "Type", "skype.som.type", FT_UINT8, BASE_HEX, VALS(skype_type_vals),
347
14
      SKYPE_SOM_TYPE_MASK, "Message type", HFILL }},
348
349
  /* Message body */
350
351
  /* Unknown_0 */
352
14
    { &hf_skype_unknown_0_unk1,
353
14
    { "Unknown1",   "skype.unknown_0.unk1", FT_BYTES, BASE_NONE, NULL,
354
14
      0x0, NULL, HFILL }},
355
356
  /* Payload */
357
14
    { &hf_skype_payload_iv,
358
14
    { "IV",   "skype.payload.iv", FT_UINT32, BASE_HEX, NULL,
359
14
      0x0, NULL, HFILL }},
360
361
14
    { &hf_skype_payload_crc,
362
14
    { "CRC",   "skype.payload.crc", FT_UINT32, BASE_HEX, NULL,
363
14
      0x0, NULL, HFILL }},
364
365
14
    { &hf_skype_payload_enc_data,
366
14
    { "Enc Data",   "skype.payload.encdata", FT_BYTES, BASE_NONE, NULL,
367
14
      0x0, NULL, HFILL }},
368
369
  /* Resend */
370
14
    { &hf_skype_ffr_num,
371
14
    { "Num",   "skype.ffr.num", FT_UINT8, BASE_HEX, NULL,
372
14
      0x0, NULL, HFILL }},
373
374
14
    { &hf_skype_ffr_unk1,
375
14
    { "Unk1",   "skype.ffr.unk1", FT_UINT32, BASE_HEX, NULL,
376
14
      0x0, NULL, HFILL }},
377
378
14
    { &hf_skype_ffr_iv,
379
14
    { "IV",   "skype.ffr.iv", FT_UINT32, BASE_HEX, NULL,
380
14
      0x0, NULL, HFILL }},
381
382
14
    { &hf_skype_ffr_crc,
383
14
    { "CRC",   "skype.ffr.crc", FT_UINT32, BASE_HEX, NULL,
384
14
      0x0, NULL, HFILL }},
385
386
14
    { &hf_skype_ffr_enc_data,
387
14
    { "Enc Data",   "skype.ffr.encdata", FT_BYTES, BASE_NONE, NULL,
388
14
      0x0, NULL, HFILL }},
389
390
  /* Nat info */
391
14
    { &hf_skype_natinfo_srcip,
392
14
    { "Src IP",   "skype.natinfo.srcip", FT_IPv4, BASE_NONE, NULL,
393
14
      0x0, "Global source IP", HFILL }},
394
395
14
    { &hf_skype_natinfo_dstip,
396
14
    { "Dst IP",   "skype.natinfo.dstip", FT_UINT32, BASE_HEX, NULL,
397
14
      0x0, "Global destination IP", HFILL }},
398
399
  /* Nat request */
400
14
    { &hf_skype_natrequest_srcip,
401
14
    { "Src IP",   "skype.natrequest.srcip", FT_IPv4, BASE_NONE, NULL,
402
14
      0x0, "Global source IP", HFILL }},
403
404
14
    { &hf_skype_natrequest_dstip,
405
14
    { "Dst IP",   "skype.natrequest.dstip", FT_UINT32, BASE_HEX, NULL,
406
14
      0x0, NULL, HFILL }},
407
408
  /* Audio */
409
14
    { &hf_skype_audio_unk1,
410
14
    { "Unknown1",   "skype.audio.unk1", FT_BYTES, BASE_NONE, NULL,
411
14
      0x0, NULL, HFILL }},
412
413
  /* Unknown_F */
414
14
    { &hf_skype_unknown_f_unk1,
415
14
    { "Unknown1",   "skype.unknown_f.unk1", FT_BYTES, BASE_NONE, NULL,
416
14
      0x0, NULL, HFILL }},
417
418
  /* Unknown packet */
419
14
    { &hf_skype_unknown_packet,
420
14
    { "Unknown Packet",   "skype.unknown_packet", FT_BYTES, BASE_NONE, NULL,
421
14
      0x0, NULL, HFILL }},
422
423
14
  };
424
14
  static int *ett[] = {
425
14
    &ett_skype,
426
14
  };
427
428
14
  proto_skype = proto_register_protocol(PROTO_LONG_NAME, PROTO_SHORT_NAME, "skype");
429
14
  proto_register_field_array(proto_skype, hf, array_length(hf));
430
14
  proto_register_subtree_array(ett, array_length(ett));
431
432
14
  skype_handle = register_dissector("skype", dissect_skype_static, proto_skype);
433
14
}
434
435
void
436
proto_reg_handoff_skype(void)
437
14
{
438
14
  dissector_add_for_decode_as_with_preference("tcp.port", skype_handle);
439
14
  dissector_add_for_decode_as_with_preference("udp.port", skype_handle);
440
441
14
  heur_dissector_add("udp", dissect_skype_heur, "Skype over UDP", "skype_udp", proto_skype, HEURISTIC_DISABLE);
442
14
}
443
444
/*
445
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
446
 *
447
 * Local variables:
448
 * c-basic-offset: 8
449
 * tab-width: 8
450
 * indent-tabs-mode: t
451
 * End:
452
 *
453
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
454
 * :indentSize=8:tabSize=8:noTabs=false:
455
 */