]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
dns: accept gaps in TCP DNS
authorJason Ish <ish@unx.ca>
Mon, 8 May 2017 19:46:00 +0000 (13:46 -0600)
committerVictor Julien <victor@inliniac.net>
Sat, 3 Jun 2017 08:45:35 +0000 (10:45 +0200)
On gap notification a flag is set, on the next call the input
data is reprobed to make sure it can be processed.

src/app-layer-dns-common.h
src/app-layer-dns-tcp.c

index bc20907f6f48464d1e86db5c9b9de50189570287..2e069d0f4b9d098c4de91099baaf067e43d4008a 100644 (file)
@@ -232,6 +232,8 @@ typedef struct DNSState_ {
     uint16_t offset;
     uint16_t record_len;
     uint8_t *buffer;
+    uint8_t gap_ts;               /**< Flag set when a gap has occurred. */
+    uint8_t gap_tc;               /**< Flag set when a gap has occurred. */
 } DNSState;
 
 #define DNS_CONFIG_DEFAULT_REQUEST_FLOOD 500
index 21b881764036f4155fb11aceacad181bf5cb394a..cb88232e201570ede4fec69a98f80fcc4ac573c6 100644 (file)
@@ -58,6 +58,9 @@ struct DNSTcpHeader_ {
 } __attribute__((__packed__));
 typedef struct DNSTcpHeader_ DNSTcpHeader;
 
+static uint16_t DNSTcpProbingParser(uint8_t *input, uint32_t ilen,
+        uint32_t *offset);
+
 /** \internal
  *  \param input_len at least enough for the DNSTcpHeader
  */
@@ -288,6 +291,13 @@ static int DNSTCPRequestParse(Flow *f, void *dstate,
     DNSState *dns_state = (DNSState *)dstate;
     SCLogDebug("starting %u", input_len);
 
+    if (input == NULL && input_len > 0) {
+        SCLogDebug("Input is NULL, but len is %"PRIu32": must be a gap.",
+                input_len);
+        dns_state->gap_ts = 1;
+        SCReturnInt(1);
+    }
+
     if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
         SCReturnInt(1);
     }
@@ -301,6 +311,18 @@ static int DNSTCPRequestParse(Flow *f, void *dstate,
         goto insufficient_data;
     }
 
+    /* Clear gap state. */
+    if (dns_state->gap_ts) {
+        if (DNSTcpProbingParser(input, input_len, NULL) == ALPROTO_DNS) {
+            SCLogDebug("New data probed as DNS, clearing gap state.");
+            BufferReset(dns_state);
+            dns_state->gap_ts = 0;
+        } else {
+            SCLogDebug("Unable to sync DNS parser, leaving gap state.");
+            SCReturnInt(1);
+        }
+    }
+
 next_record:
     /* if this is the beginning of a record, we need at least the header */
     if (dns_state->offset == 0 && input_len < sizeof(DNSTcpHeader)) {
@@ -508,6 +530,13 @@ static int DNSTCPResponseParse(Flow *f, void *dstate,
 {
     DNSState *dns_state = (DNSState *)dstate;
 
+    if (input == NULL && input_len > 0) {
+        SCLogDebug("Input is NULL, but len is %"PRIu32": must be a gap.",
+                input_len);
+        dns_state->gap_tc = 1;
+        SCReturnInt(1);
+    }
+
     if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
         SCReturnInt(1);
     }
@@ -521,6 +550,18 @@ static int DNSTCPResponseParse(Flow *f, void *dstate,
         goto insufficient_data;
     }
 
+    /* Clear gap state. */
+    if (dns_state->gap_tc) {
+        if (DNSTcpProbingParser(input, input_len, NULL) == ALPROTO_DNS) {
+            SCLogDebug("New data probed as DNS, clearing gap state.");
+            BufferReset(dns_state);
+            dns_state->gap_tc = 0;
+        } else {
+            SCLogDebug("Unable to sync DNS parser, leaving gap state.");
+            SCReturnInt(1);
+        }
+    }
+
 next_record:
     /* if this is the beginning of a record, we need at least the header */
     if (dns_state->offset == 0 &&  input_len < sizeof(DNSTcpHeader)) {
@@ -712,6 +753,11 @@ void RegisterDNSTCPParsers(void)
         AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_DNS,
                                                                DNSGetAlstateProgressCompletionStatus);
         DNSAppLayerRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_DNS);
+
+        /* This parser accepts gaps. */
+        AppLayerParserRegisterOptionFlags(IPPROTO_TCP, ALPROTO_DNS,
+                APP_LAYER_PARSER_OPT_ACCEPT_GAPS);
+
     } else {
         SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
                   "still on.", proto_name);