我正在使用内核2.6.36运行Debian 5
我已经关闭了window_scaling和tcp_timestamps,tcp_tw_recycle和tcp_tw_reuse:
cat /etc/sysctl.conf net.ipv4.tcp_tw_recycle = 0 net.ipv4.tcp_tw_reuse = 0 net.ipv4.tcp_window_scaling = 0 net.ipv4.tcp_timestamps = 0
我附上了wireshark输出的图像.
输出到netstat
netstat -natu | grep '72.23.130.104' tcp 0 0 97.107.134.212:18000 72.23.130.104:42905 SYN_RECV
我一直在尽一切可能找到解决方案并且还没有弄清楚问题,所以非常感谢任何帮助/建议.
更新1:我已设置tcp_syncookies = 0并注意到我现在每回复50个SYN请求回复1个SYN ACK.尝试连接的主机每秒发送一次SYN请求.
解决方法
在Linux上,当套接字在TIME_WAIT上并且新的SYN附加(对于同一对ip / port src,ip / port dest)时,内核检查SYN的SEQ号是否为<或>比这个插座收到的最后一个SEQ.
(PS:在附加到此问题的wireshark输出的图像中,seq编号显示为相对,如果您没有将它们设置为绝对,则无法看到问题.捕获将必须显示旧会话也能够比较SEQ数字)
>如果SYN的SEQ ID是>比起前一个数据包的SEQ号,一个新的连接被装箱,一切正常
>如果SYN的SEQ ID是<与前一个数据包的SEQ号相比,内核将发送与前一个套接字相关的ACK,因为内核认为收到的SYN是前一个套接字的延迟数据包.
行为是这样的,因为在TCP的开始处由计算机生成的SEQ号增量,几乎不可能接收到SEQ ID<比仍在TIME_WAIT中的前一个套接字的SEQ号. 计算机带宽的增加使得这几乎不可能实现.但最重要的是,现在大多数系统使用随机ISN(初始SEQ号)来提高安全性.因此,没有什么能阻止新套接字的SEQ号a>比前一个的SEQ号. 每个操作系统都使用不同的算法,这些算法或多或少都是安全的,可以避
http://www.bsdcan.org/2006/papers/ImprovingTCPIP.pdf很好地介绍了这个问题.
还有一些棘手的事情……所以内核会发送一个与旧会话相关的ACK,然后呢?客户端操作系统应该接收(先前会话的)ACK,不理解它,因为对于客户端会话关闭,发送RST.当服务器收到此RST时,它将立即清除套接字(因此它不再在TIME_WAIT中).
在他的一边,客户端正在等待SYN / ACK,因为它没有得到它,它将发送一个新的SYN.同时RST已经发送并且服务器上的会话被清除,因此这个辅助SYN将起作用,服务器将回复SYN / ACK,依此类推.
所以正常的行为是连接应该工作但延迟一秒(直到发送辅助SYN).在杰夫的案例中,他在评论中说他使用的是Fortinet防火墙,这些防火墙(默认情况下)会丢弃与旧会话相关的ACK(因为防火墙看不到与ACK相关的开放会话),所以客户端没有发送任何RST并且服务器无法从TIME_WAIT状态清除会话(当然除了TIME_WAIT计时器结束时).fortinet上的“set anti-replay loose”命令可以允许转发此ACK数据包而不是丢弃.