As some of the C code is still used it can't all be removed.
Redmine issue:
https://redmine.openinfosecfoundation.org/issues/2850
*/
#include "suricata-common.h"
-#include "stream.h"
-#include "app-layer-parser.h"
#include "app-layer-dns-common.h"
-#ifdef DEBUG
-#include "util-print.h"
-#endif
-#include "util-memcmp.h"
-#include "util-atomic.h"
-
-typedef struct DNSConfig_ {
- uint32_t request_flood;
- uint32_t state_memcap; /**< memcap in bytes per state */
- uint64_t global_memcap; /**< memcap in bytes globally for parser */
-} DNSConfig;
-static DNSConfig dns_config;
-
-void DNSConfigInit(void)
-{
- memset(&dns_config, 0x00, sizeof(dns_config));
-}
-
-void DNSConfigSetRequestFlood(uint32_t value)
-{
- dns_config.request_flood = value;
-}
-
-void DNSConfigSetStateMemcap(uint32_t value)
-{
- dns_config.state_memcap = value;
-}
-
-SC_ATOMIC_DECLARE(uint64_t, dns_memuse); /**< byte counter of current memuse */
-SC_ATOMIC_DECLARE(uint64_t, dns_memcap_state); /**< counts number of 'rejects' */
-SC_ATOMIC_DECLARE(uint64_t, dns_memcap_global); /**< counts number of 'rejects' */
-
-void DNSConfigSetGlobalMemcap(uint64_t value)
-{
- dns_config.global_memcap = value;
-
- SC_ATOMIC_INIT(dns_memuse);
- SC_ATOMIC_INIT(dns_memcap_state);
- SC_ATOMIC_INIT(dns_memcap_global);
-}
-
-void DNSIncrMemcap(uint32_t size, DNSState *state)
-{
- if (state != NULL) {
- state->memuse += size;
- }
- SC_ATOMIC_ADD(dns_memuse, size);
-}
-
-void DNSDecrMemcap(uint32_t size, DNSState *state)
-{
- if (state != NULL) {
- BUG_ON(size > state->memuse); /**< TODO remove later */
- state->memuse -= size;
- }
-
- BUG_ON(size > SC_ATOMIC_GET(dns_memuse)); /**< TODO remove later */
- (void)SC_ATOMIC_SUB(dns_memuse, size);
-}
-
-int DNSCheckMemcap(uint32_t want, DNSState *state)
-{
- if (state != NULL) {
- if (state->memuse + want > dns_config.state_memcap) {
- SC_ATOMIC_ADD(dns_memcap_state, 1);
- DNSSetEvent(state, DNS_DECODER_EVENT_STATE_MEMCAP_REACHED);
- return -1;
- }
- }
-
- if (SC_ATOMIC_GET(dns_memuse) + (uint64_t)want > dns_config.global_memcap) {
- SC_ATOMIC_ADD(dns_memcap_global, 1);
- return -2;
- }
-
- return 0;
-}
-
-uint64_t DNSMemcapGetMemuseCounter(void)
-{
- uint64_t x = SC_ATOMIC_GET(dns_memuse);
- return x;
-}
-
-uint64_t DNSMemcapGetMemcapStateCounter(void)
-{
- uint64_t x = SC_ATOMIC_GET(dns_memcap_state);
- return x;
-}
-
-uint64_t DNSMemcapGetMemcapGlobalCounter(void)
-{
- uint64_t x = SC_ATOMIC_GET(dns_memcap_global);
- return x;
-}
SCEnumCharMap dns_decoder_event_table[ ] = {
{ "UNSOLLICITED_RESPONSE", DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE, },
return;
}
-AppLayerDecoderEvents *DNSGetEvents(void *state, uint64_t id)
-{
- DNSState *dns_state = (DNSState *)state;
- DNSTransaction *tx;
-
- if (dns_state->curr && dns_state->curr->tx_num == (id + 1)) {
- return dns_state->curr->decoder_events;
- }
-
- TAILQ_FOREACH(tx, &dns_state->tx_list, next) {
- if (tx->tx_num == (id+1))
- return tx->decoder_events;
- }
- return NULL;
-}
-
-void *DNSGetTx(void *alstate, uint64_t tx_id)
-{
- DNSState *dns_state = (DNSState *)alstate;
- DNSTransaction *tx = NULL;
-
- /* fast track: try the current tx */
- if (dns_state->curr && dns_state->curr->tx_num == tx_id + 1)
- return dns_state->curr;
-
- /* fast track:
- * if the prev tx_id is equal to the stored tx ptr, we can
- * use this shortcut to get to the next. */
- if (dns_state->iter) {
- if (tx_id == dns_state->iter->tx_num) {
- tx = TAILQ_NEXT(dns_state->iter, next);
- if (tx && tx->tx_num == tx_id + 1) {
- dns_state->iter = tx;
- return tx;
- }
- }
- }
-
- /* no luck with the fast tracks, do the full list walk */
- TAILQ_FOREACH(tx, &dns_state->tx_list, next) {
- SCLogDebug("tx->tx_num %u, tx_id %"PRIu64, tx->tx_num, (tx_id+1));
- if ((tx_id+1) != tx->tx_num)
- continue;
-
- SCLogDebug("returning tx %p", tx);
- dns_state->iter = tx;
- return tx;
- }
-
- return NULL;
-}
-
-uint64_t DNSGetTxCnt(void *alstate)
-{
- DNSState *dns_state = (DNSState *)alstate;
- return (uint64_t)dns_state->transaction_max;
-}
-
-int DNSGetAlstateProgress(void *tx, uint8_t direction)
-{
- DNSTransaction *dns_tx = (DNSTransaction *)tx;
- if (direction & STREAM_TOCLIENT) {
- /* response side of the tx is done if we parsed a reply
- * or if we tagged this tx as 'reply lost'. */
- return (dns_tx->replied|dns_tx->reply_lost) ? 1 : 0;
- }
- else {
- /* tx is only created if we have a complete request,
- * or if we lost the request. Either way, if we have
- * a tx it we consider the request complete. */
- return 1;
- }
-}
-
-void DNSSetTxLogged(void *alstate, void *tx, LoggerId logged)
-{
- DNSTransaction *dns_tx = (DNSTransaction *)tx;
- dns_tx->logged = logged;
-}
-
-LoggerId DNSGetTxLogged(void *alstate, void *tx)
-{
- DNSTransaction *dns_tx = (DNSTransaction *)tx;
- return dns_tx->logged;
-}
-
-uint64_t DNSGetTxDetectFlags(void *vtx, uint8_t dir)
-{
- DNSTransaction *tx = (DNSTransaction *)vtx;
- if (dir & STREAM_TOSERVER) {
- return tx->detect_flags_ts;
- } else {
- return tx->detect_flags_tc;
- }
-}
-
-void DNSSetTxDetectFlags(void *vtx, uint8_t dir, uint64_t detect_flags)
-{
- DNSTransaction *tx = (DNSTransaction *)vtx;
- if (dir & STREAM_TOSERVER) {
- tx->detect_flags_ts = detect_flags;
- } else {
- tx->detect_flags_tc = detect_flags;
- }
-}
-
-/** \brief get value for 'complete' status in DNS
- *
- * For DNS we use a simple bool. 1 means done.
- */
-int DNSGetAlstateProgressCompletionStatus(uint8_t direction)
-{
- return 1;
-}
-
-void DNSSetEvent(DNSState *s, uint8_t e)
-{
- if (s && s->curr) {
- SCLogDebug("s->curr->decoder_events %p", s->curr->decoder_events);
- AppLayerDecoderEventsSetEventRaw(&s->curr->decoder_events, e);
- SCLogDebug("s->curr->decoder_events %p", s->curr->decoder_events);
- s->events++;
- } else {
- SCLogDebug("couldn't set event %u", e);
- }
-}
-
-/** \internal
- * \brief Allocate a DNS TX
- * \retval tx or NULL */
-static DNSTransaction *DNSTransactionAlloc(DNSState *state, const uint16_t tx_id)
-{
- if (DNSCheckMemcap(sizeof(DNSTransaction), state) < 0)
- return NULL;
-
- DNSTransaction *tx = SCMalloc(sizeof(DNSTransaction));
- if (unlikely(tx == NULL))
- return NULL;
- DNSIncrMemcap(sizeof(DNSTransaction), state);
-
- memset(tx, 0x00, sizeof(DNSTransaction));
-
- TAILQ_INIT(&tx->query_list);
- TAILQ_INIT(&tx->answer_list);
- TAILQ_INIT(&tx->authority_list);
-
- tx->tx_id = tx_id;
- return tx;
-}
-
-/** \internal
- * \brief Free a DNS TX
- * \param tx DNS TX to free */
-static void DNSTransactionFree(DNSTransaction *tx, DNSState *state)
-{
- SCEnter();
-
- DNSQueryEntry *q = NULL;
- while ((q = TAILQ_FIRST(&tx->query_list))) {
- TAILQ_REMOVE(&tx->query_list, q, next);
- DNSDecrMemcap((sizeof(DNSQueryEntry) + q->len), state);
- SCFree(q);
- }
-
- DNSAnswerEntry *a = NULL;
- while ((a = TAILQ_FIRST(&tx->answer_list))) {
- TAILQ_REMOVE(&tx->answer_list, a, next);
- DNSDecrMemcap((sizeof(DNSAnswerEntry) + a->fqdn_len + a->data_len), state);
- SCFree(a);
- }
- while ((a = TAILQ_FIRST(&tx->authority_list))) {
- TAILQ_REMOVE(&tx->authority_list, a, next);
- DNSDecrMemcap((sizeof(DNSAnswerEntry) + a->fqdn_len + a->data_len), state);
- SCFree(a);
- }
-
- AppLayerDecoderEventsFreeEvents(&tx->decoder_events);
-
- if (tx->de_state != NULL) {
- DetectEngineStateFree(tx->de_state);
- }
-
- if (state->iter == tx)
- state->iter = NULL;
-
- DNSDecrMemcap(sizeof(DNSTransaction), state);
- SCFree(tx);
- SCReturn;
-}
-
-/**
- * \brief dns transaction cleanup callback
- */
-void DNSStateTransactionFree(void *state, uint64_t tx_id)
-{
- SCEnter();
-
- DNSState *dns_state = state;
- DNSTransaction *tx = NULL;
-
- SCLogDebug("state %p, id %"PRIu64, dns_state, tx_id);
-
- TAILQ_FOREACH(tx, &dns_state->tx_list, next) {
- SCLogDebug("tx %p tx->tx_num %u, tx_id %"PRIu64, tx, tx->tx_num, (tx_id+1));
- if ((tx_id+1) < tx->tx_num)
- break;
- else if ((tx_id+1) > tx->tx_num)
- continue;
-
- if (tx == dns_state->curr)
- dns_state->curr = NULL;
-
- if (tx->decoder_events != NULL) {
- if (tx->decoder_events->cnt <= dns_state->events)
- dns_state->events -= tx->decoder_events->cnt;
- else
- dns_state->events = 0;
- }
-
- TAILQ_REMOVE(&dns_state->tx_list, tx, next);
- DNSTransactionFree(tx, state);
- break;
- }
- SCReturn;
-}
-
-/** \internal
- * \brief Find the DNS Tx in the state
- * \param tx_id id of the tx
- * \retval tx or NULL if not found */
-DNSTransaction *DNSTransactionFindByTxId(const DNSState *dns_state, const uint16_t tx_id)
-{
- if (dns_state->curr == NULL)
- return NULL;
-
- /* fast path */
- if (dns_state->curr->tx_id == tx_id) {
- return dns_state->curr;
-
- /* slow path, iterate list */
- } else {
- DNSTransaction *tx = NULL;
- TAILQ_FOREACH(tx, &dns_state->tx_list, next) {
- if (tx->tx_id == tx_id) {
- return tx;
- } else if ((dns_state->transaction_max - tx->tx_num) >
- (dns_state->window - 1U)) {
- tx->reply_lost = 1;
- }
- }
- }
- /* not found */
- return NULL;
-}
-
-DetectEngineState *DNSGetTxDetectState(void *vtx)
-{
- DNSTransaction *tx = (DNSTransaction *)vtx;
- return tx->de_state;
-}
-
-int DNSSetTxDetectState(void *vtx, DetectEngineState *s)
-{
- DNSTransaction *tx = (DNSTransaction *)vtx;
- tx->de_state = s;
- return 0;
-}
-
-void *DNSStateAlloc(void)
-{
- void *s = SCMalloc(sizeof(DNSState));
- if (unlikely(s == NULL))
- return NULL;
-
- memset(s, 0, sizeof(DNSState));
-
- DNSState *dns_state = (DNSState *)s;
-
- DNSIncrMemcap(sizeof(DNSState), dns_state);
-
- TAILQ_INIT(&dns_state->tx_list);
- return s;
-}
-
-void DNSStateFree(void *s)
-{
- SCEnter();
- if (s) {
- DNSState *dns_state = (DNSState *) s;
-
- DNSTransaction *tx = NULL;
- while ((tx = TAILQ_FIRST(&dns_state->tx_list))) {
- TAILQ_REMOVE(&dns_state->tx_list, tx, next);
- DNSTransactionFree(tx, dns_state);
- }
-
- if (dns_state->buffer != NULL) {
- DNSDecrMemcap(0xffff, dns_state); /** TODO update if/once we alloc
- * in a smarter way */
- SCFree(dns_state->buffer);
- }
-
- DNSDecrMemcap(sizeof(DNSState), dns_state);
- BUG_ON(dns_state->memuse > 0);
- SCFree(s);
- }
- SCReturn;
-}
-
-/** \brief Validation checks for DNS request header
- *
- * Will set decoder events if anomalies are found.
- *
- * \retval 0 ok
- * \retval -1 error
- */
-int DNSValidateRequestHeader(DNSState *dns_state, const DNSHeader *dns_header)
-{
- uint16_t flags = SCNtohs(dns_header->flags);
-
- if ((flags & 0x8000) != 0) {
- SCLogDebug("not a request 0x%04x", flags);
- DNSSetEvent(dns_state, DNS_DECODER_EVENT_NOT_A_REQUEST);
- goto bad_data;
- }
-
- if ((flags & 0x0040) != 0) {
- SCLogDebug("Z flag not 0, 0x%04x", flags);
- DNSSetEvent(dns_state, DNS_DECODER_EVENT_Z_FLAG_SET);
- goto bad_data;
- }
-
- return 0;
-bad_data:
- return -1;
-}
-
-/** \brief Validation checks for DNS response header
- *
- * Will set decoder events if anomalies are found.
- *
- * \retval 0 ok
- * \retval -1 error
- */
-int DNSValidateResponseHeader(DNSState *dns_state, const DNSHeader *dns_header)
-{
- uint16_t flags = SCNtohs(dns_header->flags);
-
- if ((flags & 0x8000) == 0) {
- SCLogDebug("not a response 0x%04x", flags);
- DNSSetEvent(dns_state, DNS_DECODER_EVENT_NOT_A_RESPONSE);
- goto bad_data;
- }
-
- if ((flags & 0x0040) != 0) {
- SCLogDebug("Z flag not 0, 0x%04x", flags);
- DNSSetEvent(dns_state, DNS_DECODER_EVENT_Z_FLAG_SET);
- goto bad_data;
- }
-
- return 0;
-bad_data:
- return -1;
-}
-
-/** \internal
- * \brief check the query list to see if we already have this exact query
- * \retval bool true or false
- */
-static int QueryIsDuplicate(DNSTransaction *tx, const uint8_t *fqdn, const uint16_t fqdn_len,
- const uint16_t type, const uint16_t class)
-{
- DNSQueryEntry *q = NULL;
-
- TAILQ_FOREACH(q, &tx->query_list, next) {
- uint8_t *qfqdn = (uint8_t *)q + sizeof(DNSQueryEntry);
-
- if (q->len == fqdn_len && q->type == type &&
- q->class == class &&
- SCMemcmp(qfqdn, fqdn, fqdn_len) == 0) {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-void DNSStoreQueryInState(DNSState *dns_state, const uint8_t *fqdn, const uint16_t fqdn_len,
- const uint16_t type, const uint16_t class, const uint16_t tx_id)
-{
- /* flood protection */
- if (dns_state->givenup)
- return;
-
- /* find the tx and see if this is an exact duplicate */
- DNSTransaction *tx = DNSTransactionFindByTxId(dns_state, tx_id);
- if ((tx != NULL) && (QueryIsDuplicate(tx, fqdn, fqdn_len, type, class) == TRUE)) {
- SCLogDebug("query is duplicate");
- return;
- }
-
- /* check flood limit */
- if (dns_config.request_flood != 0 &&
- dns_state->unreplied_cnt > dns_config.request_flood) {
- DNSSetEvent(dns_state, DNS_DECODER_EVENT_FLOODED);
- dns_state->givenup = 1;
- }
-
- if (tx == NULL) {
- tx = DNSTransactionAlloc(dns_state, tx_id);
- if (tx == NULL)
- return;
- dns_state->transaction_max++;
- SCLogDebug("dns_state->transaction_max updated to %"PRIu64, dns_state->transaction_max);
- TAILQ_INSERT_TAIL(&dns_state->tx_list, tx, next);
- dns_state->curr = tx;
- tx->tx_num = dns_state->transaction_max;
- SCLogDebug("new tx %u with internal id %u", tx->tx_id, tx->tx_num);
- dns_state->unreplied_cnt++;
- }
-
- if (DNSCheckMemcap((sizeof(DNSQueryEntry) + fqdn_len), dns_state) < 0)
- return;
- DNSQueryEntry *q = SCMalloc(sizeof(DNSQueryEntry) + fqdn_len);
- if (unlikely(q == NULL))
- return;
- DNSIncrMemcap((sizeof(DNSQueryEntry) + fqdn_len), dns_state);
-
- q->type = type;
- q->class = class;
- q->len = fqdn_len;
- memcpy((uint8_t *)q + sizeof(DNSQueryEntry), fqdn, fqdn_len);
-
- TAILQ_INSERT_TAIL(&tx->query_list, q, next);
-
- SCLogDebug("Query for TX %04x stored", tx_id);
-}
-
-void DNSStoreAnswerInState(DNSState *dns_state, const int rtype, const uint8_t *fqdn,
- const uint16_t fqdn_len, const uint16_t type, const uint16_t class, const uint16_t ttl,
- const uint8_t *data, const uint16_t data_len, const uint16_t tx_id)
-{
- DNSTransaction *tx = DNSTransactionFindByTxId(dns_state, tx_id);
- if (tx == NULL) {
- tx = DNSTransactionAlloc(dns_state, tx_id);
- if (tx == NULL)
- return;
- TAILQ_INSERT_TAIL(&dns_state->tx_list, tx, next);
- dns_state->curr = tx;
- dns_state->transaction_max++;
- tx->tx_num = dns_state->transaction_max;
- }
-
- if (DNSCheckMemcap((sizeof(DNSAnswerEntry) + fqdn_len + data_len), dns_state) < 0)
- return;
- DNSAnswerEntry *q = SCMalloc(sizeof(DNSAnswerEntry) + fqdn_len + data_len);
- if (unlikely(q == NULL))
- return;
- DNSIncrMemcap((sizeof(DNSAnswerEntry) + fqdn_len + data_len), dns_state);
-
- q->type = type;
- q->class = class;
- q->ttl = ttl;
- q->fqdn_len = fqdn_len;
- q->data_len = data_len;
-
- uint8_t *ptr = (uint8_t *)q + sizeof(DNSAnswerEntry);
- if (fqdn != NULL && fqdn_len > 0) {
- memcpy(ptr, fqdn, fqdn_len);
- ptr += fqdn_len;
- }
- if (data != NULL && data_len > 0) {
- memcpy(ptr, data, data_len);
- }
-
- if (rtype == DNS_LIST_ANSWER)
- TAILQ_INSERT_TAIL(&tx->answer_list, q, next);
- else if (rtype == DNS_LIST_AUTHORITY)
- TAILQ_INSERT_TAIL(&tx->authority_list, q, next);
- else
- BUG_ON(1);
-
- SCLogDebug("Answer for TX %04x stored", tx_id);
-
- /* mark tx is as replied so we can log it */
- tx->replied = 1;
-}
-
-/** \internal
- * \brief get domain name from dns packet
- *
- * In case of compressed name storage this function follows the ptrs to
- * create the full domain name.
- *
- * The length bytes are converted into dots, e.g. |03|com|00| becomes
- * .com
- * The trailing . is not stored.
- *
- * \param input input buffer (complete dns record)
- * \param input_len lenght of input buffer
- * \param offset offset into @input where dns name starts
- * \param fqdn buffer to store result
- * \param fqdn_size size of @fqdn buffer
- * \retval 0 on error/no buffer
- * \retval size size of fqdn
- */
-static uint16_t DNSResponseGetNameByOffset(const uint8_t * const input, const uint32_t input_len,
- const uint16_t offset, uint8_t *fqdn, const size_t fqdn_size)
-{
- if (offset >= input_len) {
- SCLogDebug("input buffer too small for domain of len %u", offset);
- goto insufficient_data;
- }
-
- int steps = 0;
- uint16_t fqdn_offset = 0;
- uint8_t length = *(input + offset);
- const uint8_t *qdata = input + offset;
- SCLogDebug("qry length %u", length);
-
- if (length == 0) {
- memcpy(fqdn, "<root>", 6);
- SCReturnUInt(6U);
- }
-
- if ((uint64_t)((qdata + 1) - input) >= (uint64_t)input_len) {
- SCLogDebug("input buffer too small");
- goto insufficient_data;
- }
-
- while (length != 0) {
- int cnt = 0;
- while (length & 0xc0) {
- uint16_t off = ((length & 0x3f) << 8) + *(qdata+1);
- qdata = (const uint8_t *)input + off;
-
- if ((uint64_t)((qdata + 1) - input) >= (uint64_t)input_len) {
- SCLogDebug("input buffer too small");
- goto insufficient_data;
- }
-
- length = *qdata;
- SCLogDebug("qry length %u", length);
-
- if (cnt++ == 100) {
- SCLogDebug("too many pointer iterations, loop?");
- goto bad_data;
- }
- }
- qdata++;
-
- if (length == 0) {
- break;
- }
-
- if (input + input_len < qdata + length) {
- SCLogDebug("input buffer too small for domain of len %u", length);
- goto insufficient_data;
- }
- //PrintRawDataFp(stdout, qdata, length);
-
- if ((size_t)(fqdn_offset + length + 1) < fqdn_size) {
- memcpy(fqdn + fqdn_offset, qdata, length);
- fqdn_offset += length;
- fqdn[fqdn_offset++] = '.';
- }
- qdata += length;
-
- /* if we're at the end of the input data, we're done */
- if ((uint64_t)((qdata + 1) - input) == (uint64_t)input_len) {
- break;
- }
- else if ((uint64_t)((qdata + 1) - input) > (uint64_t)input_len) {
- SCLogDebug("input buffer too small");
- goto insufficient_data;
- }
-
- length = *qdata;
- SCLogDebug("qry length %u", length);
- steps++;
- if (steps >= 255)
- goto bad_data;
- }
- if (fqdn_offset) {
- fqdn_offset--;
- }
- //PrintRawDataFp(stdout, fqdn, fqdn_offset);
- SCReturnUInt(fqdn_offset);
-bad_data:
-insufficient_data:
- SCReturnUInt(0U);
-}
-
-/** \internal
- * \brief skip past domain name field
- *
- * Skip the domain at position data. We don't care about following compressed names
- * as we only want to know when the next part of the buffer starts
- *
- * \param input input buffer (complete dns record)
- * \param input_len lenght of input buffer
- * \param data current position
- *
- * \retval NULL on out of bounds data
- * \retval sdata ptr to position in buffer past the name
- */
-static const uint8_t *SkipDomain(const uint8_t * const input,
- const uint32_t input_len, const uint8_t *data)
-{
- const uint8_t *sdata = data;
- while (*sdata != 0x00) {
- if (*sdata & 0xc0) {
- sdata++;
- break;
- } else {
- sdata += ((*sdata) + 1);
- }
- if (input + input_len < sdata) {
- SCLogDebug("input buffer too small for data of len");
- goto insufficient_data;
- }
- }
- sdata++;
- if (input + input_len < sdata) {
- SCLogDebug("input buffer too small for data of len");
- goto insufficient_data;
- }
- return sdata;
-insufficient_data:
- return NULL;
-}
-
-const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_header,
- const uint16_t num, const DnsListEnum list, const uint8_t * const input,
- const uint32_t input_len, const uint8_t *data)
-{
- if (input + input_len < data + 2) {
- SCLogDebug("input buffer too small for record 'name' field, record %u, "
- "total answer_rr %u", num, SCNtohs(dns_header->answer_rr));
- goto insufficient_data;
- }
-
- uint8_t fqdn[DNS_MAX_SIZE];
- uint16_t fqdn_len = 0;
-
- /* see if name is compressed */
- if (!(data[0] & 0xc0)) {
- if ((fqdn_len = DNSResponseGetNameByOffset(input, input_len,
- data - input, fqdn, sizeof(fqdn))) == 0)
- {
- DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA);
- goto insufficient_data;
- }
- //PrintRawDataFp(stdout, fqdn, fqdn_len);
- const uint8_t *tdata = SkipDomain(input, input_len, data);
- if (tdata == NULL) {
- goto insufficient_data;
- }
- data = tdata;
- } else {
- uint16_t offset = (data[0] & 0x3f) << 8 | data[1];
-
- if ((fqdn_len = DNSResponseGetNameByOffset(input, input_len,
- offset, fqdn, sizeof(fqdn))) == 0)
- {
- DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA);
- goto insufficient_data;
- }
- //PrintRawDataFp(stdout, fqdn, fqdn_len);
- data += 2;
- }
-
- if (input + input_len < data + sizeof(DNSAnswerHeader)) {
- SCLogDebug("input buffer too small for DNSAnswerHeader");
- goto insufficient_data;
- }
-
- const DNSAnswerHeader *head = (DNSAnswerHeader *)data;
- const uint16_t datalen = SCNtohs(head->len);
-
- data += sizeof(DNSAnswerHeader);
-
- SCLogDebug("head->len %u", SCNtohs(head->len));
-
- if (input + input_len < data + SCNtohs(head->len)) {
- SCLogDebug("input buffer too small for data of len %u", SCNtohs(head->len));
- goto insufficient_data;
- }
-
- SCLogDebug("TTL %u", SCNtohl(head->ttl));
-
- switch (SCNtohs(head->type)) {
- case DNS_RECORD_TYPE_A:
- {
- if (datalen == 0 || datalen == 4) {
- //PrintRawDataFp(stdout, data, SCNtohs(head->len));
- //char a[16];
- //PrintInet(AF_INET, (const void *)data, a, sizeof(a));
- //SCLogInfo("A %s TTL %u", a, SCNtohl(head->ttl));
-
- DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len,
- SCNtohs(head->type), SCNtohs(head->class), SCNtohl(head->ttl),
- data, datalen, SCNtohs(dns_header->tx_id));
- } else {
- SCLogDebug("invalid length for A response data: %u", SCNtohs(head->len));
- goto bad_data;
- }
-
- data += datalen;
- break;
- }
- case DNS_RECORD_TYPE_AAAA:
- {
- if (datalen == 0 || datalen == 16) {
- //char a[46];
- //PrintInet(AF_INET6, (const void *)data, a, sizeof(a));
- //SCLogInfo("AAAA %s TTL %u", a, SCNtohl(head->ttl));
-
- DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len,
- SCNtohs(head->type), SCNtohs(head->class), SCNtohl(head->ttl),
- data, datalen, SCNtohs(dns_header->tx_id));
- } else {
- SCLogDebug("invalid length for AAAA response data: %u", SCNtohs(head->len));
- goto bad_data;
- }
-
- data += datalen;
- break;
- }
- case DNS_RECORD_TYPE_MX:
- case DNS_RECORD_TYPE_CNAME:
- case DNS_RECORD_TYPE_PTR:
- {
- uint8_t name[DNS_MAX_SIZE];
- uint16_t name_len = 0;
- uint8_t skip = 0;
-
- if (SCNtohs(head->type) == DNS_RECORD_TYPE_MX) {
- // Skip the preference header
- skip = 2;
- }
-
- if ((name_len = DNSResponseGetNameByOffset(input, input_len,
- data - input + skip, name, sizeof(name))) == 0)
- {
- DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA);
- goto insufficient_data;
- }
-
- DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len,
- SCNtohs(head->type), SCNtohs(head->class), SCNtohl(head->ttl),
- name, name_len, SCNtohs(dns_header->tx_id));
-
- data += SCNtohs(head->len);
- break;
- }
- case DNS_RECORD_TYPE_NS:
- case DNS_RECORD_TYPE_SOA:
- {
- uint8_t pname[DNS_MAX_SIZE];
- uint16_t pname_len = 0;
-
- if ((pname_len = DNSResponseGetNameByOffset(input, input_len,
- data - input, pname, sizeof(pname))) == 0)
- {
- DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA);
- goto insufficient_data;
- }
-
- if (SCNtohs(head->type) == DNS_RECORD_TYPE_SOA) {
- const uint8_t *sdata = SkipDomain(input, input_len, data);
- if (sdata == NULL) {
- goto insufficient_data;
- }
-
- uint8_t pmail[DNS_MAX_SIZE];
- uint16_t pmail_len = 0;
- SCLogDebug("getting pmail");
- if ((pmail_len = DNSResponseGetNameByOffset(input, input_len,
- sdata - input, pmail, sizeof(pmail))) == 0)
- {
- DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA);
- goto insufficient_data;
- }
- SCLogDebug("pmail_len %u", pmail_len);
- //PrintRawDataFp(stdout, (uint8_t *)pmail, pmail_len);
-
- const uint8_t *tdata = SkipDomain(input, input_len, sdata);
- if (tdata == NULL) {
- goto insufficient_data;
- }
-#if DEBUG
- struct Trailer {
- uint32_t serial;
- uint32_t refresh;
- uint32_t retry;
- uint32_t experiation;
- uint32_t minttl;
- } *tail = (struct Trailer *)tdata;
-
- if (input + input_len < tdata + sizeof(struct Trailer)) {
- SCLogDebug("input buffer too small for data of len");
- goto insufficient_data;
- }
-
- SCLogDebug("serial %u refresh %u retry %u exp %u min ttl %u",
- SCNtohl(tail->serial), SCNtohl(tail->refresh),
- SCNtohl(tail->retry), SCNtohl(tail->experiation),
- SCNtohl(tail->minttl));
-#endif
- }
-
- DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len,
- SCNtohs(head->type), SCNtohs(head->class), SCNtohl(head->ttl),
- pname, pname_len, SCNtohs(dns_header->tx_id));
-
- data += SCNtohs(head->len);
- break;
- }
- case DNS_RECORD_TYPE_TXT:
- {
- uint16_t txtdatalen = datalen;
-
- if (txtdatalen == 0) {
- DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA);
- goto bad_data;
- }
-
- uint8_t txtlen = *data;
- const uint8_t *tdata = data + 1;
-
- do {
- //PrintRawDataFp(stdout, (uint8_t*)tdata, txtlen);
-
- if (txtlen >= txtdatalen)
- goto bad_data;
-
- DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len,
- SCNtohs(head->type), SCNtohs(head->class), SCNtohl(head->ttl),
- (uint8_t*)tdata, (uint16_t)txtlen, SCNtohs(dns_header->tx_id));
-
- txtdatalen -= txtlen;
- tdata += txtlen;
- txtlen = *tdata;
-
- tdata++;
- txtdatalen--;
-
- SCLogDebug("datalen %u, txtlen %u", txtdatalen, txtlen);
- } while (txtdatalen > 1);
-
- data += datalen;
- break;
- }
- case DNS_RECORD_TYPE_SSHFP:
- {
- /* data here should be:
- * [1 byte algo][1 byte type][var bytes fingerprint]
- * As we currently can't store each of those in the state,
- * we just store the raw data an let the output/detect
- * code figure out what to do with it. */
-
- DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len,
- SCNtohs(head->type), SCNtohs(head->class), SCNtohl(head->ttl),
- data, SCNtohs(head->len), SCNtohs(dns_header->tx_id));
-
- data += datalen;
- break;
- }
- default: /* unsupported record */
- {
- DNSStoreAnswerInState(dns_state, list, NULL, 0,
- SCNtohs(head->type), SCNtohs(head->class), SCNtohl(head->ttl),
- NULL, 0, SCNtohs(dns_header->tx_id));
-
- //PrintRawDataFp(stdout, data, SCNtohs(head->len));
- data += datalen;
- break;
- }
- }
- return data;
-bad_data:
-insufficient_data:
- return NULL;
-}
-
void DNSCreateTypeString(uint16_t type, char *str, size_t str_size)
{
switch (type) {
#include "app-layer-protos.h"
#include "app-layer-parser.h"
-#include "flow.h"
-#include "queue.h"
-#include "util-byte.h"
#define DNS_MAX_SIZE 256
-
#define DNS_RECORD_TYPE_A 1
#define DNS_RECORD_TYPE_NS 2
#define DNS_RECORD_TYPE_MD 3 // Obsolete
uint16_t additional_rr;
} __attribute__((__packed__)) DNSHeader;
-typedef struct DNSQueryTrailer_ {
- uint16_t type;
- uint16_t class;
-} __attribute__((__packed__)) DNSQueryTrailer;
-
-/** \brief DNS answer header
- * packed as we don't want alignment to mess up sizeof() */
-struct DNSAnswerHeader_ {
- uint16_t type;
- uint16_t class;
- uint32_t ttl;
- uint16_t len;
-} __attribute__((__packed__));
-typedef struct DNSAnswerHeader_ DNSAnswerHeader;
-
-/** \brief List types in the TX.
- * Used when storing answers from "Answer" or "Authority" */
-typedef enum {
- DNS_LIST_ANSWER = 0,
- DNS_LIST_AUTHORITY,
-} DnsListEnum;
-
-/** \brief DNS Query storage. Stored in TX list.
- *
- * Layout is:
- * [list ptr][2 byte type][2 byte class][2 byte len][...data...]
- */
-typedef struct DNSQueryEntry_ {
- TAILQ_ENTRY(DNSQueryEntry_) next;
- uint16_t type;
- uint16_t class;
- uint16_t len;
-} DNSQueryEntry;
-
-/** \brief DNS Answer storage. Stored in TX list.
- *
- * Layout is:
- * [list ptr][2 byte type][2 byte class][2 byte ttl] \
- * [2 byte fqdn len][2 byte data len][...fqdn...][...data...]
- */
-typedef struct DNSAnswerEntry_ {
- TAILQ_ENTRY(DNSAnswerEntry_) next;
-
- uint16_t type;
- uint16_t class;
-
- uint32_t ttl;
-
- uint16_t fqdn_len;
- uint16_t data_len;
-} DNSAnswerEntry;
-
-/** \brief DNS Transaction, request/reply with same TX id. */
-typedef struct DNSTransaction_ {
- uint16_t tx_num; /**< internal: id */
- uint16_t tx_id; /**< transaction id */
- uint16_t flags; /**< dns flags */
- uint32_t logged; /**< flags for loggers done logging */
- uint8_t replied; /**< bool indicating request is
- replied to. */
- uint8_t reply_lost;
- uint8_t rcode; /**< response code (e.g. "no error" / "no such name") */
- uint8_t recursion_desired; /**< server said "recursion desired" */
-
- /** detection engine flags */
- uint64_t detect_flags_ts;
- uint64_t detect_flags_tc;
-
- TAILQ_HEAD(, DNSQueryEntry_) query_list; /**< list for query/queries */
- TAILQ_HEAD(, DNSAnswerEntry_) answer_list; /**< list for answers */
- TAILQ_HEAD(, DNSAnswerEntry_) authority_list; /**< list for authority records */
-
- AppLayerDecoderEvents *decoder_events; /**< per tx events */
-
- TAILQ_ENTRY(DNSTransaction_) next;
- DetectEngineState *de_state;
-} DNSTransaction;
-
-/** \brief Per flow DNS state container */
-typedef struct DNSState_ {
- TAILQ_HEAD(, DNSTransaction_) tx_list; /**< transaction list */
- DNSTransaction *curr; /**< ptr to current tx */
- DNSTransaction *iter;
- uint64_t transaction_max;
- uint32_t unreplied_cnt; /**< number of unreplied requests in a row */
- uint32_t memuse; /**< state memuse, for comparing with
- state-memcap settings */
- struct timeval last_req; /**< Timestamp of last request. */
- struct timeval last_resp; /**< Timestamp of last response. */
-
- uint16_t window; /**< Window of allowed unreplied
- * requests. Set by the maximum
- * number of subsequent requests
- * without a response. */
- uint16_t events;
- uint16_t givenup;
-
- /* used by TCP only */
- uint16_t offset;
- uint16_t record_len;
- uint8_t gap_ts; /**< Flag set when a gap has occurred. */
- uint8_t gap_tc; /**< Flag set when a gap has occurred. */
- uint8_t *buffer;
-} DNSState;
-
-#define DNS_CONFIG_DEFAULT_REQUEST_FLOOD 500
-#define DNS_CONFIG_DEFAULT_STATE_MEMCAP 512*1024
-#define DNS_CONFIG_DEFAULT_GLOBAL_MEMCAP 16*1024*1024
-
-void DNSConfigInit(void);
-void DNSConfigSetRequestFlood(uint32_t value);
-void DNSConfigSetStateMemcap(uint32_t value);
-void DNSConfigSetGlobalMemcap(uint64_t value);
-
-void DNSIncrMemcap(uint32_t size, DNSState *state);
-void DNSDecrMemcap(uint32_t size, DNSState *state);
-int DNSCheckMemcap(uint32_t want, DNSState *state);
-uint64_t DNSMemcapGetMemuseCounter(void);
-uint64_t DNSMemcapGetMemcapStateCounter(void);
-uint64_t DNSMemcapGetMemcapGlobalCounter(void);
-
-void RegisterDNSParsers(void);
-void DNSParserTests(void);
-void DNSParserRegisterTests(void);
-void DNSAppLayerDecoderEventsRegister(int alproto);
int DNSStateGetEventInfo(const char *event_name,
int *event_id, AppLayerEventType *event_type);
void DNSAppLayerRegisterGetEventInfo(uint8_t ipproto, AppProto alproto);
-void *DNSGetTx(void *alstate, uint64_t tx_id);
-uint64_t DNSGetTxCnt(void *alstate);
-void DNSSetTxLogged(void *alstate, void *tx, LoggerId logged);
-LoggerId DNSGetTxLogged(void *alstate, void *tx);
-int DNSGetAlstateProgress(void *tx, uint8_t direction);
-int DNSGetAlstateProgressCompletionStatus(uint8_t direction);
-
-void DNSStateTransactionFree(void *state, uint64_t tx_id);
-DNSTransaction *DNSTransactionFindByTxId(const DNSState *dns_state, const uint16_t tx_id);
-
-DetectEngineState *DNSGetTxDetectState(void *vtx);
-int DNSSetTxDetectState(void *vtx, DetectEngineState *s);
-uint64_t DNSGetTxDetectFlags(void *vtx, uint8_t dir);
-void DNSSetTxDetectFlags(void *vtx, uint8_t dir, uint64_t detect_flags);
-
-void DNSSetEvent(DNSState *s, uint8_t e);
-void *DNSStateAlloc(void);
-void DNSStateFree(void *s);
-AppLayerDecoderEvents *DNSGetEvents(void *state, uint64_t id);
-
-int DNSValidateRequestHeader(DNSState *, const DNSHeader *dns_header);
-int DNSValidateResponseHeader(DNSState *, const DNSHeader *dns_header);
-
-void DNSStoreQueryInState(DNSState *dns_state, const uint8_t *fqdn, const uint16_t fqdn_len,
- const uint16_t type, const uint16_t class, const uint16_t tx_id);
-
-void DNSStoreAnswerInState(DNSState *dns_state, const int rtype, const uint8_t *fqdn,
- const uint16_t fqdn_len, const uint16_t type, const uint16_t class, const uint16_t ttl,
- const uint8_t *data, const uint16_t data_len, const uint16_t tx_id);
-
-const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_header,
- const uint16_t num, const DnsListEnum list, const uint8_t * const input,
- const uint32_t input_len, const uint8_t *data);
-
-uint16_t DNSUdpResponseGetNameByOffset(const uint8_t * const input, const uint32_t input_len,
- const uint16_t offset, uint8_t *fqdn, const size_t fqdn_size);
-
void DNSCreateTypeString(uint16_t type, char *str, size_t str_size);
void DNSCreateRcodeString(uint8_t rcode, char *str, size_t str_size);
#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"
-
-#ifdef HAVE_RUST
#include "app-layer-dns-tcp-rust.h"
-#endif
-
-#ifndef HAVE_RUST
-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;
-
-static uint16_t DNSTcpProbingParser(Flow *f, uint8_t direction,
- uint8_t *input, uint32_t ilen,
- uint8_t *rdir);
-
-/** \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 (SCNtohs(dns_tcp_header->len) < sizeof(DNSHeader)) {
- goto bad_data;
- }
- if (SCNtohs(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 < SCNtohs(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", SCNtohs(trailer->type), SCNtohs(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", SCNtohs(dns_header->tx_id));
-
- uint16_t q;
- const uint8_t *data = input + sizeof(DNSHeader);
-
- //PrintRawDataFp(stdout, (uint8_t*)data, input_len - (data - input));
-
- if (dns_state != NULL) {
- if (timercmp(&dns_state->last_req, &dns_state->last_resp, >=)) {
- if (dns_state->window <= dns_state->unreplied_cnt) {
- dns_state->window++;
- }
- }
- }
-
- for (q = 0; q < SCNtohs(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", SCNtohs(trailer->type), SCNtohs(trailer->class));
- data += sizeof(DNSQueryTrailer);
-
- /* store our data */
- if (dns_state != NULL) {
- DNSStoreQueryInState(dns_state, fqdn, fqdn_offset,
- SCNtohs(trailer->type), SCNtohs(trailer->class),
- SCNtohs(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, const uint8_t flags)
-{
- DNSState *dns_state = (DNSState *)dstate;
- SCLogDebug("starting %u", input_len);
-
- if (input == NULL && input_len > 0) {
- SCLogDebug("Input is NULL, but len is %"PRIu32": must be a gap.",
- input_len);
- dns_state->gap_ts = 1;
- SCReturnInt(1);
- }
-
- if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
- SCReturnInt(1);
- }
-
- /** \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;
- }
-
- /* Clear gap state. */
- if (dns_state->gap_ts) {
- if (DNSTcpProbingParser(f, STREAM_TOSERVER,
- input, input_len, NULL) == ALPROTO_DNS) {
- SCLogDebug("New data probed as DNS, clearing gap state.");
- BufferReset(dns_state);
- dns_state->gap_ts = 0;
- } else {
- SCLogDebug("Unable to sync DNS parser, leaving gap state.");
- SCReturnInt(1);
- }
- }
-
-next_record:
- /* if this is the beginning of a record, we need at least the header */
- if (dns_state->offset == 0 && input_len < sizeof(DNSTcpHeader)) {
- 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 (SCNtohs(dns_tcp_header->len) < sizeof(DNSHeader)) {
- /* bogus len, doesn't fit even basic dns header */
- goto bad_data;
- } else if (SCNtohs(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) > SCNtohs(dns_tcp_header->len)) {
- /* we have all data, so process w/o buffering */
- if (DNSRequestParseData(f, dns_state, input+2, SCNtohs(dns_tcp_header->len)) < 0)
- goto bad_data;
-
- /* treat the rest of the data as a (potential) new record */
- input += (2 + SCNtohs(dns_tcp_header->len));
- input_len -= (2 + SCNtohs(dns_tcp_header->len));
- goto next_record;
- } else {
- /* not enough data, store record length and buffer */
- dns_state->record_len = SCNtohs(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;
- }
-
- if (f != NULL) {
- dns_state->last_req = f->lastts;
- }
-
- 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, SCNtohs(dns_header->tx_id))) != NULL)
- found = 1;
-
- if (!found) {
- SCLogDebug("DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE");
- DNSSetEvent(dns_state, DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE);
- } else if (dns_state->unreplied_cnt > 0) {
- dns_state->unreplied_cnt--;
- }
-
- uint16_t q;
- const uint8_t *data = input + sizeof(DNSHeader);
- for (q = 0; q < SCNtohs(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", SCNtohs(trailer->type), SCNtohs(trailer->class));
-#endif
- data += sizeof(DNSQueryTrailer);
- }
-
- for (q = 0; q < SCNtohs(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 < SCNtohs(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 = SCNtohs(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 (SCNtohs(dns_header->flags) & 0x0080) {
- SCLogDebug("recursion desired");
- if (tx != NULL)
- tx->recursion_desired = 1;
- }
-
- if (tx != NULL) {
- tx->flags = ntohs(dns_header->flags);
- 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, const uint8_t flags)
-{
- DNSState *dns_state = (DNSState *)dstate;
-
- if (input == NULL && input_len > 0) {
- SCLogDebug("Input is NULL, but len is %"PRIu32": must be a gap.",
- input_len);
- dns_state->gap_tc = 1;
- SCReturnInt(1);
- }
-
- if (input == NULL && AppLayerParserStateIssetFlag(pstate, APP_LAYER_PARSER_EOF)) {
- SCReturnInt(1);
- }
-
- /** \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;
- }
-
- /* Clear gap state. */
- if (dns_state->gap_tc) {
- if (DNSTcpProbingParser(f, STREAM_TOCLIENT,
- input, input_len, NULL) == ALPROTO_DNS) {
- SCLogDebug("New data probed as DNS, clearing gap state.");
- BufferReset(dns_state);
- dns_state->gap_tc = 0;
- } else {
- SCLogDebug("Unable to sync DNS parser, leaving gap state.");
- SCReturnInt(1);
- }
- }
-
-next_record:
- /* if this is the beginning of a record, we need at least the header */
- if (dns_state->offset == 0 && input_len < sizeof(DNSTcpHeader)) {
- 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 (SCNtohs(dns_tcp_header->len) == 0) {
- goto bad_data;
- } else if (SCNtohs(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) > SCNtohs(dns_tcp_header->len)) {
- /* we have all data, so process w/o buffering */
- if (DNSReponseParseData(f, dns_state, input+2, SCNtohs(dns_tcp_header->len)) < 0)
- goto bad_data;
-
- /* treat the rest of the data as a (potential) new record */
- input += (2 + SCNtohs(dns_tcp_header->len));
- input_len -= (2 + SCNtohs(dns_tcp_header->len));
- goto next_record;
- } else {
- /* not enough data, store record length and buffer */
- dns_state->record_len = SCNtohs(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;
- }
-
- if (f != NULL) {
- dns_state->last_resp = f->lastts;
- }
-
- SCReturnInt(1);
-insufficient_data:
- SCReturnInt(-1);
-bad_data:
- SCReturnInt(-1);
-}
-
-static uint16_t DNSTcpProbingParser(Flow *f, uint8_t direction,
- uint8_t *input, uint32_t ilen,
- uint8_t *rdir)
-{
- 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 (SCNtohs(dns_header->len) < sizeof(DNSHeader)) {
- /* length field bogus, won't even fit a minimal DNS header. */
- return ALPROTO_FAILED;
- } else if (SCNtohs(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", SCNtohs(dns_header->len), ilen);
- return ALPROTO_UNKNOWN;
- }
-
- int r = DNSTCPRequestParseProbe(input, ilen);
- if (r != 1)
- return ALPROTO_FAILED;
-
- SCLogDebug("ALPROTO_DNS");
- return ALPROTO_DNS;
-}
-
-/**
- * \brief Probing parser for TCP DNS responses.
- *
- * This is a minimal parser that just checks that the input contains enough
- * data for a TCP DNS response.
- */
-static uint16_t DNSTcpProbeResponse(Flow *f, uint8_t direction,
- uint8_t *input, uint32_t len,
- uint8_t *rdir)
-{
- if (len == 0 || len < sizeof(DNSTcpHeader)) {
- return ALPROTO_UNKNOWN;
- }
-
- DNSTcpHeader *dns_header = (DNSTcpHeader *)input;
-
- if (SCNtohs(dns_header->len) < sizeof(DNSHeader)) {
- return ALPROTO_FAILED;
- }
-
- return ALPROTO_DNS;
-}
-#endif /* HAVE_RUST */
void RegisterDNSTCPParsers(void)
{
-#ifdef HAVE_RUST
RegisterRustDNSTCPParsers();
- return;
-#else
- const 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, NULL);
- } else {
- int have_cfg = AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP,
- proto_name, ALPROTO_DNS,
- 0, sizeof(DNSTcpHeader),
- DNSTcpProbingParser,
- DNSTcpProbeResponse);
- /* 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,
- DNSTcpProbeResponse);
- }
- }
- } 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);
- AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_DNS,
- DNSGetTxDetectState, DNSSetTxDetectState);
- AppLayerParserRegisterDetectFlagsFuncs(IPPROTO_TCP, ALPROTO_DNS,
- DNSGetTxDetectFlags, DNSSetTxDetectFlags);
-
- AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_DNS, DNSGetTx);
- AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_DNS, DNSGetTxCnt);
- AppLayerParserRegisterLoggerFuncs(IPPROTO_TCP, ALPROTO_DNS, DNSGetTxLogged,
- DNSSetTxLogged);
- AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_DNS,
- DNSGetAlstateProgress);
- AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_DNS,
- DNSGetAlstateProgressCompletionStatus);
- DNSAppLayerRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_DNS);
-
- /* This parser accepts gaps. */
- AppLayerParserRegisterOptionFlags(IPPROTO_TCP, ALPROTO_DNS,
- APP_LAYER_PARSER_OPT_ACCEPT_GAPS);
-
- } else {
- SCLogInfo("Parsed disabled for %s protocol. Protocol detection"
- "still on.", proto_name);
- }
-#ifdef UNITTESTS
- AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_DNS,
- DNSTCPParserRegisterTests);
-#endif
- return;
-#endif /* HAVE_RUST */
-}
-
-/* UNITTESTS */
-#ifndef HAVE_RUST
-#ifdef UNITTESTS
-
-#include "util-unittest-helper.h"
-
-static int DNSTCPParserTestMultiRecord(void)
-{
- /* This is a buffer containing 20 DNS requests each prefixed by
- * the request length for transport over TCP. It was generated with Scapy,
- * where each request is:
- * DNS(id=i, rd=1, qd=DNSQR(qname="%d.google.com" % i, qtype="A"))
- * where i is 0 to 19.
- */
- uint8_t req[] = {
- 0x00, 0x1e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- 0x00, 0x1e, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x31,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- 0x00, 0x1e, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x32,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- 0x00, 0x1e, 0x00, 0x03, 0x01, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x33,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- 0x00, 0x1e, 0x00, 0x04, 0x01, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x34,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- 0x00, 0x1e, 0x00, 0x05, 0x01, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x35,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- 0x00, 0x1e, 0x00, 0x06, 0x01, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x36,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- 0x00, 0x1e, 0x00, 0x07, 0x01, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x37,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- 0x00, 0x1e, 0x00, 0x08, 0x01, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x38,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- 0x00, 0x1e, 0x00, 0x09, 0x01, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x39,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- 0x00, 0x1f, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x31,
- 0x30, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
- 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x1f, 0x00, 0x0b, 0x01, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
- 0x31, 0x31, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
- 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01,
- 0x00, 0x01, 0x00, 0x1f, 0x00, 0x0c, 0x01, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x02, 0x31, 0x32, 0x06, 0x67, 0x6f, 0x6f, 0x67,
- 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00,
- 0x01, 0x00, 0x01, 0x00, 0x1f, 0x00, 0x0d, 0x01,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x02, 0x31, 0x33, 0x06, 0x67, 0x6f, 0x6f,
- 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00,
- 0x00, 0x01, 0x00, 0x01, 0x00, 0x1f, 0x00, 0x0e,
- 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x02, 0x31, 0x34, 0x06, 0x67, 0x6f,
- 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d,
- 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x1f, 0x00,
- 0x0f, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x02, 0x31, 0x35, 0x06, 0x67,
- 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f,
- 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x1f,
- 0x00, 0x10, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x02, 0x31, 0x36, 0x06,
- 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63,
- 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00,
- 0x1f, 0x00, 0x11, 0x01, 0x00, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x31, 0x37,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- 0x00, 0x1f, 0x00, 0x12, 0x01, 0x00, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x31,
- 0x38, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
- 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00,
- 0x01, 0x00, 0x1f, 0x00, 0x13, 0x01, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
- 0x31, 0x39, 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
- 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01,
- 0x00, 0x01
- };
- size_t reqlen = sizeof(req);
-
- DNSState *state = DNSStateAlloc();
- FAIL_IF_NULL(state);
- Flow *f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 53);
- FAIL_IF_NULL(f);
- f->proto = IPPROTO_TCP;
- f->alproto = ALPROTO_DNS;
- f->alstate = state;
-
- FAIL_IF_NOT(DNSTCPRequestParse(f, f->alstate, NULL, req, reqlen, NULL, STREAM_START));
- FAIL_IF(state->transaction_max != 20);
-
- UTHFreeFlow(f);
- PASS;
}
-
-void DNSTCPParserRegisterTests(void)
-{
- UtRegisterTest("DNSTCPParserTestMultiRecord", DNSTCPParserTestMultiRecord);
-}
-
-#endif /* UNITTESTS */
-#endif /* HAVE_RUST */
#ifndef __APP_LAYER_DNS_TCP_H__
#define __APP_LAYER_DNS_TCP_H__
-#include "app-layer-protos.h"
-#include "app-layer-parser.h"
-#include "app-layer-dns-common.h"
-#include "flow.h"
-#include "queue.h"
-#include "util-byte.h"
-
void RegisterDNSTCPParsers(void);
-void DNSTCPParserTests(void);
-void DNSTCPParserRegisterTests(void);
#endif /* __APP_LAYER_DNS_TCP_H__ */
*/
#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"
-
-#ifdef HAVE_RUST
#include "app-layer-dns-udp-rust.h"
-#endif
-
-#ifndef HAVE_RUST
-/** \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, const uint8_t flags)
-{
- 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;
-
- if (dns_state != NULL) {
- if (timercmp(&dns_state->last_req, &dns_state->last_resp, >=)) {
- if (dns_state->window <= dns_state->unreplied_cnt) {
- dns_state->window++;
- }
- }
- }
-
- uint16_t q;
- const uint8_t *data = input + sizeof(DNSHeader);
- for (q = 0; q < SCNtohs(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", SCNtohs(trailer->type), SCNtohs(trailer->class));
- data += sizeof(DNSQueryTrailer);
-
- /* store our data */
- if (dns_state != NULL) {
- DNSStoreQueryInState(dns_state, fqdn, fqdn_offset,
- SCNtohs(trailer->type), SCNtohs(trailer->class),
- SCNtohs(dns_header->tx_id));
- }
- }
-
- if (dns_state != NULL && f != NULL) {
- dns_state->last_req = f->lastts;
- }
-
- 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, const uint8_t flags)
-{
- 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, SCNtohs(dns_header->tx_id), dns_header->flags);
-
- DNSTransaction *tx = NULL;
- int found = 0;
- if ((tx = DNSTransactionFindByTxId(dns_state, SCNtohs(dns_header->tx_id))) != NULL)
- found = 1;
-
- if (!found) {
- SCLogDebug("DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE");
- DNSSetEvent(dns_state, DNS_DECODER_EVENT_UNSOLLICITED_RESPONSE);
- } else if (dns_state->unreplied_cnt > 0) {
- dns_state->unreplied_cnt--;
- }
-
- if (DNSValidateResponseHeader(dns_state, dns_header) < 0)
- goto bad_data;
-
- SCLogDebug("queries %04x", SCNtohs(dns_header->questions));
-
- uint16_t q;
- const uint8_t *data = input + sizeof(DNSHeader);
- for (q = 0; q < SCNtohs(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", SCNtohs(trailer->type), SCNtohs(trailer->class));
-#endif
- data += sizeof(DNSQueryTrailer);
- }
-
- SCLogDebug("answer_rr %04x", SCNtohs(dns_header->answer_rr));
- for (q = 0; q < SCNtohs(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", SCNtohs(dns_header->authority_rr));
- for (q = 0; q < SCNtohs(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;
- }
- }
-
- /* if we previously didn't have a tx, it could have been created by the
- * above code, so lets check again */
- if (tx == NULL) {
- tx = DNSTransactionFindByTxId(dns_state, SCNtohs(dns_header->tx_id));
- }
- if (tx != NULL) {
- /* parse rcode, e.g. "noerror" or "nxdomain" */
- uint8_t rcode = SCNtohs(dns_header->flags) & 0x0F;
- if (rcode <= DNS_RCODE_NOTZONE) {
- SCLogDebug("rcode %u", rcode);
- tx->rcode = rcode;
- } else {
- /* this is not invalid, rcodes can be user defined */
- SCLogDebug("unexpected DNS rcode %u", rcode);
- }
-
- if (SCNtohs(dns_header->flags) & 0x0080) {
- SCLogDebug("recursion desired");
- tx->recursion_desired = 1;
- }
-
- tx->flags = ntohs(dns_header->flags);
- tx->replied = 1;
- }
- if (f != NULL) {
- dns_state->last_resp = f->lastts;
- }
- SCReturnInt(1);
-
-bad_data:
-insufficient_data:
- DNSSetEvent(dns_state, DNS_DECODER_EVENT_MALFORMED_DATA);
- SCReturnInt(-1);
-}
-
-static uint16_t DNSUdpProbingParser(Flow *f, uint8_t direction,
- uint8_t *input, uint32_t ilen, uint8_t *rdir)
-{
- 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, 0) == -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;
- }
- }
- SCLogConfig("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;
- }
- }
- SCLogConfig("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;
- }
- }
- SCLogConfig("DNS global memcap: %"PRIu64, global_memcap);
- DNSConfigSetGlobalMemcap(global_memcap);
-}
-#endif /* HAVE_RUST */
void RegisterDNSUDPParsers(void)
{
-#ifdef HAVE_RUST
return RegisterRustDNSUDPParsers();
-#else
- const 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,
- NULL);
- } else {
- int have_cfg = AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP,
- proto_name, ALPROTO_DNS,
- 0, sizeof(DNSHeader),
- DNSUdpProbingParser, NULL);
- /* if we have no config, we enable the default port 53 */
- if (!have_cfg) {
-#ifndef AFLFUZZ_APPLAYER
- SCLogWarning(SC_ERR_DNS_CONFIG, "no DNS UDP config found, "
- "enabling DNS detection on "
- "port 53.");
-#endif
- AppLayerProtoDetectPPRegister(IPPROTO_UDP, "53",
- ALPROTO_DNS, 0, sizeof(DNSHeader),
- STREAM_TOSERVER, DNSUdpProbingParser, NULL);
- }
- }
- } 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);
- AppLayerParserRegisterDetectStateFuncs(IPPROTO_UDP, ALPROTO_DNS,
- DNSGetTxDetectState, DNSSetTxDetectState);
- AppLayerParserRegisterDetectFlagsFuncs(IPPROTO_UDP, ALPROTO_DNS,
- DNSGetTxDetectFlags, DNSSetTxDetectFlags);
-
- AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_DNS,
- DNSGetTx);
- AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_DNS,
- DNSGetTxCnt);
- AppLayerParserRegisterLoggerFuncs(IPPROTO_UDP, ALPROTO_DNS, DNSGetTxLogged,
- DNSSetTxLogged);
- AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP, ALPROTO_DNS,
- DNSGetAlstateProgress);
- AppLayerParserRegisterGetStateProgressCompletionStatus(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
-#endif /* HAVE_RUST */
-}
-
-/* UNITTESTS */
-#ifndef HAVE_RUST
-#ifdef UNITTESTS
-#include "util-unittest-helper.h"
-
-static int DNSUDPParserTest01 (void)
-{
- /* 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);
- FAIL_IF_NULL(f);
- f->proto = IPPROTO_UDP;
- f->alproto = ALPROTO_DNS;
- f->alstate = DNSStateAlloc();
-
- FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL, STREAM_START));
-
- UTHFreeFlow(f);
- PASS;
-}
-
-static int DNSUDPParserTest02 (void)
-{
- 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);
- FAIL_IF_NULL(f);
- f->proto = IPPROTO_UDP;
- f->alproto = ALPROTO_DNS;
- f->alstate = DNSStateAlloc();
-
- FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL, STREAM_START));
-
- UTHFreeFlow(f);
- PASS;
-}
-
-static int DNSUDPParserTest03 (void)
-{
- 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);
- FAIL_IF_NULL(f);
- f->proto = IPPROTO_UDP;
- f->alproto = ALPROTO_DNS;
- f->alstate = DNSStateAlloc();
-
- FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL, STREAM_START));
-
- UTHFreeFlow(f);
- PASS;
-}
-
-/** \test TXT records in answer */
-static int DNSUDPParserTest04 (void)
-{
- 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);
- FAIL_IF_NULL(f);
- f->proto = IPPROTO_UDP;
- f->alproto = ALPROTO_DNS;
- f->alstate = DNSStateAlloc();
-
- FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL, STREAM_START));
-
- UTHFreeFlow(f);
- PASS;
-}
-
-/** \test TXT records in answer, bad txtlen */
-static int DNSUDPParserTest05 (void)
-{
- 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);
- FAIL_IF_NULL(f);
- f->proto = IPPROTO_UDP;
- f->alproto = ALPROTO_DNS;
- f->alstate = DNSStateAlloc();
-
- FAIL_IF(DNSUDPResponseParse(f, f->alstate, NULL, buf, buflen, NULL, STREAM_START) != -1);
-
- UTHFreeFlow(f);
- PASS;
-}
-
-/**
- * \test Test subsequent requests before response.
- *
- * This test sends 2 DNS requests on the same state then sends the response
- * to the first request checking that it is seen and associated with the
- * transaction.
- */
-static int DNSUDPParserTestDelayedResponse(void)
-{
- /* DNS request:
- * - Flags: 0x0100 Standard query
- * - A www.google.com
- */
- uint8_t req[] = {
- 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- };
- size_t reqlen = sizeof(req);
-
- /* DNS response:
- * - Flags: 0x8180 Standard query response, no error
- * - www.google.com A 24.244.4.56
- * - www.google.com A 24.244.4.54
- * - www.google.com A 24.244.4.57
- * - www.google.com A 24.244.4.55
- * - www.google.com A 24.244.4.52
- * - www.google.com A 24.244.4.53
- * - www.google.com A 24.244.4.58
- * - www.google.com A 24.244.4.59
- */
- uint8_t res[] = {
- 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x38,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x39,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x34,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x35,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x36,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x3b,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x37,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x3a
- };
- size_t reslen = sizeof(res);
-
- DNSState *state = DNSStateAlloc();
- FAIL_IF_NULL(state);
- Flow *f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 53);
- FAIL_IF_NULL(f);
- f->proto = IPPROTO_UDP;
- f->alproto = ALPROTO_DNS;
- f->alstate = state;
-
- /* Send two requests with an incrementing tx id. */
- FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL, STREAM_START));
- req[1] = 0x02;
- FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL, 0));
-
- /* Send response to the first request. */
- FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, res, reslen, NULL, STREAM_START));
- DNSTransaction *tx = TAILQ_FIRST(&state->tx_list);
- FAIL_IF_NULL(tx);
- FAIL_IF_NOT(tx->replied);
-
- /* Also free's state. */
- UTHFreeFlow(f);
-
- PASS;
-}
-
-/**
- * \test Test entering the flood/givenup state.
- */
-static int DNSUDPParserTestFlood(void)
-{
- /* DNS request:
- * - Flags: 0x0100 Standard query
- * - A www.google.com
- */
- uint8_t req[] = {
- 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- };
- size_t reqlen = sizeof(req);
-
- DNSState *state = DNSStateAlloc();
- FAIL_IF_NULL(state);
- Flow *f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 53);
- FAIL_IF_NULL(f);
- f->proto = IPPROTO_UDP;
- f->alproto = ALPROTO_DNS;
- f->alstate = state;
-
- uint8_t flags = STREAM_START;
- uint16_t txid;
- for (txid = 1; txid <= DNS_CONFIG_DEFAULT_REQUEST_FLOOD + 1; txid++) {
- req[0] = (txid >> 8) & 0xff;
- req[1] = txid & 0xff;
- FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL, flags));
- FAIL_IF(state->givenup);
- flags = 0;
- }
-
- /* With one more request we should enter a flooded state. */
- txid++;
- req[0] = (txid >> 8) & 0xff;
- req[1] = txid & 0xff;
- FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL, 0));
- FAIL_IF(!state->givenup);
-
- /* Also free's state. */
- UTHFreeFlow(f);
-
- PASS;
-}
-
-static int DNSUDPParserTestLostResponse(void)
-{
- /* DNS request:
- * - Flags: 0x0100 Standard query
- * - A www.google.com
- */
- uint8_t req[] = {
- 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- };
- size_t reqlen = sizeof(req);
-
- uint8_t res[] = {
- 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x38,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x39,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x34,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x35,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x36,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x3b,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x37,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x3a
- };
- size_t reslen = sizeof(res);
-
- DNSTransaction *tx;
- DNSState *state = DNSStateAlloc();
- FAIL_IF_NULL(state);
- Flow *f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 53);
- FAIL_IF_NULL(f);
- f->proto = IPPROTO_UDP;
- f->alproto = ALPROTO_DNS;
- f->alstate = state;
-
- /* First request. */
- req[1] = 0x01;
- FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL, STREAM_START));
- FAIL_IF_NOT(state->transaction_max == 1);
- FAIL_IF_NOT(state->unreplied_cnt == 1);
- FAIL_IF_NOT(state->window == 1);
-
- /* Second request. */
- req[1] = 0x02;
- FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL, 0));
- FAIL_IF_NOT(state->transaction_max == 2);
- FAIL_IF_NOT(state->unreplied_cnt == 2);
- FAIL_IF_NOT(state->window == 2);
-
- /* Third request. */
- req[1] = 0x03;
- FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL, 0));
- FAIL_IF_NOT(state->transaction_max == 3);
- FAIL_IF_NOT(state->unreplied_cnt == 3);
- FAIL_IF_NOT(state->window == 3);
-
- /* Now respond to the second. */
- res[1] = 0x02;
- FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, res, reslen, NULL, 0));
- FAIL_IF_NOT(state->unreplied_cnt == 2);
- FAIL_IF_NOT(state->window == 3);
- tx = TAILQ_FIRST(&state->tx_list);
- FAIL_IF_NULL(tx);
- FAIL_IF(tx->replied);
- FAIL_IF(tx->reply_lost);
-
- /* Send a 4th request. */
- req[1] = 0x04;
- FAIL_IF_NOT(DNSUDPRequestParse(f, f->alstate, NULL, req, reqlen, NULL, 0));
- FAIL_IF_NOT(state->unreplied_cnt == 3);
- FAIL_IF(state->window != 3);
- FAIL_IF_NOT(state->transaction_max == 4);
-
- /* Response to the third request. */
- res[1] = 0x03;
- FAIL_IF_NOT(DNSUDPResponseParse(f, f->alstate, NULL, res, reslen, NULL, 0));
- FAIL_IF_NOT(state->unreplied_cnt == 2);
- FAIL_IF_NOT(state->window == 3);
- tx = TAILQ_FIRST(&state->tx_list);
- FAIL_IF_NULL(tx);
- FAIL_IF(tx->replied);
- FAIL_IF(!tx->reply_lost);
-
- /* Also free's state. */
- UTHFreeFlow(f);
-
- PASS;
-}
-
-static int DNSUDPParserTxCleanup(void)
-{
- uint64_t ret[4];
-
- /* DNS request:
- * - Flags: 0x0100 Standard query
- * - A www.google.com
- */
- uint8_t req[] = {
- 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- };
- size_t reqlen = sizeof(req);
-
- uint8_t res[] = {
- 0x00, 0x01, 0x81, 0x80, 0x00, 0x01, 0x00, 0x08,
- 0x00, 0x00, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77,
- 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03,
- 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x38,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x39,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x34,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x35,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x36,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x3b,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x37,
- 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
- 0x01, 0x08, 0x00, 0x04, 0x18, 0xf4, 0x04, 0x3a
- };
- size_t reslen = sizeof(res);
-
- Flow *f = UTHBuildFlow(AF_INET, "1.1.1.1", "2.2.2.2", 1024, 53);
- FAIL_IF_NULL(f);
- f->proto = IPPROTO_UDP;
- f->protomap = FlowGetProtoMapping(IPPROTO_UDP);
- f->alproto = ALPROTO_DNS;
-
- AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
- FAIL_IF_NULL(alp_tctx);
-
- /* First request. */
- req[1] = 0x01;
- int r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_DNS,
- STREAM_TOSERVER | STREAM_START, req, reqlen);
- FAIL_IF_NOT(r == 0);
- /* Second request. */
- req[1] = 0x02;
- r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_DNS,
- STREAM_TOSERVER, req, reqlen);
- FAIL_IF_NOT(r == 0);
- /* Third request. */
- req[1] = 0x03;
- r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_DNS,
- STREAM_TOSERVER, req, reqlen);
- FAIL_IF_NOT(r == 0);
-
- /* Now respond to the second. */
- res[1] = 0x02;
- r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_DNS,
- STREAM_TOCLIENT, res, reslen);
- FAIL_IF_NOT(r == 0);
-
- /* Send a 4th request. */
- req[1] = 0x04;
- r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_DNS,
- STREAM_TOSERVER, req, reqlen);
- FAIL_IF_NOT(r == 0);
-
- AppLayerParserTransactionsCleanup(f);
- UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
- FAIL_IF_NOT(ret[0] == 0); // inspect_id[0]
- FAIL_IF_NOT(ret[1] == 0); // inspect_id[1]
- FAIL_IF_NOT(ret[2] == 0); // log_id
- FAIL_IF_NOT(ret[3] == 0); // min_id
-
- /* Response to the third request. */
- res[1] = 0x03;
- r = AppLayerParserParse(NULL, alp_tctx, f, ALPROTO_DNS,
- STREAM_TOCLIENT, res, reslen);
- FAIL_IF_NOT(r == 0);
- DNSState *state = f->alstate;
- DNSTransaction *tx = TAILQ_FIRST(&state->tx_list);
- FAIL_IF_NULL(tx);
- FAIL_IF(tx->replied);
- FAIL_IF(!tx->reply_lost);
-
- AppLayerParserTransactionsCleanup(f);
- UTHAppLayerParserStateGetIds(f->alparser, &ret[0], &ret[1], &ret[2], &ret[3]);
- FAIL_IF_NOT(ret[0] == 3); // inspect_id[0]
- FAIL_IF_NOT(ret[1] == 3); // inspect_id[1]
- FAIL_IF_NOT(ret[2] == 3); // log_id
- FAIL_IF_NOT(ret[3] == 3); // min_id
-
- /* Also free's state. */
- UTHFreeFlow(f);
-
- PASS;
-}
-
-void DNSUDPParserRegisterTests(void)
-{
- UtRegisterTest("DNSUDPParserTest01", DNSUDPParserTest01);
- UtRegisterTest("DNSUDPParserTest02", DNSUDPParserTest02);
- UtRegisterTest("DNSUDPParserTest03", DNSUDPParserTest03);
- UtRegisterTest("DNSUDPParserTest04", DNSUDPParserTest04);
- UtRegisterTest("DNSUDPParserTest05", DNSUDPParserTest05);
- UtRegisterTest("DNSUDPParserTestFlood", DNSUDPParserTestFlood);
- UtRegisterTest("DNSUDPParserTestDelayedResponse",
- DNSUDPParserTestDelayedResponse);
- UtRegisterTest("DNSUDPParserTestLostResponse",
- DNSUDPParserTestLostResponse);
- UtRegisterTest("DNSUDPParserTxCleanup",
- DNSUDPParserTxCleanup);
}
-#endif
-#endif /* HAVE_RUST */
#ifndef __APP_LAYER_DNS_UDP_H__
#define __APP_LAYER_DNS_UDP_H__
-#include "app-layer-protos.h"
-#include "app-layer-parser.h"
-#include "app-layer-dns-common.h"
-#include "flow.h"
-#include "queue.h"
-#include "util-byte.h"
-
void RegisterDNSUDPParsers(void);
-void DNSUDPParserTests(void);
-void DNSUDPParserRegisterTests(void);
#endif /* __APP_LAYER_DNS_UDP_H__ */
*/
void AppLayerRegisterGlobalCounters(void)
{
- StatsRegisterGlobalCounter("dns.memuse", DNSMemcapGetMemuseCounter);
- StatsRegisterGlobalCounter("dns.memcap_state", DNSMemcapGetMemcapStateCounter);
- StatsRegisterGlobalCounter("dns.memcap_global", DNSMemcapGetMemcapGlobalCounter);
StatsRegisterGlobalCounter("http.memuse", HTPMemuseGlobalCounter);
StatsRegisterGlobalCounter("http.memcap", HTPMemcapGlobalCounter);
StatsRegisterGlobalCounter("ftp.memuse", FTPMemuseGlobalCounter);
#include "util-unittest-helper.h"
-#ifdef HAVE_RUST
#include "rust-dns-dns-gen.h"
-#endif
static int DetectDnsQuerySetup (DetectEngineCtx *, Signature *, const char *);
static void DetectDnsQueryRegisterTests(void);
struct DnsQueryGetDataArgs {
int local_id; /**< used as index into thread inspect array */
-#ifdef HAVE_RUST
void *txv;
-#else
- const DNSQueryEntry *query;
-#endif
};
static InspectionBuffer *DnsQueryGetData(DetectEngineThreadCtx *det_ctx,
const uint8_t *data;
uint32_t data_len;
-#ifdef HAVE_RUST
if (rs_dns_tx_get_query_name(cbdata->txv, (uint16_t)cbdata->local_id,
(uint8_t **)&data, &data_len) == 0) {
return NULL;
}
-#else
- const DNSQueryEntry *query = cbdata->query;
- data = (const uint8_t *)((uint8_t *)query + sizeof(DNSQueryEntry));
- data_len = query->len;
-#endif
InspectionBufferSetup(buffer, data, data_len);
InspectionBufferApplyTransforms(buffer, transforms);
transforms = engine->v2.transforms;
}
-#ifdef HAVE_RUST
while(1) {
struct DnsQueryGetDataArgs cbdata = { local_id, txv, };
InspectionBuffer *buffer = DnsQueryGetData(det_ctx,
}
local_id++;
}
-#else
- DNSTransaction *tx = (DNSTransaction *)txv;
- DNSQueryEntry *query = NULL;
- TAILQ_FOREACH(query, &tx->query_list, next)
- {
- struct DnsQueryGetDataArgs cbdata = { local_id, query };
- InspectionBuffer *buffer = DnsQueryGetData(det_ctx,
- transforms, f, &cbdata, engine->sm_list, false);
- if (buffer == NULL || buffer->inspect == NULL)
- break;
-
- det_ctx->buffer_offset = 0;
- det_ctx->discontinue_matching = 0;
- det_ctx->inspection_recursion_counter = 0;
-
- const int match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd,
- f,
- (uint8_t *)buffer->inspect,
- buffer->inspect_len,
- buffer->inspect_offset, DETECT_CI_FLAGS_SINGLE,
- DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE, NULL);
- if (match == 1) {
- return DETECT_ENGINE_INSPECT_SIG_MATCH;
- }
- local_id++;
- }
-#endif
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
}
const int list_id = ctx->list_id;
int local_id = 0;
-#ifdef HAVE_RUST
while(1) {
// loop until we get a NULL
local_id++;
}
-#else
- const DNSTransaction *tx = (DNSTransaction *)txv;
- const DNSQueryEntry *query = NULL;
- TAILQ_FOREACH(query, &tx->query_list, next)
- {
- struct DnsQueryGetDataArgs cbdata = { local_id, query };
- InspectionBuffer *buffer = DnsQueryGetData(det_ctx, ctx->transforms,
- f, &cbdata, list_id, true);
-
- if (buffer != NULL && buffer->inspect_len >= mpm_ctx->minlen) {
- (void)mpm_table[mpm_ctx->mpm_type].Search(mpm_ctx,
- &det_ctx->mtcu, &det_ctx->pmq,
- buffer->inspect, buffer->inspect_len);
- }
- local_id++;
- }
-#endif
}
static void PrefilterMpmDnsQueryFree(void *ptr)
0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00,
0x00, 0x10, 0x00, 0x01, };
Flow f;
- DNSState *dns_state = NULL;
+ RSDNSState *dns_state = NULL;
Packet *p = NULL;
Signature *s = NULL;
ThreadVars tv;
0x65, 0x03, 0x6E, 0x65, 0x74, 0x00,
0x00, 0x10, 0x00, 0x01, };
Flow f;
- DNSState *dns_state = NULL;
+ RSDNSState *dns_state = NULL;
Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
Signature *s = NULL;
ThreadVars tv;
0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00,
0x00, 0x10, 0x00, 0x01, };
Flow f;
- DNSState *dns_state = NULL;
+ RSDNSState *dns_state = NULL;
Packet *p = NULL;
Signature *s = NULL;
ThreadVars tv;
0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00,
0x00, 0x10, 0x00, 0x01, };
Flow f;
- DNSState *dns_state = NULL;
+ RSDNSState *dns_state = NULL;
Packet *p1 = NULL, *p2 = NULL;
Signature *s = NULL;
ThreadVars tv;
0x65, 0x03, 0x6E, 0x65, 0x74, 0x00,
0x00, 0x10, 0x00, 0x01, };
Flow f;
- DNSState *dns_state = NULL;
+ RSDNSState *dns_state = NULL;
Packet *p1 = NULL, *p2 = NULL, *p3 = NULL, *p4 = NULL;
Signature *s = NULL;
ThreadVars tv;
0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00,
0x00, 0x10, 0x00, 0x01, };
Flow f;
- DNSState *dns_state = NULL;
+ RSDNSState *dns_state = NULL;
Packet *p = NULL;
Signature *s = NULL;
ThreadVars tv;
0x65, 0x03, 0x6E, 0x65, 0x74, 0x00,
0x00, 0x10, 0x00, 0x01, };
Flow f;
- DNSState *dns_state = NULL;
+ RSDNSState *dns_state = NULL;
Packet *p1 = NULL, *p2 = NULL, *p3 = NULL;
Signature *s = NULL;
ThreadVars tv;
static void AlertJsonDns(const Flow *f, const uint64_t tx_id, json_t *js)
{
- DNSState *dns_state = (DNSState *)FlowGetAppState(f);
+ RSDNSState *dns_state = (RSDNSState *)FlowGetAppState(f);
if (dns_state) {
void *txptr = AppLayerParserGetTx(f->proto, ALPROTO_DNS,
dns_state, tx_id);
#include "output-json.h"
#include "output-json-dns.h"
-#ifdef HAVE_LIBJANSSON
-
-#ifdef HAVE_RUST
#include "rust-dns-log-gen.h"
-#endif
/* we can do query logging as well, but it's disabled for now as the
* TX id handling doesn't expect it */
DNS_VERSION_2
} DnsVersion;
-#ifdef HAVE_RUST
#define DNS_VERSION_DEFAULT DNS_VERSION_2
-#else
-#define DNS_VERSION_DEFAULT DNS_VERSION_1
-#endif
static struct {
const char *config_rrtype;
MemBuffer *buffer;
} LogDnsLogThread;
-#ifndef HAVE_RUST
-static int DNSRRTypeEnabled(uint16_t type, uint64_t flags)
-{
- if (likely(flags == ~0UL)) {
- return 1;
- }
-
- switch (type) {
- case DNS_RECORD_TYPE_A:
- return ((flags & LOG_A) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_NS:
- return ((flags & LOG_NS) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_MD:
- return ((flags & LOG_MD) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_MF:
- return ((flags & LOG_MF) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_CNAME:
- return ((flags & LOG_CNAME) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_SOA:
- return ((flags & LOG_SOA) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_MB:
- return ((flags & LOG_MB) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_MG:
- return ((flags & LOG_MG) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_MR:
- return ((flags & LOG_MR) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_NULL:
- return ((flags & LOG_NULL) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_WKS:
- return ((flags & LOG_WKS) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_PTR:
- return ((flags & LOG_PTR) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_HINFO:
- return ((flags & LOG_HINFO) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_MINFO:
- return ((flags & LOG_MINFO) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_MX:
- return ((flags & LOG_MX) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_TXT:
- return ((flags & LOG_TXT) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_RP:
- return ((flags & LOG_RP) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_AFSDB:
- return ((flags & LOG_AFSDB) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_X25:
- return ((flags & LOG_X25) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_ISDN:
- return ((flags & LOG_ISDN) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_RT:
- return ((flags & LOG_RT) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_NSAP:
- return ((flags & LOG_NSAP) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_NSAPPTR:
- return ((flags & LOG_NSAPPTR) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_SIG:
- return ((flags & LOG_SIG) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_KEY:
- return ((flags & LOG_KEY) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_PX:
- return ((flags & LOG_PX) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_GPOS:
- return ((flags & LOG_GPOS) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_AAAA:
- return ((flags & LOG_AAAA) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_LOC:
- return ((flags & LOG_LOC) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_NXT:
- return ((flags & LOG_NXT) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_SRV:
- return ((flags & LOG_SRV) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_ATMA:
- return ((flags & LOG_ATMA) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_NAPTR:
- return ((flags & LOG_NAPTR) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_KX:
- return ((flags & LOG_KX) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_CERT:
- return ((flags & LOG_CERT) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_A6:
- return ((flags & LOG_A6) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_DNAME:
- return ((flags & LOG_DNAME) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_OPT:
- return ((flags & LOG_OPT) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_APL:
- return ((flags & LOG_APL) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_DS:
- return ((flags & LOG_DS) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_SSHFP:
- return ((flags & LOG_SSHFP) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_IPSECKEY:
- return ((flags & LOG_IPSECKEY) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_RRSIG:
- return ((flags & LOG_RRSIG) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_NSEC:
- return ((flags & LOG_NSEC) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_DNSKEY:
- return ((flags & LOG_DNSKEY) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_DHCID:
- return ((flags & LOG_DHCID) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_NSEC3:
- return ((flags & LOG_NSEC3) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_NSEC3PARAM:
- return ((flags & LOG_NSEC3PARAM) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_TLSA:
- return ((flags & LOG_TLSA) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_HIP:
- return ((flags & LOG_HIP) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_CDS:
- return ((flags & LOG_CDS) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_CDNSKEY:
- return ((flags & LOG_CDNSKEY) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_SPF:
- return ((flags & LOG_SPF) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_TKEY:
- return ((flags & LOG_TKEY) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_TSIG:
- return ((flags & LOG_TSIG) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_MAILA:
- return ((flags & LOG_MAILA) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_ANY:
- return ((flags & LOG_ANY) != 0) ? 1 : 0;
- case DNS_RECORD_TYPE_URI:
- return ((flags & LOG_URI) != 0) ? 1 : 0;
- default:
- return 0;
- }
-}
-#endif
-
-#ifndef HAVE_RUST
-static json_t *OutputQuery(DNSTransaction *tx, uint64_t tx_id, DNSQueryEntry *entry)
-{
- json_t *djs = json_object();
- if (djs == NULL) {
- return NULL;
- }
-
- /* type */
- json_object_set_new(djs, "type", json_string("query"));
-
- /* id */
- json_object_set_new(djs, "id", json_integer(tx->tx_id));
-
- /* query */
- char *c;
- c = BytesToString((uint8_t *)((uint8_t *)entry + sizeof(DNSQueryEntry)), entry->len);
- if (c != NULL) {
- json_object_set_new(djs, "rrname", SCJsonString(c));
- SCFree(c);
- }
-
- /* name */
- char record[16] = "";
- DNSCreateTypeString(entry->type, record, sizeof(record));
- json_object_set_new(djs, "rrtype", json_string(record));
-
- /* tx id (tx counter) */
- json_object_set_new(djs, "tx_id", json_integer(tx_id));
-
- return djs;
-}
-
-static void LogQuery(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx,
- uint64_t tx_id, DNSQueryEntry *entry)
-{
- SCLogDebug("got a DNS request and now logging !!");
-
- if (!DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) {
- return;
- }
-
- json_t *djs = OutputQuery(tx, tx_id, entry);
- if (djs == NULL) {
- return;
- }
-
- /* reset */
- MemBufferReset(aft->buffer);
-
- /* dns */
- json_object_set_new(js, "dns", djs);
- OutputJSONBuffer(js, aft->dnslog_ctx->file_ctx, &aft->buffer);
- json_object_del(js, "dns");
-}
-#endif
-
json_t *JsonDNSLogQuery(void *txptr, uint64_t tx_id)
{
json_t *queryjs = json_array();
if (queryjs == NULL)
return NULL;
-#ifdef HAVE_RUST
for (uint16_t i = 0; i < UINT16_MAX; i++) {
json_t *dns = rs_dns_log_json_query((void *)txptr, i, LOG_ALL_RRTYPES);
if (unlikely(dns == NULL)) {
}
json_array_append_new(queryjs, dns);
}
-#else
- DNSTransaction *tx = txptr;
- DNSQueryEntry *entry = NULL;
- TAILQ_FOREACH(entry, &tx->query_list, next) {
- json_t *qjs = OutputQuery(tx, tx_id, entry);
- if (qjs != NULL) {
- json_array_append_new(queryjs, qjs);
- }
- }
-#endif
return queryjs;
}
-#ifndef HAVE_RUST
-
-static json_t *DnsParseSshFpType(DNSAnswerEntry *entry, uint8_t *ptr)
-{
- /* get algo and type */
- uint8_t algo = *ptr;
- uint8_t fptype = *(ptr+1);
-
- /* turn fp raw buffer into a nice :-separate hex string */
- uint16_t fp_len = (entry->data_len - 2);
- uint8_t *dptr = ptr+2;
-
- /* c-string for ':' separated hex and trailing \0. */
- uint32_t output_len = fp_len * 3 + 1;
- char hexstring[output_len];
- memset(hexstring, 0x00, output_len);
-
- uint16_t x;
- for (x = 0; x < fp_len; x++) {
- char one[4];
- snprintf(one, sizeof(one), x == fp_len - 1 ? "%02x" : "%02x:", dptr[x]);
- strlcat(hexstring, one, output_len);
- }
-
- /* wrap the whole thing in it's own structure */
- json_t *hjs = json_object();
- if (hjs == NULL) {
- return NULL;
- }
-
- json_object_set_new(hjs, "fingerprint", json_string(hexstring));
- json_object_set_new(hjs, "algo", json_integer(algo));
- json_object_set_new(hjs, "type", json_integer(fptype));
-
- return hjs;
-}
-
-static void OutputAnswerDetailed(DNSAnswerEntry *entry, json_t *js,
- uint64_t flags)
-{
- do {
- json_t *jdata = json_object();
- if (jdata == NULL) {
- return;
- }
-
- /* query */
- if (entry->fqdn_len > 0) {
- char *c;
- c = BytesToString((uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)),
- entry->fqdn_len);
- if (c != NULL) {
- json_object_set_new(jdata, "rrname", json_string(c));
- SCFree(c);
- }
- }
-
- /* name */
- char record[16] = "";
- DNSCreateTypeString(entry->type, record, sizeof(record));
- json_object_set_new(jdata, "rrtype", json_string(record));
-
- /* ttl */
- json_object_set_new(jdata, "ttl", json_integer(entry->ttl));
-
- uint8_t *ptr = (uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)+ entry->fqdn_len);
- if (entry->type == DNS_RECORD_TYPE_A && entry->data_len == 4) {
- char a[16] = "";
- PrintInet(AF_INET, (const void *)ptr, a, sizeof(a));
- json_object_set_new(jdata, "rdata", json_string(a));
- } else if (entry->type == DNS_RECORD_TYPE_AAAA && entry->data_len == 16) {
- char a[46] = "";
- PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a));
- json_object_set_new(jdata, "rdata", json_string(a));
- } else if (entry->data_len == 0) {
- json_object_set_new(jdata, "rdata", json_string(""));
- } else if (entry->type == DNS_RECORD_TYPE_TXT || entry->type == DNS_RECORD_TYPE_CNAME ||
- entry->type == DNS_RECORD_TYPE_MX || entry->type == DNS_RECORD_TYPE_PTR ||
- entry->type == DNS_RECORD_TYPE_NS) {
- if (entry->data_len != 0) {
- char buffer[256] = "";
- uint16_t copy_len = entry->data_len < (sizeof(buffer) - 1) ?
- entry->data_len : sizeof(buffer) - 1;
- memcpy(buffer, ptr, copy_len);
- buffer[copy_len] = '\0';
- json_object_set_new(jdata, "rdata", json_string(buffer));
- } else {
- json_object_set_new(jdata, "rdata", json_string(""));
- }
- } else if (entry->type == DNS_RECORD_TYPE_SSHFP) {
- if (entry->data_len > 2) {
- json_t *hjs = DnsParseSshFpType(entry, ptr);
- if (hjs != NULL) {
- json_object_set_new(jdata, "sshfp", hjs);
- }
- }
- }
- json_array_append_new(js, jdata);
- } while ((entry = TAILQ_NEXT(entry, next)));
-}
-
-static void OutputAnswerGrouped(DNSAnswerEntry *entry, json_t *js)
-{
- struct {
- #define ENTRY_TYPE_A 0
- #define ENTRY_TYPE_AAAA 1
- #define ENTRY_TYPE_TXT 2
- #define ENTRY_TYPE_CNAME 3
- #define ENTRY_TYPE_MX 4
- #define ENTRY_TYPE_PTR 5
- #define ENTRY_TYPE_NS 6
- #define ENTRY_TYPE_SSHFP 7
- #define ENTRY_TYPE_MAX 8
- const char *name;
- json_t *value;
- } dns_rtypes[] = {
- { "A", NULL },
- { "AAAA", NULL },
- { "TXT", NULL },
- { "CNAME", NULL },
- { "MX", NULL },
- { "PTR", NULL },
- { "NS", NULL },
- { "SSHFP", NULL }
- };
-
- int i;
- json_t *jrdata = json_object();
- if (jrdata == NULL) {
- return;
- }
-
- do {
- uint8_t *ptr = (uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)+ entry->fqdn_len);
- if (entry->type == DNS_RECORD_TYPE_A && entry->data_len == 4) {
- char a[16] = "";
- if (dns_rtypes[ENTRY_TYPE_A].value == NULL) {
- dns_rtypes[ENTRY_TYPE_A].value = json_array();
- if (dns_rtypes[ENTRY_TYPE_A].value == NULL) {
- goto out;
- }
- }
- PrintInet(AF_INET, (const void *)ptr, a, sizeof(a));
- json_array_append_new(dns_rtypes[ENTRY_TYPE_A].value, json_string(a));
- } else if (entry->type == DNS_RECORD_TYPE_AAAA && entry->data_len == 16) {
- char a[46] = "";
- if (dns_rtypes[ENTRY_TYPE_AAAA].value == NULL) {
- dns_rtypes[ENTRY_TYPE_AAAA].value = json_array();
- if (dns_rtypes[ENTRY_TYPE_AAAA].value == NULL) {
- goto out;
- }
- }
- PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a));
- json_array_append_new(dns_rtypes[ENTRY_TYPE_AAAA].value, json_string(a));
- } else if (entry->data_len == 0) {
- json_object_set_new(js, "rdata", json_string(""));
- } else if (entry->type == DNS_RECORD_TYPE_TXT || entry->type == DNS_RECORD_TYPE_CNAME ||
- entry->type == DNS_RECORD_TYPE_MX || entry->type == DNS_RECORD_TYPE_PTR ||
- entry->type == DNS_RECORD_TYPE_NS) {
- if (entry->data_len != 0) {
- char buffer[256] = "";
- uint16_t copy_len = entry->data_len < (sizeof(buffer) - 1) ?
- entry->data_len : sizeof(buffer) - 1;
- memcpy(buffer, ptr, copy_len);
- buffer[copy_len] = '\0';
-
- if (entry->type == DNS_RECORD_TYPE_TXT) {
- if (dns_rtypes[ENTRY_TYPE_TXT].value == NULL) {
- dns_rtypes[ENTRY_TYPE_TXT].value = json_array();
- if (dns_rtypes[ENTRY_TYPE_TXT].value == NULL) {
- goto out;
- }
- }
- json_array_append_new(dns_rtypes[ENTRY_TYPE_TXT].value, json_string(buffer));
- } else if (entry->type == DNS_RECORD_TYPE_CNAME) {
- if (dns_rtypes[ENTRY_TYPE_CNAME].value == NULL) {
- dns_rtypes[ENTRY_TYPE_CNAME].value = json_array();
- if (dns_rtypes[ENTRY_TYPE_CNAME].value == NULL) {
- goto out;
- }
- }
- json_array_append_new(dns_rtypes[ENTRY_TYPE_CNAME].value, json_string(buffer));
- } else if (entry->type == DNS_RECORD_TYPE_MX) {
- if (dns_rtypes[ENTRY_TYPE_MX].value == NULL) {
- dns_rtypes[ENTRY_TYPE_MX].value = json_array();
- if (dns_rtypes[ENTRY_TYPE_MX].value == NULL) {
- goto out;
- }
- }
- json_array_append_new(dns_rtypes[ENTRY_TYPE_MX].value, json_string(buffer));
- } else if (entry->type == DNS_RECORD_TYPE_PTR) {
- if (dns_rtypes[ENTRY_TYPE_PTR].value == NULL) {
- dns_rtypes[ENTRY_TYPE_PTR].value = json_array();
- if (dns_rtypes[ENTRY_TYPE_PTR].value == NULL) {
- goto out;
- }
- }
- json_array_append_new(dns_rtypes[ENTRY_TYPE_PTR].value, json_string(buffer));
- } else if (entry->type == DNS_RECORD_TYPE_NS) {
- if (dns_rtypes[ENTRY_TYPE_NS].value == NULL) {
- dns_rtypes[ENTRY_TYPE_NS].value = json_array();
- if (dns_rtypes[ENTRY_TYPE_NS].value == NULL) {
- goto out;
- }
- }
- json_array_append_new(dns_rtypes[ENTRY_TYPE_NS].value, json_string(buffer));
- }
- } else {
- json_object_set_new(js, "rdata", json_string(""));
- }
- } else if (entry->type == DNS_RECORD_TYPE_SSHFP) {
- if (entry->data_len > 2) {
- json_t *hjs = DnsParseSshFpType(entry, ptr);
- if (hjs != NULL) {
- if (dns_rtypes[ENTRY_TYPE_SSHFP].value == NULL) {
- dns_rtypes[ENTRY_TYPE_SSHFP].value = json_array();
- if (dns_rtypes[ENTRY_TYPE_SSHFP].value == NULL) {
- goto out;
- }
- }
- json_array_append_new(dns_rtypes[ENTRY_TYPE_SSHFP].value, hjs);
- }
- }
- }
- } while ((entry = TAILQ_NEXT(entry, next)));
-
-out:
- for (i = 0; i < ENTRY_TYPE_MAX; i++) {
- if (dns_rtypes[i].value != NULL) {
- json_object_set_new(jrdata, dns_rtypes[i].name, dns_rtypes[i].value);
- dns_rtypes[i].value = NULL;
- }
- }
-
- json_object_set_new(js, "grouped", jrdata);
-}
-
-static void OutputAnswerV1(LogDnsLogThread *aft, json_t *djs,
- DNSTransaction *tx, DNSAnswerEntry *entry)
-{
- if (!DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) {
- return;
- }
-
- json_t *js = json_object();
- if (js == NULL)
- return;
-
- /* type */
- json_object_set_new(js, "type", json_string("answer"));
-
- /* id */
- json_object_set_new(js, "id", json_integer(tx->tx_id));
-
- /* dns */
- char flags[7] = "";
- snprintf(flags, sizeof(flags), "%4x", tx->flags);
- json_object_set_new(js, "flags", json_string(flags));
- if (tx->flags & 0x8000)
- json_object_set_new(js, "qr", json_true());
- if (tx->flags & 0x0400)
- json_object_set_new(js, "aa", json_true());
- if (tx->flags & 0x0200)
- json_object_set_new(js, "tc", json_true());
- if (tx->flags & 0x0100)
- json_object_set_new(js, "rd", json_true());
- if (tx->flags & 0x0080)
- json_object_set_new(js, "ra", json_true());
-
-
- /* rcode */
- char rcode[16] = "";
- DNSCreateRcodeString(tx->rcode, rcode, sizeof(rcode));
- json_object_set_new(js, "rcode", json_string(rcode));
-
- /* query */
- if (entry->fqdn_len > 0) {
- char *c;
- c = BytesToString((uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)),
- entry->fqdn_len);
- if (c != NULL) {
- json_object_set_new(js, "rrname", SCJsonString(c));
- SCFree(c);
- }
- }
-
- /* name */
- char record[16] = "";
- DNSCreateTypeString(entry->type, record, sizeof(record));
- json_object_set_new(js, "rrtype", json_string(record));
-
- /* ttl */
- json_object_set_new(js, "ttl", json_integer(entry->ttl));
-
- uint8_t *ptr = (uint8_t *)((uint8_t *)entry + sizeof(DNSAnswerEntry)+ entry->fqdn_len);
- if (entry->type == DNS_RECORD_TYPE_A && entry->data_len == 4) {
- char a[16] = "";
- PrintInet(AF_INET, (const void *)ptr, a, sizeof(a));
- json_object_set_new(js, "rdata", json_string(a));
- } else if (entry->type == DNS_RECORD_TYPE_AAAA && entry->data_len == 16) {
- char a[46] = "";
- PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a));
- json_object_set_new(js, "rdata", json_string(a));
- } else if (entry->data_len == 0) {
- json_object_set_new(js, "rdata", json_string(""));
- } else if (entry->type == DNS_RECORD_TYPE_TXT || entry->type == DNS_RECORD_TYPE_CNAME ||
- entry->type == DNS_RECORD_TYPE_MX || entry->type == DNS_RECORD_TYPE_PTR ||
- entry->type == DNS_RECORD_TYPE_NS) {
- if (entry->data_len != 0) {
- char buffer[256] = "";
- uint16_t copy_len = entry->data_len < (sizeof(buffer) - 1) ?
- entry->data_len : sizeof(buffer) - 1;
- memcpy(buffer, ptr, copy_len);
- buffer[copy_len] = '\0';
- json_object_set_new(js, "rdata", SCJsonString(buffer));
- } else {
- json_object_set_new(js, "rdata", json_string(""));
- }
- } else if (entry->type == DNS_RECORD_TYPE_SSHFP) {
- if (entry->data_len > 2) {
- json_t *hjs = DnsParseSshFpType(entry, ptr);
- if (hjs != NULL) {
- json_object_set_new(js, "sshfp", hjs);
- }
- }
- }
-
- /* reset */
- MemBufferReset(aft->buffer);
- json_object_set_new(djs, "dns", js);
- OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer);
- json_object_del(djs, "dns");
-
- return;
-}
-
-static json_t *BuildAnswer(DNSTransaction *tx, uint64_t tx_id, uint64_t flags,
- DnsVersion version)
-{
- json_t *js = json_object();
- if (js == NULL)
- return NULL;
-
- /* version */
- if (version == DNS_VERSION_2) {
- json_object_set_new(js, "version", json_integer(DNS_VERSION_2));
- } else {
- json_object_set_new(js, "version", json_integer(DNS_VERSION_1));
- }
-
- /* type */
- json_object_set_new(js, "type", json_string("answer"));
-
- /* id */
- json_object_set_new(js, "id", json_integer(tx->tx_id));
-
- /* flags */
- char dns_flags[7] = "";
- snprintf(dns_flags, sizeof(dns_flags), "%4x", tx->flags);
- json_object_set_new(js, "flags", json_string(dns_flags));
- if (tx->flags & 0x8000)
- json_object_set_new(js, "qr", json_true());
- if (tx->flags & 0x0400)
- json_object_set_new(js, "aa", json_true());
- if (tx->flags & 0x0200)
- json_object_set_new(js, "tc", json_true());
- if (tx->flags & 0x0100)
- json_object_set_new(js, "rd", json_true());
- if (tx->flags & 0x0080)
- json_object_set_new(js, "ra", json_true());
-
- /* rcode */
- char rcode[16] = "";
- DNSCreateRcodeString(tx->rcode, rcode, sizeof(rcode));
- json_object_set_new(js, "rcode", json_string(rcode));
-
- /* Log the query rrname and rrtype. Mostly useful on error, but
- * still useful. */
- DNSQueryEntry *query = TAILQ_FIRST(&tx->query_list);
- if (query != NULL) {
- char *c;
- c = BytesToString((uint8_t *)((uint8_t *)query + sizeof(DNSQueryEntry)),
- query->len);
- if (c != NULL) {
- json_object_set_new(js, "rrname", json_string(c));
- SCFree(c);
- }
- char rrtype[16] = "";
- DNSCreateTypeString(query->type, rrtype, sizeof(rrtype));
- json_object_set_new(js, "rrtype", json_string(rrtype));
- }
-
- if (flags & LOG_FORMAT_DETAILED) {
- if (!TAILQ_EMPTY(&tx->answer_list)) {
- json_t *jarray = json_array();
- if (jarray == NULL) {
- json_decref(js);
- return NULL;
- }
- OutputAnswerDetailed(TAILQ_FIRST(&tx->answer_list), jarray, flags);
- json_object_set_new(js, "answers", jarray);
- }
-
- if (!TAILQ_EMPTY(&tx->authority_list)) {
- json_t *js_authorities = json_array();
- if (likely(js_authorities != NULL)) {
- OutputAnswerDetailed(TAILQ_FIRST(&tx->authority_list),
- js_authorities, flags);
- json_object_set_new(js, "authorities", js_authorities);
- }
- }
- }
-
- if (!TAILQ_EMPTY(&tx->answer_list) && (flags & LOG_FORMAT_GROUPED)) {
- OutputAnswerGrouped(TAILQ_FIRST(&tx->answer_list), js);
- }
-
- return js;
-}
-
-static void OutputAnswerV2(LogDnsLogThread *aft, json_t *djs,
- DNSTransaction *tx)
-{
- json_t *dnsjs = BuildAnswer(tx, tx->tx_id, aft->dnslog_ctx->flags,
- aft->dnslog_ctx->version);
- if (dnsjs != NULL) {
- /* reset */
- MemBufferReset(aft->buffer);
- json_object_set_new(djs, "dns", dnsjs);
- OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer);
- }
-}
-#endif
-
json_t *JsonDNSLogAnswer(void *txptr, uint64_t tx_id)
{
-#ifdef HAVE_RUST
return rs_dns_log_json_answer(txptr, LOG_ALL_RRTYPES);
-#else
- DNSTransaction *tx = txptr;
- DNSAnswerEntry *entry = TAILQ_FIRST(&tx->answer_list);
- if (entry) {
- return BuildAnswer(tx, tx_id, LOG_FORMAT_DETAILED, DNS_VERSION_2);
- }
- return NULL;
-#endif
-}
-
-#ifndef HAVE_RUST
-static void OutputFailure(LogDnsLogThread *aft, json_t *djs,
- DNSTransaction *tx, DNSQueryEntry *entry) __attribute__((nonnull));
-
-static void OutputFailure(LogDnsLogThread *aft, json_t *djs,
- DNSTransaction *tx, DNSQueryEntry *entry)
-{
- if (!DNSRRTypeEnabled(entry->type, aft->dnslog_ctx->flags)) {
- return;
- }
-
- json_t *js = json_object();
- if (js == NULL)
- return;
-
- /* type */
- json_object_set_new(js, "type", json_string("answer"));
-
- /* id */
- json_object_set_new(js, "id", json_integer(tx->tx_id));
-
- /* rcode */
- char rcode[16] = "";
- DNSCreateRcodeString(tx->rcode, rcode, sizeof(rcode));
- json_object_set_new(js, "rcode", json_string(rcode));
-
- /* no answer RRs, use query for rname */
- char *c;
- c = BytesToString((uint8_t *)((uint8_t *)entry + sizeof(DNSQueryEntry)), entry->len);
- if (c != NULL) {
- json_object_set_new(js, "rrname", SCJsonString(c));
- SCFree(c);
- }
-
- /* reset */
- MemBufferReset(aft->buffer);
- json_object_set_new(djs, "dns", js);
- OutputJSONBuffer(djs, aft->dnslog_ctx->file_ctx, &aft->buffer);
- json_object_del(djs, "dns");
-
- return;
}
-#endif
-
-#ifndef HAVE_RUST
-static void LogAnswers(LogDnsLogThread *aft, json_t *js, DNSTransaction *tx, uint64_t tx_id)
-{
-
- SCLogDebug("got a DNS response and now logging !!");
-
- if (aft->dnslog_ctx->version == DNS_VERSION_2) {
- DNSQueryEntry *query = TAILQ_FIRST(&tx->query_list);
- if (query && !DNSRRTypeEnabled(query->type, aft->dnslog_ctx->flags)) {
- return;
- }
- OutputAnswerV2(aft, js, tx);
- } else {
- DNSAnswerEntry *entry = NULL;
-
- /* rcode != noerror */
- if (tx->rcode) {
- /* Most DNS servers do not support multiple queries because
- * the rcode in response is not per-query. Multiple queries
- * are likely to lead to FORMERR, so log this. */
- DNSQueryEntry *query = NULL;
- TAILQ_FOREACH(query, &tx->query_list, next) {
- OutputFailure(aft, js, tx, query);
- }
- }
-
- TAILQ_FOREACH(entry, &tx->answer_list, next) {
- OutputAnswerV1(aft, js, tx, entry);
- }
- TAILQ_FOREACH(entry, &tx->authority_list, next) {
- OutputAnswerV1(aft, js, tx, entry);
- }
- }
-
-}
-#endif
static int JsonDnsLoggerToServer(ThreadVars *tv, void *thread_data,
const Packet *p, Flow *f, void *alstate, void *txptr, uint64_t tx_id)
return TM_ECODE_OK;
}
-#ifdef HAVE_RUST
for (uint16_t i = 0; i < 0xffff; i++) {
js = CreateJSONHeader(p, LOG_DIR_PACKET, "dns");
if (unlikely(js == NULL)) {
OutputJSONBuffer(js, td->dnslog_ctx->file_ctx, &td->buffer);
json_decref(js);
}
-#else
- DNSTransaction *tx = txptr;
- DNSQueryEntry *query = NULL;
- TAILQ_FOREACH(query, &tx->query_list, next) {
- js = CreateJSONHeader(p, LOG_DIR_PACKET, "dns");
- if (unlikely(js == NULL))
- return TM_ECODE_OK;
-
- JsonAddCommonOptions(&dnslog_ctx->cfg, p, f, js);
-
- LogQuery(td, js, tx, tx_id, query);
-
- json_decref(js);
- }
-#endif
SCReturnInt(TM_ECODE_OK);
}
JsonAddCommonOptions(&dnslog_ctx->cfg, p, f, js);
-#if HAVE_RUST
if (td->dnslog_ctx->version == DNS_VERSION_2) {
json_t *answer = rs_dns_log_json_answer(txptr,
td->dnslog_ctx->flags);
json_object_del(js, "dns");
}
}
-#else
- DNSTransaction *tx = txptr;
-
- LogAnswers(td, js, tx, tx_id);
-#endif
json_decref(js);
JsonDnsLoggerToClient, 1, 1, LogDnsLogThreadInit, LogDnsLogThreadDeinit,
NULL);
}
-
-#else
-
-void JsonDnsLogRegister (void)
-{
-}
-
-#endif
void JsonDnsLogRegister(void);
-#ifdef HAVE_LIBJANSSON
#include "app-layer-dns-common.h"
json_t *JsonDNSLogQuery(void *txptr, uint64_t tx_id) __attribute__((nonnull));
json_t *JsonDNSLogAnswer(void *txptr, uint64_t tx_id) __attribute__((nonnull));
-#endif
#endif /* __OUTPUT_JSON_DNS_H__ */
#include "util-lua-common.h"
#include "util-lua-dns.h"
-#ifdef HAVE_RUST
#include "rust-dns-dns-gen.h"
#include "rust-dns-lua-gen.h"
-#endif
static int DnsGetDnsRrname(lua_State *luastate)
{
if (!(LuaStateNeedProto(luastate, ALPROTO_DNS)))
return LuaCallbackError(luastate, "error: protocol not dns");
-#ifdef HAVE_RUST
RSDNSTransaction *tx = LuaStateGetTX(luastate);
if (tx == NULL) {
return LuaCallbackError(luastate, "internal error: no tx");
}
return rs_dns_lua_get_rrname(luastate, tx);
-#else
- DNSTransaction *tx = LuaStateGetTX(luastate);
- if (tx == NULL)
- return LuaCallbackError(luastate, "internal error: no tx");
-
- DNSQueryEntry *query = NULL;
- TAILQ_FOREACH(query, &tx->query_list, next) {
- char *c;
- size_t input_len;
- c = BytesToString((uint8_t *)((uint8_t *)query + sizeof(DNSQueryEntry)), query->len);
- if (c != NULL) {
- int ret;
- input_len = strlen(c);
- /* sanity check */
- if (input_len > (size_t)(2 * query->len)) {
- SCFree(c);
- return LuaCallbackError(luastate, "invalid length");
- }
- ret = LuaPushStringBuffer(luastate, (uint8_t *)c, input_len);
- SCFree(c);
- return ret;
- }
- }
- return LuaCallbackError(luastate, "no query");
-#endif
}
static int DnsGetTxid(lua_State *luastate)
{
if (!(LuaStateNeedProto(luastate, ALPROTO_DNS)))
return LuaCallbackError(luastate, "error: protocol not dns");
-#ifdef HAVE_RUST
RSDNSTransaction *tx = LuaStateGetTX(luastate);
if (tx == NULL) {
return LuaCallbackError(luastate, "internal error: no tx");
}
rs_dns_lua_get_tx_id(luastate, tx);
-#else
- DNSTransaction *tx = LuaStateGetTX(luastate);
- if (tx == NULL)
- return LuaCallbackError(luastate, "internal error: no tx");
-
- lua_pushinteger(luastate, tx->tx_id);
-#endif
return 1;
}
if (!(LuaStateNeedProto(luastate, ALPROTO_DNS)))
return LuaCallbackError(luastate, "error: protocol not dns");
uint16_t rcode = 0;
-#ifdef HAVE_RUST
RSDNSTransaction *tx = LuaStateGetTX(luastate);
if (tx == NULL) {
return LuaCallbackError(luastate, "internal error: no tx");
}
uint16_t flags = rs_dns_tx_get_response_flags(tx);
rcode = flags & 0x000f;
-#else
- DNSTransaction *tx = LuaStateGetTX(luastate);
- if (tx == NULL)
- return LuaCallbackError(luastate, "internal error: no tx");
- rcode = tx->rcode;
-#endif
if (rcode) {
char rcode_str[16] = "";
DNSCreateRcodeString(rcode, rcode_str, sizeof(rcode_str));
{
if (!(LuaStateNeedProto(luastate, ALPROTO_DNS)))
return LuaCallbackError(luastate, "error: protocol not dns");
-#ifdef HAVE_RUST
RSDNSTransaction *tx = LuaStateGetTX(luastate);
if (tx == NULL) {
return LuaCallbackError(luastate, "internal error: no tx");
uint16_t flags = rs_dns_tx_get_response_flags(tx);
int recursion_desired = flags & 0x0080 ? 1 : 0;
lua_pushboolean(luastate, recursion_desired);
-#else
- DNSTransaction *tx = LuaStateGetTX(luastate);
- if (tx == NULL)
- return LuaCallbackError(luastate, "internal error: no tx");
-
- lua_pushboolean(luastate, tx->recursion_desired);
-#endif
return 1;
}
{
if (!(LuaStateNeedProto(luastate, ALPROTO_DNS)))
return LuaCallbackError(luastate, "error: protocol not dns");
-#ifdef HAVE_RUST
RSDNSTransaction *tx = LuaStateGetTX(luastate);
if (tx == NULL) {
return LuaCallbackError(luastate, "internal error: no tx");
}
return rs_dns_lua_get_query_table(luastate, tx);
-#else
- DNSTransaction *tx = LuaStateGetTX(luastate);
- if (tx == NULL)
- return LuaCallbackError(luastate, "internal error: no tx");
-
- uint32_t u = 0;
- lua_newtable(luastate);
- DNSQueryEntry *query = NULL;
- TAILQ_FOREACH(query, &tx->query_list, next) {
- lua_pushinteger(luastate, u++);
-
- lua_newtable(luastate);
- char record[16] = "";
- DNSCreateTypeString(query->type, record, sizeof(record));
- lua_pushstring(luastate, "type");
- lua_pushstring(luastate, record);
- lua_settable(luastate, -3);
-
- {
- char *c;
- size_t input_len;
- c = BytesToString((uint8_t *)((uint8_t *)query + sizeof(DNSQueryEntry)), query->len);
- if (c != NULL) {
- input_len = strlen(c);
- /* sanity check */
- if (input_len > (size_t)(2 * query->len)) {
- SCFree(c);
- return LuaCallbackError(luastate, "invalid length");
- }
- lua_pushstring(luastate, "rrname");
- LuaPushStringBuffer(luastate, (uint8_t *)c, input_len);
- lua_settable(luastate, -3);
- SCFree(c);
- }
- }
-
-
- lua_settable(luastate, -3);
- }
-
- return 1;
-#endif
}
static int DnsGetAnswerTable(lua_State *luastate)
{
if (!(LuaStateNeedProto(luastate, ALPROTO_DNS)))
return LuaCallbackError(luastate, "error: protocol not dns");
-#ifdef HAVE_RUST
RSDNSTransaction *tx = LuaStateGetTX(luastate);
return rs_dns_lua_get_answer_table(luastate, tx);
-#else
- DNSTransaction *tx = LuaStateGetTX(luastate);
- if (tx == NULL)
- return LuaCallbackError(luastate, "internal error: no tx");
-
- uint32_t u = 0;
- lua_newtable(luastate);
- DNSAnswerEntry *answer = NULL;
- TAILQ_FOREACH(answer, &tx->answer_list, next) {
- lua_pushinteger(luastate, u++);
-
- lua_newtable(luastate);
- char record[16] = "";
- DNSCreateTypeString(answer->type, record, sizeof(record));
- lua_pushstring(luastate, "type");
- lua_pushstring(luastate, record);
- lua_settable(luastate, -3);
-
- lua_pushstring(luastate, "ttl");
- lua_pushinteger(luastate, answer->ttl);
- lua_settable(luastate, -3);
-
- {
- uint8_t *ptr = (uint8_t *)((uint8_t *)answer + sizeof(DNSAnswerEntry));
- lua_pushstring(luastate, "rrname");
- LuaPushStringBuffer(luastate, ptr, answer->fqdn_len);
- lua_settable(luastate, -3);
-
- ptr = (uint8_t *)((uint8_t *)answer + sizeof(DNSAnswerEntry) + answer->fqdn_len);
- if (answer->type == DNS_RECORD_TYPE_A) {
- char a[16] = "";
- if (answer->data_len == 4) {
- PrintInet(AF_INET, (const void *)ptr, a, sizeof(a));
- }
- lua_pushstring(luastate, "addr");
- LuaPushStringBuffer(luastate, (uint8_t *)a, strlen(a));
- lua_settable(luastate, -3);
- } else if (answer->type == DNS_RECORD_TYPE_AAAA) {
- char a[46] = "";
- if (answer->data_len == 16) {
- PrintInet(AF_INET6, (const void *)ptr, a, sizeof(a));
- }
- lua_pushstring(luastate, "addr");
- LuaPushStringBuffer(luastate, (uint8_t *)a, strlen(a));
- lua_settable(luastate, -3);
- } else if (answer->data_len == 0) {
- /* not setting 'addr' */
- } else {
- lua_pushstring(luastate, "addr");
- LuaPushStringBuffer(luastate, (uint8_t *)ptr, answer->data_len);
- lua_settable(luastate, -3);
- }
- }
-
- lua_settable(luastate, -3);
- }
-
- return 1;
-#endif
}
static int DnsGetAuthorityTable(lua_State *luastate)
{
if (!(LuaStateNeedProto(luastate, ALPROTO_DNS)))
return LuaCallbackError(luastate, "error: protocol not dns");
-#ifdef HAVE_RUST
RSDNSTransaction *tx = LuaStateGetTX(luastate);
return rs_dns_lua_get_authority_table(luastate, tx);
-#else
- DNSTransaction *tx = LuaStateGetTX(luastate);
- if (tx == NULL)
- return LuaCallbackError(luastate, "internal error: no tx");
-
- uint32_t u = 0;
- lua_newtable(luastate);
- DNSAnswerEntry *answer = NULL;
- TAILQ_FOREACH(answer, &tx->authority_list, next) {
- lua_pushinteger(luastate, u++);
-
- lua_newtable(luastate);
- char record[16] = "";
- DNSCreateTypeString(answer->type, record, sizeof(record));
- lua_pushstring(luastate, "type");
- lua_pushstring(luastate, record);
- lua_settable(luastate, -3);
-
- lua_pushstring(luastate, "ttl");
- lua_pushinteger(luastate, answer->ttl);
- lua_settable(luastate, -3);
-
- {
- char *c;
- size_t input_len;
- c = BytesToString((uint8_t *)((uint8_t *)answer + sizeof(DNSAnswerEntry)), answer->fqdn_len);
- if (c != NULL) {
- input_len = strlen(c);
- /* sanity check */
- if (input_len > (size_t)(2 * answer->fqdn_len)) {
- SCFree(c);
- return LuaCallbackError(luastate, "invalid length");
- }
- lua_pushstring(luastate, "rrname");
- LuaPushStringBuffer(luastate, (uint8_t *)c, input_len);
- lua_settable(luastate, -3);
- SCFree(c);
- }
- }
-
-
- lua_settable(luastate, -3);
- }
-
- return 1;
-#endif
}
-
/** \brief register http lua extensions in a luastate */
int LuaRegisterDnsFunctions(lua_State *luastate)
{