Apple Airplay über Subnetze hinweg ermöglichen (OpenWRT)

Ähnlich wie DLNA ist auch Apple Airplay nicht unbedingt für den Betrieb außerhalb eines einzigen Subnets ausgelegt. Mit ein paar Kniffen funktioniert es trotzdem …

mDNS: Basis vieler Heimnetzwerk-Dienste

Zunächst ist wichtig zu verstehen, dass Apple Airplay auf einer Sammlung von Standards und Protokollen aufbaut. Es genügt nicht den einen “Airplay-Port” in der Firewall durchzureichen und zu hoffen, dass alles funktioniert. Damit sich Airplay-Geräte in einem Netzwerk überhaupt gegenseitig finden können, wird das Multicast-DNS (auch mDNS) zur sog. Service Discovery eingesetzt. Dabei handelt es sich um nichts anderes als einen lokalen, dezentralen Verzeichnisdienst. Anders als beim herkömmlichen DNS gibt es also keine zentrale Serverinstanz, die sämtliche verfügbare Services und die zugehörigen Adressen vorhält. Durch regelmäßiges Bekanntgeben der selbst angebotenen Dienste via Broadcast / Multicast werden alle anderen Netzteilnehmer darüber in Kenntnis gesetzt, dass ein Service eines gewissen Typs unter einer bestimmten Adresse verfügbar ist.

Über das avahi-browse Tool können zum Beispiel folgende Einträge im eigenen Netzsegment abgerufen werden:

[thomas@thomas-nb]~% avahi-browse -a
+ wlp58s0 IPv6 [LG] webOS TV UK6470PLC                       _airplay._tcp        local
+ wlp58s0 IPv4 [LG] webOS TV UK6470PLC                       _airplay._tcp        local
+ wlp58s0 IPv6 LG webOS TV 8A66                              _hap._tcp            local
+ wlp58s0 IPv4 LG webOS TV 8A66                              _hap._tcp            local
+ wlp58s0 IPv6 Philips Hue - <id>                            _hue._tcp            local
+ wlp58s0 IPv4 Philips Hue - <id>                            _hue._tcp            local
+ wlp58s0 IPv4 turris                                        _ssh._tcp            local
+ wlp58s0 IPv4 Chromecast-Ultra-<id>                         _googlecast._tcp     local
+ wlp58s0 IPv6 turris-2                                      _http._tcp           local
+ wlp58s0 IPv6 EPSON ET-2650 Series-<id>                     _http._tcp           local
+ wlp58s0 IPv6 <id>                                          _teamviewer._tcp     local
+ wlp58s0 IPv6 EPSON ET-2650 Series-<id>                     _printer._tcp        local
+ wlp58s0 IPv6 EPSON ET-2650 Series-<id>                     _ipps._tcp           local
+ wlp58s0 IPv4 RX-V777 <id>                                  _http._tcp           local
+ wlp58s0 IPv4 eDMP32MB_<id>                                 _spotify-connect._tcp local
+ wlp58s0 IPv4 <id>@RX-V777 <id>                             _raop._tcp           local
+ wlp58s0 IPv4 <id>                                          _fosquitto._tcp      local    
[...]

Wie deutlich zu sehen ist, senden viele Geräte im Heimnetzwerk solche mDNS-Pakete und geben darüber Informationen über ihre Services preis. So informiert mein Drucker zum Beispiel darüber, dass er via IPP angesprochen werden kann. Ein Desktoprechner bewirbt seinen verfügbaren Teamviewer-Server und meine Philips Hue Bridge lässt andere Geräte (z.B. mein Smartphone) wissen, dass sie über ein Philips-spezifisches “hue” Protokoll angesprochen werden kann.

Geräte, die sich nicht im selben Netzsegment befinden, werden an dieser Stelle nicht sichtbar, weil mDNS (wie auch SSDP) standardmäßig nur im selben Subnetz funktioniert. Mein Fernseher und AV-Receiver, die beide Airplay beherrschen, bleiben also verborgen.

In meinem Artikel “DLNA und andere SSDP Dienste über lokale Subnetze hinweg nutzen (OpenWRT)” habe ich bereits einen Weg aufgezeigt, wie sich Multicast-Protokolle auch über verschiedene Subnetze hinweg nutzen lassen. Prinzipiell wäre es auch möglich, dasselbe für mDNS umzusetzen. Statt des SSDP-Multicast-Bereichs müsste dann der mDNS-Adressbereich im Router konfiguriert werden.

Für Airplay bzw. mDNS habe ich aber etwas anderes ausprobiert: Einen Avahi-Reflector!

