]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
ported dns preprocessor
authorRuss Combs <rucombs@cisco.com>
Mon, 30 Mar 2015 16:14:59 +0000 (12:14 -0400)
committerRuss Combs <rucombs@cisco.com>
Mon, 30 Mar 2015 16:14:59 +0000 (12:14 -0400)
22 files changed:
ChangeLog
configure.ac
lua/snort.lua
src/CMakeLists.txt
src/Makefile.am
src/service_inspectors/CMakeLists.txt
src/service_inspectors/Makefile.am
src/service_inspectors/dns/CMakeLists.txt [new file with mode: 0644]
src/service_inspectors/dns/Makefile.am [new file with mode: 0644]
src/service_inspectors/dns/dns.cc [new file with mode: 0644]
src/service_inspectors/dns/dns.h [new file with mode: 0644]
src/service_inspectors/dns/dns_module.cc [new file with mode: 0644]
src/service_inspectors/dns/dns_module.h [new file with mode: 0644]
src/service_inspectors/service_inspectors.cc
src/service_inspectors/ssh/ssh.cc
src/service_inspectors/ssh/ssh.h
src/service_inspectors/ssh/ssh_config.h
tools/snort2lua/preprocessor_states/CMakeLists.txt
tools/snort2lua/preprocessor_states/Makefile.am
tools/snort2lua/preprocessor_states/pps_dns.cc [new file with mode: 0644]
tools/snort2lua/preprocessor_states/preprocessor_api.cc
tools/snort2lua/tests/snort.conf.in

index a02aca8dfa18ccc46d5e3b2eeb2bde542ac4688e..f601ac2f8a0e453446d81675c5f8dbfae3ced75d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,10 @@
+Pending - build 144
+
+-- ported dns inspector
+
 15/03/26 - build 143
 
--- added ssh inspector
+-- ported ssh inspector
 -- apply service from hosts when inspector already bound to flow
 -- ensure direction and service are applied to packet regardless of flow state
 -- enable active for react / reject only if used in configuration
index 374ecac3f598d09de382e6a379971328aaf450b3..be9a2884c9be23856dd77fb47aaa5f393368ad2a 100644 (file)
@@ -967,6 +967,7 @@ src/packet_io/Makefile \
 src/parser/Makefile \
 src/service_inspectors/Makefile     \
 src/service_inspectors/back_orifice/Makefile \
+src/service_inspectors/dns/Makefile \
 src/service_inspectors/ftp_telnet/Makefile \
 src/service_inspectors/http_inspect/Makefile \
 src/service_inspectors/nhttp_inspect/Makefile \
index 7b84c10f5083eac9d6839c97dc65fbf4ef0825a3..62d9e743b56d9f02110d645f685aca7f46ae9530 100644 (file)
@@ -62,12 +62,13 @@ stream_icmp = { }
 stream_tcp = { }
 stream_udp = { }
 
-perf_monitor = { }
-
 arp_spoof = { }
 back_orifice = { }
-rpc_decode = { }
+dns = { }
+perf_monitor = { }
 port_scan = { }
+rpc_decode = { }
+ssh = { }
 telnet = { }
 
 -- use http_inspect or new_http_inspect (incomplete)
@@ -78,7 +79,5 @@ ftp_server = default_ftp_server
 ftp_client = { }
 ftp_data = { }
 
-ssh = { }
-
 wizard = default_wizard
 
