TCP/IP校验和

1. IP

https://www.cnblogs.com/xiehy/p/3166953.html

IP数据包也叫IP报文分组,传输在ISO网络7层结构中的网络层,它由IP报文头和IP报文用户数据组成,IP报文头的长度一般在2060个字节之间,而一个IP分组的最大长度则不能超过65535个字节。 
下图为IP分组的报文头格式,报文头的前20个字节是固定的,后面的可变。

 

版本:占4位(bit

IP协议的版本号。目前的主要版本为IPV4,即第4版本号,也有一些教育网和科研机构在使用IPV6。在进行通信时,通信双方的IP协议版本号必须一致,否则无法直接通信。 

首部长度:占4位(bit

IP报文头的长度。最大的长度(即4bit都为1时)为15个长度单位,每个长度单位为4字节(TCP/IP标准,DoubleWord),所以IP协议报文头的最大长度为60个字节,最短为上图所示的20个字节。

服务类型:占8位(bit

用来获得更好的服务。其中的前3位表示报文的优先级,后面的几位分别表示要求更低时延、更高的吞吐量、更高的可靠性、更低的路由代价等。对应位为1即有相应要求,为0则不要求。

总长度:16位(bit

指报文的总长度(包括报文头)。注意这里的单位为字节,而不是4字节,所以一个IP报文的的最大长度为65535个字节。

标志(flag

该字段用于标记该报文是否为分片(有一些可能不需要分片,或不希望分片),后面是否还有分片(是否是最后一个分片)。

片偏移

指当前分片在原数据报(分片前的数据报)中相对于用户数据字段的偏移量,即在原数据报中的相对位置。 

生存时间:TTLTime to Live

该字段表明当前报文还能生存多久。每经过1ms或者一个网关,TTL的值自动减1,当生存时间为0时,报文将被认为目的主机不可到达而丢弃。使用过Ping命令的用户应该有印象,在windows中输入ping命令,在返回的结果中即有TTL的数值。

协议

该字段指出在上层(网络7层结构或TCP/IP的传输层)使用的协议,可能的协议有UDPTCPICMPIGMPIGP等。 

首部校验和

用于检验IP报文头部在传播的过程中是否出错,主要校验报文头中是否有某一个或几个bit被污染或修改了。

IP地址:32位(bit

4个字节,每一个字节为0255之间的整数,及我们日常见到的IP地址格式。 

目的IP地址:32位(bit

4个字节,每一个字节为0255之间的整数,及我们日常见到的IP地址格式。

 

/*IP头定义,共20个字节*/
typedef struct _IP_HEADER
{
 char m_cVersionAndHeaderLen;       //版本信息(4),头长度(4)
 char m_cTypeOfService;            // 服务类型8
 short m_sTotalLenOfPacket;        //数据包长度
 short m_sPacketID;              //数据包标识
 short m_sSliceinfo;               //分片使用
 char m_cTTL;                  //存活时间
 char m_cTypeOfProtocol;          //协议类型
 short m_sCheckSum;             //校验和
 unsigned int m_uiSourIp;          //ip
 unsigned int m_uiDestIp;          //目的ip
} __attribute__((packed))IP_HEADER, *PIP_HEADER ;

2. IP校验和

https://www.cnblogs.com/yd1227/archive/2011/06/30/2094309.html

当发送IP包时,需要计算IP报头的校验和:

1、  把校验和字段置为0

2、  对IP头部中的每16bit进行二进制求和;

3、  如果和的高16bit不为0,则将和的高16bit和低16bit反复相加,直到和的高16bit0,从而获得一个16bit的值;

4、  将该16bit的值取反,存入校验和字段。

3. TCP head

https://www.cnblogs.com/li-hao/archive/2011/12/07/2279912.html

 

源端口:  长度为16位,2个字节。

目的端口:  长度为16位,2个字节。

    IP实现了点到点的数据通信,而TCP实现的是端到端的通信。

    通信端用一个IP与端口号来唯一标识。(其实端口号就是用来标识同一主机中的不同进程。)

    IP协议负责将数据传输到目标主机,而TCP可以根据数据报中的端口号,将数据交给相应的程序进行处理。

 

序列号: 长度32位,4个字节。

确认序列号:长度32位,4个字节。

头部长度:该字段占用4位,用来表示报文首部的长度,单位是4Byte。如:headLen = ((packet[12]>>4)&0x0F)*4;

预留6位:长度为6位,作为保留字段,暂时没有什么用处。

 

URG:长1位,表示紧急指针字段有效;

ACK:长1位,置位表示确认号字段有效;

PSH:长1位,表示当前报文需要请求推(push)操作;

RST:长1位,置位表示复位TCP连接;

SYN:长1位,用于建立TCP连接时同步序号;

FIN:长1位,用于释放TCP连接时标识发送方比特流结束;

 

窗口大小:长度为16位,2个字节。

校验和:长度为16位,2个字节。

紧急指针:长度为16位,2个字节。

以上是TCP包头必须要有的字段,也称固有字段,长度为20个字节。

可选项:此项是可选项(可有可无),解包时得具体分析(TCP包头的一部分)

 

/*TCP头定义,共20个字节*/
typedef struct _TCP_HEADER
{
 short m_sSourPort;              // 源端口号16bit
 short m_sDestPort;              // 目的端口号16bit
 unsigned int m_uiSequNum;         // 序列号32bit
 unsigned int m_uiAcknowledgeNum;  // 确认号32bit
 short m_sHeaderLenAndFlag;        // 4位:TCP头长度;中6位:保留;后6位:标志位
 short m_sWindowSize;            // 窗口大小16bit
 short m_sCheckSum;              // 检验和16bit
 short m_surgentPointer;           // 紧急数据偏移量16bit
}__attribute__((packed))TCP_HEADER, *PTCP_HEADER;


/*TCP头中的选项定义

kind(8bit)+Length(8bit,整个选项的长度,包含前两部分)+内容(如果有的话)

KIND = 1表示 无操作NOP,无后面的部分

  2表示 maximum segment   后面的LENGTH就是maximum segment选项的长度(以byte为单位,1+1+内容部分长度)

  3表示 windows scale     后面的LENGTH就是 windows scale选项的长度(以byte为单位,1+1+内容部分长度)

  4表示 SACK permitted    LENGTH2,没有内容部分

  5表示这是一个SACK     LENGTH2,没有内容部分

  8表示时间戳,LENGTH10,含8个字节的时间戳
*/

typedef struct _TCP_OPTIONS
{
 char m_ckind;
 char m_cLength;
 char m_cContext[32];
}__attribute__((packed))TCP_OPTIONS, *PTCP_OPTIONS;

4. TCP校验和

TCP头前加一个伪首部,其它步骤和IP类似。

 

        unsigned short CheckSum(unsigned short *_pBuff, int _Size)

        {

            unsigned int ckSum = 0;

 

            unsigned short *tmpBuff = _pBuff;

            int tmpSize = _Size;

 

            while (tmpSize > 1)

            {

                ckSum += *tmpBuff ++;

                tmpSize -= sizeof(unsigned short);

            }

 

            if (tmpSize > 0)

            {

                ckSum += *(unsigned char*)tmpBuff;

            }

 

            ckSum = (ckSum >> 16) + (ckSum & 0xFFFF); //将高16bit与低16bit相加

            ckSum += (ckSum >> 16); //将进位到高位的16bit与低16bit 再相加

 

            return (unsigned short)(~ckSum);

        }

 

5. 检验和更新

https://blog.csdn.net/qq_43395215/article/details/103414009

如果在报文的转发路径中遇到需要修改iptcp中部分报文字段,那么校验和需要重新计算。

当修改只是一小部分时,可以用下列方法更新校验和。

IP头校验和、TCP/UDP校验和更新

 

 

unsigned short updateCheckSum(unsigned short wOldCheckSum, unsigned short wOld, unsigned short wNew) {

    unsigned int dwCheckSum = wOldCheckSum + wOld + (~wNew & 0xFFFF);

    dwCheckSum = (dwCheckSum >> 16) + (dwCheckSum & 0xFFFF);

    dwCheckSum +=  (dwCheckSum >> 16);

    return  (unsigned short)dwCheckSum;

}

 

unsigned short updateCheckSum32(unsigned short wOldCheckSum, unsigned int dwOld, unsigned int dwNew) {

    return UpdateCheckSum(UpdateCheckSum(wOldCheckSum, (unsigned short) (dwOld >> 16), (unsigned short) (dwNew >> 16)), (unsigned short) dwOld, (unsigned short) dwNew);

}

posted on 2020-03-14 11:06  SunnyPoem  阅读(5722)  评论(0编辑  收藏  举报