pcap文件格式是常用的數據報存儲格式,包括wireshark在內的主流抓包軟件都可以生成這種格式的數據包
下面對這種格式的文件簡單分析一下:
pcap文件的格式爲:
文件頭 24字節
數據報頭 + 數據報 數據包頭爲16字節,後面緊跟數據報
數據報頭 + 數據報 ......
文件頭 24字節
數據報頭 + 數據報 數據包頭爲16字節,後面緊跟數據報
數據報頭 + 數據報 ......
pcap.h裏定義了文件頭的格式
struct pcap_file_header {
bpf_u_int32 magic;
u_short version_major;
u_short version_minor;
bpf_int32 thiszone;
bpf_u_int32 sigfigs;
bpf_u_int32 snaplen;
bpf_u_int32 linktype;
};
struct pcap_file_header {
bpf_u_int32 magic;
u_short version_major;
u_short version_minor;
bpf_int32 thiszone;
bpf_u_int32 sigfigs;
bpf_u_int32 snaplen;
bpf_u_int32 linktype;
};
Pcap文件頭24B各字段說明:
Magic:4B:0×1A 2B 3C 4D:用來識別文件自己和字節順序。0xa1b2c3d4用來表示按照原來的順序讀取,0xd4c3b2a1表示下面的字節都要交換順序讀取。一般,我們使用0xa1b2c3d4
Major:2B,0×02 00:當前文件主要的版本號
Minor:2B,0×04 00當前文件次要的版本號
ThisZone:4B 時區。GMT和本地時間的相差,用秒來表示。如果本地的時區是GMT,那麼這個值就設置爲0.這個值一般也設置爲0 SigFigs:4B時間戳的精度;全零
SnapLen:4B最大的存儲長度(該值設置所抓獲的數據包的最大長度,如果所有數據包都要抓獲,將該值設置爲65535; 例如:想獲取數據包的前64字節,可將該值設置爲64)
LinkType:4B鏈路類型
常用類型:
0 BSD loopback devices, except for later OpenBSD
1 Ethernet, and Linux loopback devices
6 802.5 Token Ring
7 ARCnet
8 SLIP
9 PPP
10 FDDI
100 LLC/SNAP-encapsulated ATM
101 “raw IP”, with no link
102 BSD/OS SLIP
103 BSD/OS PPP
104 Cisco HDLC
105 802.11
108 later OpenBSD loopback devices (with the AF_value in network byte order)
113 special Linux “cooked” capture
114 LocalTalk
1 Ethernet, and Linux loopback devices
6 802.5 Token Ring
7 ARCnet
8 SLIP
9 PPP
10 FDDI
100 LLC/SNAP-encapsulated ATM
101 “raw IP”, with no link
102 BSD/OS SLIP
103 BSD/OS PPP
104 Cisco HDLC
105 802.11
108 later OpenBSD loopback devices (with the AF_value in network byte order)
113 special Linux “cooked” capture
114 LocalTalk
Packet 包頭和Packet數據組成
字段說明:
Timestamp:時間戳高位,精確到seconds(值是自從January 1, 1970 00:00:00 GMT以來的秒數來記)
Timestamp:時間戳低位,精確到microseconds (數據包被捕獲時候的微秒(microseconds)數,是自ts-sec的偏移量)
Caplen:當前數據區的長度,即抓取到的數據幀長度,由此可以得到下一個數據幀的位置。
Len:離線數據長度:網絡中實際數據幀的長度,一般不大於caplen,多數情況下和Caplen數值相等。
(例如,實際上有一個包長度是1500 bytes(Len=1500),但是因爲在Global Header的snaplen=1300有限制,所以只能抓取這個包的前1300個字節,這個時候,Caplen = 1300 )
Packet 數據:即 Packet(通常就是鏈路層的數據幀)具體內容,長度就是Caplen,這個長度的後面,就是當前PCAP文件中存放的下一個Packet數據包,也就 是說:PCAP文件裏面並沒有規定捕獲的Packet數據包之間有什麼間隔字符串,下一組數據在文件中的起始位置。我們需要靠第一個Packet包確定。 最後,Packet數據部分的格式其實就是標準的網路協議格式了可以任何網絡教材上找得到。
typedef struct tagIpHead
{
int version;//版本
int headLength; //頭長度
int diffsever;
int totallength; //總長度
int identification;
int flag;
int fragment;
int ttl;
int protocoltype; //協議類型
int checksum;
unsigned long srcip;//源ip
unsigned long dstip;//目的ip
}IP_HEAD;
typedef struct tagUdpHead
{
unsigned short srcport; //源端口
unsigned short dstport; //目的端口
int length; //udp包長度
}UDP_HEAD;
unsigned long FileParse::Parse( const char* FileName,bool& bThreadRun)//,HWND hwnd )
{
if (_wass_session)
{
delete _wass_session;
_wass_session = NULL;
}
_wass_session = new WassSessions();
//////////////////////////////////////////////////////////////////////////
unsigned long lRes =0;
FILE* pFile=NULL;
int nReadSize = 0;
char buff[FILE_READ_LEN];
char acip[30];
char portalip[30];
char radiusip[30];
unsigned long timestamp1;
unsigned long timestamp2;
CConfigure* config=new CConfigure();
if (config)
{
//讀取ip地址,添加到iplist中
unsigned long ipTmp=0;
unsigned short portTmp=0;
config->getIPConfig(acip,portalip,radiusip);
cut_ip(acip,ipTmp,portTmp);
acport_list.push_back(portTmp);
acip_list.push_back(ipTmp);
cut_ip(portalip,ipTmp,portTmp);
portalip_list.push_back(ipTmp);
portalport_list.push_back(portTmp);
delete config;
config = NULL;
}
//////////////////////////////////////////////////////////////////////////
memset(buff,0,FILE_READ_LEN);
do
{
pFile =fopen(FileName,"rb");
//pFile =_open( FileName, _O_RDONLY | _O_BINARY );
if (!pFile)
{
//failed for the file opened
fprintf(stderr, "Open the file failed:%s ", strerror(errno));
lRes = 2;
break;
}
nReadSize = fread(buff,sizeof(char),24,pFile);
if (nReadSize == 24)
{
while (!feof(pFile) && bThreadRun)
{
memset(buff,0,FILE_READ_LEN);
nReadSize = fread(buff,sizeof(char),16,pFile);
unsigned long nPacketLen=0;
memcpy(×tamp1,buff,4);
memcpy(×tamp2,buff+4,4);
memcpy(&nPacketLen,buff+8,4);
//nPacketLen = ntohl(nPacketLen);
char* buf = new char[nPacketLen];
memset(buf,0,nPacketLen);
int nReadCount=0;
//讀取包
while (nReadCount < nPacketLen)
{
nReadSize = fread(buff,sizeof(char),nPacketLen-nReadCount,pFile);
memcpy(buf+nReadCount,buff,nReadSize);
nReadCount += nReadSize;
}
//在此處處理ip/udp包部分
int nOffset=14;//數據偏移位置
_ip->Parse(buf+nOffset);//ip解析
if(_ip->wass_ip_head.protocoltype==17)//只處理UDP
{
nOffset += 20;
_udp->Parse(buf+nOffset);//udp解析
nOffset +=8;
std::list<unsigned long>::iterator acit= acip_list.begin();
std::list<unsigned long>::iterator portalit = portalip_list.begin();
bool bFoundIP = false;
//暫時不考慮算法,遍歷ip地址
//while (acit++ != acip_list.end())
for (;acit != acip_list.end();acit++)
{
unsigned long aIP = *acit;
char aTmp[20];
IPULongToString(aIP,aTmp);
IPULongToString(_ip->wass_ip_head.dstip,aTmp);
if (_ip->wass_ip_head.dstip== *acit || _ip->wass_ip_head.srcip == *acit)
{
for (;portalit !=portalip_list.end();portalit++)
{
if (_ip->wass_ip_head.dstip== *portalit || _ip->wass_ip_head.srcip == *portalit)
{
bFoundIP = true;
break;
}
}
break;
}
}
if (bFoundIP)
{
//此處是表示可以進行數據的解析
_portalPacket = new CPortalPacket();
_portalPacket->parse(buf + nOffset,nPacketLen - nOffset);
//設置包的源IP和目的IP,源端口,目的端口
_portalPacket->setIpAndPort(_ip->wass_ip_head.srcip,
_ip->wass_ip_head.dstip,_udp->wass_udp_head.srcport,_udp->wass_udp_head.dstport);
_portalPacket->setPacketTime(timestamp1,timestamp2);
_wass_session->AddPacket(_portalPacket,_sessions);
}
else
{
}
}
if (buf)
{
delete [] buf;
}
}
}
} while (false);
if (pFile)
{
fclose(pFile);
}
//////////////////////////////////////////////////////////////////////////
//::PostMessage(_hwnd,WM_FINISHED,0,0);
return lRes;
}