背景技术长期以来,我们的防火墙一直存在问题,有时防火墙会将HTTP请求的部分挂起挂起,直到TCP超时为止。
在防火墙上跟踪流量之后,我注意到它仅在某些定时条件下发生,例如,当Web服务器在客户端已在有效负载上发送其第二个ACK之前发送了整个响应时。[SYN,SYN / ACK,ACK]已被交换,REQUEST已发送并被ACK',并且第一个RESPONSE数据包已被接收并ACK',然后网络服务器将其余的响应主体发送到一个镜头中(8个数据包)包括最后一个FIN,PSH),并且在客户端对其中任何一个进行确认之前,带有RST的Firewall REJECTS指向Web服务器,并保持客户端无限挂起。
这是整个wireshark跟踪以及来自防火墙双方的数据包。192.168.126.161是客户端的专用NAT'et IP地址。172.16.1.2是Web服务器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
我一直在根据此图表挖掘和记录数据包遍历,似乎最后一个传入数据包2133经过了raw-PREROUTING,conntrack,mangle-PREROUTING,但随后丢失了。我的iptables中没有REJECT规则,我记录了所有DROP规则,但没有一个显示包2133丢失的位置。
我很想在传入的过滤器上使用TRACE目标,但是不幸的是ubuntu 8.04并未附带对TRACE目标的支持。
因此,我认为某些内部隐式路由/ conntrack /篡改规则适用于出于某种原因而重置连接的情况。也许流量触发了一些DOS保护,但是我不知道在哪里进行配置/分析。最令人沮丧的是,数据包被拒绝并且没有任何记录...
同样,从Windows主机请求此文件的工作率为100%,但在某些Linux主机上失败,并且所有请求的99.9%都通过了,但是有时数据包的时间触发了我们防火墙中的此行为。
编辑 好吧,现在我在iptables中添加了大量日志,似乎发生了以下情况(仍然不知道为什么!)
对于成功穿越防火墙的数据包,请执行以下步骤,此处的表/步骤参考
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网络之外的Web服务器的IP被172.16.1.2替换了
编辑最新消息!
好的,最后一次尝试是丢弃RST数据包,这非常有趣,我添加了一个iptables规则,该规则将所有发往目标文件的Web服务器的RST数据包都丢弃了。然后工作,例如,上面日志中的最后一个FIN,ACK,PSH数据包2133被丢弃,但是由于RST被丢弃,因此网络服务器有时间获取所有ACK的蚂蚁,然后决定再次重传最后一个数据包2133,现在,它通过防火墙,因为contrack模块现在已经看到ACK从客户端返回,并允许最后一个ACK,FIN数据包具有最终有效负载。
因此,这绝对是一个时间/窗口问题,该特定文件以及来自客户端的ACK的时间会触发conntrack中的某些内容,从而拒绝来自Web服务器的最终数据包。
到目前为止,谷歌搜索和阅读内核文档不会发现任何会导致这种行为的内容,下一步将是阅读路由/ conntrack模块的内核源代码。
问题解决了
好吧,至少现在我们确切地知道会发生什么,并且有解决该问题的解决方法。
Sergey指出了非常有价值的-m状态--state 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服务器通过有线方式推送的数据比客户端在接收窗口中通告的数据更多(conntrack已处于满状态并进行验证),似乎是FIN数据包到达时conntrack失败了,因为接收窗口实际上超出了很多较早。
我认为这可能是由于Web服务器上网卡中TCP错误卸载所引起的。当我开始对此进行分析时,我在网络服务器上进行了捕获,并根据tcpdump / wireshark跟踪,将巨型帧由内核中的TCP层写入,然后通过网卡将其分割为MTU = 1500的较小帧。因此很显然,这需要在Web服务器中解决,因为发送与接收者在其接收窗口中有广告的数据相比更多的数据是不正确的TCP行为。
多项式和Sergey都提供了有价值的输入,但是Sergey向我指出了conntrack / NAT模块在数据包遍历方面的确切行为。