储的。网上讲述原始套接字的文章有很多,黑防也有不少这种文章,这里只给出关键代码:
//由于代码很长,部分地方会省略冗长的代码,详细请见源程序
vector<DWORD> dwMyIp; //本机IP列表,存放所有IP 地址,以便嗅探所有数据包
char szHost[256];
// 取得本地主机名称
::gethostname(szHost, 256);
// 通过主机名得到地址信息
hostent *pHost = ::gethostbyname(szHost);
in_addr addr;
for(int i = 0; ; i++)
{
char *p = pHost->h_addr_list[i];
if(p == NULL) break;
dwMyIp.push_back(inet_addr(inet_ntoa(*(in_addr
*)pHost->h_addr_list[i]))); //保存IP地址
}
nNetNum = i;
for(i = 0;i<nNetNum;i++)
{
::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WorkThread,(LPVOID)this,0,
0); //建立新线程,WorkThread是嗅探的工作线程
}
int WINAPI WorkThread(LPVOID Param)
{ // 创建原始套接字
SOCKET sock;
sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
// 设置 IP头操作选项,其中 flag 设置为ture,亲自对 IP头进行处理
BOOL flag=TRUE;
setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag));
SOCKADDR_IN addr_in;
addr_in.sin_addr.S_un.S_addr = dwMyIp[nIndex++];//用于设置监听的IP
addr_in.sin_family = AF_INET;
addr_in.sin_port = htons(10013); //绑定任意端口
if(bind(sock, (PSOCKADDR)&addr_in, sizeof(addr_in)) == SOCKET_ERROR)
{
AfxMessageBox("绑定地址失败");
return 1;
}
// dwValue为输入输出参数,为1 时执行,0时取消
DWORD dwValue = 1;
// 设置 SOCK_RAW 为SIO_RCVALL,以便接收所有的IP包。其中SIO_RCVALL
// 的定义为: #define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
ioctlsocket(sock, SIO_RCVALL, &dwValue); //将网卡设置为混合模式
char RecvBuf[BUFFER_SIZE];//接收数据的缓冲区
while(1) //死循环
{
int ret = recv(sock, RecvBuf, BUFFER_SIZE, 0);
if (ret >0)
{
IpHeader *iphdr = (IpHeader *)RecvBuf; //此处略去IP头定义,下同,
详见代码
int nLen = ntohs(iphdr->TotalLen) - sizeof(IpHeader); //获取下层
数据包长度
int bUp = IsMyIp(iphdr->SrcAddr,iphdr->DstAddr); //判断是否是发
送数据,返回-1 表示不是本机数据包,因为原始套接字必须要设为混杂模式,否则无
法监听到数据
if(bUp == -1) continue;//拒绝接收
DWORD dwLocalIp = bUp?iphdr->SrcAddr:iphdr->DstAddr;
DWORD dwRemoteIp = bUp?iphdr->DstAddr:iphdr->SrcAddr;
int hdrLen,i;
if(iphdr->Protocol == IPPROTO_TCP) //是TCP 包
{
TcpHeader *tcphdr = (TcpHeader *)(RecvBuf + iphdr->HdrLen*4);
hdrLen =iphdr->HdrLen*4+sizeof(TcpHeader);
USHORT nLocalPort =
bUp?ntohs(tcphdr->SrcPort):ntohs(tcphdr->DstPort); //获取本地端口
USHORT nRemotePort =
bUp?ntohs(tcphdr->DstPort):ntohs(tcphdr->SrcPort); //获取远程端口
for(int i=0;i<pThis->m_connList.size();i++)
{// m_connList为 vector<UpDownInfo>类型,UpDownInfo是保存连接相
关信息的结构体
if( 判断 m_connList中是否存在该连接 )
{
if(bUp)
{
m_connList[i].dwUpData += nLen - sizeof(TcpHeader);
m_connList[i].nUpPacket ++;
}else{
m_connList[i].dwDownData += nLen -sizeof(TcpHeader);
m_connList[i].nDownPacket ++;
}
}
if(i>=m_connList.size())
{
UpDownInfo info;
省略初始化结构体代码
m_connList.push_back(info);
}
}
if(iphdr->Protocol == IPPROTO_UDP) //是UDP 包
{
UdpHeader *udphdr = (UdpHeader *)(RecvBuf + iphdr->HdrLen*4);
//省略 UDP部分的处理代码,与上类似 |