Add tcp reassembly
This commit is contained in:
4
deps/dablooms/CMakeLists.txt
vendored
4
deps/dablooms/CMakeLists.txt
vendored
@@ -1,7 +1,3 @@
|
|||||||
###############################################################################
|
|
||||||
# dablooms
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
add_library(dablooms dablooms.cpp murmur.cpp)
|
add_library(dablooms dablooms.cpp murmur.cpp)
|
||||||
target_include_directories(dablooms PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
target_include_directories(dablooms PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
||||||
target_link_libraries(dablooms)
|
target_link_libraries(dablooms)
|
||||||
|
|||||||
3
deps/interval_tree/itree.cpp
vendored
3
deps/interval_tree/itree.cpp
vendored
@@ -399,8 +399,7 @@ int itree_remove(itree_t *tree, interval_t *interval)
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// else if (interval_equal(it->interval, interval))
|
else if (interval_equal(it->interval, interval))
|
||||||
else if (it->interval->low >= interval->low && it->interval->high <= interval->high)
|
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
2
deps/interval_tree/itree.h
vendored
2
deps/interval_tree/itree.h
vendored
@@ -54,11 +54,9 @@ typedef void (*rel_f)(void *p);
|
|||||||
/* Interval tree functions */
|
/* Interval tree functions */
|
||||||
itree_t *itree_new(dup_f dup, rel_f rel);
|
itree_t *itree_new(dup_f dup, rel_f rel);
|
||||||
void itree_delete(itree_t *tree);
|
void itree_delete(itree_t *tree);
|
||||||
// Find the first interval containing the specified interval
|
|
||||||
interval_t *itree_find(itree_t *tree, interval_t *interval);
|
interval_t *itree_find(itree_t *tree, interval_t *interval);
|
||||||
ilist_t *itree_findall(itree_t *tree, interval_t *interval);
|
ilist_t *itree_findall(itree_t *tree, interval_t *interval);
|
||||||
int itree_insert(itree_t *tree, interval_t *interval);
|
int itree_insert(itree_t *tree, interval_t *interval);
|
||||||
// Delete the first interval contained by the specified interval
|
|
||||||
int itree_remove(itree_t *tree, interval_t *interval);
|
int itree_remove(itree_t *tree, interval_t *interval);
|
||||||
size_t itree_size(itree_t *tree);
|
size_t itree_size(itree_t *tree);
|
||||||
|
|
||||||
|
|||||||
50
deps/interval_tree/test/gtest_interval_tree.cpp
vendored
50
deps/interval_tree/test/gtest_interval_tree.cpp
vendored
@@ -113,7 +113,7 @@ TEST(INTERVAL_TREE, FIND)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
TEST(INTERVAL_TREE, DELETE1)
|
TEST(INTERVAL_TREE, DELETE)
|
||||||
{
|
{
|
||||||
itree_t *tree;
|
itree_t *tree;
|
||||||
interval_t query;
|
interval_t query;
|
||||||
@@ -149,60 +149,18 @@ TEST(INTERVAL_TREE, DELETE1)
|
|||||||
EXPECT_TRUE(itree_remove(tree, &query) == 0);
|
EXPECT_TRUE(itree_remove(tree, &query) == 0);
|
||||||
EXPECT_TRUE(itree_size(tree) == 1);
|
EXPECT_TRUE(itree_size(tree) == 1);
|
||||||
|
|
||||||
// delete
|
|
||||||
query = {
|
|
||||||
.low = 5,
|
|
||||||
.high = 9,
|
|
||||||
};
|
|
||||||
EXPECT_TRUE(itree_remove(tree, &query) == 1);
|
|
||||||
EXPECT_TRUE(itree_size(tree) == 0);
|
|
||||||
|
|
||||||
itree_delete(tree);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
TEST(INTERVAL_TREE, DELETE2)
|
|
||||||
{
|
|
||||||
itree_t *tree;
|
|
||||||
interval_t query;
|
|
||||||
interval_t segment;
|
|
||||||
|
|
||||||
// new
|
|
||||||
tree = itree_new(my_dup, my_rel);
|
|
||||||
EXPECT_TRUE(tree != nullptr);
|
|
||||||
EXPECT_TRUE(itree_size(tree) == 0);
|
|
||||||
|
|
||||||
// insert
|
|
||||||
segment = {
|
|
||||||
.low = 5,
|
|
||||||
.high = 9,
|
|
||||||
.data = (void *)"Hello",
|
|
||||||
};
|
|
||||||
EXPECT_TRUE(itree_insert(tree, &segment) == 1);
|
|
||||||
EXPECT_TRUE(itree_size(tree) == 1);
|
|
||||||
|
|
||||||
// insert
|
|
||||||
segment = {
|
|
||||||
.low = 15,
|
|
||||||
.high = 19,
|
|
||||||
.data = (void *)"World",
|
|
||||||
};
|
|
||||||
EXPECT_TRUE(itree_insert(tree, &segment) == 1);
|
|
||||||
EXPECT_TRUE(itree_size(tree) == 2);
|
|
||||||
|
|
||||||
// delete
|
// delete
|
||||||
query = {
|
query = {
|
||||||
.low = 1,
|
.low = 1,
|
||||||
.high = 20,
|
.high = 20,
|
||||||
};
|
};
|
||||||
EXPECT_TRUE(itree_remove(tree, &query) == 1);
|
EXPECT_TRUE(itree_remove(tree, &query) == 0);
|
||||||
EXPECT_TRUE(itree_size(tree) == 1);
|
EXPECT_TRUE(itree_size(tree) == 1);
|
||||||
|
|
||||||
// delete
|
// delete
|
||||||
query = {
|
query = {
|
||||||
.low = 1,
|
.low = 5,
|
||||||
.high = 20,
|
.high = 9,
|
||||||
};
|
};
|
||||||
EXPECT_TRUE(itree_remove(tree, &query) == 1);
|
EXPECT_TRUE(itree_remove(tree, &query) == 1);
|
||||||
EXPECT_TRUE(itree_size(tree) == 0);
|
EXPECT_TRUE(itree_size(tree) == 0);
|
||||||
|
|||||||
4
deps/toml/CMakeLists.txt
vendored
4
deps/toml/CMakeLists.txt
vendored
@@ -1,7 +1,3 @@
|
|||||||
###############################################################################
|
|
||||||
# toml
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
add_library(toml toml.cpp)
|
add_library(toml toml.cpp)
|
||||||
target_include_directories(toml PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
target_include_directories(toml PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
||||||
target_link_libraries(toml)
|
target_link_libraries(toml)
|
||||||
@@ -6,6 +6,7 @@ add_subdirectory(packet)
|
|||||||
add_subdirectory(packet_io)
|
add_subdirectory(packet_io)
|
||||||
add_subdirectory(id_generator)
|
add_subdirectory(id_generator)
|
||||||
add_subdirectory(ip_reassembly)
|
add_subdirectory(ip_reassembly)
|
||||||
|
add_subdirectory(tcp_reassembly)
|
||||||
add_subdirectory(duplicated_packet_filter)
|
add_subdirectory(duplicated_packet_filter)
|
||||||
add_subdirectory(evicted_session_filter)
|
add_subdirectory(evicted_session_filter)
|
||||||
add_subdirectory(session)
|
add_subdirectory(session)
|
||||||
|
|||||||
@@ -236,6 +236,7 @@ static void *main_loop(void *arg)
|
|||||||
plugin_manager_free_ctx(plug_mgr_ctx);
|
plugin_manager_free_ctx(plug_mgr_ctx);
|
||||||
session_manager_free_session(sess_mgr, expired_sess);
|
session_manager_free_session(sess_mgr, expired_sess);
|
||||||
}
|
}
|
||||||
|
ip_reassembly_expire(ip_reass, now);
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// plugin_manager_cron();
|
// plugin_manager_cron();
|
||||||
|
|||||||
5
src/tcp_reassembly/CMakeLists.txt
Normal file
5
src/tcp_reassembly/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
add_library(tcp_reassembly tcp_reassembly.cpp)
|
||||||
|
target_include_directories(tcp_reassembly PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
target_link_libraries(tcp_reassembly interval_tree log)
|
||||||
|
|
||||||
|
add_subdirectory(test)
|
||||||
350
src/tcp_reassembly/tcp_reassembly.cpp
Normal file
350
src/tcp_reassembly/tcp_reassembly.cpp
Normal file
@@ -0,0 +1,350 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "tcp_reassembly.h"
|
||||||
|
#include "itree.h"
|
||||||
|
|
||||||
|
struct tcp_reassembly
|
||||||
|
{
|
||||||
|
// config
|
||||||
|
bool enable;
|
||||||
|
uint32_t max_timeout;
|
||||||
|
uint32_t max_packets;
|
||||||
|
uint32_t max_bytes;
|
||||||
|
|
||||||
|
// stat
|
||||||
|
struct tcp_reassembly_stat stat;
|
||||||
|
|
||||||
|
// runtime
|
||||||
|
struct itree *c2s_itree;
|
||||||
|
struct itree *s2c_itree;
|
||||||
|
uint64_t c2s_exp_seq;
|
||||||
|
uint64_t s2c_exp_seq;
|
||||||
|
|
||||||
|
// used for timeout
|
||||||
|
struct segment *head; // del segment from head
|
||||||
|
struct segment *tail; // add segment to tail
|
||||||
|
};
|
||||||
|
|
||||||
|
struct segment
|
||||||
|
{
|
||||||
|
struct tcp_reassembly *assembler;
|
||||||
|
struct itree *itree;
|
||||||
|
struct segment *next;
|
||||||
|
struct segment *prev;
|
||||||
|
|
||||||
|
uint64_t time;
|
||||||
|
uint32_t offset;
|
||||||
|
uint32_t len;
|
||||||
|
char *payload; // Flexible array member
|
||||||
|
};
|
||||||
|
|
||||||
|
void *segment_dup(void *p)
|
||||||
|
{
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void segment_rel(void *p)
|
||||||
|
{
|
||||||
|
struct segment *seg = (struct segment *)p;
|
||||||
|
if (seg)
|
||||||
|
{
|
||||||
|
struct tcp_reassembly *assembler = seg->assembler;
|
||||||
|
// delete from list
|
||||||
|
if (assembler->head == seg)
|
||||||
|
{
|
||||||
|
assembler->head = seg->next;
|
||||||
|
}
|
||||||
|
if (assembler->tail == seg)
|
||||||
|
{
|
||||||
|
assembler->tail = seg->prev;
|
||||||
|
}
|
||||||
|
if (seg->prev)
|
||||||
|
{
|
||||||
|
seg->prev->next = seg->next;
|
||||||
|
}
|
||||||
|
if (seg->next)
|
||||||
|
{
|
||||||
|
seg->next->prev = seg->prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
assembler->stat.bytes -= seg->len;
|
||||||
|
assembler->stat.packets--;
|
||||||
|
|
||||||
|
free(seg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tcp_reassembly *tcp_reassembly_new(bool enable, uint32_t max_timeout, uint32_t max_packets, uint32_t max_bytes)
|
||||||
|
{
|
||||||
|
struct tcp_reassembly *assembler = (struct tcp_reassembly *)calloc(1, sizeof(struct tcp_reassembly));
|
||||||
|
if (assembler == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
assembler->enable = enable;
|
||||||
|
assembler->max_timeout = max_timeout;
|
||||||
|
assembler->max_packets = max_packets;
|
||||||
|
assembler->max_bytes = max_bytes;
|
||||||
|
if (!assembler->enable)
|
||||||
|
{
|
||||||
|
return assembler;
|
||||||
|
}
|
||||||
|
|
||||||
|
assembler->c2s_itree = itree_new(segment_dup, segment_rel);
|
||||||
|
assembler->s2c_itree = itree_new(segment_dup, segment_rel);
|
||||||
|
if (assembler->c2s_itree == NULL || assembler->s2c_itree == NULL)
|
||||||
|
{
|
||||||
|
goto error_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
return assembler;
|
||||||
|
|
||||||
|
error_out:
|
||||||
|
tcp_reassembly_free(assembler);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcp_reassembly_init(struct tcp_reassembly *assembler, uint32_t c2s_init_seq, uint32_t s2c_init_seq)
|
||||||
|
{
|
||||||
|
if (!assembler->enable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c2s_init_seq)
|
||||||
|
{
|
||||||
|
assembler->c2s_exp_seq = c2s_init_seq + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s2c_init_seq)
|
||||||
|
{
|
||||||
|
assembler->s2c_exp_seq = s2c_init_seq + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcp_reassembly_free(struct tcp_reassembly *assembler)
|
||||||
|
{
|
||||||
|
if (assembler)
|
||||||
|
{
|
||||||
|
if (assembler->c2s_itree)
|
||||||
|
{
|
||||||
|
itree_delete(assembler->c2s_itree);
|
||||||
|
}
|
||||||
|
if (assembler->s2c_itree)
|
||||||
|
{
|
||||||
|
itree_delete(assembler->s2c_itree);
|
||||||
|
}
|
||||||
|
free(assembler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcp_reassembly_expire(struct tcp_reassembly *assembler, uint64_t now)
|
||||||
|
{
|
||||||
|
if (!assembler->enable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tcp_reassembly_stat *stat = &assembler->stat;
|
||||||
|
while (assembler->head)
|
||||||
|
{
|
||||||
|
struct segment *seg = assembler->head;
|
||||||
|
if (now - seg->time < assembler->max_timeout)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
stat->tcp_segement_timout++;
|
||||||
|
|
||||||
|
struct itree *itree = seg->itree;
|
||||||
|
interval_t interval = {
|
||||||
|
.low = seg->offset,
|
||||||
|
.high = seg->offset + seg->len - 1,
|
||||||
|
};
|
||||||
|
itree_remove(itree, &interval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcp_reassembly_update(struct tcp_reassembly *assembler, int direction, uint32_t offset, const char *payload, uint32_t len, uint64_t now)
|
||||||
|
{
|
||||||
|
if (!assembler->enable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct itree *itree = (direction == 0x01) ? assembler->c2s_itree : assembler->s2c_itree;
|
||||||
|
uint64_t exp_seq = (direction == 0x01) ? assembler->c2s_exp_seq : assembler->s2c_exp_seq;
|
||||||
|
|
||||||
|
if (len == 0 || offset + len < exp_seq)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assembler->max_packets > 0 && assembler->stat.packets >= assembler->max_packets)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assembler->max_bytes > 0 && assembler->stat.bytes >= assembler->max_bytes)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct segment *seg = (struct segment *)calloc(1, sizeof(struct segment) + len);
|
||||||
|
if (seg == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
seg->itree = itree;
|
||||||
|
seg->assembler = assembler;
|
||||||
|
seg->time = now;
|
||||||
|
seg->offset = offset;
|
||||||
|
seg->len = len;
|
||||||
|
seg->payload = (char *)seg + sizeof(struct segment);
|
||||||
|
memcpy(seg->payload, payload, len);
|
||||||
|
|
||||||
|
interval_t interval = {
|
||||||
|
.low = seg->offset,
|
||||||
|
.high = seg->offset + seg->len - 1,
|
||||||
|
.data = seg,
|
||||||
|
};
|
||||||
|
if (itree_insert(itree, &interval) == 0)
|
||||||
|
{
|
||||||
|
free(seg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TCP_REASSEMBLE_DEBUG("%s insert [%lu, %lu], segment {ptr: %p, offset: %lu, len: %lu}",
|
||||||
|
(direction == 0x01) ? "C2S" : "S2C",
|
||||||
|
seg->offset, seg->offset + seg->len - 1,
|
||||||
|
seg, seg->offset, seg->len);
|
||||||
|
|
||||||
|
if (assembler->head == NULL)
|
||||||
|
{
|
||||||
|
assembler->head = seg;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assembler->tail->next = seg;
|
||||||
|
seg->prev = assembler->tail;
|
||||||
|
}
|
||||||
|
assembler->tail = seg;
|
||||||
|
|
||||||
|
assembler->stat.packets++;
|
||||||
|
assembler->stat.bytes += len;
|
||||||
|
|
||||||
|
tcp_reassembly_expire(assembler, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *tcp_reassembly_peek(struct tcp_reassembly *assembler, int direction, uint32_t *len)
|
||||||
|
{
|
||||||
|
*len = 0;
|
||||||
|
|
||||||
|
if (!assembler->enable)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct itree *itree = (direction == 0x01) ? assembler->c2s_itree : assembler->s2c_itree;
|
||||||
|
uint64_t exp_seq = (direction == 0x01) ? assembler->c2s_exp_seq : assembler->s2c_exp_seq;
|
||||||
|
|
||||||
|
interval_t interval = {
|
||||||
|
.low = exp_seq,
|
||||||
|
.high = exp_seq,
|
||||||
|
};
|
||||||
|
interval_t *result = itree_find(itree, &interval);
|
||||||
|
if (result == NULL)
|
||||||
|
{
|
||||||
|
TCP_REASSEMBLE_DEBUG("%s peek [%lu, +∞]: not found", (direction == 0x01) ? "C2S" : "S2C", exp_seq);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct segment *seg = (struct segment *)result->data;
|
||||||
|
assert(seg != NULL);
|
||||||
|
// check overlap
|
||||||
|
if (seg->offset < exp_seq)
|
||||||
|
{
|
||||||
|
TCP_REASSEMBLE_DEBUG("%s peek [%lu, +∞], found [%lu, %lu], segment {ptr: %p, offset: %lu, len: %lu, left trim: %lu}",
|
||||||
|
(direction == 0x01) ? "C2S" : "S2C", exp_seq,
|
||||||
|
seg->offset, seg->offset + seg->len - 1,
|
||||||
|
seg, seg->offset, seg->len, exp_seq - seg->offset);
|
||||||
|
*len = seg->len - (exp_seq - seg->offset);
|
||||||
|
return seg->payload + (exp_seq - seg->offset);
|
||||||
|
}
|
||||||
|
TCP_REASSEMBLE_DEBUG("%s peek [%lu, +∞], found [%lu, %lu], segment {ptr: %p, offset: %lu, len: %lu}",
|
||||||
|
(direction == 0x01) ? "C2S" : "S2C", exp_seq,
|
||||||
|
seg->offset, seg->offset + seg->len - 1,
|
||||||
|
seg, seg->offset, seg->len);
|
||||||
|
|
||||||
|
*len = seg->len;
|
||||||
|
return seg->payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tcp_reassembly_consume(struct tcp_reassembly *assembler, int direction, uint32_t len)
|
||||||
|
{
|
||||||
|
if (!assembler->enable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct itree *itree = (direction == 0x01) ? assembler->c2s_itree : assembler->s2c_itree;
|
||||||
|
uint64_t *exp_seq = (direction == 0x01) ? &assembler->c2s_exp_seq : &assembler->s2c_exp_seq;
|
||||||
|
uint64_t old_exp_seq = *exp_seq;
|
||||||
|
|
||||||
|
*exp_seq += len;
|
||||||
|
uint64_t new_exp_seq = *exp_seq;
|
||||||
|
|
||||||
|
TCP_REASSEMBLE_DEBUG("%s consume [%lu, %lu], update expect seq %lu -> %lu",
|
||||||
|
(direction == 0x01) ? "C2S" : "S2C",
|
||||||
|
old_exp_seq, new_exp_seq - 1, old_exp_seq, new_exp_seq);
|
||||||
|
|
||||||
|
interval_t interval = {
|
||||||
|
.low = 0,
|
||||||
|
.high = *exp_seq,
|
||||||
|
};
|
||||||
|
|
||||||
|
ilist_t *list = itree_findall(itree, &interval);
|
||||||
|
if (list == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
interval_t *result;
|
||||||
|
int count = ilist_size(list);
|
||||||
|
ilisttrav_t *trav = ilisttrav_new(list);
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
result = (interval_t *)ilisttrav_first(trav);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = (interval_t *)ilisttrav_next(trav);
|
||||||
|
}
|
||||||
|
if (result && result->high < *exp_seq)
|
||||||
|
{
|
||||||
|
struct segment *seg = (struct segment *)result->data;
|
||||||
|
TCP_REASSEMBLE_DEBUG("%s consume [%lu, %lu], delete [%lu, %lu], segment {ptr: %p, offset: %lu, len: %lu}",
|
||||||
|
(direction == 0x01) ? "C2S" : "S2C", old_exp_seq, new_exp_seq - 1,
|
||||||
|
result->low, result->high, seg, seg->offset, seg->len);
|
||||||
|
itree_remove(itree, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ilisttrav_delete(trav);
|
||||||
|
ilist_delete(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tcp_reassembly_stat *tcp_reassembly_get_stat(struct tcp_reassembly *assembler)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
45
src/tcp_reassembly/tcp_reassembly.h
Normal file
45
src/tcp_reassembly/tcp_reassembly.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#ifndef _TCP_REASSEMBLY_H
|
||||||
|
#define _TCP_REASSEMBLY_H
|
||||||
|
|
||||||
|
#ifdef __cpluscplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define TCP_REASSEMBLE_DEBUG(format, ...) LOG_DEBUG("tcp_reassembly", format, ##__VA_ARGS__)
|
||||||
|
#define TCP_REASSEMBLE_ERROR(format, ...) LOG_ERROR("tcp_reassembly", format, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
struct tcp_reassembly_stat
|
||||||
|
{
|
||||||
|
uint64_t packets; // current packets
|
||||||
|
uint64_t bytes; // current bytes
|
||||||
|
|
||||||
|
uint64_t tcp_segement_timout; // total tcp segment timeout
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If retransmission or overlap occurs, the old data packet may have been consumed by the upper-layer plug-in,
|
||||||
|
* so the old data packet takes priority and the new data packet will be bypassed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct tcp_reassembly *tcp_reassembly_new(bool enable, uint32_t max_timeout, uint32_t max_packets, uint32_t max_bytes);
|
||||||
|
void tcp_reassembly_init(struct tcp_reassembly *assembler, uint32_t c2s_init_seq, uint32_t s2c_init_seq);
|
||||||
|
void tcp_reassembly_free(struct tcp_reassembly *assembler);
|
||||||
|
void tcp_reassembly_expire(struct tcp_reassembly *assembler, uint64_t now);
|
||||||
|
|
||||||
|
// direction: 1 C2S; 2: S2C
|
||||||
|
void tcp_reassembly_update(struct tcp_reassembly *assembler, int direction, uint32_t offset, const char *payload, uint32_t len, uint64_t now);
|
||||||
|
const char *tcp_reassembly_peek(struct tcp_reassembly *assembler, int direction, uint32_t *len);
|
||||||
|
void tcp_reassembly_consume(struct tcp_reassembly *assembler, int direction, uint32_t len);
|
||||||
|
|
||||||
|
struct tcp_reassembly_stat *tcp_reassembly_get_stat(struct tcp_reassembly *assembler);
|
||||||
|
|
||||||
|
#ifdef __cpluscplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
5
src/tcp_reassembly/test/CMakeLists.txt
Normal file
5
src/tcp_reassembly/test/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
add_executable(gtest_tcp_reassembly gtest_tcp_reassembly.cpp)
|
||||||
|
target_link_libraries(gtest_tcp_reassembly tcp_reassembly gtest)
|
||||||
|
|
||||||
|
include(GoogleTest)
|
||||||
|
gtest_discover_tests(gtest_tcp_reassembly)
|
||||||
302
src/tcp_reassembly/test/gtest_tcp_reassembly.cpp
Normal file
302
src/tcp_reassembly/test/gtest_tcp_reassembly.cpp
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "tcp_reassembly.h"
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
const char *session_peek_tcp_payload(struct session *session, uint32_t *len)
|
||||||
|
{
|
||||||
|
struct session_dir *dir = session_get_cur_dir(session);
|
||||||
|
struct tcp_reassembly *assembler = session_get_tcp_reassembly(session);
|
||||||
|
return tcp_reassembly_peek(assembler, dir, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void session_consume_tcp_payload(struct session *session, uint32_t len)
|
||||||
|
{
|
||||||
|
struct session_dir *dir = session_get_cur_dir(session);
|
||||||
|
struct tcp_reassembly *assembler = session_get_tcp_reassembly(session);
|
||||||
|
tcp_reassembly_consume(assembler, dir, len);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
TEST(TCP_REASSEMBLY, TEST_C2S)
|
||||||
|
{
|
||||||
|
uint32_t len;
|
||||||
|
int dir = 1;
|
||||||
|
const char *ptr;
|
||||||
|
struct tcp_reassembly *assembler;
|
||||||
|
|
||||||
|
assembler = tcp_reassembly_new(1, 10, 16, 1500);
|
||||||
|
EXPECT_TRUE(assembler != NULL);
|
||||||
|
|
||||||
|
tcp_reassembly_init(assembler, 99, 199);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* |0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|A|B|C|D|E|F|G|H|I|J|
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | | |
|
||||||
|
* +---> 90 +---> 100 +---> 110
|
||||||
|
*/
|
||||||
|
|
||||||
|
// C2S
|
||||||
|
tcp_reassembly_update(assembler, dir, 90, (const char *)"0123456789", 10, 0);
|
||||||
|
tcp_reassembly_update(assembler, dir, 100, (const char *)"abcdefghij", 10, 0);
|
||||||
|
tcp_reassembly_update(assembler, dir, 110, (const char *)"ABCDEFGHIJ", 10, 0);
|
||||||
|
|
||||||
|
ptr = tcp_reassembly_peek(assembler, dir, &len);
|
||||||
|
EXPECT_TRUE(ptr != NULL);
|
||||||
|
EXPECT_TRUE(len == 10);
|
||||||
|
EXPECT_TRUE(memcmp(ptr, "abcdefghij", len) == 0);
|
||||||
|
|
||||||
|
ptr = tcp_reassembly_peek(assembler, dir, &len);
|
||||||
|
EXPECT_TRUE(ptr != NULL);
|
||||||
|
EXPECT_TRUE(len == 10);
|
||||||
|
EXPECT_TRUE(memcmp(ptr, "abcdefghij", len) == 0);
|
||||||
|
tcp_reassembly_consume(assembler, dir, len);
|
||||||
|
|
||||||
|
ptr = tcp_reassembly_peek(assembler, dir, &len);
|
||||||
|
EXPECT_TRUE(ptr != NULL);
|
||||||
|
EXPECT_TRUE(len == 10);
|
||||||
|
EXPECT_TRUE(memcmp(ptr, "ABCDEFGHIJ", len) == 0);
|
||||||
|
tcp_reassembly_consume(assembler, dir, len);
|
||||||
|
|
||||||
|
ptr = tcp_reassembly_peek(assembler, dir, &len);
|
||||||
|
EXPECT_TRUE(ptr == NULL);
|
||||||
|
|
||||||
|
tcp_reassembly_free(assembler);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
TEST(TCP_REASSEMBLY, TEST_S2C)
|
||||||
|
{
|
||||||
|
uint32_t len;
|
||||||
|
int dir = 2;
|
||||||
|
const char *ptr;
|
||||||
|
struct tcp_reassembly *assembler;
|
||||||
|
|
||||||
|
assembler = tcp_reassembly_new(1, 10, 16, 1500);
|
||||||
|
EXPECT_TRUE(assembler != NULL);
|
||||||
|
|
||||||
|
tcp_reassembly_init(assembler, 199, 99);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* |0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|A|B|C|D|E|F|G|H|I|J|
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | | |
|
||||||
|
* +---> 90 +---> 100 +---> 110
|
||||||
|
*/
|
||||||
|
|
||||||
|
// C2S
|
||||||
|
tcp_reassembly_update(assembler, dir, 90, (const char *)"0123456789", 10, 0);
|
||||||
|
tcp_reassembly_update(assembler, dir, 100, (const char *)"abcdefghij", 10, 0);
|
||||||
|
tcp_reassembly_update(assembler, dir, 110, (const char *)"ABCDEFGHIJ", 10, 0);
|
||||||
|
|
||||||
|
ptr = tcp_reassembly_peek(assembler, dir, &len);
|
||||||
|
EXPECT_TRUE(ptr != NULL);
|
||||||
|
EXPECT_TRUE(len == 10);
|
||||||
|
EXPECT_TRUE(memcmp(ptr, "abcdefghij", len) == 0);
|
||||||
|
|
||||||
|
ptr = tcp_reassembly_peek(assembler, dir, &len);
|
||||||
|
EXPECT_TRUE(ptr != NULL);
|
||||||
|
EXPECT_TRUE(len == 10);
|
||||||
|
EXPECT_TRUE(memcmp(ptr, "abcdefghij", len) == 0);
|
||||||
|
tcp_reassembly_consume(assembler, dir, len);
|
||||||
|
|
||||||
|
ptr = tcp_reassembly_peek(assembler, dir, &len);
|
||||||
|
EXPECT_TRUE(ptr != NULL);
|
||||||
|
EXPECT_TRUE(len == 10);
|
||||||
|
EXPECT_TRUE(memcmp(ptr, "ABCDEFGHIJ", len) == 0);
|
||||||
|
tcp_reassembly_consume(assembler, dir, len);
|
||||||
|
|
||||||
|
ptr = tcp_reassembly_peek(assembler, dir, &len);
|
||||||
|
EXPECT_TRUE(ptr == NULL);
|
||||||
|
|
||||||
|
tcp_reassembly_free(assembler);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
TEST(TCP_REASSEMBLY, REPEAT1)
|
||||||
|
{
|
||||||
|
uint32_t len;
|
||||||
|
int dir = 1;
|
||||||
|
const char *ptr;
|
||||||
|
struct tcp_reassembly *assembler;
|
||||||
|
|
||||||
|
assembler = tcp_reassembly_new(1, 10, 16, 1500);
|
||||||
|
EXPECT_TRUE(assembler != NULL);
|
||||||
|
|
||||||
|
tcp_reassembly_init(assembler, 99, 199);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* |0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | |A|B|C|D|E|F|G|H|I|J|
|
||||||
|
* | +-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | | |
|
||||||
|
* +---> 90 +---> 100 +---> 109
|
||||||
|
*/
|
||||||
|
|
||||||
|
// C2S
|
||||||
|
tcp_reassembly_update(assembler, dir, 90, (const char *)"0123456789", 10, 0);
|
||||||
|
tcp_reassembly_update(assembler, dir, 100, (const char *)"abcdefghij", 10, 0);
|
||||||
|
tcp_reassembly_update(assembler, dir, 100, (const char *)"ABCDEFGHIJ", 10, 0);
|
||||||
|
|
||||||
|
ptr = tcp_reassembly_peek(assembler, dir, &len);
|
||||||
|
EXPECT_TRUE(ptr != NULL);
|
||||||
|
EXPECT_TRUE(len == 10);
|
||||||
|
EXPECT_TRUE(memcmp(ptr, "abcdefghij", len) == 0);
|
||||||
|
tcp_reassembly_consume(assembler, dir, len);
|
||||||
|
|
||||||
|
ptr = tcp_reassembly_peek(assembler, dir, &len);
|
||||||
|
EXPECT_TRUE(ptr == NULL);
|
||||||
|
|
||||||
|
tcp_reassembly_free(assembler);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
TEST(TCP_REASSEMBLY, REPEAT2)
|
||||||
|
{
|
||||||
|
uint32_t len;
|
||||||
|
int dir = 1;
|
||||||
|
const char *ptr;
|
||||||
|
struct tcp_reassembly *assembler;
|
||||||
|
|
||||||
|
assembler = tcp_reassembly_new(1, 10, 16, 1500);
|
||||||
|
EXPECT_TRUE(assembler != NULL);
|
||||||
|
|
||||||
|
tcp_reassembly_init(assembler, 99, 199);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* |0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F|G|H|I|J|
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | |a|b|c|d|e|f|g|h|i|j|
|
||||||
|
* | +-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | | |
|
||||||
|
* +---> 90 +---> 100 +---> 109
|
||||||
|
*/
|
||||||
|
|
||||||
|
// C2S
|
||||||
|
|
||||||
|
tcp_reassembly_update(assembler, dir, 90, (const char *)"0123456789", 10, 0);
|
||||||
|
tcp_reassembly_update(assembler, dir, 100, (const char *)"ABCDEFGHIJ", 10, 0);
|
||||||
|
tcp_reassembly_update(assembler, dir, 100, (const char *)"abcdefghij", 10, 0);
|
||||||
|
|
||||||
|
ptr = tcp_reassembly_peek(assembler, dir, &len);
|
||||||
|
EXPECT_TRUE(ptr != NULL);
|
||||||
|
EXPECT_TRUE(len == 10);
|
||||||
|
EXPECT_TRUE(memcmp(ptr, "ABCDEFGHIJ", len) == 0);
|
||||||
|
tcp_reassembly_consume(assembler, dir, len);
|
||||||
|
|
||||||
|
ptr = tcp_reassembly_peek(assembler, dir, &len);
|
||||||
|
EXPECT_TRUE(ptr == NULL);
|
||||||
|
|
||||||
|
tcp_reassembly_free(assembler);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
TEST(TCP_REASSEMBLY, OVERLAP)
|
||||||
|
{
|
||||||
|
uint32_t len;
|
||||||
|
int dir = 1;
|
||||||
|
const char *ptr;
|
||||||
|
struct tcp_reassembly *assembler;
|
||||||
|
|
||||||
|
assembler = tcp_reassembly_new(1, 10, 16, 1500);
|
||||||
|
EXPECT_TRUE(assembler != NULL);
|
||||||
|
|
||||||
|
tcp_reassembly_init(assembler, 89, 199);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* |0|1|2|3|4|5|6|7|8|9|
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | +-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | |a|b|c|d|e|f|g|h|i|j|
|
||||||
|
* | +-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | | | +-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | | | |A|B|C|D|E|F|G|H|I|J|
|
||||||
|
* | | | +-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* | | | | | |
|
||||||
|
* | | | | | +---> 111
|
||||||
|
* | | | | +---> 105
|
||||||
|
* | | | +---> 102
|
||||||
|
* | | +---> 99
|
||||||
|
* | +---> 96
|
||||||
|
* +---> 90
|
||||||
|
*
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
* |0|1|2|3|4|5|6|7|8|9|e|f|g|h|i|j|E|F|G|H|I|J|
|
||||||
|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
*/
|
||||||
|
|
||||||
|
// C2S
|
||||||
|
tcp_reassembly_update(assembler, dir, 90, (const char *)"0123456789", 10, 0);
|
||||||
|
tcp_reassembly_update(assembler, dir, 96, (const char *)"abcdefghij", 10, 0);
|
||||||
|
tcp_reassembly_update(assembler, dir, 102, (const char *)"ABCDEFGHIJ", 10, 0);
|
||||||
|
|
||||||
|
ptr = tcp_reassembly_peek(assembler, dir, &len);
|
||||||
|
EXPECT_TRUE(ptr != NULL);
|
||||||
|
EXPECT_TRUE(len == 10);
|
||||||
|
EXPECT_TRUE(memcmp(ptr, "0123456789", len) == 0);
|
||||||
|
tcp_reassembly_consume(assembler, dir, len);
|
||||||
|
|
||||||
|
ptr = tcp_reassembly_peek(assembler, dir, &len);
|
||||||
|
EXPECT_TRUE(ptr != NULL);
|
||||||
|
EXPECT_TRUE(len == 6);
|
||||||
|
EXPECT_TRUE(memcmp(ptr, "efghij", len) == 0);
|
||||||
|
tcp_reassembly_consume(assembler, dir, len);
|
||||||
|
|
||||||
|
ptr = tcp_reassembly_peek(assembler, dir, &len);
|
||||||
|
EXPECT_TRUE(ptr != NULL);
|
||||||
|
EXPECT_TRUE(len == 6);
|
||||||
|
EXPECT_TRUE(memcmp(ptr, "EFGHIJ", len) == 0);
|
||||||
|
tcp_reassembly_consume(assembler, dir, len);
|
||||||
|
|
||||||
|
ptr = tcp_reassembly_peek(assembler, dir, &len);
|
||||||
|
EXPECT_TRUE(ptr == NULL);
|
||||||
|
|
||||||
|
tcp_reassembly_free(assembler);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
TEST(TCP_REASSEMBLY, MAX_TIMEOUT)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
TEST(TCP_REASSEMBLY, MAX_PACKETS)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
TEST(TCP_REASSEMBLY, MAX_BYTES)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
TEST(TCP_REASSEMBLY, SEQ_WRAPAROUND)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
@@ -1,7 +1,3 @@
|
|||||||
###############################################################################
|
|
||||||
# timestamp
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
add_library(timestamp timestamp.cpp)
|
add_library(timestamp timestamp.cpp)
|
||||||
target_include_directories(timestamp PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
target_include_directories(timestamp PUBLIC ${CMAKE_CURRENT_LIST_DIR})
|
||||||
target_link_libraries(timestamp)
|
target_link_libraries(timestamp)
|
||||||
|
|||||||
Reference in New Issue
Block a user