suricata
util-exception-policy.c
Go to the documentation of this file.
1 /* Copyright (C) 2022-2024 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 
22 #include "suricata-common.h"
23 #include "suricata.h"
24 #include "packet.h"
25 #include "util-exception-policy.h"
26 #include "util-misc.h"
27 #include "stream-tcp-reassemble.h"
28 #include "action-globals.h"
29 #include "conf.h"
30 
32 /** true if exception policy was defined in config */
33 static bool g_eps_have_exception_policy = false;
34 
35 const char *ExceptionPolicyEnumToString(enum ExceptionPolicy policy, bool is_json)
36 {
37  switch (policy) {
39  return "ignore";
41  return "auto";
43  return "reject";
45  return "bypass";
47  return is_json ? "drop_flow" : "drop-flow";
49  return is_json ? "drop_packet" : "drop-packet";
51  return is_json ? "pass_packet" : "pass-packet";
53  return is_json ? "pass_flow" : "pass-flow";
54  }
55  // TODO we shouldn't reach this, but if we do, better not to leave this as simply null...
56  return "not set";
57 }
58 
60 {
61  g_eps_master_switch = ExceptionPolicyParse("exception-policy", true);
62 }
63 
64 static enum ExceptionPolicy GetMasterExceptionPolicy(void)
65 {
66  return g_eps_master_switch;
67 }
68 
69 void ExceptionPolicyApply(Packet *p, enum ExceptionPolicy policy, enum PacketDropReason drop_reason)
70 {
71  SCLogDebug("start: pcap_cnt %" PRIu64 ", policy %u", p->pcap_cnt, policy);
72  switch (policy) {
74  break;
76  break;
78  SCLogDebug("EXCEPTION_POLICY_REJECT");
79  PacketDrop(p, ACTION_REJECT, drop_reason);
80  if (!EngineModeIsIPS()) {
81  break;
82  }
83  /* fall through */
85  SCLogDebug("EXCEPTION_POLICY_DROP_FLOW");
86  if (p->flow) {
88  FlowSetNoPayloadInspectionFlag(p->flow);
89  FlowSetNoPacketInspectionFlag(p->flow);
91  }
92  /* fall through */
94  SCLogDebug("EXCEPTION_POLICY_DROP_PACKET");
95  DecodeSetNoPayloadInspectionFlag(p);
96  DecodeSetNoPacketInspectionFlag(p);
97  PacketDrop(p, ACTION_DROP, drop_reason);
98  break;
101  /* fall through */
103  SCLogDebug("EXCEPTION_POLICY_PASS_FLOW");
104  if (p->flow) {
105  p->flow->flags |= FLOW_ACTION_PASS;
106  FlowSetNoPacketInspectionFlag(p->flow); // TODO util func
107  }
108  /* fall through */
110  SCLogDebug("EXCEPTION_POLICY_PASS_PACKET");
111  DecodeSetNoPayloadInspectionFlag(p);
112  DecodeSetNoPacketInspectionFlag(p);
113  break;
114  }
115  SCLogDebug("end");
116 }
117 
118 static enum ExceptionPolicy PickPacketAction(const char *option, enum ExceptionPolicy p)
119 {
120  switch (p) {
122  SCLogWarning(
123  "flow actions not supported for %s, defaulting to \"drop-packet\"", option);
126  SCLogWarning(
127  "flow actions not supported for %s, defaulting to \"pass-packet\"", option);
130  SCLogWarning("flow actions not supported for %s, defaulting to \"ignore\"", option);
132  /* add all cases, to make sure new cases not handle will raise
133  * errors */
135  break;
137  break;
139  break;
141  break;
143  break;
144  }
145  return p;
146 }
147 
148 static enum ExceptionPolicy ExceptionPolicyConfigValueParse(
149  const char *option, const char *value_str)
150 {
152  if (strcmp(value_str, "drop-flow") == 0) {
154  } else if (strcmp(value_str, "pass-flow") == 0) {
156  } else if (strcmp(value_str, "bypass") == 0) {
158  } else if (strcmp(value_str, "drop-packet") == 0) {
160  } else if (strcmp(value_str, "pass-packet") == 0) {
162  } else if (strcmp(value_str, "reject") == 0) {
163  policy = EXCEPTION_POLICY_REJECT;
164  } else if (strcmp(value_str, "ignore") == 0) { // TODO name?
165  policy = EXCEPTION_POLICY_NOT_SET;
166  } else if (strcmp(value_str, "auto") == 0) {
167  policy = EXCEPTION_POLICY_AUTO;
168  } else {
170  "\"%s\" is not a valid exception policy value. Valid options are drop-flow, "
171  "pass-flow, bypass, reject, drop-packet, pass-packet, ignore or auto.",
172  value_str);
173  }
174 
175  return policy;
176 }
177 
178 /* Select an exception policy in case the configuration value was set to 'auto' */
179 static enum ExceptionPolicy ExceptionPolicyPickAuto(bool midstream_enabled, bool support_flow)
180 {
182  if (!midstream_enabled && EngineModeIsIPS()) {
183  if (support_flow) {
185  } else {
187  }
188  }
189  return policy;
190 }
191 
192 static enum ExceptionPolicy ExceptionPolicyMasterParse(const char *value)
193 {
194  enum ExceptionPolicy policy = ExceptionPolicyConfigValueParse("exception-policy", value);
195  if (!EngineModeIsIPS() &&
196  (policy == EXCEPTION_POLICY_DROP_PACKET || policy == EXCEPTION_POLICY_DROP_FLOW)) {
197  policy = EXCEPTION_POLICY_NOT_SET;
198  }
199  g_eps_have_exception_policy = true;
200 
201  SCLogInfo("master exception-policy set to: %s", ExceptionPolicyEnumToString(policy, false));
202 
203  return policy;
204 }
205 
206 static enum ExceptionPolicy ExceptionPolicyGetDefault(
207  const char *option, bool support_flow, bool midstream)
208 {
210  if (g_eps_have_exception_policy) {
211  p = GetMasterExceptionPolicy();
212 
213  if (p == EXCEPTION_POLICY_AUTO) {
214  p = ExceptionPolicyPickAuto(midstream, support_flow);
215  }
216 
217  if (!support_flow) {
218  p = PickPacketAction(option, p);
219  }
220  SCLogConfig("%s: %s (defined via 'exception-policy' master switch)", option,
221  ExceptionPolicyEnumToString(p, false));
222  return p;
223  } else if (EngineModeIsIPS() && !midstream) {
225  }
226  SCLogConfig("%s: %s (defined via 'built-in default' for %s-mode)", option,
227  ExceptionPolicyEnumToString(p, false), EngineModeIsIPS() ? "IPS" : "IDS");
228 
229  return p;
230 }
231 
232 enum ExceptionPolicy ExceptionPolicyParse(const char *option, bool support_flow)
233 {
235  const char *value_str = NULL;
236 
237  if ((ConfGet(option, &value_str) == 1) && value_str != NULL) {
238  if (strcmp(option, "exception-policy") == 0) {
239  policy = ExceptionPolicyMasterParse(value_str);
240  } else {
241  policy = ExceptionPolicyConfigValueParse(option, value_str);
242  if (policy == EXCEPTION_POLICY_AUTO) {
243  policy = ExceptionPolicyPickAuto(false, support_flow);
244  }
245  if (!support_flow) {
246  policy = PickPacketAction(option, policy);
247  }
248  SCLogConfig("%s: %s", option, ExceptionPolicyEnumToString(policy, false));
249  }
250  } else {
251  policy = ExceptionPolicyGetDefault(option, support_flow, false);
252  }
253 
254  return policy;
255 }
256 
257 enum ExceptionPolicy ExceptionPolicyMidstreamParse(bool midstream_enabled)
258 {
260  const char *value_str = NULL;
261  /* policy was set directly */
262  if ((ConfGet("stream.midstream-policy", &value_str)) == 1 && value_str != NULL) {
263  policy = ExceptionPolicyConfigValueParse("midstream-policy", value_str);
264  if (policy == EXCEPTION_POLICY_AUTO) {
265  policy = ExceptionPolicyPickAuto(midstream_enabled, true);
266  } else if (midstream_enabled) {
267  if (policy != EXCEPTION_POLICY_NOT_SET && policy != EXCEPTION_POLICY_PASS_FLOW) {
269  "Error parsing stream.midstream-policy from config file. \"%s\" is "
270  "not a valid exception policy when midstream is enabled. Valid options "
271  "are pass-flow and ignore.",
272  value_str);
273  }
274  }
275  if (!EngineModeIsIPS()) {
276  if (policy == EXCEPTION_POLICY_DROP_FLOW) {
278  "Error parsing stream.midstream-policy from config file. \"%s\" is "
279  "not a valid exception policy in IDS mode. See our documentation for a "
280  "list of all possible values.",
281  value_str);
282  }
283  }
284  } else {
285  policy = ExceptionPolicyGetDefault("stream.midstream-policy", true, midstream_enabled);
286  }
287 
288  if (policy == EXCEPTION_POLICY_PASS_PACKET || policy == EXCEPTION_POLICY_DROP_PACKET) {
289  FatalErrorOnInit("Error parsing stream.midstream-policy from config file. \"%s\" is "
290  "not valid for this exception policy. See our documentation for a list of "
291  "all possible values.",
292  value_str);
293  }
294 
295  return policy;
296 }
297 
299  ExceptionPolicyStatsSetts *setting, enum ExceptionPolicy conf_policy,
300  const char *default_str, bool (*isExceptionPolicyValid)(enum ExceptionPolicy))
301 {
302  if (conf_policy != EXCEPTION_POLICY_NOT_SET) {
303  /* set-up policy counters */
304  for (enum ExceptionPolicy i = EXCEPTION_POLICY_NOT_SET + 1; i < EXCEPTION_POLICY_MAX; i++) {
305  if (isExceptionPolicyValid(i)) {
306  snprintf(setting->eps_name[i], sizeof(setting->eps_name[i]), "%s%s", default_str,
307  ExceptionPolicyEnumToString(i, true));
308  counter->eps_id[i] = StatsRegisterCounter(setting->eps_name[i], tv);
309  }
310  }
311  }
312 }
313 
314 #ifndef DEBUG
315 
316 int ExceptionSimulationCommandLineParser(const char *name, const char *arg)
317 {
318  return 0;
319 }
320 
321 #else
322 
323 /* exception policy simulation (eps) handling */
324 
325 uint64_t g_eps_applayer_error_offset_ts = UINT64_MAX;
326 uint64_t g_eps_applayer_error_offset_tc = UINT64_MAX;
327 uint64_t g_eps_pcap_packet_loss = UINT64_MAX;
328 uint64_t g_eps_stream_ssn_memcap = UINT64_MAX;
329 uint64_t g_eps_stream_reassembly_memcap = UINT64_MAX;
330 uint64_t g_eps_flow_memcap = UINT64_MAX;
331 uint64_t g_eps_defrag_memcap = UINT64_MAX;
332 bool g_eps_is_alert_queue_fail_mode = false;
333 
334 /* 1: parsed, 0: not for us, -1: error */
335 int ExceptionSimulationCommandLineParser(const char *name, const char *arg)
336 {
337  if (strcmp(name, "simulate-applayer-error-at-offset-ts") == 0) {
338  BUG_ON(arg == NULL);
339  uint64_t offset = 0;
340  if (ParseSizeStringU64(arg, &offset) < 0) {
341  return -1;
342  }
343  g_eps_applayer_error_offset_ts = offset;
344  } else if (strcmp(name, "simulate-applayer-error-at-offset-tc") == 0) {
345  BUG_ON(arg == NULL);
346  uint64_t offset = 0;
347  if (ParseSizeStringU64(arg, &offset) < 0) {
348  return TM_ECODE_FAILED;
349  }
350  g_eps_applayer_error_offset_tc = offset;
351  } else if (strcmp(name, "simulate-packet-loss") == 0) {
352  BUG_ON(arg == NULL);
353  uint64_t pkt_num = 0;
354  if (ParseSizeStringU64(arg, &pkt_num) < 0) {
355  return TM_ECODE_FAILED;
356  }
357  g_eps_pcap_packet_loss = pkt_num;
358  } else if (strcmp(name, "simulate-packet-tcp-reassembly-memcap") == 0) {
359  BUG_ON(arg == NULL);
360  uint64_t pkt_num = 0;
361  if (ParseSizeStringU64(arg, &pkt_num) < 0) {
362  return TM_ECODE_FAILED;
363  }
364  g_eps_stream_reassembly_memcap = pkt_num;
365  } else if (strcmp(name, "simulate-packet-tcp-ssn-memcap") == 0) {
366  BUG_ON(arg == NULL);
367  uint64_t pkt_num = 0;
368  if (ParseSizeStringU64(arg, &pkt_num) < 0) {
369  return TM_ECODE_FAILED;
370  }
371  g_eps_stream_ssn_memcap = pkt_num;
372  } else if (strcmp(name, "simulate-packet-flow-memcap") == 0) {
373  BUG_ON(arg == NULL);
374  uint64_t pkt_num = 0;
375  if (ParseSizeStringU64(arg, &pkt_num) < 0) {
376  return TM_ECODE_FAILED;
377  }
378  g_eps_flow_memcap = pkt_num;
379  } else if (strcmp(name, "simulate-packet-defrag-memcap") == 0) {
380  BUG_ON(arg == NULL);
381  uint64_t pkt_num = 0;
382  if (ParseSizeStringU64(arg, &pkt_num) < 0) {
383  return TM_ECODE_FAILED;
384  }
385  g_eps_defrag_memcap = pkt_num;
386  } else if (strcmp(name, "simulate-alert-queue-realloc-failure") == 0) {
387  g_eps_is_alert_queue_fail_mode = true;
388  } else {
389  // not for us
390  return 0;
391  }
392  return 1;
393 }
394 #endif
ExceptionPolicyApply
void ExceptionPolicyApply(Packet *p, enum ExceptionPolicy policy, enum PacketDropReason drop_reason)
Definition: util-exception-policy.c:69
ExceptionSimulationCommandLineParser
int ExceptionSimulationCommandLineParser(const char *name, const char *arg)
Definition: util-exception-policy.c:316
EXCEPTION_POLICY_PASS_FLOW
@ EXCEPTION_POLICY_PASS_FLOW
Definition: util-exception-policy-types.h:29
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
PacketBypassCallback
void PacketBypassCallback(Packet *p)
Definition: decode.c:504
g_eps_master_switch
enum ExceptionPolicy g_eps_master_switch
Definition: util-exception-policy.c:31
ACTION_REJECT
#define ACTION_REJECT
Definition: action-globals.h:31
EXCEPTION_POLICY_DROP_PACKET
@ EXCEPTION_POLICY_DROP_PACKET
Definition: util-exception-policy-types.h:31
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
Packet_::pcap_cnt
uint64_t pcap_cnt
Definition: decode.h:592
ParseSizeStringU64
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:190
action-globals.h
ExceptionPolicyStatsSetts_
Definition: util-exception-policy-types.h:48
stream-tcp-reassemble.h
FLOW_ACTION_DROP
#define FLOW_ACTION_DROP
Definition: flow.h:69
EXCEPTION_POLICY_BYPASS_FLOW
@ EXCEPTION_POLICY_BYPASS_FLOW
Definition: util-exception-policy-types.h:30
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:81
PacketDropReason
PacketDropReason
Definition: decode.h:357
EXCEPTION_POLICY_NOT_SET
@ EXCEPTION_POLICY_NOT_SET
Definition: util-exception-policy-types.h:26
ExceptionPolicyParse
enum ExceptionPolicy ExceptionPolicyParse(const char *option, bool support_flow)
Definition: util-exception-policy.c:232
ConfGet
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:335
FLOW_ACTION_PASS
#define FLOW_ACTION_PASS
Definition: flow.h:116
EXCEPTION_POLICY_MAX
#define EXCEPTION_POLICY_MAX
Definition: util-exception-policy-types.h:36
ExceptionPolicyCounters_
Definition: util-exception-policy-types.h:43
EXCEPTION_POLICY_PASS_PACKET
@ EXCEPTION_POLICY_PASS_PACKET
Definition: util-exception-policy-types.h:28
EXCEPTION_POLICY_AUTO
@ EXCEPTION_POLICY_AUTO
Definition: util-exception-policy-types.h:27
util-exception-policy.h
ExceptionPolicyCounters_::eps_id
uint16_t eps_id[EXCEPTION_POLICY_MAX]
Definition: util-exception-policy-types.h:45
ExceptionPolicySetStatsCounters
void ExceptionPolicySetStatsCounters(ThreadVars *tv, ExceptionPolicyCounters *counter, ExceptionPolicyStatsSetts *setting, enum ExceptionPolicy conf_policy, const char *default_str, bool(*isExceptionPolicyValid)(enum ExceptionPolicy))
Definition: util-exception-policy.c:298
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
EXCEPTION_POLICY_DROP_FLOW
@ EXCEPTION_POLICY_DROP_FLOW
Definition: util-exception-policy-types.h:32
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:249
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:300
ExceptionPolicyMidstreamParse
enum ExceptionPolicy ExceptionPolicyMidstreamParse(bool midstream_enabled)
Definition: util-exception-policy.c:257
Packet_
Definition: decode.h:473
conf.h
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:224
Packet_::flow
struct Flow_ * flow
Definition: decode.h:512
EXCEPTION_POLICY_REJECT
@ EXCEPTION_POLICY_REJECT
Definition: util-exception-policy-types.h:33
StreamTcpDisableAppLayer
void StreamTcpDisableAppLayer(Flow *f)
Definition: stream-tcp-reassemble.c:446
suricata-common.h
FatalErrorOnInit
#define FatalErrorOnInit(...)
Fatal error IF we're starting up, and configured to consider errors to be fatal errors.
Definition: util-debug.h:511
packet.h
ACTION_DROP
#define ACTION_DROP
Definition: action-globals.h:30
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
ExceptionPolicyEnumToString
const char * ExceptionPolicyEnumToString(enum ExceptionPolicy policy, bool is_json)
Definition: util-exception-policy.c:35
Flow_::flags
uint32_t flags
Definition: flow.h:426
PacketDrop
void PacketDrop(Packet *p, const uint8_t action, enum PacketDropReason r)
issue drop action
Definition: packet.c:33
EngineModeIsIPS
int EngineModeIsIPS(void)
Definition: suricata.c:228
suricata.h
SetMasterExceptionPolicy
void SetMasterExceptionPolicy(void)
Definition: util-exception-policy.c:59
util-misc.h
ExceptionPolicy
ExceptionPolicy
Definition: util-exception-policy-types.h:25
StatsRegisterCounter
uint16_t StatsRegisterCounter(const char *name, struct ThreadVars_ *tv)
Registers a normal, unqualified counter.
Definition: counters.c:951
ExceptionPolicyStatsSetts_::eps_name
char eps_name[EXCEPTION_POLICY_MAX][EXCEPTION_POLICY_COUNTER_MAX_LEN]
Definition: util-exception-policy-types.h:49