服务器不发送SYN / ACK数据包来响应SYN数据包

使用iptraf,tcpdump和wireshark我可以看到一个SYN数据包进入,但只有ACK FLAG被设置在回复数据包中。

我正在运行内核2.6.36的Debian 5

我closures了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输出的图像。

View post on imgur.com

输出到netstat

 netstat -natu | grep '72.23.130.104' tcp 0 0 97.107.134.212:18000 72.23.130.104:42905 SYN_RECV 

我一直在尽一切可能find一个解决scheme,还没有找出问题,所以任何帮助/build议非常感谢。

更新1:我已经设置了tcp_syncookies = 0,并且注意到我现在每回复50个SYN请求就有1个SYN + ACK。 尝试连接的主机每秒发送一次SYN请求。

PCAP文件

遇到同样的问题后,我终于find了根本原因。

在Linux上,当套接字在TIME_WAIT和一个新的SYN追加(对于同一对ip / port src,ip / port dest)时,内核检查SYN的SEQ编号是否小于最后接收到的SEQ这个sockets。

(PS:在附加到这个问题的wireshark输出的图像中,seq编号显示为相对的,如果你不把它们设置为绝对的,你不能看到问题。捕获将不得不显示旧的会话还能够比较SEQ号码)

  • 如果SYN的SEQ编号大于前一个数据包的SEQ编号,则新的连接被创build并且一切正常
  • 如果SYN的SEQ号小于前一个数据包的SEQ数,则内核将发送与之前的数据包相关的ACK,因为内核认为接收到的SYN是前一个数据包的延迟数据包。

这种行为就像这样,因为在TCP开始的时候,增量的计算机产生的SEQ号码几乎不可能接收到一个仍然在TIME_WAIT中的前一个套接字的SEQ号<的序列号。

计算机带宽的增加使其几乎不可能变为罕见。 但是这里最重要的是现在大多数系统使用随机ISN(初始SEQ编号)来提高安全性。 所以没有什么能够阻止新套接字的SEQ号a大于前一个的SEQ号。

每个操作系统使用不同的algorithm或多或less是安全的,以避免这个问题http://www.bsdcan.org/2006/papers/ImprovingTCPIP.pdf提供了一个很好的问题&#x3002;

还有最后一个棘手的事情……所以内核会发送一个与旧会话相关的ACK,然后呢? 客户端操作系统应该收到ACK(前一个会话),不理解,因为对于客户端会话closures,发送一个RST。 当服务器收到这个RST时,它会立即清除套接字(所以不再在TIME_WAIT中)。 在他的一面,客户端正在等待一个SYN / ACK,因为它没有得到它,它会发送一个新的SYN。 同时RST已经被发送,会话在服务器上被清除,所以这个辅助SYN将起作用,并且服务器将回复SYN / ACK等等。

所以正常的行为是连接应该工作,但是被延迟一秒(直到发送辅助SYN)。 在Jeff的情况下,他在评论中说他使用的是Fortinet防火墙,这些防火墙(默认情况下)会丢弃与旧会话有关的ACK(因为防火墙看不到有关ACK的开放会话),所以客户端不会发送任何RST并且服务器不能从TIME_WAIT状态中清除会话(当然在TIME_WAIT计时器结束时除外)。 fortinet上的“set anti-replay loose”命令可以允许这个ACK包被转发而不是丢弃。

看来,97.107.134.212已经认为有一个联系(72.23.130.104:42905, 97.107.134.212:18000)

当72.23.130.104:42905发送它的SYN包时,它的序列号是246811966.接下来应该是一个带有自己的SEQ号码和一个ACK值为246811967的SYN / ACK包。

但是它发送了一个ACK = SEQ ID = 1736793629,ACK = 172352206。 这些可能是早期连接的价值。

任何新的连接尝试应该来自不同的端口号…是发生? Wireshark在pkt#11中指出:“重用TCP端口号”。

看起来问题是发件人。

FWIW,我可以连接好:

 1 0.000000 192.168.0.135 97.107.134.212 TCP 45883 > biimenu [SYN] Seq=809402803 Win=14600 Len=0 MSS=1460 SACK_PERM=1 TSV=2319725 TSER=0 WS=7 2 0.022525 97.107.134.212 192.168.0.135 TCP biimenu > 45883 [SYN, ACK] Seq=4293896301 Ack=809402804 Win=14600 Len=0 MSS=1360 SACK_PERM=1 3 0.022553 192.168.0.135 97.107.134.212 TCP 45883 > biimenu [ACK] Seq=809402804 Ack=4293896302 Win=14600 Len=0 

有一次我看到过这种情况,这是因为出站和入站数据包在networking上采取了不同的路由,并且在入站站点有一个有状态的连接跟踪设备。 由于该设备(我的情况下是一个负载均衡器,但它可能很容易成为防火墙)从来没有看到最初的SYN,所以SYN-ACK被误认为是虚假的。

它不仅仅是不对称,因为我们也丢失了一个外出的数据包:

SYN消失,但是我们看不到传入的SYN-ACK, 或者从本地服务器传出的ACK。 因此,其他东西必须代理这两个数据包,然后我们看到传入的ACK – 这实际上是序列中的第四个数据包。

我的猜测是广域网加速器configuration错误。

我会检查一些事情:

你的主机是多宿主的(例如,你有多个以太网接口?) – 如果这样你的路由可能会搞砸。 最简单的方法来testing这将是禁用您的辅助界面(S),看看问题是否消失。

其他要检查的是iptables(或其他防火墙)是否启用。 服务iptables停止将closures它,直到下一次重新启动 – 如果这解决了这个问题,那么你需要调整你的iptables设置。

另外,如果您的接口上启用了IPv6,有时会通过ipv4路由,但不会通过ipv6。 发生这种情况时,ipv6路由是“默认”,你的数据包可以通过错误的地址(即使在正确的接口)。 尝试禁用ipv6,看看是否是这个问题。