summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--tun/tun_linux.go37
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(),