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;
}



  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值