support for enforcing the depth until when the reassembly will be performed

remotes/origin/master-1.0.x
Gurvinder Singh 16 years ago committed by Victor Julien
parent 13045683ff
commit f0928a4555

@ -58,6 +58,8 @@ typedef struct TcpStream_ {
app layer protocol has not been detected, app layer protocol has not been detected,
beacuse every smsg needs to contain all the beacuse every smsg needs to contain all the
initial segments too */ initial segments too */
uint32_t reassembly_depth; /**< The depth value of a stream until when, we
will reassemble the stream */
} TcpStream; } TcpStream;
/* from /usr/include/netinet/tcp.h */ /* from /usr/include/netinet/tcp.h */

@ -1315,11 +1315,45 @@ static int HandleSegmentStartsAfterListSegment(TcpStream *stream,
SCReturnInt(0); SCReturnInt(0);
} }
/**
* \brief Function to Check the reassembly depth valuer against the
* allowed max depth of the stream reassmbly for TCP streams.
*
* \param size Size of the depth util now and received packet payload length
* \retval 1 if in bounds
* \retval 0 if not in bounds
*/
int StreamTcpReassembleCheckDepth(uint32_t size) {
SCEnter();
int ret = 0;
/* if the configured depth value is 0, it means there is no limit on
reassembly depth. Otherwise carry on my boy ;) */
if (stream_config.reassembly_depth == 0) {
ret = 1;
} else if (size <= stream_config.reassembly_depth) {
ret = 1;
}
SCReturnInt(ret);
}
int StreamTcpReassembleHandleSegmentHandleData(TcpSession *ssn, int StreamTcpReassembleHandleSegmentHandleData(TcpSession *ssn,
TcpStream *stream, Packet *p) TcpStream *stream, Packet *p)
{ {
SCEnter(); SCEnter();
/* If we have reached the defined depth for either of the stream, then stop
reassembling the TCP session */
if (StreamTcpReassembleCheckDepth(stream->reassembly_depth + p->payload_len)
!= 1)
{
ssn->flags |= STREAMTCP_FLAG_NOCLIENT_REASSEMBLY;
ssn->flags |= STREAMTCP_FLAG_NOSERVER_REASSEMBLY;
SCReturnInt(0);
}
TcpSegment *seg = StreamTcpGetSegment(p->payload_len); TcpSegment *seg = StreamTcpGetSegment(p->payload_len);
if (seg == NULL) { if (seg == NULL) {
SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[p->payload_len]); SCLogDebug("segment_pool[%"PRIu16"] is empty", segment_pool_idx[p->payload_len]);
@ -1331,6 +1365,7 @@ int StreamTcpReassembleHandleSegmentHandleData(TcpSession *ssn,
seg->seq = TCP_GET_SEQ(p); seg->seq = TCP_GET_SEQ(p);
seg->next = NULL; seg->next = NULL;
seg->prev = NULL; seg->prev = NULL;
stream->reassembly_depth += p->payload_len;
if (ReassembleInsertSegment(stream, seg, p) != 0) { if (ReassembleInsertSegment(stream, seg, p) != 0) {
SCLogDebug("ReassembleInsertSegment failed"); SCLogDebug("ReassembleInsertSegment failed");
@ -5574,6 +5609,263 @@ end:
return ret; return ret;
} }
/**
* \test Test to make sure that reassembly_depth is enforced.
*
* \retval On success it returns 1 and on failure 0.
*/
static int StreamTcpReassembleTest45 (void) {
int ret = 0;
Packet p;
Flow f;
TCPHdr tcph;
Port sp;
Port dp;
Address src;
Address dst;
struct in_addr in;
TcpSession ssn;
memset(&p, 0, sizeof (Packet));
memset(&f, 0, sizeof (Flow));
memset(&tcph, 0, sizeof (TCPHdr));
memset(&src, 0, sizeof(Address));
memset(&dst, 0, sizeof(Address));
memset(&ssn, 0, sizeof(TcpSession));
uint8_t httpbuf1[] = "/ HTTP/1.0\r\nUser-Agent: Victor/1.0";
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
FLOW_INITIALIZE(&f);
StreamTcpInitConfig(TRUE);
TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx();
ssn.server.ra_base_seq = 9;
ssn.server.isn = 9;
ssn.server.last_ack = 60;
ssn.client.ra_base_seq = 9;
ssn.client.isn = 9;
ssn.client.last_ack = 60;
f.alproto = ALPROTO_UNKNOWN;
inet_pton(AF_INET, "1.2.3.4", &in);
src.family = AF_INET;
src.addr_data32[0] = in.s_addr;
inet_pton(AF_INET, "1.2.3.5", &in);
dst.family = AF_INET;
dst.addr_data32[0] = in.s_addr;
sp = 200;
dp = 220;
f.src = src;
f.dst = dst;
f.sp = sp;
f.dp = dp;
f.protoctx = &ssn;
p.flow = &f;
tcph.th_win = htons(5480);
tcph.th_seq = htonl(10);
tcph.th_ack = htonl(20);
tcph.th_flags = TH_ACK|TH_PUSH;
p.tcph = &tcph;
p.flowflags = FLOW_PKT_TOCLIENT;
p.payload = httpbuf1;
p.payload_len = httplen1;
ssn.state = TCP_ESTABLISHED;
/* set the default value of reassembly depth, as there is no config file */
stream_config.reassembly_depth = 1048576;
ssn.server.reassembly_depth = 1048530;
TcpStream *s = NULL;
s = &ssn.server;
if (StreamTcpReassembleHandleSegment(ra_ctx, &ssn, s, &p) == -1) {
printf("failed in segments reassembly, while processing toclient packet\n");
goto end;
}
/* Check if we have flags set or not */
if ((ssn.flags & STREAMTCP_FLAG_NOCLIENT_REASSEMBLY) ||
(ssn.flags & STREAMTCP_FLAG_NOSERVER_REASSEMBLY)) {
printf("there shouldn't be any no reassembly flag be set \n");
goto end;
}
p.flowflags = FLOW_PKT_TOSERVER;
p.payload_len = httplen1;
s = &ssn.client;
if (StreamTcpReassembleHandleSegment(ra_ctx, &ssn, s, &p) == -1) {
printf("failed in segments reassembly, while processing toserver packet\n");
goto end;
}
/* Check if we have flags set or not */
if ((ssn.flags & STREAMTCP_FLAG_NOCLIENT_REASSEMBLY) ||
(ssn.flags & STREAMTCP_FLAG_NOSERVER_REASSEMBLY)) {
printf("there shouldn't be any no reassembly flag be set \n");
goto end;
}
p.flowflags = FLOW_PKT_TOCLIENT;
p.payload_len = httplen1;
s = &ssn.server;
if (StreamTcpReassembleHandleSegment(ra_ctx, &ssn, s, &p) == -1) {
printf("failed in segments reassembly, while processing toserver packet\n");
goto end;
}
/* Check if we have flags set or not */
if (! (ssn.flags & STREAMTCP_FLAG_NOCLIENT_REASSEMBLY) ||
! (ssn.flags & STREAMTCP_FLAG_NOSERVER_REASSEMBLY)) {
printf("the no_reassembly flags should be set, server.reassembly_depth "
"%"PRIu32" and p.payload_len %"PRIu16" stream_config.reassembly_"
"depth %"PRIu32"\n", ssn.server.reassembly_depth, p.payload_len,
stream_config.reassembly_depth);
goto end;
}
ret = 1;
end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx);
return ret;
}
/**
* \test Test the undefined config value of reassembly depth.
* the default value of 0 will be loaded and stream will be reassembled
* until the session ended
*
* \retval On success it returns 1 and on failure 0.
*/
static int StreamTcpReassembleTest46 (void) {
int ret = 0;
Packet p;
Flow f;
TCPHdr tcph;
Port sp;
Port dp;
Address src;
Address dst;
struct in_addr in;
TcpSession ssn;
memset(&p, 0, sizeof (Packet));
memset(&f, 0, sizeof (Flow));
memset(&tcph, 0, sizeof (TCPHdr));
memset(&src, 0, sizeof(Address));
memset(&dst, 0, sizeof(Address));
memset(&ssn, 0, sizeof(TcpSession));
uint8_t httpbuf1[] = "/ HTTP/1.0\r\nUser-Agent: Victor/1.0";
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
FLOW_INITIALIZE(&f);
StreamTcpInitConfig(TRUE);
TcpReassemblyThreadCtx *ra_ctx = StreamTcpReassembleInitThreadCtx();
ssn.server.ra_base_seq = 9;
ssn.server.isn = 9;
ssn.server.last_ack = 60;
ssn.client.ra_base_seq = 9;
ssn.client.isn = 9;
ssn.client.last_ack = 60;
f.alproto = ALPROTO_UNKNOWN;
inet_pton(AF_INET, "1.2.3.4", &in);
src.family = AF_INET;
src.addr_data32[0] = in.s_addr;
inet_pton(AF_INET, "1.2.3.5", &in);
dst.family = AF_INET;
dst.addr_data32[0] = in.s_addr;
sp = 200;
dp = 220;
f.src = src;
f.dst = dst;
f.sp = sp;
f.dp = dp;
f.protoctx = &ssn;
p.flow = &f;
tcph.th_win = htons(5480);
tcph.th_seq = htonl(10);
tcph.th_ack = htonl(20);
tcph.th_flags = TH_ACK|TH_PUSH;
p.tcph = &tcph;
p.flowflags = FLOW_PKT_TOCLIENT;
p.payload = httpbuf1;
p.payload_len = httplen1;
ssn.state = TCP_ESTABLISHED;
ssn.server.reassembly_depth = 1048530;
TcpStream *s = NULL;
s = &ssn.server;
if (StreamTcpReassembleHandleSegment(ra_ctx, &ssn, s, &p) == -1) {
printf("failed in segments reassembly, while processing toclient packet\n");
goto end;
}
/* Check if we have flags set or not */
if ((ssn.flags & STREAMTCP_FLAG_NOCLIENT_REASSEMBLY) ||
(ssn.flags & STREAMTCP_FLAG_NOSERVER_REASSEMBLY)) {
printf("there shouldn't be any no reassembly flag be set \n");
goto end;
}
p.flowflags = FLOW_PKT_TOSERVER;
p.payload_len = httplen1;
s = &ssn.client;
if (StreamTcpReassembleHandleSegment(ra_ctx, &ssn, s, &p) == -1) {
printf("failed in segments reassembly, while processing toserver packet\n");
goto end;
}
/* Check if we have flags set or not */
if ((ssn.flags & STREAMTCP_FLAG_NOCLIENT_REASSEMBLY) ||
(ssn.flags & STREAMTCP_FLAG_NOSERVER_REASSEMBLY)) {
printf("there shouldn't be any no reassembly flag be set \n");
goto end;
}
p.flowflags = FLOW_PKT_TOCLIENT;
p.payload_len = httplen1;
s = &ssn.server;
if (StreamTcpReassembleHandleSegment(ra_ctx, &ssn, s, &p) == -1) {
printf("failed in segments reassembly, while processing toserver packet\n");
goto end;
}
/* Check if we have flags set or not */
if ((ssn.flags & STREAMTCP_FLAG_NOCLIENT_REASSEMBLY) ||
(ssn.flags & STREAMTCP_FLAG_NOSERVER_REASSEMBLY)) {
printf("the no_reassembly flags should not be set, server.reassembly_depth "
"%"PRIu32" and p.payload_len %"PRIu16" stream_config.reassembly_"
"depth %"PRIu32"\n", ssn.server.reassembly_depth, p.payload_len,
stream_config.reassembly_depth);
goto end;
}
ret = 1;
end:
StreamTcpFreeConfig(TRUE);
StreamTcpReassembleFreeThreadCtx(ra_ctx);
return ret;
}
#endif /* UNITTESTS */ #endif /* UNITTESTS */
/** \brief The Function Register the Unit tests to test the reassembly engine /** \brief The Function Register the Unit tests to test the reassembly engine
@ -5626,5 +5918,7 @@ void StreamTcpReassembleRegisterTests(void) {
UtRegisterTest("StreamTcpReassembleTest42 -- pause/unpause reassembly test", StreamTcpReassembleTest42, 1); UtRegisterTest("StreamTcpReassembleTest42 -- pause/unpause reassembly test", StreamTcpReassembleTest42, 1);
UtRegisterTest("StreamTcpReassembleTest43 -- min smsg size test", StreamTcpReassembleTest43, 1); UtRegisterTest("StreamTcpReassembleTest43 -- min smsg size test", StreamTcpReassembleTest43, 1);
UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test", StreamTcpReassembleTest44, 1); UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test", StreamTcpReassembleTest44, 1);
UtRegisterTest("StreamTcpReassembleTest45 -- Depth Test", StreamTcpReassembleTest45, 1);
UtRegisterTest("StreamTcpReassembleTest46 -- Depth Test", StreamTcpReassembleTest46, 1);
#endif /* UNITTESTS */ #endif /* UNITTESTS */
} }

@ -389,6 +389,12 @@ void StreamTcpInitConfig(char quiet)
stream_config.reassembly_memcap = STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP; stream_config.reassembly_memcap = STREAMTCP_DEFAULT_REASSEMBLY_MEMCAP;
} }
if ((ConfGetInt("stream.reassembly.depth", &value)) == 1) {
stream_config.reassembly_depth = (uint32_t)value;
} else {
stream_config.reassembly_depth = 0;
}
if (!quiet) { if (!quiet) {
SCLogInfo("stream \"memcap\": %"PRIu32"", stream_config.memcap); SCLogInfo("stream \"memcap\": %"PRIu32"", stream_config.memcap);
} }

