Merge pull request #255 from Arceliar/tunfix

Fix panic when writing to closed tun (from race during shutdown)
This commit is contained in:
Arceliar 2018-12-16 18:35:21 -06:00 committed by GitHub
commit 575572d9a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -5,6 +5,7 @@ package yggdrasil
import ( import (
"bytes" "bytes"
"errors" "errors"
"sync"
"time" "time"
"github.com/songgao/packets/ethernet" "github.com/songgao/packets/ethernet"
@ -24,6 +25,8 @@ type tunAdapter struct {
icmpv6 icmpv6 icmpv6 icmpv6
mtu int mtu int
iface *water.Interface iface *water.Interface
mutex sync.RWMutex // Protects the below
isOpen bool
} }
// Gets the maximum supported MTU for the platform based on the defaults in // Gets the maximum supported MTU for the platform based on the defaults in
@ -50,8 +53,11 @@ func (tun *tunAdapter) start(ifname string, iftapmode bool, addr string, mtu int
if err := tun.setup(ifname, iftapmode, addr, mtu); err != nil { if err := tun.setup(ifname, iftapmode, addr, mtu); err != nil {
return err return err
} }
go func() { panic(tun.read()) }() tun.mutex.Lock()
go func() { panic(tun.write()) }() tun.isOpen = true
tun.mutex.Unlock()
go func() { tun.core.log.Println("WARNING: tun.read() exited with error:", tun.read()) }()
go func() { tun.core.log.Println("WARNING: tun.write() exited with error:", tun.write()) }()
if iftapmode { if iftapmode {
go func() { go func() {
for { for {
@ -148,12 +154,26 @@ func (tun *tunAdapter) write() error {
len(data)) // Payload length len(data)) // Payload length
copy(frame[tun_ETHER_HEADER_LENGTH:], data[:]) copy(frame[tun_ETHER_HEADER_LENGTH:], data[:])
if _, err := tun.iface.Write(frame); err != nil { if _, err := tun.iface.Write(frame); err != nil {
panic(err) tun.mutex.RLock()
open := tun.isOpen
tun.mutex.RUnlock()
if !open {
return nil
} else {
panic(err)
}
} }
} }
} else { } else {
if _, err := tun.iface.Write(data); err != nil { if _, err := tun.iface.Write(data); err != nil {
panic(err) tun.mutex.RLock()
open := tun.isOpen
tun.mutex.RUnlock()
if !open {
return nil
} else {
panic(err)
}
} }
} }
util.PutBytes(data) util.PutBytes(data)
@ -173,8 +193,15 @@ func (tun *tunAdapter) read() error {
for { for {
n, err := tun.iface.Read(buf) n, err := tun.iface.Read(buf)
if err != nil { if err != nil {
// panic(err) tun.mutex.RLock()
return err open := tun.isOpen
tun.mutex.RUnlock()
if !open {
return nil
} else {
// panic(err)
return err
}
} }
o := 0 o := 0
if tun.iface.IsTAP() { if tun.iface.IsTAP() {
@ -202,6 +229,9 @@ func (tun *tunAdapter) read() error {
// process stops. Typically this operation will happen quickly, but on macOS // process stops. Typically this operation will happen quickly, but on macOS
// it can block until a read operation is completed. // it can block until a read operation is completed.
func (tun *tunAdapter) close() error { func (tun *tunAdapter) close() error {
tun.mutex.Lock()
tun.isOpen = false
tun.mutex.Unlock()
if tun.iface == nil { if tun.iface == nil {
return nil return nil
} }