阅读 87

TCP/IP协议(三、tcp选项字节)

上一篇简单的介绍了tcp协议的基础,也没有涉及到具体的抓包,都不知道我说的三次握手是不是对的,今天就来从抓包开始分析。

3.1  再次分析三次握手

在这里插入图片描述

抓包工具应该都会用吧,百度一下你就知道,这里就不描述了,我这个抓包的情况是,用scp命令把本地虚拟机的文件拷贝到服务器中,所以就抓出来了一些包.

把包抓出来是不是一脸懵逼,这跟我看的那本《tcp/ip详解》抓出来的差别这么大呢?我也不知道原因,竟然实际中抓出来的包有这么多不懂的,那接下来就分析一下包表示的含义

3.1.1  TCP报文之-tcp dup ack 、tcp Out-of-Order

其实我这个也不懂,我也是百度了,看到一篇博客很好,这里引用一下:TCP报文之-tcp dup ack 、tcp Out-of-Order,有兴趣的可以看看,我这里也抄了一点过来:

3.1.1.1  TCP Out_of_Order的原因分析:

一般来说是网络拥塞,导致顺序包抵达时间不同,延时太长,或者包丢失,需要重新组合数据单元,因为他们可能是由不同的路径到达你的电脑上面。

3.1.1.2  TCP Retransmission原因分析:

很明显是上面的超时引发的数据重传。

3.1.1.3  TCP dup ack XXX#X原因分析:

就是重复应答#前的表示报文到哪个序号丢失,#后面的是表示第几次丢失。

3.1.1.4  tcp previous segment not captured原因分析

意思就是报文没有捕捉到,出现报文的丢失。

这这里再次膜拜大神,也写写这位大神为了解惑,他博客下面也是进行包的分析了,不过我这里也自己抓了包,就不用它的了,自己分析一波。

3.1.2  再次分析三次握手

这里为什么syn会出现一个乱序呢,这个我也不是太清楚,哈哈哈,以后知道了再补上。总的来说客户端往服务器发起了一个syn的信号。服务器再往客户端回复了一个ack,客户端接收到了这个ack后,也会向服务器回复一个ack,不过这里看着好像ack丢了,然后接下来再次回复一个ack,这次服务器接收到了ack。在这里插入图片描述是不是三次握手的过程跟我上节课讲的差不多,只不过我这个网络环境有点复杂,所以经过了几次重传,不过连接是建立起来,是不是有人也跟我一样好奇,后面为什么带了这么多个东西,这些东西是什么?这个就是选项字节,我当初也觉得不重要,直到我分析了后面,才发现,现在的tcp传输都会带上选项字节,怪自己当初太年轻。

3.2  选项字节

又发现了一篇好的文章,感觉是在做搬运工:TCP系列08—连接管理—7、TCP 常见选项(option),有兴趣的可以去看看。

在这里插入图片描述其中我标记为红色的部分是常见的TCP选项,我们仅针对这些红色的TCP选项进行介绍。

按照RFC793规定,一个TCP选项只需要单字节对齐,但是在实现上一般是两字节对齐或者会通过NOP选项实现四字节对齐,例如3bytes长的WSOPT选项,linux在添加这个tcp选项的时候,就会在这个选项前面加一个1byte的NOP选项凑成4bytes。

TCP选项的格式有两种,一种是单字节长的TCP选项如EOL和NOP。另外一种是包含1byte的kind,1byte的length,在加上选项的数据。除了EOL和NOP选项外,其他的TCP选项都是后一种格式,且为了兼容,协议要求后续如果扩展其他tcp选项同样需要采用后一种格式。

RFC1122协议规定TCP接收端必须能够处理任意TCP包中的选项,对于不能识别的TCP选项则采取忽略该选项的办法。其中有一些选项如EOL、NOP、MSS等是协议规定必须支持的,同时协议要求将来新增的TCP选项都需要由length域,这样TCP实现不能识别这个选项的时候就可以跳过这个选项。

