我正在根据以下答案进行工作这问题并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))。文档告诉: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。