@xunuo
2017-10-23T17:25:50.000000Z
字数 2888
阅读 1467
网络数据包分析
TCP零窗口
TCP会话的Windows Size == 0
TCP窗口偏低
TCP会话的Windows Size <= 某阈值
TCP窗口阻塞
同一TCP会话的Windows Size在一段时间或连续几个相同会话的Windows Size<=某阈值 (注:不一定每个会话的Windows Size都要相同,因为阻塞是因为窗口太低不能传送数据造成了阻塞)
TCP窗口溢出
TCP报文传输时,会发送确认号(ACK)、序列号(seq)、数据长度(len)以及自身的窗口大小(winsize,就相当于一个缓存区),
例如:当客户端发送一个数据包给服务器时,告诉了服务器这些信息,服务器就会根据客户端的窗口大小从而确定要给客户机一次性发送多少数据,正常情况下服务器发送给客户机的数据都是在winsize之内的。
但是当在服务器发送数据包给客户端的过程中,客户机由于某些原因发了一个确认包给服务器,且它的winsize是改变了的,若是winsize变小,则服务器发送给客户机的数据包到达,就会出现窗口溢出问题。
而在做判断的时候,我们只需要记录客户端发给服务器数据包的ACK+winsize的值,在[ACK,ACK+winsize]这个区间就是服务器发给客户端允许的最大的值,如果下一个数据包的seq+len在这个区间内,则窗口没有溢出,若seq+len>ACK+winsize则说明窗口溢出。
在计算winsize的时候,还有一个问题:我们所抓取的数据包的winsize是缩小了相应倍数的,而这个倍数值则是在三次握手的SYN包的option字段内。放大倍数为2^(Windows Scale);
相关代码
/*!
syn包option中窗口放大倍数的计算;
*/
int option_winscale(u_char *pkt_data,pcap_pkthdr *header)
{
//printf("%02x\n", pkt_data[optionslen]);
for (int i = 54; i < header->len; i++)
{
int num = pkt_data[i];
int mss;
if (num == 0 || num == 1)
continue;
else if (num == 2)
{
mss = (int)pkt_data[i += 2] * 256;
mss += (int)pkt_data[++i];
printf("MSS:%d\n", mss);
if (mss < 500)
printf("TCP协商MSS过小\n");
}
else if (num == 3)
{
Windows_Scale = pkt_data[i += 2];
break;
}
else if (num == 4)
i += 1;
else if (num == 5)//SACK
i+=pkt_data[++i]-1;
else if (num == 8)
i += 9;
else if (num == 19)
i += 17;
else if (num == 28)
i += 3;
}
printf("winscale:%d %d\n",(int) Windows_Scale,quick(2, Windows_Scale));
return quick(2,Windows_Scale);
}
/*计算2^windows_scale*/
int quick(int x, int y)
{
int ans = 1;
int temp = x;
while (y>0)
{
if (y & 1)
ans = ans*temp;
temp = temp*temp;
y = y >> 1;
}
return ans;
}
/*!
Tcp零窗口(2),窗口偏低(1)
*/
int Tcp_Windows_low(TCP_HEADER *tcpHeader) {
if (0 < ntohs(tcpHeader->Windows) && ntohs(tcpHeader->Windows) < 20)//偏低
return 1;
if (ntohs(tcpHeader->Windows) == 0)//零窗口
return 2;
}
/*!
上行窗口阻塞
*/
int up_windows_stuck(TCP_HEADER *tcpHeader,int up_num)
{
down_num = 0;
int i = Tcp_Windows_low(tcpHeader);
if (i == 1)
printf("窗口偏低\n");
else if (i == 2)
printf("零窗口\n");
if (i == 1 || i == 2)
up_num++;
if (up_num >= 5)
printf("窗口阻塞\n");
return up_num;
}
/*!
下行窗口阻塞
*/
int down_windows_stuck(TCP_HEADER *tcpHeader, int down_num)
{
up_num = 0;
int i = Tcp_Windows_low(tcpHeader);
if (i == 1)
printf("窗口偏低\n");
else if (i == 2)
printf("零窗口\n");
if (i == 1 || i == 2)
down_num++;
if (down_num >= 5)
printf("窗口阻塞\n");
return down_num;
}
/*
上行tcp窗口溢出
*/
u_int tcp_up_windows(Upstream *up, TCPSESSION *tcpSessionHead, TCP_HEADER *tcpHeader) {
TCPSESSION *tcpSession = tcpSessionHead;
u_int ack_winsize;
ack_winsize = up->ack + up->Windows * up->Windows_scale;
printf("down_ack_winsize:%u\n", ack_winsize);
printf("seq+len:%u\n", up->seq + up->len);
if (up->ack_winsize < up->seq + up->len) {
printf("Windows Overflow\n");
}
return ack_winsize;
}
/*
下行tcp窗口溢出
*/
u_int tcp_down_windows(Downstream *down, TCPSESSION *tcpSessionHead, TCP_HEADER *tcpHeader) {
TCPSESSION *tcpSession = tcpSessionHead;
u_int ack_winsize;
if (tcpHeader->SYN == 1)
ack_winsize = down->ack +down->Windows;
else
ack_winsize = down->ack + down->Windows * down->Windows_scale;
printf("up_ack_winsize:%u\n", ack_winsize);
printf("seq+len:%u\n", (down->seq + down->len));
if (tcpHeader->SYN != 1 && down->ack_winsize < (down->seq + down->len)) {
printf("Windows Overflow\n");
}
return ack_winsize;
}