From 15b84b4192727c45879522190b0933e51592643c Mon Sep 17 00:00:00 2001 From: Ivan Nardi <12729895+IvanNardi@users.noreply.github.com> Date: Sat, 15 Feb 2025 21:57:34 +0100 Subject: [PATCH] DNS: rework code (#2727) --- src/lib/protocols/dns.c | 426 ++++++++---------- .../default/result/malformed_dns.pcap.out | 2 +- 2 files changed, 180 insertions(+), 248 deletions(-) diff --git a/src/lib/protocols/dns.c b/src/lib/protocols/dns.c index dab225a5684..08d93bf3c3a 100644 --- a/src/lib/protocols/dns.c +++ b/src/lib/protocols/dns.c @@ -280,42 +280,44 @@ static int process_queries(struct ndpi_detection_module_struct *ndpi_struct, u_int payload_offset) { struct ndpi_packet_struct *packet = &ndpi_struct->packet; u_int x = payload_offset; + u_int16_t rsp_type; + u_int16_t num; - if(dns_header->num_queries > 0) { - u_int16_t rsp_type; - u_int16_t num; + for(num = 0; num < dns_header->num_queries; num++) { + u_int16_t data_len; - for(num = 0; num < dns_header->num_queries; num++) { - u_int16_t data_len; + if((x+6) >= packet->payload_packet_len) { + return -1; + } - if((x+6) >= packet->payload_packet_len) { - return -1; - } + if((data_len = getNameLength(x, packet->payload, + packet->payload_packet_len)) == 0) { + return -1; + } else + x += data_len; - if((data_len = getNameLength(x, packet->payload, - packet->payload_packet_len)) == 0) { - return -1; - } else - x += data_len; + if(data_len > 253) + ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET, "Invalid DNS Query Lenght"); - if((x+4) > packet->payload_packet_len) { - return -1; - } + if((x+4) > packet->payload_packet_len) { + ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET, "Invalid DNS Query Lenght"); + return -1; + } - rsp_type = get16(&x, packet->payload); + rsp_type = get16(&x, packet->payload); #ifdef DNS_DEBUG - printf("[DNS] [response (query)] response_type=%d\n", rsp_type); + printf("[DNS] [response (query)] response_type=%d\n", rsp_type); #endif - if(flow->protos.dns.query_type == 0) { - /* In case we missed the query packet... */ - flow->protos.dns.query_type = rsp_type; - } - - /* here x points to the response "class" field */ - x += 2; /* Skip class */ + if(flow->protos.dns.query_type == 0) { + /* In case we missed the query packet... */ + flow->protos.dns.query_type = rsp_type; } + + /* here x points to the response "class" field */ + x += 2; /* Skip class */ } + return x; } @@ -325,117 +327,115 @@ static int process_answers(struct ndpi_detection_module_struct *ndpi_struct, u_int payload_offset, u_int8_t ignore_checks) { struct ndpi_packet_struct *packet = &ndpi_struct->packet; u_int x = payload_offset; + u_int16_t rsp_type; + u_int32_t rsp_ttl; + u_int16_t num; + u_int8_t found = 0; - 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; - for(num = 0; num < dns_header->num_answers; num++) { - u_int16_t data_len; - - if((x+6) >= packet->payload_packet_len) { - return -1; - } + if((x+6) >= packet->payload_packet_len) { + return -1; + } - if((data_len = getNameLength(x, packet->payload, - packet->payload_packet_len)) == 0) { - return -1; - } else - x += data_len; + if((data_len = getNameLength(x, packet->payload, + packet->payload_packet_len)) == 0) { + return -1; + } else + x += data_len; - if((x+8) >= packet->payload_packet_len) { - return -1; - } + if((x+8) >= packet->payload_packet_len) { + return -1; + } - rsp_type = get16(&x, packet->payload); - rsp_ttl = ntohl(*((u_int32_t*)&packet->payload[x+2])); + rsp_type = get16(&x, packet->payload); + rsp_ttl = ntohl(*((u_int32_t*)&packet->payload[x+2])); - if(rsp_ttl == 0) - ndpi_set_risk(ndpi_struct, flow, NDPI_MINOR_ISSUES, "DNS Record with zero TTL"); + if(rsp_ttl == 0) + ndpi_set_risk(ndpi_struct, flow, NDPI_MINOR_ISSUES, "DNS Record with zero TTL"); #ifdef DNS_DEBUG - printf("[DNS] TTL = %u\n", rsp_ttl); - printf("[DNS] [response] response_type=%d\n", rsp_type); + printf("[DNS] TTL = %u\n", rsp_ttl); + printf("[DNS] [response] response_type=%d\n", rsp_type); #endif - if(found == 0) { - ndpi_check_dns_type(ndpi_struct, flow, rsp_type); - flow->protos.dns.rsp_type = rsp_type; - } + 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) { - u_int32_t ttl = ntohl(*((u_int32_t*)&packet->payload[x+2])); + /* x points to the response "class" field */ + if((x+12) <= packet->payload_packet_len) { + u_int32_t ttl = ntohl(*((u_int32_t*)&packet->payload[x+2])); - x += 6; - data_len = get16(&x, packet->payload); + x += 6; + data_len = get16(&x, packet->payload); - if((x + data_len) <= packet->payload_packet_len) { + if((x + data_len) <= packet->payload_packet_len) { #ifdef DNS_DEBUG - printf("[DNS] [rsp_type: %u][data_len: %u]\n", rsp_type, data_len); + printf("[DNS] [rsp_type: %u][data_len: %u]\n", rsp_type, data_len); #endif - if(rsp_type == 0x05 /* CNAME */) { - ; - } 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) { - 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, - ignore_checks); - found = 1; - } - } - } else if((((rsp_type == 0x1) && (data_len == 4)) /* A */ - || ((rsp_type == 0x1c) && (data_len == 16)) /* AAAA */ - )) { - if(found == 0) { - - if(flow->protos.dns.num_rsp_addr < MAX_NUM_DNS_RSP_ADDRESSES) { - /* Necessary for IP address comparison */ - memset(&flow->protos.dns.rsp_addr[flow->protos.dns.num_rsp_addr], 0, sizeof(ndpi_ip_addr_t)); - - memcpy(&flow->protos.dns.rsp_addr[flow->protos.dns.num_rsp_addr], packet->payload + x, data_len); - flow->protos.dns.is_rsp_addr_ipv6[flow->protos.dns.num_rsp_addr] = (data_len == 16) ? 1 : 0; - flow->protos.dns.rsp_addr_ttl[flow->protos.dns.num_rsp_addr] = ttl; + if(rsp_type == 0x05 /* CNAME */) { + ; + } else if(rsp_type == 0x0C /* PTR */) { + u_int16_t ptr_len = (packet->payload[x-2] << 8) + packet->payload[x-1]; - if(ndpi_struct->cfg.address_cache_size) - ndpi_cache_address(ndpi_struct, - flow->protos.dns.rsp_addr[flow->protos.dns.num_rsp_addr], - flow->host_server_name, - packet->current_time_ms/1000, - flow->protos.dns.rsp_addr_ttl[flow->protos.dns.num_rsp_addr]); - - ++flow->protos.dns.num_rsp_addr; - } + if((x + ptr_len) <= packet->payload_packet_len) { + if(found == 0) { + u_int len; - if(flow->protos.dns.num_rsp_addr >= MAX_NUM_DNS_RSP_ADDRESSES) - found = 1; + ndpi_grab_dns_name(packet, &x, + flow->protos.dns.ptr_domain_name, + sizeof(flow->protos.dns.ptr_domain_name), &len, + ignore_checks); + found = 1; } } + } else if((((rsp_type == 0x1) && (data_len == 4)) /* A */ + || ((rsp_type == 0x1c) && (data_len == 16)) /* AAAA */ + )) { + if(found == 0) { + + if(flow->protos.dns.num_rsp_addr < MAX_NUM_DNS_RSP_ADDRESSES) { + /* Necessary for IP address comparison */ + memset(&flow->protos.dns.rsp_addr[flow->protos.dns.num_rsp_addr], 0, sizeof(ndpi_ip_addr_t)); + + memcpy(&flow->protos.dns.rsp_addr[flow->protos.dns.num_rsp_addr], packet->payload + x, data_len); + flow->protos.dns.is_rsp_addr_ipv6[flow->protos.dns.num_rsp_addr] = (data_len == 16) ? 1 : 0; + flow->protos.dns.rsp_addr_ttl[flow->protos.dns.num_rsp_addr] = ttl; + + if(ndpi_struct->cfg.address_cache_size) + ndpi_cache_address(ndpi_struct, + flow->protos.dns.rsp_addr[flow->protos.dns.num_rsp_addr], + flow->host_server_name, + packet->current_time_ms/1000, + flow->protos.dns.rsp_addr_ttl[flow->protos.dns.num_rsp_addr]); + + ++flow->protos.dns.num_rsp_addr; + } - x += data_len; + if(flow->protos.dns.num_rsp_addr >= MAX_NUM_DNS_RSP_ADDRESSES) + found = 1; + } } - } - 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; + x += data_len; } } + + 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; + } } + return x; } @@ -585,14 +585,12 @@ static int process_additionals(struct ndpi_detection_module_struct *ndpi_struct, return x; } -static int search_valid_dns(struct ndpi_detection_module_struct *ndpi_struct, - struct ndpi_flow_struct *flow, - struct ndpi_dns_packet_header *dns_header, - u_int payload_offset, u_int8_t *is_query, - u_int8_t ignore_checks) { +static int is_valid_dns(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + struct ndpi_dns_packet_header *dns_header, + u_int payload_offset, u_int8_t *is_query) { struct ndpi_packet_struct *packet = &ndpi_struct->packet; u_int x = payload_offset; - int rc; memcpy(dns_header, (struct ndpi_dns_packet_header*)&packet->payload[x], sizeof(struct ndpi_dns_packet_header)); @@ -606,97 +604,33 @@ static int search_valid_dns(struct ndpi_detection_module_struct *ndpi_struct, x += sizeof(struct ndpi_dns_packet_header); - /* 0x0000 QUERY */ if((dns_header->flags & FLAGS_MASK) == 0x0000) *is_query = 1; - /* 0x8000 RESPONSE */ else *is_query = 0; if(*is_query) { - /* DNS Request */ - if((dns_header->num_queries <= NDPI_MAX_DNS_REQUESTS) - // && (dns_header->num_answers == 0) - && (((dns_header->flags & 0x2800) == 0x2800 /* Dynamic DNS Update */) - || ((dns_header->flags & 0xFCF0) == 0x00) /* Standard Query */ - || ((dns_header->flags & 0xFCFF) == 0x0800) /* Inverse query */ - || ((dns_header->num_answers == 0) && (dns_header->authority_rrs == 0)))) { + if(dns_header->num_queries <= NDPI_MAX_DNS_REQUESTS && + /* dns_header->num_answers == 0 && */ + ((dns_header->flags & 0x2800) == 0x2800 /* Dynamic DNS Update */ || + (dns_header->flags & 0xFCF0) == 0x00 /* Standard Query */ || + (dns_header->flags & 0xFCFF) == 0x0800 /* Inverse query */ || + (dns_header->num_answers == 0 && dns_header->authority_rrs == 0))) { /* This is a good query */ - while(x+2 < packet->payload_packet_len) { - if(packet->payload[x] == '\0') { - x++; - flow->protos.dns.query_type = get16(&x, packet->payload); -#ifdef DNS_DEBUG - NDPI_LOG_DBG2(ndpi_struct, "query_type=%2d\n", flow->protos.dns.query_type); - printf("[DNS] [request] query_type=%d\n", flow->protos.dns.query_type); -#endif - break; - } else - x++; - } - flow->protos.dns.transaction_id = dns_header->tr_id; - } else { - if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_UNKNOWN) - ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET, "Invalid DNS Header"); - return(1 /* invalid */); + return 1; } } else { - /* DNS Reply */ - if(((dns_header->num_queries > 0 && dns_header->num_queries <= NDPI_MAX_DNS_REQUESTS) || /* Don't assume that num_queries must be zero */ - (checkDNSSubprotocol(ntohs(flow->c_port), ntohs(flow->s_port)) == NDPI_PROTOCOL_MDNS && dns_header->num_queries == 0)) - && ((((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))) - || (dns_header->num_answers == 0 && dns_header->authority_rrs == 0 && dns_header->additional_rrs == 0)) - ) { - /* This is a good reply: we dissect it both for request and response */ - - flow->protos.dns.transaction_id = dns_header->tr_id; - flow->protos.dns.reply_code = dns_header->flags & 0x0F; - - if(flow->protos.dns.reply_code != 0) { - char str[32], buf[16]; - - snprintf(str, sizeof(str), "DNS Error Code %s", - dns_error_code2string(flow->protos.dns.reply_code, buf, sizeof(buf))); - ndpi_set_risk(ndpi_struct, flow, NDPI_ERROR_CODE_DETECTED, str); - } else { - if(ndpi_isset_risk(flow, NDPI_SUSPICIOUS_DGA_DOMAIN)) { - ndpi_set_risk(ndpi_struct, flow, NDPI_RISKY_DOMAIN, "DGA Name Query with no Error Code"); - } - } - - rc = process_queries(ndpi_struct, flow, dns_header, x); - if(rc == -1) { -#ifdef DNS_DEBUG - printf("[DNS] Error queries\n"); -#endif - } else { - x = rc; - rc = process_answers(ndpi_struct, flow, dns_header, x, ignore_checks); - if(rc == -1) { -#ifdef DNS_DEBUG - printf("[DNS] Error answers\n"); -#endif - } else { - x = rc; - rc = process_additionals(ndpi_struct, flow, dns_header, x); -#ifdef DNS_DEBUG - if(rc == -1) - printf("[DNS] Error additionals\n"); -#endif - } - } - } else { - if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_UNKNOWN) - ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET, "Invalid DNS Header"); - return(1 /* invalid */); + (checkDNSSubprotocol(ntohs(flow->c_port), ntohs(flow->s_port)) == NDPI_PROTOCOL_MDNS && dns_header->num_queries == 0)) && + ((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) || + (dns_header->num_answers == 0 && dns_header->authority_rrs == 0 && dns_header->additional_rrs == 0))) { + /* This is a good reply */ + return 1; } } - - /* Valid */ - return(0); + return 0; } /* *********************************************** */ @@ -723,6 +657,9 @@ static int process_hostname(struct ndpi_detection_module_struct *ndpi_struct, char _hostname[256]; u_int8_t hostname_is_valid; + proto->master_protocol = checkDNSSubprotocol(ntohs(flow->c_port), ntohs(flow->s_port)); + proto->app_protocol = NDPI_PROTOCOL_UNKNOWN; + is_mdns = (proto->master_protocol == NDPI_PROTOCOL_MDNS); /* TODO: should we overwrite existing hostname? @@ -814,88 +751,83 @@ static void search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct if(packet->payload_packet_len > sizeof(struct ndpi_dns_packet_header)+payload_offset) { struct ndpi_dns_packet_header dns_header; u_int off; - int invalid = search_valid_dns(ndpi_struct, flow, &dns_header, payload_offset, &is_query, is_mdns); - ndpi_protocol ret; - u_int num_queries, idx; - - ret.proto.master_protocol = checkDNSSubprotocol(s_port, d_port); - ret.proto.app_protocol = NDPI_PROTOCOL_UNKNOWN; + ndpi_master_app_protocol proto; + int rc; - if(invalid) { + if(!is_valid_dns(ndpi_struct, flow, &dns_header, payload_offset, &is_query)) { #ifdef DNS_DEBUG printf("[DNS] invalid packet\n"); #endif - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + if(flow->extra_packets_func == NULL) { + NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + } else { + ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET, "Invalid DNS Header"); + } return; } - /* extract host name server */ off = sizeof(struct ndpi_dns_packet_header) + payload_offset; - /* Before continuing let's dissect the following queries to see if they are valid */ - for(idx=off, num_queries=0; (num_queries < dns_header.num_queries) && (idx < packet->payload_packet_len);) { - u_int32_t i, tot_len = 0; - - for(i=idx; ipayload_packet_len;) { - u_int8_t is_ptr = 0, name_len = packet->payload[i]; /* Lenght of the individual name blocks aaa.bbb.com */ + if(is_query) { - if(name_len == 0) { - tot_len++; /* \0 */ - /* End of query */ - break; - } else if((name_len & 0xC0) == 0xC0) - is_ptr = 1, name_len = 0; /* Pointer */ + flow->protos.dns.transaction_id = dns_header.tr_id; + process_queries(ndpi_struct, flow, &dns_header, off); #ifdef DNS_DEBUG - if((!is_ptr) && (name_len > 0)) { - printf("[DNS] [name_len: %u][", name_len); + if(rc == -1) { + printf("[DNS] Error queries (query msg)\n"); +#endif + } else { + flow->protos.dns.transaction_id = dns_header.tr_id; + flow->protos.dns.reply_code = dns_header.flags & 0x0F; - { - int idx; + if(flow->protos.dns.reply_code != 0) { + char str[32], buf[16]; - for(idx=0; idxpayload[i+1+idx]); + snprintf(str, sizeof(str), "DNS Error Code %s", + dns_error_code2string(flow->protos.dns.reply_code, buf, sizeof(buf))); + ndpi_set_risk(ndpi_struct, flow, NDPI_ERROR_CODE_DETECTED, str); + } else { + if(ndpi_isset_risk(flow, NDPI_SUSPICIOUS_DGA_DOMAIN)) { + ndpi_set_risk(ndpi_struct, flow, NDPI_RISKY_DOMAIN, "DGA Name Query with no Error Code"); + } + } - printf("]\n"); - } - } + rc = process_queries(ndpi_struct, flow, &dns_header, off); + if(rc == -1) { +#ifdef DNS_DEBUG + printf("[DNS] Error queries (response msg)\n"); #endif - - i += name_len+1, tot_len += name_len+1; - if(is_ptr) break; - } /* for */ - + } else { + off = rc; + rc = process_answers(ndpi_struct, flow, &dns_header, off, is_mdns); + if(rc == -1) { #ifdef DNS_DEBUG - printf("[DNS] [tot_len: %u]\n\n", tot_len+4 /* type + class */); + printf("[DNS] Error answers\n"); #endif - - if(((i+4 /* Skip query type and class */) > packet->payload_packet_len) - || ((packet->payload[i+1] == 0x0) && (packet->payload[i+2] == 0x0)) /* Query type cannot be 0 */ - || (tot_len > 253) - ) { - /* Invalid */ + } else { + off = rc; + rc = process_additionals(ndpi_struct, flow, &dns_header, off); #ifdef DNS_DEBUG - printf("[DNS] Invalid query len [%u >= %u]\n", i+4, packet->payload_packet_len); + if(rc == -1) + printf("[DNS] Error additionals\n"); #endif - ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET, "Invalid DNS Query Lenght"); - break; - } else { - idx = i+5, num_queries++; + } } - } /* for */ + } - process_hostname(ndpi_struct, flow, &ret.proto); + process_hostname(ndpi_struct, flow, &proto); /* Report if this is a DNS query or reply */ flow->protos.dns.is_query = is_query; if(!ndpi_struct->cfg.dns_subclassification_enabled) - ret.proto.app_protocol = NDPI_PROTOCOL_UNKNOWN; + proto.app_protocol = NDPI_PROTOCOL_UNKNOWN; if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN || - ret.proto.app_protocol != NDPI_PROTOCOL_UNKNOWN) { + proto.app_protocol != NDPI_PROTOCOL_UNKNOWN) { - ndpi_set_detected_protocol(ndpi_struct, flow, ret.proto.app_protocol, ret.proto.master_protocol, NDPI_CONFIDENCE_DPI); + ndpi_set_detected_protocol(ndpi_struct, flow, proto.app_protocol, proto.master_protocol, NDPI_CONFIDENCE_DPI); if(is_query) { if(ndpi_struct->cfg.dns_parse_response_enabled) { diff --git a/tests/cfgs/default/result/malformed_dns.pcap.out b/tests/cfgs/default/result/malformed_dns.pcap.out index 309037ebd43..c6f33dd2086 100644 --- a/tests/cfgs/default/result/malformed_dns.pcap.out +++ b/tests/cfgs/default/result/malformed_dns.pcap.out @@ -24,4 +24,4 @@ DNS 6 5860 1 Acceptable 6 5860 1 - 1 UDP 127.0.0.1:50435 <-> 127.0.0.1:53 [proto: 5/DNS][IP: 0/Unknown][ClearText][Confidence: DPI][FPC: 5/DNS, Confidence: DPI][DPI packets: 2][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][DNS Id: 0x84b4][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) **** Minor Issues **][Risk Score: 70][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] + 1 UDP 127.0.0.1:50435 <-> 127.0.0.1:53 [proto: 5/DNS][IP: 0/Unknown][ClearText][Confidence: DPI][FPC: 5/DNS, Confidence: DPI][DPI packets: 2][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][DNS Id: 0x84b4][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) **** Minor Issues **][Risk Score: 70][Risk Info: Invalid DNS Query Lenght / DNS Record with zero TTL / 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]