基于winpcap的嗅探器设计与实现设计说明Word格式.docx
《基于winpcap的嗅探器设计与实现设计说明Word格式.docx》由会员分享,可在线阅读,更多相关《基于winpcap的嗅探器设计与实现设计说明Word格式.docx(26页珍藏版)》请在冰豆网上搜索。
网络数据包捕获功能主要负责从网络中捕获和过滤数据,这可以通过调用winPcap提供的丰富的API函数来实现;
数据解析及显示部分主要负责界面数据转化、解析、处理、格式化、协议分析等,这一部分主要通过MFC来设计一个单文档图形用户界面GUI,解析结果将通过MFC的类库显示到GUI中
系统总系结构
网络嗅探器的整体设计由三个模块组成,自底向上分别是嗅探器设置模块,数据包捕获模块,解析和显示模块。
嗅探器设置模块主要调用winPcaP提供的API,分为获取网络设备信息,设置并编译过滤器,打开网络设备三个步骤。
数据包捕获模块创建了新的线程,利用了winPcap的非回调函数Pcap_next_ex()函数从winPcap底层驱动的数据缓冲区中读取数据包,并将数据包存储在系统临时文件中,以便之后的分析。
用Pcap_open_offline()函数从离线文件中读取包。
读取到的任意一个符合捕获条件数据包,将其容解析,并显示本数据包。
捕获完成后,进人解析和显示模块。
(嗅探器总体结构如图1)
图1.嗅探器总体结构
五、设计步骤
嗅探器的设置模块
a.获取已连接的网络设备列表,winPcap提供了pcap_findalldevs_ex()函数,这个函数返回一个PcaP-if结构的链表,每个这样的结构都包含了一个适配器的详细信息。
b.打开网络设备,winPcap提供了pcap_open()函数,该函数第一参数制定要捕获数据包的哪些部分,第二参数用来制定适配器是否为混杂模式,第三参数为读取数据的超时时间,当适配器被打开后,就可以进行捕获工作了;
c.设置过滤器,winPcap中用来过滤数据包的函数是pcap_compile()和pcap_setfilter()。
pcap_compile()它将一个高层的布尔过滤表达式编译成一个能够被过滤引擎所解释的低层的字节码。
pcap_setfilter()将一个过滤器与核捕获会话相关联。
当pcap_set_filter()被调用时,这个过滤器将被应用到来自网络的所有数据包,并且,所有的符合要求的数据包(即那些经过过滤器以后,布尔表达式为真的包),将会立即复制给应用程序。
数据包的捕获模块
该部分创建了一个用于捕获数据包的线程,在该线程中调用winPcap提供的pcap_next_ex()函数从底层驱动数据缓冲区中读取数据包,该函数接受已打开的网络设备句柄,返回捕获数据包的实体,并用pcap_dump函数将每一个数据包写人临时文件中。
解析与显示模块
该部分在接收到用户发出的捕获完成消息后,将数据包从离线文件中逐条取出并进行解析和显示。
将解析完毕数据包中的各项容填人已经预先声明的协议的数据结构中,包括(序号,捕获时间,以太帧长度,传输层协议,源IP地址,目的IP地址,源MAC地址,目的MAC地址),然后将数据结构添加到列表视图中
六、关键问题及其解决方法
界面初始化
BOOLCzszhangDlg:
:
OnInitDialog()
{
CDialog:
OnInitDialog();
ASSERT((IDM_ABOUTBOX&
0xFFF0)==IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX<
0xF000);
CMenu*pSysMenu=GetSystemMenu(FALSE);
if(pSysMenu!
=NULL)
{
CStringstrAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if(!
strAboutMenu.IsEmpty())
{
pSysMenu->
AppendMenu(MF_SEPARATOR);
AppendMenu(MF_STRING,IDM_ABOUTBOX,strAboutMenu);
}
}
SetIcon(m_hIcon,TRUE);
//设置大图标
SetIcon(m_hIcon,FALSE);
//设置小图标
ShowWindow(SW_MINIMIZE);
m_listCtrl.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
m_listCtrl.InsertColumn(0,_T("
编号"
),3,30);
//1表示右,表示中,表示左
m_listCtrl.InsertColumn(1,_T("
时间"
),3,130);
m_listCtrl.InsertColumn(2,_T("
长度"
),3,72);
m_listCtrl.InsertColumn(3,_T("
源MAC地址"
),3,140);
m_listCtrl.InsertColumn(4,_T("
目的MAC地址"
m_listCtrl.InsertColumn(5,_T("
协议"
),3,70);
m_listCtrl.InsertColumn(6,_T("
源IP地址"
),3,145);
m_listCtrl.InsertColumn(7,_T("
目的IP地址"
m_combobox.AddString(_T("
请选择一个网卡接口(必选)"
));
m_comboBoxRule.AddString(_T("
请选择过滤规则(可选)"
if(sniffer_initCap()<
0)
returnFALSE;
/*初始化接口列表*/
for(dev=alldev;
dev;
dev=dev->
next)
if(dev->
description)
m_combobox.AddString(CString(dev->
description));
}
/*初始化过滤规则列表*/
tcp"
udp"
ip"
icmp"
arp"
m_combobox.SetCurSel(0);
m_comboBoxRule.SetCurSel(0);
m_buttonStop.EnableWindow(FALSE);
m_buttonSave.EnableWindow(FALSE);
returnTRUE;
//除非将焦点设置到控件,否则返回TRUE
}
捕获数据包
//开始捕获
intCzszhangDlg:
sniffer_startCap()
{
intif_index,filter_index,count;
u_intnetmask;
structbpf_programfcode;
CStringNcard;
sniffer_initCap();
//获得接口和过滤器索引
if_index=this->
m_combobox.GetCurSel();
filter_index=this->
m_comboBoxRule.GetCurSel();
if(0==if_index||CB_ERR==if_index)
MessageBox(_T("
请选择一个合适的网卡接口"
return-1;
if(CB_ERR==filter_index)
过滤器选择错误"
/*获得选中的网卡接口*/
dev=alldev;
for(count=0;
count<
if_index-1;
count++)
dev=dev->
next;
if((adhandle=pcap_open_live(dev->
name,//设备名
65536,//捕获数据包长度
1,//混杂模式(非意味着是混杂模式)
1000,//读超时设置
errbuf//错误信息
))==NULL)
无法打开接口:
"
+CString(dev->
description)));
pcap_freealldevs(alldev);
/*检查是否为以太网*/
if(pcap_datalink(adhandle)!
=DLT_EN10MB)
这不适合于非以太网的网络!
if(dev->
addresses!
=NULL)
netmask=((structsockaddr_in*)(dev->
addresses->
netmask))->
sin_addr.S_un.S_addr;
else
netmask=0xffffff;
//编译过滤器
if(0==filter_index)
charfilter[]="
;
if(pcap_compile(adhandle,&
fcode,filter,1,netmask)<
0)
MessageBox(_T("
语法错误,无法编译过滤器"
pcap_freealldevs(alldev);
return-1;
}else{
CStringstr;
char*filter;
intlen,x;
this->
m_comboBoxRule.GetLBText(filter_index,str);
len=str.GetLength()+1;
filter=(char*)malloc(len);
for(x=0;
x<
len;
x++)
filter[x]=str.GetAt(x);
//设置过滤器
if(pcap_setfilter(adhandle,&
fcode)<
设置过滤器错误"
/*设置数据包存储路径*/
CFileFindfile;
charthistime[30];
structtm*ltime;
memset(filepath,0,512);
memset(filename,0,64);
if(!
file.FindFile(_T("
SavedData"
)))
CreateDirectory(_T("
),NULL);
time_tnowtime;
time(&
nowtime);
ltime=localtime(&
strftime(thistime,sizeof(thistime),"
%Y%m%d%H%M%S"
ltime);
strcpy(filepath,"
SavedData\\"
);
strcat(filename,thistime);
strcat(filename,"
.zsz"
strcat(filepath,filename);
dumpfile=pcap_dump_open(adhandle,filepath);
if(dumpfile==NULL)
文件创建错误!
pcap_freealldevs(alldev);
/*接收数据,新建线程处理*/
LPDWORDthreadCap=NULL;
m_ThreadHandle=CreateThread(NULL,0,sniffer_CapThread,this,0,threadCap);
if(m_ThreadHandle==NULL)
intcode=GetLastError();
str.Format(_T("
创建线程错误,代码为%d."
),code);
MessageBox(str);
return1;
数据包处理
DWORDWINAPIsniffer_CapThread(LPVOIDlpParameter)
intres,nItem;
CStringtimestr,buf,srcMac,destMac;
time_tlocal_tv_sec;
structpcap_pkthdr*header;
//数据
constu_char*pkt_data=NULL,*pData=NULL;
//网络中收到的字节流数据
u_char*ppkt_data;
CzszhangDlg*pthis=(CzszhangDlg*)lpParameter;
if(NULL==pthis->
m_ThreadHandle)
MessageBox(NULL,_T("
线程句柄错误"
),_T("
提示"
),MB_OK);
while((res=pcap_next_ex(pthis->
adhandle,&
header,&
pkt_data))>
=0)
if(res==0)//超时
continue;
structdatapkt*data=(structdatapkt*)malloc(sizeof(structdatapkt));
memset(data,0,sizeof(structdatapkt));
if(NULL==data)
MessageBox(NULL,_T("
空间已满,无法接收新的数据包"
Error"
//分析出错或所接收数据包不在处理围
if(analyze_frame(pkt_data,data,&
(pthis->
npacket))<
//将数据包保存到打开的文件中
if(pthis->
dumpfile!
=NULL)
pcap_dump((unsignedchar*)pthis->
dumpfile,header,pkt_data);
//更新各类数据包计数
pthis->
sniffer_updateNPacket();
//将本地化后的数据装入一个链表中,以便后来使用
ppkt_data=(u_char*)malloc(header->
len);
memcpy(ppkt_data,pkt_data,header->
m_localDataList.AddTail(data);
m_netDataList.AddTail(ppkt_data);
/*预处理,获得时间、长度*/
data->
len=header->
//链路中收到的数据长度
local_tv_sec=header->
ts.tv_sec;
ltime=localtime(&
local_tv_sec);
time[0]=ltime->
tm_year+1900;
time[1]=ltime->
tm_mon+1;
time[2]=ltime->
tm_mday;
time[3]=ltime->
tm_hour;
time[4]=ltime->
tm_min;
time[5]=ltime->
tm_sec;
/*为新接收到的数据包在listControl中新建一个item*/
buf.Format(_T("
%d"
),pthis->
npkt);
nItem=pthis->
m_listCtrl.InsertItem(pthis->
npkt,buf);
/*显示时间戳*/
timestr.Format(_T("
%d/%d/%d%d:
%d:
),data->
time[0],
time[1],data->
time[2],data->
time[3],data->
time[4],data->
time[5]);
m_listCtrl.SetItemText(nItem,1,timestr);
/*显示长度*/
buf.Empty();
m_listCtrl.SetItemText(nItem,2,buf);
/*显示源MAC*/
buf.Format(_T("
%02X-%02X-%02X-%02X-%02X-%02X"
ethh->
src[0],data->
src[1],
data->
src[2],data->
src[3],data->
src[4],data->
src[5]);
m_listCtrl.SetItemText(nItem,3,buf);
/*显示目的MAC*/
buf.Format(_T("
dest[0],data->
dest[1],
dest[2],data->
dest[3],data->
dest[4],data->
dest[5]);
m_listCtrl.SetItemText(nItem,4,buf);
/*获得协议*/
m_listCtrl.SetItemText(nItem,5,CString(data->
pktType));
/*获得源IP*/
if(0x0806==data->
type)
%d.%d.%d.%d"
arph->
ar_srcip[0],
data->
ar_srcip[1],data->
ar_srcip[2],data->
ar_srcip[3]);
}elseif(0x0800==data->
type){
structin_addrin;
in.S_un.S_addr=data->
iph->
saddr;
buf=CString(inet_ntoa(in));
}elseif(0x86dd==data->
type){
intn;
for(n=0;
n<
8;
n++)
{
if(n<
=6)
buf.AppendFormat(_T("
%02x:
iph6->
saddr[n]);
else
%02x"
}
m_listCtrl.SetItemText(nItem,6,buf);
/*获得目的IP*/
if(0x0806