Skip to content

Commit

Permalink
Support for SlickVPN
Browse files Browse the repository at this point in the history
  • Loading branch information
qdm12 committed Jun 18, 2022
1 parent 75454be commit 453acb5
Show file tree
Hide file tree
Showing 20 changed files with 2,038 additions and 16 deletions.
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/bug.yml
Expand Up @@ -54,6 +54,7 @@ body:
- PrivateVPN
- ProtonVPN
- PureVPN
- SlickVPN
- Surfshark
- TorGuard
- VPNUnlimited
Expand Down
3 changes: 3 additions & 0 deletions .github/labels.yml
Expand Up @@ -64,6 +64,9 @@
- name: ":cloud: PureVPN"
color: "cfe8d4"
description: ""
- name: ":cloud: SlickVPN"
color: "cfe8d4"
description: ""
- name: ":cloud: Surfshark"
color: "cfe8d4"
description: ""
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Expand Up @@ -3,6 +3,7 @@ module github.com/qdm12/gluetun
go 1.17

require (
github.com/andybalholm/cascadia v1.3.1
github.com/breml/rootcerts v0.2.3
github.com/fatih/color v1.13.0
github.com/golang/mock v1.6.0
Expand All @@ -17,6 +18,7 @@ require (
github.com/qdm12/updated v0.0.0-20210603204757-205acfe6937e
github.com/stretchr/testify v1.7.2
github.com/vishvananda/netlink v1.1.1-0.20211129163951-9ada19101fc5
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
golang.org/x/text v0.3.7
golang.zx2c4.com/wireguard v0.0.0-20210805125648-3957e9b9dd19
Expand All @@ -40,6 +42,5 @@ require (
go4.org/intern v0.0.0-20210108033219-3eb7198706b2 // indirect
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 // indirect
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
golang.org/x/net v0.0.0-20210504132125-bbd867fde50d // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
5 changes: 4 additions & 1 deletion go.sum
@@ -1,6 +1,8 @@
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
Expand Down Expand Up @@ -178,8 +180,9 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210504132125-bbd867fde50d h1:nTDGCTeAu2LhcsHTRzjyIUbZHCJ4QePArsm27Hka0UM=
golang.org/x/net v0.0.0-20210504132125-bbd867fde50d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8 h1:/6y1LfuqNuQdHAm0jjtPtgRcxIxjVZgm5OTu8/QhZvk=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
Expand Down
1 change: 1 addition & 0 deletions internal/configuration/settings/openvpnselection.go
Expand Up @@ -43,6 +43,7 @@ func (o OpenVPNSelection) validate(vpnProvider string) (err error) {
providers.Ipvanish,
providers.Perfectprivacy,
providers.Privado,
providers.SlickVPN,
providers.VPNUnlimited,
providers.Vyprvpn,
) {
Expand Down
2 changes: 2 additions & 0 deletions internal/constants/providers/providers.go
Expand Up @@ -18,6 +18,7 @@ const (
Privatevpn = "privatevpn"
Protonvpn = "protonvpn"
Purevpn = "purevpn"
SlickVPN = "slickvpn"
Surfshark = "surfshark"
Torguard = "torguard"
VPNUnlimited = "vpn unlimited"
Expand All @@ -43,6 +44,7 @@ func All() []string {
Privatevpn,
Protonvpn,
Purevpn,
SlickVPN,
Surfshark,
Torguard,
VPNUnlimited,
Expand Down
2 changes: 2 additions & 0 deletions internal/models/markdown.go
Expand Up @@ -123,6 +123,8 @@ func getMarkdownHeaders(vpnProvider string) (headers []string) {
return []string{countryHeader, regionHeader, cityHeader, hostnameHeader, freeHeader}
case providers.Purevpn:
return []string{countryHeader, regionHeader, cityHeader, hostnameHeader, tcpHeader, udpHeader}
case providers.SlickVPN:
return []string{regionHeader, countryHeader, cityHeader, hostnameHeader}
case providers.Surfshark:
return []string{regionHeader, countryHeader, cityHeader, hostnameHeader, multiHopHeader, tcpHeader, udpHeader}
case providers.Torguard:
Expand Down
2 changes: 2 additions & 0 deletions internal/models/servers_test.go
Expand Up @@ -38,6 +38,7 @@ func Test_AllServers_MarshalJSON(t *testing.T) {
`"privatevpn":{"version":0,"timestamp":0},` +
`"protonvpn":{"version":0,"timestamp":0},` +
`"purevpn":{"version":0,"timestamp":0},` +
`"slickvpn":{"version":0,"timestamp":0},` +
`"surfshark":{"version":0,"timestamp":0},` +
`"torguard":{"version":0,"timestamp":0},` +
`"vpn unlimited":{"version":0,"timestamp":0},` +
Expand Down Expand Up @@ -82,6 +83,7 @@ func Test_AllServers_MarshalJSON(t *testing.T) {
`"privatevpn":{"version":0,"timestamp":0},` +
`"protonvpn":{"version":0,"timestamp":0},` +
`"purevpn":{"version":0,"timestamp":0},` +
`"slickvpn":{"version":0,"timestamp":0},` +
`"surfshark":{"version":0,"timestamp":0},` +
`"torguard":{"version":0,"timestamp":0},` +
`"vpn unlimited":{"version":0,"timestamp":0},` +
Expand Down
8 changes: 7 additions & 1 deletion internal/provider/hidemyass/updater/hosttourl.go
Expand Up @@ -33,5 +33,11 @@ func getHostToURL(ctx context.Context, client *http.Client, protocol string) (
return nil, err
}

return openvpn.FetchMultiFiles(ctx, client, urls)
const failEarly = true
hostToURL, errors := openvpn.FetchMultiFiles(ctx, client, urls, failEarly)
if len(errors) > 0 {
return nil, errors[0]
}

return hostToURL, nil
}
2 changes: 2 additions & 0 deletions internal/provider/providers.go
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/qdm12/gluetun/internal/provider/privatevpn"
"github.com/qdm12/gluetun/internal/provider/protonvpn"
"github.com/qdm12/gluetun/internal/provider/purevpn"
"github.com/qdm12/gluetun/internal/provider/slickvpn"
"github.com/qdm12/gluetun/internal/provider/surfshark"
"github.com/qdm12/gluetun/internal/provider/torguard"
"github.com/qdm12/gluetun/internal/provider/vpnunlimited"
Expand Down Expand Up @@ -71,6 +72,7 @@ func NewProviders(storage Storage, timeNow func() time.Time,
providers.Privatevpn: privatevpn.New(storage, randSource, unzipper, updaterWarner, parallelResolver),
providers.Protonvpn: protonvpn.New(storage, randSource, client, updaterWarner, parallelResolver),
providers.Purevpn: purevpn.New(storage, randSource, ipFetcher, unzipper, updaterWarner, parallelResolver),
providers.SlickVPN: slickvpn.New(storage, randSource, client, updaterWarner, parallelResolver),
providers.Surfshark: surfshark.New(storage, randSource, client, unzipper, updaterWarner, parallelResolver),
providers.Torguard: torguard.New(storage, randSource, unzipper, updaterWarner, parallelResolver),
providers.VPNUnlimited: vpnunlimited.New(storage, randSource, unzipper, updaterWarner, parallelResolver),
Expand Down
13 changes: 13 additions & 0 deletions internal/provider/slickvpn/connection.go
@@ -0,0 +1,13 @@
package slickvpn

import (
"github.com/qdm12/gluetun/internal/configuration/settings"
"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) {
defaults := utils.NewConnectionDefaults(0, 443, 0) //nolint:gomnd
return utils.GetConnection(p.Name(), p.storage, selection, defaults, p.randSource)
}
29 changes: 29 additions & 0 deletions internal/provider/slickvpn/openvpnconf.go
@@ -0,0 +1,29 @@
package slickvpn

import (
"github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/constants/openvpn"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/utils"
)

func (p *Provider) OpenVPNConfig(connection models.Connection,
settings settings.OpenVPN) (lines []string) {
const pingSeconds = 10
const bufSize = 393216
providerSettings := utils.OpenVPNProviderSettings{
RemoteCertTLS: true,
AuthUserPass: true,
Ciphers: []string{
openvpn.AES256cbc,
},
Ping: pingSeconds,
SndBuf: bufSize,
RcvBuf: bufSize,
CA: "MIIDQDCCAqmgAwIBAgIJAM8Brk2pUr0KMA0GCSqGSIb3DQEBBQUAMHQxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEMMAoGA1UEBxMDVlBOMQwwCgYDVQQKEwNWUE4xDDAKBgNVBAsTA1ZQTjEMMAoGA1UEAxMDVlBOMQwwCgYDVQQpEwNWUE4xEjAQBgkqhkiG9w0BCQEWA1ZQTjAeFw0xMjAzMDMwMjExNDJaFw0yMjAzMDEwMjExNDJaMHQxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEMMAoGA1UEBxMDVlBOMQwwCgYDVQQKEwNWUE4xDDAKBgNVBAsTA1ZQTjEMMAoGA1UEAxMDVlBOMQwwCgYDVQQpEwNWUE4xEjAQBgkqhkiG9w0BCQEWA1ZQTjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwY2K08N7or1Br/EsD9XBon7gs7dKflWYuymgMLJfeMFWuJloNdsn+3GARIhYBbN6zhvFGFE214qKPqAydW1WmIIK7KoC0sgndr+Vk/au9gssFzVmmvr6+WN/nfo2L9KvvBMoYLrMAiyw/D4cRapZi2pXJLcMDfC+p1VWAX8TYWkCAwEAAaOB2TCB1jAdBgNVHQ4EFgQUmyvO4rTnu5/ABnp0FngU+SdR8WAwgaYGA1UdIwSBnjCBm4AUmyvO4rTnu5/ABnp0FngU+SdR8WCheKR2MHQxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEMMAoGA1UEBxMDVlBOMQwwCgYDVQQKEwNWUE4xDDAKBgNVBAsTA1ZQTjEMMAoGA1UEAxMDVlBOMQwwCgYDVQQpEwNWUE4xEjAQBgkqhkiG9w0BCQEWA1ZQToIJAM8Brk2pUr0KMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAoB0kOuGvrzPBTIRXIDHCCxBMdny+3sKAOllmH4+51j2aWhAJ4Pyc/yBTYyQGNoriABjmNzp+R05oiaxAD3vTgR80juKDPtQb8LoGLBF18gL7Vtc3+hJXcJasXZaDSSoyh5f+TtGvytIT+eceJWIrKnFXzlHOvKlyLkcZn15gwKQ=", //nolint:lll
ExtraLines: []string{
"redirect-gateway",
},
}
return utils.OpenVPNConfig(providerSettings, connection, settings)
}
33 changes: 33 additions & 0 deletions internal/provider/slickvpn/provider.go
@@ -0,0 +1,33 @@
package slickvpn

import (
"math/rand"
"net/http"

"github.com/qdm12/gluetun/internal/constants/providers"
"github.com/qdm12/gluetun/internal/provider/common"
"github.com/qdm12/gluetun/internal/provider/slickvpn/updater"
"github.com/qdm12/gluetun/internal/provider/utils"
)

type Provider struct {
storage common.Storage
randSource rand.Source
utils.NoPortForwarder
common.Fetcher
}

func New(storage common.Storage, randSource rand.Source,
client *http.Client, updaterWarner common.Warner,
parallelResolver common.ParallelResolver) *Provider {
return &Provider{
storage: storage,
randSource: randSource,
NoPortForwarder: utils.NewNoPortForwarding(providers.SlickVPN),
Fetcher: updater.New(client, updaterWarner, parallelResolver),
}
}

func (p *Provider) Name() string {
return providers.SlickVPN
}
28 changes: 28 additions & 0 deletions internal/provider/slickvpn/updater/resolve.go
@@ -0,0 +1,28 @@
package updater

import (
"time"

"github.com/qdm12/gluetun/internal/updater/resolver"
)

func parallelResolverSettings(hosts []string) (settings resolver.ParallelSettings) {
const (
maxFailRatio = 0.1
maxDuration = 20 * time.Second
betweenDuration = time.Second
maxNoNew = 2
maxFails = 2
)
return resolver.ParallelSettings{
Hosts: hosts,
MaxFailRatio: maxFailRatio,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
MaxNoNew: maxNoNew,
MaxFails: maxFails,
SortIPs: true,
},
}
}
85 changes: 85 additions & 0 deletions internal/provider/slickvpn/updater/servers.go
@@ -0,0 +1,85 @@
package updater

import (
"context"
"errors"
"fmt"
"sort"

"github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/common"
"github.com/qdm12/gluetun/internal/updater/openvpn"
)

var ErrNotEnoughServers = errors.New("not enough servers found")

func (u *Updater) FetchServers(ctx context.Context, minServers int) (
servers []models.Server, err error) {
hostToData, err := fetchAndParseWebsite(ctx, u.client)
if err != nil {
return nil, fmt.Errorf("fetching and parsing website: %w", err)
}

openvpnURLs := make([]string, 0, len(hostToData))
for _, data := range hostToData {
openvpnURLs = append(openvpnURLs, data.ovpnURL)
}

if len(openvpnURLs) < minServers {
return nil, fmt.Errorf("%w: %d and expected at least %d",
common.ErrNotEnoughServers, len(openvpnURLs), minServers)
}

const failEarly = false // some URLs from the website are not valid
udpHostToURL, errors := openvpn.FetchMultiFiles(ctx, u.client, openvpnURLs, failEarly)
for _, err := range errors {
u.warner.Warn(fmt.Sprintf("fetching OpenVPN files: %s", err))
}

if len(udpHostToURL) < minServers {
return nil, fmt.Errorf("%w: %d and expected at least %d",
common.ErrNotEnoughServers, len(udpHostToURL), minServers)
}

hosts := make([]string, 0, len(udpHostToURL))
for host := range udpHostToURL {
hosts = append(hosts, host)
}

resolveSettings := parallelResolverSettings(hosts)
hostToIPs, warnings, err := u.parallelResolver.Resolve(ctx, resolveSettings)
for _, warning := range warnings {
u.warner.Warn(warning)
}
if err != nil {
return nil, err
}

if len(hostToIPs) < minServers {
return nil, fmt.Errorf("%w: %d and expected at least %d",
common.ErrNotEnoughServers, len(hosts), minServers)
}

servers = make([]models.Server, 0, len(hostToIPs))
for host, IPs := range hostToIPs {
_, udp := udpHostToURL[host]

serverData := hostToData[host]

server := models.Server{
VPN: vpn.OpenVPN,
Region: serverData.region,
Country: serverData.country,
City: serverData.city,
Hostname: host,
UDP: udp,
IPs: IPs,
}
servers = append(servers, server)
}

sort.Sort(models.SortableServers(servers))

return servers, nil
}
22 changes: 22 additions & 0 deletions internal/provider/slickvpn/updater/updater.go
@@ -0,0 +1,22 @@
package updater

import (
"net/http"

"github.com/qdm12/gluetun/internal/provider/common"
)

type Updater struct {
client *http.Client
parallelResolver common.ParallelResolver
warner common.Warner
}

func New(client *http.Client, warner common.Warner,
parallelResolver common.ParallelResolver) *Updater {
return &Updater{
client: client,
parallelResolver: parallelResolver,
warner: warner,
}
}

0 comments on commit 453acb5

Please sign in to comment.