monotux.tech

Chromecast, Home Assistant & different subnets

networking, nftables

I'm using Home Assistant a lot these days to automate things around the house. One of the things that is interesting to know is the current state of my Chromecast devices - so I can turn on or off the stereo amplifier (or lamps in the same room ) if something is playing, for example.

As I try to pretend to have a security posture, I've tried to move IoT devices from my main client subnet. Chromecast devices aren't designed for dorks like me, and they expect to be in the same broadcast domain as the client devices that will control them…so you have to be a bit creative to make it work.

TL;DR

  • You have to allow 1900/udp with destination address 239.255.255.250 from both networks
  • You have to reflect mDNS between the networks (which means more ports)
  • Update: you need to enable 8008-8009/tcp as well

Ports

I'm using nftables but you should get the idea:

  # This is obviously not a complete example...

  define homeassistant_if = eth0
  define chromecast_if = eth1
  define homeassistant_host = 192.168.0.2

  chain firewall_out {
    type filter hook output priority 100; policy drop;
    # ...
    oifname $chromecast_if udp dport 5353 ip daddr 244.0.0.251 ct state new accept
    oifname $homeassistant_if udp dport 5353 ip daddr 244.0.0.251 ct state new accept
  }

  chain firewall_in {
    type filter hook input priority 0; policy drop;
    # ...
    iifname $chromecast_if udp dport 5353 ip daddr 244.0.0.251 ct state new accept
    iifname $homeassistant_if udp dport 5353 ip daddr 244.0.0.251 ct state new accept
  }

  chain chromecast_forwarding {
    type filter hook forward priority 0; policy drop;
    tcp dport { 8008, 8009 } ip saddr $homeassistant_host ct state new accept
  }

  chain chromecast_out {
    type filter hook forward priority 0; policy drop;
    # mdns
    udp dport 5353 ip daddr 224.0.0.251 ct state new accept
  }

  chain homeassistant_out {
    type filter hook forward priority 0; policy drop;
    # ssdp
    udp dport 1900 ip daddr 239.255.255.250 ct state new accept

    # mdns
    udp dport 5353 ip daddr 224.0.0.251 ct state new accept
  }

Update: The scary part here is that I have no idea why it's enough to just enable 8008-8009/tcp in the forwarding chain for the chromecast network..? I should really try to understand why that works…

mDNS

This is fairly simple as well, install and enable avahi on your machine, do some basic configuration:

  # /etc/avahi/avahi-daemon.conf - but just the important changes
  [server]
  allow-interfaces=chromecast_if,homeassistant_if
  [reflector]
  enable-reflector=yes

Testing

I setup a FreeBSD jail1 in each subnet and installed avahi-app on both. You can either use the nss_mdns adapter (and then host(1) or ping(8)) or avahi-browse to test it. I've only had partial success with the nsswitch.conf changes so I got lazy and just used avahi-app (rather that reading the manual).

  # pkg install nss_mdns

  # /etc/nsswitch.conf
  # Add mdns to the end of the hosts line, like this:
  hosts: files dns mdns

  # or, if that doesn't work:
  # pkg install avahi-app
  # service dbus enable
  # service dbus start
  # service avahi-daemon enable
  # service avahi-daemon start
  # avahi-browse -a --ignore-local --terminate

If you can use ping to resolve .local addresses, you should be fine. If the system configuration doesn't like using mdns, try avahi-browse instead and see if you list non-local hosts with it. It should return a list that looks something like this:

  # avahi-browse -a --ignore-local --terminate
  + epair0b IPv4 testwifi                                      _ssh._tcp            local
  + epair0b IPv4 testwifi                                      _sftp-ssh._tcp       local
  + epair0b IPv4 CCCC12312312@Audio+                           _raop._tcp           local
  + epair0b IPv4 CCCC23423423@SHIELD+                          _raop._tcp           local
  + epair0b IPv4 googlerpc                                     _googlerpc._tcp      local
  + epair0b IPv4 Chromecast-Audio-$uuid                        _googlecast._tcp     local
  + epair0b IPv4 SHIELD-Android-TV-$uuid                       _googlecast._tcp     local
  + epair0b IPv4 SHIELD                                        _nv_shield_remote._tcp local
  + epair0b IPv4 SHIELD                                        _androidtvremote2._tcp local
  + epair0b IPv4 $uuid                                         _googlezone._tcp     local
  + epair0b IPv4 Homeassistant-instance-name                   _home-assistant._tcp local
  + epair0b IPv4 HASS Bridge xyzyxzyxz                         _hap._tcp            local
  + epair0b IPv4 homeassistant [longstring]                    _workstation._tcp    local
  + epair0b IPv4 router [00:ma:ca:dd:r]                        _workstation._tcp    local

Conclusions

This Works For Me™ and might help someone else. I can now poll and control my Chromecast devices from my Home Assistant installation.

Footnotes


1

as my FreeBSD machine handles DHCP for both subnets both vlans were easily accessible on that machine already. It was also the easiest way I could think off