3.2.1  EOL格式如下

    +--------+
    |00000000|
    +--------+
     Kind=0复制代码

这个选项用来指示TCP的选项列表结束,这个选项是用在所有TCP选项的后面,并不是每个TCP选项后面都需要这个选项来指示选项结束,只有在TCP选项列表结束后没有与TCP头中的Header Length字段指定的头长重合时候才需要使用EOL选项,另外这个选项并不一定放在TCP头(包括扩展头)的末尾。举个例子,假如Header Length指定的TCP头长为40bytes,其中第29-38bytes为TSOPT选项,则可以在第39byte处添加一个EOL选项指示选项列表结束,可以看到EOL并没有位于TCP头的结束位置的第40byte。对于最后一个byte RFC793协议规定需要以0来填充。注意这个EOL后面填充的0已经不属于TCP选项的一部分了。

3.2.2  NOP选项格式如下

	+--------+
    |00000001|
    +--------+
     Kind=1    
复制代码

这个选项可以使用在选项之间或者结尾处,比如,为了使3bytes的WSOPT选项在四字节对齐的边界处结束,可以在WSOPT选项之前添加一个NOP选项,这样整个选项长度为4bytes,更容易对齐。但是按照RFC793协议规定,发送端并不保证会填充NOP选项来让其他选项达到对齐的目的,因此接收端也应该准备好接收非四字节对齐的WSOPT选项。也就是说同样的几个TCP选项可以有不同的选项排列顺序,即使是相同的排列顺序也可能因为NOP和EOL等等而有不同的排列布局。

最后从linux实现的角度来说,linux本身发送TCP数据包的时候并不会添加EOL选项,而是通过添加一个或者多个NOP选项来实现整个TCP头长的四字节对齐(还记得我们之前说过TCP头中的Header Length字段的单位是32-bit word,因此TCP的头长一定是4bytes的整数倍)。但是linux在接收数据包的时候支持解析EOL选项。另外协议虽然没有限制TCP选项的排列顺序,但是linux实现上会按照一定的顺序排列TCP选项。原因是虽然协议没有限定options的顺序,但是互联网上有些设备对这个顺序是比较敏感的,一些特定的options顺序可能会引起问题。

3.2.3  MSS

Maximum segment size(MSS)格式如下

    +--------+--------+---------+--------+
    |00000010|00000100|   max seg size   |
    +--------+--------+---------+--------+
     Kind=2   Length=4复制代码

Maximum segment size(MSS)是TCP期望从对端接收的最大的报文长度,自然也是对端在发送报文的时候的最大报文长度,注意MSS值仅指示TCP数据长度,并不包含关联的TCP头和IP头的长度。当连接在建立的时候,每个endpoint通常会在对应的SYN包中通过MSS option通告对方自己的MSS,按照RFC1122规定如果没有MSS选项提供则会使用默认的536bytes作为MSS(注意原始的RFC793协议是说没有提供MSS选项的时候可以发送任意大小的包,RFC1122修正了该说法)。还有一点需要注意由于目前网卡普遍支持TSO、GSO功能,在开启这些功能的前提下,协议栈中的TCP层可能会按照MSS的整数倍发包,然后再由网卡硬件来对TCP分段,这样减轻了CPU的处理压力。后面为了方便讨论窗口管理等特性,我们还是按照TCP层最大包不超过MSS来讨论。

在IPV6的jumbogram中(RFC2675),如果接收端接收到的MSS值为65535时候,标识真实的MSS需要根据PMTU值来确定。即MSS=PMTU-60。(jumbogram是IPV6中一种发送超大IP报文的协议特性,PMTU是接收端和发送端链路之间所有设备的最小MTU。)

RFC6691重新澄清了MSS选项的相关说明,并修正了之前几个RFC的错误说法。RFC6691明确规定在MSS选项中传递的MSS值为MTU减去IP基本头(ipv4为20bytes,IPV6为40bytes)和TCP基本头(20bytes)的值,不考虑扩展头。发送端负责发送数据前在这个MSS值的基础上扣除扩展头长度得出真实传输数据的长度。

