分享

pcap文件解析(三)

 mediatv 2014-03-15

这一章,我们将了解SCTP数据包结构,并简要介绍SCTP协议,最后将带有多个chunk的SCTP包拆分问单个SCTP数据包。

SCTP数据包

数据包头

Eth信息

IP头

SCTP头

SCTP Chunk 1

……

SCTP Chunk n

其中数据包头和IP头已经在前面做过介绍了,这里先简单介绍一下Eth信息。

  1. // Ethernet 信息  
  2. typedef struct__Ethernet_Info  
  3. {  
  4.         Byte    DestMac[6];  
  5.         Byte    SrcMac[6];  
  6.         _Int16  iType;  
  7.    
  8. } __EthernetInfo;  



DsetMac 目的主机mac地址

SrcMac   源主机MAC地址

Type 协议类型,IP为0x0800

 

SCTP简介


一个 SCTP 分组含了一个公共的分组头(Common Header)和若干数据块(Chunk),每个数据块中既可以包含控制信息,也可以包含用户数据。除了INIT、INIT ACK和SHUTDOWN COMPLETE 数据块外,其他类型的多个数据块可以捆绑在一个SCTP 分组中,以满足对 MTU 大小的要求。当然,这些数据块也可以不与其他数据块捆绑在一个分组中。如果一个用户消息不能放在一个SCTP 分组中,这个消息可以被分成若干个数据块。

SCTP头

         SCTP 公共分组头中包括了源端口号(Source Port Number)、目的端口号(Destination PortNumber)、验证标签(Verification Tag)和校验码(Checksum)

 1.源端口号(16 bits)

                   源端口号识别 SCTP 发送端点的SCTP 端口号。接收方可以使用源端口号、源IP 地址、目的端口号和目的IP 地址标识该SCTP 分组所属的偶联。

         2.目的端口号(16 bits)

                   目的端口号为目的端点的 SCTP 端口号。接收主机可以使用目的端口号将SCTP 分组解复用到正确的端点或应用中。

         3.验证标签(32 bits)

                   验证标签是偶联建立时,本端端点为这个偶联生成一个随机标识。偶联建立过程中,双方会交换这个TAG,到了数据传递时,发送端必须在公共分组头中带上对端的这个TAG,以备校验。

          4.校验码(32 bits)

                   SCTP 通过对用户数据使用ADLER-32 算法,计算出一个32 位的校验码,带在数据报中,在接收端进行同样的运算,通过检查校验码是否相等来验证用户数据是否遭到破坏。

数据块

         数据块包括了块类型(Chunk Type)、块标志位(Chunk Flags)、块长度(Chunk Length)和块值(Chunk Value )。

          1.块类型(8 bits)

                   块类型定义在块值(Chunk Value)中消息所属的类型。

                  

0 DATA(净数据) 传输的用户数据块。
1 INIT 用于发起两个端点之间的SCTP 偶联。
2 INIT ACK 用来确认SCTP 偶联的发起消息(INIT)。
3 SACK 该数据块送至对端,以确认收到DATA 块,并且通知对端DATA 的接收顺序间隙。
4 HEARTBEAT 端点发送该数据块至对端,以检测当前偶联中定义的某一目的地址的可达性。
5 HEARTBEAT ACK 响应HEARTBEAT 消息。
6 ABORT 关闭偶联。
7 SHUTDOWN 偶联中的一个端点对其偶联发起一个GRACEFUL关闭。
8 SHUTDOWN ACK 响应SHUTDOWN 消息,关闭程序完成时发出。
9 ERROR 通知对端,SCTP 偶联发生某种错误。
10 COOKIE ECHO 仅用于偶联发起过程,它由偶联的发起者发送至对端以完成发起程序。
11 COOKIE ACK COOKIE 证实,相对于COOKIE ECHO
12 ECNE 保留,应用于外部环境拥塞发布回声
13 CWR 保留,应用于降低拥塞窗口
14 SHUTDOWN COMPLETE用于关闭程序完成时对SHUTDOWN ACK 消息进行确认
15-62 IETF 保留
63 IETF 定义块扩展使用
64-126 IETF 保留
127 定义块扩展使用
128-190 IETF 保留
191 定义块扩展使用
192-254 IETF 保留
255 IETF 定义块扩展使用如果接收端点不能识别块类型时,块类型最高位2bit 用于标识需要进行的各种操作。

                            Bits(最高两位) 含义

                           

00 停止处理并丢弃此SCTP 分组,不再处理该SCTP 分组中的其他消息块。
01 停止处理并丢弃此SCTP 分组,不再处理该SCTP 分组中的其他消息块,并且在“ERROR”或“INIT ACK”中向发起端点返回不能识别的参数。
10  跳过此数据块并继续执行。
11 跳过此数据块并继续执行,并且在“ERROR”或“INIT ACK”中向发起端点返回不能识别的参数。

          2.数据块标志位(8bit)

                   块标志位用法由块类型决定。除非被置为其他值,块标记在传送过程中会被置0 而且接收端点会忽视块标记。

                   定义见:HTTP:\\

          3.块长度(16bit)

                   块长度包括块类型(Chunk Type)、块标记(Chunk Flags)、块长度(Chunk Length)和块值(Chunk Value),长度使用二进制表示。

          4.块值(可变长度)

                   块值的内容在块中传送实际的信息,内容由消息块类型决定。块值的长度为不定长。

