aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib/protocols/quic.c53
-rw-r--r--tests/cfgs/default/pcap/gquic_only_from_server.pcapbin0 -> 40244 bytes
-rw-r--r--tests/cfgs/default/result/gquic_only_from_server.pcap.out28
-rw-r--r--tests/cfgs/default/result/radius_false_positive.pcapng.out16
4 files changed, 78 insertions, 19 deletions
diff --git a/src/lib/protocols/quic.c b/src/lib/protocols/quic.c
index 183d2e524..0b8674f38 100644
--- a/src/lib/protocols/quic.c
+++ b/src/lib/protocols/quic.c
@@ -1491,11 +1491,31 @@ void process_chlo(struct ndpi_detection_module_struct *ndpi_struct,
}
}
+static int may_be_gquic_rej(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow)
+{
+ struct ndpi_packet_struct *packet = &ndpi_struct->packet;
+ void *ptr;
+
+ /* Common case: msg from server default port */
+ if(packet->udp->source != ntohs(443))
+ return 0;
+ /* GQUIC. Common case: cid length 8, no version, packet number length 1 */
+ if(packet->payload[0] != 0x08)
+ return 0;
+ if(packet->payload_packet_len < 1 + 8 + 1 + 12 /* Message auth hash */ + 16 /* Arbitrary length */)
+ return 0;
+ /* Search for "REJ" tag in the first 16 bytes after the hash */
+ ptr = memchr(&packet->payload[1 + 8 + 1 + 12], 'R', 16 - 3);
+ if(ptr && memcmp(ptr, "REJ", 3) == 0)
+ return 1;
+ return 0;
+}
+
static int may_be_0rtt(struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow)
+ struct ndpi_flow_struct *flow, uint32_t *version)
{
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
- uint32_t version;
u_int8_t first_byte;
u_int8_t pub_bit1, pub_bit2, pub_bit3, pub_bit4;
u_int8_t dest_conn_id_len, source_conn_id_len;
@@ -1512,23 +1532,23 @@ static int may_be_0rtt(struct ndpi_detection_module_struct *ndpi_struct,
pub_bit3 = ((first_byte & 0x20) != 0);
pub_bit4 = ((first_byte & 0x10) != 0);
- version = ntohl(*((u_int32_t *)&packet->payload[1]));
+ *version = ntohl(*((u_int32_t *)&packet->payload[1]));
/* IETF versions, Long header, fixed bit (ignore QUIC-bit-greased case), 0RTT */
- if(!(is_version_quic(version) &&
+ if(!(is_version_quic(*version) &&
pub_bit1 && pub_bit2)) {
NDPI_LOG_DBG2(ndpi_struct, "Invalid header or version\n");
return 0;
}
- if(!is_version_quic_v2(version) &&
+ if(!is_version_quic_v2(*version) &&
(pub_bit3 != 0 || pub_bit4 != 1)) {
- NDPI_LOG_DBG2(ndpi_struct, "Version 0x%x not 0-RTT Packet\n", version);
+ NDPI_LOG_DBG2(ndpi_struct, "Version 0x%x not 0-RTT Packet\n", *version);
return 0;
}
- if(is_version_quic_v2(version) &&
+ if(is_version_quic_v2(*version) &&
(pub_bit3 != 1 || pub_bit4 != 0)) {
- NDPI_LOG_DBG2(ndpi_struct, "Version 0x%x not 0-RTT Packet\n", version);
+ NDPI_LOG_DBG2(ndpi_struct, "Version 0x%x not 0-RTT Packet\n", *version);
return 0;
}
@@ -1546,7 +1566,7 @@ static int may_be_0rtt(struct ndpi_detection_module_struct *ndpi_struct,
if(dest_conn_id_len > QUIC_MAX_CID_LENGTH ||
source_conn_id_len > QUIC_MAX_CID_LENGTH) {
NDPI_LOG_DBG2(ndpi_struct, "Version 0x%x invalid CIDs length %u %u\n",
- version, dest_conn_id_len, source_conn_id_len);
+ *version, dest_conn_id_len, source_conn_id_len);
return 0;
}
@@ -1847,16 +1867,18 @@ 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 1 easy case:
+ * CHLO/CH is VERY hard. Let try only 2 easy cases:
* * out-of-order 0-RTT, i.e 0-RTT packets received before the Initial;
* in that case, keep looking for the Initial
+ * * 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...
*/
is_initial_quic = may_be_initial_pkt(ndpi_struct, &version);
if(!is_initial_quic) {
if(!is_ch_reassembler_pending(flow)) { /* Better safe than sorry */
- ret = may_be_0rtt(ndpi_struct, flow);
+ ret = may_be_0rtt(ndpi_struct, flow, &version);
if(ret == 1) {
NDPI_LOG_DBG(ndpi_struct, "Found 0-RTT, keep looking for Initial\n");
flow->l4.udp.quic_0rtt_found = 1;
@@ -1864,14 +1886,23 @@ static void ndpi_search_quic(struct ndpi_detection_module_struct *ndpi_struct,
/* We haven't still found an Initial.. give up */
NDPI_LOG_INFO(ndpi_struct, "QUIC 0RTT\n");
ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_QUIC, NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI);
+ flow->protos.tls_quic.quic_version = version;
}
return;
} else if(flow->l4.udp.quic_0rtt_found == 1) {
/* Unknown packet (probably an Handshake one) after a 0-RTT */
NDPI_LOG_INFO(ndpi_struct, "QUIC 0RTT (without Initial)\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;
}
+ ret = may_be_gquic_rej(ndpi_struct, flow);
+ if(ret == 1) {
+ NDPI_LOG_INFO(ndpi_struct, "GQUIC REJ\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;
+ }
}
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return;
diff --git a/tests/cfgs/default/pcap/gquic_only_from_server.pcap b/tests/cfgs/default/pcap/gquic_only_from_server.pcap
new file mode 100644
index 000000000..a0c521b03
--- /dev/null
+++ b/tests/cfgs/default/pcap/gquic_only_from_server.pcap
Binary files differ
diff --git a/tests/cfgs/default/result/gquic_only_from_server.pcap.out b/tests/cfgs/default/result/gquic_only_from_server.pcap.out
new file mode 100644
index 000000000..7a0f0605c
--- /dev/null
+++ b/tests/cfgs/default/result/gquic_only_from_server.pcap.out
@@ -0,0 +1,28 @@
+Guessed flow protos: 0
+
+DPI Packets (UDP): 1 (1.00 pkts/flow)
+Confidence DPI : 1 (flows)
+Num dissector calls: 1 (1.00 diss/flow)
+LRU cache ookla: 0/0/0 (insert/search/found)
+LRU cache bittorrent: 0/0/0 (insert/search/found)
+LRU cache zoom: 0/0/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 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 risk mask: 0/0 (search/found)
+Automa common alpns: 0/0 (search/found)
+Patricia risk mask: 2/0 (search/found)
+Patricia risk mask IPv6: 0/0 (search/found)
+Patricia risk: 0/0 (search/found)
+Patricia risk IPv6: 0/0 (search/found)
+Patricia protocols: 2/0 (search/found)
+Patricia protocols IPv6: 0/0 (search/found)
+
+QUIC 30 39740 1
+
+ 1 UDP 213.202.7.26:443 -> 10.189.122.71:60524 [VLAN: 1508][proto: 188/QUIC][IP: 0/Unknown][Encrypted][Confidence: DPI][DPI packets: 1][cat: Web/5][30 pkts/39740 bytes -> 0 pkts/0 bytes][Goodput ratio: 97/0][0.09 sec][bytes ratio: 1.000 (Upload)][IAT c2s/s2c min/avg/max/stddev: 0/0 3/0 59/0 11/0][Pkt Len c2s/s2c min/avg/max/stddev: 69/0 1325/0 1396/0 275/0][Risk: ** Unidirectional Traffic **][Risk Score: 10][Risk Info: No client to server traffic][PLAIN TEXT (AESGCC20)][Plen Bins: 3,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,93,0,0,0,0,0]
diff --git a/tests/cfgs/default/result/radius_false_positive.pcapng.out b/tests/cfgs/default/result/radius_false_positive.pcapng.out
index 7d0aa0535..9fc1b1750 100644
--- a/tests/cfgs/default/result/radius_false_positive.pcapng.out
+++ b/tests/cfgs/default/result/radius_false_positive.pcapng.out
@@ -1,16 +1,16 @@
-Guessed flow protos: 1
+Guessed flow protos: 0
-DPI Packets (UDP): 10 (10.00 pkts/flow)
-Confidence Match by port : 1 (flows)
-Num dissector calls: 205 (205.00 diss/flow)
+DPI Packets (UDP): 1 (1.00 pkts/flow)
+Confidence DPI : 1 (flows)
+Num dissector calls: 1 (1.00 diss/flow)
LRU cache ookla: 0/0/0 (insert/search/found)
-LRU cache bittorrent: 0/3/0 (insert/search/found)
+LRU cache bittorrent: 0/0/0 (insert/search/found)
LRU cache zoom: 0/0/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/1/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/1/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)
@@ -25,4 +25,4 @@ Patricia protocols IPv6: 2/0 (search/found)
QUIC 10 7479 1
- 1 UDP [2bc6:b5ac:cb3b:676b::18]:443 -> [3dba:3762:c186:e122:89b0:5170:a86c:ecff]:53129 [proto: 188/QUIC][IP: 0/Unknown][Encrypted][Confidence: Match by port][DPI packets: 10][cat: Web/5][10 pkts/7479 bytes -> 0 pkts/0 bytes][Goodput ratio: 92/0][0.34 sec][bytes ratio: 1.000 (Upload)][IAT c2s/s2c min/avg/max/stddev: 0/0 38/0 290/0 90/0][Pkt Len c2s/s2c min/avg/max/stddev: 82/0 748/0 1292/0 549/0][Risk: ** Unidirectional Traffic **][Risk Score: 10][Risk Info: No client to server traffic][PLAIN TEXT (AESGCC20at)][Plen Bins: 20,0,0,0,0,0,20,10,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,50,0,0,0,0,0,0,0,0,0]
+ 1 UDP [2bc6:b5ac:cb3b:676b::18]:443 -> [3dba:3762:c186:e122:89b0:5170:a86c:ecff]:53129 [proto: 188/QUIC][IP: 0/Unknown][Encrypted][Confidence: DPI][DPI packets: 1][cat: Web/5][10 pkts/7479 bytes -> 0 pkts/0 bytes][Goodput ratio: 92/0][0.34 sec][bytes ratio: 1.000 (Upload)][IAT c2s/s2c min/avg/max/stddev: 0/0 38/0 290/0 90/0][Pkt Len c2s/s2c min/avg/max/stddev: 82/0 748/0 1292/0 549/0][Risk: ** Unidirectional Traffic **][Risk Score: 10][Risk Info: No client to server traffic][PLAIN TEXT (AESGCC20at)][Plen Bins: 20,0,0,0,0,0,20,10,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,50,0,0,0,0,0,0,0,0,0]