在上一篇我們簡單認識pcap文件,現在我們來看看IP包的大致結構。
IP包
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Bit 1: (DF) 0 = May Fragment, 1 = Don't Fragment.
Bit 2: (MF) 0 = Last Fragment, 1 = More Fragments.
IP數據在PCAP文件中的位置
pcap頭 |
數據包頭 |
目的MAC、源MAC、TYPE(14字節) |
IP數據 |
…… |
數據包頭 |
目的MAC、源MAC、TYPE(14字節) |
IP數據 |
…… |
根據上表……在每個IP數據包中,IP數據的起始位置=數據包起始位置+包頭長度+14。
解析IP數據
#pragma pack( push, 1)
// 爲了保證在windows和linux下都能正常編譯,放棄使用INT64或者_int_64
typedef unsigned short _Int16;
typedef unsigned long _Int32;
typedef unsigned char Byte;
typedef int bool;
#define false 1
#define true 0
// Pcap文件頭
struct __file_header
{
_Int32 iMagic;
_Int16 iMaVersion;
_Int16 iMiVersion;
_Int32 iTimezone;
_Int32 iSigFlags;
_Int32 iSnapLen;
_Int32 iLinkType;
};
typedef struct __file_header __pcap_header;
// 數據包頭
struct __pkthdr
{
_Int32 iTimeSecond;
_Int32 iTimeSS;
_Int32 iPLength;
_Int32 iLength;
};
typedef struct __pkthdr __pk_header;
struct __iphdr
{
Byte byteVersions:4;
Byte byteHdLength:4;
Byte byteSerType;
_Int16 iTotalLength;
_Int16 iIdentification;
union
{
_Int16 iFlags;
_Int16 iFragmentOffset;
};
Byte byteTimeToLive;
Byte byteProtocol;
_Int16 iHeaderChecksum;
_Int32 iSourceAddress;
_Int32 iDestinationAddress;
};
// Flags
#define IP_DF 0x4000
#define IP_MF 0x2000
// FragmentOffset mask
#define IP_OFFMASK 0x1fff
typedef struct __iphdr __ip_header;
#pragma pack( pop)
pcap_adapter.h
#include <stdio.h>
#include "pcap_header.h"
// 打開Pcap文件
bool OpenPcapFile( char* strPath);
// 獲得Pcap文件頭
void GetPcapHeader( __pcap_header* pHeader);
// 獲得當前包內容 返回值爲buffer長度,buffer不含頭信息, 獲得信息後會自動跳轉到下個包頭
int GetPacketAndMoveNext( __pk_header* pPacket, Byte** pBuffer);
// 移動到第一個包的位置 讀取包數據前需要優先調用這個函數
bool MoveFirst();
// 是否已經到達文件尾
bool IeEof();
// 獲取ip信息
void GetIpData( /*out*/ __ip_header* pIpData , /*IN*/ Byte* pDataBuffer);
#include "pcap_adapter.h"
#include "value_checker.h"
#define NULL 0
#define CHECKFILE if( m_gpPcapFile == NULL) \
{ \
printf( "未打開文件"); \
return ; \
}
#define CHECKFILEEX(x) if( m_gpPcapFile == NULL) \
{ \
printf( "未打開文件"); \
return x; \
}
#define NTETOHOST_SHORT(x) x = t_ntohs(x)
#define NTETOHOST_LONG(x) x = t_ntohl(x)
FILE* m_gpPcapFile = NULL;
int m_giFileLength = 0;
bool OpenPcapFile( char* strPath)
{
m_gpPcapFile = fopen( strPath, "rb");
CHECKFILEEX(false);
fseek( m_gpPcapFile, 0, SEEK_END);
m_giFileLength = ftell( m_gpPcapFile);
fseek( m_gpPcapFile, 0, SEEK_SET);
return true;
}
void GetPcapHeader( __pcap_header* pHeader)
{
CHECKFILE;
// 保存當前遊標位置
int iNowPos = ftell( m_gpPcapFile);
fseek( m_gpPcapFile, 0, SEEK_SET);
fread( (void*)pHeader, sizeof( __pcap_header), 1,m_gpPcapFile);
fseek( m_gpPcapFile, iNowPos, SEEK_SET);
}
bool MoveFirst()
{
CHECKFILEEX(false);
return fseek( m_gpPcapFile, sizeof( __pcap_header), SEEK_SET) == 0;
}
int GetPacketAndMoveNext( __pk_header* pPacket, Byte** pBuffer)
{
CHECKFILEEX(0);
fread( (void*)pPacket, sizeof( __pk_header), 1,m_gpPcapFile);
*pBuffer = (Byte*)malloc( pPacket->iLength);
fread( (void*)*pBuffer, pPacket->iLength, 1,m_gpPcapFile);
return pPacket->iLength;
}
bool IeEof()
{
CHECKFILEEX(false);
int iNowPos = ftell( m_gpPcapFile);
return iNowPos >= m_giFileLength;
}
void GetIpData( /*out*/ __ip_header* pIpData , /*IN*/ Byte* pDataBuffer)
{
memcpy( (void*)pIpData, pDataBuffer + 14, sizeof( __ip_header));
NTETOHOST_SHORT(pIpData->iTotalLength);
NTETOHOST_SHORT( pIpData->iIdentification);
NTETOHOST_SHORT( pIpData->iFragmentOffset);
NTETOHOST_SHORT( pIpData->iHeaderChecksum);
NTETOHOST_LONG( pIpData->iSourceAddress);
NTETOHOST_LONG( pIpData->iDestinationAddress);
}
main.c
#include"pcap_adapter.h"
int main()
{
if( OpenPcapFile( "ZSRNC3_IUPS_inerface3.pcap"))
{
printf( "打開pcap文件失敗");
return 0;
}
__pcap_header header;
GetPcapHeader( &header);
int iNo = 1;
MoveFirst();
FILE* pwFile = fopen( "export-file.pcap", "wb");
fwrite((void*)&header, sizeof( __pcap_header), 1, pwFile);
while( !IeEof())
{
__pk_header data;
__ip_header ipData;
Byte* pBuffer;
GetPacketAndMoveNext( &data, &pBuffer);
GetIpData( &ipData, pBuffer);
// SCTP == 132
if( ipData.byteProtocol == 132)
{
fwrite( (void*)(&data), sizeof(struct __pkthdr), 1, pwFile);
fwrite( (void*)pBuffer, data.iLength, 1, pwFile);
}
free( pBuffer);
}
fclose( pwFile);
printf( "Export over");
return 1;
}