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

来源:互联网 发布:java进阶书籍中级 编辑:程序博客网 时间:2024/04/29 21:48

在上一篇我们简单认识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_64typedef unsigned short _Int16;typedef unsigned long  _Int32;typedef unsigned char Byte;typedef int  bool;#define false 1#define true  0// Pcap文件头struct __file_header{_Int32iMagic;_Int16iMaVersion;_Int16iMiVersion;_Int32iTimezone;_Int32iSigFlags;_Int32iSnapLen;_Int32iLinkType;};typedef struct __file_header __pcap_header;// 数据包头struct __pkthdr{_Int32iTimeSecond;_Int32iTimeSS;_Int32iPLength;_Int32iLength;};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 0x1ffftypedef 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;}