为什么我们的防火墙(Ubuntu 8.04)使用RST拒绝最终数据包(FIN,ACK,PSH)

背景,很长一段时间我们的防火墙都遇到问题,有时候在TCP超时之前,HTTP请求会暂停部分加载.

在跟踪防火墙上的流量后,我注意到它仅在某些时间条件下发生,例如,当客户端在有效载荷上发送第二个ACK之前,Web服务器已发送了整个响应. [SYN,SYN / ACK,ACK]已经被交换,REQUEST已被发送并且已经确认并且第一个RESPONSE数据包已经被接收并且被确认,然后网络服务器一次性发送其余的响应主体(8个数据包)包括最后一个FIN,PSH)并且在客户端确认任何这些之前,防火墙拒绝向网络服务器发送RST并使客户端保持无限.

以下是整个wireshark跟踪,其中包含来自防火墙两侧的数据包. 192.168.126.161是客户端的私有NAT’et IP地址. 172.16.1.2是网络服务器IP(不显示真实公共IP),10.1.1.1是防火墙外部IP(不显示真实公共IP)

2105 0.086275 192.168.126.161  172.16.1.2       TCP 37854 > http [SYN] Seq=0 Win=5840 Len=0 MSS=1460 SACK_PERM=1 TSV=89375083 TSER=0
2106 0.000066 10.1.1.1         172.16.1.2       TCP 37854 > http [SYN] Seq=0 Win=5840 Len=0 MSS=1460 SACK_PERM=1 TSV=89375083 TSER=0
2107 0.002643 172.16.1.2       10.1.1.1         TCP http > 37854 [SYN,ACK] Seq=0 Ack=1 Win=32768 Len=0 MSS=1460
2108 0.007705 172.16.1.2       192.168.126.161  TCP http > 37854 [SYN,ACK] Seq=0 Ack=1 Win=32768 Len=0 MSS=1460
2109 0.006301 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=1 Ack=1 Win=5840 Len=0
2110 0.000025 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=1 Ack=1 Win=5840 Len=0
2111 0.000007 192.168.126.161  172.16.1.2       HTTP GET /test/style.css HTTP/1.1 
2112 0.000015 10.1.1.1         172.16.1.2       HTTP GET /test/style.css HTTP/1.1 
2113 0.001536 172.16.1.2       10.1.1.1         TCP http > 37854 [ACK] Seq=1 Ack=111 Win=32658 Len=0
2114 0.000014 172.16.1.2       192.168.126.161  TCP http > 37854 [ACK] Seq=1 Ack=111 Win=32658 Len=0
2115 0.002274 172.16.1.2       10.1.1.1         HTTP HTTP/1.1 200 OK  (text/css)
2116 0.000025 172.16.1.2       192.168.126.161  HTTP HTTP/1.1 200 OK  (text/css)
2117 0.005689 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=1461 Win=8760 Len=0
2118 0.000024 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=1461 Win=8760 Len=0
2119 0.001536 172.16.1.2       10.1.1.1         HTTP Continuation or non-HTTP traffic
2120 0.000026 172.16.1.2       192.168.126.161  HTTP Continuation or non-HTTP traffic
2121 0.000007 172.16.1.2       10.1.1.1         HTTP Continuation or non-HTTP traffic
2122 0.000023 172.16.1.2       192.168.126.161  HTTP Continuation or non-HTTP traffic
2123 0.000313 172.16.1.2       10.1.1.1         HTTP Continuation or non-HTTP traffic
2124 0.000030 172.16.1.2       192.168.126.161  HTTP Continuation or non-HTTP traffic
2125 0.000007 172.16.1.2       10.1.1.1         HTTP Continuation or non-HTTP traffic
2126 0.000023 172.16.1.2       192.168.126.161  HTTP Continuation or non-HTTP traffic
2127 0.000009 172.16.1.2       10.1.1.1         HTTP Continuation or non-HTTP traffic
2128 0.000023 172.16.1.2       192.168.126.161  HTTP Continuation or non-HTTP traffic
2129 0.001108 172.16.1.2       10.1.1.1         HTTP Continuation or non-HTTP traffic
2130 0.000035 172.16.1.2       192.168.126.161  HTTP Continuation or non-HTTP traffic
2131 0.000008 172.16.1.2       10.1.1.1         HTTP Continuation or non-HTTP traffic
2132 0.000022 172.16.1.2       192.168.126.161  HTTP Continuation or non-HTTP traffic
2133 0.000007 172.16.1.2       10.1.1.1         HTTP Continuation or non-HTTP traffic
REJECT-->
2134 0.000089 10.1.1.1         172.16.1.2       TCP 37854 > http [RST] Seq=111 Win=0 Len=0
CLIENT FIRST ACK-->
2135 0.002421 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=2921 Win=11680 Len=0
2136 0.000033 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=2921 Win=11680 Len=0
2137 0.000007 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=4381 Win=14600 Len=0
2138 0.000014 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=4381 Win=14600 Len=0
2139 0.000008 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=5841 Win=17520 Len=0
2140 0.000014 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=5841 Win=17520 Len=0
2141 0.000007 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=7301 Win=20440 Len=0
2142 0.000013 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=7301 Win=20440 Len=0
2143 0.000007 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=8761 Win=23360 Len=0
2144 0.000015 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=8761 Win=23360 Len=0
2145 0.000007 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=10221 Win=26280 Len=0
2146 0.000013 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=10221 Win=26280 Len=0
2147 0.001059 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=11681 Win=29200 Len=0
2148 0.000018 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=11681 Win=29200 Len=0

