aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Nardi <12729895+IvanNardi@users.noreply.github.com>2023-06-26 12:07:26 +0200
committerGitHub <noreply@github.com>2023-06-26 12:07:26 +0200
commit31a9da238cdbb2f5d7cd3d3d508e246f12dcdc8b (patch)
tree913629e6a7791cf487d66bc4494ddf0eaaee3b3d
parent88425e0199dc85f95b05ffb244c6ecc048dab853 (diff)
STUN: add dissection of DTLS handshake (#2018)
-rw-r--r--src/include/ndpi_typedefs.h4
-rw-r--r--src/lib/ndpi_content_match.c.inc4
-rw-r--r--src/lib/ndpi_main.c6
-rw-r--r--src/lib/protocols/stun.c53
-rw-r--r--src/lib/protocols/tls.c85
-rw-r--r--tests/cfgs/default/result/stun.pcap.out17
6 files changed, 118 insertions, 51 deletions
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index 7f6e34b2c..7940a7d78 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -1306,6 +1306,7 @@ struct ndpi_detection_module_struct {
int opportunistic_tls_imap_enabled;
int opportunistic_tls_pop_enabled;
int opportunistic_tls_ftp_enabled;
+ int opportunistic_tls_stun_enabled;
u_int32_t monitoring_stun_pkts_to_process;
u_int32_t monitoring_stun_flags;
@@ -1458,8 +1459,7 @@ struct ndpi_flow_struct {
} kerberos_buf;
struct {
- u_int8_t num_pkts, num_binding_requests;
- u_int16_t num_processed_pkts;
+ u_int8_t num_pkts, num_binding_requests, num_processed_pkts, maybe_dtls;
} stun;
struct {
diff --git a/src/lib/ndpi_content_match.c.inc b/src/lib/ndpi_content_match.c.inc
index adeb8e4ad..f3731bfbf 100644
--- a/src/lib/ndpi_content_match.c.inc
+++ b/src/lib/ndpi_content_match.c.inc
@@ -1560,6 +1560,10 @@ static ndpi_tls_cert_name_match tls_certificate_match [] = {
{ "O=Riot Games, Inc.", NDPI_PROTOCOL_RIOTGAMES },
{ "O=Riot Games Inc", NDPI_PROTOCOL_RIOTGAMES },
+ { "CN=hangouts", NDPI_PROTOCOL_HANGOUT_DUO },
+ { "CN=Snapchat Inc.", NDPI_PROTOCOL_SNAPCHAT_CALL },
+ { "CN=NVIDIA GameStream", NDPI_PROTOCOL_GEFORCENOW },
+
{ NULL, 0 }
};
diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c
index ac3227d74..e8cc046b4 100644
--- a/src/lib/ndpi_main.c
+++ b/src/lib/ndpi_main.c
@@ -3001,6 +3001,7 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(ndpi_init_prefs
ndpi_str->opportunistic_tls_imap_enabled = 1;
ndpi_str->opportunistic_tls_pop_enabled = 1;
ndpi_str->opportunistic_tls_ftp_enabled = 1;
+ ndpi_str->opportunistic_tls_stun_enabled = 1;
ndpi_str->monitoring_stun_pkts_to_process = 4;
ndpi_str->monitoring_stun_flags = 0;
@@ -9843,6 +9844,9 @@ int ndpi_set_opportunistic_tls(struct ndpi_detection_module_struct *ndpi_struct,
case NDPI_PROTOCOL_FTP_CONTROL:
ndpi_struct->opportunistic_tls_ftp_enabled = value;
return 0;
+ case NDPI_PROTOCOL_STUN:
+ ndpi_struct->opportunistic_tls_stun_enabled = value;
+ return 0;
default:
return -1;
}
@@ -9865,6 +9869,8 @@ int ndpi_get_opportunistic_tls(struct ndpi_detection_module_struct *ndpi_struct,
return ndpi_struct->opportunistic_tls_pop_enabled;
case NDPI_PROTOCOL_FTP_CONTROL:
return ndpi_struct->opportunistic_tls_ftp_enabled;
+ case NDPI_PROTOCOL_STUN:
+ return ndpi_struct->opportunistic_tls_stun_enabled;
default:
return -1;
}
diff --git a/src/lib/protocols/stun.c b/src/lib/protocols/stun.c
index e8cdaa699..1bd27643c 100644
--- a/src/lib/protocols/stun.c
+++ b/src/lib/protocols/stun.c
@@ -36,6 +36,10 @@
#define STUN_HDR_LEN 20 /* STUN message header length, Classic-STUN (RFC 3489) and STUN (RFC 8489) both */
+extern void switch_to_tls(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow);
+extern int is_dtls(const u_int8_t *buf, u_int32_t buf_len, u_int32_t *block_len);
+
static int stun_monitoring(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow)
{
@@ -212,6 +216,7 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
u_int16_t *app_proto) {
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
u_int16_t msg_type, msg_len;
+ u_int32_t unused;
int rc;
if(packet->iph &&
@@ -221,6 +226,31 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
return(NDPI_IS_NOT_STUN);
}
+ /* If we're here it's because this does not look like STUN anymore
+ as this was a flow that started as STUN and turned into something
+ else. Let's investigate what is that about */
+ if(flow->stun.num_pkts > 0 && is_dtls(payload, payload_length, &unused)) {
+#ifdef DEBUG_STUN
+ printf("[STUN] DTLS?\n");
+#endif
+ /* Switching to TLS dissector is tricky, because we are calling one dissector
+ from another one, and that is not a common operation...
+ Additionally:
+ * at that point protocol stack is still empty
+ * we have room for only two protocols in flow->detected_protocol_stack[] so
+ we can't have something like STUN/DTLS/SNAPCHAT_CALL
+ * the easiest solution is skipping STUN, and let TLS dissector to set both
+ master (i.e. DTLS) and subprotocol (if any) */
+ if(ndpi_struct->opportunistic_tls_stun_enabled) {
+ flow->stun.maybe_dtls = 1;
+ switch_to_tls(ndpi_struct, flow);
+ }
+ /* We don't want to mess up with TLS classification/results but we don't want to
+ exclude STUN right away to keep trying it in the case that this packet is
+ not a real DTLS one */
+ return(NDPI_IS_NOT_STUN);
+ }
+
if(payload_length < STUN_HDR_LEN) {
/* This looks like an invalid packet */
@@ -260,29 +290,6 @@ static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *
#ifdef DEBUG_STUN
printf("[STUN] msg_type = %04X\n", msg_type);
#endif
-
- /*
- If we're here it's because this does not look like STUN anymore
- as this was a flow that started as STUN and turned into something
- else. Let's investigate what is that about
- */
- if(payload[0] == 0x16) {
- /* Let's check if this is DTLS used by some socials */
- struct ndpi_packet_struct *packet = &ndpi_struct->packet;
- u_int16_t total_len, version = htons(*((u_int16_t*) &packet->payload[1]));
-
- switch (version) {
- case 0xFEFF: /* DTLS 1.0 */
- case 0xFEFD: /* DTLS 1.2 */
- total_len = ntohs(*((u_int16_t*) &packet->payload[11])) + 13;
-
- if(payload_length == total_len) {
- flow->guessed_protocol_id = NDPI_PROTOCOL_DTLS;
- return(NDPI_IS_NOT_STUN);
- }
- }
- }
-
return(NDPI_IS_NOT_STUN);
}
diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c
index e1b85db15..e2c20ee03 100644
--- a/src/lib/protocols/tls.c
+++ b/src/lib/protocols/tls.c
@@ -30,6 +30,8 @@
extern char *strptime(const char *s, const char *format, struct tm *tm);
extern int processClientServerHello(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow, uint32_t quic_version);
+static void ndpi_search_tls_wrapper(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow);
extern int http_process_user_agent(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
const u_int8_t *ua_ptr, u_int16_t ua_ptr_len);
@@ -1188,6 +1190,36 @@ static int ndpi_search_tls_tcp(struct ndpi_detection_module_struct *ndpi_struct,
/* **************************************** */
+int is_dtls(const u_int8_t *buf, u_int32_t buf_len, u_int32_t *block_len) {
+ if(buf_len <= 13)
+ return 0;
+
+ if((buf[0] != 0x16 && buf[0] != 0x14 && buf[0] != 0x17) || /* Handshake, change-cipher-spec, Application-Data */
+ !((buf[1] == 0xfe && buf[2] == 0xff) || /* Versions */
+ (buf[1] == 0xfe && buf[2] == 0xfd) ||
+ (buf[1] == 0x01 && buf[2] == 0x00))) {
+#ifdef DEBUG_TLS
+ printf("[TLS] DTLS invalid block 0x%x or old version 0x%x-0x%x-0x%x\n",
+ buf[0], buf[1], buf[2], buf[3]);
+#endif
+ return 0;
+ }
+ *block_len = ntohs(*((u_int16_t*)&buf[11]));
+#ifdef DEBUG_TLS
+ printf("[TLS] DTLS block len: %d\n", *block_len);
+#endif
+ if(*block_len == 0 || (*block_len + 12 >= buf_len)) { /* We might have multiple DTLS records */
+#ifdef DEBUG_TLS
+ printf("[TLS] DTLS invalid block len %d (buf_len %d)\n",
+ *block_len, buf_len);
+#endif
+ return 0;
+ }
+ return 1;
+}
+
+/* **************************************** */
+
static int ndpi_search_tls_udp(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
@@ -1210,29 +1242,23 @@ static int ndpi_search_tls_udp(struct ndpi_detection_module_struct *ndpi_struct,
u_int32_t block_len;
const u_int8_t *block = (const u_int8_t *)&p[processed];
- if((block[0] != 0x16 && block[0] != 0x14 && block[0] != 0x17) || /* Handshake, change-cipher-spec, Application-Data */
- !((block[1] == 0xfe && block[2] == 0xff) ||
- (block[1] == 0xfe && block[2] == 0xfd) ||
- (block[1] == 0x01 && block[2] == 0x00))) {
-#ifdef DEBUG_TLS
- printf("[TLS] DTLS invalid block 0x%x or old version 0x%x-0x%x-0x%x\n",
- block[0], block[1], block[2], block[3]);
-#endif
- no_dtls = 1;
- break;
- }
- block_len = ntohs(*((u_int16_t*)&block[11]));
+ if(!is_dtls(block, p_len, &block_len)) {
+ if(processed == 0 && /* First block */
+ flow->stun.maybe_dtls == 1) {
+ /* Sometimes STUN packets are interleaved with TLS ones. Ignore STUN ones
+ since we already are after STUN dissection and we are interested only on
+ TLS stuff right now */
#ifdef DEBUG_TLS
- printf("[TLS] DTLS block len: %d\n", block_len);
-#endif
- if(block_len == 0 || (processed + block_len + 12 >= p_len)) {
-#ifdef DEBUG_TLS
- printf("[TLS] DTLS invalid block len %d (processed %d, p_len %d)\n",
- block_len, processed, p_len);
+ printf("Probably a stun packet. Keep going with TLS on next packets\n");
#endif
+ /* Note that we can immediately "return" because, being the first block,
+ we don't need to restore packet->payload and packet->payload_packet_len */
+ return(1); /* Keep working */
+ }
no_dtls = 1;
break;
}
+
/* We process only handshake msgs */
if(block[0] == 0x16) {
if(processed + block_len + 13 > p_len) {
@@ -1358,8 +1384,9 @@ static void tlsInitExtraPacketProcessing(struct ndpi_detection_module_struct *nd
struct ndpi_flow_struct *flow) {
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
- /* At most 12 packets should almost always be enough to find the server certificate if it's there */
- flow->max_extra_packets_to_check = 12 + (ndpi_struct->num_tls_blocks_to_follow*4);
+ /* At most 12 packets should almost always be enough to find the server certificate if it's there.
+ Exception: DTLS traffic with fragments, retransmissions and STUN packets */
+ flow->max_extra_packets_to_check = ((packet->udp != NULL) ? 20 : 12) + (ndpi_struct->num_tls_blocks_to_follow*4);
flow->extra_packets_func = (packet->udp != NULL) ? ndpi_search_tls_udp : ndpi_search_tls_tcp;
}
@@ -1385,6 +1412,24 @@ void switch_extra_dissection_to_tls(struct ndpi_detection_module_struct *ndpi_st
/* **************************************** */
+void switch_to_tls(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow)
+{
+#ifdef DEBUG_TLS
+ printf("Switching to TLS\n");
+#endif
+
+ /* Reset reassemblers */
+ if(flow->tls_quic.message[0].buffer)
+ ndpi_free(flow->tls_quic.message[0].buffer);
+ memset(&flow->tls_quic.message[0], '\0', sizeof(flow->tls_quic.message[0]));
+ if(flow->tls_quic.message[1].buffer)
+ ndpi_free(flow->tls_quic.message[1].buffer);
+ memset(&flow->tls_quic.message[1], '\0', sizeof(flow->tls_quic.message[1]));
+
+ ndpi_search_tls_wrapper(ndpi_struct, flow);
+}
+
static void tls_subclassify_by_alpn(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow) {
/* Right now we have only one rule so we can keep it trivial */
diff --git a/tests/cfgs/default/result/stun.pcap.out b/tests/cfgs/default/result/stun.pcap.out
index 5bcff7c12..7cb1e3871 100644
--- a/tests/cfgs/default/result/stun.pcap.out
+++ b/tests/cfgs/default/result/stun.pcap.out
@@ -1,20 +1,20 @@
Guessed flow protos: 0
DPI Packets (TCP): 7 (3.50 pkts/flow)
-DPI Packets (UDP): 17 (5.67 pkts/flow)
+DPI Packets (UDP): 18 (6.00 pkts/flow)
Confidence DPI : 5 (flows)
-Num dissector calls: 595 (119.00 diss/flow)
+Num dissector calls: 578 (115.60 diss/flow)
LRU cache ookla: 0/0/0 (insert/search/found)
LRU cache bittorrent: 0/3/0 (insert/search/found)
LRU cache zoom: 0/0/0 (insert/search/found)
-LRU cache stun: 6/38/0 (insert/search/found)
-LRU cache tls_cert: 0/0/0 (insert/search/found)
+LRU cache stun: 4/34/0 (insert/search/found)
+LRU cache tls_cert: 1/2/0 (insert/search/found)
LRU cache mining: 0/0/0 (insert/search/found)
LRU cache msteams: 0/0/0 (insert/search/found)
LRU cache stun_zoom: 0/0/0 (insert/search/found)
Automa host: 0/0 (search/found)
Automa domain: 0/0 (search/found)
-Automa tls cert: 0/0 (search/found)
+Automa tls cert: 1/1 (search/found)
Automa risk mask: 1/0 (search/found)
Automa common alpns: 0/0 (search/found)
Patricia risk mask: 8/0 (search/found)
@@ -26,8 +26,13 @@ STUN 62 7620 2
GoogleHangoutDuo 33 6292 1
FacebookVoip 75 10554 1
+JA3 Host Stats:
+ IP Address # JA3C
+ 1 192.168.12.169 1
+
+
1 UDP 192.168.12.169:38123 <-> 31.13.86.54:40003 [proto: 78.268/STUN.FacebookVoip][IP: 119/Facebook][ClearText][Confidence: DPI][DPI packets: 2][cat: VoIP/10][40 pkts/6134 bytes <-> 35 pkts/4420 bytes][Goodput ratio: 73/67][10.09 sec][Hostname/SNI: turner.facebook][bytes ratio: 0.162 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/0 260/331 6004/5997 1040/1126][Pkt Len c2s/s2c min/avg/max/stddev: 70/68 153/126 190/174 31/39][Risk: ** Known Proto on Non Std Port **][Risk Score: 50][PLAIN TEXT (unauthorized)][Plen Bins: 8,14,9,28,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
- 2 UDP 192.168.12.169:49153 <-> 142.250.82.99:3478 [proto: 78.201/STUN.GoogleHangoutDuo][IP: 126/Google][ClearText][Confidence: DPI][DPI packets: 4][cat: VoIP/10][18 pkts/2856 bytes <-> 15 pkts/3436 bytes][Goodput ratio: 74/82][2.12 sec][bytes ratio: -0.092 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 8/0 88/153 699/625 177/222][Pkt Len c2s/s2c min/avg/max/stddev: 107/76 159/229 588/1240 107/297][PLAIN TEXT (BwlkYDtFJ)][Plen Bins: 0,6,57,21,6,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0]
+ 2 UDP 192.168.12.169:49153 <-> 142.250.82.99:3478 [proto: 30.201/DTLS.GoogleHangoutDuo][IP: 126/Google][Encrypted][Confidence: DPI][DPI packets: 5][cat: VoIP/10][18 pkts/2856 bytes <-> 15 pkts/3436 bytes][Goodput ratio: 74/82][2.12 sec][bytes ratio: -0.092 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 8/0 88/153 699/625 177/222][Pkt Len c2s/s2c min/avg/max/stddev: 107/76 159/229 588/1240 107/297][Risk: ** Self-signed Cert **** TLS (probably) Not Carrying HTTPS **** Missing SNI TLS Extn **][Risk Score: 160][Risk Info: No ALPN / CN=hangouts][DTLSv1.2][JA3C: c14667d7da3e6f7a7ab5519ef78c2452][JA3S: 1f5d6a6d0bc5d514dd84d13e6283d309][Issuer: CN=hangouts][Subject: CN=hangouts][Certificate SHA-1: 6C:D0:9A:70:A1:F1:9E:BF:8E:EF:FE:B6:F1:37:A3:E8:8A:3B:F7:C8][Validity: 2022-03-17 02:11:17 - 2023-03-18 02:11:17][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256][PLAIN TEXT (BwlkYDtFJ)][Plen Bins: 0,6,57,21,6,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0]
3 UDP [3516:bf0b:fc53:75e7:70af:f67f:8e49:f603]:56880 <-> [2a38:e156:8167:a333:face:b00c::24d9]:3478 [proto: 78/STUN][IP: 0/Unknown][ClearText][Confidence: DPI][DPI packets: 11][cat: Network/14][21 pkts/1722 bytes <-> 21 pkts/2226 bytes][Goodput ratio: 24/41][191.49 sec][bytes ratio: -0.128 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 2/2 9451/9451 10358/10358 2441/2441][Pkt Len c2s/s2c min/avg/max/stddev: 82/106 82/106 82/106 0/0][PLAIN TEXT (WOBTrOXR)][Plen Bins: 50,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
4 TCP 87.47.100.17:3478 <-> 54.1.57.155:37257 [proto: 78/STUN][IP: 0/Unknown][ClearText][Confidence: DPI][DPI packets: 4][cat: Network/14][9 pkts/1494 bytes <-> 11 pkts/2178 bytes][Goodput ratio: 60/67][0.95 sec][Hostname/SNI: apps-host.com][bytes ratio: -0.186 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/0 104/96 267/252 102/93][Pkt Len c2s/s2c min/avg/max/stddev: 74/94 166/198 234/354 41/65][PLAIN TEXT (Unauthorized)][Plen Bins: 10,0,15,21,42,5,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
5 TCP 10.77.110.51:41588 <-> 10.206.50.239:42000 [VLAN: 1611][proto: 78.38/STUN.Skype_TeamsCall][IP: 0/Unknown][ClearText][Confidence: DPI][DPI packets: 3][cat: VoIP/10][7 pkts/1006 bytes <-> 8 pkts/1118 bytes][Goodput ratio: 58/57][1.05 sec][bytes ratio: -0.053 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/0 189/134 369/399 144/153][Pkt Len c2s/s2c min/avg/max/stddev: 70/64 144/140 164/172 31/43][Plen Bins: 0,0,25,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]