Coverage Report

Created: 2025-09-17 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ndpi/src/lib/protocols/stun.c
Line
Count
Source
1
/*
2
 * stun.c
3
 *
4
 * Copyright (C) 2011-25 - 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
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_STUN
27
28
#include "ndpi_api.h"
29
#include "ndpi_private.h"
30
31
// #define DEBUG_LRU  1
32
33
0
#define STUN_HDR_LEN   20 /* STUN message header length, Classic-STUN (RFC 3489) and STUN (RFC 8489) both */
34
35
36
/* Methods */
37
#define METHOD_BINDING                 0x0001 /* RFC8489 */
38
#define METHOD_SHARED_SECRET           0x0002 /* RFC3489 */
39
0
#define METHOD_ALLOCATE                0x0003 /* RFC8489 */
40
0
#define METHOD_REFRESH                 0x0004 /* RFC8489 */
41
0
#define METHOD_DATA_IND_OLD            0x0005
42
0
#define METHOD_SEND                    0x0006 /* RFC8656 */
43
0
#define METHOD_DATA_IND                0x0007 /* RFC8656 */
44
0
#define METHOD_CREATE_PERMISSION       0x0008 /* RFC8656 */
45
0
#define METHOD_CHANNELBIND             0x0009 /* RFC8656 */
46
/* TCP specific */
47
0
#define METHOD_CONNECT                 0x000a /* RFC6062 */
48
0
#define METHOD_CONNECTION_BIND         0x000b /* RFC6062 */
49
0
#define METHOD_CONNECTION_ATTEMPT      0x000c /* RFC6062 */
50
51
52
static u_int64_t get_stun_lru_key(struct ndpi_flow_struct *flow, u_int8_t rev);
53
static u_int64_t get_stun_lru_key_raw4(u_int32_t ip, u_int16_t port);
54
static u_int64_t get_stun_lru_key_raw6(u_int8_t *ip, u_int16_t port);
55
static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
56
           struct ndpi_flow_struct *flow,
57
           u_int16_t app_proto,
58
           u_int16_t master_proto,
59
           ndpi_protocol_category_t category);
60
static int stun_search_again(struct ndpi_detection_module_struct *ndpi_struct,
61
                             struct ndpi_flow_struct *flow);
62
63
64
/* Valid classifications:
65
    * STUN, DTLS, STUN/RTP, DTLS/SRTP, RTP or RTCP (only from RTP dissector)
66
      and TELEGRAM (only from Telegram dissector, note that TELEGRAM != TELEGRAM_VOIP!!)
67
    * STUN/APP, DTLS/APP, SRTP/APP ["real" sub-classification]
68
   The idea is:
69
    * the specific "real" application (WA/FB/Signal/...), if present, should
70
      be always set as "app" protocol, with STUN or DTLS or SRTP as "master" protocol
71
    * every "real" application that we handle, if it uses RTP, it is
72
      encrypted --> SRTP
73
    * keep STUN/RTP for the generic case without sub-classification [because
74
      nDPI uses SRTP only when it is sure that there is encryption]
75
*/
76
77
static int is_subclassification_real_by_proto(u_int16_t proto)
78
0
{
79
0
  if(proto == NDPI_PROTOCOL_UNKNOWN ||
80
0
     proto == NDPI_PROTOCOL_STUN ||
81
0
     proto == NDPI_PROTOCOL_RTP ||
82
0
     proto == NDPI_PROTOCOL_RTCP ||
83
0
     proto == NDPI_PROTOCOL_SRTP ||
84
0
     proto == NDPI_PROTOCOL_DTLS ||
85
0
     proto == NDPI_PROTOCOL_TELEGRAM)
86
0
    return 0;
87
0
  return 1;
88
0
}
89
90
/* ***************************************************** */
91
92
static int is_subclassification_real(struct ndpi_flow_struct *flow)
93
0
{
94
  /* No previous subclassification */
95
0
  if(flow->detected_protocol_stack[1] == NDPI_PROTOCOL_UNKNOWN)
96
0
    return 0;
97
0
  return is_subclassification_real_by_proto(flow->detected_protocol_stack[0]);
98
0
}
99
100
/* ***************************************************** */
101
102
static int is_new_subclassification_better(struct ndpi_detection_module_struct *ndpi_struct,
103
                                           struct ndpi_flow_struct *flow,
104
                                           u_int16_t new_app_proto)
105
0
{
106
0
  NDPI_LOG_DBG(ndpi_struct, "%d/%d -> %d\n",
107
0
               flow->detected_protocol_stack[1], flow->detected_protocol_stack[0],
108
0
               new_app_proto);
109
110
  /* If we don't have a real subclassification, we might want to lookup into the cache again
111
     (even if new_app_proto == NDPI_PROTOCOL_UNKNOWN) */
112
113
0
  if(is_subclassification_real(flow) &&
114
0
     new_app_proto == NDPI_PROTOCOL_UNKNOWN)
115
0
    return 0;
116
117
  /* Debug */
118
0
  if(new_app_proto != NDPI_PROTOCOL_UNKNOWN &&
119
0
     is_subclassification_real(flow) &&
120
0
     new_app_proto != flow->detected_protocol_stack[0]) {
121
0
    NDPI_LOG_DBG(ndpi_struct, "Incoherent sub-classification change %d/%d->%d \n",
122
0
                 flow->detected_protocol_stack[1],
123
0
                 flow->detected_protocol_stack[0], new_app_proto);
124
0
  }
125
126
0
  if(new_app_proto != flow->detected_protocol_stack[0])
127
0
    return 1;
128
0
  return 0;
129
0
}
130
131
/* ***************************************************** */
132
133
static u_int16_t search_into_cache(struct ndpi_detection_module_struct *ndpi_struct,
134
           struct ndpi_flow_struct *flow)
135
0
{
136
0
  u_int16_t proto;
137
0
  u_int64_t key;
138
0
  int rc;
139
140
0
  if(ndpi_struct->stun_cache) {
141
0
    key = get_stun_lru_key(flow, 0);
142
0
    rc = ndpi_lru_find_cache(ndpi_struct->stun_cache, key, &proto,
143
0
           0 /* Don't remove it as it can be used for other connections */,
144
0
           ndpi_get_current_time(flow));
145
#ifdef DEBUG_LRU
146
    printf("[LRU] Searching 0x%llx\n", (long long unsigned int)key);
147
#endif
148
149
0
    if(!rc) {
150
0
      key = get_stun_lru_key(flow, 1);
151
0
      rc = ndpi_lru_find_cache(ndpi_struct->stun_cache, key, &proto,
152
0
             0 /* Don't remove it as it can be used for other connections */,
153
0
             ndpi_get_current_time(flow));
154
#ifdef DEBUG_LRU
155
      printf("[LRU] Searching 0x%llx\n", (long long unsigned int)key);
156
#endif
157
0
    }
158
159
0
    if(rc) {
160
#ifdef DEBUG_LRU
161
      printf("[LRU] Cache FOUND 0x%llx / %u\n", (long long unsigned int)key, proto);
162
#endif
163
164
0
      return proto;
165
0
    } else {
166
#ifdef DEBUG_LRU
167
      printf("[LRU] NOT FOUND 0x%llx\n", (long long unsigned int)key);
168
#endif
169
0
    }
170
0
  } else {
171
#ifdef DEBUG_LRU
172
    printf("[LRU] NO/EMPTY CACHE\n");
173
#endif
174
0
  }
175
0
  return NDPI_PROTOCOL_UNKNOWN;
176
0
}
177
178
/* ***************************************************** */
179
180
static void add_to_cache(struct ndpi_detection_module_struct *ndpi_struct,
181
       struct ndpi_flow_struct *flow,
182
       u_int16_t app_proto)
183
0
{
184
0
  u_int64_t key, key_rev;
185
186
0
  if(ndpi_struct->stun_cache) {
187
0
    key = get_stun_lru_key(flow, 0);
188
0
    ndpi_lru_add_to_cache(ndpi_struct->stun_cache, key, app_proto, ndpi_get_current_time(flow));
189
0
    key_rev = get_stun_lru_key(flow, 1);
190
0
    ndpi_lru_add_to_cache(ndpi_struct->stun_cache, key_rev, app_proto, ndpi_get_current_time(flow));
191
192
#ifdef DEBUG_LRU
193
    printf("[LRU] ADDING 0x%llx 0x%llx app %u [%u -> %u]\n",
194
     (long long unsigned int)key, (long long unsigned int)key_rev, app_proto,
195
     ntohs(flow->c_port), ntohs(flow->s_port));
196
#endif
197
0
  }
198
0
}
199
200
/* ***************************************************** */
201
202
static void parse_ip_port_attribute(const u_int8_t *payload, u_int16_t payload_length,
203
                                    int off, u_int16_t real_len, ndpi_address_port *ap,
204
                                    ndpi_address_port *ap_monit)
