]> git.ipfire.org Git - ipfire-2.x.git/blobdiff - src/scripts/vpn-watch
Erstmal ein Commit:
[ipfire-2.x.git] / src / scripts / vpn-watch
index 22107d02af7a5254fbf4555ec9c81fd636fc344f..8bd75215755ebae00a885e66439fd40d7010a718 100755 (executable)
-#!/bin/sh
-#
-# IPFire script - vpn-watch
-#
-# This code is distributed under the terms of the GPL
-#
-# (c) Daniel Berlin <daniel berlin_itechnology de> - Check for
-#      remote peer with dynamic IPs and restart when change
-#      is detected. Works with DPD which is not perfect!
-#
-# 2006: Franck - adapted original script to fit in IPCop 1.4
-# 2007: Michael Tremer - mitch@ipfire.org - Merged into IPFire
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-
-#
-# Configuration
-#
-
-VPN_CONFIG='/var/ipfire/vpn/config'            # Location of IPFire's vpn configuration file
-SETTINGS='/var/ipfire/vpn/settings'            # and settings
-
-CHECK_INTERVAL='60'                            # Check this often (in seconds)
-DNS_RESOLVE_TRIES='4'                  # Try to resolve IPs this often (each try takes max. 2 seconds)
-NICENESS='+5'                                                  # Adjust niceness of child processes: '-20' ... '+19'; '0' is default
-case "$1" in
-       'start' | '--start')
-               eval $(/usr/local/bin/readhash $SETTINGS)
-               test "${VPN_WATCH}" != "on"  && exit 1                  # not activated, cannot start!
-
-               if test ! -r "$VPN_CONFIG"; then
-                       echo 'Error: cannot read IPFire VPN configuration file; exit.' >&2
-                       exit 1
-               fi
-
-               if /usr/bin/test -p /var/run/$(basename $0); then
-                       if ps --no-heading axw | grep -v 'grep' | grep -q "$(basename $0) conn: "; then
-                               echo "Error: use '$(basename $0) stop' please; exit." >&2
-                               exit 1
-                        else
-                               rm /var/run/$(basename $0)              # pipe was left alone, correct error condition
-                       fi
-               fi
-
-               # the pipe serves for "-status" but is not used yet
-               /bin/mknod -m 0660 "/var/run/$(basename $0)" p >/dev/null 2>&1  # Create pipe for status-information
-
-               #
-               # Read VPN configuration and fork a child process for each VPN connection active, net-to-net & RED 
-               #
-               while read line; do
-                       VPN=($(echo $line | cut --delimiter=',' --output-delimiter=' ' -f2,3,5,12,28 )) # Activated, Name, Host/Net-to-net, Remote, ITF.
-                       test  "${VPN[0]}" != "on"  && continue                          # Ignore: deactivated connections
-                       test  "${VPN[2]}"  = "host"  && continue                        # Ignore: roadwarriors
-                       ## test  "${VPN[4]}" != "RED"  && continue                      # Ignore: local vpns needed or not ?
-                       echo -n "${VPN[3]}" | grep -q '^[[:digit:]\.]\+$' && continue   #If fixed remote IP, no need to watch!
-                       $0 'conn:' "${VPN[1]}" "${VPN[3]}">/dev/null 2>&1 &             #Fork child process (parameters: "conn: NAME RIGHT")
-               done < "$VPN_CONFIG"
-               exit 0                                                                  # Parent dies here... RIP
-               ;;
-
-       'stop' | '--stop')
-               # Terminate processes
-               for proc in $(pidof -x -o %PPID $(basename $0)); do
-                       kill -s SIGTERM -- "$proc"
-               done
-               sleep 1
-
-               # Kill remaining processes
-               for proc in $(/bin/pidof -x -o %PPID $(basename $0)); do
-                       kill -s SIGKILL -- "$proc"
-               done
-               rm -f "/var/run/$(basename $0)"                 # Remove pipe
-               exit 0
-               ;;
-
-       #'status' | '--status')
-       #       echo "VPN-Watch"
-       #       if ps --no-heading axw | grep -v 'grep' | grep -q "$(basename $0) conn: "; then
-       #               trap '' USR1
-       #               killall -q -g -s USR1 -- $(basename $0)
-       #               sleep 1
-       #               cat "/var/run/$(basename $0)" | sort    # Read children's info from pipe
-       #       else
-       #               echo '     no instance running.'
-       #       fi
-       #       exit 0
-       #       ;;
-
-       'conn:')
-               # Children proceed here...
-               renice ${NICENESS:-0} -p $$ >/dev/null 2>&1     # Adjust niceness
-               shift           # Remove the first positional parameter ("conn:"), as we don't need it anymore
-               ;;
-       *)
-               /bin/echo "Usage: $0 { start | stop }" >&2
-               exit 1
-               ;;
-esac
-
-# Logging, signal handlers
-alias log="logger -t vpn-watch \'${1}\':"
-
-trap 'log "terminated after ${RESTART_COUNT} restarts."' EXIT
-#trap 'echo "connection \"${1}\" restarted ${RESTART_COUNT} times" >>/var/run/$(basename $0)' USR1
-
-#
-# Get IP of a FQDN... using 'host' command. Everything is ok when dns server responds.
-# If no response,
-# -maybe RED is down. The script can terminate. It will restart with rc.updatered.
-# or
-# -the dns server is down. In this case, terminate the script is not a good idea...
-# Thus 4 retries before returning response 'stop'
-#
-function get_ip () {
-       local RESULT=''
-       # delay divided by two for each loop
-       delay=8
-       for ((i=1; ${i} <= ${DNS_RESOLVE_TRIES}; i++)); do
-
-               # extract IP address
-               RESULT=$(/usr/bin/host "$1" 2>/dev/null| awk '{ print $4 }')
-               if echo -n $RESULT | /bin/grep -q '^[[:digit:]\.]\+$' ; then 
-                       echo -n $RESULT
-                       return
-               fi
-
-               sleep $delay
-               delay=$((delay>>1))
-       done
-       # Change 'stop' to something else to let the script running
-       echo -n "stop" # stop: the script will terminate
-
-}
-
-# Infinite loop; checks, whether the IP of FQDN has changed.
-# If so, the affected connection gets restarted.
-#
-RESTART_COUNT=0
-REMOTE_IP_OLD=$(get_ip $2)
-log "start watching $REMOTE_IP_OLD"
-
-while [ $REMOTE_IP_OLD != 'stop' ] ;  do
-       sleep $CHECK_INTERVAL
-       # Skip check until IPSec is running. Update IP_OLD while our ipsec is down
-       /usr/sbin/ipsec auto --status >/dev/null 2>&1 || {
-               REMOTE_IP_OLD=$(get_ip $2)
-               continue
-       }
-
-       REMOTE_IP_NEW=$(get_ip $2)
-
-       if test "${REMOTE_IP_OLD}" != "${REMOTE_IP_NEW}"; then
-               /usr/sbin/ipsec auto --down  $1
-               /usr/sbin/ipsec auto --replace  $1
-               /usr/sbin/ipsec auto --rereadsecrets
-               /usr/sbin/ipsec auto --up  $1
-               let RESTART_COUNT++
-               log "Remote IP has changed from $REMOTE_IP_OLD to $REMOTE_IP_NEW. Connection restarted (#$RESTART_COUNT times)."
-               REMOTE_IP_OLD=$REMOTE_IP_NEW
-       fi
-done
+#!/bin/sh 
+################################################## 
+#####     VPN-Watch.sh     Version 1.6.3     ##### 
+################################################## 
+
+# This program is free software; you can redistribute it and/or modify 
+# it under the terms of the GNU General Public License as published by 
+# the Free Software Foundation; either version 2, or (at your option) 
+# any later version. 
+# 
+# This program is distributed in the hope that it will be useful, 
+# but WITHOUT ANY WARRANTY; without even the implied warranty of 
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+# GNU General Public License for more details. 
+
+# Written by: Daniel Berlin <daniel.berlin@itechnology.de>. 
+# Download: http://www.itechnology.de/front_content.php?idcat=87 
+# 
+
+# changed by: Rüdiger Sobeck 
+# last changed: 31-01-2006 
+
+# Configuration 
+# 
+CHECK_INTERVAL='120'            # Check this often (in seconds) 
+DNS_RESOLVE_TRIES='3'            # Try to resolve IPs this often (each try takes max. 2 seconds) 
+NICENESS='+5'               # Adjust niceness of child processes: '-20' ... '+19'; '0' is default 
+ipfire_VPN_CONFIG='/var/ipfire/vpn/config'   # Location of ipfire's vpn configuration file 
+ipfire_VPN_SETTINGS='/var/ipfire/vpn/settings'    # Location of ipfire's vpn settings file 
+VERSION='1.6.3' 
+
+# Workaround for nonexistent "nl" command on ipfire 1.4.x 
+nl --help >/dev/null 2>&1 
+if test $? -ne 0; then 
+    alias nl='cat' 
+fi 
+
+MyHost=`grep VPN_IP /var/ipfire/vpn/settings |  cut --delimiter='=' --output-delimiter=' ' -f2` 
+MyIP=`cat /var/ipfire/red/local-ipaddress` 
+MyDynDnsIP=`ping -c 1 "$1" 2>/dev/null | head -n1 | awk '{print $3}' | tr -d '()' | tr -d ':'` 
+
+case "$1" in 
+   'start' | '--start') 
+      if test ! -r "$ipfire_VPN_CONFIG"; then 
+         echo 'Error: cannot read ipfire VPN configuration file; exit.' >&2 
+         exit 1 
+      fi 
+
+      mknod -m 0660 "/var/run/$(basename $0)" p >/dev/null 2>&1   # Create pipe for status-information 
+
+      # Read VPN configuration and fork a child process for each VPN connection 
+      # 
+      while read line; do 
+         VPN=($(echo $line | cut --delimiter=',' --output-delimiter=' ' -f1,2,3,5,6,12))   # 
+                        CONNR=${VPN[0]}                             # connection number 
+                        CONACTIVE=${VPN[1]}                        # active (on|off) 
+                        CONNAME=${VPN[2]}                        # connection name 
+                        CONTYPE=${VPN[3]}                        # connection type (host|net) 
+                        CONCERTPSK=${VPN[4]}                        # key type (cert|psk) 
+                        CONDNSNAME=${VPN[5]}                        # FQDN name of other side 
+                        
+         echo -n "${CONACTIVE}" | grep -qi '^off$' && continue            # Ignore: deactivated connections 
+         echo -n "${CONTYPE}" | grep -qi '^host$' && continue            # Ignore: Roadwarriors (->DPD) 
+#         echo -n "${VPN[1]}${MyHost}" | grep -q '^[[:digit:]\.]\+$' && continue      # Ignore: "left" and "right" side set to an IP 
+
+         $0 'conn:' "${CONNAME}" "${MyHost}" "${CONDNSNAME}" "${CONNR}" >/dev/null 2>&1 &      # Fork child process (parameters: "conn: NAME LEFT RIGHT NUMBER") 
+         echo -n 'S' 
+      done < "$ipfire_VPN_CONFIG" 
+      echo Â"ÂStarte VPN-Watch" 
+      exit 0                                          # Parent dies here... RIP 
+      ;; 
+   'stop' | '--stop') 
+      # Terminate processes 
+      for proc in $(pidof -x -o %PPID $(basename $0)); do 
+         kill -15 $proc 
+         echo -n 'T' 
+      done 
+      sleep 1 
+      # Kill remaining processes 
+      for proc in $(pidof -x -o %PPID $(basename $0)); do 
+         kill -9 $proc
+         echo -n 'K' 
+      done 
+      rm -f "/var/run/$(basename $0)"                        # Remove pipe 
+      echo "Stoppe VPN-Watch"
+      exit 0 
+      ;; 
+   'restart' | '--restart') 
+      $0 stop 
+      $0 start 
+      exit 0 
+      ;; 
+   'status' | '--status') 
+      echo "VPN-Watch ${VERSION}  (mail: daniel@itechnology.de, web: www.itechnology.de/vpn-watch)" 
+      if ps --no-heading axw | grep -v 'grep' | grep -q "$(basename $0) conn: "; then 
+         trap '' USR1 
+         killall -q -g -s USR1 -- $(basename $0) 
+         sleep 1 
+         cat "/var/run/$(basename $0)" | sort | nl            # Read children's info from pipe 
+      else 
+         echo '     no instances running.' 
+      fi 
+      exit 0 
+      ;; 
+   'conn:') 
+      # Children proceed here... 
+      renice ${NICENESS:-0} -p $$ >/dev/null 2>&1               # Adjust niceness 
+      shift                              # Remove the first positional parameter ("conn:"), as we don't need it anymore 
+      ;; 
+   *) 
+      echo "Usage: $0 { start | stop | restart | status }" >&2 
+      exit 1 
+      ;; 
+esac 
+
+# Logging, signal handlers 
+# 
+alias log="logger -t '$(basename $0 | cut -d '.' -f 1) ${VERSION}' \(${1}\)" 
+trap 'log "terminated after ${RESTART_COUNT} restarts."' EXIT 
+trap 'echo "connection \"${1}\" restarted ${RESTART_COUNT} times" >>/var/run/$(basename $0)' USR1 
+
+log "started" 
+
+# Get IP of a FQDN... using 'arp', 'traceroute' or 'ping', 
+#  because ipfire has no 'nslookup', 'host' or 'dig' command. 
+# 
+function get_ip () { 
+   local RESULT='' 
+   for ((i=1; ${i} <= ${DNS_RESOLVE_TRIES}; i++)); do 
+      if which arp >/dev/null 2>&1; then 
+         RESULT=$(arp "$1" 2>/dev/null | awk '{ print $2 }' | tr -d '()') 
+      elif which traceroute >/dev/null 2>&1; then 
+         RESULT=$(traceroute -m1 -q1 "$1" 2>/dev/null | head -n1 | awk '{ print $4 }' | tr -d '(),') 
+      else 
+         RESULT=$(ping -c 1 "$1" 2>/dev/null | head -n1 | awk '{print $3}' | tr -d '()' | tr -d ':') 
+      fi 
+      test -n "$RESULT" && break 
+   done 
+   test -z "$RESULT" && log "Warning: could not resolve ${1} after ${DNS_RESOLVE_TRIES} tries..." 
+   echo -n "$RESULT" 
+} 
+
+function get_tunnelip () { 
+   file=/var/tmp/$1.remoteip 
+   local TRESULT='' 
+   TVPN=`grep "$1" /var/ipfire/vpn/config| awk 'BEGIN{FS=","}{print $2}'` 
+   DYNHOST=`grep "$1" /var/ipfire/vpn/config| awk 'BEGIN{FS=","}{print $12}'` 
+   CONNR=`grep "$1" /var/ipfire/vpn/config| awk 'BEGIN{FS=","}{print $1}'` 
+   REMOTEIP=`/usr/bin/ping -c 1 "$DYNHOST" 2>/dev/null | head -n1 | awk '{print $3}' | tr -d '()' | tr -d ':'` 
+   if ! test -f $file; then 
+      cat $REMOTEIP > $file 
+   fi 
+   OLDIP=`cat $file` 
+   TUNIP=`ipsec whack --status | grep "$1"` 
+   if [ "$TUNIP" != "" ]; then 
+      TUNIP=`ipsec whack --status | grep "$1" | awk 'BEGIN{FS="["}{print $2}' | awk 'BEGIN{FS="---"}{print $3}'` 
+      log "currently used tunnel IP = $TUNIP, current remote IP = $REMOTEIP" 
+      echo $REMOTEIP > $file 
+      TRESULT=${TUNIP} 
+   fi 
+
+   test -n "$TRESULT" && break 
+   test -z "$TRESULT" && log "Warning: could not retrieve last used VPN tunnel IP..." 
+   echo -n "$TRESULT" 
+} 
+
+# Restarts a VPN connection 
+# 
+function restart_vpn () { 
+   if test -x /usr/local/bin/ipsecctrl; then 
+      /usr/local/bin/ipsecctrl D "$1"         # This works for ipfire 1.4.x 
+      /usr/local/bin/ipsecctrl R         # re-read secrets 
+      /usr/local/bin/ipsecctrl S "$1"         # start tunnel 
+   else 
+      ipsec auto --down      "$1"         # This works for ipfire 1.3.x 
+      ipsec auto --unroute   "$1" 
+      ipsec auto --delete      "$1" 
+      ipsec auto --rereadall 
+      ipsec auto --add      "$1" 
+      ipsec auto --route      "$1" 
+      ipsec auto --up         "$1" 
+   fi 
+} 
+
+# Get left and right IP 
+# 
+LEFT_IP_OLD=$MyIP 
+RIGHT_IP_OLD=$(get_ip $3) 
+
+# Infinite loop; checks, whether the IP of a left or right FQDN has changed. 
+#  If so, the affected connection gets restarted; this is logged to syslog. 
+# 
+RESTART_COUNT=0 
+while :; do 
+   sleep $CHECK_INTERVAL 
+
+   # Skip check until IPSec is running 
+   ipsec auto --status >/dev/null 2>&1 || continue 
+
+   # get own IP (may have changed) 
+   ThisHostIP=`cat /var/ipfire/red/local-ipaddress` 
+    
+   # this our own IP as reported in /var/ipfire/ppp/local-ipadress 
+   LEFT_IP_NEW=$ThisHostIP 
+   # check our own DYNDNS IP 
+   LEFT_IP_DYN=$(get_ip $MyHost) 
+   # this is DYNDNS IP of other side 
+   RIGHT_IP_NEW=$(get_ip $3) 
+   # this the last used (right) IP for VPN-Tunnel 
+   RIGHT_TUN_IP_OLD=$(get_tunnelip $1) 
+
+#   for whatever reason, ipsec did not notice our own IP has changed for this connection 
+   if [ "${LEFT_IP_NEW}" != "${LEFT_IP_DYN}" ]; then 
+      restart_vpn "$4" 
+      let RESTART_COUNT++ 
+      log "Red IP = $LEFT_IP_NEW, IP by DynDNS = $LEFT_IP_DYN" 
+      log 'incorrect dynamic IP in tunnel used: restarting connection...' 
+   fi 
+    
+#   left or right IP has changed...    
+   if test "${LEFT_IP_OLD} ${RIGHT_IP_OLD}" != "${LEFT_IP_NEW} ${RIGHT_IP_NEW}"; then 
+      restart_vpn "$4" 
+      let RESTART_COUNT++ 
+      log 'left or right IP has changed: restarting connection...' 
+   fi 
+
+#   right IP / IP of tunnel endpoint has changed... 
+   if [ "$RIGHT_TUN_IP_OLD" != "" ]; then 
+      if test "${RIGHT_TUN_IP_OLD}" != "${RIGHT_IP_NEW}"; then 
+         restart_vpn "$4" 
+         let RESTART_COUNT++ 
+         log 'VPN tunnel IP has changed: restarting connection...' 
+      fi 
+   fi 
+
+   LEFT_IP_OLD=$LEFT_IP_NEW 
+   RIGHT_IP_OLD=$RIGHT_IP_NEW 
+done 
+