WireGuard on OS X with bash v3

Bernhard Ehlers wg at bernhard-ehlers.de
Mon Oct 1 09:11:25 CEST 2018


I can understand, that the devs don’t want to use the old bash v3 used by Apple.
But from a users post of view it’s not that nice, that the installation of a newer bash
is needed.

So I had a look at the wg-quick for Darwin. The only changes needed to support
both bash versions is to get rid of the associative array SERVICE_DNS and to
handle BASHPID for v3.

Here my changes, for me they are working quite fine:

diff --git a/src/tools/wg-quick/darwin.bash b/src/tools/wg-quick/darwin.bash
index 30f3541..170caed 100755
--- a/src/tools/wg-quick/darwin.bash
+++ b/src/tools/wg-quick/darwin.bash
@@ -38,8 +38,6 @@ die() {
 	exit 1
 }
 
-[[ ${BASH_VERSINFO[0]} -ge 4 ]] || die "Version mismatch: bash ${BASH_VERSINFO[0]} detected, when bash 4+ required"
-
 CONFIG_SEARCH_PATHS=( /etc/wireguard /usr/local/etc/wireguard )
 
 parse_options() {
@@ -200,22 +198,37 @@ collect_endpoints() {
 	done < <(wg show "$REAL_INTERFACE" endpoints)
 }
 
-declare -A SERVICE_DNS
+declare -a SERVICE_DNS_KEY
+declare -a SERVICE_DNS_VAL
+
 collect_new_service_dns() {
+	local old_key old_val
 	local service get_response
-	local -A found_services
+	local idx
+
+	old_key=("${SERVICE_DNS_KEY[@]}")
+	old_val=("${SERVICE_DNS_VAL[@]}")
+	SERVICE_DNS_KEY=()
+	SERVICE_DNS_VAL=()
 	{ read -r _ && while read -r service; do
 		[[ $service == "*"* ]] && service="${service:1}"
-		found_services["$service"]=1
-		[[ -n ${SERVICE_DNS["$service"]} ]] && continue
-		get_response="$(cmd networksetup -getdnsservers "$service")"
-		[[ $get_response == *" "* ]] && get_response="Empty"
-		[[ -n $get_response ]] && SERVICE_DNS["$service"]="$get_response"
+		get_response=""
+		for idx in "${!old_key[@]}"; do
+			if [[ $service = ${old_key[$idx]} ]]; then
+				get_response="${old_val[$idx]}"
+				unset old_key[$idx]
+				break
+			fi
+		done
+		if [[ -z $get_response ]]; then
+			get_response="$(cmd networksetup -getdnsservers "$service")"
+			[[ $get_response == *" "* ]] && get_response="Empty"
+		fi
+		if [[ -n $get_response ]]; then
+			SERVICE_DNS_KEY+=("$service")
+			SERVICE_DNS_VAL+=("$get_response")
+		fi
 	done; } < <(networksetup -listallnetworkservices)
-
-	for service in "${!SERVICE_DNS[@]}"; do
-		[[ -n ${found_services["$service"]} ]] || unset SERVICE_DNS["$service"]
-	done
 }
 
 set_endpoint_direct_route() {
@@ -272,7 +285,7 @@ set_endpoint_direct_route() {
 set_dns() {
 	collect_new_service_dns
 	local service response
-	for service in "${!SERVICE_DNS[@]}"; do
+	for service in "${SERVICE_DNS_KEY[@]}"; do
 		while read -r response; do
 			[[ $response == *Error* ]] && echo "$response" >&2
 		done < <(cmd networksetup -setdnsservers "$service" "${DNS[@]}")
@@ -280,11 +293,11 @@ set_dns() {
 }
 
 del_dns() {
-	local service response
-	for service in "${!SERVICE_DNS[@]}"; do
+	local idx response
+	for idx in "${!SERVICE_DNS_KEY[@]}"; do
 		while read -r response; do
 			[[ $response == *Error* ]] && echo "$response" >&2
-		done < <(cmd networksetup -setdnsservers "$service" ${SERVICE_DNS["$service"]} || true)
+		done < <(cmd networksetup -setdnsservers "${SERVICE_DNS_KEY[$idx]}" ${SERVICE_DNS_VAL[$idx]} || true)
 	done
 }
 
@@ -292,6 +305,7 @@ monitor_daemon() {
 	echo "[+] Backgrounding route monitor" >&2
 	(trap 'del_routes; del_dns; exit 0' INT TERM EXIT
 	exec >/dev/null 2>&1
+	[[ ${BASH_VERSINFO[0]} -ge 4 ]] || BASHPID=$(sh -c 'echo $PPID')
 	local event pid=$BASHPID
 	[[ ${#DNS[@]} -gt 0 ]] && trap set_dns ALRM
 	# TODO: this should also check to see if the endpoint actually changes



More information about the WireGuard mailing list