TL;DR: when spoofing MAC addresses, how can I make sure the real addresses won't be leaked to the rest of the network using nftables ?
Context
For network security training purposes I am currently building a network tap consisting of a transparent bridge with two interfaces (the tap).
The tap is a computer is running Debian Bullseye, that has 4 ethernet interfaces as follows:
Interface | MAC |
---|---|
enp3s0 | 00:90:27:b4:40:58 |
enp4s0 | 00:90:27:b4:40:59 |
enp6s0 | 00:90:27:b4:40:5a |
enp7s0 | 00:90:27:b4:40:5b |
- enp3s0 is connected to the switch and gets an IP address via DHCP.
- Additionally I created a bridge br0 with nmcli, with two slave interfaces: enp6s0 and enp7s0
- enp7s0 is connected to the switch
The bridge is created as follows:
nmcli connection add connection.type bridge ifname br0 con-name br0 ipv4.method disabled ipv6.method ignore bridge.stp no bridge.vlan-filtering yes connection.autoconnect-slaves 1 autoconnect no
nmcli connection add type ethernet ifname enp6s0 con-name br0-slave-enp6s0 slave-type bridge master br0 autoconnect no
nmcli connection add type ethernet ifname enp7s0 con-name br0-slave-enp7s0 slave-type bridge master br0 autoconnect no
Goal
I want the machine to remain stealth at all times on the network since it is a passive tap, so I want to drop outgoing traffic that could accidentally leak the MAC addresses of my machine. So I made an attempt with nftables as follows, with a named set for the MAC addresses:
table netdev bridge {
set macs {
type ether_addr
elements = { 00:90:27:b4:40:59,
00:90:27:b4:40:5a, 00:90:27:b4:40:5b }
}
chain br0 {
type filter hook ingress devices = { enp4s0, enp6s0, enp7s0 } priority filter; policy accept;
ether saddr @macs drop
log flags all prefix "myfilter " counter
}
}
I also want to have counters and log details of the dropped packets.
Problem
Traffic is being dropped and logging is done to /var/log/syslog as expected. Counters are being updated. But the netfilter rule does not seem to be working as intended. Instead it seems to be dropping all traffic sent to enp7s0.
Sample:
Dec 20 01:23:47 testbox kernel: [32441.125971] myfilter IN=enp7s0 OUT= MACSRC=10:c2:5a:58:72:8f MACDST=01:00:5e:7f:ff:fa MACPROTO=0800 SRC=192.168.0.1 DST=239.255.255.250 LEN=367 TOS=0x00 PREC=0x00 TTL=4 ID=37026 PROTO=UDP SPT=1900 DPT=1900 LEN=347 Dec 20 01:23:47 testbox kernel: [32441.126842] myfilter IN=enp7s0 OUT= MACSRC=10:c2:5a:58:72:8f MACDST=01:00:5e:7f:ff:fa MACPROTO=0800 SRC=192.168.0.1 DST=239.255.255.250 LEN=312 TOS=0x00 PREC=0x00 TTL=4 ID=37027 PROTO=UDP SPT=1900 DPT=1900 LEN=292 Dec 20 01:23:47 testbox kernel: [32441.127554] myfilter IN=enp7s0 OUT= MACSRC=10:c2:5a:58:72:8f MACDST=01:00:5e:7f:ff:fa MACPROTO=0800 SRC=192.168.0.1 DST=239.255.255.250 LEN=303 TOS=0x00 PREC=0x00 TTL=4 ID=37028 PROTO=UDP SPT=1900 DPT=1900 LEN=283 Dec 20 01:23:47 testbox kernel: [32441.128342] myfilter IN=enp7s0 OUT= MACSRC=10:c2:5a:58:72:8f MACDST=01:00:5e:7f:ff:fa MACPROTO=0800 SRC=192.168.0.1 DST=239.255.255.250 LEN=377 TOS=0x00 PREC=0x00 TTL=4 ID=37029 PROTO=UDP SPT=1900 DPT=1900 LEN=357 Dec 20 01:23:53 testbox kernel: [32447.003559] myfilter IN=enp7s0 OUT= MACSRC=10:c2:5a:58:72:8f MACDST=33:33:00:00:00:01 MACPROTO=86dd SRC=fe80:0000:0000:0000:12c2:5aff:fe75:899d DST=ff02:0000:0000:0000:0000:0000:0000:0001 LEN=176 TC=0 HOPLIMIT=255 FLOWLBL=0 PROTO=ICMPv6 TYPE=134 CODE=0 Dec 20 01:23:53 testbox kernel: [32447.015382] myfilter IN=enp7s0 OUT= MACSRC=00:90:27:e6:10:58 MACDST=33:33:00:00:00:16 MACPROTO=86dd SRC=fe80:0000:0000:0000:6d06:284e:2844:db03 DST=ff02:0000:0000:0000:0000:0000:0000:0016 LEN=136 TC=0 HOPLIMIT=1 FLOWLBL=0 OPT ( ) PROTO=ICMPv6 TYPE=143 CODE=0 Dec 20 01:23:53 testbox kernel: [32447.619279] myfilter IN=enp7s0 OUT= MACSRC=00:90:27:e6:10:58 MACDST=33:33:00:00:00:16 MACPROTO=86dd SRC=fe80:0000:0000:0000:6d06:284e:2844:db03 DST=ff02:0000:0000:0000:0000:0000:0000:0016 LEN=136 TC=0 HOPLIMIT=1 FLOWLBL=0 OPT ( ) PROTO=ICMPv6 TYPE=143 CODE=0
I believe I might need to use an egress hook instead of ingress. I understand the egress hook is available in nft from version 1.01. Current stable version of nft in Debian is 0.98, so I manually upgraded to v1.01 by downloading the packages manually. But replacing ingress with egress does not work: nft does not recognize my rule.
Questions
- Does my approach make sense ? Can I use the ingress hook for my purpose ? Or is egress required ?
- Alternatively, can this be done with tc ?
- Or can the bridge be further isolated against traffic originating from other interfaces ?
0 Answers