3.2.4  WSOPT

WSOPT格式如下

        +---------+---------+---------+
        | Kind=3  |Length=3 |shift.cnt|
        +---------+---------+---------+    
复制代码

RFC1323为长肥管道提供了两个高性能扩展,一个是WSOPT选项另外一个是TSOPT选项。长肥管道是指带宽时延积很大的网络。

我们在介绍TCP头结构的时候提到过Window Size字段,这个字段占16位,最大为2^16-1,在长肥管道中,当发送端TCP需要通告更大的接收窗口的时候,就需要通过WSOPT选项了。当使用WSOPT选项的时候,接收窗口的实际大小则为Window Size<<shift.cnt,其中shift.cnt按照协议最大只能为14,当接收端接收到的shift.cnt大于14的时候,则按照14来处理Window Size。

WSOPT选项只能在SYN包中发送,因此当TCP连接建立起来后,window scale就固定了。一般在TCP实现上会有一个最大接收缓存,进而决定了最大接收窗口和window scale。WSOPT选项将原有的16位Window Size扩展到近30位大小(大约1GB)可以有效提升TCP允许使用的接收缓存,进而提升长肥网络的性能。

如果要使能window scale,需要发送端在SYN包中发送WSOPT选项,接收端在SYN-ACK包中同样发送WSOPT。注意协商window scale过程中协议要求不能对SYN和SYN-ACK报文头中的window size应用WSopt选项。WSOPT中的shift.cnt可以为0,标识window scale factor为1(即2^0=1),即接收窗口的实际大小即为Window Size。如果发送端发送了WSOPT选项但是没有收到对端的WSOPT选项,则需要将自己的window scale factor设置为1。

发送端和接收端都各有一个接收窗口和一个发送窗口,因此总共四个窗口,共维护4个scale factor。假设发送端接收窗口的scale factor为R,发送窗口的scale factor为S,则对应的接收端的接收窗口scale factor为R,发送窗口scale factor为S。在协商好两端的scale factor后,之后接收到的数据包中的Window Size字段自动进行scale factor,发送出去的数据包中的这个字段则为实际接收窗口右移scale factor后的结果。

在这里插入图片描述

3.2.5  ACK-Permitted和SACK

SACK-Permitted格式

   Kind: 4
   +---------+---------+
   | Kind=4  | Length=2|
   +---------+---------+复制代码

SACK格式

   Kind: 5
   Length: Variable
                     +--------+--------+
                     | Kind=5 | Length |
   +--------+--------+--------+--------+
   |      Left Edge of 1st Block       |
   +--------+--------+--------+--------+
   |      Right Edge of 1st Block      |
   +--------+--------+--------+--------+
   |                                   |
   /            . . .                  /
   |                                   |
   +--------+--------+--------+--------+
   |      Left Edge of nth Block       |
   +--------+--------+--------+--------+
   |      Right Edge of nth Block      |
   +--------+--------+--------+--------+复制代码

之前我们介绍过TCP的滑窗和ACK机制,我们再来简单的举个例子,假设接收端依序接收到系列号为2100的byte,序列号2100之前的byte都已经按序接收到了,接着因为乱序传输或者丢包的原因,接收端并没有接收到系列号为2101的TCP数据包,而是收到了系列号为2201的TCP报文并且长度为100byte。也就是说接收端缺少了2101-2200byte的数据,我们称接收端这种情况在滑窗上面形成了一个洞(hole)。如下图红色部分表示接收端已经接收到的数据。

在这里插入图片描述

此时接收端给发送端返回ACK报文的时候,TCP头中的ack number字段只能填写2101,还记得我们之前说过ack number表示接收端期望接收到的下一个byte的系列号吧,它是已经收到的连续报文中的最大序列号加1。注意是连续报文,因为2100和2201之间有洞,因此此时ack number只能是2101,发送端在接收到2101这个ack number后,并不能知道接收端实际上已经接收到了2201-2300byte,因而可能会在重传2101-2200byte的同时也会重传2201-2300byte的数据。那么有了SACK后,接收端就可以通过SACK来告诉发送端已经接收到了2201-2300byte的数据,这个就是一个SACK块(SACK block),同时结合ack number,发送端就可以仅仅只是重传2101-2200byte的数据,而不需要重传2201-2300byte的数据了。

