aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tun/tun_linux.go14
1 files changed, 13 insertions, 1 deletions
diff --git a/tun/tun_linux.go b/tun/tun_linux.go
index 2f97ebb..1e44b59 100644
--- a/tun/tun_linux.go
+++ b/tun/tun_linux.go
@@ -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