我设置了一条匹配多播数据包的规则,如下所示:
add rule filter_4 new_out_4 meta pkttype multicast goto multicast_out_4
filter_4
是 IPv4 表,new_out4
是输出链,multicast_out_4
是处理纯组播流量的链。
这是排除不相关部分的 IPv4 表的更完整图片:
#!/usr/sbin/nft -f
add table filter_4
add chain filter_4 output {
# filter = 0
type filter hook output priority filter; policy drop;
}
add chain filter_4 multicast_out_4 {
comment "Output multicast IPV4 traffic"
}
add chain filter_4 new_out_4 {
comment "New output IPv4 traffic"
}
#
# Stateful filtering
#
# Established IPv4 traffic
add rule filter_4 input ct state established goto established_in_4
add rule filter_4 output ct state established goto established_out_4
# Related IPv4 traffic
add rule filter_4 input ct state related goto related_in_4
add rule filter_4 output ct state related goto related_out_4
# New IPv4 traffic ( PACKET IS MATCHED HERE )
add rule filter_4 input ct state new goto new_in_4
add rule filter_4 output ct state new goto new_out_4
# Invalid IPv4 traffic
add rule filter_4 input ct state invalid log prefix "drop invalid_filter_in_4: " counter name invalid_filter_count_4 drop
add rule filter_4 output ct state invalid log prefix "drop invalid_filter_out_4: " counter name invalid_filter_count_4 drop
# Untracked IPv4 traffic
add rule filter_4 input ct state untracked log prefix "drop untracked_filter_in_4: " counter name untracked_filter_count_4 drop
add rule filter_4 output ct state untracked log prefix "drop untracked_filter_out_4: " counter name untracked_filter_count_4 drop
在上面的设置中,包括多播在内的新输出流量通过规则进行匹配add rule filter_4 output ct state new goto new_out_4
这是new_out_4
仅包含不起作用的相关(非工作)多播规则的链:
# Multicast IPv4 traffic ( THIS RULE DOES NOT WORK, SEE LOG OUTPUT BELOW)
add rule filter_4 new_out_4 meta pkttype multicast goto multicast_out_4
#
# Default chain action ( MULTICAST PACKET IS DROPPED HERE )
#
add rule filter_4 new_out_4 log prefix "drop new_out_4: " counter name new_out_filter_count_4 drop
以下是日志中有关丢弃的多播数据包的内容:
删除new_out_4:IN = OUT = eth0 SRC = 192.168.1.100 DST = 224.0.0.251 LEN = 163 TOS = 0x00 PREC = 0x00 TTL = 255 ID = 27018 DF PROTO = UDP SPT = 5353 DPT = 5353 LEN = 143
被丢弃的数据包被发送到目标地址224.0.0.251
,这是多播地址,它应该与new_out_4
链中的多播规则匹配,并且应该由multicast_out_4
链处理,但没有。
相反,数据包不匹配,并被new_out_4
上面链中的默认丢弃规则丢弃,请参阅注释(默认链操作)。
显然这意味着组播规则不起作用。
为什么组播规则不起作用?
预期的:
meta pkttype multicast
匹配目标地址224.0.0.251
编辑:
系统信息:
内核:6.5.0-0.deb12.4-amd64
与早期内核 6.1 存在相同的问题
nftables:v1.0.6(莱斯特·古奇#5)
答案1
使用一些附加条目复制(并完成缺失的部分)设置,例如:
nft insert rule filter_4 new_out_4 counter meta pkttype host counter
meta pkttype
实际上,此 skbuff 的属性不是传出多播数据包的host
预期属性。multicast
注意当引入此关键字时,这是关于输入,而不是输出:
src:在元表达式中添加对 pkttype 的支持
如果你想匹配 skbuff 的 pkttype 字段,你必须使用以下语法:
nft 添加规则 ip 过滤器输入元 pkttype PACKET_TYPE
其中 PACKET_TYPE 可以是:单播、广播和多播。
实际上直接相当于iptables是个pkttype匹配模块:
pkttype
该模块匹配链路层数据包类型。
[!] --pkt-type {unicast|broadcast|multicast}
# iptables-translate -A OUTPUT -m pkttype --pkt-type multicast
nft 'add rule ip filter OUTPUT pkttype multicast counter'
将所有这些放在一起,当创建传出 IP(路由:第 3 层)数据包时,它尚未到达第 2 层(链路层),因此它的 skbuff 不会反映它可能会变成什么,即使以后打算这样做。
实际应该测试的是关于路由堆栈的IP地址属性,而不是关于以太网的数据包属性。iptables
为此规定了addrtype
匹配模块:
addrtype
该模块根据数据包匹配数据包地址类型。 [...]
它的翻译暗示了实际应该使用什么:fib
表达:
# iptables-translate -A OUTPUT -m addrtype --dst-type MULTICAST
nft 'add rule ip filter OUTPUT fib daddr type multicast counter'
FIB 表达式
fib {saddr | daddr | mark | iif | oif} [. ...] {oif | oifname | type}
fib 表达式查询 fib(转发信息库)以获取诸如特定地址将使用的输出接口索引之类的信息。输入是一个元素元组,用作 fib 查找函数的输入。
没有多播的直接示例。最近的例子是一个更复杂的例子,关于丢弃不打算用于传入接口上的地址的 pacjet,其中多播属于 3 个例外:
# drop packets to address not configured on incoming interface filter prerouting fib daddr . iif type != { local, broadcast, multicast } drop
因此,只需替换输出(或后路由)挂钩中使用的任何位置即可:
meta pkttype multicast
和:
fib daddr type multicast
在输入(或预路由)钩子中,虽然 skbuff 属性可能与 IP 属性匹配,但为了保持一致,也应该将其替换为完全相同:
fib daddr type multicast
下面的测试命令在 LAN 中的其他主机(用于测试输入)和主机(用于测试输出)上联合使用:
socat -d -d UDP4-DATAGRAM:224.0.0.251:5555,bind=:5555,ip-add-membership=224.0.0.251:eth0 -
将正确匹配fib daddr type multicast
输入和输出。
重要说明:
我相信上面解决了这个问题,但请注意,Netfilter 无法正确跟踪多播连线,因为它无法将使用其他单播源地址的回复关联到初始查询的多播目标地址:它们不同,因此它认为回复是其他(新)流,而不是关联它们并将此类回复视为一部分之前的流程。因此,这种流永远不会显示为 ESTABLISHED 状态连线或conntrack -L
命令。规则集应该适应这一点:它不能仅依赖于ct state established,related
某种规则,但这超出了这个问题的范围。