diff options
author | Luca Deri <deri@ntop.org> | 2019-09-26 23:50:02 +0200 |
---|---|---|
committer | Luca Deri <deri@ntop.org> | 2019-09-26 23:50:02 +0200 |
commit | 17f560a1cd5a539bf8940072bac05ccbf3b547f9 (patch) | |
tree | d647cc792cb15f1700ece1c7e95fb2bb14713439 /src/lib/protocols/dns.c | |
parent | 194cdcf581f7d405fca191f99eedcb734e68f5ec (diff) |
Added ndpi_extra_dissection_possible() API call
Diffstat (limited to 'src/lib/protocols/dns.c')
-rw-r--r-- | src/lib/protocols/dns.c | 247 |
1 files changed, 131 insertions, 116 deletions
diff --git a/src/lib/protocols/dns.c b/src/lib/protocols/dns.c index 4e3ffb5ed..b3df9b466 100644 --- a/src/lib/protocols/dns.c +++ b/src/lib/protocols/dns.c @@ -30,7 +30,7 @@ #define FLAGS_MASK 0x8000 -/* #define DNS_DEBUG 1 */ +// #define DNS_DEBUG 1 /* *********************************************** */ @@ -60,31 +60,36 @@ static u_int getNameLength(u_int i, const u_int8_t *payload, u_int payloadLen) { } } /* - allowed chars for dns names A-Z 0-9 _ - - Perl script for generation map: + allowed chars for dns names A-Z 0-9 _ - + Perl script for generation map: my @M; for(my $ch=0; $ch < 256; $ch++) { - $M[$ch >> 5] |= 1 << ($ch & 0x1f) if chr($ch) =~ /[a-z0-9_-]/i; + $M[$ch >> 5] |= 1 << ($ch & 0x1f) if chr($ch) =~ /[a-z0-9_-]/i; } print join(',', map { sprintf "0x%08x",$_ } @M),"\n"; - */ +*/ static uint32_t dns_validchar[8] = { - 0x00000000,0x03ff2000,0x87fffffe,0x07fffffe,0,0,0,0 + 0x00000000,0x03ff2000,0x87fffffe,0x07fffffe,0,0,0,0 }; /* *********************************************** */ -static int search_valid_dns(struct ndpi_flow_struct *flow, struct ndpi_dns_packet_header *dns_header, int payload_offset, u_int8_t*is_query) { +static int search_valid_dns(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow, + struct ndpi_dns_packet_header *dns_header, + int payload_offset, u_int8_t *is_query) { int x = payload_offset; - memcpy(dns_header, (struct ndpi_dns_packet_header*) &flow->packet.payload[x], sizeof(struct ndpi_dns_packet_header)); + memcpy(dns_header, (struct ndpi_dns_packet_header*)&flow->packet.payload[x], + sizeof(struct ndpi_dns_packet_header)); dns_header->tr_id = ntohs(dns_header->tr_id); dns_header->flags = ntohs(dns_header->flags); dns_header->num_queries = ntohs(dns_header->num_queries); dns_header->num_answers = ntohs(dns_header->num_answers); dns_header->authority_rrs = ntohs(dns_header->authority_rrs); dns_header->additional_rrs = ntohs(dns_header->additional_rrs); + x += sizeof(struct ndpi_dns_packet_header); /* 0x0000 QUERY */ @@ -99,88 +104,93 @@ static int search_valid_dns(struct ndpi_flow_struct *flow, struct ndpi_dns_packe if(*is_query) { /* DNS Request */ if((dns_header->num_queries > 0) && (dns_header->num_queries <= NDPI_MAX_DNS_REQUESTS) - && (((dns_header->flags & 0x2800) == 0x2800 /* Dynamic DNS Update */) - || ((dns_header->num_answers == 0) && (dns_header->authority_rrs == 0)))) { - /* This is a good query */ + && (((dns_header->flags & 0x2800) == 0x2800 /* Dynamic DNS Update */) + || ((dns_header->num_answers == 0) && (dns_header->authority_rrs == 0)))) { + /* This is a good query */ while(x < flow->packet.payload_packet_len) { if(flow->packet.payload[x] == '\0') { x++; flow->protos.dns.query_type = get16(&x, flow->packet.payload); #ifdef DNS_DEBUG NDPI_LOG_DBG2(ndpi_struct, "query_type=%2d\n", flow->protos.dns.query_type); + printf("[DNS] query_type=%d\n", flow->protos.dns.query_type); #endif - break; - } else - x++; + + if(ndpi_struct->dns_dont_dissect_response) + ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_DNS, NDPI_PROTOCOL_UNKNOWN); + + break; + } else + x++; } } else return(1 /* invalid */); } else { - /* DNS Reply */ - flow->protos.dns.reply_code = dns_header->flags & 0x0F; - - 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 */ - - /* Leave the statement below commented necessary in case of call to ndpi_get_partial_detection() */ - /* if(ndpi_struct->dns_dont_dissect_response == 0) */ { + /* DNS Reply */ + flow->protos.dns.reply_code = dns_header->flags & 0x0F; + + 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 */ + + /* Leave the statement below commented necessary in case of call to ndpi_get_partial_detection() */ + /* if(ndpi_struct->dns_dont_dissect_response == 0) */ { + x++; + + if(flow->packet.payload[x] != '\0') { + while((x < flow->packet.payload_packet_len) + && (flow->packet.payload[x] != '\0')) { x++; + } - if(flow->packet.payload[x] != '\0') { - while((x < flow->packet.payload_packet_len) - && (flow->packet.payload[x] != '\0')) { - x++; - } - - x++; - } + x++; + } - x += 4; + x += 4; - if(dns_header->num_answers > 0) { - u_int16_t rsp_type; - u_int16_t num; + if(dns_header->num_answers > 0) { + u_int16_t rsp_type; + u_int16_t num; - 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) >= flow->packet.payload_packet_len) { - break; - } + if((x+6) >= flow->packet.payload_packet_len) { + break; + } - if((data_len = getNameLength(x, flow->packet.payload, flow->packet.payload_packet_len)) == 0) { - break; - } else - x += data_len; + if((data_len = getNameLength(x, flow->packet.payload, flow->packet.payload_packet_len)) == 0) { + break; + } else + x += data_len; - rsp_type = get16(&x, flow->packet.payload); - flow->protos.dns.rsp_type = rsp_type; + rsp_type = get16(&x, flow->packet.payload); + flow->protos.dns.rsp_type = rsp_type; - /* here x points to the response "class" field */ - if((x+12) <= flow->packet.payload_packet_len) { - x += 6; - data_len = get16(&x, flow->packet.payload); + /* here x points to the response "class" field */ + if((x+12) <= flow->packet.payload_packet_len) { + x += 6; + data_len = get16(&x, flow->packet.payload); - if(((x + data_len) <= flow->packet.payload_packet_len) - && (((rsp_type == 0x1) && (data_len == 4)) /* A */ + if(((x + data_len) <= flow->packet.payload_packet_len) + && (((rsp_type == 0x1) && (data_len == 4)) /* A */ #ifdef NDPI_DETECTION_SUPPORT_IPV6 - || ((rsp_type == 0x1c) && (data_len == 16)) /* AAAA */ + || ((rsp_type == 0x1c) && (data_len == 16)) /* AAAA */ #endif - )) { - memcpy(&flow->protos.dns.rsp_addr, flow->packet.payload + x, data_len); - } - } - - break; + )) { + memcpy(&flow->protos.dns.rsp_addr, flow->packet.payload + x, data_len); } } + + break; } - } else - return(1 /* invalid */); + } + } + } else + return(1 /* invalid */); } /* Valid */ @@ -195,6 +205,7 @@ void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct nd u_int16_t s_port = 0, d_port = 0; NDPI_LOG_DBG(ndpi_struct, "search DNS\n"); + if(flow->packet.udp != NULL) { s_port = ntohs(flow->packet.udp->source); d_port = ntohs(flow->packet.udp->dest); @@ -210,78 +221,82 @@ void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct nd if((s_port == 53 || d_port == 53 || d_port == 5355) && (flow->packet.payload_packet_len > sizeof(struct ndpi_dns_packet_header)+payload_offset)) { - struct ndpi_dns_packet_header dns_header; - int j = 0, max_len, off; - int invalid = search_valid_dns(flow, &dns_header, payload_offset, &is_query); + struct ndpi_dns_packet_header dns_header; + int j = 0, max_len, off; + int invalid = search_valid_dns(ndpi_struct, flow, &dns_header, payload_offset, &is_query); - if(invalid) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); - return; - } + if(invalid) { + NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + return; + } - /* extract host name server */ - max_len = sizeof(flow->host_server_name)-1; - off = sizeof(struct ndpi_dns_packet_header) + payload_offset; + /* extract host name server */ + max_len = sizeof(flow->host_server_name)-1; + off = sizeof(struct ndpi_dns_packet_header) + payload_offset; - while(j < max_len && off < flow->packet.payload_packet_len && flow->packet.payload[off] != '\0') { - uint8_t c, cl = flow->packet.payload[off++]; + while(j < max_len && off < flow->packet.payload_packet_len && flow->packet.payload[off] != '\0') { + uint8_t c, cl = flow->packet.payload[off++]; - if( (cl & 0xc0) != 0 || // we not support compressed names in query - off + cl >= flow->packet.payload_packet_len) { - j = 0; - break; - } + if( (cl & 0xc0) != 0 || // we not support compressed names in query + off + cl >= flow->packet.payload_packet_len) { + j = 0; + break; + } - if(j && j < max_len) flow->host_server_name[j++] = '.'; + if(j && j < max_len) flow->host_server_name[j++] = '.'; - while(j < max_len && cl != 0) { - c = flow->packet.payload[off++]; - flow->host_server_name[j++] = (dns_validchar[c >> 5] & (1 << (c & 0x1f))) ? c : '_'; - cl--; - } + while(j < max_len && cl != 0) { + c = flow->packet.payload[off++]; + flow->host_server_name[j++] = (dns_validchar[c >> 5] & (1 << (c & 0x1f))) ? c : '_'; + cl--; } - flow->host_server_name[j] = '\0'; + } + flow->host_server_name[j] = '\0'; - if(is_query && (ndpi_struct->dns_dont_dissect_response == 0)) { - // dpi_set_detected_protocol(ndpi_struct, flow, (d_port == 5355) ? NDPI_PROTOCOL_LLMNR : NDPI_PROTOCOL_DNS, NDPI_PROTOCOL_UNKNOWN); - return; /* The response will set the verdict */ - } + if(is_query && (ndpi_struct->dns_dont_dissect_response == 0)) { + // dpi_set_detected_protocol(ndpi_struct, flow, (d_port == 5355) ? NDPI_PROTOCOL_LLMNR : NDPI_PROTOCOL_DNS, NDPI_PROTOCOL_UNKNOWN); + return; /* The response will set the verdict */ + } - flow->protos.dns.num_queries = (u_int8_t)dns_header.num_queries, + 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); - if(j > 0) { - ndpi_protocol_match_result ret_match; + if(j > 0) { + ndpi_protocol_match_result ret_match; - ndpi_match_host_subprotocol(ndpi_struct, flow, - (char *)flow->host_server_name, - strlen((const char*)flow->host_server_name), - &ret_match, - NDPI_PROTOCOL_DNS); - } + ndpi_match_host_subprotocol(ndpi_struct, flow, + (char *)flow->host_server_name, + strlen((const char*)flow->host_server_name), + &ret_match, + NDPI_PROTOCOL_DNS); + } #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->packet.detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) { - /** - Do not set the protocol with DNS if ndpi_match_host_subprotocol() has - matched a subprotocol - **/ - NDPI_LOG_INFO(ndpi_struct, "found DNS\n"); - ndpi_set_detected_protocol(ndpi_struct, flow, (d_port == 5355) ? NDPI_PROTOCOL_LLMNR : NDPI_PROTOCOL_DNS, NDPI_PROTOCOL_UNKNOWN); - } else { + if(flow->packet.detected_protocol_stack[0] == NDPI_PROTOCOL_UNKNOWN) { + /** + Do not set the protocol with DNS if ndpi_match_host_subprotocol() has + matched a subprotocol + **/ + NDPI_LOG_INFO(ndpi_struct, "found DNS\n"); + ndpi_set_detected_protocol(ndpi_struct, flow, (d_port == 5355) ? NDPI_PROTOCOL_LLMNR : NDPI_PROTOCOL_DNS, NDPI_PROTOCOL_UNKNOWN); + } else { + if((flow->packet.detected_protocol_stack[0] == NDPI_PROTOCOL_DNS) + || (flow->packet.detected_protocol_stack[1] == NDPI_PROTOCOL_DNS)) + ; + else NDPI_EXCLUDE_PROTO(ndpi_struct, flow); - } + } } } -void init_dns_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) -{ +void init_dns_dissector(struct ndpi_detection_module_struct *ndpi_struct, + u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) { ndpi_set_bitmask_protocol_detection("DNS", ndpi_struct, detection_bitmask, *id, NDPI_PROTOCOL_DNS, ndpi_search_dns, |