TCP Analysis Flags 之 TCP Window Full

admin 2024年8月2日14:37:35评论42 views字数 5839阅读19分27秒阅读模式

分析最重要的一件事:理解你的协议。

前言

默认情况下,Wireshark 的 TCP 解析器会跟踪每个 TCP 会话的状态,并在检测到问题或潜在问题时提供额外的信息。在第一次打开捕获文件时,会对每个 TCP 数据包进行一次分析,数据包按照它们在数据包列表中出现的顺序进行处理。可以通过 “Analyze TCP sequence numbers” TCP 解析首选项启用或禁用此功能。

TCP 分析展示

在数据包文件中进行 TCP 分析时,关于 "TCP Window Full" 一般是如下显示的,包括:

  1. Packet List 窗口中的 Info 信息列,以 [TCP Window Full] 黑底红字进行标注;

  2. Packet Details 窗口中的 TCP 协议树下,在 [SEQ/ACK analysis] -> [TCP Analysis Flags] 中定义该 TCP 数据包的分析说明。

TCP Analysis Flags 之 TCP Window Full

TCP Window Full 定义

实际在 TCP 分析中,关于 TCP Window Full 的定义非常简单,如下,为本端发送端所发的 TCP 段大小超过对端接收端的接收窗口大小,受到对端接收窗口大小的限制,需注意的是这个标记是在发送端标记,而不是在接收端标记

Set when the segment size is non-zero, we know the window size in the reverse direction, and our segment size exceeds the window size in the reverse direction.

具体的代码如下,总的来说这段代码的作用是检测 TCP 数据流中的“窗口已满”情况,即当前数据段刚好达到接收端宣告的窗口边界,检测到这种情况时,会设置相应的标志以供后续处理使用。

    /* WINDOW FULL     * If we know the window scaling     * and if this segment contains data and goes all the way to the     * edge of the advertised window     * then we mark it as WINDOW FULL     * SYN/RST/FIN packets are never WINDOW FULL     */    if( seglen>0    &&  tcpd->rev->win_scale!=-1    &&  (seq+seglen)==(tcpd->rev->tcp_analyze_seq_info->lastack+(tcpd->rev->window<<(tcpd->rev->is_first_ack?0:(tcpd->rev->win_scale==-2?0:tcpd->rev->win_scale))))    &&  (flags&(TH_SYN|TH_FIN|TH_RST))==0 ) {        if(!tcpd->ta) {            tcp_analyze_get_acked_struct(pinfo->num, seq, ack, TRUE, tcpd);        }        tcpd->ta->flags|=TCP_A_WINDOW_FULL;    }

1. lastack,定义为 Last seen ack for the reverse flow。

2. 关于 tcpd->rev->is_first_ack,在之后实例中会展开说明。

Packetdrill 示例

在上述 TCP Window Full 定义和代码可知,TCP 分析的逻辑很简单,因此通过 packetdrill 比较容易模拟出相关现象。

# cat tcp_window_full.pkt0   socket(..., SOCK_STREAM, IPPROTO_TCP) = 3+0  setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0+0  bind(3, ..., ...) = 0+0  listen(3, 1) = 0+0 < S 0:0(0) win 1000 <mss 1460>+0 > S. 0:0(0) ack 1 <...>+0.01 < . 1:1(0) ack 1 win 1000+0 accept(3, ..., ...) = 4+.1 write(4, ..., 500) = 500+0 > P. 1:501(500) ack 1+0.1 < . 1:1(0) ack 501 win 1000+.1 write(4, ..., 1000) = 1000+0 > . 501:1001(500) ack 1+0 > P. 1001:1501(500) ack 1+0.1 < . 1:1(0) ack 1501 win 1000

通过 tcpdump 捕获数据包后,经 Wireshark 展示如下,可以看到由于客户端 No.5 宣告的 Win 为 1000,所以服务器仅能发送 1000 字节大小的数据分段,也就是分别发送了 No.6 和 No.7 两个 Len 为 500 字节的数据包,这样在 No.7 数据包中会判断为 [TCP Window Full],因为发送字节大小已经达到了对端也就是客户端宣告的 Win 大小。

TCP Analysis Flags 之 TCP Window Full


BIF 大小 1000,专家信息标识说明为
TCP window specified by the receiver is now completely full接收端窗口满

