diff options
-rw-r--r-- | tun/tun_linux.go | 37 |
1 files changed, 35 insertions, 2 deletions
diff --git a/tun/tun_linux.go b/tun/tun_linux.go index 12cd49f..bbc1888 100644 --- a/tun/tun_linux.go +++ b/tun/tun_linux.go @@ -29,6 +29,8 @@ const ( type NativeTun struct { tunFile *os.File + tunRdFile *os.File + nextTunFile *os.File index int32 // if index errors chan error // async error handling events chan Event // device related events @@ -358,6 +360,16 @@ func (tun *NativeTun) Write(bufs [][]byte, offset int) (int, error) { if errors.Is(err, syscall.EBADFD) { return total, os.ErrClosed } + + if tun.tunFile != tun.nextTunFile && errors.Is(err, os.ErrDeadlineExceeded) { + // Switch to new tunFile + tun.tunFile = tun.nextTunFile + n, err = tun.tunFile.Write(bufs[bufsI][offset:]) + if errors.Is(err, syscall.EBADFD) { + return total, os.ErrClosed + } + } + if err != nil { errs = errors.Join(errs, err) } else { @@ -452,7 +464,14 @@ func (tun *NativeTun) Read(bufs [][]byte, sizes []int, offset int) (int, error) if tun.vnetHdr { readInto = tun.readBuff[:] } - n, err := tun.tunFile.Read(readInto) + n, err := tun.tunRdFile.Read(readInto) + if tun.tunRdFile != tun.nextTunFile && errors.Is(err, os.ErrDeadlineExceeded) { + // Old tun is empty. Retry with new tun. + tun.tunRdFile.Close() + tun.tunRdFile = tun.nextTunFile + n, err = tun.tunRdFile.Read(readInto) + } + if errors.Is(err, syscall.EBADFD) { err = os.ErrClosed } @@ -468,6 +487,18 @@ func (tun *NativeTun) Read(bufs [][]byte, sizes []int, offset int) (int, error) } } +func (tun *NativeTun) SetFd(fd int) error { + err := unix.SetNonblock(fd, true) + if err != nil { + return err + } + oldTun := tun.tunFile + tun.nextTunFile = os.NewFile(uintptr(fd), "/dev/tunB") + tun.tunFile = tun.nextTunFile + oldTun.SetDeadline(time.Now()) // Release blocked in Read and Write + return nil +} + func (tun *NativeTun) Events() <-chan Event { return tun.events } @@ -572,6 +603,7 @@ func CreateTUN(name string, mtu int) (Device, error) { func CreateTUNFromFile(file *os.File, mtu int) (Device, error) { tun := &NativeTun{ tunFile: file, + tunRdFile: file, events: make(chan Event, 5), errors: make(chan error, 5), statusListenersShutdown: make(chan struct{}), @@ -621,7 +653,7 @@ func CreateTUNFromFile(file *os.File, mtu int) (Device, error) { // CreateUnmonitoredTUNFromFD creates a Device from the provided file // descriptor. -func CreateUnmonitoredTUNFromFD(fd int) (Device, string, error) { +func CreateUnmonitoredTUNFromFD(fd int) (*NativeTun, string, error) { err := unix.SetNonblock(fd, true) if err != nil { return nil, "", err @@ -629,6 +661,7 @@ func CreateUnmonitoredTUNFromFD(fd int) (Device, string, error) { file := os.NewFile(uintptr(fd), "/dev/tun") tun := &NativeTun{ tunFile: file, + tunRdFile: file, events: make(chan Event, 5), errors: make(chan error, 5), tcp4GROTable: newTCPGROTable(), |