aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src/app-layer-dns-udp.c
diff options
context:
space:
mode:
authorAshlee Young <ashlee@onosfw.com>2015-09-09 22:21:41 -0700
committerAshlee Young <ashlee@onosfw.com>2015-09-09 22:21:41 -0700
commit8879b125d26e8db1a5633de5a9c692eb2d1c4f83 (patch)
treec7259d85a991b83dfa85ab2e339360669fc1f58e /framework/src/suricata/src/app-layer-dns-udp.c
parent13d05bc8458758ee39cb829098241e89616717ee (diff)
suricata checkin based on commit id a4bce14770beee46a537eda3c3f6e8e8565d5d0a
Change-Id: I9a214fa0ee95e58fc640e50bd604dac7f42db48f
Diffstat (limited to 'framework/src/suricata/src/app-layer-dns-udp.c')
-rw-r--r--framework/src/suricata/src/app-layer-dns-udp.c635
1 files changed, 635 insertions, 0 deletions
diff --git a/framework/src/suricata/src/app-layer-dns-udp.c b/framework/src/suricata/src/app-layer-dns-udp.c
new file mode 100644
index 00000000..e3ee01ff
--- /dev/null
+++ b/framework/src/suricata/src/app-layer-dns-udp.c
@@ -0,0 +1,635 @@
+/* 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 "conf.h"
+#include "util-misc.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-udp.h"
+
+/** \internal
+ * \brief Parse DNS request packet
+ */
+static int DNSUDPRequestParse(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_UDP)
+ SCReturnInt(-1);
+
+ if (input == NULL || input_len == 0 || input_len < sizeof(DNSHeader)) {
+ SCLogDebug("ilen too small, hoped for at least %"PRIuMAX, (uintmax_t)sizeof(DNSHeader));
+ goto insufficient_data;
+ }
+
+ DNSHeader *dns_header = (DNSHeader *)input;
+ SCLogDebug("DNS %p", dns_header);
+
+ if (DNSValidateRequestHeader(dns_state, dns_header) < 0)
+ goto bad_data;
+
+ 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");
+ 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) {
+ break;
+ }
+
+ 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 len(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 DNS UDP record parser, entry function
+ *
+ * Parses a DNS UDP record and fills the DNS state
+ *
+ */
+static int DNSUDPResponseParse(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_UDP)
+ SCReturnInt(-1);
+
+ if (input == NULL || input_len == 0 || input_len < sizeof(DNSHeader)) {
+ SCLogDebug("ilen too small, hoped for at least %"PRIuMAX, (uintmax_t)sizeof(DNSHeader));
+ goto insufficient_data;
+ }
+
+ DNSHeader *dns_header = (DNSHeader *)input;
+ SCLogDebug("DNS %p %04x %04x", dns_header, ntohs(dns_header->tx_id), dns_header->flags);
+
+ 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);
+ }
+
+ if (DNSValidateResponseHeader(dns_state, dns_header) < 0)
+ goto bad_data;
+
+ SCLogDebug("queries %04x", ntohs(dns_header->questions));
+
+ 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");
+ goto insufficient_data;
+ }
+ SCLogDebug("qry length %u", *data);
+
+ while (*data != 0) {
+ uint8_t length = *data;
+ data++;
+
+ if (length == 0)
+ break;
+
+ 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");
+ 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);
+ }
+
+ SCLogDebug("answer_rr %04x", ntohs(dns_header->answer_rr));
+ 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;
+ }
+ }
+
+ SCLogDebug("authority_rr %04x", ntohs(dns_header->authority_rr));
+ 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:
+ DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA);
+ SCReturnInt(-1);
+}
+
+static uint16_t DNSUdpProbingParser(uint8_t *input, uint32_t ilen, uint32_t *offset)
+{
+ if (ilen == 0 || ilen < sizeof(DNSHeader)) {
+ SCLogDebug("ilen too small, hoped for at least %"PRIuMAX, (uintmax_t)sizeof(DNSHeader));
+ return ALPROTO_UNKNOWN;
+ }
+
+ if (DNSUDPRequestParse(NULL, NULL, NULL, input, ilen, NULL) == -1)
+ return ALPROTO_FAILED;
+
+ return ALPROTO_DNS;
+}
+
+static void DNSUDPConfigure(void)
+{
+ uint32_t request_flood = DNS_CONFIG_DEFAULT_REQUEST_FLOOD;
+ uint32_t state_memcap = DNS_CONFIG_DEFAULT_STATE_MEMCAP;
+ uint64_t global_memcap = DNS_CONFIG_DEFAULT_GLOBAL_MEMCAP;
+
+ ConfNode *p = ConfGetNode("app-layer.protocols.dns.request-flood");
+ if (p != NULL) {
+ uint32_t value;
+ if (ParseSizeStringU32(p->val, &value) < 0) {
+ SCLogError(SC_ERR_DNS_CONFIG, "invalid value for request-flood %s", p->val);
+ } else {
+ request_flood = value;
+ }
+ }
+ SCLogInfo("DNS request flood protection level: %u", request_flood);
+ DNSConfigSetRequestFlood(request_flood);
+
+ p = ConfGetNode("app-layer.protocols.dns.state-memcap");
+ if (p != NULL) {
+ uint32_t value;
+ if (ParseSizeStringU32(p->val, &value) < 0) {
+ SCLogError(SC_ERR_DNS_CONFIG, "invalid value for state-memcap %s", p->val);
+ } else {
+ state_memcap = value;
+ }
+ }
+ SCLogInfo("DNS per flow memcap (state-memcap): %u", state_memcap);
+ DNSConfigSetStateMemcap(state_memcap);
+
+ p = ConfGetNode("app-layer.protocols.dns.global-memcap");
+ if (p != NULL) {
+ uint64_t value;
+ if (ParseSizeStringU64(p->val, &value) < 0) {
+ SCLogError(SC_ERR_DNS_CONFIG, "invalid value for global-memcap %s", p->val);
+ } else {
+ global_memcap = value;
+ }
+ }
+ SCLogInfo("DNS global memcap: %"PRIu64, global_memcap);
+ DNSConfigSetGlobalMemcap(global_memcap);
+}
+
+void RegisterDNSUDPParsers(void)
+{
+ char *proto_name = "dns";
+
+ /** DNS */
+ if (AppLayerProtoDetectConfProtoDetectionEnabled("udp", proto_name)) {
+ AppLayerProtoDetectRegisterProtocol(ALPROTO_DNS, proto_name);
+
+ if (RunmodeIsUnittests()) {
+ AppLayerProtoDetectPPRegister(IPPROTO_UDP,
+ "53",
+ ALPROTO_DNS,
+ 0, sizeof(DNSHeader),
+ STREAM_TOSERVER,
+ DNSUdpProbingParser);
+ } else {
+ int have_cfg = AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP,
+ proto_name, ALPROTO_DNS,
+ 0, sizeof(DNSHeader),
+ DNSUdpProbingParser);
+ /* if we have no config, we enable the default port 53 */
+ if (!have_cfg) {
+ SCLogWarning(SC_ERR_DNS_CONFIG, "no DNS UDP config found, "
+ "enabling DNS detection on "
+ "port 53.");
+ AppLayerProtoDetectPPRegister(IPPROTO_UDP, "53",
+ ALPROTO_DNS, 0, sizeof(DNSHeader),
+ STREAM_TOSERVER, DNSUdpProbingParser);
+ }
+ }
+ } else {
+ SCLogInfo("Protocol detection and parser disabled for %s protocol.",
+ proto_name);
+ return;
+ }
+
+ if (AppLayerParserConfParserEnabled("udp", proto_name)) {
+ AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_DNS, STREAM_TOSERVER,
+ DNSUDPRequestParse);
+ AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_DNS, STREAM_TOCLIENT,
+ DNSUDPResponseParse);
+ AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_DNS, DNSStateAlloc,
+ DNSStateFree);
+ AppLayerParserRegisterTxFreeFunc(IPPROTO_UDP, ALPROTO_DNS,
+ DNSStateTransactionFree);
+
+ AppLayerParserRegisterGetEventsFunc(IPPROTO_UDP, ALPROTO_DNS, DNSGetEvents);
+ AppLayerParserRegisterHasEventsFunc(IPPROTO_UDP, ALPROTO_DNS, DNSHasEvents);
+ AppLayerParserRegisterDetectStateFuncs(IPPROTO_UDP, ALPROTO_DNS,
+ DNSStateHasTxDetectState,
+ DNSGetTxDetectState, DNSSetTxDetectState);
+
+ AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_DNS,
+ DNSGetTx);
+ AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_DNS,
+ DNSGetTxCnt);
+ AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP, ALPROTO_DNS,
+ DNSGetAlstateProgress);
+ AppLayerParserRegisterGetStateProgressCompletionStatus(IPPROTO_UDP, ALPROTO_DNS,
+ DNSGetAlstateProgressCompletionStatus);
+
+ DNSAppLayerRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_DNS);
+
+ DNSUDPConfigure();
+ } else {
+ SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
+ "still on.", proto_name);
+ }
+#ifdef UNITTESTS
+ AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_DNS, DNSUDPParserRegisterTests);
+#endif
+}
+
+/* UNITTESTS */
+#ifdef UNITTESTS
+#include "util-unittest-helper.h"
+
+static int DNSUDPParserTest01 (void)
+{
+ int result = 0;
+ /* query: abcdefghijk.com
+ * TTL: 86400
+ * serial 20130422 refresh 28800 retry 7200 exp 604800 min ttl 86400
+ * ns, hostmaster */
+ uint8_t buf[] = { 0x00, 0x3c, 0x85, 0x00, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x0b, 0x61, 0x62, 0x63,
+ 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
+ 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x0f, 0x00,
+ 0x01, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x01,
+ 0x51, 0x80, 0x00, 0x25, 0x02, 0x6e, 0x73, 0x00,
+ 0x0a, 0x68, 0x6f, 0x73, 0x74, 0x6d, 0x61, 0x73,
+ 0x74, 0x65, 0x72, 0xc0, 0x2f, 0x01, 0x33, 0x2a,
+ 0x76, 0x00, 0x00, 0x70, 0x80, 0x00, 0x00, 0x1c,
+ 0x20, 0x00, 0x09, 0x3a, 0x80, 0x00, 0x01, 0x51,
+ 0x80};
+ size_t buflen = sizeof(buf);
+ Flow *f = NULL;
+
+ f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53);
+ if (f == NULL)
+ goto end;
+ f->proto = IPPROTO_UDP;
+ f->alproto = ALPROTO_DNS;
+ f->alstate = DNSStateAlloc();
+
+ int r = DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL);
+ if (r != 1)
+ goto end;
+
+ result = 1;
+end:
+ UTHFreeFlow(f);
+ return (result);
+}
+
+static int DNSUDPParserTest02 (void)
+{
+ int result = 0;
+ uint8_t buf[] = {
+ 0x6D,0x08,0x84,0x80,0x00,0x01,0x00,0x08,0x00,0x00,0x00,0x01,0x03,0x57,0x57,0x57,
+ 0x04,0x54,0x54,0x54,0x54,0x03,0x56,0x56,0x56,0x03,0x63,0x6F,0x6D,0x02,0x79,0x79,
+ 0x00,0x00,0x01,0x00,0x01,0xC0,0x0C,0x00,0x05,0x00,0x01,0x00,0x00,0x0E,0x10,0x00,
+ 0x02,0xC0,0x0C,0xC0,0x31,0x00,0x05,0x00,0x01,0x00,0x00,0x0E,0x10,0x00,0x02,0xC0,
+ 0x31,0xC0,0x3F,0x00,0x05,0x00,0x01,0x00,0x00,0x0E,0x10,0x00,0x02,0xC0,0x3F,0xC0,
+ 0x4D,0x00,0x05,0x00,0x01,0x00,0x00,0x0E,0x10,0x00,0x02,0xC0,0x4D,0xC0,0x5B,0x00,
+ 0x05,0x00,0x01,0x00,0x00,0x0E,0x10,0x00,0x02,0xC0,0x5B,0xC0,0x69,0x00,0x05,0x00,
+ 0x01,0x00,0x00,0x0E,0x10,0x00,0x02,0xC0,0x69,0xC0,0x77,0x00,0x05,0x00,0x01,0x00,
+ 0x00,0x0E,0x10,0x00,0x02,0xC0,0x77,0xC0,0x85,0x00,0x05,0x00,0x01,0x00,0x00,0x0E,
+ 0x10,0x00,0x02,0xC0,0x85,0x00,0x00,0x29,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ };
+ size_t buflen = sizeof(buf);
+ Flow *f = NULL;
+
+ f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53);
+ if (f == NULL)
+ goto end;
+ f->proto = IPPROTO_UDP;
+ f->alproto = ALPROTO_DNS;
+ f->alstate = DNSStateAlloc();
+
+ int r = DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL);
+ if (r != 1)
+ goto end;
+
+ result = 1;
+end:
+ UTHFreeFlow(f);
+ return (result);
+}
+
+static int DNSUDPParserTest03 (void)
+{
+ int result = 0;
+ uint8_t buf[] = {
+ 0x6F,0xB4,0x84,0x80,0x00,0x01,0x00,0x02,0x00,0x02,0x00,0x03,0x03,0x57,0x57,0x77,
+ 0x0B,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x56,0x03,0x55,0x55,0x55,
+ 0x02,0x79,0x79,0x00,0x00,0x01,0x00,0x01,0xC0,0x0C,0x00,0x05,0x00,0x01,0x00,0x00,
+ 0x0E,0x10,0x00,0x02,0xC0,0x10,0xC0,0x34,0x00,0x01,0x00,0x01,0x00,0x00,0x0E,0x10,
+ 0x00,0x04,0xC3,0xEA,0x04,0x19,0xC0,0x34,0x00,0x02,0x00,0x01,0x00,0x00,0x0E,0x10,
+ 0x00,0x0A,0x03,0x6E,0x73,0x31,0x03,0x61,0x67,0x62,0xC0,0x20,0xC0,0x46,0x00,0x02,
+ 0x00,0x01,0x00,0x00,0x0E,0x10,0x00,0x06,0x03,0x6E,0x73,0x32,0xC0,0x56,0xC0,0x52,
+ 0x00,0x01,0x00,0x01,0x00,0x00,0x0E,0x10,0x00,0x04,0xC3,0xEA,0x04,0x0A,0xC0,0x68,
+ 0x00,0x01,0x00,0x01,0x00,0x00,0x0E,0x10,0x00,0x04,0xC3,0xEA,0x05,0x14,0x00,0x00,
+ 0x29,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ };
+ size_t buflen = sizeof(buf);
+ Flow *f = NULL;
+
+ f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53);
+ if (f == NULL)
+ goto end;
+ f->proto = IPPROTO_UDP;
+ f->alproto = ALPROTO_DNS;
+ f->alstate = DNSStateAlloc();
+
+ int r = DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL);
+ if (r != 1)
+ goto end;
+
+ result = 1;
+end:
+ UTHFreeFlow(f);
+ return (result);
+}
+
+/** \test TXT records in answer */
+static int DNSUDPParserTest04 (void)
+{
+ int result = 0;
+ uint8_t buf[] = {
+ 0xc2,0x2f,0x81,0x80,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x0a,0x41,0x41,0x41,
+ 0x41,0x41,0x4f,0x31,0x6b,0x51,0x41,0x05,0x3d,0x61,0x75,0x74,0x68,0x03,0x73,0x72,
+ 0x76,0x06,0x74,0x75,0x6e,0x6e,0x65,0x6c,0x03,0x63,0x6f,0x6d,0x00,0x00,0x10,0x00,
+ 0x01,
+ /* answer record start */
+ 0xc0,0x0c,0x00,0x10,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x22,
+ /* txt record starts: */
+ 0x20, /* <txt len 32 */ 0x41,0x68,0x76,0x4d,0x41,0x41,0x4f,0x31,0x6b,0x41,0x46,
+ 0x45,0x35,0x54,0x45,0x39,0x51,0x54,0x6a,0x46,0x46,0x4e,0x30,0x39,0x52,0x4e,0x31,
+ 0x6c,0x59,0x53,0x44,0x6b,0x00, /* <txt len 0 */ 0xc0,0x1d,0x00,0x02,0x00,0x01,
+ 0x00,0x09,0x3a,0x80,0x00,0x09,0x06,0x69,0x6f,0x64,0x69,0x6e,0x65,0xc0,0x21,0xc0,
+ 0x6b,0x00,0x01,0x00,0x01,0x00,0x09,0x3a,0x80,0x00,0x04,0x0a,0x1e,0x1c,0x5f
+ };
+ size_t buflen = sizeof(buf);
+ Flow *f = NULL;
+
+ f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53);
+ if (f == NULL)
+ goto end;
+ f->proto = IPPROTO_UDP;
+ f->alproto = ALPROTO_DNS;
+ f->alstate = DNSStateAlloc();
+
+ int r = DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL);
+ if (r != 1)
+ goto end;
+
+ result = 1;
+end:
+ UTHFreeFlow(f);
+ return (result);
+}
+
+/** \test TXT records in answer, bad txtlen */
+static int DNSUDPParserTest05 (void)
+{
+ int result = 0;
+ uint8_t buf[] = {
+ 0xc2,0x2f,0x81,0x80,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x0a,0x41,0x41,0x41,
+ 0x41,0x41,0x4f,0x31,0x6b,0x51,0x41,0x05,0x3d,0x61,0x75,0x74,0x68,0x03,0x73,0x72,
+ 0x76,0x06,0x74,0x75,0x6e,0x6e,0x65,0x6c,0x03,0x63,0x6f,0x6d,0x00,0x00,0x10,0x00,
+ 0x01,
+ /* answer record start */
+ 0xc0,0x0c,0x00,0x10,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x22,
+ /* txt record starts: */
+ 0x40, /* <txt len 64 */ 0x41,0x68,0x76,0x4d,0x41,0x41,0x4f,0x31,0x6b,0x41,0x46,
+ 0x45,0x35,0x54,0x45,0x39,0x51,0x54,0x6a,0x46,0x46,0x4e,0x30,0x39,0x52,0x4e,0x31,
+ 0x6c,0x59,0x53,0x44,0x6b,0x00, /* <txt len 0 */ 0xc0,0x1d,0x00,0x02,0x00,0x01,
+ 0x00,0x09,0x3a,0x80,0x00,0x09,0x06,0x69,0x6f,0x64,0x69,0x6e,0x65,0xc0,0x21,0xc0,
+ 0x6b,0x00,0x01,0x00,0x01,0x00,0x09,0x3a,0x80,0x00,0x04,0x0a,0x1e,0x1c,0x5f
+ };
+ size_t buflen = sizeof(buf);
+ Flow *f = NULL;
+
+ f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53);
+ if (f == NULL)
+ goto end;
+ f->proto = IPPROTO_UDP;
+ f->alproto = ALPROTO_DNS;
+ f->alstate = DNSStateAlloc();
+
+ int r = DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL);
+ if (r != -1)
+ goto end;
+
+ result = 1;
+end:
+ UTHFreeFlow(f);
+ return (result);
+}
+
+
+void DNSUDPParserRegisterTests(void)
+{
+ UtRegisterTest("DNSUDPParserTest01", DNSUDPParserTest01, 1);
+ UtRegisterTest("DNSUDPParserTest02", DNSUDPParserTest02, 1);
+ UtRegisterTest("DNSUDPParserTest03", DNSUDPParserTest03, 1);
+ UtRegisterTest("DNSUDPParserTest04", DNSUDPParserTest04, 1);
+ UtRegisterTest("DNSUDPParserTest05", DNSUDPParserTest05, 1);
+}
+#endif