Compare commits
1 Commits
v3.39.0
...
v4-storage
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a6e8d74d6 |
@@ -37,12 +37,12 @@
|
||||
"go.useLanguageServer": true,
|
||||
"[go]": {
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": "explicit"
|
||||
"source.organizeImports": true
|
||||
}
|
||||
},
|
||||
"[go.mod]": {
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": "explicit"
|
||||
"source.organizeImports": true
|
||||
}
|
||||
},
|
||||
"gopls": {
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/config.yml
vendored
4
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,10 +1,10 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Report a Wiki issue
|
||||
url: https://github.com/qdm12/gluetun-wiki/issues/new/choose
|
||||
url: https://github.com/qdm12/gluetun-wiki/issues/new
|
||||
about: Please create an issue on the gluetun-wiki repository.
|
||||
- name: Configuration help?
|
||||
url: https://github.com/qdm12/gluetun/discussions/new/choose
|
||||
url: https://github.com/qdm12/gluetun/discussions/new
|
||||
about: Please create a Github discussion.
|
||||
- name: Unraid template issue
|
||||
url: https://github.com/qdm12/gluetun/discussions/550
|
||||
|
||||
8
.github/labels.yml
vendored
8
.github/labels.yml
vendored
@@ -3,9 +3,6 @@
|
||||
- name: "Status: 🔴 Blocked"
|
||||
color: "f7d692"
|
||||
description: "Blocked by another issue or pull request"
|
||||
- name: "Status: 📌 Before next release"
|
||||
color: "f7d692"
|
||||
description: "Has to be done before the next release"
|
||||
- name: "Status: 🔒 After next release"
|
||||
color: "f7d692"
|
||||
description: "Will be done after the next release"
|
||||
@@ -39,8 +36,6 @@
|
||||
# VPN providers
|
||||
- name: "☁️ AirVPN"
|
||||
color: "cfe8d4"
|
||||
- name: "☁️ Custom"
|
||||
color: "cfe8d4"
|
||||
- name: "☁️ Cyberghost"
|
||||
color: "cfe8d4"
|
||||
- name: "☁️ HideMyAss"
|
||||
@@ -96,9 +91,6 @@
|
||||
- name: "Category: Maintenance ⛓️"
|
||||
description: "Anything related to code or other maintenance"
|
||||
color: "ffc7ea"
|
||||
- name: "Category: Logs 📚"
|
||||
description: "Something to change in logs"
|
||||
color: "ffc7ea"
|
||||
- name: "Category: Good idea 🎯"
|
||||
description: "This is a good idea, judged by the maintainers"
|
||||
color: "ffc7ea"
|
||||
|
||||
@@ -120,3 +120,9 @@ linters:
|
||||
- wastedassign
|
||||
- whitespace
|
||||
- zerologlint
|
||||
|
||||
run:
|
||||
skip-dirs:
|
||||
- .devcontainer
|
||||
- .github
|
||||
- doc
|
||||
|
||||
@@ -60,8 +60,8 @@ Lightweight swiss-knife-like VPN client to multiple VPN service providers
|
||||
- Supports: **AirVPN**, **Cyberghost**, **ExpressVPN**, **FastestVPN**, **HideMyAss**, **IPVanish**, **IVPN**, **Mullvad**, **NordVPN**, **Perfect Privacy**, **Privado**, **Private Internet Access**, **PrivateVPN**, **ProtonVPN**, **PureVPN**, **SlickVPN**, **Surfshark**, **TorGuard**, **VPNSecure.me**, **VPNUnlimited**, **Vyprvpn**, **WeVPN**, **Windscribe** servers
|
||||
- Supports OpenVPN for all providers listed
|
||||
- Supports Wireguard both kernelspace and userspace
|
||||
- For **AirVPN**, **FastestVPN**, **Ivpn**, **Mullvad**, **NordVPN**, **Perfect privacy**, **ProtonVPN**, **Surfshark** and **Windscribe**
|
||||
- For **Cyberghost**, **Private Internet Access**, **PrivateVPN**, **PureVPN**, **Torguard**, **VPN Unlimited**, **VyprVPN** and **WeVPN** using [the custom provider](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/custom.md)
|
||||
- For **AirVPN**, **FastestVPN**, **Ivpn**, **Mullvad**, **NordVPN**, **Perfect privacy**, **Surfshark** and **Windscribe**
|
||||
- For **ProtonVPN**, **PureVPN**, **Torguard**, **VPN Unlimited** and **WeVPN** using [the custom provider](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/custom.md)
|
||||
- For custom Wireguard configurations using [the custom provider](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/custom.md)
|
||||
- More in progress, see [#134](https://github.com/qdm12/gluetun/issues/134)
|
||||
- DNS over TLS baked in with service provider(s) of your choice
|
||||
@@ -73,7 +73,7 @@ Lightweight swiss-knife-like VPN client to multiple VPN service providers
|
||||
- [Connect other containers to it](https://github.com/qdm12/gluetun-wiki/blob/main/setup/connect-a-container-to-gluetun.md)
|
||||
- [Connect LAN devices to it](https://github.com/qdm12/gluetun-wiki/blob/main/setup/connect-a-lan-device-to-gluetun.md)
|
||||
- Compatible with amd64, i686 (32 bit), **ARM** 64 bit, ARM 32 bit v6 and v7, and even ppc64le 🎆
|
||||
- Custom VPN server side port forwarding for [Perfect Privacy](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/perfect-privacy.md#vpn-server-port-forwarding), [Private Internet Access](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/private-internet-access.md#vpn-server-port-forwarding) and [ProtonVPN](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/protonvpn.md#vpn-server-port-forwarding)
|
||||
- [Custom VPN server side port forwarding for Private Internet Access](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/private-internet-access.md#vpn-server-port-forwarding)
|
||||
- Possibility of split horizon DNS by selecting multiple DNS over TLS providers
|
||||
- Unbound subprogram drops root privileges once launched
|
||||
- Can work as a Kubernetes sidecar container, thanks @rorph
|
||||
@@ -84,7 +84,7 @@ Lightweight swiss-knife-like VPN client to multiple VPN service providers
|
||||
|
||||
Go to the [Wiki](https://github.com/qdm12/gluetun-wiki)!
|
||||
|
||||
[🐛 Found a bug in the Wiki?!](https://github.com/qdm12/gluetun-wiki/issues/new/choose)
|
||||
[🐛 Found a bug in the Wiki?!](https://github.com/qdm12/gluetun-wiki/issues/new)
|
||||
|
||||
Here's a docker-compose.yml for the laziest:
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||
Emails: []string{"quentin.mcgaw@gmail.com"},
|
||||
Version: buildInfo.Version,
|
||||
Commit: buildInfo.Commit,
|
||||
Created: buildInfo.Created,
|
||||
BuildDate: buildInfo.Created,
|
||||
Announcement: "Wiki moved to https://github.com/qdm12/gluetun-wiki",
|
||||
AnnounceExp: announcementExp,
|
||||
// Sponsor information
|
||||
|
||||
4
go.mod
4
go.mod
@@ -3,7 +3,7 @@ module github.com/qdm12/gluetun
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/breml/rootcerts v0.2.17
|
||||
github.com/breml/rootcerts v0.2.16
|
||||
github.com/fatih/color v1.17.0
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/klauspost/compress v1.17.8
|
||||
@@ -12,7 +12,7 @@ require (
|
||||
github.com/qdm12/golibs v0.0.0-20210822203818-5c568b0777b6
|
||||
github.com/qdm12/gosettings v0.4.2
|
||||
github.com/qdm12/goshutdown v0.3.0
|
||||
github.com/qdm12/gosplash v0.2.0
|
||||
github.com/qdm12/gosplash v0.1.0
|
||||
github.com/qdm12/gotree v0.2.0
|
||||
github.com/qdm12/log v0.1.0
|
||||
github.com/qdm12/ss-server v0.6.0
|
||||
|
||||
10
go.sum
10
go.sum
@@ -4,8 +4,8 @@ github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/g
|
||||
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=
|
||||
github.com/breml/rootcerts v0.2.17 h1:0/M2BE2Apw0qEJCXDOkaiu7d5Sx5ObNfe1BkImJ4u1I=
|
||||
github.com/breml/rootcerts v0.2.17/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
|
||||
github.com/breml/rootcerts v0.2.16 h1:yN1TGvicfHx8dKz3OQRIrx/5nE/iN3XT1ibqGbd6urc=
|
||||
github.com/breml/rootcerts v0.2.16/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
@@ -93,12 +93,14 @@ github.com/qdm12/golibs v0.0.0-20210603202746-e5494e9c2ebb/go.mod h1:15RBzkun0i8
|
||||
github.com/qdm12/golibs v0.0.0-20210723175634-a75ca7fd74c2/go.mod h1:6aRbg4Z/bTbm9JfxsGXfWKHi7zsOvPfUTK1S5HuAFKg=
|
||||
github.com/qdm12/golibs v0.0.0-20210822203818-5c568b0777b6 h1:bge5AL7cjHJMPz+5IOz5yF01q/l8No6+lIEBieA8gMg=
|
||||
github.com/qdm12/golibs v0.0.0-20210822203818-5c568b0777b6/go.mod h1:6aRbg4Z/bTbm9JfxsGXfWKHi7zsOvPfUTK1S5HuAFKg=
|
||||
github.com/qdm12/gosettings v0.4.1 h1:c7+14jO1Y2kFXBCUfS2+QE2NgwTKfzcdJzGEFRItCI8=
|
||||
github.com/qdm12/gosettings v0.4.1/go.mod h1:uItKwGXibJp2pQ0am6MBKilpjfvYTGiH+zXHd10jFj8=
|
||||
github.com/qdm12/gosettings v0.4.2 h1:Gb39NScPr7OQV+oy0o1OD7A121udITDJuUGa7ljDF58=
|
||||
github.com/qdm12/gosettings v0.4.2/go.mod h1:CPrt2YC4UsURTrslmhxocVhMCW03lIrqdH2hzIf5prg=
|
||||
github.com/qdm12/goshutdown v0.3.0 h1:pqBpJkdwlZlfTEx4QHtS8u8CXx6pG0fVo6S1N0MpSEM=
|
||||
github.com/qdm12/goshutdown v0.3.0/go.mod h1:EqZ46No00kCTZ5qzdd3qIzY6ayhMt24QI8Mh8LVQYmM=
|
||||
github.com/qdm12/gosplash v0.2.0 h1:DOxCEizbW6ZG+FgpH2oK1atT6bM8MHL9GZ2ywSS4zZY=
|
||||
github.com/qdm12/gosplash v0.2.0/go.mod h1:k+1PzhO0th9cpX4q2Nneu4xTsndXqrM/x7NTIYmJ4jo=
|
||||
github.com/qdm12/gosplash v0.1.0 h1:Sfl+zIjFZFP7b0iqf2l5UkmEY97XBnaKkH3FNY6Gf7g=
|
||||
github.com/qdm12/gosplash v0.1.0/go.mod h1:+A3fWW4/rUeDXhY3ieBzwghKdnIPFJgD8K3qQkenJlw=
|
||||
github.com/qdm12/gotree v0.2.0 h1:+58ltxkNLUyHtATFereAcOjBVfY6ETqRex8XK90Fb/c=
|
||||
github.com/qdm12/gotree v0.2.0/go.mod h1:1SdFaqKZuI46U1apbXIf25pDMNnrPuYLEqMF/qL4lY4=
|
||||
github.com/qdm12/log v0.1.0 h1:jYBd/xscHYpblzZAd2kjZp2YmuYHjAAfbTViJWxoPTw=
|
||||
|
||||
@@ -39,7 +39,6 @@ func (p *Provider) validate(vpnType string, storage Storage) (err error) {
|
||||
providers.Ivpn,
|
||||
providers.Mullvad,
|
||||
providers.Nordvpn,
|
||||
providers.Protonvpn,
|
||||
providers.Surfshark,
|
||||
providers.Windscribe,
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@ func (w Wireguard) validate(vpnProvider string, ipv6Supported bool) (err error)
|
||||
providers.Ivpn,
|
||||
providers.Mullvad,
|
||||
providers.Nordvpn,
|
||||
providers.Protonvpn,
|
||||
providers.Surfshark,
|
||||
providers.Windscribe,
|
||||
) {
|
||||
@@ -174,15 +173,10 @@ func (w *Wireguard) overrideWith(other Wireguard) {
|
||||
func (w *Wireguard) setDefaults(vpnProvider string) {
|
||||
w.PrivateKey = gosettings.DefaultPointer(w.PrivateKey, "")
|
||||
w.PreSharedKey = gosettings.DefaultPointer(w.PreSharedKey, "")
|
||||
switch vpnProvider {
|
||||
case providers.Nordvpn:
|
||||
if vpnProvider == providers.Nordvpn {
|
||||
defaultNordVPNAddress := netip.AddrFrom4([4]byte{10, 5, 0, 2})
|
||||
defaultNordVPNPrefix := netip.PrefixFrom(defaultNordVPNAddress, defaultNordVPNAddress.BitLen())
|
||||
w.Addresses = gosettings.DefaultSlice(w.Addresses, []netip.Prefix{defaultNordVPNPrefix})
|
||||
case providers.Protonvpn:
|
||||
defaultAddress := netip.AddrFrom4([4]byte{10, 2, 0, 2})
|
||||
defaultPrefix := netip.PrefixFrom(defaultAddress, defaultAddress.BitLen())
|
||||
w.Addresses = gosettings.DefaultSlice(w.Addresses, []netip.Prefix{defaultPrefix})
|
||||
}
|
||||
defaultAllowedIPs := []netip.Prefix{
|
||||
netip.PrefixFrom(netip.IPv4Unspecified(), 0),
|
||||
|
||||
@@ -39,8 +39,8 @@ func (w WireguardSelection) validate(vpnProvider string) (err error) {
|
||||
// Validate EndpointIP
|
||||
switch vpnProvider {
|
||||
case providers.Airvpn, providers.Fastestvpn, providers.Ivpn,
|
||||
providers.Mullvad, providers.Nordvpn, providers.Protonvpn,
|
||||
providers.Surfshark, providers.Windscribe:
|
||||
providers.Mullvad, providers.Nordvpn, providers.Surfshark,
|
||||
providers.Windscribe:
|
||||
// endpoint IP addresses are baked in
|
||||
case providers.Custom:
|
||||
if !w.EndpointIP.IsValid() || w.EndpointIP.IsUnspecified() {
|
||||
@@ -57,8 +57,7 @@ func (w WireguardSelection) validate(vpnProvider string) (err error) {
|
||||
return fmt.Errorf("%w", ErrWireguardEndpointPortNotSet)
|
||||
}
|
||||
// EndpointPort cannot be set
|
||||
case providers.Fastestvpn, providers.Nordvpn,
|
||||
providers.Protonvpn, providers.Surfshark:
|
||||
case providers.Fastestvpn, providers.Surfshark, providers.Nordvpn:
|
||||
if *w.EndpointPort != 0 {
|
||||
return fmt.Errorf("%w", ErrWireguardEndpointPortSet)
|
||||
}
|
||||
|
||||
@@ -3,4 +3,13 @@ package vpn
|
||||
const (
|
||||
OpenVPN = "openvpn"
|
||||
Wireguard = "wireguard"
|
||||
Both = "openvpn+wireguard"
|
||||
)
|
||||
|
||||
func IsWireguard(s string) bool {
|
||||
return s == Wireguard || s == Both
|
||||
}
|
||||
|
||||
func IsOpenVPN(s string) bool {
|
||||
return s == OpenVPN || s == Both
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
// empty string path is returned.
|
||||
func findIP6tablesSupported(ctx context.Context, runner command.Runner) (
|
||||
ip6tablesPath string, err error) {
|
||||
ip6tablesPath, err = checkIptablesSupport(ctx, runner, "ip6tables", "ip6tables-nft", "ip6tables-legacy")
|
||||
ip6tablesPath, err = checkIptablesSupport(ctx, runner, "ip6tables-legacy", "ip6tables", "ip6tables-nft")
|
||||
if errors.Is(err, ErrIPTablesNotSupported) {
|
||||
return "", nil
|
||||
} else if err != nil {
|
||||
|
||||
@@ -210,14 +210,10 @@ func (c *Config) redirectPort(ctx context.Context, intf string,
|
||||
}
|
||||
|
||||
err = c.runIptablesInstructions(ctx, []string{
|
||||
fmt.Sprintf("-t nat %s PREROUTING %s -p tcp --dport %d -j REDIRECT --to-ports %d",
|
||||
fmt.Sprintf("-t nat %s PREROUTING %s -d 127.0.0.1 -p tcp --dport %d -j REDIRECT --to-ports %d",
|
||||
appendOrDelete(remove), interfaceFlag, sourcePort, destinationPort),
|
||||
fmt.Sprintf("%s INPUT %s -p tcp -m tcp --dport %d -j ACCEPT",
|
||||
appendOrDelete(remove), interfaceFlag, destinationPort),
|
||||
fmt.Sprintf("-t nat %s PREROUTING %s -p udp --dport %d -j REDIRECT --to-ports %d",
|
||||
fmt.Sprintf("-t nat %s PREROUTING %s -d 127.0.0.1 -p udp --dport %d -j REDIRECT --to-ports %d",
|
||||
appendOrDelete(remove), interfaceFlag, sourcePort, destinationPort),
|
||||
fmt.Sprintf("%s INPUT %s -p udp -m udp --dport %d -j ACCEPT",
|
||||
appendOrDelete(remove), interfaceFlag, destinationPort),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("redirecting IPv4 source port %d to destination port %d on interface %s: %w",
|
||||
@@ -225,14 +221,10 @@ func (c *Config) redirectPort(ctx context.Context, intf string,
|
||||
}
|
||||
|
||||
err = c.runIP6tablesInstructions(ctx, []string{
|
||||
fmt.Sprintf("-t nat %s PREROUTING %s -p tcp --dport %d -j REDIRECT --to-ports %d",
|
||||
fmt.Sprintf("-t nat %s PREROUTING %s -d ::1 -p tcp --dport %d -j REDIRECT --to-ports %d",
|
||||
appendOrDelete(remove), interfaceFlag, sourcePort, destinationPort),
|
||||
fmt.Sprintf("%s INPUT %s -p tcp -m tcp --dport %d -j ACCEPT",
|
||||
appendOrDelete(remove), interfaceFlag, destinationPort),
|
||||
fmt.Sprintf("-t nat %s PREROUTING %s -p udp --dport %d -j REDIRECT --to-ports %d",
|
||||
fmt.Sprintf("-t nat %s PREROUTING %s -d ::1 -p udp --dport %d -j REDIRECT --to-ports %d",
|
||||
appendOrDelete(remove), interfaceFlag, sourcePort, destinationPort),
|
||||
fmt.Sprintf("%s INPUT %s -p udp -m udp --dport %d -j ACCEPT",
|
||||
appendOrDelete(remove), interfaceFlag, destinationPort),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("redirecting IPv6 source port %d to destination port %d on interface %s: %w",
|
||||
|
||||
@@ -21,7 +21,7 @@ type Connection struct {
|
||||
PubKey string `json:"pubkey"`
|
||||
// ServerName is used for PIA for port forwarding
|
||||
ServerName string `json:"server_name,omitempty"`
|
||||
// PortForward is used for PIA and ProtonVPN for port forwarding
|
||||
// PortForward is used for PIA for port forwarding
|
||||
PortForward bool `json:"port_forward"`
|
||||
}
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ func getMarkdownHeaders(vpnProvider string) (headers []string) {
|
||||
case providers.Mullvad:
|
||||
return []string{countryHeader, cityHeader, ispHeader, ownedHeader, hostnameHeader, vpnHeader}
|
||||
case providers.Nordvpn:
|
||||
return []string{countryHeader, regionHeader, cityHeader, hostnameHeader, vpnHeader, categoriesHeader}
|
||||
return []string{countryHeader, regionHeader, cityHeader, hostnameHeader, categoriesHeader}
|
||||
case providers.Perfectprivacy:
|
||||
return []string{cityHeader, tcpHeader, udpHeader}
|
||||
case providers.Privado:
|
||||
@@ -135,15 +135,14 @@ func getMarkdownHeaders(vpnProvider string) (headers []string) {
|
||||
case providers.Privatevpn:
|
||||
return []string{countryHeader, cityHeader, hostnameHeader}
|
||||
case providers.Protonvpn:
|
||||
return []string{countryHeader, regionHeader, cityHeader, hostnameHeader, vpnHeader,
|
||||
return []string{countryHeader, regionHeader, cityHeader, hostnameHeader,
|
||||
freeHeader, portForwardHeader, secureHeader, torHeader}
|
||||
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,
|
||||
vpnHeader, multiHopHeader, tcpHeader, udpHeader}
|
||||
return []string{regionHeader, countryHeader, cityHeader, hostnameHeader, multiHopHeader, tcpHeader, udpHeader}
|
||||
case providers.Torguard:
|
||||
return []string{countryHeader, cityHeader, hostnameHeader, tcpHeader, udpHeader}
|
||||
case providers.VPNSecure:
|
||||
|
||||
@@ -22,8 +22,8 @@ type Server struct {
|
||||
Number uint16 `json:"number,omitempty"`
|
||||
ServerName string `json:"server_name,omitempty"`
|
||||
Hostname string `json:"hostname,omitempty"`
|
||||
TCP bool `json:"tcp,omitempty"`
|
||||
UDP bool `json:"udp,omitempty"`
|
||||
TCP bool `json:"tcp,omitempty"` // TODO v4 rename to openvpn_tcp
|
||||
UDP bool `json:"udp,omitempty"` // TODO v4 rename to openvpn_udp
|
||||
OvpnX509 string `json:"x509,omitempty"`
|
||||
RetroLoc string `json:"retroloc,omitempty"` // TODO remove in v4
|
||||
MultiHop bool `json:"multihop,omitempty"`
|
||||
@@ -38,6 +38,25 @@ type Server struct {
|
||||
IPs []netip.Addr `json:"ips,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Server) SetVPN(vpnType string) {
|
||||
switch s.VPN {
|
||||
case "":
|
||||
s.VPN = vpnType
|
||||
case vpn.Both:
|
||||
return
|
||||
case vpn.OpenVPN:
|
||||
if vpnType == vpn.Wireguard {
|
||||
s.VPN = vpn.Both
|
||||
}
|
||||
case vpn.Wireguard:
|
||||
if vpnType == vpn.OpenVPN {
|
||||
s.VPN = vpn.Both
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("VPN type %q not supported", s.VPN))
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
ErrVPNFieldEmpty = errors.New("vpn field is empty")
|
||||
ErrHostnameFieldEmpty = errors.New("hostname field is empty")
|
||||
@@ -48,16 +67,18 @@ var (
|
||||
)
|
||||
|
||||
func (s *Server) HasMinimumInformation() (err error) {
|
||||
isOpenVPN := s.VPN == vpn.OpenVPN || s.VPN == vpn.Both
|
||||
isWireguard := s.VPN == vpn.Wireguard || s.VPN == vpn.Both
|
||||
switch {
|
||||
case s.VPN == "":
|
||||
return fmt.Errorf("%w", ErrVPNFieldEmpty)
|
||||
case len(s.IPs) == 0:
|
||||
return fmt.Errorf("%w", ErrIPsFieldEmpty)
|
||||
case s.VPN == vpn.Wireguard && (s.TCP || s.UDP):
|
||||
case isWireguard && !isOpenVPN && (s.TCP || s.UDP):
|
||||
return fmt.Errorf("%w", ErrNetworkProtocolSet)
|
||||
case s.VPN == vpn.OpenVPN && !s.TCP && !s.UDP:
|
||||
case isOpenVPN && !s.TCP && !s.UDP:
|
||||
return fmt.Errorf("%w", ErrNoNetworkProtocol)
|
||||
case s.VPN == vpn.Wireguard && s.WgPubKey == "":
|
||||
case isWireguard && s.WgPubKey == "":
|
||||
return fmt.Errorf("%w", ErrWireguardPublicKeyEmpty)
|
||||
default:
|
||||
return nil
|
||||
|
||||
@@ -18,11 +18,6 @@ var (
|
||||
func extractDataFromLines(lines []string) (
|
||||
connection models.Connection, err error) {
|
||||
for i, line := range lines {
|
||||
hashSymbolIndex := strings.Index(line, "#")
|
||||
if hashSymbolIndex >= 0 {
|
||||
line = line[:hashSymbolIndex]
|
||||
}
|
||||
|
||||
ip, port, protocol, err := extractDataFromLine(line)
|
||||
if err != nil {
|
||||
return connection, fmt.Errorf("on line %d: %w", i+1, err)
|
||||
|
||||
@@ -40,12 +40,11 @@ func getOpenVPNConnection(extractor Extractor,
|
||||
connection.Port = customPort
|
||||
}
|
||||
|
||||
// assume all custom provider servers support port forwarding
|
||||
connection.PortForward = true
|
||||
if len(selection.Names) > 0 {
|
||||
// Set the server name for PIA port forwarding code used
|
||||
// together with the custom provider.
|
||||
connection.ServerName = selection.Names[0]
|
||||
connection.PortForward = true
|
||||
}
|
||||
|
||||
return connection, nil
|
||||
@@ -54,17 +53,17 @@ func getOpenVPNConnection(extractor Extractor,
|
||||
func getWireguardConnection(selection settings.ServerSelection) (
|
||||
connection models.Connection) {
|
||||
connection = models.Connection{
|
||||
Type: vpn.Wireguard,
|
||||
IP: selection.Wireguard.EndpointIP,
|
||||
Port: *selection.Wireguard.EndpointPort,
|
||||
Protocol: constants.UDP,
|
||||
PubKey: selection.Wireguard.PublicKey,
|
||||
PortForward: true, // assume all custom provider servers support port forwarding
|
||||
Type: vpn.Wireguard,
|
||||
IP: selection.Wireguard.EndpointIP,
|
||||
Port: *selection.Wireguard.EndpointPort,
|
||||
Protocol: constants.UDP,
|
||||
PubKey: selection.Wireguard.PublicKey,
|
||||
}
|
||||
if len(selection.Names) > 0 {
|
||||
// Set the server name for PIA port forwarding code used
|
||||
// together with the custom provider.
|
||||
connection.ServerName = selection.Names[0]
|
||||
connection.PortForward = true
|
||||
}
|
||||
return connection
|
||||
}
|
||||
|
||||
@@ -68,26 +68,17 @@ func (hts hostToServerData) adaptWithIPs(hostToIPs map[string][]netip.Addr) {
|
||||
func (hts hostToServerData) toServersSlice() (servers []models.Server) {
|
||||
servers = make([]models.Server, 0, 2*len(hts)) //nolint:gomnd
|
||||
for hostname, serverData := range hts {
|
||||
baseServer := models.Server{
|
||||
server := models.Server{
|
||||
VPN: vpn.Both,
|
||||
Hostname: hostname,
|
||||
Country: serverData.country,
|
||||
City: serverData.city,
|
||||
IPs: serverData.ips,
|
||||
TCP: serverData.openvpnTCP,
|
||||
UDP: serverData.openvpnUDP,
|
||||
WgPubKey: "658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0=",
|
||||
}
|
||||
if serverData.openvpn {
|
||||
openvpnServer := baseServer
|
||||
openvpnServer.VPN = vpn.OpenVPN
|
||||
openvpnServer.TCP = serverData.openvpnTCP
|
||||
openvpnServer.UDP = serverData.openvpnUDP
|
||||
servers = append(servers, openvpnServer)
|
||||
}
|
||||
if serverData.wireguard {
|
||||
wireguardServer := baseServer
|
||||
wireguardServer.VPN = vpn.Wireguard
|
||||
const wireguardPublicKey = "658QxufMbjOTmB61Z7f+c7Rjg7oqWLnepTalqBERjF0="
|
||||
wireguardServer.WgPubKey = wireguardPublicKey
|
||||
servers = append(servers, wireguardServer)
|
||||
}
|
||||
servers = append(servers, server)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -35,11 +35,11 @@ func (hts hostToServer) add(data serverData) (err error) {
|
||||
|
||||
switch data.Type {
|
||||
case "openvpn":
|
||||
server.VPN = vpn.OpenVPN
|
||||
server.SetVPN(vpn.OpenVPN)
|
||||
server.UDP = true
|
||||
server.TCP = true
|
||||
case "wireguard":
|
||||
server.VPN = vpn.Wireguard
|
||||
server.SetVPN(vpn.Wireguard)
|
||||
case "bridge":
|
||||
// ignore bridge servers
|
||||
return nil
|
||||
|
||||
@@ -98,12 +98,6 @@ func extractServers(jsonServer serverData, groups map[uint32]groupData,
|
||||
server.Number = number
|
||||
}
|
||||
|
||||
var wireguardFound, openvpnFound bool
|
||||
wireguardServer := server
|
||||
wireguardServer.VPN = vpn.Wireguard
|
||||
openVPNServer := server // accumulate UDP+TCP technologies
|
||||
openVPNServer.VPN = vpn.OpenVPN
|
||||
|
||||
for _, technology := range jsonServer.Technologies {
|
||||
if technology.Status != "online" {
|
||||
continue
|
||||
@@ -118,33 +112,25 @@ func extractServers(jsonServer serverData, groups map[uint32]groupData,
|
||||
|
||||
switch technologyData.Identifier {
|
||||
case "openvpn_udp", "openvpn_dedicated_udp":
|
||||
openvpnFound = true
|
||||
openVPNServer.UDP = true
|
||||
server.SetVPN(vpn.OpenVPN)
|
||||
server.UDP = true
|
||||
case "openvpn_tcp", "openvpn_dedicated_tcp":
|
||||
openvpnFound = true
|
||||
openVPNServer.TCP = true
|
||||
server.SetVPN(vpn.OpenVPN)
|
||||
server.TCP = true
|
||||
case "wireguard_udp":
|
||||
wireguardFound = true
|
||||
wireguardServer.WgPubKey, err = jsonServer.wireguardPublicKey(technologies)
|
||||
server.WgPubKey, err = jsonServer.wireguardPublicKey(technologies)
|
||||
if err != nil {
|
||||
warning := fmt.Sprintf("ignoring Wireguard server %s: %s", jsonServer.Name, err)
|
||||
warnings = append(warnings, warning)
|
||||
wireguardFound = false
|
||||
continue
|
||||
}
|
||||
server.SetVPN(vpn.Wireguard)
|
||||
default: // Ignore other technologies
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
const maxServers = 2
|
||||
servers = make([]models.Server, 0, maxServers)
|
||||
if openvpnFound {
|
||||
servers = append(servers, openVPNServer)
|
||||
}
|
||||
if wireguardFound {
|
||||
servers = append(servers, wireguardServer)
|
||||
}
|
||||
servers = append(servers, server)
|
||||
|
||||
return servers, warnings
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants"
|
||||
"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"
|
||||
@@ -65,7 +64,6 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
|
||||
continue
|
||||
}
|
||||
server := models.Server{
|
||||
VPN: vpn.OpenVPN,
|
||||
Country: country,
|
||||
City: city,
|
||||
IPs: ips,
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
func (p *Provider) GetConnection(selection settings.ServerSelection, ipv6Supported bool) (
|
||||
connection models.Connection, err error) {
|
||||
defaults := utils.NewConnectionDefaults(443, 1194, 51820) //nolint:gomnd
|
||||
defaults := utils.NewConnectionDefaults(443, 1194, 0) //nolint:gomnd
|
||||
return utils.GetConnection(p.Name(),
|
||||
p.storage, selection, defaults, ipv6Supported, p.randSource)
|
||||
}
|
||||
|
||||
@@ -28,11 +28,10 @@ type logicalServer struct {
|
||||
}
|
||||
|
||||
type physicalServer struct {
|
||||
EntryIP netip.Addr `json:"EntryIP"`
|
||||
ExitIP netip.Addr `json:"ExitIP"`
|
||||
Domain string `json:"Domain"`
|
||||
Status uint8 `json:"Status"`
|
||||
X25519PublicKey string `json:"X25519PublicKey"`
|
||||
EntryIP netip.Addr `json:"EntryIP"`
|
||||
ExitIP netip.Addr `json:"ExitIP"`
|
||||
Domain string `json:"Domain"`
|
||||
Status uint8 `json:"Status"`
|
||||
}
|
||||
|
||||
func fetchAPI(ctx context.Context, client *http.Client) (
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
|
||||
type ipToServers map[string][2]models.Server // first server is OpenVPN, second is Wireguard.
|
||||
type ipToServer map[string]models.Server
|
||||
|
||||
type features struct {
|
||||
secureCore bool
|
||||
@@ -16,50 +16,36 @@ type features struct {
|
||||
stream bool
|
||||
}
|
||||
|
||||
func (its ipToServers) add(country, region, city, name, hostname, wgPubKey string,
|
||||
func (its ipToServer) add(country, region, city, name, hostname string,
|
||||
free bool, entryIP netip.Addr, features features) {
|
||||
key := entryIP.String()
|
||||
|
||||
servers, ok := its[key]
|
||||
server, ok := its[key]
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
|
||||
baseServer := models.Server{
|
||||
Country: country,
|
||||
Region: region,
|
||||
City: city,
|
||||
ServerName: name,
|
||||
Hostname: hostname,
|
||||
Free: free,
|
||||
SecureCore: features.secureCore,
|
||||
Tor: features.tor,
|
||||
PortForward: features.p2p,
|
||||
Stream: features.stream,
|
||||
IPs: []netip.Addr{entryIP},
|
||||
}
|
||||
openvpnServer := baseServer
|
||||
openvpnServer.VPN = vpn.OpenVPN
|
||||
openvpnServer.UDP = true
|
||||
openvpnServer.TCP = true
|
||||
servers[0] = openvpnServer
|
||||
wireguardServer := baseServer
|
||||
wireguardServer.VPN = vpn.Wireguard
|
||||
wireguardServer.WgPubKey = wgPubKey
|
||||
servers[1] = wireguardServer
|
||||
its[key] = servers
|
||||
server.VPN = vpn.OpenVPN
|
||||
server.Country = country
|
||||
server.Region = region
|
||||
server.City = city
|
||||
server.ServerName = name
|
||||
server.Hostname = hostname
|
||||
server.Free = free
|
||||
server.SecureCore = features.secureCore
|
||||
server.Tor = features.tor
|
||||
server.PortForward = features.p2p
|
||||
server.Stream = features.stream
|
||||
server.UDP = true
|
||||
server.TCP = true
|
||||
server.IPs = []netip.Addr{entryIP}
|
||||
its[key] = server
|
||||
}
|
||||
|
||||
func (its ipToServers) toServersSlice() (serversSlice []models.Server) {
|
||||
const vpnProtocols = 2
|
||||
serversSlice = make([]models.Server, 0, vpnProtocols*len(its))
|
||||
for _, servers := range its {
|
||||
serversSlice = append(serversSlice, servers[0], servers[1])
|
||||
func (its ipToServer) toServersSlice() (servers []models.Server) {
|
||||
servers = make([]models.Server, 0, len(its))
|
||||
for _, server := range its {
|
||||
servers = append(servers, server)
|
||||
}
|
||||
return serversSlice
|
||||
}
|
||||
|
||||
func (its ipToServers) numberOfServers() int {
|
||||
const serversPerIP = 2
|
||||
return len(its) * serversPerIP
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
|
||||
common.ErrNotEnoughServers, count, minServers)
|
||||
}
|
||||
|
||||
ipToServer := make(ipToServers, count)
|
||||
ipToServer := make(ipToServer, count)
|
||||
for _, logicalServer := range data.LogicalServers {
|
||||
region := getStringValue(logicalServer.Region)
|
||||
city := getStringValue(logicalServer.City)
|
||||
@@ -65,7 +65,6 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
|
||||
|
||||
hostname := physicalServer.Domain
|
||||
entryIP := physicalServer.EntryIP
|
||||
wgPubKey := physicalServer.X25519PublicKey
|
||||
|
||||
// Note: for multi-hop use the server name or hostname
|
||||
// instead of the country
|
||||
@@ -75,11 +74,11 @@ func (u *Updater) FetchServers(ctx context.Context, minServers int) (
|
||||
u.warner.Warn(warning)
|
||||
}
|
||||
|
||||
ipToServer.add(country, region, city, name, hostname, wgPubKey, free, entryIP, features)
|
||||
ipToServer.add(country, region, city, name, hostname, free, entryIP, features)
|
||||
}
|
||||
}
|
||||
|
||||
if ipToServer.numberOfServers() < minServers {
|
||||
if len(ipToServer) < minServers {
|
||||
return nil, fmt.Errorf("%w: %d and expected at least %d",
|
||||
common.ErrNotEnoughServers, len(ipToServer), minServers)
|
||||
}
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/vpn"
|
||||
"github.com/qdm12/gluetun/internal/provider/surfshark/servers"
|
||||
)
|
||||
|
||||
func addServersFromAPI(ctx context.Context, client *http.Client,
|
||||
hts hostToServers) (err error) {
|
||||
hts hostToServer) (err error) {
|
||||
data, err := fetchAPI(ctx, client)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -25,12 +26,14 @@ func addServersFromAPI(ctx context.Context, client *http.Client,
|
||||
retroLoc := locationData.RetroLoc // empty string if the host has no retro-compatible region
|
||||
|
||||
tcp, udp := true, true // OpenVPN servers from API supports both TCP and UDP
|
||||
hts.addOpenVPN(serverData.Host, serverData.Region, serverData.Country,
|
||||
serverData.Location, retroLoc, tcp, udp)
|
||||
const wgPubKey = ""
|
||||
hts.add(serverData.Host, vpn.OpenVPN, serverData.Region, serverData.Country,
|
||||
serverData.Location, retroLoc, wgPubKey, tcp, udp)
|
||||
|
||||
if serverData.PubKey != "" {
|
||||
hts.addWireguard(serverData.Host, serverData.Region, serverData.Country,
|
||||
serverData.Location, retroLoc, serverData.PubKey)
|
||||
const wgTCP, wgUDP = false, false // unused
|
||||
hts.add(serverData.Host, vpn.Wireguard, serverData.Region, serverData.Country,
|
||||
serverData.Location, retroLoc, serverData.PubKey, wgTCP, wgUDP)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ func Test_addServersFromAPI(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := map[string]struct {
|
||||
hts hostToServers
|
||||
hts hostToServer
|
||||
exchanges []httpExchange
|
||||
expected hostToServers
|
||||
expected hostToServer
|
||||
err error
|
||||
}{
|
||||
"fetch API error": {
|
||||
@@ -37,8 +37,8 @@ func Test_addServersFromAPI(t *testing.T) {
|
||||
err: errors.New("HTTP status code not OK: 204 No Content"),
|
||||
},
|
||||
"success": {
|
||||
hts: hostToServers{
|
||||
"existinghost": []models.Server{{Hostname: "existinghost"}},
|
||||
hts: hostToServer{
|
||||
"existinghost": models.Server{Hostname: "existinghost"},
|
||||
},
|
||||
exchanges: []httpExchange{{
|
||||
requestURL: "https://api.surfshark.com/v4/server/clusters/generic",
|
||||
@@ -61,25 +61,19 @@ func Test_addServersFromAPI(t *testing.T) {
|
||||
responseStatus: http.StatusOK,
|
||||
responseBody: io.NopCloser(strings.NewReader(`[]`)),
|
||||
}},
|
||||
expected: map[string][]models.Server{
|
||||
"existinghost": {{Hostname: "existinghost"}},
|
||||
"host1": {{
|
||||
VPN: vpn.OpenVPN,
|
||||
expected: map[string]models.Server{
|
||||
"existinghost": {Hostname: "existinghost"},
|
||||
"host1": {
|
||||
VPN: vpn.Both,
|
||||
Region: "region1",
|
||||
Country: "country1",
|
||||
City: "location1",
|
||||
Hostname: "host1",
|
||||
TCP: true,
|
||||
UDP: true,
|
||||
}, {
|
||||
VPN: vpn.Wireguard,
|
||||
Region: "region1",
|
||||
Country: "country1",
|
||||
City: "location1",
|
||||
Hostname: "host1",
|
||||
WgPubKey: "pubKeyValue",
|
||||
}},
|
||||
"host2": {{
|
||||
},
|
||||
"host2": {
|
||||
VPN: vpn.OpenVPN,
|
||||
Region: "region2",
|
||||
Country: "country1",
|
||||
@@ -87,7 +81,7 @@ func Test_addServersFromAPI(t *testing.T) {
|
||||
Hostname: "host2",
|
||||
TCP: true,
|
||||
UDP: true,
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -7,94 +7,62 @@ import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
|
||||
type hostToServers map[string][]models.Server
|
||||
type hostToServer map[string]models.Server
|
||||
|
||||
func (hts hostToServers) addOpenVPN(host, region, country, city,
|
||||
retroLoc string, tcp, udp bool) {
|
||||
// Check for existing server for this host and OpenVPN.
|
||||
servers := hts[host]
|
||||
for i, existingServer := range servers {
|
||||
if existingServer.Hostname != host ||
|
||||
existingServer.VPN != vpn.OpenVPN {
|
||||
continue
|
||||
}
|
||||
|
||||
// Update OpenVPN supported protocols and return
|
||||
if !existingServer.TCP {
|
||||
servers[i].TCP = tcp
|
||||
}
|
||||
if !existingServer.UDP {
|
||||
servers[i].UDP = udp
|
||||
func (hts hostToServer) add(host, vpnType, region, country, city,
|
||||
retroLoc, wgPubKey string, openvpnTCP, openvpnUDP bool) {
|
||||
server, ok := hts[host]
|
||||
if !ok {
|
||||
server := models.Server{
|
||||
VPN: vpnType,
|
||||
Region: region,
|
||||
Country: country,
|
||||
City: city,
|
||||
RetroLoc: retroLoc,
|
||||
Hostname: host,
|
||||
WgPubKey: wgPubKey,
|
||||
TCP: openvpnTCP,
|
||||
UDP: openvpnUDP,
|
||||
}
|
||||
hts[host] = server
|
||||
return
|
||||
}
|
||||
|
||||
server := models.Server{
|
||||
VPN: vpn.OpenVPN,
|
||||
Region: region,
|
||||
Country: country,
|
||||
City: city,
|
||||
RetroLoc: retroLoc,
|
||||
Hostname: host,
|
||||
TCP: tcp,
|
||||
UDP: udp,
|
||||
server.SetVPN(vpnType)
|
||||
if vpnType == vpn.OpenVPN {
|
||||
server.TCP = server.TCP || openvpnTCP
|
||||
server.UDP = server.UDP || openvpnUDP
|
||||
} else if wgPubKey != "" {
|
||||
server.WgPubKey = wgPubKey
|
||||
}
|
||||
hts[host] = append(servers, server)
|
||||
|
||||
hts[host] = server
|
||||
}
|
||||
|
||||
func (hts hostToServers) addWireguard(host, region, country, city, retroLoc,
|
||||
wgPubKey string) {
|
||||
// Check for existing server for this host and Wireguard.
|
||||
servers := hts[host]
|
||||
for _, existingServer := range servers {
|
||||
if existingServer.Hostname == host &&
|
||||
existingServer.VPN == vpn.Wireguard {
|
||||
// No update necessary for Wireguard
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
server := models.Server{
|
||||
VPN: vpn.Wireguard,
|
||||
Region: region,
|
||||
Country: country,
|
||||
City: city,
|
||||
RetroLoc: retroLoc,
|
||||
Hostname: host,
|
||||
WgPubKey: wgPubKey,
|
||||
}
|
||||
hts[host] = append(servers, server)
|
||||
}
|
||||
|
||||
func (hts hostToServers) toHostsSlice() (hosts []string) {
|
||||
const vpnServerTypes = 2 // OpenVPN + Wireguard
|
||||
hosts = make([]string, 0, vpnServerTypes*len(hts))
|
||||
func (hts hostToServer) toHostsSlice() (hosts []string) {
|
||||
hosts = make([]string, 0, len(hts))
|
||||
for host := range hts {
|
||||
hosts = append(hosts, host)
|
||||
}
|
||||
return hosts
|
||||
}
|
||||
|
||||
func (hts hostToServers) adaptWithIPs(hostToIPs map[string][]netip.Addr) {
|
||||
for host, IPs := range hostToIPs {
|
||||
servers := hts[host]
|
||||
for i := range servers {
|
||||
servers[i].IPs = IPs
|
||||
}
|
||||
hts[host] = servers
|
||||
}
|
||||
for host, servers := range hts {
|
||||
if len(servers[0].IPs) == 0 {
|
||||
func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]netip.Addr) {
|
||||
for host, server := range hts {
|
||||
ips := hostToIPs[host]
|
||||
if len(ips) == 0 {
|
||||
delete(hts, host)
|
||||
continue
|
||||
}
|
||||
server.IPs = ips
|
||||
hts[host] = server
|
||||
}
|
||||
}
|
||||
|
||||
func (hts hostToServers) toServersSlice() (servers []models.Server) {
|
||||
const vpnServerTypes = 2 // OpenVPN + Wireguard
|
||||
servers = make([]models.Server, 0, vpnServerTypes*len(hts))
|
||||
for _, serversForHost := range hts {
|
||||
servers = append(servers, serversForHost...)
|
||||
func (hts hostToServer) toServersSlice() (servers []models.Server) {
|
||||
servers = make([]models.Server, 0, len(hts))
|
||||
for _, server := range hts {
|
||||
servers = append(servers, server)
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package updater
|
||||
|
||||
import (
|
||||
"github.com/qdm12/gluetun/internal/constants/vpn"
|
||||
"github.com/qdm12/gluetun/internal/provider/surfshark/servers"
|
||||
)
|
||||
|
||||
// getRemainingServers finds extra servers not found in the API or in the ZIP file.
|
||||
func getRemainingServers(hts hostToServers) {
|
||||
func getRemainingServers(hts hostToServer) {
|
||||
locationData := servers.LocationData()
|
||||
hostnameToLocationLeft := hostToLocation(locationData)
|
||||
for _, hostnameDone := range hts.toHostsSlice() {
|
||||
@@ -15,7 +16,8 @@ func getRemainingServers(hts hostToServers) {
|
||||
for hostname, locationData := range hostnameToLocationLeft {
|
||||
// we assume the OpenVPN server supports both TCP and UDP
|
||||
const tcp, udp = true, true
|
||||
hts.addOpenVPN(hostname, locationData.Region, locationData.Country,
|
||||
locationData.City, locationData.RetroLoc, tcp, udp)
|
||||
const wgPubKey = ""
|
||||
hts.add(hostname, vpn.OpenVPN, locationData.Region, locationData.Country,
|
||||
locationData.City, locationData.RetroLoc, wgPubKey, tcp, udp)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
func (u *Updater) FetchServers(ctx context.Context, minServers int) (
|
||||
servers []models.Server, err error) {
|
||||
hts := make(hostToServers)
|
||||
hts := make(hostToServer)
|
||||
|
||||
err = addServersFromAPI(ctx, u.client, hts)
|
||||
if err != nil {
|
||||
|
||||
@@ -4,13 +4,14 @@ import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/vpn"
|
||||
"github.com/qdm12/gluetun/internal/provider/common"
|
||||
"github.com/qdm12/gluetun/internal/provider/surfshark/servers"
|
||||
"github.com/qdm12/gluetun/internal/updater/openvpn"
|
||||
)
|
||||
|
||||
func addOpenVPNServersFromZip(ctx context.Context,
|
||||
unzipper common.Unzipper, hts hostToServers) (
|
||||
unzipper common.Unzipper, hts hostToServer) (
|
||||
warnings []string, err error) {
|
||||
const url = "https://my.surfshark.com/vpn/api/v1/server/configurations"
|
||||
contents, err := unzipper.FetchAndExtract(ctx, url)
|
||||
@@ -66,8 +67,9 @@ func addOpenVPNServersFromZip(ctx context.Context,
|
||||
continue
|
||||
}
|
||||
|
||||
hts.addOpenVPN(host, data.Region, data.Country, data.City,
|
||||
data.RetroLoc, tcp, udp)
|
||||
const wgPubKey = ""
|
||||
hts.add(host, vpn.OpenVPN, data.Region, data.Country, data.City,
|
||||
data.RetroLoc, wgPubKey, tcp, udp)
|
||||
}
|
||||
|
||||
return warnings, nil
|
||||
|
||||
@@ -50,11 +50,11 @@ func filterServer(server models.Server,
|
||||
selection settings.ServerSelection) (filtered bool) {
|
||||
// Note each condition is split to make sure
|
||||
// we have full testing coverage.
|
||||
if server.VPN != selection.VPN {
|
||||
if server.VPN != vpn.Both && server.VPN != selection.VPN {
|
||||
return true
|
||||
}
|
||||
|
||||
if server.VPN != vpn.Wireguard &&
|
||||
if selection.VPN == vpn.OpenVPN &&
|
||||
filterByProtocol(selection, server.TCP, server.UDP) {
|
||||
return true
|
||||
}
|
||||
@@ -119,8 +119,6 @@ func filterServer(server models.Server,
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO filter port forward server for PIA
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
@@ -50,17 +49,13 @@ func getLatestRelease(ctx context.Context, client *http.Client) (tagName, name s
|
||||
if err != nil {
|
||||
return "", "", time, err
|
||||
}
|
||||
// Sort releases by tag names (semver)
|
||||
sort.Slice(releases, func(i, j int) bool {
|
||||
return releases[i].TagName > releases[j].TagName
|
||||
})
|
||||
for _, release := range releases {
|
||||
if release.Prerelease {
|
||||
continue
|
||||
}
|
||||
return release.TagName, release.Name, release.PublishedAt, nil
|
||||
}
|
||||
return "", "", time, fmt.Errorf("%w", errReleaseNotFound)
|
||||
return "", "", time, errReleaseNotFound
|
||||
}
|
||||
|
||||
var errCommitNotFound = errors.New("commit not found")
|
||||
|
||||
Reference in New Issue
Block a user