Nftables - 如何不在接口上对 IP 进行 dnat(DNS)

Nftables - 如何不在接口上对 IP 进行 dnat(DNS)

我一直在搜索,但似乎找不到我的具体问题的答案。我今天在预路由下有以下规则: iifname "br0" udp dport 53 counter dnat to 192.168.22.5:53

但是,我有一个问题,IP 地址 192.168.22.5 也在“br0”上。所以手头的问题是,我如何让 nftables 忽略这个 IP 并允许它访问网络上的端口 53(这是我的 pihole),但将所有其他端口 53 udp 数据重定向到它?

感谢您的回复!

答案1

您只需添加一个附加条件即可不匹配此 IP 地址,从而最终不执行 NAT:

iifname "br0" ip saddr != 192.168.22.5 udp dport 53 counter dnat to 192.168.22.5:53

但...如果客户端和 DNS 服务器都在同一个 LAN 中,那么回复将直接从 DNS 服务器发送到客户端。例如,如果客户端 192.168.22.101 设置为使用 google 的公共解析器(涉及所有隐私问题),您将得到以下信息:

查询:192.168.22.101 到 8.8.8.8 -> 路由和 dnat-ed -> 192.168.22.5

回复:192.168.22.5 -> 桥接(或两种情况下路由器都看不到)ip 家族规则 -> 192.168.22.101

但是由于 192.168.22.101 期望的应答来自 8.8.8.8,而不是来自 192.168.22.5,因此它将失败。

因此你也必须斯奈特查询。任何使数据包使用路由器的 IP 地址都可以:路由器的内部 IP(masquerade),因为路由器拥有此 IP,或任何 Internet IP(使用snat),因为它们是通过路由器路由的。您甚至可以想象为此使用一些 TEST-NET IP(例如:192.0.2.2):无论如何,IP 地址永远不会在本地网络之外看到。缺点是 DNS 服务器无法识别哪个 IP 发出了查询。较新的内核(即将推出的 5.7 或 5.8)将具有相当于 iptables 的 NETMAP如果这确实很重要,则可用。

masquerade为了简单起见,我们就在这里使用。

因此,在等效的后路由链中可以使用类似以下内容创建(请适应您自己的命名约定):

nft add chain ip nat postrouting '{ type nat hook postrouting priority 100; policy accept; }'

规则如下:

ip daddr 192.168.22.5 udp dport 53 counter masquerade

这不会影响从 DNS 服务器发起的任何返回流量,因为它的 conntrack 条目将不再处于 NEW 状态,并且这纳特规则不会被遍历。

如果你只想影响来自br0而不是来自其他地方,有以下几种选择:

  • 检查源 IP 来自 192.168.22.0/24 并且经过 dnat-ed

    ip saddr 192.168.22.0/24 ip daddr 192.168.22.5 udp dport 53 ct status dnat counter masquerade
    
  • 使用足够新的内核(>= 5.6)匹配传入接口(仍然在后路由中)就足够了:

    iifname "br0" ip daddr 192.168.22.5 udp dport 53 ct status dnat counter masquerade
    
  • 或者,如果它们不与其他用途冲突,您可以在预布线和后布线中使用标记:

    预路由:

    iifname "br0" ip saddr != 192.168.22.5 udp dport 53 counter set mark 1 dnat to 192.168.22.5:53
    

    后路由:

    mark 1 counter masquerade
    

最后,由于 DNS 使用 TCP 和 UDP,您可能也应该使用相同的方法tcp dport 53

答案2

来自主机本身的流量不会被匹配iifname $outgoing_interface(但是iifname lo),所以您的担心不存在。

相关内容