pcap文件解析(三)--拆分SCTP包

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

SCTP数据包

数据包头

Eth信息

IP头

SCTP头

SCTP Chunk 1

……

SCTP Chunk n

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

[cpp]  view plain copy
  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)中消息所属的类型。

                  

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

[cpp]  view plain copy
  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进行拆分。

[cpp]  view plain copy
  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( ðInfo, 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(ðInfo);  
  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(ðInfo);  
  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. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值