-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathvpnwatchdog
executable file
·158 lines (142 loc) · 4.62 KB
/
vpnwatchdog
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/bin/sh
# Monitor a VPN connection set up by vpnc on Linux
# with cron and the dash shell.
#
# Use as root (with sudo) to check the VPN connection
# and to try & activate it:
# $ sudo vpnwatchdog [-v|--debug]
#
# Use as a normal user to check the VPN connection:
# $ vpnwatchdog
# Result is one of:
# VPN up: <local IP address> -> <public IP Address>
# VPN down
#
# Prerequisite: install 'vpnc', for example on Debian and derivatives:
# $ sudo apt install vpnc
#
# Create a vpnc configuration file. This script assumes that the
# configuration file is named home.conf, adjust below under 'Constants'.
# $ sudo nano /etc/vpnc/home.conf
#
# Example configuration to connect to an AVM Fritz!Box modem:
# IPSec gateway <server name = fritzbox public name or address>
# IPSec ID <user name on fritzbox>
# IPSec secret <shared secret from VPN settings for this user>
# IKE Authmode psk
# Xauth username <user name again>
# Xauth password <fritzbox password for user>
# local port 0
# DPD idle timeout (our side) 0
#
# Test the connection:
# $ sudo vpnc home.conf
# $ ip a
# $ sudo vpnc-disconnect
#
# Install this script on the system, for example in /usr/local/bin
# and make it executable:
# $ sudo cp vpnwatchdog /usr/local/bin/
# $ sudo chmod 755 /usr/local/bin/vpnwatchdog
#
# Edit the root user's cron jobs:
# $ sudo VISUAL=nano crontab -e
#
# Because the script location might not be in the $PATH for cron jobs,
# use its full path. For example, to check every hour on the 27th minute:
# 27 * * * * /usr/local/bin/vpnwatchdog
#
# Exit codes:
# 0 : VPN is up (success) or user is not root
# 1 : no network, like, at all
# 2 : vpn server unreachable
# 3 : vpnc not running
# 4 : no connection to vpn server
# 5 : no route to internet via vpn
# 6 : unable to (re-) start vpnc
#
# LIMITATIONS:
# Only tested without IPv6. Will probably fail if 'ip' returns
# multiple addresses.
# System might have multiple VPN connections tun1, tun2, etc.
# Will fail if the VPN connection to be monitored is not the
# same as the one defined under 'Constants'.
# Constants
MYSERV='<my vpn server>'
MYCONF='home.conf'
MYINTF='tun0'
MYADDR='https://ipecho.net/plain'
# Program locations
ID='/usr/bin/id'
PING='/usr/bin/ping'
PGREP='/usr/bin/pgrep'
AWK='/usr/bin/awk'
CUT='/usr/bin/cut'
CURL='/usr/bin/curl'
SLEEP='/usr/bin/sleep'
IP='/usr/sbin/ip'
VPNC='/usr/sbin/vpnc'
VPND='/usr/sbin/vpnc-disconnect'
# Variables
VPN_PID=
VPN_LAN=
VPN_WAN=
# Extra info with command line option -v or --debug
[ "$1" = "-v" -o "$1" = "--debug" ] && DEBUG=1 || DEBUG=
vpn_pid () {
[ "$DEBUG" ] && echo -n 'Getting PID ... ' >&2
VPN_PID=$($PGREP -xf "$VPNC $MYCONF" 2>/dev/null)
[ -z "$VPN_PID" ] && VPN_PID=$($PGREP -xf "vpnc $MYCONF" 2>/dev/null)
[ -z "$VPN_PID" ] && VPN_PID=$($PGREP -f "vpnc $MYCONF" 2>/dev/null)
[ -z "$VPN_PID" ] && VPN_PID=$($PGREP vpnc 2>/dev/null)
[ "$DEBUG" ] && echo "$VPN_PID" >&2
[ -n "$VPN_PID" ] && RET=0 || RET=3
return $RET
}
vpn_lan () {
[ "$DEBUG" ] && echo -n 'Getting LAN ... ' >&2
VPN_LAN=$($IP -o -c=never a show up scope global dev "$MYINTF" 2>/dev/null | $AWK '{print $4}' | $CUT -d/ -f1)
[ "$DEBUG" ] && echo "$VPN_LAN" >&2
[ -n "$VPN_LAN" ] && RET=0 || RET=4
return $RET
}
vpn_wan () {
[ "$DEBUG" ] && echo -n 'Getting WAN ... ' >&2
VPN_WAN=$($CURL -s --connect-timeout 3 --interface "$MYINTF" "$MYADDR" 2>/dev/null)
[ "$DEBUG" ] && echo "$VPN_WAN" >&2
[ -n "$VPN_WAN" ] && RET=0 || RET=5
return $RET
}
vpn_start () {
[ "$DEBUG" ] && echo -n 'Starting VPN ... ' >&2
RES=$($VPNC $MYCONF 2>&1)
[ $? -eq 0 ] && RET=0 || RET=6
[ "$DEBUG" ] && echo "$RES" >&2
return $RET
}
vpn_restart () {
[ "$DEBUG" ] && echo -n 'Restarting VPN ... ' >&2
RES=$($VPND 2>&1)
[ "$DEBUG" ] && echo "$RES" >&2
T="$1" && [ -z "$T" -o "$T" -lt 1 ] && T=1
$SLEEP "$T"
vpn_start
}
if [ "$($ID -u)" -eq 0 ]; then
# Has network interface?
$PING -c 1 -w 1 -q localhost >/dev/null 2>&1 || exit 1
# Destination reachable?
$PING -c 1 -w 3 -q "$MYSERV" >/dev/null 2>&1 || exit 2
# Test if running, start if not, test again, exit if fail
vpn_pid || { vpn_start && vpn_pid || exit $?; }
# Test for connection to server, restart if down, test again, exit if fail
vpn_lan || { vpn_restart && vpn_pid && vpn_lan || exit $?; }
# Test for remote endpoint, slow restart if down, test again, exit if fail
vpn_wan || { vpn_restart 3 && vpn_pid && vpn_lan && vpn_wan || exit $?; }
# Show working configuration if DEBUG is set
[ "$DEBUG" ] && echo "VPN $VPN_PID $VPN_LAN $VPN_WAN" >&2
else
# User is not root: show current configuration
vpn_pid && vpn_lan && vpn_wan && echo "VPN up: $VPN_LAN -> $VPN_WAN" || echo 'VPN down'
fi
exit 0