diff --git a/src/lib/protocols/dns.c b/src/lib/protocols/dns.c index 08d93bf3c3a..22ab422fb46 100644 --- a/src/lib/protocols/dns.c +++ b/src/lib/protocols/dns.c @@ -592,6 +592,9 @@ static int is_valid_dns(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_packet_struct *packet = &ndpi_struct->packet; u_int x = payload_offset; + if(packet->payload_packet_len < sizeof(struct ndpi_dns_packet_header) + payload_offset) + return 0; + memcpy(dns_header, (struct ndpi_dns_packet_header*)&packet->payload[x], sizeof(struct ndpi_dns_packet_header)); @@ -623,12 +626,18 @@ static int is_valid_dns(struct ndpi_detection_module_struct *ndpi_struct, 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->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; } + if(dns_header->num_queries == 0 && dns_header->num_answers == 0 && + dns_header->authority_rrs == 0 && dns_header->additional_rrs == 0 && + packet->payload_packet_len == sizeof(struct ndpi_dns_packet_header)) { + /* This is a good empty reply */ + return 1; + } } return 0; } @@ -636,6 +645,11 @@ static int is_valid_dns(struct ndpi_detection_module_struct *ndpi_struct, /* *********************************************** */ static int search_dns_again(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { + struct ndpi_packet_struct *packet = &ndpi_struct->packet; + + if(packet->tcp_retransmission || packet->payload_packet_len == 0) + return(1); + /* possibly dissect the DNS reply */ search_dns(ndpi_struct, flow); @@ -735,6 +749,10 @@ static void search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct int payload_offset = 0; u_int8_t is_query, is_mdns; u_int16_t s_port = 0, d_port = 0; + struct ndpi_dns_packet_header dns_header; + u_int off; + ndpi_master_app_protocol proto; + int rc; if(packet->udp != NULL) { s_port = ntohs(packet->udp->source); @@ -748,117 +766,110 @@ static void search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct is_mdns = ((s_port == MDNS_PORT) || (d_port == MDNS_PORT)) ? 1 : 0; - if(packet->payload_packet_len > sizeof(struct ndpi_dns_packet_header)+payload_offset) { - struct ndpi_dns_packet_header dns_header; - u_int off; - ndpi_master_app_protocol proto; - int rc; - - if(!is_valid_dns(ndpi_struct, flow, &dns_header, payload_offset, &is_query)) { + if(!is_valid_dns(ndpi_struct, flow, &dns_header, payload_offset, &is_query)) { #ifdef DNS_DEBUG - printf("[DNS] invalid packet\n"); + printf("[DNS] invalid packet\n"); #endif - 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; + 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; + } - off = sizeof(struct ndpi_dns_packet_header) + payload_offset; + off = sizeof(struct ndpi_dns_packet_header) + payload_offset; - if(is_query) { + if(is_query) { - flow->protos.dns.transaction_id = dns_header.tr_id; + flow->protos.dns.transaction_id = dns_header.tr_id; - process_queries(ndpi_struct, flow, &dns_header, off); + process_queries(ndpi_struct, flow, &dns_header, off); #ifdef DNS_DEBUG - if(rc == -1) { - printf("[DNS] Error queries (query msg)\n"); + 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; + } else { + 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]; + 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"); - } + 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, off); + rc = process_queries(ndpi_struct, flow, &dns_header, off); + if(rc == -1) { +#ifdef DNS_DEBUG + printf("[DNS] Error queries (response msg)\n"); +#endif + } else { + off = rc; + rc = process_answers(ndpi_struct, flow, &dns_header, off, is_mdns); if(rc == -1) { #ifdef DNS_DEBUG - printf("[DNS] Error queries (response msg)\n"); + printf("[DNS] Error answers\n"); #endif } else { off = rc; - rc = process_answers(ndpi_struct, flow, &dns_header, off, is_mdns); - if(rc == -1) { -#ifdef DNS_DEBUG - printf("[DNS] Error answers\n"); -#endif - } else { - off = rc; - rc = process_additionals(ndpi_struct, flow, &dns_header, off); + rc = process_additionals(ndpi_struct, flow, &dns_header, off); #ifdef DNS_DEBUG - if(rc == -1) - printf("[DNS] Error additionals\n"); + if(rc == -1) + printf("[DNS] Error additionals\n"); #endif - } } } + } - process_hostname(ndpi_struct, flow, &proto); + process_hostname(ndpi_struct, flow, &proto); - /* Report if this is a DNS query or reply */ - flow->protos.dns.is_query = is_query; + /* Report if this is a DNS query or reply */ + flow->protos.dns.is_query = is_query; - if(!ndpi_struct->cfg.dns_subclassification_enabled) - proto.app_protocol = NDPI_PROTOCOL_UNKNOWN; + if(!ndpi_struct->cfg.dns_subclassification_enabled) + proto.app_protocol = NDPI_PROTOCOL_UNKNOWN; - if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN || - proto.app_protocol != NDPI_PROTOCOL_UNKNOWN) { + if(flow->detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN || + proto.app_protocol != NDPI_PROTOCOL_UNKNOWN) { - ndpi_set_detected_protocol(ndpi_struct, flow, proto.app_protocol, 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) { - /* We have never triggered extra-dissection for LLMNR. Keep the old behavior */ - if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_LLMNR && - flow->detected_protocol_stack[1] != NDPI_PROTOCOL_LLMNR) { - /* Don't use just 1 as in TCP DNS more packets could be returned (e.g. ACK). */ - flow->max_extra_packets_to_check = 5; - flow->extra_packets_func = search_dns_again; - } - } + if(is_query) { + if(ndpi_struct->cfg.dns_parse_response_enabled) { + /* We have never triggered extra-dissection for LLMNR. Keep the old behavior */ + if(flow->detected_protocol_stack[0] != NDPI_PROTOCOL_LLMNR && + flow->detected_protocol_stack[1] != NDPI_PROTOCOL_LLMNR) { + /* Don't use just 1 as in TCP DNS more packets could be returned (e.g. ACK). */ + flow->max_extra_packets_to_check = 5; + flow->extra_packets_func = search_dns_again; + } } } - /* Category is always NDPI_PROTOCOL_CATEGORY_NETWORK, regardless of the subprotocol */ - flow->category = NDPI_PROTOCOL_CATEGORY_NETWORK; + } + /* Category is always NDPI_PROTOCOL_CATEGORY_NETWORK, regardless of the subprotocol */ + flow->category = NDPI_PROTOCOL_CATEGORY_NETWORK; - if(is_query) - return; + if(is_query) + return; - if(strlen(flow->host_server_name) > 0) + if(strlen(flow->host_server_name) > 0) - flow->protos.dns.num_queries = (u_int8_t)dns_header.num_queries, - flow->protos.dns.num_answers = (u_int8_t) (dns_header.num_answers + dns_header.authority_rrs + dns_header.additional_rrs); + flow->protos.dns.num_queries = (u_int8_t)dns_header.num_queries, + flow->protos.dns.num_answers = (u_int8_t) (dns_header.num_answers + dns_header.authority_rrs + dns_header.additional_rrs); #ifdef DNS_DEBUG - NDPI_LOG_DBG2(ndpi_struct, "[num_queries=%d][num_answers=%d][reply_code=%u][rsp_type=%u][host_server_name=%s]\n", - flow->protos.dns.num_queries, flow->protos.dns.num_answers, - flow->protos.dns.reply_code, flow->protos.dns.rsp_type, flow->host_server_name - ); + NDPI_LOG_DBG2(ndpi_struct, "[num_queries=%d][num_answers=%d][reply_code=%u][rsp_type=%u][host_server_name=%s]\n", + flow->protos.dns.num_queries, flow->protos.dns.num_answers, + flow->protos.dns.reply_code, flow->protos.dns.rsp_type, flow->host_server_name + ); #endif - } if((flow->detected_protocol_stack[0] == NDPI_PROTOCOL_DNS) || (flow->detected_protocol_stack[1] == NDPI_PROTOCOL_DNS)) { diff --git a/tests/cfgs/default/result/dns_invert_query.pcapng.out b/tests/cfgs/default/result/dns_invert_query.pcapng.out index 5de70bf7967..f7291ba646c 100644 --- a/tests/cfgs/default/result/dns_invert_query.pcapng.out +++ b/tests/cfgs/default/result/dns_invert_query.pcapng.out @@ -24,4 +24,4 @@ DNS 2 134 1 Acceptable 2 134 1 - 1 UDP 173.147.108.174:18427 <-> 244.187.95.1:53 [proto: 5/DNS][IP: 0/Unknown][ClearText][Confidence: DPI][FPC: 5/DNS, Confidence: DPI][DPI packets: 2][cat: Network/14][1 pkts/78 bytes <-> 1 pkts/56 bytes][Goodput ratio: 46/21][0.00 sec][Hostname/SNI: 216.58.202.4][0.0.0.0][DNS Id: 0x77fc][Plen Bins: 50,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,0,0] + 1 UDP 173.147.108.174:18427 <-> 244.187.95.1:53 [proto: 5/DNS][IP: 0/Unknown][ClearText][Confidence: DPI][FPC: 5/DNS, Confidence: DPI][DPI packets: 2][cat: Network/14][1 pkts/78 bytes <-> 1 pkts/56 bytes][Goodput ratio: 46/21][0.00 sec][0.0.0.0][DNS Id: 0x77fc][Risk: ** Error Code **][Risk Score: 10][Risk Info: DNS Error Code NOTIMP][Plen Bins: 50,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,0,0]