aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Nardi <12729895+IvanNardi@users.noreply.github.com>2022-12-10 18:32:25 +0100
committerGitHub <noreply@github.com>2022-12-10 18:32:25 +0100
commit8c7071e040865b3b70b98ff8d8ad18c41f3fb74c (patch)
treeb52a3e84e4997d53049226611584e820767bb5b6
parent79931b2ec7dffc88df4cdd6855d7b1ec95cca20f (diff)
DTLS: handle (certificate) fragments (#1811)
Keep using the existing function to handle reassembling buffer: rename it from `ndpi_search_tls_tcp_memory` to `ndpi_search_tls_memory` and make it "transport" agnostic
-rw-r--r--example/reader_util.c4
-rw-r--r--src/include/ndpi_typedefs.h3
-rw-r--r--src/lib/ndpi_main.c10
-rw-r--r--src/lib/protocols/tls.c137
-rw-r--r--tests/pcap/dtls_certificate_fragments.pcapbin6322 -> 10633 bytes
-rw-r--r--tests/result/dtls_certificate_fragments.pcap.out25
6 files changed, 118 insertions, 61 deletions
diff --git a/example/reader_util.c b/example/reader_util.c
index 5b85c4784..2e285a7f1 100644
--- a/example/reader_util.c
+++ b/example/reader_util.c
@@ -1151,7 +1151,9 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
inet_ntop(AF_INET, &flow->ndpi_flow->protos.natpmp.external_address.ipv4, &flow->natpmp.ip[0], sizeof(flow->natpmp.ip));
}
/* DISCORD */
- else if(is_ndpi_proto(flow, NDPI_PROTOCOL_DISCORD) && !is_ndpi_proto(flow, NDPI_PROTOCOL_TLS) &&
+ else if(is_ndpi_proto(flow, NDPI_PROTOCOL_DISCORD) &&
+ !is_ndpi_proto(flow, NDPI_PROTOCOL_TLS) &&
+ !is_ndpi_proto(flow, NDPI_PROTOCOL_DTLS) &&
flow->ndpi_flow->protos.discord.client_ip[0] != '\0') {
flow->info_type = INFO_GENERIC;
ndpi_snprintf(flow->info, sizeof(flow->info), "Client IP: %s",
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index ad33eb5e6..1e75e5ee4 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -709,8 +709,6 @@ struct ndpi_flow_tcp_struct {
u_int32_t telnet_stage:2; // 0 - 2
struct {
- message_t message[2]; /* Directions */
-
/* NDPI_PROTOCOL_TLS */
u_int8_t app_data_seen[2];
u_int8_t num_tls_blocks;
@@ -1384,6 +1382,7 @@ struct ndpi_flow_struct {
} stun;
struct {
+ message_t message[2]; /* Directions */
u_int8_t certificate_processed:1, _pad:7;
} tls_quic; /* Used also by DTLS and POPS/IMAPS/SMTPS/FTPS */
diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c
index 7880aeae3..a3c017930 100644
--- a/src/lib/ndpi_main.c
+++ b/src/lib/ndpi_main.c
@@ -5092,12 +5092,10 @@ void ndpi_free_flow_data(struct ndpi_flow_struct* flow) {
ndpi_free(flow->protos.tls_quic.encrypted_sni.esni);
}
- if(flow->l4_proto == IPPROTO_TCP) {
- if(flow->l4.tcp.tls.message[0].buffer)
- ndpi_free(flow->l4.tcp.tls.message[0].buffer);
- if(flow->l4.tcp.tls.message[1].buffer)
- ndpi_free(flow->l4.tcp.tls.message[1].buffer);
- }
+ if(flow->tls_quic.message[0].buffer)
+ ndpi_free(flow->tls_quic.message[0].buffer);
+ if(flow->tls_quic.message[1].buffer)
+ ndpi_free(flow->tls_quic.message[1].buffer);
if(flow->l4_proto == IPPROTO_UDP) {
if(flow->l4.udp.quic_reasm_buf)
diff --git a/src/lib/protocols/tls.c b/src/lib/protocols/tls.c
index 05b03d98c..6bc6bf059 100644
--- a/src/lib/protocols/tls.c
+++ b/src/lib/protocols/tls.c
@@ -146,18 +146,18 @@ static u_int32_t __get_master(struct ndpi_detection_module_struct *ndpi_struct,
/* **************************************** */
-int ndpi_search_tls_tcp_memory(struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow) {
- struct ndpi_packet_struct *packet = &ndpi_struct->packet;
- message_t *message = &flow->l4.tcp.tls.message[packet->packet_direction];
+static int ndpi_search_tls_memory(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow,
+ const u_int8_t *payload,
+ u_int16_t payload_len,
+ u_int32_t seq,
+ message_t *message) {
u_int avail_bytes;
- /* TCP */
#ifdef DEBUG_TLS_MEMORY
- printf("[TLS Mem] Handling TCP/TLS flow [payload_len: %u][buffer_len: %u][direction: %u]\n",
- packet->payload_packet_len,
- message->buffer_len,
- packet->packet_direction);
+ printf("[TLS Mem] Handling TLS flow [payload_len: %u][buffer_len: %u]\n",
+ payload_len,
+ message->buffer_len);
#endif
if(message->buffer == NULL) {
@@ -175,8 +175,8 @@ int ndpi_search_tls_tcp_memory(struct ndpi_detection_module_struct *ndpi_struct,
avail_bytes = message->buffer_len - message->buffer_used;
- if(avail_bytes < packet->payload_packet_len) {
- u_int new_len = message->buffer_len + packet->payload_packet_len - avail_bytes + 1;
+ if(avail_bytes < payload_len) {
+ u_int new_len = message->buffer_len + payload_len - avail_bytes + 1;
void *newbuf = ndpi_realloc(message->buffer,
message->buffer_len, new_len);
if(!newbuf) return -1;
@@ -190,35 +190,33 @@ int ndpi_search_tls_tcp_memory(struct ndpi_detection_module_struct *ndpi_struct,
avail_bytes = message->buffer_len - message->buffer_used;
}
- if(packet->payload_packet_len > 0 && avail_bytes >= packet->payload_packet_len) {
+ if(payload_len > 0 && avail_bytes >= payload_len) {
u_int8_t ok = 0;
if(message->next_seq != 0) {
- if(ntohl(packet->tcp->seq) == message->next_seq)
+ if(seq == message->next_seq)
ok = 1;
} else
ok = 1;
if(ok) {
memcpy(&message->buffer[message->buffer_used],
- packet->payload, packet->payload_packet_len);
+ payload, payload_len);
- message->buffer_used += packet->payload_packet_len;
+ message->buffer_used += payload_len;
#ifdef DEBUG_TLS_MEMORY
- printf("[TLS Mem] Copied data to buffer [%u/%u bytes][direction: %u][tcp_seq: %u][next: %u]\n",
+ printf("[TLS Mem] Copied data to buffer [%u/%u bytes][tcp_seq: %u][next: %u]\n",
message->buffer_used, message->buffer_len,
- packet->packet_direction,
- ntohl(packet->tcp->seq),
- ntohl(packet->tcp->seq)+packet->payload_packet_len);
+ seq,
+ seq + payload_len);
#endif
- message->next_seq = ntohl(packet->tcp->seq)+packet->payload_packet_len;
+ message->next_seq = seq + payload_len;
} else {
#ifdef DEBUG_TLS_MEMORY
- printf("[TLS Mem] Skipping packet [%u bytes][direction: %u][tcp_seq: %u][expected next: %u]\n",
+ printf("[TLS Mem] Skipping packet [%u bytes][tcp_seq: %u][expected next: %u]\n",
message->buffer_len,
- packet->packet_direction,
- ntohl(packet->tcp->seq),
+ seq,
message->next_seq);
#endif
}
@@ -958,8 +956,8 @@ static int ndpi_search_tls_tcp(struct ndpi_detection_module_struct *ndpi_struct,
message_t *message;
#ifdef DEBUG_TLS_MEMORY
- printf("[TLS Mem] ndpi_search_tls_tcp() Processing new packet [payload_packet_len: %u]\n",
- packet->payload_packet_len);
+ printf("[TLS Mem] ndpi_search_tls_tcp() Processing new packet [payload_packet_len: %u][Dir: %u]\n",
+ packet->payload_packet_len, packet->packet_direction);
#endif
/* This function is also called by "extra dissection" data path. Unfortunately,
@@ -974,9 +972,11 @@ static int ndpi_search_tls_tcp(struct ndpi_detection_module_struct *ndpi_struct,
return 1; /* Keep working */
}
- if(ndpi_search_tls_tcp_memory(ndpi_struct, flow) == -1)
+ message = &flow->tls_quic.message[packet->packet_direction];
+ if(ndpi_search_tls_memory(ndpi_struct, flow, packet->payload,
+ packet->payload_packet_len, ntohl(packet->tcp->seq),
+ message) == -1)
return 0; /* Error -> stop */
- message = &flow->l4.tcp.tls.message[packet->packet_direction];
/* Valid TLS Content Types:
https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-5 */
@@ -1153,10 +1153,11 @@ static int ndpi_search_tls_tcp(struct ndpi_detection_module_struct *ndpi_struct,
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;
- u_int32_t handshake_len;
+ u_int32_t handshake_len, handshake_frag_off, handshake_frag_len;
u_int16_t p_len, processed;
const u_int8_t *p;
u_int8_t no_dtls = 0, change_cipher_found = 0;
+ message_t *message = NULL;
#ifdef DEBUG_TLS
printf("[TLS] %s()\n", __FUNCTION__);
@@ -1204,19 +1205,73 @@ static int ndpi_search_tls_udp(struct ndpi_detection_module_struct *ndpi_struct,
break;
}
/* TODO: handle (certificate) fragments */
- if(block_len > 16) {
+ if(block_len > 24) {
handshake_len = (block[14] << 16) + (block[15] << 8) + block[16];
- if((handshake_len + 12) != block_len) {
+ handshake_frag_off = (block[19] << 16) + (block[20] << 8) + block[21];
+ handshake_frag_len = (block[22] << 16) + (block[23] << 8) + block[24];
+ message = &flow->tls_quic.message[packet->packet_direction];
+
+
+#ifdef DEBUG_TLS
+ printf("[TLS] DTLS frag off %d len %d\n", handshake_frag_off, handshake_frag_len);
+#endif
+
+ if((handshake_len + 12) == block_len) {
+ packet->payload = &block[13];
+ packet->payload_packet_len = block_len;
+ processTLSBlock(ndpi_struct, flow);
+ } else if(handshake_len + 12 > block_len) {
+ int rc;
+
+#ifdef DEBUG_TLS
+ printf("[TLS] DTLS fragment off %d len %d\n", handshake_frag_off, handshake_frag_len);
+#endif
+ if(handshake_frag_len + 12 > block_len) {
+#ifdef DEBUG_TLS
+ printf("[TLS] DTLS fragment invalid len %d + 12 > %d\n", handshake_frag_len, block_len);
+#endif
+ no_dtls = 1;
+ break;
+ }
+
+ if(handshake_frag_off == 0) {
+ rc = ndpi_search_tls_memory(ndpi_struct, flow, &block[13],
+ handshake_frag_len + 12,
+ handshake_frag_off, message);
+ } else {
+ rc = ndpi_search_tls_memory(ndpi_struct, flow, &block[13 + 12],
+ handshake_frag_len,
+ handshake_frag_off + 12, message);
+ }
+ if(rc == -1) {
+ no_dtls = 1;
+ break;
+ }
+#ifdef DEBUG_TLS
+ printf("[TLS] DTLS reassembled len %d vs %d\n",
+ message->buffer_used, handshake_len + 12);
+#endif
+
+ if(handshake_len + 12 == message->buffer_used) {
+ packet->payload = message->buffer;
+ packet->payload_packet_len = message->buffer_used;
+ processTLSBlock(ndpi_struct, flow);
+
+ ndpi_free(message->buffer);
+ memset(message, '\0', sizeof(*message));
+ message = NULL;
+ } else {
+ /* No break, next fragments might be in the same packet */
+ }
+
+ } else {
#ifdef DEBUG_TLS
- printf("[TLS] DTLS invalid handshake_len %d, %d)\n",
+ printf("[TLS] DTLS invalid handshake_len %d, %d\n",
handshake_len, block_len);
#endif
no_dtls = 1;
break;
}
- packet->payload = &block[13];
- packet->payload_packet_len = block_len;
- processTLSBlock(ndpi_struct, flow);
}
} else if(block[0] == 0x14) {
/* Change-cipher-spec: any subsequent block might be encrypted */
@@ -1239,7 +1294,7 @@ static int ndpi_search_tls_udp(struct ndpi_detection_module_struct *ndpi_struct,
processed += block_len + 13;
}
- if(processed != p_len) {
+ if(processed != p_len && message == NULL /* No pending reassembler */) {
#ifdef DEBUG_TLS
printf("[TLS] DTLS invalid processed len %d/%d (%d)\n", processed, p_len, change_cipher_found);
#endif
@@ -1280,12 +1335,12 @@ void switch_extra_dissection_to_tls(struct ndpi_detection_module_struct *ndpi_st
#endif
/* Reset reassemblers */
- if(flow->l4.tcp.tls.message[0].buffer)
- ndpi_free(flow->l4.tcp.tls.message[0].buffer);
- memset(&flow->l4.tcp.tls.message[0], '\0', sizeof(flow->l4.tcp.tls.message[0]));
- if(flow->l4.tcp.tls.message[1].buffer)
- ndpi_free(flow->l4.tcp.tls.message[1].buffer);
- memset(&flow->l4.tcp.tls.message[1], '\0', sizeof(flow->l4.tcp.tls.message[1]));
+ 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]));
tlsInitExtraPacketProcessing(ndpi_struct, flow);
}
diff --git a/tests/pcap/dtls_certificate_fragments.pcap b/tests/pcap/dtls_certificate_fragments.pcap
index 5551b5cab..869c60229 100644
--- a/tests/pcap/dtls_certificate_fragments.pcap
+++ b/tests/pcap/dtls_certificate_fragments.pcap
Binary files differ
diff --git a/tests/result/dtls_certificate_fragments.pcap.out b/tests/result/dtls_certificate_fragments.pcap.out
index 970818d21..ed275fa88 100644
--- a/tests/result/dtls_certificate_fragments.pcap.out
+++ b/tests/result/dtls_certificate_fragments.pcap.out
@@ -1,29 +1,32 @@
Guessed flow protos: 0
-DPI Packets (UDP): 4 (4.00 pkts/flow)
-Confidence DPI : 1 (flows)
-Num dissector calls: 2 (2.00 diss/flow)
+DPI Packets (UDP): 9 (4.50 pkts/flow)
+Confidence DPI : 2 (flows)
+Num dissector calls: 4 (2.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/3/0 (insert/search/found)
+LRU cache tls_cert: 0/6/0 (insert/search/found)
LRU cache mining: 0/0/0 (insert/search/found)
LRU cache msteams: 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 host: 3/1 (search/found)
+Automa domain: 3/0 (search/found)
+Automa tls cert: 1/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: 4/0 (search/found)
Patricia risk: 0/0 (search/found)
-Patricia protocols: 1/1 (search/found)
+Patricia protocols: 2/2 (search/found)
DTLS 20 5978 1
+Discord 6 4215 1
JA3 Host Stats:
IP Address # JA3C
- 1 10.186.198.149 1
+ 1 192.168.1.26 1
+ 2 10.186.198.149 1
- 1 UDP 10.186.198.149:39347 <-> 35.210.59.134:44443 [proto: 30/DTLS][IP: 284/GoogleCloud][Encrypted][Confidence: DPI][cat: Web/5][11 pkts/2624 bytes <-> 9 pkts/3354 bytes][Goodput ratio: 82/89][2.92 sec][bytes ratio: -0.122 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/0 324/76 2179/186 659/75][Pkt Len c2s/s2c min/avg/max/stddev: 167/90 239/373 416/1454 97/388][Risk: ** Weak TLS Cipher **** TLS (probably) Not Carrying HTTPS **** Missing SNI TLS Extn **][Risk Score: 160][Risk Info: No ALPN / Cipher TLS_RSA_WITH_AES_256_CBC_SHA][DTLSv1.2][JA3C: 3c3d129780d0066cd8936a6291a8d44f][JA3S: d45798bc098cd930de7eb2f5f866e994 (WEAK)][Firefox][Cipher: TLS_RSA_WITH_AES_256_CBC_SHA][PLAIN TEXT (Opera Software ASA1)][Plen Bins: 0,5,0,35,5,10,10,0,10,10,5,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,5,0,0,0]
+ 1 UDP 10.186.198.149:39347 <-> 35.210.59.134:44443 [proto: 30/DTLS][IP: 284/GoogleCloud][Encrypted][Confidence: DPI][cat: Web/5][11 pkts/2624 bytes <-> 9 pkts/3354 bytes][Goodput ratio: 82/89][2.92 sec][bytes ratio: -0.122 (Mixed)][IAT c2s/s2c min/avg/max/stddev: 0/0 324/76 2179/186 659/75][Pkt Len c2s/s2c min/avg/max/stddev: 167/90 239/373 416/1454 97/388][Risk: ** Weak TLS Cipher **** TLS (probably) Not Carrying HTTPS **** Missing SNI TLS Extn **** TLS Cert About To Expire **][Risk Score: 210][Risk Info: No ALPN / Cipher TLS_RSA_WITH_AES_256_CBC_SHA / 25/Apr/2019 09:58:06 - 25/May/2019 09:58:06][DTLSv1.2][JA3C: 3c3d129780d0066cd8936a6291a8d44f][ServerNames: *.samsungmax.com,*.opera-mini.net][JA3S: d45798bc098cd930de7eb2f5f866e994 (WEAK)][Issuer: C=NO, ST=Oslo, L=Oslo, O=Opera Software ASA, OU=Opera Max, CN=Opera Max CA][Subject: C=NO, ST=Oslo, L=Oslo, O=Opera Software ASA, OU=Opera Max, CN=*.opera-mini.net, C=NO, ST=Oslo, L=Oslo, O=Opera Software ASA, OU=Opera Max, CN=Opera Max CA][Certificate SHA-1: 2F:5F:33:93:DE:4E:8B:EA:87:19:43:1A:7A:28:C2:33:FB:10:B3:A0][Firefox][Validity: 2019-04-25 09:58:06 - 2019-05-25 09:58:06][Cipher: TLS_RSA_WITH_AES_256_CBC_SHA][PLAIN TEXT (Opera Software ASA1)][Plen Bins: 0,5,0,35,5,10,10,0,10,10,5,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,5,0,0,0]
+ 2 UDP 192.168.1.26:43594 <-> 104.153.87.149:50001 [proto: 30.58/DTLS.Discord][IP: 58/Discord][Encrypted][Confidence: DPI][cat: Collaborative/15][3 pkts/1015 bytes <-> 3 pkts/3200 bytes][Goodput ratio: 88/96][0.13 sec][bytes ratio: -0.518 (Download)][IAT c2s/s2c min/avg/max/stddev: 29/44 44/22 59/44 15/22][Pkt Len c2s/s2c min/avg/max/stddev: 197/621 338/1067 621/1322 200/316][Risk: ** TLS (probably) Not Carrying HTTPS **** Missing SNI TLS Extn **][Risk Score: 60][Risk Info: No ALPN][DTLSv1.2][JA3C: 681eb4fb79ccb6d60d35fa502c279d42][ServerNames: *.discord.gg,discord.gg][JA3S: 201fdaa63db9a086f36651aa4cfd0819][Issuer: C=GB, ST=Greater Manchester, L=Salford, O=Sectigo Limited, CN=Sectigo RSA Domain Validation Secure Server CA][Subject: CN=*.discord.gg][Certificate SHA-1: 0C:A2:45:E6:4A:06:B0:31:C6:BF:B6:C5:1B:AE:A0:A3:8E:41:B2:3C][Validity: 2020-03-26 00:00:00 - 2022-06-28 00:00:00][Cipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256][PLAIN TEXT (Greater Manchester1)][Plen Bins: 0,0,0,0,33,0,0,0,0,0,0,0,0,0,0,0,0,0,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,16,0,0,0,0,0,0,0]