根据这个chart,我一直在挖掘和记录数据包遍历,似乎最后一个传入的数据包2133超过了原始的PREROUTING,conntrack,mangle-PREROUTING但后来丢失了.我的iptables中没有REJECT规则,我记录了所有DROP规则,但没有一个显示数据包2133丢失的位置.

我很乐意在传入的过滤器上使用TRACE目标,但不幸的是,ubuntu 8.04不附带TRACE目标的支持.

因此,我认为某些内部隐式路由/ conntrack / mangling规则适用于某种原因会重置连接.也许流量会触发一些DOS保护,但我不知道在哪里配置/分析它.最令人沮丧的是,数据包被拒绝,没有任何记录……

同样请求此文件100%来自Windows主机,但它在某些Linux主机上失败,99.9%的请求通过,但有时数据包的时间会在我们的防火墙中触发此行为.

编辑
好的,现在我已经在iptables中添加了大量的日志记录,看起来好像发生了以下情况(仍然不知道为什么!)

对于成功遍历防火墙的数据包,将执行以下步骤,表/步参考自here

Table 3-3 step

2     raw-pre
      conntrack
3     mangle-pre
4     [nat-pre]
5     routing-decision -> destination forward
6     mangle-fwd
7     filter-fwd
8     mangle-post
9     [nat-post]

被拒绝的数据包2133遍历这些步骤:

Table 3-1 steps for the incoming FIN,ACK packet 2133
2     raw-pre
      conntrack
3     mangle-pre
4     [nat-pre]
5     routing-decision -> destination local
6     mangle-input
7     filter-input
8     local process emits RST -> webserver

Table 3-2 steps for the outgoing RST packet 2134 in response to 2133
1     raw-out
2     routing decision
      conntrack
3     mangle-out
      reroute-check
4     [nat-out]
5     filter-out
6     mangle-post
7     nat-post

奇怪的是,步骤5中的分组2133的路由决定现在不同于其他分组的路由决定.在分析有效的请求时,例如不会卡住,即使最后一个FIN也能正确路由.它似乎是内核中的一个错误,或者路由决策在某种程度上是有状态的.

编辑

可能导致这些问题的一件事是以下事实:流量在防火墙和本地LAN之间路由,因此客户端LAN不通过L2直接连接到防火墙.

+---------------------------+       +------------------+                         +------------------------+
                |                           |       |      Router      |   (   Lab network    )  |                        |
( Internet ) -- + eth1                 eth0 +-------+                  +-- (                  ) -+ Client 192.168.126.161 |
                | 10.1.1.1   192.168.60.254 |       |                  |   ( 192.168.126.0/24 )  |                        |
                +---------------------------+       +------------------+                         +------------------------+

