Skip to content

Instantly share code, notes, and snippets.

@plmcgrn
Last active July 12, 2024 15:58
Show Gist options
  • Save plmcgrn/eead9fbe125a9464e673ef91ed688d95 to your computer and use it in GitHub Desktop.
Save plmcgrn/eead9fbe125a9464e673ef91ed688d95 to your computer and use it in GitHub Desktop.
Unifi UDM and Sonos home theater with multiple VLAN's

Overview

This goal of this setup is to put the Sonos speakers on an untrusted network to keep all but the required traffic away from the trusted network where devices like personal computers, phones, etc. live. This write-up assumes you already have two networks setup and working.

Important Note on Unifi OS 3.x

UI broke cross-VLAN multicast DNS in this version. See below for steps to install the multicast-relay script to re-enable this. Without it, your Sonos controller app will not be able to discover your speakers on the other VLAN.

System

I have a Sonos Playbar, Sub, and 2 Play:3's as rear surrounds as one home theater setup connected to a UDM (non-Pro, but this should work on Pro too). Some of this setup may be easier for people with non-paired speakers, as Sonos does some shenanigans with which speaker is actively sending traffic to your wifi.

Networks

MAIN network: Personal computers, phones, tablets, and trusted devices IOT network: Untrusted devices like smart plugs, smart thermostats, and the Sonos gear

Prep

In order to get everything ready, we'll prep the entire non-firewall configuration first.

If you have a Sonos home theater setup, you'll need to create DHCP reservations/fixed IP's for every device in the setup. Sonos seems to let the other speakers in a system actively impersonate the "main" speaker, and the result is the firewall blocking that traffic if you don't explicity allow every speaker's IP.

  1. In the Sonos controller app, go to Settings (gear) > System > About My System Note each MAC address and which speaker it corresponds to.
  2. In UDM > Network > Client Devices, find your existing Sonos speaker. This is the "current" main, but may not be the "actual" main as you see it, but that's not important. Click it, go to Settings, and assign a Fixed IP. For convenience, I left this one as the IP it currently had, and just added my other speakers for fixed IP's adjacent to it.
  3. Click the Add Device button on the top right of Client Devices, and use this to add each of the other speakers by MAC address, assigning IP's as desired.

Now that those are added, you can create the Profiles (IP and Port Groups) to cover the traffic classifications in the UDM firewall.

Create Profiles

Go to Network > Settings > Profiles > IP Groups

Here's you'll create IP address and port groups

Name Type Value(s)
MULTICAST Address Group 224.0.0.0/24
SONOS-SPEAKERS Address Group ALl the IP's you reserved earlier for your speakers
MAIN-SUBNET Address Group Your main network, default is 192.168.1.0/24
IOT-SUBNET Address Group Your IOT network, mine is 192.168.3.0/24 in this build
SONOS-SPEAKERS-TCP Port group 1400, 3400-3401, 3500, 4444, 1443
SONOS-SPEAKERS-UDP Port group 1900-1901, 6969, 30000-60000

Verify Multicast DNS

In UDM > Networks, ensure that Multicast DNS is enabled. You can do this on each individual network, or just use the global setting and add both IOT and MAIN to it, if not already there by default.

Firewall Rules

That's it for the prep, now we can create the firewall rules in Network > Firewall & Security. These rules are all in the LAN IN category.

ALLOW-MULTICAST

In my network, I'm OK with all multicast being cross-network. The firewall will prevent anything undesired. Example, my printer was "discoverable" by the IOT network, even though it's on the main network, but nothing in IOT can actually connect back to it due to a firewall drop rule created further down.

Field Value
Rule Applied Applied before pre-defined rules
Action Accept
IPv4 Protocol All Protocols
Source Type IP/Port Group
Source IPv4 Address Group Any
Source Port Group Any
Destination IPv4 Address Group MULTICAST
Destination IPv4 Port Group Any

LAN-ALLOW-ESTABLISHED

This allows for TCP connections to work without "reverse" firewall rules for the return traffic. In my network, I allow anything in the main VLAN to attempt communications with the IOT VLAN (inboudn to IOT from Main). The drop rule will weed out any unexpected IOT -> Main traffic that isn't initiated from Main.

