nftables dnat 映射规则默默失败

nftables dnat 映射规则默默失败

我正在根据以下答案进行工作问题并man nft为了dnat在我的配置中创建一些规则nftables

相关配置摘录为:

define src_ip       = 192.168.1.128/26
define dst_ip       = 192.168.1.1
define docker_dns   = 172.20.10.5

table inet nat {
    map dns_nat {
        type ipv4_addr . ipv4_addr . ip_proto . inet_service : ipv4_addr . inet_service
        flags interval
        elements = {
            $src_ip . $dst_ip . udp . 53 : $docker_dns . 5353,
        }
    }
    chain prerouting {
        type nat hook prerouting priority -100; policy accept;
        
        dnat to ip saddr . ip daddr . ip protocol . th dport map @dns_nat;
    }
}

当我应用此规则时nft -f,我没有看到任何命令输出,因此我认为它已成功。但是,当我使用规则检查规则集时,nft list ruleset这些规则不存在。当该dnat to ...行被注释掉时,规则似乎被应用,但是当该行存在时,规则不被应用。

prerouting我试图替换的链中的规则集合是:

ip saddr $src_ip ip daddr $dst_ip udp dport 53 dnat to $docker_dns:5353;
...

版本信息:

# nft -v
nftables v1.0.6 (Lester Gooch #5)
# uname -r
6.1.0-11-amd64

为什么这可能不起作用?谢谢

答案1

有3个问题。

  • 没有显示错误

    这看起来是一个错误nftables1.0.6,请参阅以下项目符号。

    这里有相同的版本和OP的规则集/tmp/ruleset.nft

    # nft -V
    nftables v1.0.6 (Lester Gooch #5)
    [...]
    # nft -f /tmp/ruleset.nft 
    /tmp/ruleset.nft:7:38-45: Error: unknown datatype ip_proto
            type ipv4_addr . ipv4_addr . ip_proto . inet_service : ipv4_addr . inet_service
                                         ^^^^^^^^
    /tmp/ruleset.nft:6:9-15: Error: set definition does not specify key
        map dns_nat {
            ^^^^^^^
    
  • 错误:未知数据类型ip_proto

    原始链接的问答使用了正确的类型inet_proto。不应将其替换为ip_proto未知类型。所以替换回来:

    type ipv4_addr . ipv4_addr . ip_proto . inet_service : ipv4_addr . inet_service
    

    正确的原始拼写:

    type ipv4_addr . ipv4_addr . inet_proto . inet_service : ipv4_addr . inet_service
    

    可用类型的列表可以在nft(8)以下位置找到:有效负载表达式更准确地说,对于这种情况IPV4 标头表达式:

    关键词 描述 类型
    [...]
    protocol 上层协议 inet_proto
    [...]

    typeof ip protocol<=> type inet_proto(不是type ip_proto)。

    通常typeof应该优先选择以type避免猜测正确的类型,但是正如我在链接的问答中所写的,某些版本nftables可能无法正确处理这种具体情况。替代方案是:

    typeof ip saddr . ip daddr . ip protocol . th dport : ip daddr . th dport
    

    这几乎是使用它的规则的剪切/粘贴,但它的行为应该经过彻底的测试。

  • 没有显示错误 - 采取 2

    一旦修复了之前的错误(并将结果放入/tmp/ruleset2.nft),那么,正如OP所写,再次尝试规则集会默默失败:

    # nft -V
    nftables v1.0.6 (Lester Gooch #5)
      cli:        editline
      json:       yes
      minigmp:    no
      libxtables: yes
    # nft -f /tmp/ruleset2.nft
    # echo $?
    1
    #
    

    失败的唯一线索是非 0 返回代码。

    虽然使用较新的nftables版本:

    # nft -V
    nftables v1.0.8 (Old Doc Yak #2)
      cli:        editline
      json:       yes
      minigmp:    no
      libxtables: yes
    # nft -f /tmp/ruleset2.nft 
    /tmp/ruleset2.nft:16:9-12: Error: specify `dnat ip' or 'dnat ip6' in inet table to disambiguate
            dnat to ip saddr . ip daddr . ip protocol . th dport map @dns_nat;
            ^^^^
    #
    

    现在显示错误。无论 1.0.6 中出现什么问题,至少在 1.0.8 版本中已得到修复。

  • 错误:在 inet 表中指定“dnat ip”或“dnat ip6”以消除歧义

    由于 NAT 是在inet系列(组合 IPv4+IPv6)中完成的,而不是在ip(IPv4) 或ip6(IPv6) 系列中完成,因此通常可选的一个参数变成了必需参数:声明应应用 NAT 的 IP 版本(即使可以推断出它)来自地图表布局 (IPv4))。文档告诉:

    NAT 语句

    snat [[ip | ip6] to] ADDR_SPEC [:PORT_SPEC] [FLAGS]
    dnat [[ip | ip6] to] ADDR_SPEC [:PORT_SPEC] [FLAGS]
    masquerade [to :PORT_SPEC] [FLAGS]
    redirect [to :PORT_SPEC] [FLAGS]
    

    [...]

    当用于 inet 系列时(内核 5.2 可用),dnat 和 snat 语句需要使用 ip 和 ip6 关键字如果提供了地址,请参阅下面的示例。

    所以:

    dnat to ip saddr . ip daddr . ip protocol . th dport map @dns_nat;
    

    应替换为:

    dnat ip to ip saddr . ip daddr . ip protocol . th dport map @dns_nat
    

    最初的 Q/A 没有说明该系列,因此假设它是默认ip系列,不需要这样做。

    当然,这将与nftables1.0.6,只有错误报告有问题。返回码现在将为 0。

相关内容