DNSTransaction *tx = NULL;
TAILQ_FOREACH(tx, &dns_state->tx_list, next) {
- SCLogDebug("tx->tx_num %u, tx_id %"PRIu64, tx->tx_num, tx_id);
+ 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);
return tx;
}
CASE_CODE (ALPROTO_DCERPC);
CASE_CODE (ALPROTO_DCERPC_UDP);
+ CASE_CODE (ALPROTO_DNS);
CASE_CODE (ALPROTO_DNS_UDP);
CASE_CODE (ALPROTO_DNS_TCP);
ALPROTO_DNS, NULL);
}
+/**
+ * \brief Run the pattern matcher against the queries
+ *
+ * \param f locked flow
+ * \param dns_state initialized dns state
+ *
+ * \warning Make sure the flow/state is locked
+ * \todo what should we return? Just the fact that we matched?
+ */
+uint32_t DetectDnsQueryInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f,
+ DNSState *dns_state, uint8_t flags, void *txv,
+ uint64_t tx_id)
+{
+ SCEnter();
+
+ DNSTransaction *tx = (DNSTransaction *)txv;
+ DNSQueryEntry *query = NULL;
+ uint8_t *buffer;
+ uint16_t buffer_len;
+ uint32_t cnt = 0;
+
+ TAILQ_FOREACH(query, &tx->query_list, next) {
+ SCLogDebug("tx %p query %p", tx, query);
+
+ buffer = (uint8_t *)((uint8_t *)query + sizeof(DNSQueryEntry));
+ buffer_len = query->len;
+
+ cnt += DnsQueryPatternSearch(det_ctx,
+ buffer, buffer_len,
+ flags);
+ }
+
+ SCReturnUInt(cnt);
+}
+
#ifdef UNITTESTS
/** \test simple google.com query matching */
static int DetectDnsQueryTest01(void) {
#ifndef __DETECT_DNS_QUERY_H__
#define __DETECT_DNS_QUERY_H__
+#include "app-layer-dns-common.h"
+
void DetectDnsQueryRegister (void);
+uint32_t DetectDnsQueryInspectMpm(DetectEngineThreadCtx *det_ctx, Flow *f,
+ DNSState *dns_state, uint8_t flags, void *txv, uint64_t tx_id);
#endif /* __DETECT_DNS_QUERY_H__ */
fprintf(rule_engine_analysis_FD, "http stat msg content");
else if (list_type == DETECT_SM_LIST_HUADMATCH)
fprintf(rule_engine_analysis_FD, "http user agent content");
+ else if (list_type == DETECT_SM_LIST_DNSQUERY_MATCH)
+ fprintf(rule_engine_analysis_FD, "dns query name content");
fprintf(rule_engine_analysis_FD, "\" buffer.\n");
uint16_t buffer_len;
int r = 0;
+ SCLogDebug("start");
+
TAILQ_FOREACH(query, &tx->query_list, next) {
SCLogDebug("tx %p query %p", tx, query);
det_ctx->discontinue_matching = 0;
SCReturnUInt(ret);
}
+/**
+ * \brief DNS query match -- searches for one pattern per signature.
+ *
+ * \param det_ctx Detection engine thread ctx.
+ * \param hrh Buffer to inspect.
+ * \param hrh_len buffer length.
+ * \param flags Flags
+ *
+ * \retval ret Number of matches.
+ */
+uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx,
+ uint8_t *buffer, uint32_t buffer_len,
+ uint8_t flags)
+{
+ SCEnter();
+
+ uint32_t ret;
+
+ if (flags & STREAM_TOSERVER) {
+ if (det_ctx->sgh->mpm_dnsquery_ctx_ts == NULL)
+ SCReturnUInt(0);
+
+ ret = mpm_table[det_ctx->sgh->mpm_dnsquery_ctx_ts->mpm_type].
+ Search(det_ctx->sgh->mpm_dnsquery_ctx_ts, &det_ctx->mtcu,
+ &det_ctx->pmq, buffer, buffer_len);
+ }
+
+ SCReturnUInt(ret);
+}
+
/** \brief Pattern match -- searches for only one pattern per signature.
*
* \param det_ctx detection engine thread ctx
}
}
+ /* dns query */
+ if (sh->mpm_dnsquery_ctx_ts != NULL) {
+ if (!sh->mpm_dnsquery_ctx_ts->global) {
+ mpm_table[sh->mpm_dnsquery_ctx_ts->mpm_type].DestroyCtx(sh->mpm_dnsquery_ctx_ts);
+ SCFree(sh->mpm_dnsquery_ctx_ts);
+ }
+ sh->mpm_dnsquery_ctx_ts = NULL;
+ }
+
return;
}
case DETECT_SM_LIST_HUADMATCH:
case DETECT_SM_LIST_HHHDMATCH:
case DETECT_SM_LIST_HRHHDMATCH:
+ case DETECT_SM_LIST_DNSQUERY_MATCH:
{
MpmCtx *mpm_ctx_ts = NULL;
MpmCtx *mpm_ctx_tc = NULL;
sig_flags |= SIG_FLAG_MPM_HTTP;
if (cd->flags & DETECT_CONTENT_NEGATED)
sig_flags |= SIG_FLAG_MPM_HTTP_NEG;
+ } else if (sm_list == DETECT_SM_LIST_DNSQUERY_MATCH) {
+ if (s->flags & SIG_FLAG_TOSERVER)
+ mpm_ctx_ts = sgh->mpm_dnsquery_ctx_ts;
+ if (s->flags & SIG_FLAG_TOCLIENT)
+ mpm_ctx_tc = NULL;
+ sgh_flags = SIG_GROUP_HEAD_MPM_DNSQUERY;
+ sig_flags |= SIG_FLAG_MPM_DNS;
+ if (cd->flags & DETECT_CONTENT_NEGATED)
+ sig_flags |= SIG_FLAG_MPM_DNS_NEG;
}
if (cd->flags & DETECT_CONTENT_FAST_PATTERN_CHOP) {
uint32_t has_co_hrhhd = 0;
//uint32_t cnt = 0;
uint32_t sig = 0;
+ /* sgh has at least one sig with dns_query */
+ int has_co_dnsquery = 0;
/* see if this head has content and/or uricontent */
for (sig = 0; sig < sh->sig_cnt; sig++) {
if (s->sm_lists[DETECT_SM_LIST_HRHHDMATCH] != NULL) {
has_co_hrhhd = 1;
}
+
+ if (s->sm_lists[DETECT_SM_LIST_DNSQUERY_MATCH] != NULL) {
+ has_co_dnsquery = 1;
+ }
}
/* intialize contexes */
MpmInitCtx(sh->mpm_hrhhd_ctx_tc, de_ctx->mpm_matcher, -1);
}
+ if (has_co_dnsquery) {
+ if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_SINGLE) {
+ sh->mpm_dnsquery_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, de_ctx->sgh_mpm_context_dnsquery, 0);
+ } else {
+ sh->mpm_dnsquery_ctx_ts = MpmFactoryGetMpmCtxForProfile(de_ctx, MPM_CTX_FACTORY_UNIQUE_CONTEXT, 0);
+ }
+ if (sh->mpm_dnsquery_ctx_ts == NULL) {
+ SCLogDebug("sh->mpm_hrhhd_ctx == NULL. This should never happen");
+ exit(EXIT_FAILURE);
+ }
+
+#ifndef __SC_CUDA_SUPPORT__
+ MpmInitCtx(sh->mpm_dnsquery_ctx_ts, de_ctx->mpm_matcher, -1);
+#else
+ MpmInitCtx(sh->mpm_dnsquery_ctx_ts, de_ctx->mpm_matcher, de_ctx->cuda_rc_mod_handle);
+#endif
+ }
+
if (has_co_packet ||
has_co_stream ||
has_co_uri ||
has_co_hrud ||
has_co_huad ||
has_co_hhhd ||
- has_co_hrhhd) {
+ has_co_hrhhd ||
+ has_co_dnsquery) {
PatternMatchPreparePopulateMpm(de_ctx, sh);
}
}
}
+ if (sh->mpm_dnsquery_ctx_ts != NULL) {
+ if (sh->mpm_dnsquery_ctx_ts->pattern_cnt == 0) {
+ MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_dnsquery_ctx_ts);
+ sh->mpm_dnsquery_ctx_ts = NULL;
+ } else {
+ if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) {
+ if (mpm_table[sh->mpm_dnsquery_ctx_ts->mpm_type].Prepare != NULL)
+ mpm_table[sh->mpm_dnsquery_ctx_ts->mpm_type].Prepare(sh->mpm_dnsquery_ctx_ts);
+ }
+ }
+ }
//} /* if (de_ctx->sgh_mpm_context == ENGINE_SGH_MPM_FACTORY_CONTEXT_FULL) */
} else {
MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_other_ctx);
sh->mpm_hhhd_ctx_ts = NULL;
MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_hrhhd_ctx_ts);
sh->mpm_hrhhd_ctx_ts = NULL;
+ MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_dnsquery_ctx_ts);
+ sh->mpm_dnsquery_ctx_ts = NULL;
MpmFactoryReClaimMpmCtx(de_ctx, sh->mpm_proto_tcp_ctx_tc);
sh->mpm_proto_tcp_ctx_tc = NULL;
uint32_t HttpUAPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t);
uint32_t HttpHHPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t);
uint32_t HttpHRHPatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t, uint8_t);
+uint32_t DnsQueryPatternSearch(DetectEngineThreadCtx *det_ctx, uint8_t *buffer, uint32_t buffer_len, uint8_t flags);
void PacketPatternCleanup(ThreadVars *, DetectEngineThreadCtx *);
void StreamPatternCleanup(ThreadVars *t, DetectEngineThreadCtx *det_ctx, StreamMsg *smsg);
}
tx_id = AppLayerTransactionGetInspectId(f, flags);
+ SCLogDebug("tx_id %"PRIu64, tx_id);
total_txs = AppLayerGetTxCnt(alproto, alstate);
+ SCLogDebug("total_txs %"PRIu64, total_txs);
+
for (; tx_id < total_txs; tx_id++) {
total_matches = 0;
tx = AppLayerGetTx(alproto, alstate, tx_id);
DE_STATE_FLAG_DNSQUERY_INSPECT,
0,
DetectEngineInspectDnsQueryName },
+ /* specifically for UDP, register again
+ * allows us to use the alproto w/o translation
+ * in the detection engine */
+ { ALPROTO_DNS_UDP,
+ DETECT_SM_LIST_DNSQUERY_MATCH,
+ DE_STATE_FLAG_DNSQUERY_INSPECT,
+ DE_STATE_FLAG_DNSQUERY_INSPECT,
+ 0,
+ DetectEngineInspectDnsQueryName },
+ /* dito for TCP */
+ { ALPROTO_DNS_TCP,
+ DETECT_SM_LIST_DNSQUERY_MATCH,
+ DE_STATE_FLAG_DNSQUERY_INSPECT,
+ DE_STATE_FLAG_DNSQUERY_INSPECT,
+ 0,
+ DetectEngineInspectDnsQueryName },
};
struct tmp_t data_toclient[] = {
SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSCDMATCH, 3);
SupportFastPatternForSigMatchList(DETECT_SM_LIST_HSMDMATCH, 3);
+ SupportFastPatternForSigMatchList(DETECT_SM_LIST_DNSQUERY_MATCH, 2);
+
#if 0
SCFPSupportSMList *tmp = sm_fp_support_smlist_list;
while (tmp != NULL) {
s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH] == NULL &&
s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH] == NULL &&
s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH] == NULL &&
- s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL) {
+ s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH] == NULL &&
+ s->sm_lists_tail[DETECT_SM_LIST_DNSQUERY_MATCH] == NULL) {
SCLogWarning(SC_WARN_COMPATIBILITY, "fast_pattern found inside the "
"rule, without a preceding content based keyword. "
"Currently we provide fast_pattern support for content, "
"uricontent, http_client_body, http_server_body, http_header, "
"http_raw_header, http_method, http_cookie, "
"http_raw_uri, http_stat_msg, http_stat_code, "
- "http_user_agent, http_host or http_raw_host option");
+ "http_user_agent, http_host, http_raw_host or "
+ "dns_query option");
return -1;
}
DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH],
DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH],
DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH],
- DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]);
+ DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH],
+ DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_DNSQUERY_MATCH]);
if (pm == NULL) {
SCLogError(SC_ERR_INVALID_SIGNATURE, "fast_pattern found inside "
"the rule, without a content context. Please use a "
#include "detect-engine-payload.h"
#include "detect-engine-dcepayload.h"
#include "detect-engine-uri.h"
+#include "detect-dns-query.h"
#include "detect-engine-state.h"
#include "detect-engine-analyzer.h"
}
/* check for a pattern match of the one pattern in this sig. */
- if (likely(s->flags & (SIG_FLAG_MPM_PACKET|SIG_FLAG_MPM_STREAM|SIG_FLAG_MPM_HTTP)))
+ if (likely(s->flags & (SIG_FLAG_MPM_PACKET|SIG_FLAG_MPM_STREAM|SIG_FLAG_MPM_HTTP|SIG_FLAG_MPM_DNS)))
{
/* filter out sigs that want pattern matches, but
* have no matches */
if (!(s->flags & SIG_FLAG_MPM_HTTP_NEG)) {
return 0;
}
+ } else if (s->flags & SIG_FLAG_MPM_DNS) {
+ if (!(s->flags & SIG_FLAG_MPM_DNS_NEG)) {
+ return 0;
+ }
}
}
}
FLOWLOCK_UNLOCK(p->flow);
}
+ /* all dns based mpms */
+ else if (alproto == ALPROTO_DNS_TCP && alstate != NULL) {
+ if (p->flowflags & FLOW_PKT_TOSERVER) {
+ if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_DNSQUERY) {
+ FLOWLOCK_RDLOCK(p->flow);
+
+ uint64_t idx = AppLayerTransactionGetInspectId(p->flow, flags);
+ uint64_t total_txs = AppLayerGetTxCnt(alproto, alstate);
+ for (; idx < total_txs; idx++) {
+ void *tx = AppLayerGetTx(alproto, alstate, idx);
+ if (tx == NULL)
+ continue;
+
+ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_DNSQUERY);
+ DetectDnsQueryInspectMpm(det_ctx, p->flow, alstate, flags, tx, idx);
+ PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_DNSQUERY);
+ }
+ FLOWLOCK_UNLOCK(p->flow);
+ }
+ }
+ }
if (smsg != NULL && (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_STREAM)) {
PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_STREAM);
*sms_runflags |= SMS_USED_PM;
}
}
+
+ /* UDP DNS inspection is independent of est or not */
+ if (alproto == ALPROTO_DNS_UDP && alstate != NULL) {
+ if (p->flowflags & FLOW_PKT_TOSERVER) {
+ SCLogDebug("mpm inspection");
+ if (det_ctx->sgh->flags & SIG_GROUP_HEAD_MPM_DNSQUERY) {
+ FLOWLOCK_RDLOCK(p->flow);
+ uint64_t idx = AppLayerTransactionGetInspectId(p->flow, flags);
+ uint64_t total_txs = AppLayerGetTxCnt(alproto, alstate);
+ for (; idx < total_txs; idx++) {
+ void *tx = AppLayerGetTx(alproto, alstate, idx);
+ if (tx == NULL)
+ continue;
+ SCLogDebug("tx %p",tx);
+ PACKET_PROFILING_DETECT_START(p, PROF_DETECT_MPM_DNSQUERY);
+ DetectDnsQueryInspectMpm(det_ctx, p->flow, alstate, flags, tx, idx);
+ PACKET_PROFILING_DETECT_END(p, PROF_DETECT_MPM_DNSQUERY);
+ }
+ FLOWLOCK_UNLOCK(p->flow);
+ }
+ }
+ }
}
#ifdef DEBUG
#define SIG_FLAG_TLSSTORE (1<<21)
+#define SIG_FLAG_MPM_DNS (1<<22)
+#define SIG_FLAG_MPM_DNS_NEG (1<<23)
+
/* signature init flags */
#define SIG_FLAG_INIT_DEONLY 1 /**< decode event only signature */
#define SIG_FLAG_INIT_PACKET (1<<1) /**< signature has matches against a packet (as opposed to app layer) */
int32_t sgh_mpm_context_hhhd;
int32_t sgh_mpm_context_hrhhd;
int32_t sgh_mpm_context_app_proto_detect;
+ int32_t sgh_mpm_context_dnsquery;
/* the max local id used amongst all sigs */
int32_t byte_extract_max_local_id;
#define SIG_GROUP_HEAD_HAVEFILEMAGIC (1 << 20)
#define SIG_GROUP_HEAD_HAVEFILEMD5 (1 << 21)
#define SIG_GROUP_HEAD_HAVEFILESIZE (1 << 22)
+#define SIG_GROUP_HEAD_MPM_DNSQUERY (1 << 23)
typedef struct SigGroupHeadInitData_ {
/* list of content containers
MpmCtx *mpm_huad_ctx_ts;
MpmCtx *mpm_hhhd_ctx_ts;
MpmCtx *mpm_hrhhd_ctx_ts;
+ MpmCtx *mpm_dnsquery_ctx_ts;
MpmCtx *mpm_proto_tcp_ctx_tc;
MpmCtx *mpm_proto_udp_ctx_tc;
PROF_DETECT_MPM_HUAD,
PROF_DETECT_MPM_HHHD,
PROF_DETECT_MPM_HRHHD,
+ PROF_DETECT_MPM_DNSQUERY,
PROF_DETECT_IPONLY,
PROF_DETECT_RULES,
PROF_DETECT_STATEFUL,
CASE_CODE (PROF_DETECT_MPM_HSMD);
CASE_CODE (PROF_DETECT_MPM_HSCD);
CASE_CODE (PROF_DETECT_MPM_HUAD);
+ CASE_CODE (PROF_DETECT_MPM_DNSQUERY);
CASE_CODE (PROF_DETECT_IPONLY);
CASE_CODE (PROF_DETECT_RULES);
CASE_CODE (PROF_DETECT_PREFILTER);