Skip to content

Commit b1782b2

Browse files
committed
wip: dns.query.name
1 parent 5a4f0cd commit b1782b2

File tree

5 files changed

+233
-0
lines changed

5 files changed

+233
-0
lines changed

rust/src/dns/dns.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,31 @@ pub unsafe extern "C" fn rs_dns_tx_get_query_name(
881881
return 0;
882882
}
883883

884+
/// Get the DNS query name at index i.
885+
#[no_mangle]
886+
pub unsafe extern "C" fn SCDnsTxGetQueryName(
887+
tx: &mut DNSTransaction, to_client: bool, i: u32, buf: *mut *const u8, len: *mut u32,
888+
) -> bool {
889+
let queries = if to_client {
890+
tx.response.as_ref().map(|response| &response.queries)
891+
} else {
892+
tx.request.as_ref().map(|request| &request.queries)
893+
};
894+
let index = i as usize;
895+
896+
if let Some(queries) = queries {
897+
if let Some(query) = queries.get(index) {
898+
if !query.name.is_empty() {
899+
*buf = query.name.as_ptr();
900+
*len = query.name.len() as u32;
901+
return true;
902+
}
903+
}
904+
}
905+
906+
false
907+
}
908+
884909
/// Get the DNS response answer name and index i.
885910
#[no_mangle]
886911
pub unsafe extern "C" fn SCDnsTxGetAnswerName(

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ noinst_HEADERS = \
124124
detect-dns-answer-name.h \
125125
detect-dns-opcode.h \
126126
detect-dns-query.h \
127+
detect-dns-query-name.h \
127128
detect-dsize.h \
128129
detect-engine-address.h \
129130
detect-engine-address-ipv4.h \
@@ -736,6 +737,7 @@ libsuricata_c_a_SOURCES = \
736737
detect-dns-answer-name.c \
737738
detect-dns-opcode.c \
738739
detect-dns-query.c \
740+
detect-dns-query-name.c \
739741
detect-dsize.c \
740742
detect-engine-address.c \
741743
detect-engine-address-ipv4.c \

src/detect-dns-query-name.c

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/* Copyright (C) 2023 Open Information Security Foundation
2+
*
3+
* You can copy, redistribute or modify this Program under the terms of
4+
* the GNU General Public License version 2 as published by the Free
5+
* Software Foundation.
6+
*
7+
* This program is distributed in the hope that it will be useful,
8+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+
* GNU General Public License for more details.
11+
*
12+
* You should have received a copy of the GNU General Public License
13+
* version 2 along with this program; if not, write to the Free Software
14+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15+
* 02110-1301, USA.
16+
*/
17+
18+
/**
19+
* \file
20+
*
21+
* Detect keyword for DNS query names: dns.query.name
22+
*/
23+
24+
#include "detect.h"
25+
#include "detect-parse.h"
26+
#include "detect-engine.h"
27+
#include "detect-engine-prefilter.h"
28+
#include "detect-engine-content-inspection.h"
29+
#include "detect-dns-query-name.h"
30+
#include "util-profiling.h"
31+
#include "rust.h"
32+
33+
static int DetectSetup(DetectEngineCtx *, Signature *, const char *);
34+
static uint8_t DetectEngineInspectCb(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
35+
const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f,
36+
uint8_t flags, void *alstate, void *txv, uint64_t tx_id);
37+
static int PrefilterMpmRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx,
38+
const DetectBufferMpmRegistry *mpm_reg, int list_id);
39+
40+
static int dns_query_name_id = 0;
41+
42+
void DetectDnsQueryNameRegister(void)
43+
{
44+
static const char *keyword = "dns.query.name";
45+
sigmatch_table[DETECT_AL_DNS_QUERY_NAME].name = keyword;
46+
sigmatch_table[DETECT_AL_DNS_QUERY_NAME].desc = "DNS query name sticky buffer";
47+
sigmatch_table[DETECT_AL_DNS_QUERY_NAME].url = "/rules/TODOTODOTODO";
48+
sigmatch_table[DETECT_AL_DNS_QUERY_NAME].Setup = DetectSetup;
49+
sigmatch_table[DETECT_AL_DNS_QUERY_NAME].flags |= SIGMATCH_NOOPT;
50+
sigmatch_table[DETECT_AL_DNS_QUERY_NAME].flags |= SIGMATCH_INFO_STICKY_BUFFER;
51+
52+
/* Register in both directions as the query is usually echoed back
53+
in the response. */
54+
DetectAppLayerInspectEngineRegister(
55+
keyword, ALPROTO_DNS, SIG_FLAG_TOSERVER, 0, DetectEngineInspectCb, NULL);
56+
DetectAppLayerMpmRegister(
57+
keyword, SIG_FLAG_TOSERVER, 2, PrefilterMpmRegister, NULL, ALPROTO_DNS, 1);
58+
59+
DetectAppLayerInspectEngineRegister(
60+
keyword, ALPROTO_DNS, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectCb, NULL);
61+
DetectAppLayerMpmRegister(
62+
keyword, SIG_FLAG_TOCLIENT, 2, PrefilterMpmRegister, NULL, ALPROTO_DNS, 1);
63+
64+
DetectBufferTypeSetDescriptionByName(keyword, "dns query name");
65+
DetectBufferTypeSupportsMultiInstance(keyword);
66+
67+
dns_query_name_id = DetectBufferTypeGetByName(keyword);
68+
}
69+
70+
static int DetectSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
71+
{
72+
if (DetectBufferSetActiveList(de_ctx, s, dns_query_name_id) < 0) {
73+
return -1;
74+
}
75+
if (DetectSignatureSetAppProto(s, ALPROTO_DNS) < 0) {
76+
return -1;
77+
}
78+
79+
return 0;
80+
}
81+
82+
static InspectionBuffer *GetBuffer(DetectEngineThreadCtx *det_ctx, const uint8_t flags,
83+
const DetectEngineTransforms *transforms, void *txv, uint32_t index, int list_id)
84+
{
85+
InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, index);
86+
if (buffer == NULL) {
87+
return NULL;
88+
}
89+
if (buffer->initialized) {
90+
return buffer;
91+
}
92+
93+
bool to_client = (flags & STREAM_TOSERVER) == 0;
94+
const uint8_t *data = NULL;
95+
uint32_t data_len = 0;
96+
97+
if (!SCDnsTxGetQueryName(txv, to_client, index, &data, &data_len)) {
98+
InspectionBufferSetupMultiEmpty(buffer);
99+
return NULL;
100+
}
101+
InspectionBufferSetupMulti(buffer, transforms, data, data_len);
102+
return buffer;
103+
}
104+
105+
static uint8_t DetectEngineInspectCb(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
106+
const struct DetectEngineAppInspectionEngine_ *engine, const Signature *s, Flow *f,
107+
uint8_t flags, void *alstate, void *txv, uint64_t tx_id)
108+
{
109+
const DetectEngineTransforms *transforms = NULL;
110+
if (!engine->mpm) {
111+
transforms = engine->v2.transforms;
112+
}
113+
114+
for (uint32_t i = 0;; i++) {
115+
InspectionBuffer *buffer = GetBuffer(det_ctx, flags, transforms, txv, i, engine->sm_list);
116+
if (buffer == NULL || buffer->inspect == NULL) {
117+
break;
118+
}
119+
120+
det_ctx->buffer_offset = 0;
121+
det_ctx->discontinue_matching = 0;
122+
det_ctx->inspection_recursion_counter = 0;
123+
124+
const int match = DetectEngineContentInspection(de_ctx, det_ctx, s, engine->smd, NULL, f,
125+
(uint8_t *)buffer->inspect, buffer->inspect_len, buffer->inspect_offset,
126+
DETECT_CI_FLAGS_SINGLE, DETECT_ENGINE_CONTENT_INSPECTION_MODE_STATE);
127+
if (match == 1) {
128+
return DETECT_ENGINE_INSPECT_SIG_MATCH;
129+
}
130+
}
131+
132+
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
133+
}
134+
135+
typedef struct PrefilterMpm {
136+
int list_id;
137+
const MpmCtx *mpm_ctx;
138+
const DetectEngineTransforms *transforms;
139+
} PrefilterMpm;
140+
141+
static void PrefilterTx(DetectEngineThreadCtx *det_ctx, const void *pectx, Packet *p, Flow *f,
142+
void *txv, const uint64_t idx, const AppLayerTxData *_txd, const uint8_t flags)
143+
{
144+
SCEnter();
145+
146+
const PrefilterMpm *ctx = (const PrefilterMpm *)pectx;
147+
const MpmCtx *mpm_ctx = ctx->mpm_ctx;
148+
const int list_id = ctx->list_id;
149+
150+
for (uint32_t i = 0;; i++) {
151+
InspectionBuffer *buffer = GetBuffer(det_ctx, flags, ctx->transforms, txv, i, list_id);
152+
if (buffer == NULL) {
153+
break;
154+
}
155+
156+
if (buffer->inspect_len >= mpm_ctx->minlen) {
157+
(void)mpm_table[mpm_ctx->mpm_type].Search(
158+
mpm_ctx, &det_ctx->mtcu, &det_ctx->pmq, buffer->inspect, buffer->inspect_len);
159+
PREFILTER_PROFILING_ADD_BYTES(det_ctx, buffer->inspect_len);
160+
}
161+
}
162+
}
163+
164+
static void PrefilterMpmFree(void *ptr)
165+
{
166+
SCFree(ptr);
167+
}
168+
169+
static int PrefilterMpmRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh, MpmCtx *mpm_ctx,
170+
const DetectBufferMpmRegistry *mpm_reg, int list_id)
171+
{
172+
PrefilterMpm *pectx = SCCalloc(1, sizeof(*pectx));
173+
if (pectx == NULL) {
174+
return -1;
175+
}
176+
pectx->list_id = list_id;
177+
pectx->mpm_ctx = mpm_ctx;
178+
pectx->transforms = &mpm_reg->transforms;
179+
180+
return PrefilterAppendTxEngine(de_ctx, sgh, PrefilterTx, mpm_reg->app_v2.alproto,
181+
mpm_reg->app_v2.tx_min_progress, pectx, PrefilterMpmFree, mpm_reg->pname);
182+
}

