tun: use netpoll instead of rwcancel

The new sysconn function of Go 1.12 makes this possible:

package main

import "log"
import "os"
import "unsafe"
import "time"
import "syscall"
import "sync"
import "golang.org/x/sys/unix"

func main() {
	fd, err := os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
	if err != nil {
		log.Fatal(err)
	}

	var ifr [unix.IFNAMSIZ + 64]byte
	copy(ifr[:], []byte("cheese"))
	*(*uint16)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = unix.IFF_TUN

	var errno syscall.Errno
	s, _ := fd.SyscallConn()
	s.Control(func(fd uintptr) {
		_, _, errno = unix.Syscall(
			unix.SYS_IOCTL,
			fd,
			uintptr(unix.TUNSETIFF),
			uintptr(unsafe.Pointer(&ifr[0])),
		)
	})
	if errno != 0 {
		log.Fatal(errno)
	}

	b := [4]byte{}
	wait := sync.WaitGroup{}
	wait.Add(1)
	go func() {
		_, err := fd.Read(b[:])
		log.Print("Read errored: ", err)
		wait.Done()
	}()
	time.Sleep(time.Second)
	log.Print("Closing")
	err = fd.Close()
	if err != nil {
		log.Print("Close errored: " , err)
	}
	wait.Wait()
	log.Print("Exiting")
}
This commit is contained in:
Jason A. Donenfeld
2019-02-27 01:48:58 +01:00
parent ab0f442daf
commit 366cbd11a4
6 changed files with 39 additions and 138 deletions

View File

@@ -31,7 +31,6 @@ const (
type nativeTun struct {
tunFile *os.File
fdCancel *rwcancel.RWCancel
index int32 // if index
name string // name of interface
errors chan error // async error handling
@@ -307,7 +306,7 @@ func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
return tun.tunFile.Write(buff)
}
func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
select {
case err := <-tun.errors:
return 0, err
@@ -325,18 +324,6 @@ func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
}
}
func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
for {
n, err := tun.doRead(buff, offset)
if err == nil || !rwcancel.RetryAfterError(err) {
return n, err
}
if !tun.fdCancel.ReadyRead() {
return 0, errors.New("tun device closed")
}
}
}
func (tun *nativeTun) Events() chan TUNEvent {
return tun.events
}
@@ -352,30 +339,20 @@ func (tun *nativeTun) Close() error {
close(tun.events)
}
err2 := tun.tunFile.Close()
err3 := tun.fdCancel.Cancel()
if err1 != nil {
return err1
}
if err2 != nil {
return err2
}
return err3
return err2
}
func CreateTUN(name string, mtu int) (TUNDevice, error) {
nfd, err := unix.Open(cloneDevicePath, os.O_RDWR, 0)
if err != nil {
return nil, err
}
fd := os.NewFile(uintptr(nfd), cloneDevicePath)
tunFile, err := os.OpenFile(cloneDevicePath, os.O_RDWR, 0)
if err != nil {
return nil, err
}
// create new device
var ifr [ifReqSize]byte
var flags uint16 = unix.IFF_TUN // | unix.IFF_NO_PI (disabled for TUN status hack)
nameBytes := []byte(name)
@@ -385,17 +362,20 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) {
copy(ifr[:], nameBytes)
*(*uint16)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = flags
_, _, errno := unix.Syscall(
unix.SYS_IOCTL,
nfd,
uintptr(unix.TUNSETIFF),
uintptr(unsafe.Pointer(&ifr[0])),
)
var errno syscall.Errno
(&nativeTun{tunFile: tunFile}).operateOnFd(func(fd uintptr) {
_, _, errno = unix.Syscall(
unix.SYS_IOCTL,
fd,
uintptr(unix.TUNSETIFF),
uintptr(unsafe.Pointer(&ifr[0])),
)
})
if errno != 0 {
return nil, errno
}
return CreateTUNFromFile(fd, mtu)
return CreateTUNFromFile(tunFile, mtu)
}
func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
@@ -408,14 +388,6 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
}
var err error
tun.operateOnFd(func(fd uintptr) {
tun.fdCancel, err = rwcancel.NewRWCancel(int(fd))
})
if err != nil {
tun.tunFile.Close()
return nil, err
}
_, err = tun.Name()
if err != nil {
tun.tunFile.Close()