IpCop

Aus ConfigWiki
Wechseln zu: Navigation, Suche

IPCop

IPCop ist eine Linuxdistribution für Router und Firewalls und ist erhältlich unter http://www.ipcop.org/ . Weitere allg. Informationen unter http://de.wikipedia.org/wiki/IPCop

Im praktischen Einsatz ergab sich das Problem, daß dead-peer-detection bei den IPsec-VPN-Verbindungen nicht funktionierte. Zum Teil liegt das vermutlich auch an der Art des Internetzugangs.

Der 1. Router befindet sich hinter einem Kabelmodem, welches als Bridge arbeitet und dem IPCop die öffentliche IP durchreicht.
Der 2. Router befindet sich hinter einer FritzBox und hat eine private IP an RED.
Beide Router haben eine dynamische IP, die aber erst nach 14 Tagen geändert wird. (Kabel Deutschland)

Der 3. Router wählt sich via DSL-Modem selbst ein und erhält jeden Tag eine neue IP. (T-Com)

Nach der DSL-Neueinwahl mit Änderung der IP-Adresse werden die VPN-Verbindungen nicht neu initialisiert. Die genaue Ursache ist noch nicht ermittelt.

Da es sich um Netz-zu-Netz-VPNs handelt ist ein Monitoring via ping von den IPCops selbst nicht möglich. Ein externes Monitoring einer Maschine im Netz informiert per Mail über eine fehlende Verbindung. Ggf. kann von dort aus auch ein gezielter Neustart einzelner Verbindungen mit dedizierten ssh-Keys eingerichtet werden. Ziel ist es jedoch, daß die IPCops selbst den Fehler zu korrigieren.

Als Workaround wurde ein Shellskript geschrieben, welches regelmäßig kontrolliert, ob die Verbindungen in einem definierten Zustand sind und diese ggf. neu startet. Das Skript vergleicht die in der Konfigurationsdatei hinterlegten Verbindungen mit der Ausgabe von "ipsec eroute" ( -> $EROUTE). Der einzige als "garantiert bestehende Verbindung" bekannte Zustand ist "tun0x*@<IP>:0", wobei die IP der aktuell gültigen IP der Gegenstelle entsprechen muß. Letztere wird wiederum mit "host" aus dem FQDN der zugehörigen Verbindung aus der Config (Feld_12 -> $RIGHT) ermittelt. Die zugehörige Verbindung ergibt sich aus der Config (Feld_13 -> $RIGHTSUBNET_CFG) und $EROUTE (Feld_4 -> $RIGHTSUBNET), jeweils ab dem "/" um die in unterschiedlicher Schreibweise angegebene Subnetzmaske gekürzt. Feld_1 in der Config ist der jeweilige Verbindungsname (bzw. Nr.) für ipsecctrl. Damit kann die jeweilige Verbindung gezielt neugestartet werden.

Als fehlerhaft bekannt sind die Zustände:

  • "tun" + alte <IP>
  • "trap"
  • ggf. "hold"
#!/bin/bash

CONFIG='/var/ipcop/vpn/config'
EROUTE=$( ipsec eroute )

