blob: 3ea9fad76ba4924c249324a3c1a6accf3749b1ba [file] [log] [blame] [raw]
#!/bin/sh
# Copyright 2015-2024 Rivoreo
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
# IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# May specify custom name servers to override resolv.conf(5)
NAME_SERVERS=
[ -f /etc/default/wireguard-peer-resolver ] && . /etc/default/wireguard-peer-resolver
is_inet4_address() {
[ "${1#.}" = "$1" ] && [ "${1%.}" = "$1" ] || return
local ORIG_IFS="$IFS"
IFS=.
set -- $1
IFS="$ORIG_IFS"
[ $# = 4 ] || return
local i=1 v
while [ $i -lt 5 ]; do
eval "v=\"\${$i}\""
[ "$v" -le 255 ] && [ "$v" -ge 0 ] || return
[ "$v" -gt 0 ] && [ "${v#0}" != "$v" ] && return 1
i=$((i+1))
done
[ $1 != 0 ] && return
[ $2 = 0 ] || return
[ $3 = 0 ] || return
[ $4 = 0 ] || return
true
}
is_inet6_address() {
printf %s\\n "$1" | grep -Eq '^\[(([0-9a-f]{1,4}:){7}[0-9a-f]{1,4}|([0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|([0-9a-f]{1,4})?::([0-9a-f]{1,4})?)\]$'
}
parse_key_value() {
case "$1" in
*=*)
key="${1%%=*}"
key="${key%%[ ]*}"
value="${1#*=}"
local trim_value
while trim_value="${value#[ ]}" && [ "$trim_value" != "$value" ]; do value="$trim_value"; done
;;
*\ *|*\ *)
key="${1%%[ ]*}"
value="${1#*[ ]}"
;;
*)
false
;;
esac
}
unset LC_ALL LC_MESSAGES
unset LANGUAGE
set -f
while true; do
sleep 60
#interfaces="`wg show interfaces`" || continue
#for i in $interfaces; do
echo
wg show all latest-handshakes
done | while read -r line; do
if [ -z "$line" ]; then
t="`date +%s`"
continue
fi
set -- $line
[ $# != 3 ] && continue
interface="$1"
publickey="$2"
handshake="$3"
[ $((t-handshake)) -lt 240 ] && continue
[ -f "/etc/wireguard/$interface.conf" ] || continue
section=
found_peer=
while read -r line; do case "$line" in
\[[Pp][Ee][Ee][Rr]\]*)
[ -n "$found_peer" ] && break
section=peer
name=
port=
;;
\[*\]*)
[ -n "$found_peer" ] && break
section=
;;
?*=*)
[ "$section" != peer ] && continue
parse_key_value "$line" || continue
case "$key" in
[Pp][Uu][Bb][Ll][Ii][Cc][Kk][Ee][Yy])
[ "$value" != "$publickey" ] && continue
found_peer=1
[ -n "$name" ] && [ -n "$loop_gre_interface" ] && [ -n "$loop_gre_domain" ] && break
;;
[Ee][Nn][Dd][Pp][Oo][Ii][Nn][Tt])
name="${value%:*}"
port="${value##*:}"
[ -n "$found_peer" ] && [ -n "$loop_gre_interface" ] && [ -n "$loop_gre_domain" ] && [ -n "$loop_gre_key" ] && break
;;
\#[Gg][Rr][Ee][Tt][Uu][Nn][Nn][Ee][Ll][Ii][Nn][Tt][Ee][Rr][Ff][Aa][Cc][Ee])
loop_gre_interface=1
gre_tunnel_interface="$value"
[ -n "$name" ] && [ -n "$found_peer" ] && [ -n "$loop_gre_domain" ] && [ -n "$loop_gre_key" ] && break
;;
\#[Gg][Rr][Ee][Tt][Uu][Nn][Nn][Ee][Ll][Dd][Oo][Mm][Aa][Ii][Nn])
loop_gre_domain=1
gre_tunnel_domain="$value"
[ -n "$found_peer" ] && [ -n "$loop_gre_interface" ] && [ -n "$loop_gre_interface" ] && [ -n "$loop_gre_key" ] && break
;;
\#[Gg][Rr][Ee][Tt][Uu][Nn][Nn][Ee][Ll][Kk][Ee][Yy])
loop_gre_key=1
gre_tunnel_key="$value"
[ -n "$found_peer" ] && [ -n "$loop_gre_interface" ] && [ -n "$loop_gre_interface" ] && [ -n "$loop_gre_domain" ] && break
;;
esac
;;
esac done < "/etc/wireguard/$interface.conf"
if [ -n "$found_peer" ] && [ -n "$name" ] && ! is_inet4_address "$name" && ! is_inet6_address "$name" &&
if [ -z "${name#\`*\`}" ]; then
command="${name%\`}"
command="${command#\`}"
address="`sh -c \"$command\"`"
elif address="`LANG=C host -4 -t A -- \"$name\" $NAME_SERVERS`" && [ "${address%%* has no A record}" = "$address" ]; then
address="${address%%
*}"
address="${address##* has address }"
elif address="`LANG=C host -4 -t AAAA -- \"$name\" $NAME_SERVERS`" && [ "${address%%* has no AAAA record}" = "$address" ]; then
address="${address%%
*}"
address="${address##* has IPv6 address }"
else
false
fi
then
wg set "$interface" peer "$publickey" endpoint "$address:$port"
fi
if [ -n "$gre_tunnel_interface" ] && [ -n "$gre_tunnel_domain" ] && ! is_inet4_address "$name" && ! is_inet6_address "$name" &&
if address="`LANG=C host -4 -t A -- \"$gre_tunnel_domain\" $NAME_SERVERS`" && [ "${address%%* has no A record}" = "$address" ]; then
address="${address%%
*}"
address="${address##* has address }"
elif address="`LANG=C host -4 -t AAAA -- \"$gre_tunnel_domain\" $NAME_SERVERS`" && [ "${address%%* has no AAAA record}" = "$address" ]; then
address="${address%%
*}"
address="${address##* has IPv6 address }"
else
false
fi
then
if [ -n "$gre_tunnel_key" ]; then
ip tunnel change $gre_tunnel_interface mode gre remote $address ttl inherit key $gre_tunnel_key
else
ip tunnel change $gre_tunnel_interface mode gre remote $address ttl inherit
fi
fi
done