IC-VPN auf Internet-Gateway einrichten

Eine eigenes Freifunk-Netz aufzubauen ist eine tolle Sache. Bis zum Erreichen der kritischen Masse ist man innerhalb des eigenen Neztes jedoch vergleichsweise einsam. Wäre es also nicht noch viel toller, wenn man alle bestehenden Freifunk-Netze miteinander verbinden könnte?
Dies ist tatsächlich möglich. Die existierende Lösung nennt sich Inter City VPN (IC-VPN) und ist ein Transportnetz, welches von Pionieren der Freifunk-Szene geschaffen wurde. Zum Zeitpunkt der Veröffentlichung dieses Artikels befinden sich bereits mehr als 50 Freifunk-Gemeinden innerhalb des Verbundes. Der Anschluss des eigenen Freifunk-Netzes an das IC-VPN ist Inhalt der folgenden Anleitung. Diese wurde aus verschiedenen Quellen zusammengetragen und basiert im Kern auf den Instruktionen der Seite IC-VPN im Freifunk-Wiki. Die Konfiguration des Routing-Dämonen bird wurde von einer Vorlage aus Hamburg abgeleitet.

Als Grundlage für die Vernetzung dienen verschlüsselte VPN-Verbindungen via tinc, einem leichtgewichtigen VPN-Dämonen. Zusätzlich werden mittels des Border Gateway Protocols (BGP) Routen ausgetauscht, um Pakete über das Transportnetz korrekt zustellen zu können. Hierfür verwenden wir den Routing-Dämonen bird. Ein drittes Element ist die Einbindung aller DNS-Server, um Host-Namen auch unter den Domains anderer Freifunk-Gemeinden aufzulösen. Hierfür werden wir die Konfiguration des zuvor eingerichteten DNS-Proxy dnsmasq erweitern.
Um die Verbindungsdaten der anderen Gemeinden nicht manuell eingeben und fortwährend aktualisiern zu müssen, werden wir weiterhin auf die Daten in den öffentlichen Git-Ablagen icvpn, icvpn-meta und icvpn-scripts auf github.com zurückgreifen. Über diese Ablagen sowie das Freifunk Wiki werden wir zusätzlich unsere eigene Gemeinde für das IC-VPN “registrieren”.
In den folgenden Schritten wird von der Installation auf einem bestehenden Internet-Gateway ausgegangen. Die beschriebenen Schritte wurden unter Debian Wheezy ausgeführt und getestet. Für die Konfiguration wurde von den Daten des Freifunk 3Ländereck ausgegangen. Die Einrichtung erfolgt als Benutzer root.

Registrierung im Freifunk-Wiki

Wie bei Freifunk üblich, erfolgt die Registrierung für das IC-VPN ganz unförmlich über das Freifunk-Wiki. Unsere Daten tragen wir in die große Tabelle am Ende der zugehörigen Wiki-Seite ein. Um das Pflegen der Liste zu erleichtern, sollte der Eintrag in alphabetischer Reihenfolge nach dem Namen des Gateways vorgenommen werden:

Stadt / City dreilaendereck1
AS 65043
IPv4 (Transfernetz / Transitnetwork) 10.207.0.75
IPv6 (Site-Local) fec0::a:cf:0:be
Public IP gw1.freifunk-3laendereck.de
Admin icvpn@freifunk-3laendereck.de
Announciert / announces 10.119.0.0/16, fdc7:3c9d:b889:a272::/64

Mit dem Eintrag registrieren wir unser erstes IC-VPN-Gateway unter der Bezeichnung “dreilaendereck1″ (der Titel der Kopfzeile ist ein wenig irreführend). Als Kennzahl für unser “Autonymous System” (AS) wählen wir die Nummer 65043. Diese Nummer bezeichnet unser lokales Freifunk-Netz und wird später von allen unseren IC-VPN-Gateways geteilt. Es scheint sich die Konvention festgesetzt zu haben, Nummern >65000 zu verwenden. Die gewählte Nummer darf noch nicht in Verwendung sein. Eine Tabelle mit den bereits vergebenen AS-Nummern findet man auf einer separaten Wiki-Seite. Dort sollte man zusätzlich einen Eintrag für die eigene Gemeinde vornehmen.

Als IPv4- und IPv6-Adressen für das Gateway wählen wir 10.207.0.75 bzw. fec0::a:cf:0:be. Die erste Adresse entstammt dem Transportnetz 10.207.X.0/16, letztere dem Transportnetz fec0::a:cf:X:0/112. Für den Platzhalter X wird eine einheitliche Wahl nach Land vorgeschlagen. Leider ist diese nicht dokumentiert. Für Deutschland hat sich in beiden Fällen die Zahl “0” durchgesetzt. Ansonsten orientiert man sich am besten an den bestehenden Einträgen bzw. schafft einen “Präzidenzfall”. Wie im Fall der AS-Nummer müssen beide Adressen noch unbelegt sein. Dies überprüft man am besten durch Durchsuchen der ganzen Wiki-Seite. Im Gegensatz zur AS-Nummer werden die Adressen zwischen den eigenen Gateways nicht geteilt.

Als Public IP geben wir für unser Gateway den vollständigen Domain-Namen (Internet!) an; darunter noch eine Kontaktaddresse für den Fall der Fälle. Als letztes folgen die Freifunknetze (IPv4 und IPv6), welche wir über das IC-VPN integrieren möchten.

Konfiguration des tinc-VPN-Dämonen

Damit sind wir soweit, dass wir mit der eigentlichen Einrichtung unseres IC-VPN-Gateways beginnen können. Bevor wir loslegen, müssen wir jedoch zuerst noch den VPN-Dämonen tinc installieren. Da unter Debian Wheezy ein funktionsfähiges Paket existiert, gelingt dies mit:$ apt-get install tinc
Weiterhin beziehen wir die öffentliche Git-Ablage mit den Schlüsseln der Peers, welche am IC-VPN teilnehmen. Das Verzeichnis der Ablage dient uns gleichzeitig zur Aufnahme weiterer Konfigurationsdateien:
$ cd /etc/tinc
$ git clone https://github.com/freifunk/icvpn
Da die Kommunikation über tinc verschlüsselt erfolgt, generieren wir als nächstes ein RSA-Schlüsselpaar. Dieses dient gleichzeitig zur Authentifizierung:$ tincd -n icvpn -K
Als Dateinamen akzeptieren wir die Vorgaben (rsa_key.priv für den privaten und rsa_key.pub für den öffentlichen Schlüssel). Beide Dateien werden automatisch im Verzeichnis /etc/tinc/icvpn abgelegt. Der Zugriff ist standardmäßig auf den Benutzer root beschränkt.

Um tinc grundlegend zu konfigurieren, erstellen wir eine Basiskonfiguration in der Datei /etc/tinc/icvpn/tinc.conf.header. Diese spezifiziert den Namen der Host-Konfigurationsdatei unseres Gateways (“Name = dreilaendereck1″) sowie den privaten RSA-Schlüssel (“PrivateKeyFile = “…”). Mit der Option “Mode = Switch” teilen wir tinc mit, dass es sich wie ein Ethernet-Switch verhalten soll. Den Ping Timeout erhöhen wir großzügig auf 30 s. Als Port verwenden wir die Nummer 656. Mit “Hostnames = Yes” erlauben wir die Auflösung von IP-Adressen in Domain-Namen. Dies erleichtert später die Interpretation der Log-Dateien:

Name = dreilaendereck1
PrivateKeyFile = /etc/tinc/icvpn/rsa_key.priv
Mode = Switch
PingTimeout = 30
Port = 656
Hostnames = yes

Den Inhalt der Datei kopieren wir manuell in die eigentliche Konfigurationstatei /etc/tinc/icvpn/tinc.conf:

$ cp icvpn/tinc.conf.header icvpn/tinc.conf

