feat(vpn): auto detection of IPv6 support
- `OPENVPN_IPV6` removed - Affects OpenVPN - Use the same mechanism for OpenVPN and Wireguard - Check only once at program start since this is unlikely to change at runtime - Log if IPv6 is supported - Remove `IPv6` boolean from settings structs - Move IPv6 detection as a method on NetLinker
This commit is contained in:
@@ -55,6 +55,7 @@ func Test_New(t *testing.T) {
|
||||
Mask: net.IPv4Mask(255, 255, 255, 255)},
|
||||
},
|
||||
FirewallMark: 100,
|
||||
IPv6: ptr(false),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package wireguard
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/netlink"
|
||||
)
|
||||
|
||||
func (w *Wireguard) isIPv6Supported() (supported bool, err error) {
|
||||
links, err := w.netlink.LinkList()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("cannot list links: %w", err)
|
||||
}
|
||||
|
||||
w.logger.Debug("Checking for IPv6 support...")
|
||||
for _, link := range links {
|
||||
linkName := link.Attrs().Name
|
||||
routes, err := w.netlink.RouteList(link, netlink.FAMILY_V6)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("cannot list routes for link %s: %w", linkName, err)
|
||||
}
|
||||
|
||||
if len(routes) == 0 {
|
||||
w.logger.Debugf("Link %s has no IPv6 route", linkName)
|
||||
continue
|
||||
}
|
||||
|
||||
w.logger.Debugf("Link %s has IPv6 routes: %#v",
|
||||
linkName, routes)
|
||||
supported = true
|
||||
}
|
||||
|
||||
return supported, nil
|
||||
}
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrDetectIPv6 = errors.New("cannot detect IPv6 support")
|
||||
ErrDetectKernel = errors.New("cannot detect Kernel support")
|
||||
ErrCreateTun = errors.New("cannot create TUN device")
|
||||
ErrAddLink = errors.New("cannot add Wireguard link")
|
||||
@@ -36,12 +35,6 @@ var (
|
||||
|
||||
// See https://git.zx2c4.com/wireguard-go/tree/main.go
|
||||
func (w *Wireguard) Run(ctx context.Context, waitError chan<- error, ready chan<- struct{}) {
|
||||
doIPv6, err := w.isIPv6Supported()
|
||||
if err != nil {
|
||||
waitError <- fmt.Errorf("%w: %s", ErrDetectIPv6, err)
|
||||
return
|
||||
}
|
||||
|
||||
doKernel, err := w.netlink.IsWireguardSupported()
|
||||
if err != nil {
|
||||
waitError <- fmt.Errorf("%w: %s", ErrDetectKernel, err)
|
||||
@@ -101,7 +94,7 @@ func (w *Wireguard) Run(ctx context.Context, waitError chan<- error, ready chan<
|
||||
return
|
||||
}
|
||||
|
||||
if doIPv6 {
|
||||
if *w.settings.IPv6 {
|
||||
// requires net.ipv6.conf.all.disable_ipv6=0
|
||||
err = w.addRoute(link, allIPv6(), w.settings.FirewallMark)
|
||||
if err != nil {
|
||||
|
||||
@@ -30,6 +30,9 @@ type Settings struct {
|
||||
// RulePriority is the priority for the rule created with the
|
||||
// FirewallMark.
|
||||
RulePriority int
|
||||
// IPv6 can bet set to true if IPv6 should be handled.
|
||||
// It defaults to false if left unset.
|
||||
IPv6 *bool
|
||||
}
|
||||
|
||||
func (s *Settings) SetDefaults() {
|
||||
@@ -47,6 +50,11 @@ func (s *Settings) SetDefaults() {
|
||||
const defaultFirewallMark = 51820
|
||||
s.FirewallMark = defaultFirewallMark
|
||||
}
|
||||
|
||||
if s.IPv6 == nil {
|
||||
ipv6 := false // this should be injected from host
|
||||
s.IPv6 = &ipv6
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -187,6 +195,12 @@ func (s Settings) ToLines(settings ToLinesSettings) (lines []string) {
|
||||
}
|
||||
lines = append(lines, fieldPrefix+"Endpoint: "+endpointStr)
|
||||
|
||||
ipv6Status := "disabled"
|
||||
if *s.IPv6 {
|
||||
ipv6Status = "enabled"
|
||||
}
|
||||
lines = append(lines, fieldPrefix+"IPv6: "+ipv6Status)
|
||||
|
||||
if s.FirewallMark != 0 {
|
||||
lines = append(lines, fieldPrefix+"Firewall mark: "+fmt.Sprint(s.FirewallMark))
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func ptr[T any](v T) *T { return &v }
|
||||
|
||||
func Test_Settings_SetDefaults(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -20,6 +22,7 @@ func Test_Settings_SetDefaults(t *testing.T) {
|
||||
expected: Settings{
|
||||
InterfaceName: "wg0",
|
||||
FirewallMark: 51820,
|
||||
IPv6: ptr(false),
|
||||
},
|
||||
},
|
||||
"default endpoint port": {
|
||||
@@ -35,6 +38,7 @@ func Test_Settings_SetDefaults(t *testing.T) {
|
||||
IP: net.IPv4(1, 2, 3, 4),
|
||||
Port: 51820,
|
||||
},
|
||||
IPv6: ptr(false),
|
||||
},
|
||||
},
|
||||
"not empty settings": {
|
||||
@@ -45,6 +49,7 @@ func Test_Settings_SetDefaults(t *testing.T) {
|
||||
IP: net.IPv4(1, 2, 3, 4),
|
||||
Port: 9999,
|
||||
},
|
||||
IPv6: ptr(true),
|
||||
},
|
||||
expected: Settings{
|
||||
InterfaceName: "wg1",
|
||||
@@ -53,6 +58,7 @@ func Test_Settings_SetDefaults(t *testing.T) {
|
||||
IP: net.IPv4(1, 2, 3, 4),
|
||||
Port: 9999,
|
||||
},
|
||||
IPv6: ptr(true),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -282,11 +288,13 @@ func Test_Settings_String(t *testing.T) {
|
||||
|
||||
settings := Settings{
|
||||
InterfaceName: "wg0",
|
||||
IPv6: ptr(true),
|
||||
}
|
||||
const expected = `├── Interface name: wg0
|
||||
├── Private key: not set
|
||||
├── Pre shared key: not set
|
||||
├── Endpoint: not set
|
||||
├── IPv6: enabled
|
||||
└── Addresses: not set`
|
||||
s := settings.String()
|
||||
assert.Equal(t, expected, s)
|
||||
@@ -301,11 +309,15 @@ func Test_Settings_Lines(t *testing.T) {
|
||||
lines []string
|
||||
}{
|
||||
"empty settings": {
|
||||
settings: Settings{
|
||||
IPv6: ptr(false),
|
||||
},
|
||||
lines: []string{
|
||||
"├── Interface name: ",
|
||||
"├── Private key: not set",
|
||||
"├── Pre shared key: not set",
|
||||
"├── Endpoint: not set",
|
||||
"├── IPv6: disabled",
|
||||
"└── Addresses: not set",
|
||||
},
|
||||
},
|
||||
@@ -325,6 +337,7 @@ func Test_Settings_Lines(t *testing.T) {
|
||||
{IP: net.IPv4(1, 1, 1, 1), Mask: net.CIDRMask(24, 32)},
|
||||
{IP: net.IPv4(2, 2, 2, 2), Mask: net.CIDRMask(32, 32)},
|
||||
},
|
||||
IPv6: ptr(true),
|
||||
},
|
||||
lines: []string{
|
||||
"├── Interface name: wg0",
|
||||
@@ -332,6 +345,7 @@ func Test_Settings_Lines(t *testing.T) {
|
||||
"├── PublicKey: public key",
|
||||
"├── Pre shared key: set",
|
||||
"├── Endpoint: 1.2.3.4:51820",
|
||||
"├── IPv6: enabled",
|
||||
"├── Firewall mark: 999",
|
||||
"├── Rule priority: 888",
|
||||
"└── Addresses:",
|
||||
@@ -351,12 +365,14 @@ func Test_Settings_Lines(t *testing.T) {
|
||||
{IP: net.IPv4(1, 1, 1, 1), Mask: net.CIDRMask(24, 32)},
|
||||
{IP: net.IPv4(2, 2, 2, 2), Mask: net.CIDRMask(32, 32)},
|
||||
},
|
||||
IPv6: ptr(false),
|
||||
},
|
||||
lines: []string{
|
||||
"- Interface name: wg0",
|
||||
"- Private key: not set",
|
||||
"- Pre shared key: not set",
|
||||
"- Endpoint: not set",
|
||||
"- IPv6: disabled",
|
||||
"* Addresses:",
|
||||
" - 1.1.1.1/24",
|
||||
" * 2.2.2.2/32",
|
||||
|
||||
Reference in New Issue
Block a user