tun: fix data race on name field
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
abd287159e
commit
85a45a9651
|
@ -31,7 +31,6 @@ const (
|
||||||
type NativeTun struct {
|
type NativeTun struct {
|
||||||
tunFile *os.File
|
tunFile *os.File
|
||||||
index int32 // if index
|
index int32 // if index
|
||||||
name string // name of interface
|
|
||||||
errors chan error // async error handling
|
errors chan error // async error handling
|
||||||
events chan Event // device related events
|
events chan Event // device related events
|
||||||
nopi bool // the device was passed IFF_NO_PI
|
nopi bool // the device was passed IFF_NO_PI
|
||||||
|
@ -39,6 +38,10 @@ type NativeTun struct {
|
||||||
netlinkCancel *rwcancel.RWCancel
|
netlinkCancel *rwcancel.RWCancel
|
||||||
hackListenerClosed sync.Mutex
|
hackListenerClosed sync.Mutex
|
||||||
statusListenersShutdown chan struct{}
|
statusListenersShutdown chan struct{}
|
||||||
|
|
||||||
|
nameOnce sync.Once // guards calling initNameCache, which sets following fields
|
||||||
|
nameCache string // name of interface
|
||||||
|
nameErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tun *NativeTun) File() *os.File {
|
func (tun *NativeTun) File() *os.File {
|
||||||
|
@ -192,6 +195,11 @@ func getIFIndex(name string) (int32, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tun *NativeTun) setMTU(n int) error {
|
func (tun *NativeTun) setMTU(n int) error {
|
||||||
|
name, err := tun.Name()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// open datagram socket
|
// open datagram socket
|
||||||
fd, err := unix.Socket(
|
fd, err := unix.Socket(
|
||||||
unix.AF_INET,
|
unix.AF_INET,
|
||||||
|
@ -206,9 +214,8 @@ func (tun *NativeTun) setMTU(n int) error {
|
||||||
defer unix.Close(fd)
|
defer unix.Close(fd)
|
||||||
|
|
||||||
// do ioctl call
|
// do ioctl call
|
||||||
|
|
||||||
var ifr [ifReqSize]byte
|
var ifr [ifReqSize]byte
|
||||||
copy(ifr[:], tun.name)
|
copy(ifr[:], name)
|
||||||
*(*uint32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = uint32(n)
|
*(*uint32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])) = uint32(n)
|
||||||
_, _, errno := unix.Syscall(
|
_, _, errno := unix.Syscall(
|
||||||
unix.SYS_IOCTL,
|
unix.SYS_IOCTL,
|
||||||
|
@ -225,6 +232,11 @@ func (tun *NativeTun) setMTU(n int) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tun *NativeTun) MTU() (int, error) {
|
func (tun *NativeTun) MTU() (int, error) {
|
||||||
|
name, err := tun.Name()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
// open datagram socket
|
// open datagram socket
|
||||||
fd, err := unix.Socket(
|
fd, err := unix.Socket(
|
||||||
unix.AF_INET,
|
unix.AF_INET,
|
||||||
|
@ -241,7 +253,7 @@ func (tun *NativeTun) MTU() (int, error) {
|
||||||
// do ioctl call
|
// do ioctl call
|
||||||
|
|
||||||
var ifr [ifReqSize]byte
|
var ifr [ifReqSize]byte
|
||||||
copy(ifr[:], tun.name)
|
copy(ifr[:], name)
|
||||||
_, _, errno := unix.Syscall(
|
_, _, errno := unix.Syscall(
|
||||||
unix.SYS_IOCTL,
|
unix.SYS_IOCTL,
|
||||||
uintptr(fd),
|
uintptr(fd),
|
||||||
|
@ -256,6 +268,15 @@ func (tun *NativeTun) MTU() (int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tun *NativeTun) Name() (string, error) {
|
func (tun *NativeTun) Name() (string, error) {
|
||||||
|
tun.nameOnce.Do(tun.initNameCache)
|
||||||
|
return tun.nameCache, tun.nameErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tun *NativeTun) initNameCache() {
|
||||||
|
tun.nameCache, tun.nameErr = tun.nameSlow()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tun *NativeTun) nameSlow() (string, error) {
|
||||||
sysconn, err := tun.tunFile.SyscallConn()
|
sysconn, err := tun.tunFile.SyscallConn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -276,13 +297,11 @@ func (tun *NativeTun) Name() (string, error) {
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
return "", errors.New("failed to get name of TUN device: " + errno.Error())
|
return "", errors.New("failed to get name of TUN device: " + errno.Error())
|
||||||
}
|
}
|
||||||
nullStr := ifr[:]
|
name := ifr[:]
|
||||||
i := bytes.IndexByte(nullStr, 0)
|
if i := bytes.IndexByte(name, 0); i != -1 {
|
||||||
if i != -1 {
|
name = name[:i]
|
||||||
nullStr = nullStr[:i]
|
|
||||||
}
|
}
|
||||||
tun.name = string(nullStr)
|
return string(name), nil
|
||||||
return tun.name, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
|
func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
|
||||||
|
@ -402,16 +421,15 @@ func CreateTUNFromFile(file *os.File, mtu int) (Device, error) {
|
||||||
statusListenersShutdown: make(chan struct{}),
|
statusListenersShutdown: make(chan struct{}),
|
||||||
nopi: false,
|
nopi: false,
|
||||||
}
|
}
|
||||||
var err error
|
|
||||||
|
|
||||||
_, err = tun.Name()
|
name, err := tun.Name()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// start event listener
|
// start event listener
|
||||||
|
|
||||||
tun.index, err = getIFIndex(tun.name)
|
tun.index, err = getIFIndex(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue