Drop streams on inline mode when a drop rule match from a reassembled stream and/or app layer inspection

remotes/origin/master-1.0.x
Pablo Rincon 15 years ago committed by Victor Julien
parent 76af1b049b
commit 5c43db85ce

@ -33,6 +33,8 @@
#include "util-debug.h"
extern uint8_t engine_mode;
/** \brief Get the active app layer proto from the packet
* \param p packet pointer
* \retval alstate void pointer to the state

@ -209,8 +209,14 @@ typedef struct PacketAlert_ {
char *msg;
char *class_msg;
Reference *references;
uint8_t flags;
} PacketAlert;
/* After processing an alert by the thresholding module, if at
* last it gets triggered, we might want to stick the drop action to
* the flow on IPS mode */
#define PACKET_ALERT_FLAG_DROP_FLOW 0x01
#define PACKET_ALERT_MAX 256
typedef struct PacketAlerts_ {

@ -110,7 +110,7 @@ int PacketAlertRemove(Packet *p, uint16_t pos)
return match;
}
int PacketAlertAppend(DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p)
int PacketAlertAppend(DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p, uint8_t flags)
{
int i = 0;
@ -138,6 +138,7 @@ int PacketAlertAppend(DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p)
p->alerts.alerts[p->alerts.cnt].class = s->class;
p->alerts.alerts[p->alerts.cnt].class_msg = s->class_msg;
p->alerts.alerts[p->alerts.cnt].references = s->references;
p->alerts.alerts[p->alerts.cnt].flags = flags;
} else {
/* We need to make room for this s->num
(a bit ugly with mamcpy but we are planning changes here)*/
@ -162,6 +163,7 @@ int PacketAlertAppend(DetectEngineThreadCtx *det_ctx, Signature *s, Packet *p)
p->alerts.alerts[i].class = s->class;
p->alerts.alerts[i].class_msg = s->class_msg;
p->alerts.alerts[i].references = s->references;
p->alerts.alerts[i].flags = flags;
}
/* Update the count */
@ -256,6 +258,14 @@ void PacketAlertFinalize(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx
* so we ignore the rest with less prio */
p->alerts.cnt = i;
break;
} else if ( ((p->alerts.alerts[i].flags & PACKET_ALERT_FLAG_DROP_FLOW) ||
(s->flags & SIG_FLAG_APPLAYER))
&& p->flow != NULL)
{
SCMutexLock(&p->flow->m);
/* This will apply only on IPS mode (check StreamTcpPacket) */
p->flow->flags |= FLOW_ACTION_DROP;
SCMutexUnlock(&p->flow->m);
}
}
/* Because we removed the alert from the array, we should

@ -28,7 +28,7 @@
#include "detect.h"
void PacketAlertFinalize(DetectEngineCtx *, DetectEngineThreadCtx *, Packet *);
int PacketAlertAppend(DetectEngineThreadCtx *, Signature *, Packet *);
int PacketAlertAppend(DetectEngineThreadCtx *, Signature *, Packet *, uint8_t);
int PacketAlertAppendTag(Packet *, PacketAlert *);
int PacketAlertCheck(Packet *, uint32_t);
int PacketAlertRemove(Packet *, uint16_t);

@ -983,7 +983,10 @@ void IPOnlyMatchPacket(DetectEngineCtx *de_ctx,
u * 8 + i, s->id, s->msg);
if ( !(s->flags & SIG_FLAG_NOALERT)) {
PacketAlertAppend(det_ctx, s, p);
if (s->action & ACTION_DROP)
PacketAlertAppend(det_ctx, s, p, PACKET_ALERT_FLAG_DROP_FLOW);
else
PacketAlertAppend(det_ctx, s, p, 0);
}
}
}

@ -51,6 +51,7 @@
#include "detect-http-method.h"
#include "detect-decode-event.h"
#include "decode.h"
#include "detect-ipopts.h"
#include "detect-flags.h"
@ -147,6 +148,8 @@
#include "util-profiling.h"
#include "util-validate.h"
extern uint8_t engine_mode;
SigMatch *SigMatchAlloc(void);
void DetectExitPrintStats(ThreadVars *tv, void *data);
@ -691,6 +694,12 @@ end:
*/
int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
{
/* No need to perform any detection on this packet, if the the given flag is set.*/
if (p->flags & PKT_NOPACKET_INSPECTION)
return 0;
int match = 0, fmatch = 0;
Signature *s = NULL;
SigMatch *sm = NULL;
@ -703,6 +712,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh
char use_flow_sgh = FALSE;
StreamMsg *smsg = NULL;
char no_store_flow_sgh = FALSE;
uint8_t alert_flags = 0;
SCEnter();
@ -782,7 +792,15 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh
/* if it matched a "pass" rule, we have to let it go */
p->action |= ACTION_PASS;
}
if (p->flow->flags & FLOW_ACTION_DROP) p->action |= ACTION_DROP;
/* If we have a drop from IP only module,
* we will drop the rest of the flow packets
* This will apply only to inline/IPS */
if (p->flow != NULL &&
(p->flow->flags & FLOW_ACTION_DROP))
{
alert_flags = PACKET_ALERT_FLAG_DROP_FLOW;
p->action |= ACTION_DROP;
}
} else {
/* Even without flow we should match the packet src/dst */
IPOnlyMatchPacket(de_ctx, det_ctx, &de_ctx->io_ctx, &det_ctx->io_ctx, p);
@ -942,6 +960,10 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh
if (DetectEngineInspectStreamPayload(de_ctx, det_ctx, s, p->flow, smsg_inspect->data.data, smsg_inspect->data.data_len) == 1) {
SCLogDebug("match in smsg %p", smsg);
pmatch = 1;
/* Tell the enigne that this reassembled stream can drop the
* rest of the pkts with no further inspection */
if (s->action == ACTION_DROP)
alert_flags |= PACKET_ALERT_FLAG_DROP_FLOW;
break;
}
}
@ -972,8 +994,12 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh
if (det_ctx->de_state_sig_array[s->num] == DE_STATE_MATCH_NOSTATE) {
SCLogDebug("stateful app layer match inspection starting");
if (DeStateDetectStartDetection(th_v, de_ctx, det_ctx, s,
p->flow, flags, alstate, alproto) != 1)
p->flow, flags, alstate, alproto) != 1) {
goto next;
} else {
if (s->action == ACTION_DROP)
alert_flags |= PACKET_ALERT_FLAG_DROP_FLOW;
}
} else {
SCLogDebug("already having a destate");
@ -981,6 +1007,9 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh
s->id, (uintmax_t)s->num, DeStateMatchResultToString(det_ctx->de_state_sig_array[s->num]));
if (det_ctx->de_state_sig_array[s->num] != DE_STATE_MATCH_NEW) {
goto next;
} else {
if (s->action == ACTION_DROP)
alert_flags |= PACKET_ALERT_FLAG_DROP_FLOW;
}
}
}
@ -992,7 +1021,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh
fmatch = 1;
if (!(s->flags & SIG_FLAG_NOALERT)) {
PacketAlertAppend(det_ctx, s, p);
PacketAlertAppend(det_ctx, s, p, alert_flags);
}
} else {
if (s->flags & SIG_FLAG_RECURSIVE) {
@ -1012,7 +1041,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh
if (!(s->flags & SIG_FLAG_NOALERT)) {
/* only add once */
if (rmatch == 0) {
PacketAlertAppend(det_ctx, s, p);
PacketAlertAppend(det_ctx, s, p, alert_flags);
}
}
rmatch = fmatch = 1;
@ -1045,7 +1074,7 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh
if (sm == NULL) {
fmatch = 1;
if (!(s->flags & SIG_FLAG_NOALERT)) {
PacketAlertAppend(det_ctx, s, p);
PacketAlertAppend(det_ctx, s, p, alert_flags);
}
}
} else {
@ -8828,6 +8857,525 @@ end:
return result;
}
/** \test test if the engine set flag to drop pkts of a flow that
* triggered a drop action on IPS mode */
static int SigTestDropFlow01(void)
{
int result = 0;
Flow f;
HtpState *http_state = NULL;
uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n"
"User-Agent: Mozilla/1.0\r\n"
"Cookie: hellocatch\r\n\r\n";
uint32_t http_buf1_len = sizeof(http_buf1) - 1;
TcpSession ssn;
Packet *p = NULL;
Signature *s = NULL;
ThreadVars tv;
DetectEngineThreadCtx *det_ctx = NULL;
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
memset(&ssn, 0, sizeof(TcpSession));
p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
FLOW_INITIALIZE(&f);
f.protoctx = (void *)&ssn;
f.src.family = AF_INET;
f.dst.family = AF_INET;
p->flow = &f;
p->flowflags |= FLOW_PKT_TOSERVER;
p->flowflags |= FLOW_PKT_ESTABLISHED;
f.alproto = ALPROTO_HTTP;
StreamTcpInitConfig(TRUE);
FlowL7DataPtrInit(&f);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
de_ctx->mpm_matcher = MPM_B2G;
de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx, "drop http any any -> any any "
"(msg:\"Test proto match\"; "
"sid:1;)");
if (s == NULL) {
goto end;
}
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
goto end;
}
http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
if (http_state == NULL) {
printf("no http state: ");
goto end;
}
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
if (!PacketAlertCheck(p, 1)) {
printf("sig 1 didn't alert, but it should: ");
goto end;
}
if ( !(p->flow->flags & FLOW_ACTION_DROP)) {
printf("sig 1 alerted but flow was not flagged correctly: ");
goto end;
}
/* Ok, now we know that the flag is set for proto http */
result = 1;
end:
if (det_ctx != NULL)
DetectEngineThreadCtxDeinit(&tv, det_ctx);
if (de_ctx != NULL)
SigGroupCleanup(de_ctx);
if (de_ctx != NULL)
DetectEngineCtxFree(de_ctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePackets(&p, 1);
return result;
}
/** \test test if the engine set flag to drop pkts of a flow that
* triggered a drop action on IPS mode */
static int SigTestDropFlow02(void)
{
int result = 0;
Flow f;
HtpState *http_state = NULL;
uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n"
"User-Agent: Mozilla/1.0\r\n"
"Cookie: hellocatch\r\n\r\n";
uint32_t http_buf1_len = sizeof(http_buf1) - 1;
TcpSession ssn;
Packet *p = NULL;
Signature *s = NULL;
ThreadVars tv;
DetectEngineThreadCtx *det_ctx = NULL;
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
memset(&ssn, 0, sizeof(TcpSession));
p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
FLOW_INITIALIZE(&f);
f.protoctx = (void *)&ssn;
f.src.family = AF_INET;
f.dst.family = AF_INET;
p->flow = &f;
p->flowflags |= FLOW_PKT_TOSERVER;
p->flowflags |= FLOW_PKT_ESTABLISHED;
f.alproto = ALPROTO_HTTP;
StreamTcpInitConfig(TRUE);
FlowL7DataPtrInit(&f);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
de_ctx->mpm_matcher = MPM_B2G;
de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 "
"(msg:\"Test proto match\"; uricontent:\"one\";"
"sid:1;)");
if (s == NULL) {
goto end;
}
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
goto end;
}
http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
if (http_state == NULL) {
printf("no http state: ");
goto end;
}
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
if (!PacketAlertCheck(p, 1)) {
printf("sig 1 didn't alert, but it should: ");
goto end;
}
if ( !(p->flow->flags & FLOW_ACTION_DROP)) {
printf("sig 1 alerted but flow was not flagged correctly: ");
goto end;
}
/* Ok, now we know that the flag is set for app layer sigs
* (ex: inspecting uricontent) */
result = 1;
end:
if (det_ctx != NULL)
DetectEngineThreadCtxDeinit(&tv, det_ctx);
if (de_ctx != NULL)
SigGroupCleanup(de_ctx);
if (de_ctx != NULL)
DetectEngineCtxFree(de_ctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePackets(&p, 1);
return result;
}
/** \test test if the engine set flag to drop pkts of a flow that
* triggered a drop action on IPS mode, and it doesn't inspect
* any other packet of the stream */
static int SigTestDropFlow03(void)
{
int result = 0;
Flow f;
HtpState *http_state = NULL;
uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n"
"User-Agent: Mozilla/1.0\r\n"
"Cookie: hellocatch\r\n\r\n";
uint32_t http_buf1_len = sizeof(http_buf1) - 1;
uint8_t http_buf2[] = "POST /two HTTP/1.0\r\n"
"User-Agent: Mozilla/1.0\r\n"
"Cookie: hellocatch\r\n\r\n";
uint32_t http_buf2_len = sizeof(http_buf1) - 1;
/* Set the engine mode to IPS */
SET_ENGINE_MODE_IPS(engine_mode);
TcpSession ssn;
Packet *p1 = NULL;
Packet *p2 = NULL;
Signature *s = NULL;
ThreadVars tv;
DetectEngineThreadCtx *det_ctx = NULL;
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
memset(&ssn, 0, sizeof(TcpSession));
p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
FLOW_INITIALIZE(&f);
f.protoctx = (void *)&ssn;
f.src.family = AF_INET;
f.dst.family = AF_INET;
p1->flow = &f;
p1->flowflags |= FLOW_PKT_TOSERVER;
p1->flowflags |= FLOW_PKT_ESTABLISHED;
p2->flow = &f;
p2->flowflags |= FLOW_PKT_TOSERVER;
p2->flowflags |= FLOW_PKT_ESTABLISHED;
f.alproto = ALPROTO_HTTP;
StreamTcpInitConfig(TRUE);
FlowL7DataPtrInit(&f);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
de_ctx->mpm_matcher = MPM_B2G;
de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 "
"(msg:\"Test proto match\"; uricontent:\"one\";"
"sid:1;)");
if (s == NULL) {
goto end;
}
/* the no inspection flag should be set after the first sig gets triggered,
* so the second packet should not match the next sig (because of no inspection) */
s = de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any 80 "
"(msg:\"Test proto match\"; uricontent:\"two\";"
"sid:2;)");
if (s == NULL) {
goto end;
}
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
goto end;
}
http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
if (http_state == NULL) {
printf("no http state: ");
goto end;
}
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p1);
if (!PacketAlertCheck(p1, 1)) {
printf("sig 1 didn't alert on p1, but it should: ");
goto end;
}
if ( !(p1->flow->flags & FLOW_ACTION_DROP)) {
printf("sig 1 alerted but flow was not flagged correctly: ");
goto end;
}
/* Second part.. Let's feed with another packet */
if (StreamTcpCheckFlowDrops(p2) == 1) {
SCLogDebug("This flow/stream triggered a drop rule");
FlowSetNoPacketInspectionFlag(p2->flow);
DecodeSetNoPacketInspectionFlag(p2);
FlowSetSessionNoApplayerInspectionFlag(p2->flow);
p2->action |= ACTION_DROP;
/* return the segments to the pool */
StreamTcpSessionPktFree(p2);
}
if ( !(p2->flags & PKT_NOPACKET_INSPECTION)) {
printf("The packet was not flagged with no-inspection: ");
goto end;
}
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len);
if (r != 0) {
printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p2);
if (PacketAlertCheck(p2, 1)) {
printf("sig 1 alerted, but it should not since the no pkt inspection should be set: ");
goto end;
}
if (PacketAlertCheck(p2, 2)) {
printf("sig 2 alerted, but it should not since the no pkt inspection should be set: ");
goto end;
}
if ( !(p2->action & ACTION_DROP)) {
printf("A \"drop\" action should be set from the flow to the packet: ");
goto end;
}
result = 1;
end:
if (det_ctx != NULL)
DetectEngineThreadCtxDeinit(&tv, det_ctx);
if (de_ctx != NULL)
SigGroupCleanup(de_ctx);
if (de_ctx != NULL)
DetectEngineCtxFree(de_ctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePackets(&p1, 1);
UTHFreePackets(&p2, 1);
/* Restore mode to IDS */
SET_ENGINE_MODE_IDS(engine_mode);
return result;
}
/** \test test if the engine set flag to drop pkts of a flow that
* triggered a drop action on IDS mode, but continue the inspection
* as usual (instead of on IPS mode) */
static int SigTestDropFlow04(void)
{
int result = 0;
Flow f;
HtpState *http_state = NULL;
uint8_t http_buf1[] = "POST /one HTTP/1.0\r\n"
"User-Agent: Mozilla/1.0\r\n"
"Cookie: hellocatch\r\n\r\n";
uint32_t http_buf1_len = sizeof(http_buf1) - 1;
uint8_t http_buf2[] = "POST /two HTTP/1.0\r\n"
"User-Agent: Mozilla/1.0\r\n"
"Cookie: hellocatch\r\n\r\n";
uint32_t http_buf2_len = sizeof(http_buf1) - 1;
TcpSession ssn;
Packet *p1 = NULL;
Packet *p2 = NULL;
Signature *s = NULL;
ThreadVars tv;
DetectEngineThreadCtx *det_ctx = NULL;
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
memset(&ssn, 0, sizeof(TcpSession));
p1 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
p2 = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
FLOW_INITIALIZE(&f);
f.protoctx = (void *)&ssn;
f.src.family = AF_INET;
f.dst.family = AF_INET;
p1->flow = &f;
p1->flowflags |= FLOW_PKT_TOSERVER;
p1->flowflags |= FLOW_PKT_ESTABLISHED;
p2->flow = &f;
p2->flowflags |= FLOW_PKT_TOSERVER;
p2->flowflags |= FLOW_PKT_ESTABLISHED;
f.alproto = ALPROTO_HTTP;
StreamTcpInitConfig(TRUE);
FlowL7DataPtrInit(&f);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
de_ctx->mpm_matcher = MPM_B2G;
de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx, "drop tcp any any -> any 80 "
"(msg:\"Test proto match\"; uricontent:\"one\";"
"sid:1;)");
if (s == NULL) {
goto end;
}
/* the no inspection flag should be set after the first sig gets triggered,
* so the second packet should not match the next sig (because of no inspection) */
s = de_ctx->sig_list->next = SigInit(de_ctx, "alert tcp any any -> any 80 "
"(msg:\"Test proto match\"; uricontent:\"two\";"
"sid:2;)");
if (s == NULL) {
goto end;
}
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf1, http_buf1_len);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
goto end;
}
http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
if (http_state == NULL) {
printf("no http state: ");
goto end;
}
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p1);
if (!PacketAlertCheck(p1, 1)) {
printf("sig 1 didn't alert on p1, but it should: ");
goto end;
}
if ( !(p1->flow->flags & FLOW_ACTION_DROP)) {
printf("sig 1 alerted but flow was not flagged correctly: ");
goto end;
}
/* Second part.. Let's feed with another packet */
if (StreamTcpCheckFlowDrops(p2) == 1) {
FlowSetNoPacketInspectionFlag(p2->flow);
DecodeSetNoPacketInspectionFlag(p2);
FlowSetSessionNoApplayerInspectionFlag(p2->flow);
p2->action |= ACTION_DROP;
/* return the segments to the pool */
StreamTcpSessionPktFree(p2);
}
if ( (p2->flags & PKT_NOPACKET_INSPECTION)) {
printf("The packet was flagged with no-inspection but we are not on IPS mode: ");
goto end;
}
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, http_buf2, http_buf2_len);
if (r != 0) {
printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p2);
if (PacketAlertCheck(p2, 1)) {
printf("sig 1 alerted, but it should not since the no pkt inspection should be set: ");
goto end;
}
if (!PacketAlertCheck(p2, 2)) {
printf("sig 2 didn't alert, but it should, since we are not on IPS mode: ");
goto end;
}
if (p2->action & ACTION_DROP) {
printf("A \"drop\" action was set from the flow to the packet, but on IDS mode it whould not (it should be inspected as usual: ");
goto end;
}
result = 1;
end:
if (det_ctx != NULL)
DetectEngineThreadCtxDeinit(&tv, det_ctx);
if (de_ctx != NULL)
SigGroupCleanup(de_ctx);
if (de_ctx != NULL)
DetectEngineCtxFree(de_ctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePackets(&p1, 1);
UTHFreePackets(&p2, 1);
return result;
}
#endif /* UNITTESTS */
void SigRegisterTests(void) {
@ -9030,6 +9578,11 @@ void SigRegisterTests(void) {
UtRegisterTest("SigTestDetectAlertCounter", SigTestDetectAlertCounter, 1);
UtRegisterTest("SigTestDropFlow01", SigTestDropFlow01, 1);
UtRegisterTest("SigTestDropFlow02", SigTestDropFlow02, 1);
UtRegisterTest("SigTestDropFlow03", SigTestDropFlow03, 1);
UtRegisterTest("SigTestDropFlow04", SigTestDropFlow04, 1);
#endif /* UNITTESTS */
}

@ -1432,70 +1432,6 @@ int FlowSetProtoEmergencyTimeout(uint8_t proto, uint32_t emerg_new_timeout, uint
return 1;
}
/** \brief Set the No Packet Inspection Flag after locking the flow.
*
* \param f Flow to set the flag in
*/
void FlowLockSetNoPacketInspectionFlag(Flow *f) {
SCEnter();
SCLogDebug("flow %p", f);
SCMutexLock(&f->m);
f->flags |= FLOW_NOPACKET_INSPECTION;
SCMutexUnlock(&f->m);
SCReturn;
}
/** \brief Set the No Packet Inspection Flag without locking the flow.
*
* \param f Flow to set the flag in
*/
void FlowSetNoPacketInspectionFlag(Flow *f) {
SCEnter();
SCLogDebug("flow %p", f);
f->flags |= FLOW_NOPACKET_INSPECTION;
SCReturn;
}
/** \brief Set the No payload inspection Flag after locking the flow.
*
* \param f Flow to set the flag in
*/
void FlowLockSetNoPayloadInspectionFlag(Flow *f) {
SCEnter();
SCLogDebug("flow %p", f);
SCMutexLock(&f->m);
f->flags |= FLOW_NOPAYLOAD_INSPECTION;
SCMutexUnlock(&f->m);
SCReturn;
}
/** \brief Set the No payload inspection Flag without locking the flow.
*
* \param f Flow to set the flag in
*/
void FlowSetNoPayloadInspectionFlag(Flow *f) {
SCEnter();
SCLogDebug("flow %p", f);
f->flags |= FLOW_NOPAYLOAD_INSPECTION;
SCReturn;
}
/** \brief set flow flag to disable app layer inspection
*
* \param f *LOCKED* flow
*/
void FlowSetSessionNoApplayerInspectionFlag(Flow *f) {
f->alflags |= FLOW_AL_NO_APPLAYER_INSPECTION;
}
#ifdef UNITTESTS
#include "stream-tcp-private.h"
#include "threads.h"

@ -254,16 +254,83 @@ int FlowSetProtoFreeFunc (uint8_t , void (*Free)(void *));
int FlowSetFlowStateFunc (uint8_t , int (*GetProtoState)(void *));
void FlowUpdateQueue(Flow *);
void FlowLockSetNoPacketInspectionFlag(Flow *);
void FlowSetNoPacketInspectionFlag(Flow *);
void FlowLockSetNoPayloadInspectionFlag(Flow *);
void FlowSetNoPayloadInspectionFlag(Flow *);
void FlowSetSessionNoApplayerInspectionFlag(Flow *);
static inline void FlowLockSetNoPacketInspectionFlag(Flow *);
static inline void FlowSetNoPacketInspectionFlag(Flow *);
static inline void FlowLockSetNoPayloadInspectionFlag(Flow *);
static inline void FlowSetNoPayloadInspectionFlag(Flow *);
static inline void FlowSetSessionNoApplayerInspectionFlag(Flow *);
int FlowGetPacketDirection(Flow *, Packet *);
void FlowL7DataPtrInit(Flow *);
void FlowL7DataPtrFree(Flow *);
/** ----- Inline functions ----- */
/** \brief Set the No Packet Inspection Flag after locking the flow.
*
* \param f Flow to set the flag in
*/
static inline void FlowLockSetNoPacketInspectionFlag(Flow *f) {
SCEnter();
SCLogDebug("flow %p", f);
SCMutexLock(&f->m);
f->flags |= FLOW_NOPACKET_INSPECTION;
SCMutexUnlock(&f->m);
SCReturn;
}
/** \brief Set the No Packet Inspection Flag without locking the flow.
*
* \param f Flow to set the flag in
*/
static inline void FlowSetNoPacketInspectionFlag(Flow *f) {
SCEnter();
SCLogDebug("flow %p", f);
f->flags |= FLOW_NOPACKET_INSPECTION;
SCReturn;
}
/** \brief Set the No payload inspection Flag after locking the flow.
*
* \param f Flow to set the flag in
*/
static inline void FlowLockSetNoPayloadInspectionFlag(Flow *f) {
SCEnter();
SCLogDebug("flow %p", f);
SCMutexLock(&f->m);
f->flags |= FLOW_NOPAYLOAD_INSPECTION;
SCMutexUnlock(&f->m);
SCReturn;
}
/** \brief Set the No payload inspection Flag without locking the flow.
*
* \param f Flow to set the flag in
*/
static inline void FlowSetNoPayloadInspectionFlag(Flow *f) {
SCEnter();
SCLogDebug("flow %p", f);
f->flags |= FLOW_NOPAYLOAD_INSPECTION;
SCReturn;
}
/** \brief set flow flag to disable app layer inspection
*
* \param f *LOCKED* flow
*/
static inline void FlowSetSessionNoApplayerInspectionFlag(Flow *f) {
f->alflags |= FLOW_AL_NO_APPLAYER_INSPECTION;
}
#endif /* __FLOW_H__ */

@ -98,6 +98,8 @@ static SCMutex ssn_pool_mutex;
static uint64_t ssn_pool_cnt = 0; /** counts ssns, protected by ssn_pool_mutex */
#endif
extern uint8_t engine_mode;
static SCSpinlock stream_memuse_spinlock;
static uint32_t stream_memuse;
static uint32_t stream_memuse_max;
@ -231,7 +233,7 @@ void StreamTcpSessionClear(void *ssnptr)
*
* \param p Packet used to identify the stream.
*/
static void StreamTcpSessionPktFree (Packet *p)
void StreamTcpSessionPktFree (Packet *p)
{
SCEnter();
@ -515,28 +517,6 @@ static void StreamTcpPacketSetState(Packet *p, TcpSession *ssn,
FlowUpdateQueue(p->flow);
}
/**
* \brief Function to flip the direction When we missed the SYN packet,
* SYN/ACK is considered as sent by server, but our engine flagged the
* packet as from client for the host whose packet is received first in
* the session.
*
* \param ssn TcpSession to whom this packet belongs
* \param p Packet whose flag has to be changed
*/
static void StreamTcpPacketSwitchDir(TcpSession *ssn, Packet *p)
{
SCLogDebug("ssn %p: switching pkt direction", ssn);
if (PKT_IS_TOSERVER(p)) {
p->flowflags &= ~FLOW_PKT_TOSERVER;
p->flowflags |= FLOW_PKT_TOCLIENT;
} else {
p->flowflags &= ~FLOW_PKT_TOCLIENT;
p->flowflags |= FLOW_PKT_TOSERVER;
}
}
/**
* \brief Function to set the OS policy for the given stream based on the
* destination of the received packet.
@ -2591,6 +2571,21 @@ static int StreamTcpPacket (ThreadVars *tv, Packet *p, StreamTcpThread *stt)
SCEnter();
TcpSession *ssn = (TcpSession *)p->flow->protoctx;
/* If we are on IPS mode, and got a drop action triggered from
* the IP only module, or from a reassembled msg and/or from an
* applayer detection, then drop the rest of the packets of the
* same stream and avoid inspecting it any further */
if (StreamTcpCheckFlowDrops(p) == 1) {
SCLogDebug("This flow/stream triggered a drop rule");
FlowSetNoPacketInspectionFlag(p->flow);
DecodeSetNoPacketInspectionFlag(p);
FlowSetSessionNoApplayerInspectionFlag(p->flow);
p->action |= ACTION_DROP;
/* return the segments to the pool */
StreamTcpSessionPktFree(p);
SCReturnInt(0);
}
if (ssn == NULL || ssn->state == TCP_NONE) {
if (StreamTcpPacketStateNone(tv, p, stt, ssn) == -1)
SCReturnInt(-1);

@ -52,9 +52,58 @@ void StreamTcpInitConfig (char);
void StreamTcpFreeConfig(char);
void StreamTcpRegisterTests (void);
void StreamTcpSessionPktFree (Packet *);
void StreamTcpIncrMemuse(uint32_t);
void StreamTcpDecrMemuse(uint32_t);
int StreamTcpCheckMemcap(uint32_t);
/** ------- Inline functions: ------ */
/**
* \brief If we are on IPS mode, and got a drop action triggered from
* the IP only module, or from a reassembled msg and/or from an
* applayer detection, then drop the rest of the packets of the
* same stream and avoid inspecting it any further
* \param p pointer to the Packet to check
* \retval 1 if we must drop this stream
* \retval 0 if the stream still legal
*/
static inline int StreamTcpCheckFlowDrops(Packet *p) {
extern uint8_t engine_mode;
/* If we are on IPS mode, and got a drop action triggered from
* the IP only module, or from a reassembled msg and/or from an
* applayer detection, then drop the rest of the packets of the
* same stream and avoid inspecting it any further */
if (IS_ENGINE_MODE_IPS(engine_mode) && (p->flow->flags & FLOW_ACTION_DROP))
return 1;
return 0;
}
/**
* \brief Function to flip the direction When we missed the SYN packet,
* SYN/ACK is considered as sent by server, but our engine flagged the
* packet as from client for the host whose packet is received first in
* the session.
*
* \param ssn TcpSession to whom this packet belongs
* \param p Packet whose flag has to be changed
*/
static inline void StreamTcpPacketSwitchDir(TcpSession *ssn, Packet *p)
{
SCLogDebug("ssn %p: switching pkt direction", ssn);
if (PKT_IS_TOSERVER(p)) {
p->flowflags &= ~FLOW_PKT_TOSERVER;
p->flowflags |= FLOW_PKT_TOCLIENT;
} else {
p->flowflags &= ~FLOW_PKT_TOCLIENT;
p->flowflags |= FLOW_PKT_TOSERVER;
}
}
#endif /* __STREAM_TCP_H__ */

@ -168,6 +168,10 @@ uint8_t suricata_ctl_flags = 0;
/** Run mode selected */
int run_mode = MODE_UNKNOWN;
/** Engine mode: inline (ENGINE_MODE_IPS) or just
* detection mode (ENGINE_MODE_IDS by default) */
uint8_t engine_mode = ENGINE_MODE_IDS;
/** Maximum packets to simultaneously process. */
intmax_t max_pending_packets;
@ -386,6 +390,10 @@ int main(int argc, char **argv)
/* initialize the logging subsys */
SCLogInitLogModule(NULL);
/* By default use IDS mode, but if nfq or ipfw
* are specified, IPS mode will overwrite this */
SET_ENGINE_MODE_IDS(engine_mode);
#ifdef OS_WIN32
/* service initialization */
if (SCRunningAsService()) {
@ -627,6 +635,7 @@ int main(int argc, char **argv)
#ifdef NFQ
if (run_mode == MODE_UNKNOWN) {
run_mode = MODE_NFQ;
SET_ENGINE_MODE_IPS(engine_mode);
} else {
SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode "
"has been specified");
@ -643,6 +652,7 @@ int main(int argc, char **argv)
#ifdef IPFW
if (run_mode == MODE_UNKNOWN) {
run_mode = MODE_IPFW;
SET_ENGINE_MODE_IPS(engine_mode);
} else {
SCLogError(SC_ERR_MULTIPLE_RUN_MODE, "more than one run mode "
"has been specified");

@ -58,6 +58,18 @@ enum {
SURICATA_DEINIT
};
/* Engine is acting as */
enum {
ENGINE_MODE_IDS,
ENGINE_MODE_IPS,
};
/** You can use this macros to set/check if we have real drop capabilities */
#define SET_ENGINE_MODE_IPS(engine_mode) (engine_mode = ENGINE_MODE_IPS);
#define SET_ENGINE_MODE_IDS(engine_mode) (engine_mode = ENGINE_MODE_IDS);
#define IS_ENGINE_MODE_IPS(engine_mode) (engine_mode == ENGINE_MODE_IPS)
#define IS_ENGINE_MODE_IDS(engine_mode) (engine_mode == ENGINE_MODE_IDS)
/* queue's between various other threads
* XXX move to the TmQueue structure later
*/

Loading…
Cancel
Save