Coverage Report

Created: 2023-06-29 06:52

/src/ndpi/src/lib/protocols/stun.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * stun.c
3
 *
4
 * Copyright (C) 2011-22 - ntop.org
5
 *
6
 * This file is part of nDPI, an open source deep packet inspection
7
 * library based on the OpenDPI and PACE technology by ipoque GmbH
8
 *
9
 * nDPI is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Lesser General Public License as published by
11
 * the Free Software Foundation, either version 3 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * nDPI is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with nDPI. If not, see <http://www.gnu.org/licenses/>.
21
 *
22
 */
23
24
#include "ndpi_protocol_ids.h"
25
26
137
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_STUN
27
28
#include "ndpi_api.h"
29
30
6.58k
#define MAX_NUM_STUN_PKTS     3
31
32
// #define DEBUG_STUN 1
33
// #define DEBUG_LRU  1
34
// #define DEBUG_ZOOM_LRU  1
35
// #define DEBUG_MONITORING 1
36
37
3.16k
#define STUN_HDR_LEN   20 /* STUN message header length, Classic-STUN (RFC 3489) and STUN (RFC 8489) both */
38
39
extern void switch_to_tls(struct ndpi_detection_module_struct *ndpi_struct,
40
        struct ndpi_flow_struct *flow);
41
extern int is_rtp_or_rtcp(struct ndpi_detection_module_struct *ndpi_struct,
42
                          struct ndpi_flow_struct *flow);
43
extern u_int8_t rtp_get_stream_type(u_int8_t payloadType, ndpi_multimedia_flow_type *s_type);
44
extern int is_dtls(const u_int8_t *buf, u_int32_t buf_len, u_int32_t *block_len);
45
46
static int stun_monitoring(struct ndpi_detection_module_struct *ndpi_struct,
47
                           struct ndpi_flow_struct *flow)
48
0
{
49
0
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
50
0
  int rtp_rtcp;
51
0
  u_int8_t first_byte;
52
53
#ifdef DEBUG_MONITORING
54
  printf("[STUN-MON] Packet counter %d\n", flow->packet_counter);
55
#endif
56
57
0
  if(packet->payload_packet_len == 0)
58
0
    return 1;
59
60
0
  first_byte = packet->payload[0];
61
62
  /* draft-ietf-avtcore-rfc7983bis */
63
0
  if(first_byte <= 3) {
64
#ifdef DEBUG_MONITORING
65
    printf("[STUN-MON] Still STUN\n");
66
#endif
67
0
    return 1;
68
0
  } else if(first_byte <= 19) {
69
#ifdef DEBUG_MONITORING
70
    printf("[STUN-MON] DROP or ZRTP range. Unexpected but keep looking\n");
71
#endif
72
0
    return 1;
73
0
  } else if(first_byte <= 63) {
74
#ifdef DEBUG_MONITORING
75
    printf("[STUN-MON] DTLS\n");
76
#endif
77
    /* TODO */
78
0
    return 1;
79
0
  } else if(first_byte <= 127) {
80
#ifdef DEBUG_MONITORING
81
    printf("[STUN-MON] QUIC or TURN range. Unexpected but keep looking\n");
82
#endif
83
0
    return 1;
84
0
  } else if(first_byte <= 191) {
85
86
0
    rtp_rtcp = is_rtp_or_rtcp(ndpi_struct, flow);
87
0
    if(rtp_rtcp == IS_RTP) {
88
#ifdef DEBUG_MONITORING
89
      printf("[STUN-MON] RTP (dir %d)\n", packet->packet_direction);
90
#endif
91
0
      NDPI_LOG_INFO(ndpi_struct, "Found RTP over STUN\n");
92
93
0
      rtp_get_stream_type(packet->payload[1] & 0x7F, &flow->flow_multimedia_type);
94
95
0
      if(flow->detected_protocol_stack[1] != NDPI_PROTOCOL_UNKNOWN) {
96
        /* STUN/SUBPROTO -> SUBPROTO/RTP */
97
0
        ndpi_set_detected_protocol(ndpi_struct, flow,
98
0
                                   NDPI_PROTOCOL_RTP, flow->detected_protocol_stack[0],
99
0
                                   NDPI_CONFIDENCE_DPI);
100
0
      } else {
101
        /* STUN -> STUN/RTP */
102
0
        ndpi_set_detected_protocol(ndpi_struct, flow,
103
0
                                   NDPI_PROTOCOL_RTP, NDPI_PROTOCOL_STUN,
104
0
                                   NDPI_CONFIDENCE_DPI);
105
0
      }
106
0
      return 0; /* Stop */
107
0
    } else if(rtp_rtcp == IS_RTCP) {
108
#ifdef DEBUG_MONITORING
109
      printf("[STUN-MON] RTCP\n");
110
#endif
111
0
      return 1;
112
0
    } else {
113
#ifdef DEBUG_MONITORING
114
      printf("[STUN-MON] Unexpected\n");
115
#endif
116
0
      return 1;
117
0
    }
118
0
  } else {
119
#ifdef DEBUG_MONITORING
120
    printf("[STUN-MON] QUIC range. Unexpected but keep looking\n");
121
#endif
122
0
    return 1;
123
0
  }
124
0
}
125
126
/* ************************************************************ */
127
128
907
u_int32_t get_stun_lru_key(struct ndpi_flow_struct *flow, u_int8_t rev) {
129
907
  if(rev) {
130
11
    if(flow->is_ipv6)
131
11
      return ndpi_quick_hash(flow->s_address.v6, 16) + ntohs(flow->s_port);
132
0
    else
133
0
      return ntohl(flow->s_address.v4) + ntohs(flow->s_port);
134
896
  } else {
135
896
    if(flow->is_ipv6)
136
454
      return ndpi_quick_hash(flow->c_address.v6, 16) + ntohs(flow->c_port);
137
442
    else
138
442
      return ntohl(flow->c_address.v4) + ntohs(flow->c_port);
139
896
  }
140
907
}
141
142
/* ************************************************************ */
143
144
int stun_search_into_zoom_cache(struct ndpi_detection_module_struct *ndpi_struct,
145
                                struct ndpi_flow_struct *flow)
