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