From 2e772194cf7cd7c37d24364a9f9d407dc96a25e8 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Wed, 17 Oct 2018 21:26:53 +0200 Subject: [PATCH] tun: only call .Fd() once Doing so tends to make the tunnel blocking, so we only retrieve it once before we call SetNonblock, and then cache the result. --- tun/tun_darwin.go | 30 ++++++++++++++++-------------- tun/tun_freebsd.go | 40 +++++++++++++++++++++------------------- tun/tun_linux.go | 32 +++++++++++++++++--------------- tun/tun_openbsd.go | 26 +++++++++++++------------- 4 files changed, 67 insertions(+), 61 deletions(-) diff --git a/tun/tun_darwin.go b/tun/tun_darwin.go index 24d2319..a4e2e9a 100644 --- a/tun/tun_darwin.go +++ b/tun/tun_darwin.go @@ -37,7 +37,8 @@ type sockaddrCtl struct { type nativeTun struct { name string - fd *os.File + tunFile *os.File + fd uintptr rwcancel *rwcancel.RWCancel events chan TUNEvent errors chan error @@ -171,14 +172,15 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) { func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { tun := &nativeTun{ - fd: file, - events: make(chan TUNEvent, 10), - errors: make(chan error, 1), + tunFile: file, + fd: file.Fd(), + events: make(chan TUNEvent, 10), + errors: make(chan error, 1), } name, err := tun.Name() if err != nil { - tun.fd.Close() + tun.tunFile.Close() return nil, err } @@ -190,19 +192,19 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { return iface.Index, nil }() if err != nil { - tun.fd.Close() + tun.tunFile.Close() return nil, err } - tun.rwcancel, err = rwcancel.NewRWCancel(int(file.Fd())) + tun.rwcancel, err = rwcancel.NewRWCancel(int(tun.fd)) if err != nil { - tun.fd.Close() + tun.tunFile.Close() return nil, err } tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC) if err != nil { - tun.fd.Close() + tun.tunFile.Close() return nil, err } @@ -226,7 +228,7 @@ func (tun *nativeTun) Name() (string, error) { _, _, errno := unix.Syscall6( unix.SYS_GETSOCKOPT, - uintptr(tun.fd.Fd()), + uintptr(tun.fd), 2, /* #define SYSPROTO_CONTROL 2 */ 2, /* #define UTUN_OPT_IFNAME 2 */ uintptr(unsafe.Pointer(&ifName)), @@ -241,7 +243,7 @@ func (tun *nativeTun) Name() (string, error) { } func (tun *nativeTun) File() *os.File { - return tun.fd + return tun.tunFile } func (tun *nativeTun) Events() chan TUNEvent { @@ -254,7 +256,7 @@ func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) { return 0, err default: buff := buff[offset-4:] - n, err := tun.fd.Read(buff[:]) + n, err := tun.tunFile.Read(buff[:]) if n < 4 { return 0, err } @@ -294,13 +296,13 @@ func (tun *nativeTun) Write(buff []byte, offset int) (int, error) { // write - return tun.fd.Write(buff) + return tun.tunFile.Write(buff) } func (tun *nativeTun) Close() error { var err3 error err1 := tun.rwcancel.Cancel() - err2 := tun.fd.Close() + err2 := tun.tunFile.Close() if tun.routeSocket != -1 { unix.Shutdown(tun.routeSocket, unix.SHUT_RDWR) err3 = unix.Close(tun.routeSocket) diff --git a/tun/tun_freebsd.go b/tun/tun_freebsd.go index a0c8b28..c1ae30a 100644 --- a/tun/tun_freebsd.go +++ b/tun/tun_freebsd.go @@ -51,7 +51,8 @@ type ifstat struct { type nativeTun struct { name string - fd *os.File + tunFile *os.File + fd uintptr rwcancel *rwcancel.RWCancel events chan TUNEvent errors chan error @@ -237,15 +238,15 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) { return nil, fmt.Errorf("interface %s already exists", name) } - tunfile, err := os.OpenFile("/dev/tun", unix.O_RDWR, 0) + tunFile, err := os.OpenFile("/dev/tun", unix.O_RDWR, 0) if err != nil { return nil, err } - tunfd := tunfile.Fd() + tunfd := tunFile.Fd() assignedName, err := tunName(tunfd) if err != nil { - tunfile.Close() + tunFile.Close() return nil, err } @@ -293,25 +294,26 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) { uintptr(unsafe.Pointer(&ifr)), ) if errno != 0 { - tunfile.Close() + tunFile.Close() tunDestroy(name) return nil, fmt.Errorf("failed to rename %s to %s: %s", assignedName, name, errno.Error()) } - return CreateTUNFromFile(tunfile, mtu) + return CreateTUNFromFile(tunFile, mtu) } func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { tun := &nativeTun{ - fd: file, - events: make(chan TUNEvent, 10), - errors: make(chan error, 1), + tunFile: file, + fd: file.Fd(), + events: make(chan TUNEvent, 10), + errors: make(chan error, 1), } name, err := tun.Name() if err != nil { - tun.fd.Close() + tun.tunFile.Close() return nil, err } @@ -323,19 +325,19 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { return iface.Index, nil }() if err != nil { - tun.fd.Close() + tun.tunFile.Close() return nil, err } - tun.rwcancel, err = rwcancel.NewRWCancel(int(file.Fd())) + tun.rwcancel, err = rwcancel.NewRWCancel(int(tun.fd)) if err != nil { - tun.fd.Close() + tun.tunFile.Close() return nil, err } tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC) if err != nil { - tun.fd.Close() + tun.tunFile.Close() return nil, err } @@ -351,7 +353,7 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { } func (tun *nativeTun) Name() (string, error) { - name, err := tunName(tun.fd.Fd()) + name, err := tunName(tun.fd) if err != nil { return "", err } @@ -360,7 +362,7 @@ func (tun *nativeTun) Name() (string, error) { } func (tun *nativeTun) File() *os.File { - return tun.fd + return tun.tunFile } func (tun *nativeTun) Events() chan TUNEvent { @@ -373,7 +375,7 @@ func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) { return 0, err default: buff := buff[offset-4:] - n, err := tun.fd.Read(buff[:]) + n, err := tun.tunFile.Read(buff[:]) if n < 4 { return 0, err } @@ -413,13 +415,13 @@ func (tun *nativeTun) Write(buff []byte, offset int) (int, error) { // write - return tun.fd.Write(buff) + return tun.tunFile.Write(buff) } func (tun *nativeTun) Close() error { var err4 error err1 := tun.rwcancel.Cancel() - err2 := tun.fd.Close() + err2 := tun.tunFile.Close() err3 := tunDestroy(tun.name) if tun.routeSocket != -1 { unix.Shutdown(tun.routeSocket, unix.SHUT_RDWR) diff --git a/tun/tun_linux.go b/tun/tun_linux.go index d0af51d..bb6bede 100644 --- a/tun/tun_linux.go +++ b/tun/tun_linux.go @@ -29,7 +29,8 @@ const ( ) type nativeTun struct { - fd *os.File + tunFile *os.File + fd uintptr fdCancel *rwcancel.RWCancel index int32 // if index name string // name of interface @@ -43,7 +44,7 @@ type nativeTun struct { } func (tun *nativeTun) File() *os.File { - return tun.fd + return tun.tunFile } func (tun *nativeTun) routineHackListener() { @@ -51,7 +52,7 @@ 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.Fd()) + fd := int(tun.fd) for { _, err := unix.Write(fd, nil) switch err { @@ -266,7 +267,7 @@ func (tun *nativeTun) Name() (string, error) { var ifr [ifReqSize]byte _, _, errno := unix.Syscall( unix.SYS_IOCTL, - tun.fd.Fd(), + tun.fd, uintptr(unix.TUNGETIFF), uintptr(unsafe.Pointer(&ifr[0])), ) @@ -307,7 +308,7 @@ func (tun *nativeTun) Write(buff []byte, offset int) (int, error) { // write - return tun.fd.Write(buff) + return tun.tunFile.Write(buff) } func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) { @@ -316,10 +317,10 @@ func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) { return 0, err default: if tun.nopi { - return tun.fd.Read(buff[offset:]) + return tun.tunFile.Read(buff[offset:]) } else { buff := buff[offset-4:] - n, err := tun.fd.Read(buff[:]) + n, err := tun.tunFile.Read(buff[:]) if n < 4 { return 0, err } @@ -354,7 +355,7 @@ func (tun *nativeTun) Close() error { } else if tun.events != nil { close(tun.events) } - err2 := tun.fd.Close() + err2 := tun.tunFile.Close() err3 := tun.fdCancel.Cancel() if err1 != nil { @@ -413,23 +414,24 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) { func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { tun := &nativeTun{ - fd: file, + tunFile: file, + fd: file.Fd(), events: make(chan TUNEvent, 5), errors: make(chan error, 5), statusListenersShutdown: make(chan struct{}), - nopi: false, + nopi: false, } var err error - tun.fdCancel, err = rwcancel.NewRWCancel(int(file.Fd())) + tun.fdCancel, err = rwcancel.NewRWCancel(int(tun.fd)) if err != nil { - tun.fd.Close() + tun.tunFile.Close() return nil, err } _, err = tun.Name() if err != nil { - tun.fd.Close() + tun.tunFile.Close() return nil, err } @@ -442,12 +444,12 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { tun.netlinkSock, err = createNetlinkSocket() if err != nil { - tun.fd.Close() + tun.tunFile.Close() return nil, err } tun.netlinkCancel, err = rwcancel.NewRWCancel(tun.netlinkSock) if err != nil { - tun.fd.Close() + tun.tunFile.Close() return nil, err } diff --git a/tun/tun_openbsd.go b/tun/tun_openbsd.go index 58871b1..b99c9f6 100644 --- a/tun/tun_openbsd.go +++ b/tun/tun_openbsd.go @@ -29,7 +29,7 @@ const _TUNSIFMODE = 0x8004745d type nativeTun struct { name string - fd *os.File + tunFile *os.File rwcancel *rwcancel.RWCancel events chan TUNEvent errors chan error @@ -144,14 +144,14 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) { func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { tun := &nativeTun{ - fd: file, - events: make(chan TUNEvent, 10), - errors: make(chan error, 1), + tunFile: file, + events: make(chan TUNEvent, 10), + errors: make(chan error, 1), } name, err := tun.Name() if err != nil { - tun.fd.Close() + tun.tunFile.Close() return nil, err } @@ -163,19 +163,19 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { return iface.Index, nil }() if err != nil { - tun.fd.Close() + tun.tunFile.Close() return nil, err } tun.rwcancel, err = rwcancel.NewRWCancel(int(file.Fd())) if err != nil { - tun.fd.Close() + tun.tunFile.Close() return nil, err } tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC) if err != nil { - tun.fd.Close() + tun.tunFile.Close() return nil, err } @@ -191,7 +191,7 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { } func (tun *nativeTun) Name() (string, error) { - gostat, err := tun.fd.Stat() + gostat, err := tun.tunFile.Stat() if err != nil { tun.name = "" return "", err @@ -202,7 +202,7 @@ func (tun *nativeTun) Name() (string, error) { } func (tun *nativeTun) File() *os.File { - return tun.fd + return tun.tunFile } func (tun *nativeTun) Events() chan TUNEvent { @@ -215,7 +215,7 @@ func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) { return 0, err default: buff := buff[offset-4:] - n, err := tun.fd.Read(buff[:]) + n, err := tun.tunFile.Read(buff[:]) if n < 4 { return 0, err } @@ -255,13 +255,13 @@ func (tun *nativeTun) Write(buff []byte, offset int) (int, error) { // write - return tun.fd.Write(buff) + return tun.tunFile.Write(buff) } func (tun *nativeTun) Close() error { var err3 error err1 := tun.rwcancel.Cancel() - err2 := tun.fd.Close() + err2 := tun.tunFile.Close() if tun.routeSocket != -1 { unix.Shutdown(tun.routeSocket, unix.SHUT_RDWR) err3 = unix.Close(tun.routeSocket)