协议分析器程序的设计报告(青岛理工袁超)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

协议分析器设计报告
协议分析器是一种常用的网络数据收集软件,它是在广播式网络环境下利用计算机网络接口截获目的地计算机的数据报文的一种工具。

1.协议分析器的基本原理
Ethernet是目前应用最广泛的计算机连网方式,它是基于总线结构的,物理层采用广播方式。

当一台主机向另一台主机发送数据时,发送主机会将包含目的主机MAC地址的数据帧发送到总线上,因此同一链路上所有活跃主机的网卡都能接收到该帧。

正常情况下,网卡收到数据帧后,会先检测帧头的目的地址字段,如果该地址不是本机的MAC地址,则丢弃不管,因此只有具有该地址的目的主机会接受这个数据帧。

但是,如果某个主机上的程序能够修改网卡的接收方式,使其成为“混杂”模式,即程序可以接收网络上所有的数据帧而不理会帧头的目的地址,利用这一点,就可以实现协议分析器。

因此协议分析器就是一种能将本地网卡状态设成“混杂”模式并接收网络上所有数据帧的软件。

协议分析器工作在网络环境中的底层,拦截所有正在网络上传送的数据,并且通过相应的解析处理,可以实时分析这些数据的内容,进而分析所处的网络状态和整体拓扑布局。

当应用程序通过IP网络传送数据时,数据就被送入TCP/IP协议栈中,然后由上至下逐一通过每一层,直到最后被当做一串比特流送入网络。

其中每一层对收到的数据都要增加一些首部信息这个过程被称作封装。

通过以太网传输的比特流被称作帧。

在传输的另一端,当目的主机收到一个以太网数据帧时,数据就开始从协议栈有底向上逐层解析,去掉各层协议所加上的报文头部。

每层协议均要检查报头中的协议标识字段,以确定要接收数据的上层协议,最终从报文中解析出应用层数据后交给应用程序处理。

协议分析器就是从网络中捕获数据包并对其进行解析的过程。

因此我们需要了解每层协议所规定的报文格式,然后由底向上逐层对数据包进行解码,最后将分析的结果显示出来。

2.协议分析器总体结构设计
此次编程的编程环境为:
(1)操作系统:Windows XP SP2;
(2)开发语言:C++ / MFC;
(3)编译环境:MS Visual C++6.0;
(4)第3方函数库:Winpcap3.1;
协议分析器的整体结构按功能分成3个部分,自底向上分别是数据捕获模块、协议解析模块和用户显示模块。

整体结构图1所示。

图1 协议分析器整体结构图
3 数据捕获模块设计
数据捕获模块的主要功能是进行数据采集,这个是整个系统的基础和数据来源。

程序使用Winpcap来捕获网络中原始数据包。

Winpcap是数据包捕获的开放代码函数库,它可以完成以下主要功能:
(1)捕获网络中的的原始数据包。

(2)使用用户自定义规则对数据包进行过滤。

(3)发送用户自己构造的数据包到网络中。

(4)统计网络流量。

(5)使用Winpcap捕获数据包的算法
使用Winpcap来捕获数据包的算法一般分为以下几步:
(1)获取并列出当前网络设备列表。

(2)由用户选择并打开指定网卡。

(3)根据过滤规则设置过滤器。

(4)捕获数据包并进行解析处理。

编程流程如图2所示。

图2 数据包捕获流程图
4 协议解析模块设计
该模块的主要功能就是对捕获的数据包按照数据链路层(MAC)、网络层(IP、ARP)、传输层(TCP、UDP、ICMP)的层次结构自底向上进行解析,最后将解析结果显示输出。

协议解析过程如图3所示。

图3协议解析流程图
4.1 解析Ethernet帧
Ethernet帧结构中,前导码、帧前定界符和帧校验和(CRC)3个字段均属于物理层内容,而我们使用的Winpcap抓包驱动程序不包含这些字段,因此只需解析目的地址、源地址、长度/类型和数据4个字段即可。

图4 Ethernet帧结构
4.2解析ARP数据包
此处不做过多说明,主要代码分析见本文第5部分。

图5 ARP报文结构
4.3解析IP数据包
为了提高效率,可以使用链表结构存储IP数据包信息,同时还可以使用模板类map来存储IP数据包信息。

图6 IP报文结构
4.4解析ICMP、TCP、和UDP数据包
解析ICMP、TCP和UDP数据包与解析IP报文类似,首先定义出各报文头部的数据结构类型,然后使用报头指针对结构成员进行访问。