一个endpoint如果在SYN包或者SYN-ACK包中解析处SACK-Permitted选项,那么就说明对端支持SACK扩展。那么本端就可以把收到的不连续报文信息发送给对端来帮助对端高效重传了。通常SACK-Permitted选项一般是在SYN包中发送,一旦收到对端SACK-Permitted选项后,SACK选项则可以在任意包中传输。Linux中可以通过/proc/sys/net/ipv4/tcp_sack控制是否使能SACK功能,设置为1时候使能,设置为0时候关闭SACK功能。因为SACK选项和TCP重传以及拥塞控制等等由比较大的关系,后面我们讲到这些的时候再来详细介绍。

3.2.6  TSOPT

TSOPT格式如下

     Kind: 8
     Length: 10 bytes
      +-------+-------+---------------------+---------------------+
      |Kind=8 |  10   |   TS Value (TSval)  |TS Echo Reply (TSecr)|
      +-------+-------+---------------------+---------------------+
          1       1              4                     4          
复制代码

TSOPT选项也叫做timestamp选项,有时也会写为TSopt。如上面介绍WSOPT时候所说,TSOPT也是RFC1323为了改善长肥管道而提出的一个TCP扩展。当使用这个选项的时候,发送方在TSval处放置一个时间戳,接收方则会把这个时间通过TSecr返回来。因为接收端并不会处理这个TSval而只是直接从TSecr返回来,因此不需要双方时钟同步。这个时间戳一般是一个单调增的值,RFC1323建议这个时间戳每秒至少增加1。其中在初始SYN包中因为发送方没有对方时间戳的信息,因此TSecr会以0填充,TSval则填充自己的时间戳信息。

在RFC1323中,TSOPT主要有两个用途一个是RTTM(round-trip time measurement)即根据ACK报文中的这个选项测量往返时延,另外一个用途是PAWS(protect against wrapped sequence numbers),即防止同一个连接的系列号重叠。另外还有一些其他的用途,如SYN-cookie、 Eifel Detection Algorithm 等等。关于RTTM我们留到TCP重传部分进行介绍,此处我们简单介绍一下PAWS。

PAWS假设接收到的每个TCP包中的TSval都是随时间单调增的,基本思想就是如果接收到的一个TCP包中的TSval小于刚刚在这个连接上接收到的报文的TSval,则可以认为这个报文是一个旧的重复包而丢掉。实际上接收到的TCP报文的系列号如果落在接收窗口外面就可以丢弃,但是对于一些高速不稳定网络,可能会出现一种情况,就是系列号翻转后,之前某个无效的重传包系列号满足条件,落在了接收窗口内,这个时候仅仅依靠系列号就不足以鉴定这个TCP报文的有效性了,结合TSOPT则可以通过时间戳选项来进一步过滤旧的重复包。

类似PAWS,实际上时间戳作为了系列号的一个扩展,在同一个连接上单调增。RFC6191进一步利用这个特点,在同一个连接的不同实例间时间戳单调增的时候,可以利用这个时间戳区分同一个连接的不同实例的时候,即使在TIME-WAIT状态下也允许建立连接。

RFC7323明确在TCP头中的ACK标志位有效的时候TSecr字段才有效,如果ACK标志位没有置位的时候,发送端应该把TSecr置为0。当发送出去的数据包ACK标志位置位的时候,发送端必须在TSecr中回显一个最近接收到的TSval。当ACK标志位没有置位的时候,接收端必须忽视TSecr字段。