205
0
{
206
0
  if(off + 4 + real_len <= payload_length &&
207
0
     (real_len == 8 || real_len == 20)) {
208
0
    u_int8_t protocol_family = payload[off+5];
209
210
0
    if(protocol_family == 0x01 /* IPv4 */ &&
211
0
       real_len == 8) {
212
0
      u_int16_t port = ntohs(*((u_int16_t*)&payload[off+6]));
213
0
      u_int32_t ip   = ntohl(*((u_int32_t*)&payload[off+8]));
214
215
      /* Only the first attribute ever in the flow */
216
0
      if(ap->port == 0) {
217
0
        ap->port = port;
218
0
        ap->address.v4 = htonl(ip);
219
0
        ap->is_ipv6 = 0;
220
0
      }
221
222
0
      if(ap_monit) {
223
0
        ap_monit->port = port;
224
0
        ap_monit->address.v4 = htonl(ip);
225
0
        ap_monit->is_ipv6 = 0;
226
0
      }
227
0
    } else if(protocol_family == 0x02 /* IPv6 */ &&
228
0
              real_len == 20) {
229
0
      u_int16_t port = ntohs(*((u_int16_t*)&payload[off+6]));
230
0
      u_int32_t ip[4];
231
232
0
      ip[0] = *((u_int32_t *)&payload[off + 8]);
233
0
      ip[1] = *((u_int32_t *)&payload[off + 12]);
234
0
      ip[2] = *((u_int32_t *)&payload[off + 16]);
235
0
      ip[3] = *((u_int32_t *)&payload[off + 20]);
236
237
      /* Only the first attribute ever in the flow */
238
0
      if(ap->port == 0) {
239
0
        ap->port = port;
240
0
        memcpy(&ap->address, &ip, 16);
241
0
        ap->is_ipv6 = 1;
242
0
      }
243
244
0
      if(ap_monit) {
245
0
        ap_monit->port = port;
246
0
        memcpy(&ap_monit->address, &ip, 16);
247
0
        ap_monit->is_ipv6 = 1;
248
0
      }
249
0
    }
250
0
  }
251
0
}
252
253
/* ***************************************************** */
254
255
static void parse_xor_ip_port_attribute(struct ndpi_detection_module_struct *ndpi_struct,
256
                                        struct ndpi_flow_struct *flow,
257
                                        const u_int8_t *payload, u_int16_t payload_length,
258
                                        int off, u_int16_t real_len,
259
                                        ndpi_address_port *ap, ndpi_address_port *ap_monit,
260
                                        u_int32_t transaction_id[3], u_int32_t magic_cookie,
261
                                        int add_to_cache)
