精华内容
下载资源
问答
  • IP首部检验和详细计算步骤

    千次阅读 2021-06-22 14:25:52
    可是我翻来找去,发现课本上这部分的描述十分的.......干净利索。 IP首部的检验和不采用复杂的CRC检验码而采用下面的简单计算方法: 在发送方,先把IP数据报首部划分为许多16位字的序列,并把检验和字段置零。...

    前言

    前段时间自己在做计算机网络的期末课设,题目就是关于IP首部检验和的计算程序的实现,要实现这个程序的首要步骤就是要搞明白相关的计算原理。可是我翻来找去,发现课本上对这部分的描述十分的.......干净利索。

    IP首部的检验和不采用复杂的CRC检验码而采用下面的简单计算方法:

    在发送方,先把IP数据报首部划分为许多16位字的序列,并把检验和字段置零。用反码算术运算把所有16位字相加后,将得到的和的反码写入检验和字段。

    接收方收到数据报后,将首部的所有16位字再使用反码算术运算相加一次。将得到的和取反码,即得出接收方检验和的计算结果。

    若首部未发生任何变化,则此结果必为0,于是就保留这个数据报。否则即认为出差错。

     说句实话,当时我看完这段话之后,本来只有一个问题在阻碍着我,然后一个问题就变成了很多的问题。

    既然课本看不懂那我就去网上找找,没想到找到的结果也和课本上差不多,基本没啥用。给的例子看着好像很详细,实际上知识点非常的混乱,东说一句,西说一句,在完全不了解原理之前这些东西简直就是天书(至少在当时的我看来是这样的)。不过好在最后还是通过为数不多的高质量文章知道了如何计算IP首部检验和及其具体计算步骤,所以在这做一个详细的计算方法的总结与说明,以尽可能的帮助那些有类似经历的朋友 。

    “什么是IP数据报”,“IP首部检验和是干什么用”,类似的理论叙述就不在这里详细阐述了,直接上方法。

    详细计算步骤

    要计算IP首部检验和,我们得先知道在IP数据报的固定部分里有什么字段(这个不是套话,很重要),以下12个字段是我们待会在计算过程中使用到的数据。

    ①版本(Version)   ②首部长度(Header Length)   ③区分服务(Differentiated Service Field) 

    ④总长度(Total Length)         ⑤标识 (Identification)            ⑥标志 (Flags)

    ⑦片偏移(Fragment Offset)   ⑧生存时间 (Time to Live)     ⑨协议(Protocol)

    ⑩首部检验和(Header CheckSum)        ⑩①源地址(Source Address) 

    ⑩②目的地址 (Destination Address)

    上面这张图是我在WireShark中随机抓取的一个IP数据报的报头部分的数据。

    通过分析这个数据报,结合上面说的12个字段,我们可以得到以下信息:

    (1)版本 = 4            (2)首部长度 = 5     (3)区分服务 = 0x00      (4)总长度 = 40

    (5)标识 = 5386 (0x150a)               (6)标志 = 0x40                 (7)片偏移 = 0

    (8)生存时间 = 128                            (9)协议 = 6                      (10)首部检验和 = 0x72e3

    (11)源地址 = 192.168.1.176            (12)目的地址 = 39.106.137.32

    这里稍微介绍一下“协议”字段,课本上对协议的字段值是这么说明的:

    协议名ICMPIGMPIPTCPEGPIGPUDPIPv6ESPOSPF
    协议字段值12468917415089

     即什么协议就取其对应的值,上面的数据报里的协议是TCP,所以取的值是6。

    在了解了上述知识点后,现在我们可以开始计算了。为了更为直观的说明计算过程,接下来均采用二进制数据作为计算数据。实际上,采用二进制数据进行计算与采用十六进制数据进行计算并无区别,读者可根据自身情况进行选择。 

    将上述11个字段(除了首部检验和)转为二进制这里提一嘴,在实际的程序中,包内的首部检验和是要置零然后要参与计算的,但是因为“将首部检验和置零参与计算”和“将首部检验和排除在外然后计算”,这两者在计算结果上没有任何区别。所以,遵循怎么简单怎么来的原则,在下面的计算步骤中就不再涉及首部检验和,大家心里有个数就好,并进行字段拼接。

    要注意的是,每个拼接的字段长度均为 16 位(拼接规则:每个字段括号内的数字为该字段转为二进制的最长位数,若该字段转为二进制后小于所规定的最长位数,则在该二进制首位添零,直至达到最长位数)。(“+”表示拼接)

    ① 版本(4) + 首部长度(4) + 区分服务(8)

    ② 总长度(16)

    ③ 标识(16)

    ④ 标志(8) + 片偏移(8)

    ⑤ 生存时间(8) + 协议(8)

    ⑥ 源地址第一部分(8) + 源地址第二部分(8)

    ⑦ 源地址第三部分(8) + 源地址第四部分(8)

    ⑧ 目的地址第一部分(8) + 目的地址第二部分(8)

    ⑨ 目的地址第三部分(8) + 目的地址第四部分(8)


    由此,将得到的11个字段通过上述转换,我们可以得到如下数据(“+”表示拼接):

    0100 0101 0000 0000(4 + 5 + 00)

    0000 0000 0010 1000(40)

    0001 0101 0000 1010(5386)

    0100 0000 0000 0000(40 + 0)

    1000 0000 0000 0110(128 + 6)

    1100 0000 1010 1000(192 + 168)

    0000 0001 1011 0000(1 + 176)

    0010 0111 0110 1010(39 + 106)

    1000 1001 0010 0000(137 + 32)

    将这 9 个二进制数据相加,我们可以得到 0010 1000 1101 0001 10100x2 8d1a

    可以看出,累加后的数据发生了进位,即 0b0010(0x0002)部分。

    是否发生了进位可以通过位数进行判断,以二进制为例,从最后一位开始向前数 16 位,超出的位数即进位部分(0010),若该二进制数刚好为16 位,则说明未发生进位。

    若发生了进位情况,只需要将进位部分(0010)与剩余部分(1000 1101 0001 1010)重新累加,直至得到的二进制数据位数等于 16 位,然后对该二进制数据取反码,即可得到首部检验和。此处可以用递归的思想实现,长度 > 16 继续递归,else return 当前计算结果

    0010(进位部分) + 1000 1101 0001 1010(剩余部分) = 1000 1101 0001 1100,此时位数为 16 位,未发生进位,则无需累加。对该二进制取反码,可以得到 0111 0010 1110 00110x72e3,该计算结果与包内IP首部检验和相同,计算完成。 

    结语

    以上就是IP首部检验和的计算步骤,都是较为详尽的步骤。对刚接触该方法的读者来说,个人建议采用二进制的计算模式,二进制在字段拼接上比较直观易懂,能使读者尽快的了解字段拼接规则。但二进制在计算方面较为冗长,容易在累加的过程中出现错误;如果读者对该计算思想有了较为清晰的认识,可以改为采用十六进制数据进行计算,这样在计算方面会比二进制简短不少,同时也不容易出错。

    展开全文
  • java ip首部效验和

    2020-12-07 20:31:32
    大学生网络实验课 (1)在界面上,用户能够输入或编辑IP协议包各字段数据,例如,“协议”字段应该是下拉选择 方式; (2)程序能够自动检查IP地址的合法性,且主机可用;...检验“首部校验和”字段的计算结果:
  • IP首部检验和的理解

    千次阅读 2014-04-14 13:57:26
    很多文章ip首部检验和的计算介绍得很简略,在理解上常常会比较困难。这篇文章是我自己的一些理解。或许也有不正确的地方,希望大家指正。 这个问题一直困绕了我很长时间,今天终于理解了。 我们可以通过spynet ...
    很多文章对ip首部检验和的计算介绍得很简略,在理解上常常会比较困难。这篇文章是我自己的一些理解。或许也有不正确的地方,希望大家指正。
    
    这个问题一直困绕了我很长时间,今天终于理解了。 


    我们可以通过spynet sniffer抓包软件,抓取一个ip数据包进行分析研究。
    下面我以本机抓到的一个完整的ip首部为例(红色字体表示):

    0000: 00 e0 0f 7d 1e ba 00 13 8f 54 3b 70 08 00 45 00
    0010: 00 2e be 55 00 00 7a 11 51 ac de b7 7e e3 c0 a8
    0020: 12 7a

    45 00 00 2e----4表示ip版本号为ip第4版;5表示首部长度为5个32 bit字长,即为20字节;00 2e表示ip总长度为46字节,其中ip数据部分为
    26字节。
    be 55 00 00----be 55表示标识符;00 00表示3 bit标志及13 bit片偏移量;
    7a 11 51 ac----7a表示ttl值为122;11表示协议号为17的udp协议;51 ac表示16 bit首部检验和值;
    de b7 7e e3----表示32 bit 源ip地址为222.183.126.227
    c0 a8 12 7a----表示32 bit 目的ip地址为192.168.18.122



    检验和计算:
    首先,把检验和字段置为0。
    45 00 00 2e
    be 55 00 00
    7a 11 00 00<----检验和置为0
    de b7 7e e3
    c0 a8 12 7a
    其次,对整个首部中的每个16 bit进行二进制反码求和,即4500+002e+be55+7a11+..+127a求和值为3ae50,然后3+ae50=ae53(这是根据源代码中算法 cksum = (cksum
    >> 16) + (cksum & 0xffff) 进行的 )

    最后,ae53+51ac=ffff。因此判断ip首部在传输过程中没有发生任何差错。
    展开全文
  • MAC首部 IP首部 TCP首部介绍

    千次阅读 2020-07-24 12:12:46
    了解数据传输过程中的MAC帧首部,IP数据包首部,TCP首部。了解结构是基本,为了直观显示,本文采用抓包的方式逐层验证这些首部结构。同时,列出这些首部结构在系统中C语言结构体的实现。

    0. 前言

    因为原生套接字编程,需要了解数据传输过程中的MAC帧首部,IP数据包首部,TCP首部。了解结构是基本,为了直观显示,本文采用抓包的方式逐层验证这些首部结构。同时,列出这些首部结构在系统中C语言结构体的实现。

    抓包工具采用:tcpdump + wireshark

    工具使用方法:超详细的网络抓包神器 tcpdump 使用指南实战!我用 Wireshark 让你“看见“ TCP

    (“实战!我用 Wireshark 让你“看见TCP” 是一篇很好的文章,介绍了TCP的三次握手;握手过程中包丢失的几种情况等)

    1. 使用tcpdump抓取数据包

      # 数据准备
      sudo tcpdump -nn tcp and host www.baidu.com -w http.pcap
      curl www.baidu.com
      
    2. 使用wireshark展示数据包内容
      在这里插入图片描述


    1. 背景介绍

    了解主机之间的数据传输过程

    在这里插入图片描述

    了解数据封装和解封装过程,下面图片传输层使用TCP进行举例。

    在这里插入图片描述

    这里值得特别注意的是,在每一层,有不同的英文术语来对应包的概念,比如在 TCP 层的包叫做 Segment,在 IP 层的叫做 Packet,在链路层的叫做 Frame,另外和 TCP 位于同一层的 UDP 包我们一般叫做 Datagram


    3. MAC首部

    以太帧有很多种类型。不同类型的帧具有不同的格式和MTU值。

    如何选择使用哪种格式的帧我不知道。下面仅仅看Ethernet_II 帧格式

    在这里插入图片描述

    字段含义
    目的地址接收帧的网络适配器的物理地址(MAC 地址),为 6 个字节(48 比特)。作用是当网卡接收到一个数据帧时,首先会检查该帧的目的地址,是否与当前适配器的物理地址相同,如果相同,就会进一步处理;如果不同,则直接丢弃。
    源地址发送帧的网络适配器的物理地址(MAC 地址),为 6 个字节(48 比特)。
    类型上层协议的类型。由于上层协议众多,所以在处理数据的时候必须设置该字段,标识数据交付哪个协议处理。例如,字段为 0x0800 时,表示将数据交付给 IP 协议。
    数据也称为效载荷,表示交付给上层的数据。以太网帧数据长度最小为 46 字节,最大为 1500 字节。如果不足 46 字节时,会填充到最小长度。最大值也叫最大传输单元(MTU)。 在 Linux 中,使用 ifconfig 命令可以查看该值,通常为 1500。
    帧检验序列 FCS检测该帧是否出现差错,占 4 个字节(32 比特)。发送方计算帧的循环冗余码校验(CRC)值,把这个值写到帧里。接收方计算机重新计算 CRC,与 FCS 字段的值进行比较。如果两个值不相同,则表示传输过程中发生了数据丢失或改变。这时,就需要重新传输这一帧。

    在这里插入图片描述

    // 结构体位置:/usr/include/net/ethernet.h
    struct ether_header
    {
      uint8_t  ether_dhost[ETH_ALEN];	/* destination eth addr	*/
      uint8_t  ether_shost[ETH_ALEN];	/* source ether addr	*/
      uint16_t ether_type;		        /* packet type ID field	*/
    } __attribute__ ((__packed__));
    

    4. IP首部

    IP首部分为IPv4首部和IPv6首部,下面仅仅列出IPv4首部。

    IPv4 数据报头字段如图所示。
    在这里插入图片描述

    IP 报头的最小长度为 20 字节,上图中每个字段的含义如下:

    1) 版本(version)

    占 4 位,表示 IP 协议的版本。通信双方使用的 IP 协议版本必须一致。

    2) 首部长度(网际报头长度IHL)

    占 4 位,可表示的最大十进制数值是 15。这个字段所表示数的单位是 32 位字长(1 个 32 位字长是 4 字节)。因此,当 IP 的首部长度为 1111 时(即十进制的 15),首部长度就达到 60 字节。当 IP 分组的首部长度不是 4 字节的整数倍时,必须利用最后的填充字段加以填充。

    数据部分永远在 4 字节的整数倍开始,这样在实现 IP 协议时较为方便。首部长度限制为 60 字节的缺点是,长度有时可能不够用,之所以限制长度为 60 字节,是希望用户尽量减少开销。最常用的首部长度就是 20 字节(即首部长度为 0101),这时不使用任何选项。

    3) 区分服务(tos)

    也被称为服务类型,占 8 位,用来获得更好的服务。这个字段在旧标准中叫做服务类型,但实际上一直没有被使用过。1998 年 IETF 把这个字段改名为区分服务(Differentiated Services,DS)。只有在使用区分服务时,这个字段才起作用。

    4) 总长度(totlen)

    首部和数据之和,单位为字节。总长度字段为 16 位,因此数据报的最大长度为 2^16-1=65535 字节。

    5) 标识(identification)

    用来标识数据报,占 16 位。IP 协议在存储器中维持一个计数器。每产生一个数据,计数器就加 1,并将此值赋给标识字段。当数据报的长度超过网络的 MTU,而必须分片时,这个标识字段的值就被复制到所有的数据报的标识字段中。具有相同的标识字段值的分片报文会被重组成原来的数据报

    6) 标志(flag)

    占 3 位。第一位未使用,其值为 0。第二位称为 DF(不分片),表示是否允许分片。取值为 0 时,表示允许分片;取值为 1 时,表示不允许分片。第三位称为 MF(更多分片),表示是否还有分片正在传输,设置为 0 时,表示没有更多分片需要发送,或数据报没有分片。

    7) 片偏移(offsetfrag)

    占 13 位。**当报文被分片后,该字段标记该分片在原报文中的相对位置。**片偏移以 8 个字节为偏移单位。所以,除了最后一个分片,其他分片的偏移值都是 8 字节(64 位)的整数倍。

    8) 生存时间(TTL)

    表示数据报在网络中的寿命,占 8 位。该字段由发出数据报的源主机设置。其目的是防止无法交付的数据报无限制地在网络中传输,从而消耗网络资源。

    路由器在转发数据报之前,先把 TTL 值减 1。若 TTL 值减少到 0,则丢弃这个数据报,不再转发。因此,TTL 指明数据报在网络中最多可经过多少个路由器。TTL 的最大数值为 255。若把 TTL 的初始值设为 1,则表示这个数据报只能在本局域网中传送。

    9) 协议

    表示该数据报文所携带的数据所使用的协议类型,占 8 位。该字段可以方便目的主机的 IP 层知道按照什么协议来处理数据部分。不同的协议有专门不同的协议号。

    例如,TCP 的协议号为 6,UDP 的协议号为 17,ICMP 的协议号为 1。

    10) 首部检验和(checksum)

    用于校验数据报的首部,占 16 位。数据报每经过一个路由器,首部的字段都可能发生变化(如TTL),所以需要重新校验。而数据部分不发生变化,所以不用重新生成校验值。

    11) 源地址

    表示数据报的源 IP 地址,占 32 位。

    12) 目的地址

    表示数据报的目的 IP 地址,占 32 位。该字段用于校验发送是否正确。

    13) 可选字段

    该字段用于一些可选的报头设置,主要用于测试、调试和安全的目的。这些选项包括严格源路由(数据报必须经过指定的路由)、网际时间戳(经过每个路由器时的时间戳记录)和安全限制。

    14) 填充

    由于可选字段中的长度不是固定的,使用若干个 0 填充该字段,可以保证整个报头的长度是 32 位的整数倍。

    15) 数据部分

    表示传输层的数据,如保存 TCP、UDP、ICMP 或 IGMP 的数据。数据部分的长度不固定。

    我不进行标注了,标注比较麻烦,可自行对比数据,我从网上找了张图。

    在这里插入图片描述

    IP头部结构体实现有两种定义方式,如下所示。这两种有什么区别?分别在什么场合下使用?

    我目前仅仅看到这一篇:Difference between struct ip and struct iphdr

    struct ip and struct iphdr are two different definitions of the same underlying structure, brought in from different places.

    struct ip is defined in <netinet/ip.h>, which is a reasonably standard header on UNIX systems.

    struct iphdr is defined in <linux/ip.h>. This header (and structure) are Linux-specific, and will not be present in other operating systems.

    If you’re not sure which one to use, use struct ip; code which uses this structure is more likely to be portable to non-Linux systems.

    // 结构体位置 /usr/include/netinet/ip.h
    struct iphdr
      {
    #if __BYTE_ORDER == __LITTLE_ENDIAN
        unsigned int ihl:4;
        unsigned int version:4;
    #elif __BYTE_ORDER == __BIG_ENDIAN
        unsigned int version:4;
        unsigned int ihl:4;
    #else
    # error	"Please fix <bits/endian.h>"
    #endif
        uint8_t tos;
        uint16_t tot_len;
        uint16_t id;
        uint16_t frag_off;
        uint8_t ttl;
        uint8_t protocol;
        uint16_t check;
        uint32_t saddr;
        uint32_t daddr;
        /*The options start here. */
      };
    
    struct ip
      {
    #if __BYTE_ORDER == __LITTLE_ENDIAN
        unsigned int ip_hl:4;		/* header length */
        unsigned int ip_v:4;		/* version */
    #endif
    #if __BYTE_ORDER == __BIG_ENDIAN
        unsigned int ip_v:4;		/* version */
        unsigned int ip_hl:4;		/* header length */
    #endif
        uint8_t ip_tos;			/* type of service */
        unsigned short ip_len;		/* total length */
        unsigned short ip_id;		/* identification */
        unsigned short ip_off;		/* fragment offset field */
    #define	IP_RF 0x8000			/* reserved fragment flag */
    #define	IP_DF 0x4000			/* dont fragment flag */
    #define	IP_MF 0x2000			/* more fragments flag */
    #define	IP_OFFMASK 0x1fff		/* mask for fragmenting bits */
        uint8_t ip_ttl;			/* time to live */
        uint8_t ip_p;			/* protocol */
        unsigned short ip_sum;		/* checksum */
        struct in_addr ip_src, ip_dst;	/* source and dest address */
      };
    

    5. TCP首部

    在这里插入图片描述

    1. 源端口和目的端口:各占2个字节.端口是传输层和应用层的服务接口。传输层的复用和分用功能都有要通过端口才能实现。

    2. 序号:占4个字节,序号范围是(0,2^32 - 1),共2^32 (即4294967296)个序号。序号增加到2^32-1后,下一个序号就又回到0。也就是说,序号使用mod 2^32运算。TCP是面向字节流的。在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。整个要传送的字节流的起始序号必须在连接建立时设置。首部中的序号字段值则是指的是本报文段所发送的数据的第一个字节的序号。例如,一报文段的序号是301,而接待的数据共有100字节。这就表明:本报文段的数据的第一个字节的序号是301,最后一个字节的序号是400。显然,下一个报文段(如果还有的话)的数据序号应当从401开始,即下一个报文段的序号字段值应为401。这个字段的序号也叫“报文段序号”。

    3. 确认号:占4字节,是期望收到对方下一个报文段的第一个数据字节的序号。例如,B正确收到了A发送过来的一个报文段,其序号字段值是501,而数据长度是200字节(序号501~700),这表明B正确收到了A发送的到序号700为止的数据。因此,B期望收到A的下一个数据序号是701,于是B在发送给A的确认报文段中把确认号置为701。注意,现在确认号不是501,也不是700,而是701。

      若确认号为N,则表明,起始序号到序号N-1为止的所有数据都已正确收到,期望的序号是N。

    4. 数据偏移(即首部长度):占4位,它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。这个字段实际上是指出TCP报文段的首部长度。由于首部中还有长度不确定的选项字段,因此数据偏移字段是必要的,但应注意,“数据偏移”的单位是32位字(即以4字节的字为计算单位)。由于4位二进制数能表示的最大十进制数字是15,因此数据偏移的最大值是60字节,这也是TCP首部的最大字节(即选项长度不能超过40字节)。

    5. 保留:占6位,保留为今后使用,但目前应置为0。

    6. 紧急URG(URGent):占1位, 当URG=1时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快发送(相当于高优先级的数据),而不要按原来的排队顺序来传送。例如,已经发送了很长的一个程序要在远地的主机上运行。但后来发现了一些问题,需要取消该程序的运行,因此用户从键盘发出中断命令。如果不使用紧急数据,那么这两个字符将存储在接收TCP的缓存末尾。只有在所有的数据被处理完毕后这两个字符才被交付接收方的应用进程。这样做就浪费了很多时间。当URG置为1时,发送应用进程就告诉发送方的TCP有紧急数据要传送。于是发送方TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍然是普通数据。这时要与首部中紧急指针(Urgent Pointer)字段配合使用。

    7. 确认ACK(ACKnowledgment):占1位, 仅当ACK = 1时确认号字段才有效,当ACK = 0时确认号无效。TCP规定,在连接建立后所有的传送的报文段都必须把ACK置为1。

    8. 推送PSH(Push):占1位,当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应。在这种情况下,TCP就可以使用推送(push)操作。这时,发送方TCP把PSH置为1,并立即创建一个报文段发送出去。接收方TCP收到PSH=1的报文段,就尽快地(即“推送”向前)交付接收应用进程。而不用再等到整个缓存都填满了后再向上交付。

    9. 复位RST(ReSet):占1位,当RST=1时,表名TCP连接中出现了严重错误(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立传输连接。RST置为1还用来拒绝一个非法的报文段或拒绝打开一个连接。

    10. 同步SYN(SYNchronization):占1位,在连接建立时用来同步序号。当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使SYN=1和ACK=1,因此SYN置为1就表示这是一个连接请求或连接接受报文。

    11. 终止FIN(FINish):占1位,用来释放一个连接。当FIN=1时,表明此报文段的发送发的数据已发送完毕,并要求释放运输连接。

    12. 窗口:占2个字节,窗口值是(0,2^16-1)之间的整数。窗口指的是发送本报文段的一方的接受窗口(而不是自己的发送窗口)。窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量(以字节为单位)。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。总之,窗口值作为接收方让发送方设置其发送窗口的依据。

      例如,发送了一个报文段,其确认号是701,窗口字段是1000.这就是告诉对方:“从701算起,我(即发送方报文段的一方)的接收缓存空间还可接受1000个字节数据(字节序号是701~1700),你在给我发数据时,必须考虑到这一点。”

      窗口字段明确指出了现在允许对方发送的数据量。窗口值经常在动态变化。

    13. 检验和:占2个字节,检验和字段检验的范围包括首部和数据这两部分。和UDP用户数据报一样,在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。伪首部的格式和UDP用户数据报的伪首部一样。但应把伪首部第4个字段中的17改为6(TCP的协议号是6);把第5字段中的UDP中的长度改为TCP长度。接收方收到此报文段后,仍要加上这个伪首部来计算检验和。若使用TPv6,则相应的伪首部也要改变。

    14. 紧急指针:占2个字节,紧急指针仅在URG=1时才有意义,它指出本报文段中的紧急数据的字节数(紧急数据结束后就是普通数据) 。因此,在紧急指针指出了紧急数据的末尾在报文段中的位置。当所有紧急数据都处理完时,TCP就告诉应用程序恢复到正常操作。值得注意的是,即使窗口为0时也可以发送紧急数据。

    15. 选项:长度可变,最长可达40字节。当没有使用“选项”时,TCP的首部长度是20字节。其最大长度可根据TCP首部长度进行推算。TCP首部长度用4位表示,那么选项部分最长为:(2^4-1)*4-20=40字节。

      • MSS最大报文段长度(Maxium Segment Size):TCP最初只规定了一种选项,即最大报文段长度MSS(Maximum Segment Szie)。注意MSS这个名词含义。MSS是每一个TCP报文段中的数据字段的最大长度。数据字段加上TCP首部才等于整个的TCP报文段。所以MSS并不是整个TCP报文段的最大长度,而是“TCP报文段长度减去TCP首部长度”。

      • 为什么要规定一个最大报文长度MSS呢?

        • 这并不是考虑接受方的接收缓存可能存放不下TCP报文段中的数据。实际上,MSS与接收窗口值没有关系。我们知道,TCP报文段的数据部分,至少要加上40字节的首部(TCP首部20字节和IP首部20字节,这里还没有考虑首部中的可选部分)才能组装成一个IP数据报。若选择较小的MSS长度,网络的利用率就降低。设想在极端情况下,当TCP报文段只含有1字节的数据时,在IP层传输的数据报的开销至少有40字节(包括TCP报文段的首部和IP数据报的首部)。这样,对网络的利用率就不会超过1/41。到了数据链路层还要加上一些开销。但反过来,若TCP报文段非常长,那么在IP层传输时就有可能要分解成多个短数据报片。在终点要把收到的各个短数据报片组成成原来的TCP报文段,当传输出错时还要进行重传,这些也都会使开销增大。
        • 因此,MSS应尽可能大些,只要在IP层传输时不需要分片就行。由于IP数据报所经历的路径是动态变化的,因此在这条路径上确定的不需要的分片的MSS,如果改走另一条路径就可能需要进行分片。因此最佳的MSS是很难确定的。在连接过程中,双方都把自己能够支持的MSS写入这一字段,以后就按照这个数值传输数据,两个传送方向可以有不同的MSS值。若主机未填写这一项,则MSS的默认值是536字节长。因此,所有在互联网上的主机都应该接受的报文段长度是536+20(固定首部长度)=556字节。
      • 其他选项:

        • 窗口扩大选项

          (Windows Scaling):是为了扩大窗口。我们知道,TCP首部中窗口字段长度是16位,因此最大的窗口大小为64K字节。虽然这对早期的网络是足够用的,但对于包含卫星信道的网络,传播时延和宽带都很大,要获得高吞吐量需要更大的窗口大小。

          • 窗口扩大选项占3字节,其中有一个字节表示移位值S。新的窗口值等于TCP首部中的窗口位数从16增大到(16+S)。移位值允许使用的最大值是14,相当于窗口最大值增大到2(16+14)-1=230-1。
          • 窗口扩大选项可以在双方初始建立TCP连接时进行协商。如果连接的某一端实现了窗口扩大,当它不再需要扩大其窗口时,可发送S=0选项,使窗口大小回到16。
        • 时间戳选项(Timestamps):占10字节,其中最主要的字段是时间戳字段(4字节)和时间戳回送回答字段(4字节)。时间戳选项有以下两个概念:

          • 用来计算往返时间RTT。发送方在发送报文段时把当前时钟的时间值放入时间戳字段,接收方在确认该报文段时把时间戳字段复制到时间戳回送回答字段。因此,发送方在收到确认报文后,可以准确地计算出RTT来。
          • 用于处理TCP序号超过232的情况,这又称为防止序号绕回PAWS。我们知道,TCP报文段的序号只有32位,而每增加232个序号就会重复使用原来用过的序号。当使用高速网络时,在一次TCP连接的数据传送中序号很可能被重复使用。例如,当使用1.5Mbit/s的速度发送报文段时,序号重复要6小时以上。但若用2.5Gbit/s的速率发送报文段,则不到14秒钟序号就会重复。为了使接收方能够把新的报文段和迟到很久的报文段区分开,则可以在报文段中加上这种时间戳。
        • SACK选择确认项(Selective Acknowledgements):用来确保只重传缺少的报文段,而不是重传所有报文段。比如主机A发送报文段1、2、3,而主机B仅收到报文段1、3。那么此时就需要使用SACK选项来告诉发送方只发送丢失的数据。那么又如何指明丢失了哪些报文段呢?使用SACK需要两个功能字节。一个表示要使用SACK选项,另一个指明这个选项占用多少字节。描述丢失的报文段2,是通过描述它的左右边界报文段1、3来完成的。而这个1、3实际上是表示序列号,所以描述一个丢失的报文段需要64位即8个字节的空间。那么可以推算整个选项字段最多描述(40-2)/8=4个丢失的报文段。

        • NOP(NO-Operation):它要求选项部分中的每种选项长度必须是4字节的倍数,不足的则用NOP填充。同时也可以用来分割不同的选项字段。如窗口扩大选项和SACK之间用NOP隔开。

    1. 填充:为了使整个首部长度是4字节的整数倍。

    在这里插入图片描述

    // 结构体位置:/usr/include/netinet/tcp.h
    // union中有两个结构体,给目标赋值的时候,可以采用两种方式
    // tcph->dest = htons (80); or tcph->th_dest = htons (80);
    // 这两个变量在同一位置
    // 应为过程中会有类型强制转换,便于取内容;所以对字节序用# if
    struct tcphdr
      {
        __extension__ union
        {
          struct
          {
    	uint16_t th_sport;	/* source port */
    	uint16_t th_dport;	/* destination port */
    	tcp_seq th_seq;		/* sequence number */
    	tcp_seq th_ack;		/* acknowledgement number */
    # if __BYTE_ORDER == __LITTLE_ENDIAN
    	uint8_t th_x2:4;	/* (unused) */
    	uint8_t th_off:4;	/* data offset */
    # endif
    # if __BYTE_ORDER == __BIG_ENDIAN
    	uint8_t th_off:4;	/* data offset */
    	uint8_t th_x2:4;	/* (unused) */
    # endif
    	uint8_t th_flags;
    # define TH_FIN	0x01
    # define TH_SYN	0x02
    # define TH_RST	0x04
    # define TH_PUSH	0x08
    # define TH_ACK	0x10
    # define TH_URG	0x20
    	uint16_t th_win;	/* window */
    	uint16_t th_sum;	/* checksum */
    	uint16_t th_urp;	/* urgent pointer */
          };
          struct
          {
    	uint16_t source;
    	uint16_t dest;
    	uint32_t seq;
    	uint32_t ack_seq;
    # if __BYTE_ORDER == __LITTLE_ENDIAN
    	uint16_t res1:4;
    	uint16_t doff:4;
    	uint16_t fin:1;
    	uint16_t syn:1;
    	uint16_t rst:1;
    	uint16_t psh:1;
    	uint16_t ack:1;
    	uint16_t urg:1;
    	uint16_t res2:2;
    # elif __BYTE_ORDER == __BIG_ENDIAN
    	uint16_t doff:4;
    	uint16_t res1:4;
    	uint16_t res2:2;
    	uint16_t urg:1;
    	uint16_t ack:1;
    	uint16_t psh:1;
    	uint16_t rst:1;
    	uint16_t syn:1;
    	uint16_t fin:1;
    # else
    #  error "Adjust your <bits/endian.h> defines"
    # endif
    	uint16_t window;
    	uint16_t check;
    	uint16_t urg_ptr;
          };
        };
    };
    

    附录

    涉及但未介绍内容

    • 从网上拼凑而来,皆是二手来源。

    • 所有的代码/文档见:github

    • 这些首部的应用,因为还需要更多的背景支持,这里暂不介绍。

    • 暂不介绍循环冗余码校验,首部校验和,字节序。

    参考文章

    超详细的网络抓包神器 tcpdump 使用指南

    实战!我用 Wireshark 让你“看见“ TCP

    展开全文
  • 有些首部是某些报文专用的,如请求首部只适用于请求报文中,有些通用些。按类型用途不同可以分为 5 类。 通用首部 请求首部 响应首部 实体首部 常见非标准字段(自定义) 通用首部 服务器和客户端都可以使用的首部...

    HTTP 首部用于给服务器和客户端提供报文主体大小、使用的语言及认证消息等内容。首部字段由字段名和字段值构成,中间用冒号「:」隔开。有些首部是某些报文专用的,如请求首部只适用于请求报文中,有些通用些。按类型用途不同可以分为 5 类。

    • 通用首部
    • 请求首部
    • 响应首部
    • 实体首部
    • 常见非标准字段(自定义)
    通用首部

    服务器和客户端都可以使用的首部。

    首部字段说明例子
    Cache-Control控制缓存的行为Cache-Control: no-cache
    Connection浏览器优先使用的连接类型Connection: keep-alive
    Connection: Uprade
    Date报文创建日期时间Date: Sat, 19 Sep 2020 06:13:42 GMT
    Pragma另一种报文指令,但不专用于缓存Pragme: no-cache
    Trailer报文采用了分块传输编码(chunked transfer encoding)方式Trailer: Max-Forwards
    Transfer-Encoding报文的传输编码方式:chunked、compress、deflate、gzip 和 identityTransfer-Encoding: chunked
    Upgrade要求升级为另一个协议Upgrade: HTTP/2.0, STTP/1.3, IRC/6.9, RTA/x11
    Via代理服务器相关信息,告知请求代理是哪个Via: 1.0 fred, 1.1 example.com (Apace/1.1)
    Warning一般性错误警告,告知内容中哪里可能存在错误Warning: 199 Miscellaneous warning
    • chunked:数据分块形式发送。
    • compress:采用 LZW (Lempel-Ziv-Welch)压缩算法。
    • deflate:采用 zlib 结构和 deflate 压缩算法。
    • gzip:采用 LZ77(Lempel-Ziv coding)压缩算法和 32 位 CRC 检验的编码方式。
    • identity:不压缩处理或修改
    请求首部

    客户端想服务端发送请求报文,补充请求的附加内容、客户端信息、响应内容相关优先级等信息。

    首部字段名说明例子
    Accept告知服务器能发送哪些媒体类型Accept: application/json, text/javascript, /; q=0.01
    Accept-Charset告知服务器能发送哪些字符集Accept-Charset: utf-8
    Accept-Encoding告知服务器能发送哪些编码方式Accept-Encoding: gzip, deflate
    Accept-Language告知服务器能发送哪些语言Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,zh-CN;q=0.7,zh;q=0.6
    Authorization提供信息给服务器对其身份认证Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
    Expect要求服务器对某请求需要做出的行为Expect: 100-continue
    From提供客户端 E-mail 地址From: test@test.com
    Host提供接受请求的服务器主机号和端口号(如果是标准端口即可忽略)Host: test.test.com
    Host: test.test.com:1111
    If-Match字段值与服务器特定资源标记值(ETag)匹配才处理请求If-Match: “123456”
    If-Modified-Since确认本地资源是否有效,如果有更新就处理请求,否则响应返回 304 Not ModifiedIf-Modified-Since: Sat, 19 Sep 2020 06:13:28 GMT
    If-None-Match与 If-Match 相反,不匹配才处理请求If-None-Match: “123”
    If-Range对资源的某个范围请求If-Range: “737060cd8c284d8af7ad3082f209582d”
    If-Unmodified-Since与 If-Modified-Since 相反,未发生更新才处理请求。如果有更新,则响应返回状态码 412 Precondition FailedIf-Unmodified-Since: Sat, 19 Sep 2020 06:13:28 GMT
    Max-Forwards限制代理或网关转发次数Max-Forwards: 5
    Proxy-Authorization提供信息给服务器对代理进行身份认证Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
    Range获取部分资源Range: bytes=500-999
    Referer当前文档的 URLReferer: https://www.baidu.com/
    TE告知服务器可以使用哪些扩展传输编码TE: trailers, deflate
    User-Agent发出请求的应用程序名称User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36…
    响应首部

    服务端向客户端返回响应报文中所使用的字段。补充响应的附加内容,也要求客户端提供额外的内容信息。

    首部字段名说明例子
    Accept-Ranges服务器可接受的资源请求范围类型Accept-Ranges: bytes
    Age资源在代理缓存中存在的时间,单位为秒Age: 20
    ETag将资源以字符串形式作唯一性标识ETag: “test”
    Location引导客户端访问另一个 URL,通常配合 3xx 响应,提供重定向 URLLocation: http://www.baidu.com/test.html
    Proxy-Authenticate把代理服务器所要求的认证消息发给客户端Proxy-Authenticate: Basic realm=“Auth”
    Retry-After告知客户端多久(具体日期或秒数)后再发送请求,主要配合状态码 503 Service Unavailable 或 3xx Redirect 响应Retry-After: 120
    Retry-After: Sat, 19 Sep 2020 06:13:28 GMT
    Server告知客户端当前服务器安装的应用程序信息Server: Apache/2.4.38 (Uos)
    Vary列出所有客户端请求首部,服务器根据这些首部选择文档或产生定制内容。如所提供的文档取决于 User-Agent,那么 Vary 首部必须含有 User-AgentVary: User-Agent
    WWW-Authenticate告知客户端请求是使用的认证模式(Basic 或 Digest)WWW-Authenticate: Basic

    实体首部

    补充实体主体的更多信息,如主体长度或 MIME 类型。

    首部字段名说明例子
    Allow告知客户端对特定资源能使用的 HTTP 方法。但服务器收到不支持的方法请求时,会返回状态码 405 Method Not Allow.Allow: GET, HEAD
    Content-Encoding用于对特定媒体类型的数据进行压缩。告知客户端要用的解压方式:gzip, compress, deflate, identity, brContent-Encoding: gzip
    Content-Language内容所使用的语言Content-Language: zh-CN
    Content-Length响应消息体长度,单位为字节(8 位/字节)Content-Length: 15000
    Content-Location报文主体返回资源所对应的 URL(相对/绝对地址). Location 是返回重定义 URLContent-Location: /index.html
    Content-Range数据片段在整个文件中的位置Content-Range: bytes 200-1000/67589
    Content-Type资源的 MIME 类型Content-Type: text/html; charset=utf-8
    Expires指定日期/时间,超过即表示已过期。如果 Cache-Control 设置了 max-age 和 s-max-age,那么 Expires 会被忽略Expires: Mon, 21 Sep 2020 02:16:21 GMT
    Last-Modified该实体最后修改时间Last-Modified: Mon, 21 Sep 2020 02:16:21 GMT
    常见非标注字段(自定义)

    HTTP 首部字段可以自定义。

    首部字段名说明例子类别
    X-Frame-Options为了防止点击劫持攻击(clckjacking)。用于控制网站 Frame 标签内容显示问题:deny, sameorigin, allow-from uriX-Frame-Options: deny响应首部
    X-XSS-Protection控制浏览器 XXS 防护机制开关:0(关闭 XSS 过滤)或(开启 XSS 过滤)X-XSS-Protection: 1响应首部
    DNT拒绝被精准广告跟踪:0 (同意被跟踪) 或 1 (不同意被跟踪)DNT: 1请求首部
    • deny: 表示该页面不允许在 frame 中展示,即使是在同域名中。
    • sameorigin: 表示该页面可以在同域名 frame 中展示。X-Frame-Options: sameorigin
    • allow-from uri: 表示该页面可以在指定 uri 中展示。X-Frame-Options: allow-from https://wwww.test.com/

    参考

    • HTTP Headers

    • HTTP头字段

    • 《图解HTTP》

    • 《HTTP权威指南》

    展开全文
  • 首部字段结构: HTTP报文:点击查看。 首部组成:由首部字段名和字段值构成的,中间用冒号“:”分隔。 例: Content- Type: text/html 一个首部字段可以有多个字段值。 例:Keep-Alive: timeout=15, max=100 若...
  • 为什么UDP和TCP要有伪首部

    万次阅读 2018-06-08 15:53:07
    UDP和TCP的伪首部只用于计算校验和,在UDP和TCP的报文中是不存在的,为什么要引入伪首部呢?为什么伪首部的要有这些字段?   下面讲讲我的理解,通信系统原理告诉我们,校验码是有检错能力的,当错误个数超过检错...
  • 1.首部字段概述 先来回顾一下首部字段在报文的位置,HTTP 报文包含报文首部和报文主体,报文首部包含请求行(或状态行)和首部字段。 在报文众多的字段当中,HTTP 首部字段包含的信息最为丰富。首部字段同时存在于...
  • IP首部校验和的理解

    千次阅读 2010-06-28 23:28:00
    (转)IP首部检验和的理解 很多文章ip首部检验和的计算介绍得很简略,在理解上常常会比较困难。这篇文章是我自己的一些理解。或许也有不正确的地方,希望大家指正。 这个问题一直困绕了我很长时间,...
  • 而一般TCP首部和IP首部均为20字节的长度,故MSS=MTU-20(TCP首部长度)-20(IP首部长度)。 TCP首部: 1.源端口,16位;发送数据的源进程端口 2.目的端口,16位;接收数据的进程端口 3.序号,32位;代表当前TCP...
  • TCP协议首部分析

    千次阅读 2017-03-10 13:16:58
    源端口和目的端口–> 各两个字节,用来表明源和目标。和UDP类似。 序号–>用来指定发送数据的编号...4位首部长度–>指报文段的首部的总长度。4位能表示最大数为15,一个单位为4字节,所以首部最大长度为4*15=60字节,
  • HTTP首部字段详解

    2020-11-24 21:39:37
    声明:本人的所有博客皆为个人笔记,作为个人知识索引使用,因此在叙述上存在逻辑不通顺、跨度大等问题,希望理解。分享出来仅供大家学习翻阅,若有错误希望指出,感谢! HTTP首部 HTTP首部内容为客户端和...首部字段名
  • IP首部、TCP首部

    2019-06-17 23:16:39
    2.IP首部 3. TCP首部 URG 紧急指针(urgent pointer) ACK 确认序号有效 PSH 接收方应尽快把这个报文段交给应用层 RST 重建连接 SYN 同步序号,用来发起一个连接 FIN 结束一个连接 4.UDP首部 ...
  • 目录 HTTP 报文首部 ... ... HTTP首部字段 HTTP首部字段传递重要信息 ...HTTP首部字段结构 ...HTTP首部字段重复了会如何 ...4种HTTP首部字段类型 ...HTTP/1.1首部字段一览 ...End-to-end首部和Hop-by-hop首部 端到端首部(E...
  • tcp首部

    2012-05-10 17:45:14
    tcp首部
  • IP首部

    千次阅读 多人点赞 2019-03-17 12:32:15
    IP数据报首部的格式。 首部最小20个字节,最大60个字节。最小时就是只有固定部分(每个单位32bit,也就是4个字节,共5行,就是20个字节),一个单位指的是一行。 wireshark抓包分析 版本 在数据传输时,发送方...
  • 文章主要介绍了IP数据首部检验和它的计算过程
  • HTTP请求首部字段与响应首部字段

    千次阅读 2018-03-28 15:56:46
    一、请求首部字段1、AcceptAccept首部可通知服务器,用户代理能够处理的媒体类型及媒体类型的相对优先级Accept:text/html, application/xhtml+xml, application/xml; q=0.9, */*; q=0.82、Accept-Charset用来通知...
  • TCP首部详解

    2021-04-29 17:01:05
    笔者认为在了解了TCP协议的特点及原理之后,再回过头来看TCP的首部,追根溯源更为有趣,如果在你还不知道它怎么建立连接,怎么传输数据,怎么保证它的可靠性的时候,就开始看TCP首部格式,就会一脸懵圈,不知所云,...
  • TCP首部

    千次阅读 2019-03-17 17:56:23
    首部格式 wireshark抓包分析 源端口和目的端口 各占2个字节,分别写入源端口和目的端口。 序号 占4字节。序号范围是【0,2^32 - 1】,共232(即4294967296)个序号。序号增加到232-1后,下一个序号就又回到0。...
  • UDP首部

    千次阅读 2019-03-17 18:14:31
    UDP首部字段很简单,只有8个字节,由4个字段组成,每个字段的长度都是两个字节。 源端口:源端口号。在需要对方回信时选用。不需要时可用全0。 目的端口:目的端口号。这在终点交付报文时必须要使用到。 长度: UDP...
  • ICMP首部

    千次阅读 2019-03-17 17:40:26
    ICMP虽然和IP协议是同一层的协议,但是ICMP是在IP数据报的内部被传输的,紧跟着IP报文的首部(如果IP首部有可选部分,则紧跟着可选部分) 报文格式 常见的报文格式 显请求和应答报文格式:通常用来判断目的...
  • UDP的首部格式

    千次阅读 2019-09-15 20:12:47
    用户数据报UDP有两个字段:数据字段和首部字段。首部字段很简单,只有8个字节,由四个字段组成,每个字段的长度都是两个字节。 (1)源端口:源端口号。在需要对方回信时选用。不需要时可用全0。 (2)目的...
  • HTTP请求首部字段及响应首部字段

    千次阅读 2018-06-19 15:32:26
    请求首部字段,预检请求发送给服务器: Origin 预检请求或实际请求的原域名,不管是否为跨域请求, Origin 字段总是被发送 Access-Control-Request-Method 预检请求将实际请求的 HTTP 方法告诉服务器 ...
  • TCP 首部详解

    千次阅读 2018-06-28 01:41:49
    另一端收到的数据进行确认,失序的数据重新排序,丢弃重复数据;TCP提供端到端的流量控制,并计算和验证一个强制性的端到端检验和。许多流行的应用程序如 Telent、Rlogin、 FTP 和 SMTP 都使用TCP。 先上图:...
  • TCP报文段首部结构分析

    千次阅读 2019-09-02 20:37:08
    TCP报文段如APR报文、IP数据报一样,也是由首部与数据区域组成,TCP首部内容很丰富,各个字段都有特定的含义,一般来说TCP首部只有20个字节,TCP报文段首部的前20个字节是固定的,后面有4N字节是根据需要而增加的...
  • 计算机网络(十四)IPv4首部及IPv6首部格式
  • 请求首部是只在请求报恩中有意义的首部。用于说明是谁或什么在发送请求、请求源自何处,或者客户端的洗好及能力。服务器可以根据请求首部给出的客户端信息,试着为客户端提供更好的响应。 请求首部字段如下:首部...
  • 响应首部:从服务器端向客户端返回响应报文时,使用的首部.补充了响应的附加内容,服务器信息,也会要求客户端附加额外的内容信息等. 主要有以下字段: 响应首部字段 说明 Accept-Ranges 告知客户端...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 125,932
精华内容 50,372
关键字:

对的首部