diff options
author | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-04-21 10:11:36 +0900 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2019-04-23 20:12:54 +0900 |
commit | b3e1a1b07d3631bd816f9bfc27452a89dc29fa28 (patch) | |
tree | a1aa7640339e4fe3c504396ac9f607d3ac8e79db /src/tools/wg-quick | |
parent | compat: udp_tunnel: force cast sk_data_ready (diff) | |
download | wireguard-monolithic-historical-b3e1a1b07d3631bd816f9bfc27452a89dc29fa28.tar.xz wireguard-monolithic-historical-b3e1a1b07d3631bd816f9bfc27452a89dc29fa28.zip |
wg-quick: freebsd: workaround SIOCGIFSTATUS race in FreeBSD kernel
Diffstat (limited to '')
-rwxr-xr-x | src/tools/wg-quick/freebsd.bash | 31 |
1 files changed, 22 insertions, 9 deletions
diff --git a/src/tools/wg-quick/freebsd.bash b/src/tools/wg-quick/freebsd.bash index 9d3a402..72e0bd0 100755 --- a/src/tools/wg-quick/freebsd.bash +++ b/src/tools/wg-quick/freebsd.bash @@ -137,18 +137,30 @@ del_routes() { done } +if_exists() { + # HACK: The goal is simply to determine whether or not the interface exists. The + # straight-forward way of doing this would be `ifconfig $INTERFACE`, but this + # invokes the SIOCGIFSTATUS ioctl, which races with interface shutdown inside + # the tun driver, resulting in a kernel panic. So we work around it the stupid + # way by using the one utility that appears to call if_nametoindex fairly early + # and fails if it doesn't exist: `arp`. + if arp -i "$INTERFACE" -a -n >/dev/null 2>&1; then + return 0 + else + return 1 + fi +} + del_if() { - local line monitor_pid [[ $HAVE_SET_DNS -eq 0 ]] || unset_dns - exec 39< <(exec route -n monitor 2>/dev/null) - monitor_pid=$! cmd rm -f "/var/run/wireguard/$INTERFACE.sock" - while ifconfig "$INTERFACE" >/dev/null 2>&1; do - while read -r line; do - [[ $line =~ ^RTM_IFANNOUNCE:.* ]] && break - done <&39 + while if_exists; do + # HACK: it would be nice to `route monitor` here and wait for RTM_IFANNOUNCE + # but it turns out that the announcement is made before the interface + # disappears so we sometimes get a hang. So, we're instead left with polling + # in a sleep loop like this. + sleep 0.1 done - kill $monitor_pid } up_if() { @@ -274,7 +286,8 @@ monitor_daemon() { # endpoints change. while read -r event; do [[ $event == RTM_* ]] || continue - ifconfig "$INTERFACE" >/dev/null 2>&1 || break + [[ -e /var/run/wireguard/$INTERFACE.sock ]] || break + if_exists || break [[ $AUTO_ROUTE4 -eq 1 || $AUTO_ROUTE6 -eq 1 ]] && set_endpoint_direct_route # TODO: set the mtu as well, but only if up done < <(route -n monitor)) & disown |