pcap文件解析(二)--初識IP包

在上一篇我們簡單認識pcap文件,現在我們來看看IP包的大致結構。

IP包

在開始之前給大家推薦一個非常好用的工具RFCView,通過這個工具我們只需要輸入RFC(Request For Comments,基本的因特網通訊協定都有在RFC文件內詳細說明)號碼就能查看各種RFC文檔了。
在RFC791中詳細定義了IP包的數據結構,這裏做大致介紹:
 0 1 2 3
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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Version:版本號 4位
IHL:包頭長度,IHL並不直接表示包頭所佔用的長度,而是表示包頭佔用了多少個32位 4位
Type of Service: 服務類型,爲在數據傳輸中選擇具體網絡類型的摘要描述。 8位
Total Length: 總長度 16位
Identification: 用於組裝數據包的標識符 16位
Flags:控制表示 3位
  Bit 0: reserved, must be zero
Bit 1: (DF) 0 = May Fragment, 1 = Don't Fragment.
Bit 2: (MF) 0 = Last Fragment, 1 = More Fragments.

Fragment Offset:數據偏移 13位
 Time to Live:生命週期 8位
Protocol:協議類型,具體定義見:RFC790文檔 8位
Header Checksum:頭校驗碼 16位
Source Address:源地址 32位
Destination Address:目的地址 32位

IP數據在PCAP文件中的位置

pcap頭
數據包頭
目的MAC、源MAC、TYPE(14字節)
IP數據
……
數據包頭
目的MAC、源MAC、TYPE(14字節)
IP數據
……

根據上表……在每個IP數據包中,IP數據的起始位置=數據包起始位置+包頭長度+14。

解析IP數據

下面是一個重pacp文件中導出SCTP協議數據的程序。

pcap_header.h
#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);

pcap_adapter.c
#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;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章