fix(wireguard): fix detection of kernelspace wireguard

This commit is contained in:
Quentin McGaw
2026-01-20 15:40:59 +00:00
parent a10349e378
commit 857fe425ec
10 changed files with 31 additions and 62 deletions
+1 -1
View File
@@ -549,7 +549,7 @@ type netLinker interface {
Router Router
Ruler Ruler
Linker Linker
IsWireguardSupported() (ok bool, err error) IsWireguardSupported() bool
IsIPv6Supported() (ok bool, err error) IsIPv6Supported() (ok bool, err error)
PatchLoggerLevel(level log.Level) PatchLoggerLevel(level log.Level)
} }
+11 -1
View File
@@ -1,8 +1,18 @@
package netlink package netlink
import "net/netip" import (
"net/netip"
"github.com/qdm12/log"
)
func makeNetipPrefix(n byte) netip.Prefix { func makeNetipPrefix(n byte) netip.Prefix {
const bits = 24 const bits = 24
return netip.PrefixFrom(netip.AddrFrom4([4]byte{n, n, n, 0}), bits) return netip.PrefixFrom(netip.AddrFrom4([4]byte{n, n, n, 0}), bits)
} }
type noopLogger struct{}
func (l *noopLogger) Debug(_ string) {}
func (l *noopLogger) Debugf(_ string, _ ...any) {}
func (l *noopLogger) Patch(_ ...log.Option) {}
+9 -26
View File
@@ -3,52 +3,35 @@
package netlink package netlink
import ( import (
"fmt"
"github.com/qdm12/gluetun/internal/mod" "github.com/qdm12/gluetun/internal/mod"
"github.com/vishvananda/netlink" "github.com/vishvananda/netlink"
) )
func (n *NetLink) IsWireguardSupported() (ok bool, err error) { func (n *NetLink) IsWireguardSupported() bool {
// Check for Wireguard family without loading the wireguard module. // Check for Wireguard family without loading the wireguard module.
// Some kernels have the wireguard module built-in, and don't have a // Some kernels have the wireguard module built-in, and don't have a
// modules directory, such as WSL2 kernels. // modules directory, such as WSL2 kernels.
ok, err = hasWireguardFamily() ok := hasWireguardFamily()
if err != nil {
return false, fmt.Errorf("checking for wireguard family: %w", err)
}
if ok { if ok {
return true, nil return true
} }
// Try loading the wireguard module, since some systems do not load // Try loading the wireguard module, since some systems do not load
// it after a boot. If this fails, wireguard is assumed to not be supported. // it after a boot. If this fails, wireguard is assumed to not be supported.
n.debugLogger.Debugf("wireguard family not found, trying to load wireguard kernel module") n.debugLogger.Debugf("wireguard family not found, trying to load wireguard kernel module")
err = mod.Probe("wireguard") err := mod.Probe("wireguard")
if err != nil { if err != nil {
n.debugLogger.Debugf("failed loading wireguard kernel module: %s", err) n.debugLogger.Debugf("failed loading wireguard kernel module: %s", err)
return false, nil return false
} }
n.debugLogger.Debugf("wireguard kernel module loaded successfully") n.debugLogger.Debugf("wireguard kernel module loaded successfully")
// Re-check if the Wireguard family is now available, after loading // Re-check if the Wireguard family is now available, after loading
// the wireguard kernel module. // the wireguard kernel module.
ok, err = hasWireguardFamily() return hasWireguardFamily()
if err != nil {
return false, fmt.Errorf("checking for wireguard family: %w", err)
}
return ok, nil
} }
func hasWireguardFamily() (ok bool, err error) { func hasWireguardFamily() bool {
families, err := netlink.GenlFamilyList() _, err := netlink.GenlFamilyGet("wireguard")
if err != nil { return err == nil
return false, fmt.Errorf("listing gen 1 families: %w", err)
}
for _, family := range families {
if family.Name == "wireguard" {
return true, nil
}
}
return false, nil
} }
+5 -7
View File
@@ -4,17 +4,15 @@ package netlink
import ( import (
"testing" "testing"
"github.com/stretchr/testify/require"
) )
func Test_NetLink_IsWireguardSupported(t *testing.T) { func Test_NetLink_IsWireguardSupported(t *testing.T) {
t.Skip() // TODO unskip once the data race problem with netlink.GenlFamilyList() is fixed
t.Parallel() t.Parallel()
netLink := &NetLink{}
ok, err := netLink.IsWireguardSupported() netLink := &NetLink{
require.NoError(t, err) debugLogger: &noopLogger{},
}
ok := netLink.IsWireguardSupported()
if ok { // cannot assert since this depends on kernel if ok { // cannot assert since this depends on kernel
t.Log("wireguard is supported") t.Log("wireguard is supported")
} else { } else {
-15
View File
@@ -63,21 +63,6 @@ func (mr *MockNetLinkerMockRecorder) AddrReplace(arg0, arg1 interface{}) *gomock
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrReplace", reflect.TypeOf((*MockNetLinker)(nil).AddrReplace), arg0, arg1) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrReplace", reflect.TypeOf((*MockNetLinker)(nil).AddrReplace), arg0, arg1)
} }
// IsWireguardSupported mocks base method.
func (m *MockNetLinker) IsWireguardSupported() (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IsWireguardSupported")
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// IsWireguardSupported indicates an expected call of IsWireguardSupported.
func (mr *MockNetLinkerMockRecorder) IsWireguardSupported() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsWireguardSupported", reflect.TypeOf((*MockNetLinker)(nil).IsWireguardSupported))
}
// LinkAdd mocks base method. // LinkAdd mocks base method.
func (m *MockNetLinker) LinkAdd(arg0 netlink.Link) (int, error) { func (m *MockNetLinker) LinkAdd(arg0 netlink.Link) (int, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
-1
View File
@@ -12,7 +12,6 @@ type NetLinker interface {
Router Router
Ruler Ruler
Linker Linker
IsWireguardSupported() (ok bool, err error)
} }
type Addresser interface { type Addresser interface {
+1 -1
View File
@@ -61,7 +61,7 @@ type NetLinker interface {
Router Router
Ruler Ruler
Linker Linker
IsWireguardSupported() (ok bool, err error) IsWireguardSupported() bool
} }
type Router interface { type Router interface {
+1 -1
View File
@@ -9,7 +9,7 @@ type NetLinker interface {
Router Router
Ruler Ruler
Linker Linker
IsWireguardSupported() (ok bool, err error) IsWireguardSupported() bool
} }
type Router interface { type Router interface {
+2 -3
View File
@@ -49,12 +49,11 @@ func (mr *MockNetLinkerMockRecorder) AddrReplace(arg0, arg1 interface{}) *gomock
} }
// IsWireguardSupported mocks base method. // IsWireguardSupported mocks base method.
func (m *MockNetLinker) IsWireguardSupported() (bool, error) { func (m *MockNetLinker) IsWireguardSupported() bool {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "IsWireguardSupported") ret := m.ctrl.Call(m, "IsWireguardSupported")
ret0, _ := ret[0].(bool) ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error) return ret0
return ret0, ret1
} }
// IsWireguardSupported indicates an expected call of IsWireguardSupported. // IsWireguardSupported indicates an expected call of IsWireguardSupported.
+1 -6
View File
@@ -16,7 +16,6 @@ import (
) )
var ( var (
ErrDetectKernel = errors.New("cannot detect Kernel support")
ErrCreateTun = errors.New("cannot create TUN device") ErrCreateTun = errors.New("cannot create TUN device")
ErrAddLink = errors.New("cannot add Wireguard link") ErrAddLink = errors.New("cannot add Wireguard link")
ErrFindLink = errors.New("cannot find link") ErrFindLink = errors.New("cannot find link")
@@ -35,11 +34,7 @@ var (
// See https://git.zx2c4.com/wireguard-go/tree/main.go // See https://git.zx2c4.com/wireguard-go/tree/main.go
func (w *Wireguard) Run(ctx context.Context, waitError chan<- error, ready chan<- struct{}) { func (w *Wireguard) Run(ctx context.Context, waitError chan<- error, ready chan<- struct{}) {
kernelSupported, err := w.netlink.IsWireguardSupported() kernelSupported := w.netlink.IsWireguardSupported()
if err != nil {
waitError <- fmt.Errorf("%w: %s", ErrDetectKernel, err)
return
}
setupFunction := setupUserSpace setupFunction := setupUserSpace
switch w.settings.Implementation { switch w.settings.Implementation {