src/detect-dns-query-name.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/* Copyright (C) 2023 Open Information Security Foundation
2+
*
3+
* You can copy, redistribute or modify this Program under the terms of
4+
* the GNU General Public License version 2 as published by the Free
5+
* Software Foundation.
6+
*
7+
* This program is distributed in the hope that it will be useful,
8+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+
* GNU General Public License for more details.
11+
*
12+
* You should have received a copy of the GNU General Public License
13+
* version 2 along with this program; if not, write to the Free Software
14+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15+
* 02110-1301, USA.
16+
*/
17+
18+
#ifndef __DETECT_DNS_QUERY_NAME_H__
19+
#define __DETECT_DNS_QUERY_NAME_H__
20+
21+
void DetectDnsQueryNameRegister(void);
22+
23+
#endif /* __DETECT_DNS_QUERY_NAME_H__ */

src/detect-engine-register.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ enum DetectKeywordId {
224224
DETECT_AL_DNS_QUERY,
225225
DETECT_AL_DNS_OPCODE,
226226
DETECT_AL_DNS_ANSWER_NAME,
227+
DETECT_AL_DNS_QUERY_NAME,
227228
DETECT_AL_TLS_SNI,
228229
DETECT_AL_TLS_CERTS,
229230
DETECT_AL_TLS_CERT_ISSUER,

0 commit comments

Comments
 (0)