Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wg-quick: fix dns cleaning on MacOS #22

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

nesstord
Copy link

@nesstord nesstord commented Nov 14, 2023

I found out that sometimes on MacOS calling wg-quick to shut down Wireguard doesn't return the original DNS servers that are specified in the network services.

To see why that happens, I added a file output on the line 327 in the function monitor_daemon and wrote a little script that tries to detect and log the problem.

# wireguard-tools/src/wg-quick/darwin.bash

# ...

monitor_daemon() {
	echo "[+] Backgrounding route monitor" >&2
	(trap 'del_routes; del_dns; exit 0' INT TERM EXIT
	#exec >/dev/null 2>&1
        exec >> /Users/user/wg-quick.log 2>&1
	exec 19< <(exec route -n monitor)
	local event bpid=$BASHPID mpid=$!
	[[ ${#DNS[@]} -gt 0 ]] && trap set_dns ALRM
  
  # ...
 
}
# test_dns.bash

#!/usr/bin/env bash

LOG_FILE=/Users/user/wg-quick.log

echo "[$(date -u)] start test" >> $LOG_FILE

declare -A found_services
get_response=""

{ read -r _ && while read -r service; do
		[[ $service == "*"* ]] && service="${service:1}"
		get_response="$(networksetup -getdnsservers "$service")"
		[[ $get_response == *" "* ]] && get_response="Empty"
		[[ -n $get_response ]] && found_services["$service"]="$get_response"
		echo "[$(date -u)] $service: $get_response" >> $LOG_FILE
done; } < <(networksetup -listallnetworkservices)

for (( i = 0; ; i++ )); do
    echo "[$(date -u)] loop $i" >> $LOG_FILE

    echo "[$(date -u)] up" >> $LOG_FILE
    wg-quick up "$1" > /dev/null 2>&1
    sleep $(( RANDOM % 30 ))
    echo "[$(date -u)] down" >> $LOG_FILE
    wg-quick down "$1" > /dev/null 2>&1
    sleep 3 # wait for graceful shutdown

    for service in "${!found_services[@]}"; do
        get_response="$(networksetup -getdnsservers "$service")"
        [[ $get_response == *" "* ]] && get_response="Empty"
        [[ $get_response != "${found_services["$service"]}" ]] || continue
        msg="dns error on loop $i, service $service, expected ${found_services["$service"]}, got $get_response"
        echo "$msg"
        osascript -e "display notification \"$msg\" with title \"Found\""
        exit
    done
done

I ran the script using
sudo ./test_dns.bash ~/wg0.conf

In this case, the problem occurred on the 82 try.

// /Users/user/wg-quick.log

[Mon Nov 13 11:08:09 UTC 2023] start test
[Mon Nov 13 11:08:09 UTC 2023] Thunderbolt Bridge: Empty
[Mon Nov 13 11:08:09 UTC 2023] Wi-Fi: Empty
[Mon Nov 13 11:08:09 UTC 2023] iPhone USB: Empty
[Mon Nov 13 11:08:09 UTC 2023] loop 0
[Mon Nov 13 11:08:09 UTC 2023] up

...

[Mon Nov 13 11:36:23 UTC 2023] loop 81
[Mon Nov 13 11:36:23 UTC 2023] up
[#] networksetup -setdnsservers iPhone USB 8.8.8.8 8.8.4.4
[#] networksetup -setsearchdomains iPhone USB Empty
[#] networksetup -setdnsservers Wi-Fi 8.8.8.8 8.8.4.4
[#] networksetup -setsearchdomains Wi-Fi Empty
[#] networksetup -setdnsservers Thunderbolt Bridge 8.8.8.8 8.8.4.4
[#] networksetup -setsearchdomains Thunderbolt Bridge Empty
[#] networksetup -setdnsservers iPhone USB 8.8.8.8 8.8.4.4
[#] networksetup -setsearchdomains iPhone USB Empty
[#] networksetup -setdnsservers Wi-Fi 8.8.8.8 8.8.4.4
[#] networksetup -setsearchdomains Wi-Fi Empty
[#] networksetup -setdnsservers Thunderbolt Bridge 8.8.8.8 8.8.4.4
[#] networksetup -setsearchdomains Thunderbolt Bridge Empty
[Mon Nov 13 11:36:48 UTC 2023] down
[#] networksetup -setdnsservers iPhone USB Empty
[#] networksetup -setsearchdomains iPhone USB Empty
[#] networksetup -setdnsservers Wi-Fi Empty
[#] networksetup -setsearchdomains Wi-Fi Empty
[#] networksetup -setdnsservers Thunderbolt Bridge Empty
[#] networksetup -setsearchdomains Thunderbolt Bridge Empty
[Mon Nov 13 11:36:51 UTC 2023] loop 82
[Mon Nov 13 11:36:51 UTC 2023] up
[#] networksetup -setdnsservers iPhone USB 8.8.8.8 8.8.4.4
[#] networksetup -setsearchdomains iPhone USB Empty
[#] networksetup -setdnsservers Wi-Fi 8.8.8.8 8.8.4.4
[#] networksetup -setsearchdomains Wi-Fi Empty
[#] networksetup -setdnsservers Thunderbolt Bridge 8.8.8.8 8.8.4.4
[#] networksetup -setsearchdomains Thunderbolt Bridge Empty
[Mon Nov 13 11:36:55 UTC 2023] down
[#] networksetup -setdnsservers iPhone USB Empty
[#] networksetup -setsearchdomains iPhone USB Empty
[#] networksetup -setdnsservers Wi-Fi Empty
[#] networksetup -setsearchdomains Wi-Fi Empty
[#] networksetup -setdnsservers Thunderbolt Bridge Empty
[#] networksetup -setsearchdomains Thunderbolt Bridge Empty
[#] networksetup -setdnsservers iPhone USB 8.8.8.8 8.8.4.4 // !!! set_dns is called after del_dns !!!
[#] networksetup -setsearchdomains iPhone USB Empty
[#] networksetup -setdnsservers Wi-Fi 8.8.8.8 8.8.4.4
[#] networksetup -setsearchdomains Wi-Fi Empty
[#] networksetup -setdnsservers Thunderbolt Bridge 8.8.8.8 8.8.4.4
[#] networksetup -setsearchdomains Thunderbolt Bridge Empty

As you see, sometimes set_dns is called after del_dns. I decided to implement a very simple fix that doesn't change the original logic: I added a flag that will stop the execution of set_dns if the monitor_daemon subprocess has finished. You can check out the changes in the commit.

I've been using this fix for about a week, and the bug hasn't occurred since then.
It could be used as a temporary solution until the proper fix is implemented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

1 participant