由于我使用透明代理服务,因此我使用树莓派作为我的家庭路由器。它的操作系统是普通的 Raspbian。现在我正在 上设置 Minecraft 服务器192.168.2.28
,并使用 NAT 将其暴露到 WAN。这是我的/etc/nftables.conf
:
#!/sbin/nft -f
flush ruleset
table ip filter {
chain output {
type filter hook output priority 0; policy accept;
tcp sport 25565 drop
}
}
table ip nat {
chain prerouting {
type nat hook prerouting priority 0; policy accept;
tcp dport 25565 dnat 192.168.2.28
}
chain postrouting {
type nat hook postrouting priority 0; policy accept;
tcp sport 25565 ip saddr 192.168.2.28 masquerade
}
}
但是,我有以下问题: On 192.168.2.28
,我运行
nc -l -p 25565
On 192.168.2.27
,我运行
echo "Hello, world!" | nc wan_ip 25565
想要的行为是我得到“Hello, world!”留言于192.168.2.28
.
然而,当第一个 SYN 数据包通过路由器时,它仅将其 baddr 进行了 NAT,保持其 Saddr 等于192.168.2.27
。
当192.168.2.28
收到数据包时,它会回复192.168.2.27
。由于它们位于同一 L2 网络中,因此数据包不会通过路由器,因此不会经过 NAT。
然后192.168.2.27
收到来自 的数据包192.168.2.28
,但它不知道这是来自 的回复wan_ip
。
如何解决此问题并使端口转发在任何地方(包括 LAN 主机)都可以工作?
答案1
提醒一句,nftables(就像iptables)仅看到要进行 NAT 处理的流的第一个数据包。当进行 NAT 时,同一流中的所有其他数据包将直接由网络过滤器/连线没有看到nftables不再:因此返回流量会自动取消 NAT,无需进一步帮助。
唯一重要的部分是第一个数据包发生了什么(因此对于 TCP 来说,它是一个 SYN 数据包)。此流的进一步流量(包括回复数据包)会自动处理并绕过 NAT 挂钩。
这意味着不应该有特殊的后路由规则来处理从 192.168.2.28 发出的流量。应该只有一个通用的伪装规则全部与互联网通信时为 192.168.2.0/24。无论如何,这个规则本身不是问题:当发出的流量是回复流量时,它不会像人们想象的那样频繁使用:它是预先存在的流量的一部分,因此如上所述,此类数据包不会遍历nftables不再了。
重要的是要有合适的NAT 发夹支持:客户端与服务器位于同一 LAN 中的情况,如果不小心,可能会发生不对称流量。
这里:
当路由器发现任何内容(来自任何地方)发往 tcp 目标端口 25565 时,将目标地址重定向到 192.168.2.28
由于重定向不区分外部和内部,因此当与整个 LAN 的适当通用伪装规则关联时,该规则本身就足够了。但OP并没有使用这样的规则。
而不是后路由中的通用伪装,
使用OP
tcp sport 25565 ip saddr 192.168.2.28
与之前规则的过滤部分无关第一的包tcp dport 25565
(并且还收到了新的目的地192.168.2.28):未实现 NAT 发夹。
什么需要被完成而是以下之一:
对整个 LAN 使用通用伪装(适应 NAT 发夹用例且缺乏附加信息)
chain postrouting { type nat hook postrouting priority 0; policy accept; ip saddr 192.168.2.0/24 ip daddr != 192.168.2.0/24 masquerade }
仅当服务器是目标时才对目标端口为 25565 的数据包使用伪装
chain postrouting { type nat hook postrouting priority 0; policy accept; tcp dport 25565 ip daddr 192.168.2.28 masquerade }
这意味着只有流向服务器的流量(包括用于正确 NAT 发夹的 LAN 到 LAN 的流量)才会被伪装(LAN 系统将无法访问 Internet)。
而不是 2. 选择仅对首先获得 DNAT 的流量应用伪装
chain postrouting { type nat hook postrouting priority 0; policy accept; ct status dnat masquerade }
与 2. 效果相同,但更通用。
仅在需要时结合 1 和 3 进行伪装
项目符号 2. 或 3. 具有隐藏 Internet 源地址的副作用,因此最好仅将其应用于 LAN:
chain postrouting { type nat hook postrouting priority 0; policy accept; ip saddr 192.168.2.0/24 ip daddr != 192.168.2.0/24 ct status dnat masquerade }
因此,要么使用 1. 要么使用 4.(限制 LAN 访问 Internet) 还有其他可能的选择。
注意:1. 有一个极端情况:如果客户端使用路由器的内部 IP 地址作为目标,如果没有针对这种情况的附加规则,它将无法工作,但我怀疑客户端会这样做,而且我没有足够的规则来自OP的信息:路由器的内部IP地址。