Spotify connect to sonos over different subnets and a firewall

We have some nice Sonos speaker in our network. Of course we devided our network in private and guest. Guest just have acces to the internet.

Sometimes we want our guests to be able to choose the music. In the past they used a tablet for this but they had no access to their own playlists.

Since some weeks Spotify connect is able to control Sonos speaker to play music on them. So why not allow devices from guest-LAN to acces Sonos speaker to control them via Spotify connect?

Our setup: We have a linux box with iptables as a gateway between these two subnets (seperated by VLANs).

Spotify connect uses mDNS for discovery so I sat up the avahi deamon and enabled two options in the configuration.

apt-get install avahi-daemon
[server]
allow-point-to-point=yes

[reflector]
enable-reflector=yes

Also you need a tiny hole in your firewall. The first rule is to allow the access to the mDNS daemon. The other rules are one per Sonos device you want to allow acces to. We have „private“ Sonos devices we don’t want to share so we have not allowed all of them.

/sbin/iptables -A INPUT -p udp --dport 5353 -j ACCEPT -m comment --comment "mDNS for Spotify"
/sbin/iptables -I FORWARD --destination 192.168.X.Y -p tcp --dport 1400 -j ACCEPT -m comment --comment "Spotify to Sonos Wohnzimmer"
/sbin/iptables -I FORWARD --destination 192.168.X.Z -p tcp --dport 1400 -j ACCEPT -m comment --comment "Spotify to Sonos Kueche"

Spotify uses the local network just for gaining control – all the control itself is made via internet.

Diskless Media Center mit XBMC

Diskless Media Center (XBMC) mit iSCSI und PXE

xbmc
XBMC ist eine Anwendung, die unter anderem auf Linux läuft und sämtliche Medienformate über sämtliche Netzwerkprotokolle abspielen kann. Da es ein reiner Player sein soll und sämtliche Daten auf dem Fileserver liegen, braucht die Kiste auch keine Festplatte. Hier erkläre ich kurz die Schritte, die ich benötigt und zusammengesucht habe, um die XBMC-Installation über iSCSI auf den Fileserver zu legen und über das Netzwerk zu booten.

Ausgangslage

  • Fileserver
    • OS: Ubuntu 10.04.3 LTS
    • Name: marvin.home
    • Stellt bereit: TFTP, iSCSI
  • XBMC-PC
    • OS: XBMC Live 10.1 (basiert auf Ubuntu 10.04.2 LTS)
    • Name: htpc.home
  • Fritzbox
    • FW: Freetz
    • Stellt bereit: DHCP

iSCSI Target einrichten

iSCSI hat gewöhnungsbedürftige Name: der iSCSI-Initiator ist der Client und das iSCSI-Target der Server.
Zunächst habe ich das iSCSI-Target eingerichtet:

apt-get install iscsitarget

Danach muss es noch aktiviert werden, indem man in der Datei /etc/default/iscsitarget den Wert ISCSITARGET_ENABLE auf true ändert:

vi /etc/default/iscsitarget
ISCSITARGET_ENABLE=true

Danach muss ein Volume erzeugt werden, das als Festplatte über iSCSI freigegeben wird. Das kann eine Platte, eine Partition, ein Logical Volume oder einfach nur eine Datei sein. Ich habe mich für letzteres entschieden und ein Sparse File angelegt (Speicherplatz wird erst bei Bedarf belegt, nicht beim Erstellen).

dd if=/dev/zero of=/path/to/image/htpc.iscsi.raw bs=1 count=1 seek=10G

Da es ein Sparse File ist, habe ich ihm ganze 10GB gegönnt – XBMC kann Cover herunterladen und benötigt dafür etwas Platz. Mindestanforderung für XBMC-Live ist 2GB.
Die Datei wird jetzt als iSCSI-LUN freigegeben:

vi /etc/ietd.conf
Target iqn.2011-08.home.marvin:htpc.lun0
        Lun 0 Path=/path/to/image/htpc.iscsi.raw,Type=fileio

Der Target-Name setzt sich nach RFC wie folgt zusammen: iqn.<yyyy-mm>.<reversed domain name>:<disk name>
Man kann das ganze auch noch mit User und Passwort absichern, das habe ich mir hier im Heimnetz aber gespart.
Jetzt beschränken wir den Zugriff noch auf die IP des XBMC-Rechners:

vi /etc/initiators.allow
#ALL ALL
iqn.2010-08.home.marvin:htpc.lun0 192.168.0.x

Nicht vergessen, dass der ALL ALL Eintrag auskommentiert werden muss.

Das wars dann auch schon – jetzt können wir den iSCSI-Daemon starten:

/etc/init.d/iscsitarget start

Quelle: http://www.howtoforge.com/using-iscsi-on-ubuntu-10.04-initiator-and-target

XBMC Installieren

Die XBMC-Installation hätte man auch direkt per Netzwerk mit PXE starten können. Da ich aber grad einen USB-Stick vor mir liegen hatte, war das dann doch die einfachere Variante.
Man lädt sich das XBMC-Live ISO von http://xbmc.org/download/ und lässt dieses mit unetbootin auf den USB-Stick schreiben. Unetbootin gibt es sowohl für Windows, als auch für Linux.

Danach startet man den XBMC-PC von dem USB-Stick und sollte in der Ubuntu-Installation landen. Hier „klickt“ man sich wie gewohnt durch, bis zu dem Punkt mit den Festplatten – dort sollte so etwas wie „iSCSI Targets konfigurieren“ stehen. Mit dem Menüpunkt verbindet man sich zur oben eingerichteten iSCSI-Disk. Diese taucht dann in der Liste auf und kann für die Partitionierung ausgewählt werden. Danach läuft die Installation weiter wie bisher. Beim reboot wird das Ubuntu nicht starten können, d.h. man kann den XBMC-PC erstmal wieder ausschalten.

XBMC für iSCSI-Boot anpassen

Jetzt haben wir zwar das frische XBMC-Ubuntu per iSCSI in unser Image installiert, es ist aber nicht in der Lage per iSCSI zu booten (ich finde das ist eine Lücke in der Installationsroutine – das muss dort eigentlich mit erledigt werden, sonst macht der iSCSI-Punkt keinen Sinn ..).
Hier profitieren wir direkt von dem Vorteil, dass die komplette Disk auf einem laufenden Linux-System liegt. Von daher führen wir die folgenden Befehle alle auf dem Server aus. Hier können wir die Partition mounten, die initrd anpassen und den iSCSI-Initiator installieren.
Zunächst installieren wir uns kpartx – ein Tool um ein Devicemapping aus Partitionstabellen zu erstellen.

apt-get install kpartx

Jetzt machen wir aus dem Disk-Image ein Device:

losetup /dev/loop0 /path/to/image/htpc.iscsi.raw

Und lesen die Partitionstabelle ein:

kpartx /dev/loop0

Jetzt hat der Devicemapper Einträge zu den Partitionen und wir können das root-Filesystem mounten:

mount /dev/mapper/loop0p1 /mnt

Dann wechseln wir in unser neu aufgesetztes XBMC-Ubuntu:

chroot /mnt

Nun müssen folgende zwei Dateien erstellt werden:

Eigentlich müssten wir jetzt eine neue initrd erzeugen – das macht die Installationsroutine vom iSCSI-Initiator aber auch nochmal, deswegen können wir uns das hier sparen. Den Initiator installieren wir mit:

apt-get install open-iscsi open-iscsi-utils

Hier tauchen Fehler auf, dass einige Sachen unter /proc nicht gefunden werden können, etc – die können ignoriert werden.
Nun verlassen wir die chroot-Umgebung wieder.

exit

Da wir den Kernel und die Initrd noch für den PXEBoot benötigen, lassen wir den mount noch bestehen.

Quelle: http://apfelboymchen.homeunix.net/gnu/notes/booting%20ubuntu%20iscsi.html

PXE und TFTP-Server einrichten

Der Bootvorgang läuft so ab, dass die Netzwerkkarte vom DHCP-Server die IP zu einem TFTP-Server und einen Dateinamen mitgeteilt bekommt. Diese Datei wird per TFTP geladen und ausgeführt. Wir benutzen hier die Datei pxelinux.0 aus dem Syslinux-Paket. Dazu installieren wir zunächst syslinux und den TFTPD auf unserem Server:

apt-get install syslinux tftpd-hpa tftp-hpa

Per default greift der TFTP-Server auf das Verzeichnis /var/lib/tftpboot zu. Hier legen wir pxelinux.0, den Kernel und die Initrd ab. Das pxelinux lädt dann beim Booten per TFTP den Kernel und die Initrd und führt diese aus.

