我遇到了一个让我颇为头痛的问题,并find了解决办法,但我不明白为什么这个问题首先发生。
我有一个nginx反向代理,它将请求路由到3台服务器中的一台。 所有的节点服务器,其中两个是明确的,一个是定制的。
问题是: 当我的防火墙启动时 ,两个快速服务器总运行时间中的第一个请求遭受504:网关超时 。 发生这种情况后,即使在多天的过程中,这些文件也可以很快得到处理。
我能够把问题缩小到防火墙,注意到当我彻底closures防火墙时问题就消失了。 我的服务器运行FreeBSD,使用PF作为防火墙。 这里是相关的pf.conf:
iface = "vtnet0" loopback = "lo0" public_ip = "132.148.77.28/32" localnet = "127.0.0.1" nat on $iface from any to any -> $public_ip # added by cloud server provider pass out quick on $iface proto { tcp udp } from port ntp keep state block log all pass in on $iface proto tcp from $localnet to port mail pass in log on $iface proto tcp to $public_ip port { ssh http } keep state pass in log on $loopback proto tcp to $localnet port { 5555 5556 5557 } keep state pass out log all keep state
据我所知, vtnet0设备上的任何stream量都将被转换为使用public-ip。
我用下面的命令运行了tcpdump: sudo tcpdump -c 10 -vvv -t -i pflog0 -e -n tcp
我在pflog0上捕获了10个数据包,三重冗长,压制时间戳,打印允许或阻止数据包的pf规则,将ip地址和端口作为数字,仅使用tcp捕获stream量。
以下是第一个请求的有趣结果以及后续请求的结果:
$ sudo tcpdump -c 10 -vvv -t -i pflog0 -e -n tcp tcpdump: WARNING: pflog0: no IPv4 address assigned tcpdump: listening on pflog0, link-type PFLOG (OpenBSD pflog file), capture size 65535 bytes rule 8..16777216/0(match): pass in on vtnet0: (tos 0x0, ttl 52, id 53488, offset 0, flags [DF], proto TCP (6), length 60) 67.197.156.119.45274 > 132.148.77.28.80: Flags [S], cksum 0x76df (correct), seq 356096480, win 29200, options [mss 1460,sackOK,TS val 63916304 ecr 0,nop,wscale 7], length 0 rule 9..16777216/0(match): pass out on lo0: (tos 0x0, ttl 64, id 2406, offset 0, flags [DF], proto TCP (6), length 60) 127.0.0.1.28850 > 127.0.0.1.5556: Flags [S], cksum 0xfe30 (incorrect -> 0x180a), seq 2069090201, win 65535, options [mss 16344,nop,wscale 6,sackOK,TS val 33367168 ecr 0], length 0 rule 5..16777216/0(match): pass in on lo0: (tos 0x0, ttl 64, id 2406, offset 0, flags [DF], proto TCP (6), length 60, bad cksum 0 (->3354)!) 127.0.0.1.28850 > 127.0.0.1.5556: Flags [S], cksum 0xfe30 (incorrect -> 0x180a), seq 2069090201, win 65535, options [mss 16344,nop,wscale 6,sackOK,TS val 33367168 ecr 0], length 0 rule 9..16777216/0(match): pass out on lo0: (tos 0x0, ttl 64, id 2414, offset 0, flags [DF], proto TCP (6), length 60) 132.148.77.28.48488 > 132.148.77.28.80: Flags [S], cksum 0xa38f (incorrect -> 0x1728), seq 3973611725, win 65535, options [mss 16344,nop,wscale 6,sackOK,TS val 33367544 ecr 0], length 0 rule 2..16777216/0(match): **block in on lo0**: (tos 0x0, ttl 64, id 2414, offset 0, flags [DF], proto TCP (6), length 60, bad cksum 0 (->8ded)!) 132.148.77.28.48488 > 132.148.77.28.80: Flags [S], cksum 0xa38f (incorrect -> 0x1728), seq 3973611725, win 65535, options [mss 16344,nop,wscale 6,sackOK,TS val 33367544 ecr 0], length 0 rule 2..16777216/0(match): **block in on lo0**: (tos 0x0, ttl 64, id 2416, offset 0, flags [DF], proto TCP (6), length 60, bad cksum 0 (->8deb)!) 132.148.77.28.48488 > 132.148.77.28.80: Flags [S], cksum 0xa38f (incorrect -> 0x0b6a), seq 3973611725, win 65535, options [mss 16344,nop,wscale 6,sackOK,TS val 33370550 ecr 0], length 0 rule 2..16777216/0(match): **block in on lo0**: (tos 0x0, ttl 64, id 2418, offset 0, flags [DF], proto TCP (6), length 60, bad cksum 0 (->8de9)!) 132.148.77.28.48488 > 132.148.77.28.80: Flags [S], cksum 0xa38f (incorrect -> 0xfee6), seq 3973611725, win 65535, options [mss 16344,nop,wscale 6,sackOK,TS val 33373753 ecr 0], length 0 rule 2..16777216/0(match): **block in on lo0**: (tos 0x0, ttl 64, id 2420, offset 0, flags [DF], proto TCP (6), length 60, bad cksum 0 (->8de7)!) 132.148.77.28.48488 > 132.148.77.28.80: Flags [S], cksum 0xa38f (incorrect -> 0xf265), seq 3973611725, win 65535, options [mss 16344,nop,wscale 6,sackOK,TS val 33376954 ecr 0], length 0 rule 2..16777216/0(match): **block in on lo0**: (tos 0x0, ttl 64, id 2422, offset 0, flags [DF], proto TCP (6), length 60, bad cksum 0 (->8de5)!) 132.148.77.28.48488 > 132.148.77.28.80: Flags [S], cksum 0xa38f (incorrect -> 0xe5c8), seq 3973611725, win 65535, options [mss 16344,nop,wscale 6,sackOK,TS val 33380183 ecr 0], length 0 rule 2..16777216/0(match): **block in on lo0**: (tos 0x0, ttl 64, id 2424, offset 0, flags [DF], proto TCP (6), length 60, bad cksum 0 (->8de3)!) 132.148.77.28.48488 > 132.148.77.28.80: Flags [S], cksum 0xa38f (incorrect -> 0xd943), seq 3973611725, win 65535, options [mss 16344,nop,wscale 6,sackOK,TS val 33383388 ecr 0], length 0 10 packets captured 11 packets received by filter 0 packets dropped by kernel $ sudo tcpdump -c 10 -vvv -t -i pflog0 -e -n tcp tcpdump: WARNING: pflog0: no IPv4 address assigned tcpdump: listening on pflog0, link-type PFLOG (OpenBSD pflog file), capture size 65535 bytes rule 8..16777216/0(match): pass in on vtnet0: (tos 0x0, ttl 52, id 408, offset 0, flags [DF], proto TCP (6), length 60) 67.197.156.119.45482 > 132.148.77.28.80: Flags [S], cksum 0x2e49 (correct), seq 3314040182, win 29200, options [mss 1460,sackOK,TS val 64109806 ecr 0,nop,wscale 7], length 0 rule 9..16777216/0(match): pass out on lo0: (tos 0x0, ttl 64, id 2446, offset 0, flags [DF], proto TCP (6), length 60) 127.0.0.1.19450 > 127.0.0.1.5556: Flags [S], cksum 0xfe30 (incorrect -> 0x603e), seq 629617255, win 65535, options [mss 16344,nop,wscale 6,sackOK,TS val 34141175 ecr 0], length 0 rule 5..16777216/0(match): pass in on lo0: (tos 0x0, ttl 64, id 2446, offset 0, flags [DF], proto TCP (6), length 60, bad cksum 0 (->332c)!) 127.0.0.1.19450 > 127.0.0.1.5556: Flags [S], cksum 0xfe30 (incorrect -> 0x603e), seq 629617255, win 65535, options [mss 16344,nop,wscale 6,sackOK,TS val 34141175 ecr 0], length 0 rule 9..16777216/0(match): pass out on lo0: (tos 0x0, ttl 64, id 2459, offset 0, flags [DF], proto TCP (6), length 60) 127.0.0.1.54320 > 127.0.0.1.5556: Flags [S], cksum 0xfe30 (incorrect -> 0x8ec2), seq 2137792783, win 65535, options [mss 16344,nop,wscale 6,sackOK,TS val 34141359 ecr 0], length 0 rule 5..16777216/0(match): pass in on lo0: (tos 0x0, ttl 64, id 2459, offset 0, flags [DF], proto TCP (6), length 60, bad cksum 0 (->331f)!) 127.0.0.1.54320 > 127.0.0.1.5556: Flags [S], cksum 0xfe30 (incorrect -> 0x8ec2), seq 2137792783, win 65535, options [mss 16344,nop,wscale 6,sackOK,TS val 34141359 ecr 0], length 0 rule 8..16777216/0(match): pass in on vtnet0: (tos 0x0, ttl 52, id 13349, offset 0, flags [DF], proto TCP (6), length 60) 67.197.156.119.45484 > 132.148.77.28.80: Flags [S], cksum 0x9e57 (correct), seq 2310473985, win 29200, options [mss 1460,sackOK,TS val 64109860 ecr 0,nop,wscale 7], length 0 rule 8..16777216/0(match): pass in on vtnet0: (tos 0x0, ttl 52, id 32739, offset 0, flags [DF], proto TCP (6), length 60) 67.197.156.119.45486 > 132.148.77.28.80: Flags [S], cksum 0x5b67 (correct), seq 2464105159, win 29200, options [mss 1460,sackOK,TS val 64109860 ecr 0,nop,wscale 7], length 0 rule 8..16777216/0(match): pass in on vtnet0: (tos 0x0, ttl 52, id 55497, offset 0, flags [DF], proto TCP (6), length 60) 67.197.156.119.45488 > 132.148.77.28.80: Flags [S], cksum 0x832f (correct), seq 3354322413, win 29200, options [mss 1460,sackOK,TS val 64109860 ecr 0,nop,wscale 7], length 0 rule 9..16777216/0(match): pass out on lo0: (tos 0x0, ttl 64, id 2474, offset 0, flags [DF], proto TCP (6), length 60) 127.0.0.1.60189 > 127.0.0.1.5556: Flags [S], cksum 0xfe30 (incorrect -> 0xe2c0), seq 1589892785, win 65535, options [mss 16344,nop,wscale 6,sackOK,TS val 34141386 ecr 0], length 0 rule 5..16777216/0(match): pass in on lo0: (tos 0x0, ttl 64, id 2474, offset 0, flags [DF], proto TCP (6), length 60, bad cksum 0 (->3310)!) 127.0.0.1.60189 > 127.0.0.1.5556: Flags [S], cksum 0xfe30 (incorrect -> 0xe2c0), seq 1589892785, win 65535, options [mss 16344,nop,wscale 6,sackOK,TS val 34141386 ecr 0], length 0 10 packets captured 14 packets received by filter 0 packets dropped by kernel
我在数据包信息之间添加了换行符以提高可读性。 您会注意到第一个转储中“规则2”阻塞了数据包,这只发生在上游服务器重新启动之后的第一个请求中。
是什么赋予了? 你也会注意到这些阻塞的数据包在回送接口上,但是它们来自公共IP地址。 我认为他们不应该NAT,因为他们不在vtnet0接口。 即使如此,为什么后续的请求采取不同的path来促进从nginx到上游服务器的通信呢?
我发现的修改是从我的pf.conf中更改以下行: pass in log on $iface proto tcp to $public_ip port { ssh http } keep state : pass in log proto tcp to $public_ip port { ssh http } keep state
我删除了on $iface部分,这样防火墙将会在loopback接口上将数据包传递给$ public_ip端口80。 我也对松散规则的安全性提出了轻微的担忧 – 这只是因为我不完全了解这些不同的networking接口之间的stream量是如何操作的。
在这一点上,我甚至不确定问题出在我的防火墙还是用nginx,只是当防火墙被禁用时,问题就消失了。
请注意,nginx是proxy_pass在三个不同的server块的请求http://127.0.0.1:[port]其中端口是5555,5556或5557之一。
经过大量的研究,对于我的问题的正确解决方法,不是修改我提到的那一行,而是完全删除该行,并在pf.conf的Options块中的set skip on lo0添加一个set skip on lo0 (在macros之后和包之前过滤规则)。 这完全阻止了回路接口被pf感动。
至于127.xxx ip出现在回环设备上,我有一个理论。 正如@理查德·史密斯所build议的,我运行了netstat -rn并注意到以下两行:
Destination Gateway Flags Netif 132.148.77.28 link#1 UHS lo0 132.148.77.28/32 link#1 U vtnet0
我做了一些挖掘,发现这两个条目通过ifconfig添加到ifconfig输出中列出的第一个以太网接口:vtnet0。 所以,自然而然地,交通真的可以通过回路路由到132.148.77.28,如这条路线所示。 这只是意味着它将使用vtnet0作为网关来做到这一点。 现在,我不确定发生了什么事情,当它到达vtnet0作为网关时,它已经通过了pf规则的NAT – 但是我不知道为什么tcpdump仍然会显示旧的接口(lo0),从哪个接口它来了。 对于我来说,在127.0.0.1上监听的上游服务器会select打开132.148.77.28上的端口来尝试第一次回应代理服务器,然后在随后的请求中使用127.0,这似乎仍然很奇怪。 0.1并且反向代理“降到其级别”进行通信。 我的理论是路由algorithm“记住”以前的path不好(即被阻塞),所以尝试了一种不同的方法。 我不会将我的答案标记为已接受的答案,因为我真的需要一位训练有素的专业人员来validation我的轻量级理论是否有效。