suricata
detect-config.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2020 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 * \author Victor Julien <victor@inliniac.net>
22 *
23 * Implements the config keyword
24 */
25
26#include "suricata-common.h"
27#include "threads.h"
28#include "decode.h"
29
30#include "detect.h"
31#include "detect-parse.h"
32
33#include "detect-engine.h"
34#include "detect-engine-mpm.h"
35#include "detect-engine-state.h"
36
37#include "flow.h"
38#include "flow-var.h"
39#include "flow-util.h"
40
41#include "util-debug.h"
42#include "util-spm-bm.h"
43#include "util-unittest.h"
45
46#include "app-layer.h"
47#include "app-layer-parser.h"
48#include "app-layer-htp.h"
49
50#include "stream-tcp.h"
51
52#include "detect-config.h"
53
54#include "output.h"
55
56/**
57 * \brief Regex for parsing our config keyword options
58 */
59#define PARSE_REGEX "^\\s*([A-z_]+)\\s*\\s*([A-z_]+)\\s*(?:,\\s*([A-z_]+)\\s+([A-z_]+))?\\s*(?:,\\s*([A-z_]+)\\s+([A-z_]+))?$"
60
61static DetectParseRegex parse_regex;
62
63static int DetectConfigPostMatch (DetectEngineThreadCtx *det_ctx, Packet *p,
64 const Signature *s, const SigMatchCtx *ctx);
65static int DetectConfigSetup (DetectEngineCtx *, Signature *, const char *);
66static void DetectConfigFree(DetectEngineCtx *, void *);
67#ifdef UNITTESTS
68static void DetectConfigRegisterTests(void);
69#endif
70
71/**
72 * \brief Registers the "config" keyword for detection.
73 */
75{
77 sigmatch_table[DETECT_CONFIG].Match = DetectConfigPostMatch;
78 sigmatch_table[DETECT_CONFIG].Setup = DetectConfigSetup;
79 sigmatch_table[DETECT_CONFIG].Free = DetectConfigFree;
80#ifdef UNITTESTS
81 sigmatch_table[DETECT_CONFIG].RegisterTests = DetectConfigRegisterTests;
82#endif
85}
86
87/**
88 * \brief Apply configuration settings to a transaction based on the provided DetectConfigData.
89 *
90 * This function applies specific configurations to a transaction. The configurations are
91 * determined by the subsystems and types specified in the DetectConfigData structure.
92 *
93 * \param f Pointer to the Flow structure that will be configured.
94 * \param tx_id Transaction ID within the flow.
95 * \param config Pointer to the DetectConfigData structure containing configuration settings.
96 */
97static void ConfigApplyTx(Flow *f,
98 const uint64_t tx_id, const DetectConfigData *config)
99{
100 if (f->alstate == NULL) {
101 return;
102 }
103 void *tx = AppLayerParserGetTx(f->proto, f->alproto, f->alstate, tx_id);
104 if (tx) {
106 SCLogDebug("tx %p txd %p: log_flags %x", tx, txd, txd->config.log_flags);
107 txd->config.log_flags |= BIT_U8(config->type);
108
109 const bool unidir =
111 if (unidir) {
112 SCLogDebug("handle unidir tx");
114 memset(&req, 0, sizeof(req));
115 req.log_flags = BIT_U8(config->type);
117 f->proto, f->alproto, f->alstate, tx, CONFIG_ACTION_SET, req);
118 }
119 } else {
120 SCLogDebug("no tx");
121 }
122}
123
124/**
125 * \brief Apply configuration settings to a packet based on the provided DetectConfigData.
126 *
127 * This function applies specific configurations to a packet. The configurations are
128 * determined by the subsystems and types specified in the DetectConfigData structure.
129 *
130 * \param p Pointer to the Packet structure that will be configured.
131 * \param config Pointer to the DetectConfigData structure containing configuration settings.
132 */
133static void ConfigApplyPacket(Packet *p, const DetectConfigData *config)
134{
136
137 switch (config->subsys) {
139 switch (config->type) {
140 case CONFIG_TYPE_FLOW:
141 if (p->flags & PKT_WANTS_FLOW) {
142 p->flags &= ~PKT_WANTS_FLOW;
143 }
144 break;
145 case CONFIG_TYPE_TX:
146 break;
147 }
148 break;
150 break;
151 }
152}
153
154/**
155 * \brief Apply configuration settings based on the scope.
156 *
157 * This function applies post-match configurations with options. It
158 * determines which logic to apply based on the scope of the configuration,
159 * whether it is packet, transaction (tx), or flow level.
160 *
161 * \param det_ctx Pointer to the detection engine thread context.
162 * \param p Pointer to the current packet being processed.
163 * \param config Pointer to the configuration data structure.
164 *
165 * \retval 0 on success.
166 */
167static int ConfigApply(DetectEngineThreadCtx *det_ctx,
168 Packet *p, const DetectConfigData *config)
169{
170 bool this_packet = false;
171 bool this_tx = false;
172 bool this_flow = false;
173
174 switch (config->scope) {
176 this_packet = true;
177 break;
178 case CONFIG_SCOPE_TX:
179 this_tx = true;
180 break;
182 this_flow = true;
183 break;
184 }
185
186 if (this_packet) {
187 SCLogDebug("packet logic here: %" PRIu64, p->pcap_cnt);
188 ConfigApplyPacket(p, config);
189 } else if (this_tx) {
190 SCLogDebug("tx logic here: tx_id %"PRIu64, det_ctx->tx_id);
191 ConfigApplyTx(p->flow, det_ctx->tx_id, config);
192 } else if (this_flow) {
193 SCLogDebug("flow logic here");
194 }
195
196 SCReturnInt(0);
197}
198
199/**
200 * \brief Post-match configuration detection function.
201 *
202 * This function is called after a match has been detected. It applies the
203 * configuration settings to the packet and returns 1 indicating that the
204 * configuration was successfully applied.
205 *
206 * \param det_ctx Pointer to the detection engine thread context.
207 * \param p Pointer to the packet being processed.
208 * \param s Pointer to the signature that matched.
209 * \param ctx Pointer to the match context, which contains the configuration data.
210 * \return 1 indicating the configuration was successfully applied
211 */
212static int DetectConfigPostMatch(DetectEngineThreadCtx *det_ctx,
213 Packet *p, const Signature *s, const SigMatchCtx *ctx)
214{
215 SCEnter();
216 const DetectConfigData *config = (const DetectConfigData *)ctx;
217 ConfigApply(det_ctx, p, config);
218 SCReturnInt(1);
219}
220
222 char subsys[32];
223 char state[32];
224 char type[32];
225 char typeval[32];
226 char scope[32];
227 char scopeval[32];
228};
229
230static int GetStrings(const char *str, struct ConfigStrings *p)
231{
232 pcre2_match_data *match = NULL;
233
234 if (str == NULL || strlen(str) == 0) {
235 SCLogError("config keywords need arguments");
236 return -1;
237 }
238 SCLogDebug("str %s", str);
239
240 int ret = DetectParsePcreExec(&parse_regex, &match, str, 0, 0);
241 if (ret != 7) {
242 SCLogError("config is rather picky at this time");
243 goto error;
244 }
245 size_t pcre2len = sizeof(p->subsys);
246 int res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)p->subsys, &pcre2len);
247 if (res < 0) {
248 SCLogError("failed to copy subsys substring");
249 goto error;
250 }
251
252 pcre2len = sizeof(p->state);
253 res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)p->state, &pcre2len);
254 if (res < 0) {
255 SCLogError("failed to copy state substring");
256 goto error;
257 }
258
259 pcre2len = sizeof(p->type);
260 res = pcre2_substring_copy_bynumber(match, 3, (PCRE2_UCHAR8 *)p->type, &pcre2len);
261 if (res < 0) {
262 SCLogError("failed to copy type substring");
263 goto error;
264 }
265
266 pcre2len = sizeof(p->typeval);
267 res = pcre2_substring_copy_bynumber(match, 4, (PCRE2_UCHAR8 *)p->typeval, &pcre2len);
268 if (res < 0) {
269 SCLogError("failed to copy typeval substring");
270 goto error;
271 }
272
273 pcre2len = sizeof(p->scope);
274 res = pcre2_substring_copy_bynumber(match, 5, (PCRE2_UCHAR8 *)p->scope, &pcre2len);
275 if (res < 0) {
276 SCLogError("failed to copy scope substring");
277 goto error;
278 }
279
280 pcre2len = sizeof(p->scopeval);
281 res = pcre2_substring_copy_bynumber(match, 6, (PCRE2_UCHAR8 *)p->scopeval, &pcre2len);
282 if (res < 0) {
283 SCLogError("failed to copy scopeval substring");
284 goto error;
285 }
286
287 pcre2_match_data_free(match);
288 return 0;
289error:
290 pcre2_match_data_free(match);
291 return -1;
292}
293
294static bool ParseValues(const struct ConfigStrings *c, enum ConfigType *type,
295 enum ConfigSubsys *subsys, enum ConfigScope *scope)
296{
297 SCLogDebug("subsys %s", c->subsys);
298 if (strcmp(c->subsys, "logging") == 0) {
299 *subsys = CONFIG_SUBSYS_LOGGING;
300 } else if (strcmp(c->subsys, "tracking") == 0) {
301 *subsys = CONFIG_SUBSYS_TRACKING;
302 } else {
303 SCLogError("invalid subsys '%s': only 'logging' and 'tracking' supported at this time",
304 c->subsys);
305 return false;
306 }
307
308 SCLogDebug("state %s", c->state);
309 if (strcmp(c->state, "disable") != 0) {
310 SCLogError("only 'disable' supported at this time");
311 return false;
312 }
313
314 SCLogDebug("type %s", c->type);
315 if (strcmp(c->type, "type") != 0) {
316 SCLogError("only 'type' supported at this time");
317 return false;
318 }
319
320 SCLogDebug("typeval %s", c->typeval);
321 if (strcmp(c->typeval, "tx") == 0) {
323 } else if (strcmp(c->typeval, "flow") == 0) {
325 } else {
326 SCLogError("only 'tx' and 'flow' supported at this time");
327 return false;
328 }
329
330 SCLogDebug("scope %s", c->scope);
331 if (strcmp(c->scope, "scope") != 0) {
332 SCLogError("only 'scope' supported at this time");
333 return false;
334 }
335
336 if (strcmp(c->scopeval, "tx") == 0) {
337 *scope = CONFIG_SCOPE_TX;
338 } else if (strcmp(c->scopeval, "flow") == 0) {
339 *scope = CONFIG_SCOPE_FLOW;
340 } else if (strcmp(c->scopeval, "packet") == 0) {
341 *scope = CONFIG_SCOPE_PACKET;
342 } else {
343 SCLogError("invalid scope '%s': only 'tx', 'flow' and 'packet' supported at this time",
344 c->scopeval);
345 return false;
346 }
347 SCLogDebug("scopeval %s", c->scopeval);
348 return true;
349}
350
351/**
352 * \brief this function is used to parse config option into the current signature
353 *
354 * \param de_ctx pointer to the Detection Engine Context
355 * \param s pointer to the Current Signature
356 * \param str pointer to the user provided "config" input option string
357 *
358 * \retval 0 on Success
359 * \retval -1 on Failure
360 */
361static int DetectConfigSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
362{
363 SCEnter();
364
365 struct ConfigStrings c;
366 memset(&c, 0, sizeof(c));
367
368 if (GetStrings(str, &c) != 0) {
369 SCReturnInt(-1);
370 }
371
372 enum ConfigType type;
373 enum ConfigSubsys subsys;
374 enum ConfigScope scope;
375
376 if (ParseValues(&c, &type, &subsys, &scope) == false) {
377 SCReturnInt(-1);
378 }
379
380 /* TODO table is not yet set here */
385 SCLogError("disabling flow tracking is only supported in 'pre_flow' hook");
386 SCReturnInt(-1);
387 }
388 }
389
391 if (unlikely(fd == NULL))
392 return -1;
393
394 fd->type = type;
395 fd->scope = scope;
396 fd->subsys = subsys;
397
398 if (fd->scope == CONFIG_SCOPE_TX) {
400 }
401
404 return -1;
405 }
406
407 return 0;
408}
409
410static void DetectConfigFree(DetectEngineCtx *de_ctx, void *ptr)
411{
412 if (ptr != NULL) {
413 SCFree(ptr);
414 }
415}
416
417#ifdef UNITTESTS
418static int DetectConfigTest01(void)
419{
421 FAIL_IF(de_ctx == NULL);
424 "config dns any any -> any any ("
425 "dns.query; content:\"common.domain.com\"; "
426 "config:logging disable, type tx, scope tx; "
427 "sid:1;)");
428 FAIL_IF_NULL(s);
430 PASS;
431}
432
433void DetectConfigRegisterTests(void)
434{
435 UtRegisterTest("DetectConfigTest01", DetectConfigTest01);
436}
437#endif /* UNITTESTS */
AppLayerTxData * AppLayerParserGetTxData(uint8_t ipproto, AppProto alproto, void *tx)
void * AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
void AppLayerParserApplyTxConfig(uint8_t ipproto, AppProto alproto, void *state, void *tx, enum ConfigAction mode, AppLayerTxConfig config)
struct AppLayerTxData AppLayerTxData
#define APP_LAYER_TX_SKIP_INSPECT_TC
#define APP_LAYER_TX_SKIP_INSPECT_TS
struct AppLayerTxConfig AppLayerTxConfig
uint16_t type
#define PKT_WANTS_FLOW
Definition decode.h:1296
#define PARSE_REGEX
Regex for parsing our config keyword options.
void DetectConfigRegister(void)
Registers the "config" keyword for detection.
DetectEngineCtx * DetectEngineCtxInit(void)
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
Data structures and function prototypes for keeping state for the detection engine.
void DetectSetupParseRegexes(const char *parse_str, DetectParseRegex *detect_parse)
int DetectParsePcreExec(DetectParseRegex *parse_regex, pcre2_match_data **match, const char *str, int start_offset, int options)
SigMatch * SCSigMatchAppendSMToList(DetectEngineCtx *de_ctx, Signature *s, uint16_t type, SigMatchCtx *ctx, const int list)
Append a SigMatch to the list type.
SigTableElmt * sigmatch_table
@ SIGNATURE_HOOK_PKT_PRE_FLOW
Definition detect.h:541
#define DE_QUIET
Definition detect.h:330
#define SIGMATCH_SUPPORT_FIREWALL
Definition detect.h:1682
@ DETECT_SM_LIST_POSTMATCH
Definition detect.h:127
@ SIGNATURE_HOOK_TYPE_PKT
Definition detect.h:548
#define SIG_FLAG_APPLAYER
Definition detect.h:249
DetectEngineCtx * de_ctx
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define PASS
Pass the test.
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
struct Thresholds ctx
char scopeval[32]
enum ConfigSubsys subsys
enum ConfigType type
enum ConfigScope scope
main detection engine ctx
Definition detect.h:932
uint8_t flags
Definition detect.h:934
Flow data structure.
Definition flow.h:356
uint8_t proto
Definition flow.h:378
AppProto alproto
application level protocol
Definition flow.h:450
void * alstate
Definition flow.h:479
uint64_t pcap_cnt
Definition decode.h:626
struct Flow_ * flow
Definition decode.h:546
uint32_t flags
Definition decode.h:544
Used to start a pointer to SigMatch context Should never be dereferenced without casting to something...
Definition detect.h:351
int(* Setup)(DetectEngineCtx *, Signature *, const char *)
Definition detect.h:1441
void(* Free)(DetectEngineCtx *, void *)
Definition detect.h:1446
uint16_t flags
Definition detect.h:1450
void(* RegisterTests)(void)
Definition detect.h:1448
int(* Match)(DetectEngineThreadCtx *, Packet *, const Signature *, const SigMatchCtx *)
Definition detect.h:1421
const char * name
Definition detect.h:1459
struct SignatureHook_::@95::@97 pkt
union SignatureHook_::@95 t
enum SignatureHookPkt ph
Definition detect.h:582
enum SignatureHookType type
Definition detect.h:572
SignatureHook hook
Definition detect.h:590
Signature container.
Definition detect.h:668
uint32_t flags
Definition detect.h:669
SignatureInitData * init_data
Definition detect.h:747
#define BIT_U8(n)
#define str(s)
@ CONFIG_ACTION_SET
Definition util-config.h:28
ConfigSubsys
Definition util-config.h:31
@ CONFIG_SUBSYS_LOGGING
Definition util-config.h:32
@ CONFIG_SUBSYS_TRACKING
Definition util-config.h:33
ConfigScope
Definition util-config.h:49
@ CONFIG_SCOPE_FLOW
Definition util-config.h:51
@ CONFIG_SCOPE_PACKET
Definition util-config.h:52
@ CONFIG_SCOPE_TX
Definition util-config.h:50
ConfigType
Definition util-config.h:36
@ CONFIG_TYPE_FLOW
Definition util-config.h:38
@ CONFIG_TYPE_TX
Definition util-config.h:37
#define SCEnter(...)
Definition util-debug.h:277
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturnInt(x)
Definition util-debug.h:281
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define unlikely(expr)
#define DEBUG_VALIDATE_BUG_ON(exp)