毕设网站代做一般预算多少钱,企业网站模板湖南岚鸿模板,音乐网站建设价格,开源零代码平台前言
默认情况下#xff0c;Wireshark 的 TCP 解析器会跟踪每个 TCP 会话的状态#xff0c;并在检测到问题或潜在问题时提供额外的信息。在第一次打开捕获文件时#xff0c;会对每个 TCP 数据包进行一次分析#xff0c;数据包按照它们在数据包列表中出现的顺序进行处理。可…前言
默认情况下Wireshark 的 TCP 解析器会跟踪每个 TCP 会话的状态并在检测到问题或潜在问题时提供额外的信息。在第一次打开捕获文件时会对每个 TCP 数据包进行一次分析数据包按照它们在数据包列表中出现的顺序进行处理。可以通过 “Analyze TCP sequence numbers” TCP 解析首选项启用或禁用此功能。
TCP 分析展示
在数据包文件中进行 TCP 分析时关于 “TCP Window Full” 一般是如下显示的包括
Packet List 窗口中的 Info 信息列以 [TCP Window Full] 黑底红字进行标注Packet Details 窗口中的 TCP 协议树下在 [SEQ/ACK analysis] - [TCP Analysis Flags] 中定义该 TCP 数据包的分析说明。 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( seglen0 tcpd-rev-win_scale!-1 (seqseglen)(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;}lastack定义为 Last seen ack for the reverse flow。关于 tcpd-rev-is_first_ack在之后实例中会展开说明。 Packetdrill 示例
在上述 TCP Window Full 定义和代码可知TCP 分析的逻辑很简单因此通过 packetdrill 比较容易模拟出相关现象。
# cat tcp_window_full.pkt
0 socket(..., SOCK_STREAM, IPPROTO_TCP) 3
0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) 0
0 bind(3, ..., ...) 0
0 listen(3, 1) 00 S 0:0(0) win 1000 mss 1460
0 S. 0:0(0) ack 1 ...
0.01 . 1:1(0) ack 1 win 10000 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 大小。 BIF 大小 1000专家信息标识说明为 TCP window specified by the receiver is now completely full 接收端窗口满。 实例
关于 TCP Window Full 的实例正常来说考虑到接收端接收窗口的释放速度再加上 Window Scale 的存在TCP 窗口满现象相对来说并不是那么容易出现。而在不同的场景中也会伴生着出现像是 TCP Window Update、TCP ZeroWindow、TCP ZeroWindowProbe、TCP ZeroWindowProbeAck 等信息。
窗口满
可以看到客户端 No.277 宣告的 Win 为 8712而服务器 No.278 标识为 [TCP Window Full]是由于在途字节数达到了 8712 字节。 而在之后的通讯过程中由于客户端 Win 降为了 0在 No.281 也就标识了 [TCP ZeroWindow]之后由于接收窗口释放变化又发送了 No.282 Win 为 4356 的 ACK之后服务器再次发送 No.283 数据分段时又一次标识了 [TCP Window Full]同样的原因是由于在途字节数达到了 4356 字节。 该案例中客户端并不支持 Window Scale 也就是在 TCP SYN 中未携带该选项。 窗口满的特例
当 TCP 通讯速率上不去疑似某端接收窗口满或有问题时但又没看到明显的 [TCP Window Full] 标识时请相信自己的判断真有可能是发生了 TCP 窗口满问题。
看不到 [TCP Window Full] 标识仅仅是有可能数据包文件或者说这条 TCP 流不完整并没有抓到 TCP 三次握手的信息因此后续的数据通讯过程中是无法得知这条流是否支持 Window Scale 以及它的具体数值没有这些信息的情况下是没有办法根据数据包中携带的 Win 字段值计算出实际的窗口值所以也就没法判断什么时候发生了窗口满事件。
如下就像只会知道接收窗口 250在不知道 Window Scale 为 4 的情况下如何能得出计算后的 Win 大小为 1000 这种情况下看到的现象就是一端通告的 Win 只是一个小值但是另一端发送的在途数据又能超过这个值此时的情况你就可以判断出是因为缺少了 TCP 三次握手。 注意仅仅是 Wireshark 因为数据包文件不完整无法判断真实的数据流如果双方均支持 Window Scale实际的通讯流均是按照各自的缩放因子来计算且发送数据的。 案例也很好模拟出在上述 packetdrill 示例中把 No.1-3 TCP 三次握手数据包忽略掉即可如下No.7 此时已经不再标识 [TCP Window Full] 虽然对端 No.5 所通告的 Win 为 1000 但是 Window size scaling factor: -1unknown从 [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 连接重新捕获到 TCP 三次握手即可不管是 -2 不支持或者其它的值。然而就算知道了再通过手动指定 Window Scale 值的方式也无法让 [TCP Window Full] 再出现 。
再谈窗口满的特例
这里就要提到之前代码中的 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 (SYNACK): 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。 这是因为对于客户端 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] 。
继续谈窗口满的特例
再说一个案例服务器端 No.5 判定为 [TCP Window Full]是因为客户端 No.3 通告的 Win 为 1000也就是 Win 250 使用了 Window Scale 4 来相乘计算因此服务器端能发送 No.4 和 No.5 两个 500 字节大小的数据分段并在 No.5 上标记 [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 有两句话说得很到位
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.The Window Scale option has to be honored and interpreted adequately.