aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Deri <deri@ntop.org>2022-12-29 19:38:25 +0100
committerLuca Deri <deri@ntop.org>2022-12-29 19:38:25 +0100
commit8f91b8ba72e61eb15a3fdfcddd6339b2fae341be (patch)
treebb20eebc202f69a6fd95146191e718e8249c168f
parent560280e6f082d22e6a9de8e537b7876bacf8d072 (diff)
Implemented EDNS(0) support in DNS dissector
Improved DNS dissection
-rw-r--r--src/include/ndpi_typedefs.h2
-rw-r--r--src/lib/ndpi_main.c4
-rw-r--r--src/lib/ndpi_utils.c8
-rw-r--r--src/lib/protocols/dns.c229
-rw-r--r--tests/result/fuzz-2006-06-26-2594.pcap.out2
-rw-r--r--tests/result/malformed_dns.pcap.out2
6 files changed, 191 insertions, 56 deletions
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index d9de63d5e..16612ce87 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -1381,7 +1381,7 @@ struct ndpi_flow_struct {
/* the only fields useful for nDPI and ntopng */
struct {
u_int8_t num_queries, num_answers, reply_code, is_query;
- u_int16_t query_type, query_class, rsp_type;
+ u_int16_t query_type, query_class, rsp_type, edns0_udp_payload_size;
ndpi_ip_addr_t rsp_addr; /* The first address in a DNS response packet (A and AAAA) */
char ptr_domain_name[64 /* large enough but smaller than { } tls */];
} dns;
diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c
index 95d880dcb..739010025 100644
--- a/src/lib/ndpi_main.c
+++ b/src/lib/ndpi_main.c
@@ -6447,8 +6447,10 @@ ndpi_protocol ndpi_detection_process_packet(struct ndpi_detection_module_struct
struct ndpi_packet_struct *packet;
NDPI_SELECTION_BITMASK_PROTOCOL_SIZE ndpi_selection_packet;
u_int32_t num_calls = 0;
- ndpi_protocol ret = { 0 };
+ ndpi_protocol ret;
+ memset(&ret, 0, sizeof(ret));
+
if(!flow || !ndpi_str)
return(ret);
diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c
index 990aef9bd..12313a0f7 100644
--- a/src/lib/ndpi_utils.c
+++ b/src/lib/ndpi_utils.c
@@ -2355,8 +2355,9 @@ static u_int8_t ndpi_check_hostname_risk_exception(struct ndpi_detection_module_
if(automa->ac_automa) {
AC_TEXT_t ac_input_text;
- AC_REP_t match = {0};
-
+ AC_REP_t match;
+
+ memset(&match, 0, sizeof(match));
ac_input_text.astring = hostname, ac_input_text.length = strlen(hostname);
ac_input_text.option = 0;
@@ -2666,8 +2667,9 @@ u_int8_t is_a_common_alpn(struct ndpi_detection_module_struct *ndpi_str,
if(automa->ac_automa) {
AC_TEXT_t ac_input_text;
- AC_REP_t match = {0};
+ AC_REP_t match;
+ memset(&match, 0, sizeof(match));
ac_input_text.astring = (char*)alpn_to_check, ac_input_text.length = alpn_to_check_len;
ac_input_text.option = 0;
diff --git a/src/lib/protocols/dns.c b/src/lib/protocols/dns.c
index 298f0967f..7df825f8b 100644
--- a/src/lib/protocols/dns.c
+++ b/src/lib/protocols/dns.c
@@ -29,7 +29,7 @@
#define FLAGS_MASK 0x8000
-// #define DNS_DEBUG 1
+/* #define DNS_DEBUG 1 */
#define DNS_PORT 53
#define LLMNR_PORT 5355
@@ -202,7 +202,7 @@ static char* dns_error_code2string(u_int16_t error_code, char *buf, u_int buf_le
case 7: return((char*)"XRRSET");
case 8: return((char*)"NOTAUTH");
case 9: return((char*)"NOTZONE");
-
+
default:
snprintf(buf, buf_len, "%u", error_code);
return(buf);
@@ -217,7 +217,7 @@ static u_int8_t ndpi_grab_dns_name(struct ndpi_packet_struct *packet,
u_int *_hostname_len) {
u_int8_t hostname_is_valid = 1;
u_int j = 0;
-
+
max_len--;
while((j < max_len)
@@ -255,12 +255,12 @@ static u_int8_t ndpi_grab_dns_name(struct ndpi_packet_struct *packet,
}
_hostname[j] = '\0', *_hostname_len = j;
-
+
return(hostname_is_valid);
}
/* *********************************************** */
-
+
static int search_valid_dns(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
struct ndpi_dns_packet_header *dns_header,
@@ -331,7 +331,7 @@ static int search_valid_dns(struct ndpi_detection_module_struct *ndpi_struct,
x++;
}
}
-
+
flow->protos.dns.reply_code = dns_header->flags & 0x0F;
if(flow->protos.dns.reply_code != 0) {
@@ -342,35 +342,54 @@ static int search_valid_dns(struct ndpi_detection_module_struct *ndpi_struct,
ndpi_set_risk(ndpi_struct, flow, NDPI_ERROR_CODE_DETECTED, str);
} else {
if(ndpi_isset_risk(ndpi_struct, flow, NDPI_SUSPICIOUS_DGA_DOMAIN)) {
- ndpi_set_risk(ndpi_struct, flow, NDPI_RISKY_DOMAIN, "DGA Name Query with no Error Code");
+ ndpi_set_risk(ndpi_struct, flow, NDPI_RISKY_DOMAIN, "DGA Name Query with no Error Code");
}
}
-
+
if((dns_header->num_queries > 0) && (dns_header->num_queries <= NDPI_MAX_DNS_REQUESTS) /* Don't assume that num_queries must be zero */
&& ((((dns_header->num_answers > 0) && (dns_header->num_answers <= NDPI_MAX_DNS_REQUESTS))
|| ((dns_header->authority_rrs > 0) && (dns_header->authority_rrs <= NDPI_MAX_DNS_REQUESTS))
|| ((dns_header->additional_rrs > 0) && (dns_header->additional_rrs <= NDPI_MAX_DNS_REQUESTS))))
) {
/* This is a good reply: we dissect it both for request and response */
+
+ if(dns_header->num_queries > 0) {
+ u_int16_t rsp_type;
+ u_int16_t num;
- /* Leave the statement below commented necessary in case of call to ndpi_get_partial_detection() */
- x++;
+ for(num = 0; num < dns_header->num_queries; num++) {
+ u_int16_t data_len;
- if(x < packet->payload_packet_len && packet->payload[x] != '\0') {
- while((x < packet->payload_packet_len)
- && (packet->payload[x] != '\0')) {
- x++;
- }
+ if((x+6) >= packet->payload_packet_len) {
+ break;
+ }
- x++;
- }
+ if((data_len = getNameLength(x, packet->payload,
+ packet->payload_packet_len)) == 0) {
+ break;
+ } else
+ x += data_len;
+
+ if((x+8) >= packet->payload_packet_len) {
+ break;
+ }
+
+ rsp_type = get16(&x, packet->payload);
+
+#ifdef DNS_DEBUG
+ printf("[DNS] [response (query)] response_type=%d\n", rsp_type);
+#endif
- x += 4;
+ /* here x points to the response "class" field */
+ x += 2; /* Skip class */
+ }
+ }
if(dns_header->num_answers > 0) {
u_int16_t rsp_type;
u_int32_t rsp_ttl;
u_int16_t num;
+ u_int8_t found = 0;
for(num = 0; num < dns_header->num_answers; num++) {
u_int16_t data_len;
@@ -393,61 +412,171 @@ static int search_valid_dns(struct ndpi_detection_module_struct *ndpi_struct,
rsp_ttl = ntohl(*((u_int32_t*)&packet->payload[x+2]));
if(rsp_ttl == 0)
- ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_SUSPICIOUS_TRAFFIC, "DNS Record with zero TTL");
+ ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_SUSPICIOUS_TRAFFIC, "DNS Record with zero TTL");
#ifdef DNS_DEBUG
printf("[DNS] TTL = %u\n", rsp_ttl);
printf("[DNS] [response] response_type=%d\n", rsp_type);
#endif
- ndpi_check_dns_type(ndpi_struct, flow, rsp_type);
-
- flow->protos.dns.rsp_type = rsp_type;
-
- /* here x points to the response "class" field */
+ if(found == 0) {
+ ndpi_check_dns_type(ndpi_struct, flow, rsp_type);
+ flow->protos.dns.rsp_type = rsp_type;
+ }
+
+ /* x points to the response "class" field */
if((x+12) <= packet->payload_packet_len) {
x += 6;
data_len = get16(&x, packet->payload);
if((x + data_len) <= packet->payload_packet_len) {
- // printf("[rsp_type: %u][data_len: %u]\n", rsp_type, data_len);
+#ifdef DNS_DEBUG
+ printf("[DNS] [rsp_type: %u][data_len: %u]\n", rsp_type, data_len);
+#endif
if(rsp_type == 0x05 /* CNAME */) {
- x += data_len;
- continue; /* Skip CNAME */
- }
-
- if(rsp_type == 0x0C /* PTR */) {
+ ;
+ } else if(rsp_type == 0x0C /* PTR */) {
u_int16_t ptr_len = (packet->payload[x-2] << 8) + packet->payload[x-1];
if((x + ptr_len) <= packet->payload_packet_len) {
- u_int len;
-
- ndpi_grab_dns_name(packet, &x,
- flow->protos.dns.ptr_domain_name,
+ if(found == 0) {
+ u_int len;
+
+ ndpi_grab_dns_name(packet, &x,
+ flow->protos.dns.ptr_domain_name,
sizeof(flow->protos.dns.ptr_domain_name), &len);
+ found = 1;
+ }
}
} else if((((rsp_type == 0x1) && (data_len == 4)) /* A */
|| ((rsp_type == 0x1c) && (data_len == 16)) /* AAAA */
)) {
- memcpy(&flow->protos.dns.rsp_addr, packet->payload + x, data_len);
+ if(found == 0) {
+ memcpy(&flow->protos.dns.rsp_addr, packet->payload + x, data_len);
+ found = 1;
+ }
}
+
+ x += data_len;
}
}
- break;
+ if(found && (dns_header->additional_rrs == 0)) {
+ /*
+ In case we have RR we need to iterate
+ all the answers and not just consider the
+ first one as we need to properly move 'x'
+ to the right offset
+ */
+ break;
+ }
}
}
- if((flow->detected_protocol_stack[0] == NDPI_PROTOCOL_DNS)
- || (flow->detected_protocol_stack[1] == NDPI_PROTOCOL_DNS)) {
- /* Request already set the protocol */
- // flow->extra_packets_func = NULL; /* Removed so the caller can keep dissecting DNS flows */
- } else {
- /* We missed the request */
- u_int16_t s_port = packet->udp ? ntohs(packet->udp->source) : ntohs(packet->tcp->source);
+ if(dns_header->additional_rrs > 0) {
+ /*
+ Dissect the rest of the packet only if there are
+ additional_rrs as we need to check fo EDNS(0)
+
+ In this case we need to go through the whole packet
+ as we need to update the 'x' offset
+ */
+ if(dns_header->authority_rrs > 0) {
+ u_int16_t rsp_type;
+ u_int32_t rsp_ttl;
+ u_int16_t num;
+
+ for(num = 0; num < dns_header->authority_rrs; num++) {
+ u_int16_t data_len;
+
+ if((x+6) >= packet->payload_packet_len) {
+ break;
+ }
+
+ if((data_len = getNameLength(x, packet->payload,
+ packet->payload_packet_len)) == 0) {
+ break;
+ } else
+ x += data_len;
+
+ if((x+8) >= packet->payload_packet_len) {
+ break;
+ }
+
+ rsp_type = get16(&x, packet->payload);
+ rsp_ttl = ntohl(*((u_int32_t*)&packet->payload[x+2]));
+
+#ifdef DNS_DEBUG
+ printf("[DNS] [RRS response] response_type=%d\n", rsp_type);
+#endif
+
+ /* here x points to the response "class" field */
+ if((x+12) <= packet->payload_packet_len) {
+ x += 6;
+ data_len = get16(&x, packet->payload);
+
+ if((x + data_len) <= packet->payload_packet_len)
+ x += data_len;
+ }
+ }
+ }
+
+ if(dns_header->additional_rrs > 0) {
+ u_int16_t rsp_type;
+ u_int16_t num;
+
+ for(num = 0; num < dns_header->additional_rrs; num++) {
+ u_int16_t data_len;
+
+ if((x+6) > packet->payload_packet_len) {
+ break;
+ }
+
+ if((data_len = getNameLength(x, packet->payload, packet->payload_packet_len)) == 0) {
+ break;
+ } else
+ x += data_len;
+
+ if((x+10) > packet->payload_packet_len) {
+ break;
+ }
+
+ rsp_type = get16(&x, packet->payload);
+
+#ifdef DNS_DEBUG
+ printf("[DNS] [RR response] response_type=%d\n", rsp_type);
+#endif
+
+ if(rsp_type == 41 /* OPT */) {
+ /* https://en.wikipedia.org/wiki/Extension_Mechanisms_for_DNS */
+ flow->protos.dns.edns0_udp_payload_size = ntohs(*((u_int16_t*)&packet->payload[x])); /* EDNS(0) */
- ndpi_set_detected_protocol(ndpi_struct, flow, checkPort(s_port), NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI);
+#ifdef DNS_DEBUG
+ printf("[DNS] [response] edns0_udp_payload_size: %u\n", flow->protos.dns.edns0_udp_payload_size);
+#endif
+ x += 6;
+ } else {
+ x += 6;
+ }
+
+ if((data_len = getNameLength(x, packet->payload, packet->payload_packet_len)) == 0) {
+ break;
+ } else
+ x += data_len;
+ }
+ }
+
+ if((flow->detected_protocol_stack[0] == NDPI_PROTOCOL_DNS)
+ || (flow->detected_protocol_stack[1] == NDPI_PROTOCOL_DNS)) {
+ /* Request already set the protocol */
+ // flow->extra_packets_func = NULL; /* Removed so the caller can keep dissecting DNS flows */
+ } else {
+ /* We missed the request */
+ u_int16_t s_port = packet->udp ? ntohs(packet->udp->source) : ntohs(packet->tcp->source);
+
+ ndpi_set_detected_protocol(ndpi_struct, flow, checkPort(s_port), NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI);
+ }
}
}
}
@@ -547,7 +676,7 @@ static void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, st
for(idx=0; idx<name_len; idx++)
printf("%c", packet->payload[i+1+idx]);
-
+
printf("]\n");
}
}
@@ -581,7 +710,7 @@ static void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, st
ndpi_hostname_sni_set(flow, (const u_int8_t *)_hostname, len);
if (hostname_is_valid == 0)
- ndpi_set_risk(ndpi_struct, flow, NDPI_INVALID_CHARACTERS, NULL);
+ ndpi_set_risk(ndpi_struct, flow, NDPI_INVALID_CHARACTERS, NULL);
if(len > 0) {
ndpi_protocol_match_result ret_match;
@@ -652,13 +781,15 @@ static void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, st
|| (flow->detected_protocol_stack[1] == NDPI_PROTOCOL_DNS)) {
/* TODO: add support to RFC6891 to avoid some false positives */
if((packet->udp != NULL)
- && (packet->payload_packet_len > PKT_LEN_ALERT)) {
+ && (packet->payload_packet_len > PKT_LEN_ALERT)
+ && (packet->payload_packet_len > flow->protos.dns.edns0_udp_payload_size)
+ ) {
char str[48];
snprintf(str, sizeof(str), "%u Bytes DNS Packet", packet->payload_packet_len);
ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_LARGE_PACKET, str);
}
-
+
if(packet->iph != NULL) {
/* IPv4 */
u_int8_t flags = ((u_int8_t*)packet->iph)[6];
@@ -674,7 +805,7 @@ static void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, st
if(ip6_hdr->ip6_un1_nxt == 0x2C /* Next Header: Fragment Header for IPv6 (44) */) {
ndpi_set_risk(ndpi_struct, flow, NDPI_DNS_FRAGMENTED, NULL);
- }
+ }
}
}
}
diff --git a/tests/result/fuzz-2006-06-26-2594.pcap.out b/tests/result/fuzz-2006-06-26-2594.pcap.out
index 3b1a8963c..4a167174b 100644
--- a/tests/result/fuzz-2006-06-26-2594.pcap.out
+++ b/tests/result/fuzz-2006-06-26-2594.pcap.out
@@ -96,7 +96,7 @@ SIP 85 39540 15
60 UDP 192.168.1.2:2810 -> 192.168.1.1:53 [proto: 5/DNS][IP: 0/Unknown][ClearText][Confidence: DPI][cat: Network/14][3 pkts/258 bytes -> 0 pkts/0 bytes][Goodput ratio: 51/0][4.01 sec][Hostname/SNI: _sip._udp.sip.nybercity.dk][::][Risk: ** Unidirectional Traffic **][Risk Score: 10][Risk Info: No server to client traffic][PLAIN TEXT (Mybercity)][Plen Bins: 0,100,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]
61 UDP 192.168.1.2:2814 -> 192.168.1.1:53 [proto: 5/DNS][IP: 0/Unknown][ClearText][Confidence: DPI][cat: Network/14][3 pkts/258 bytes -> 0 pkts/0 bytes][Goodput ratio: 51/0][9.01 sec][Hostname/SNI: _sib._udp.sip.cybercity.dk][::][Risk: ** Malformed Packet **** Unidirectional Traffic **][Risk Score: 20][Risk Info: No server to client traffic / Invalid DNS Query Lenght][PLAIN TEXT (cybercity)][Plen Bins: 0,100,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]
62 UDP 192.168.1.2:138 -> 192.168.1.251:138 [proto: 10.16/NetBIOS.SMBv1][IP: 0/Unknown][ClearText][Confidence: DPI][cat: System/18][1 pkts/243 bytes -> 0 pkts/0 bytes][Goodput ratio: 82/0][< 1 sec][Risk: ** Unsafe Protocol **** Unidirectional Traffic **][Risk Score: 20][Risk Info: No server to client traffic][Plen Bins: 0,0,0,0,0,0,100,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]
- 63 UDP 192.168.1.2:2719 <-> 192.168.1.1:53 [proto: 5/DNS][IP: 0/Unknown][ClearText][Confidence: DPI][cat: Network/14][1 pkts/75 bytes <-> 1 pkts/168 bytes][Goodput ratio: 43/75][1.01 sec][147.234.1.253][Risk: ** Malformed Packet **][Risk Score: 10][Risk Info: Invalid DNS Query Lenght][PLAIN TEXT (ecitele)][Plen Bins: 0,50,0,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]
+ 63 UDP 192.168.1.2:2719 <-> 192.168.1.1:53 [proto: 5/DNS][IP: 0/Unknown][ClearText][Confidence: DPI][cat: Network/14][1 pkts/75 bytes <-> 1 pkts/168 bytes][Goodput ratio: 43/75][1.01 sec][::][Risk: ** Malformed Packet **][Risk Score: 10][Risk Info: Invalid DNS Query Lenght][PLAIN TEXT (ecitele)][Plen Bins: 0,50,0,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]
64 UDP 192.168.1.41:138 -> 192.168.1.255:394 [proto: 10/NetBIOS][IP: 0/Unknown][ClearText][Confidence: Match by port][cat: System/18][1 pkts/243 bytes -> 0 pkts/0 bytes][Goodput ratio: 82/0][< 1 sec][PLAIN TEXT (MEBECDBDBDBCACACACACACACACACACA)][Plen Bins: 0,0,0,0,0,0,100,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]
65 UDP 81.168.1.2:30000 -> 212.242.33.36:40392 [proto: 87/RTP][IP: 0/Unknown][ClearText][Confidence: DPI][cat: Media/1][1 pkts/214 bytes -> 0 pkts/0 bytes][Goodput ratio: 80/0][< 1 sec][RTP Stream Type: audio][Plen Bins: 0,0,0,0,0,100,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]
66 UDP 192.168.1.2:30000 -> 37.115.0.36:40392 [proto: 87/RTP][IP: 0/Unknown][ClearText][Confidence: DPI][cat: Media/1][1 pkts/214 bytes -> 0 pkts/0 bytes][Goodput ratio: 80/0][< 1 sec][RTP Stream Type: audio][PLAIN TEXT (njlndlj)][Plen Bins: 0,0,0,0,0,100,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]
diff --git a/tests/result/malformed_dns.pcap.out b/tests/result/malformed_dns.pcap.out
index fa0af82b1..db360b157 100644
--- a/tests/result/malformed_dns.pcap.out
+++ b/tests/result/malformed_dns.pcap.out
@@ -22,4 +22,4 @@ Patricia protocols: 2/0 (search/found)
DNS 6 5860 1
- 1 UDP 127.0.0.1:50435 <-> 127.0.0.1:53 [proto: 5/DNS][IP: 0/Unknown][ClearText][Confidence: DPI][cat: Network/14][2 pkts/140 bytes <-> 4 pkts/5720 bytes][Goodput ratio: 40/97][5.03 sec][Hostname/SNI: www.xt.com][0.0.0.0][bytes ratio: -0.952 (Download)][IAT c2s/s2c min/avg/max/stddev: 4999/13 4999/1670 4999/4983 0/2343][Pkt Len c2s/s2c min/avg/max/stddev: 70/1430 70/1430 70/1430 0/0][Risk: ** Malformed Packet **** Large DNS Packet (512+ bytes) **][Risk Score: 60][Risk Info: Invalid DNS Query Lenght / 1388 Bytes DNS Packet][PLAIN TEXT (AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA)][Plen Bins: 33,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,66,0,0,0,0]
+ 1 UDP 127.0.0.1:50435 <-> 127.0.0.1:53 [proto: 5/DNS][IP: 0/Unknown][ClearText][Confidence: DPI][cat: Network/14][2 pkts/140 bytes <-> 4 pkts/5720 bytes][Goodput ratio: 40/97][5.03 sec][Hostname/SNI: www.xt.com][66.66.66.66][bytes ratio: -0.952 (Download)][IAT c2s/s2c min/avg/max/stddev: 4999/13 4999/1670 4999/4983 0/2343][Pkt Len c2s/s2c min/avg/max/stddev: 70/1430 70/1430 70/1430 0/0][Risk: ** Malformed Packet **** Suspicious DNS Traffic **** Large DNS Packet (512+ bytes) **][Risk Score: 160][Risk Info: DNS Record with zero TTL / Invalid DNS Query Lenght / 1388 Bytes DNS Packet][PLAIN TEXT (AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA)][Plen Bins: 33,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,66,0,0,0,0]