TCP会话重组Word下载.docx
- 文档编号:16348313
- 上传时间:2022-11-23
- 格式:DOCX
- 页数:27
- 大小:99.35KB
TCP会话重组Word下载.docx
《TCP会话重组Word下载.docx》由会员分享,可在线阅读,更多相关《TCP会话重组Word下载.docx(27页珍藏版)》请在冰豆网上搜索。
规则2:
TCP头中4元组<
syn、fin、seq、len>
,它应该是唯一的,不唯一说明存在重传情况。
在TCP/IP协议栈中,3层对应的是IP层,4层对应TCP层,在这里,从3层到4层转化主要做了两件重要的事情:
IP分片重组和TCP会话重组。
本篇先分析其中TCP会话重组的部分(自顶向下嘛,哈哈)。
OK,先看下重要的数据结构,在tcp.h中:
[cpp]viewplaincopyprint?
1.struct
skbuff
2.{
3.
//万年不变的next和prev,这向我们昭示了这是一个双向队列。
4.
//对于每个TCP会话(ip:
端口<
-
->
ip:
端口)都要维护两个skbuf队列(每个方向都有一个嘛)
5.
//每个skbuf对应网络上的一个IP包,TCP流就是一个接一个的IP包嘛。
6.
struct
*next;
7.
*prev;
8.
9.
void
*data;
10.
u_int
len;
11.
truesize;
12.
urg_ptr;
13.
14.
char
fin;
15.
urg;
16.
seq;
17.
ack;
18.};
structskbuff
{
//万年不变的next和prev,这向我们昭示了这是一个双向队列。
//对于每个TCP会话(ip:
-->
端口)都要维护两个skbuf队列(每个方向都有一个嘛)
//每个skbuf对应网络上的一个IP包,TCP流就是一个接一个的IP包嘛。
structskbuff*next;
structskbuff*prev;
void*data;
u_intlen;
u_inttruesize;
u_inturg_ptr;
charfin;
charurg;
u_intseq;
u_intack;
};
这个结构体就是模仿的内核中的sk_buff结构体,只不过比内核中的要小很多(你懂的,因为这里只做会话重组)。
下面是在nids.h中的
tuple4
u_short
source;
dest;
saddr;
daddr;
7.};
structtuple4
u_shortsource;
u_shortdest;
u_intsaddr;
u_intdaddr;
这是用来表示一个TCP连接的,不解释。
half_stream
state;
collect;
collect_urg;
//这里存放着已经按顺序集齐排列好的数据
int
offset;
count;
//这里存放data中数据的字节数
count_new;
//这里存放data中还没回调过的数据的字节数
bufsize;
rmem_alloc;
urg_count;
acked;
ack_seq;
18.
first_data_seq;
19.
u_char
urgdata;
20.
count_new_urg;
21.
urg_seen;
22.
23.
window;
24.
ts_on;
//tcp时间戳选项是否打开
25.
wscale_on;
//窗口扩展选项是否打开
26.
curr_ts;
27.
wscale;
28.
29.
//下面是ip包缓冲区
30.
*list;
31.
*listtail;
32.}
structhalf_stream
charstate;
charcollect;
charcollect_urg;
char*data;
//这里存放着已经按顺序集齐排列好的数据
intoffset;
intcount;
//这里存放data中数据的字节数
intcount_new;
//这里存放data中还没回调过的数据的字节数
intbufsize;
intrmem_alloc;
inturg_count;
u_intacked;
u_intack_seq;
u_intfirst_data_seq;
u_charurgdata;
u_charcount_new_urg;
u_charurg_seen;
u_shortwindow;
u_charts_on;
//tcp时间戳选项是否打开
u_charwscale_on;
//窗口扩展选项是否打开
u_intcurr_ts;
u_intwscale;
//下面是ip包缓冲区
structskbuff*list;
structskbuff*listtail;
}
这个是用来表示“半个TCP会话”,其实就是一个方向上的TCP流。
还有
tcp_stream
addr;
nids_state;
lurker_node
*listeners;
client;
server;
*next_node;
*prev_node;
hash_index;
*next_time;
*prev_time;
read;
*next_free;
*user;
16.};
structtcp_stream
structtuple4addr;
charnids_state;
structlurker_node*listeners;
structhalf_streamclient;
structhalf_streamserver;
structtcp_stream*next_node;
structtcp_stream*prev_node;
inthash_index;
structtcp_stream*next_time;
structtcp_stream*prev_time;
intread;
structtcp_stream*next_free;
void*user;
显然,这是用来表示一个完整的TCP会话了,最后是staticstructtcp_stream**tcp_stream_table;
一个TCP会话指针的数组,其实就是hash表了。
下面来看处理过程,先是初始化:
1.int
tcp_init(int
size)
...
//初始化全局tcp会话哈希表
tcp_stream_table_size
=
size;
tcp_stream_table
calloc(tcp_stream_table_size,
sizeof(char
*));
if
(!
tcp_stream_table)
{
nids_params.no_mem("
tcp_init"
);
return
-1;
}
//设置最大会话数,为了哈希的效率,哈希表的元素个数上限设为3/4表大小
max_stream
3
*
/
4;
//先将max_stream个tcp会话结构体申请好,放着(避免后面陆陆续续申请浪费时间)。
streams_pool
(struct
*)
malloc((max_stream
+
1)
sizeof(struct
tcp_stream));
streams_pool)
//ok,将这个数组初始化成链表
for
(i
0;
i
<
max_stream;
i++)
streams_pool[i].next_free
&
(streams_pool[i
1]);
streams_pool[max_stream].next_free
free_streams
streams_pool;
30.}
inttcp_init(intsize)
...
//初始化全局tcp会话哈希表
tcp_stream_table_size=size;
tcp_stream_table=calloc(tcp_stream_table_size,sizeof(char*));
if(!
tcp_stream_table){
nids_params.no_mem("
return-1;
}
//设置最大会话数,为了哈希的效率,哈希表的元素个数上限设为3/4表大小
max_stream=3*tcp_stream_table_size/4;
//先将max_stream个tcp会话结构体申请好,放着(避免后面陆陆续续申请浪费时间)。
streams_pool=(structtcp_stream*)malloc((max_stream+1)*sizeof(structtcp_stream));
streams_pool){
//ok,将这个数组初始化成链表
for(i=0;
i<
max_stream;
i++)
streams_pool[i].next_free=&
(streams_pool[i+1]);
streams_pool[max_stream].next_free=0;
free_streams=streams_pool;
return0;
很简单,做了两件事:
1.初始化tcp会话哈希表。
2.初始化会话池。
这个初始化函数只在库初始化时执行一次。
初始化完成之后,就进入了pcap_loop中了,nids中的回调函数是nids_pcap_handler,在这个函数里面做了些ip分片重组(等下篇再说)后(tcp包)便来到了process_tcp函数,这里tcp会话重组开始了。
来看看。
1.void
process_tcp(u_char
data,
skblen){
2.
//处理头,得到ip包和tcp包
ip
*this_iphdr
*)data;
tcphdr
*this_tcphdr
*)(data
4
this_iphdr->
ip_hl);
...//此处忽略安检代码
//在哈希表里找找,如果没有此tcp会话则看看是不是要新建一个
(a_tcp
find_stream(this_tcphdr,
this_iphdr,
from_client)))
//这里判断此包是否是tcp回话周期中的第一个包(由客户端发出的syn包)
//如果是,说明客户端发起了一个连接,那就新建一个回话
((this_tcphdr->
th_flags
TH_SYN)
!
(this_tcphdr->
TH_ACK)
TH_RST))
add_new_tcp(this_tcphdr,
this_iphdr);
//否则,果断忽略
return;
//如果找到会话,根据数据流向,将发送方(snd)和接收方(rcv)设置好
(from_client)
snd
a_tcp->
rcv
else
//来了一个SYN包
TH_SYN))
32.
//syn包是用来建立新连接的,所以,要么来自客户端且没标志(前面处理了),要么来自服务端且加ACK标志
33.
//所以这里只能来自服务器,检查服务器状态是否正常,不正常的话果断忽略这个包
34.
(from_client
||
client.state
TCP_SYN_SENT
35.
server.state
TCP_CLOSE
TH_ACK))
36.
37.
38.
//忽略流水号错误的包
39.
(a_tcp->
client.seq
ntohl(this_tcphdr->
th_ack))
40.
41.
42.
//自此,说明此包是服务端的第二次握手包,初始化连接(初始状态、流水号、窗口大小等等)
43.
TCP_SYN_RECV;
44.
server.seq
th_seq)
1;
45.
server.first_data_seq
server.seq;
46.
server.ack_seq
th_ack);
47.
server.window
ntohs(this_tcphdr->
th_win);
48.
49.
//下面处理tcp的一些附加选项
50.
//先是时间戳选项
51.
client.ts_on)
52.
server.ts_on
get_ts(this_tcphdr,
server.curr_ts);
53.
server.ts_on)
54.
client.ts_on
55.
56.
//再是窗口扩大选项
57.
client.wscale_on)
58.
server.wscale_on
get_wscale(this_tcphdr,
server.wscale);
59.
server.wscale_on)
60.
client.wscale_on
61.
client.wscale
62.
server.wscale
63.
64.
65.
66.
67.
68.
//syn包处理完,返回
69.
70.
71.
72.
(
73.
datalen
==
rcv->
ack_seq
)/*不是流水号正确且没数据的包*/
74.
//而且这个包不再当前窗口之内
75.
before(ntohl(this_tcphdr->
th_seq),
window*rcv->
wscale)
//流水号大于等于窗口右侧
76.
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- TCP 会话 重组