262
0
{
263
#ifdef NDPI_ENABLE_DEBUG_MESSAGES
264
  char buf[128];
265
#endif
266
267
0
  if(off + 4 + real_len <= payload_length &&
268
0
     (real_len == 8 || real_len == 20)) {
269
0
    u_int8_t protocol_family = payload[off+5];
270
271
0
    if(protocol_family == 0x01 /* IPv4 */ &&
272
0
       real_len == 8) {
273
0
      u_int32_t ip;
274
0
      u_int16_t port;
275
276
0
      port = ntohs(*((u_int16_t *)&payload[off + 6])) ^ (magic_cookie >> 16);
277
0
      ip = *((u_int32_t *)&payload[off + 8]) ^ htonl(magic_cookie);
278
279
      /* Only the first attribute ever in the flow */
280
0
      if(ap->port == 0) {
281
0
        ap->port = port;
282
0
        ap->address.v4 = ip;
283
0
        ap->is_ipv6 = 0;
284
0
      }
285
286
0
      if(ap_monit) {
287
0
          ap_monit->port = port;
288
0
          ap_monit->address.v4 = ip;
289
0
          ap_monit->is_ipv6 = 0;
290
0
      }
291
292
0
      if(add_to_cache) {
293
0
        NDPI_LOG_DBG(ndpi_struct, "Peer %s:%d [proto %d]\n",
294
0
                     inet_ntop(AF_INET, &ip, buf, sizeof(buf)), port,
295
0
                     flow->detected_protocol_stack[0]);
296
297
0
        if(ndpi_struct->stun_cache &&
298
0
           is_subclassification_real(flow)) {
299
0
          u_int64_t key = get_stun_lru_key_raw4(ip, port);
300
301
0
          ndpi_lru_add_to_cache(ndpi_struct->stun_cache, key,
302
0
        flow->detected_protocol_stack[0],
303
0
        ndpi_get_current_time(flow));
304
#ifdef DEBUG_LRU
305
          printf("[LRU] Add peer 0x%llx %d\n", (long long unsigned int)key, flow->detected_protocol_stack[0]);
306
#endif
307
0
  }
308
0
      }
309
0
    } else if(protocol_family == 0x02 /* IPv6 */ &&
310
0
              real_len == 20) {
311
0
      u_int32_t ip[4];
312
0
      u_int16_t port;
313
314
0
      port = ntohs(*((u_int16_t *)&payload[off + 6])) ^ (magic_cookie >> 16);
315
0
      ip[0] = *((u_int32_t *)&payload[off + 8]) ^ htonl(magic_cookie);
316
0
      ip[1] = *((u_int32_t *)&payload[off + 12]) ^ htonl(transaction_id[0]);
317
0
      ip[2] = *((u_int32_t *)&payload[off + 16]) ^ htonl(transaction_id[1]);
318
0
      ip[3] = *((u_int32_t *)&payload[off + 20]) ^ htonl(transaction_id[2]);
319
320
      /* Only the first attribute ever in the flow */
321
0
      if(ap->port == 0) {
322
0
        ap->port = port;
323
0
        memcpy(&ap->address, &ip, 16);
324
0
        ap->is_ipv6 = 1;
325
0
      }
326
327
0
      if(ap_monit) {
328
0
        ap_monit->port = port;
329
0
        memcpy(&ap_monit->address, &ip, 16);
330
0
        ap_monit->is_ipv6 = 1;
331
0
      }
332
333
0
      if(add_to_cache) {
334
0
        NDPI_LOG_DBG(ndpi_struct, "Peer %s:%d [proto %d]\n",
335
0
                     inet_ntop(AF_INET6, &ip, buf, sizeof(buf)), port,
336
0
                     flow->detected_protocol_stack[0]);
337
338
0
        if(ndpi_struct->stun_cache &&
339
0
           is_subclassification_real(flow)) {
340
0
          u_int64_t key = get_stun_lru_key_raw6((u_int8_t *)ip, port);
341
342
0
          ndpi_lru_add_to_cache(ndpi_struct->stun_cache, key,
343
0
                                flow->detected_protocol_stack[0],
344
0
                                ndpi_get_current_time(flow));
345
#ifdef DEBUG_LRU
346
          printf("[LRU] Add peer 0x%llx %d\n", (long long unsigned int)key, flow->detected_protocol_stack[0]);
347
#endif
348
0
  }
349
0
      }
350
0
    }
351
0
  }
352
0
}
353
354
/* ***************************************************** */
355
356
int is_stun(struct ndpi_detection_module_struct *ndpi_struct,
357
            struct ndpi_flow_struct *flow,
358
            u_int16_t *app_proto,
359
0
      ndpi_protocol_category_t *category) {
360
0
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
361
0
  u_int16_t msg_type, msg_len, method;
362
0
  int off;
363
0
  const u_int8_t *payload = packet->payload;
364
0
  u_int16_t payload_length = packet->payload_packet_len;
365
0
  const u_int8_t *orig_payload;
366
0
  u_int16_t orig_payload_length;
367
0
  u_int32_t magic_cookie;
368
0
  u_int32_t transaction_id[3];
369
370
0
  *category = NDPI_PROTOCOL_CATEGORY_UNSPECIFIED;
371
  
372
0
  if(payload_length < STUN_HDR_LEN)
373
0
    return(-1);
374
375
  /* Some really old/legacy stuff */
376
0
  if(strncmp((const char *)payload, "RSP/", 4) == 0 &&
377
0
     strncmp((const char *)&payload[7], " STUN_", 6) == 0) {
378
0
    NDPI_LOG_DBG(ndpi_struct, "found old/legacy stun in rsp\n");
379
0
    return 1; /* No real metadata */
380
0
  }
381
382
  /* STUN may be encapsulated in TCP packets with a special TCP framing described in RFC 4571 */
383
0
  if(packet->tcp &&
384
0
     payload_length >= STUN_HDR_LEN + 2 &&
385
     /* TODO: multiple STUN messagges */
386
0
     ((ntohs(get_u_int16_t(payload, 0)) + 2) == payload_length)) {
387
0
    payload += 2;
388
0
    payload_length -=2;
389
0
  }
390
391
  /* Microsoft Multiplexed TURN messages */
392
0
  if(payload_length >= STUN_HDR_LEN + 12 &&
393
0
     ntohs(get_u_int16_t(payload, 0)) == 0xFF10 &&
394
0
     ntohs(get_u_int16_t(payload, 2)) + 4 == payload_length) {
395
0
    payload += 12;
396
0
    payload_length -= 12;
397
0
  }
398
399
0
  msg_type = ntohs(*((u_int16_t *)&payload[0]));
400
0
  msg_len = ntohs(*((u_int16_t *)&payload[2]));
401
0
  magic_cookie = ntohl(*((u_int32_t *)&payload[4]));
402
0
  transaction_id[0] = ntohl(*((u_int32_t *)&payload[8]));
403
0
  transaction_id[1] = ntohl(*((u_int32_t *)&payload[12]));
404
0
  transaction_id[2] = ntohl(*((u_int32_t *)&payload[16]));
405
406
  /* No magic_cookie on classic-stun */
407
  /* Let's hope that we don't have anymore classic-stun over TCP */
408
0
  if(packet->tcp && magic_cookie != 0x2112A442) {
409
0
    return 0;
410
0
  }
411
412
0
  NDPI_LOG_DBG2(ndpi_struct, "msg_type = %04X msg_len = %d\n", msg_type, msg_len);
413
414
  /* With tcp, we might have multiple msg in the same TCP pkt.
415
     Parse only the first one. TODO */
416
0
  if(packet->tcp) {
417
0
    if(msg_len + STUN_HDR_LEN > payload_length)
418
0
      return 0;
419
420
0
    payload_length = msg_len + STUN_HDR_LEN;
421
0
  }
422
423
0
  if(msg_type == 0 || (msg_len + STUN_HDR_LEN != payload_length)) {
424
0
    NDPI_LOG_DBG(ndpi_struct, "Invalid msg_type = %04X or len %d %d\n",
425
0
                 msg_type, msg_len, payload_length);
426
0
    return -1;
427
0
  }
428
429
  /* https://www.iana.org/assignments/stun-parameters/stun-parameters.xhtml */
430
0
  if(((msg_type & 0x3EEF) > 0x000B) &&
431
0
     msg_type != 0x0800 && msg_type != 0x0801 && msg_type != 0x0802 &&
432
0
     msg_type != 0x0804 && msg_type != 0x0805) {
433
0
    NDPI_LOG_DBG(ndpi_struct, "Invalid msg_type = %04X\n", msg_type);
434
0
    return -1;
435
0
  }
436
437
0
  if(magic_cookie != 0x2112A442) {
438
    /* Some heuristic to detect classic-stun:
439
       * msg type check (list from Wireshark)
440
       * let's see if attributes list seems ok */
441
0
    if(msg_type != 0x0001 && msg_type != 0x0101 && msg_type != 0x0111 && /* Binding */
442
0
       msg_type != 0x0002 && msg_type != 0x0102 && msg_type != 0x0112 && /* Shared secret */
443
0
       msg_type != 0x0003 && msg_type != 0x0103 && msg_type != 0x0113 && /* Allocate */
444
0
       msg_type != 0x0004 && msg_type != 0x0104 && msg_type != 0x0114 && /* Send */
445
0
       msg_type != 0x0115 && /* Data Indication */
446
0
       msg_type != 0x0006 && msg_type != 0x0106 && msg_type != 0x0116 /* Set Active Destination */) {
447
0
      NDPI_LOG_DBG(ndpi_struct, "No classic-stun 0x%x\n", msg_type);
448
0
      return 0;
449
0
    }
450
451
0
    off = STUN_HDR_LEN;
452
0
    while(off + 4 < payload_length) {
453
0
      u_int16_t len = ntohs(*((u_int16_t *)&payload[off + 2]));
454
0
      u_int16_t real_len = (len + 3) & 0xFFFFFFFC;
455
456
0
      off += 4 + real_len;
457
0
    }
458
0
    if(off != payload_length) {
459
0
      NDPI_LOG_DBG(ndpi_struct, "No classic-stun %d/%d\n", off, payload_length);
460
0
      return 0;
461
0
    }
462
0
  }
463
464
  /* STUN */
465
466
0
  if(flow->monit == NULL &&
467
0
     is_monitoring_enabled(ndpi_struct, NDPI_PROTOCOL_STUN))
468
0
    flow->monit = ndpi_calloc(1, sizeof(struct ndpi_metadata_monitoring));
469
470
0
  if(msg_type == 0x0800 || msg_type == 0x0801 || msg_type == 0x0802 ||
471
0
     msg_type == 0x0804 || msg_type == 0x0805) {
472
0
    *app_proto = NDPI_PROTOCOL_WHATSAPP_CALL;
473
0
    return 1;
474
0
  }
475
476
0
  method = (msg_type & 0x000F) | ((msg_type & 0x00E0) >> 1) | ((msg_type & 0x3E00) >> 2);
477
0
  switch(method) {
478
0
  case METHOD_ALLOCATE:
479
0
  case METHOD_REFRESH:
480
0
  case METHOD_SEND:
481
0
  case METHOD_DATA_IND:
482
0
  case METHOD_DATA_IND_OLD:
483
0
  case METHOD_CREATE_PERMISSION:
484
0
  case METHOD_CHANNELBIND:
485
0
  case METHOD_CONNECT:
486
0
  case METHOD_CONNECTION_BIND:
487
0
  case METHOD_CONNECTION_ATTEMPT:
488
0
    NDPI_LOG_DBG(ndpi_struct, "TURN flow (method %d)\n", method);
489
0
    flow->stun.is_turn = 1;
490
0
    break;
491
0
  }
492
493
  /* See https://support.signal.org/hc/en-us/articles/360007320291-Firewall-and-Internet-settings.
494
     Since the check is quite weak, give time to other applications to kick in */
495
0
  if(flow->packet_counter > 4 && !flow->stun.is_turn &&
496
0
     !is_subclassification_real(flow) &&
497
0
     (ntohs(flow->c_port) == 10000 || ntohs(flow->s_port) == 10000)) {
498
0
     *app_proto = NDPI_PROTOCOL_SIGNAL_VOIP;
499
0
  }
500
501
0
  if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_TELEGRAM)
502
0
    *app_proto = NDPI_PROTOCOL_TELEGRAM_VOIP;
503
504
0
  off = STUN_HDR_LEN;
