IPv6分组分析器
开发思路:
本问题的目的是深入了解IPv6分组格式;掌握程序抓包方法。
具体开发思路为:
1. 先显示出所有网络适配器的列表,然后让用户选择想在哪个适配器上截获数据包。
2. 使用winpcap在用户所选择的网络适配器上进行截获。
3. 将截获的数据包的信息显示出来
流程:
² 需求分析
IPv6_packet_analyzer是程序抓包工具。需要能够侦听所有进出本主机的数据包,并过滤出IPV6格式的数据包。对IPV6头而言,需要显示版本、下一个头或协议类型:TCP或UDP、流标签、载荷长度、跳数限制、源IP地址、目的IP地址。
² 概要设计
1. 编程环境
本软件是在VC环境下编写,使用WinPcap中定义的头文件和lib文件为支持,运用WinPcap提供的数据包捕获程序执行核心操作。
2. 模块分析
Ø 本软件使用的主要模块及其功能如下:
1.网络适配器选择及显示模块
2.抓包和数据包分析线程
² 详细设计
Ø 主要数据结构
typedef struct ip_address{//128位的IP地址
WORD byte[8];
}ip6_address;
typedef struct ip_header{
u_char ver_traffic; // 版本(4比特) + 通信流类别(前4比特)
u_char traffic_flow; // 通信流类别(后4比特) + 流标签(前4比特)
u_short flow; // 流标签(后16比特)
u_short payloadlen; // 有效载荷长度(两个字节)
u_char nexthead; // 下一个报头(1个字节)
u_char hoplim; // 跳限制
ip6_address saddr; // 源地址
ip6_address daddr; // 目的地址
}ip6_header;
Ø 主要代码描述
Ø 查找主机上所有的适配器并显示
HTREEITEM root = m_treeCtrl.InsertItem(_T("Network Adpater"));
if(alldevs==NULL){//查找所有网卡
if (pcap_findalldevs(&alldevs, errbuf) == -1)
return FALSE;
}
pcap_if_t *tempdev=alldevs;
for (dev=alldevs;dev;dev=dev->next)
{
char *temp;
temp=dev->name;
HTREEITEM h=m_treeCtrl.InsertItem(_T(temp),root);
}
DWORD log = GetWindowLong(m_listCtrl.GetSafeHwnd(),GWL_STYLE);
log |= LVS_REPORT;
SetWindowLong(m_listCtrl.GetSafeHwnd(),GWL_STYLE,log);
m_listCtrl.SetExtendedStyle(LVS_EX_FULLROWSELECT);
m_listCtrl.InsertColumn(0,"项目名称",LVCFMT_LEFT,150);
m_listCtrl.InsertColumn(1,"项目属性",LVCFMT_LEFT,300);
m_treeCtrl.Expand(root,TVE_EXPAND);
if(dev!=NULL){//当前已有网卡被绑定,责显示该网卡信息
m_listCtrl.DeleteAllItems();
m_listCtrl.InsertItem(0,"名称",0);
m_listCtrl.InsertItem(1,"描述",0);
if(dev->name!=NULL){
m_listCtrl.SetItemText(0,1,dev->name);
}
else{
m_listCtrl.SetItemText(0,1,"没有找到");
}
if(dev->description!=NULL){
m_listCtrl.SetItemText(1,1,dev->description);
}
else{
m_listCtrl.SetItemText(1,1,"没有找到");
}
}//当前已有网卡被绑定,显示该网卡信息
Ø 显示选定网卡
HTREEITEM h=m_treeCtrl.GetSelectedItem();
if (m_treeCtrl.GetParentItem(h)==NULL)
return;
dev=alldevs;
while(strcmp(dev->name,m_treeCtrl.GetItemText(h))!=0)//找到被选中网卡
dev=dev->next;
m_listCtrl.DeleteAllItems();
m_listCtrl.InsertItem(0,"名称",0);
m_listCtrl.InsertItem(1,"描述",0);
if(dev!=NULL){//显示选中网卡内容
if(dev->name!=NULL){
m_listCtrl.SetItemText(0,1,dev->name);
}
else{
m_listCtrl.SetItemText(0,1,"Not Found");
}
if(dev->description!=NULL){
m_listCtrl.SetItemText(1,1,dev->description);
}
else{
m_listCtrl.SetItemText(1,1,"没有找到");
}
}
Ø 打开指定的适配器
HTREEITEM h=This->m_treeCtrl.GetSelectedItem();
This->dev=This->alldevs;
while(strcmp(This->dev->name,This->m_treeCtrl.GetItemText(h))!=0)//找到被选中网卡
This->dev=This->dev->next;
if ( (adhandle= pcap_open(This->dev->name,
65536,
PCAP_OPENFLAG_PROMISCUOUS,
1000,
NULL,
errbuf
) ) == NULL)
{
AfxMessageBox("网卡打开失败!");
return -1;
}
Ø 捕包并进行包信息分析
ip6_header *i6h;
int res=-1;
struct pcap_pkthdr * header;
const unsigned char * pkt_data;
This->Packetno=0;
while(!This->isStop&&(res = pcap_next_ex( adhandle, &header, &pkt_data)) >= 0){
if(res == 0)
//超时时间到
continue;
i6h = (ip6_header *) (pkt_data +14);
u_int ve = (i6h->ver_traffic) & 0xf0;
u_int traffic=i6h->ver_traffic&0xf+(i6h->traffic_flow&0xf0)*8;//通信流类别
u_int flowlabel = (i6h->traffic_flow & 0xf) * 32 * 1024 + ntohs(i6h->flow);//流标签
CString sPacketno,sve,straffic,sflowlabel,spayloadlen,shoplimit;
char temp[100];
itoa(This->Packetno,temp,10);
sPacketno=temp;
ltoa(flowlabel,temp,10);
sflowlabel = temp;
ltoa(traffic,temp,10);
straffic = temp;
ltoa(ve,temp,10);
sve = temp;
itoa(ntohs(i6h->payloadlen),temp,10);
spayloadlen = temp;
itoa(i6h->hoplim,temp,10);
shoplimit = temp;
CString nhtype;
switch(i6h->nexthead)
{
case 6: nhtype="TCP";break;
case 17: nhtype="UDP"; break;
case 43: nhtype="Routing";break;
case 44: nhtype="Fragment";break;
case 58: nhtype="ICMP6";break;
default : nhtype ="type unknown";
}
CString srcip,desip;
//打印ip地址
for (int i=0;i<8;i++)
{
itoa(ntohs(i6h->saddr.byte[i]),temp,16);
srcip += temp;
if(i<7)
srcip +=":";
}
for (int j=0;j<8;j++)
{
itoa(ntohs(i6h->daddr.byte[i]),temp,16);
desip += temp;
if(j<7)
desip += ":";
}
This->m_listCtrlip.InsertItem(This->Packetno,sPacketno);
This->m_listCtrlip.SetItemText(This->Packetno,1,sve);
This->m_listCtrlip.SetItemText(This->Packetno,2,straffic);
This->m_listCtrlip.SetItemText(This->Packetno,3,sflowlabel);
This->m_listCtrlip.SetItemText(This->Packetno,4,spayloadlen);
This->m_listCtrlip.SetItemText(This->Packetno,5,nhtype);
This->m_listCtrlip.SetItemText(This->Packetno,6,shoplimit);
This->m_listCtrlip.SetItemText(This->Packetno,7,srcip);
This->m_listCtrlip.SetItemText(This->Packetno,8,desip);
This->Packetno++;
}
This->isStop=false;
注:
此线程函数通过对isStop的值的判断来确定是否终止。
关键问题:
1. 采用何种方法进行捕包
2. 如何对IPV6的包进行数据分析
解决方法:
1. 采用winpcap中函数实现抓包。包括查找设备,打开设备,抓包等。通过本项目学会了如何使用这一系列的库函数。
2. 定义了IPV6的数据包头以及IP地址的结构体,通过找到数据包头的指针对包头的信息进行分析。
进一步的改进:
增加了GUI图形界面,主要通过树形控件显示设备列表,通过列表控件显示选定网卡信息,通过另一个列表控件显示IPV6包的详细信息。在图形化界面中应注意线程的调用。本软件未进行统计信息的显示,可进一步改进。