From 2047e72cbeabd5304ebae8381aed40f8b162f7d3 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 7 Dec 2013 11:41:45 +0100 Subject: [PATCH] DNS: don't store duplicate queries When an exact duplicate DNS query is received, don't store it in the tx. --- src/app-layer-dns-common.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index e07920d755..d4daf8dc50 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -28,6 +28,7 @@ #ifdef DEBUG #include "util-print.h" #endif +#include "util-memcmp.h" typedef struct DNSConfig_ { uint32_t request_flood; @@ -331,6 +332,26 @@ bad_data: return -1; } +/** \internal + * \brief check the query list to see if we already have this exact query + * \retval bool true or false + */ +static int QueryIsDuplicate(DNSTransaction *tx, const uint8_t *fqdn, const uint16_t fqdn_len, + const uint16_t type, const uint16_t class) { + DNSQueryEntry *q = NULL; + + TAILQ_FOREACH(q, &tx->query_list, next) { + uint8_t *qfqdn = (uint8_t *)q + sizeof(DNSQueryEntry); + + if (q->len == fqdn_len && q->type == type && + q->class == class && + SCMemcmp(qfqdn, fqdn, fqdn_len) == 0) { + return TRUE; + } + } + return FALSE; +} + void DNSStoreQueryInState(DNSState *dns_state, const uint8_t *fqdn, const uint16_t fqdn_len, const uint16_t type, const uint16_t class, const uint16_t tx_id) { @@ -338,19 +359,28 @@ void DNSStoreQueryInState(DNSState *dns_state, const uint8_t *fqdn, const uint16 if (dns_state->givenup) return; - if (dns_state->curr != NULL && dns_state->curr->replied == 0) { + /* find the tx and see if this is an exact duplicate */ + DNSTransaction *tx = DNSTransactionFindByTxId(dns_state, tx_id); + if ((tx != NULL) && (QueryIsDuplicate(tx, fqdn, fqdn_len, type, class) == TRUE)) { + SCLogDebug("query is duplicate"); + return; + } + + /* see if the last tx is unreplied */ + if (dns_state->curr != tx && dns_state->curr != NULL && + dns_state->curr->replied == 0) + { dns_state->curr->reply_lost = 1; dns_state->unreplied_cnt++; /* check flood limit */ if (dns_config.request_flood != 0 && - dns_state->unreplied_cnt > dns_config.request_flood) { + dns_state->unreplied_cnt > dns_config.request_flood) { DNSSetEvent(dns_state, DNS_DECODER_EVENT_FLOODED); dns_state->givenup = 1; } } - DNSTransaction *tx = DNSTransactionFindByTxId(dns_state, tx_id); if (tx == NULL) { tx = DNSTransactionAlloc(tx_id); if (tx == NULL)