cd /var/lib/tftpboot
cp /usr/lib/syslinux/pxelinux.0 .
mkdir htpc
cp /mnt/boot/vmlinuz-2.6.32-29-generic htpc/
cp /mnt/boot/initrd.img-2.6.32-29-generic htpc/
cd htpc
ln -s vmlinuz-2.6.32-29-generic vmlinuz
ln -s initrd.img-2.6.32-29-generic initrd
cd ..
mkdir pxelinux.cfg

Die beiden Symlinks sind ganz hilfreich, wenn man später auf andere Versionen schwenken will. Außerdem muss man dann beim Tippen der Konfigurationsdatei nicht den kompletten Namen wissen 😀
Der Ordner pxelinux.cfg ist für die Konfigurationsdateien, die pxelinux.0 benutzt. Hier kann z.B. eine Datei mit dem Namen default angelegt werden, die immer verwendet wird, wenn keine spezielle Konfiguration vorhanden ist. Da aber nur der eine spezielle XBMC-PC mit dem Kernel starten soll, legen wir eine spezielle Konfiguration an – diese wird anhand der MAC-Adresse identifiziert:

vi /var/lib/tftpboot/pxelinux.cfg/aa-bb-cc-dd-ee-ff
default xbmc

label xbmc
  kernel htpc/vmlinuz
  append initrd=htpc/initrd ip=dhcp iscsi_ip=192.168.0.x iscsi_iqn=iqn.2011-08.home.marvin:htpc.lun0 root=/dev/sda1 quiet splash xbmc=autostart,nodiskmount loglevel=0 video=vesafb

Das war schon der ganze Zauber mit PXE und TFTP – jetzt können wir das Image wieder aushängen.

umount /mnt
kpartx -d /dev/loop0
losetup -d /dev/loop0

DHCP einrichten

Das Problem an der Fritzbox ist, dass man keine DHCP-Optionen setzen kann. Deswegen habe ich schon direkt nach Kauf die alternative Firmware freetz aufgespielt.
Man ruft dann das Freetz-Webinterface (Port 81) auf und geht zu Dnsmasq→Einstellungen. Dort trägt man unter DHCP-Boot folgendes ein:

pxelinux.0,,192.168.0.x

Wenn man einen eigenen Dnsmasq laufen hat, reicht folgende Zeile in der Konfiguration:

dhcp-boot=pxelinux.0,,192.168.0.x

Beim DHCPD sind das folgende Konfigurationseinträge:

filename "pxelinux.0";
next-server 192.168.0.x;

Das war’s – jetzt sollte der XBMC-PC über Netzwerk booten.

Alternative: gPXE/etherboot

Bei diesem Projekt bin ich auf gPXE/etherboot gestoßen. gPXE ist ein erweiterter PXE-Loader, der direkt das Booten per iSCSI, HTTP, NFS, .. unterstützt. Damit hätte man sich das Bereitstellen des Kernels und der Initrd sparen können und wäre mit dem Betriebssystem noch unabhängiger gewesen (updates des Kernels usw.). Das Problem ist nur, dass gPXE erstmal irgendwie geladen werden muss – das geht durch Flashen der Netzwerkkarte/BIOS, chainload vom originalen PXE oder nachgelagert als „Kernel“ der von pxelinux geladen wird. Ersteres kam für mich nicht in Frage, da mir das zu aufwendig ist, außerdem setze ich PXE ganz gerne auch für andere Rechner und Zwecke ein und müsste dann alle Rechner flashen. Die anderen beiden Varianten sind da schon umgänglicher, die habe ich beide auch getestet, das Problem dabei ist aber, dass der gPXE den Pfad zu seiner Konfiguration vom DHCP-Server erwartet – das heißt wiederum, dass im DHCP-Server if-Abfragen dafür sorgen, dass beim ersten Request pxelinux.0 ausgeliefert wird und beim zweiten Request die gPXE-Konfiguration. Dann hätte ich den Dnsmasq ersetzen müssen, da er sowas (vermutlich) nicht kann.
Und dann noch der dritte Grund: Ich hatte erhofft, das Anpassen der initrd zu vermeiden mit dem direkten Booten per gPXE – da sich aber herausgestellt hat, dass Ubuntu die initrd bei der Installation nicht passend vorbereitet hat, musste sie eh angepasst werden.
Ich hoffe, dass gPXE den schmalen PXEloader auf Dauer ersetzen wird, dann eröffnen sich doch einige neue Spielereien, die man testen könnte 😉