tun: linux: account for interface removal from outside

On Linux we can run `ip link del wg0`, in which case the fd becomes
stale, and we should exit. Since this is an intentional action, don't
treat it as an error.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2021-05-20 18:26:01 +02:00
parent bd83f0ac99
commit 99e8b4ba60
2 changed files with 34 additions and 27 deletions

View File

@ -8,7 +8,9 @@ package device
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"errors"
"net" "net"
"os"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
@ -227,7 +229,9 @@ func (device *Device) RoutineReadFromTUN() {
if err != nil { if err != nil {
if !device.isClosed() { if !device.isClosed() {
device.log.Errorf("Failed to read packet from TUN device: %v", err) if !errors.Is(err, os.ErrClosed) {
device.log.Errorf("Failed to read packet from TUN device: %v", err)
}
go device.Close() go device.Close()
} }
device.PutMessageBuffer(elem.buffer) device.PutMessageBuffer(elem.buffer)

View File

@ -10,6 +10,7 @@ package tun
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"os" "os"
"sync" "sync"
@ -329,32 +330,30 @@ func (tun *NativeTun) nameSlow() (string, error) {
return string(name), nil return string(name), nil
} }
func (tun *NativeTun) Write(buff []byte, offset int) (int, error) { func (tun *NativeTun) Write(buf []byte, offset int) (int, error) {
if tun.nopi { if tun.nopi {
buff = buff[offset:] buf = buf[offset:]
} else { } else {
// reserve space for header // reserve space for header
buf = buf[offset-4:]
buff = buff[offset-4:]
// add packet information header // add packet information header
buf[0] = 0x00
buff[0] = 0x00 buf[1] = 0x00
buff[1] = 0x00 if buf[4]>>4 == ipv6.Version {
buf[2] = 0x86
if buff[4]>>4 == ipv6.Version { buf[3] = 0xdd
buff[2] = 0x86
buff[3] = 0xdd
} else { } else {
buff[2] = 0x08 buf[2] = 0x08
buff[3] = 0x00 buf[3] = 0x00
} }
} }
// write n, err := tun.tunFile.Write(buf)
if errors.Is(err, syscall.EBADFD) {
return tun.tunFile.Write(buff) err = os.ErrClosed
}
return n, err
} }
func (tun *NativeTun) Flush() error { func (tun *NativeTun) Flush() error {
@ -362,22 +361,26 @@ func (tun *NativeTun) Flush() error {
return nil return nil
} }
func (tun *NativeTun) Read(buff []byte, offset int) (int, error) { func (tun *NativeTun) Read(buf []byte, offset int) (n int, err error) {
select { select {
case err := <-tun.errors: case err = <-tun.errors:
return 0, err
default: default:
if tun.nopi { if tun.nopi {
return tun.tunFile.Read(buff[offset:]) n, err = tun.tunFile.Read(buf[offset:])
} else { } else {
buff := buff[offset-4:] buff := buf[offset-4:]
n, err := tun.tunFile.Read(buff[:]) n, err = tun.tunFile.Read(buff[:])
if n < 4 { if errors.Is(err, syscall.EBADFD) {
return 0, err err = os.ErrClosed
}
if n < 4 {
n = 0
} else {
n -= 4
} }
return n - 4, err
} }
} }
return
} }
func (tun *NativeTun) Events() chan Event { func (tun *NativeTun) Events() chan Event {