Ebtables
Firewalling with Ethernet Tables
On AAISP I have decided to run a NAT-free home network, but some recent additions to the network need both internet access to function at the same time as any IPv4 address that can access them to control them.
In addition to all that, I assigned v4 addresses dynamically to conserve the address space. This means that IPtables rules to control inward access on their own would not do, so I am using ebtables to control access.
I have an external interface ppp0 (towards AAISP) and an internal interface eth0.20 which is in fact a VLAN on eth0.
To use ebtables, the internal interface must be enslaved to an ethernet bridge
I didn’t need Spanning Tree unless the bridge is part of a loop, which it could not be with only the one ethernet interface attached. If more than one interface is used, then STP may be needed.
/etc/network/interfaces
Valid if eth0.20 used IEEE's example of AC-DE-48-23-45-67
iface int0 inet static # configure IP addresses here address 192.0.2.0 netmask 255.255.255.0 up /sbin/ifconfig int0 del fe80::aede:48ff:fe23:4567/64 up /sbin/ifconfig int0 add fe80::aede:48ff:fe23:4567/64 up /sbin/ifconfig int0 add 2001:db8:cafe:1:aede:48ff:fe23:4567/64 bridge_ports eth0.20 bridge_stp off bridge_ageing 0 bridge_bridgeprio 34000 bridge_fd 0 bridge_gcint 0 bridge_hello 0 bridge_maxage 0 bridge_maxwait 0
It is also possible to do this directly with brctl if you run a GNU/Linux system that has not got /etc/network/interfaces
I had also disabled the callout of iptables from within ebtables via sysctl at this point as the feature seems to be broken in Linux 2.6.32-5-amd64 causing IPv6’s address resolution to break amongst ofther things. IP6tables is still working independently.
In /etc/sysctl.conf
net.bridge.bridge-nf-call-arptables=0 net.bridge.bridge-nf-call-ip6tables=0 net.bridge.bridge-nf-call-iptables=0
Ebtables and IPtables rules
I use the netfilter mark to communicate between ebtables and iptables that has 32 bits to use and each can be independently set. The 2 type of device I want to filter are Freesat boxes, which want to access BBC iPlayer, and Sonos which will access radio stations via Tunein/Radiotime, so I am using 3 of my bits for now, as I also do MAC address based accounting.
MINET=$'0x4' MSONOS=$'0x1' MFREESAT=$'0x2'
The flag is set on outgoing frames from the devices by ebtables to say they want to access a particular IP address. IPtables then remembers that destination address for the packet in a recents list.
For incoming packets, netfilter flags are set on all packets unless they are from an IP address that has been approved in the corresponding recents list. When the packets are converted to frames and reach ebtables, they are DROPPED unless the netfilter flag of the device is cleared. I would have liked to REJECT instead but ebtables does not offer that.
# first let’s do some accounting. # These rules need only match, not do anything, as we are interested in the Ebtables counters. ebtables -N accounting -P RETURN ebtables -A accounting --destination AC:DE:48:23:45:67/ff:ff:ff:ff:ff:ff ebtables -A accounting --destination AC:DE:48:23:45:67/ff:ff:ff:ff:ff:ff ebtables -A OUTPUT -o eth0.20 -p 0x0800 --mark $MINET/$MINET -j accounting ebtables -A OUTPUT -o eth0.20 -p 0x86DD --mark $MINET/$MINET -j accounting # freesat devices. ebtables -A INPUT -i eth0.20 --source 00:03:78:00:00:00/ff:ff:ff:00:00:00 -p 0x0800 -j mark --mark-or $MFREESAT --mark-target CONTINUE ebtables -A INPUT -i eth0.20 --source 00:06:f4:00:00:00/ff:ff:ff:00:00:00 -p 0x0800 -j mark --mark-or $MFREESAT --mark-target CONTINUE iptables -A FORWARD -i int0 -o ppp0 -m mark --mark $MFREESAT/$MFREESAT -m recent --rdest --set --name freesat iptables -A FORWARD -i ppp0 -o int0 -m recent --rsource ! --update --name freesat -j MARK --or-mark $MFREESAT ebtables -A OUTPUT -o eth0.20 --destination 00:03:78:00:00:00/ff:ff:ff:00:00:00 -p 0x0800 --mark /$MFREESAT -j DROP ebtables -A OUTPUT -o eth0.20 --destination 00:06:f4:00:00:00/ff:ff:ff:00:00:00 -p 0x0800 --mark /$MFREESAT -j DROP # sonos devices. ebtables -A INPUT -i eth0.20 --source 00:0e:58:00:00:00/ff:ff:ff:00:00:00 -p 0x0800 -j mark --mark-or $MSONOS --mark-target CONTINUE iptables -A FORWARD -i int0 -o ppp0 -m mark --mark $MSONOS/$MSONOS -m recent --rdest --set --name sonos iptables -A FORWARD -i ppp0 -o int0 -m recent --rsource ! --update --name sonos -j MARK --or-mark $MSONOS ebtables -A OUTPUT -o eth0.20 --destination 00:0e:58:00:00:00/ff:ff:ff:00:00:00 -p 0x0800 --mark $MSONOS/$MSONOS -j DROP # mark incoming data so that we can account it. iptables -A FORWARD -i ppp0 -o int0 -j MARK --or-mark $MINET