net/wireguard: workaround SIOCGIFSTATUS race in FreeBSD kernel

PR:		233955
This commit is contained in:
Bernhard Froehlich 2019-04-23 12:36:30 +00:00
parent 58993b6b59
commit 4ad662d0e4
Notes: svn2git 2021-03-31 03:12:20 +00:00
svn path=/head/; revision=499755
2 changed files with 66 additions and 0 deletions

View File

@ -2,6 +2,7 @@
PORTNAME= wireguard
PORTVERSION= 0.0.20190406
PORTREVISION= 1
CATEGORIES= net
MASTER_SITES= https://git.zx2c4.com/WireGuard/snapshot/
DISTNAME= WireGuard-${PORTVERSION}

View File

@ -0,0 +1,65 @@
From b3e1a1b07d3631bd816f9bfc27452a89dc29fa28 Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Sun, 21 Apr 2019 10:11:36 +0900
Subject: wg-quick: freebsd: workaround SIOCGIFSTATUS race in FreeBSD kernel
---
src/tools/wg-quick/freebsd.bash | 31 ++++++++++++++++++++++---------
1 file changed, 22 insertions(+), 9 deletions(-)
diff --git a/src/tools/wg-quick/freebsd.bash b/src/tools/wg-quick/freebsd.bash
index 9d3a4026..72e0bd04 100755
--- wg-quick/freebsd.bash
+++ 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
--
cgit v1.2.1-20-gc37e