Field Value
Rule Applied Before pre-defined rules
Action Accept
IPv4 Protocol All Protocols
Source IPv4 Address Group Any
Source Port Group Any
Destination IPv4 Address Group Any
Destination Port Group Any

Under Advanced, enable the Match State Established and Match State Related checkboxes (IMPORTANT, otherwise this rule is an allow any/any for all traffic).

SONOS-CONTROLLER-UDP

Field Value
Rule Applied Before pre-defined rules
Source Type Port/IP Group
Source IPv4 Address Group SONOS-SPEAKERS
Source Port Group SONOS-CONTROLLER-UDP
Destination Type Port/IP Group
Destination IPv4 Address Group MAIN-SUBNET
Destination Port Group Any

Under Advanced, I have all the Match State checkboxes enabled. This is a relatively safe rule since it's scoped only to the Sonos IP address group.

SONOS-CONTROLLER-TCP

Field Value
Rule Applied Before pre-defined rules
Source Type Port/IP Group
Source IPv4 Address Group SONOS-SPEAKERS
Source Port Group SONOS-CONTROLLER-TCP
Destination Type Port/IP Group
Destination IPv4 Address Group MAIN-SUBNET
Destination Port Group Any

Under Advanced, I have all the Match State checkboxes enabled. This is a relatively safe rule since it's scoped only to the Sonos IP address group.

BLOCK-IOT-TO-MAIN

Field Value
Source Type Port/IP Group
Source IPv4 Address Group IOT-SUBNET
Source Port Group Any
Destination IPv4 Address Group MAIN-SUBNET
Destination IPv4 Port Group Any

This rule drops any traffic that is directed from IOT to MAIN that is not explicitly from the Sonos speakers on their defined ports.

Verification

That's it for configuration. You'll want to verify:

  1. Sonos controller on MAIN subnet can see the system. If not, this could either be the firewall rules or mDNS, verify both. See the important update below on mDNS
  2. Sonos controller can play music and updates what is playing on-screen. I had issues with the app when switching my phone between wifi networks, so ensure that when you start the app, you're already connected to the MAIN network.
  3. Devices on IOT network cannot communicate with anything on MAIN network. You can enable the DROP firewall rule for Logging, and go to System Log > Triggers, to see if any traffic attempts are actually dropped.

UI broke cross-VLAN multicast DNS in some version after 3.x, though I'm not sure which specific build. These steps will install the multicast-relay script to re-enable this. Without it, your Sonos controller app will not be able to discover your speakers on the other VLAN, whereas if your controller and speakers are on the same VLAN (you connect your phone to the IOT network) the controller will work normally.

SSH into UDM

mkdir /data/custom/multicast-relay cd /data/custom/multicast-relay wget https://raw.githubusercontent.com/alsmith/multicast-relay/master/multicast-relay.py chmod +x ./multicast-relay.py

Test it (br0 is the default network, and in this example, br3 is my IOT network) /usr/bin/python3 /data/custom/multicast-relay/multicast-relay.py --interfaces br0 br3

Sonos contorller should now see your speakers

Set it as an on-boot script

This uses the UDM Utility "On-Boot-Script" which allows for custom scripts to run init.d style curl -fsL "https://raw.githubusercontent.com/unifi-utilities/unifios-utilities/HEAD/on-boot-script/remote_install.sh" | /bin/sh

cd /data/on_boot.d

Create a new script

vi 10-multicast-relay.sh

Add the content and !wq to save it

#!/bin/sh /usr/bin/python3 /data/custom/multicast-relay/multicast-relay.py --interfaces br0 br20 br30

Make it executable

chmod +x 10-multicast-relay.sh

It'll now run on next boot, or you can just execute it manually (make sure to use the correct VLAN number(s) for your networks

/usr/bin/python3 /data/custom/multicast-relay/multicast-relay.py --interfaces br0 b3

@jeffreyb5478
Copy link

jeffreyb5478 commented Feb 6, 2024

Solved! Once the startup script was seperated over two lines it starts to work! Thank you for your support!

@plmcgrn
Copy link
Author

plmcgrn commented Feb 6, 2024

Solved! Once the startup script was seperated over two lines it starts to work! Thank you for your support!

Unsure. Maybe the on_boot stuff needs it, or one of its dependencies does.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment