使用 nftables 和 VLAN 的透明防火墙

使用 nftables 和 VLAN 的透明防火墙

我想向您咨询有关透明防火墙构建的最佳实践建议。

我有 2 个网络段和带有 2 个 10G 接口的 CentOS 服务器。我想过滤/监控/限制/丢弃段之间的流量。流量已标记。我应该取消标记流量以进行过滤并将其重新标记,还是 nftable 可以处理已标记的流量?

现在方案如下:

PCs--|                                         |--PCs
PCs--|--untag--[Switch]--tag--[Switch]--untag--|--PCs
PCs--|                                         |--PCs

我想:

PCs--|                                                              |--PCs
PCs--|--untag--[Switch]--tag--**[Firewall]**--tag--[Switch]--untag--|--PCs
PCs--|                                                              |--PCs

答案1

TL;DR:nftables 在桥接级别,通过使用略有不同的规则,可以很好地处理带标签或未带标签的数据包。所有标记工作都可以在 Linux 端通过使用可感知 vlan 的桥接来完成,因此无论在防火墙中为 nftables 做出何种选择,都无需在交换机上更改配置。

在这些博客系列中可以找到很多有关测试 VLAN 的有趣文档(特别是第 IV 部分,即使其中一些信息可能不完全准确):

在未命名的 Linux 网络命名空间中使用 veth 设备、Linux 桥接器和 VLAN 的乐趣

让我们将两个防火墙的极简模型(放在网络命名空间中)放在一起。trunk100trunk200链接到两个交换机,从左侧计算机发送带有 VLAN 100 标签的数据包,从右侧计算机发送带有 VLAN 200 标签的数据包。请注意,这里明确允许 VLAN 标签出现在另一侧,方法是创建具有另一侧 VLAN ID 的子接口,或者直接将另一侧的 VLAN ID 添加到中继接口。

  1. vlan 子接口将未标记的数据包放入网桥

    ip link add fw0 type bridge vlan_filtering 1
    ip link set fw0 up
    for trunk in 100 200; do
        for vlan in 100 200; do
            ip link add link trunk$trunk name trunk$trunk.$vlan type vlan id $vlan
            ip link set trunk$trunk.$vlan master fw0
            bridge vlan add vid $vlan pvid untagged dev trunk$trunk.$vlan
            bridge vlan del vid 1 dev trunk$trunk.$vlan
            ip link set trunk$trunk.$vlan up
        done
    done
    bridge vlan del vid 1 dev fw0 self
    

    在这种情况下,通过 trunk100 和 trunk200 到达的带标签的数据包将拆分到每个 VLAN 子接口中,并且数据包未带标签。网桥仍然在内部了解正在使用的 VLAN,并且正在对源和目标应用 VLAN 过滤。nft将添加自己的限制。传出的数据包一旦到达父中继接口,就会重新标记。

  2. 标记数据包直接进入网桥

    ip link add fw0 type bridge vlan_filtering 1
    ip link set fw0 up
    for trunk in 100 200; do
        ip link set trunk$trunk master fw0
        for vlan in 100 200; do
            bridge vlan add vid $vlan tagged dev trunk$trunk
        done
        bridge vlan del vid 1 dev trunk$trunk
        ip link set trunk$trunk up
    done
    bridge vlan del vid 1 dev fw0 self
    

对于这种更简单的情况,标记的数据包穿过网桥,同时保留其 VLAN 标记。

这里有一个 nftables 规则集,展示了如何处理这两种情况。iifname这里选择了 而不是 ,iif这样同一组规则就可以在两种情况下工作(不会因为缺少接口而出现错误)。通常iif应该是首选。还有额外的计数器条目,只是为了检查到底匹配了什么或不匹配了什么(带有nft list ruleset -a):

#!/usr/sbin/nft -f

flush ruleset

table bridge filter {
    chain input {
        type filter hook input priority -200; policy drop;
    }

    chain forward {
        type filter hook forward priority -200; policy drop;
        counter
        arp operation request counter
        arp operation reply counter
        vlan type arp arp operation request counter
        vlan type arp arp operation reply counter
        arp operation request counter accept
        arp operation reply counter accept
        vlan type arp arp operation request counter accept
        vlan type arp arp operation reply counter accept
        ip protocol icmp icmp type echo-request counter
        ip protocol icmp icmp type echo-reply counter
        vlan type ip icmp type echo-request counter
        vlan type ip icmp type echo-reply counter
        iifname trunk100.100 ip protocol icmp icmp type echo-request counter accept
        oifname trunk100.200 ip protocol icmp icmp type echo-reply counter accept
        vlan id 100 vlan type ip icmp type echo-request counter accept
        vlan id 200 vlan type ip icmp type echo-reply counter accept
    }

    chain output {
        type filter hook output priority 200; policy drop;
    }
}

请注意,这些规则可以写得更详细。例如:

iifname "trunk100.100" ether type ip ip protocol icmp icmp type echo-request

或者

ether type vlan vlan id 200 vlan type ip ip protocol icmp icmp type echo-reply

当使用第一个设置时(通过子接口的未标记数据包),只有经典规则才会匹配。当使用第二个设置时,只有明确使用 vlan 的规则才会匹配。因此,这组双重规则(允许基本 ARP 解析以及允许 VLAN 100 ping VLAN 200,但不允许相反操作)在两种情况下都有效。

这组规则与 CentOS 的 nftables v0.6(未在 CentOS 内核上测试)或当前 nftables v0.8.3 一起使用时应该可以正常工作。

目前已知的限制:

从 v0.8.3 开始,nftables 无法像 ebtables/iptables 交互那样使用 conntrack。似乎有这方面的计划,请参阅此 PDF:使用 nftables 进行桥接过滤。因此这使得状态规则很难实施。

还请注意,nftables 仍然存在(截至 0.8.3)显示问题:如果未使用其任何选项,则会从“反编译”规则中nft list ruleset -a删除。例如,这两个规则:vlan

nft add rule bridge filter forward ip protocol icmp counter
nft add rule bridge filter forward vlan type ip ip protocol icmp counter

nft list ruleset -a当使用(v0.8.3)显示时:

        ip protocol icmp counter packets 0 bytes 0 # handle 23
        ip protocol icmp counter packets 0 bytes 0 # handle 24

只有nft --debug=netlink list ruleset -a这样才能转储字节码,很明显这确实是两个不同的规则(这里的数据是小端的):

bridge filter forward 23 22 
  [ payload load 2b @ link header + 12 => reg 1 ]
  [ cmp eq reg 1 0x00000008 ]
  [ payload load 1b @ network header + 9 => reg 1 ]
  [ cmp eq reg 1 0x00000001 ]
  [ counter pkts 0 bytes 0 ]

bridge filter forward 24 23 
  [ payload load 2b @ link header + 12 => reg 1 ]
  [ cmp eq reg 1 0x00000081 ]
  [ payload load 2b @ link header + 16 => reg 1 ]
  [ cmp eq reg 1 0x00000008 ]
  [ payload load 1b @ network header + 9 => reg 1 ]
  [ cmp eq reg 1 0x00000001 ]
  [ counter pkts 0 bytes 0 ]

CentOS v0.6(在内核 4.15 上测试)也有其自己的不同的“反编译”显示问题:

ip protocol icmp icmp type echo-request

显示为:

icmp type echo-request counter

如果在 v0.6 中尝试这样做,则会出现语法错误(但在 v0.8.3 中则没有问题)。

相关内容