505
0
  while(off + 4 < payload_length) {
506
0
    u_int16_t attribute = ntohs(*((u_int16_t *)&payload[off]));
507
0
    u_int16_t len = ntohs(*((u_int16_t *)&payload[off + 2]));
508
0
    u_int16_t real_len = (len + 3) & 0xFFFFFFFC;
509
510
0
    NDPI_LOG_DBG(ndpi_struct, "Attribute 0x%x (%d/%d)\n", attribute, len, real_len);
511
512
0
    switch(attribute) {
513
0
    case 0x0001: /* MAPPED-ADDRESS */
514
0
      if(ndpi_struct->cfg.stun_mapped_address_enabled) {
515
0
        parse_ip_port_attribute(payload, payload_length, off, real_len, &flow->stun.mapped_address,
516
0
                                flow->monit ? &flow->monit->protos.dtls_stun_rtp.mapped_address : NULL);
517
0
      }
518
0
      break;
519
520
0
    case 0x802b: /* RESPONSE-ORIGIN */
521
0
      if(ndpi_struct->cfg.stun_response_origin_enabled) {
522
0
        parse_ip_port_attribute(payload, payload_length, off, real_len, &flow->stun.response_origin,
523
0
                                flow->monit ? &flow->monit->protos.dtls_stun_rtp.response_origin : NULL);
524
0
      }
525
0
      break;
526
527
0
    case 0x802c: /* OTHER-ADDRESS */
528
0
      if(ndpi_struct->cfg.stun_other_address_enabled) {
529
0
        parse_ip_port_attribute(payload, payload_length, off, real_len, &flow->stun.other_address,
530
0
                                flow->monit ? &flow->monit->protos.dtls_stun_rtp.other_address : NULL);
531
0
      }
532
0
      break;
533
534
0
    case 0x0012: /* XOR-PEER-ADDRESS */
535
0
      if(ndpi_struct->cfg.stun_peer_address_enabled) {
536
0
        parse_xor_ip_port_attribute(ndpi_struct, flow,
537
0
                                    payload, payload_length, off, real_len,
538
0
                                    &flow->stun.peer_address,
539
0
                                    flow->monit ? &flow->monit->protos.dtls_stun_rtp.peer_address : NULL,
540
0
                                    transaction_id, magic_cookie, 1);
541
0
      }
542
0
      break;
543
544
0
    case 0x0101:
545
0
    case 0x0103:
546
0
      *app_proto = NDPI_PROTOCOL_ZOOM;
547
0
      return 1;
548
549
0
    case 0x4000:
550
0
    case 0x4001:
551
0
    case 0x4002:
552
0
    case 0x4003:
553
0
    case 0x4004:
554
0
    case 0x4007:
555
      /* These are the only messages apparently whatsapp voice can use */
556
0
      *app_proto = NDPI_PROTOCOL_WHATSAPP_CALL;
557
0
      break;
558
559
0
    case 0x0014: /* Realm */
560
0
      if(flow->host_server_name[0] == '\0') {
561
0
  int i;
562
0
  bool valid = true;
563
564
0
        ndpi_hostname_sni_set(flow, payload + off + 4, ndpi_min(len, payload_length - off - 4), NDPI_HOSTNAME_NORM_ALL);
565
0
        NDPI_LOG_DBG(ndpi_struct, "Realm [%s]\n", flow->host_server_name);       
566
  
567
  /* Some Realm contain junk, so let's validate it */
568
0
  for(i=0; flow->host_server_name[i] != '\0'; i++) {
569
0
    if(flow->host_server_name[i] == '?') {
570
0
      valid = false;
571
0
      break;
572
0
    }
573
0
  }
574
575
0
  if(valid) {
576
0
    if(strstr(flow->host_server_name, "google.com") != NULL) {
577
0
      *app_proto = NDPI_PROTOCOL_GOOGLE_CALL;
578
0
    } else if(strstr(flow->host_server_name, "whispersystems.org") != NULL ||
579
0
        strstr(flow->host_server_name, "signal.org") != NULL) {
580
0
      *app_proto = NDPI_PROTOCOL_SIGNAL_VOIP;
581
0
    } else if(strstr(flow->host_server_name, "facebook") != NULL) {
582
0
      *app_proto = NDPI_PROTOCOL_FACEBOOK_VOIP;
583
0
    } else if(strstr(flow->host_server_name, "stripcdn.com") != NULL) {
584
0
      *category = NDPI_PROTOCOL_CATEGORY_ADULT_CONTENT;
585
0
    } else if(strstr(flow->host_server_name, "telegram") != NULL) {
586
0
      *app_proto = NDPI_PROTOCOL_TELEGRAM_VOIP;
587
0
    } else if(strstr(flow->host_server_name, "viber") != NULL) {
588
0
      *app_proto = NDPI_PROTOCOL_VIBER_VOIP;
589
0
    } else if(strstr(flow->host_server_name, "turn.cloudflare.com") != NULL) {
590
      /* The latest signal implementations hide behind cloudflare */
591
0
      if(signal_search_into_cache(ndpi_struct, flow)) {
592
0
        *app_proto = NDPI_PROTOCOL_SIGNAL_VOIP;
593
0
      }
594
0
    }
595
0
  } else
596
0
    flow->host_server_name[0] = '\0';
597
0
      }
598
0
      break;
599
600
    /* Proprietary fields found on Microsoft Teams/Skype calls */
601
0
    case 0x8054: /* Candidate Identifier: Either skype for business or "normal" skype with multiparty call */
602
0
    case 0x24DF:
603
0
    case 0x3802:
604
0
    case 0x8036:
605
0
    case 0x8095: /* MS-Multiplexed-TURN-Session-ID */
606
0
    case 0x0800:
607
0
    case 0x8006:
608
0
    case 0x8070: /* MS Implementation Version */
609
0
    case 0x8055: /* MS Service Quality */
610
0
      *app_proto = NDPI_PROTOCOL_MSTEAMS_CALL;
611
0
      break;
612
613
0
    case 0x8029: /* ICE-CONTROLLED */
614
0
      if(current_pkt_from_client_to_server(ndpi_struct, flow))
615
0
        flow->stun.is_client_controlling = 0;
616
0
      else
617
0
        flow->stun.is_client_controlling = 1;
618
0
      break;
619
620
0
    case 0x802A: /* ICE-CONTROLLING */
621
0
      if(current_pkt_from_client_to_server(ndpi_struct, flow))
622
0
        flow->stun.is_client_controlling = 1;
623
0
      else
624
0
        flow->stun.is_client_controlling = 0;
625
0
      break;
626
627
0
    case 0xFF03:
628
0
      *app_proto = NDPI_PROTOCOL_GOOGLE_CALL;
629
0
      break;
630
631
0
    case 0x0013:
632
0
      NDPI_LOG_DBG(ndpi_struct, "DATA attribute (%d/%d)\n",
633
0
                  real_len, payload_length - off - 4);
634
0
      if(real_len <= payload_length - off - 4) {
635
0
        orig_payload = packet->payload;
636
0
        orig_payload_length = packet->payload_packet_len;
637
0
        packet->payload = payload + off + 4;
638
0
        packet->payload_packet_len = real_len;
639
640
0
        stun_search_again(ndpi_struct, flow);
641
0
        NDPI_LOG_DBG(ndpi_struct, "End recursion\n");
642
643
0
        packet->payload = orig_payload;
644
0
        packet->payload_packet_len = orig_payload_length;
645
0
      }
646
0
      break;
647
648
0
    case 0x0020: /* XOR-MAPPED-ADDRESS */
649
0
      if(ndpi_struct->cfg.stun_mapped_address_enabled) {
650
0
        parse_xor_ip_port_attribute(ndpi_struct, flow,
651
0
                                    payload, payload_length, off, real_len,
652
0
                                    &flow->stun.mapped_address,
653
0
                                    flow->monit ? &flow->monit->protos.dtls_stun_rtp.mapped_address : NULL,
654
0
                                    transaction_id, magic_cookie, 0);
655
0
  flow->stun.num_xor_mapped_addresses++;
656
0
      }
657
0
      break;
658
659
0
    case 0x0016: /* XOR-RELAYED-ADDRESS */
660
0
      if(ndpi_struct->cfg.stun_relayed_address_enabled) {
661
0
        parse_xor_ip_port_attribute(ndpi_struct, flow,
662
0
                                    payload, payload_length, off, real_len,
663
0
                                    &flow->stun.relayed_address,
664
0
                                    flow->monit ? &flow->monit->protos.dtls_stun_rtp.relayed_address : NULL,
665
0
                                    transaction_id, magic_cookie, 0);
666
0
  flow->stun.num_xor_relayed_addresses++;
667
0
      }
668
0
      break;
669
670
0
    default:
671
0
      NDPI_LOG_DBG2(ndpi_struct, "Unknown attribute %04X\n", attribute);
672
0
      break;
673
0
    }
674
675
0
    off += 4 + real_len;
676
0
  }
677
678
0
  return 1;
679
0
}
680
681
/* ***************************************************** */
682
683
static int keep_extra_dissection(struct ndpi_detection_module_struct *ndpi_struct,
684
                                 struct ndpi_flow_struct *flow)
685
0
{
686
0
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
687
688
  /* We want extra dissection for:
689
   * sub-classification
690
   * metadata extraction (*-ADDRESS) or looking for RTP
691
   * At the moment:
692
   * it seems ZOOM doens't have any meaningful attributes
693
   * we want (all) XOR-PEER-ADDRESS only for Telegram.
694
   * for the other protocols, we stop after we have all metadata (if enabled)
695
   * for some specific protocol, we might know that some attributes are never used
696
   * if monitoring is enabled, keep looking for (S)RTP anyway
697
698
   **After** extra dissection is ended, we might move to monitoring. Note that:
699
   * classification doesn't change while in monitoring!
700
   */
701
702
0
  if(packet->udp
703
0
     && (ntohs(packet->udp->source) == 3478)
704
0
     && (packet->payload_packet_len > 0)
705
0
     && (packet->payload[0] != 0x0) && (packet->payload[0] != 0x1)) {
706
0
    if(flow->stun.num_non_stun_pkt < 2) {
707
0
      flow->stun.non_stun_pkt_len[flow->stun.num_non_stun_pkt++] = packet->payload_packet_len;
708
709
#ifdef STUN_DEBUG
710
      if(flow->stun.num_non_stun_pkt == 2)
711
  printf("%d %d\n", flow->stun.non_stun_pkt_len[0], flow->stun.non_stun_pkt_len[1]);
712
#endif
713
0
    }
714
0
  }
715
716
0
  if(packet->payload_packet_len > 699) {
717
0
    if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_TELEGRAM_VOIP) {
718
0
      if((packet->payload[0] == 0x16) && (packet->payload[1] == 0xfe)
719
0
   && ((packet->payload[2] == 0xff) /* DTLS 1.0 */
720
0
       || (packet->payload[2] == 0xfd) /* DTLS 1.2 */ ))
721
0
  ; /* Skip DTLS */
722
0
      else {
723
  /* STUN or RTP */
724
  /* This packet is too big to be audio: add video */
725
0
  flow->flow_multimedia_types |= ndpi_multimedia_video_flow;
726
0
      }
727
0
    }
728
0
  }
