This commit is contained in:
JackDoan
2025-11-07 14:26:35 -06:00
parent a89f95182c
commit 6e22bfeeb1
2 changed files with 122 additions and 88 deletions

View File

@@ -26,11 +26,11 @@ func NewDeviceFromConfig(c *config.C, l *logrus.Logger, vpnNetworks []netip.Pref
} }
} }
func NewFdDeviceFromConfig(fd *int) DeviceFactory { //func NewFdDeviceFromConfig(fd *int) DeviceFactory {
return func(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, routines int) (Device, error) { // return func(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, routines int) (Device, error) {
return newTunFromFd(c, l, *fd, vpnNetworks) // return newTunFromFd(c, l, *fd, vpnNetworks)
} // }
} //}
func getAllRoutesFromConfig(c *config.C, vpnNetworks []netip.Prefix, initial bool) (bool, []Route, error) { func getAllRoutesFromConfig(c *config.C, vpnNetworks []netip.Prefix, initial bool) (bool, []Route, error) {
if !initial && !c.HasChanged("tun.routes") && !c.HasChanged("tun.unsafe_routes") { if !initial && !c.HasChanged("tun.routes") && !c.HasChanged("tun.unsafe_routes") {

View File

@@ -11,10 +11,14 @@ import (
"os" "os"
"strings" "strings"
"sync/atomic" "sync/atomic"
"syscall"
"time" "time"
"unsafe" "unsafe"
"github.com/gaissmai/bart" "github.com/gaissmai/bart"
"github.com/hetznercloud/virtio-go/tuntap"
"github.com/hetznercloud/virtio-go/vhostnet"
"github.com/hetznercloud/virtio-go/virtio"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/slackhq/nebula/config" "github.com/slackhq/nebula/config"
"github.com/slackhq/nebula/routing" "github.com/slackhq/nebula/routing"
@@ -24,8 +28,8 @@ import (
) )
type tun struct { type tun struct {
io.ReadWriteCloser dev *tuntap.Device
fd int vdev *vhostnet.Device
Device string Device string
vpnNetworks []netip.Prefix vpnNetworks []netip.Prefix
MaxMTU int MaxMTU int
@@ -65,68 +69,87 @@ type ifreqQLEN struct {
pad [8]byte pad [8]byte
} }
func newTunFromFd(c *config.C, l *logrus.Logger, deviceFd int, vpnNetworks []netip.Prefix) (*tun, error) { //func newTunFromFd(c *config.C, l *logrus.Logger, deviceFd int, vpnNetworks []netip.Prefix) (*tun, error) {
file := os.NewFile(uintptr(deviceFd), "/dev/net/tun") // file := os.NewFile(uintptr(deviceFd), "/dev/net/tun")
//
t, err := newTunGeneric(c, l, file, vpnNetworks) // t, err := newTunGeneric(c, l, file, vpnNetworks)
if err != nil { // if err != nil {
return nil, err // return nil, err
} // }
//
t.Device = "tun0" // t.Device = "tun0"
//
return t, nil // return t, nil
} //}
func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, multiqueue bool) (*tun, error) { func newTun(c *config.C, l *logrus.Logger, vpnNetworks []netip.Prefix, multiqueue bool) (*tun, error) {
fd, err := unix.Open("/dev/net/tun", os.O_RDWR, 0) //fd, err := unix.Open("/dev/net/tun", os.O_RDWR, 0)
if err != nil { //if err != nil {
// If /dev/net/tun doesn't exist, try to create it (will happen in docker) // // If /dev/net/tun doesn't exist, try to create it (will happen in docker)
if os.IsNotExist(err) { // if os.IsNotExist(err) {
err = os.MkdirAll("/dev/net", 0755) // err = os.MkdirAll("/dev/net", 0755)
if err != nil { // if err != nil {
return nil, fmt.Errorf("/dev/net/tun doesn't exist, failed to mkdir -p /dev/net: %w", err) // return nil, fmt.Errorf("/dev/net/tun doesn't exist, failed to mkdir -p /dev/net: %w", err)
} // }
err = unix.Mknod("/dev/net/tun", unix.S_IFCHR|0600, int(unix.Mkdev(10, 200))) // err = unix.Mknod("/dev/net/tun", unix.S_IFCHR|0600, int(unix.Mkdev(10, 200)))
if err != nil { // if err != nil {
return nil, fmt.Errorf("failed to create /dev/net/tun: %w", err) // return nil, fmt.Errorf("failed to create /dev/net/tun: %w", err)
} // }
//
// fd, err = unix.Open("/dev/net/tun", os.O_RDWR, 0)
// if err != nil {
// return nil, fmt.Errorf("created /dev/net/tun, but still failed: %w", err)
// }
// } else {
// return nil, err
// }
//}
//
//var req ifReq
//req.Flags = uint16(unix.IFF_TUN | unix.IFF_NO_PI)
//if multiqueue {
// req.Flags |= unix.IFF_MULTI_QUEUE
//}
//copy(req.Name[:], c.GetString("tun.dev", ""))
//if err = ioctl(uintptr(fd), uintptr(unix.TUNSETIFF), uintptr(unsafe.Pointer(&req))); err != nil {
// return nil, err
//}
//name := strings.Trim(string(req.Name[:]), "\x00")
//
//file := os.NewFile(uintptr(fd), "/dev/net/tun")
fd, err = unix.Open("/dev/net/tun", os.O_RDWR, 0) name := strings.Trim(c.GetString("tun.dev", ""), "\x00")
if err != nil { tundev, err := tuntap.NewDevice(
return nil, fmt.Errorf("created /dev/net/tun, but still failed: %w", err) tuntap.WithName(name),
} tuntap.WithDeviceType(tuntap.DeviceTypeTUN),
} else { tuntap.WithVirtioNetHdr(true),
return nil, err tuntap.WithOffloads(0x0), //todo
} )
}
var req ifReq
req.Flags = uint16(unix.IFF_TUN | unix.IFF_NO_PI)
if multiqueue {
req.Flags |= unix.IFF_MULTI_QUEUE
}
copy(req.Name[:], c.GetString("tun.dev", ""))
if err = ioctl(uintptr(fd), uintptr(unix.TUNSETIFF), uintptr(unsafe.Pointer(&req))); err != nil {
return nil, err
}
name := strings.Trim(string(req.Name[:]), "\x00")
file := os.NewFile(uintptr(fd), "/dev/net/tun")
t, err := newTunGeneric(c, l, file, vpnNetworks)
if err != nil { if err != nil {
return nil, err return nil, err
} }
t, err := newTunGeneric(c, l, tundev.File(), vpnNetworks)
if err != nil {
return nil, err
}
t.dev = tundev
t.Device = name t.Device = name
vdev, err := vhostnet.NewDevice(
vhostnet.WithBackendDevice(tundev),
vhostnet.WithQueueSize(8), //todo config
)
if err != nil {
return nil, err
}
t.vdev = vdev
return t, nil return t, nil
} }
func newTunGeneric(c *config.C, l *logrus.Logger, file *os.File, vpnNetworks []netip.Prefix) (*tun, error) { func newTunGeneric(c *config.C, l *logrus.Logger, file *os.File, vpnNetworks []netip.Prefix) (*tun, error) {
t := &tun{ t := &tun{
ReadWriteCloser: file,
fd: int(file.Fd()),
vpnNetworks: vpnNetworks, vpnNetworks: vpnNetworks,
TXQueueLen: c.GetInt("tun.tx_queue", 500), TXQueueLen: c.GetInt("tun.tx_queue", 500),
useSystemRoutes: c.GetBool("tun.use_system_route_table", false), useSystemRoutes: c.GetBool("tun.use_system_route_table", false),
@@ -217,21 +240,22 @@ func (t *tun) reload(c *config.C, initial bool) error {
} }
func (t *tun) NewMultiQueueReader() (io.ReadWriteCloser, error) { func (t *tun) NewMultiQueueReader() (io.ReadWriteCloser, error) {
fd, err := unix.Open("/dev/net/tun", os.O_RDWR, 0) //fd, err := unix.Open("/dev/net/tun", os.O_RDWR, 0)
if err != nil { //if err != nil {
return nil, err // return nil, err
} //}
//
//var req ifReq
//req.Flags = uint16(unix.IFF_TUN | unix.IFF_NO_PI | unix.IFF_MULTI_QUEUE)
//copy(req.Name[:], t.Device)
//if err = ioctl(uintptr(fd), uintptr(unix.TUNSETIFF), uintptr(unsafe.Pointer(&req))); err != nil {
// return nil, err
//}
//
//file := os.NewFile(uintptr(fd), "/dev/net/tun")
var req ifReq //return file, nil
req.Flags = uint16(unix.IFF_TUN | unix.IFF_NO_PI | unix.IFF_MULTI_QUEUE) return nil, syscall.ENOTSUP
copy(req.Name[:], t.Device)
if err = ioctl(uintptr(fd), uintptr(unix.TUNSETIFF), uintptr(unsafe.Pointer(&req))); err != nil {
return nil, err
}
file := os.NewFile(uintptr(fd), "/dev/net/tun")
return file, nil
} }
func (t *tun) RoutesFor(ip netip.Addr) routing.Gateways { func (t *tun) RoutesFor(ip netip.Addr) routing.Gateways {
@@ -239,27 +263,33 @@ func (t *tun) RoutesFor(ip netip.Addr) routing.Gateways {
return r return r
} }
func (t *tun) Read(p []byte) (int, error) {
_, out, err := t.vdev.ReceivePacket()
if err != nil {
return 0, err
}
p = p[:len(out)]
copy(p, out)
return len(out), nil
}
func (t *tun) Write(b []byte) (int, error) { func (t *tun) Write(b []byte) (int, error) {
var nn int
maximum := len(b) maximum := len(b)
for { hdr := virtio.NetHdr{ //todo
n, err := unix.Write(t.fd, b[nn:maximum]) Flags: 0,
if n > 0 { GSOType: 0,
nn += n HdrLen: 0,
GSOSize: 0,
CsumStart: 0,
CsumOffset: 0,
NumBuffers: 0,
} }
if nn == len(b) { err := t.vdev.TransmitPacket(hdr, b)
return nn, err
}
if err != nil { if err != nil {
return nn, err return 0, err
}
if n == 0 {
return nn, io.ErrUnexpectedEOF
}
} }
return maximum, nil
} }
func (t *tun) deviceBytes() (o [16]byte) { func (t *tun) deviceBytes() (o [16]byte) {
@@ -674,8 +704,12 @@ func (t *tun) Close() error {
close(t.routeChan) close(t.routeChan)
} }
if t.ReadWriteCloser != nil { if t.vdev != nil {
_ = t.ReadWriteCloser.Close() _ = t.vdev.Close()
}
if t.dev != nil {
_ = t.dev.Close()
} }
if t.ioctlFd > 0 { if t.ioctlFd > 0 {