|
|
|
|
@ -61,6 +61,36 @@ static uint64_t segment_pool_memuse = 0;
|
|
|
|
|
static uint64_t segment_pool_memcnt = 0;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* We define several pools with prealloced segments with fixed size
|
|
|
|
|
* payloads. We do this to prevent having to do an SCMalloc call for every
|
|
|
|
|
* data segment we receive, which would be a large performance penalty.
|
|
|
|
|
* The cost is in memory of course. */
|
|
|
|
|
#define segment_pool_num 8
|
|
|
|
|
static uint16_t segment_pool_pktsizes[segment_pool_num] = {4, 16, 112, 248, 512,
|
|
|
|
|
768, 1448, 0xffff};
|
|
|
|
|
//static uint16_t segment_pool_poolsizes[segment_pool_num] = {2048, 3072, 3072,
|
|
|
|
|
// 3072, 3072, 8192,
|
|
|
|
|
// 8192, 512};
|
|
|
|
|
static uint16_t segment_pool_poolsizes[segment_pool_num] = {0, 0, 0,
|
|
|
|
|
0, 0, 0,
|
|
|
|
|
0, 0};
|
|
|
|
|
static uint16_t segment_pool_poolsizes_prealloc[segment_pool_num] = {256, 512, 512,
|
|
|
|
|
512, 512, 1024,
|
|
|
|
|
1024, 128};
|
|
|
|
|
static Pool *segment_pool[segment_pool_num];
|
|
|
|
|
static SCMutex segment_pool_mutex[segment_pool_num];
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
static SCMutex segment_pool_cnt_mutex;
|
|
|
|
|
static uint64_t segment_pool_cnt = 0;
|
|
|
|
|
#endif
|
|
|
|
|
/* index to the right pool for all packet sizes. */
|
|
|
|
|
static uint16_t segment_pool_idx[65536]; /* O(1) lookups of the pool */
|
|
|
|
|
|
|
|
|
|
/* Memory use counters */
|
|
|
|
|
static SCSpinlock stream_reassembly_memuse_spinlock;
|
|
|
|
|
static uint32_t stream_reassembly_memuse;
|
|
|
|
|
static uint32_t stream_reassembly_memuse_max;
|
|
|
|
|
|
|
|
|
|
/* prototypes */
|
|
|
|
|
static int HandleSegmentStartsBeforeListSegment(TcpStream *, TcpSegment *,
|
|
|
|
|
TcpSegment *);
|
|
|
|
|
@ -74,10 +104,70 @@ TcpSegment* StreamTcpGetSegment(uint16_t);
|
|
|
|
|
void StreamTcpSegmentReturntoPool(TcpSegment *);
|
|
|
|
|
void StreamTcpCreateTestPacket(uint8_t *, uint8_t, uint8_t, uint8_t);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Function to Increment the memory usage counter for the TCP reassembly
|
|
|
|
|
* segments
|
|
|
|
|
*
|
|
|
|
|
* \param size Size of the TCP segment and its payload length memory allocated
|
|
|
|
|
*/
|
|
|
|
|
void StreamTcpReassembleIncrMemuse(uint32_t size) {
|
|
|
|
|
|
|
|
|
|
SCSpinLock(&stream_reassembly_memuse_spinlock);
|
|
|
|
|
stream_reassembly_memuse += size;
|
|
|
|
|
|
|
|
|
|
if (stream_reassembly_memuse > stream_reassembly_memuse_max)
|
|
|
|
|
stream_reassembly_memuse_max = stream_reassembly_memuse;
|
|
|
|
|
|
|
|
|
|
SCSpinUnlock(&stream_reassembly_memuse_spinlock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Function to Decrease the memory usage counter for the TCP reassembly
|
|
|
|
|
* segments
|
|
|
|
|
*
|
|
|
|
|
* \param size Size of the TCP segment and its payload length memory allocated
|
|
|
|
|
*/
|
|
|
|
|
void StreamTcpReassembleDecrMemuse(uint32_t size) {
|
|
|
|
|
SCSpinLock(&stream_reassembly_memuse_spinlock);
|
|
|
|
|
|
|
|
|
|
if (size <= stream_reassembly_memuse) {
|
|
|
|
|
stream_reassembly_memuse -= size;
|
|
|
|
|
} else {
|
|
|
|
|
BUG_ON(size > stream_reassembly_memuse);
|
|
|
|
|
stream_reassembly_memuse = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCSpinUnlock(&stream_reassembly_memuse_spinlock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* \brief Function to Check the reassembly memory usage counter against the
|
|
|
|
|
* allowed max memory usgae for TCP segments.
|
|
|
|
|
*
|
|
|
|
|
* \param size Size of the TCP segment and its payload length memory allocated
|
|
|
|
|
* \retval 1 if in bounds
|
|
|
|
|
* \retval 0 if not in bounds
|
|
|
|
|
*/
|
|
|
|
|
int StreamTcpReassembleCheckMemcap(uint32_t size) {
|
|
|
|
|
SCEnter();
|
|
|
|
|
|
|
|
|
|
int ret = 0;
|
|
|
|
|
SCSpinLock(&stream_reassembly_memuse_spinlock);
|
|
|
|
|
if (size + stream_reassembly_memuse <= stream_config.reassembly_memcap)
|
|
|
|
|
ret = 1;
|
|
|
|
|
SCSpinUnlock(&stream_reassembly_memuse_spinlock);
|
|
|
|
|
|
|
|
|
|
SCReturnInt(ret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \brief alloc a tcp segment pool entry */
|
|
|
|
|
void *TcpSegmentPoolAlloc(void *payload_len) {
|
|
|
|
|
if (StreamTcpCheckMemcap((uint32_t)sizeof(TcpSegment) + *((uint16_t *) payload_len)) == 0)
|
|
|
|
|
if (StreamTcpReassembleCheckMemcap((uint32_t)sizeof(TcpSegment) +
|
|
|
|
|
*((uint16_t *) payload_len)) == 0)
|
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TcpSegment *seg = SCMalloc(sizeof (TcpSegment));
|
|
|
|
|
if (seg == NULL)
|
|
|
|
|
@ -102,7 +192,7 @@ void *TcpSegmentPoolAlloc(void *payload_len) {
|
|
|
|
|
SCMutexUnlock(&segment_pool_memuse_mutex);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
StreamTcpIncrMemuse((uint32_t)seg->pool_size + sizeof(TcpSegment));
|
|
|
|
|
StreamTcpReassembleIncrMemuse((uint32_t)seg->pool_size + sizeof(TcpSegment));
|
|
|
|
|
return seg;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -113,7 +203,7 @@ void TcpSegmentPoolFree(void *ptr) {
|
|
|
|
|
|
|
|
|
|
TcpSegment *seg = (TcpSegment *) ptr;
|
|
|
|
|
|
|
|
|
|
StreamTcpDecrMemuse((uint32_t)seg->pool_size + sizeof(TcpSegment));
|
|
|
|
|
StreamTcpReassembleDecrMemuse((uint32_t)seg->pool_size + sizeof(TcpSegment));
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
SCMutexLock(&segment_pool_memuse_mutex);
|
|
|
|
|
@ -128,34 +218,15 @@ void TcpSegmentPoolFree(void *ptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We define serveral pools with prealloced segments with fixed size
|
|
|
|
|
* payloads. We do this to prevent having to do an SCMalloc call for every
|
|
|
|
|
* data segment we receive, which would be a large performance penalty.
|
|
|
|
|
* The cost is in memory of course. */
|
|
|
|
|
#define segment_pool_num 8
|
|
|
|
|
static uint16_t segment_pool_pktsizes[segment_pool_num] = {4, 16, 112, 248, 512,
|
|
|
|
|
768, 1448, 0xffff};
|
|
|
|
|
//static uint16_t segment_pool_poolsizes[segment_pool_num] = {2048, 3072, 3072,
|
|
|
|
|
// 3072, 3072, 8192,
|
|
|
|
|
// 8192, 512};
|
|
|
|
|
static uint16_t segment_pool_poolsizes[segment_pool_num] = {0, 0, 0,
|
|
|
|
|
0, 0, 0,
|
|
|
|
|
0, 0};
|
|
|
|
|
static uint16_t segment_pool_poolsizes_prealloc[segment_pool_num] = {256, 512, 512,
|
|
|
|
|
512, 512, 1024,
|
|
|
|
|
1024, 128};
|
|
|
|
|
static Pool *segment_pool[segment_pool_num];
|
|
|
|
|
static SCMutex segment_pool_mutex[segment_pool_num];
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
static SCMutex segment_pool_cnt_mutex;
|
|
|
|
|
static uint64_t segment_pool_cnt = 0;
|
|
|
|
|
#endif
|
|
|
|
|
/* index to the right pool for all packet sizes. */
|
|
|
|
|
static uint16_t segment_pool_idx[65536]; /* O(1) lookups of the pool */
|
|
|
|
|
|
|
|
|
|
int StreamTcpReassembleInit(char quiet)
|
|
|
|
|
{
|
|
|
|
|
StreamMsgQueuesInit();
|
|
|
|
|
|
|
|
|
|
/* init the memcap and it's lock */
|
|
|
|
|
stream_reassembly_memuse = 0;
|
|
|
|
|
stream_reassembly_memuse_max = 0;
|
|
|
|
|
SCSpinInit(&stream_reassembly_memuse_spinlock, PTHREAD_PROCESS_PRIVATE);
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
SCMutexInit(&segment_pool_memuse_mutex, NULL);
|
|
|
|
|
#endif
|
|
|
|
|
@ -211,6 +282,14 @@ void StreamTcpReassembleFree(char quiet)
|
|
|
|
|
|
|
|
|
|
StreamMsgQueuesDeinit(quiet);
|
|
|
|
|
|
|
|
|
|
if (!quiet) {
|
|
|
|
|
SCLogInfo("Max memuse of the stream reassembly engine %"PRIu32" (in use"
|
|
|
|
|
" %"PRIu32")", stream_reassembly_memuse_max,
|
|
|
|
|
stream_reassembly_memuse);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCSpinDestroy(&stream_reassembly_memuse_spinlock);
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
SCLogDebug("segment_pool_cnt %"PRIu64"", segment_pool_cnt);
|
|
|
|
|
SCLogDebug("segment_pool_memuse %"PRIu64"", segment_pool_memuse);
|
|
|
|
|
@ -5448,6 +5527,49 @@ end:
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \test Test the memcap incrementing/decrementing and memcap check */
|
|
|
|
|
static int StreamTcpReassembleTest44(void)
|
|
|
|
|
{
|
|
|
|
|
uint8_t ret = 0;
|
|
|
|
|
StreamTcpInitConfig(TRUE);
|
|
|
|
|
uint32_t memuse = stream_reassembly_memuse;
|
|
|
|
|
|
|
|
|
|
StreamTcpReassembleIncrMemuse(500);
|
|
|
|
|
if (stream_reassembly_memuse != (memuse+500)) {
|
|
|
|
|
printf("failed in incrementing the memory");
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StreamTcpReassembleDecrMemuse(500);
|
|
|
|
|
if (stream_reassembly_memuse != memuse) {
|
|
|
|
|
printf("failed in decrementing the memory");
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (StreamTcpReassembleCheckMemcap(500) != 1) {
|
|
|
|
|
printf("failed in validating the memcap");
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (StreamTcpReassembleCheckMemcap((memuse + stream_config.reassembly_memcap)) != 0) {
|
|
|
|
|
printf("failed in validating the memcap");
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StreamTcpFreeConfig(TRUE);
|
|
|
|
|
|
|
|
|
|
if (stream_reassembly_memuse != 0) {
|
|
|
|
|
printf("failed in clearing the memory");
|
|
|
|
|
goto end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = 1;
|
|
|
|
|
return ret;
|
|
|
|
|
end:
|
|
|
|
|
StreamTcpFreeConfig(TRUE);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif /* UNITTESTS */
|
|
|
|
|
|
|
|
|
|
/** \brief The Function Register the Unit tests to test the reassembly engine
|
|
|
|
|
@ -5499,5 +5621,6 @@ void StreamTcpReassembleRegisterTests(void) {
|
|
|
|
|
UtRegisterTest("StreamTcpReassembleTest41 -- app proto test", StreamTcpReassembleTest41, 1);
|
|
|
|
|
UtRegisterTest("StreamTcpReassembleTest42 -- pause/unpause reassembly test", StreamTcpReassembleTest42, 1);
|
|
|
|
|
UtRegisterTest("StreamTcpReassembleTest43 -- min smsg size test", StreamTcpReassembleTest43, 1);
|
|
|
|
|
UtRegisterTest("StreamTcpReassembleTest44 -- Memcap Test", StreamTcpReassembleTest44, 1);
|
|
|
|
|
#endif /* UNITTESTS */
|
|
|
|
|
}
|
|
|
|
|
|