我正在做一个研究项目,需要拆分 tcp 连接。所以我有一些奇怪的问题,这些问题可能会在我的开发中发生。问题在于对 TCP SACK 允许协商的理解。我读了 RFC,但找不到答案。
对于两个 TCP 程序 A 和 B 之间的 3 次 TCP 握手,如果 A 向 B 发送一个允许 SACK 的 TCP SYN,B 一定会响应一个允许 SACK 的 SYN/ACK 数据包吗?如果 B 回复一个不允许 SACK 的 TCP SYN/ACK,是否意味着
1)SACK-permmited 仅在 A 上启用。A 可以选择性地确认来自 A 的 tcp 数据包,但 A 不能选择性地确认来自 B 的 tcp 数据包。
或者
2)A 和 B 上均未启用 SACK-permmited
如果 A 向 B 发送一个没有 SACK 许可的 TCP SYN,B 是否可以响应一个带有 SACK 许可的 SYN/ACK 数据包?
此外,为什么允许或禁止 SACK-permitted?这取决于操作系统或内核设置还是其他什么?可以控制它吗?谢谢!
答案1
SACK 是后来添加的,因此需要向后兼容,无论是对于终端主机还是中间件(另见下文)。该SACK-permitted
选项正好满足了这一点。
SACK-permitted
从 A 发送到 B,表示 A 愿意接收 SACK 选项。对于 SACK 处理(与大多数重传处理一样),TCP 可以被视为由两个单工连接组成,每个连接的状态不同。因此,让 SACK 只在一个方向上传输是完全合法的(但不常见)(SACK-permitted
SYN 或 SYNACK 期间的反向传输)。
通常,您可能希望保持 SACK 处于启用状态,因为它可以提高性能。但是,过去(现在可能仍然)有防火墙和 NAT 盒会更改 SEQ 和 ACK 标头字段,但不知道 SACK,因此不会相应地调整 SACK 选项中的序列号。这可能会导致连接挂起(因为 SACK 已确认尚未收到的不同段)。这就是您可能希望禁用 SACK 的原因,即使两台机器都支持它。
在 *BSD 系统(包括 MacOS X)上可以通过输入禁用 SACK(用于测试或存在上述丑陋的中间盒),然后sysctl -w net.inet.tcp.sack=0
将其设置回 1 来重新启用。在 Linux 上,sysctl -w net.ipv4.tcp_sack=0
可以达到相同的效果。
第一段RFC 2018 第 4 节允许在收到允许 SACK 时发送 SACK。通常,支持 SACK 的主机会宣布允许 SACK。我无法想象一个有用的场景,即支持 SACK 的主机不会宣布允许 SACK,但会使用 SACK(一个不切实际的例子是中间盒仅在一个方向上严重摆弄 SACK)。因此,我不希望仅在一个方向上使用 SACK。
使用 Wireshark 对 Linux、MacOSX(可能适用于 *BSD)和 HP 打印机进行的快速测试表明,当 SYN 中包含 SACK-permitted 时,它们将以 SYNACK 中的 SACK-permitted 进行响应。但是,我发现 RFC 中没有任何内容要求或鼓励这种行为。
答案2
由于数据包丢失(握手消息中发送的 TCP 标头中的某些字节被丢弃),SACK-permitted 可能会丢失。这可能是因为您这边的 PMTUD 运行不正常。请尝试手动减少您这边的 MTU 大小。
答案3
除非 Van Jacobsen 或他的同事恰好在这个论坛上闲逛,否则这个问题很可能会要求任何试图回答的人付出巨大的努力。如果你仔细想想,回答你的问题所需的研究水平将与你目前从事的研究项目一样高甚至更高。这可能会让大多数人觉得这有点不公平。
然而,我们中的许多人也曾遇到过不得不提出一些棘手问题的情况,而这些问题的答案并不明显或难以找到。虽然就我而言,我最终还是得自己找到这些问题的答案,但我很幸运,有热心人士为我指明了正确的方向……
我目前没有两个 BSD-unix 系统上的 root 访问权限,但如果我有的话……我知道可以使用 来控制选择性 ACks sysctl
。在我的 Mac 上,启用 SACK 的条目是net.inet.tcp.sack
。启用时,它的值为 1;要禁用,sysctl -w net.inet.tcp.sack=0
。我会设置各种场景并用来tcpdump
测试您的问题。
其他人可能会给你不同的提示......