From: Jason Ish Date: Thu, 4 Apr 2019 05:48:48 +0000 (-0600) Subject: dns: remove as much C DNS code as possible X-Git-Tag: suricata-5.0.0-beta1~50 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=67b2692d345c6fcfbd606468a6dc3b2b40e14dc1;p=thirdparty%2Fsuricata.git dns: remove as much C DNS code as possible As some of the C code is still used it can't all be removed. Redmine issue: https://redmine.openinfosecfoundation.org/issues/2850 --- diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index e52680631b..2c35e2fd89 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -22,104 +22,7 @@ */ #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, }, @@ -156,891 +59,6 @@ void DNSAppLayerRegisterGetEventInfo(uint8_t ipproto, AppProto alproto) 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, "", 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) { diff --git a/src/app-layer-dns-common.h b/src/app-layer-dns-common.h index 65d40cdabf..c016ba79e1 100644 --- a/src/app-layer-dns-common.h +++ b/src/app-layer-dns-common.h @@ -26,13 +26,9 @@ #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 @@ -138,172 +134,10 @@ typedef struct DNSHeader_ { 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); diff --git a/src/app-layer-dns-tcp.c b/src/app-layer-dns-tcp.c index fcc477ee29..08b4de18d6 100644 --- a/src/app-layer-dns-tcp.c +++ b/src/app-layer-dns-tcp.c @@ -23,888 +23,10 @@ #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 */ diff --git a/src/app-layer-dns-tcp.h b/src/app-layer-dns-tcp.h index 2f3b4ffcec..31329a4b2c 100644 --- a/src/app-layer-dns-tcp.h +++ b/src/app-layer-dns-tcp.h @@ -24,15 +24,6 @@ #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__ */ diff --git a/src/app-layer-dns-udp.c b/src/app-layer-dns-udp.c index 4e28133002..09b7df721c 100644 --- a/src/app-layer-dns-udp.c +++ b/src/app-layer-dns-udp.c @@ -21,966 +21,11 @@ */ #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, /* 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, /* 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 */ diff --git a/src/app-layer-dns-udp.h b/src/app-layer-dns-udp.h index a6ee12a820..f5a9359793 100644 --- a/src/app-layer-dns-udp.h +++ b/src/app-layer-dns-udp.h @@ -23,15 +23,6 @@ #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__ */ diff --git a/src/app-layer.c b/src/app-layer.c index 761f9497b7..99d8a0111f 100644 --- a/src/app-layer.c +++ b/src/app-layer.c @@ -852,9 +852,6 @@ void AppLayerProfilingStoreInternal(AppLayerThreadCtx *app_tctx, Packet *p) */ 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); diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c index e47d502aca..01339d8f1e 100644 --- a/src/detect-dns-query.c +++ b/src/detect-dns-query.c @@ -60,9 +60,7 @@ #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); @@ -70,11 +68,7 @@ static int g_dns_query_buffer_id = 0; 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, @@ -92,16 +86,10 @@ 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); @@ -121,7 +109,6 @@ static int DetectEngineInspectDnsQuery( transforms = engine->v2.transforms; } -#ifdef HAVE_RUST while(1) { struct DnsQueryGetDataArgs cbdata = { local_id, txv, }; InspectionBuffer *buffer = DnsQueryGetData(det_ctx, @@ -144,33 +131,6 @@ static int DetectEngineInspectDnsQuery( } 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; } @@ -200,7 +160,6 @@ static void PrefilterTxDnsQuery(DetectEngineThreadCtx *det_ctx, const int list_id = ctx->list_id; int local_id = 0; -#ifdef HAVE_RUST while(1) { // loop until we get a NULL @@ -218,23 +177,6 @@ static void PrefilterTxDnsQuery(DetectEngineThreadCtx *det_ctx, 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) @@ -333,7 +275,7 @@ static int DetectDnsQueryTest01(void) 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; @@ -438,7 +380,7 @@ static int DetectDnsQueryTest02(void) 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; @@ -592,7 +534,7 @@ static int DetectDnsQueryTest03(void) 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; @@ -681,7 +623,7 @@ static int DetectDnsQueryTest04(void) 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; @@ -822,7 +764,7 @@ static int DetectDnsQueryTest05(void) 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; @@ -1008,7 +950,7 @@ static int DetectDnsQueryTest06(void) 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; @@ -1124,7 +1066,7 @@ static int DetectDnsQueryTest07(void) 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; diff --git a/src/output-json-alert.c b/src/output-json-alert.c index 16db84b00e..7a330b60f6 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -189,7 +189,7 @@ static void AlertJsonDnp3(const Flow *f, const uint64_t tx_id, json_t *js) 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); diff --git a/src/output-json-dns.c b/src/output-json-dns.c index 5de09758ff..e0dd45bcf6 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -51,11 +51,7 @@ #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 */ @@ -196,11 +192,7 @@ typedef enum { 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; @@ -281,200 +273,12 @@ typedef struct LogDnsLogThread_ { 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)) { @@ -482,548 +286,14 @@ json_t *JsonDNSLogQuery(void *txptr, uint64_t tx_id) } 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) @@ -1038,7 +308,6 @@ static int JsonDnsLoggerToServer(ThreadVars *tv, void *thread_data, 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)) { @@ -1056,21 +325,6 @@ static int JsonDnsLoggerToServer(ThreadVars *tv, void *thread_data, 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); } @@ -1093,7 +347,6 @@ static int JsonDnsLoggerToClient(ThreadVars *tv, void *thread_data, 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); @@ -1128,11 +381,6 @@ static int JsonDnsLoggerToClient(ThreadVars *tv, void *thread_data, json_object_del(js, "dns"); } } -#else - DNSTransaction *tx = txptr; - - LogAnswers(td, js, tx, tx_id); -#endif json_decref(js); @@ -1447,11 +695,3 @@ void JsonDnsLogRegister (void) JsonDnsLoggerToClient, 1, 1, LogDnsLogThreadInit, LogDnsLogThreadDeinit, NULL); } - -#else - -void JsonDnsLogRegister (void) -{ -} - -#endif diff --git a/src/output-json-dns.h b/src/output-json-dns.h index 9ad89fc1a1..4a5d280130 100644 --- a/src/output-json-dns.h +++ b/src/output-json-dns.h @@ -26,11 +26,9 @@ 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__ */ diff --git a/src/util-lua-dns.c b/src/util-lua-dns.c index c825ba00df..4c473619ea 100644 --- a/src/util-lua-dns.c +++ b/src/util-lua-dns.c @@ -58,65 +58,29 @@ #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; } @@ -125,19 +89,12 @@ static int DnsGetRcode(lua_State *luastate) 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)); @@ -151,7 +108,6 @@ static int DnsGetRecursionDesired(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"); @@ -159,13 +115,6 @@ static int DnsGetRecursionDesired(lua_State *luastate) 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; } @@ -173,180 +122,29 @@ static int DnsGetQueryTable(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_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) {