aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/include/ndpi_typedefs.h8
-rw-r--r--src/lib/protocols/quic.c70
-rw-r--r--tests/cfgs/default/pcap/quic_sh.pcapbin0 -> 24572 bytes
-rw-r--r--tests/cfgs/default/result/dnscrypt_skype_false_positive.pcapng.out2
-rw-r--r--tests/cfgs/default/result/openvpn.pcap.out2
-rw-r--r--tests/cfgs/default/result/quic_sh.pcap.out29
6 files changed, 106 insertions, 5 deletions
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index e292633fd..e7fdb9541 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -907,6 +907,7 @@ struct ndpi_flow_udp_struct {
u_int32_t xbox_stage:1;
/* NDPI_PROTOCOL_QUIC */
+ u_int32_t quic_server_cid_stage:2;
u_int32_t quic_0rtt_found:1;
u_int32_t quic_vn_pair:1;
@@ -942,6 +943,9 @@ struct ndpi_flow_udp_struct {
u_int8_t *quic_reasm_buf;
u_int8_t *quic_reasm_buf_bitmap;
u_int32_t quic_reasm_buf_last_pos;
+#define QUIC_SERVER_CID_HEURISTIC_LENGTH 8
+ u_int8_t quic_server_cid[QUIC_SERVER_CID_HEURISTIC_LENGTH];
+ u_int8_t quic_client_last_byte;
/* DCID of the first Initial sent by the client */
u_int8_t quic_orig_dest_conn_id[20]; /* Max length is 20 on all QUIC versions */
u_int8_t quic_orig_dest_conn_id_len;
@@ -1544,8 +1548,8 @@ struct ndpi_flow_struct {
_Static_assert(sizeof(((struct ndpi_flow_struct *)0)->protos) <= 264,
"Size of the struct member protocols increased to more than 264 bytes, "
"please check if this change is necessary.");
-_Static_assert(sizeof(struct ndpi_flow_struct) <= 1128,
- "Size of the flow struct increased to more than 1120 bytes, "
+_Static_assert(sizeof(struct ndpi_flow_struct) <= 1136,
+ "Size of the flow struct increased to more than 1136 bytes, "
"please check if this change is necessary.");
#endif
#endif
diff --git a/src/lib/protocols/quic.c b/src/lib/protocols/quic.c
index 939413ea7..12ec27048 100644
--- a/src/lib/protocols/quic.c
+++ b/src/lib/protocols/quic.c
@@ -1527,6 +1527,54 @@ static int may_be_gquic_rej(struct ndpi_detection_module_struct *ndpi_struct)
return 0;
}
+static int may_be_sh(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow)
+{
+ struct ndpi_packet_struct *packet = &ndpi_struct->packet;
+ u_int8_t last_byte;
+
+ if((packet->payload[0] & 0x40) == 0)
+ return 0;
+ if(packet->udp->dest != ntohs(443)) {
+ if(packet->udp->source == ntohs(443)) {
+ return -1; /* Keep looking for packets sent by the client */
+ }
+ return 0;
+ }
+
+ /* SH packet sent by the client */
+
+ /* QUIC never retransmits packet, but we should also somehow check that
+ * these 3 packets from the client are really different from each other
+ * to avoid matching retransmissions on some other protocols.
+ * To avoid saving too much state, simply check the last byte of each packet
+ * (the idea is that being QUIC fully encrypted, the bytes are somehow always
+ * different; a weak assumption, but it allow us to save only 1 byte in
+ * flow structure and it seems to work)
+ * TODO: do we need something better?
+ */
+
+ if(packet->payload_packet_len < 1 + QUIC_SERVER_CID_HEURISTIC_LENGTH)
+ return 0;
+ last_byte = packet->payload[packet->payload_packet_len - 1];
+ if(flow->l4.udp.quic_server_cid_stage > 0) {
+ if(memcmp(flow->l4.udp.quic_server_cid, &packet->payload[1],
+ QUIC_SERVER_CID_HEURISTIC_LENGTH) != 0 ||
+ flow->l4.udp.quic_client_last_byte == last_byte)
+ return 0;
+ flow->l4.udp.quic_server_cid_stage++;
+ if(flow->l4.udp.quic_server_cid_stage == 3) {
+ /* Found QUIC via 3 SHs by client */
+ return 1;
+ }
+ } else {
+ memcpy(flow->l4.udp.quic_server_cid, &packet->payload[1], QUIC_SERVER_CID_HEURISTIC_LENGTH);
+ flow->l4.udp.quic_server_cid_stage = 1;
+ }
+ flow->l4.udp.quic_client_last_byte = last_byte;
+ return -1; /* Keep looking for other packets sent by client */
+}
+
static int may_be_0rtt(struct ndpi_detection_module_struct *ndpi_struct,
uint32_t *version)
{
@@ -1881,9 +1929,16 @@ static void ndpi_search_quic(struct ndpi_detection_module_struct *ndpi_struct,
* CHLO/ClientHello message and we need (only) it to sub-classify
* the flow.
* Detecting QUIC sessions where the first captured packet is not a
- * CHLO/CH is VERY hard. Let try only 2 easy cases:
+ * CHLO/CH is VERY hard. Let try only some easy cases:
* * out-of-order 0-RTT, i.e 0-RTT packets received before the Initial;
* in that case, keep looking for the Initial
+ * * if we have only SH pkts, focus on standard case where server
+ * port is 443 and default length of Server CID is >=8 (as it happens
+ * with most common broswer and apps). Look for 3 consecutive SH
+ * pkts send by the client and check their CIDs (note that
+ * some QUIC implementations have Client CID length set to 0, so
+ * checking pkts sent by server is useless). Since we don't know the
+ * real CID length, use the min value 8, i.e. QUIC_SERVER_CID_HEURISTIC_LENGTH
* * with only GQUIC packets from server (usefull with unidirectional
* captures) look for Rejection packet
* Avoid the generic cases and let's see if anyone complains...
@@ -1910,6 +1965,19 @@ static void ndpi_search_quic(struct ndpi_detection_module_struct *ndpi_struct,
flow->protos.tls_quic.quic_version = 0; /* unknown */
return;
}
+ ret = may_be_sh(ndpi_struct, flow);
+ if(ret == 1) {
+ NDPI_LOG_INFO(ndpi_struct, "SH Quic\n");
+ ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_QUIC, NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI);
+ flow->protos.tls_quic.quic_version = 0; /* unknown */
+ return;
+ }
+ if(ret == -1) {
+ NDPI_LOG_DBG2(ndpi_struct, "Keep looking for SH by client\n");
+ if(flow->packet_counter > 10 /* TODO */)
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
+ }
ret = may_be_gquic_rej(ndpi_struct);
if(ret == 1) {
NDPI_LOG_INFO(ndpi_struct, "GQUIC REJ\n");
diff --git a/tests/cfgs/default/pcap/quic_sh.pcap b/tests/cfgs/default/pcap/quic_sh.pcap
new file mode 100644
index 000000000..e4997e46f
--- /dev/null
+++ b/tests/cfgs/default/pcap/quic_sh.pcap
Binary files differ
diff --git a/tests/cfgs/default/result/dnscrypt_skype_false_positive.pcapng.out b/tests/cfgs/default/result/dnscrypt_skype_false_positive.pcapng.out
index 92c7b4919..1bfbc7ec0 100644
--- a/tests/cfgs/default/result/dnscrypt_skype_false_positive.pcapng.out
+++ b/tests/cfgs/default/result/dnscrypt_skype_false_positive.pcapng.out
@@ -1,6 +1,6 @@
DPI Packets (UDP): 2 (2.00 pkts/flow)
Confidence DPI : 1 (flows)
-Num dissector calls: 154 (154.00 diss/flow)
+Num dissector calls: 155 (155.00 diss/flow)
LRU cache ookla: 0/0/0 (insert/search/found)
LRU cache bittorrent: 0/3/0 (insert/search/found)
LRU cache stun: 0/0/0 (insert/search/found)
diff --git a/tests/cfgs/default/result/openvpn.pcap.out b/tests/cfgs/default/result/openvpn.pcap.out
index c1903a83d..09a96d23f 100644
--- a/tests/cfgs/default/result/openvpn.pcap.out
+++ b/tests/cfgs/default/result/openvpn.pcap.out
@@ -1,7 +1,7 @@
DPI Packets (TCP): 24 (8.00 pkts/flow)
DPI Packets (UDP): 24 (3.43 pkts/flow)
Confidence DPI : 10 (flows)
-Num dissector calls: 1754 (175.40 diss/flow)
+Num dissector calls: 1755 (175.50 diss/flow)
LRU cache ookla: 0/0/0 (insert/search/found)
LRU cache bittorrent: 0/9/0 (insert/search/found)
LRU cache stun: 0/0/0 (insert/search/found)
diff --git a/tests/cfgs/default/result/quic_sh.pcap.out b/tests/cfgs/default/result/quic_sh.pcap.out
new file mode 100644
index 000000000..3e7d07938
--- /dev/null
+++ b/tests/cfgs/default/result/quic_sh.pcap.out
@@ -0,0 +1,29 @@
+DPI Packets (UDP): 14 (4.67 pkts/flow)
+Confidence DPI : 3 (flows)
+Num dissector calls: 530 (176.67 diss/flow)
+LRU cache ookla: 0/0/0 (insert/search/found)
+LRU cache bittorrent: 0/9/0 (insert/search/found)
+LRU cache stun: 0/0/0 (insert/search/found)
+LRU cache tls_cert: 0/0/0 (insert/search/found)
+LRU cache mining: 0/0/0 (insert/search/found)
+LRU cache msteams: 0/0/0 (insert/search/found)
+LRU cache fpc_dns: 0/3/0 (insert/search/found)
+Automa host: 0/0 (search/found)
+Automa domain: 0/0 (search/found)
+Automa tls cert: 0/0 (search/found)
+Automa risk mask: 0/0 (search/found)
+Automa common alpns: 0/0 (search/found)
+Patricia risk mask: 2/0 (search/found)
+Patricia risk mask IPv6: 4/0 (search/found)
+Patricia risk: 0/0 (search/found)
+Patricia risk IPv6: 2/0 (search/found)
+Patricia protocols: 1/1 (search/found)
+Patricia protocols IPv6: 2/2 (search/found)
+
+QUIC 38 23111 3
+
+Acceptable 38 23111 3
+
+ 1 UDP [2001:b07:a3d:c112:91b7:b97e:6e2:fad8]:37542 <-> [2606:4700:7::a29f:9804]:443 [proto: 188/QUIC][IP: 220/Cloudflare][Encrypted][Confidence: DPI][FPC: 220/Cloudflare, Confidence: IP address][DPI packets: 5][cat: Web/5][6 pkts/634 bytes <-> 15 pkts/13073 bytes][Goodput ratio: 41/93][0.11 sec][bytes ratio: -0.907 (Download)][IAT c2s/s2c min/avg/max/stddev: 0/0 7/7 20/86 9/23][Pkt Len c2s/s2c min/avg/max/stddev: 105/90 106/872 109/1262 1/472][Risk: ** Susp Entropy **][Risk Score: 10][Risk Info: Entropy: 6.456 (Executable?)][PLAIN TEXT (vS17md)][Plen Bins: 4,34,0,4,0,0,0,0,0,4,0,4,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,0,0,0]
+ 2 UDP 192.168.1.245:40408 <-> 13.226.175.53:443 [proto: 188/QUIC][IP: 265/AmazonAWS][Encrypted][Confidence: DPI][FPC: 265/AmazonAWS, Confidence: IP address][DPI packets: 3][cat: Web/5][4 pkts/340 bytes <-> 3 pkts/4482 bytes][Goodput ratio: 50/97][0.00 sec][bytes ratio: -0.859 (Download)][IAT c2s/s2c min/avg/max/stddev: 0/0 0/0 0/0 0/0][Pkt Len c2s/s2c min/avg/max/stddev: 85/1494 85/1494 85/1494 0/0][Plen Bins: 0,57,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,42,0,0]
+ 3 UDP [2a00:1450:4002:411::200e]:443 <-> [2001:b07:a3d:c112:91b7:b97e:6e2:fad8]:33144 [proto: 188/QUIC][IP: 126/Google][Encrypted][Confidence: DPI][FPC: 126/Google, Confidence: IP address][DPI packets: 6][cat: Web/5][3 pkts/3876 bytes <-> 7 pkts/706 bytes][Goodput ratio: 95/38][0.03 sec][bytes ratio: 0.692 (Upload)][IAT c2s/s2c min/avg/max/stddev: 0/0 0/0 1/0 0/0][Pkt Len c2s/s2c min/avg/max/stddev: 1292/99 1292/101 1292/104 0/2][Risk: ** Susp Entropy **][Risk Score: 10][Risk Info: Entropy: 7.836 (Encrypted or Random?)][Plen Bins: 0,70,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,30,0,0,0,0,0,0,0,0,0]