tun: freebsd: work around numerous kernel panics on shutdown
There are numerous race conditions. But even this will crash it: while true; do ifconfig tun0 create; ifconfig tun0 destroy; done It seems like LLv6 is related, which we're not using anyway, so explicitly disable it on the interface.
This commit is contained in:
parent
f1dc167901
commit
bb42ec7d18
|
@ -19,9 +19,19 @@ import (
|
||||||
|
|
||||||
// _TUNSIFHEAD, value derived from sys/net/{if_tun,ioccom}.h
|
// _TUNSIFHEAD, value derived from sys/net/{if_tun,ioccom}.h
|
||||||
// const _TUNSIFHEAD = ((0x80000000) | (((4) & ((1 << 13) - 1) ) << 16) | (uint32(byte('t')) << 8) | (96))
|
// const _TUNSIFHEAD = ((0x80000000) | (((4) & ((1 << 13) - 1) ) << 16) | (uint32(byte('t')) << 8) | (96))
|
||||||
const _TUNSIFHEAD = 0x80047460
|
const (
|
||||||
const _TUNSIFMODE = 0x8004745e
|
_TUNSIFHEAD = 0x80047460
|
||||||
const _TUNSIFPID = 0x2000745f
|
_TUNSIFMODE = 0x8004745e
|
||||||
|
_TUNSIFPID = 0x2000745f
|
||||||
|
)
|
||||||
|
|
||||||
|
//TODO: move into x/sys/unix
|
||||||
|
const (
|
||||||
|
SIOCGIFINFO_IN6 = 0xc048696c
|
||||||
|
SIOCSIFINFO_IN6 = 0xc048696d
|
||||||
|
ND6_IFF_AUTO_LINKLOCAL = 0x20
|
||||||
|
ND6_IFF_NO_DAD = 0x100
|
||||||
|
)
|
||||||
|
|
||||||
// Iface status string max len
|
// Iface status string max len
|
||||||
const _IFSTATMAX = 800
|
const _IFSTATMAX = 800
|
||||||
|
@ -32,7 +42,7 @@ const SIZEOF_UINTPTR = 4 << (^uintptr(0) >> 32 & 1)
|
||||||
type ifreq_ptr struct {
|
type ifreq_ptr struct {
|
||||||
Name [unix.IFNAMSIZ]byte
|
Name [unix.IFNAMSIZ]byte
|
||||||
Data uintptr
|
Data uintptr
|
||||||
Pad0 [24 - SIZEOF_UINTPTR]byte
|
Pad0 [16 - SIZEOF_UINTPTR]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// Structure for iface mtu get/set ioctls
|
// Structure for iface mtu get/set ioctls
|
||||||
|
@ -48,6 +58,23 @@ type ifstat struct {
|
||||||
Ascii [_IFSTATMAX]byte
|
Ascii [_IFSTATMAX]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Structures for nd6 flag manipulation
|
||||||
|
type in6_ndireq struct {
|
||||||
|
Name [unix.IFNAMSIZ]byte
|
||||||
|
Linkmtu uint32
|
||||||
|
Maxmtu uint32
|
||||||
|
Basereachable uint32
|
||||||
|
Reachable uint32
|
||||||
|
Retrans uint32
|
||||||
|
Flags uint32
|
||||||
|
Recalctm int
|
||||||
|
Chlim uint8
|
||||||
|
Initialized uint8
|
||||||
|
Randomseed0 [8]byte
|
||||||
|
Randomseed1 [8]byte
|
||||||
|
Randomid [8]byte
|
||||||
|
}
|
||||||
|
|
||||||
type NativeTun struct {
|
type NativeTun struct {
|
||||||
name string
|
name string
|
||||||
tunFile *os.File
|
tunFile *os.File
|
||||||
|
@ -191,23 +218,18 @@ func tunName(fd uintptr) (string, error) {
|
||||||
|
|
||||||
// Destroy a named system interface
|
// Destroy a named system interface
|
||||||
func tunDestroy(name string) error {
|
func tunDestroy(name string) error {
|
||||||
// open control socket
|
// Open control socket.
|
||||||
var fd int
|
var fd int
|
||||||
|
|
||||||
fd, err := unix.Socket(
|
fd, err := unix.Socket(
|
||||||
unix.AF_INET,
|
unix.AF_INET,
|
||||||
unix.SOCK_DGRAM,
|
unix.SOCK_DGRAM,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer unix.Close(fd)
|
defer unix.Close(fd)
|
||||||
|
|
||||||
// do ioctl call
|
|
||||||
|
|
||||||
var ifr [32]byte
|
var ifr [32]byte
|
||||||
copy(ifr[:], name)
|
copy(ifr[:], name)
|
||||||
_, _, errno := unix.Syscall(
|
_, _, errno := unix.Syscall(
|
||||||
|
@ -216,7 +238,6 @@ func tunDestroy(name string) error {
|
||||||
uintptr(unix.SIOCIFDESTROY),
|
uintptr(unix.SIOCIFDESTROY),
|
||||||
uintptr(unsafe.Pointer(&ifr[0])),
|
uintptr(unsafe.Pointer(&ifr[0])),
|
||||||
)
|
)
|
||||||
|
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
return fmt.Errorf("failed to destroy interface %s: %s", name, errno.Error())
|
return fmt.Errorf("failed to destroy interface %s: %s", name, errno.Error())
|
||||||
}
|
}
|
||||||
|
@ -263,33 +284,71 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) {
|
||||||
})
|
})
|
||||||
|
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
return nil, fmt.Errorf("error %s", errno.Error())
|
tunFile.Close()
|
||||||
|
tunDestroy(assignedName)
|
||||||
|
return nil, fmt.Errorf("Unable to put into IFHEAD mode: %v", errno)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rename tun interface
|
// Open control sockets
|
||||||
|
|
||||||
// Open control socket
|
|
||||||
confd, err := unix.Socket(
|
confd, err := unix.Socket(
|
||||||
unix.AF_INET,
|
unix.AF_INET,
|
||||||
unix.SOCK_DGRAM,
|
unix.SOCK_DGRAM,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
tunFile.Close()
|
||||||
|
tunDestroy(assignedName)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer unix.Close(confd)
|
defer unix.Close(confd)
|
||||||
|
confd6, err := unix.Socket(
|
||||||
|
unix.AF_INET6,
|
||||||
|
unix.SOCK_DGRAM,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
tunFile.Close()
|
||||||
|
tunDestroy(assignedName)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer unix.Close(confd6)
|
||||||
|
|
||||||
// set up struct for iface rename
|
// Disable link-local v6, not just because WireGuard doesn't do that anyway, but
|
||||||
|
// also because there are serious races with attaching and detaching LLv6 addresses
|
||||||
|
// in relation to interface lifetime within the FreeBSD kernel.
|
||||||
|
var ndireq in6_ndireq
|
||||||
|
copy(ndireq.Name[:], assignedName)
|
||||||
|
_, _, errno = unix.Syscall(
|
||||||
|
unix.SYS_IOCTL,
|
||||||
|
uintptr(confd6),
|
||||||
|
uintptr(SIOCGIFINFO_IN6),
|
||||||
|
uintptr(unsafe.Pointer(&ndireq)),
|
||||||
|
)
|
||||||
|
if errno != 0 {
|
||||||
|
tunFile.Close()
|
||||||
|
tunDestroy(assignedName)
|
||||||
|
return nil, fmt.Errorf("Unable to get nd6 flags for %s: %v", assignedName, errno)
|
||||||
|
}
|
||||||
|
ndireq.Flags = ndireq.Flags &^ ND6_IFF_AUTO_LINKLOCAL
|
||||||
|
ndireq.Flags = ndireq.Flags | ND6_IFF_NO_DAD
|
||||||
|
_, _, errno = unix.Syscall(
|
||||||
|
unix.SYS_IOCTL,
|
||||||
|
uintptr(confd6),
|
||||||
|
uintptr(SIOCSIFINFO_IN6),
|
||||||
|
uintptr(unsafe.Pointer(&ndireq)),
|
||||||
|
)
|
||||||
|
if errno != 0 {
|
||||||
|
tunFile.Close()
|
||||||
|
tunDestroy(assignedName)
|
||||||
|
return nil, fmt.Errorf("Unable to set nd6 flags for %s: %v", assignedName, errno)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rename the interface
|
||||||
var newnp [unix.IFNAMSIZ]byte
|
var newnp [unix.IFNAMSIZ]byte
|
||||||
copy(newnp[:], name)
|
copy(newnp[:], name)
|
||||||
|
|
||||||
var ifr ifreq_ptr
|
var ifr ifreq_ptr
|
||||||
copy(ifr.Name[:], assignedName)
|
copy(ifr.Name[:], assignedName)
|
||||||
ifr.Data = uintptr(unsafe.Pointer(&newnp[0]))
|
ifr.Data = uintptr(unsafe.Pointer(&newnp[0]))
|
||||||
|
|
||||||
//do actual ioctl to rename iface
|
|
||||||
_, _, errno = unix.Syscall(
|
_, _, errno = unix.Syscall(
|
||||||
unix.SYS_IOCTL,
|
unix.SYS_IOCTL,
|
||||||
uintptr(confd),
|
uintptr(confd),
|
||||||
|
@ -298,8 +357,8 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) {
|
||||||
)
|
)
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
tunFile.Close()
|
tunFile.Close()
|
||||||
tunDestroy(name)
|
tunDestroy(assignedName)
|
||||||
return nil, fmt.Errorf("failed to rename %s to %s: %s", assignedName, name, errno.Error())
|
return nil, fmt.Errorf("Failed to rename %s to %s: %v", assignedName, name, errno)
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateTUNFromFile(tunFile, mtu)
|
return CreateTUNFromFile(tunFile, mtu)
|
||||||
|
|
Loading…
Reference in a new issue