146
5.40k
{
147
5.40k
  u_int16_t dummy;
148
5.40k
  u_int32_t key;
149
150
5.40k
  if(ndpi_struct->stun_zoom_cache &&
151
5.40k
     flow->l4_proto == IPPROTO_UDP) {
152
880
    key = get_stun_lru_key(flow, 0); /* Src */
153
#ifdef DEBUG_ZOOM_LRU
154
    printf("[LRU ZOOM] Search %u [src_port %u]\n", key, ntohs(flow->c_port));
155
#endif
156
157
880
    if(ndpi_lru_find_cache(ndpi_struct->stun_zoom_cache, key,
158
880
                           &dummy, 0 /* Don't remove it as it can be used for other connections */,
159
880
         ndpi_get_current_time(flow))) {
160
#ifdef DEBUG_ZOOM_LRU
161
      printf("[LRU ZOOM] Found");
162
#endif
163
0
      return 1;
164
0
    }
165
880
  }
166
5.40k
  return 0;
167
5.40k
}
168
169
/* ************************************************************ */
170
171
static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
172
           struct ndpi_flow_struct *flow,
173
7
           u_int app_proto) {
174
7
  ndpi_confidence_t confidence = NDPI_CONFIDENCE_DPI;
175
176
7
  if(app_proto == NDPI_PROTOCOL_UNKNOWN) {
177
    /* https://support.google.com/a/answer/1279090?hl=en */
178
0
    if((ntohs(flow->c_port) >= 19302 && ntohs(flow->c_port) <= 19309) ||
179
0
       ntohs(flow->c_port) == 3478 ||
180
0
       (ntohs(flow->s_port) >= 19302 && ntohs(flow->s_port) <= 19309) ||
181
0
       ntohs(flow->s_port) == 3478) {
182
0
      if(flow->is_ipv6) {
183
0
  u_int64_t pref1 = 0x2001486048640005; /* 2001:4860:4864:5::/64 */
184
0
  u_int64_t pref2 = 0x2001486048640006; /* 2001:4860:4864:6::/64 */
185
186
0
        if(memcmp(&flow->c_address.v6, &pref1, sizeof(pref1)) == 0 ||
187
0
           memcmp(&flow->c_address.v6, &pref2, sizeof(pref2)) == 0 ||
188
0
           memcmp(&flow->s_address.v6, &pref1, sizeof(pref1)) == 0 ||
189
0
           memcmp(&flow->s_address.v6, &pref2, sizeof(pref2)) == 0) {
190
0
          app_proto = NDPI_PROTOCOL_HANGOUT_DUO;
191
0
  }
192
0
      } else {
193
0
        u_int32_t c_address, s_address;
194
195
0
  c_address = ntohl(flow->c_address.v4);
196
0
  s_address = ntohl(flow->s_address.v4);
197
0
        if((c_address & 0xFFFFFFF0) == 0x4a7dfa00 || /* 74.125.250.0/24 */
198
0
           (c_address & 0xFFFFFFF0) == 0x8efa5200 || /* 142.250.82.0/24 */
199
0
           (s_address & 0xFFFFFFF0) == 0x4a7dfa00 ||
200
0
           (s_address & 0xFFFFFFF0) == 0x8efa5200) {
201
0
          app_proto = NDPI_PROTOCOL_HANGOUT_DUO;
202
0
  }
203
0
      }
204
0
    }
205
0
  }
206
207
7
  if(ndpi_struct->stun_cache
208
7
     && (app_proto != NDPI_PROTOCOL_UNKNOWN)
209
7
     ) /* Cache flow sender info */ {
210
5
    u_int32_t key = get_stun_lru_key(flow, 0);
211
5
    u_int16_t cached_proto;
212
213
5
    if(ndpi_lru_find_cache(ndpi_struct->stun_cache, key,
214
5
         &cached_proto, 0 /* Don't remove it as it can be used for other connections */,
215
5
         ndpi_get_current_time(flow))) {
216
#ifdef DEBUG_LRU
217
      printf("[LRU] FOUND %u / %u: no need to cache %u.%u\n", key, cached_proto, proto, app_proto);
218
#endif
219
0
      if(app_proto != cached_proto) {
220
0
        app_proto = cached_proto;
221
0
        confidence = NDPI_CONFIDENCE_DPI_CACHE;
222
0
      }
223
5
    } else {
224
5
      u_int32_t key_rev = get_stun_lru_key(flow, 1);
225
226
5
      if(ndpi_lru_find_cache(ndpi_struct->stun_cache, key_rev,
227
5
           &cached_proto, 0 /* Don't remove it as it can be used for other connections */,
228
5
           ndpi_get_current_time(flow))) {
229
#ifdef DEBUG_LRU
230
  printf("[LRU] FOUND %u / %u: no need to cache %u.%u\n", key_rev, cached_proto, proto, app_proto);
231
#endif
232
0
  if(app_proto != cached_proto) {
233
0
    app_proto = cached_proto;
234
0
    confidence = NDPI_CONFIDENCE_DPI_CACHE;
235
0
  }
236
5
      } else {
237
5
  if(app_proto != NDPI_PROTOCOL_STUN) {
238
    /* No sense to add STUN, but only subprotocols */
239
240
#ifdef DEBUG_LRU
241
    printf("[LRU] ADDING %u / %u.%u [%u -> %u]\n", key, proto, app_proto,
242
     ntohs(packet->udp->source), ntohs(packet->udp->dest));
243
#endif
244
245
5
    ndpi_lru_add_to_cache(ndpi_struct->stun_cache, key, app_proto, ndpi_get_current_time(flow));
246
5
    ndpi_lru_add_to_cache(ndpi_struct->stun_cache, key_rev, app_proto, ndpi_get_current_time(flow));
247
5
  }
248
5
      }
249
5
    }
250
5
  }
251
252
  /* TODO: extend to other protocols? */
253
7
  if(ndpi_struct->stun_zoom_cache &&
254
7
     app_proto == NDPI_PROTOCOL_ZOOM &&
255
7
     flow->l4_proto == IPPROTO_UDP) {
256
5
    u_int32_t key = get_stun_lru_key(flow, 0); /* Src */
257
#ifdef DEBUG_ZOOM_LRU
258
    printf("[LRU ZOOM] ADDING %u [src_port %u]\n", key, ntohs(flow->c_port));
259
#endif
260
5
    ndpi_lru_add_to_cache(ndpi_struct->stun_zoom_cache, key,
261
5
                          0 /* dummy */, ndpi_get_current_time(flow));
262
5
  }
263
264
7
  ndpi_set_detected_protocol(ndpi_struct, flow, app_proto, NDPI_PROTOCOL_STUN, confidence);
265
266
7
  if(ndpi_struct->monitoring_stun_pkts_to_process > 0 &&
267
     flow->l4_proto == IPPROTO_UDP /* TODO: support TCP. We need to pay some attention because:
268
                                      * multiple msg in the same TCP segment
269
7
                                      * same msg split across multiple segments */) {
270
6
    if((ndpi_struct->monitoring_stun_flags & NDPI_MONITORING_STUN_SUBCLASSIFIED) ||
271
6
       app_proto == NDPI_PROTOCOL_UNKNOWN /* No-subclassification */) {
272
3
      flow->max_extra_packets_to_check = ndpi_struct->monitoring_stun_pkts_to_process;
273
3
      flow->extra_packets_func = stun_monitoring;
274
3
    }
275
6
  }
276
7
}
277
278
typedef enum {
279
  NDPI_IS_STUN,
280
  NDPI_IS_NOT_STUN
281
} ndpi_int_stun_t;
282
283
/* ************************************************************ */
284
285
static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *ndpi_struct,
286
             struct ndpi_flow_struct *flow,
