我們知道,libnids本身可以實現TCP數據流的重組,但是如果一個TCP流數據量比較大的時候,就會分成好多個TCP報文段,這些報文段在網絡中的傳播可能是亂序的,利用libnids可以幫助我們按順序接收到這些報文段,即實現TCP報文段的重組。
但是我們如何把這些順序的報文段重新還原成一個完整的數據文件,也是要考慮的一個問題,因爲在很多時候,單個的報文段對我們的意義不大,我們需要一個完整的數據,這樣才有助於我們進一步分析網絡中的數據內容。
下面的程序實現了基於libnids的TCP數據流的還原,我使用了多線程來控制數據的處理,主要的數據結構是一個帶頭結點的雙向鏈表隊列,隊列中的每個結點存儲一個完整的TCP數據流的內容,另外還有兩個元素,分別是指向前導和後續結點的結構體指針。結構體定義如下:
struct buf{
char *buffer;
struct buf *prev;
struct buf *next;
};
頭結點: struct buf *head;
多線程對該鏈表的操作:
向鏈表中放數據:void put_function(int size, char *data)
{
pthread_mutex_lock(&mutex);
meke_new_item(size, data);
buffer_has_item++;
pthread_mutex_unlock(&mutex);
sleep(1);
}
mutex爲互斥鎖,size爲data的大小,data爲完整的數據流,buffer_has_item爲當前鏈表中結點的數目。
從鏈表中去數據的操作:(這是一個線程函數,在執行pthread_create是創建)
void get_function(void)
{
while(1){
pthread_mutex_lock(&mutex);
if(buffer_has_item > 0){
consume_item();
buffer_has_item--;
}
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
創建新的節點並把它掛到隊列當中:
void make_new_item(int size, char *data)
{
struct buf *con;
if(!(con = (struct buf *)malloc(sizeof(struct buf)))){
assert("con malloc fail!");
}
if(!(con->buffer = (char *)malloc(size*sizeof(char)))){
assert("con buffer malloc fail!");
}
memset(con->buffer, 0, size*sizeof(char));
memcpy(con->buffer, data, size*sizeof(char));
con->prev = NULL;
con->next = NULL;
if(head->next == NULL){
head->next = con;
head->prev = con;
con->prev = head;
}else{
con->prev = head->prev;
head->prev->next = con;
head->prev = con;
con->next = NULL;
}
}
處理還原之後的數據:
void consume_item()
{
int k;
struct buf *p;
if(head->next){
printf("%s", head->next->buffer);
p = head->next;
if(head->next->next){
head->next = head->next->next;
head->next->preb = head;
}else{
head->next = NULL;
head->prev = NULL;
}
if(p){
free(p);
p = NULL;
}
}
}
鏈表初始化(可以把整個程序的初始化都放在這裏進行):
void init_dlink()
{
if(!(head = (struct buf *)malloc(sizeof(struct buf)))){
assert("head malloc fail!");
}
head->next = NULL;
head->prev = NULL;
}
head的定義是一個全局變量,struct buf *head;
在主函數當中,要創建線程,註冊libnids回調函數:
int main(int argc, char *argc[])
{
pthread_t thread;
init_dlink();
pthread_mutex_init(&mutex, NULL);
if(!nids_init())P{
assert("nids init fail!");
}
pthread_create(&thread, NULL, (void *)get_function, NULL);
nids_register_tcp(tcp_protocol_callback);
nids_tun();
return 0;
}
在回調函數當中,我們可以組織實現TCP數據流的還原,並把還原之後的數據添加到鏈表當中:
void tcp_protocol_callback(struct tcp_stream *tcp_connection, void **arg)
{
switch(tcp_connection->nids_state){
.....................
case NIDS_DATA:{
................
if(tcp_connection->client.count_new){
..............
put_function(sum_len, content);
}
}
}
}
至此,就完成了還原TCP數據流的多線程處理。