How to build a MAC-based Vlan using Linux ebtables and netdev

How to build a MAC-based Vlan using Linux ebtables and netdev

In this guide, we will explore the potential of ebtables to build a Vlan like network-segment using the MAC addresses of a set of devices. Unlike Vlans, these segments will be semi-isolated broadcast domains. As illustrated below, the bridge splits the Ethernet traffic coming from Port_0 in between Port_1 and Port_2 based on MAC addresses. To avoid complexity, there is no split between Port_1 and Port2. However, it can be defined in the same fashion.


Software Bridge Configuration
  • No packet filter between Port_1 and Port_2
  • No packet filter from Port_1 to Port_0
  • No packet filter from Port_2 to Port_0
  • Selected packets flow to Port_1 from Port_0
  • All other packets flow to Port_2 from Port_0

Step 1 - Create virtual network devices (netdev)

Let’s create two devices of type “dummy.” Although dummy devices drop all packets sent to them, a Guest OS running inside Virtual Machine can read and write to these interfaces. A virtual Machine host has to bridge them to the virtual interfaces.

In folder /etc/systemd/network, create a filename “25-macsink0.netdev” with following contents
[NetDev]
Name=macsink0
Kind=dummy
MACAddress=XX:XX:XX:XX:XX:01"
Replace MAC XX:XX:XX:XX:XX:01 with some random MAC.

In folder /etc/systemd/network, create a filename “25-macsink1.netdev” with following contents
[NetDev]
Name=macsink1
Kind=dummy
MACAddress=XX:XX:XX:XX:XX:02
Replace MAC XX:XX:XX:XX:XX:02 with some random MAC.

Restart the networkd service
systemctl restart systemd-networkd

Step 2 – Create a bridge and configure network devices

As I am using a netplan to configure the network devices, the following are the content of
the file “01-network-manager-all.yaml” (/etc/netplan/).

    network:
      version: 2
      renderer: networkd
      ethernets:
      	eth1:
        	addresses:
          	- 192.168.1.2/24
        eth0:
        	dhcp4: false
                dhcp6: false
        macsink0:
        	dhcp4: false
        	dhcp6: false
        macsink1:
        	dhcp4: false
                dhcp6: false
      bridges:
        br0:
        	interfaces: [eth0, macsink0, macsink1]
        	addresses: [192.168.100.12/24]
        	gateway4: 192.168.100.10
        	mtu: 1500
        	nameservers:
        		addresses: [192.168.100.10]
	        parameters:
        		stp: false
	       		forward-delay: 4
        	dhcp4: no
                dhcp6: no
            

Where

  • eth1 interface is connected to WAN using static IP 192.168.1.2 (can be omitted).
  • eth0 interface is connected to a wireless AP.
  • br0 is the bridge between eth0, macsink0, and macsink1.
  • 192.168.100/24 subnet is the main LAN1 or default LAN.

Generate the netplan configuration and apply the plan.
netplan generate
netplan apply

Check the existence of the interfaces using the ifconfig command.
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
    inet 192.168.100.12 netmask 255.255.255.0 broadcast 192.168.100.255
    ether xx:xx:xx:xx:xx:03 txqueuelen 1000 (Ethernet)

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
    ether xx:xx:xx:xx:xx:04 txqueuelen 1000 (Ethernet)

eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
    inet 192.168.1.2 netmask 255.255.255.0 broadcast 192.168.1.255
    ether xx:xx:xx:xx:xx:05 txqueuelen 1000 (Ethernet)

macsink0: flags=195<UP,BROADCAST,RUNNING,NOARP> mtu 1500
    ether xx:xx:xx:xx:xx:01 txqueuelen 1000 (Ethernet)

macsink1: flags=195<UP,BROADCAST,RUNNING,NOARP> mtu 1500
    ether xx:xx:xx:xx:xx:02 txqueuelen 1000 (Ethernet)

The netplan dump for reference (/run/systemd/network/)
File: 10-netplan-br0.netdev
[NetDev]
Name=br0
MTUBytes=1500
Kind=bridge

[Bridge]
ForwardDelaySec=4
STP=false

File: 10-netplan-br0.network
[Match]
Name=br0

[Link]
MTUBytes=1500

[Network]
LinkLocalAddressing=ipv6
Address=192.168.100.12/24
Gateway=192.168.100.10
DNS=192.168.100.10
ConfigureWithoutCarrier=yes

File: 10-netplan-eth0.network
[Match]
Name=eth0

[Network]
LinkLocalAddressing=no
Bridge=br0

File: 10-netplan-macsink0.network
[Match]
Name=macsink0

[Network]
LinkLocalAddressing=no
Bridge=br0

File: 10-netplan-macsink1.network
[Match]
Name=macsink1

[Network]
LinkLocalAddressing=no
Bridge=br0

Step 3 – Configure ebtables to split the LAN

ebtables are analogous to iptables. The ebtables deal with Ethernet packets (L2) while iptables handle IP packets (L3). Unlike iptables, they are simple and less complicated.

On the filter table, the policy allows all on INPUT and OUTPUT chains but drops everything on the FORWARD chain.
ebtables -P INPUT ACCEPT
ebtables -P OUTPUT ACCEPT
ebtables -P FORWARD DROP

Allow forwarding from dummy interfaces. No special treatment is required for packets coming from those interfaces.
ebtables -A FORWARD -i macsink0 -j ACCEPT
ebtables -A FORWARD -i macsink1 -j ACCEPT

Mark all incoming packets from the real LAN interface (eth0) with value 1.
ebtables -A FORWARD -i eth0 -j mark --set-mark 1 --mark-target CONTINUE 

Override all incoming packets from the real LAN with value 2 for selected MACs.
ebtables -A FORWARD -i eth0 -s xx:xx:xx:xx:xx:aa -j mark --set-mark 2 --mark-target CONTINUE
ebtables -A FORWARD -i eth0 -s xx:xx:xx:xx:xx:ab -j mark --set-mark 2 --mark-target CONTINUE
ebtables -A FORWARD -i eth0 -s xx:xx:xx:xx:xx:ac -j mark --set-mark 2 --mark-target CONTINUE
ebtables -A FORWARD -i eth0 -s xx:xx:xx:xx:xx:ad -j mark --set-mark 2 --mark-target CONTINUE
 

Allow Forward for selected MACs to macsink0
ebtables -A FORWARD --mark 2/2 -o macsink0 -j ACCEPT

Allow Forward for other MACs to macsink1
ebtables -A FORWARD --mark 1/1 -o macsink1 -j ACCEPT

Step 4 – VM as a firewall (use case)

Create a virtual machine, the OPNsense is used as guest OS, with three network interfaces, and bridged them accordingly.


  1. The eth1 interface to the first interface of VM,
         eth1 -> em0. (WAN)
  2. The macsink0 interface to the second interface of VM,
         macsink0 -> em1. (LAN)
  3. The macsink1 interface to the third interface of the VM,
         macsink1 -> em2. (OPT1/GUSTNET)

Install the Guest OS or use a pre-installed VM. Configure Guest OS interfaces accordingly (WAN, LAN, OPT1).

Configure DHCP on LAN and OPT1 with different subnet and pool.
Let say the LAN pool will be 192.168.100.50 to 192.168.100.150
And the OPT1 pool will be 192.168.200.50 to 192.168.200.150

There should be no other DHCP server running. Now try to get the IP from the machine having selected MAC and others from having anything else. Selected MAC will get the IP from 192.168.100.0/24 subnet. All other devices will get the IP from 192.168.200.0/24 subnets.

Some useful commands and tips
To dump rules in text format: /sbin/ebtables-save
To save rules in the loadable format: service ebtables save
To Load saved rules: service ebtables load
To reload saved rules on reboot, edit file /etc/default/ebtables and modify EBTABLES_LOAD_ON_START="yes"

References
ebtables
systemd.netdev
OPNsense, Setup a Guest Network

Comments

Popular posts from this blog

Virtual Sy to extend the PCRF functionality

5G specific data offers in 5G NSA.