Um notwendige Netzwerkmanipulationen automatisch durchzuführen, erstellen wir das Skript /etc/tinc/icvpn/tinc-up, welches von tinc nach erfolgtem Verbindungsaufbau aufgerufen wird. In diesem aktivieren wir zuerst die Schnittstelle (“ip link set …”). Danach weisen wir der Schnittstelle eine IPv4 (“ip addr add…”) sowie IPv6-Addresse (“ip -6 addr add…”) zu. Diese müssen identisch mit den zuvor für den Router registrierten Adressen innerhalb des IC-VPN-Transportnetzes sein:

#!/bin/sh
/sbin/ip link set dev $INTERFACE up
/sbin/ip addr add dev $INTERFACE 10.207.0.75/16 broadcast 10.207.255.255 scope link
/sbin/ip -6 addr add dev $INTERFACE fec0::a:cf:0:be/96 preferred_lft 0

Analog erstellen wir das Skript /etc/tinc/icvpn/tinc-down, welches von tinc nach Terminierung der Verbindung aufgerufen wird. In ihm werden der Netzwerkschnittstelle alle IP-Adressen wieder entzogen und die Schnittstelle im Anschluss deaktiviert:

#!/bin/sh
/sbin/ip addr del dev $INTERFACE 10.207.X.Y/16 broadcast 10.207.255.255
/sbin/ip -6 addr del dev $INTERFACE fec0::a:cf:X:Y/96
/sbin/ip link set dev $INTERFACE down

Zuletzt machen wir die beiden Skripte ausführbar:

$ chmod 755 /etc/tinc/icvpn/tinc-*

Um die tincd-Konfiguration automatisch um die Peers zu ergänzen, installieren wir das folgende Skript unter /usr/local/bin/update-tincd-icvpn. Es überprüft zuerst die entfernte Git-Ablage auf Änderungen und gleicht diese gegebenenfalls lokal ab. Im Anschluss wird die Konfigurationsdatei tinc.conf auf Basis der Grundkonfiguration tinc.conf.header erstellt. Zusätzlich wir der Basiskonfiguration für jeden Host im hosts-Verzeichnis eine “ConnectTo”-Zeile hinzugefügt. Zuletzt wird tincd mittels des Signals HUP aufgefordert, die Konfiguration neu zu laden:

TINC_ICVPN=/etc/tinc/icvpn

# IC-VPN configuration file
TINC_CONF=tinc.conf

# IC-VPN configuration file header
TINC_CONF_HEADER=tinc.conf.header

# IC-VPN host file directory
TINC_HOSTS=hosts
function getCurrentVersion() {
# Get hash from latest revision
git log --format=format:%H -1
}

cd $TINC_ICVPN

# Get current version hash
GIT_REVISION=$(getCurrentVersion)

# Automagically commit local changes
# This preserves local changes
git commit -m "CRON: auto commit"

# Pull latest changes from upstream
git fetch
git merge origin/master -m "Auto Merge"

# Get new version hash
GIT_NEW_REVISION=$(getCurrentVersion)

if [ $GIT_REVISION != $GIT_NEW_REVISION ]
then
  # Start with header file for tinc configuration
  cp $TINC_CONF_HEADER $TINC_CONF

  # Iterate through hosts in host directory
  for HOST in $TINC_HOSTS/*; do
    # Skip hosts without address
    grep -q '^Address' -- "$HOST" || continue
    # Add ConnectTo line for current host
    echo "ConnectTo = ${HOST##*/}" >> $TINC_CONF
  done

  # Reload updated configuration
  echo "Reload tincd configuration."
  kill -HUP $(pidof tincd)
fi

Mit dem folgenden Befehl machen wir das Skript ausführbar:
$ chmod 750 /usr/local/bin/update-tincd-icvpn
Damit es in Zukunft regelmäßig (in unserem Fall stündlich) ausgeführt wird, fügen wir der Datei /etc/crontab die folgenden Zeilen hinzu:

# Update tincd IC-VPN peers every hour.
12 *    * * *   root    update-tincd-icvpn > /dev/null

Um cron zur Übernahme der Änderung zu bewegen, starten wir den Dämonen im Anschluss neu:
$ /etc/init.d/cron restart

Kommentare