--- /dev/null
+#!/bin/bash
+###############################################################################
+# #
+# IPFire.org - A linux based firewall #
+# Copyright (C) 2024 Michael Tremer <michael.tremer@ipfire.org> #
+# #
+# 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/>. #
+# #
+###############################################################################
+# #
+# This script tries to keep WireGuard connections with dynamic peers alive #
+# #
+# It resolves the endpoint if it is an FQDN, and if so, will check if the #
+# currently connected endpoint matches any of the resolved IP addresses. If #
+# not it will reload the WireGuard configuration in the hope that wg will #
+# update the kernel with the new IP address and the connection comes back up #
+# again. #
+# #
+###############################################################################
+
+. /etc/sysconfig/rc
+. ${rc_functions}
+
+# Fetches the first endpoint that is currently active on the given interface
+current_endpoint() {
+ local intf="${1}"
+
+ local pubkey
+ local endpoint
+
+ # List the first endpoint (are there even more than one?)
+ wg show "${intf}" endpoints | while read -r pubkey endpoint; do
+ echo "${endpoint%:*}"
+ break
+ done
+
+ return 0
+}
+
+# Resolves a hostname
+resolve() {
+ local endpoint="${1}"
+
+ dig +short "A" "${endpoint}" 2>/dev/null
+}
+
+main() {
+ local -A settings=()
+
+ # Read WireGuard settings
+ readhash settings /var/ipfire/wireguard/settings
+
+ # Do nothing if WireGuard is not enabled
+ if [ "${settings[ENABLED]}" != "on" ]; then
+ return 0
+ fi
+
+ local line
+ while IFS=',' read -r -a line; do
+ local id="${line[0]}"
+ local enabled="${line[1]}"
+ local type="${line[2]}"
+ local name="${line[3]}"
+ local endpoint="${line[7]}"
+
+ # Only process enabled net-to-net connections
+ case "${enabled},${type}" in
+ on,net)
+ ;;
+ *)
+ continue
+ ;;
+ esac
+
+ # The endpoint must be an FQDN
+ case "${endpoint}" in
+ # Ignore IP addresses
+ [0-9]*.[0-9]*.[0-9]*.[0-9]*)
+ continue
+ ;;
+
+ # Ignore if we don't know the endpoint
+ "")
+ continue
+ ;;
+ esac
+
+ local address
+ local match=0
+
+ # Fetch the current endpoint address
+ local current_address="$(current_endpoint "wg${id}")"
+
+ # Walk through all IP addresses the FQDN resolves to
+ for address in $(resolve "${endpoint}"); do
+ if [ "${current_address}" = "${address}" ]; then
+ match=1
+ break
+ fi
+ done
+
+ # If there has been no match, we have to reload everything
+ if [ "${match}" -eq 0 ]; then
+ exec /etc/init.d/wireguard reload
+ fi
+ done < /var/ipfire/wireguard/peers
+
+ return 0
+}
+
+main "$@" || exit $?