在此图中,10.1.1.1表示防火墙的外部IP地址,所有其他地址都是使用的真实IP地址.

这是防火墙上的路由表:

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
10.1.1.0        0.0.0.0         255.255.255.240 U     0      0        0 eth1
192.168.126.0   0.0.0.0         255.255.255.0   U     0      0        0 eth0
192.168.60.0    0.0.0.0         255.255.255.0   U     0      0        0 eth0
0.0.0.0         10.1.1.15       0.0.0.0         UG    0      0        0 eth1

请注意,10.1.1.0和默认gw 10.1.1.15组成,其余与使用完全相同.我必须手动添加192.168.126.0/24路由才能从eth0(192.168.60.254)到达实验室网络.

以下是针对最后一个数据包2133的数据包遍历的一些详细日志,这些数据包由于被路由到本地主机(例如防火墙)而被拒绝.

[16406874.374588] raw pre IN=eth1 OUT= MAC=00:02:b3:b9:ff:b5:00:90:1a:10:06:88:08:00 SRC=172.16.1.2 DST=10.1.1.1 LEN=1004 TOS=0x00 PREC=0x00 TTL=55 ID=13739 DF PROTO=TCP SPT=80 DPT=53497 WINDOW=5840 RES=0x00 ACK PSH FIN URGP=0 
[16406874.374625] mangle pre IN=eth1 OUT= MAC=00:02:b3:b9:ff:b5:00:90:1a:10:06:88:08:00 SRC=172.16.1.2 DST=10.1.1.1 LEN=1004 TOS=0x00 PREC=0x00 TTL=55 ID=13739 DF PROTO=TCP SPT=80 DPT=53497 WINDOW=5840 RES=0x00 ACK PSH FIN URGP=0 
[16406874.374667] mangle in IN=eth1 OUT= MAC=00:02:b3:b9:ff:b5:00:90:1a:10:06:88:08:00 SRC=172.16.1.2 DST=10.1.1.1 LEN=1004 TOS=0x00 PREC=0x00 TTL=55 ID=13739 DF PROTO=TCP SPT=80 DPT=53497 WINDOW=5840 RES=0x00 ACK PSH FIN URGP=0 
[16406874.374699] filter in IN=eth1 OUT= MAC=00:02:b3:b9:ff:b5:00:90:1a:10:06:88:08:00 SRC=172.16.1.2 DST=10.1.1.1 LEN=1004 TOS=0x00 PREC=0x00 TTL=55 ID=13739 DF PROTO=TCP SPT=80 DPT=53497 WINDOW=5840 RES=0x00 ACK PSH FIN URGP=0 
[16406874.374780] mangle out IN= OUT=eth1 SRC=10.1.1.1 DST=172.16.1.2 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=53497 DPT=80 WINDOW=0 RES=0x00 RST URGP=0 
[16406874.374807] mangle post IN= OUT=eth1 SRC=10.1.1.1 DST=172.16.1.2 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=53497 DPT=80 WINDOW=0 RES=0x00 RST URGP=0 
[16406874.378813] mangle pre IN=eth0 OUT= MAC=00:02:b3:b9:ff:b4:00:90:1a:10:0c:dd:08:00 SRC=192.168.126.161 DST=172.16.1.2 LEN=40 TOS=0x00 PREC=0x00 TTL=63 ID=35424 DF PROTO=TCP SPT=53497 DPT=80 WINDOW=11680 RES=0x00 ACK URGP=0 
[16406874.378863] mangle fwd IN=eth0 OUT=eth1 SRC=192.168.126.161 DST=172.16.1.2 LEN=40 TOS=0x00 PREC=0x00 TTL=62 ID=35424 DF PROTO=TCP SPT=53497 DPT=80 WINDOW=11680 RES=0x00 ACK URGP=0

我们的fw外部IP再次被10.1.1.1取代,NAT网络外的网络服务器的ip被替换为172.16.1.2

编辑突发新闻!

