Auf cthulhu läuft ein OpenVPN im Server-Modus. Da auch IPv6 über den
Tunnel laufen soll, muss OpenVPN im TAP-Modus laufen. Dabei verhält sich das
Tunnel-Gerät wie eine virtuelle Ethernet-Karte. Das bringt mit sich, dass
Clients ARP-Anfragen starten müssen, bevor sie mit irgendjemandem auf dem
Tunnel reden können. Will man dazu noch, dass die Clients sich gegenseitig
sehen, steht man vor einem Problem: ARP-Spoofing ist Tür und Tor geöffnet,
keiner kann mehr sicher sein, mit wem er wirklich auf dem Tunnel spricht. Eine
Alternative wäre in OpenVPN die Option client-to-client auszuschalten und
den Client etwas vermurkste Routen beizubringen. Da sich das etwas schwierig
beschreiben lässt, mache ich am besten mal ein Beispiel:
Auf cthulhu liegt auf dem Tunnel das Netz 172.22.110.0/26. cthulhu
selbst hat die IP 172.22.110.1. pledge (172.22.110.6), mein
Laptop, und zee (172.22.110.3), mein Server, haben jeweils einen
Tunnel dorthin. Auf den einzelnen Rechnern sieht es folgendermaßen aus (modulo
IP-Adresse und Interface-Namen):
$ ip -o -4 address show dev tap0
21: tap0 inet 172.22.110.1/26 brd 172.22.110.63 scope global tap0
$ ip route show | grep '^172\.22\.110'
172.22.110.0/26 dev tap0 proto kernel scope link src 172.22.110.1
Schaltet man nun client-to-client in OpenVPN aus, können pledge und
zee nicht mehr miteinander reden, da die ARP-Anfragen nicht mehr
durchgelassen werden (was man ja erreichen wollte). Um nun doch wieder
Kommunikation zwischen den beiden Rechnern zu erlauben, muss man die Routen
etwas umbiegen, so dass diese z.B. folgendermaßen aussehen:
$ ip -o -4 address show dev tap0
21: tap0 inet 172.22.110.6/32 brd 172.22.110.6 scope global tap0
$ ip route show | grep '^172\.22\.110'
172.22.110.1 dev tap0 scope link
172.22.110.0/26 via 172.22.110.1 dev tap0
Diese Änderung muss man natürlich nur auf den Clients vornehmen. Auf dem
Server bleibt alles wie gehabt, denn dieser kann ja alle Clients sehen.
Eigentlich ist das recht praktikabel: die Clients schicken keine ARP-Requests
für andere Clients mehr sondern lassen den Server die Pakete an diese Routen.
Allerdings hat man damit zwei neue Probleme: OpenVPN bietet von hause aus
keine Möglichkeit, per PUSH den Clients diese Option mitzuteilen. Entweder
trägt diese Konfiguration also auf allen Clients statisch in eine up.sh
ein, oder man denkt sich ein etwas flexibleres System mit der
setenv-safe-Option aus, wofür man allerdings OpenVPN 2.1 braucht. Das
zweite Problem bestand bei mir darin, dass Quagga sich weigerte, Routen per
BGP zu akzeptieren, wahrscheinlich weil es nicht verstanden hat, dass
172.22.110.1 doch direkt verbunden ist.
Die Lösung, die mir dabei einfiel, war recht einfach: man lässt die Routen und
Netzmasken wie sie sind, schaltet aber trotzdem client-to-client
aus. Damit sich die Clients gegenseitig erreichen können, genügt es
eigentlich, wenn der Server, hier also cthulhu, ARP-Proxy für alle Clients
spielt. Das bedeutet, dass er alle ARP-Anfragen der Clients mit seiner eigenen
MAC-Adresse beantwortet und die Pakete, die er dann bekommt, einfach an die
jeweils anderen Clients weiterroutet. Linux bietet zwar die Möglichkeit zum
ARP-Proxying, aber man kann es scheinbar nicht auf einem einzelnen Interface
aktivieren. Ist auch verständlich, denn wer erwartet schon, dass auf einem
Ethernet-Gerät die anderen Rechner sich nicht gegenseitig nicht sehen
können. Es musste also ein Tool her, was diese Aufgabe übernimmt. Was einem
dabei als erstes einfällt, sind diese bösen Hacker-Werkzeuge zum ARP-Spoofing.
Leider hatten sich die von mir gefunden dafür nicht geeignet, denn sie waren
erstens nur dazu ausgelegt, nur eine einzelne IP zu Spoofen (z.B. den Router
des LANs), d.h. ich müsste im Extremfall 61 Kopien davon laufen lassen
(nicht praktikabel!), und zweitens sind diese bestimmt nicht
im Hinblick auf Sicherheit und Zuverlässigkeit programmiert.
Was mir am Ende aber doch über den Weg lief, war ipsentinel. Das ist ein
Daemon, der eigentlich dazu gedacht ist, ARP-Anfragen für unbenutzte IPs zu
beantworten. Der Programmierer, Enrico Scholz, hat diesen aber flexibel genug
gemacht, dass er natürlich auch ARP-Anfragen für benutzte IPs beantworten
kann. Dazu noch als gespoofte MAC-Adresse die des Server festlegen, bingo!
Schön ist, dass er die Möglichkeit vorgesehen hat, den Daemon als
unprivigierten Nutzer in einem chroot-Verzeichnis laufen zu lassen. Ich
vermute, er hat sich bei der Programmierung ein bisschen von DJBs Prinzipien
inspirieren lassen.
Auf cthulhu läuft also jetzt ip-sentinel parallel zu OpenVPN, natürlich
als runit-Dienst. Meine Bedürfnisse hinsichtlich Sicherheit und Wartbarkeit
sind dahingehend damit vorerst gestillt. Was mir an der Lösung besonders
gefällt, ist, dass die Clients davon nichts merken und dass ich damit sogar
die Möglichkeit habe Client-zu-Client-Traffic zu filtern.