抓取网络数据包
当用户在局域网内传递数据时,处于同一网段的所有计算机的网卡都会收到这些数据,尽管它不是传递数据的目的地。利用这一特点,我们就可以截获局域网中传递的数据。为了能够获取通过网卡上的数据,需要创建原始套接字。用户可以将socket函数的第二个参数设置为SOCK_RAW来创建原始套接字。例如:
m_Socket=socket(AF_INET,SOCK_RAW,IPPROTO_IP);
由原始套接字获得的数据是IP数据报,而不仅仅是一个用户数据。它还包含IP数据头和相应协议的数据头,最后才是用户数据。为了获得用户数据,需要逐一去掉IP数据头及各个协议的数据头。
//创建套接字,开始监听网络
void CSniffAppDlg::OnBeginlistn()
{
//创建套接字
m_Sock=socket(AF_INET,SOCK_RAW,IPPROTO_IP);
char name[128];
memset(name,0,128);
hostent* phostent;
phostent=gethostbyname(name);
DWORD ip;
ip=inet_addr(inet_ntoa(*(int_addr)phostent->h_addr_list[0]));
int timeout=4000; //超时4秒
//设置接受数据的超时时间
setsockopt(m_Sock,SOL_SOCKET.SO_RCVTIMEO.(const char *)&timeou.sizeof(timeout));
sockadd_in_skaddr;
skaddr.sin_family=AF_INET;
skaddr.sin_port=htons(700);
skaddr.sin_addr.S_un.S_addr=ip;
//绑定地址
if(bind(m_Sock,(sockaddr*)$skaddr,sizeof(skaddr))==SOCKET_ERROR)
{
MessageBox("地址绑定错误");
return;
}
DWORD inBuffer=1;
DWORD outBuffer[10];
DWORD reValue=0;
if(WSAIoctl(m_Sock,SIO_RCVAL,&inBuffer,sizeof(inBuffer),&outBuffer,sizeof(outBuffer),&reValue,NULL)==SOCKET_ERROR)
{
MessageBox("设置缓冲区错误。");
closesocket(m_Sock);
return;
}
else
m_pThread=AfxBeginThread(ThreadFun.(void*)this);
}
UINT ThreadFun(LPVOID pFaram) //去除数据头
{
CSniffAppDlg* pDlg=static_cast<CSniffAppDlg*>(pParam);
MSG msg;
char buffer[1000],sourceip[32],*tempbuf;
char *ptemp;
BYTE* pData=NULL; //实际数据包中的数据
UINT sourceport;
CString str;
HEADIP* pHeadIP;
HEADICMP* pHeadICMP;
HEADUDP* pHeadUDP;
HEADTCP* pHeadTCP;
in_addr addr;
int ret;
while(TRUE)
{
pData=NULL;
if(PeekMessage(&msg.pDlg->m_hWnd,WM_CLOSE,WM_CLOSE,PM_NOREMOVE))
{
closesocket(pDlg->m_Sock);
break;
}
memst(buffer,0,1000);
ret=recv(pDlg->m_Sock,buffer,1000,0);
if(ret==SOCKET_ERROR)
{
continue;
}
else //接收到的数据
{
tempbuf=buffer;
pHeadIP=(HEADIP*)tempbuf;
WORD len=ntohs(pHeadIP->totallen); //获取数据报总长度
//获取源IP
pDlg->m_List.InsertItem(pDlg->m_List.GetItemCount()."");
addr.S_un.S_addr=pHeadIP->sourceIP;
ptemp=inet_ntoa(addr);
pDlg->m_List.SetItemText(pDlg->m_List.GetItemCount()-1,1,ptemp);
//获取目的IP
addr.S_un.S_addr=pHeadIP->destIP;
ptemp=inet_ntoa(addr);
pDlg->m_List.SetItemText(pDlg->m_List.GetItemCount()-1,2,ptemp);
//获取协议名称
ptem=get_protoname(pHeadIP->proto);
strcpy(sourceip,ptemp);
pDlg->m_List.SetItemText(pDlg->m_List.GetItemCount()-1,0,sourceip);
//获取IP数据报总长度
WORD ipSunLen=ntohs(pHeadIP->totallen);
//IP数据报头总长度
int netlen=ipSumLen-ipHeadLen;
//根据不同的协议获得不同协议的数据
switch(pHeadIP-proto)
{
case IPPROTO_ICMP:
{
pHeadICMP=(HEADICMP*)(tempbuf+20);
pData=(BYTE*)(pHeadICMP)+4;//ICMP数据报头功4个字节
//获取数据的长度
netlen-=4;
break;
}
case IPPROTO_UDP:
{
pHeadUDP=(HEADUDP*)(tempbuf+20);
pData=(BYTE*)(pHeadUDP)+8;//UDP数据报头共8个字节
sourceport=ntohs(pHeadUDP->SourcePort);
str.Format("%d",sourceport);
//设置源端口
pDlg->m_List.SetItemText(pDlg->m_List.GetItemCount()-1,3,str);
str.Empty();
netlen-=8;
break;
}
case IPPROTO_TCP:
{
pHeadTCP=(HEADTCP*)(tempbuf+20);
sourceport=ntohs(pHeadTCP->SourcePort);
pData=(BYTE*)(pHeadTCP)+20;//TCP数据报头共20个字节
str.Format("%d",sourceport);
//设置源端口
pDlg->m_List.SetItemText(pDlg->m_List.GetItemCount()-1,3,str);
str.Empty();
netlen-=20;
break;
}
}
//设置数据大小
str.Format("%d",netlen);
pDlg->m_List.SetItemText(pDlg->m_List.GetItemCount()-1,4,str);
str.Empty();
//设置数据
if(pData!=NULL)
{
str.Format("%s",pData);
pDlg->m_List.SetItemText(pDlg->m_List.GetItemCount()-1,5,str);
}
str.Empty();
}
}
return 0;
}