我有两台运行 CentOS 7 的服务器,它们具有公共 IP,也连接到同一个 LAN。服务器 A 有一些虚拟机,我正尝试将端口 80 转发到其中一个。我使用 执行此操作firewall-cmd
,并且我的 WAN NIC 在两种情况下都加入了外部区域(LAN 是内部区域)。这当然意味着伪装已启用(因为这是外部的默认设置)。我还检查过(至少十几次)以确保设置ip_forwarding
为 1,并且该设置在重启后仍然存在。
firewall-cmd --list-all
以下是服务器 A 上的输出:
external (active)
target: default
icmp-block-inversion: no
interfaces: em1
sources:
services:
ports:
protocols:
masquerade: yes
forward-ports: port=80:proto=tcp:toport=80:toaddr=192.168.11.1
source-ports:
icmp-blocks:
rich rules:
据我所知,这应该可以工作,但实际上却不行。为了测试,我nc -vl 80
在虚拟机和nc -v [external IP] 80
异地服务器上运行。连接超时。
服务器 B 上的相同配置运行良好。我能够使用 netcat 发送和接收文本,没有任何问题。
下面是包含更多详细信息的网络图:
WAN
|
_____Switch_____
/ \
em1 enp1s0
| | zone: external
+----------+ +----------+ ---------------
| Server A | | Server B |
+----------+ +----------+ ---------------
| | zone: internal
bridge1 bridge1
| | |
| em2 enp3s0
| \____Switch_____/
|
vnet0
+--------+
| Web VM |
+--------+
网络配置通过脚本在两台服务器的所有接口上完成
NM_CONTROLLED=no
。两台服务器的配置也基本相同(明显的区别是 IP 地址)。将 SELinux 设置为宽容不会改变任何事情(它在服务器 B 上启用时没有问题,并且服务器 A 也没有在审计日志中显示任何相关的拒绝)
我可以像在服务器 A 上一样通过 netcat 传输流量:
nc -vl 80 | nc -v 192.168.11.1 80
,而且它工作正常。我也可以在服务器 A 上打开端口 80 并从那里监听,不会出现问题。所以这里的问题完全是转发。我运行
iptables -t nat -S
查看已加载的规则,看到以下内容:-A PRE_external_allow -p tcp -m mark --mark 0x66 -j DNAT --to-destination 192.168.11.1:80
当我运行时,
iptables -t nat -vnL | grep :80
我可以看到尝试连接时数据包计数器增加(尽管再次连接超时),所以我知道规则正在被满足。我尝试将端口转发到网络上不位于任何一台服务器上的其他设备,结果相同(服务器 B 正常,服务器 A 失败)。
服务器 A 现在才第一次连接到 WAN,所以我不知道转发过去是否有效。
至于主要的区别,我只能想到以下几点:
两台服务器都运行不同的内核版本(服务器 A 运行
3.10.0-693.11.1.el7.x86_64
,服务器 B 运行3.10.0-514.26.2.el7.x86_64
)。但是,我确实尝试在服务器 A 上运行较旧的内核,但这并没有解决问题(因此我相对确定这不是内核错误,除非它与 NIC 驱动程序有关,尽管这仍然很奇怪)。服务器 A 运行的是 Firewalld v0.4.4.4,而服务器 B 运行的是 v0.4.3.2。我还没有尝试在服务器 A 上回滚到 v0.4.3.2(yum 找不到该版本的软件包)。
您可能已经猜到了,服务器 B 自 8 月以来没有进行过重大更新。尽管我应该这样做,但我现在还犹豫着是否要更新它,因为我担心转发也会中断(请放心,我最终会更新的。希望很快)。不幸的是,这意味着服务器 A 上有非常多的软件包具有较新的版本。简单地对软件包版本进行差异化将导致需要筛选大量信息。
我还注意到一些 iptables 规则有点不同:
服务器 A
-A POSTROUTING_ZONES -o em1 -g POST_external -A POSTROUTING_ZONES -o bridge1 -g POST_internal -A POSTROUTING_ZONES -o em2 -g POST_internal -A POSTROUTING_ZONES -g POST_external -A PREROUTING_ZONES -i em1 -g PRE_external -A PREROUTING_ZONES -i bridge1 -g PRE_internal -A PREROUTING_ZONES -i em2 -g PRE_internal -A PREROUTING_ZONES -g PRE_external
服务器 B
-A POSTROUTING_ZONES -o enp1s0 -g POST_external -A POSTROUTING_ZONES -o bridge1 -j POST_internal -A POSTROUTING_ZONES -o enp3s0 -j POST_internal -A POSTROUTING_ZONES -g POST_external -A PREROUTING_ZONES -i enp1s0 -g PRE_external -A PREROUTING_ZONES -i bridge1 -j PRE_internal -A PREROUTING_ZONES -i enp3s0 -j PRE_internal -A PREROUTING_ZONES -g PRE_external
服务器 B 使用
jump
内部区域,而服务器 A 使用goto
。这可能是由于防火墙版本的差异造成的,也是我目前能想到的唯一可能导致此问题的原因(尽管我仍然认为这不太可能,因为这与内部区域有关)。两台服务器都安装并配置了 Docker。服务器 A 上的容器仅供内部使用。服务器 B 上的一些容器具有到互联网的端口转发(通过配置
docker run
)。服务器 B 还运行 OpenVPN。我能想到的唯一需要注意的另一件事是服务器之间的硬件有很大差异(服务器 A 是戴尔 T420,服务器 B 是 LGA 775 定制,因此只是台式硬件)。
这时我开始有点疯狂了。我甚至尝试在内部区域启用伪装,就像我在其他地方看到的建议一样(这完全没有意义,而且令人惊讶的是,并没有解决问题)。
我在这里遗漏了什么?
更新
尝试本地转发到服务器 A 上的其他端口(即firewall-cmd --zone=external --add-forward-port=port=80:proto=tcp:toaddr=192.168.11.3:toport:81
)。当我使用 netcat 在服务器 A 的端口 81 上监听时,我可以连接到端口 80,因此本地转发工作正常。只是无法转发到其他 IP 地址。
答案1
将内部区域的目标设置为“接受”可以为我解决此问题。
IEfirewall-cmd --permanent --zone=internal --set-target=ACCEPT
我承认我不知怎么地错过了服务器 B 上的设置。不过,我发现目标下默认不接受传出连接,这有点奇怪default
。
答案2
显而易见的是,要确保您的 WAN 路由器(无论它是什么)将入站端口 80 流量发送到您想要的服务器。