nftables:具有动态 IP 的发夹/环回 NAT

nftables:具有动态 IP 的发夹/环回 NAT

我有一台 Debian 12 服务器(公共 IP85.xxx.xxx.xxxenp6s0),它在网桥上运行一堆 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,并且通信失败:

发夹型NAT

我该如何解决这个问题无需借助 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 localdaddr是与任何匹配 NAT 盒的地址相匹配的部分。

请注意,您可能还需要提供适当的 SNAT 映射才能使其工作(因为返回数据包可能会直接发送到具有内部源地址的桥接接口,该地址与 VM 上的任何连接都不匹配)。

答案2

好的,我设法解决了这个问题,并且简化了我的配置。

  1. 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
  }
}
  1. 使用如下描述的 FIB 表达式这里。并确保到的流量dnat可以来自enp6s0cbr0
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

相关内容