diff options
Diffstat (limited to 'src/lib/protocols/dns.c')
-rw-r--r-- | src/lib/protocols/dns.c | 341 |
1 files changed, 82 insertions, 259 deletions
diff --git a/src/lib/protocols/dns.c b/src/lib/protocols/dns.c index 3b4322823..ea136f453 100644 --- a/src/lib/protocols/dns.c +++ b/src/lib/protocols/dns.c @@ -1,7 +1,9 @@ /* * dns.c * - * Copyright (C) 2012-15 - ntop.org + * Copyright (C) 2012-16 - ntop.org + * + * Michele Campus - <campus@ntop.org> * * This file is part of nDPI, an open source deep packet inspection * library based on the OpenDPI and PACE technology by ipoque GmbH @@ -21,282 +23,103 @@ * */ - #include "ndpi_protocols.h" #ifdef NDPI_PROTOCOL_DNS -static u_int getNameLength(u_int i, const u_int8_t *payload, u_int payloadLen) { - if(payload[i] == 0x00) - return(1); - else if(payload[i] == 0xC0) - return(2); - else { - u_int8_t len = payload[i]; - u_int8_t off = len + 1; - - if(off == 0) /* Bad packet */ - return(0); - else - return(off + getNameLength(i+off, payload, payloadLen)); - } -} - -/* *********************************************** */ - -static char* ndpi_intoa_v4(unsigned int addr, char* buf, u_short bufLen) { - char *cp, *retStr; - uint byte; - int n; - - cp = &buf[bufLen]; - *--cp = '\0'; - - n = 4; - do { - byte = addr & 0xff; - *--cp = byte % 10 + '0'; - byte /= 10; - if(byte > 0) { - *--cp = byte % 10 + '0'; - byte /= 10; - if(byte > 0) - *--cp = byte + '0'; - } - *--cp = '.'; - addr >>= 8; - } while (--n > 0); - - /* Convert the string to lowercase */ - retStr = (char*)(cp+1); - - return(retStr); -} - -/* *********************************************** */ - -static u_int16_t get16(int *i, const u_int8_t *payload) { - u_int16_t v = *(u_int16_t*)&payload[*i]; - - (*i) += 2; - - return(ntohs(v)); -} - -/* *********************************************** */ +#define FLAGS_MASK 0x8000 void ndpi_search_dns(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { - struct ndpi_packet_struct *packet = &flow->packet; - u_int16_t dport = 0, sport = 0; - -#define NDPI_MAX_DNS_REQUESTS 16 - NDPI_LOG(NDPI_PROTOCOL_DNS, ndpi_struct, NDPI_LOG_DEBUG, "search DNS.\n"); + int x; + u_int8_t is_query, ret_code; + u_int16_t s_port = 0; + u_int16_t d_port = 0; - if (packet->udp != NULL) { - sport = ntohs(packet->udp->source), dport = ntohs(packet->udp->dest); - NDPI_LOG(NDPI_PROTOCOL_DNS, ndpi_struct, NDPI_LOG_DEBUG, "calculated dport over UDP.\n"); - } else if(packet->tcp != NULL) { - sport = ntohs(packet->tcp->source), dport = ntohs(packet->tcp->dest); - NDPI_LOG(NDPI_PROTOCOL_DNS, ndpi_struct, NDPI_LOG_DEBUG, "calculated dport over tcp.\n"); - } - - if(((dport == 53) || (sport == 53) || (dport == 5355)) - && (packet->payload_packet_len > sizeof(struct ndpi_dns_packet_header))) { - int i = packet->tcp ? 2 : 0; - struct ndpi_dns_packet_header header, *dns = (struct ndpi_dns_packet_header*)&packet->payload[i]; - u_int8_t is_query, ret_code, is_dns = 0; - u_int32_t a_record[NDPI_MAX_DNS_REQUESTS] = { 0 }, query_offset, num_a_records = 0; - - header.flags = ntohs(dns->flags); - header.transaction_id = ntohs(dns->transaction_id); - header.num_queries = ntohs(dns->num_queries); - header.answer_rrs = ntohs(dns->answer_rrs); - header.authority_rrs = ntohs(dns->authority_rrs); - header.additional_rrs = ntohs(dns->additional_rrs); - is_query = (header.flags & 0x8000) ? 0 : 1; - ret_code = is_query ? 0 : (header.flags & 0x0F); - i += sizeof(struct ndpi_dns_packet_header); - query_offset = i; - - if(is_query) { - /* DNS Request */ - if((header.num_queries > 0) && (header.num_queries <= NDPI_MAX_DNS_REQUESTS) - && (((header.flags & 0x2800) == 0x2800 /* Dynamic DNS Update */) - || ((header.answer_rrs == 0) && (header.authority_rrs == 0)))) { - /* This is a good query */ - is_dns = 1; - - if(header.num_queries > 0) { - while(i < packet->payload_packet_len) { - if(packet->payload[i] == '\0') { - i++; - flow->protos.dns.query_type = get16(&i, packet->payload); - break; - } else - i++; - } - } - } - } else { - /* DNS Reply */ - - flow->server_id = flow->dst; - - if((header.num_queries <= NDPI_MAX_DNS_REQUESTS) /* Don't assume that num_queries must be zero */ - && (((header.answer_rrs > 0) && (header.answer_rrs <= NDPI_MAX_DNS_REQUESTS)) - || ((header.authority_rrs > 0) && (header.authority_rrs <= NDPI_MAX_DNS_REQUESTS)) - || ((header.additional_rrs > 0) && (header.additional_rrs <= NDPI_MAX_DNS_REQUESTS))) - ) { - /* This is a good reply */ - is_dns = 1; - - i++; - - if(packet->payload[i] != '\0') { - while((i < packet->payload_packet_len) - && (packet->payload[i] != '\0')) { - i++; - } - - i++; - } - - i += 4; - - if(header.answer_rrs > 0) { - u_int16_t rsp_type; - u_int16_t num; - - for(num = 0; num < header.answer_rrs; num++) { - u_int16_t data_len; - - if((i+6) >= packet->payload_packet_len) { - break; - } - - if((data_len = getNameLength(i, packet->payload, packet->payload_packet_len)) == 0) { - break; - } else - i += data_len; - - rsp_type = get16(&i, packet->payload); - - // Skip past the CLASS (2 octets) and TTL (4 octets) fields. - i += 6; - data_len = get16(&i, packet->payload); - - if((data_len <= 1) || (data_len > (packet->payload_packet_len-i))) { - break; - } - - flow->protos.dns.rsp_type = rsp_type; - - if(rsp_type == 1 /* A */) { - if(data_len == 4) { - u_int32_t v = ntohl(*((u_int32_t*)&packet->payload[i])); - - if(num_a_records < (NDPI_MAX_DNS_REQUESTS-1)) - a_record[num_a_records++] = v; - else - break; /* One record is enough */ - } - } - - if(data_len == 0) { - break; - } + NDPI_LOG(NDPI_PROTOCOL_DNS, ndpi_struct, NDPI_LOG_DEBUG, "search DNS.\n"); - i += data_len; - } /* for */ - } - } + if(flow->packet.udp != NULL) + { + s_port = ntohs(flow->packet.udp->source); + d_port = ntohs(flow->packet.udp->dest); + x = 0; + } + else if(flow->packet.tcp != NULL) /* pkt size > 512 bytes */ + { + s_port = ntohs(flow->packet.tcp->source); + d_port = ntohs(flow->packet.tcp->dest); + x = 2; + } + else + { + NDPI_LOG(NDPI_PROTOCOL_DNS, ndpi_struct, NDPI_LOG_DEBUG, "exclude DNS.\n"); + NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_DNS); + } - if((header.num_queries <= NDPI_MAX_DNS_REQUESTS) - && ((header.answer_rrs == 0) - || (header.authority_rrs == 0) - || (header.additional_rrs == 0)) - && (ret_code != 0 /* 0 == OK */) - ) { - /* This is a good reply */ - is_dns = 1; - } + if((s_port == 53 || d_port == 53 || d_port == 5355) + && (flow->packet.payload_packet_len > sizeof(struct ndpi_dns_packet_header))) + { + struct ndpi_dns_packet_header * dns_header = (struct ndpi_dns_packet_header*) &flow->packet.payload[x]; + 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); + + /* 0x0000 QUERY */ + if(dns_header->flags & FLAGS_MASK == 0x0000) + is_query = 0; + /* 0x8000 RESPONSE */ + else if(dns_header->flags & FLAGS_MASK != 0x8000) + is_query = 1; + else + { + NDPI_LOG(NDPI_PROTOCOL_DNS, ndpi_struct, NDPI_LOG_DEBUG, "exclude DNS.\n"); + NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_DNS); } - - if(is_dns) { - int j = 0; - int size_host_server_name = sizeof(flow->host_server_name); - - flow->protos.dns.num_queries = (u_int8_t)header.num_queries, - flow->protos.dns.num_answers = (u_int8_t)(header.answer_rrs+header.authority_rrs+header.additional_rrs), - flow->protos.dns.ret_code = ret_code; - - i = query_offset+1; - - while((i < packet->payload_packet_len) - && (j < (size_host_server_name-1)) - && (packet->payload[i] != '\0')) { - flow->host_server_name[j] = tolower(packet->payload[i]); - if(flow->host_server_name[j] < ' ') - flow->host_server_name[j] = '.'; - j++, i++; - } - - if(a_record[0] != 0) { - char a_buf[32]; - int i; - - for(i=0; i<num_a_records && j < size_host_server_name; i++) { - j += snprintf((char*)&flow->host_server_name[j], size_host_server_name-1-j, "%s%s", - (i == 0) ? "@" : ";", - ndpi_intoa_v4(a_record[i], a_buf, sizeof(a_buf))); - } - } - - flow->host_server_name[j] = '\0'; - - if(j > 0) { -#ifdef DEBUG - printf("==> %s\n", flow->host_server_name); -#endif - - if(ndpi_struct->match_dns_host_names) - ndpi_match_host_subprotocol(ndpi_struct, flow, - (char *)flow->host_server_name, - strlen((const char*)flow->host_server_name), - NDPI_PROTOCOL_DNS); - } - - i++; - - memcpy(&flow->protos.dns.query_type, &packet->payload[i], 2); - flow->protos.dns.query_type = ntohs(flow->protos.dns.query_type), i += 2; - - memcpy(&flow->protos.dns.query_class, &packet->payload[i], 2); - flow->protos.dns.query_class = ntohs(flow->protos.dns.query_class), i += 2; - -#ifdef DEBUG - printf("%s [type=%04X][class=%04X]\n", flow->host_server_name, flow->protos.dns.query_type, flow->protos.dns.query_class); -#endif - - if(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(NDPI_PROTOCOL_DNS, ndpi_struct, NDPI_LOG_DEBUG, "found DNS.\n"); - ndpi_set_detected_protocol(ndpi_struct, flow, (dport == 5355) ? NDPI_PROTOCOL_LLMNR : NDPI_PROTOCOL_DNS, NDPI_PROTOCOL_UNKNOWN); - } - } else { - flow->protos.dns.bad_packet = 1; + + /* extract host name server */ + ret_code = (is_query == 0) ? 0 : (dns_header->flags & 0x0F); + int j = 0; + int off = sizeof(struct ndpi_dns_packet_header) + 1; + while((flow->packet.payload[off] != '\0')) + { + flow->host_server_name[j] = flow->packet.payload[off]; + if(flow->host_server_name[j] < ' ') + flow->host_server_name[j] = '.'; + off++; + j++; + } + flow->host_server_name[j] = '\0'; + + flow->protos.dns.num_answers = (u_int8_t) (dns_header->num_answers + dns_header->authority_rrs + dns_header->additional_rrs); + flow->protos.dns.ret_code = ret_code; + + if(j > 0) + ndpi_match_host_subprotocol(ndpi_struct, flow, + (char *)flow->host_server_name, + strlen((const char*)flow->host_server_name), + NDPI_PROTOCOL_DNS); + + 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(NDPI_PROTOCOL_DNS, ndpi_struct, NDPI_LOG_DEBUG, "found DNS.\n"); + ndpi_set_detected_protocol(ndpi_struct, flow, (d_port == 5355) ? NDPI_PROTOCOL_LLMNR : NDPI_PROTOCOL_DNS, NDPI_PROTOCOL_UNKNOWN); + } + else + { NDPI_LOG(NDPI_PROTOCOL_DNS, ndpi_struct, NDPI_LOG_DEBUG, "exclude DNS.\n"); NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_DNS); } } } - 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, |