# pruefe alle aktiven Verbindungen ($2=on) aus CONFIG
while read CONN_NR CONN_NAME RIGHT RIGHTSUBNET_CFG; do

   # IP-Adresse aus Config-FQDN der Gegenstelle ermitteln
   read F1 F2 F3 RIGHT_IP F4 <<< $( host -t a $RIGHT )
   # ToDo: vorher pruefen, ob in CONFIG eine IP statt FQDN eingetragen wurde
   #       dann eruebrigt sich die Namensaufloesung
   #       BASH#IP-Validierung funktioniert nicht, =~ wird nicht akzeptiert

   # Werte zuruecksetzen
   CONN_STATE="-"
   CONN_STATE_RAW="-"
   CONN_RIGHT_IP="-"

   # vergleichen, falls noch wenigstens 1 Verbindung steht
   if [ "$EROUTE" != "" ]; then
	# EROUTE zeilenweise verarbeiten
	while read P_COUNT LEFTSUBNET A1 RIGHTSUBNET A2 RAW_STATE; do
	    if [ "${RIGHTSUBNET_CFG%/*}" == "${RIGHTSUBNET%/*}" ] ; then
		CONN_STATE=${RAW_STATE%%0x*}          # alles ab 0x entfernen
		if [ "$CONN_STATE" == "tun" ]; then
	    	    # RAW_STATE = tun0x<NR>@<IP>:0
	    	    CONN_RIGHT=${RAW_STATE#*\@}       # alles bis zum @ entfernen
		    CONN_RIGHT_IP=${CONN_RIGHT%:*}    # alles ab : entfernen
		else
	    	    # RAW_STATE = %trap:0 || %hold:0 (oder war das bei hold anders?)
		    CONN_STATE_RAW=$RAW_STATE         # zum loggen, falls ein unbekannter Status auftaucht
		    CONN_STATE=${RAW_STATE#%}         # % am Anfang entfernen
		    CONN_STATE=${CONN_STATE%:*}       # alles ab : entfernen
		fi
	    fi
	done <<< "$EROUTE"
   fi

   if [ "$CONN_STATE" == "tun" ] ; then
	# aufgeloeste IP aus Config mit aktueller IP der Gegenstelle aus EROUTE vergleichen
	if [ "$RIGHT_IP" != "$CONN_RIGHT_IP" ] ; then
	    logger -p local0.warning -t ipcop "$CONN_NAME $RIGHT_IP $CONN_STATE $CONN_RIGHT_IP"
	    if [ "$CONN_RIGHT_IP" == "-" ]; then
		logger -p local0.warning -t ipcop "ipsec-watch restarting $CONN_NAME (connection down)"
	    else
		logger -p local0.warning -t ipcop "ipsec-watch restarting $CONN_NAME (IP changed)"
   	    fi
	    /usr/local/bin/ipsecctrl S $CONN_NR       # betreffende Verbindung gezielt neu starten
	fi
   else
	logger -p local0.warning -t ipcop "$CONN_NAME $RIGHT_IP $CONN_STATE $CONN_STATE_RAW"
	logger -p local0.warning -t ipcop "ipsec-watch restarting $CONN_NAME (state != tun)"
	/usr/local/bin/ipsecctrl S $CONN_NR           # betreffende Verbindung gezielt neu starten
   fi

done <<< "$( awk -F , '($2 == "on")  {printf "%s %s %s %s\n", $1, $3, $12, $13}' $CONFIG )"

Eintrag in der crontab (fcrontab -e):

*/2 * * * *     [ -x "/usr/local/bin/ipsec-watch" ] && /usr/local/bin/ipsec-watch >/dev/null 2>&1

schaut alle 2 Minuten nach dem Rechten. (ursprünglich aller 5 Minuten)

Festgestellt wurde, daß der (2.) Router mit der privaten IP an RED nach der DSL-Neueinwahl des 3. Routers die geänderte IP-Adresse nach 5 Minuten noch nicht bemerkt hat. Die Verbindung wurde erst mit dem 2. Neustart wieder aktiviert, also erst nach 10 Minuten. Der 1. Router war bereits nach dem 1. Versuch wieder im Normalzustand.

Zustand der VPNs nach der DSL-Neueinwahl: 1. Check (+5min):

  • 1 -> 2: nicht betroffen (wird nicht neugestartet)
  • 1 <- 2: nicht betroffen (wird nicht neugestartet)
  • 1 -> 3: Verbindung weg (kein eroute-Eintrag)
  • 1 <- 3: trap
  • 2 -> 3: tun -> alte IP
  • 2 <- 3: trap

2. Check (+10min):

  • 2 -> 3: Verbindung weg (kein eroute-Eintrag)
  • 2 <- 3: trap
Meine Werkzeuge