我试图通过混杂设备和附加的 macvtap 将 libvirt (qemu) 虚拟机暴露给单独地址上的开放世界,但同时保护本地网络免遭窥探,例如通过禁止 192.168.0.0/16 (特殊地址(广播/网关/DNS)除外)。但是,看起来我的规则并未完全应用于子 macvtap 设备,甚至规则集中具有最低优先级的推荐元跟踪标志也仅标记 enp88s0 数据包,而不标记 macvtap0 数据包。是否可以使用 nftables 拦截 macvtap 流量?如果是这样,怎么办?
我试图通过混杂设备和附加的 macvtap 将 libvirt (qemu) 虚拟机暴露给单独地址上的开放世界,但同时保护本地网络免遭窥探,例如通过禁止 192.168.0.0/16 (特殊地址(广播/网关/DNS)除外)。但是,看起来我的规则并未完全应用于子 macvtap 设备,甚至规则集中具有最低优先级的推荐元跟踪标志也仅标记 enp88s0 数据包,而不标记 macvtap0 数据包。是否可以使用 nftables 拦截 macvtap 流量?如果是这样,怎么办?
MACVTAP接口是 VM 的MACVLAN的一种变体,它会劫持发送到主机接口的帧,该主机接口将 VM 的 NIC 的以太网 MAC 地址作为目标。同样,VM 发送的帧被注入到主机的物理接口上,指向外部。这通常也意味着虚拟机和主机无法直接通信(两者都会发送到外部,而另一方不会接收它,除非使用 VEPA 模式的交换机,或者它们之间的流量被路由)。
由于虚拟机的流量既不是针对主机的路由堆栈:
ip
/ip6
/inet
或arp
nftables系列,也不是针对主机桥:bridge
nftables系列,因此在这些系列中不会看到它(除了inet ingress
下面的内容)。netdev
,ingress
和egress
然而,仍然有一个
netdev
系列的ingress
和egress
(kernel >= 5.16) 钩子可以看到这样的流量。其实为了方便,inet
家里也有这样的ingress
仅限于IPv4/IPv6的hook(但没有等效的egress
hook)。这里ingress
与实际接口的方向相同:从“外部”到用户空间进程(QEMU)。egress
是从用户空间进程到“外部”。此级别没有可用的conntrack设施:无法进行状态过滤。如果需要过滤双向(
egress
需要内核 >= 5.16 和最新的nftables),或者过滤除 IPv4/IPv6 之外的其他协议(例如 ARP),那么只有该netdev
系列可以提供。此外,这些钩子有些特殊:它们附加到一个或多个接口,定义链的语法反映了这一点:它必须包含关键字(或)
device
和devices =
一个设备(或设备列表)。因此,如果接口被命名(但请参阅libvirt
macvtap0
集成的 Bonus 段落),则规则集会阻止 192.168.0.0/16(192.168.2.1 除外)(并且不关心通过以太网 MAC 地址或 ARP 协议进行过滤,因为这只是一个示例)像这样(通常以太网层过滤器的开始由 暗示并省略):ether type ip
ip saddr
filterout
如果使用 < 5.16 的内核,请删除该链(无论如何它可能并不是真正有用)。奖励:libvirt集成
这也意味着在创建虚拟机接口之前无法创建此规则集,因为设备引用必须事先存在。libvirt提供了一些钩子来帮助解决这个问题:
借助
xmlstarlet
(这是一个更难使用的命令,xmllint
但提供了更好的输出,并且在libvirt的文档中有一个示例),我们可以从start begin
libvirt挂钩检索动态创建的接口名称,并将其用作适当的nftables规则集中的参数。规则集文件
/etc/filtermacvtap.nft
:完成后:
并重新启动libvirtd;创建下面的文件并使其可执行,该文件仅针对名为的 VM 触发
myvm
,并且仅在使用链接到 的 MACVTAP 接口时才工作enp88s0
。/etc/libvirt/hooks/qemu.d/installfiltermacvtap.sh
:链接到实际接口的 MACVTAP 接口的名称从libvirt(VM 的 xmldump 可用作输入)
enp88s0
检索,并定义为调用nftables 的参数。$intf
清理作为一项练习(尽管当它们引用的接口消失时,链也会消失,留下一个无害的空表)。