TCP可以在初始的SYN包中发送TSopt选项,但是接收端只有在接收到的初始SYN报文中解析到TSopt选项的时候才允许在SYN-ACK报文中发送TSopt选项。一旦TCP通信的两端通过SYN报文和SYN-ACK报文协商好TSopt选项后,在这个连接随后的非RST报文中,TSopt选项必须被发送。一旦接收到一个不带由TSopt选项的非RST报文的时候,TCP应该静默的丢弃这个报文(注意是应该should,不是必须must)。TCP不能(must not)因为缺少预期的TSopt选项而中止一个TCP连接。注意这里是协议的要求,实现上并不一定会静默的丢弃这个数据包,比如linux在协商好TSopt后,收到没有TSopt选项的数据也会正常接收,后面文章会有wireshark示例。

当在三次握手中没有协商TSopt选项而在随后的数据传输中接收到TSopt选项的时候,TCP必须忽视这个TSopt选项然后正常处理这个TCP报文。在TCP同开的时候如果一个SYN报文包含TSopt选项,另外一个SYN报文不包含TSopt选项,那么两端都可以在随后的SYN-ACK报文中发送TSopt选项。

另外TSopt选项还有两个重要作用,一个是RACK重传,另外一个是Eifel探测算法,后面的文章我们会专门进行实例介绍。Linux中/proc/sys/net/ipv4/tcp_timestamps可以设置是否启用TSopt选项,这个参数设置为0的时候TCP连接就不会使用TSopt选项。

3.2.7  FOC

FOC选项的格式如下

  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|      Kind     |    Length     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                                                               |
~                            Cookie                             ~
|                                                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Kind            1 byte: value = 34
Length          1 byte: range 6 to 18 (bytes); limited by
                       remaining space in the options field.
                       The number MUST be even.
Cookie          0, or 4 to 16 bytes (Length - 2)复制代码

Fast Open选项用来请求或者发送一个FOC(Fast Open Cookie),当cookie域为空的时候,client使用这个选项来从服务器请求一个FOC。当cookie域非空的时候,服务器可使用这个选项来把cookie传递给client,或者client可以使用这个选项来执行TFO。

最小的cookie大小是4byte,虽然图示中cookie是32位对齐的,但不是强制要求的,当数据包中不带SYN标志、Length值无效或者TFO功能没有打开的时候,需要忽略这个选项。

选项字节总算抄完了,确实有点多,以前还觉得不总要,这样理解完了,再回来看看抓包,就知道各个字段的含义了吧。在这里插入图片描述

TCP:表明是个TCP协议

Length:74 表明包的长度是74个字节

56739->443 :表明是从源地址的56739端口发送给目的地址的443端口

[SYN]表明这是一个TCP的同步请求,是TCP握手的第一步

Seq=0: TCP协议中的序号,这里为0.

在TCP中第一个SYN 包所包含的 sequence 是随机的,而第一个 SYN+ACK包里的sequence 也是随机的,wireshark 为了你便于观察都使用相对值,初始化这两个随机值为0,后面的sequence 和 acknowledge 都在上面累加 Win=29200: 发送报文段一方的接收窗口。TCP协议中的字段

Len=0: 发送文件TCP报文段Datas段的长度

MSS=1460: 最大报文段长度,指每个TCP报文段中数据字段的最大长度。它不包含首部长度。是TCP首部中,选项中的字段。

WS=128:窗口扩大因子;只能在连接建立阶段确定;在连接期间他的值不能够改变;新的窗口值=首部中定义的窗口值乘以2的(窗口扩大因子)的次方;由于窗口值不够用。选项中的字段。 ??书上说,窗口扩大选项占3个字节,其中一个字节表示移位值S,S最大为14,新的窗口值等于TCP首部中的窗口位数从16增大到(16+S)。可这里WS怎么会等于128呢??

答:这里的128是指窗口扩大了128倍,其S=7, 2的7次方 = 128. 符合S<=14. 打开软件下面TCP部分的详细说明,有介绍。(计算后的结果了,原始数据为7)

SACK_PERM=1: 允许选择确认。 TCP选项中的字段


作者:善良的小油条
链接:https://juejin.cn/post/7022423411892682760


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