]> git.ipfire.org Git - thirdparty/wireguard-go.git/commitdiff
tun: NetlinkListener: don't send EventDown before sending EventUp
authorAvery Pennarun <apenwarr@tailscale.com>
Wed, 6 Nov 2019 08:28:02 +0000 (00:28 -0800)
committerJason A. Donenfeld <Jason@zx2c4.com>
Sat, 2 May 2020 07:46:42 +0000 (01:46 -0600)
This works around a startup race condition when competing with
HackListener, which is trying to do the same job. If HackListener
detects that the tundev is running while there is still an event in the
netlink queue that says it isn't running, then the device receives a
string of events like
EventUp (HackListener)
EventDown (NetlinkListener)
EventUp (NetlinkListener)
Unfortunately, after the first EventDown, the device stops itself,
thinking incorrectly that the administrator has downed its tundev.

The device is ignoring the initial EventDown anyway, so just don't emit
it.

Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
tun/tun_linux.go

index 2f97ebbc536712980019576f4a597a725c2da202..1e44b59cab6ff77af64824db50fd6dd45936f66b 100644 (file)
@@ -66,14 +66,19 @@ func (tun *NativeTun) routineHackListener() {
                }
                switch err {
                case unix.EINVAL:
+                       // If the tunnel is up, it reports that write() is
+                       // allowed but we provided invalid data.
                        tun.events <- EventUp
                case unix.EIO:
+                       // If the tunnel is down, it reports that no I/O
+                       // is possible, without checking our provided data.
                        tun.events <- EventDown
                default:
                        return
                }
                select {
                case <-time.After(time.Second):
+                       // nothing
                case <-tun.statusListenersShutdown:
                        return
                }
@@ -128,6 +133,7 @@ func (tun *NativeTun) routineNetlinkListener() {
                default:
                }
 
+               wasEverUp := false
                for remain := msg[:msgn]; len(remain) >= unix.SizeofNlMsghdr; {
 
                        hdr := *(*unix.NlMsghdr)(unsafe.Pointer(&remain[0]))
@@ -151,10 +157,16 @@ func (tun *NativeTun) routineNetlinkListener() {
 
                                if info.Flags&unix.IFF_RUNNING != 0 {
                                        tun.events <- EventUp
+                                       wasEverUp = true
                                }
 
                                if info.Flags&unix.IFF_RUNNING == 0 {
-                                       tun.events <- EventDown
+                                       // Don't emit EventDown before we've ever emitted EventUp.
+                                       // This avoids a startup race with HackListener, which
+                                       // might detect Up before we have finished reporting Down.
+                                       if wasEverUp {
+                                               tun.events <- EventDown
+                                       }
                                }
 
                                tun.events <- EventMTUUpdate