729
730
0
  if(flow->monitoring)
731
0
    return 1;
732
733
0
  if(flow->num_extra_packets_checked + 1 == flow->max_extra_packets_to_check) {
734
0
    if(is_monitoring_enabled(ndpi_struct, NDPI_PROTOCOL_STUN)) {
735
0
      NDPI_LOG_DBG(ndpi_struct, "Enabling monitoring (end extra dissection)\n");
736
0
      flow->monitoring = 1;
737
0
      return 1;
738
0
    }
739
0
  }
740
741
0
  if(!is_subclassification_real(flow))
742
0
    return 1;
743
744
0
  if(is_monitoring_enabled(ndpi_struct, NDPI_PROTOCOL_STUN) &&
745
0
     (flow->detected_protocol_stack[1] != NDPI_PROTOCOL_SRTP &&
746
0
      flow->detected_protocol_stack[1] != NDPI_PROTOCOL_DTLS))
747
0
    return 1;
748
749
0
  if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_TELEGRAM_VOIP &&
750
0
     ndpi_struct->cfg.stun_peer_address_enabled)
751
0
    return 1;
752
753
  /* General rule */
754
0
  if((flow->stun.mapped_address.port || !ndpi_struct->cfg.stun_mapped_address_enabled) &&
755
0
     (flow->stun.peer_address.port || !ndpi_struct->cfg.stun_peer_address_enabled) &&
756
0
     (flow->stun.relayed_address.port || !ndpi_struct->cfg.stun_relayed_address_enabled) &&
757
0
     (flow->stun.response_origin.port || !ndpi_struct->cfg.stun_response_origin_enabled) &&
758
0
     (flow->stun.other_address.port || !ndpi_struct->cfg.stun_other_address_enabled)) {
759
0
    if(is_monitoring_enabled(ndpi_struct, NDPI_PROTOCOL_STUN)) {
760
0
      NDPI_LOG_DBG(ndpi_struct, "Enabling monitoring (found all metadata)\n");
761
0
      flow->monitoring = 1;
762
0
      return 1;
763
0
    }
764
0
    return 0;
765
0
  }
766
767
  /* Exception WA: only relayed and mapped address attributes but we keep looking for RTP packets */
768
0
  if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_WHATSAPP_CALL &&
769
0
     flow->detected_protocol_stack[1] == NDPI_PROTOCOL_SRTP &&
770
0
     (flow->stun.mapped_address.port || !ndpi_struct->cfg.stun_mapped_address_enabled) &&
771
0
     (flow->stun.relayed_address.port || !ndpi_struct->cfg.stun_relayed_address_enabled)) {
772
0
    if(is_monitoring_enabled(ndpi_struct, NDPI_PROTOCOL_STUN)) {
773
0
      NDPI_LOG_DBG(ndpi_struct, "Enabling monitor (found all metadata; wa case)\n");
774
0
      flow->monitoring = 1;
775
0
      return 1;
776
0
    }
777
0
    return 0;
778
0
  }
779
780
  /* Exception Zoom: no metadata */
781
0
  if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_ZOOM) {
782
0
    if(is_monitoring_enabled(ndpi_struct, NDPI_PROTOCOL_STUN)) {
783
0
      NDPI_LOG_DBG(ndpi_struct, "Enabling monitor (zoom case)\n");
784
0
      flow->monitoring = 1;
785
0
      return 1;
786
0
    }
787
0
    return 0;
788
0
  }
789
790
0
  return 1;
791
0
}
792
793
/* ***************************************************** */
794
795
0
static u_int32_t __get_master(struct ndpi_flow_struct *flow) {
796
797
0
  if(flow->detected_protocol_stack[1] != NDPI_PROTOCOL_UNKNOWN)
798
0
    return flow->detected_protocol_stack[1];
799
0
  if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_UNKNOWN &&
800
0
     flow->detected_protocol_stack[0] != NDPI_PROTOCOL_TELEGRAM)
801
0
    return flow->detected_protocol_stack[0];
802
0
  return NDPI_PROTOCOL_STUN;
803
0
}
804
805
/* ***************************************************** */
806
807
static int stun_search_again(struct ndpi_detection_module_struct *ndpi_struct,
808
                             struct ndpi_flow_struct *flow)