@ -43,6 +43,7 @@ typedef struct TcpStreamCnf_ {
int midstream; int midstream;
int async_oneside; int async_oneside;
uint32_t reassembly_memcap; /**< max memory usage for stream reassembly */ uint32_t reassembly_memcap; /**< max memory usage for stream reassembly */
uint32_t reassembly_depth; /**< Depth until when we reassemble the stream */
} TcpStreamCnf; } TcpStreamCnf;
TcpStreamCnf stream_config; TcpStreamCnf stream_config;

@ -239,6 +239,7 @@ flow-timeouts:
# memcap: 33554432 # 32mb memcap # memcap: 33554432 # 32mb memcap
# reassembly: # reassembly:
# memcap: 67108864 # 64mb reassembly memcap # memcap: 67108864 # 64mb reassembly memcap
# depth: 1048576 # 1 MB reassembly depth
# max_sessions: 262144 # 256k concurrent sessions # max_sessions: 262144 # 256k concurrent sessions
# prealloc_sessions: 32768 # 32k sessions prealloc'd # prealloc_sessions: 32768 # 32k sessions prealloc'd
# midstream: false # don't allow midstream session pickups # midstream: false # don't allow midstream session pickups
@ -247,6 +248,7 @@ stream:
memcap: 33554432 memcap: 33554432
reassembly: reassembly:
memcap: 67108864 memcap: 67108864
depth: 1048576
# Logging configuration. This is not about logging IDS alerts, but # Logging configuration. This is not about logging IDS alerts, but
# IDS output about what its doing, errors, etc. # IDS output about what its doing, errors, etc.

Loading…
Cancel
Save