TL; DR: nftables, no nível da ponte, pode lidar bem com pacotes marcados ou não marcados, usando regras ligeiramente diferentes. Todo o trabalho de marcação pode ser feito no lado do Linux, fazendo com uma ponte com reconhecimento de vlan, portanto, nenhuma mudança de configuração é necessária nos switches, seja qual for a escolha feita no firewall para nftables.
Muita documentação interessante sobre o teste de VLANs pode ser encontrada nesta série de blogs (especialmente parte IV, mesmo que algumas informações possam não ser totalmente precisas):
Fun with veth-devices, Linux bridges and VLANs in unnamed Linux network namespaces I II III IV V VI VII VIII
Vamos colocar dois modelos minimalistas do firewall (em um namespace de rede). trunk100
e trunk200
estão vinculados aos dois switches enviando pacotes marcados com vlan 100 dos computadores à esquerda e pacotes com vlan 200 marcados dos computadores à direita. Observe que aqui as tags de VLANs podem ser explicitamente exibidas no outro lado, seja criando uma subinterface com o ID de VLAN do outro, seja adicionando diretamente o ID de VLAN do outro lado à interface de tronco.
-
sub-interfaces vlan colocando pacotes não marcados na bridge
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
Neste caso, os pacotes marcados que chegam através do trunk100 e do trunk200 são divididos em subinterfaces por vlan e os pacotes não são marcados. A ponte ainda está ciente das VLANs em uso e está aplicando a filtragem de vlan em fontes e destinos.
nft
adicionará suas próprias restrições. Os pacotes de saída serão retagulados assim que chegarem na interface de tronco pai. -
marcou pacotes diretamente na ponte
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
Para este caso mais simples, os pacotes marcados atravessam a ponte enquanto retêm sua tag vlan.
Aqui está um único conjunto de regras nftables mostrando como ambos os casos são tratados. iifname
foi escolhido aqui em vez de iif
, então o mesmo conjunto de regras pode funcionar nos dois casos (sem ter um erro devido a uma interface ausente). Normalmente, iif
deve ser preferido. Há entradas adicionais no contador apenas para verificar o que exatamente correspondeu ou não (com 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;
}
}
Observe que essas regras poderiam ter sido escritas ainda mais detalhadamente. Exemplo:
iifname "trunk100.100" ether type ip ip protocol icmp icmp type echo-request
ou
ether type vlan vlan id 200 vlan type ip ip protocol icmp icmp type echo-reply
Quando a primeira configuração estiver em uso (pacotes não marcados através de subinterfaces), somente as regras clássicas serão correspondentes. Quando a segunda configuração estiver em uso, apenas as regras explicitamente usando vlan corresponderão. Portanto, este conjunto de regras duplas, permitindo a resolução ARP básica, bem como permitir que a VLAN 100 faça o ping da VLAN 200, mas não o contrário, funcionará em ambos os casos.
Esse conjunto de regras deve estar funcionando quando usado com os nftables v0.6 do CentOS (não testado no kernel do CentOS) ou com os nftables atuais v0.8.3.
Limitações atuais conhecidas:
Os nftables da v0.8.3 não podem usar conntrack da maneira que era possível com interações de ebtables / iptables. Parece que há planos sobre isso, veja este PDF: filtragem de ponte com nftables . Então, isso torna as regras de estado muito difíceis de implementar.
Note também que o nftables ainda tem (a partir de 0.8.3) problemas de exibição: nft list ruleset -a
cairá vlan
das regras "descompiladas" se nenhuma das suas opções forem usadas. Exemplo, essas duas regras:
nft add rule bridge filter forward ip protocol icmp counter
nft add rule bridge filter forward vlan type ip ip protocol icmp counter
Quando exibido de volta com 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
É somente com nft --debug=netlink list ruleset -a
que vai despejar o bytecode, que está claro que essas são de fato duas regras diferentes (os dados estão aqui em little endian):
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 ]
O CentOS 'v0.6 (testado no kernel 4.15) também tem seus próprios problemas de exibição "decompile":
ip protocol icmp icmp type echo-request
é exibido como:
icmp type echo-request counter
que faz um erro de sintaxe se tentado como está na v0.6 (mas está bem na v0.8.3).