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;
80 #ifdef UNITTESTS
81  sigmatch_table[DETECT_CONFIG].RegisterTests = DetectConfigRegisterTests;
82 #endif
84  DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
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  */
97 static 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");
113  AppLayerTxConfig req;
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  */
133 static 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  */
167 static 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) {
175  case CONFIG_SCOPE_PACKET:
176  this_packet = true;
177  break;
178  case CONFIG_SCOPE_TX:
179  this_tx = true;
180  break;
181  case CONFIG_SCOPE_FLOW:
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  */
212 static 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 
230 static 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;
289 error:
290  pcre2_match_data_free(match);
291  return -1;
292 }
293 
294 static 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) {
322  *type = CONFIG_TYPE_TX;
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  */
361 static 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 */
382  type == CONFIG_TYPE_FLOW) {
385  SCLogError("disabling flow tracking is only supported in 'pre_flow' hook");
386  SCReturnInt(-1);
387  }
388  }
389 
390  DetectConfigData *fd = SCCalloc(1, sizeof(DetectConfigData));
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) {
399  s->flags |= SIG_FLAG_APPLAYER;
400  }
401 
404  return -1;
405  }
406 
407  return 0;
408 }
409 
410 static void DetectConfigFree(DetectEngineCtx *de_ctx, void *ptr)
411 {
412  if (ptr != NULL) {
413  SCFree(ptr);
414  }
415 }
416 
417 #ifdef UNITTESTS
418 static int DetectConfigTest01(void)
419 {
421  FAIL_IF(de_ctx == NULL);
422  de_ctx->flags |= DE_QUIET;
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 
433 void DetectConfigRegisterTests(void)
434 {
435  UtRegisterTest("DetectConfigTest01", DetectConfigTest01);
436 }
437 #endif /* UNITTESTS */
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:224
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:226
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:2643
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:221
ConfigStrings::typeval
char typeval[32]
Definition: detect-config.c:225
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:223
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:222
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:227
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:2604
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