作为一个还没有深入研究过 OSI 各层的人,我对 nftables 中桥接过滤的文档感到非常沮丧:https://wiki.nftables.org/wiki-nftables/index.php/Bridge_filtering
是我理解错了吗?还是 IP 地址、端口、ICMP 匹配等在 nftables 的桥接表中不可能实现?不过,在使用检查规则时它并没有抱怨,nft
而且我所包含的页面文档甚至给出了 IP 端口作为桥接过滤的示例。文档是否有误?我是否误解了什么?
作为一个还没有深入研究过 OSI 各层的人,我对 nftables 中桥接过滤的文档感到非常沮丧:https://wiki.nftables.org/wiki-nftables/index.php/Bridge_filtering
是我理解错了吗?还是 IP 地址、端口、ICMP 匹配等在 nftables 的桥接表中不可能实现?不过,在使用检查规则时它并没有抱怨,nft
而且我所包含的页面文档甚至给出了 IP 端口作为桥接过滤的示例。文档是否有误?我是否误解了什么?
我在 nftables 中有两个表:
$ sudo nft list tables
table inet filter
table ip nat
表格nat
可以列得很好:
$ sudo nft list table nat
table ip nat {
chain prerouting {
type nat hook prerouting priority filter; policy accept;
<output truncated>
}
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
<output truncated>
}
}
但不是filter
表格:
$ sudo nft list table filter
Error: No such file or directory
list table filter
^^^^^^
这意味着我无法在命令行添加新规则:
$ sudo nft add rule filter forward oif <interface> ip saddr <ip> accept
Error: No such file or directory; did you mean table ‘filter’ in family inet?
add rule filter forward oif <interface> ip saddr <ip> accept
^^^^^^
这是我第一次尝试使用nft
命令行,到目前为止,我只有静态配置,/etc/nftables.conf
这已经足够了。这是怎么回事?
以下是我精简的ARP
规则集,仅显示广播规则,其他规则(此处未显示)不相关。
请参阅有问题的代码注释(?)
#!/usr/sbin/nft -f
add chain arp arp_table input {
# filter = 0
# Packets delivered to the local system
type filter hook input priority filter; policy drop;
}
add chain arp arp_table output {
# filter = 0
# Packets send by the local system
type filter hook output priority filter; policy drop;
}
# ARP Broadcast address
define broadcast_ether = { ff:ff:ff:ff:ff:ff }
# IPv4 network address
define network_addr_4 = { 192.168.1.0/24 }
# NIC ether address
define physical_ether = { bb:c9:51:d4:4a:b6 }
# Why input to broadcast address never hits?
# This rule should handle broadcast input
add rule arp arp_table input arp daddr ether $broadcast_ether log prefix "ACCEPT input broadcast: " accept
# Why input to 00:00:00:00:00:00 hits instead?
# This rule handles input toward 00:00:00:00:00:00 from LAN
add rule arp arp_table input arp saddr ip $network_addr_4 arp daddr ether 00:00:00:00:00:00 accept
# Why output to broadcast never hits?
# This rule should handle output toward ff:ff:ff:ff:ff:ff to LAN
add rule arp arp_table output arp daddr ether $broadcast_ether log prefix "ACCEPT output broadcast: " accept
# Why output to 00:00:00:00:00:00 hits instead?
# This rule handles output toward 00:00:00:00:00:00 to LAN
add rule arp arp_table output arp saddr ether $physical_ether arp daddr ether 00:00:00:00:00:00 accept
这里有几个问题,主要问题是ARP
广播流量ff:ff:ff:ff:ff:ff
不存在,这就是为什么我添加了日志语句以希望捕获这种流量,但它从未出现,对于input
和output
流量都如此。
相反,我看到很多针对00:00:00:00:00:00
地址的输入/输出,这表明该00:00:00:00:00:00
地址某种程度上是广播地址。
所以主要的问题是为什么我看不到ARP
指向广播地址的流量以及为什么00:00:00:00:00:00
使用地址来代替?
第二个问题是,什么是00:00:00:00:00:00
地址?为什么需要它以及它意味着什么?
如果我阻止来往的流量00:00:00:00:00:00
(例如,通过删除这些规则),那么网络将由于此类ARP
数据包被丢弃而停止运行。
这不起作用(通过 systemd 重启 nftables,它应该加载/etc/nftables.conf
):
cat /etc/nftables.d/forward/example.conf
meta oifname "eth2" ip daddr 5.6.7.8/30 accept
^^^^^^^^^^^^^^^^^^^ ~~~~
Error: Statement after terminal statement has no effect
但这也不起作用:
ip daddr 5.6.7.8/30 meta oifname "eth2" accept
^^^^^^^^^^^^^^^^^^^ ~~~~
Error: Statement after terminal statement has no effect
这也不是(使用连接示例)
ip daddr . meta oifname {5.6.7.8/30 . "eth2"} accept
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: Statement after terminal statement has no effect
注意:/etc/nftables.conf 的内容:
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority filter;
}
chain forward {
type filter hook forward priority filter;
include "/etc/nftables.d/forward/*.conf"
}
chain output {
type filter hook output priority filter;
}
}
我该如何同时执行这两项操作?如果此 IP 范围并不总是路由到 eth2(例如,策略路由),而 eth2 不只包含此 IP 范围,那么这是否有必要?
下面的链接是解释跨链数据包流的图像nftables
我了解一切,除了一件事,该图像没有说明在哪个阶段完成routing decision
?
根据图像,应该在两个地方完成:
prerouting
钩子之后但在input
引擎盖forward
之前output
当数据包离开本地主机进程时挂钩之前上面的第一点是有道理的,因为后面有 2 个可能的钩子prerouting
,但是对于第 2 点,不清楚要执行什么路由决策,因为来自本地进程的唯一流选项是钩子,output
因此不应该有任何路由决策,而是图片说有一个。
这让我相信只有一个路由决策,即上面的第 1 点。
为什么图像指定和hookrouting decision
之间的节点?local process
output
SNAT
是在钩子中完成的postrouting
,根据文档“在路由之后,就在它们离开本地系统之前查看所有数据包”,
但问题是哪个路由?因为根据图像有 2 个路由决策。
顺便说一句。什么是“路由决策”(图像中的节点)我不认为那是NAT
因为NAT
是在prerouting
和postrouting
挂钩中完成的。
以下是相关示例规则集,其中包含 2 个示例nftables
NAT 规则,这些规则将 IP 从虚拟机伪装到 LAN:
#!/usr/sbin/nft -f
add table nat_4
# Sees all packets after routing, just before they leave the local system
add chain nat_4 postrouting_nat_4 {
type nat hook postrouting priority srcnat; policy accept;
comment "Postrouting SNAT IPv4 traffic"
}
# Masquerade all packets going from VMs to the LAN/Internet
add rule nat_4 postrouting_nat_4 meta l4proto tcp ip saddr 192.168.122.0/24 ip daddr != 192.168.122.0/24 counter masquerade to :1024-65535
# Same rule as above but without [to :PORT_SPEC]
add rule nat_4 postrouting_nat_4 meta l4proto tcp ip saddr 192.168.122.0/24 ip daddr != 192.168.122.0/24 counter masquerade
示例 IP 地址192.168.122.0/24
是虚拟机运行的网络地址。
我明白了什么masquerade
,它SNAT
通过将源IP更改为出站接口IP来执行。
从这个意义上说,我理解上面示例中的第二条规则的作用。
我不明白的是 [to :PORT_SPEC] 声明(文档链接),在示例中(第一条规则):masquerade to :1024-65535
具体是masquerade to :1024-65535
做什么的,有必要具体说明吗?
这两条规则基本上相同还是有什么不同?
哪一个更适合通过本地主机上的虚拟交换机从虚拟机到互联网进行 NAT?
unamed set
以下是我当前如何使用包含 ICMP 类型的工作示例:
#!/usr/sbin/nft -f
add table filter_4
add chain filter_4 icmp_out_4 {
comment "Output ICMPv4 traffic"
}
define response_icmp_4 = {
0, # Echo Reply
3, # Destination Unreachable
10, # Router Solicitation
11, # Time Exceeded
12, # Parameter Problem
14 # Timestamp Reply
}
# Block ICMP response from localhost
add rule filter_4 icmp_out_4 icmp type $response_icmp_4 drop
我想要做的是将其转换unamed set
为response_icmp_4
命名集。
这是我不成功的尝试:
# Declare named set
add set filter_4 response_icmp_4 { type inet_service }
# Add ICMP type elements
add element filter_4 response_icmp_4 {
0, # Echo Reply
3, # Destination Unreachable
10, # Router Solicitation
11, # Time Exceeded
12, # Parameter Problem
14 # Timestamp Reply
}
创建集合可以工作,但在规则处理过程中被拒绝:
# Block ICMP response from localhost
add rule filter_4 icmp_out_4 icmp type @response_icmp_4 drop
具有以下错误输出:
错误:数据类型不匹配,预期的 ICMP 类型,表达式的类型为 Internet 网络服务
该错误是不言自明的,但问题是type
我应该指定什么?因为type inet_service
不起作用。
根据文档,有效的type
表达式是ipv4_addr, ipv6_addr, ether_addr, inet_proto, inet_service, mark
也可以指定typeof
自动派生数据类型,但这效果不佳,例如:
add set filter_4 response_icmp_4 { typeof vlan id }
哪些错误与类似错误:
错误:数据类型不匹配,预期的 ICMP 类型,表达式的类型为整数
这是一个奇怪的错误,因为ICMP type
它是一个整数。
如果您还可以链接到解释这一点的文档,那将会很有帮助,因为我找不到它。
ct helper
这是当前如何根据nftables 文档声明对象的工作示例
#!/usr/sbin/nft -f
add table filter_4 {
# TODO: Can helper object be declared outside the scope of table declaration scope?
# ct helper stateful object
# "ftp-standard" is the name of this ct helper stateful object
# "ftp" is the in-kernel name of the ct helper for ftp
ct helper ftp-standard {
type "ftp" protocol tcp;
}
}
然后该ct helper
对象用于 ex。如下:
add chain filter_4 new_out_4 {
comment "New output IPv4 traffic"
}
# FTP (active and passive)
# Rule for initial ftp connection (control channel), setting ct helper stateful object to use
# "ftp-standard" is the name of the ct helper stateful object
add rule filter_4 new_out_4 tcp sport >1023 tcp dport 21 ct helper set "ftp-standard" accept
我想要实现的是了解ct helper
在表外声明对象的语法,其方式与声明集合的方式类似。
有关如何在表声明范围之外声明集合的示例
add set filter_4 multicast_proto { type inet_proto; comment "IPv4 multicast protocols"; }
add element ip filter_4 multicast_proto { udp, igmp }
以类似的方式,我想声明ct helper
对象,例如:
# Table declaration
add table filter_4
# Declare ct helper separately
add ct helper ftp-standard {
type "ftp" protocol tcp;
}
这当然不行,ct helper
像这样添加\声明的语法是什么?
似乎ct helper
必须绑定到一个表(这是真的吗?),因此也许应该在上面的示例中指定表名称。
我正在运行 AlmaLinux 9,启动时我看到警告
Warning: Deprecated Driver is detected: nft_compat will not be maintained in a future major release and may be disabled
但是加载该驱动程序的是什么?我禁用了firewalld服务。我想(正确地)消除这个警告。
附加信息:
[root@server ~]# lsmod | grep nft_compat
nft_compat 20480 14
nf_tables 278528 98 nft_compat,nft_counter,nft_chain_nat
nfnetlink 20480 2 nft_compat,nf_tables
[root@server ~]# iptables -L -n
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
NETAVARK_FORWARD all -- 0.0.0.0/0 0.0.0.0/0 /* netavark firewall plugin rules */
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain NETAVARK_FORWARD (1 references)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 10.88.0.0/16 ctstate RELATED,ESTABLISHED
ACCEPT all -- 10.88.0.0/16 0.0.0.0/0
Chain NETAVARK_ISOLATION_2 (1 references)
target prot opt source destination
Chain NETAVARK_ISOLATION_3 (0 references)
target prot opt source destination
DROP all -- 0.0.0.0/0 0.0.0.0/0
NETAVARK_ISOLATION_2 all -- 0.0.0.0/0 0.0.0.0/0
nftables
支持动态填充集,这些集记录在nftables wiki中。wiki 页面上的第一个示例如下:
table ip my_filter_table {
set my_ssh_meter {
type ipv4_addr
size 65535
flags dynamic
}
chain my_input_chain {
type filter hook input priority filter; policy accept;
tcp dport 22 ct state new add @my_ssh_meter { ip saddr limit rate 10/second } accept
}
}
nftables
上面的配置解释如下:
在此示例中,我们创建一条规则来匹配新的 TCP ssh(端口 22)连接,该规则使用名为 my_ssh_meter 的动态集将每个源 IP 地址的流量速率限制为每秒 10 个连接。
如何解读这条规则或者如何理解它?我的意思是,如果 Linux 连接跟踪子系统看到到 TCP 目标端口 22( ) 的新连接 ( ip saddr
),则带有数据的源 IP 地址 ( )limit rate 10/second
会添加到命名集中。不过这套好像从来没用过?填充集合时执行的操作是否成功?my_ssh_meter
ct state new
tcp dport 22
my_ssh_meter
accept