[Openvpn-devel] Workaround FreeBSD 12+ race condition on tun/tap open with IPv6.

Message ID 20200723121949.78223-1-gert@greenie.muc.de
State Accepted
Headers show
Series [Openvpn-devel] Workaround FreeBSD 12+ race condition on tun/tap open with IPv6. | expand

Commit Message

Gert Doering July 23, 2020, 2:19 a.m. UTC
On FreeBSD 12 (tested and verified on 12.1-RELEASE-p2), after "ifconfig
inet6" for a tun/tap interface, there sometimes is a race condition
where the "IFDISABLED" flag shows up after a short time frame, under
a second, and never clears itself.  This disables use of the configured
IPv6 address on the interface, breaking IPv6 over tun/tap operation.

This only happens if ipv6_activate_all_interfaces="YES" is not
set in /etc/rc.conf - but there might be reasons why this is not so.

As a workaround until this can be fixed on the FreeBSD side (or a
better workaround is found), sleep(1) after ifconfig, then call
"ifconfig $dev inet6 -ifdisable".

Yes, this is massively ugly but makes the problem completely go
away for my test systems.

(The same effect can be achieved with an --up script that does this,
but it's even less pretty - see trac ticket)

FreeBSD: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=248172

v2: reword text, refer to FreeBSD bug with much more details

Trac: 1226
Signed-off-by: Gert Doering <gert@greenie.muc.de>
---
 src/openvpn/tun.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

Comments

Arne Schwabe Aug. 11, 2020, 11:43 p.m. UTC | #1
Am 23.07.20 um 14:19 schrieb Gert Doering:
> On FreeBSD 12 (tested and verified on 12.1-RELEASE-p2), after "ifconfig
> inet6" for a tun/tap interface, there sometimes is a race condition
> where the "IFDISABLED" flag shows up after a short time frame, under
> a second, and never clears itself.  This disables use of the configured
> IPv6 address on the interface, breaking IPv6 over tun/tap operation.
> 
> This only happens if ipv6_activate_all_interfaces="YES" is not
> set in /etc/rc.conf - but there might be reasons why this is not so.
> 
> As a workaround until this can be fixed on the FreeBSD side (or a
> better workaround is found), sleep(1) after ifconfig, then call
> "ifconfig $dev inet6 -ifdisable".
> 
> Yes, this is massively ugly but makes the problem completely go
> away for my test systems.
> 
> (The same effect can be achieved with an --up script that does this,
> but it's even less pretty - see trac ticket)
> 
> FreeBSD: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=248172
> 
> v2: reword text, refer to FreeBSD bug with much more details

Acked-By: Arne Schwabe <arne@rfc2549.org>

This looks like a ugly workaround but if it is the best we can, so be it.

Arne
Gert Doering Aug. 23, 2020, 10:11 a.m. UTC | #2
Your patch has been applied to the master and release/2.5 branch.

commit 5e19cc2c1bf22d44f10dc585ba69d48951dc7a86 (master)
commit 6dac3342d851995bdee75db4b52cfb3a3f9232e3 (release/2.5)
Author: Gert Doering
Date:   Thu Jul 23 14:19:49 2020 +0200

     Workaround FreeBSD 12+ race condition on tun/tap open with IPv6.

     Signed-off-by: Gert Doering <gert@greenie.muc.de>
     Acked-by: Arne Schwabe <arne@rfc2549.org>
     Message-Id: <20200723121949.78223-1-gert@greenie.muc.de>
     URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg20553.html
     Signed-off-by: Gert Doering <gert@greenie.muc.de>


--
kind regards,

Gert Doering

Patch

diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index e96368ca..bbccc1cc 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -1038,6 +1038,29 @@  do_ifconfig_ipv6(struct tuntap *tt, const char *ifname, int tun_mtu,
     openvpn_execve_check(&argv, es, S_FATAL,
                          "generic BSD ifconfig inet6 failed");
 
+#if defined(TARGET_FREEBSD) && __FreeBSD_version >= 1200000
+    /* On FreeBSD 12 and up, there is ipv6_activate_all_interfaces="YES"
+     * in rc.conf, which is not set by default.  If it is *not* set,
+     * "all new interfaces that are not already up" are configured by
+     * devd + /etc/pccard_ether as "inet6 ifdisabled".
+     *
+     * The "is this interface already up?" test is a non-zero time window
+     * which we manage to hit with our ifconfig often enough to cause 
+     * frequent fails in the openvpn test environment.
+     *
+     * Thus: assume that the system might interfere, wait for things to
+     * settle (it's a very short time window), and remove -ifdisable again.
+     *
+     * See: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=248172
+     */
+    sleep(1);
+    argv_printf(&argv, "%s %s inet6 -ifdisabled", IFCONFIG_PATH, ifname);
+    argv_msg(M_INFO, &argv);
+
+    openvpn_execve_check(&argv, es, S_FATAL,
+                         "FreeBSD BSD 'ifconfig inet6 -ifdisabled' failed");
+#endif
+
 #if defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) \
     || defined(TARGET_DARWIN)
     /* and, hooray, we explicitly need to add a route... */