TCP Analysis Flags 之 TCP Window Full

实例

关于 TCP Window Full 的实例,正常来说考虑到接收端接收窗口的释放速度,再加上 Window Scale 的存在,TCP 窗口满现象相对来说并不是那么容易出现。而在不同的场景中,也会伴生着出现像是 TCP Window UpdateTCP ZeroWindowTCP ZeroWindowProbeTCP ZeroWindowProbeAck 等信息。

  1. 窗口满

可以看到客户端 No.277 宣告的 Win 为 8712,而服务器 No.278 标识为 [TCP Window Full],是由于在途字节数达到了 8712 字节。

TCP Analysis Flags 之 TCP Window Full

TCP Analysis Flags 之 TCP Window Full

而在之后的通讯过程中,由于客户端 Win 降为了 0,在 No.281 也就标识了 [TCP ZeroWindow],之后由于接收窗口释放变化,又发送了 No.282 Win 为 4356 的 ACK,之后服务器再次发送 No.283 数据分段时又一次标识了 [TCP Window Full],同样的原因是由于在途字节数达到了 4356 字节。

TCP Analysis Flags 之 TCP Window Full

该案例中,客户端并不支持 Window Scale ,也就是在 TCP SYN 中未携带该选项。

  1. 窗口满的特例

当 TCP 通讯速率上不去,疑似某端接收窗口满或有问题时,但又没看到明显的 [TCP Window Full] 标识时,请相信自己的判断,真有可能是发生了 TCP 窗口满问题。

看不到 [TCP Window Full] 标识,仅仅是有可能数据包文件或者说这条 TCP 流不完整,并没有抓到 TCP 三次握手的信息,因此后续的数据通讯过程中是无法得知这条流是否支持 Window Scale 以及它的具体数值,没有这些信息的情况下,是没有办法根据数据包中携带的 Win 字段值计算出实际的窗口值,所以也就没法判断什么时候发生了窗口满事件。

如下,就像只会知道接收窗口 250,在不知道 Window Scale 为 4 的情况下,如何能得出计算后的 Win 大小为 1000 ?

TCP Analysis Flags 之 TCP Window Full

这种情况下,看到的现象就是一端通告的 Win 只是一个小值,但是另一端发送的在途数据又能超过这个值,此时的情况你就可以判断出是因为缺少了 TCP 三次握手。

注意,仅仅是 Wireshark 因为数据包文件不完整无法判断,真实的数据流如果双方均支持 Window Scale,实际的通讯流均是按照各自的缩放因子来计算且发送数据的。

案例也很好模拟出,在上述 packetdrill 示例中把 No.1-3 TCP 三次握手数据包忽略掉即可,如下,No.7 此时已经不再标识 [TCP Window Full], 虽然对端 No.5 所通告的 Win 为 1000 ,但是 Window size scaling factor: -1(unknown),从 [TCP Window Full] 的代码来说,tcpd->rev->win_scale =-1 已经没有后续判断的依据了,因此 [TCP Window Full] 不再出现。

注意区别 Window size scaling factor: -2 (no window scaling used),-2 代表着说数据包文件完整,也就是捕获到了 TCP 三次握手,但双方不支持 Window Scale。

TCP Analysis Flags 之 TCP Window Full

如何知道?有条件的话,复现一次 TCP 连接,重新捕获到 TCP 三次握手即可,不管是 -2 不支持,或者其它的值。然而就算知道了,再通过手动指定 Window Scale 值的方式,也无法让 [TCP Window Full] 再出现 。

  1. 再谈窗口满的特例

这里就要提到之前代码中的 tcpd->rev->is_first_ack ,如下,如果 is_frist_ack 为真,对于 Window 的偏移量也就是 Window Scale ,使用值 0,而不是用 TCP 三次握手中的 Window Scale 值。

tcpd->rev->window<<(tcpd->rev->is_first_ack?0:(tcpd->rev->win_scale==-2?0:tcpd->rev->win_scale))