809
0
{
810
0
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
811
0
  int rtp_rtcp;
812
0
  u_int8_t first_byte;
813
0
  u_int16_t msg_type, app_proto = NDPI_PROTOCOL_UNKNOWN;
814
0
  u_int32_t unused;
815
0
  int first_dtls_pkt = 0;
816
0
  u_int16_t old_proto_stack[2] = {NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_UNKNOWN};
817
818
0
  NDPI_LOG_DBG2(ndpi_struct, "Packet counter %d protos %d/%d Monitoring? %d\n",
819
0
                flow->packet_counter,
820
0
                flow->detected_protocol_stack[0], flow->detected_protocol_stack[1],
821
0
                flow->monitoring);
822
823
  /* TODO: check TCP support. We need to pay some attention because:
824
     * multiple msg in the same TCP segment
825
     * same msg split across multiple segments */
826
827
0
  if(packet->payload_packet_len <= 1)
828
0
    return keep_extra_dissection(ndpi_struct, flow);
829
830
0
  first_byte = packet->payload[0];
831
0
  msg_type = ntohs(*((u_int16_t *)&packet->payload[0]));
832
833
  /* RFC9443 */
834
0
  if(first_byte <= 3 ||
835
     /* Whatsapp special case */
836
0
     (flow->detected_protocol_stack[0] == NDPI_PROTOCOL_WHATSAPP_CALL &&
837
0
      (msg_type == 0x0800 || msg_type == 0x0801 || msg_type == 0x0802 ||
838
0
       msg_type == 0x0804 || msg_type == 0x0805))) {
839
0
    ndpi_protocol_category_t category;
840
    
841
0
    NDPI_LOG_DBG(ndpi_struct, "Still STUN\n");
842
    
843
0
    if(is_stun(ndpi_struct, flow, &app_proto, &category) == 1) { /* To extract other metadata */
844
0
      if(is_new_subclassification_better(ndpi_struct, flow, app_proto)) {
845
0
        ndpi_int_stun_add_connection(ndpi_struct, flow,
846
0
             app_proto, __get_master(flow), category);
847
0
      }
848
0
    }
849
0
  } else if(first_byte <= 15) {
850
0
    NDPI_LOG_DBG(ndpi_struct, "DROP range. Unexpected\n");
851
0
  } else if(first_byte <= 19) {
852
0
    NDPI_LOG_DBG(ndpi_struct, "ZRTP range. Unexpected\n");
853
0
  } else if(first_byte <= 63) {
854
0
    NDPI_LOG_DBG(ndpi_struct, "DTLS\n");
855
856
0
    if(ndpi_struct->cfg.stun_opportunistic_tls_enabled &&
857
0
       is_dtls(packet->payload, packet->payload_packet_len, &unused)) {
858
859
      /* Process this DTLS packet via TLS/DTLS code but keep using STUN dissection.
860
         This way we can keep demultiplexing DTLS/STUN/RTP */
861
862
      /* Switching to TLS dissector is tricky, because we are calling one dissector
863
         from another one, and that is not a common operation...
864
         Additionally:
865
         * at that point protocol stack is already set to STUN or STUN/XXX
866
         * we have room for only two protocols in flow->detected_protocol_stack[] so
867
           we can't have something like STUN/DTLS/SNAPCHAT_CALL
868
         * the easiest (!?) solution is to remove everything, and let the TLS dissector
869
     to set both master (i.e. DTLS) and subprotocol (if any) */
870
871
      /* If we already have a real sub-classification, and the DTLS code doesn't set any
872
         subclassification iself (it is quite unlikely that we have a subprotocol only via
873
         Client Hello, for example), keep the original one */
874
875
      /* In same rare cases, with malformed/fuzzed traffic, `is_dtls()` might return false
876
         positives. In that case, the TLS dissector doesn't set the master protocol, so we
877
         need to rollback to the current state */
878
879
0
      if(flow->tls_quic.certificate_processed == 1) {
880
0
        NDPI_LOG_DBG(ndpi_struct, "Interesting DTLS stuff already processed. Ignoring\n");
881
0
      } else if(!flow->monitoring) {
882
0
        NDPI_LOG_DBG(ndpi_struct, "Switch to DTLS (%d/%d)\n",
883
0
                     flow->detected_protocol_stack[0], flow->detected_protocol_stack[1]);
884
885
0
        if(flow->stun.maybe_dtls == 0) {
886
          /* First DTLS packet of the flow */
887
0
          first_dtls_pkt = 1;
888
889
          /* We might need to rollback this change... */
890
0
          old_proto_stack[0] = flow->detected_protocol_stack[0];
891
0
          old_proto_stack[1] = flow->detected_protocol_stack[1];
892
893
          /* TODO: right way? It is a bit scary... do we need to reset something else too? */
894
0
          reset_detected_protocol(flow);
895
          /* We keep the category/breed related to STUN traffic */
896
          /* TODO: clear some risks? */
897
898
          /* Give room for DTLS handshake, where we might have
899
             retransmissions and fragments */
900
0
          flow->max_extra_packets_to_check = ndpi_min(255, (int)flow->max_extra_packets_to_check + 10);
901
0
          flow->stun.maybe_dtls = 1;
902
0
        }
903
904
0
        switch_to_tls(ndpi_struct, flow, first_dtls_pkt);
905
906
0
        if(first_dtls_pkt &&
907
0
           flow->detected_protocol_stack[0] == NDPI_PROTOCOL_DTLS &&
908
0
           flow->detected_protocol_stack[1] == NDPI_PROTOCOL_UNKNOWN &&
909
0
           old_proto_stack[0] != NDPI_PROTOCOL_UNKNOWN &&
910
0
           old_proto_stack[0] != NDPI_PROTOCOL_STUN) {
911
0
          NDPI_LOG_DBG(ndpi_struct, "Keeping old subclassification %d\n", old_proto_stack[0]);
912
0
          ndpi_int_stun_add_connection(ndpi_struct, flow,
913
0
                                       old_proto_stack[0] == NDPI_PROTOCOL_RTP ? NDPI_PROTOCOL_SRTP : old_proto_stack[0],
914
0
                                       __get_master(flow), NDPI_PROTOCOL_CATEGORY_UNSPECIFIED);
915
0
        }
916
917
        /* If this is not a real DTLS packet, we need to restore the old state */
918
0
        if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN &&
919
0
           first_dtls_pkt) {
920
0
          NDPI_LOG_DBG(ndpi_struct, "Switch to TLS failed. Rollback to old classification\n");
921
922
0
          ndpi_set_detected_protocol(ndpi_struct, flow,
923
0
                                     old_proto_stack[0], old_proto_stack[1],
924
0
                                     NDPI_CONFIDENCE_DPI);
925
926
0
          flow->stun.maybe_dtls = 0;
927
0
          flow->max_extra_packets_to_check -= 10;
928
0
        }
929
930
0
        NDPI_LOG_DBG(ndpi_struct, "(%d/%d)\n",
931
0
                     flow->detected_protocol_stack[0], flow->detected_protocol_stack[1]);
932
0
      } else {
933
0
        NDPI_LOG_DBG(ndpi_struct, "Skip DTLS packet because in monitoring\n");
934
0
      }
935
0
    }
936
0
  } else if(first_byte <= 79) {
937
0
    if(flow->stun.is_turn) {
938
0
      NDPI_LOG_DBG(ndpi_struct, "TURN range\n");
939
940
0
      if(packet->payload_packet_len >= 4) {
941
0
        u_int16_t ch_len;
942
943
0
        ch_len = ntohs(*(u_int16_t *)&packet->payload[2]);
944
945
0
        if(ch_len <= packet->payload_packet_len - 4) {
946
0
          const u_int8_t *orig_payload;
947
0
          u_int16_t orig_payload_length;
948
949
0
          orig_payload = packet->payload;
950
0
          orig_payload_length = packet->payload_packet_len;
951
0
          packet->payload = packet->payload + 4;
952
0
          packet->payload_packet_len = ch_len;
953
954
0
          stun_search_again(ndpi_struct, flow);
955
0
          NDPI_LOG_DBG(ndpi_struct, "End recursion on turn channel\n");
956
957
0
          packet->payload = orig_payload;
958
0
          packet->payload_packet_len = orig_payload_length;
959
960
0
        } else {
961
0
          if(flow->l4_proto == IPPROTO_UDP) /* The error is quite common on TCP since we don't reassemble msgs */
962
0
            NDPI_LOG_DBG(ndpi_struct, "Invalid channel length %d %d\n",
963
0
                         ch_len, packet->payload_packet_len - 4);
964
0
        }
965
0
      }
966
0
    } else {
967
0
      NDPI_LOG_DBG(ndpi_struct, "QUIC range (not turn). Unexpected\n");
968
0
    }
969
0
  } else if(first_byte <= 127) {
970
0
    NDPI_LOG_DBG(ndpi_struct, "QUIC range. Unexpected\n");
971
0
  } else if(first_byte <= 191) {
972
973
0
    rtp_rtcp = is_rtp_or_rtcp(ndpi_struct, packet->payload, packet->payload_packet_len, NULL);
974
0
    if(rtp_rtcp == IS_RTP) {
975
0
      NDPI_LOG_DBG(ndpi_struct, "RTP (dir %d) [%d/%d]\n", packet->packet_direction,
976
0
                                 flow->stun.rtp_counters[0], flow->stun.rtp_counters[1]);
977
978
0
      flow->stun.rtp_counters[packet->packet_direction]++;
979
      /* TODO: store RTP information in 'struct rtp_info' */
980
0
      NDPI_LOG_INFO(ndpi_struct, "Found RTP over STUN\n");
981
982
0
      if(flow->stun.t_start != 0) {
983
0
        flow->stun.t_end = ndpi_get_current_time(flow);
984
0
      } else if(flow->stun.rtp_counters[0] != 0 && flow->stun.rtp_counters[1] != 0) {
985
0
        flow->stun.t_start = ndpi_get_current_time(flow);
986
0
        flow->stun.t_end = ndpi_get_current_time(flow);
987
0
      }
988
989
0
      rtp_get_stream_type(packet->payload[1] & 0x7F, &flow->flow_multimedia_types, flow->detected_protocol_stack[0]);
990
991
0
      if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_RTP &&
992
0
         flow->detected_protocol_stack[0] != NDPI_PROTOCOL_RTCP &&
993
0
         flow->detected_protocol_stack[1] != NDPI_PROTOCOL_SRTP) {
994
995
0
        if(flow->detected_protocol_stack[1] != NDPI_PROTOCOL_UNKNOWN) {
996
0
          if(flow->detected_protocol_stack[1] == NDPI_PROTOCOL_DTLS) {
997
            /* Keep DTLS/SUBPROTO since we already wrote to flow->protos.tls_quic */
998
0
          } else {
999
            /* STUN/SUBPROTO -> SRTP/SUBPROTO */
1000
0
            ndpi_int_stun_add_connection(ndpi_struct, flow,
1001
0
                                         flow->detected_protocol_stack[0], NDPI_PROTOCOL_SRTP,
1002
0
           NDPI_PROTOCOL_CATEGORY_UNSPECIFIED);
1003
0
          }
1004
0
        } else {
1005
          /* STUN -> STUN/RTP, or
1006
             DTLS -> DTLS/SRTP */
1007
0
          ndpi_int_stun_add_connection(ndpi_struct, flow,
1008
0
                                       __get_master(flow) == NDPI_PROTOCOL_STUN ? NDPI_PROTOCOL_RTP: NDPI_PROTOCOL_SRTP,
1009
0
                                       __get_master(flow), NDPI_PROTOCOL_CATEGORY_UNSPECIFIED);
1010
0
        }
1011
0
      } else if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_RTCP &&
1012
0
                flow->detected_protocol_stack[1] == NDPI_PROTOCOL_UNKNOWN) {
1013
        /* From RTP dissector; if we have RTP and RTCP multiplexed together (but not STUN, yet) we always
1014
     use RTP, as we do in RTP dissector */
1015
0
        if(!flow->monitoring)
1016
0
          ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_UNKNOWN, NDPI_PROTOCOL_RTP, NDPI_CONFIDENCE_DPI);
1017
0
        else
