summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2019-05-31 15:40:08 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2019-05-31 16:55:03 +0200
commitda61947ec3717fbfdc84d98866ab60e82f154ce0 (patch)
tree3eb3fc593f6d7dbf792fd7ea2da8e016fa946181
parentd9f995209c3cc7bda242e8752680d78684fd62e4 (diff)
tun: windows: mitigate infinite loop in Flush()
It's possible that for whatever reason, we keep returning EOF, resulting in repeated close/open/write operations, except with empty packets.
-rw-r--r--tun/tun_windows.go64
1 files changed, 35 insertions, 29 deletions
diff --git a/tun/tun_windows.go b/tun/tun_windows.go
index a28dce9..583ff6b 100644
--- a/tun/tun_windows.go
+++ b/tun/tun_windows.go
@@ -8,6 +8,7 @@ package tun
import (
"errors"
"fmt"
+ "io"
"os"
"sync"
"time"
@@ -230,6 +231,7 @@ func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
default:
}
+ retries := 1000
for {
if tun.rdBuff.offset+packetExchangeAlignment <= tun.rdBuff.avail {
// Get packet from the exchange buffer.
@@ -255,31 +257,31 @@ func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
return 0, err
}
- // Fill queue.
- retries := 1000
- for {
- n, err := file.Read(tun.rdBuff.data[:])
- if err != nil {
- tun.rdBuff.offset = 0
- tun.rdBuff.avail = 0
- pe, ok := err.(*os.PathError)
- if tun.close {
- return 0, os.ErrClosed
- }
- if retries > 0 && ok && pe.Err == windows.ERROR_OPERATION_ABORTED {
- retries--
- continue
- }
- if ok && pe.Err == windows.ERROR_HANDLE_EOF {
- tun.closeTUN()
- break
- }
- return 0, err
- }
+ n, err := file.Read(tun.rdBuff.data[:])
+ if err != nil {
tun.rdBuff.offset = 0
- tun.rdBuff.avail = uint32(n)
- break
+ tun.rdBuff.avail = 0
+ pe, ok := err.(*os.PathError)
+ if tun.close {
+ return 0, os.ErrClosed
+ }
+ if retries > 0 && ok && (pe.Err == windows.ERROR_HANDLE_EOF || pe.Err == windows.ERROR_OPERATION_ABORTED) {
+ retries--
+ tun.closeTUN()
+ time.Sleep(time.Millisecond * 2)
+ continue
+ }
+ return 0, err
}
+ if n == 0 {
+ if retries == 0 {
+ return 0, io.ErrShortBuffer
+ }
+ retries--
+ continue
+ }
+ tun.rdBuff.offset = 0
+ tun.rdBuff.avail = uint32(n)
}
}
@@ -289,6 +291,11 @@ func (tun *NativeTun) Flush() error {
if tun.wrBuff.offset == 0 {
return nil
}
+ defer func() {
+ tun.wrBuff.packetNum = 0
+ tun.wrBuff.offset = 0
+ }()
+ retries := 1000
for {
// Get TUN data pipe.
@@ -297,23 +304,22 @@ func (tun *NativeTun) Flush() error {
return err
}
- // Flush write buffer.
- retries := 1000
for {
_, err = file.Write(tun.wrBuff.data[:tun.wrBuff.offset])
- tun.wrBuff.packetNum = 0
- tun.wrBuff.offset = 0
if err != nil {
pe, ok := err.(*os.PathError)
if tun.close {
return os.ErrClosed
}
- if retries > 0 && ok && pe.Err == windows.ERROR_OPERATION_ABORTED {
+ if retries > 0 && ok && pe.Err == windows.ERROR_OPERATION_ABORTED { // Adapter is paused or in low-power state.
retries--
+ time.Sleep(time.Millisecond * 2)
continue
}
- if ok && pe.Err == windows.ERROR_HANDLE_EOF {
+ if retries > 0 && ok && pe.Err == windows.ERROR_HANDLE_EOF { // Adapter is going down.
+ retries--
tun.closeTUN()
+ time.Sleep(time.Millisecond * 2)
break
}
return err