is_first_ack 具体是在 TCP 三次握手阶段即设置为 True,不管是 SYN 或是 SYN/ACK 数据包,均会设置本方向的 is_first_ack 值为 True 。

    if(tcph->th_flags & TH_SYN) {        if(tcph->th_flags & TH_ACK) {           expert_add_info_format(pinfo, tf_syn, &ei_tcp_connection_synack,                                  "Connection establish acknowledge (SYN+ACK): server port %u", tcph->th_sport);           /* Save the server port to help determine dissector used */           tcpd->server_port = tcph->th_sport;        }        else {           expert_add_info_format(pinfo, tf_syn, &ei_tcp_connection_syn,                                  "Connection establish request (SYN): server port %u", tcph->th_dport);           /* Save the server port to help determine dissector used */           tcpd->server_port = tcph->th_dport;           tcpd->ts_mru_syn = pinfo->abs_ts;        }        /* Remember where the next segment will start. */        if (tcp_desegment && tcp_reassemble_out_of_order && tcpd && !PINFO_FD_VISITED(pinfo)) {            if (tcpd->fwd->maxnextseq == 0) {                tcpd->fwd->maxnextseq = tcph->th_seq + 1;            }        }        /* Initiliaze the is_first_ack */        tcpd->fwd->is_first_ack = TRUE;

在以下这个案例中,No.79 判定为  [TCP Window Full] ,光从表面现象来看会感觉很奇怪,因为 TCP 三次握手中明显双方均支持 Window Scale,且双方均为很大的一个值 WS 128,而客户端仅仅从 No.70-79 传了 10 个 MSS 1448 的分段后即出现了窗口满现象。No.79 显示为 BIF 14480 大小,和 SYN/ACK 通告的窗口 Win 14480 相等,但没有使用 Window Scale 来相乘计算,即对于 [TCP Window FUll] 的判断,使用的直接是 0 值,而不是 Window Scale 128。

TCP Analysis Flags 之 TCP Window Full

TCP Analysis Flags 之 TCP Window Full

这是因为对于客户端 No.79 来说,tcpd->rev->is_first_ack 实际就是服务器端 is_first_ack 的取值,而此时在 rev 方向仅有 No.68 SYN/ACK 数据包,此时 is_first_ack 的值为 True,因此对于 Window 的偏移量也就是 Window Scale ,使用值 0,所以最终判断为 [TCP Window Full] 。

  1. 继续谈窗口满的特例

再说一个案例,服务器端 No.5 判定为 [TCP Window Full] ,是因为客户端 No.3 通告的 Win 为 1000,也就是 Win 250 使用了 Window Scale 4 来相乘计算,因此服务器端能发送 No.4 和 No.5 两个 500 字节大小的数据分段,并在 No.5 上标记 [TCP Window Full] 。

TCP Analysis Flags 之 TCP Window Full

也就是说服务器端在 No.5 数据包分析时,判断 rev 方向 Window Scale 的值是真实值 4 而不是 0 ,这也就意味着此时客户端的 is_first_ack 的值为 False 。而这是在分析客户端 No.3 ACK 数据包时,通过以下代码所实现:

    /*     * Remember if we have already seen at least one ACK,     * then we can neutralize the Window Scale side-effect at the beginning (issue 14690)     */    if(tcp_analyze_seq            && (tcph->th_flags & (TH_SYN|TH_ACK)) == TH_ACK) {        if(tcpd->fwd->is_first_ack) {            tcpd->fwd->is_first_ack = FALSE;        }    }

总结

总结来说,关于 TCP Window Scale ,有两句话说得很到位:

  1. RFC7323 2.2 The window field in a segment where the SYN bit is set (i.e., a or <SYN,ACK>) MUST NOT be scaled.

  2. The Window Scale option has to be honored and interpreted adequately.

TCP Analysis Flags 之 TCP Window Full

往期推荐

1. Wireshark 提示和技巧 | 捕获点之 TCP 三次握手
2. Wireshark 提示和技巧 | a == ${a} 显示过滤宏
3. Wireshark TS | 防火墙空闲会话超时问题
4. Wireshark TS | 循序渐进看系统访问偶发失败
5. 网络设备 MTU MSS Jumboframe 全解

后台回复「TT」获取 Wireshark 提示和技巧系列 合集
后台回复「TS」获取 Wireshark Troubleshooting 系列 合集
如需交流,可后台直接留言,我会在第一时间回复,谢谢!
TCP Analysis Flags 之 TCP Window Full

原文始发于微信公众号(Echo Reply):TCP Analysis Flags 之 TCP Window Full

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年8月2日14:37:35
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   TCP Analysis Flags 之 TCP Window Fullhttps://cn-sec.com/archives/3025473.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息