针对数据长度为8位的字段通过结构成员直接存取,对于16位和32位长度的字段使用ntohs()或ntohl()转化为主机字节序列后再做后续处理;对于长度小于8位的字段(如标志位或子字段)可以通过结构体中定义位域存取。

图7 ICMP报文结构
图8 TCP报文结构
图9 UDP报文结构
5 部分主要源代码分析
5.1数据捕获模块
5.1.1 获取并列出网络设备列表
pcap_if_t *pAdaptersList=NULL; //网卡列表指针
pChar errbuf[PCAP_ERRBUF_SIZE]; //错误消息缓冲区
pcap_findalldevs(&pAdaptersList,errbuf); //获取本地网络设备列表
int iAdapterCount=0;
for(pcap_if_t
*pAdapter=pAdatersList;pAdapter!=NULL;pAdapter=pAdapter->next)
{
iAdapterCount++;
if(pAdapter->description) //如果有描述则输出详细信息
………………………….
else //否则输出网卡号
………………………….
}
5.1.2 由用户选择并打开指定网卡
………..
//跳到指定网卡
pAdapter=pAdapterslist;
for(int i=0;i<iAdapterSelected;i++)
pAdapter=pAdapter->next;
//打开网卡,bpromiscMode标志设为1表示混杂模式
pcap_t *hAdapterHandle;
hAdapterHandle=pcap_open_live(pAdapter->name,//网卡句柄
65535,//允许数据包的最大长度
bPromiscMode, // 混杂模式标志
300,//读取数据超时时间
errbuf ); //错误信息缓冲区
5.1.3 根据过滤规则设置过滤器
//pAdater指向要设置的网卡,首先获取子网掩码
u_int uNetMask;
if(pAdapter->addresser)
uNetMask=((sockadder_in*)(pAdapter->addresser->addresses->netmask))->sin_addr. s_addr;
else
uNetMask=oxffffff; //忽略子网掩码
char szFilterCode[1024];
....../*根据规则构造过滤表达式,并存放在szFileterCode缓冲区中*/
//编译过滤器
bpf_program fpcode;
if (pcap_compile(hAdapterHandle,&fpCode,szFilterCode,TRUE,uNetMask)<0) {TRACE(“unale to compile the filter.error Msg %s”,pcap_geterr(hAdapterHandle));
return;
}
//设置过滤器
pcap_setfilter(hAdapterHandle,&fpCode);
5.1.4 捕获数据包
While((iResult=pcap_next_ex(hAdapterHandle,&pPktHdr,&pPktData))>=0)
{
//接收超时继续循环
if(iResult==0)continue;
//处理收到的数据包
PacketHandler();
}
5.2协议解析模块
5.2.1 解析Ethernet帧
//MAC头部
typedef struct
{
BYTE DesMacAddr[6]; //目的地址
BYTE SrcMacAddr[6]; //源地址
WORD LengthOrType; //数据长度或类型
} MAC_HEADER;
//MAC帧类型
const u_short MAC_TYPE_IP = 0x0800;
const u_short MAC_TYPE_ARP = 0x0806;
const u_short MAC_TYPE_RARP = 0x8035;
MAC_HEADER* pMacHdr = (MAC_HEADER*) pPkt
//MAC目的地址
strItem.Format("%02X:%02X:%02X:%02X:%02X:%02X",
pMacHdr->SrcMacAddr[0],
pMacHdr->SrcMacAddr[1],
pMacHdr->SrcMacAddr[2],
pMacHdr->SrcMacAddr[3],
pMacHdr->SrcMacAddr[4],
pMacHdr->SrcMacAddr[5]);
// Mac目的地址
strItem.Format("%02X:%02X:%02X:%02X:%02X:%02X",
pMacHdr->DesMacAddr[0],
pMacHdr->DesMacAddr[1],
pMacHdr->DesMacAddr[2],
pMacHdr->DesMacAddr[3],
pMacHdr->DesMacAddr[4],
pMacHdr->DesMacAddr[5]);
//根据协议类型调用相应解析函数
if (ntohs(pMacHdr->LengthOrType) > 1500)
{
if (ntohs(pMacHdr->LengthOrType) == MAC_TYPE_IP) //IP协议
{
ParseIPPacket((BYTE*)pMacHdr+sizeof(MAC_HEADER),
pRawPacket->PktHeader.caplen-sizeof(MAC_HEADER));
}
else if (ntohs(pMacHdr->LengthOrType) == MAC_TYPE_ARP) //ARP协议
{
ParseARPPacket((BYTE*)pMacHdr+sizeof(MAC_HEADER),
pRawPacket->PktHeader.caplen-sizeof(MAC_HEADER));
}
else
{
//帧数据中报文类型未知
ctlList.AddItem(m_iIndex, 4, "UNKNOWN");
}
}
else //长度
{
Parse802Packet((BYTE*)pMacHdr+sizeof(MAC_HEADER),
pRawPacket->PktHeader.caplen-sizeof(MAC_HEADER));
}
5.2.2解析ARP数据包
//ARP头部
typedef struct
{
u_short hardware_type; //16位硬件类型
u_short proto_type; //16位协议类型
u_char hardware_addr_len; //8位硬件地址长度
u_char proto_addr_len; //8位协议地址长度
u_short operation_code; //16位操作码
u_char src_mac_addr[6]; //源以太网地址
u_char scr_ip_addr[4]; //源IP地址
u_char dest_mac_addr[6]; //目的以太网地址
u_char dest_ip_addr[4]; //目的IP地址
//ARP报文操作码类型
const u_short ARP_OP_REQUEST = 1;//ARP请求
const u_short ARP_OP_REPLY = 2;//ARP应答
//解析ARP报文------------------------------------------------------------
ARP_HEADER* pARPHdr = (ARP_HEADER*)pPkt;
ntohs(pARPHdr->hardware_type); //硬件类型
ntohs(pARPHdr->proto_type); //上层协议类型
pARPHdr->hardware_addr_len; //硬件地址长度
pARPHdr->proto_addr_len; //协议地址长度
//操作类型
if (ntohs(pARPHdr->operation_code) == ARP_OP_REQUEST)
strItem += " (Request)";
else if (ntohs(pARPHdr->operation_code) == ARP_OP_REPL Y)
strItem += " (Reply)";
//ARP头部子节点:源Mac地址
strItem.Format("Sender's hardware address: %02X:%02X:%02X:%02X:%02X:%02X",
pARPHdr->src_mac_addr[0],
pARPHdr->src_mac_addr[1],
pARPHdr->src_mac_addr[2],
pARPHdr->src_mac_addr[3],
pARPHdr->src_mac_addr[4],
pARPHdr->src_mac_addr[5]);
//ARP头部子节点:源IP地址
in_addr ipAddr;
memcpy(&ipAddr, pARPHdr->scr_ip_addr, sizeof(in_addr));
strItem.Format("Sender's IP address: %s", inet_ntoa(ipAddr));
tARPHdr.AddTail(strItem, IID_ADDRESS);
//ARP头部子节点:目的Mac地址
strItem.Format("Target's hardware address: %02X:%02X:%02X:%02X:%02X:%02X",
pARPHdr->dest_mac_addr[0],
pARPHdr->dest_mac_addr[1],
pARPHdr->dest_mac_addr[2],
pARPHdr->dest_mac_addr[3],
pARPHdr->dest_mac_addr[4],
pARPHdr->dest_mac_addr[5]);
//ARP头部子节点:目的IP地址
memcpy(&ipAddr, pARPHdr->dest_ip_addr, sizeof(in_addr));
strItem.Format("Target's IP address: %s", inet_ntoa(ipAddr));
//ARP头部子节点:填充字段
strItem.Format("Frame padding: %d bytes", iLen-sizeof(ARP_HEADER));
5.2.3解析IP数据包
//IP头部
typedef struct
{
unsigned char hdr_len :4; // 4位头部长度
unsigned char version :4; //4位版本号
unsigned char tos; // 8位服务类型
unsigned short total_len; // 16位总长度
unsigned short identifier; //16位标识符
unsigned short frag_and_flags; // 3位标志+13位片偏移
unsigned char ttl; //8位生存时间
unsigned char protocol; //8位上层协议号
unsigned short checksum; //16位校验和
unsigned long source_ip; // 32位目的地址
unsigned long dest_ip; // 32位目的偏移地址
} IP_HEADER;
//解析IP报文-------------------------------------------------
IP_HEADER* pIPHdr = (IP_HEADER*)pPkt;
…/*解析IP头部各字段并显示输出*/
//根据不同上层协议调用相应解析函数
switch (pIPHdr->protocol)
{
case IPPROTO_TCP:
strItem += "TCP";
ParseTCPPacket((BYTE*)pIPHdr+iIPHdrLen, iLen-iIPHdrLen, tParentCursor);
break;
case IPPROTO_UDP:
strItem += "UDP";
ParseUDPPacket((BYTE*)pIPHdr+iIPHdrLen, iLen-iIPHdrLen, tParentCursor);
break;
case IPPROTO_ICMP:
strItem += "ICMP";
ParseICMPPacket((BYTE*)pIPHdr+iIPHdrLen, iLen-iIPHdrLen, tParentCursor);
break;
case IPPROTO_IGMP:
strItem += "IGMP";
ParseIGMPPacket((BYTE*)pIPHdr+iIPHdrLen, iLen-iIPHdrLen, tParentCursor);
break;
default:
strItem += "OTHERS";
}
5.2.4解析ICMP、TCP和UDP数据包
//ICMP基本头部
typedef struct
{
BYTE type; //8位类型
BYTE code; //8位代码
USHORT cksum; //16位校验和
} ICMP_BASE_HEADER;
//----------------------------------------------------
//ICMP 回显头部
typedef struct
{
ICMP_BASE_HEADER base_hdr; //基本头部
USHORT id; //16位标识符
USHORT seq; //16位序列号
} ICMP_ECHO_HEADER;
//----------------------------------------------------
//ICMP差错报文头部
typedef struct
{
ICMP_BASE_HEADER base_hdr; //基本头部
ULONGunused; //32位未用,必须为0
} ICMP_ERROR_HEADER;
ICMP_BASE_HEADER* pICMPHdr = (ICMP_BASE_HEADER*)pPkt;
//ICMP头部子节点:类型
strItem.Format("Type: %d", pICMPHdr->type);
switch (pICMPHdr->type)
{
case ICMP_ECHO_REQUEST:
strItem += " (Echo Request)";
break;
case ICMP_ECHO_REPLY:
strItem += " (Echo Reply)";
break;
case ICMP_TIMEOUT:
strItem += " (Time Exceeded)";
break;
case ICMP_HOST_UNREACHABLE:
strItem += " (Destination Unreachable)";
break;
}
tICMPHdr.AddTail(strItem, IID_ITEM);
//ICMP头部子节点:代码
strItem.Format("Code: %d", pICMPHdr->code);
tICMPHdr.AddTail(strItem, IID_ITEM);
//ICMP头部子节点:校验和
strItem.Format("Checksum: 0x%04X", ntohs(pICMPHdr->cksum));
tICMPHdr.AddTail(strItem, IID_CHECKSUM);
//ICMP头部子节点:后续字段
switch (pICMPHdr->type)
{
case ICMP_ECHO_REQUEST:
case ICMP_ECHO_REPLY:
{
ICMP_ECHO_HEADER* pICMPEchoHdr = (ICMP_ECHO_HEADER*)pPkt;
//ICMP ECHO报文头部子节点:标识符
strItem.Format("Identifier: %d", ntohs(pICMPEchoHdr->id));
tICMPHdr.AddTail(strItem, IID_ITEM);
//ICMP ECHO报文头部子节点:序列号
strItem.Format("Sequence number: %d", ntohs(pICMPEchoHdr->seq));
tICMPHdr.AddTail(strItem, IID_ITEM);
//ICMP ECHO报文头部子节点:选项数据
if (iLen > sizeof(ICMP_ECHO_HEADER))
{
strItem.Format("Data: %d bytes", iLen-sizeof(ICMP_ECHO_HEADER));
tICMPHdr.AddTail(strItem, IID_INFORMATION);
}
break;
}
case ICMP_TIMEOUT:
case ICMP_HOST_UNREACHABLE:
{
//ICMP差错报文头部子节点:保留字段
ICMP_ERROR_HEADER* pICMPErrHdr = (ICMP_ERROR_HEADER*)pPkt;
strItem.Format("Unused: %d", ntohl(pICMPErrHdr->unused));
tICMPHdr.AddTail(strItem, IID_ITEM);
ParseIPPacket((BYTE*)pICMPErrHdr+sizeof(ICMP_ERROR_HEADER), iLen-sizeof(ICMP_ERROR_HEADER), tICMPHdr);
break;
}
}
6.使用说明
6.1启动:
程序启动后首先出现网卡选择对话框,如图1所示,在设备列表中选择需要进行捕获的网卡。

图10 网卡选择界面
6.2界面:
图11 程序界面
程序解析了ARP、IP、ICMP、TCP、UDP协议,但仍不全面,例如没有包括HTTP等协议,以后可对可解析的协议类型作进一步的扩充。

相关文档
最新文档