index 015f8570af16b6f7788f6e15bef4b4fed56f48a7..85ffc2d5791e8c7359f2855fdfc75f8942c51802 100644 (file)
@@ -55,6 +55,7 @@ if (STATIC_INSPECTORS)
     set (STATIC_INSPECTOR_LIBRARIES
         arp_spoof
         back_orifice
+        dns
         ftp_telnet
         nhttp_inspect
         rpc_decode
index e66948fba4a420e97aed88f1eed6b702bd71e2fb..432892c4f02efc44451101de273b490354fb44f3 100644 (file)
@@ -10,6 +10,7 @@ if STATIC_INSPECTORS
 lib_list = \
 network_inspectors/arp_spoof/libarp_spoof.a \
 service_inspectors/back_orifice/libback_orifice.a \
+service_inspectors/dns/libdns.a \
 service_inspectors/ftp_telnet/libftp_telnet.a \
 service_inspectors/nhttp_inspect/libnhttp_inspect.a \
 service_inspectors/rpc_decode/librpc_decode.a \
index 44657f3443137e1ee217fcc3f7472f65a9494b8a..df448bbc12e88fca99ddf02f3e8defec3fef17bd 100644 (file)
@@ -1,6 +1,7 @@
 
 add_subdirectory(back_orifice)
 add_subdirectory(ftp_telnet)
+add_subdirectory(dns)
 add_subdirectory(http_inspect)
 add_subdirectory(nhttp_inspect)
 add_subdirectory(rpc_decode)
@@ -11,9 +12,10 @@ if (STATIC_INSPECTORS)
     set (STATIC_INSECTOR_LIBS
         back_orifice
         ftp_telnet
+        dns
         nhttp_inspect
-        ssh
         rpc_decode
+        ssh
         wizard
     )
 endif()
index 3f8b28463a9935d1325177a801aaca57e5f8702f..067ee9aab5d8b440c0bee97aa9f5eb9412a35fcc 100644 (file)
@@ -18,6 +18,7 @@ service_inspectors.h
 
 SUBDIRS = \
 back_orifice \
+dns \
 ftp_telnet \
 http_inspect \
 nhttp_inspect \
diff --git a/src/service_inspectors/dns/CMakeLists.txt b/src/service_inspectors/dns/CMakeLists.txt
new file mode 100644 (file)
index 0000000..94ab376
--- /dev/null
@@ -0,0 +1,15 @@
+
+set( FILE_LIST
+    dns.cc
+    dns.h
+    dns_module.cc
+    dns_module.h
+)
+
+if (STATIC_INSPECTORS)
+    add_library( dns STATIC ${FILE_LIST})
+
+else (STATIC_INSPECTORS)
+    add_shared_library(dns inspectors ${FILE_LIST})
+
+endif (STATIC_INSPECTORS)
diff --git a/src/service_inspectors/dns/Makefile.am b/src/service_inspectors/dns/Makefile.am
new file mode 100644 (file)
index 0000000..72f57bf
--- /dev/null
@@ -0,0 +1,21 @@
+AUTOMAKE_OPTIONS=foreign no-dependencies
+
+file_list = \
+dns.cc \
+dns.h \
+dns_module.cc \
+dns_module.h
+
+if STATIC_INSPECTORS
+noinst_LIBRARIES = libdns.a
+libdns_a_SOURCES = $(file_list)
+else
+shlibdir = $(pkglibdir)/inspectors
+shlib_LTLIBRARIES = libdns.la
+libdns_la_CXXFLAGS = $(AM_CXXFLAGS) -DBUILDING_SO
+libdns_la_LDFLAGS = -export-dynamic -shared
+libdns_la_SOURCES = $(file_list)
+endif
+
+AM_CXXFLAGS = @AM_CXXFLAGS@
+
diff --git a/src/service_inspectors/dns/dns.cc b/src/service_inspectors/dns/dns.cc
new file mode 100644 (file)
index 0000000..c55c7d1
--- /dev/null
@@ -0,0 +1,1173 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2004-2013 Sourcefire, Inc.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+//
+
+/*
+ * DNS preprocessor
+ * Author: Chris Sherwin
+ * Contributors: Adam Keeton, Ryan Jordan
+ *
+ *
+ * Alert for Gobbles, CRC32, protocol mismatch (Cisco catalyst vulnerability),
+ * and a SecureCRT vulnerability.  Will also alert if the client or server
+ * traffic appears to flow the wrong direction, or if packets appear
+ * malformed/spoofed.
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "snort_types.h"
+#include "snort_debug.h"
+
+#include "dns.h"
+#include "dns_module.h"
+#include "profiler.h"
+#include "stream/stream_api.h"
+#include "parser.h"
+#include "framework/inspector.h"
+#include "utils/sfsnprintfappend.h"
+
+THREAD_LOCAL ProfileStats dnsPerfStats;
+THREAD_LOCAL SimpleStats dnsstats;
+
+#define MIN_UDP_PAYLOAD 0x1FFF
+#define DNS_RR_PTR 0xC0
+
+/*
+ * Function prototype(s)
+ */
+static void snort_dns(Packet* p);
+
+unsigned DnsFlowData::flow_id = 0;
+
+DNSData udpSessionData;
+
+DNSData* SetNewDNSData(Packet* p)
+{
+    DnsFlowData* fd;
+
+    if (p->is_udp())
+        return NULL;
+
+    fd = new DnsFlowData;
+
+    p->flow->set_application_data(fd);
+    return &fd->session;
+}
+
+static DNSData* get_dns_session_data(Packet* p)
+{
+    DnsFlowData* fd;
+
+    if (p->is_udp())
+    {
+        if (p->dsize < (sizeof(DNSHdr) + sizeof(DNSRR) + MIN_UDP_PAYLOAD))
+            return NULL;
+
+        memset(&udpSessionData, 0, sizeof(udpSessionData));
+        return &udpSessionData;
+    }
+
+    fd = (DnsFlowData*)((p->flow)->get_application_data(
+        DnsFlowData::flow_id));
+
+    return fd ? &fd->session : NULL;
+}
+
+static uint16_t ParseDNSHeader(const unsigned char* data,
+    uint16_t bytes_unused,
+    DNSData* dnsSessionData)
+{
+    if (bytes_unused == 0)
+    {
+        return bytes_unused;
+    }
+
+    switch (dnsSessionData->state)
+    {
+    case DNS_RESP_STATE_LENGTH:
+        /* First two bytes are length in TCP */
+        dnsSessionData->length = ((uint8_t)*data) << 8;
+        dnsSessionData->state = DNS_RESP_STATE_LENGTH_PART;
+        data++;
+        bytes_unused--;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_LENGTH_PART:
+        dnsSessionData->length |= ((uint8_t)*data);
+        dnsSessionData->state = DNS_RESP_STATE_HDR_ID;
+        data++;
+        bytes_unused--;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_HDR_ID:
+        dnsSessionData->hdr.id = (uint8_t)*data << 8;
+        data++;
+        bytes_unused--;
+        dnsSessionData->state = DNS_RESP_STATE_HDR_ID_PART;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_HDR_ID_PART:
+        dnsSessionData->hdr.id |= (uint8_t)*data;
+        data++;
+        bytes_unused--;
+        dnsSessionData->state = DNS_RESP_STATE_HDR_FLAGS;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_HDR_FLAGS:
+        dnsSessionData->hdr.flags = (uint8_t)*data << 8;
+        data++;
+        bytes_unused--;
+        dnsSessionData->state = DNS_RESP_STATE_HDR_FLAGS_PART;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_HDR_FLAGS_PART:
+        dnsSessionData->hdr.flags |= (uint8_t)*data;
+        data++;
+        bytes_unused--;
+        dnsSessionData->state = DNS_RESP_STATE_HDR_QS;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_HDR_QS:
+        dnsSessionData->hdr.questions = (uint8_t)*data << 8;
+        data++;
+        bytes_unused--;
+        dnsSessionData->state = DNS_RESP_STATE_HDR_QS_PART;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_HDR_QS_PART:
+        dnsSessionData->hdr.questions |= (uint8_t)*data;
+        data++;
+        bytes_unused--;
+        dnsSessionData->state = DNS_RESP_STATE_HDR_ANSS;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_HDR_ANSS:
+        dnsSessionData->hdr.answers = (uint8_t)*data << 8;
+        data++;
+        bytes_unused--;
+        dnsSessionData->state = DNS_RESP_STATE_HDR_ANSS_PART;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_HDR_ANSS_PART:
+        dnsSessionData->hdr.answers |= (uint8_t)*data;
+        data++;
+        bytes_unused--;
+        dnsSessionData->state = DNS_RESP_STATE_HDR_AUTHS;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_HDR_AUTHS:
+        dnsSessionData->hdr.authorities = (uint8_t)*data << 8;
+        data++;
+        bytes_unused--;
+        dnsSessionData->state = DNS_RESP_STATE_HDR_AUTHS_PART;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_HDR_AUTHS_PART:
+        dnsSessionData->hdr.authorities |= (uint8_t)*data;
+        data++;
+        bytes_unused--;
+        dnsSessionData->state = DNS_RESP_STATE_HDR_ADDS;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_HDR_ADDS:
+        dnsSessionData->hdr.additionals = (uint8_t)*data << 8;
+        data++;
+        bytes_unused--;
+        dnsSessionData->state = DNS_RESP_STATE_HDR_ADDS_PART;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_HDR_ADDS_PART:
+        dnsSessionData->hdr.additionals |= (uint8_t)*data;
+        data++;
+        bytes_unused--;
+        dnsSessionData->state = DNS_RESP_STATE_QUESTION;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    default:
+        /* Continue -- we're beyond the header */
+        break;
+    }
+
+    return bytes_unused;
+}
+
+uint16_t ParseDNSName(const unsigned char* data,
+    uint16_t bytes_unused,
+    DNSData* dnsSessionData)
+{
+    uint16_t bytes_required = dnsSessionData->curr_txt.txt_len -
+        dnsSessionData->curr_txt.txt_bytes_seen;
+
+    while (dnsSessionData->curr_txt.name_state != DNS_RESP_STATE_NAME_COMPLETE)
+    {
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+
+        switch (dnsSessionData->curr_txt.name_state)
+        {
+        case DNS_RESP_STATE_NAME_SIZE:
+            dnsSessionData->curr_txt.txt_len = (uint8_t)*data;
+            data++;
+            bytes_unused--;
+            dnsSessionData->bytes_seen_curr_rec++;
+            if (dnsSessionData->curr_txt.txt_len == 0)
+            {
+                dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_NAME_COMPLETE;
+                return bytes_unused;
+            }
+
+            dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_NAME;
+            dnsSessionData->curr_txt.txt_bytes_seen = 0;
+
+            if ((dnsSessionData->curr_txt.txt_len & DNS_RR_PTR) == DNS_RR_PTR)
+            {
+                /* A reference to another location...
+                   This is an offset */
+                dnsSessionData->curr_txt.offset = (dnsSessionData->curr_txt.txt_len & ~0xC0) << 8;
+                bytes_required = dnsSessionData->curr_txt.txt_len = 1;
+                dnsSessionData->curr_txt.relative = 1;
+                /* Setup to read 2nd Byte of Location */
+            }
+            else
+            {
+                bytes_required = dnsSessionData->curr_txt.txt_len;
+                dnsSessionData->curr_txt.offset = 0;
+                dnsSessionData->curr_txt.relative = 0;
+            }
+
+            if (bytes_unused == 0)
+            {
+                return bytes_unused;
+            }
+
+        /* Fall through */
+        case DNS_RESP_STATE_NAME:
+            if (bytes_required <= bytes_unused)
+            {
+                bytes_unused -= bytes_required;
+                if (dnsSessionData->curr_txt.relative)
+                {
+                    /* If this one is a relative offset, read that extra byte */
+                    dnsSessionData->curr_txt.offset |= *data;
+                }
+                data += bytes_required;
+                dnsSessionData->bytes_seen_curr_rec += bytes_required;
+                dnsSessionData->curr_txt.txt_bytes_seen += bytes_required;
+
+                if (bytes_unused == 0)
+                {
+                    return bytes_unused;
+                }
+            }
+            else
+            {
+                dnsSessionData->bytes_seen_curr_rec+= bytes_unused;
+                dnsSessionData->curr_txt.txt_bytes_seen += bytes_unused;
+                return 0;
+            }
+            if (dnsSessionData->curr_txt.relative)
+            {
+                /* And since its relative, we're done */
+                dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_NAME_COMPLETE;
+                return bytes_unused;
+            }
+            break;
+        }
+
+        /* Go to the next portion of the name */
+        dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_NAME_SIZE;
+    }
+
+    return bytes_unused;
+}
+
+static uint16_t ParseDNSQuestion(const unsigned char* data,
+    uint16_t /*data_size*/,
+    uint16_t bytes_unused,
+    DNSData* dnsSessionData)
+{
+    uint16_t bytes_used = 0;
+    uint16_t new_bytes_unused = 0;
+
+    if (bytes_unused == 0)
+    {
+        return bytes_unused;
+    }
+
+    if (dnsSessionData->curr_rec_state < DNS_RESP_STATE_Q_NAME_COMPLETE)
+    {
+        new_bytes_unused = ParseDNSName(data, bytes_unused, dnsSessionData);
+        bytes_used = bytes_unused - new_bytes_unused;
+
+        if (dnsSessionData->curr_txt.name_state == DNS_RESP_STATE_NAME_COMPLETE)
+        {
+            dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_TYPE;
+            memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState));
+            data = data + bytes_used;
+            bytes_unused = new_bytes_unused;
+
+            if (bytes_unused == 0)
+            {
+                /* ran out of data */
+                return bytes_unused;
+            }
+        }
+        else
+        {
+            /* Should be 0 -- ran out of data */
+            return new_bytes_unused;
+        }
+    }
+
+    switch (dnsSessionData->curr_rec_state)
+    {
+    case DNS_RESP_STATE_Q_TYPE:
+        dnsSessionData->curr_q.type = (uint8_t)*data << 8;
+        data++;
+        bytes_unused--;
+        dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_TYPE_PART;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_Q_TYPE_PART:
+        dnsSessionData->curr_q.type |= (uint8_t)*data;
+        data++;
+        bytes_unused--;
+        dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_CLASS;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_Q_CLASS:
+        dnsSessionData->curr_q.dns_class = (uint8_t)*data << 8;
+        data++;
+        bytes_unused--;
+        dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_CLASS_PART;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_Q_CLASS_PART:
+        dnsSessionData->curr_q.dns_class |= (uint8_t)*data;
+        data++;
+        bytes_unused--;
+        dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_COMPLETE;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    default:
+        /* Continue -- we're beyond this question */
+        break;
+    }
+
+    return bytes_unused;
+}
+
+uint16_t ParseDNSAnswer(const unsigned char* data,
+    uint16_t /*data_size*/,
+    uint16_t bytes_unused,
+    DNSData* dnsSessionData)
+{
+    uint16_t bytes_used = 0;
+    uint16_t new_bytes_unused = 0;
+
+    if (bytes_unused == 0)
+    {
+        return bytes_unused;
+    }
+
+    if (dnsSessionData->curr_rec_state < DNS_RESP_STATE_RR_NAME_COMPLETE)
+    {
+        new_bytes_unused = ParseDNSName(data, bytes_unused, dnsSessionData);
+        bytes_used = bytes_unused - new_bytes_unused;
+
+        if (dnsSessionData->curr_txt.name_state == DNS_RESP_STATE_NAME_COMPLETE)
+        {
+            dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_TYPE;
+            memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState));
+            data = data + bytes_used;
+        }
+        bytes_unused = new_bytes_unused;
+
+        if (bytes_unused == 0)
+        {
+            /* ran out of data */
+            return bytes_unused;
+        }
+    }
+
+    switch (dnsSessionData->curr_rec_state)
+    {
+    case DNS_RESP_STATE_RR_TYPE:
+        dnsSessionData->curr_rr.type = (uint8_t)*data << 8;
+        data++;
+        bytes_unused--;
+        dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_TYPE_PART;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_RR_TYPE_PART:
+        dnsSessionData->curr_rr.type |= (uint8_t)*data;
+        data++;
+        bytes_unused--;
+        dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_CLASS;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_RR_CLASS:
+        dnsSessionData->curr_rr.dns_class = (uint8_t)*data << 8;
+        data++;
+        bytes_unused--;
+        dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_CLASS_PART;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_RR_CLASS_PART:
+        dnsSessionData->curr_rr.dns_class |= (uint8_t)*data;
+        data++;
+        bytes_unused--;
+        dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_TTL;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_RR_TTL:
+        dnsSessionData->curr_rr.ttl = (uint8_t)*data << 24;
+        data++;
+        bytes_unused--;
+        dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_TTL_PART;
+        dnsSessionData->bytes_seen_curr_rec = 1;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_RR_TTL_PART:
+        while (dnsSessionData->bytes_seen_curr_rec < 4)
+        {
+            dnsSessionData->bytes_seen_curr_rec++;
+            dnsSessionData->curr_rr.ttl |=
+                (uint8_t)*data << (4-dnsSessionData->bytes_seen_curr_rec)*8;
+            data++;
+            bytes_unused--;
+            if (bytes_unused == 0)
+            {
+                return bytes_unused;
+            }
+        }
+        dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDLENGTH;
+    /* Fall through */
+    case DNS_RESP_STATE_RR_RDLENGTH:
+        dnsSessionData->curr_rr.length = (uint8_t)*data << 8;
+        data++;
+        bytes_unused--;
+        dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDLENGTH_PART;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    case DNS_RESP_STATE_RR_RDLENGTH_PART:
+        dnsSessionData->curr_rr.length |= (uint8_t)*data;
+        data++;
+        bytes_unused--;
+        dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDATA_START;
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+    /* Fall through */
+    default:
+        /* Continue -- we're beyond this answer */
+        break;
+    }
+
+    return bytes_unused;
+}
+
+/* The following check is to look for an attempt to exploit
+ * a vulnerability in the DNS client, per MS 06-041.
+ *
+ * For details, see:
+ * http://www.microsoft.com/technet/security/bulletin/ms06-007.mspx
+ * http://cve.mitre.org/cgi-bin/cvename.cgi?name=2006-3441
+ *
+ * Vulnerability Research by Lurene Grenier, Judy Novak,
+ * and Brian Caswell.
+ */
+uint16_t CheckRRTypeTXTVuln(const unsigned char* data,
+    uint16_t bytes_unused,
+    DNSData* dnsSessionData)
+{
+    uint16_t bytes_required = dnsSessionData->curr_txt.txt_len -
+        dnsSessionData->curr_txt.txt_bytes_seen;
+
+    while (dnsSessionData->curr_txt.name_state != DNS_RESP_STATE_RR_NAME_COMPLETE)
+    {
+        if (dnsSessionData->bytes_seen_curr_rec == dnsSessionData->curr_rr.length)
+        {
+            /* Done with the name */
+            dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_RR_NAME_COMPLETE;
+            /* Got to the end of the rdata in this packet! */
+            dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_COMPLETE;
+            return bytes_unused;
+        }
+
+        if (bytes_unused == 0)
+        {
+            return bytes_unused;
+        }
+
+        switch (dnsSessionData->curr_txt.name_state)
+        {
+        case DNS_RESP_STATE_RR_NAME_SIZE:
+            dnsSessionData->curr_txt.txt_len = (uint8_t)*data;
+            dnsSessionData->curr_txt.txt_count++;
+
+            /* include the NULL */
+            dnsSessionData->curr_txt.total_txt_len += dnsSessionData->curr_txt.txt_len + 1;
+
+            if (!dnsSessionData->curr_txt.alerted)
+            {
+                uint32_t overflow_check = (dnsSessionData->curr_txt.txt_count * 4) +
+                    (dnsSessionData->curr_txt.total_txt_len * 2) + 4;
+                /* if txt_count * 4 + total_txt_len * 2 + 4 > FFFF, vulnerability! */
+                if (overflow_check > 0xFFFF)
+                {
+                    /* Alert on obsolete DNS RR types */
+                    SnortEventqAdd(GID_DNS, DNS_EVENT_RDATA_OVERFLOW);
+
+                    dnsSessionData->curr_txt.alerted = 1;
+                }
+            }
+
+            data++;
+            bytes_unused--;
+            dnsSessionData->bytes_seen_curr_rec++;
+            if (dnsSessionData->curr_txt.txt_len > 0)
+            {
+                dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_RR_NAME;
+                dnsSessionData->curr_txt.txt_bytes_seen = 0;
+                bytes_required = dnsSessionData->curr_txt.txt_len;
+            }
+            else
+            {
+                continue;
+            }
+            if (bytes_unused == 0)
+            {
+                return bytes_unused;
+            }
+        /* Fall through */
+        case DNS_RESP_STATE_RR_NAME:
+            if (bytes_required <= bytes_unused)
+            {
+                bytes_unused -= bytes_required;
+                dnsSessionData->bytes_seen_curr_rec += bytes_required;
+                data += bytes_required;
+                dnsSessionData->curr_txt.txt_bytes_seen += bytes_required;
+                if (bytes_unused == 0)
+                {
+                    return bytes_unused;
+                }
+            }
+            else
+            {
+                dnsSessionData->curr_txt.txt_bytes_seen += bytes_unused;
+                dnsSessionData->bytes_seen_curr_rec += bytes_unused;
+                return 0;
+            }
+            break;
+        }
+
+        /* Go to the next portion of the name */
+        dnsSessionData->curr_txt.name_state = DNS_RESP_STATE_RR_NAME_SIZE;
+    }
+
+    return bytes_unused;
+}
+
+uint16_t SkipDNSRData(const unsigned char* data,
+    uint16_t bytes_unused,
+    DNSData* dnsSessionData)
+{
+    uint16_t bytes_required = dnsSessionData->curr_rr.length - dnsSessionData->bytes_seen_curr_rec;
+
+    if (bytes_required <= bytes_unused)
+    {
+        bytes_unused -= bytes_required;
+        data += bytes_required;
+        dnsSessionData->bytes_seen_curr_rec += bytes_required;
+    }
+    else
+    {
+        dnsSessionData->bytes_seen_curr_rec += bytes_unused;
+        return 0;
+    }
+
+    /* Got to the end of the rdata in this packet! */
+    dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_COMPLETE;
+    return bytes_unused;
+}
+
+uint16_t ParseDNSRData(Packet*,
+    const unsigned char* data,
+    uint16_t bytes_unused,
+    DNSData* dnsSessionData)
+{
+    if (bytes_unused == 0)
+    {
+        return bytes_unused;
+    }
+
+    switch (dnsSessionData->curr_rr.type)
+    {
+    case DNS_RR_TYPE_TXT:
+        /* Check for RData Overflow */
+        bytes_unused = CheckRRTypeTXTVuln(data, bytes_unused, dnsSessionData);
+        break;
+
+    case DNS_RR_TYPE_MD:
+    case DNS_RR_TYPE_MF:
+        /* Alert on obsolete DNS RR types */
+        SnortEventqAdd(GID_DNS, DNS_EVENT_OBSOLETE_TYPES);
+        bytes_unused = SkipDNSRData(data, bytes_unused, dnsSessionData);
+        break;
+
+    case DNS_RR_TYPE_MB:
+    case DNS_RR_TYPE_MG:
+    case DNS_RR_TYPE_MR:
+    case DNS_RR_TYPE_NULL:
+    case DNS_RR_TYPE_MINFO:
+        /* Alert on experimental DNS RR types */
+        SnortEventqAdd(GID_DNS, DNS_EVENT_EXPERIMENTAL_TYPES);
+        bytes_unused = SkipDNSRData(data, bytes_unused, dnsSessionData);
+        break;
+    case DNS_RR_TYPE_A:
+    case DNS_RR_TYPE_NS:
+    case DNS_RR_TYPE_CNAME:
+    case DNS_RR_TYPE_SOA:
+    case DNS_RR_TYPE_WKS:
+    case DNS_RR_TYPE_PTR:
+    case DNS_RR_TYPE_HINFO:
+    case DNS_RR_TYPE_MX:
+        bytes_unused = SkipDNSRData(data, bytes_unused, dnsSessionData);
+        break;
+    default:
+        /* Not one of the known types.  Stop looking at this session
+         * as DNS. */
+        dnsSessionData->flags |= DNS_FLAG_NOT_DNS;
+        break;
+    }
+
+    return bytes_unused;
+}
+
+void ParseDNSResponseMessage(Packet* p, DNSData* dnsSessionData)
+{
+    uint16_t bytes_unused = p->dsize;
+    int i;
+    const unsigned char* data = p->data;
+
+    while (bytes_unused)
+    {
+        /* Parse through the DNS Header */
+        if (dnsSessionData->state < DNS_RESP_STATE_QUESTION)
+        {
+            /* Length only applies on a TCP packet, skip to header ID
+             * if at beginning of a UDP Response.
+             */
+            if ((dnsSessionData->state == DNS_RESP_STATE_LENGTH) &&
+                p->is_udp())
+            {
+                dnsSessionData->state = DNS_RESP_STATE_HDR_ID;
+            }
+
+            bytes_unused = ParseDNSHeader(data, bytes_unused, dnsSessionData);
+            if (bytes_unused > 0)
+            {
+                data = p->data + (p->dsize - bytes_unused);
+            }
+            else
+            {
+                /* No more data */
+                return;
+            }
+
+            dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_NAME;
+            dnsSessionData->curr_rec = 0;
+        }
+
+        /* Print out the header (but only once -- when we're ready to parse the Questions */
+        if ((dnsSessionData->curr_rec_state == DNS_RESP_STATE_Q_NAME) &&
+            (dnsSessionData->curr_rec == 0))
+        {
+            DEBUG_WRAP(
+                DebugMessage(DEBUG_DNS,
+                "DNS Header: length %d, id 0x%x, flags 0x%x, "
+                "questions %d, answers %d, authorities %d, additionals %d\n",
+                dnsSessionData->length, dnsSessionData->hdr.id,
+                dnsSessionData->hdr.flags, dnsSessionData->hdr.questions,
+                dnsSessionData->hdr.answers,
+                dnsSessionData->hdr.authorities,
+                dnsSessionData->hdr.additionals);
+                );
+        }
+
+        if (!(dnsSessionData->hdr.flags & DNS_HDR_FLAG_RESPONSE))
+        {
+            /* Not a response */
+            return;
+        }
+
+        /* Handle the DNS Queries */
+        if (dnsSessionData->state == DNS_RESP_STATE_QUESTION)
+        {
+            /* Skip over the 4 byte question records... */
+            for (i=dnsSessionData->curr_rec; i< dnsSessionData->hdr.questions; i++)
+            {
+                bytes_unused = ParseDNSQuestion(data, p->dsize, bytes_unused, dnsSessionData);
+
+                if (dnsSessionData->curr_rec_state == DNS_RESP_STATE_Q_COMPLETE)
+                {
+                    DEBUG_WRAP(
+                        DebugMessage(DEBUG_DNS,
+                        "DNS Question %d: type %d, class %d\n",
+                        i, dnsSessionData->curr_q.type,
+                        dnsSessionData->curr_q.dns_class);
+                        );
+                    dnsSessionData->curr_rec_state = DNS_RESP_STATE_Q_NAME;
+                    dnsSessionData->curr_rec++;
+                }
+                if (bytes_unused > 0)
+                {
+                    data = p->data + (p->dsize - bytes_unused);
+                }
+                else
+                {
+                    /* No more data */
+                    return;
+                }
+            }
+            dnsSessionData->state = DNS_RESP_STATE_ANS_RR;
+            dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE;
+            dnsSessionData->curr_rec = 0;
+        }
+
+        /* Handle the RRs */
+        switch (dnsSessionData->state)
+        {
+        case DNS_RESP_STATE_ANS_RR: /* ANSWERS section */
+            for (i=dnsSessionData->curr_rec; i<dnsSessionData->hdr.answers; i++)
+            {
+                bytes_unused = ParseDNSAnswer(data, p->dsize,
+                    bytes_unused, dnsSessionData);
+
+                if (bytes_unused == 0)
+                {
+                    /* No more data */
+                    return;
+                }
+
+                switch (dnsSessionData->curr_rec_state)
+                {
+                case DNS_RESP_STATE_RR_RDATA_START:
+                    DEBUG_WRAP(
+                        DebugMessage(DEBUG_DNS,
+                        "DNS ANSWER RR %d: type %d, class %d, "
+                        "ttl %d rdlength %d\n", i,
+                        dnsSessionData->curr_rr.type,
+                        dnsSessionData->curr_rr.dns_class,
+                        dnsSessionData->curr_rr.ttl,
+                        dnsSessionData->curr_rr.length);
+                        );
+
+                    dnsSessionData->bytes_seen_curr_rec = 0;
+                    dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDATA_MID;
+                /* Fall through */
+                case DNS_RESP_STATE_RR_RDATA_MID:
+                    /* Data now points to the beginning of the RDATA */
+                    data = p->data + (p->dsize - bytes_unused);
+                    bytes_unused = ParseDNSRData(p, data, bytes_unused, dnsSessionData);
+                    if (dnsSessionData->curr_rec_state != DNS_RESP_STATE_RR_COMPLETE)
+                    {
+                        /* Out of data, pick up on the next packet */
+                        return;
+                    }
+                    else
+                    {
+                        /* Go to the next record */
+                        dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE;
+                        dnsSessionData->curr_rec++;
+
+                        if (dnsSessionData->curr_rr.type == DNS_RR_TYPE_TXT)
+                        {
+                            /* Reset the state tracking for this record */
+                            memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState));
+                        }
+                        data = p->data + (p->dsize - bytes_unused);
+                    }
+                }
+            }
+            dnsSessionData->state = DNS_RESP_STATE_AUTH_RR;
+            dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE;
+            dnsSessionData->curr_rec = 0;
+        /* Fall through */
+        case DNS_RESP_STATE_AUTH_RR: /* AUTHORITIES section */
+            for (i=dnsSessionData->curr_rec; i<dnsSessionData->hdr.authorities; i++)
+            {
+                bytes_unused = ParseDNSAnswer(data, p->dsize,
+                    bytes_unused, dnsSessionData);
+
+                if (bytes_unused == 0)
+                {
+                    /* No more data */
+                    return;
+                }
+
+                switch (dnsSessionData->curr_rec_state)
+                {
+                case DNS_RESP_STATE_RR_RDATA_START:
+                    DEBUG_WRAP(
+                        DebugMessage(DEBUG_DNS,
+                        "DNS AUTH RR %d: type %d, class %d, "
+                        "ttl %d rdlength %d\n", i,
+                        dnsSessionData->curr_rr.type,
+                        dnsSessionData->curr_rr.dns_class,
+                        dnsSessionData->curr_rr.ttl,
+                        dnsSessionData->curr_rr.length);
+                        );
+
+                    dnsSessionData->bytes_seen_curr_rec = 0;
+                    dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDATA_MID;
+                /* Fall through */
+                case DNS_RESP_STATE_RR_RDATA_MID:
+                    /* Data now points to the beginning of the RDATA */
+                    data = p->data + (p->dsize - bytes_unused);
+                    bytes_unused = ParseDNSRData(p, data, bytes_unused, dnsSessionData);
+                    if (dnsSessionData->curr_rec_state != DNS_RESP_STATE_RR_COMPLETE)
+                    {
+                        /* Out of data, pick up on the next packet */
+                        return;
+                    }
+                    else
+                    {
+                        /* Go to the next record */
+                        dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE;
+                        dnsSessionData->curr_rec++;
+
+                        if (dnsSessionData->curr_rr.type == DNS_RR_TYPE_TXT)
+                        {
+                            /* Reset the state tracking for this record */
+                            memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState));
+                        }
+                        data = p->data + (p->dsize - bytes_unused);
+                    }
+                }
+            }
+            dnsSessionData->state = DNS_RESP_STATE_ADD_RR;
+            dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE;
+            dnsSessionData->curr_rec = 0;
+        /* Fall through */
+        case DNS_RESP_STATE_ADD_RR: /* ADDITIONALS section */
+            for (i=dnsSessionData->curr_rec; i<dnsSessionData->hdr.authorities; i++)
+            {
+                bytes_unused = ParseDNSAnswer(data, p->dsize,
+                    bytes_unused, dnsSessionData);
+
+                if (bytes_unused == 0)
+                {
+                    /* No more data */
+                    return;
+                }
+
+                switch (dnsSessionData->curr_rec_state)
+                {
+                case DNS_RESP_STATE_RR_RDATA_START:
+                    DEBUG_WRAP(
+                        DebugMessage(DEBUG_DNS,
+                        "DNS ADDITONAL RR %d: type %d, class %d, "
+                        "ttl %d rdlength %d\n", i,
+                        dnsSessionData->curr_rr.type,
+                        dnsSessionData->curr_rr.dns_class,
+                        dnsSessionData->curr_rr.ttl,
+                        dnsSessionData->curr_rr.length);
+                        );
+
+                    dnsSessionData->bytes_seen_curr_rec = 0;
+                    dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_RDATA_MID;
+                /* Fall through */
+                case DNS_RESP_STATE_RR_RDATA_MID:
+                    /* Data now points to the beginning of the RDATA */
+                    data = p->data + (p->dsize - bytes_unused);
+                    bytes_unused = ParseDNSRData(p, data, bytes_unused, dnsSessionData);
+                    if (dnsSessionData->curr_rec_state != DNS_RESP_STATE_RR_COMPLETE)
+                    {
+                        /* Out of data, pick up on the next packet */
+                        return;
+                    }
+                    else
+                    {
+                        /* Go to the next record */
+                        dnsSessionData->curr_rec_state = DNS_RESP_STATE_RR_NAME_SIZE;
+                        dnsSessionData->curr_rec++;
+
+                        if (dnsSessionData->curr_rr.type == DNS_RR_TYPE_TXT)
+                        {
+                            /* Reset the state tracking for this record */
+                            memset(&dnsSessionData->curr_txt, 0, sizeof(DNSNameState));
+                        }
+                        data = p->data + (p->dsize - bytes_unused);
+                    }
+                }
+            }
+            /* Done with this one, onto the next -- may also be in this packet */
+            dnsSessionData->state = DNS_RESP_STATE_LENGTH;
+            dnsSessionData->curr_rec_state = 0;
+            dnsSessionData->curr_rec = 0;
+        }
+    }
+}
+
+static void snort_dns(Packet* p)
+{
+    DNSData* dnsSessionData = NULL;
+    uint8_t direction = 0;
+    PROFILE_VARS;
+
+    /* For TCP, do a few extra checks... */
+    if (p->is_udp())
+    {
+        /* If session picked up mid-stream, do not process further.
+         * Would be almost impossible to tell where we are in the
+         * data stream. */
+        if ( stream.get_session_flags(p->flow) & SSNFLAG_MIDSTREAM )
+        {
+            return;
+        }
+
+        if ( stream.is_stream_sequenced(p->flow, SSN_DIR_FROM_CLIENT) )
+        {
+            return;
+        }
+
+        /* If we're waiting on stream reassembly, don't process this packet. */
+        if ( p->packet_flags & PKT_STREAM_INSERT )
+        {
+            return;
+        }
+    }
+
+    /* Get the direction of the packet. */
+    direction = ( (p->packet_flags & PKT_FROM_SERVER ) ?
+        DNS_DIR_FROM_SERVER : DNS_DIR_FROM_CLIENT );
+
+    MODULE_PROFILE_START(dnsPerfStats);
+
+    /* Attempt to get a previously allocated DNS block. */
+    dnsSessionData = get_dns_session_data(p);
+
+    if (dnsSessionData == NULL)
+    {
+        /* Check the stream session. If it does not currently
+         * have our DNS data-block attached, create one.
+         */
+        dnsSessionData = SetNewDNSData(p);
+
+        if ( !dnsSessionData )
+        {
+            /* Could not get/create the session data for this packet. */
+            MODULE_PROFILE_END(dnsPerfStats);
+            return;
+        }
+    }
+
+    if (dnsSessionData->flags & DNS_FLAG_NOT_DNS)
+    {
+        MODULE_PROFILE_END(dnsPerfStats);
+        return;
+    }
+
+    if (direction == DNS_DIR_FROM_SERVER)
+    {
+        ParseDNSResponseMessage(p, dnsSessionData);
+    }
+
+    MODULE_PROFILE_END(dnsPerfStats);
+}
+
+//-------------------------------------------------------------------------
+// class stuff
+//-------------------------------------------------------------------------
+
+class Dns : public Inspector
+{
+public:
+    Dns(DnsModule*);
+
+    void show(SnortConfig*) override;
+    void eval(Packet*) override;
+};
+
+Dns::Dns(DnsModule*)
+{ }
+
+void Dns::show(SnortConfig*)
+{
+    LogMessage("DNS\n");
+}
+
+void Dns::eval(Packet* p)
+{
+    // precondition - what we registered for
+    assert(p->is_udp() && p->is_tcp() && p->dsize && p->data);
+
+    ++dnsstats.total_packets;
+    snort_dns(p);
+}
+
+//-------------------------------------------------------------------------
+// api stuff
+//-------------------------------------------------------------------------
+
+static Module* mod_ctor()
+{ return new DnsModule; }
+
+static void mod_dtor(Module* m)
+{ delete m; }
+
+static void dns_init()
+{
+    DnsFlowData::init();
+}
+
+static Inspector* dns_ctor(Module* m)
+{
+    DnsModule* mod = (DnsModule*)m;
+    return new Dns(mod);
+}
+
+static void dns_dtor(Inspector* p)
+{
+    delete p;
+}
+
+const InspectApi dns_api =
+{
+    {
+        PT_INSPECTOR,
+        sizeof(InspectApi),
+        INSAPI_VERSION,
+        0,
+        API_RESERVED,
+        API_OPTIONS,
+        DNS_NAME,
+        DNS_HELP,
+        mod_ctor,
+        mod_dtor
+    },
+    IT_SERVICE,
+    (uint16_t)PktType::TCP | (uint16_t)PktType::UDP,
+    nullptr, // buffers
+    "dns",
+    dns_init,
+    nullptr, // pterm
+    nullptr, // tinit
+    nullptr, // tterm
+    dns_ctor,
+    dns_dtor,
+    nullptr, // ssn
+    nullptr  // reset
+};
+
+#ifdef BUILDING_SO
+SO_PUBLIC const BaseApi* snort_plugins[] =
+{
+    &dns_api.base,
+    nullptr
+};
+#else
+const BaseApi* sin_dns = &dns_api.base;
+#endif
+
diff --git a/src/service_inspectors/dns/dns.h b/src/service_inspectors/dns/dns.h
new file mode 100644 (file)
index 0000000..11a6dc2
--- /dev/null
@@ -0,0 +1,201 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2004-2013 Sourcefire, Inc.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+//
+
+/*
+ * dns.h: Definitions, structs, function prototype(s) for
+ *             the DNS service inspectors.
+ * Author: Chris Sherwin
+ */
+
+#ifndef DNS_H
+#define DNS_H
+
+#include "protocols/packet.h"
+#include "stream/stream_api.h"
+#include "profiler.h"
+
+/*
+ * Directional defines
+ */
+#define DNS_DIR_FROM_SERVER 1
+#define DNS_DIR_FROM_CLIENT 2
+
+/****** A few data structures ******/
+typedef struct _DNSHdr
+{
+    uint16_t id;
+    uint16_t flags;
+    uint16_t questions;
+    uint16_t answers;
+    uint16_t authorities;
+    uint16_t additionals;
+} DNSHdr;
+
+#define DNS_HDR_FLAG_REPLY_CODE_MASK        0x000F
+#define DNS_HDR_FLAG_NON_AUTHENTICATED_OK   0x0010
+#define DNS_HDR_FLAG_ANS_AUTHENTICATED      0x0020
+#define DNS_HDR_FLAG_RESERVED               0x0040
+#define DNS_HDR_FLAG_RECURSION_AVAIL        0x0080
+#define DNS_HDR_FLAG_RECURSION_DESIRED      0x0100
+#define DNS_HDR_FLAG_TRUNCATED              0x0200
+#define DNS_HDR_FLAG_AUTHORITATIVE          0x0400
+#define DNS_HDR_FLAG_OPCODE_MASK            0x7800
+#define DNS_HDR_FLAG_RESPONSE               0x8000
+
+typedef struct _DNSQuestion
+{
+    uint16_t type;
+    uint16_t dns_class;
+} DNSQuestion;
+
+typedef struct _DNSRR
+{
+    uint16_t type;
+    uint16_t dns_class;
+    uint32_t ttl;
+    uint16_t length;
+} DNSRR;
+
+typedef struct _DNSNameState
+{
+    uint32_t txt_count;
+    uint32_t total_txt_len;
+    uint8_t txt_len;
+    uint8_t txt_bytes_seen;
+    uint8_t name_state;
+    uint8_t alerted;
+    uint16_t offset;
+    uint8_t relative;
+} DNSNameState;
+
+#define DNS_RR_TYPE_A                       0x0001
+#define DNS_RR_TYPE_NS                      0x0002
+#define DNS_RR_TYPE_MD                      0x0003 /* obsolete */
+#define DNS_RR_TYPE_MF                      0x0004 /* obsolete */
+#define DNS_RR_TYPE_CNAME                   0x0005
+#define DNS_RR_TYPE_SOA                     0x0006
+#define DNS_RR_TYPE_MB                      0x0007 /* experimental */
+#define DNS_RR_TYPE_MG                      0x0008 /* experimental */
+#define DNS_RR_TYPE_MR                      0x0009 /* experimental */
+#define DNS_RR_TYPE_NULL                    0x000a /* experimental */
+#define DNS_RR_TYPE_WKS                     0x000b
+#define DNS_RR_TYPE_PTR                     0x000c
+#define DNS_RR_TYPE_HINFO                   0x000d
+#define DNS_RR_TYPE_MINFO                   0x000e /* experimental */
+#define DNS_RR_TYPE_MX                      0x000f
+#define DNS_RR_TYPE_TXT                     0x0010
+
+#define DNS_FLAG_NOT_DNS                0x01
+
+/* DNSSessionData States */
+#define DNS_RESP_STATE_LENGTH           0x00 /* 2 bytes - TCP only*/
+#define DNS_RESP_STATE_LENGTH_PART      0x01 /* Partial length */
+
+#define DNS_RESP_STATE_HDR              0x10 /* 12 bytes */
+#define DNS_RESP_STATE_HDR_ID           0x11 /*  (2 bytes) */
+#define DNS_RESP_STATE_HDR_ID_PART      0x12 /*  (2 bytes) */
+#define DNS_RESP_STATE_HDR_FLAGS        0x13 /*  (2 bytes) */
+#define DNS_RESP_STATE_HDR_FLAGS_PART   0x14 /*  (2 bytes) */
+#define DNS_RESP_STATE_HDR_QS           0x15 /*  (2 bytes) */
+#define DNS_RESP_STATE_HDR_QS_PART      0x16 /*  (2 bytes) */
+#define DNS_RESP_STATE_HDR_ANSS         0x17 /*  (2 bytes) */
+#define DNS_RESP_STATE_HDR_ANSS_PART    0x18 /*  (2 bytes) */
+#define DNS_RESP_STATE_HDR_AUTHS        0x19 /*  (2 bytes) */
+#define DNS_RESP_STATE_HDR_AUTHS_PART   0x1a /*  (2 bytes) */
+#define DNS_RESP_STATE_HDR_ADDS         0x1b /*  (2 bytes) */
+#define DNS_RESP_STATE_HDR_ADDS_PART    0x1c /*  (2 bytes) */
+
+#define DNS_RESP_STATE_QUESTION         0x20 /* 4 bytes */
+#define DNS_RESP_STATE_Q_NAME           0x21 /* (size depends on data) */
+#define DNS_RESP_STATE_Q_NAME_COMPLETE  0x22 /* (size depends on data) */
+#define DNS_RESP_STATE_Q_TYPE           0x23 /*  (2 bytes) */
+#define DNS_RESP_STATE_Q_TYPE_PART      0x24 /*  (2 bytes) */
+#define DNS_RESP_STATE_Q_CLASS          0x25 /*  (2 bytes) */
+#define DNS_RESP_STATE_Q_CLASS_PART     0x26 /*  (2 bytes) */
+#define DNS_RESP_STATE_Q_COMPLETE       0x27
+
+#define DNS_RESP_STATE_NAME_SIZE        0x31 /* (1 byte) */
+#define DNS_RESP_STATE_NAME             0x32 /* (size depends on field) */
+#define DNS_RESP_STATE_NAME_COMPLETE    0x33
+
+#define DNS_RESP_STATE_ANS_RR           0x40 /* (size depends on field) */
+#define DNS_RESP_STATE_RR_NAME_SIZE     0x41 /* (1 byte) */
+#define DNS_RESP_STATE_RR_NAME          0x42 /* (size depends on field) */
+#define DNS_RESP_STATE_RR_NAME_COMPLETE 0x43
+#define DNS_RESP_STATE_RR_TYPE          0x44 /*  (2 bytes) */
+#define DNS_RESP_STATE_RR_TYPE_PART     0x45 /*  (2 bytes) */
+#define DNS_RESP_STATE_RR_CLASS         0x46 /*  (2 bytes) */
+#define DNS_RESP_STATE_RR_CLASS_PART    0x47 /*  (2 bytes) */
+#define DNS_RESP_STATE_RR_TTL           0x48 /*  (4 bytes) */
+#define DNS_RESP_STATE_RR_TTL_PART      0x49 /*  (4 bytes) */
+#define DNS_RESP_STATE_RR_RDLENGTH      0x4a /*  (2 bytes) */
+#define DNS_RESP_STATE_RR_RDLENGTH_PART 0x4b /*  (2 bytes) */
+#define DNS_RESP_STATE_RR_RDATA_START   0x4c /* (size depends on RDLENGTH) */
+#define DNS_RESP_STATE_RR_RDATA_MID     0x4d /* (size depends on RDLENGTH) */
+#define DNS_RESP_STATE_RR_COMPLETE      0x4e
+
+#define DNS_RESP_STATE_AUTH_RR          0x50
+#define DNS_RESP_STATE_ADD_RR           0x60
+
+/*
+ * Per-session data block containing current state
+ * of the DNS preprocessor for the session.
+ *
+ * state:              The current state of the session.
+ * num_records:        Number of records in the session.
+ * curr_record:        Record number for the current record
+ * curr_record_length: Current record length.
+ * total_record_length: Total data length of records.
+ * length:             Total length of DNS response (TCP only)
+ * hdr:                Copy of the data from the DNS Header
+ */
+struct DNSData
+{
+    uint32_t state;
+    uint16_t curr_rec;
+    uint16_t curr_rec_length;
+    uint16_t bytes_seen_curr_rec;
+    uint16_t length;
+    uint8_t curr_rec_state;
+    DNSHdr hdr;
+    DNSQuestion curr_q;
+    DNSRR curr_rr;
+    DNSNameState curr_txt;
+    uint8_t flags;
+};
+
+class DnsFlowData : public FlowData
+{
+public:
+    DnsFlowData() : FlowData(flow_id)
+    { memset(&session, 0, sizeof(session)); }
+
+    ~DnsFlowData() { }
+
+    static void init()
+    { flow_id = FlowData::get_flow_id(); }
+
+public:
+    static unsigned flow_id;
+    DNSData session;
+};
+
+#endif /* DNS_H */
+
diff --git a/src/service_inspectors/dns/dns_module.cc b/src/service_inspectors/dns/dns_module.cc
new file mode 100644 (file)
index 0000000..21e43d4
--- /dev/null
@@ -0,0 +1,67 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// dns_module.cc author Bhagyashree Bantwal <bbantwal@cisco.com>
+
+#include "dns_module.h"
+#include <assert.h>
+#include <sstream>
+#include "main/snort_config.h"
+
+using namespace std;
+
+#define DNS_EVENT_OBSOLETE_TYPES_STR \
+    "Obsolete DNS RR Types"
+#define DNS_EVENT_EXPERIMENTAL_TYPES_STR \
+    "Experimental DNS RR Types"
+#define DNS_EVENT_RDATA_OVERFLOW_STR \
+    "DNS Client rdata txt Overflow"
+
+static const Parameter s_params[] =
+{
+    { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+static const RuleMap dns_rules[] =
+{
+    { DNS_EVENT_OBSOLETE_TYPES, DNS_EVENT_OBSOLETE_TYPES_STR },
+    { DNS_EVENT_EXPERIMENTAL_TYPES, DNS_EVENT_EXPERIMENTAL_TYPES_STR },
+    { DNS_EVENT_RDATA_OVERFLOW, DNS_EVENT_RDATA_OVERFLOW_STR },
+
+    { 0, nullptr }
+};
+
+//-------------------------------------------------------------------------
+// dns module
+//-------------------------------------------------------------------------
+
+DnsModule::DnsModule() : Module(DNS_NAME, DNS_HELP, s_params)
+{ }
+
+const RuleMap* DnsModule::get_rules() const
+{ return dns_rules; }
+
+const PegInfo* DnsModule::get_pegs() const
+{ return simple_pegs; }
+
+PegCount* DnsModule::get_counts() const
+{ return (PegCount*)&dnsstats; }
+
+ProfileStats* DnsModule::get_profile() const
+{ return &dnsPerfStats; }
+
diff --git a/src/service_inspectors/dns/dns_module.h b/src/service_inspectors/dns/dns_module.h
new file mode 100644 (file)
index 0000000..7edba8d
--- /dev/null
@@ -0,0 +1,60 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// dns_module.h author Bhagyashree Bantwal <bbantwal@cisco.com>
+
+#ifndef DNS_MODULE_H
+#define DNS_MODULE_H
+
+#include "framework/module.h"
+#include "framework/bits.h"
+#include "main/thread.h"
+
+#define GID_DNS 131
+
+#define DNS_EVENT_OBSOLETE_TYPES            1
+#define DNS_EVENT_EXPERIMENTAL_TYPES        2
+#define DNS_EVENT_RDATA_OVERFLOW            3
+
+#define DNS_NAME "dns"
+#define DNS_HELP "dns inspection"
+
+struct SnortConfig;
+
+extern THREAD_LOCAL SimpleStats dnsstats;
+extern THREAD_LOCAL ProfileStats dnsPerfStats;
+
+class DnsModule : public Module
+{
+public:
+    DnsModule();
+
+    bool set(const char*, Value&, SnortConfig*) override
+    { return false; }
+
+    unsigned get_gid() const override
+    { return GID_DNS; }
+
+    const RuleMap* get_rules() const override;
+    const PegInfo* get_pegs() const override;
+    PegCount* get_counts() const override;
+    ProfileStats* get_profile() const override;
+};
+
+#endif
+
index dc625cbec6f0a1da9eed275384c1adb2322ab59c..ae4ae7461e4302e44f25f396d803046955c15d36 100644 (file)
@@ -29,6 +29,7 @@ extern const BaseApi* sin_http_inspect;
 
 #ifdef STATIC_INSPECTORS
 extern const BaseApi* sin_bo;
+extern const BaseApi* sin_dns;
 extern const BaseApi* sin_ftp_client;
 extern const BaseApi* sin_ftp_server;
 extern const BaseApi* sin_ftp_data;
@@ -46,6 +47,7 @@ const BaseApi* service_inspectors[] =
 
 #ifdef STATIC_INSPECTORS
     sin_bo,
+    sin_dns,
     sin_ftp_client,
     sin_ftp_server,
     sin_ftp_data,
index d0b74b4fc7b5ae6288ef14d2984fc66c795324bf..1e062513e9262d278eca12df4dd9c9e9cbea97fb 100644 (file)
@@ -363,8 +363,7 @@ static inline int SSHCheckStrlen(char* str, int max)
  * p:    Pointer to the packet to inspect.
  * direction:     Which direction the packet is going.
  *
- * RETURNS:    SSH_SUCCESS, if successfully processed a proto exch msg
- *        SSH_FAILURE, otherwise.
+ * RETURNS:  offset processed
  */
 static unsigned int ProcessSSHProtocolVersionExchange(SSH_PROTO_CONF* config, SSHData* sessionp,
     Packet* p, uint8_t direction)
@@ -444,8 +443,7 @@ static unsigned int ProcessSSHProtocolVersionExchange(SSH_PROTO_CONF* config, SS
  * p:    Pointer to the packet to inspect.
  * direction:     Which direction the packet is going.
  *
- * RETURN:    SSH_SUCCESS, if a valid key exchange message is processed
- *        SSH_FAILURE, otherwise.
+ * RETURNS:  offset processed
  */
 static unsigned int ProcessSSHKeyInitExchange(SSHData* sessionp, Packet* p,
     uint8_t direction, unsigned int offset)
@@ -622,8 +620,7 @@ static unsigned int ProcessSSHKeyInitExchange(SSHData* sessionp, Packet* p,
  * p:    Pointer to the packet to inspect.
  * direction:     Which direction the packet is going.
  *
- * RETURN:    SSH_SUCCESS, if a valid key exchange message is processed
- *        SSH_FAILURE, otherwise.
+ * RETURNS:  offset processed
  */
 static unsigned int ProcessSSHKeyExchange(SSHData* sessionp, Packet* p,
     uint8_t direction, unsigned int offset)
index a2f075b0fa014f8814de7763d9559fb66d478b0d..268ffbb7074ffd8cb3417d9304af0b671712e4fb 100644 (file)
@@ -67,8 +67,6 @@ public:
     SSHData session;
 };
 
-#define SSH_TRUE    (1)
-#define SSH_FALSE   (0)
 
 /*
  *  * Error codes.
@@ -178,32 +176,5 @@ typedef struct _ssh2Packet
 #define SSH_DIR_FROM_SERVER (0x1)
 #define SSH_DIR_FROM_CLIENT (0x2)
 
-/*
- * Keyword strings for parsing configuration options.
- */
-#define SSH_MAX_ENC_PKTS_KEYWORD        "max_encrypted_packets"
-#define SSH_MAX_CLIENT_BYTES_KEYWORD        "max_client_bytes"
-#define SSH_MAX_SERVER_VERSION_KEYWORD  "max_server_version_len"
-#define SSH_ENABLE_RESPOVERFLOW_KEYWORD     "enable_respoverflow"
-#define SSH_ENABLE_CRC32_KEYWORD        "enable_ssh1crc32"
-#define SSH_ENABLE_SECURECRT_KEYWORD        "enable_srvoverflow"
-#define SSH_ENABLE_PROTOMISMATCH_KEYWORD    "enable_protomismatch"
-#define SSH_ENABLE_WRONGDIR_KEYWORD         "enable_badmsgdir"
-#define SSH_ENABLE_PAYLOAD_SIZE         "enable_paysize"
-#define SSH_ENABLE_UNRECOGNIZED_VER     "enable_recognition"
-
-/*
- * SSH alert flags
- */
-#define SSH_ALERT_NONE          (0x0)
-#define SSH_ALERT_RESPOVERFLOW  (0x1)
-#define SSH_ALERT_CRC32         (0x2)
-#define SSH_ALERT_SECURECRT     (0x4)
-#define SSH_ALERT_PROTOMISMATCH (0x8)
-#define SSH_ALERT_WRONGDIR      (0x10)
-#define SSH_ALERT_PAYSIZE       (0x20)
-#define SSH_ALERT_UNRECOGNIZED  (0x40)
-#define SSH_ALERT_ALL           (0xFFFF)
-
 #endif /* SSH_H */
 
index 019c3cd2b838c7cb0c331238edc8278027561c76..e8d6a8061e182fa91c18793064c5cc4cfe17a50f 100644 (file)
 /*
  * Global SSH preprocessor configuration.
  *
- * AutodetectEnabled:  Whether or not to apply auto-detection of SSH
- *                             to ports other than those configured.
  * MaxEncryptedPackets: Maximum number of encrypted packets examined per
  *                             session.
  * MaxClientBytes:     Maximum bytes of encrypted data that can be
  *                             sent by client without a server response.
  * MaxServerVersionLen: Maximum length of a server's version string.
  *              Configurable threshold for Secure CRT-style overflow.
- * EnabledAlerts:   Bit vector describing which alerts are enabled.
  */
 struct SSH_PROTO_CONF
 {
     uint16_t MaxEncryptedPackets;
     uint16_t MaxClientBytes;
     uint16_t MaxServerVersionLen;
-    bool AutodetectEnabled;
 };
 
 #define SSH_DEFAULT_MAX_ENC_PKTS    25
index 56c7ba203119055e877837836e20b2480bec3d8f..67f5a04f533846a4e833c7a220f2f89d29c5aa45 100644 (file)
@@ -13,6 +13,7 @@ add_library(preprocessor_states
     pps_perfmonitor.cc
     pps_rpc_decode.cc
     pps_ssh.cc
+    pps_dns.cc
     pps_sfportscan.cc
     pps_stream5_ip.cc
     pps_stream5_global.cc
index 478d3263517712fd315ea79a158d4f628a5e8fec..d88d0f06e802a4a4798cb428766dfd61bece59ad 100644 (file)
@@ -17,6 +17,7 @@ pps_normalizers.cc \
 pps_perfmonitor.cc \
 pps_rpc_decode.cc \
 pps_ssh.cc \
+pps_dns.cc \
 pps_sfportscan.cc \
 pps_stream5_ip.cc \
 pps_stream5_global.cc \
diff --git a/tools/snort2lua/preprocessor_states/pps_dns.cc b/tools/snort2lua/preprocessor_states/pps_dns.cc
new file mode 100644 (file)
index 0000000..88e4b09
--- /dev/null
@@ -0,0 +1,123 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2015-2015 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// pps_dns.cc author Bhagya Bantwal <bbantwal@cisco.com>
+
+#include <sstream>
+#include <vector>
+
+#include "conversion_state.h"
+#include "helpers/s2l_util.h"
+#include "helpers/util_binder.h"
+
+namespace preprocessors
+{
+namespace
+{
+class Dns : public ConversionState
+{
+public:
+    Dns(Converter& c) : ConversionState(c) { }
+    virtual ~Dns() { }
+    virtual bool convert(std::istringstream& data_stream);
+
+};
+} // namespace
+
+bool Dns::convert(std::istringstream& data_stream)
+{
+    std::string keyword;
+    bool retval = true;
+    bool ports_set = false;
+    Binder bind(table_api);
+
+    bind.set_when_proto("tcp");
+    bind.set_use_type("dns");
+
+    table_api.open_table("dns");
+
+
+    // parse the file configuration
+    while (data_stream >> keyword)
+    {
+        bool tmpval = true;
+
+        if (!keyword.compare("enable_obsolete_types"))
+            table_api.add_deleted_comment("enable_obsolete_types");
+
+        else if (!keyword.compare("enable_experimental_types"))
+            table_api.add_deleted_comment("enable_experimental_types");
+
+        else if (!keyword.compare("enable_rdata_overflow"))
+            table_api.add_deleted_comment("enable_rdata_overflow");
+
+        else if (!keyword.compare("ports"))
+        {
+            std::string tmp = "";
+            table_api.add_diff_option_comment("ports", "bindings");
+
+            if ((data_stream >> keyword) && !keyword.compare("{"))
+            {
+                while (data_stream >> keyword && keyword.compare("}"))
+                {
+                    ports_set = true;
+                    bind.add_when_port(keyword);
+                }
+            }
+            else
+            {
+                data_api.failed_conversion(data_stream, "ports <bracketed_port_list>");
+                retval = false;
+            }
+        }
+
+        else
+        {
+            tmpval = false;
+        }
+
+        if (!tmpval)
+        {
+            data_api.failed_conversion(data_stream, keyword);
+            retval = false;
+        }
+    }
+
+    if (!ports_set)
+        bind.add_when_port("53");
+
+    return retval;
+}
+
+/**************************
+ *******  A P I ***********
+ **************************/
+
+static ConversionState* ctor(Converter& c)
+{
+    return new Dns(c);
+}
+
+static const ConvertMap preprocessor_dns =
+{
+    "dns",
+    ctor,
+};
+
+const ConvertMap* dns_map = &preprocessor_dns;
+}
+
index ac6dcc119351482668b74305798998cfc1259e0b..c8e77a4c9838057cd8b914e7242fb7fb83b0599d 100644 (file)
@@ -39,6 +39,7 @@ extern const ConvertMap* normalizer_tcp_map;
 extern const ConvertMap* perfmonitor_map;
 extern const ConvertMap* rpc_decode_map;
 extern const ConvertMap* ssh_map;
+extern const ConvertMap* dns_map;
 extern const ConvertMap* sfportscan_map;
 extern const ConvertMap* stream_ip_map;
 extern const ConvertMap* stream_global_map;
@@ -65,6 +66,7 @@ const std::vector<const ConvertMap*> preprocessor_api =
     perfmonitor_map,
     rpc_decode_map,
     ssh_map,
+    dns_map,
     sfportscan_map,
     stream_ip_map,
     stream_global_map,
index 253d5cd141363df6c15297fb68edff6c5746a571..c6bcdfc3ff31b7c7b10b8353590da680063deeb3 100644 (file)
@@ -791,7 +791,7 @@ preprocessor ssh: server_ports { 22 } \
 
 #
 # TODO: Add once this is included in Snort++
-#preprocessor dns: ports { 53 } enable_rdata_overflow
+preprocessor dns: ports { 53 } enable_rdata_overflow
 
 
 # TODO: Add once this is included in Snort++