1018
0
          NDPI_LOG_DBG(ndpi_struct, "Skip RTP packet because in monitoring\n");
1019
0
      }
1020
0
    } else if(rtp_rtcp == IS_RTCP) {
1021
0
      NDPI_LOG_DBG(ndpi_struct, "RTCP\n");
1022
0
      flow->stun.rtcp_seen = 1;
1023
0
    } else {
1024
0
      NDPI_LOG_DBG(ndpi_struct, "Unexpected\n");
1025
0
    }
1026
0
  } else {
1027
    /* Microsoft Multiplexed TURN messages.
1028
       See: https://msopenspecs.azureedge.net/files/MS-TURN/%5bMS-TURN%5d.pdf 2.2.3 */
1029
0
    if(packet->payload_packet_len >= 12 &&
1030
0
       ntohs(get_u_int16_t(packet->payload, 0)) == 0xFF10 &&
1031
0
       flow->detected_protocol_stack[0] == NDPI_PROTOCOL_MSTEAMS_CALL) {
1032
0
      u_int16_t ch_len;
1033
1034
0
      ch_len = ntohs(get_u_int16_t(packet->payload, 2));
1035
1036
0
      if(ch_len == packet->payload_packet_len - 4 &&
1037
0
         ch_len >= 8) {
1038
0
        const u_int8_t *orig_payload;
1039
0
        u_int16_t orig_payload_length;
1040
1041
0
        orig_payload = packet->payload;
1042
0
        orig_payload_length = packet->payload_packet_len;
1043
0
        packet->payload = packet->payload + 12;
1044
0
        packet->payload_packet_len = ch_len - 8;
1045
1046
0
        stun_search_again(ndpi_struct, flow);
1047
1048
0
        NDPI_LOG_DBG(ndpi_struct, "End recursion on MS channel\n");
1049
1050
0
        packet->payload = orig_payload;
1051
0
        packet->payload_packet_len = orig_payload_length;
1052
1053
0
      } else {
1054
0
        NDPI_LOG_DBG(ndpi_struct, "Invalid MS channel length %d %d\n",
1055
0
                     ch_len, packet->payload_packet_len - 4);
1056
0
      }
1057
0
    } else {
1058
0
      NDPI_LOG_DBG(ndpi_struct, "QUIC other range. Unexpected\n");
1059
0
    }
1060
0
  }
1061
0
  return keep_extra_dissection(ndpi_struct, flow);
1062
0
}
1063
1064
/* ************************************************************ */
1065
1066
static int stun_telegram_search_again(struct ndpi_detection_module_struct *ndpi_struct,
1067
                                      struct ndpi_flow_struct *flow)
1068
0
{
1069
0
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
1070
0
  const u_int8_t *orig_payload;
1071
0
  u_int16_t orig_payload_length;
1072
0
  char pattern[12] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1073
0
                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1074
0
  u_int16_t length;
1075
1076
0
  NDPI_LOG_DBG2(ndpi_struct, "[T] Packet counter %d protos %d/%d Monitoring? %d\n",
1077
0
                flow->packet_counter,
1078
0
                flow->detected_protocol_stack[0], flow->detected_protocol_stack[1],
1079
0
                flow->monitoring);
1080
1081
  /* For SOME of its STUN flows, Telegram uses a custom encapsulation
1082
     There is no documentation. It seems:
1083
     * some unknown packets (especially at the beginning/end of the flow) have a bunch of 0xFF
1084
     * the other packets encapsulate standard STUN/DTLS/RTP payload at offset 24
1085
       (with a previous field containing the payload length)
1086
   */
1087
1088
0
  if(packet->payload_packet_len <= 28) {
1089
0
    NDPI_LOG_DBG(ndpi_struct, "Malformed custom Telegram packet (too short)\n");
1090
0
    return keep_extra_dissection(ndpi_struct, flow);
1091
0
  }
1092
1093
0
  if(memcmp(&packet->payload[16], pattern, sizeof(pattern)) == 0) {
1094
0
    NDPI_LOG_DBG(ndpi_struct, "Custom/Unknown Telegram packet\n");
1095
0
    return keep_extra_dissection(ndpi_struct, flow);
1096
0
  }
1097
1098
  /* It should be STUN/DTLS/RTP */
1099
1100
0
  length = ntohs(*(u_int16_t *)&packet->payload[22]);
1101
0
  if(24 + length > packet->payload_packet_len) {
1102
0
    NDPI_LOG_DBG(ndpi_struct, "Malformed custom Telegram packet (too long: %d %d)\n",
1103
0
                 length, packet->payload_packet_len);
1104
0
    return keep_extra_dissection(ndpi_struct, flow);
1105
0
  }
1106
1107
0
  orig_payload = packet->payload;
1108
0
  orig_payload_length = packet->payload_packet_len ;
1109
0
  packet->payload = packet->payload + 24;
1110
0
  packet->payload_packet_len = length;
1111
1112
0
  stun_search_again(ndpi_struct, flow);
1113
1114
0
  packet->payload = orig_payload;
1115
0
  packet->payload_packet_len = orig_payload_length;
1116
1117
0
  return keep_extra_dissection(ndpi_struct, flow);
1118
0
}
1119
1120
/* ************************************************************ */
1121
1122
0
static u_int64_t get_stun_lru_key(struct ndpi_flow_struct *flow, u_int8_t rev) {
1123
0
  if(rev) {
1124
0
    if(flow->is_ipv6)
1125
0
      return (ndpi_quick_hash64((const char *)flow->s_address.v6, 16) << 16) | ntohs(flow->s_port);
1126
0
    else
1127
0
      return ((u_int64_t)flow->s_address.v4 << 32) | flow->s_port;
1128
0
  } else {
1129
0
    if(flow->is_ipv6)
1130
0
      return (ndpi_quick_hash64((const char *)flow->c_address.v6, 16) << 16) | ntohs(flow->c_port);
1131
0
    else
1132
0
      return ((u_int64_t)flow->c_address.v4 << 32) | flow->c_port;
1133
0
  }
1134
0
}
1135
1136
/* ************************************************************ */
1137
1138
0
static u_int64_t get_stun_lru_key_raw4(u_int32_t ip, u_int16_t port_host_order) {
1139
0
  return ((u_int64_t)ip << 32) | htons(port_host_order);
1140
0
}
1141
1142
/* ************************************************************ */
1143
1144
0
static u_int64_t get_stun_lru_key_raw6(u_int8_t *ip, u_int16_t port_host_order) {
1145
0
  return ((u_int64_t)ndpi_quick_hash(ip, 16) << 32) | htons(port_host_order);
1146
0
}
1147
1148
/* ************************************************************ */
1149
1150
static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
1151
           struct ndpi_flow_struct *flow,
1152
           u_int16_t app_proto,
1153
           u_int16_t master_proto,