好的最后一次尝试是DROP RST数据包,非常非常有趣,我添加了一个iptables规则,该规则删除了所有RST数据包,这些数据包都是我们在请求文件时遇到问题的网络服务器.然后它工作,例如上面的日志中的最后一个FIN,ACK,PSH数据包2133被丢弃,但是由于RST被丢弃,网络服务器有时间获得所有ACK的蚂蚁然后决定再次重发最后一个数据包,包2133,现在它通过防火墙,因为对战模块现在已经看到ACK从客户端返回并允许最后的ACK,FIN数据包和最终有效载荷.

所以这肯定是一个时间/窗口问题,这个特定的文件,来自客户端的ACK的时间,触发conntrack中的一些东西拒绝来自网络服务器的最终数据包.

到目前为止,谷歌搜索和阅读内核文件显示没有任何可能导致此行为,下一步将是读取路由/ conntrack模块的内核源代码.

问题解决了

好吧,至少现在我们确切知道发生了什么,并有一个解决问题的解决方法.

谢尔盖指出非常有价值的-m状态 – 状态INVALID匹配规则在调试中有很多帮助,我现在意识到没有明确的INVALID数据包规则的iptables设置不完整,所以有时似乎会发生奇怪的行为.

当启用在conntrack模块中记录导致无效数据包的原因时,会发生什么事情非常明显,我怀疑这一点.

[16659529.322465] nf_ct_tcp: SEQ is over the upper bound (over the window of the receiver) IN= OUT= SRC=172.16.1.2 DST=10.1.1.1 LEN=1004 TOS=0x00 PREC=0x00 TTL=55 ID=40874 DF PROTO=TCP SPT=80 DPT=55498 SEQ=658735108 ACK=1194081763 WINDOW=5840 RES=0x00 ACK PSH FIN URGP=0

172.16.1.2再次是外部Web服务器(行为不正确),10.1.1.1是防火墙的外部地址.

在Web服务器上比客户端在接收窗口(跟踪连接的全状态,并验证这一点)发布的电线推动更多的数据,似乎它是当FIN数据包到达该连接跟踪捞出,因为接收窗口实际上是超出了很多早.

我认为这可能是由于网络服务器上的网卡中的TCP卸载不正确造成的.当我开始分析这个时,我在网络服务器上进行了捕获,根据tcpdump / wireshark跟踪,jumbo帧由内核中的TCP层写入,然后由网卡分割成MTU = 1500的较小帧.显然,这需要在网络服务器中得到解决,因为发送比接收者在其接收窗口中有广告的数据更多的TCP行为是不正确的.

Polynomial和Sergey都提供了宝贵的意见,但谢尔盖向我指出了conntrack / NAT模块关于数据包遍历的确切行为.

http://www.spinics.net/lists/netfilter/msg51408.html描述了类似的情况:应该由NAT处理的一些数据包以某种方式被标记为INVALID而不是ESTABLISHED,并且转到INPUT链.您应该使用-m state –state INVALID添加一些规则来检查这一点,并且 http://www.spinics.net/lists/netfilter/msg51409.html的答案表明此类INVALID数据包应始终为DROPped,因为NAT未正确执行,因此其中的地址可能是错误的.

如果你的有问题的数据包真的标记为INVALID,添加iptables -I INPUT -m state –state INVALID -j DROP可能会解决问题(破坏的数据包不会到达本地进程,也不会导致RST响应,然后TCP将在超时后从丢失的数据包中恢复.然后,您可以尝试进一步调试问题,如http://www.spinics.net/lists/netfilter/msg51411.html中所述:

echo 255 >/proc/sys/net/netfilter/nf_conntrack_log_invalid

(在这种特殊情况下,问题是由路径上的某些网络硬件损坏引起的,可能与某些TCP校验和卸载故障相结合.)

相关文章

文章浏览阅读2.3k次,点赞4次,收藏22次。最近安装了CARLA预...
文章浏览阅读6.3k次,点赞5次,收藏15次。在清华镜像中下载U...
文章浏览阅读5k次。linux环境, python3.7.问题描述: 安装...
文章浏览阅读4.2k次,点赞4次,收藏17次。要安装这个 standa...
文章浏览阅读894次,点赞51次,收藏31次。在安卓使用vscode主...