287
             const u_int8_t * payload,
288
             u_int16_t payload_length,
289
3.29k
             u_int16_t *app_proto) {
290
3.29k
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
291
3.29k
  u_int16_t msg_type, msg_len;
292
3.29k
  u_int32_t unused;
293
3.29k
  int rc;
294
  
295
3.29k
  if(packet->iph &&
296
3.29k
     ((packet->iph->daddr == 0xFFFFFFFF /* 255.255.255.255 */) ||
297
2.70k
     ((ntohl(packet->iph->daddr) & 0xF0000000) == 0xE0000000 /* A multicast address */))) {
298
137
    NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
299
137
    return(NDPI_IS_NOT_STUN);
300
137
  }
301
302
  /* If we're here it's because this does not look like STUN anymore
303
     as this was a flow that started as STUN and turned into something
304
     else. Let's investigate what is that about */
305
3.16k
  if(flow->stun.num_pkts > 0 && is_dtls(payload, payload_length, &unused)) {
306
#ifdef DEBUG_STUN
307
    printf("[STUN] DTLS?\n");
308
#endif
309
    /* Switching to TLS dissector is tricky, because we are calling one dissector
310
       from another one, and that is not a common operation...
311
       Additionally:
312
       * at that point protocol stack is still empty
313
       * we have room for only two protocols in flow->detected_protocol_stack[] so
314
         we can't have something like STUN/DTLS/SNAPCHAT_CALL
315
       * the easiest solution is skipping STUN, and let TLS dissector to set both
316
         master (i.e. DTLS) and subprotocol (if any) */
317
0
    if(ndpi_struct->opportunistic_tls_stun_enabled) {
318
0
      flow->stun.maybe_dtls = 1;
319
0
      switch_to_tls(ndpi_struct, flow);
320
0
    }
321
    /* We don't want to mess up with TLS classification/results but we don't want to
322
       exclude STUN right away to keep trying it in the case that this packet is
323
       not a real DTLS one */
324
0
    return(NDPI_IS_NOT_STUN);
325
0
  }
326
327
3.16k
  if(payload_length < STUN_HDR_LEN) {
328
    /* This looks like an invalid packet */
329
330
438
    if(flow->stun.num_pkts > 0) {
331
0
      return(NDPI_IS_STUN);
332
0
    } else
333
438
      return(NDPI_IS_NOT_STUN);
334
438
  }
335
336
2.72k
  if((strncmp((const char*)payload, (const char*)"RSP/", 4) == 0)
337
2.72k
     && (strncmp((const char*)&payload[7], (const char*)" STUN_", 6) == 0)) {
338
1
    NDPI_LOG_INFO(ndpi_struct, "found stun\n");
339
1
    goto stun_found;
340
1
  }
341
342
2.72k
  msg_type = ntohs(*((u_int16_t*)payload));
343
2.72k
  msg_len  = ntohs(*((u_int16_t*)&payload[2]));
344
345
  /* With tcp, we might have multiple msg in the same TCP pkt.
346
     Parse only the first one. TODO */
347
2.72k
  if(packet->tcp) {
348
1.99k
    if(msg_len + 20 > payload_length)
349
1.55k
      return(NDPI_IS_NOT_STUN);
350
    /* Let's hope that classic-stun is no more used over TCP */
351
444
    if(ntohl(*((u_int32_t *)&payload[4])) != 0x2112A442)
352
444
      return(NDPI_IS_NOT_STUN);
353
354
0
    payload_length = msg_len + 20;
355
0
  }
356
357
725
  if((msg_type == 0) || ((msg_len+20) != payload_length))
358
712
    return(NDPI_IS_NOT_STUN);  
359
  
360
  /* https://www.iana.org/assignments/stun-parameters/stun-parameters.xhtml */
361
13
  if(((msg_type & 0x3EEF) > 0x000B) &&
362
13
     (msg_type != 0x0800 && msg_type != 0x0801 && msg_type != 0x0802)) {
363
#ifdef DEBUG_STUN
364
    printf("[STUN] msg_type = %04X\n", msg_type);
365
#endif
366
1
    return(NDPI_IS_NOT_STUN);
367
1
  }
368
369
12
  if(ndpi_struct->stun_cache) {
370
6
    u_int16_t proto;
371
6
    u_int32_t key = get_stun_lru_key(flow, 0);
372
6
    int rc = ndpi_lru_find_cache(ndpi_struct->stun_cache, key, &proto,
373
6
                                 0 /* Don't remove it as it can be used for other connections */,
374
6
         ndpi_get_current_time(flow));
375
376
#ifdef DEBUG_LRU
377
    printf("[LRU] Searching %u\n", key);
378
#endif
379
380
6
    if(!rc) {
381
6
      key = get_stun_lru_key(flow, 1);
382
6
      rc = ndpi_lru_find_cache(ndpi_struct->stun_cache, key, &proto,
383
6
                               0 /* Don't remove it as it can be used for other connections */,
384
6
             ndpi_get_current_time(flow));
385
386
#ifdef DEBUG_LRU
387
      printf("[LRU] Searching %u\n", key);
388
#endif
389
6
    }
390
391
6
    if(rc) {
392
#ifdef DEBUG_LRU
393
      printf("[LRU] Cache FOUND %u / %u\n", key, proto);
394
#endif
395
396
0
      *app_proto = proto;
397
0
      return(NDPI_IS_STUN);
398
6
    } else {
399
#ifdef DEBUG_LRU
400
      printf("[LRU] NOT FOUND %u\n", key);
401
#endif
402
6
    }
403
6
  } else {
404
#ifdef DEBUG_LRU
405
    printf("[LRU] NO/EMPTY CACHE\n");
406
#endif
407
6
  }
408
409
12
  if(msg_type == 0x01 /* Binding Request */) {
410
10
    flow->stun.num_binding_requests++;
411
412
10
    flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
413
414
10
    if(!msg_len) {
415
      /* flow->stun.num_pkts++; */
416
0
      return(NDPI_IS_NOT_STUN); /* This to keep analyzing STUN instead of giving up */
417
0
    }
418
10
  }
419
420
12
  flow->stun.num_pkts++;
421
422
12
  flow->guessed_protocol_id = NDPI_PROTOCOL_STUN;
423
424
12
  if(payload_length == (msg_len+20)) {
425
12
    if((msg_type & 0x3EEF) <= 0x000B) /* http://www.3cx.com/blog/voip-howto/stun-details/ */ {
426
12
      u_int offset = 20;
427
428
      /*
429
  This can either be the standard RTCP or Ms Lync RTCP that
430
  later will become Ms Lync RTP. In this case we need to
431
  be careful before deciding about the protocol before dissecting the packet
432
433
  MS Lync = Skype
434
  https://en.wikipedia.org/wiki/Skype_for_Business
435
      */
436
437
20
      while((offset+4) < payload_length) {
438
15
        u_int16_t attribute = ntohs(*((u_int16_t*)&payload[offset]));
439
15
        u_int16_t len = ntohs(*((u_int16_t*)&payload[offset+2]));
440
15
        u_int16_t x = (len + 4) % 4;
441
442
15
        if(x)
443
12
          len += 4-x;
444
445
#ifdef DEBUG_STUN
446
        printf("==> Attribute: %04X\n", attribute);
447
#endif
448
449
15
        switch(attribute) {
450
7
  case 0x0101:
451
7
  case 0x0103:
452
7
          *app_proto = NDPI_PROTOCOL_ZOOM;
453
7
          return(NDPI_IS_STUN);
454
    
455
0
        case 0x4000:
456
0
        case 0x4001:
457
0
        case 0x4002:
458
0
        case 0x4003:
459
0
        case 0x4004:
460
0
        case 0x4007:
461
          /* These are the only messages apparently whatsapp voice can use */
462
0
          *app_proto = NDPI_PROTOCOL_WHATSAPP_CALL;
463
0
          return(NDPI_IS_STUN);
464
465
0
        case 0x0014: /* Realm */
466
0
    {
467
0
      u_int16_t realm_len = ntohs(*((u_int16_t*)&payload[offset+2]));
468
469
0
      if(flow->host_server_name[0] == '\0') {
470
0
        u_int k = offset+4;
471
472
0
        ndpi_hostname_sni_set(flow, payload + k, ndpi_min(realm_len, payload_length - k));
473
474
#ifdef DEBUG_STUN
475
        printf("==> [%s]\n", flow->host_server_name);
476
#endif
477
478
0
        if(strstr(flow->host_server_name, "google.com") != NULL) {
479
0
                *app_proto = NDPI_PROTOCOL_HANGOUT_DUO;
480
0
                return(NDPI_IS_STUN);
481
0
        } else if(strstr(flow->host_server_name, "whispersystems.org") != NULL ||
482
0
                  (strstr(flow->host_server_name, "signal.org") != NULL)) {
483
0
    *app_proto = NDPI_PROTOCOL_SIGNAL_VOIP;
484
0
    return(NDPI_IS_STUN);
485
0
        } else if(strstr(flow->host_server_name, "facebook") != NULL) {
486
0
    *app_proto = NDPI_PROTOCOL_FACEBOOK_VOIP;
487
0
    return(NDPI_IS_STUN);
488
0
        } else if(strstr(flow->host_server_name, "stripcdn.com") != NULL) {
489
0
    *app_proto = NDPI_PROTOCOL_ADULT_CONTENT;
490
0
    return(NDPI_IS_STUN);
491
0
        }
492
0
      }
493
0
    }
494
0
    break;
495
496
0
        case 0xC057: /* Messeger */
497
0
          if(msg_type == 0x0001) {
498
0
            if((msg_len == 100) || (msg_len == 104)) {
499
0
              *app_proto = NDPI_PROTOCOL_FACEBOOK_VOIP;
500
0
              return(NDPI_IS_STUN);
501
0
            }
502
0
          }
503
0
          break;
504
505
0
        case 0x8054: /* Candidate Identifier */
506
0
          if((len == 4)
507
0
             && ((offset+7) < payload_length)
508
0
             && (payload[offset+5] == 0x00)
509
0
             && (payload[offset+6] == 0x00)
510
0
             && (payload[offset+7] == 0x00)) {
511
            /* Either skype for business or "normal" skype with multiparty call */
512
#ifdef DEBUG_STUN
513
            printf("==> Skype found\n");
514
#endif
515
0
            *app_proto = NDPI_PROTOCOL_SKYPE_TEAMS_CALL;
516
0
            return(NDPI_IS_STUN);
517
0
          }
518
519
0
          break;
520
521
0
        case 0x8055: /* MS Service Quality (skype?) */
522
0
          break;
523
524
          /* Proprietary fields found on skype calls */
525
0
        case 0x24DF:
526
0
        case 0x3802:
527
0
        case 0x8036:
528
0
        case 0x8095:
529
0
        case 0x0800:
530
0
        case 0x8006: /* This is found on skype calls) */
531
          /* printf("====>>>> %04X\n", attribute); */
532
#ifdef DEBUG_STUN
533
          printf("==> Skype (2) found\n");
534
#endif
535
536
0
          *app_proto = NDPI_PROTOCOL_SKYPE_TEAMS_CALL;
537
0
          return(NDPI_IS_STUN);
538
539
0
        case 0x8070: /* Implementation Version */
540
0
          if(len == 4 && ((offset+7) < payload_length)
541
0
             && (payload[offset+4] == 0x00) && (payload[offset+5] == 0x00) && (payload[offset+6] == 0x00) &&
542
0
             ((payload[offset+7] == 0x02) || (payload[offset+7] == 0x03))) {
543
#ifdef DEBUG_STUN
544
            printf("==> Skype (3) found\n");
545
#endif
546
547
0
            *app_proto = NDPI_PROTOCOL_SKYPE_TEAMS_CALL;
548
0
            return(NDPI_IS_STUN);
549
0
          }
550
0
          break;
551
552
0
        case 0xFF03:
553
0
          *app_proto = NDPI_PROTOCOL_HANGOUT_DUO;
554
0
          return(NDPI_IS_STUN);
555
556
8
        default:
557
#ifdef DEBUG_STUN
558
          printf("==> %04X\n", attribute);
559
#endif
560
8
          break;
561
15
        }
562
563
8
        offset += len + 4;
564
8
      }
565
566
5
      goto stun_found;
567
12
    } else if(msg_type == 0x0800 ||
568
0
              msg_type == 0x0801 ||
569
0
              msg_type == 0x0802) {
570
0
      *app_proto = NDPI_PROTOCOL_WHATSAPP_CALL;
571
0
      return(NDPI_IS_STUN);
572
0
    }
573
12
  }
574
575
0
  if((flow->stun.num_pkts > 0) && (msg_type <= 0x00FF)) {
576
0
    *app_proto = NDPI_PROTOCOL_WHATSAPP_CALL;
577
0
    return(NDPI_IS_STUN);
578
0
  } else
579
0
    return(NDPI_IS_NOT_STUN);
580
581
6
stun_found:
582
6
  flow->stun.num_processed_pkts++;
583
584
6
  rc = (flow->stun.num_pkts < MAX_NUM_STUN_PKTS) ? NDPI_IS_NOT_STUN : NDPI_IS_STUN;
585
586
#ifdef DEBUG_STUN
587
  printf("stun.num_pkts %d, stun.num_processed_pkts %d, rc: %d\n",
588
         flow->stun.num_pkts, flow->stun.num_processed_pkts, rc);
589
#endif
590
591
6
  return rc;
592
0
}
593
594
static void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
595
3.29k
{
596
3.29k
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
597
3.29k
  u_int16_t app_proto;
598
599
3.29k
  NDPI_LOG_DBG(ndpi_struct, "search stun\n");
600
601
3.29k
  app_proto = NDPI_PROTOCOL_UNKNOWN;
602
603
  /* STUN may be encapsulated in TCP packets with a special TCP framing described in RFC 4571 */
604
3.29k
  if(packet->tcp &&
605
3.29k
     packet->payload_packet_len >= 22 &&
606
3.29k
     ((ntohs(get_u_int16_t(packet->payload, 0)) + 2) == packet->payload_packet_len)) {
607
    /* TODO there could be several STUN packets in a single TCP packet so maybe the detection could be
608
     * improved by checking only the STUN packet of given length */
609
610
1
    if(ndpi_int_check_stun(ndpi_struct, flow, packet->payload + 2,
611
1
         packet->payload_packet_len - 2, &app_proto) == NDPI_IS_STUN) {
612
0
      ndpi_int_stun_add_connection(ndpi_struct, flow, app_proto);
613
0
      return;
614
0
    }
615
3.29k
  } else { /* UDP or TCP without framing */
616
3.29k
    if(ndpi_int_check_stun(ndpi_struct, flow, packet->payload,
617
3.29k
         packet->payload_packet_len, &app_proto) == NDPI_IS_STUN) {
618
7
      ndpi_int_stun_add_connection(ndpi_struct, flow, app_proto);
619
7
      return;
620
7
    }
621
3.29k
  }
622
623
3.29k
  if(flow->stun.num_pkts >= MAX_NUM_STUN_PKTS ||
624
3.29k
     flow->packet_counter > 10)
625
0
    NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
626
627
3.29k
  if(flow->packet_counter > 0) {
628
    /* This might be a RTP stream: let's make sure we check it */
629
    /* At this point the flow has not been fully classified as STUN yet */
630
3.29k
    NDPI_LOG_DBG(ndpi_struct, "re-enable RTP\n");
631
3.29k
    NDPI_CLR(&flow->excluded_protocol_bitmask, NDPI_PROTOCOL_RTP);
632
3.29k
  }
633
3.29k
}
634
635
636
8.54k
void init_stun_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id) {
637
8.54k
  ndpi_set_bitmask_protocol_detection("STUN", ndpi_struct, *id,
638
8.54k
              NDPI_PROTOCOL_STUN,
639
8.54k
              ndpi_search_stun,
640
8.54k
              NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION,
641
8.54k
              SAVE_DETECTION_BITMASK_AS_UNKNOWN,
642
8.54k
              ADD_TO_DETECTION_BITMASK);
643
644
8.54k
  *id += 1;
645
8.54k
}