## 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
package tun
-import "os"
+import (
+ "fmt"
+ "os"
+)
type TUNEvent int
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
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"
type nativeTun struct {
name string
tunFile *os.File
- fd uintptr
rwcancel *rwcancel.RWCancel
events chan TUNEvent
errors chan 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),
}
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
}
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)
"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"
type nativeTun struct {
name string
tunFile *os.File
- fd uintptr
rwcancel *rwcancel.RWCancel
events chan TUNEvent
errors chan 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
// 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())
tun := &nativeTun{
tunFile: file,
- fd: file.Fd(),
events: make(chan TUNEvent, 10),
errors: make(chan error, 1),
}
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
}
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
}
"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"
)
type nativeTun struct {
tunFile *os.File
- fd uintptr
fdCancel *rwcancel.RWCancel
index int32 // if index
name string // name of interface
/* 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
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
}
}
func (tun *nativeTun) setMTU(n int) error {
-
// open datagram socket
-
fd, err := unix.Socket(
unix.AF_INET,
unix.SOCK_DGRAM,
}
func (tun *nativeTun) MTU() (int, error) {
-
// open datagram socket
-
fd, err := unix.Socket(
unix.AF_INET,
unix.SOCK_DGRAM,
}
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))
}
_, _, errno := unix.Syscall(
unix.SYS_IOCTL,
- fd.Fd(),
+ nfd,
uintptr(unix.TUNSETIFF),
uintptr(unsafe.Pointer(&ifr[0])),
)
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{}),
}
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
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"
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