]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/scripts/vpn-watch
Erstmal ein Commit:
[people/pmueller/ipfire-2.x.git] / src / scripts / vpn-watch
1 #!/bin/sh
2 ##################################################
3 ##### VPN-Watch.sh Version 1.6.3 #####
4 ##################################################
5
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2, or (at your option)
9 # any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15
16 # Written by: Daniel Berlin <daniel.berlin@itechnology.de>.
17 # Download: http://www.itechnology.de/front_content.php?idcat=87
18 #
19
20 # changed by: Rüdiger Sobeck
21 # last changed: 31-01-2006
22
23 # Configuration
24 #
25 CHECK_INTERVAL='120' # Check this often (in seconds)
26 DNS_RESOLVE_TRIES='3' # Try to resolve IPs this often (each try takes max. 2 seconds)
27 NICENESS='+5' # Adjust niceness of child processes: '-20' ... '+19'; '0' is default
28 ipfire_VPN_CONFIG='/var/ipfire/vpn/config' # Location of ipfire's vpn configuration file
29 ipfire_VPN_SETTINGS='/var/ipfire/vpn/settings' # Location of ipfire's vpn settings file
30 VERSION='1.6.3'
31
32 # Workaround for nonexistent "nl" command on ipfire 1.4.x
33 nl --help >/dev/null 2>&1
34 if test $? -ne 0; then
35 alias nl='cat'
36 fi
37
38 MyHost=`grep VPN_IP /var/ipfire/vpn/settings | cut --delimiter='=' --output-delimiter=' ' -f2`
39 MyIP=`cat /var/ipfire/red/local-ipaddress`
40 MyDynDnsIP=`ping -c 1 "$1" 2>/dev/null | head -n1 | awk '{print $3}' | tr -d '()' | tr -d ':'`
41
42 case "$1" in
43 'start' | '--start')
44 if test ! -r "$ipfire_VPN_CONFIG"; then
45 echo 'Error: cannot read ipfire VPN configuration file; exit.' >&2
46 exit 1
47 fi
48
49 mknod -m 0660 "/var/run/$(basename $0)" p >/dev/null 2>&1 # Create pipe for status-information
50
51 # Read VPN configuration and fork a child process for each VPN connection
52 #
53 while read line; do
54 VPN=($(echo $line | cut --delimiter=',' --output-delimiter=' ' -f1,2,3,5,6,12)) #
55 CONNR=${VPN[0]} # connection number
56 CONACTIVE=${VPN[1]} # active (on|off)
57 CONNAME=${VPN[2]} # connection name
58 CONTYPE=${VPN[3]} # connection type (host|net)
59 CONCERTPSK=${VPN[4]} # key type (cert|psk)
60 CONDNSNAME=${VPN[5]} # FQDN name of other side
61
62 echo -n "${CONACTIVE}" | grep -qi '^off$' && continue # Ignore: deactivated connections
63 echo -n "${CONTYPE}" | grep -qi '^host$' && continue # Ignore: Roadwarriors (->DPD)
64 # echo -n "${VPN[1]}${MyHost}" | grep -q '^[[:digit:]\.]\+$' && continue # Ignore: "left" and "right" side set to an IP
65
66 $0 'conn:' "${CONNAME}" "${MyHost}" "${CONDNSNAME}" "${CONNR}" >/dev/null 2>&1 & # Fork child process (parameters: "conn: NAME LEFT RIGHT NUMBER")
67 echo -n 'S'
68 done < "$ipfire_VPN_CONFIG"
69 echo Â"ÂStarte VPN-Watch"
70 exit 0 # Parent dies here... RIP
71 ;;
72 'stop' | '--stop')
73 # Terminate processes
74 for proc in $(pidof -x -o %PPID $(basename $0)); do
75 kill -15 $proc
76 echo -n 'T'
77 done
78 sleep 1
79 # Kill remaining processes
80 for proc in $(pidof -x -o %PPID $(basename $0)); do
81 kill -9 $proc
82 echo -n 'K'
83 done
84 rm -f "/var/run/$(basename $0)" # Remove pipe
85 echo "Stoppe VPN-Watch"
86 exit 0
87 ;;
88 'restart' | '--restart')
89 $0 stop
90 $0 start
91 exit 0
92 ;;
93 'status' | '--status')
94 echo "VPN-Watch ${VERSION} (mail: daniel@itechnology.de, web: www.itechnology.de/vpn-watch)"
95 if ps --no-heading axw | grep -v 'grep' | grep -q "$(basename $0) conn: "; then
96 trap '' USR1
97 killall -q -g -s USR1 -- $(basename $0)
98 sleep 1
99 cat "/var/run/$(basename $0)" | sort | nl # Read children's info from pipe
100 else
101 echo ' no instances running.'
102 fi
103 exit 0
104 ;;
105 'conn:')
106 # Children proceed here...
107 renice ${NICENESS:-0} -p $$ >/dev/null 2>&1 # Adjust niceness
108 shift # Remove the first positional parameter ("conn:"), as we don't need it anymore
109 ;;
110 *)
111 echo "Usage: $0 { start | stop | restart | status }" >&2
112 exit 1
113 ;;
114 esac
115
116 # Logging, signal handlers
117 #
118 alias log="logger -t '$(basename $0 | cut -d '.' -f 1) ${VERSION}' \(${1}\)"
119 trap 'log "terminated after ${RESTART_COUNT} restarts."' EXIT
120 trap 'echo "connection \"${1}\" restarted ${RESTART_COUNT} times" >>/var/run/$(basename $0)' USR1
121
122 log "started"
123
124 # Get IP of a FQDN... using 'arp', 'traceroute' or 'ping',
125 # because ipfire has no 'nslookup', 'host' or 'dig' command.
126 #
127 function get_ip () {
128 local RESULT=''
129 for ((i=1; ${i} <= ${DNS_RESOLVE_TRIES}; i++)); do
130 if which arp >/dev/null 2>&1; then
131 RESULT=$(arp "$1" 2>/dev/null | awk '{ print $2 }' | tr -d '()')
132 elif which traceroute >/dev/null 2>&1; then
133 RESULT=$(traceroute -m1 -q1 "$1" 2>/dev/null | head -n1 | awk '{ print $4 }' | tr -d '(),')
134 else
135 RESULT=$(ping -c 1 "$1" 2>/dev/null | head -n1 | awk '{print $3}' | tr -d '()' | tr -d ':')
136 fi
137 test -n "$RESULT" && break
138 done
139 test -z "$RESULT" && log "Warning: could not resolve ${1} after ${DNS_RESOLVE_TRIES} tries..."
140 echo -n "$RESULT"
141 }
142
143 function get_tunnelip () {
144 file=/var/tmp/$1.remoteip
145 local TRESULT=''
146 TVPN=`grep "$1" /var/ipfire/vpn/config| awk 'BEGIN{FS=","}{print $2}'`
147 DYNHOST=`grep "$1" /var/ipfire/vpn/config| awk 'BEGIN{FS=","}{print $12}'`
148 CONNR=`grep "$1" /var/ipfire/vpn/config| awk 'BEGIN{FS=","}{print $1}'`
149 REMOTEIP=`/usr/bin/ping -c 1 "$DYNHOST" 2>/dev/null | head -n1 | awk '{print $3}' | tr -d '()' | tr -d ':'`
150 if ! test -f $file; then
151 cat $REMOTEIP > $file
152 fi
153 OLDIP=`cat $file`
154 TUNIP=`ipsec whack --status | grep "$1"`
155 if [ "$TUNIP" != "" ]; then
156 TUNIP=`ipsec whack --status | grep "$1" | awk 'BEGIN{FS="["}{print $2}' | awk 'BEGIN{FS="---"}{print $3}'`
157 log "currently used tunnel IP = $TUNIP, current remote IP = $REMOTEIP"
158 echo $REMOTEIP > $file
159 TRESULT=${TUNIP}
160 fi
161
162 test -n "$TRESULT" && break
163 test -z "$TRESULT" && log "Warning: could not retrieve last used VPN tunnel IP..."
164 echo -n "$TRESULT"
165 }
166
167 # Restarts a VPN connection
168 #
169 function restart_vpn () {
170 if test -x /usr/local/bin/ipsecctrl; then
171 /usr/local/bin/ipsecctrl D "$1" # This works for ipfire 1.4.x
172 /usr/local/bin/ipsecctrl R # re-read secrets
173 /usr/local/bin/ipsecctrl S "$1" # start tunnel
174 else
175 ipsec auto --down "$1" # This works for ipfire 1.3.x
176 ipsec auto --unroute "$1"
177 ipsec auto --delete "$1"
178 ipsec auto --rereadall
179 ipsec auto --add "$1"
180 ipsec auto --route "$1"
181 ipsec auto --up "$1"
182 fi
183 }
184
185 # Get left and right IP
186 #
187 LEFT_IP_OLD=$MyIP
188 RIGHT_IP_OLD=$(get_ip $3)
189
190 # Infinite loop; checks, whether the IP of a left or right FQDN has changed.
191 # If so, the affected connection gets restarted; this is logged to syslog.
192 #
193 RESTART_COUNT=0
194 while :; do
195 sleep $CHECK_INTERVAL
196
197 # Skip check until IPSec is running
198 ipsec auto --status >/dev/null 2>&1 || continue
199
200 # get own IP (may have changed)
201 ThisHostIP=`cat /var/ipfire/red/local-ipaddress`
202
203 # this our own IP as reported in /var/ipfire/ppp/local-ipadress
204 LEFT_IP_NEW=$ThisHostIP
205 # check our own DYNDNS IP
206 LEFT_IP_DYN=$(get_ip $MyHost)
207 # this is DYNDNS IP of other side
208 RIGHT_IP_NEW=$(get_ip $3)
209 # this the last used (right) IP for VPN-Tunnel
210 RIGHT_TUN_IP_OLD=$(get_tunnelip $1)
211
212 # for whatever reason, ipsec did not notice our own IP has changed for this connection
213 if [ "${LEFT_IP_NEW}" != "${LEFT_IP_DYN}" ]; then
214 restart_vpn "$4"
215 let RESTART_COUNT++
216 log "Red IP = $LEFT_IP_NEW, IP by DynDNS = $LEFT_IP_DYN"
217 log 'incorrect dynamic IP in tunnel used: restarting connection...'
218 fi
219
220 # left or right IP has changed...
221 if test "${LEFT_IP_OLD} ${RIGHT_IP_OLD}" != "${LEFT_IP_NEW} ${RIGHT_IP_NEW}"; then
222 restart_vpn "$4"
223 let RESTART_COUNT++
224 log 'left or right IP has changed: restarting connection...'
225 fi
226
227 # right IP / IP of tunnel endpoint has changed...
228 if [ "$RIGHT_TUN_IP_OLD" != "" ]; then
229 if test "${RIGHT_TUN_IP_OLD}" != "${RIGHT_IP_NEW}"; then
230 restart_vpn "$4"
231 let RESTART_COUNT++
232 log 'VPN tunnel IP has changed: restarting connection...'
233 fi
234 fi
235
236 LEFT_IP_OLD=$LEFT_IP_NEW
237 RIGHT_IP_OLD=$RIGHT_IP_NEW
238 done
239