DNS: enable mpm/fast_pattern support for dns_query

pull/412/merge
Victor Julien 13 years ago
parent 4817e1305f
commit 43ba5a677e

@ -78,10 +78,11 @@ void *DNSGetTx(void *alstate, uint64_t tx_id) {
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;
}

@ -49,6 +49,7 @@ const char *TmModuleAlprotoToString(int proto)
CASE_CODE (ALPROTO_DCERPC);
CASE_CODE (ALPROTO_DCERPC_UDP);
CASE_CODE (ALPROTO_DNS);
CASE_CODE (ALPROTO_DNS_UDP);
CASE_CODE (ALPROTO_DNS_TCP);

@ -95,6 +95,41 @@ static int DetectDnsQuerySetup(DetectEngineCtx *de_ctx, Signature *s, char *str)
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) {

@ -24,6 +24,10 @@
#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__ */

@ -430,6 +430,8 @@ static void EngineAnalysisRulesPrintFP(Signature *s)
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");

@ -70,6 +70,8 @@ int DetectEngineInspectDnsQueryName(ThreadVars *tv,
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;

@ -689,6 +689,36 @@ uint32_t HttpHRHPatternSearch(DetectEngineThreadCtx *det_ctx,
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
@ -1109,6 +1139,15 @@ void PatternMatchDestroyGroup(SigGroupHead *sh) {
}
}
/* 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;
}
@ -1510,6 +1549,7 @@ static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx,
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;
@ -1635,6 +1675,15 @@ static void PopulateMpmAddPatternToMpm(DetectEngineCtx *de_ctx,
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) {
@ -2028,6 +2077,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh)
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++) {
@ -2093,6 +2144,10 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh)
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 */
@ -2376,6 +2431,24 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh)
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 ||
@ -2390,7 +2463,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh)
has_co_hrud ||
has_co_huad ||
has_co_hhhd ||
has_co_hrhhd) {
has_co_hrhhd ||
has_co_dnsquery) {
PatternMatchPreparePopulateMpm(de_ctx, sh);
@ -2779,6 +2853,17 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *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);
@ -2814,6 +2899,8 @@ int PatternMatchPrepareGroup(DetectEngineCtx *de_ctx, SigGroupHead *sh)
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;

@ -51,6 +51,7 @@ uint32_t HttpStatCodePatternSearch(DetectEngineThreadCtx *, uint8_t *, uint32_t,
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);

@ -275,7 +275,10 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx,
}
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);

@ -222,6 +222,22 @@ void DetectEngineRegisterAppInspectionEngines(void)
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[] = {

@ -134,6 +134,8 @@ void SupportFastPatternForSigMatchTypes(void)
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) {
@ -221,14 +223,16 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a
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;
}
@ -246,7 +250,8 @@ static int DetectFastPatternSetup(DetectEngineCtx *de_ctx, Signature *s, char *a
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 "

@ -46,6 +46,7 @@
#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"
@ -527,7 +528,7 @@ static inline int SigMatchSignaturesBuildMatchArrayAddSignature(DetectEngineThre
}
/* 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 */
@ -546,6 +547,10 @@ static inline int SigMatchSignaturesBuildMatchArrayAddSignature(DetectEngineThre
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;
}
}
}
}
@ -1077,6 +1082,27 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx,
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);
@ -1110,6 +1136,28 @@ static inline void DetectMpmPrefilter(DetectEngineCtx *de_ctx,
*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

@ -271,6 +271,9 @@ typedef struct DetectPort_ {
#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) */
@ -689,6 +692,7 @@ typedef struct DetectEngineCtx_ {
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;
@ -905,6 +909,7 @@ typedef struct SigTableElmt_ {
#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
@ -965,6 +970,7 @@ typedef struct SigGroupHead_ {
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;

@ -288,6 +288,7 @@ typedef enum PacketProfileDetectId_ {
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,

@ -871,6 +871,7 @@ const char * PacketProfileDetectIdToString(PacketProfileDetectId id)
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);

Loading…
Cancel
Save