mirror of
				https://git.zx2c4.com/wireguard-go
				synced 2025-10-27 02:10:26 +08:00 
			
		
		
		
	tun: use sysconn instead of .Fd with Go 1.12
This commit is contained in:
		| @@ -48,7 +48,7 @@ This will run on OpenBSD. It does not yet support sticky sockets. Fwmark is mapp | |||||||
|  |  | ||||||
| ## Building | ## 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 | $ git clone https://git.zx2c4.com/wireguard-go | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								tun/tun.go
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								tun/tun.go
									
									
									
									
									
								
							| @@ -5,7 +5,10 @@ | |||||||
|  |  | ||||||
| package tun | package tun | ||||||
|  |  | ||||||
| import "os" | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"os" | ||||||
|  | ) | ||||||
|  |  | ||||||
| type TUNEvent int | type TUNEvent int | ||||||
|  |  | ||||||
| @@ -24,3 +27,15 @@ type TUNDevice interface { | |||||||
| 	Events() chan TUNEvent          // returns a constant channel of events related to the device | 	Events() chan TUNEvent          // returns a constant channel of events related to the device | ||||||
| 	Close() error                   // stops the device and closes the event channel | 	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()) | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -8,9 +8,9 @@ package tun | |||||||
| import ( | import ( | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"golang.zx2c4.com/wireguard/rwcancel" |  | ||||||
| 	"golang.org/x/net/ipv6" | 	"golang.org/x/net/ipv6" | ||||||
| 	"golang.org/x/sys/unix" | 	"golang.org/x/sys/unix" | ||||||
|  | 	"golang.zx2c4.com/wireguard/rwcancel" | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"net" | 	"net" | ||||||
| 	"os" | 	"os" | ||||||
| @@ -36,7 +36,6 @@ type sockaddrCtl struct { | |||||||
| type nativeTun struct { | type nativeTun struct { | ||||||
| 	name        string | 	name        string | ||||||
| 	tunFile     *os.File | 	tunFile     *os.File | ||||||
| 	fd          uintptr |  | ||||||
| 	rwcancel    *rwcancel.RWCancel | 	rwcancel    *rwcancel.RWCancel | ||||||
| 	events      chan TUNEvent | 	events      chan TUNEvent | ||||||
| 	errors      chan error | 	errors      chan error | ||||||
| @@ -168,10 +167,8 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { | func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { | ||||||
|  |  | ||||||
| 	tun := &nativeTun{ | 	tun := &nativeTun{ | ||||||
| 		tunFile: file, | 		tunFile: file, | ||||||
| 		fd:      file.Fd(), |  | ||||||
| 		events:  make(chan TUNEvent, 10), | 		events:  make(chan TUNEvent, 10), | ||||||
| 		errors:  make(chan error, 1), | 		errors:  make(chan error, 1), | ||||||
| 	} | 	} | ||||||
| @@ -194,7 +191,9 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { | |||||||
| 		return nil, err | 		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 { | 	if err != nil { | ||||||
| 		tun.tunFile.Close() | 		tun.tunFile.Close() | ||||||
| 		return nil, err | 		return nil, err | ||||||
| @@ -218,19 +217,21 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (tun *nativeTun) Name() (string, error) { | func (tun *nativeTun) Name() (string, error) { | ||||||
|  |  | ||||||
| 	var ifName struct { | 	var ifName struct { | ||||||
| 		name [16]byte | 		name [16]byte | ||||||
| 	} | 	} | ||||||
| 	ifNameSize := uintptr(16) | 	ifNameSize := uintptr(16) | ||||||
|  |  | ||||||
| 	_, _, errno := unix.Syscall6( | 	var errno syscall.Errno | ||||||
| 		unix.SYS_GETSOCKOPT, | 	tun.operateOnFd(func(fd uintptr) { | ||||||
| 		uintptr(tun.fd), | 		_, _, errno = unix.Syscall6( | ||||||
| 		2, /* #define SYSPROTO_CONTROL 2 */ | 			unix.SYS_GETSOCKOPT, | ||||||
| 		2, /* #define UTUN_OPT_IFNAME 2 */ | 			fd, | ||||||
| 		uintptr(unsafe.Pointer(&ifName)), | 			2, /* #define SYSPROTO_CONTROL 2 */ | ||||||
| 		uintptr(unsafe.Pointer(&ifNameSize)), 0) | 			2, /* #define UTUN_OPT_IFNAME 2 */ | ||||||
|  | 			uintptr(unsafe.Pointer(&ifName)), | ||||||
|  | 			uintptr(unsafe.Pointer(&ifNameSize)), 0) | ||||||
|  | 	}) | ||||||
|  |  | ||||||
| 	if errno != 0 { | 	if errno != 0 { | ||||||
| 		return "", fmt.Errorf("SYS_GETSOCKOPT: %v", errno) | 		return "", fmt.Errorf("SYS_GETSOCKOPT: %v", errno) | ||||||
|   | |||||||
| @@ -9,9 +9,9 @@ import ( | |||||||
| 	"bytes" | 	"bytes" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"golang.zx2c4.com/wireguard/rwcancel" |  | ||||||
| 	"golang.org/x/net/ipv6" | 	"golang.org/x/net/ipv6" | ||||||
| 	"golang.org/x/sys/unix" | 	"golang.org/x/sys/unix" | ||||||
|  | 	"golang.zx2c4.com/wireguard/rwcancel" | ||||||
| 	"net" | 	"net" | ||||||
| 	"os" | 	"os" | ||||||
| 	"syscall" | 	"syscall" | ||||||
| @@ -52,7 +52,6 @@ type ifstat struct { | |||||||
| type nativeTun struct { | type nativeTun struct { | ||||||
| 	name        string | 	name        string | ||||||
| 	tunFile     *os.File | 	tunFile     *os.File | ||||||
| 	fd          uintptr |  | ||||||
| 	rwcancel    *rwcancel.RWCancel | 	rwcancel    *rwcancel.RWCancel | ||||||
| 	events      chan TUNEvent | 	events      chan TUNEvent | ||||||
| 	errors      chan error | 	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) | 	tunFile, err := os.OpenFile("/dev/tun", unix.O_RDWR, 0) | ||||||
|  |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		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 { | 	if err != nil { | ||||||
| 		tunFile.Close() | 		tunFile.Close() | ||||||
| 		return nil, err | 		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 | 	// Enable ifhead mode, otherwise tun will complain if it gets a non-AF_INET packet | ||||||
| 	ifheadmode := 1 | 	ifheadmode := 1 | ||||||
| 	_, _, errno := unix.Syscall( | 	var errno syscall.Errno | ||||||
| 		unix.SYS_IOCTL, | 	tun.operateOnFd(func(fd uintptr) { | ||||||
| 		uintptr(tunfd), | 		_, _, errno = unix.Syscall( | ||||||
| 		uintptr(_TUNSIFHEAD), | 			unix.SYS_IOCTL, | ||||||
| 		uintptr(unsafe.Pointer(&ifheadmode)), | 			fd, | ||||||
| 	) | 			uintptr(_TUNSIFHEAD), | ||||||
|  | 			uintptr(unsafe.Pointer(&ifheadmode)), | ||||||
|  | 		) | ||||||
|  | 	}) | ||||||
|  |  | ||||||
| 	if errno != 0 { | 	if errno != 0 { | ||||||
| 		return nil, fmt.Errorf("error %s", errno.Error()) | 		return nil, fmt.Errorf("error %s", errno.Error()) | ||||||
| @@ -306,7 +311,6 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { | |||||||
|  |  | ||||||
| 	tun := &nativeTun{ | 	tun := &nativeTun{ | ||||||
| 		tunFile: file, | 		tunFile: file, | ||||||
| 		fd:      file.Fd(), |  | ||||||
| 		events:  make(chan TUNEvent, 10), | 		events:  make(chan TUNEvent, 10), | ||||||
| 		errors:  make(chan error, 1), | 		errors:  make(chan error, 1), | ||||||
| 	} | 	} | ||||||
| @@ -329,7 +333,9 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { | |||||||
| 		return nil, err | 		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 { | 	if err != nil { | ||||||
| 		tun.tunFile.Close() | 		tun.tunFile.Close() | ||||||
| 		return nil, err | 		return nil, err | ||||||
| @@ -353,7 +359,11 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (tun *nativeTun) Name() (string, 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 { | 	if err != nil { | ||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -12,13 +12,14 @@ import ( | |||||||
| 	"bytes" | 	"bytes" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"golang.zx2c4.com/wireguard/rwcancel" |  | ||||||
| 	"golang.org/x/net/ipv6" | 	"golang.org/x/net/ipv6" | ||||||
| 	"golang.org/x/sys/unix" | 	"golang.org/x/sys/unix" | ||||||
|  | 	"golang.zx2c4.com/wireguard/rwcancel" | ||||||
| 	"net" | 	"net" | ||||||
| 	"os" | 	"os" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"sync" | 	"sync" | ||||||
|  | 	"syscall" | ||||||
| 	"time" | 	"time" | ||||||
| 	"unsafe" | 	"unsafe" | ||||||
| ) | ) | ||||||
| @@ -30,7 +31,6 @@ const ( | |||||||
|  |  | ||||||
| type nativeTun struct { | type nativeTun struct { | ||||||
| 	tunFile                 *os.File | 	tunFile                 *os.File | ||||||
| 	fd                      uintptr |  | ||||||
| 	fdCancel                *rwcancel.RWCancel | 	fdCancel                *rwcancel.RWCancel | ||||||
| 	index                   int32         // if index | 	index                   int32         // if index | ||||||
| 	name                    string        // name of interface | 	name                    string        // name of interface | ||||||
| @@ -52,9 +52,11 @@ func (tun *nativeTun) routineHackListener() { | |||||||
| 	/* This is needed for the detection to work across network namespaces | 	/* 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. | 	 * If you are reading this and know a better method, please get in touch. | ||||||
| 	 */ | 	 */ | ||||||
| 	fd := int(tun.fd) |  | ||||||
| 	for { | 	for { | ||||||
| 		_, err := unix.Write(fd, nil) | 		var err error | ||||||
|  | 		tun.operateOnFd(func(fd uintptr) { | ||||||
|  | 			_, err = unix.Write(int(fd), nil) | ||||||
|  | 		}) | ||||||
| 		switch err { | 		switch err { | ||||||
| 		case unix.EINVAL: | 		case unix.EINVAL: | ||||||
| 			tun.events <- TUNEventUp | 			tun.events <- TUNEventUp | ||||||
| @@ -162,16 +164,12 @@ func (tun *nativeTun) isUp() (bool, error) { | |||||||
| 	return inter.Flags&net.FlagUp != 0, err | 	return inter.Flags&net.FlagUp != 0, err | ||||||
| } | } | ||||||
|  |  | ||||||
| func getDummySock() (int, error) { | func getIFIndex(name string) (int32, error) { | ||||||
| 	return unix.Socket( | 	fd, err := unix.Socket( | ||||||
| 		unix.AF_INET, | 		unix.AF_INET, | ||||||
| 		unix.SOCK_DGRAM, | 		unix.SOCK_DGRAM, | ||||||
| 		0, | 		0, | ||||||
| 	) | 	) | ||||||
| } |  | ||||||
|  |  | ||||||
| func getIFIndex(name string) (int32, error) { |  | ||||||
| 	fd, err := getDummySock() |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return 0, err | 		return 0, err | ||||||
| 	} | 	} | ||||||
| @@ -195,9 +193,7 @@ func getIFIndex(name string) (int32, error) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (tun *nativeTun) setMTU(n int) error { | func (tun *nativeTun) setMTU(n int) error { | ||||||
|  |  | ||||||
| 	// open datagram socket | 	// open datagram socket | ||||||
|  |  | ||||||
| 	fd, err := unix.Socket( | 	fd, err := unix.Socket( | ||||||
| 		unix.AF_INET, | 		unix.AF_INET, | ||||||
| 		unix.SOCK_DGRAM, | 		unix.SOCK_DGRAM, | ||||||
| @@ -230,9 +226,7 @@ func (tun *nativeTun) setMTU(n int) error { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (tun *nativeTun) MTU() (int, error) { | func (tun *nativeTun) MTU() (int, error) { | ||||||
|  |  | ||||||
| 	// open datagram socket | 	// open datagram socket | ||||||
|  |  | ||||||
| 	fd, err := unix.Socket( | 	fd, err := unix.Socket( | ||||||
| 		unix.AF_INET, | 		unix.AF_INET, | ||||||
| 		unix.SOCK_DGRAM, | 		unix.SOCK_DGRAM, | ||||||
| @@ -263,14 +257,16 @@ func (tun *nativeTun) MTU() (int, error) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (tun *nativeTun) Name() (string, error) { | func (tun *nativeTun) Name() (string, error) { | ||||||
|  |  | ||||||
| 	var ifr [ifReqSize]byte | 	var ifr [ifReqSize]byte | ||||||
| 	_, _, errno := unix.Syscall( | 	var errno syscall.Errno | ||||||
| 		unix.SYS_IOCTL, | 	tun.operateOnFd(func(fd uintptr) { | ||||||
| 		tun.fd, | 		_, _, errno = unix.Syscall( | ||||||
| 		uintptr(unix.TUNGETIFF), | 			unix.SYS_IOCTL, | ||||||
| 		uintptr(unsafe.Pointer(&ifr[0])), | 			fd, | ||||||
| 	) | 			uintptr(unix.TUNGETIFF), | ||||||
|  | 			uintptr(unsafe.Pointer(&ifr[0])), | ||||||
|  | 		) | ||||||
|  | 	}) | ||||||
| 	if errno != 0 { | 	if errno != 0 { | ||||||
| 		return "", errors.New("failed to get name of TUN device: " + strconv.FormatInt(int64(errno), 10)) | 		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( | 	_, _, errno := unix.Syscall( | ||||||
| 		unix.SYS_IOCTL, | 		unix.SYS_IOCTL, | ||||||
| 		fd.Fd(), | 		nfd, | ||||||
| 		uintptr(unix.TUNSETIFF), | 		uintptr(unix.TUNSETIFF), | ||||||
| 		uintptr(unsafe.Pointer(&ifr[0])), | 		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) { | func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { | ||||||
| 	tun := &nativeTun{ | 	tun := &nativeTun{ | ||||||
| 		tunFile:                 file, | 		tunFile:                 file, | ||||||
| 		fd:                      file.Fd(), |  | ||||||
| 		events:                  make(chan TUNEvent, 5), | 		events:                  make(chan TUNEvent, 5), | ||||||
| 		errors:                  make(chan error, 5), | 		errors:                  make(chan error, 5), | ||||||
| 		statusListenersShutdown: make(chan struct{}), | 		statusListenersShutdown: make(chan struct{}), | ||||||
| @@ -413,7 +408,9 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { | |||||||
| 	} | 	} | ||||||
| 	var err 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 { | 	if err != nil { | ||||||
| 		tun.tunFile.Close() | 		tun.tunFile.Close() | ||||||
| 		return nil, err | 		return nil, err | ||||||
|   | |||||||
| @@ -8,9 +8,9 @@ package tun | |||||||
| import ( | import ( | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"golang.zx2c4.com/wireguard/rwcancel" |  | ||||||
| 	"golang.org/x/net/ipv6" | 	"golang.org/x/net/ipv6" | ||||||
| 	"golang.org/x/sys/unix" | 	"golang.org/x/sys/unix" | ||||||
|  | 	"golang.zx2c4.com/wireguard/rwcancel" | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"net" | 	"net" | ||||||
| 	"os" | 	"os" | ||||||
| @@ -167,7 +167,9 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) { | |||||||
| 		return nil, err | 		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 { | 	if err != nil { | ||||||
| 		tun.tunFile.Close() | 		tun.tunFile.Close() | ||||||
| 		return nil, err | 		return nil, err | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Jason A. Donenfeld
					Jason A. Donenfeld