aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/app-layer-dns-tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/suricata/src/app-layer-dns-tcp.c')
-rw-r--r--framework/src/suricata/src/app-layer-dns-tcp.c682
1 files changed, 682 insertions, 0 deletions
diff --git a/framework/src/suricata/src/app-layer-dns-tcp.c b/framework/src/suricata/src/app-layer-dns-tcp.c
new file mode 100644
index 00000000..f1cb597d
--- /dev/null
+++ b/framework/src/suricata/src/app-layer-dns-tcp.c
@@ -0,0 +1,682 @@
+/* Copyright (C) 2013 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * 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
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ * \author Victor Julien <victor@inliniac.net>
+ */
+
+#include "suricata-common.h"
+#include "suricata.h"
+
+#include "debug.h"
+#include "decode.h"
+
+#include "flow-util.h"
+
+#include "threads.h"
+
+#include "util-print.h"
+#include "util-pool.h"
+#include "util-debug.h"
+
+#include "stream-tcp-private.h"
+#include "stream-tcp-reassemble.h"
+#include "stream-tcp.h"
+#include "stream.h"
+
+#include "app-layer-protos.h"
+#include "app-layer-parser.h"
+
+#include "util-spm.h"
+#include "util-unittest.h"
+
+#include "app-layer-dns-tcp.h"
+
+struct DNSTcpHeader_ {
+ uint16_t len;
+ uint16_t tx_id;
+ uint16_t flags;
+ uint16_t questions;
+ uint16_t answer_rr;
+ uint16_t authority_rr;
+ uint16_t additional_rr;
+} __attribute__((__packed__));
+typedef struct DNSTcpHeader_ DNSTcpHeader;
+
+/** \internal
+ * \param input_len at least enough for the DNSTcpHeader
+ */
+static int DNSTCPRequestParseProbe(uint8_t *input, uint32_t input_len)
+{
+#ifdef DEBUG
+ BUG_ON(input_len < sizeof(DNSTcpHeader));
+#endif
+ SCLogDebug("starting %u", input_len);
+
+ DNSTcpHeader *dns_tcp_header = (DNSTcpHeader *)input;
+ if (ntohs(dns_tcp_header->len) < sizeof(DNSHeader)) {
+ goto bad_data;
+ }
+ if (ntohs(dns_tcp_header->len) >= input_len) {
+ goto insufficient_data;
+ }
+
+ input += 2;
+ input_len -= 2;
+ DNSHeader *dns_header = (DNSHeader *)input;
+
+ uint16_t q;
+ const uint8_t *data = input + sizeof(DNSHeader);
+
+ for (q = 0; q < ntohs(dns_header->questions); q++) {
+ uint16_t fqdn_offset = 0;
+
+ if (input + input_len < data + 1) {
+ SCLogDebug("input buffer too small for len field");
+ goto insufficient_data;
+ }
+ SCLogDebug("query length %u", *data);
+
+ while (*data != 0) {
+ if (*data > 63) {
+ /** \todo set event?*/
+ goto bad_data;
+ }
+ uint8_t length = *data;
+
+ data++;
+
+ if (length > 0) {
+ if (input + input_len < data + length) {
+ SCLogDebug("input buffer too small for domain of len %u", length);
+ goto insufficient_data;
+ }
+ //PrintRawDataFp(stdout, data, qry->length);
+
+ if ((fqdn_offset + length + 1) < DNS_MAX_SIZE) {
+ fqdn_offset += length;
+ } else {
+ /** \todo set event? */
+ goto bad_data;
+ }
+ }
+
+ data += length;
+
+ if (input + input_len < data + 1) {
+ SCLogDebug("input buffer too small for new len");
+ goto insufficient_data;
+ }
+
+ SCLogDebug("qry length %u", *data);
+ }
+ if (fqdn_offset) {
+ fqdn_offset--;
+ }
+
+ data++;
+ if (input + input_len < data + sizeof(DNSQueryTrailer)) {
+ SCLogDebug("input buffer too small for DNSQueryTrailer");
+ goto insufficient_data;
+ }
+#ifdef DEBUG
+ DNSQueryTrailer *trailer = (DNSQueryTrailer *)data;
+ SCLogDebug("trailer type %04x class %04x", ntohs(trailer->type), ntohs(trailer->class));
+#endif
+ data += sizeof(DNSQueryTrailer);
+ }
+
+ SCReturnInt(1);
+insufficient_data:
+ SCReturnInt(0);
+bad_data:
+ SCReturnInt(-1);
+}
+
+static int BufferData(DNSState *dns_state, uint8_t *data, uint16_t len)
+{
+ if (dns_state->buffer == NULL) {
+ if (DNSCheckMemcap(0xffff, dns_state) < 0)
+ return -1;
+
+ /** \todo be smarter about this, like use a pool or several pools for
+ * chunks of various sizes */
+ dns_state->buffer = SCMalloc(0xffff);
+ if (dns_state->buffer == NULL) {
+ return -1;
+ }
+ DNSIncrMemcap(0xffff, dns_state);
+ }
+
+ if ((uint32_t)len + (uint32_t)dns_state->offset > (uint32_t)dns_state->record_len) {
+ SCLogDebug("oh my, we have more data than the max record size. What do we do. WHAT DO WE DOOOOO!");
+#ifdef DEBUG
+ BUG_ON(1);
+#endif
+ len = dns_state->record_len - dns_state->offset;
+ }
+
+ memcpy(dns_state->buffer + dns_state->offset, data, len);
+ dns_state->offset += len;
+ return 0;
+}
+
+static void BufferReset(DNSState *dns_state)
+{
+ dns_state->record_len = 0;
+ dns_state->offset = 0;
+}
+
+static int DNSRequestParseData(Flow *f, DNSState *dns_state, const uint8_t *input, const uint32_t input_len)
+{
+ DNSHeader *dns_header = (DNSHeader *)input;
+
+ if (DNSValidateRequestHeader(dns_state, dns_header) < 0)
+ goto bad_data;
+
+ //SCLogInfo("ID %04x", ntohs(dns_header->tx_id));
+
+ uint16_t q;
+ const uint8_t *data = input + sizeof(DNSHeader);
+
+ //PrintRawDataFp(stdout, (uint8_t*)data, input_len - (data - input));
+
+ for (q = 0; q < ntohs(dns_header->questions); q++) {
+ uint8_t fqdn[DNS_MAX_SIZE];
+ uint16_t fqdn_offset = 0;
+
+ if (input + input_len < data + 1) {
+ SCLogDebug("input buffer too small for DNSTcpQuery");
+ goto insufficient_data;
+ }
+ SCLogDebug("query length %u", *data);
+
+ while (*data != 0) {
+ if (*data > 63) {
+ /** \todo set event?*/
+ goto insufficient_data;
+ }
+ uint8_t length = *data;
+
+ data++;
+
+ if (length > 0) {
+ if (input + input_len < data + length) {
+ SCLogDebug("input buffer too small for domain of len %u", length);
+ goto insufficient_data;
+ }
+ //PrintRawDataFp(stdout, data, qry->length);
+
+ if ((size_t)(fqdn_offset + length + 1) < sizeof(fqdn)) {
+ memcpy(fqdn + fqdn_offset, data, length);
+ fqdn_offset += length;
+ fqdn[fqdn_offset++] = '.';
+ } else {
+ /** \todo set event? */
+ goto insufficient_data;
+ }
+ }
+
+ data += length;
+
+ if (input + input_len < data + 1) {
+ SCLogDebug("input buffer too small for DNSTcpQuery(2)");
+ goto insufficient_data;
+ }
+
+ SCLogDebug("qry length %u", *data);
+ }
+ if (fqdn_offset) {
+ fqdn_offset--;
+ }
+
+ data++;
+ if (input + input_len < data + sizeof(DNSQueryTrailer)) {
+ SCLogDebug("input buffer too small for DNSQueryTrailer");
+ goto insufficient_data;
+ }
+ DNSQueryTrailer *trailer = (DNSQueryTrailer *)data;
+ SCLogDebug("trailer type %04x class %04x", ntohs(trailer->type), ntohs(trailer->class));
+ data += sizeof(DNSQueryTrailer);
+
+ /* store our data */
+ if (dns_state != NULL) {
+ DNSStoreQueryInState(dns_state, fqdn, fqdn_offset,
+ ntohs(trailer->type), ntohs(trailer->class),
+ ntohs(dns_header->tx_id));
+ }
+ }
+
+ SCReturnInt(1);
+bad_data:
+insufficient_data:
+ SCReturnInt(-1);
+
+}
+
+/** \internal
+ * \brief Parse DNS request packet
+ */
+static int DNSTCPRequestParse(Flow *f, void *dstate,
+ AppLayerParserState *pstate,
+ uint8_t *input, uint32_t input_len,
+ void *local_data)
+{
+ DNSState *dns_state = (DNSState *)dstate;
+ SCLogDebug("starting %u", input_len);
+
+ if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
+ SCReturnInt(1);
+ }
+
+ /** \todo remove this when PP is fixed to enforce ipproto */
+ if (f != NULL && f->proto != IPPROTO_TCP)
+ SCReturnInt(-1);
+
+ /* probably a rst/fin sending an eof */
+ if (input == NULL || input_len == 0) {
+ goto insufficient_data;
+ }
+
+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)) {
+ SCLogDebug("ilen too small, hoped for at least %"PRIuMAX, (uintmax_t)sizeof(DNSTcpHeader));
+ goto insufficient_data;
+ }
+ SCLogDebug("input_len %u offset %u record %u",
+ input_len, dns_state->offset, dns_state->record_len);
+
+ /* this is the first data of this record */
+ if (dns_state->offset == 0) {
+ DNSTcpHeader *dns_tcp_header = (DNSTcpHeader *)input;
+ SCLogDebug("DNS %p", dns_tcp_header);
+
+ if (ntohs(dns_tcp_header->len) < sizeof(DNSHeader)) {
+ /* bogus len, doesn't fit even basic dns header */
+ goto bad_data;
+ } else if (ntohs(dns_tcp_header->len) == (input_len-2)) {
+ /* we have all data, so process w/o buffering */
+ if (DNSRequestParseData(f, dns_state, input+2, input_len-2) < 0)
+ goto bad_data;
+
+ } else if ((input_len-2) > ntohs(dns_tcp_header->len)) {
+ /* we have all data, so process w/o buffering */
+ if (DNSRequestParseData(f, dns_state, input+2, ntohs(dns_tcp_header->len)) < 0)
+ goto bad_data;
+
+ /* treat the rest of the data as a (potential) new record */
+ input += ntohs(dns_tcp_header->len);
+ input_len -= ntohs(dns_tcp_header->len);
+ goto next_record;
+ } else {
+ /* not enough data, store record length and buffer */
+ dns_state->record_len = ntohs(dns_tcp_header->len);
+ BufferData(dns_state, input+2, input_len-2);
+ }
+ } else if (input_len + dns_state->offset < dns_state->record_len) {
+ /* we don't have the full record yet, buffer */
+ BufferData(dns_state, input, input_len);
+ } else if (input_len > (uint32_t)(dns_state->record_len - dns_state->offset)) {
+ /* more data than expected, we may have another record coming up */
+ uint16_t need = (dns_state->record_len - dns_state->offset);
+ BufferData(dns_state, input, need);
+ int r = DNSRequestParseData(f, dns_state, dns_state->buffer, dns_state->record_len);
+ BufferReset(dns_state);
+ if (r < 0)
+ goto bad_data;
+
+ /* treat the rest of the data as a (potential) new record */
+ input += need;
+ input_len -= need;
+ goto next_record;
+ } else {
+ /* implied exactly the amount of data we want
+ * add current to buffer, then inspect buffer */
+ BufferData(dns_state, input, input_len);
+ int r = DNSRequestParseData(f, dns_state, dns_state->buffer, dns_state->record_len);
+ BufferReset(dns_state);
+ if (r < 0)
+ goto bad_data;
+ }
+
+ SCReturnInt(1);
+insufficient_data:
+ SCReturnInt(-1);
+bad_data:
+ SCReturnInt(-1);
+}
+
+static int DNSReponseParseData(Flow *f, DNSState *dns_state, const uint8_t *input, const uint32_t input_len)
+{
+ DNSHeader *dns_header = (DNSHeader *)input;
+
+ if (DNSValidateResponseHeader(dns_state, dns_header) < 0)
+ goto bad_data;
+
+ DNSTransaction *tx = NULL;
+ int found = 0;
+ if ((tx = DNSTransactionFindByTxId(dns_state, ntohs(dns_header->tx_id))) != NULL)
+ found = 1;
+
+ if (!found) {
+ SCLogDebug("DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE");
+ DNSSetEvent(dns_state, DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE);
+ }
+
+ uint16_t q;
+ const uint8_t *data = input + sizeof(DNSHeader);
+ for (q = 0; q < ntohs(dns_header->questions); q++) {
+ uint8_t fqdn[DNS_MAX_SIZE];
+ uint16_t fqdn_offset = 0;
+
+ if (input + input_len < data + 1) {
+ SCLogDebug("input buffer too small for len field");
+ goto insufficient_data;
+ }
+ SCLogDebug("qry length %u", *data);
+
+ while (*data != 0) {
+ uint8_t length = *data;
+ data++;
+
+ if (length > 0) {
+ if (input + input_len < data + length) {
+ SCLogDebug("input buffer too small for domain of len %u", length);
+ goto insufficient_data;
+ }
+ //PrintRawDataFp(stdout, data, length);
+
+ if ((size_t)(fqdn_offset + length + 1) < sizeof(fqdn)) {
+ memcpy(fqdn + fqdn_offset, data, length);
+ fqdn_offset += length;
+ fqdn[fqdn_offset++] = '.';
+ }
+ }
+
+ data += length;
+
+ if (input + input_len < data + 1) {
+ SCLogDebug("input buffer too small for len field");
+ goto insufficient_data;
+ }
+
+ SCLogDebug("length %u", *data);
+ }
+ if (fqdn_offset) {
+ fqdn_offset--;
+ }
+
+ data++;
+ if (input + input_len < data + sizeof(DNSQueryTrailer)) {
+ SCLogDebug("input buffer too small for DNSQueryTrailer");
+ goto insufficient_data;
+ }
+#if DEBUG
+ DNSQueryTrailer *trailer = (DNSQueryTrailer *)data;
+ SCLogDebug("trailer type %04x class %04x", ntohs(trailer->type), ntohs(trailer->class));
+#endif
+ data += sizeof(DNSQueryTrailer);
+ }
+
+ for (q = 0; q < ntohs(dns_header->answer_rr); q++) {
+ data = DNSReponseParse(dns_state, dns_header, q, DNS_LIST_ANSWER,
+ input, input_len, data);
+ if (data == NULL) {
+ goto insufficient_data;
+ }
+ }
+
+ //PrintRawDataFp(stdout, (uint8_t *)data, input_len - (data - input));
+ for (q = 0; q < ntohs(dns_header->authority_rr); q++) {
+ data = DNSReponseParse(dns_state, dns_header, q, DNS_LIST_AUTHORITY,
+ input, input_len, data);
+ if (data == NULL) {
+ goto insufficient_data;
+ }
+ }
+
+ /* parse rcode, e.g. "noerror" or "nxdomain" */
+ uint8_t rcode = ntohs(dns_header->flags) & 0x0F;
+ if (rcode <= DNS_RCODE_NOTZONE) {
+ SCLogDebug("rcode %u", rcode);
+ if (tx != NULL)
+ tx->rcode = rcode;
+ } else {
+ /* this is not invalid, rcodes can be user defined */
+ SCLogDebug("unexpected DNS rcode %u", rcode);
+ }
+
+ if (ntohs(dns_header->flags) & 0x0080) {
+ SCLogDebug("recursion desired");
+ if (tx != NULL)
+ tx->recursion_desired = 1;
+ }
+
+ if (tx != NULL) {
+ tx->replied = 1;
+ }
+
+ SCReturnInt(1);
+bad_data:
+insufficient_data:
+ SCReturnInt(-1);
+}
+
+/** \internal
+ * \brief DNS TCP record parser, entry function
+ *
+ * Parses a DNS TCP record and fills the DNS state
+ *
+ * As TCP records can be 64k we'll have to buffer the data. Streaming parsing
+ * would have been _very_ tricky due to the way names are compressed in DNS
+ *
+ */
+static int DNSTCPResponseParse(Flow *f, void *dstate,
+ AppLayerParserState *pstate,
+ uint8_t *input, uint32_t input_len,
+ void *local_data)
+{
+ DNSState *dns_state = (DNSState *)dstate;
+
+ if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
+ SCReturnInt(1);
+ }
+
+ /** \todo remove this when PP is fixed to enforce ipproto */
+ if (f != NULL && f->proto != IPPROTO_TCP)
+ SCReturnInt(-1);
+
+ /* probably a rst/fin sending an eof */
+ if (input == NULL || input_len == 0) {
+ goto insufficient_data;
+ }
+
+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)) {
+ SCLogDebug("ilen too small, hoped for at least %"PRIuMAX, (uintmax_t)sizeof(DNSTcpHeader));
+ goto insufficient_data;
+ }
+ SCLogDebug("input_len %u offset %u record %u",
+ input_len, dns_state->offset, dns_state->record_len);
+
+ /* this is the first data of this record */
+ if (dns_state->offset == 0) {
+ DNSTcpHeader *dns_tcp_header = (DNSTcpHeader *)input;
+ SCLogDebug("DNS %p", dns_tcp_header);
+
+ if (ntohs(dns_tcp_header->len) == (input_len-2)) {
+ /* we have all data, so process w/o buffering */
+ if (DNSReponseParseData(f, dns_state, input+2, input_len-2) < 0)
+ goto bad_data;
+
+ } else if ((input_len-2) > ntohs(dns_tcp_header->len)) {
+ /* we have all data, so process w/o buffering */
+ if (DNSReponseParseData(f, dns_state, input+2, ntohs(dns_tcp_header->len)) < 0)
+ goto bad_data;
+
+ /* treat the rest of the data as a (potential) new record */
+ input += ntohs(dns_tcp_header->len);
+ input_len -= ntohs(dns_tcp_header->len);
+ goto next_record;
+ } else {
+ /* not enough data, store record length and buffer */
+ dns_state->record_len = ntohs(dns_tcp_header->len);
+ BufferData(dns_state, input+2, input_len-2);
+ }
+ } else if (input_len + dns_state->offset < dns_state->record_len) {
+ /* we don't have the full record yet, buffer */
+ BufferData(dns_state, input, input_len);
+ } else if (input_len > (uint32_t)(dns_state->record_len - dns_state->offset)) {
+ /* more data than expected, we may have another record coming up */
+ uint16_t need = (dns_state->record_len - dns_state->offset);
+ BufferData(dns_state, input, need);
+ int r = DNSReponseParseData(f, dns_state, dns_state->buffer, dns_state->record_len);
+ BufferReset(dns_state);
+ if (r < 0)
+ goto bad_data;
+
+ /* treat the rest of the data as a (potential) new record */
+ input += need;
+ input_len -= need;
+ goto next_record;
+ } else {
+ /* implied exactly the amount of data we want
+ * add current to buffer, then inspect buffer */
+ BufferData(dns_state, input, input_len);
+ int r = DNSReponseParseData(f, dns_state, dns_state->buffer, dns_state->record_len);
+ BufferReset(dns_state);
+ if (r < 0)
+ goto bad_data;
+ }
+ SCReturnInt(1);
+insufficient_data:
+ SCReturnInt(-1);
+bad_data:
+ SCReturnInt(-1);
+}
+
+static uint16_t DNSTcpProbingParser(uint8_t *input, uint32_t ilen, uint32_t *offset)
+{
+ if (ilen == 0 || ilen < sizeof(DNSTcpHeader)) {
+ SCLogDebug("ilen too small, hoped for at least %"PRIuMAX, (uintmax_t)sizeof(DNSTcpHeader));
+ return ALPROTO_UNKNOWN;
+ }
+
+ DNSTcpHeader *dns_header = (DNSTcpHeader *)input;
+ if (ntohs(dns_header->len) < sizeof(DNSHeader)) {
+ /* length field bogus, won't even fit a minimal DNS header. */
+ return ALPROTO_FAILED;
+ } else if (ntohs(dns_header->len) > ilen) {
+ int r = DNSTCPRequestParseProbe(input, ilen);
+ if (r == -1) {
+ /* probing parser told us "bad data", so it's not
+ * DNS */
+ return ALPROTO_FAILED;
+ } else if (ilen > 512) {
+ SCLogDebug("all the parser told us was not enough data, which is expected. Lets assume it's DNS");
+ return ALPROTO_DNS;
+ }
+
+ SCLogDebug("not yet enough info %u > %u", ntohs(dns_header->len), ilen);
+ return ALPROTO_UNKNOWN;
+ }
+
+ int r = DNSTCPRequestParseProbe(input, ilen);
+ if (r != 1)
+ return ALPROTO_FAILED;
+
+ SCLogDebug("ALPROTO_DNS");
+ return ALPROTO_DNS;
+}
+
+void RegisterDNSTCPParsers(void)
+{
+ char *proto_name = "dns";
+
+ /** DNS */
+ if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
+ AppLayerProtoDetectRegisterProtocol(ALPROTO_DNS, proto_name);
+
+ if (RunmodeIsUnittests()) {
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP,
+ "53",
+ ALPROTO_DNS,
+ 0, sizeof(DNSTcpHeader),
+ STREAM_TOSERVER,
+ DNSTcpProbingParser);
+ } else {
+ int have_cfg = AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP,
+ proto_name, ALPROTO_DNS,
+ 0, sizeof(DNSTcpHeader),
+ DNSTcpProbingParser);
+ /* if we have no config, we enable the default port 53 */
+ if (!have_cfg) {
+ SCLogWarning(SC_ERR_DNS_CONFIG, "no DNS TCP config found, "
+ "enabling DNS detection on "
+ "port 53.");
+ AppLayerProtoDetectPPRegister(IPPROTO_TCP, "53",
+ ALPROTO_DNS, 0, sizeof(DNSTcpHeader),
+ STREAM_TOSERVER, DNSTcpProbingParser);
+ }
+ }
+ } else {
+ SCLogInfo("Protocol detection and parser disabled for %s protocol.",
+ proto_name);
+ return;
+ }
+
+ if (AppLayerParserConfParserEnabled("tcp", proto_name)) {
+ AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_DNS, STREAM_TOSERVER,
+ DNSTCPRequestParse);
+ AppLayerParserRegisterParser(IPPROTO_TCP , ALPROTO_DNS, STREAM_TOCLIENT,
+ DNSTCPResponseParse);
+ AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_DNS, DNSStateAlloc,
+ DNSStateFree);
+ AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_DNS,
+ DNSStateTransactionFree);
+
+ AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_DNS, DNSGetEvents);
+ AppLayerParserRegisterHasEventsFunc(IPPROTO_TCP, ALPROTO_DNS, DNSHasEvents);
+ AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_DNS,
+ DNSStateHasTxDetectState,
+ DNSGetTxDetectState, DNSSetTxDetectState);
+
+ AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_DNS, DNSGetTx);
+ AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_DNS, DNSGetTxCnt);
+ AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_DNS,
+ DNSGetAlstateProgress);
+ AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_TCP, ALPROTO_DNS,
+ DNSGetAlstateProgressCompletionStatus);
+ DNSAppLayerRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_DNS);
+ } else {
+ SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
+ "still on.", proto_name);
+ }
+
+ return;
+}
+
+/* UNITTESTS */
+#ifdef UNITTESTS
+void DNSTCPParserRegisterTests(void)
+{
+// UtRegisterTest("DNSTCPParserTest01", DNSTCPParserTest01, 1);
+}
+#endif