我有一台 Debian 12 服务器(公共 IP85.xxx.xxx.xxx
为enp6s0
),它在网桥上运行一堆 LXC 容器cbr0
。
由于公共 IP 是动态的,因此我必须设置forward
+prerouting
规则,dnat
以便传入请求到达容器。例如,端口 80/443 被指定给容器10.10.0.1
。以下是我的nftables
规则:
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
ct state {established, related} accept
iifname lo accept
iifname cbr0 accept
ip protocol icmp accept
ip6 nexthdr icmpv6 accept
}
chain forward {
type filter hook forward priority 0; policy accept;
}
chain output {
type filter hook output priority 0;
}
}
table ip filter {
chain forward {
type filter hook forward priority 0; policy drop;
oifname enp6s0 iifname cbr0 accept
iifname enp6s0 oifname cbr0 ct state related, established accept
# Webproxy
iifname enp6s0 oifname cbr0 tcp dport 80 accept
iifname enp6s0 oifname cbr0 udp dport 80 accept
iifname enp6s0 oifname cbr0 tcp dport 443 accept
iifname enp6s0 oifname cbr0 udp dport 443 accept
}
}
table ip nat {
chain postrouting {
type nat hook postrouting priority 100; policy accept;
}
chain prerouting {
type nat hook prerouting priority -100; policy accept;
# Webproxy
iifname enp6s0 tcp dport 80 dnat to 10.10.0.1:80
iifname enp6s0 udp dport 80 dnat to 10.10.0.1:80
iifname enp6s0 tcp dport 443 dnat to 10.10.0.1:443
iifname enp6s0 udp dport 443 dnat to 10.10.0.1:443
}
}
现在的问题是:发夹式 NAT。我有多个托管网站的容器,有时其中一些需要使用域名与其他容器通信。当它们对这些域运行 DNS 查询时,它们将获得主机 IP,并且通信失败:
我该如何解决这个问题无需借助 DNS 黑客? 有没有办法nftables
在拥有动态 IP 的情况下内部转发请求?iifname
上面的内容如何处理?
谢谢。
答案1
您可能需要的是 nft 手册页中的“FIB EXPRESSION”。这是我用于 DNAT 的规则(您需要根据自己的设置进行调整):
chain PREROUTING {
type nat hook prerouting priority dstnat; policy accept;
iiftype ppp fib daddr type local dnat ip to meta l4proto . th dport map @PRE-DNAT-IPV4
}
fib daddr type local
daddr
是与任何匹配 NAT 盒的地址相匹配的部分。
请注意,您可能还需要提供适当的 SNAT 映射才能使其工作(因为返回数据包可能会直接发送到具有内部源地址的桥接接口,该地址与 VM 上的任何连接都不匹配)。
答案2
好的,我设法解决了这个问题,并且简化了我的配置。
- 该
forward
链不需要明确接受特定端口的流量,我只需告诉它dnat
稍后转发具有特定规则的任何内容:
table ip filter {
chain forward {
type filter hook forward priority 0; policy drop;
# cbr0->anywhere (including to itself)
iifname cbr0 accept
# publicif->cbr0 only related connections
iifname enp6s0 oifname cbr0 ct state related, established accept
# publicif->cbr0 allow fwd for things that have dnat rules
iifname enp6s0 oifname cbr0 ct status dnat accept
}
}
- 使用如下描述的 FIB 表达式这里。并确保到的流量
dnat
可以来自enp6s0
和cbr0
:
table ip nat {
chain postrouting {
type nat hook postrouting priority 100; policy accept;
ip saddr 10.0.0.0/24 masquerade
}
chain prerouting {
type nat hook prerouting priority -100; policy accept;
# Webproxy
iifname { enp6s0, cbr0 } tcp dport { 80, 443 } fib daddr type local dnat to 10.0.0.1
iifname { enp6s0, cbr0 } udp dport { 80, 443 } fib daddr type local dnat to 10.0.0.1
}
}
现在一切似乎都正常了,然而有一个小细节:当我的 webproxy 容器从互联网获取请求时(enp6s0
),它会将真实的远程机器 IP 记录为这些请求的来源,然而当它们来自另一个容器时,源 IP 显示为 10.0.0.254,即 中的主机 IP cbr0
。