With an IPFire box behind NAT it is difficult to keep an IPsec VPN up all of the time. On-demand mode does not work when one side cannot initiate the connection.
This patch adds a script which will check every 5 minutes or when RED comes up if all VPNs are up and launch those which are not.
This should ensure that we are constantly attempting to establish the connection.
Additionally this patch changes that "always-on" VPNs will be "routed" like "on-demand" connections. When we see traffic, we will now automatically try to bring up the tunnel.
Signed-off-by: Michael Tremer michael.tremer@ipfire.org --- config/cron/crontab | 3 ++ config/rootfiles/common/aarch64/stage2 | 1 + config/rootfiles/common/stage2 | 1 + config/rootfiles/common/x86_64/stage2 | 1 + html/cgi-bin/vpnmain.cgi | 10 ++++-- src/misc-progs/ipsecctrl.c | 1 + src/scripts/ipsec-always-on | 65 ++++++++++++++++++++++++++++++++++ 7 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 src/scripts/ipsec-always-on
diff --git a/config/cron/crontab b/config/cron/crontab index 56801394e..46cbe6ece 100644 --- a/config/cron/crontab +++ b/config/cron/crontab @@ -30,6 +30,9 @@ HOME=/ # Update dynamic DNS records every five minutes. */5 * * * * [ -f "/var/ipfire/red/active" ] && /usr/bin/ddns update-all
+# Make sure VPNs are up +*/5 * * * * /usr/local/bin/ipsec-always-on + # Logwatch 05 0 * * * /usr/local/bin/logwatch > /var/log/logwatch/`date -I -d yesterday`; \ LOGWATCH_KEEP=$(sed -ne 's/^LOGWATCH_KEEP=([0-9]+)$/\1/p' /var/ipfire/logging/settings); \ diff --git a/config/rootfiles/common/aarch64/stage2 b/config/rootfiles/common/aarch64/stage2 index f4169a44e..eda34f743 100644 --- a/config/rootfiles/common/aarch64/stage2 +++ b/config/rootfiles/common/aarch64/stage2 @@ -95,6 +95,7 @@ usr/local/bin/convert-dns-settings usr/local/bin/convert-ovpn usr/local/bin/filesystem-cleanup usr/local/bin/hddshutdown +usr/local/bin/ipsec-always-on usr/local/bin/ipsec-interfaces usr/local/bin/makegraphs usr/local/bin/qosd diff --git a/config/rootfiles/common/stage2 b/config/rootfiles/common/stage2 index fca540431..cc0e1dea5 100644 --- a/config/rootfiles/common/stage2 +++ b/config/rootfiles/common/stage2 @@ -94,6 +94,7 @@ usr/local/bin/convert-dns-settings usr/local/bin/convert-ovpn usr/local/bin/filesystem-cleanup usr/local/bin/hddshutdown +usr/local/bin/ipsec-always-on usr/local/bin/ipsec-interfaces usr/local/bin/makegraphs usr/local/bin/qosd diff --git a/config/rootfiles/common/x86_64/stage2 b/config/rootfiles/common/x86_64/stage2 index cc67837e5..28a99ceec 100644 --- a/config/rootfiles/common/x86_64/stage2 +++ b/config/rootfiles/common/x86_64/stage2 @@ -96,6 +96,7 @@ usr/local/bin/convert-dns-settings usr/local/bin/convert-ovpn usr/local/bin/filesystem-cleanup usr/local/bin/hddshutdown +usr/local/bin/ipsec-always-on usr/local/bin/ipsec-interfaces usr/local/bin/makegraphs usr/local/bin/qosd diff --git a/html/cgi-bin/vpnmain.cgi b/html/cgi-bin/vpnmain.cgi index 43cdc5aa0..b3cd3e51e 100644 --- a/html/cgi-bin/vpnmain.cgi +++ b/html/cgi-bin/vpnmain.cgi @@ -453,7 +453,7 @@ sub writeipsecfiles {
my $start_action = $lconfighash{$key}[33]; if (!$start_action) { - $start_action = "start"; + $start_action = "route"; }
my $inactivity_timeout = $lconfighash{$key}[34]; @@ -466,13 +466,17 @@ sub writeipsecfiles { print CONF "\tauto=add\n"; print CONF "\trightsourceip=$lvpnsettings{'RW_NET'}\n"; } else { - print CONF "\tauto=$start_action\n"; - # If in on-demand mode, we terminate the tunnel # after 15 min of no traffic if ($start_action eq 'route' && $inactivity_timeout > 0) { print CONF "\tinactivity=$inactivity_timeout\n"; } + + # Always route connections so that we have the triggers + if ($start_action eq "start") { + $start_action = "route"; + } + print CONF "\tauto=$start_action\n"; }
# Fragmentation diff --git a/src/misc-progs/ipsecctrl.c b/src/misc-progs/ipsecctrl.c index 2a64775f0..54e3b3410 100644 --- a/src/misc-progs/ipsecctrl.c +++ b/src/misc-progs/ipsecctrl.c @@ -216,6 +216,7 @@ int main(int argc, char *argv[]) { safe_system("/usr/lib/firewall/ipsec-policy >/dev/null"); safe_system("/usr/local/bin/ipsec-interfaces >/dev/null"); safe_system("/usr/sbin/ipsec restart >/dev/null"); + safe_system("/usr/local/bin/ipsec-always-on >/dev/null"); exit(0); }
diff --git a/src/scripts/ipsec-always-on b/src/scripts/ipsec-always-on new file mode 100644 index 000000000..34cae169d --- /dev/null +++ b/src/scripts/ipsec-always-on @@ -0,0 +1,65 @@ +#!/bin/bash +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2020 IPFire Team # +# # +# 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 3 of the License, 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. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see http://www.gnu.org/licenses/. # +# # +############################################################################### + +VPN_CONFIG="/var/ipfire/vpn/config" + +VARS=( + id status name lefthost type ctype psk local local_id leftsubnets + remote_id remote rightsubnets x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 + x13 x14 x15 x16 x17 x18 x19 proto x20 x21 x22 + route x23 mode interface_mode interface_address interface_mtu rest +) + +# Load IPsec configuration +eval $(/usr/local/bin/readhash /var/ipfire/vpn/settings) + +log() { + logger -t ipsec "$@" +} + +main() { + # Do nothing if IPsec is disabled + if [ "${ENABLED}" != "on" ]; then + return 0 + fi + + # Do nothing if we are not online + if [ ! -e "/var/ipfire/red/active" ]; then + return 0 + fi + + local "${VARS[@]}" + while IFS="," read -r "${VARS[@]}"; do + # Skip disabled connections + [ "${status}" = "on" ] || continue + + # Skip all connections that are not in always-on mode + [ "${route}" = "start" ] || continue + + # If the connection is not up, try bringing it up + if ! ipsec status "${name}" | grep -q "INSTALLED"; then + log "Trying to start ${name}..." + ipsec stroke up-nb "${name}" &>/dev/null + fi + done < "${VPN_CONFIG}" +} + +main "$@" || exit $?