diff options
author | Ivan Nardi <12729895+IvanNardi@users.noreply.github.com> | 2022-12-10 18:32:25 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-10 18:32:25 +0100 |
commit | 8c7071e040865b3b70b98ff8d8ad18c41f3fb74c (patch) | |
tree | b52a3e84e4997d53049226611584e820767bb5b6 | |
parent | 79931b2ec7dffc88df4cdd6855d7b1ec95cca20f (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.c | 4 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 3 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 10 | ||||
-rw-r--r-- | src/lib/protocols/tls.c | 137 | ||||
-rw-r--r-- | tests/pcap/dtls_certificate_fragments.pcap | bin | 6322 -> 10633 bytes | |||
-rw-r--r-- | tests/result/dtls_certificate_fragments.pcap.out | 25 |
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 Binary files differindex 5551b5cab..869c60229 100644 --- a/tests/pcap/dtls_certificate_fragments.pcap +++ b/tests/pcap/dtls_certificate_fragments.pcap 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] |