到目前为止,我一直使用一台装有 2 个网卡并运行 iptables 的 CentOS 5.x PC 作为我的网络路由器。它工作得很好,但最近我决定买一个运行 Debian 5.0.3/kernel 2.6.33.6 的 DreamPlug,用它来替换我的 CentOS 路由器。我复制了我的 iptables 配置并以相同的方式设置接口,然后将它们切换出去。
一切似乎都运行正常,但后来我注意到,在连接初始化后,我的 tcp 会话会持续挂起 1 到 10 秒。这导致无法立即加载的网站卡在加载过程中。文件下载运行了几秒钟,然后无限期停止。有几次传输恢复了,但只持续了几秒钟,然后又停滞了。
此时,我用一个新的基本 NAT 配置替换了我的 iptables 配置(http://pastebin.com/raw.php?i=bhLHk2wh) 以排除任何防火墙配置问题。我使用 wget 在几十个不同的网站 (GET /) 上进行了测试,并从一些不同的镜像下载了 iso 文件。无论我从哪里下载,该问题始终可重现。我捕获了数据在离开我的网络之前经过的三个接口中的每一个的 tcpdump:内部主机 NIC、防火墙内部 NIC、防火墙外部 NIC。每个接口上的数据包之间没有任何差异(我能看出)。iptables 日志证实,防火墙没有阻止任何数据包。
以下是本次测试的 wget 输出:http://pastebin.com/raw.php?i=qyXtE2rJ
我不是 tcp 专家,所以我的分析可能很基础,但我发现 tcp 会话设置正确。一些 P 数据包被发送并被确认,突然间数据包开始丢失。
以下是防火墙上外部接口 (eth0) 的转储:http://pastebin.com/raw.php?i=q73b1rXZ
序列号 3655108323 有几个重复的 ACK,而远程主机似乎仍在发送未确认的数据。然后发送了 R 标志,连接在 16:30:32.310469 处挂起五分钟,然后我通过中断 wget 导致会话终止。还值得注意的是,在我的测试过程中,我会看到这种挂起行为以两种不同的方式开始。
- 防火墙会发送 R 标志,并且不会再接收来自远程主机的数据包。
- 防火墙将发送一个无标志的确认,并且不会再收到来自远程主机的数据包。
我看到的唯一其他潜在问题是 272 个数据包被外部防火墙接口丢弃。我对此有点困惑,因为防火墙以 100Mbps(内部)的速度下载文件,毫不费力。这些小连接微不足道,不应该有任何数据包被丢弃。此外,我能从防火墙本身运行 wget 时,可以非常快速地下载文件。我获得超过 1MBps 的稳定速度(通过互联网)。以下是转储的截取版本:http://pastebin.com/raw.php?i=Fb9zhqh4
以下是防火墙上内部接口(eth1)的转储:http://pastebin.com/raw.php?i=TuM4sTxB
内部接口上看上去并没有什么不同,也没有丢弃任何数据包。
以下是我的内部主机(OS X)上的接口(en0)的转储:http://pastebin.com/raw.php?i=SSXHFqVf
我注意到,这台主机发出的帧的校验和几乎总是错误的。这在 CentOS 路由器上也发生过,但由于它似乎没有产生任何负面影响,我认为一定是校验和不正确。如果有人知道是什么原因造成的,我很想找出原因。
总之,似乎有一些 PL 正在发生,但我无法确定原因。外部 fw 转储让我认为问题存在于 eth0 上,但我可以在防火墙本身上正常 wget 文件(流量仅通过 eth0),所以不可能是它。有人对我可以采取的其他故障排除步骤有什么建议吗,以缩小此处的潜在原因?
答案1
TCP 连接挂起可能意味着您在传输过程中遇到了 MTU 问题。最有可能的是,在您的路径上某处有一个设备阻止了需要 ICMP 碎片处理的数据包。
您可以在这里找到如何规避此问题的说明:http://www.netfilter.org/documentation/HOWTO/netfilter-extensions-HOWTO-4.html#ss4.7。
我建议确定您可以使用的最大 MTU
ping -M do -s MTU REMOTE_IP
(将 MTU 从 1500 向下更改,直到找到合适的值),然后
iptables -I FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss MTU