From 9a68aedba47182d1f2193f4055357b113da19b74 Mon Sep 17 00:00:00 2001 From: Orwa Diraneyya <107997002+diraneyya@users.noreply.github.com> Date: Sat, 25 Oct 2025 20:56:08 +0200 Subject: [PATCH 1/5] allow specifying interface name On Mac OS X and while using `wg-quick` it is possible that the config base filename be `wg1.conf` while the actual interface name is something like `utun4`. In this case, this improvement allows us to enter something like: ```bash sudo ./reresolve-dns.sh /opt/homebrew/etc/wireguard/wg1.conf utun4 ``` (on Mac OS X, when installing wireguard-tools using homebrew, elevated privileges are needed when running `wg`) Signed-off-by: Orwa Diraneyya <107997002+diraneyya@users.noreply.github.com> --- contrib/reresolve-dns/reresolve-dns.sh | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/contrib/reresolve-dns/reresolve-dns.sh b/contrib/reresolve-dns/reresolve-dns.sh index 711c3325..9f5b47e9 100755 --- a/contrib/reresolve-dns/reresolve-dns.sh +++ b/contrib/reresolve-dns/reresolve-dns.sh @@ -8,14 +8,31 @@ shopt -s nocasematch shopt -s extglob export LC_ALL=C +show_usage() { + printf "%sUSAGE:%s %s []%s\n" \ + "$(tput smul)$(tput setaf 3)" "$(tput rmul)" \ + "$(basename "$0")" "$(tput sgr0)" + if [ -n "$INTERFACE" ]; then + printf "%s(Note that in your invocation, was set to '$INTERFACE')%s\n" \ + "$(tput dim)$(tput setaf 3)" "$(tput sgr0)" + fi + exit 0 +} + CONFIG_FILE="$1" [[ $CONFIG_FILE =~ ^[a-zA-Z0-9_=+.-]{1,15}$ ]] && CONFIG_FILE="/etc/wireguard/$CONFIG_FILE.conf" [[ $CONFIG_FILE =~ /?([a-zA-Z0-9_=+.-]{1,15})\.conf$ ]] + +if ! [ -f "$CONFIG_FILE" ]; then show_usage; fi + INTERFACE="${BASH_REMATCH[1]}" +INTERFACE="${2:-$INTERFACE}" process_peer() { [[ $PEER_SECTION -ne 1 || -z $PUBLIC_KEY || -z $ENDPOINT ]] && return 0 - [[ $(wg show "$INTERFACE" latest-handshakes) =~ ${PUBLIC_KEY//+/\\+}\ ([0-9]+) ]] || return 0 + LATEST_HANDSHAKE="$(wg show "$INTERFACE" latest-handshakes 2>/dev/null || true)" + if [ -z "$LATEST_HANDSHAKE" ]; then show_usage; fi + [[ "$LATEST_HANDSHAKE" =~ ${PUBLIC_KEY//+/\\+}\ ([0-9]+) ]] || return 0 (( ($EPOCHSECONDS - ${BASH_REMATCH[1]}) > 135 )) || return 0 wg set "$INTERFACE" peer "$PUBLIC_KEY" endpoint "$ENDPOINT" reset_peer_section From 88bb4ee74dcc0bd9bdedb5421dcb9173a0c92915 Mon Sep 17 00:00:00 2001 From: Orwa Diraneyya <107997002+diraneyya@users.noreply.github.com> Date: Sat, 25 Oct 2025 21:15:59 +0200 Subject: [PATCH 2/5] add logging support for cron jobs In this improvement, redirecting output using `>>` results in a more meaningful output Signed-off-by: Orwa Diraneyya <107997002+diraneyya@users.noreply.github.com> --- contrib/reresolve-dns/reresolve-dns.sh | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/contrib/reresolve-dns/reresolve-dns.sh b/contrib/reresolve-dns/reresolve-dns.sh index 9f5b47e9..b93d8a7d 100755 --- a/contrib/reresolve-dns/reresolve-dns.sh +++ b/contrib/reresolve-dns/reresolve-dns.sh @@ -9,12 +9,16 @@ shopt -s extglob export LC_ALL=C show_usage() { - printf "%sUSAGE:%s %s []%s\n" \ - "$(tput smul)$(tput setaf 3)" "$(tput rmul)" \ - "$(basename "$0")" "$(tput sgr0)" - if [ -n "$INTERFACE" ]; then - printf "%s(Note that in your invocation, was set to '$INTERFACE')%s\n" \ - "$(tput dim)$(tput setaf 3)" "$(tput sgr0)" + if [ -t 1 ]; then + printf "%sUSAGE:%s %s []%s\n" \ + "$(tput smul)$(tput setaf 3)" "$(tput rmul)" \ + "$(basename "$0")" "$(tput sgr0)" + if [ -n "$INTERFACE" ]; then + printf "%s(Note that in your invocation, was set to '$INTERFACE')%s\n" \ + "$(tput dim)$(tput setaf 3)" "$(tput sgr0)" + fi + else + printf "ERROR: %s\n" "$0" fi exit 0 } @@ -35,6 +39,9 @@ process_peer() { [[ "$LATEST_HANDSHAKE" =~ ${PUBLIC_KEY//+/\\+}\ ([0-9]+) ]] || return 0 (( ($EPOCHSECONDS - ${BASH_REMATCH[1]}) > 135 )) || return 0 wg set "$INTERFACE" peer "$PUBLIC_KEY" endpoint "$ENDPOINT" + if ! [ -t 1 ]; then + printf "HANDSHAKES STOPPED: RE-RESOLVING ENDPOINT '%s'\n" "$ENDPOINT" + fi reset_peer_section } From f8a429a659cb3673b7a1cc0ee9e63fb154128814 Mon Sep 17 00:00:00 2001 From: Orwa Diraneyya <107997002+diraneyya@users.noreply.github.com> Date: Sun, 26 Oct 2025 07:07:45 +0100 Subject: [PATCH 3/5] support bash 3.2 Since the shebang line refers to bash at /bin/bash and since on most Mac OS X systems this location contains an outdated bash version (3.2), I have added a polyfill for the $EPOCHSECONDS env variable which otherwise would lead to this script failing on early bash versions that do not support it. I took this path because it is always better to support older bash versions regardless of the choice of interpreter and since it was all that we needed to run the script on bash 3.2 Signed-off-by: Orwa Diraneyya <107997002+diraneyya@users.noreply.github.com> --- contrib/reresolve-dns/reresolve-dns.sh | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/contrib/reresolve-dns/reresolve-dns.sh b/contrib/reresolve-dns/reresolve-dns.sh index b93d8a7d..b99d2614 100755 --- a/contrib/reresolve-dns/reresolve-dns.sh +++ b/contrib/reresolve-dns/reresolve-dns.sh @@ -3,11 +3,16 @@ # # Copyright (C) 2015-2020 Jason A. Donenfeld . All Rights Reserved. +if [ -n "$DEBUG" ]; then set -x; fi + set -e shopt -s nocasematch shopt -s extglob export LC_ALL=C +# Fix for bash 3 +EPOCHSECONDS=$(date +'%s') + show_usage() { if [ -t 1 ]; then printf "%sUSAGE:%s %s []%s\n" \ @@ -24,11 +29,11 @@ show_usage() { } CONFIG_FILE="$1" +if ! [ -f "$CONFIG_FILE" ]; then show_usage; fi + [[ $CONFIG_FILE =~ ^[a-zA-Z0-9_=+.-]{1,15}$ ]] && CONFIG_FILE="/etc/wireguard/$CONFIG_FILE.conf" [[ $CONFIG_FILE =~ /?([a-zA-Z0-9_=+.-]{1,15})\.conf$ ]] -if ! [ -f "$CONFIG_FILE" ]; then show_usage; fi - INTERFACE="${BASH_REMATCH[1]}" INTERFACE="${2:-$INTERFACE}" From 90b9444633ae84a2e6aead175ff563dfa2bf1c44 Mon Sep 17 00:00:00 2001 From: Orwa Diraneyya <107997002+diraneyya@users.noreply.github.com> Date: Mon, 27 Oct 2025 08:48:52 +0100 Subject: [PATCH 4/5] fixed bugs and improved debugging capabilities It is possible now to retain xtrace output for each exit code using carefully crafted cron job invocation while also attaching useful information Signed-off-by: Orwa Diraneyya <107997002+diraneyya@users.noreply.github.com> --- contrib/reresolve-dns/reresolve-dns.sh | 71 ++++++++++++++++++++------ 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/contrib/reresolve-dns/reresolve-dns.sh b/contrib/reresolve-dns/reresolve-dns.sh index b99d2614..f7427567 100755 --- a/contrib/reresolve-dns/reresolve-dns.sh +++ b/contrib/reresolve-dns/reresolve-dns.sh @@ -3,33 +3,50 @@ # # Copyright (C) 2015-2020 Jason A. Donenfeld . All Rights Reserved. -if [ -n "$DEBUG" ]; then set -x; fi +# This script was modified by Orwa Diraneyya specifically for being used on a modern +# Mac OS X system as a cronjob using something like: +# * * * * SUDO_ASKPASS="$HOME"/.config/askpass sudo -A \ +# PATH="$PATH:/opt/homebrew/bin" DEBUG=1 \ +# "$HOME"/.config/wireguard/reresolve-dns.sh \ +# /opt/homebrew/etc/wireguard/wgX.conf utunX \ +# >>/tmp/wireguard.log 2>/tmp/wireguard.debug || \ +# cp /tmp/wireguard.debug /tmp/wireguard.debug."$?" + +if [ -n "$DEBUG" ]; then + set -x + BASH_XTRACEFD=2 + # Append useful information to the end of the xtrace log when debugging + trap "set +x; printf 'PATH=%s\n' \"$PATH\" >&2; id >&2; date >&2" EXIT +fi -set -e shopt -s nocasematch shopt -s extglob export LC_ALL=C -# Fix for bash 3 -EPOCHSECONDS=$(date +'%s') +# Fix for bash 3.2 +if [ -z "$EPOCHSECONDS" ]; then + EPOCHSECONDS=$(date +'%s') +fi show_usage() { if [ -t 1 ]; then printf "%sUSAGE:%s %s []%s\n" \ - "$(tput smul)$(tput setaf 3)" "$(tput rmul)" \ + "$(tput smul)$(tput setaf 2)" "$(tput rmul)" \ "$(basename "$0")" "$(tput sgr0)" if [ -n "$INTERFACE" ]; then printf "%s(Note that in your invocation, was set to '$INTERFACE')%s\n" \ - "$(tput dim)$(tput setaf 3)" "$(tput sgr0)" + "$(tput dim)$(tput setaf 7)" "$(tput sgr0)" fi else - printf "ERROR: %s\n" "$0" + printf "ERROR: %s %s (%s)\n" "$(basename "$0")" "$*" "$(date)" fi - exit 0 } CONFIG_FILE="$1" -if ! [ -f "$CONFIG_FILE" ]; then show_usage; fi +if ! [ -f "$CONFIG_FILE" ]; then + show_usage "$@" + exit 2 +fi [[ $CONFIG_FILE =~ ^[a-zA-Z0-9_=+.-]{1,15}$ ]] && CONFIG_FILE="/etc/wireguard/$CONFIG_FILE.conf" [[ $CONFIG_FILE =~ /?([a-zA-Z0-9_=+.-]{1,15})\.conf$ ]] @@ -38,15 +55,22 @@ INTERFACE="${BASH_REMATCH[1]}" INTERFACE="${2:-$INTERFACE}" process_peer() { - [[ $PEER_SECTION -ne 1 || -z $PUBLIC_KEY || -z $ENDPOINT ]] && return 0 - LATEST_HANDSHAKE="$(wg show "$INTERFACE" latest-handshakes 2>/dev/null || true)" - if [ -z "$LATEST_HANDSHAKE" ]; then show_usage; fi - [[ "$LATEST_HANDSHAKE" =~ ${PUBLIC_KEY//+/\\+}\ ([0-9]+) ]] || return 0 - (( ($EPOCHSECONDS - ${BASH_REMATCH[1]}) > 135 )) || return 0 + # Only process peer sections in the configuration, a non-peer section is skipped without erroring + [[ "$PEER_SECTION" -ne 1 ]] && return 0 + [ -z "$PUBLIC_KEY" ] && return 3 + [ -z "$ENDPOINT" ] && return 4 + LATEST_HANDSHAKE="$(wg show "$INTERFACE" latest-handshakes || true)" + [[ "$LATEST_HANDSHAKE" =~ ${PUBLIC_KEY//+/\\+}\ ([0-9]+) ]] || return 5 + DISCONNECT_DURATION=$(($EPOCHSECONDS - ${BASH_REMATCH[1]})) + [[ "$DISCONNECT_DURATION" =~ ^[0-9]+$ ]] || return 6 + [ "$DISCONNECT_DURATION" -gt 135 ] || return 0 + wg set "$INTERFACE" peer "$PUBLIC_KEY" endpoint "$ENDPOINT" if ! [ -t 1 ]; then - printf "HANDSHAKES STOPPED: RE-RESOLVING ENDPOINT '%s'\n" "$ENDPOINT" + printf "HANDSHAKE ABSENT FOR %s SECONDS: RE-RESOLVING ENDPOINT '%s'\n" \ + "$DISCONNECT_DURATION" "$ENDPOINT" fi + reset_peer_section } @@ -61,7 +85,14 @@ while read -r line || [[ -n $line ]]; do stripped="${line%%\#*}" key="${stripped%%=*}"; key="${key##*([[:space:]])}"; key="${key%%*([[:space:]])}" value="${stripped#*=}"; value="${value##*([[:space:]])}"; value="${value%%*([[:space:]])}" - [[ $key == "["* ]] && { process_peer; reset_peer_section; } + [[ $key == "["* ]] && { + process_peer || { + EXIT_CODE=$? + show_usage "$@" + exit $EXIT_CODE + } + reset_peer_section; + } [[ $key == "[Peer]" ]] && PEER_SECTION=1 if [[ $PEER_SECTION -eq 1 ]]; then case "$key" in @@ -70,4 +101,10 @@ while read -r line || [[ -n $line ]]; do esac fi done < "$CONFIG_FILE" -process_peer + +process_peer || { + EXIT_CODE=$? + show_usage "$@" + exit $EXIT_CODE +} + From 970f28e398ca9678651ff802bfb854f0aa954b86 Mon Sep 17 00:00:00 2001 From: Orwa Diraneyya <107997002+diraneyya@users.noreply.github.com> Date: Mon, 27 Oct 2025 08:50:49 +0100 Subject: [PATCH 5/5] re-enabled strict error handling Signed-off-by: Orwa Diraneyya <107997002+diraneyya@users.noreply.github.com> --- contrib/reresolve-dns/reresolve-dns.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/reresolve-dns/reresolve-dns.sh b/contrib/reresolve-dns/reresolve-dns.sh index f7427567..6b1e159b 100755 --- a/contrib/reresolve-dns/reresolve-dns.sh +++ b/contrib/reresolve-dns/reresolve-dns.sh @@ -19,6 +19,7 @@ if [ -n "$DEBUG" ]; then trap "set +x; printf 'PATH=%s\n' \"$PATH\" >&2; id >&2; date >&2" EXIT fi +set -e shopt -s nocasematch shopt -s extglob export LC_ALL=C