我的电视(192.168.1.48)正在多播 SSDP 数据包(到 239.255.255.250:1900),并且在我的服务器(192.168.1.17)上,通过运行 smcroute 并进行一些数据包处理来增加此多播数据包的 IP TTL,我可以将其路由到通过桥接网络连接的容器(Podman / Docker):
ISP LAN bridge network @ server
| (192.168.1.0/24) (10.1.1.0/24)
| | |
+--[router]--(.1)--+ |
| | |
| +--(.48)--[tv] +--(.2)--[container_A]
| | |
: | +--(.3)--[container_B]
| |
+--(.17)--[server]--(.1)--+
| |
: :
容器甚至可以回复此 SSDP 数据包,并且容器中的媒体服务器发现正在运行,所有路由均无需代理或 NAT。(LAN 上的路由器(192.168.1.1)通过 192.168.1.17 具有 10.1.1.0/24 网络的静态路由,这也有所帮助。)
我的问题是,当我nft
在服务器上的 FORWARD 链中创建一条规则以允许往返于容器的 SSDP 流量时,conntrack 系统似乎没有意识到响应是从 192.168.1.48 到 10.1.1.2 和 10.1.1.3 的已建立流的一部分,因此它将响应数据包(来自 10.1.1.2:1900 和 10.1.1.3:1900)视为新流,这意味着我必须添加另一条规则以允许从桥接网络到 LAN 的 udp/1900 数据包。
这些是相关的防火墙规则:
table inet fw {
chain FORWARD {
type filter hook forward priority filter; policy drop;
ct state invalid drop
ct state established accept
ct state related accept
ct state untracked counter packets 0 bytes 0
ip daddr 239.255.255.250 udp dport 1900 accept comment "forward SSDP"
log prefix "CHAIN=FORWARD " accept # TODO: remove temporary rule
}
chain MANGLE {
type nat hook prerouting priority mangle; policy accept;
meta pkttype multicast ip ttl set 2
}
}
显示的内容如下conntrack -L conntrack
,请注意第一行,它期待来自 239.255.255.250:1900 的回复数据包,而实际上应该是 10.1.1.2:1900 和 10.1.1.3:1900:
udp 17 3 src=192.168.1.48 dst=239.255.255.250 sport=49155 dport=1900 [UNREPLIED] src=239.255.255.250 dst=192.168.1.48 sport=1900 dport=49155 use=1
udp 17 3 src=10.1.1.2 dst=192.168.1.48 sport=1900 dport=49155 [UNREPLIED] src=192.168.1.48 dst=10.1.1.2 sport=49155 dport=1900 use=1
udp 17 3 src=10.1.1.3 dst=192.168.1.48 sport=1900 dport=49155 [UNREPLIED] src=192.168.1.48 dst=10.1.1.3 sport=49155 dport=1900 use=1
conntrack 系统是否应该足够智能,能够识别出多播数据包和两个响应是同一流的一部分?或者是否应该由助手设置一个期望,以便将这些数据包视为 RELATED 而不是 ESTABLISHED?
答案1
如上所述,conntrack 基础设施本身不会将对多播请求的响应识别为同一流的一部分。
一个选择是使用 conntrack 助手。对于我的具体情况 (SSDP),conntrack-tools 包中有一个 ssdp 助手。
暗示了另一种选择在这个答案中,但对于 iptables 和 ipset,它们有(或曾经有)一个专用的hash:ip4,port
类型。使用 nftables套和连接,我能够使其适应 nftables 并使其适用于所有多播请求,如下所示:
table inet filter {
set mc4_out {
type ipv4_addr . inet_service
timeout 5s
}
set mc6_out {
type ipv6_addr . inet_service
timeout 5s
}
chain OUTPUT {
type filter hook output priority filter
policy accept
meta nfproto ipv4 fib daddr type multicast counter add @mc4_out { ip saddr . udp sport }
meta nfproto ipv6 fib daddr type multicast counter add @mc6_out { ip6 saddr . udp sport }
}
chain INPUT {
type filter hook input priority filter
policy drop
meta nfproto ipv4 ip daddr . udp dport @mc4_out counter accept
meta nfproto ipv6 ip6 daddr . udp dport @mc6_out counter accept
}
}
一个小问题是meta pkttype multicast
在我的 OUTPUT 链中不起作用,这在这个答案:meta pkttype
查看链路级数据包类型,并且当数据包遍历 OUTPUT 链时,还没有链路级报头,解决方案是使用 查询 FIB fib daddr type multicast
。