Using multicast-relay to do SSDP relaying for Roku, Sonos, Tivo discovery
Firewalla Gold doesn't natively support SSDP relaying for discovering Roku, Sonos, Tivo and other related devices between different subnets. I found that the following utility works to add this relaying capability.
https://github.com/alsmith/multicast-relay
I have put all the information needed in this initial post but it is the culmination of very useful discussion and inputs from the comments in this discussion thread.
Listing your network interfaces: The examples I provide here use the interfaces "br0 br1" but this is network specific and you will need to provide the interfaces for relaying that work for your network configuration.
Thanks to Michael Bierman for suggesting the following command which allows you to list your available network interfaces.
ip -4 -j address | jq -r '.[] | "index: \(.ifindex), interface: \(.ifname), local: \(.addr_info[].local)"'
Non-Docker method: This directly runs the Python utility which performs the multicast broadcasting. Note that it needs the Python netifaces package to be installed first. You would also need to put this into a cronjob to have it rerun automatically on reboot.
# Download the utility from GitHub
git clone https://github.com/alsmith/multicast-relay
cd multicast-relay
sudo pip install netifaces
# Relay Sonos and SSDP messages between Firewalla ethernet ports 1 & 2
# Skip relaying mDNS which is already supported
sudo multicast-relay.py --interfaces br0 br1 --noMDNS
Docker method: Here's how to do this using a Docker container. With this method there is no need to manually download anything and this will automatically run on reboot as well.
This is using https://github.com/scyto/multicast-relay as a Docker front-end to https://github.com/alsmith/multicast-relay
# Create the ssdp-relay container the first time and run it
sudo docker run --detach --restart=always --name ssdp-relay --network=host -e OPTS="--noMDNS" -e INTERFACES="br0 br1" scyto/multicast-relay
# Stop the SSDP relaying
sudo docker stop ssdp-relay
# Restart the SSDP relaying
sudo docker start ssdp-relay
# Remove the ssdp-relay container (if you want to reconfigure it)
sudo docker rm -f ssdp-relay
Note about Samsung TVs: mDNS and SSDP relaying are not enough for Samsung TV discovery because Samsung TVs apparently are restricted to communicating only on the same subnet. Some people have had success with running a proxy server on the same subnet as the TV as a workaround for this. Clients communicate with the TV via the proxy server. (See https://realmenweardress.es/2022/04/vlans-and-samsung-tvs & https://github.com/home-assistant/core/issues/35049#issuecomment-893194912)
-
The docker container would need access to the interfaces on the Firewalla over which you wanted to relay SSDP messages. I don't know if that's possible right now (or ever) on the Firewalla.
There's a feature request for more flexible docker networking options.
-
@Michael Thanks for the pointer! I'll take a look at it. Even github.com/alsmith/multicast-relay already provides a Docker file but I'm very new to using Dockers so I will need time to study it.
@David Thanks for pointing out the interface permissions issue! Maybe someone with more advanced FWG Docker experience can try to get this working.
In the meantime, this utility might be simple enough to run directly on FWG without a Docker container. Once you download it somewhere, it runs as a single Python process to do the relaying. It would just need to be added to the startup cronjobs.
-
Ok I got it working with https://github.com/scyto/multicast-relay !
This is my first time using Docker containers so I'm pretty happy about having success with this!
# Create the ssdp-relay container the first time
sudo docker run --detach --restart=always --name ssdp-relay --network=host -e OPTS="--noMDNS" -e INTERFACES="br0 br1" scyto/multicast-relay
# Stop the SSDP relaying
sudo docker stop ssdp-relay
# Restart the SSDP relaying
sudo docker start ssdp-relay
# Remove the ssdp-relay container (if you want to reconfigure it)
sudo docker container rm -f ssdp-relay -
Thanks Michael!
I found that it also works for a Guest network if you create an allow rule between the Guest network and the specific device like a Roku. You do need to reserve static IP addresses for those AV devices for the rule.
Hopefully this helps out some folks who were putting all their AV devices on the same subnet as their casting devices because of this limitation.
-
@alak and others in the future, this will tell you the available interfaces on your firewalla
ip -4 -j address | jq -r '.[] | "index: \(.ifindex), interface: \(.ifname), local: \(.addr_info[].local)"'
Not quite sure what you mean by the Guest network. That seems like it will depend if the Guest network is part of an AP like eero or just another VLAN. What kind of set up did you test it on?
-
In my case, the guest network is a VLAN with Firewalla guest network template rules (block traffic to all local networks, block traffic from internet) on a WAP connected to one of the listed interfaces (br1) given to multi-cast relay. The actual interface of the VLAN is different from br1 but that doesn't seem to matter. Relaying it to br1 covers all VLANS connected to this interface. This is not an issue though because guest networks can't discover devices on other subnets without a rule overriding the block rule that prevents traffic to local networks.
If the WAP has a guest network feature preventing all local traffic, it needs to be turned off to allow device discovery and media casting. You also need an allow override rule allowing guest network to reach your specific AV device on a non-guest subnet.
-
Thanks, @Alak. That still appears as an interface so I would have assumed it would be no different. For example ,here are before and after when I added a Guest network to my Purple.
pi@Firewalla:~ (Purple) $ ip -4 -j address | jq -r '.[] |"index: \(.ifindex), interface: \(.ifname), local: \(.addr_info[].local)"'
index: 1, interface: lo, local: 127.0.0.1
index: 2, interface: eth0, local: 192.168.177.2
index: 9, interface: br-83eef645874c, local: 172.16.0.1
index: 10, interface: docker0, local: 172.17.0.1
index: 11, interface: br-08065b5411e2, local: 172.16.1.1
index: 17, interface: wg0, local: 10.189.10.1
index: 20, interface: br0, local: 10.11.227.1
pi@Firewalla:~ (Purple) $ ip -4 -j address | jq -r '.[] | "index: \(.ifindex), interface: \(.ifname), local: \(.addr_info[].local)"'
index: 1, interface: lo, local: 127.0.0.1
index: 2, interface: eth0, local: 192.168.177.2
index: 9, interface: br-83eef645874c, local: 172.16.0.1
index: 10, interface: docker0, local: 172.17.0.1
index: 11, interface: br-08065b5411e2, local: 172.16.1.1
index: 17, interface: wg0, local: 10.189.10.1
index: 20, interface: br0, local: 10.11.227.1
index: 21, interface: br1, local: 192.168.118.1 -
@Michael - I have something like the following on my network
interface: eth2.40, local: 192.168.40.1 (guest VLAN 40 on WAP on FWG LAN port 2)
interface: br1, local: 192.168.2.1 (FWG LAN port 2)
interface: br0, local: 192.168.1.1 (FWG LAN port 1)WAP is on br1 but also creates a guest VLAN 40 which is eth2.40. When I relay SSDP between br0 and br1, it also works for the guest VLAN 40 on interface eth2.40 without the need to explicitly add it.
Consequently FWG users should simply be able to set the relay interfaces to "br0 br1 br2" in order to relay everything across all LAN subnets since everything ultimately connects through those interfaces. That is my humble observation anyway.
-
Consequently FWG users should simply be able to set the relay interfaces to "br0 br1 br2" in order to relay everything across all LAN subnets since everything ultimately connects through those interfaces. That is my humble observation anyway.
This will depend on your configuration. For example, on my FWG, I only have a "docker0" bridge. I do not have br0, br1, or br2.
For reference, I have three of the FWG's ports combined into a LAG that is connected to my switch. So for me, the interface names are things like "bond0.20" and "bond0.70".
-
@alak, @David,
Agreed, I'm sure there are people who know what the bare minimum requirements are for what interfaces need to be included with the many possible interface configurations LAG, Bridges, VLANs, etc. I am unfortunately not knowledgable enough right now to be certain. If I did, I would probably write another "installer" like I did for pi-hole and homebridge to make this trivial and walk people through answering a few questions and, "BOOM!" they would be in business.
The command I posted earlier should be enough to allow some painless experimentation though and get people going. I think that's the best I can do at the moment. Most people probably don't have that many interfaces and can figure it out by trial and error.
Also, I can't test any of this because I don't currently have any Sonos equipment. Always open to donations so I can test things though. ;) -
I don't have Sonos equipment, but this did solve the problems I was having discovering Rokus. It also solved a problem discovering a Yamaha receiver.
So, thanks very much, @alak!
The only AV device I can't get to work in a subnet is a Libratone Zipp Mini speaker. I really wish I could move that device, too, since it communicates with China a lot, but oh, well.
-
@Michael, @David
Thanks for setting me straight on the variety of configurations and interface definitions out there!
@Michael, your utility should help people discover their interface names. I can add it to my original post text if you're ok with it.
@David You're my first Beta tester! Glad it works! It does seem to have the ability to relay for other multicast ports as well if you can find out what Zipp Mini speaker is using for discovery. It might work if it is simple multicast. Unfortunately there are devices like Samsung TVs that only allow communication on the same subnet. That's a device limitation and some people have worked around it by running a proxy server to relay the communication with those devices. I've got that problem as well but I won't dive into that rat hole for now.
-
@Alak, thank you very much for the wonderful guide. I also wanted to do a quick follow up for those who likes/prefers docker-compose for containers. IMO, it makes it easy to start/stop containers, and make config changes easier.
Create a docker-compose.yaml (i created it under /data/docker-manifest directory) file with the following:
---
version: "3.9"
services:
ssdp-relay:
image: scyto/multicast-relay:latest
container_name: ssdp-relay
environment:
- INTERFACES=eth1.11 eth1.13 <----- Left here for example, use your network interfaces discovered from earlier step
- OPTS=--noMDNS
- TZ=America/New_York <---- Change this for your time zone
network_mode: host
deploy:
restart_policy:
condition: any
resources:
limits:
cpus: '0.15'
memory: 16M
logging:
options:
max-size: "250k"Couple things to note here:
- When you are running containers, always set a CPU and Memory resource limits. I ran the application for a few hours and profiled based on how much it used. You may need more depending on how many interfaces you have configured. Use sudo docker stats command to discover current usage.
- This specific container does not generate logs, but it's a good idea to limit how much space it can consume.
If you would like to automatically update the container image(s), you can use watchtower container. Here is a blurb you can add to the same docker-compose.yaml file:
watchtower:
container_name: watchtower
image: containrrr/watchtower
read_only: true
environment:
WATCHTOWER_DEBUG: 'true'
TZ: 'America/New_York'
WATCHTOWER_CLEANUP: 'true'
WATCHTOWER_INCLUDE_RESTARTING: 'true'
WATCHTOWER_SCHEDULE: '0 0 0 * * *'
WATCHTOWER_ROLLING_RESTART: 'true'
WATCHTOWER_TIMEOUT: '60s'
volumes:
- /var/run/docker.sock:/var/run/docker.sock
networks:
- fwg <--- Extra steps needed
deploy:
restart_policy:
condition: any
resources:
limits:
cpus: '0.25'
memory: 64M
logging:
options:
max-size: "250k"watchtower container will need to be able to access internet (so that it can check container images from image repositories). In my container above, I've created a docker network called fwg with the following:
sudo docker network create --driver=bridge --subnet=172.30.0.0/26 --gateway=172.30.0.1 --attachable fwg
Then created a route, so containers attached to that network can access internet:
$ sudo docker network ls | grep fwg
grab the ID
$ sudo ip route add 172.30.0.0/26 dev br-(ID FROM EARLIER) table wan_routableOnly attach containers that need to access internet to fwg docker network (or whatever you decide to name).
Once you have the file created, use sudo docker-compose up -d command to start your containers listed in docker-compose.yaml file. You can use sudo docker-compose down stop containers.
Please sign in to leave a comment.
Comments
18 comments