From f10dd603ff42201ec931c33325327d1bdce00e18 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Sat, 20 Apr 2013 19:37:05 +0200 Subject: [PATCH] DNS: adding dns_request content modifier --- src/Makefile.am | 2 + src/app-layer-dns-common.c | 14 +++- src/app-layer-protos.h | 3 + src/detect-app-layer-event.c | 8 ++- src/detect-dns-query.c | 91 +++++++++++++++++++++++++ src/detect-dns-query.h | 29 ++++++++ src/detect-engine-content-inspection.h | 1 + src/detect-engine-dns.c | 92 ++++++++++++++++++++++++++ src/detect-engine-dns.h | 30 +++++++++ src/detect-engine-state.c | 25 ++++--- src/detect-engine-state.h | 1 + src/detect-engine.c | 8 +++ src/detect-parse.c | 4 +- src/detect.c | 7 ++ src/detect.h | 4 ++ 15 files changed, 304 insertions(+), 15 deletions(-) create mode 100644 src/detect-dns-query.c create mode 100644 src/detect-dns-query.h create mode 100644 src/detect-engine-dns.c create mode 100644 src/detect-engine-dns.h diff --git a/src/Makefile.am b/src/Makefile.am index 4f39391182..0c2ecff364 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -73,6 +73,7 @@ detect-dce-stub-data.c detect-dce-stub-data.h \ detect-depth.c detect-depth.h \ detect-detection-filter.c detect-detection-filter.h \ detect-distance.c detect-distance.h \ +detect-dns-query.c detect-dns-query.h \ detect-dsize.c detect-dsize.h \ detect-engine-address.c detect-engine-address.h \ detect-engine-address-ipv4.c detect-engine-address-ipv4.h \ @@ -82,6 +83,7 @@ detect-engine-analyzer.c detect-engine-analyzer.h \ detect-engine.c detect-engine.h \ detect-engine-content-inspection.c detect-engine-content-inspection.h \ detect-engine-dcepayload.c detect-engine-dcepayload.h \ +detect-engine-dns.c detect-engine-dns.h \ detect-engine-event.c detect-engine-event.h \ detect-engine-file.c detect-engine-file.h \ detect-engine-hcbd.c detect-engine-hcbd.h \ diff --git a/src/app-layer-dns-common.c b/src/app-layer-dns-common.c index a1fb7329b8..46925b9994 100644 --- a/src/app-layer-dns-common.c +++ b/src/app-layer-dns-common.c @@ -74,13 +74,23 @@ void DNSStateFree(void *s) { } void *DNSGetTx(void *alstate, uint64_t tx_id) { - /* todo */ + DNSState *dns_state = (DNSState *)alstate; + DNSTransaction *tx = NULL; + + TAILQ_FOREACH(tx, &dns_state->tx_list, next) { + SCLogDebug("tx->tx_num %u, tx_id %"PRIu64, tx->tx_num, tx_id); + if ((tx_id+1) != tx->tx_num) + continue; + + return tx; + } + return NULL; } uint64_t DNSGetTxCnt(void *alstate) { DNSState *dns_state = (DNSState *)alstate; - return (uint64_t)dns_state->transaction_cnt; + return (uint64_t)dns_state->transaction_max; } int DNSGetAlstateProgress(void *tx, uint8_t direction) { diff --git a/src/app-layer-protos.h b/src/app-layer-protos.h index c065509be0..8c1c93154f 100644 --- a/src/app-layer-protos.h +++ b/src/app-layer-protos.h @@ -39,8 +39,11 @@ enum { ALPROTO_DCERPC, ALPROTO_DCERPC_UDP, ALPROTO_IRC, + + ALPROTO_DNS, ALPROTO_DNS_UDP, ALPROTO_DNS_TCP, + /* used by the probing parser when alproto detection fails * permanently for that particular stream */ ALPROTO_FAILED, diff --git a/src/detect-app-layer-event.c b/src/detect-app-layer-event.c index 147a30ba14..b20417ccb6 100644 --- a/src/detect-app-layer-event.c +++ b/src/detect-app-layer-event.c @@ -158,13 +158,17 @@ int DetectAppLayerEventSetup(DetectEngineCtx *de_ctx, Signature *s, char *arg) sm->ctx = (void *)data; if (s->alproto != ALPROTO_UNKNOWN) { - if (s->alproto != ((DetectAppLayerEventData *)sm->ctx)->alproto) { + if (s->alproto == ALPROTO_DNS && + (data->alproto == ALPROTO_DNS_UDP || data->alproto == ALPROTO_DNS_TCP)) + { + SCLogDebug("DNS app layer event"); + } else if (s->alproto != data->alproto) { SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains " "conflicting keywords needing different alprotos"); goto error; } } else { - s->alproto = ((DetectAppLayerEventData *)sm->ctx)->alproto; + s->alproto = data->alproto; } SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH); diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c new file mode 100644 index 0000000000..39d0a601ab --- /dev/null +++ b/src/detect-dns-query.c @@ -0,0 +1,91 @@ +/* Copyright (C) 2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \ingroup dnslayer + * + * @{ + */ + + +/** + * \file + * + * \author Victor Julien + */ + +#include "suricata-common.h" +#include "threads.h" +#include "debug.h" +#include "decode.h" +#include "detect.h" + +#include "detect-parse.h" +#include "detect-engine.h" +#include "detect-engine-mpm.h" +#include "detect-content.h" +#include "detect-pcre.h" + +#include "flow.h" +#include "flow-var.h" + +#include "util-debug.h" +#include "util-unittest.h" +#include "util-spm.h" +#include "util-print.h" + +#include "app-layer.h" + +#include "detect-dns-query.h" + +static int DetectDnsQuerySetup (DetectEngineCtx *, Signature *, char *); + +/** + * \brief Registration function for keyword: http_uri + */ +void DetectDnsQueryRegister (void) { + sigmatch_table[DETECT_AL_DNS_QUERY].name = "dns_query"; + sigmatch_table[DETECT_AL_DNS_QUERY].desc = "content modifier to match specifically and only on the DNS query-buffer"; + sigmatch_table[DETECT_AL_DNS_QUERY].Match = NULL; + sigmatch_table[DETECT_AL_DNS_QUERY].AppLayerMatch = NULL; + sigmatch_table[DETECT_AL_DNS_QUERY].alproto = ALPROTO_DNS; + sigmatch_table[DETECT_AL_DNS_QUERY].Setup = DetectDnsQuerySetup; + sigmatch_table[DETECT_AL_DNS_QUERY].Free = NULL; + sigmatch_table[DETECT_AL_DNS_QUERY].RegisterTests = NULL; + + sigmatch_table[DETECT_AL_DNS_QUERY].flags |= SIGMATCH_PAYLOAD; +} + + +/** + * \brief this function setups the dns_query modifier keyword used in the rule + * + * \param de_ctx Pointer to the Detection Engine Context + * \param s Pointer to the Signature to which the current keyword belongs + * \param str Should hold an empty string always + * + * \retval 0 On success + * \retval -1 On failure + */ + +static int DetectDnsQuerySetup(DetectEngineCtx *de_ctx, Signature *s, char *str) +{ + return DetectEngineContentModifierBufferSetup(de_ctx, s, str, + DETECT_AL_DNS_QUERY, + DETECT_SM_LIST_DNSQUERY_MATCH, + ALPROTO_DNS, NULL); +} diff --git a/src/detect-dns-query.h b/src/detect-dns-query.h new file mode 100644 index 0000000000..c894b878db --- /dev/null +++ b/src/detect-dns-query.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_DNS_QUERY_H__ +#define __DETECT_DNS_QUERY_H__ + +void DetectDnsQueryRegister (void); + +#endif /* __DETECT_DNS_QUERY_H__ */ diff --git a/src/detect-engine-content-inspection.h b/src/detect-engine-content-inspection.h index 3fff4a869b..090e39495d 100644 --- a/src/detect-engine-content-inspection.h +++ b/src/detect-engine-content-inspection.h @@ -47,6 +47,7 @@ enum { DETECT_ENGINE_CONTENT_INSPECTION_MODE_HUAD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HHHD, DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_DNSQUERY, }; int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, diff --git a/src/detect-engine-dns.c b/src/detect-engine-dns.c new file mode 100644 index 0000000000..e904838557 --- /dev/null +++ b/src/detect-engine-dns.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** \file + * + * \author Victor Julien + * + * Based on detect-engine-uri.c + */ + +#include "suricata-common.h" +#include "suricata.h" +#include "decode.h" + +#include "detect.h" +#include "detect-engine.h" +#include "detect-parse.h" +#include "detect-engine-state.h" +#include "detect-engine-content-inspection.h" + +#include "flow-util.h" +#include "util-debug.h" +#include "util-print.h" +#include "flow.h" + +#include "app-layer.h" +#include "app-layer-parser.h" +#include "app-layer-protos.h" +#include "app-layer-dns-common.h" + +#include "util-unittest.h" +#include "util-unittest-helper.h" + +/** \brief Do the content inspection & validation for a signature + * + * \param de_ctx Detection engine context + * \param det_ctx Detection engine thread context + * \param s Signature to inspect + * \param sm SigMatch to inspect + * \param f Flow + * \param flags app layer flags + * \param state App layer state + * + * \retval 0 no match + * \retval 1 match + */ +int DetectEngineInspectDnsQueryName(ThreadVars *tv, + DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *det_ctx, + Signature *s, Flow *f, uint8_t flags, + void *alstate, void *txv, uint64_t tx_id) +{ + DNSTransaction *tx = (DNSTransaction *)txv; + DNSQueryEntry *query = NULL; + uint8_t *buffer; + uint16_t buffer_len; + int r = 0; + + TAILQ_FOREACH(query, &tx->query_list, next) { + SCLogDebug("tx %p query %p", tx, query); + det_ctx->discontinue_matching = 0; + det_ctx->buffer_offset = 0; + det_ctx->inspection_recursion_counter = 0; + + buffer = (uint8_t *)((uint8_t *)query + sizeof(DNSQueryEntry)); + buffer_len = query->len; + + //PrintRawDataFp(stdout, buffer, buffer_len); + + r = DetectEngineContentInspection(de_ctx, det_ctx, + s, s->sm_lists[DETECT_SM_LIST_DNSQUERY_MATCH], + f, buffer, buffer_len, 0, + DETECT_ENGINE_CONTENT_INSPECTION_MODE_DNSQUERY, NULL); + if (r == 1) + break; + } + return r; +} diff --git a/src/detect-engine-dns.h b/src/detect-engine-dns.h new file mode 100644 index 0000000000..419f0fed03 --- /dev/null +++ b/src/detect-engine-dns.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2013 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** \file + * + * \author Victor Julien + */ + +#ifndef __DETECT_ENGINE_DNS_H__ +#define __DETECT_ENGINE_DNS_H__ + +int DetectEngineInspectDnsQueryName(ThreadVars *, DetectEngineCtx *de_ctx, + DetectEngineThreadCtx *, Signature *, + Flow *, uint8_t, void *, void *, uint64_t); + +#endif /* __DETECT_ENGINE_DNS_H__ */ diff --git a/src/detect-engine-state.c b/src/detect-engine-state.c index 62effe57c1..738cd7645e 100644 --- a/src/detect-engine-state.c +++ b/src/detect-engine-state.c @@ -69,6 +69,7 @@ #include "app-layer-smb.h" #include "app-layer-dcerpc-common.h" #include "app-layer-dcerpc.h" +#include "app-layer-dns-common.h" #include "util-unittest.h" #include "util-unittest-helper.h" @@ -265,14 +266,16 @@ int DeStateDetectStartDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, if (AppLayerAlprotoSupportsTxs(alproto)) { FLOWLOCK_WRLOCK(f); - htp_state = (HtpState *)alstate; - if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { - FLOWLOCK_UNLOCK(f); - goto end; + if (alproto == ALPROTO_HTTP) { + htp_state = (HtpState *)alstate; + if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { + FLOWLOCK_UNLOCK(f); + goto end; + } } tx_id = AppLayerTransactionGetInspectId(f, flags); - total_txs = AppLayerGetTxCnt(alproto, htp_state); + total_txs = AppLayerGetTxCnt(alproto, alstate); for (; tx_id < total_txs; tx_id++) { total_matches = 0; tx = AppLayerGetTx(alproto, alstate, tx_id); @@ -526,11 +529,13 @@ void DeStateDetectContinueDetection(ThreadVars *tv, DetectEngineCtx *de_ctx, if (alproto_supports_txs) { FLOWLOCK_WRLOCK(f); - htp_state = (HtpState *)alstate; - if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { - FLOWLOCK_UNLOCK(f); - RULE_PROFILING_END(det_ctx, s, match); - goto end; + if (alproto == ALPROTO_HTTP) { + htp_state = (HtpState *)alstate; + if (htp_state->connp == NULL || htp_state->connp->conn == NULL) { + FLOWLOCK_UNLOCK(f); + RULE_PROFILING_END(det_ctx, s, match); + goto end; + } } engine = app_inspection_engine[alproto][(flags & STREAM_TOSERVER) ? 0 : 1]; diff --git a/src/detect-engine-state.h b/src/detect-engine-state.h index 17ac46ebeb..06fd568b4e 100644 --- a/src/detect-engine-state.h +++ b/src/detect-engine-state.h @@ -74,6 +74,7 @@ #define DE_STATE_FLAG_FILE_TS_INSPECT (1 << 14) #define DE_STATE_FLAG_FULL_INSPECT (1 << 15) #define DE_STATE_FLAG_SIG_CANT_MATCH (1 << 16) +#define DE_STATE_FLAG_DNSQUERY_INSPECT (1 << 17) /* state flags */ #define DETECT_ENGINE_STATE_FLAG_FILE_STORE_DISABLED 0x0001 diff --git a/src/detect-engine.c b/src/detect-engine.c index c5f6d931d3..72727d77c7 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -56,6 +56,7 @@ #include "detect-engine-hhhd.h" #include "detect-engine-hrhhd.h" #include "detect-engine-file.h" +#include "detect-engine-dns.h" #include "detect-engine.h" #include "detect-engine-state.h" @@ -214,6 +215,13 @@ void DetectEngineRegisterAppInspectionEngines(void) DE_STATE_FLAG_HRHHD_INSPECT, 0, DetectEngineInspectHttpHRH }, + /* DNS */ + { ALPROTO_DNS, + DETECT_SM_LIST_DNSQUERY_MATCH, + DE_STATE_FLAG_DNSQUERY_INSPECT, + DE_STATE_FLAG_DNSQUERY_INSPECT, + 0, + DetectEngineInspectDnsQueryName }, }; struct tmp_t data_toclient[] = { diff --git a/src/detect-parse.c b/src/detect-parse.c index 2b32842fbf..98324d65c1 100644 --- a/src/detect-parse.c +++ b/src/detect-parse.c @@ -779,7 +779,7 @@ static int SigParseBasics(Signature *s, char *sigstr, char ***result, uint8_t ad goto error; if (SigParseProto(s, "dnsudp") < 0) goto error; - + s->alproto = ALPROTO_DNS; } else { if (SigParseProto(s, arr[CONFIG_PROTO]) < 0) goto error; @@ -1402,6 +1402,8 @@ static Signature *SigInitHelper(DetectEngineCtx *de_ctx, char *sigstr, sig->flags |= SIG_FLAG_STATE_MATCH; if (sig->sm_lists[DETECT_SM_LIST_HRHHDMATCH]) sig->flags |= SIG_FLAG_STATE_MATCH; + if (sig->sm_lists[DETECT_SM_LIST_DNSQUERY_MATCH]) + sig->flags |= SIG_FLAG_STATE_MATCH; if (!(sig->init_flags & SIG_FLAG_INIT_FLOW)) { sig->flags |= SIG_FLAG_TOSERVER; diff --git a/src/detect.c b/src/detect.c index 1e39710156..2845722977 100644 --- a/src/detect.c +++ b/src/detect.c @@ -149,6 +149,7 @@ #include "detect-luajit.h" #include "detect-iprep.h" #include "detect-geoip.h" +#include "detect-dns-query.h" #include "util-rule-vars.h" @@ -505,6 +506,11 @@ static inline int SigMatchSignaturesBuildMatchArrayAddSignature(DetectEngineThre SCLogDebug("DCERPC sig, alproto not SMB or SMB2"); return 0; } + } else if (s->alproto == ALPROTO_DNS) { + if (alproto != ALPROTO_DNS_UDP && alproto != ALPROTO_DNS_TCP) { + SCLogDebug("DNS sig, alproto not DNS/TCP or DNS/UDP"); + return 0; + } } else { SCLogDebug("alproto mismatch"); return 0; @@ -4869,6 +4875,7 @@ void SigTableSetup(void) { DetectHttpHRHRegister(); DetectLuajitRegister(); DetectIPRepRegister(); + DetectDnsQueryRegister(); uint8_t i = 0; for (i = 0; i < DETECT_TBLSIZE; i++) { diff --git a/src/detect.h b/src/detect.h index 0dbdd65815..35ff5d3b34 100644 --- a/src/detect.h +++ b/src/detect.h @@ -115,6 +115,8 @@ enum { DETECT_SM_LIST_FILEMATCH, + DETECT_SM_LIST_DNSQUERY_MATCH, + /* list for post match actions: flowbit set, flowint increment, etc */ DETECT_SM_LIST_POSTMATCH, @@ -1122,6 +1124,8 @@ enum { DETECT_LUAJIT, DETECT_IPREP, + DETECT_AL_DNS_QUERY, + /* make sure this stays last */ DETECT_TBLSIZE, };