From d80003c5a70c3f6f03e4987c686558324bffd5b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Pratt?= Date: Wed, 30 Oct 2024 23:23:58 -0400 Subject: [PATCH 1/6] Allow disabling IPv6 servers using WIREGUARD_USE_IPV6_SERVER --- .../settings/wireguardselection.go | 77 ++++--------------- 1 file changed, 16 insertions(+), 61 deletions(-) diff --git a/internal/configuration/settings/wireguardselection.go b/internal/configuration/settings/wireguardselection.go index 2f4bf115b..9133ad2f9 100644 --- a/internal/configuration/settings/wireguardselection.go +++ b/internal/configuration/settings/wireguardselection.go @@ -13,29 +13,18 @@ import ( ) type WireguardSelection struct { - // EndpointIP is the server endpoint IP address. - // It is only used with VPN providers generating Wireguard - // configurations specific to each server and user. - // To indicate it should not be used, it should be set - // to netip.IPv4Unspecified(). It can never be the zero value - // in the internal state. - EndpointIP netip.Addr `json:"endpoint_ip"` - // EndpointPort is a the server port to use for the VPN server. - // It is optional for VPN providers IVPN, Mullvad, Surfshark - // and Windscribe, and compulsory for the others. - // When optional, it can be set to 0 to indicate not use - // a custom endpoint port. It cannot be nil in the internal - // state. - EndpointPort *uint16 `json:"endpoint_port"` - // PublicKey is the server public key. - // It is only used with VPN providers generating Wireguard - // configurations specific to each server and user. - PublicKey string `json:"public_key"` + EndpointIP netip.Addr `json:"endpoint_ip"` + EndpointPort *uint16 `json:"endpoint_port"` + PublicKey string `json:"public_key"` + UseIPv6 bool `json:"use_ipv6"` } -// Validate validates WireguardSelection settings. -// It should only be ran if the VPN type chosen is Wireguard. func (w WireguardSelection) validate(vpnProvider string) (err error) { + // Validate IPv6 usage setting + if !w.UseIPv6 && w.EndpointIP.Is6() { + return fmt.Errorf("%w: IPv6 address is disabled by configuration", ErrWireguardEndpointIPNotSet) + } + // Validate EndpointIP switch vpnProvider { case providers.Airvpn, providers.Fastestvpn, providers.Ivpn, @@ -111,47 +100,6 @@ func (w WireguardSelection) validate(vpnProvider string) (err error) { return nil } -func (w *WireguardSelection) copy() (copied WireguardSelection) { - return WireguardSelection{ - EndpointIP: w.EndpointIP, - EndpointPort: gosettings.CopyPointer(w.EndpointPort), - PublicKey: w.PublicKey, - } -} - -func (w *WireguardSelection) overrideWith(other WireguardSelection) { - w.EndpointIP = gosettings.OverrideWithValidator(w.EndpointIP, other.EndpointIP) - w.EndpointPort = gosettings.OverrideWithPointer(w.EndpointPort, other.EndpointPort) - w.PublicKey = gosettings.OverrideWithComparable(w.PublicKey, other.PublicKey) -} - -func (w *WireguardSelection) setDefaults() { - w.EndpointIP = gosettings.DefaultValidator(w.EndpointIP, netip.IPv4Unspecified()) - w.EndpointPort = gosettings.DefaultPointer(w.EndpointPort, 0) -} - -func (w WireguardSelection) String() string { - return w.toLinesNode().String() -} - -func (w WireguardSelection) toLinesNode() (node *gotree.Node) { - node = gotree.New("Wireguard selection settings:") - - if !w.EndpointIP.IsUnspecified() { - node.Appendf("Endpoint IP address: %s", w.EndpointIP) - } - - if *w.EndpointPort != 0 { - node.Appendf("Endpoint port: %d", *w.EndpointPort) - } - - if w.PublicKey != "" { - node.Appendf("Server public key: %s", w.PublicKey) - } - - return node -} - func (w *WireguardSelection) read(r *reader.Reader) (err error) { w.EndpointIP, err = r.NetipAddr("WIREGUARD_ENDPOINT_IP", reader.RetroKeys("VPN_ENDPOINT_IP")) if err != nil { @@ -164,5 +112,12 @@ func (w *WireguardSelection) read(r *reader.Reader) (err error) { } w.PublicKey = r.String("WIREGUARD_PUBLIC_KEY", reader.ForceLowercase(false)) + + // Read the IPv6 usage setting + w.UseIPv6, err = r.Bool("WIREGUARD_USE_IPV6_SERVER", reader.RetroKeys("VPN_USE_IPV6_SERVER")) + if err != nil { + return err + } + return nil } From 7b49e5a2f47db3e6b4382620ca137db37263021c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Pratt?= Date: Wed, 30 Oct 2024 23:49:33 -0400 Subject: [PATCH 2/6] Revert "Allow disabling IPv6 servers using WIREGUARD_USE_IPV6_SERVER" This reverts commit f3f8c10b5595993e4fac4128713de10e5b47680c. --- .../settings/wireguardselection.go | 77 +++++++++++++++---- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/internal/configuration/settings/wireguardselection.go b/internal/configuration/settings/wireguardselection.go index 9133ad2f9..2f4bf115b 100644 --- a/internal/configuration/settings/wireguardselection.go +++ b/internal/configuration/settings/wireguardselection.go @@ -13,18 +13,29 @@ import ( ) type WireguardSelection struct { - EndpointIP netip.Addr `json:"endpoint_ip"` - EndpointPort *uint16 `json:"endpoint_port"` - PublicKey string `json:"public_key"` - UseIPv6 bool `json:"use_ipv6"` + // EndpointIP is the server endpoint IP address. + // It is only used with VPN providers generating Wireguard + // configurations specific to each server and user. + // To indicate it should not be used, it should be set + // to netip.IPv4Unspecified(). It can never be the zero value + // in the internal state. + EndpointIP netip.Addr `json:"endpoint_ip"` + // EndpointPort is a the server port to use for the VPN server. + // It is optional for VPN providers IVPN, Mullvad, Surfshark + // and Windscribe, and compulsory for the others. + // When optional, it can be set to 0 to indicate not use + // a custom endpoint port. It cannot be nil in the internal + // state. + EndpointPort *uint16 `json:"endpoint_port"` + // PublicKey is the server public key. + // It is only used with VPN providers generating Wireguard + // configurations specific to each server and user. + PublicKey string `json:"public_key"` } +// Validate validates WireguardSelection settings. +// It should only be ran if the VPN type chosen is Wireguard. func (w WireguardSelection) validate(vpnProvider string) (err error) { - // Validate IPv6 usage setting - if !w.UseIPv6 && w.EndpointIP.Is6() { - return fmt.Errorf("%w: IPv6 address is disabled by configuration", ErrWireguardEndpointIPNotSet) - } - // Validate EndpointIP switch vpnProvider { case providers.Airvpn, providers.Fastestvpn, providers.Ivpn, @@ -100,6 +111,47 @@ func (w WireguardSelection) validate(vpnProvider string) (err error) { return nil } +func (w *WireguardSelection) copy() (copied WireguardSelection) { + return WireguardSelection{ + EndpointIP: w.EndpointIP, + EndpointPort: gosettings.CopyPointer(w.EndpointPort), + PublicKey: w.PublicKey, + } +} + +func (w *WireguardSelection) overrideWith(other WireguardSelection) { + w.EndpointIP = gosettings.OverrideWithValidator(w.EndpointIP, other.EndpointIP) + w.EndpointPort = gosettings.OverrideWithPointer(w.EndpointPort, other.EndpointPort) + w.PublicKey = gosettings.OverrideWithComparable(w.PublicKey, other.PublicKey) +} + +func (w *WireguardSelection) setDefaults() { + w.EndpointIP = gosettings.DefaultValidator(w.EndpointIP, netip.IPv4Unspecified()) + w.EndpointPort = gosettings.DefaultPointer(w.EndpointPort, 0) +} + +func (w WireguardSelection) String() string { + return w.toLinesNode().String() +} + +func (w WireguardSelection) toLinesNode() (node *gotree.Node) { + node = gotree.New("Wireguard selection settings:") + + if !w.EndpointIP.IsUnspecified() { + node.Appendf("Endpoint IP address: %s", w.EndpointIP) + } + + if *w.EndpointPort != 0 { + node.Appendf("Endpoint port: %d", *w.EndpointPort) + } + + if w.PublicKey != "" { + node.Appendf("Server public key: %s", w.PublicKey) + } + + return node +} + func (w *WireguardSelection) read(r *reader.Reader) (err error) { w.EndpointIP, err = r.NetipAddr("WIREGUARD_ENDPOINT_IP", reader.RetroKeys("VPN_ENDPOINT_IP")) if err != nil { @@ -112,12 +164,5 @@ func (w *WireguardSelection) read(r *reader.Reader) (err error) { } w.PublicKey = r.String("WIREGUARD_PUBLIC_KEY", reader.ForceLowercase(false)) - - // Read the IPv6 usage setting - w.UseIPv6, err = r.Bool("WIREGUARD_USE_IPV6_SERVER", reader.RetroKeys("VPN_USE_IPV6_SERVER")) - if err != nil { - return err - } - return nil } From 81fbeb9f2fd677506af2aad6489febf6aec1d6f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Pratt?= Date: Thu, 31 Oct 2024 00:12:25 -0400 Subject: [PATCH 3/6] Skip IPv6 Servers if VPN_IPV6_SERVER is set to off --- internal/provider/utils/connection.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/internal/provider/utils/connection.go b/internal/provider/utils/connection.go index 7e10d7397..f6dce9701 100644 --- a/internal/provider/utils/connection.go +++ b/internal/provider/utils/connection.go @@ -7,6 +7,7 @@ import ( "github.com/qdm12/gluetun/internal/configuration/settings" "github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/models" + "github.com/qdm12/gosettings/reader" ) type ConnectionDefaults struct { @@ -38,6 +39,14 @@ func GetConnection(provider string, randSource rand.Source) ( connection models.Connection, err error, ) { + // Use reader.BoolPtr to check the VPN_IPV6_SERVER environment variable + vpnIPv6ServerPtr := reader.BoolPtr("VPN_IPV6_SERVER") + useIPv6 := ipv6Supported // Default to system IPv6 support + + if vpnIPv6ServerPtr != nil && !*vpnIPv6ServerPtr { + useIPv6 = false // Disable IPv6 if the environment variable is set to "off" + } + servers, err := storage.FilterServers(provider, selection) if err != nil { return connection, fmt.Errorf("filtering servers: %w", err) @@ -50,7 +59,8 @@ func GetConnection(provider string, connections := make([]models.Connection, 0, len(servers)) for _, server := range servers { for _, ip := range server.IPs { - if !ipv6Supported && ip.Is6() { + // Skip IPv6 addresses if IPv6 is unsupported or explicitly disabled + if !useIPv6 && ip.Is6() { continue } From 4ff8195ee90241174b18596e18bd1d6d80b9c8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Pratt?= Date: Thu, 31 Oct 2024 00:40:19 -0400 Subject: [PATCH 4/6] Try and fix reader --- internal/provider/utils/connection.go | 29 +++++++++++++++++---------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/internal/provider/utils/connection.go b/internal/provider/utils/connection.go index f6dce9701..c9c049192 100644 --- a/internal/provider/utils/connection.go +++ b/internal/provider/utils/connection.go @@ -31,20 +31,29 @@ type Storage interface { servers []models.Server, err error) } +type VPNSettings struct { + IPv6Server *bool +} + +// Read method to populate the VPNSettings from the reader +func (v *VPNSettings) read(reader *reader.Reader) (err error) { + v.IPv6Server, err = reader.BoolPtr("VPN_IPV6_SERVER") + return err +} + func GetConnection(provider string, storage Storage, selection settings.ServerSelection, defaults ConnectionDefaults, ipv6Supported bool, - randSource rand.Source) ( + randSource rand.Source, + reader *reader.Reader) ( connection models.Connection, err error, ) { - // Use reader.BoolPtr to check the VPN_IPV6_SERVER environment variable - vpnIPv6ServerPtr := reader.BoolPtr("VPN_IPV6_SERVER") - useIPv6 := ipv6Supported // Default to system IPv6 support - - if vpnIPv6ServerPtr != nil && !*vpnIPv6ServerPtr { - useIPv6 = false // Disable IPv6 if the environment variable is set to "off" + // Create an instance of VPNSettings and read settings + var vpnSettings VPNSettings + if err := vpnSettings.read(reader); err != nil { + return connection, fmt.Errorf("reading VPN settings: %w", err) } servers, err := storage.FilterServers(provider, selection) @@ -59,15 +68,13 @@ func GetConnection(provider string, connections := make([]models.Connection, 0, len(servers)) for _, server := range servers { for _, ip := range server.IPs { - // Skip IPv6 addresses if IPv6 is unsupported or explicitly disabled - if !useIPv6 && ip.Is6() { + // Skip IPv6 if unsupported or if VPN_IPV6_SERVER is false + if !ipv6Supported || (vpnSettings.IPv6Server != nil && !*vpnSettings.IPv6Server && ip.Is6()) { continue } hostname := server.Hostname if selection.VPN == vpn.OpenVPN && server.OvpnX509 != "" { - // For Windscribe where hostname and - // OpenVPN x509 are not the same. hostname = server.OvpnX509 } From 2eab51c460756fc996699955091a9ae3c735333e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Pratt?= Date: Thu, 31 Oct 2024 00:45:35 -0400 Subject: [PATCH 5/6] Use normal env variable reading as I couldn't figure reader out --- internal/provider/utils/connection.go | 31 ++++++++++----------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/internal/provider/utils/connection.go b/internal/provider/utils/connection.go index c9c049192..5e0c0f637 100644 --- a/internal/provider/utils/connection.go +++ b/internal/provider/utils/connection.go @@ -3,11 +3,12 @@ package utils import ( "fmt" "math/rand" + "os" + "strings" "github.com/qdm12/gluetun/internal/configuration/settings" "github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/models" - "github.com/qdm12/gosettings/reader" ) type ConnectionDefaults struct { @@ -31,30 +32,17 @@ type Storage interface { servers []models.Server, err error) } -type VPNSettings struct { - IPv6Server *bool -} - -// Read method to populate the VPNSettings from the reader -func (v *VPNSettings) read(reader *reader.Reader) (err error) { - v.IPv6Server, err = reader.BoolPtr("VPN_IPV6_SERVER") - return err -} - func GetConnection(provider string, storage Storage, selection settings.ServerSelection, defaults ConnectionDefaults, ipv6Supported bool, - randSource rand.Source, - reader *reader.Reader) ( + randSource rand.Source) ( connection models.Connection, err error, ) { - // Create an instance of VPNSettings and read settings - var vpnSettings VPNSettings - if err := vpnSettings.read(reader); err != nil { - return connection, fmt.Errorf("reading VPN settings: %w", err) - } + // Read the VPN_IPV6_SERVER environment variable + vpnIPv6Server := os.Getenv("VPN_IPV6_SERVER") + skipIPv6Servers := strings.EqualFold(vpnIPv6Server, "off") servers, err := storage.FilterServers(provider, selection) if err != nil { @@ -68,8 +56,11 @@ func GetConnection(provider string, connections := make([]models.Connection, 0, len(servers)) for _, server := range servers { for _, ip := range server.IPs { - // Skip IPv6 if unsupported or if VPN_IPV6_SERVER is false - if !ipv6Supported || (vpnSettings.IPv6Server != nil && !*vpnSettings.IPv6Server && ip.Is6()) { + if skipIPv6Servers && ip.Is6() { + continue + } + + if !ipv6Supported && ip.Is6() { continue } From a3463210886f6d97a5902613a4f29918a05e105f Mon Sep 17 00:00:00 2001 From: diamkil <35732047+diamkil@users.noreply.github.com> Date: Mon, 4 Nov 2024 23:44:54 -0500 Subject: [PATCH 6/6] Revert deleted comment --- internal/provider/utils/connection.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/provider/utils/connection.go b/internal/provider/utils/connection.go index 5e0c0f637..39cba66ca 100644 --- a/internal/provider/utils/connection.go +++ b/internal/provider/utils/connection.go @@ -66,6 +66,8 @@ func GetConnection(provider string, hostname := server.Hostname if selection.VPN == vpn.OpenVPN && server.OvpnX509 != "" { + // For Windscribe where hostname and + // OpenVPN x509 are not the same. hostname = server.OvpnX509 }