From ab0f442dafba417c3a13d883a447e882d7983690 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Wed, 27 Feb 2019 01:06:43 +0100 Subject: [PATCH] tun: use sysconn instead of .Fd with Go 1.12 --- README.md | 2 +- tun/tun.go | 17 ++++++++++++++++- tun/tun_darwin.go | 27 ++++++++++++++------------- tun/tun_freebsd.go | 38 ++++++++++++++++++++++++-------------- tun/tun_linux.go | 45 +++++++++++++++++++++------------------------ tun/tun_openbsd.go | 6 ++++-- 6 files changed, 80 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index cbdf4e3..b6a9f39 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ This will run on OpenBSD. It does not yet support sticky sockets. Fwmark is mapp ## Building -This requires an installation of [go](https://golang.org) ≥ 1.11. +This requires an installation of [go](https://golang.org) ≥ 1.12. ``` $ git clone https://git.zx2c4.com/wireguard-go diff --git a/tun/tun.go b/tun/tun.go index baf6fbb..d9c3c15 100644 --- a/tun/tun.go +++ b/tun/tun.go @@ -5,7 +5,10 @@ package tun -import "os" +import ( + "fmt" + "os" +) type TUNEvent int @@ -24,3 +27,15 @@ type TUNDevice interface { Events() chan TUNEvent // returns a constant channel of events related to the device Close() error // stops the device and closes the event channel } + +func (tun *nativeTun) operateOnFd(fn func(fd uintptr)) { + sysconn, err := tun.tunFile.SyscallConn() + if err != nil { + tun.errors <- fmt.Errorf("unable to find sysconn for tunfile: %s", err.Error()) + return + } + err = sysconn.Control(fn) + if err != nil { + tun.errors <- fmt.Errorf("unable to control sysconn for tunfile: %s", err.Error()) + } +} \ No newline at end of file diff --git a/tun/tun_darwin.go b/tun/tun_darwin.go index 9eef4e8..1190a9d 100644 --- a/tun/tun_darwin.go +++ b/tun/tun_darwin.go @@ -8,9 +8,9 @@ package tun import ( "errors" "fmt" - "golang.zx2c4.com/wireguard/rwcancel" "golang.org/x/net/ipv6" "golang.org/x/sys/unix" + "golang.zx2c4.com/wireguard/rwcancel" "io/ioutil" "net" "os" @@ -36,7 +36,6 @@ type sockaddrCtl struct { type nativeTun struct { name string tunFile *os.File - fd uintptr rwcancel *rwcancel.RWCancel events chan TUNEvent errors chan error @@ -168,10 +167,8 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) { } func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { - tun := &nativeTun{ tunFile: file, - fd: file.Fd(), events: make(chan TUNEvent, 10), errors: make(chan error, 1), } @@ -194,7 +191,9 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { return nil, err } - tun.rwcancel, err = rwcancel.NewRWCancel(int(tun.fd)) + tun.operateOnFd(func (fd uintptr) { + tun.rwcancel, err = rwcancel.NewRWCancel(int(fd)) + }) if err != nil { tun.tunFile.Close() return nil, err @@ -218,19 +217,21 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { } func (tun *nativeTun) Name() (string, error) { - var ifName struct { name [16]byte } ifNameSize := uintptr(16) - _, _, errno := unix.Syscall6( - unix.SYS_GETSOCKOPT, - uintptr(tun.fd), - 2, /* #define SYSPROTO_CONTROL 2 */ - 2, /* #define UTUN_OPT_IFNAME 2 */ - uintptr(unsafe.Pointer(&ifName)), - uintptr(unsafe.Pointer(&ifNameSize)), 0) + var errno syscall.Errno + tun.operateOnFd(func(fd uintptr) { + _, _, errno = unix.Syscall6( + unix.SYS_GETSOCKOPT, + fd, + 2, /* #define SYSPROTO_CONTROL 2 */ + 2, /* #define UTUN_OPT_IFNAME 2 */ + uintptr(unsafe.Pointer(&ifName)), + uintptr(unsafe.Pointer(&ifNameSize)), 0) + }) if errno != 0 { return "", fmt.Errorf("SYS_GETSOCKOPT: %v", errno) diff --git a/tun/tun_freebsd.go b/tun/tun_freebsd.go index a2c4562..1aec123 100644 --- a/tun/tun_freebsd.go +++ b/tun/tun_freebsd.go @@ -9,9 +9,9 @@ import ( "bytes" "errors" "fmt" - "golang.zx2c4.com/wireguard/rwcancel" "golang.org/x/net/ipv6" "golang.org/x/sys/unix" + "golang.zx2c4.com/wireguard/rwcancel" "net" "os" "syscall" @@ -52,7 +52,6 @@ type ifstat struct { type nativeTun struct { name string tunFile *os.File - fd uintptr rwcancel *rwcancel.RWCancel events chan TUNEvent errors chan error @@ -239,12 +238,15 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) { } tunFile, err := os.OpenFile("/dev/tun", unix.O_RDWR, 0) - if err != nil { return nil, err } - tunfd := tunFile.Fd() - assignedName, err := tunName(tunfd) + + tun := nativeTun{tunFile: tunFile} + var assignedName string + tun.operateOnFd(func(fd uintptr) { + assignedName, err = tunName(fd) + }) if err != nil { tunFile.Close() return nil, err @@ -252,12 +254,15 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) { // Enable ifhead mode, otherwise tun will complain if it gets a non-AF_INET packet ifheadmode := 1 - _, _, errno := unix.Syscall( - unix.SYS_IOCTL, - uintptr(tunfd), - uintptr(_TUNSIFHEAD), - uintptr(unsafe.Pointer(&ifheadmode)), - ) + var errno syscall.Errno + tun.operateOnFd(func(fd uintptr) { + _, _, errno = unix.Syscall( + unix.SYS_IOCTL, + fd, + uintptr(_TUNSIFHEAD), + uintptr(unsafe.Pointer(&ifheadmode)), + ) + }) if errno != 0 { return nil, fmt.Errorf("error %s", errno.Error()) @@ -306,7 +311,6 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { tun := &nativeTun{ tunFile: file, - fd: file.Fd(), events: make(chan TUNEvent, 10), errors: make(chan error, 1), } @@ -329,7 +333,9 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { return nil, err } - tun.rwcancel, err = rwcancel.NewRWCancel(int(tun.fd)) + tun.operateOnFd(func(fd uintptr) { + tun.rwcancel, err = rwcancel.NewRWCancel(int(fd)) + }) if err != nil { tun.tunFile.Close() return nil, err @@ -353,7 +359,11 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { } func (tun *nativeTun) Name() (string, error) { - name, err := tunName(tun.fd) + var name string + var err error + tun.operateOnFd(func(fd uintptr) { + name, err = tunName(fd) + }) if err != nil { return "", err } diff --git a/tun/tun_linux.go b/tun/tun_linux.go index 7a0647f..abdcce2 100644 --- a/tun/tun_linux.go +++ b/tun/tun_linux.go @@ -12,13 +12,14 @@ import ( "bytes" "errors" "fmt" - "golang.zx2c4.com/wireguard/rwcancel" "golang.org/x/net/ipv6" "golang.org/x/sys/unix" + "golang.zx2c4.com/wireguard/rwcancel" "net" "os" "strconv" "sync" + "syscall" "time" "unsafe" ) @@ -30,7 +31,6 @@ const ( type nativeTun struct { tunFile *os.File - fd uintptr fdCancel *rwcancel.RWCancel index int32 // if index name string // name of interface @@ -52,9 +52,11 @@ func (tun *nativeTun) routineHackListener() { /* This is needed for the detection to work across network namespaces * If you are reading this and know a better method, please get in touch. */ - fd := int(tun.fd) for { - _, err := unix.Write(fd, nil) + var err error + tun.operateOnFd(func(fd uintptr) { + _, err = unix.Write(int(fd), nil) + }) switch err { case unix.EINVAL: tun.events <- TUNEventUp @@ -162,16 +164,12 @@ func (tun *nativeTun) isUp() (bool, error) { return inter.Flags&net.FlagUp != 0, err } -func getDummySock() (int, error) { - return unix.Socket( +func getIFIndex(name string) (int32, error) { + fd, err := unix.Socket( unix.AF_INET, unix.SOCK_DGRAM, 0, ) -} - -func getIFIndex(name string) (int32, error) { - fd, err := getDummySock() if err != nil { return 0, err } @@ -195,9 +193,7 @@ func getIFIndex(name string) (int32, error) { } func (tun *nativeTun) setMTU(n int) error { - // open datagram socket - fd, err := unix.Socket( unix.AF_INET, unix.SOCK_DGRAM, @@ -230,9 +226,7 @@ func (tun *nativeTun) setMTU(n int) error { } func (tun *nativeTun) MTU() (int, error) { - // open datagram socket - fd, err := unix.Socket( unix.AF_INET, unix.SOCK_DGRAM, @@ -263,14 +257,16 @@ func (tun *nativeTun) MTU() (int, error) { } func (tun *nativeTun) Name() (string, error) { - var ifr [ifReqSize]byte - _, _, errno := unix.Syscall( - unix.SYS_IOCTL, - tun.fd, - uintptr(unix.TUNGETIFF), - uintptr(unsafe.Pointer(&ifr[0])), - ) + var errno syscall.Errno + tun.operateOnFd(func(fd uintptr) { + _, _, errno = unix.Syscall( + unix.SYS_IOCTL, + fd, + uintptr(unix.TUNGETIFF), + uintptr(unsafe.Pointer(&ifr[0])), + ) + }) if errno != 0 { return "", errors.New("failed to get name of TUN device: " + strconv.FormatInt(int64(errno), 10)) } @@ -391,7 +387,7 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) { _, _, errno := unix.Syscall( unix.SYS_IOCTL, - fd.Fd(), + nfd, uintptr(unix.TUNSETIFF), uintptr(unsafe.Pointer(&ifr[0])), ) @@ -405,7 +401,6 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) { func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { tun := &nativeTun{ tunFile: file, - fd: file.Fd(), events: make(chan TUNEvent, 5), errors: make(chan error, 5), statusListenersShutdown: make(chan struct{}), @@ -413,7 +408,9 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { } var err error - tun.fdCancel, err = rwcancel.NewRWCancel(int(tun.fd)) + tun.operateOnFd(func(fd uintptr) { + tun.fdCancel, err = rwcancel.NewRWCancel(int(fd)) + }) if err != nil { tun.tunFile.Close() return nil, err diff --git a/tun/tun_openbsd.go b/tun/tun_openbsd.go index ab4c87b..b10c460 100644 --- a/tun/tun_openbsd.go +++ b/tun/tun_openbsd.go @@ -8,9 +8,9 @@ package tun import ( "errors" "fmt" - "golang.zx2c4.com/wireguard/rwcancel" "golang.org/x/net/ipv6" "golang.org/x/sys/unix" + "golang.zx2c4.com/wireguard/rwcancel" "io/ioutil" "net" "os" @@ -167,7 +167,9 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { return nil, err } - tun.rwcancel, err = rwcancel.NewRWCancel(int(file.Fd())) + tun.operateOnFd(func(fd uintptr) { + tun.rwcancel, err = rwcancel.NewRWCancel(int(fd)) + }) if err != nil { tun.tunFile.Close() return nil, err