SCTP结构体定义

  1. // SCTP头  
  2. typedef struct __Sctp_header  
  3. {  
  4.     _Int16 SrcPort;  
  5.     _Int16 DstPort;  
  6.   
  7.     _Int32 iVerTag;  
  8.     _Int32 iChecksum;  
  9. } __SctpHeader;  
  10.   
  11. // chunk头  
  12. typedef struct __Sctp_chunk_header  
  13. {  
  14.     Byte Type;  
  15.     Byte Flag;  
  16.     _Int16  iLength;  
  17. } __SctpChunkHeader;  
  18.   
  19. // 单个SCTP Chunk  
  20. typedef struct __Sctp_chunk  
  21. {  
  22.     __SctpChunkHeader header;  
  23.     Byte* pData;  
  24. } __SctpChunk;  


拆分SCTP数据块

         下面的代码将逐个解析数据包,当数据包位SCTP包时,对DATA chunk进行拆分。

  1. bool main()  
  2. {  
  3.         __pcap_header header;  
  4.         int iNo = 1;  
  5.          
  6.         // 打开源文件和输出文件  
  7.     if( !OpenPcapFile( "sctp.pcap")|| !OpenOutFile( "export.pcap"))  
  8.     {  
  9.         return false;  
  10.     }  
  11.    
  12.     // 获得文件头  
  13.     GetPcapHeader( &header);  
  14.         //写入文件头  
  15.         WriteFileHeader( &header);  
  16.    
  17.         MoveFirst();  
  18.         while( !IeEof())  
  19.         {  
  20.                __pk_header data;  
  21.                __ip_header ipData;  
  22.                __EthernetInfo ethInfo;  
  23.                Byte* pBuffer;  
  24.                // 获取下一个数据包  
  25.         GetPacketAndMoveNext( &data,&pBuffer);  
  26.                // 获得ETH信息  
  27.                GetEthernetInfo( eInfo, pBuffer,0);  
  28.                // 获得IP信息  
  29.         GetIpData( &ipData, pBuffer,sizeof(__EthernetInfo));  
  30.    
  31.         // SCTP == 132  
  32.         if( ipData.byteProtocol == 132)  
  33.         {  
  34.                        // 获取SCTP头  
  35.                        int iOffset = sizeof(__EthernetInfo) + ipData.byteHdLength * 4;  
  36.                        int iChunkOffset =iOffset + sizeof( __SctpHeader);  
  37.                        __SctpHeader sctpHeader;  
  38.                        __SctpChunksctpChunkArr[MAX_CHUNK_NUM];  
  39.                        // 当前已保存的chunk数量  
  40.                        int iChunkNum = 0;  
  41.                        // 当前已保存的chunk长度  
  42.                        int iLenght = 0;  
  43.                        // 获得SCTP头  
  44.                        GetSctpHeader(&sctpHeader, pBuffer, iOffset);  
  45.    
  46.                        whiletrue)  
  47.                        {  
  48.                                // 当前读取的chunk  
  49.                                __SctpChunksctpChunk;  
  50.                                // for 循环标志  
  51.                                int i = 0;  
  52.                                GetSctpChunk(&sctpChunk, pBuffer, iChunkOffset);  
  53.                                 
  54.                                if(sctpChunk.header.Type == 0) // DATA块  建立新数据包并写入chunk信息  
  55.                                {  
  56.                                       WritePkHeader(&data, iLenght + sctpChunk.header.iLength + LENGTH_SCTPALLHEADER(ipData));  
  57.                                       WriteEthInfo(eInfo);  
  58.                                       WriteIpHeader(&ipData, iLenght + sctpChunk.header.iLength + LENGTH_SCTPIPHEADER(ipData));  
  59.                                       WriteSctpHeader(&sctpHeader);  
  60.                                       for( i =0; i < iChunkNum; i++)  
  61.                                       {  
  62.                                               WriteSctpChunk(sctpChunkArr + i);  
  63.                                       }  
  64.                                       WriteSctpChunk(&sctpChunk);  
  65.                                       iChunkNum = iLenght = 0;  
  66.                                }  
  67.                                else  
  68.                                {  
  69.                                       // 当前块位非DATA块  
  70.                                       sctpChunkArr[iChunkNum++] = sctpChunk;  
  71.                                       iLenght +=sctpChunk.header.iLength;  
  72.                                }  
  73.    
  74.                                iChunkOffset +=sctpChunk.header.iLength;  
  75.    
  76.                                if( iChunkOffset>=  
  77.                                       ipData.iTotalLength- ((ipData.byteHdLength & 0x0f) * 4))  
  78.                                {  
  79.                                       if(iChunkNum > 0)  
  80.                                       {  
  81.                                               //存在未写入的chunk数据,全部新建数据包写入  
  82.                                               if(sctpChunk.header.Type != 0)  
  83.                                                      iLenght-= sctpChunk.header.iLength;  
  84.    
  85.                                               WritePkHeader(&data, iLenght + sctpChunk.header.iLength + LENGTH_SCTPALLHEADER(ipData));  
  86.                                               WriteEthInfo(eInfo);  
  87.                                               WriteIpHeader(&ipData, iLenght + sctpChunk.header.iLength + LENGTH_SCTPIPHEADER(ipData));  
  88.                                               WriteSctpHeader(&sctpHeader);  
  89.                                               for(i = 0; i < iChunkNum; i++)  
  90.                                               {  
  91.                                                      WriteSctpChunk(sctpChunkArr + i);  
  92.                                               }  
  93.                                       }  
  94.                                       break;  
  95.                                }  
  96.    
  97.                        }  
  98.         }  
  99.    
  100.         free( pBuffer);  
  101.         }  
  102.    
  103.      
  104.         CloseOutFile();  
  105.         ClosePcapFile();  
  106.         printf( "Export over");  
  107.         return true;  
  108. }  



源码下载:http://download.csdn.net/detail/yhangleo/4998322

 

IP checksum 计算 :http://blog.csdn.net/yhangleo/article/details/8508003

 

 


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多