]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
DNS: don't store duplicate queries
authorVictor Julien <victor@inliniac.net>
Sat, 7 Dec 2013 10:41:45 +0000 (11:41 +0100)
committerVictor Julien <victor@inliniac.net>
Mon, 13 Jan 2014 10:19:25 +0000 (11:19 +0100)
When an exact duplicate DNS query is received, don't store it in the
tx.

src/app-layer-dns-common.c

index e07920d755d25f103f260e7b884e5d33b3b5571c..d4daf8dc502dc1e2177d49396fae0f4c06fbf249 100644 (file)
@@ -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)