diff --git a/internal/configuration/settings/openvpnselection.go b/internal/configuration/settings/openvpnselection.go index 67f8a140..2935bc40 100644 --- a/internal/configuration/settings/openvpnselection.go +++ b/internal/configuration/settings/openvpnselection.go @@ -77,6 +77,12 @@ func (o OpenVPNSelection) validate(vpnProvider string) (err error) { case providers.Perfectprivacy: allowedTCP = []uint16{44, 443, 4433} allowedUDP = []uint16{44, 443, 4433} + case providers.PrivateInternetAccess: + allowedTCP = []uint16{80, 110, 443} + allowedUDP = []uint16{53, 1194, 1197, 1198, 8080, 9201} + case providers.Protonvpn: + allowedTCP = []uint16{443, 5995, 8443} + allowedUDP = []uint16{80, 443, 1194, 4569, 5060} case providers.Wevpn: allowedTCP = []uint16{53, 1195, 1199, 2018} allowedUDP = []uint16{80, 1194, 1198} diff --git a/internal/provider/custom/connection.go b/internal/provider/custom/connection.go index 4e85ee3c..2e2d0dbe 100644 --- a/internal/provider/custom/connection.go +++ b/internal/provider/custom/connection.go @@ -9,7 +9,6 @@ import ( "github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/openvpn/extract" - "github.com/qdm12/gluetun/internal/provider/utils" ) var ( @@ -37,23 +36,21 @@ func getOpenVPNConnection(extractor extract.Interface, return connection, fmt.Errorf("cannot extract connection: %w", err) } - connection.Port = getPort(connection.Port, selection) + customPort := *selection.OpenVPN.CustomPort + if customPort > 0 { + connection.Port = customPort + } + return connection, nil } func getWireguardConnection(selection settings.ServerSelection) ( connection models.Connection) { - port := getPort(*selection.Wireguard.EndpointPort, selection) return models.Connection{ Type: vpn.Wireguard, IP: selection.Wireguard.EndpointIP, - Port: port, + Port: *selection.Wireguard.EndpointPort, Protocol: constants.UDP, PubKey: selection.Wireguard.PublicKey, } } - -// Port found is overridden by custom port set with `VPN_ENDPOINT_PORT`. -func getPort(foundPort uint16, selection settings.ServerSelection) (port uint16) { - return utils.GetPort(selection, foundPort, foundPort, foundPort) -} diff --git a/internal/provider/cyberghost/connection.go b/internal/provider/cyberghost/connection.go index 961610c6..28ee55d0 100644 --- a/internal/provider/cyberghost/connection.go +++ b/internal/provider/cyberghost/connection.go @@ -2,36 +2,12 @@ package cyberghost import ( "github.com/qdm12/gluetun/internal/configuration/settings" - "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/provider/utils" ) func (c *Cyberghost) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - const port = 443 - protocol := constants.UDP - if *selection.OpenVPN.TCP { - protocol = constants.TCP - } - - servers, err := utils.FilterServers(c.servers, selection) - if err != nil { - return connection, err - } - - var connections []models.Connection - for _, server := range servers { - for _, IP := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: IP, - Port: port, - Protocol: protocol, - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, c.randSource) + defaults := utils.NewConnectionDefaults(443, 443, 0) //nolint:gomnd + return utils.GetConnection(c.servers, selection, defaults, c.randSource) } diff --git a/internal/provider/expressvpn/connection.go b/internal/provider/expressvpn/connection.go index 56b85604..8c02d68e 100644 --- a/internal/provider/expressvpn/connection.go +++ b/internal/provider/expressvpn/connection.go @@ -8,37 +8,6 @@ import ( func (p *Provider) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - port := getPort(selection) - protocol := utils.GetProtocol(selection) - - servers, err := utils.FilterServers(p.servers, selection) - if err != nil { - return connection, err - } - - var connections []models.Connection - for _, server := range servers { - for _, IP := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: IP, - Port: port, - Protocol: protocol, - Hostname: server.Hostname, - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, p.randSource) -} - -func getPort(selection settings.ServerSelection) (port uint16) { - const ( - defaultOpenVPNTCP = 0 - defaultOpenVPNUDP = 1195 - defaultWireguard = 0 - ) - return utils.GetPort(selection, defaultOpenVPNTCP, - defaultOpenVPNUDP, defaultWireguard) + defaults := utils.NewConnectionDefaults(0, 1195, 0) //nolint:gomnd + return utils.GetConnection(p.servers, selection, defaults, p.randSource) } diff --git a/internal/provider/expressvpn/connection_test.go b/internal/provider/expressvpn/connection_test.go index 78a68bda..ecd3b884 100644 --- a/internal/provider/expressvpn/connection_test.go +++ b/internal/provider/expressvpn/connection_test.go @@ -27,7 +27,7 @@ func Test_Provider_GetConnection(t *testing.T) { "no server available": { selection: settings.ServerSelection{}.WithDefaults(providers.Expressvpn), errWrapped: utils.ErrNoServerFound, - errMessage: "no server found: for VPN openvpn; protocol udp", + errMessage: "cannot filter servers: no server found: for VPN openvpn; protocol udp", }, "no filter": { servers: []models.Server{ diff --git a/internal/provider/fastestvpn/connection.go b/internal/provider/fastestvpn/connection.go index 92379be9..67d0d829 100644 --- a/internal/provider/fastestvpn/connection.go +++ b/internal/provider/fastestvpn/connection.go @@ -2,36 +2,12 @@ package fastestvpn import ( "github.com/qdm12/gluetun/internal/configuration/settings" - "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/provider/utils" ) func (f *Fastestvpn) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - const port = 4443 - protocol := constants.UDP - if *selection.OpenVPN.TCP { - protocol = constants.TCP - } - - servers, err := utils.FilterServers(f.servers, selection) - if err != nil { - return connection, err - } - - var connections []models.Connection - for _, server := range servers { - for _, IP := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: IP, - Port: port, - Protocol: protocol, - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, f.randSource) + defaults := utils.NewConnectionDefaults(4443, 4443, 0) //nolint:gomnd + return utils.GetConnection(f.servers, selection, defaults, f.randSource) } diff --git a/internal/provider/hidemyass/connection.go b/internal/provider/hidemyass/connection.go index 4c9c2004..261eaf95 100644 --- a/internal/provider/hidemyass/connection.go +++ b/internal/provider/hidemyass/connection.go @@ -2,41 +2,12 @@ package hidemyass import ( "github.com/qdm12/gluetun/internal/configuration/settings" - "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/provider/utils" ) func (h *HideMyAss) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - var port uint16 = 553 - protocol := constants.UDP - if *selection.OpenVPN.TCP { - protocol = constants.TCP - port = 8080 - } - - if *selection.OpenVPN.CustomPort > 0 { - port = *selection.OpenVPN.CustomPort - } - - servers, err := utils.FilterServers(h.servers, selection) - if err != nil { - return connection, err - } - - var connections []models.Connection - for _, server := range servers { - for _, IP := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: IP, - Port: port, - Protocol: protocol, - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, h.randSource) + defaults := utils.NewConnectionDefaults(8080, 553, 0) //nolint:gomnd + return utils.GetConnection(h.servers, selection, defaults, h.randSource) } diff --git a/internal/provider/ipvanish/connection.go b/internal/provider/ipvanish/connection.go index 871be42c..e680e1c3 100644 --- a/internal/provider/ipvanish/connection.go +++ b/internal/provider/ipvanish/connection.go @@ -2,34 +2,12 @@ package ipvanish import ( "github.com/qdm12/gluetun/internal/configuration/settings" - "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/provider/utils" ) func (i *Ipvanish) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - const port = 443 - const protocol = constants.UDP - - servers, err := utils.FilterServers(i.servers, selection) - if err != nil { - return connection, err - } - - var connections []models.Connection - for _, server := range servers { - for _, IP := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: IP, - Port: port, - Protocol: protocol, - Hostname: server.Hostname, - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, i.randSource) + defaults := utils.NewConnectionDefaults(0, 443, 0) //nolint:gomnd + return utils.GetConnection(i.servers, selection, defaults, i.randSource) } diff --git a/internal/provider/ivpn/connection.go b/internal/provider/ivpn/connection.go index cee40761..9063f7c8 100644 --- a/internal/provider/ivpn/connection.go +++ b/internal/provider/ivpn/connection.go @@ -8,38 +8,6 @@ import ( func (i *Ivpn) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - port := getPort(selection) - protocol := utils.GetProtocol(selection) - - servers, err := utils.FilterServers(i.servers, selection) - if err != nil { - return connection, err - } - - var connections []models.Connection - for _, server := range servers { - for _, IP := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: IP, - Port: port, - Protocol: protocol, - Hostname: server.Hostname, - PubKey: server.WgPubKey, // Wireguard only - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, i.randSource) -} - -func getPort(selection settings.ServerSelection) (port uint16) { - const ( - defaultOpenVPNTCP = 443 - defaultOpenVPNUDP = 1194 - defaultWireguard = 58237 - ) - return utils.GetPort(selection, defaultOpenVPNTCP, - defaultOpenVPNUDP, defaultWireguard) + defaults := utils.NewConnectionDefaults(443, 1194, 58237) //nolint:gomnd + return utils.GetConnection(i.servers, selection, defaults, i.randSource) } diff --git a/internal/provider/ivpn/connection_test.go b/internal/provider/ivpn/connection_test.go index 66974df0..451cda4b 100644 --- a/internal/provider/ivpn/connection_test.go +++ b/internal/provider/ivpn/connection_test.go @@ -27,7 +27,7 @@ func Test_Ivpn_GetConnection(t *testing.T) { "no server available": { selection: settings.ServerSelection{}.WithDefaults(providers.Ivpn), errWrapped: utils.ErrNoServerFound, - errMessage: "no server found: for VPN openvpn; protocol udp", + errMessage: "cannot filter servers: no server found: for VPN openvpn; protocol udp", }, "no filter": { servers: []models.Server{ diff --git a/internal/provider/mullvad/connection.go b/internal/provider/mullvad/connection.go index 17ff0d57..a21f189b 100644 --- a/internal/provider/mullvad/connection.go +++ b/internal/provider/mullvad/connection.go @@ -8,41 +8,6 @@ import ( func (m *Mullvad) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - port := getPort(selection) - protocol := utils.GetProtocol(selection) - - servers, err := utils.FilterServers(m.servers, selection) - if err != nil { - return connection, err - } - - connections := make([]models.Connection, 0, len(servers)) - for _, server := range servers { - for _, IP := range server.IPs { - if IP.To4() == nil { - // do not use IPv6 connections for now - continue - } - connection := models.Connection{ - Type: selection.VPN, - IP: IP, - Port: port, - Protocol: protocol, - PubKey: server.WgPubKey, // Wireguard only - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, m.randSource) -} - -func getPort(selection settings.ServerSelection) (port uint16) { - const ( - defaultOpenVPNTCP = 443 - defaultOpenVPNUDP = 1194 - defaultWireguard = 51820 - ) - return utils.GetPort(selection, defaultOpenVPNTCP, - defaultOpenVPNUDP, defaultWireguard) + defaults := utils.NewConnectionDefaults(443, 1194, 51820) //nolint:gomnd + return utils.GetConnection(m.servers, selection, defaults, m.randSource) } diff --git a/internal/provider/mullvad/connection_test.go b/internal/provider/mullvad/connection_test.go index 44bd9e77..15c35650 100644 --- a/internal/provider/mullvad/connection_test.go +++ b/internal/provider/mullvad/connection_test.go @@ -27,7 +27,7 @@ func Test_Mullvad_GetConnection(t *testing.T) { "no server available": { selection: settings.ServerSelection{}.WithDefaults(providers.Mullvad), errWrapped: utils.ErrNoServerFound, - errMessage: "no server found: for VPN openvpn; protocol udp", + errMessage: "cannot filter servers: no server found: for VPN openvpn; protocol udp", }, "no filter": { servers: []models.Server{ @@ -72,6 +72,7 @@ func Test_Mullvad_GetConnection(t *testing.T) { Type: vpn.OpenVPN, IP: net.IPv4(2, 2, 2, 2), Port: 1194, + Hostname: "b", Protocol: constants.UDP, }, }, diff --git a/internal/provider/nordvpn/connection.go b/internal/provider/nordvpn/connection.go index fc21bf6b..cce5e8fa 100644 --- a/internal/provider/nordvpn/connection.go +++ b/internal/provider/nordvpn/connection.go @@ -2,37 +2,12 @@ package nordvpn import ( "github.com/qdm12/gluetun/internal/configuration/settings" - "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/provider/utils" ) func (n *Nordvpn) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - var port uint16 = 1194 - protocol := constants.UDP - if *selection.OpenVPN.TCP { - port = 443 - protocol = constants.TCP - } - - servers, err := utils.FilterServers(n.servers, selection) - if err != nil { - return connection, err - } - - connections := make([]models.Connection, 0, len(servers)) - for _, server := range servers { - for _, ip := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: ip, - Port: port, - Protocol: protocol, - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, n.randSource) + defaults := utils.NewConnectionDefaults(443, 1194, 0) //nolint:gomnd + return utils.GetConnection(n.servers, selection, defaults, n.randSource) } diff --git a/internal/provider/perfectprivacy/connection.go b/internal/provider/perfectprivacy/connection.go index da571d04..70f78b16 100644 --- a/internal/provider/perfectprivacy/connection.go +++ b/internal/provider/perfectprivacy/connection.go @@ -8,30 +8,6 @@ import ( func (p *Perfectprivacy) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - const defaultPort uint16 = 443 - port := defaultPort - if *selection.OpenVPN.CustomPort > 0 { - port = *selection.OpenVPN.CustomPort - } - protocol := utils.GetProtocol(selection) - - servers, err := utils.FilterServers(p.servers, selection) - if err != nil { - return connection, err - } - - var connections []models.Connection - for _, server := range servers { - for _, IP := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: IP, - Port: port, - Protocol: protocol, - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, p.randSource) + defaults := utils.NewConnectionDefaults(443, 443, 0) //nolint:gomnd + return utils.GetConnection(p.servers, selection, defaults, p.randSource) } diff --git a/internal/provider/privado/connection.go b/internal/provider/privado/connection.go index f84b4e70..3817f215 100644 --- a/internal/provider/privado/connection.go +++ b/internal/provider/privado/connection.go @@ -2,34 +2,12 @@ package privado import ( "github.com/qdm12/gluetun/internal/configuration/settings" - "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/provider/utils" ) func (p *Privado) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - const port = 1194 - const protocol = constants.UDP - - servers, err := utils.FilterServers(p.servers, selection) - if err != nil { - return connection, err - } - - connections := make([]models.Connection, 0, len(servers)) - for _, server := range servers { - for _, ip := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: ip, - Port: port, - Protocol: protocol, - Hostname: server.Hostname, - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, p.randSource) + defaults := utils.NewConnectionDefaults(0, 1194, 0) //nolint:gomnd + return utils.GetConnection(p.servers, selection, defaults, p.randSource) } diff --git a/internal/provider/privateinternetaccess/connection.go b/internal/provider/privateinternetaccess/connection.go index 567a8017..65dcf755 100644 --- a/internal/provider/privateinternetaccess/connection.go +++ b/internal/provider/privateinternetaccess/connection.go @@ -9,34 +9,16 @@ import ( func (p *PIA) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - protocol := constants.UDP - if *selection.OpenVPN.TCP { - protocol = constants.TCP + // Set port defaults depending on encryption preset. + var defaults utils.ConnectionDefaults + switch *selection.OpenVPN.PIAEncPreset { + case constants.PIAEncryptionPresetNone, constants.PIAEncryptionPresetNormal: + defaults.OpenVPNTCPPort = 502 + defaults.OpenVPNUDPPort = 1198 + case constants.PIAEncryptionPresetStrong: + defaults.OpenVPNTCPPort = 501 + defaults.OpenVPNUDPPort = 1197 } - port, err := getPort(selection.OpenVPN) - if err != nil { - return connection, err - } - - servers, err := utils.FilterServers(p.servers, selection) - if err != nil { - return connection, err - } - - var connections []models.Connection - for _, server := range servers { - for _, IP := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: IP, - Port: port, - Protocol: protocol, - Hostname: server.ServerName, // used for port forwarding TLS - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, p.randSource) + return utils.GetConnection(p.servers, selection, defaults, p.randSource) } diff --git a/internal/provider/privateinternetaccess/port.go b/internal/provider/privateinternetaccess/port.go deleted file mode 100644 index a81279a1..00000000 --- a/internal/provider/privateinternetaccess/port.go +++ /dev/null @@ -1,62 +0,0 @@ -package privateinternetaccess - -import ( - "errors" - "fmt" - - "github.com/qdm12/gluetun/internal/configuration/settings" - "github.com/qdm12/gluetun/internal/constants" -) - -func getPort(openvpnSelection settings.OpenVPNSelection) ( - port uint16, err error) { - customPort := *openvpnSelection.CustomPort - tcp := *openvpnSelection.TCP - if customPort == 0 { - return getDefaultPort(tcp, *openvpnSelection.PIAEncPreset), nil - } - - if err := checkPort(customPort, tcp); err != nil { - return 0, err - } - - return customPort, nil -} - -func getDefaultPort(tcp bool, encryptionPreset string) (port uint16) { - if tcp { - switch encryptionPreset { - case constants.PIAEncryptionPresetNone, constants.PIAEncryptionPresetNormal: - port = 502 - case constants.PIAEncryptionPresetStrong: - port = 501 - } - } else { - switch encryptionPreset { - case constants.PIAEncryptionPresetNone, constants.PIAEncryptionPresetNormal: - port = 1198 - case constants.PIAEncryptionPresetStrong: - port = 1197 - } - } - return port -} - -var ErrInvalidPort = errors.New("invalid port number") - -func checkPort(port uint16, tcp bool) (err error) { - if tcp { - switch port { - case 80, 110, 443: //nolint:gomnd - return nil - default: - return fmt.Errorf("%w: %d for protocol TCP", ErrInvalidPort, port) - } - } - switch port { - case 53, 1194, 1197, 1198, 8080, 9201: //nolint:gomnd - return nil - default: - return fmt.Errorf("%w: %d for protocol UDP", ErrInvalidPort, port) - } -} diff --git a/internal/provider/privatevpn/connection.go b/internal/provider/privatevpn/connection.go index d6efa89d..7a9d87a9 100644 --- a/internal/provider/privatevpn/connection.go +++ b/internal/provider/privatevpn/connection.go @@ -2,40 +2,12 @@ package privatevpn import ( "github.com/qdm12/gluetun/internal/configuration/settings" - "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/provider/utils" ) func (p *Privatevpn) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - protocol := constants.UDP - var port uint16 = 1194 - if *selection.OpenVPN.TCP { - protocol = constants.TCP - port = 443 - } - if *selection.OpenVPN.CustomPort > 0 { - port = *selection.OpenVPN.CustomPort - } - - servers, err := utils.FilterServers(p.servers, selection) - if err != nil { - return connection, err - } - - var connections []models.Connection - for _, server := range servers { - for _, ip := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: ip, - Port: port, - Protocol: protocol, - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, p.randSource) + defaults := utils.NewConnectionDefaults(443, 1194, 0) //nolint:gomnd + return utils.GetConnection(p.servers, selection, defaults, p.randSource) } diff --git a/internal/provider/protonvpn/connection.go b/internal/provider/protonvpn/connection.go index 727505e0..78d5a197 100644 --- a/internal/provider/protonvpn/connection.go +++ b/internal/provider/protonvpn/connection.go @@ -2,40 +2,12 @@ package protonvpn import ( "github.com/qdm12/gluetun/internal/configuration/settings" - "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/provider/utils" ) func (p *Protonvpn) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - protocol := constants.UDP - if *selection.OpenVPN.TCP { - protocol = constants.TCP - } - - port, err := getPort(*selection.OpenVPN.TCP, *selection.OpenVPN.CustomPort) - if err != nil { - return connection, err - } - - servers, err := utils.FilterServers(p.servers, selection) - if err != nil { - return connection, err - } - - connections := make([]models.Connection, 0, len(servers)) - for _, server := range servers { - for _, ip := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: ip, - Port: port, - Protocol: protocol, - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, p.randSource) + defaults := utils.NewConnectionDefaults(443, 1194, 0) //nolint:gomnd + return utils.GetConnection(p.servers, selection, defaults, p.randSource) } diff --git a/internal/provider/protonvpn/port.go b/internal/provider/protonvpn/port.go deleted file mode 100644 index b6903cdd..00000000 --- a/internal/provider/protonvpn/port.go +++ /dev/null @@ -1,41 +0,0 @@ -package protonvpn - -import ( - "errors" - "fmt" -) - -func getPort(tcp bool, customPort uint16) (port uint16, err error) { - if customPort == 0 { - const defaultTCPPort, defaultUDPPort = 443, 1194 - if tcp { - return defaultTCPPort, nil - } - return defaultUDPPort, nil - } - - if err := checkPort(customPort, tcp); err != nil { - return 0, err - } - - return customPort, nil -} - -var ErrInvalidPort = errors.New("invalid port number") - -func checkPort(port uint16, tcp bool) (err error) { - if tcp { - switch port { - case 443, 5995, 8443: //nolint:gomnd - return nil - default: - return fmt.Errorf("%w: %d for protocol TCP", ErrInvalidPort, port) - } - } - switch port { - case 80, 443, 1194, 4569, 5060: //nolint:gomnd - return nil - default: - return fmt.Errorf("%w: %d for protocol UDP", ErrInvalidPort, port) - } -} diff --git a/internal/provider/purevpn/connection.go b/internal/provider/purevpn/connection.go index e84e2c51..43681163 100644 --- a/internal/provider/purevpn/connection.go +++ b/internal/provider/purevpn/connection.go @@ -2,37 +2,12 @@ package purevpn import ( "github.com/qdm12/gluetun/internal/configuration/settings" - "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/provider/utils" ) func (p *Purevpn) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - protocol := constants.UDP - var port uint16 = 53 - if *selection.OpenVPN.TCP { - protocol = constants.TCP - port = 80 - } - - servers, err := utils.FilterServers(p.servers, selection) - if err != nil { - return connection, err - } - - var connections []models.Connection - for _, server := range servers { - for _, IP := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: IP, - Port: port, - Protocol: protocol, - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, p.randSource) + defaults := utils.NewConnectionDefaults(80, 53, 0) //nolint:gomnd + return utils.GetConnection(p.servers, selection, defaults, p.randSource) } diff --git a/internal/provider/surfshark/connection.go b/internal/provider/surfshark/connection.go index f1ea078f..56f747f7 100644 --- a/internal/provider/surfshark/connection.go +++ b/internal/provider/surfshark/connection.go @@ -2,37 +2,12 @@ package surfshark import ( "github.com/qdm12/gluetun/internal/configuration/settings" - "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/provider/utils" ) func (s *Surfshark) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - protocol := constants.UDP - var port uint16 = 1194 - if *selection.OpenVPN.TCP { - protocol = constants.TCP - port = 1443 - } - - servers, err := utils.FilterServers(s.servers, selection) - if err != nil { - return connection, err - } - - var connections []models.Connection - for _, server := range servers { - for _, IP := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: IP, - Port: port, - Protocol: protocol, - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, s.randSource) + defaults := utils.NewConnectionDefaults(1443, 1194, 0) //nolint:gomnd + return utils.GetConnection(s.servers, selection, defaults, s.randSource) } diff --git a/internal/provider/torguard/connection.go b/internal/provider/torguard/connection.go index 3202b408..9dd8474d 100644 --- a/internal/provider/torguard/connection.go +++ b/internal/provider/torguard/connection.go @@ -2,40 +2,12 @@ package torguard import ( "github.com/qdm12/gluetun/internal/configuration/settings" - "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/provider/utils" ) -func (t *Torguard) GetConnection(selection settings.ServerSelection) ( +func (p *Torguard) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - protocol := constants.UDP - if *selection.OpenVPN.TCP { - protocol = constants.TCP - } - - var port uint16 = 1912 - if *selection.OpenVPN.CustomPort > 0 { - port = *selection.OpenVPN.CustomPort - } - - servers, err := utils.FilterServers(t.servers, selection) - if err != nil { - return connection, err - } - - var connections []models.Connection - for _, server := range servers { - for _, IP := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: IP, - Port: port, - Protocol: protocol, - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, t.randSource) + defaults := utils.NewConnectionDefaults(1912, 1912, 0) //nolint:gomnd + return utils.GetConnection(p.servers, selection, defaults, p.randSource) } diff --git a/internal/provider/utils/connection.go b/internal/provider/utils/connection.go new file mode 100644 index 00000000..b01860b4 --- /dev/null +++ b/internal/provider/utils/connection.go @@ -0,0 +1,60 @@ +package utils + +import ( + "fmt" + "math/rand" + + "github.com/qdm12/gluetun/internal/configuration/settings" + "github.com/qdm12/gluetun/internal/models" +) + +type ConnectionDefaults struct { + OpenVPNTCPPort uint16 + OpenVPNUDPPort uint16 + WireguardPort uint16 +} + +func NewConnectionDefaults(openvpnTCPPort, openvpnUDPPort, + wireguardPort uint16) ConnectionDefaults { + return ConnectionDefaults{ + OpenVPNTCPPort: openvpnTCPPort, + OpenVPNUDPPort: openvpnUDPPort, + WireguardPort: wireguardPort, + } +} + +func GetConnection(servers []models.Server, + selection settings.ServerSelection, + defaults ConnectionDefaults, + randSource rand.Source) ( + connection models.Connection, err error) { + servers, err = FilterServers(servers, selection) + if err != nil { + return connection, fmt.Errorf("cannot filter servers: %w", err) + } + + protocol := getProtocol(selection) + port := GetPort(selection, defaults.OpenVPNTCPPort, + defaults.OpenVPNUDPPort, defaults.WireguardPort) + + connections := make([]models.Connection, 0, len(servers)) + for _, server := range servers { + for _, ip := range server.IPs { + if ip.To4() == nil { + // do not use IPv6 connections for now + continue + } + connection := models.Connection{ + Type: selection.VPN, + IP: ip, + Port: port, + Protocol: protocol, + Hostname: server.Hostname, + PubKey: server.WgPubKey, // Wireguard + } + connections = append(connections, connection) + } + } + + return PickConnection(connections, selection, randSource) +} diff --git a/internal/provider/utils/connection_test.go b/internal/provider/utils/connection_test.go new file mode 100644 index 00000000..4e08758c --- /dev/null +++ b/internal/provider/utils/connection_test.go @@ -0,0 +1,9 @@ +package utils + +import "testing" + +func Test_GetConnection(t *testing.T) { + t.Parallel() + + // testCases := map[string]struct{}{} +} diff --git a/internal/provider/utils/filtering.go b/internal/provider/utils/filtering.go index a992c60a..2d455d9a 100644 --- a/internal/provider/utils/filtering.go +++ b/internal/provider/utils/filtering.go @@ -34,7 +34,7 @@ func filterServer(server models.Server, return true } - if FilterByProtocol(selection, server.TCP, server.UDP) { + if filterByProtocol(selection, server.TCP, server.UDP) { return true } diff --git a/internal/provider/utils/port.go b/internal/provider/utils/port.go index 588d3b58..8cfff4e4 100644 --- a/internal/provider/utils/port.go +++ b/internal/provider/utils/port.go @@ -1,7 +1,11 @@ package utils import ( + "errors" + "fmt" + "github.com/qdm12/gluetun/internal/configuration/settings" + "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants/vpn" ) @@ -13,6 +17,7 @@ func GetPort(selection settings.ServerSelection, if customPort > 0 { return customPort } + checkDefined("Wireguard", defaultWireguard) return defaultWireguard default: // OpenVPN customPort := *selection.OpenVPN.CustomPort @@ -20,8 +25,40 @@ func GetPort(selection settings.ServerSelection, return customPort } if *selection.OpenVPN.TCP { + checkDefined("OpenVPN TCP", defaultOpenVPNTCP) return defaultOpenVPNTCP } + + checkDefined("OpenVPN UDP", defaultOpenVPNUDP) return defaultOpenVPNUDP } } + +func checkDefined(portName string, port uint16) { + if port > 0 { + return + } + message := fmt.Sprintf("no default %s port is defined!", portName) + panic(message) +} + +var ErrInvalidPort = errors.New("invalid port number") + +// CheckPortAllowed for custom port used for OpenVPN. +func CheckPortAllowed(port uint16, tcp bool, + allowedTCP, allowedUDP []uint16) (err error) { + allowedPorts := allowedUDP + protocol := constants.UDP + if tcp { + allowedPorts = allowedTCP + protocol = constants.TCP + } + for _, allowedPort := range allowedPorts { + if port == allowedPort { + return nil + } + } + + return fmt.Errorf("%w: %d for protocol %s", + ErrInvalidPort, port, protocol) +} diff --git a/internal/provider/utils/port_test.go b/internal/provider/utils/port_test.go index 47c2f7a6..6b608757 100644 --- a/internal/provider/utils/port_test.go +++ b/internal/provider/utils/port_test.go @@ -21,12 +21,19 @@ func Test_GetPort(t *testing.T) { ) testCases := map[string]struct { - selection settings.ServerSelection - port uint16 + selection settings.ServerSelection + defaultOpenVPNTCP uint16 + defaultOpenVPNUDP uint16 + defaultWireguard uint16 + port uint16 + panics string }{ "default": { - selection: settings.ServerSelection{}.WithDefaults(""), - port: defaultOpenVPNUDP, + selection: settings.ServerSelection{}.WithDefaults(""), + defaultOpenVPNTCP: defaultOpenVPNTCP, + defaultOpenVPNUDP: defaultOpenVPNUDP, + defaultWireguard: defaultWireguard, + port: defaultOpenVPNUDP, }, "OpenVPN UDP": { selection: settings.ServerSelection{ @@ -36,7 +43,20 @@ func Test_GetPort(t *testing.T) { TCP: boolPtr(false), }, }, - port: defaultOpenVPNUDP, + defaultOpenVPNTCP: defaultOpenVPNTCP, + defaultOpenVPNUDP: defaultOpenVPNUDP, + defaultWireguard: defaultWireguard, + port: defaultOpenVPNUDP, + }, + "OpenVPN UDP no default port defined": { + selection: settings.ServerSelection{ + VPN: vpn.OpenVPN, + OpenVPN: settings.OpenVPNSelection{ + CustomPort: uint16Ptr(0), + TCP: boolPtr(false), + }, + }, + panics: "no default OpenVPN UDP port is defined!", }, "OpenVPN TCP": { selection: settings.ServerSelection{ @@ -46,7 +66,18 @@ func Test_GetPort(t *testing.T) { TCP: boolPtr(true), }, }, - port: defaultOpenVPNTCP, + defaultOpenVPNTCP: defaultOpenVPNTCP, + port: defaultOpenVPNTCP, + }, + "OpenVPN TCP no default port defined": { + selection: settings.ServerSelection{ + VPN: vpn.OpenVPN, + OpenVPN: settings.OpenVPNSelection{ + CustomPort: uint16Ptr(0), + TCP: boolPtr(true), + }, + }, + panics: "no default OpenVPN TCP port is defined!", }, "OpenVPN custom port": { selection: settings.ServerSelection{ @@ -61,7 +92,8 @@ func Test_GetPort(t *testing.T) { selection: settings.ServerSelection{ VPN: vpn.Wireguard, }.WithDefaults(""), - port: defaultWireguard, + defaultWireguard: defaultWireguard, + port: defaultWireguard, }, "Wireguard custom port": { selection: settings.ServerSelection{ @@ -70,7 +102,14 @@ func Test_GetPort(t *testing.T) { EndpointPort: uint16Ptr(1234), }, }, - port: 1234, + defaultWireguard: defaultWireguard, + port: 1234, + }, + "Wireguard no default port defined": { + selection: settings.ServerSelection{ + VPN: vpn.Wireguard, + }.WithDefaults(""), + panics: "no default Wireguard port is defined!", }, } @@ -79,8 +118,20 @@ func Test_GetPort(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() + if testCase.panics != "" { + assert.PanicsWithValue(t, testCase.panics, func() { + _ = GetPort(testCase.selection, + testCase.defaultOpenVPNTCP, + testCase.defaultOpenVPNUDP, + testCase.defaultWireguard) + }) + return + } + port := GetPort(testCase.selection, - defaultOpenVPNTCP, defaultOpenVPNUDP, defaultWireguard) + testCase.defaultOpenVPNTCP, + testCase.defaultOpenVPNUDP, + testCase.defaultWireguard) assert.Equal(t, testCase.port, port) }) diff --git a/internal/provider/utils/protocol.go b/internal/provider/utils/protocol.go index 56071e52..982aa3c2 100644 --- a/internal/provider/utils/protocol.go +++ b/internal/provider/utils/protocol.go @@ -6,14 +6,14 @@ import ( "github.com/qdm12/gluetun/internal/constants/vpn" ) -func GetProtocol(selection settings.ServerSelection) (protocol string) { +func getProtocol(selection settings.ServerSelection) (protocol string) { if selection.VPN == vpn.OpenVPN && *selection.OpenVPN.TCP { return constants.TCP } return constants.UDP } -func FilterByProtocol(selection settings.ServerSelection, +func filterByProtocol(selection settings.ServerSelection, serverTCP, serverUDP bool) (filtered bool) { switch selection.VPN { case vpn.Wireguard: diff --git a/internal/provider/utils/protocol_test.go b/internal/provider/utils/protocol_test.go index b8a40870..103a887f 100644 --- a/internal/provider/utils/protocol_test.go +++ b/internal/provider/utils/protocol_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" ) -func Test_GetProtocol(t *testing.T) { +func Test_getProtocol(t *testing.T) { t.Parallel() testCases := map[string]struct { @@ -50,14 +50,14 @@ func Test_GetProtocol(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - protocol := GetProtocol(testCase.selection) + protocol := getProtocol(testCase.selection) assert.Equal(t, testCase.protocol, protocol) }) } } -func Test_FilterByProtocol(t *testing.T) { +func Test_filterByProtocol(t *testing.T) { t.Parallel() testCases := map[string]struct { @@ -127,7 +127,7 @@ func Test_FilterByProtocol(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() - filtered := FilterByProtocol(testCase.selection, + filtered := filterByProtocol(testCase.selection, testCase.serverTCP, testCase.serverUDP) assert.Equal(t, testCase.filtered, filtered) diff --git a/internal/provider/vpnunlimited/connection.go b/internal/provider/vpnunlimited/connection.go index d9b691d2..e81f3136 100644 --- a/internal/provider/vpnunlimited/connection.go +++ b/internal/provider/vpnunlimited/connection.go @@ -2,33 +2,12 @@ package vpnunlimited import ( "github.com/qdm12/gluetun/internal/configuration/settings" - "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/provider/utils" ) func (p *Provider) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - const port = 1194 - const protocol = constants.UDP - - servers, err := utils.FilterServers(p.servers, selection) - if err != nil { - return connection, err - } - - var connections []models.Connection - for _, server := range servers { - for _, IP := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: IP, - Port: port, - Protocol: protocol, - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, p.randSource) + defaults := utils.NewConnectionDefaults(0, 1194, 0) //nolint:gomnd + return utils.GetConnection(p.servers, selection, defaults, p.randSource) } diff --git a/internal/provider/vyprvpn/connection.go b/internal/provider/vyprvpn/connection.go index a5ec441f..f2b38bd9 100644 --- a/internal/provider/vyprvpn/connection.go +++ b/internal/provider/vyprvpn/connection.go @@ -2,33 +2,12 @@ package vyprvpn import ( "github.com/qdm12/gluetun/internal/configuration/settings" - "github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/provider/utils" ) func (v *Vyprvpn) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - const port = 443 - const protocol = constants.UDP - - servers, err := utils.FilterServers(v.servers, selection) - if err != nil { - return connection, err - } - - var connections []models.Connection - for _, server := range servers { - for _, IP := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: IP, - Port: port, - Protocol: protocol, - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, v.randSource) + defaults := utils.NewConnectionDefaults(0, 443, 0) //nolint:gomnd + return utils.GetConnection(v.servers, selection, defaults, v.randSource) } diff --git a/internal/provider/wevpn/connection.go b/internal/provider/wevpn/connection.go index 3f009823..6b789efe 100644 --- a/internal/provider/wevpn/connection.go +++ b/internal/provider/wevpn/connection.go @@ -8,36 +8,6 @@ import ( func (w *Wevpn) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - port := getPort(selection) - protocol := utils.GetProtocol(selection) - - servers, err := utils.FilterServers(w.servers, selection) - if err != nil { - return connection, err - } - - var connections []models.Connection - for _, server := range servers { - for _, IP := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: IP, - Port: port, - Protocol: protocol, - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, w.randSource) -} - -func getPort(selection settings.ServerSelection) (port uint16) { - const ( - defaultOpenVPNTCP = 1195 - defaultOpenVPNUDP = 1194 - defaultWireguard = 0 // Wireguard not supported - ) - return utils.GetPort(selection, defaultOpenVPNTCP, - defaultOpenVPNUDP, defaultWireguard) + defaults := utils.NewConnectionDefaults(1195, 1194, 0) //nolint:gomnd + return utils.GetConnection(w.servers, selection, defaults, w.randSource) } diff --git a/internal/provider/wevpn/connection_test.go b/internal/provider/wevpn/connection_test.go index b60c45f1..709d2421 100644 --- a/internal/provider/wevpn/connection_test.go +++ b/internal/provider/wevpn/connection_test.go @@ -29,7 +29,7 @@ func Test_Wevpn_GetConnection(t *testing.T) { VPN: vpn.OpenVPN, }.WithDefaults(providers.Wevpn), errWrapped: utils.ErrNoServerFound, - errMessage: "no server found: for VPN openvpn; protocol udp", + errMessage: "cannot filter servers: no server found: for VPN openvpn; protocol udp", }, "no filter": { servers: []models.Server{ @@ -74,6 +74,7 @@ func Test_Wevpn_GetConnection(t *testing.T) { Type: vpn.OpenVPN, IP: net.IPv4(2, 2, 2, 2), Port: 1194, + Hostname: "b", Protocol: constants.UDP, }, }, diff --git a/internal/provider/windscribe/connection.go b/internal/provider/windscribe/connection.go index 2ce148a3..821c5a1a 100644 --- a/internal/provider/windscribe/connection.go +++ b/internal/provider/windscribe/connection.go @@ -6,40 +6,8 @@ import ( "github.com/qdm12/gluetun/internal/provider/utils" ) -func (w *Windscribe) GetConnection(selection settings.ServerSelection) ( +func (p *Windscribe) GetConnection(selection settings.ServerSelection) ( connection models.Connection, err error) { - port := getPort(selection) - protocol := utils.GetProtocol(selection) - - servers, err := utils.FilterServers(w.servers, selection) - if err != nil { - return connection, err - } - - var connections []models.Connection - for _, server := range servers { - for _, IP := range server.IPs { - connection := models.Connection{ - Type: selection.VPN, - IP: IP, - Port: port, - Protocol: protocol, - Hostname: server.OvpnX509, - PubKey: server.WgPubKey, - } - connections = append(connections, connection) - } - } - - return utils.PickConnection(connections, selection, w.randSource) -} - -func getPort(selection settings.ServerSelection) (port uint16) { - const ( - defaultOpenVPNTCP = 443 - defaultOpenVPNUDP = 1194 - defaultWireguard = 1194 - ) - return utils.GetPort(selection, defaultOpenVPNTCP, - defaultOpenVPNUDP, defaultWireguard) + defaults := utils.NewConnectionDefaults(443, 1194, 1194) //nolint:gomnd + return utils.GetConnection(p.servers, selection, defaults, p.randSource) } diff --git a/internal/provider/windscribe/connection_test.go b/internal/provider/windscribe/connection_test.go index b37a8a70..6ff61ec6 100644 --- a/internal/provider/windscribe/connection_test.go +++ b/internal/provider/windscribe/connection_test.go @@ -27,7 +27,7 @@ func Test_Windscribe_GetConnection(t *testing.T) { "no server available": { selection: settings.ServerSelection{}.WithDefaults(providers.Windscribe), errWrapped: utils.ErrNoServerFound, - errMessage: "no server found: for VPN openvpn; protocol udp", + errMessage: "cannot filter servers: no server found: for VPN openvpn; protocol udp", }, "no filter": { servers: []models.Server{ @@ -72,6 +72,7 @@ func Test_Windscribe_GetConnection(t *testing.T) { Type: vpn.OpenVPN, IP: net.IPv4(2, 2, 2, 2), Port: 1194, + Hostname: "b", Protocol: constants.UDP, }, },