suricata
util-exception-policy.c
Go to the documentation of this file.
1 /* Copyright (C) 2022-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 
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 
31 /** true if exception policy was defined in config */
32 static bool g_eps_have_exception_policy = false;
33 
34 static const char *ExceptionPolicyEnumToString(enum ExceptionPolicy policy)
35 {
36  switch (policy) {
38  return "ignore";
40  return "auto";
42  return "reject";
44  return "bypass";
46  return "drop-flow";
48  return "drop-packet";
50  return "pass-packet";
52  return "pass-flow";
53  }
54  // TODO we shouldn't reach this, but if we do, better not to leave this as simply null...
55  return "not set";
56 }
57 
59 {
60  g_eps_master_switch = ExceptionPolicyParse("exception-policy", true);
61 }
62 
63 static enum ExceptionPolicy GetMasterExceptionPolicy(const char *option)
64 {
65  return g_eps_master_switch;
66 }
67 
68 void ExceptionPolicyApply(Packet *p, enum ExceptionPolicy policy, enum PacketDropReason drop_reason)
69 {
70  SCLogDebug("start: pcap_cnt %" PRIu64 ", policy %u", p->pcap_cnt, policy);
71  switch (policy) {
73  break;
75  break;
77  SCLogDebug("EXCEPTION_POLICY_REJECT");
78  PacketDrop(p, ACTION_REJECT, drop_reason);
79  if (!EngineModeIsIPS()) {
80  break;
81  }
82  /* fall through */
84  SCLogDebug("EXCEPTION_POLICY_DROP_FLOW");
85  if (p->flow) {
87  FlowSetNoPayloadInspectionFlag(p->flow);
88  FlowSetNoPacketInspectionFlag(p->flow);
90  }
91  /* fall through */
93  SCLogDebug("EXCEPTION_POLICY_DROP_PACKET");
94  DecodeSetNoPayloadInspectionFlag(p);
95  DecodeSetNoPacketInspectionFlag(p);
96  PacketDrop(p, ACTION_DROP, drop_reason);
97  break;
100  /* fall through */
102  SCLogDebug("EXCEPTION_POLICY_PASS_FLOW");
103  if (p->flow) {
104  p->flow->flags |= FLOW_ACTION_PASS;
105  FlowSetNoPacketInspectionFlag(p->flow); // TODO util func
106  }
107  /* fall through */
109  SCLogDebug("EXCEPTION_POLICY_PASS_PACKET");
110  DecodeSetNoPayloadInspectionFlag(p);
111  DecodeSetNoPacketInspectionFlag(p);
112  break;
113  }
114  SCLogDebug("end");
115 }
116 
117 static enum ExceptionPolicy PickPacketAction(const char *option, enum ExceptionPolicy p)
118 {
119  switch (p) {
121  SCLogWarning(
122  "flow actions not supported for %s, defaulting to \"drop-packet\"", option);
125  SCLogWarning(
126  "flow actions not supported for %s, defaulting to \"pass-packet\"", option);
129  SCLogWarning("flow actions not supported for %s, defaulting to \"ignore\"", option);
131  /* add all cases, to make sure new cases not handle will raise
132  * errors */
134  break;
136  break;
138  break;
140  break;
142  break;
143  }
144  return p;
145 }
146 
147 static enum ExceptionPolicy ExceptionPolicyConfigValueParse(
148  const char *option, const char *value_str)
149 {
151  if (strcmp(value_str, "drop-flow") == 0) {
153  } else if (strcmp(value_str, "pass-flow") == 0) {
155  } else if (strcmp(value_str, "bypass") == 0) {
157  } else if (strcmp(value_str, "drop-packet") == 0) {
159  } else if (strcmp(value_str, "pass-packet") == 0) {
161  } else if (strcmp(value_str, "reject") == 0) {
162  policy = EXCEPTION_POLICY_REJECT;
163  } else if (strcmp(value_str, "ignore") == 0) { // TODO name?
164  policy = EXCEPTION_POLICY_NOT_SET;
165  } else if (strcmp(value_str, "auto") == 0) {
166  policy = EXCEPTION_POLICY_AUTO;
167  } else {
169  "\"%s\" is not a valid exception policy value. Valid options are drop-flow, "
170  "pass-flow, bypass, reject, drop-packet, pass-packet, ignore or auto.",
171  value_str);
172  }
173 
174  return policy;
175 }
176 
177 /* Select an exception policy in case the configuration value was set to 'auto' */
178 static enum ExceptionPolicy ExceptionPolicyPickAuto(bool midstream_enabled, bool support_flow)
179 {
181  if (!midstream_enabled && EngineModeIsIPS()) {
182  if (support_flow) {
184  } else {
186  }
187  }
188  return policy;
189 }
190 
191 static enum ExceptionPolicy ExceptionPolicyMasterParse(const char *value)
192 {
193  enum ExceptionPolicy policy = ExceptionPolicyConfigValueParse("exception-policy", value);
194  if (!EngineModeIsIPS() &&
195  (policy == EXCEPTION_POLICY_DROP_PACKET || policy == EXCEPTION_POLICY_DROP_FLOW)) {
196  policy = EXCEPTION_POLICY_NOT_SET;
197  }
198  g_eps_have_exception_policy = true;
199 
200  SCLogInfo("master exception-policy set to: %s", ExceptionPolicyEnumToString(policy));
201 
202  return policy;
203 }
204 
205 static enum ExceptionPolicy ExceptionPolicyGetDefault(
206  const char *option, bool support_flow, bool midstream)
207 {
209  if (g_eps_have_exception_policy) {
210  p = GetMasterExceptionPolicy(option);
211 
212  if (p == EXCEPTION_POLICY_AUTO) {
213  p = ExceptionPolicyPickAuto(midstream, support_flow);
214  }
215 
216  if (!support_flow) {
217  p = PickPacketAction(option, p);
218  }
219  SCLogConfig("%s: %s (defined via 'exception-policy' master switch)", option,
220  ExceptionPolicyEnumToString(p));
221  return p;
222  } else if (EngineModeIsIPS() && !midstream) {
224  }
225  SCLogConfig("%s: %s (defined via 'built-in default' for %s-mode)", option,
226  ExceptionPolicyEnumToString(p), EngineModeIsIPS() ? "IPS" : "IDS");
227 
228  return p;
229 }
230 
231 enum ExceptionPolicy ExceptionPolicyParse(const char *option, bool support_flow)
232 {
234  const char *value_str = NULL;
235 
236  if ((ConfGet(option, &value_str) == 1) && value_str != NULL) {
237  if (strcmp(option, "exception-policy") == 0) {
238  policy = ExceptionPolicyMasterParse(value_str);
239  } else {
240  policy = ExceptionPolicyConfigValueParse(option, value_str);
241  if (policy == EXCEPTION_POLICY_AUTO) {
242  policy = ExceptionPolicyPickAuto(false, support_flow);
243  }
244  if (!support_flow) {
245  policy = PickPacketAction(option, policy);
246  }
247  SCLogConfig("%s: %s", option, ExceptionPolicyEnumToString(policy));
248  }
249  } else {
250  policy = ExceptionPolicyGetDefault(option, support_flow, false);
251  }
252 
253  return policy;
254 }
255 
256 enum ExceptionPolicy ExceptionPolicyMidstreamParse(bool midstream_enabled)
257 {
259  const char *value_str = NULL;
260  /* policy was set directly */
261  if ((ConfGet("stream.midstream-policy", &value_str)) == 1 && value_str != NULL) {
262  policy = ExceptionPolicyConfigValueParse("midstream-policy", value_str);
263  if (policy == EXCEPTION_POLICY_AUTO) {
264  policy = ExceptionPolicyPickAuto(midstream_enabled, true);
265  } else if (midstream_enabled) {
266  if (policy != EXCEPTION_POLICY_NOT_SET && policy != EXCEPTION_POLICY_PASS_FLOW) {
268  "Error parsing stream.midstream-policy from config file. \"%s\" is "
269  "not a valid exception policy when midstream is enabled. Valid options "
270  "are pass-flow and ignore.",
271  value_str);
272  }
273  }
274  if (!EngineModeIsIPS()) {
275  if (policy == EXCEPTION_POLICY_DROP_FLOW) {
277  "Error parsing stream.midstream-policy from config file. \"%s\" is "
278  "not a valid exception policy in IDS mode. See our documentation for a "
279  "list of all possible values.",
280  value_str);
281  }
282  }
283  } else {
284  policy = ExceptionPolicyGetDefault("stream.midstream-policy", true, midstream_enabled);
285  }
286 
287  if (policy == EXCEPTION_POLICY_PASS_PACKET || policy == EXCEPTION_POLICY_DROP_PACKET) {
288  FatalErrorOnInit("Error parsing stream.midstream-policy from config file. \"%s\" is "
289  "not valid for this exception policy. See our documentation for a list of "
290  "all possible values.",
291  value_str);
292  }
293 
294  return policy;
295 }
296 
297 #ifndef DEBUG
298 
299 int ExceptionSimulationCommandLineParser(const char *name, const char *arg)
300 {
301  return 0;
302 }
303 
304 #else
305 
306 /* exception policy simulation (eps) handling */
307 
308 uint64_t g_eps_applayer_error_offset_ts = UINT64_MAX;
309 uint64_t g_eps_applayer_error_offset_tc = UINT64_MAX;
310 uint64_t g_eps_pcap_packet_loss = UINT64_MAX;
311 uint64_t g_eps_stream_ssn_memcap = UINT64_MAX;
312 uint64_t g_eps_stream_reassembly_memcap = UINT64_MAX;
313 uint64_t g_eps_flow_memcap = UINT64_MAX;
314 uint64_t g_eps_defrag_memcap = UINT64_MAX;
315 bool g_eps_is_alert_queue_fail_mode = false;
316 
317 /* 1: parsed, 0: not for us, -1: error */
318 int ExceptionSimulationCommandLineParser(const char *name, const char *arg)
319 {
320  if (strcmp(name, "simulate-applayer-error-at-offset-ts") == 0) {
321  BUG_ON(arg == NULL);
322  uint64_t offset = 0;
323  if (ParseSizeStringU64(arg, &offset) < 0) {
324  return -1;
325  }
326  g_eps_applayer_error_offset_ts = offset;
327  } else if (strcmp(name, "simulate-applayer-error-at-offset-tc") == 0) {
328  BUG_ON(arg == NULL);
329  uint64_t offset = 0;
330  if (ParseSizeStringU64(arg, &offset) < 0) {
331  return TM_ECODE_FAILED;
332  }
333  g_eps_applayer_error_offset_tc = offset;
334  } else if (strcmp(name, "simulate-packet-loss") == 0) {
335  BUG_ON(arg == NULL);
336  uint64_t pkt_num = 0;
337  if (ParseSizeStringU64(arg, &pkt_num) < 0) {
338  return TM_ECODE_FAILED;
339  }
340  g_eps_pcap_packet_loss = pkt_num;
341  } else if (strcmp(name, "simulate-packet-tcp-reassembly-memcap") == 0) {
342  BUG_ON(arg == NULL);
343  uint64_t pkt_num = 0;
344  if (ParseSizeStringU64(arg, &pkt_num) < 0) {
345  return TM_ECODE_FAILED;
346  }
347  g_eps_stream_reassembly_memcap = pkt_num;
348  } else if (strcmp(name, "simulate-packet-tcp-ssn-memcap") == 0) {
349  BUG_ON(arg == NULL);
350  uint64_t pkt_num = 0;
351  if (ParseSizeStringU64(arg, &pkt_num) < 0) {
352  return TM_ECODE_FAILED;
353  }
354  g_eps_stream_ssn_memcap = pkt_num;
355  } else if (strcmp(name, "simulate-packet-flow-memcap") == 0) {
356  BUG_ON(arg == NULL);
357  uint64_t pkt_num = 0;
358  if (ParseSizeStringU64(arg, &pkt_num) < 0) {
359  return TM_ECODE_FAILED;
360  }
361  g_eps_flow_memcap = pkt_num;
362  } else if (strcmp(name, "simulate-packet-defrag-memcap") == 0) {
363  BUG_ON(arg == NULL);
364  uint64_t pkt_num = 0;
365  if (ParseSizeStringU64(arg, &pkt_num) < 0) {
366  return TM_ECODE_FAILED;
367  }
368  g_eps_defrag_memcap = pkt_num;
369  } else if (strcmp(name, "simulate-alert-queue-realloc-failure") == 0) {
370  g_eps_is_alert_queue_fail_mode = true;
371  } else {
372  // not for us
373  return 0;
374  }
375  return 1;
376 }
377 #endif
ExceptionPolicyApply
void ExceptionPolicyApply(Packet *p, enum ExceptionPolicy policy, enum PacketDropReason drop_reason)
Definition: util-exception-policy.c:68
ExceptionSimulationCommandLineParser
int ExceptionSimulationCommandLineParser(const char *name, const char *arg)
Definition: util-exception-policy.c:299
offset
uint64_t offset
Definition: util-streaming-buffer.h:0
PacketBypassCallback
void PacketBypassCallback(Packet *p)
Definition: decode.c:443
g_eps_master_switch
enum ExceptionPolicy g_eps_master_switch
Definition: util-exception-policy.c:30
ACTION_REJECT
#define ACTION_REJECT
Definition: action-globals.h:31
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
Packet_::pcap_cnt
uint64_t pcap_cnt
Definition: decode.h:598
ParseSizeStringU64
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:198
action-globals.h
EXCEPTION_POLICY_DROP_PACKET
@ EXCEPTION_POLICY_DROP_PACKET
Definition: util-exception-policy.h:33
stream-tcp-reassemble.h
FLOW_ACTION_DROP
#define FLOW_ACTION_DROP
Definition: flow.h:66
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:85
PacketDropReason
PacketDropReason
Definition: decode.h:390
ExceptionPolicyParse
enum ExceptionPolicy ExceptionPolicyParse(const char *option, bool support_flow)
Definition: util-exception-policy.c:231
EXCEPTION_POLICY_AUTO
@ EXCEPTION_POLICY_AUTO
Definition: util-exception-policy.h:29
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:113
util-exception-policy.h
EXCEPTION_POLICY_REJECT
@ EXCEPTION_POLICY_REJECT
Definition: util-exception-policy.h:35
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:249
EXCEPTION_POLICY_PASS_PACKET
@ EXCEPTION_POLICY_PASS_PACKET
Definition: util-exception-policy.h:30
EXCEPTION_POLICY_DROP_FLOW
@ EXCEPTION_POLICY_DROP_FLOW
Definition: util-exception-policy.h:34
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:295
ExceptionPolicy
ExceptionPolicy
Definition: util-exception-policy.h:27
ExceptionPolicyMidstreamParse
enum ExceptionPolicy ExceptionPolicyMidstreamParse(bool midstream_enabled)
Definition: util-exception-policy.c:256
Packet_
Definition: decode.h:430
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:224
Packet_::flow
struct Flow_ * flow
Definition: decode.h:469
StreamTcpDisableAppLayer
void StreamTcpDisableAppLayer(Flow *f)
Definition: stream-tcp-reassemble.c:451
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
EXCEPTION_POLICY_BYPASS_FLOW
@ EXCEPTION_POLICY_BYPASS_FLOW
Definition: util-exception-policy.h:32
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
EXCEPTION_POLICY_PASS_FLOW
@ EXCEPTION_POLICY_PASS_FLOW
Definition: util-exception-policy.h:31
Flow_::flags
uint32_t flags
Definition: flow.h:417
PacketDrop
void PacketDrop(Packet *p, const uint8_t action, enum PacketDropReason r)
issue drop action
Definition: packet.c:32
EngineModeIsIPS
int EngineModeIsIPS(void)
Definition: suricata.c:228
suricata.h
SetMasterExceptionPolicy
void SetMasterExceptionPolicy(void)
Definition: util-exception-policy.c:58
util-misc.h
EXCEPTION_POLICY_NOT_SET
@ EXCEPTION_POLICY_NOT_SET
Definition: util-exception-policy.h:28