利用SNIFFER PRO学习TCP/IP(一)
2003/10/28
ydzqw
注:Sniffer Pro应该大家都知道,不知道的到GOOGLE搜索J
最好手头有本<<TCP/IP详解卷1:协议>>
这两天在看<<TCP/IP详解>>,总觉得有些地方理解的不够深。于是写了个小程序,再加上Sniffer,慢慢咀嚼。
程序如下:
---------------------Server-----------------------------
#include<iostream>
#include<winsock2.h>
#include<windows.h>
using namespace std;
void main()
{
WORD wVer;
WSADATA wsaData;
//WSAStartup
wVer = MAKEWORD(1, 1);
if ( WSAStartup(wVer, &wsaData) )
{
cout << "WSAStaup error!";
return;
}
//SOCKET init
SOCKET sock;
if ( (sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
{
cout << "socket error!";
return;
}
//bind, listen and accept
sockaddr_in sockadr;
sockadr.sin_family = AF_INET;
sockadr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
sockadr.sin_port = htons(6666);
if ( bind(sock, (sockaddr*)&sockadr, sizeof(sockadr)) )
{
cout << "bind error!";
return;
}
if ( listen(sock, 5) )
{
cout << "listen error!";
return;
}
SOCKET sock_svr;
sockaddr_in sockadr_svr;
int iLen = sizeof(sockadr_svr);
//accept时blocking了,如果这时要退出程序,那该如何?
sock_svr = accept(sock, (sockaddr*)&sockadr_svr, &iLen);
if ( sock_svr == INVALID_SOCKET )
{
cout << "accetp error!";
return;
}
//select and recv
fd_set rdfs;
timeval tv;
char buf[1024 * 2];
int retval;
int recv_err;
tv.tv_sec = 5;
tv.tv_usec = 0;
for(; ;)
{
FD_ZERO(&rdfs);
FD_SET(sock_svr, &rdfs);
retval = select(0, &rdfs, NULL, NULL, &tv);
memset(buf, 0, sizeof(buf));
if ( retval > 0 )
{
recv_err = recv(sock_svr, buf, sizeof(buf), 0);
if (recv_err == 0)
{
closesocket(sock_svr);
break;
}
else
{
cout << buf;
}
}
}
closesocket(sock);
WSACleanup();
}
-------------------------------------Client-------------------------------------
#include<iostream>
#include<winsock2.h>
#include<windows.h>
using namespace std;
void main()
{
WORD wVer;
WSADATA wsaData;
//WSAStartup
wVer = MAKEWORD(1, 1);
if ( WSAStartup(wVer, &wsaData) )
{
cout << "WSAStaup error!";
return;
}
//SOCKET init
SOCKET sock;
if ( (sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
{
cout << "socket error!";
return;
}
//connect and send
sockaddr_in sockadr;
sockadr.sin_family = AF_INET;
//Server在本机时启用环回接口,按理说可以捕捉到数据
//用sniffer却捕捉不到数据,这应该是Windows在底层做了相应处理
sockadr.sin_addr.S_un.S_addr = inet_addr("192.168.1.81");
sockadr.sin_port = htons(6666);
if ( connect(sock, (sockaddr*)&sockadr, sizeof(sockadr)) == SOCKET_ERROR )
{
cout << "connect error!";
return;
}
//分片会在哪里进行?IP层?TCP层?
char Test[2000];
memset(Test, 65, sizeof(Test));
Test[sizeof(Test) - 1] = 'B';//这样才可看出是否全部传过去了
if ( send(sock, Test, sizeof(Test), 0) == SOCKET_ERROR )
{
cout << "send error!";
return;
}
//Sleep(1000);//等待Server的响应包再关闭
//close and WSACleanup
if ( closesocket(sock) )
{
cout << "closesocket error!";
return;
}
if ( WSACleanup() )
{
cout << "WSACleanup error!";
return;
}
}
------------------------------------------------------------------------------------
把Client端的192.168.1.81改成运行Server端所在机器的IP地址。Client和Server不能在同一台机器(这一点我也很困惑),不然Sniffer捕捉不到数据。
Start SnifferPro(Capture->Start),接着运行Server,Client,程序一闪而过就结束了,Stop and Display SnifferPro(Capture->Stop and Display)。程序虽然一闪就结束了,没关系,我们要的东西都被Sniffer Capture了。
在面板中点击Decode,可以开始了。
注意上图,从NO.12到NO.21(当然,在你的机器执行时不见得是12-21)就是此次发送的全过程。12,13,14是建立连接的三次握手(DDoS攻击就有利用三次握手的漏洞),参见<<详解>>P176。15,16是数据传送(这里有个数据分片问题,下面会详细说明),17,19,20,21是终止连接的四次握手,18是响应包,响应15,16的数据传送。因为在我程序中send之后马上就进行closesocket,所以响应包反而到终止连接请求后面了,当然,只要在send之后Sleep(1000),就不会发生这种情况。开始我也疑惑怎么会有五次握手,在这里我没更正回来,就是为了启示大家,要小心分析。
下面开始分析数据包的结构: