Ebtables rules to fully isolate guest clients in 23.05.3 [Router <> Switch+AP]

I (finally) made the switch from 19.07.10 to 23.05.3 and replaced my main router from a WRT3200ACM to a GL-MT6000.

With the help of the OpenWrt community I got VLANs via DSA working but to fully isolate clients in my guest network I need some ebtables rules as with 19.07.10.
I'm using the GL-MT6000 as my main router (Lan + Wifi clients) and a DIR860L as a Switch + AP (Lan + Wifi cleints).

With my old WRT3200 and 19.07.10 I've used the following ebtables rules for the guest network:
ebtables -A FORWARD --logical-in br-guest -j DROP # Client Isolation [GUEST]

And on my DIR860L (Switch + AP) running 19.07.10:

ebtables -A FORWARD -i ! eth0.3 -o eth0.3 -j ACCEPT # allow AP clients to talk to router
ebtables -A FORWARD -i eth0.3 -o ! eth0.3 -j ACCEPT # allow router to talk to AP clients
ebtables -A FORWARD --logical-in br-guest -j DROP

For the reference here is my current network config (GL-MT6000):

config interface 'loopback'
	option device 'lo'
	option proto 'static'
	option ipaddr '127.0.0.1'
	option netmask '255.0.0.0'

config globals 'globals'
	option ula_prefix 'fd85:9f09:019d::/48'

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'lan1'
	list ports 'lan2'
	list ports 'lan3'
	list ports 'lan4'
	list ports 'lan5'

config device
	option name 'lan1'
	option macaddr '**:**:**:**:**:**'

config device
	option name 'lan2'
	option macaddr '**:**:**:**:**:**'

config device
	option name 'lan3'
	option macaddr '**:**:**:**:**:**'

config device
	option name 'lan4'
	option macaddr '**:**:**:**:**:**'

config device
	option name 'lan5'
	option macaddr '**:**:**:**:**:**'

config interface 'lan'
	option device 'br-lan.1'
	option proto 'static'
	option ipaddr '192.168.1.1'
	option netmask '255.255.255.0'
	option ip6assign '60'

config device
	option name 'eth1'
	option macaddr '**:**:**:**:**:**'

config interface 'wan'
	option device 'eth1.7'
	option proto 'pppoe'
	option username '**'
	option password '**'
	option ipv6 'auto'
	option peerdns '0'
	option pppd_options 'debug'
	list dns '1.1.1.1'
	list dns '8.8.8.8'

config interface 'wan6'
	option device 'eth1.7'
	option proto 'dhcpv6'
	option reqaddress 'try'
	option reqprefix 'auto'

config bridge-vlan
	option device 'br-lan'
	option vlan '1'
	list ports 'lan1:t'
	list ports 'lan2:u*'
	list ports 'lan3:u*'
	list ports 'lan4:u*'
	list ports 'lan5:u*'

config bridge-vlan
	option device 'br-lan'
	option vlan '3'
	list ports 'lan1:t'

config bridge-vlan
	option device 'br-lan'
	option vlan '15'
	list ports 'lan1:t'

config interface 'guest'
	option proto 'static'
	option device 'br-lan.3'
	option ipaddr '192.168.55.1'
	option netmask '255.255.255.0'

config interface 'psx'
	option proto 'static'
	option device 'br-lan.15'
	option ipaddr '192.168.100.1'
	option netmask '255.255.255.0'

config device
	option type '8021q'
	option ifname 'eth1'
	option vid '7'
	option name 'eth1.7'

config interface 'modem'
	option proto 'static'
	option device 'eth1.42'
	option ipaddr '192.168.254.1'
	option netmask '255.255.255.0'

config device
	option type '8021q'
	option ifname 'eth1'
	option vid '42'
	option name 'eth1.42'

br-guest doesn't exist anymore with my GL-MT6000, it's now br-lan.3 and I'm also missing the custom rules tab at the firewall section of Luci. I also don't know if ebtables rules are still working with 23.05.3, so I'm stuck at the moment and would appreciate a helping hand!

Any suggestions?

1 Like

Why don't you use the isolate function in the SSID section of the wireless?

I use this option on both devices but it doesn't fix the issue. Devices can still see each other when e.g. one device is connected to the Router (GL-MT6000) and the other one is connected to the Switch+AP (DIR860L).
Those ebtables rules are needed and I have no idea how to implement them with 23.05.3.

The isolate is not covering traffic between clients in different APs.
One solution is to follow the dumbAP guest wifi guide and adjust it to forward the guest traffic to specific upstream interface on main router.
Another option is to use the bridge table of nftables in some hotplug
https://openwrt.org/docs/guide-user/base-system/hotplug
https://openwrt.org/docs/guide-user/advanced/hotplug_extras

3 Likes

Ebtables is replaced by nftables.
See bridge filtering here:
https://wiki.nftables.org/wiki-nftables/index.php/Bridge_filtering

To enable it in OpenWrt you need to install kmod-nft-bridge.

3 Likes

Are you certain that the dumbAP guest wifi guide/setup will solve my issue?

@bluewavenet
I got zero experience with nftables and it was already lucky that I found a post here in the forum with the correct ebtables rules for my issue.
My plan was to flash the DIR860L (Switch + AP) with the current stable OpenWrt Version (23.05.3) but I guess that would mean that I have to apply the bridge filtering via nftables on both devices and I got idea how to do so.

Pretty certain, what is troubling you?

1 Like

Well my Issue isn't that guest client can access anything on my private LAN, the issue is that guest clients can see/access other guest client across my two OpenWrt devices.

Anyway I have a second DIR860L and I'm going to test it now with 23.05.3 and the DumpAP guest Wifi setup. As long as I can still use VLANs for Ethernet clients and everything is isolated in guest network (Ethernet+Wifi) across my two OpenWrt devices I'm a happy user.

I understood that, in Firewall Part 2 you'll add the guest subnet of the other device.

2 Likes

Ok, I configured everything to my best knowledge with my DSA VLAN setup in mind.
Please tell me if this looks alright. I'm using the WAN port as the uplink to my main Router..

Network config:

config interface 'loopback'
	option device 'lo'
	option proto 'static'
	option ipaddr '127.0.0.1'
	option netmask '255.0.0.0'

config globals 'globals'
	option ula_prefix 'fde9:40ae:62da::/48'
	option packet_steering '1'

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'lan1'
	list ports 'wan'

config device
	option name 'lan1'
	option macaddr '**:**:**:**:**:**'

config device
	option name 'lan2'
	option macaddr '**:**:**:**:**:**'

config device
	option name 'lan3'
	option macaddr '**:**:**:**:**:**'

config device
	option name 'lan4'
	option macaddr '**:**:**:**:**:**'

config interface 'lan'
	option device 'br-lan.1'
	option proto 'static'
	option ipaddr '192.168.1.2'
	option netmask '255.255.255.0'
	option delegate '0'
	option gateway '192.168.1.1'
	list dns '192.168.1.1'

config device
	option name 'wan'
	option macaddr '**:**:**:**:**:**'

config device
	option type 'bridge'
	option name 'br-guest'
	option bridge_empty '1'
	list ports 'lan2'
	list ports 'wan'

config interface 'guest'
	option proto 'static'
	option device 'br-guest.3'
	option ipaddr '192.168.55.2'
	option netmask '255.255.255.0'

config bridge-vlan
	option device 'br-lan'
	option vlan '1'
	list ports 'lan1:u*'
	list ports 'wan:t'

config bridge-vlan
	option device 'br-guest'
	option vlan '3'
	list ports 'lan2:u*'
	list ports 'wan:t'

config device
	option type 'bridge'
	option name 'br-psx'
	option bridge_empty '1'
	list ports 'lan3'
	list ports 'lan4'
	list ports 'wan'

config interface 'psx'
	option proto 'static'
	option device 'br-psx.15'
	option ipaddr '192.168.100.2'
	option netmask '255.255.255.0'

config bridge-vlan
	option device 'br-psx'
	option vlan '15'
	list ports 'lan3:u*'
	list ports 'lan4:u*'
	list ports 'wan:t'

Firewall config:

config defaults
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option synflood_protect '1'

config zone
	option name 'lan'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'
	list network 'lan'
	option masq '1'

config zone
	option name 'guest'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	list network 'guest'

config forwarding
	option src 'guest'
	option dest 'lan'

config rule
	option name 'Guest_DHCP'
	list proto 'udp'
	option src 'guest'
	option dest_port '67-68'
	option target 'ACCEPT'

config rule
	option name 'Guest_DNS'
	option src 'guest'
	option dest_port '53'
	option target 'ACCEPT'

config rule
	option name 'Block_Guest_from_LAN'
	list proto 'all'
	option src 'guest'
	option dest 'lan'
	list dest_ip '192.168.1.0/24'
	option target 'REJECT'

config zone
	option name 'psx'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'REJECT'
	list network 'psx'

config forwarding
	option src 'psx'
	option dest 'lan'

config rule
	option name 'PSX_DHCP'
	list proto 'udp'
	option src 'psx'
	option dest_port '67-68'
	option target 'ACCEPT'

config rule
	option name 'PSX_DNS'
	option src 'psx'
	option dest_port '53'
	option target 'ACCEPT'

config rule
	option name 'Block_PSX_from_LAN'
	option src 'psx'
	option dest 'lan'
	list dest_ip '192.168.1.0/24'
	option target 'REJECT'
	list proto 'all'

I'm not sure if the PSX traffic rules are needed but I put them there just in case.

Wireless config:

config wifi-device 'radio0'
	option type 'mac80211'
	option path '1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0'
	option channel '36'
	option band '5g'
	option htmode 'VHT80'
	option country 'DE'
	option cell_density '0'
	option disabled '1'

config wifi-iface 'default_radio0'
	option device 'radio0'
	option network 'lan'
	option mode 'ap'
	option ssid 'OpenWrt-Test'
	option encryption 'psk2+ccmp'
	option key '**'
	option disabled '1'

config wifi-device 'radio1'
	option type 'mac80211'
	option path '1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0'
	option channel '1'
	option band '2g'
	option htmode 'HT20'
	option country 'DE'
	option cell_density '0'
	option disabled '1'

config wifi-iface 'default_radio1'
	option device 'radio1'
	option network 'lan'
	option mode 'ap'
	option ssid 'OpenWrt-Test-2.4'
	option encryption 'psk2+ccmp'
	option key '**'
	option disabled '1'

config wifi-iface 'wifinet2'
	option device 'radio0'
	option mode 'ap'
	option ssid 'OpenWrt-Guest'
	option encryption 'psk2+ccmp'
	option key '**'
	option network 'guest'
	option isolate '1'
	option disabled '1'

config wifi-iface 'wifinet3'
	option device 'radio1'
	option mode 'ap'
	option ssid 'OpenWrt-Guest-2.4'
	option encryption 'psk2+ccmp'
	option key '**'
	option network 'guest'
	option isolate '1'
	option disabled '1'

Well, didn't worked out so far!
I was able to get an IP address and Internet access via OpenWrt-Guest-Test AP and also at LAN (port 2) via br-guest.
Connecting to OpenWrt-Test-2.4 did gave me a valid IP adress (192.168.1.160) but with Gateway 192.168.1.2 and DNS 192.168.1.2 and therefore no Internet access was possible!
I've also tried to access the DIR860L GUI when connected to my main router but I couldn't access the GUI at 192.168.1.2 anymore. Accessing the GUI was only possible while connected to OpenWrt-Test-2.4 AP or via LAN port 1 (br-lan) but ofc with Lan Port 1 Internet access was also not possible.
When the DIR860L was connected to my main router I would also loose access to the Inernet over the Guest Wifi AP on my main router.

I'm lost... :frowning:

Remove the device from guest interface. It should not bridge to the wan interface. The guest interface should terminate on the AP and then forward to the main router with the firewall blocking local connections.

OK thanks, I'll give it a try later.

But what about my Ethernet guest client? I got one connected to LAN-Port 2. Should I create another guest interface for it (e.g. guest-lan) and attach br-guest-lan.3 to it?

No need to create a new one, only to remove the device.

config interface 'guest'
	option proto 'static'
	option ipaddr '192.168.55.2'
	option netmask '255.255.255.0'

Ok. So with the following network and firewall config guest clients via Wifi, PSX clients (Port 3+4) via Ethernet cable and LAN/private clients (Lan Port 1 + Wifi) are able to receive and IP address and browse the internet but my guest client on Lan Port 2 can't receive an IP address and can't surf the net.
What's the issue here?

Network:

config interface 'loopback'
	option device 'lo'
	option proto 'static'
	option ipaddr '127.0.0.1'
	option netmask '255.0.0.0'

config globals 'globals'
	option ula_prefix 'fde9:40ae:98da::/48'
	option packet_steering '1'

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'lan1'
	list ports 'wan'

config device
	option name 'lan1'
	option macaddr ''

config device
	option name 'lan2'
	option macaddr ''

config device
	option name 'lan3'
	option macaddr ''

config device
	option name 'lan4'
	option macaddr ''

config interface 'lan'
	option device 'br-lan.1'
	option proto 'static'
	option ipaddr '192.168.1.2'
	option netmask '255.255.255.0'
	option delegate '0'
	option gateway '192.168.1.1'
	list dns '192.168.1.1'

config device
	option name 'wan'
	option macaddr ''

config device
	option type 'bridge'
	option name 'br-guest'
	option bridge_empty '1'
	list ports 'lan2'
	list ports 'wan'

config interface 'guest'
	option proto 'static'
	option ipaddr '192.168.55.2'
	option netmask '255.255.255.0'

config bridge-vlan
	option device 'br-lan'
	option vlan '1'
	list ports 'lan1'
	list ports 'wan:t'

config bridge-vlan
	option device 'br-guest'
	option vlan '3'
	list ports 'lan2'
	list ports 'wan:t'

config device
	option type 'bridge'
	option name 'br-psx'
	option bridge_empty '1'
	list ports 'lan3'
	list ports 'lan4'
	list ports 'wan'

config interface 'psx'
	option proto 'static'
	option device 'br-psx.15'
	option ipaddr '192.168.100.2'
	option netmask '255.255.255.0'

config bridge-vlan
	option device 'br-psx'
	option vlan '15'
	list ports 'lan3'
	list ports 'lan4'
	list ports 'wan:t'

Firewall:

config defaults
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option synflood_protect '1'

config zone
	option name 'lan'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'REJECT'
	list network 'lan'
	option masq '1'

config zone
	option name 'guest'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	list network 'guest'

config forwarding
	option src 'guest'
	option dest 'lan'

config rule
	option name 'Guest_DHCP'
	list proto 'udp'
	option src 'guest'
	option dest_port '67-68'
	option target 'ACCEPT'

config rule
	option name 'Guest_DNS'
	option src 'guest'
	option dest_port '53'
	option target 'ACCEPT'

config rule
	option name 'Block_Guest_from_LAN'
	list proto 'all'
	option src 'guest'
	option dest 'lan'
	list dest_ip '192.168.1.0/24'
	option target 'REJECT'

config zone
	option name 'psx'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	list network 'psx'

config forwarding
	option src 'psx'
	option dest 'lan'

config rule
	option name 'PSX_DHCP'
	list proto 'udp'
	option src 'psx'
	option dest_port '67-68'
	option target 'ACCEPT'

config rule
	option name 'PSX_DNS'
	option src 'psx'
	option dest_port '53'
	option target 'ACCEPT'

config rule
	option name 'Block_PSX_from_LAN'
	option src 'psx'
	option dest 'lan'
	list dest_ip '192.168.1.0/24'
	option target 'REJECT'
	list proto 'all'

I didn't get that there is some wired device that must be in an isolated vlan. Add the vlan3 in a new interface with access only to wan excluding local networks (like you blocked on the firewall the guest).

That makes sense, thanks.

Another issue is that clients that are connected to PSX will receive the gateway 192.168.100.2 which breaks my UPNP setup for consoles which is limited to the PSX interface on my main router (miniupnd option internal_iface 'psx'). The same is also valid for guest clients that are connected to my DIR860L.
On top I also think this kind of setup for PSX and GUEST on my DIR860L will compromise my SQM setup with the Qdisc options "nat dual-dsthost" and nat dual-srchost on my GL-MT6000 (main router) as it does not see my consoles and guest clients that are connected to the DIR860L as individual devices anymore.

It's all a big mess for me at the moment and I wish I could just use my old ebtables rules again as the isolation of my guest clients across two my two OpenWrt devices just worked fine with them!

You can always try to do it with nftables rules, which we suggested above.

Try this script to get started:

#!/bin/sh
#

br_iface="br-guest"


isolate_guests() {
	# Check if the ruleset already exists
	table_ruleset=$(nft -a list table bridge guests 2> /dev/null)

	if [ "$?" -gt 0 ]; then
		# no rulset so create our table and chain
		# Create the table
		nft add table bridge guests
		# Create the chain, giving it higher priority than other things eg fw4
		nft add chain bridge guests guests_PRE { type filter hook prerouting priority -350\; }
	fi

	# count the rules
	rulecount=$(nft -a list table bridge guests 2> /dev/null | grep -w -c "$br_iface" | awk '{printf "%s", $1}')

	if [ "$rulecount" -eq 0 ]; then
		# no rules so create what we need
		rule_status=$(nft add rule bridge guests guests_PRE meta iifname { $br_iface } counter drop comment "\"Guest Isolation\""; echo -n $?)
	fi

}

isolate_guests

Check to see if the ruleset was added:
nft list table bridge guests

I think this will be the equivalent to:
ebtables -A FORWARD --logical-in br-guest -j DROP # Client Isolation [GUEST]

Edit: fixed bad cut and paste from another script.

1 Like

Thank you! I'll give it a try but br-guest doesn't exist anymore with my current DSA setup on my main router. It was replaced with br-lan.3

Will this script still work if I replace br-guest with br-lan.3? I guess that I need to install kmod-nft-bridge for this but I don't know where to put this script and where to execute it.

#!/bin/sh
#

br_iface="br-lan.3"


isolate_guests() {
	# Check if the ruleset already exists
	table_ruleset=$(nft -a list table bridge guests 2> /dev/null)

	if [ "$?" -gt 0 ]; then
		# no rulset so create our table and chain
		# Create the table
		nft add table bridge guests
		# Create the chain, giving it higher priority than other things eg fw4
		nft add chain bridge guests guests_PRE { type filter hook prerouting priority -350\; }
	fi

	# count the rules
	rulecount=$(nft -a list table bridge guests 2> /dev/null | grep -w -c "$br_iface" | awk '{printf "%s", $1}')

	if [ "$rulecount" -eq 0 ]; then
		# no rules so create what we need
		rule_status=$(nft add rule bridge guests guests_PRE meta iifname { $br_iface } counter drop comment "\"Guest Isolation\""; echo -n $?)
	fi

}

isolate_guests