1154
0
           ndpi_protocol_category_t category) {
1155
0
  ndpi_confidence_t confidence = NDPI_CONFIDENCE_DPI;
1156
0
  u_int16_t new_app_proto;
1157
1158
  /* In monitoring the classification can't change again */
1159
0
  if(flow->monitoring)
1160
0
    return;
1161
1162
0
  NDPI_LOG_DBG(ndpi_struct, "Wanting %d/%d\n", master_proto, app_proto);
1163
1164
0
  if(app_proto == NDPI_PROTOCOL_UNKNOWN) {
1165
    /* https://support.google.com/a/answer/1279090?hl=en */
1166
0
    if((ntohs(flow->c_port) >= 19302 && ntohs(flow->c_port) <= 19309) ||
1167
0
       ntohs(flow->c_port) == 3478 ||
1168
0
       (ntohs(flow->s_port) >= 19302 && ntohs(flow->s_port) <= 19309) ||
1169
0
       ntohs(flow->s_port) == 3478) {
1170
0
      if(flow->is_ipv6) {
1171
0
  u_int64_t pref1 = ndpi_htonll(0x2001486048640005); /* 2001:4860:4864:5::/64 */
1172
0
  u_int64_t pref2 = ndpi_htonll(0x2001486048640006); /* 2001:4860:4864:6::/64 */
1173
1174
0
        if(memcmp(flow->c_address.v6, &pref1, sizeof(pref1)) == 0 ||
1175
0
           memcmp(flow->c_address.v6, &pref2, sizeof(pref2)) == 0 ||
1176
0
           memcmp(flow->s_address.v6, &pref1, sizeof(pref1)) == 0 ||
1177
0
           memcmp(flow->s_address.v6, &pref2, sizeof(pref2)) == 0) {
1178
0
          app_proto = NDPI_PROTOCOL_GOOGLE_CALL;
1179
0
  }
1180
0
      } else {
1181
0
        u_int32_t c_address, s_address;
1182
1183
0
  c_address = ntohl(flow->c_address.v4);
1184
0
  s_address = ntohl(flow->s_address.v4);
1185
0
  if((c_address & 0xFFFFFF00) == 0x4a7dfa00 || /* 74.125.250.0/24 */
1186
0
           (c_address & 0xFFFFFF00) == 0x8efa5200 || /* 142.250.82.0/24 */
1187
0
           (s_address & 0xFFFFFF00) == 0x4a7dfa00 ||
1188
0
           (s_address & 0xFFFFFF00) == 0x8efa5200) {
1189
0
          app_proto = NDPI_PROTOCOL_GOOGLE_CALL;
1190
0
  }
1191
0
      }
1192
0
    }
1193
0
  }
1194
1195
0
  if(!is_subclassification_real_by_proto(app_proto)) {
1196
0
    new_app_proto = search_into_cache(ndpi_struct, flow);
1197
0
    if(new_app_proto != NDPI_PROTOCOL_UNKNOWN) {
1198
0
      confidence = NDPI_CONFIDENCE_DPI_CACHE;
1199
0
      if(app_proto == NDPI_PROTOCOL_RTP)
1200
0
        master_proto = NDPI_PROTOCOL_SRTP; /* STUN/RTP --> SRTP/APP */
1201
0
      if(master_proto == NDPI_PROTOCOL_RTP || master_proto == NDPI_PROTOCOL_RTCP)
1202
0
        master_proto = NDPI_PROTOCOL_SRTP; /* RTP|RTCP --> SRTP/APP */
1203
0
      app_proto = new_app_proto;
1204
0
    }
1205
0
  }
1206
1207
  /* From RTP dissector */
1208
0
  if(master_proto == NDPI_PROTOCOL_RTP || master_proto == NDPI_PROTOCOL_RTCP) {
1209
0
    if(app_proto == NDPI_PROTOCOL_UNKNOWN) {
1210
0
      app_proto = NDPI_PROTOCOL_RTP;
1211
0
      master_proto = NDPI_PROTOCOL_STUN; /* RTP|RTCP -> STUN/RTP */
1212
0
    } else {
1213
0
      master_proto = NDPI_PROTOCOL_SRTP;
1214
0
    }
1215
0
  }
1216
1217
  /* Adding only real subclassifications */
1218
0
  if(is_subclassification_real_by_proto(app_proto))
1219
0
    add_to_cache(ndpi_struct, flow, app_proto);
1220
1221
0
  if(category != NDPI_PROTOCOL_CATEGORY_UNSPECIFIED)
1222
0
    flow->category = category;
1223
  
1224
0
  if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN ||
1225
0
     app_proto != NDPI_PROTOCOL_UNKNOWN) {
1226
0
    NDPI_LOG_DBG(ndpi_struct, "Setting %d/%d\n", master_proto, app_proto);
1227
0
    ndpi_set_detected_protocol(ndpi_struct, flow, app_proto, master_proto, confidence);
1228
1229
    /* In "normal" data-path the generic code in `ndpi_internal_detection_process_packet()`
1230
       takes care of setting the category */
1231
0
    if(flow->extra_packets_func) {
1232
0
      ndpi_master_app_protocol proto;
1233
1234
0
      proto.master_protocol = master_proto;
1235
0
      proto.app_protocol = app_proto;
1236
0
      flow->category = get_proto_category(ndpi_struct, proto);
1237
0
      flow->breed = get_proto_breed(ndpi_struct, proto);
1238
0
    }
1239
0
  }
1240
  
1241
0
  switch_extra_dissection_to_stun(ndpi_struct, flow, 1);
1242
0
}
1243
1244
/* ************************************************************ */
1245
1246
void switch_extra_dissection_to_stun(struct ndpi_detection_module_struct *ndpi_struct,
1247
             struct ndpi_flow_struct *flow,
1248
             int std_callback)
1249
0
{
1250
0
  if(!flow->extra_packets_func) {
1251
0
    if(keep_extra_dissection(ndpi_struct, flow)) {
1252
0
      NDPI_LOG_DBG(ndpi_struct, "Enabling extra dissection\n");
1253
0
      flow->max_extra_packets_to_check = ndpi_struct->cfg.stun_max_packets_extra_dissection;
1254
0
      if(std_callback)
1255
0
        flow->extra_packets_func = stun_search_again;
1256
0
      else
1257
0
        flow->extra_packets_func = stun_telegram_search_again;
1258
0
    }
1259
0
  }
1260
0
}
1261
1262
/* ************************************************************ */
1263
1264
static void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
1265
0
{
1266
0
  struct ndpi_packet_struct *packet = &ndpi_struct->packet;
1267
0
  u_int16_t app_proto;
1268
0
  ndpi_protocol_category_t category;
1269
0
  int rc;
1270
1271
0
  NDPI_LOG_DBG(ndpi_struct, "search stun\n");
1272
1273
0
  app_proto = NDPI_PROTOCOL_UNKNOWN;
1274
1275
0
  if(packet->iph &&
1276
0
     ((packet->iph->daddr == 0xFFFFFFFF /* 255.255.255.255 */) ||
1277
0
      ((ntohl(packet->iph->daddr) & 0xF0000000) == 0xE0000000 /* A multicast address */))) {
1278
0
    NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
1279
0
    return;
1280
0
  }
1281
1282
0
  rc = is_stun(ndpi_struct, flow, &app_proto, &category);
1283
1284
0
  if(rc == 1) {
1285
0
    ndpi_int_stun_add_connection(ndpi_struct, flow, app_proto,
1286
0
         __get_master(flow), category);
1287
0
    return;
1288
0
  }
1289
1290
  /* TODO: can we stop earlier? */
1291
0
  if(flow->packet_counter > 5)
1292
0
    NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
1293
0
}
1294
1295
/* ************************************************************* */
1296
1297
static u_int64_t get_signal_key(struct ndpi_flow_struct *flow)
1298
0
{
1299
0
  if(flow->is_ipv6)
1300
0
    return ndpi_quick_hash64((const char *)flow->c_address.v6, 16);
1301
0
  else
1302
0
    return flow->c_address.v4;
1303
0
}
1304
1305
/* ************************************************************* */
1306
1307
int signal_search_into_cache(struct ndpi_detection_module_struct *ndpi_struct,
1308
                            struct ndpi_flow_struct *flow)
1309
0
{
1310
0
  u_int64_t key;
1311
0
  u_int16_t dummy;
1312
1313
0
  if(ndpi_struct->signal_cache) {
1314
0
    key = get_signal_key(flow);
1315
1316
0
    if(ndpi_lru_find_cache(ndpi_struct->signal_cache, key,
1317
0
                           &dummy, 0 /* Don't remove it as it can be used for other connections */,
1318
0
         ndpi_get_current_time(flow))) {
1319
#ifdef DEBUG_SIGNAL_LRU
1320
      printf("[LRU SIGNAL] Found %lu [%u <-> %u]\n", key, ntohs(flow->c_port), ntohs(flow->s_port));
1321
#endif
1322
0
      return 1;
1323
0
    } else {
1324
#ifdef DEBUG_SIGNAL_LRU
1325
      printf("[LRU SIGNAL] Not found %lu [%u <-> %u]\n", key, ntohs(flow->c_port), ntohs(flow->s_port));
1326
#endif
1327
0
    }      
1328
0
  }
1329
  
1330
0
  return 0;
1331
0
}
1332
1333
/* ************************************************************* */
1334
1335
void signal_add_to_cache(struct ndpi_detection_module_struct *ndpi_struct,
1336
                        struct ndpi_flow_struct *flow)
1337
0
{
1338
0
  u_int64_t key;
1339
1340
0
  if(ndpi_struct->signal_cache) {
1341
0
    key = get_signal_key(flow);
1342
#ifdef DEBUG_SIGNAL_LRU
1343
    printf("[LRU SIGNAL] ADDING %lu [%u <-> %u]\n", key, ntohs(flow->c_port), ntohs(flow->s_port));
1344
#endif
1345
0
    ndpi_lru_add_to_cache(ndpi_struct->signal_cache, key, 1 /* dummy */,
1346
0
                          ndpi_get_current_time(flow));
1347
0
  }
1348
0
}
1349
1350
/* ************************************************************ */
1351
1352
1
void init_stun_dissector(struct ndpi_detection_module_struct *ndpi_struct) {
1353
1
  register_dissector("STUN", ndpi_struct,
1354
1
                     ndpi_search_stun,
1355
1
                     NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION,
1356
1
                     1, NDPI_PROTOCOL_STUN);
1357
1
}