在网络中,数据是以帧的形式进行传输的。以TCP协议为例,当用户发送数据时,在传输层,用户数据的前端会附加TCP首部,TCP首部包括源端口号、目的端口号、位序号、确认序号等信息。在网络层会附加IP首部,IP首部包括数据报的源地址和目标地址等信息,详细信息请参考本例实现过程中的HeadIP结构。在链路层附加地址解析协议和逆向地址解析协议,用于转换IP层和网络接口层使用的地址。
为了获得网络中传输的数据,首先需要创建一个原始套接字,该套接字获得的数据是IP层的数据报。包含IP首部、TCP或UDP首部、用户数据等信息。然后对获得的数据报去除IP首部,根据IP首部获得数据报的源地址、目的地址、采用的协议及数据报的长度等信息。接着根据不同的协议去除TCP或UDP首部,根据TCP或UDP首部确定源端口和目的端口。最后数据报剩余的部分即是用户数据
在APP类中加:
#include "winsock2.h"
#pragma comment (lib,"ws2_32.lib")
#include "AFXSOCK.H"
BOOL CSniffAppApp::InitInstance()
{
AfxEnableControlContainer();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
//初始化套接字
WSADATA data;
AfxSocketInit(&data);
//WSAStartup(2,&data);
CSniffAppDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Place code here to handle when the dialog is
// dismissed with OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Place code here to handle when the dialog is
// dismissed with Cancel
}
// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}
// CSniffAppDlg dialog
#define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
#define SIO_RCVALL_MCAST _WSAIOW(IOC_VENDOR,2)
#define SIO_RCVALL_IGMPMCAST _WSAIOW(IOC_VENDOR,3)
#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
#define SIO_ABSORB_RTRALERT _WSAIOW(IOC_VENDOR,5)
#define SIO_UCAST_IF _WSAIOW(IOC_VENDOR,6)
#define SIO_LIMIT_BROADCASTS _WSAIOW(IOC_VENDOR,7)
#define SIO_INDEX_BIND _WSAIOW(IOC_VENDOR,8)
#define SIO_INDEX_MCASTIF _WSAIOW(IOC_VENDOR,9)
#define SIO_INDEX_ADD_MCAST _WSAIOW(IOC_VENDOR,10)
#define SIO_INDEX_DEL_MCAST _WSAIOW(IOC_VENDOR,11)
//定义Ip数据报头结构,20个字节
typedef struct HeadIP {
unsigned char headerlen:4; //首部长度,占4位
unsigned char version:4; //版本,占4位
unsigned char servertype; //服务类型,占8位,即1个字节
unsigned short totallen; //总长度,占16位
unsigned short id; //与idoff构成标识 ,共占16位,前3位是标识,后13位是片偏移
unsigned short idoff;
unsigned char ttl; //生存时间 ,占8位
unsigned char proto; //协议,占8位
unsigned short checksum; //首部检验和,占16位
unsigned int sourceIP; //源IP地址,占32位
unsigned int destIP; //目的IP地址,占32位
}HEADIP;
//定义TCP数据报首部
typedef struct HeadTCP {
WORD SourcePort; //16位源端口号
WORD DePort; //16位目的端口
DWORD SequenceNo; //32位序号
DWORD ConfirmNo; //32位确认序号
BYTE HeadLen; //与Flag为一个组成部分, 首部长度,占4位,保留6位,6位标识,共16位
BYTE Flag;
WORD WndSize; //16位窗口大小
WORD CheckSum; //16位校验和
WORD UrgPtr; //16位紧急指针
} HEADTCP;
//定义UDP数据报首部
typedef struct HeadUDP {
WORD SourcePort; //16位源端口号
WORD DePort; //16位目的端口
WORD Len; //16为UDP长度
WORD ChkSum; //16位UDP校验和
} HEADUDP;
//定义ICMP数据报首部
typedef struct HeadICMP {
BYTE Type; //8位类型
BYTE Code; //8位代码
WORD ChkSum; //16位校验和
} HEADICMP;
//定义协议名称
struct PROTONAME{
int value;
char* protoname;
};
在类.h中添加:
SOCKET m_Sock ;
CWinThread* m_pThread;
CListCtrl m_List;
// CSniffAppDlg dialog
PROTONAME protos[11] = {
{IPPROTO_IP ,"IP"},
{IPPROTO_ICMP,"ICMP"},
{IPPROTO_IGMP,"IGMP"},
{IPPROTO_GGP,"GGP"},
{IPPROTO_TCP,"TCP"},
{IPPROTO_PUP,"PUP"},
{IPPROTO_UDP,"UDP"},
{IPPROTO_IDP,"IDP"},
{IPPROTO_ND,"ND"},
{IPPROTO_RAW,"RAW"},
{IPPROTO_MAX,"MAX"}
};
char* get_protoname(int protoID)
{
for (int i= 0; i<11; i++)
if (protoID == protos[i].value)
{
return protos[i].protoname;
}
return "";
}
CSniffAppDlg::CSniffAppDlg(CWnd* pParent /*=NULL*/)
: CDialog(CSniffAppDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CSniffAppDlg)
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_pThread = NULL;
}
BOOL CSniffAppDlg::OnInitDialog()
{
CDialog::OnInitDialog();
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
m_List.SetExtendedStyle(LVS_EX_FLATSB|LVS_EX_GRIDLINES|LVS_EX_TWOCLICKACTIVATE);
m_List.InsertColumn(0,"协议",LVCFMT_LEFT,80);
m_List.InsertColumn(1,"源IP地址",LVCFMT_LEFT,120);
m_List.InsertColumn(2,"目的IP地址",LVCFMT_LEFT,120);
m_List.InsertColumn(3,"通信端口",LVCFMT_LEFT,80);
m_List.InsertColumn(4,"大小",LVCFMT_LEFT,100);
m_List.InsertColumn(5,"数据",LVCFMT_LEFT,120);
return TRUE; // return TRUE unless you set the focus to a control
}
void CSniffAppDlg::OnOK()
{
}
//线程函数
UINT ThreadFun( LPVOID pParam )
{
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;
}
memset(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);
//获取协议名称
ptemp = get_protoname(pHeadIP->proto);
strcpy(sourceip,ptemp);
pDlg->m_List.SetItemText(pDlg->m_List.GetItemCount()-1,0,sourceip);
//获取IP数据报总长度
WORD ipSumLen = ntohs(pHeadIP->totallen);
//IP数据报头总长度
int ipHeadLen = 20;
//获得去除IP层数据的长度
WORD 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;
}
void CSniffAppDlg::OnBeginlisten()
{
//创建套接字
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(*(in_addr*)phostent->h_addr_list[0]));
int timeout = 4000; //超时4秒
//设置接收数据的超时时间
setsockopt(m_Sock,SOL_SOCKET,SO_RCVTIMEO,(const char*)&timeout,sizeof(timeout));
sockaddr_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_RCVALL,&inBuffer,sizeof(inBuffer),&outBuffer,sizeof(outBuffer),&reValue,NULL,NULL)==SOCKET_ERROR)
{
MessageBox("设置缓冲区错误.");
closesocket(m_Sock);
return;
}
else
m_pThread = AfxBeginThread(ThreadFun,(void*)this);
}
void CSniffAppDlg::OnCancel()
{
if (m_pThread)
{
//m_pThread->ExitInstance();
delete m_pThread;
}
closesocket( m_Sock) ;
CDialog::OnCancel();
}
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/AIHANZI/archive/2010/05/25/5623739.aspx