Avahi (-Reflektor)

Auf meinem Router - einem Turris Omnia 2020 mit OpenWRT - befindet sich bereits der Avahi-Daemon. Avahi ist ein Daemon, der via mDNS im lokalen Netz verkündet, welche Services ein Gerät anbietet. Auf meinem Omnia kündigt Avahi beispielsweise SSH auf Port 22 und die Weboberfläche auf Port 80 an.

Praktischerweise kann Avahi mDNS-Einträge von einem Subnetz / Interface auslesen und dann in ein anderes Subnetz replizieren (oder auch “reflektieren”). Korrekt konfiguriert werden angekündigte Services aus Netz A also auch im Netz B und C angekündigt. Die dafür notwendige Konfiguration sieht in meinem Fall so aus:

(/etc/avahi/avahi-daemon.conf)

[server]
host-name=turris
domain-name=local
use-ipv4=yes
use-ipv6=yes
check-response-ttl=no
use-iff-running=no
allow-interfaces=br-lan,br-SRV,br-IOT

[publish]
publish-addresses=yes
publish-hinfo=yes
publish-workstation=no
publish-domain=yes
publish-aaaa-on-ipv4=no
publish-a-on-ipv6=no

[reflector]
enable-reflector=yes
reflect-ipv=no

[rlimits]
rlimit-core=0
rlimit-data=4194304
rlimit-fsize=0
rlimit-nofile=30
rlimit-stack=4194304
rlimit-nproc=3

Bedeutend sind vor allem die Zeilen unter [reflector] und allow-interfaces. Hinter den Interfaces befinden sich Bridged für meine Subnetze für LAN, Server und IoT Geräte. enable-reflector=yes sorgt schließlich für das Spiegeln der Einträge zwischen den Netzen.

Nach einem Serviceneustart sollte das Airplay-Gerät auf den anderen Clients zumindest schon einmal über das avahi-browse Tool sichtbar sein.

Firewall-Konfiguration

Die Firewall zwischen meinen Subnetzen ist relativ restriktiv, sodass meine Arbeit hier noch nicht erledigt ist. Airplay benötigt noch einige Freischaltungen, damit es korrekt funktioniert.

In meinem Szenario sollen nur Geräte aus dem LAN (br-lan) Inhalte an meinen AV-Receiver (br-IOT) mit Airplay senden können. Folgende Konfiguration habe ich hierzu in /etc/config/firewall hinterlegt:

config rule
    option dest_port '80'
    list proto 'tcp'
    option name 'allow_iot_yamaha_lan_ipad_airplay_http'
    option dest 'lan'
    option target 'ACCEPT'
    option src 'iot'

config rule
    option dest_port '443'
    list proto 'tcp'
    option name 'allow_iot_yamaha_lan_ipad_airplay_https'
    option dest 'lan'
    option target 'ACCEPT'
    option src 'iot'

config rule
    option dest_port '554'
    option src 'iot'
    option name 'allow_iot_yamaha_lan_ipad_airplay_rtsp'
    option dest 'lan'
    option target 'ACCEPT'

config rule
    option dest_port '3689'
    option dest 'lan'
    option target 'ACCEPT'
    option src 'iot'
    option name 'allow_iot_yamaha_lan_ipad_airplay_daap'
    list proto 'tcp'

config rule
    option dest_port '49152-65535'
    option src 'iot'
    option name 'allow_iot_lan_airplay_dynamic'
    option dest 'lan'
    option target 'ACCEPT'

Die Firewallregeln lassen Geräte aus dem IoT-Netzsegment auf definierte Resosurcen aus dem LAN-Segment zugreifen, denn beim Aufbau einer Airplay-Verbindung bietet die Streamingquelle (z.B. iPad) auf einem Port die Inhalte an - das Abspielgerät greift dann darauf zu. Die Freigaben müssen also gewissermaßen “umgekehrt” betrachtet werden. Nicht der Port am Abspielgerät wird freigeschaltet, sondern der Port an der Quelle.

Wenn nur bestimmte Geräte miteinander kombinierbar sein sollen, ließen sich die Regeln durch die Angabe von “Source” und “Destination” IP-Adressen noch verschärfen. Ich habe der Einfachheit darauf verzichtet.

Eine Liste der von Airplay verwendeten Ports lässt sich übrigens hier einsehen. Insbesonders die letzte Regel hat mir Kopfschmerzen bereitet, weil sie nicht explizit im Zusammenhang mit “Airplay” aufgelistet ist.