常见的二层协议和三层协议结构以及IP头checksum计算方法

一、常见的二层协议

1、802.3/ETH2帧格式

常见的二层协议和三层协议结构以及IP头checksum计算方法_第1张图片

2、802.1Q VLAN帧格式

常见的二层协议和三层协议结构以及IP头checksum计算方法_第2张图片

3、802.11帧格式

总结:三种二层协议帧只有二层头不一样。换句话说,去掉二层头,上述三种二层协议帧都拥有相同的结构,包括:

802.2 LLC + 802.2 SNAP + data。

 

二、最常见的三层协议——IP协议

1、IP数据报格式(封装在802.3/ETH2/802.1Q/802.11等二层协议的数据字段)

常见的二层协议和三层协议结构以及IP头checksum计算方法_第3张图片

类似的还有ARP等。

三、常见的IP子协议

1、IP子协议1——ICMP

常见的二层协议和三层协议结构以及IP头checksum计算方法_第4张图片

2、IP子协议2——TCP

常见的二层协议和三层协议结构以及IP头checksum计算方法_第5张图片

3、IP子协议3——UDP

常见的二层协议和三层协议结构以及IP头checksum计算方法_第6张图片

常见的二层协议和三层协议结构以及IP头checksum计算方法_第7张图片

总结:三种IP子协议拥有相同的IP头格式,如下(对照二.1的图来看):

struct{
    uchar   ver;                  /* version and internet header length */
    uchar   tos;                  /* type of service,通过该字段指定有线报文的优先级 */
    ushort  totlen;             /* number of bytes in packet (max 65535) */
    ushort  usId;
    ushort  frag;                /* 3 flag bits and fragment offset */
    uchar   ttl;                    /* Time To Live */
    uchar   prot;                 /* Protocol ,ICMP/TCP/UDP等就通过这个字段区分*/
    ushort  chksum;           /* IP header checksum,如果修改了IP头某个字段,需要重新计算IP头checksum */
    uint    srcip;                  /* Source IP Address */
    uint    destip;                /* Destination IP Address */
} ip_headers;

三、IP头的修改注意事项

1、如果修改了IP头中的某个字段,需要重新计算IP头的校验和,并写回到IP头的chksum字段,对端接收到该

报文会利用该值对IP头做校验,校验通过,认为报文OK,否则丢弃报文。

2、具体操作流程如下

(1)修改IP头某个字段

(2)将IP头chksum字段清零

(3)计算IP头的checksum,方法参见博文:

   https://www.cnblogs.com/adamite/p/3317376.html

(4)将计算好的IP头的checksum写回IP头chksum字段

3.计算IP头checksum代码实现

USHORT CalIPHeaderChecksum(UCHAR *pstIPHeader, UINT uiLen)
{
    ULONG usChecksum = 0x0;

    while(uiLen > 1)
    {
        usChecksum += (USHORT)ntohs(*(USHORT*)pstIPHeader);
        pstIPHeader += sizeof(USHORT);    /* 每次累加2个字节 */
        uiLen -= sizeof(USHORT);                /* 需要计算的IP头长度减2字节 */
    }

    if(uiLen)        /* IP header长度为奇数的情况,普通IP首部长度为20个字节,除非含有选项字段(见TCP/IP协议卷) */
    {
        usChecksum += (USHORT)ntohs(*pstIPHeader);
    }
    while((usChecksum >> 16) != 0x0)    /* 如果有进位 */
    {
        usChecksum = (usChecksum >> 16) + (usChecksum & 0xffff);
    }
    return (USHORT)(~(USHORT)usChecksum);
}

 

你可能感兴趣的:(网络协议)