mirror of
				https://git.zx2c4.com/wireguard-go
				synced 2025-10-27 02:10:26 +08:00 
			
		
		
		
	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:
		
							
								
								
									
										5
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								main.go
									
									
									
									
									
								
							| @@ -145,6 +145,11 @@ func main() { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		err = syscall.SetNonblock(int(fd), true) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		file := os.NewFile(uintptr(fd), "") | ||||
| 		return tun.CreateTUNFromFile(file, DefaultMTU) | ||||
| 	}() | ||||
|   | ||||
| @@ -6,11 +6,9 @@ | ||||
| package tun | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"golang.org/x/net/ipv6" | ||||
| 	"golang.org/x/sys/unix" | ||||
| 	"golang.zx2c4.com/wireguard/rwcancel" | ||||
| 	"io/ioutil" | ||||
| 	"net" | ||||
| 	"os" | ||||
| @@ -36,7 +34,6 @@ type sockaddrCtl struct { | ||||
| type nativeTun struct { | ||||
| 	name        string | ||||
| 	tunFile     *os.File | ||||
| 	rwcancel    *rwcancel.RWCancel | ||||
| 	events      chan TUNEvent | ||||
| 	errors      chan error | ||||
| 	routeSocket int | ||||
| @@ -154,6 +151,10 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) { | ||||
| 		return nil, fmt.Errorf("SYS_CONNECT: %v", errno) | ||||
| 	} | ||||
|  | ||||
| 	err = syscall.SetNonblock(fd, true) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	tun, err := CreateTUNFromFile(os.NewFile(uintptr(fd), ""), mtu) | ||||
|  | ||||
| 	if err == nil && name == "utun" { | ||||
| @@ -191,14 +192,6 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	tun.operateOnFd(func (fd uintptr) { | ||||
| 		tun.rwcancel, err = rwcancel.NewRWCancel(int(fd)) | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		tun.tunFile.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC) | ||||
| 	if err != nil { | ||||
| 		tun.tunFile.Close() | ||||
| @@ -249,7 +242,7 @@ func (tun *nativeTun) Events() chan TUNEvent { | ||||
| 	return tun.events | ||||
| } | ||||
|  | ||||
| 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 | ||||
| @@ -263,18 +256,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.rwcancel.ReadyRead() { | ||||
| 			return 0, errors.New("tun device closed") | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (tun *nativeTun) Write(buff []byte, offset int) (int, error) { | ||||
|  | ||||
| 	// reserve space for header | ||||
| @@ -299,12 +280,11 @@ func (tun *nativeTun) Write(buff []byte, offset int) (int, error) { | ||||
| } | ||||
|  | ||||
| func (tun *nativeTun) Close() error { | ||||
| 	var err3 error | ||||
| 	err1 := tun.rwcancel.Cancel() | ||||
| 	err2 := tun.tunFile.Close() | ||||
| 	var err2 error | ||||
| 	err1 := tun.tunFile.Close() | ||||
| 	if tun.routeSocket != -1 { | ||||
| 		unix.Shutdown(tun.routeSocket, unix.SHUT_RDWR) | ||||
| 		err3 = unix.Close(tun.routeSocket) | ||||
| 		err2 = unix.Close(tun.routeSocket) | ||||
| 		tun.routeSocket = -1 | ||||
| 	} else if tun.events != nil { | ||||
| 		close(tun.events) | ||||
| @@ -312,11 +292,8 @@ func (tun *nativeTun) Close() error { | ||||
| 	if err1 != nil { | ||||
| 		return err1 | ||||
| 	} | ||||
| 	if err2 != nil { | ||||
| 	return err2 | ||||
| } | ||||
| 	return err3 | ||||
| } | ||||
|  | ||||
| func (tun *nativeTun) setMTU(n int) error { | ||||
|  | ||||
|   | ||||
| @@ -11,7 +11,6 @@ import ( | ||||
| 	"fmt" | ||||
| 	"golang.org/x/net/ipv6" | ||||
| 	"golang.org/x/sys/unix" | ||||
| 	"golang.zx2c4.com/wireguard/rwcancel" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"syscall" | ||||
| @@ -52,7 +51,6 @@ type ifstat struct { | ||||
| type nativeTun struct { | ||||
| 	name        string | ||||
| 	tunFile     *os.File | ||||
| 	rwcancel    *rwcancel.RWCancel | ||||
| 	events      chan TUNEvent | ||||
| 	errors      chan error | ||||
| 	routeSocket int | ||||
| @@ -333,14 +331,6 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	tun.operateOnFd(func(fd uintptr) { | ||||
| 		tun.rwcancel, err = rwcancel.NewRWCancel(int(fd)) | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		tun.tunFile.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC) | ||||
| 	if err != nil { | ||||
| 		tun.tunFile.Close() | ||||
| @@ -379,7 +369,7 @@ func (tun *nativeTun) Events() chan TUNEvent { | ||||
| 	return tun.events | ||||
| } | ||||
|  | ||||
| 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 | ||||
| @@ -393,18 +383,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.rwcancel.ReadyRead() { | ||||
| 			return 0, errors.New("tun device closed") | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (tun *nativeTun) Write(buff []byte, offset int) (int, error) { | ||||
|  | ||||
| 	// reserve space for header | ||||
| @@ -429,13 +407,12 @@ func (tun *nativeTun) Write(buff []byte, offset int) (int, error) { | ||||
| } | ||||
|  | ||||
| func (tun *nativeTun) Close() error { | ||||
| 	var err4 error | ||||
| 	err1 := tun.rwcancel.Cancel() | ||||
| 	err2 := tun.tunFile.Close() | ||||
| 	err3 := tunDestroy(tun.name) | ||||
| 	var err3 error | ||||
| 	err1 := tun.tunFile.Close() | ||||
| 	err2 := tunDestroy(tun.name) | ||||
| 	if tun.routeSocket != -1 { | ||||
| 		unix.Shutdown(tun.routeSocket, unix.SHUT_RDWR) | ||||
| 		err4 = unix.Close(tun.routeSocket) | ||||
| 		err3 = unix.Close(tun.routeSocket) | ||||
| 		tun.routeSocket = -1 | ||||
| 	} else if tun.events != nil { | ||||
| 		close(tun.events) | ||||
| @@ -446,11 +423,8 @@ func (tun *nativeTun) Close() error { | ||||
| 	if err2 != nil { | ||||
| 		return err2 | ||||
| 	} | ||||
| 	if err3 != nil { | ||||
| 	return err3 | ||||
| } | ||||
| 	return err4 | ||||
| } | ||||
|  | ||||
| func (tun *nativeTun) setMTU(n int) error { | ||||
| 	// open datagram socket | ||||
|   | ||||
| @@ -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 | ||||
| } | ||||
|  | ||||
| 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( | ||||
| 	var errno syscall.Errno | ||||
| 	(&nativeTun{tunFile: tunFile}).operateOnFd(func(fd uintptr) { | ||||
| 		_, _, errno = unix.Syscall( | ||||
| 			unix.SYS_IOCTL, | ||||
| 		nfd, | ||||
| 			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() | ||||
|   | ||||
| @@ -6,11 +6,9 @@ | ||||
| package tun | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"golang.org/x/net/ipv6" | ||||
| 	"golang.org/x/sys/unix" | ||||
| 	"golang.zx2c4.com/wireguard/rwcancel" | ||||
| 	"io/ioutil" | ||||
| 	"net" | ||||
| 	"os" | ||||
| @@ -30,7 +28,6 @@ const _TUNSIFMODE = 0x8004745d | ||||
| type nativeTun struct { | ||||
| 	name        string | ||||
| 	tunFile     *os.File | ||||
| 	rwcancel    *rwcancel.RWCancel | ||||
| 	events      chan TUNEvent | ||||
| 	errors      chan error | ||||
| 	routeSocket int | ||||
| @@ -167,14 +164,6 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	tun.operateOnFd(func(fd uintptr) { | ||||
| 		tun.rwcancel, err = rwcancel.NewRWCancel(int(fd)) | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		tun.tunFile.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC) | ||||
| 	if err != nil { | ||||
| 		tun.tunFile.Close() | ||||
| @@ -211,7 +200,7 @@ func (tun *nativeTun) Events() chan TUNEvent { | ||||
| 	return tun.events | ||||
| } | ||||
|  | ||||
| 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 | ||||
| @@ -225,18 +214,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.rwcancel.ReadyRead() { | ||||
| 			return 0, errors.New("tun device closed") | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (tun *nativeTun) Write(buff []byte, offset int) (int, error) { | ||||
|  | ||||
| 	// reserve space for header | ||||
| @@ -261,12 +238,11 @@ func (tun *nativeTun) Write(buff []byte, offset int) (int, error) { | ||||
| } | ||||
|  | ||||
| func (tun *nativeTun) Close() error { | ||||
| 	var err3 error | ||||
| 	err1 := tun.rwcancel.Cancel() | ||||
| 	err2 := tun.tunFile.Close() | ||||
| 	var err2 error | ||||
| 	err1 := tun.tunFile.Close() | ||||
| 	if tun.routeSocket != -1 { | ||||
| 		unix.Shutdown(tun.routeSocket, unix.SHUT_RDWR) | ||||
| 		err3 = unix.Close(tun.routeSocket) | ||||
| 		err2 = unix.Close(tun.routeSocket) | ||||
| 		tun.routeSocket = -1 | ||||
| 	} else if tun.events != nil { | ||||
| 		close(tun.events) | ||||
| @@ -274,11 +250,8 @@ func (tun *nativeTun) Close() error { | ||||
| 	if err1 != nil { | ||||
| 		return err1 | ||||
| 	} | ||||
| 	if err2 != nil { | ||||
| 	return err2 | ||||
| } | ||||
| 	return err3 | ||||
| } | ||||
|  | ||||
| func (tun *nativeTun) setMTU(n int) error { | ||||
| 	// open datagram socket | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jason A. Donenfeld
					Jason A. Donenfeld