Compare commits
94 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b6caa435f | ||
|
|
f9cb71027c | ||
|
|
82ac568ee3 | ||
|
|
61afdce788 | ||
|
|
119cac5a67 | ||
|
|
c6fedd9214 | ||
|
|
da525e039d | ||
|
|
29d92fd307 | ||
|
|
3863cc439e | ||
|
|
b1cfc03fc5 | ||
|
|
f706071048 | ||
|
|
501ae2741b | ||
|
|
5b75635386 | ||
|
|
2901db3cf3 | ||
|
|
6c2a3e36b5 | ||
|
|
8b125e6e95 | ||
|
|
e1cc14e055 | ||
|
|
d6659552df | ||
|
|
67001fa958 | ||
|
|
ffeeae91ab | ||
|
|
04fad1b781 | ||
|
|
dcaf952986 | ||
|
|
ca3b9e892d | ||
|
|
9f12ffc069 | ||
|
|
0d6800a515 | ||
|
|
b3d8b78205 | ||
|
|
ee82a85543 | ||
|
|
7907146aaf | ||
|
|
1a677ce4f7 | ||
|
|
f1a6594474 | ||
|
|
f1a82d9d9c | ||
|
|
8b52af0d03 | ||
|
|
dbf5c569ea | ||
|
|
06a2d79cb4 | ||
|
|
eb6238ee52 | ||
|
|
f41fec57ed | ||
|
|
c348343b22 | ||
|
|
b69dcb62e3 | ||
|
|
e4a260f148 | ||
|
|
614eb10d67 | ||
|
|
0bfd58a3f5 | ||
|
|
ff56857fc8 | ||
|
|
8d258feff7 | ||
|
|
96ee1bbfb2 | ||
|
|
abaf688ad8 | ||
|
|
bec8ff27ae | ||
|
|
7191d4e911 | ||
|
|
6f59bc3037 | ||
|
|
5c2286f4e8 | ||
|
|
9218c7ef19 | ||
|
|
3d8e61900b | ||
|
|
105d81c018 | ||
|
|
d4ca5cf257 | ||
|
|
05018ec971 | ||
|
|
538bc72c3c | ||
|
|
0027a76c49 | ||
|
|
a0cb6fabfd | ||
|
|
9e5400f52d | ||
|
|
7a1d0ff3ec | ||
|
|
d9fbecaa01 | ||
|
|
ecdf9396a5 | ||
|
|
df51aa40f4 | ||
|
|
996942af47 | ||
|
|
f17a4eae3e | ||
|
|
c515603d2f | ||
|
|
14c3b6429b | ||
|
|
bd110b960b | ||
|
|
3ad4319163 | ||
|
|
97340ec70b | ||
|
|
5140a7b010 | ||
|
|
bd74879303 | ||
|
|
da30ae287f | ||
|
|
6a545aa088 | ||
|
|
384a4bae3a | ||
|
|
e65f924cd7 | ||
|
|
9105b33e9f | ||
|
|
cc2235653a | ||
|
|
a00de75f61 | ||
|
|
836412b032 | ||
|
|
ba16270059 | ||
|
|
2c73672e64 | ||
|
|
74b7c81195 | ||
|
|
a021ff6b22 | ||
|
|
6d1a90cac0 | ||
|
|
1f47c16102 | ||
|
|
abbcf60aed | ||
|
|
f339c882d7 | ||
|
|
982536e9e8 | ||
|
|
c17b351efb | ||
|
|
130bebf2c6 | ||
|
|
83c4ad2e59 | ||
|
|
0bcc6ed597 | ||
|
|
c61f854edc | ||
|
|
2998cf5e48 |
@@ -1 +1,2 @@
|
|||||||
FROM qmcgaw/godevcontainer
|
FROM qmcgaw/godevcontainer
|
||||||
|
RUN apk add wireguard-tools
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ services:
|
|||||||
vscode:
|
vscode:
|
||||||
build: .
|
build: .
|
||||||
image: godevcontainer
|
image: godevcontainer
|
||||||
|
devices:
|
||||||
|
- /dev/net/tun:/dev/net/tun
|
||||||
volumes:
|
volumes:
|
||||||
- ../:/workspace
|
- ../:/workspace
|
||||||
# Docker socket to access Docker server
|
# Docker socket to access Docker server
|
||||||
@@ -23,7 +25,8 @@ services:
|
|||||||
- TZ=
|
- TZ=
|
||||||
cap_add:
|
cap_add:
|
||||||
# For debugging with dlv
|
# For debugging with dlv
|
||||||
- SYS_PTRACE
|
# - SYS_PTRACE
|
||||||
|
- NET_ADMIN
|
||||||
security_opt:
|
security_opt:
|
||||||
# For debugging with dlv
|
# For debugging with dlv
|
||||||
- seccomp:unconfined
|
- seccomp:unconfined
|
||||||
|
|||||||
4
.github/ISSUE_TEMPLATE/bug.md
vendored
4
.github/ISSUE_TEMPLATE/bug.md
vendored
@@ -15,6 +15,10 @@ assignees: qdm12
|
|||||||
|
|
||||||
**Host OS** (approximate answer is fine too): Ubuntu 18
|
**Host OS** (approximate answer is fine too): Ubuntu 18
|
||||||
|
|
||||||
|
<!---
|
||||||
|
🚧 If this is about the Unraid template see https://github.com/qdm12/gluetun/discussions/550
|
||||||
|
-->
|
||||||
|
|
||||||
**CPU arch** or **device name**: amd64
|
**CPU arch** or **device name**: amd64
|
||||||
|
|
||||||
**What VPN provider are you using**:
|
**What VPN provider are you using**:
|
||||||
|
|||||||
3
.github/labels.yml
vendored
3
.github/labels.yml
vendored
@@ -70,6 +70,9 @@
|
|||||||
- name: "Openvpn"
|
- name: "Openvpn"
|
||||||
color: "ffc7ea"
|
color: "ffc7ea"
|
||||||
description: ""
|
description: ""
|
||||||
|
- name: "Wireguard"
|
||||||
|
color: "ffc7ea"
|
||||||
|
description: ""
|
||||||
- name: "Unbound (DNS over TLS)"
|
- name: "Unbound (DNS over TLS)"
|
||||||
color: "ffc7ea"
|
color: "ffc7ea"
|
||||||
description: ""
|
description: ""
|
||||||
|
|||||||
16
Dockerfile
16
Dockerfile
@@ -1,6 +1,6 @@
|
|||||||
ARG ALPINE_VERSION=3.14
|
ARG ALPINE_VERSION=3.14
|
||||||
ARG GO_ALPINE_VERSION=3.13
|
ARG GO_ALPINE_VERSION=3.14
|
||||||
ARG GO_VERSION=1.16
|
ARG GO_VERSION=1.17
|
||||||
ARG XCPUTRANSLATE_VERSION=v0.6.0
|
ARG XCPUTRANSLATE_VERSION=v0.6.0
|
||||||
ARG GOLANGCI_LINT_VERSION=v1.41.1
|
ARG GOLANGCI_LINT_VERSION=v1.41.1
|
||||||
ARG BUILDPLATFORM=linux/amd64
|
ARG BUILDPLATFORM=linux/amd64
|
||||||
@@ -68,6 +68,8 @@ LABEL \
|
|||||||
org.opencontainers.image.description="VPN swiss-knife like client to tunnel to multiple VPN servers using OpenVPN, IPtables, DNS over TLS, Shadowsocks, an HTTP proxy and Alpine Linux"
|
org.opencontainers.image.description="VPN swiss-knife like client to tunnel to multiple VPN servers using OpenVPN, IPtables, DNS over TLS, Shadowsocks, an HTTP proxy and Alpine Linux"
|
||||||
ENV VPNSP=pia \
|
ENV VPNSP=pia \
|
||||||
VERSION_INFORMATION=on \
|
VERSION_INFORMATION=on \
|
||||||
|
LOG_LEVEL=info \
|
||||||
|
VPN_TYPE=openvpn \
|
||||||
PROTOCOL=udp \
|
PROTOCOL=udp \
|
||||||
OPENVPN_VERSION=2.5 \
|
OPENVPN_VERSION=2.5 \
|
||||||
OPENVPN_VERBOSITY=1 \
|
OPENVPN_VERBOSITY=1 \
|
||||||
@@ -76,6 +78,12 @@ ENV VPNSP=pia \
|
|||||||
OPENVPN_TARGET_IP= \
|
OPENVPN_TARGET_IP= \
|
||||||
OPENVPN_IPV6=off \
|
OPENVPN_IPV6=off \
|
||||||
OPENVPN_CUSTOM_CONFIG= \
|
OPENVPN_CUSTOM_CONFIG= \
|
||||||
|
OPENVPN_INTERFACE=tun0 \
|
||||||
|
WIREGUARD_PRIVATE_KEY= \
|
||||||
|
WIREGUARD_PRESHARED_KEY= \
|
||||||
|
WIREGUARD_ADDRESS= \
|
||||||
|
WIREGUARD_PORT= \
|
||||||
|
WIREGUARD_INTERFACE=wg0 \
|
||||||
TZ= \
|
TZ= \
|
||||||
PUID= \
|
PUID= \
|
||||||
PGID= \
|
PGID= \
|
||||||
@@ -147,10 +155,10 @@ ENV VPNSP=pia \
|
|||||||
# Shadowsocks
|
# Shadowsocks
|
||||||
SHADOWSOCKS=off \
|
SHADOWSOCKS=off \
|
||||||
SHADOWSOCKS_LOG=off \
|
SHADOWSOCKS_LOG=off \
|
||||||
SHADOWSOCKS_PORT=8388 \
|
SHADOWSOCKS_ADDRESS=":8388" \
|
||||||
SHADOWSOCKS_PASSWORD= \
|
SHADOWSOCKS_PASSWORD= \
|
||||||
SHADOWSOCKS_PASSWORD_SECRETFILE=/run/secrets/shadowsocks_password \
|
SHADOWSOCKS_PASSWORD_SECRETFILE=/run/secrets/shadowsocks_password \
|
||||||
SHADOWSOCKS_METHOD=chacha20-ietf-poly1305 \
|
SHADOWSOCKS_CIPHER=chacha20-ietf-poly1305 \
|
||||||
UPDATER_PERIOD=0
|
UPDATER_PERIOD=0
|
||||||
ENTRYPOINT ["/entrypoint"]
|
ENTRYPOINT ["/entrypoint"]
|
||||||
EXPOSE 8000/tcp 8888/tcp 8388/tcp 8388/udp
|
EXPOSE 8000/tcp 8888/tcp 8388/tcp 8388/udp
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ HideMyAss, IPVanish, IVPN, Mullvad, NordVPN, Privado, Private Internet Access, P
|
|||||||
ProtonVPN, PureVPN, Surfshark, TorGuard, VPNUnlimited, VyprVPN and Windscribe VPN servers
|
ProtonVPN, PureVPN, Surfshark, TorGuard, VPNUnlimited, VyprVPN and Windscribe VPN servers
|
||||||
using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
|
using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
|
||||||
|
|
||||||
**ANNOUNCEMENT**:
|
**ANNOUNCEMENT**: Wireguard is now supported for all providers supporting it!
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -55,9 +55,10 @@ using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Based on Alpine 3.13 for a small Docker image of 54MB
|
- Based on Alpine 3.14 for a small Docker image of 31MB
|
||||||
- Supports: **Cyberghost**, **FastestVPN**, **HideMyAss**, **IPVanish**, **IVPN**, **Mullvad**, **NordVPN**, **Privado**, **Private Internet Access**, **PrivateVPN**, **ProtonVPN**, **PureVPN**, **Surfshark**, **TorGuard**, **VPNUnlimited**, **Vyprvpn**, **Windscribe** servers
|
- Supports: **Cyberghost**, **FastestVPN**, **HideMyAss**, **IPVanish**, **IVPN**, **Mullvad**, **NordVPN**, **Privado**, **Private Internet Access**, **PrivateVPN**, **ProtonVPN**, **PureVPN**, **Surfshark**, **TorGuard**, **VPNUnlimited**, **Vyprvpn**, **Windscribe** servers
|
||||||
- Supports Openvpn only for now
|
- Supports OpenVPN
|
||||||
|
- Supports Wireguard for **Mullvad**, **Ivpn** and **Windscribe** (more in progress, see #134)
|
||||||
- DNS over TLS baked in with service provider(s) of your choice
|
- DNS over TLS baked in with service provider(s) of your choice
|
||||||
- DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses, with live update every 24 hours
|
- DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses, with live update every 24 hours
|
||||||
- Choose the vpn network protocol, `udp` or `tcp`
|
- Choose the vpn network protocol, `udp` or `tcp`
|
||||||
@@ -110,6 +111,7 @@ The following points are all optional but should give you insights on all the po
|
|||||||
|
|
||||||
- [Test your setup](https://github.com/qdm12/gluetun/wiki/Test-your-setup)
|
- [Test your setup](https://github.com/qdm12/gluetun/wiki/Test-your-setup)
|
||||||
- [How to connect other containers and devices to Gluetun](https://github.com/qdm12/gluetun/wiki/Connect-to-gluetun)
|
- [How to connect other containers and devices to Gluetun](https://github.com/qdm12/gluetun/wiki/Connect-to-gluetun)
|
||||||
|
- [How to use Wireguard](https://github.com/qdm12/gluetun/wiki/Wireguard)
|
||||||
- [VPN server side port forwarding](https://github.com/qdm12/gluetun/wiki/Port-forwarding)
|
- [VPN server side port forwarding](https://github.com/qdm12/gluetun/wiki/Port-forwarding)
|
||||||
- [HTTP control server](https://github.com/qdm12/gluetun/wiki/HTTP-Control-server) to automate things, restart Openvpn etc.
|
- [HTTP control server](https://github.com/qdm12/gluetun/wiki/HTTP-Control-server) to automate things, restart Openvpn etc.
|
||||||
- Update the image with `docker pull qmcgaw/gluetun:latest`. See this [Wiki document](https://github.com/qdm12/gluetun/wiki/Docker-image-tags) for Docker tags available.
|
- Update the image with `docker pull qmcgaw/gluetun:latest`. See this [Wiki document](https://github.com/qdm12/gluetun/wiki/Docker-image-tags) for Docker tags available.
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
@@ -23,15 +22,17 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/healthcheck"
|
"github.com/qdm12/gluetun/internal/healthcheck"
|
||||||
"github.com/qdm12/gluetun/internal/httpproxy"
|
"github.com/qdm12/gluetun/internal/httpproxy"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/gluetun/internal/netlink"
|
||||||
"github.com/qdm12/gluetun/internal/openvpn"
|
"github.com/qdm12/gluetun/internal/openvpn"
|
||||||
|
"github.com/qdm12/gluetun/internal/portforward"
|
||||||
"github.com/qdm12/gluetun/internal/publicip"
|
"github.com/qdm12/gluetun/internal/publicip"
|
||||||
"github.com/qdm12/gluetun/internal/routing"
|
"github.com/qdm12/gluetun/internal/routing"
|
||||||
"github.com/qdm12/gluetun/internal/server"
|
"github.com/qdm12/gluetun/internal/server"
|
||||||
"github.com/qdm12/gluetun/internal/shadowsocks"
|
"github.com/qdm12/gluetun/internal/shadowsocks"
|
||||||
"github.com/qdm12/gluetun/internal/storage"
|
"github.com/qdm12/gluetun/internal/storage"
|
||||||
"github.com/qdm12/gluetun/internal/unix"
|
"github.com/qdm12/gluetun/internal/tun"
|
||||||
"github.com/qdm12/gluetun/internal/updater"
|
"github.com/qdm12/gluetun/internal/updater"
|
||||||
versionpkg "github.com/qdm12/gluetun/internal/version"
|
"github.com/qdm12/gluetun/internal/vpn"
|
||||||
"github.com/qdm12/golibs/command"
|
"github.com/qdm12/golibs/command"
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/params"
|
"github.com/qdm12/golibs/params"
|
||||||
@@ -59,29 +60,32 @@ func main() {
|
|||||||
Created: created,
|
Created: created,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
background := context.Background()
|
||||||
ctx, stop := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
|
signalCtx, stop := signal.NotifyContext(background, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(background)
|
||||||
|
|
||||||
logger := logging.NewParent(logging.Settings{
|
logger := logging.New(logging.Settings{
|
||||||
Level: logging.LevelInfo,
|
Level: logging.LevelInfo,
|
||||||
})
|
})
|
||||||
|
|
||||||
args := os.Args
|
args := os.Args
|
||||||
unix := unix.New()
|
tun := tun.New()
|
||||||
|
netLinker := netlink.New()
|
||||||
cli := cli.New()
|
cli := cli.New()
|
||||||
env := params.NewEnv()
|
env := params.New()
|
||||||
cmder := command.NewCmder()
|
cmder := command.NewCmder()
|
||||||
|
|
||||||
errorCh := make(chan error)
|
errorCh := make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
errorCh <- _main(ctx, buildInfo, args, logger, env, unix, cmder, cli)
|
errorCh <- _main(ctx, buildInfo, args, logger, env, tun, netLinker, cmder, cli)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-signalCtx.Done():
|
||||||
stop()
|
stop()
|
||||||
|
fmt.Println("")
|
||||||
logger.Warn("Caught OS signal, shutting down")
|
logger.Warn("Caught OS signal, shutting down")
|
||||||
|
cancel()
|
||||||
case err := <-errorCh:
|
case err := <-errorCh:
|
||||||
stop()
|
stop()
|
||||||
close(errorCh)
|
close(errorCh)
|
||||||
@@ -113,8 +117,9 @@ var (
|
|||||||
|
|
||||||
//nolint:gocognit,gocyclo
|
//nolint:gocognit,gocyclo
|
||||||
func _main(ctx context.Context, buildInfo models.BuildInformation,
|
func _main(ctx context.Context, buildInfo models.BuildInformation,
|
||||||
args []string, logger logging.ParentLogger, env params.Env,
|
args []string, logger logging.ParentLogger, env params.Interface,
|
||||||
unix unix.Unix, cmder command.RunStarter, cli cli.CLIer) error {
|
tun tun.Interface, netLinker netlink.NetLinker, cmder command.RunStarter,
|
||||||
|
cli cli.CLIer) error {
|
||||||
if len(args) > 1 { // cli operation
|
if len(args) > 1 { // cli operation
|
||||||
switch args[1] {
|
switch args[1] {
|
||||||
case "healthcheck":
|
case "healthcheck":
|
||||||
@@ -122,7 +127,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
case "clientkey":
|
case "clientkey":
|
||||||
return cli.ClientKey(args[2:])
|
return cli.ClientKey(args[2:])
|
||||||
case "openvpnconfig":
|
case "openvpnconfig":
|
||||||
return cli.OpenvpnConfig(logger)
|
return cli.OpenvpnConfig(logger, env)
|
||||||
case "update":
|
case "update":
|
||||||
return cli.Update(ctx, args[2:], logger)
|
return cli.Update(ctx, args[2:], logger)
|
||||||
default:
|
default:
|
||||||
@@ -130,19 +135,37 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO run this in a loop or in openvpn to reload from file without restarting
|
||||||
|
storageLogger := logger.NewChild(logging.Settings{Prefix: "storage: "})
|
||||||
|
storage, err := storage.New(storageLogger, constants.ServersData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
allServers := storage.GetServers()
|
||||||
|
|
||||||
|
var allSettings configuration.Settings
|
||||||
|
err = allSettings.Read(env, allServers,
|
||||||
|
logger.NewChild(logging.Settings{Prefix: "configuration: "}))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.PatchLevel(allSettings.Log.Level)
|
||||||
|
|
||||||
|
puid, pgid := allSettings.System.PUID, allSettings.System.PGID
|
||||||
|
|
||||||
const clientTimeout = 15 * time.Second
|
const clientTimeout = 15 * time.Second
|
||||||
httpClient := &http.Client{Timeout: clientTimeout}
|
httpClient := &http.Client{Timeout: clientTimeout}
|
||||||
// Create configurators
|
// Create configurators
|
||||||
alpineConf := alpine.New()
|
alpineConf := alpine.New()
|
||||||
ovpnConf := openvpn.NewConfigurator(
|
ovpnConf := openvpn.New(
|
||||||
logger.NewChild(logging.Settings{Prefix: "openvpn configurator: "}),
|
logger.NewChild(logging.Settings{Prefix: "openvpn configurator: "}),
|
||||||
unix, cmder)
|
cmder, puid, pgid)
|
||||||
dnsCrypto := dnscrypto.New(httpClient, "", "")
|
dnsCrypto := dnscrypto.New(httpClient, "", "")
|
||||||
const cacertsPath = "/etc/ssl/certs/ca-certificates.crt"
|
const cacertsPath = "/etc/ssl/certs/ca-certificates.crt"
|
||||||
dnsConf := unbound.NewConfigurator(nil, cmder, dnsCrypto,
|
dnsConf := unbound.NewConfigurator(nil, cmder, dnsCrypto,
|
||||||
"/etc/unbound", "/usr/sbin/unbound", cacertsPath)
|
"/etc/unbound", "/usr/sbin/unbound", cacertsPath)
|
||||||
|
|
||||||
announcementExp, err := time.Parse(time.RFC3339, "2021-07-22T00:00:00Z")
|
announcementExp, err := time.Parse(time.RFC3339, "2021-10-02T00:00:00Z")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -153,7 +176,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
Version: buildInfo.Version,
|
Version: buildInfo.Version,
|
||||||
Commit: buildInfo.Commit,
|
Commit: buildInfo.Commit,
|
||||||
BuildDate: buildInfo.Created,
|
BuildDate: buildInfo.Created,
|
||||||
Announcement: "",
|
Announcement: "Wireguard is now supported for Mullvad, IVPN and Windscribe!",
|
||||||
AnnounceExp: announcementExp,
|
AnnounceExp: announcementExp,
|
||||||
// Sponsor information
|
// Sponsor information
|
||||||
PaypalUser: "qmcgaw",
|
PaypalUser: "qmcgaw",
|
||||||
@@ -176,12 +199,6 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var allSettings configuration.Settings
|
|
||||||
err = allSettings.Read(env,
|
|
||||||
logger.NewChild(logging.Settings{Prefix: "configuration: "}))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
logger.Info(allSettings.String())
|
logger.Info(allSettings.String())
|
||||||
|
|
||||||
if err := os.MkdirAll("/tmp/gluetun", 0644); err != nil {
|
if err := os.MkdirAll("/tmp/gluetun", 0644); err != nil {
|
||||||
@@ -191,18 +208,6 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO run this in a loop or in openvpn to reload from file without restarting
|
|
||||||
storage := storage.New(
|
|
||||||
logger.NewChild(logging.Settings{Prefix: "storage: "}),
|
|
||||||
constants.ServersData)
|
|
||||||
allServers, err := storage.SyncServers(constants.GetAllServers())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should never change
|
|
||||||
puid, pgid := allSettings.System.PUID, allSettings.System.PGID
|
|
||||||
|
|
||||||
const defaultUsername = "nonrootuser"
|
const defaultUsername = "nonrootuser"
|
||||||
nonRootUsername, err := alpineConf.CreateUser(defaultUsername, puid)
|
nonRootUsername, err := alpineConf.CreateUser(defaultUsername, puid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -214,12 +219,13 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
// set it for Unbound
|
// set it for Unbound
|
||||||
// TODO remove this when migrating to qdm12/dns v2
|
// TODO remove this when migrating to qdm12/dns v2
|
||||||
allSettings.DNS.Unbound.Username = nonRootUsername
|
allSettings.DNS.Unbound.Username = nonRootUsername
|
||||||
|
allSettings.VPN.OpenVPN.ProcUser = nonRootUsername
|
||||||
|
|
||||||
if err := os.Chown("/etc/unbound", puid, pgid); err != nil {
|
if err := os.Chown("/etc/unbound", puid, pgid); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
firewallLogLevel := logging.LevelInfo
|
firewallLogLevel := allSettings.Log.Level
|
||||||
if allSettings.Firewall.Debug {
|
if allSettings.Firewall.Debug {
|
||||||
firewallLogLevel = logging.LevelDebug
|
firewallLogLevel = logging.LevelDebug
|
||||||
}
|
}
|
||||||
@@ -227,7 +233,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
Prefix: "routing: ",
|
Prefix: "routing: ",
|
||||||
Level: firewallLogLevel,
|
Level: firewallLogLevel,
|
||||||
})
|
})
|
||||||
routingConf := routing.NewRouting(routingLogger)
|
routingConf := routing.New(netLinker, routingLogger)
|
||||||
|
|
||||||
defaultInterface, defaultGateway, err := routingConf.DefaultRoute()
|
defaultInterface, defaultGateway, err := routingConf.DefaultRoute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -271,17 +277,14 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ovpnConf.CheckTUN(); err != nil {
|
if err := tun.Check(constants.TunnelDevice); err != nil {
|
||||||
logger.Warn(err.Error())
|
logger.Info(err.Error() + "; creating it...")
|
||||||
err = ovpnConf.CreateTUN()
|
err = tun.Create(constants.TunnelDevice)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tunnelReadyCh := make(chan struct{})
|
|
||||||
defer close(tunnelReadyCh)
|
|
||||||
|
|
||||||
if allSettings.Firewall.Enabled {
|
if allSettings.Firewall.Enabled {
|
||||||
err := firewallConf.SetEnabled(ctx, true) // disabled by default
|
err := firewallConf.SetEnabled(ctx, true) // disabled by default
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -290,7 +293,8 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, vpnPort := range allSettings.Firewall.VPNInputPorts {
|
for _, vpnPort := range allSettings.Firewall.VPNInputPorts {
|
||||||
err = firewallConf.SetAllowedPort(ctx, vpnPort, string(constants.TUN))
|
vpnIntf := allSettings.VPN.VPNInterface()
|
||||||
|
err = firewallConf.SetAllowedPort(ctx, vpnPort, vpnIntf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -321,21 +325,12 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
tickersGroupHandler := goshutdown.NewGroupHandler("tickers", defaultGroupSettings)
|
tickersGroupHandler := goshutdown.NewGroupHandler("tickers", defaultGroupSettings)
|
||||||
otherGroupHandler := goshutdown.NewGroupHandler("other", defaultGroupSettings)
|
otherGroupHandler := goshutdown.NewGroupHandler("other", defaultGroupSettings)
|
||||||
|
|
||||||
openvpnLooper := openvpn.NewLoop(allSettings.OpenVPN, nonRootUsername, puid, pgid, allServers,
|
portForwardLogger := logger.NewChild(logging.Settings{Prefix: "port forwarding: "})
|
||||||
ovpnConf, firewallConf, logger, httpClient, tunnelReadyCh)
|
portForwardLooper := portforward.NewLoop(allSettings.VPN.Provider.PortForwarding,
|
||||||
openvpnHandler, openvpnCtx, openvpnDone := goshutdown.NewGoRoutineHandler(
|
httpClient, firewallConf, portForwardLogger)
|
||||||
"openvpn", goshutdown.GoRoutineSettings{Timeout: time.Second})
|
portForwardHandler, portForwardCtx, portForwardDone := goshutdown.NewGoRoutineHandler(
|
||||||
// wait for restartOpenvpn
|
"port forwarding", goshutdown.GoRoutineSettings{Timeout: time.Second})
|
||||||
go openvpnLooper.Run(openvpnCtx, openvpnDone)
|
go portForwardLooper.Run(portForwardCtx, portForwardDone)
|
||||||
|
|
||||||
updaterLooper := updater.NewLooper(allSettings.Updater,
|
|
||||||
allServers, storage, openvpnLooper.SetServers, httpClient,
|
|
||||||
logger.NewChild(logging.Settings{Prefix: "updater: "}))
|
|
||||||
updaterHandler, updaterCtx, updaterDone := goshutdown.NewGoRoutineHandler(
|
|
||||||
"updater", defaultGoRoutineSettings)
|
|
||||||
// wait for updaterLooper.Restart() or its ticket launched with RunRestartTicker
|
|
||||||
go updaterLooper.Run(updaterCtx, updaterDone)
|
|
||||||
tickersGroupHandler.Add(updaterHandler)
|
|
||||||
|
|
||||||
unboundLogger := logger.NewChild(logging.Settings{Prefix: "dns over tls: "})
|
unboundLogger := logger.NewChild(logging.Settings{Prefix: "dns over tls: "})
|
||||||
unboundLooper := dns.NewLoop(dnsConf, allSettings.DNS, httpClient,
|
unboundLooper := dns.NewLoop(dnsConf, allSettings.DNS, httpClient,
|
||||||
@@ -346,6 +341,11 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
go unboundLooper.Run(dnsCtx, dnsDone)
|
go unboundLooper.Run(dnsCtx, dnsDone)
|
||||||
otherGroupHandler.Add(dnsHandler)
|
otherGroupHandler.Add(dnsHandler)
|
||||||
|
|
||||||
|
dnsTickerHandler, dnsTickerCtx, dnsTickerDone := goshutdown.NewGoRoutineHandler(
|
||||||
|
"dns ticker", defaultGoRoutineSettings)
|
||||||
|
go unboundLooper.RunRestartTicker(dnsTickerCtx, dnsTickerDone)
|
||||||
|
controlGroupHandler.Add(dnsTickerHandler)
|
||||||
|
|
||||||
publicIPLooper := publicip.NewLoop(httpClient,
|
publicIPLooper := publicip.NewLoop(httpClient,
|
||||||
logger.NewChild(logging.Settings{Prefix: "ip getter: "}),
|
logger.NewChild(logging.Settings{Prefix: "ip getter: "}),
|
||||||
allSettings.PublicIP, puid, pgid)
|
allSettings.PublicIP, puid, pgid)
|
||||||
@@ -359,6 +359,29 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
go publicIPLooper.RunRestartTicker(pubIPTickerCtx, pubIPTickerDone)
|
go publicIPLooper.RunRestartTicker(pubIPTickerCtx, pubIPTickerDone)
|
||||||
tickersGroupHandler.Add(pubIPTickerHandler)
|
tickersGroupHandler.Add(pubIPTickerHandler)
|
||||||
|
|
||||||
|
vpnLogger := logger.NewChild(logging.Settings{Prefix: "vpn: "})
|
||||||
|
vpnLooper := vpn.NewLoop(allSettings.VPN,
|
||||||
|
allServers, ovpnConf, netLinker, firewallConf, routingConf, portForwardLooper,
|
||||||
|
cmder, publicIPLooper, unboundLooper, vpnLogger, httpClient,
|
||||||
|
buildInfo, allSettings.VersionInformation)
|
||||||
|
vpnHandler, vpnCtx, vpnDone := goshutdown.NewGoRoutineHandler(
|
||||||
|
"vpn", goshutdown.GoRoutineSettings{Timeout: time.Second})
|
||||||
|
go vpnLooper.Run(vpnCtx, vpnDone)
|
||||||
|
|
||||||
|
updaterLooper := updater.NewLooper(allSettings.Updater,
|
||||||
|
allServers, storage, vpnLooper.SetServers, httpClient,
|
||||||
|
logger.NewChild(logging.Settings{Prefix: "updater: "}))
|
||||||
|
updaterHandler, updaterCtx, updaterDone := goshutdown.NewGoRoutineHandler(
|
||||||
|
"updater", defaultGoRoutineSettings)
|
||||||
|
// wait for updaterLooper.Restart() or its ticket launched with RunRestartTicker
|
||||||
|
go updaterLooper.Run(updaterCtx, updaterDone)
|
||||||
|
tickersGroupHandler.Add(updaterHandler)
|
||||||
|
|
||||||
|
updaterTickerHandler, updaterTickerCtx, updaterTickerDone := goshutdown.NewGoRoutineHandler(
|
||||||
|
"updater ticker", defaultGoRoutineSettings)
|
||||||
|
go updaterLooper.RunRestartTicker(updaterTickerCtx, updaterTickerDone)
|
||||||
|
controlGroupHandler.Add(updaterTickerHandler)
|
||||||
|
|
||||||
httpProxyLooper := httpproxy.NewLoop(
|
httpProxyLooper := httpproxy.NewLoop(
|
||||||
logger.NewChild(logging.Settings{Prefix: "http proxy: "}),
|
logger.NewChild(logging.Settings{Prefix: "http proxy: "}),
|
||||||
allSettings.HTTPProxy)
|
allSettings.HTTPProxy)
|
||||||
@@ -374,26 +397,18 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
go shadowsocksLooper.Run(shadowsocksCtx, shadowsocksDone)
|
go shadowsocksLooper.Run(shadowsocksCtx, shadowsocksDone)
|
||||||
otherGroupHandler.Add(shadowsocksHandler)
|
otherGroupHandler.Add(shadowsocksHandler)
|
||||||
|
|
||||||
eventsRoutingHandler, eventsRoutingCtx, eventsRoutingDone := goshutdown.NewGoRoutineHandler(
|
|
||||||
"events routing", defaultGoRoutineSettings)
|
|
||||||
go routeReadyEvents(eventsRoutingCtx, eventsRoutingDone, buildInfo, tunnelReadyCh,
|
|
||||||
unboundLooper, updaterLooper, publicIPLooper, routingConf, logger, httpClient,
|
|
||||||
allSettings.VersionInformation, allSettings.OpenVPN.Provider.PortForwarding.Enabled, openvpnLooper.PortForward,
|
|
||||||
)
|
|
||||||
controlGroupHandler.Add(eventsRoutingHandler)
|
|
||||||
|
|
||||||
controlServerAddress := ":" + strconv.Itoa(int(allSettings.ControlServer.Port))
|
controlServerAddress := ":" + strconv.Itoa(int(allSettings.ControlServer.Port))
|
||||||
controlServerLogging := allSettings.ControlServer.Log
|
controlServerLogging := allSettings.ControlServer.Log
|
||||||
httpServerHandler, httpServerCtx, httpServerDone := goshutdown.NewGoRoutineHandler(
|
httpServerHandler, httpServerCtx, httpServerDone := goshutdown.NewGoRoutineHandler(
|
||||||
"http server", defaultGoRoutineSettings)
|
"http server", defaultGoRoutineSettings)
|
||||||
httpServer := server.New(httpServerCtx, controlServerAddress, controlServerLogging,
|
httpServer := server.New(httpServerCtx, controlServerAddress, controlServerLogging,
|
||||||
logger.NewChild(logging.Settings{Prefix: "http server: "}),
|
logger.NewChild(logging.Settings{Prefix: "http server: "}),
|
||||||
buildInfo, openvpnLooper, unboundLooper, updaterLooper, publicIPLooper)
|
buildInfo, vpnLooper, portForwardLooper, unboundLooper, updaterLooper, publicIPLooper)
|
||||||
go httpServer.Run(httpServerCtx, httpServerDone)
|
go httpServer.Run(httpServerCtx, httpServerDone)
|
||||||
controlGroupHandler.Add(httpServerHandler)
|
controlGroupHandler.Add(httpServerHandler)
|
||||||
|
|
||||||
healthLogger := logger.NewChild(logging.Settings{Prefix: "healthcheck: "})
|
healthLogger := logger.NewChild(logging.Settings{Prefix: "healthcheck: "})
|
||||||
healthcheckServer := healthcheck.NewServer(allSettings.Health, healthLogger, openvpnLooper)
|
healthcheckServer := healthcheck.NewServer(allSettings.Health, healthLogger, vpnLooper)
|
||||||
healthServerHandler, healthServerCtx, healthServerDone := goshutdown.NewGoRoutineHandler(
|
healthServerHandler, healthServerCtx, healthServerDone := goshutdown.NewGoRoutineHandler(
|
||||||
"HTTP health server", defaultGoRoutineSettings)
|
"HTTP health server", defaultGoRoutineSettings)
|
||||||
go healthcheckServer.Run(healthServerCtx, healthServerDone)
|
go healthcheckServer.Run(healthServerCtx, healthServerDone)
|
||||||
@@ -406,21 +421,14 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
}
|
}
|
||||||
orderHandler := goshutdown.NewOrder("gluetun", orderSettings)
|
orderHandler := goshutdown.NewOrder("gluetun", orderSettings)
|
||||||
orderHandler.Append(controlGroupHandler, tickersGroupHandler, healthServerHandler,
|
orderHandler.Append(controlGroupHandler, tickersGroupHandler, healthServerHandler,
|
||||||
openvpnHandler, otherGroupHandler)
|
vpnHandler, portForwardHandler, otherGroupHandler)
|
||||||
|
|
||||||
// Start openvpn for the first time in a blocking call
|
// Start VPN for the first time in a blocking call
|
||||||
// until openvpn is launched
|
// until the VPN is launched
|
||||||
_, _ = openvpnLooper.ApplyStatus(ctx, constants.Running) // TODO option to disable with variable
|
_, _ = vpnLooper.ApplyStatus(ctx, constants.Running) // TODO option to disable with variable
|
||||||
|
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
|
|
||||||
if allSettings.OpenVPN.Provider.PortForwarding.Enabled {
|
|
||||||
logger.Info("Clearing forwarded port status file " + allSettings.OpenVPN.Provider.PortForwarding.Filepath)
|
|
||||||
if err := os.Remove(allSettings.OpenVPN.Provider.PortForwarding.Filepath); err != nil {
|
|
||||||
logger.Error(err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return orderHandler.Shutdown(context.Background())
|
return orderHandler.Shutdown(context.Background())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,73 +453,3 @@ func printVersions(ctx context.Context, logger logging.Logger,
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func routeReadyEvents(ctx context.Context, done chan<- struct{}, buildInfo models.BuildInformation,
|
|
||||||
tunnelReadyCh <-chan struct{},
|
|
||||||
unboundLooper dns.Looper, updaterLooper updater.Looper, publicIPLooper publicip.Looper,
|
|
||||||
routing routing.VPNGetter, logger logging.Logger, httpClient *http.Client,
|
|
||||||
versionInformation, portForwardingEnabled bool, startPortForward func(vpnGateway net.IP)) {
|
|
||||||
defer close(done)
|
|
||||||
|
|
||||||
// for linters only
|
|
||||||
var restartTickerContext context.Context
|
|
||||||
var restartTickerCancel context.CancelFunc = func() {}
|
|
||||||
|
|
||||||
unboundTickerDone := make(chan struct{})
|
|
||||||
close(unboundTickerDone)
|
|
||||||
updaterTickerDone := make(chan struct{})
|
|
||||||
close(updaterTickerDone)
|
|
||||||
|
|
||||||
first := true
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
restartTickerCancel() // for linters only
|
|
||||||
<-unboundTickerDone
|
|
||||||
<-updaterTickerDone
|
|
||||||
return
|
|
||||||
case <-tunnelReadyCh: // blocks until openvpn is connected
|
|
||||||
vpnDestination, err := routing.VPNDestinationIP()
|
|
||||||
if err != nil {
|
|
||||||
logger.Warn(err.Error())
|
|
||||||
} else {
|
|
||||||
logger.Info("VPN routing IP address: " + vpnDestination.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
if unboundLooper.GetSettings().Enabled {
|
|
||||||
_, _ = unboundLooper.ApplyStatus(ctx, constants.Running)
|
|
||||||
}
|
|
||||||
|
|
||||||
restartTickerCancel() // stop previous restart tickers
|
|
||||||
<-unboundTickerDone
|
|
||||||
<-updaterTickerDone
|
|
||||||
restartTickerContext, restartTickerCancel = context.WithCancel(ctx)
|
|
||||||
|
|
||||||
// Runs the Public IP getter job once
|
|
||||||
_, _ = publicIPLooper.ApplyStatus(ctx, constants.Running)
|
|
||||||
if versionInformation && first {
|
|
||||||
first = false
|
|
||||||
message, err := versionpkg.GetMessage(ctx, buildInfo, httpClient)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("cannot get version information: " + err.Error())
|
|
||||||
} else {
|
|
||||||
logger.Info(message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unboundTickerDone = make(chan struct{})
|
|
||||||
updaterTickerDone = make(chan struct{})
|
|
||||||
go unboundLooper.RunRestartTicker(restartTickerContext, unboundTickerDone)
|
|
||||||
go updaterLooper.RunRestartTicker(restartTickerContext, updaterTickerDone)
|
|
||||||
if portForwardingEnabled {
|
|
||||||
// vpnGateway required only for PIA
|
|
||||||
vpnGateway, err := routing.VPNLocalGatewayIP()
|
|
||||||
if err != nil {
|
|
||||||
logger.Error("cannot get VPN local gateway IP: " + err.Error())
|
|
||||||
}
|
|
||||||
logger.Info("VPN gateway IP address: " + vpnGateway.String())
|
|
||||||
startPortForward(vpnGateway)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -15,10 +15,11 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- /yourpath:/gluetun
|
- /yourpath:/gluetun
|
||||||
environment:
|
environment:
|
||||||
# More variables are available, see the readme table
|
# More variables are available, see the Wiki table
|
||||||
- OPENVPN_USER=
|
- OPENVPN_USER=
|
||||||
- OPENVPN_PASSWORD=
|
- OPENVPN_PASSWORD=
|
||||||
- VPNSP=private internet access
|
- VPNSP=private internet access
|
||||||
|
- VPN_TYPE=openvpn
|
||||||
# Timezone for accurate logs times
|
# Timezone for accurate logs times
|
||||||
- TZ=
|
- TZ=
|
||||||
restart: always
|
restart: always
|
||||||
|
|||||||
28
go.mod
28
go.mod
@@ -1,18 +1,40 @@
|
|||||||
module github.com/qdm12/gluetun
|
module github.com/qdm12/gluetun
|
||||||
|
|
||||||
go 1.16
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/fatih/color v1.12.0
|
github.com/fatih/color v1.12.0
|
||||||
github.com/golang/mock v1.6.0
|
github.com/golang/mock v1.6.0
|
||||||
github.com/qdm12/dns v1.11.0
|
github.com/qdm12/dns v1.11.0
|
||||||
github.com/qdm12/golibs v0.0.0-20210723175634-a75ca7fd74c2
|
github.com/qdm12/golibs v0.0.0-20210822203818-5c568b0777b6
|
||||||
github.com/qdm12/goshutdown v0.1.0
|
github.com/qdm12/goshutdown v0.1.0
|
||||||
github.com/qdm12/gosplash v0.1.0
|
github.com/qdm12/gosplash v0.1.0
|
||||||
github.com/qdm12/ss-server v0.2.0
|
github.com/qdm12/ss-server v0.3.0
|
||||||
github.com/qdm12/updated v0.0.0-20210603204757-205acfe6937e
|
github.com/qdm12/updated v0.0.0-20210603204757-205acfe6937e
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/vishvananda/netlink v1.1.0
|
github.com/vishvananda/netlink v1.1.0
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
|
||||||
|
golang.zx2c4.com/wireguard v0.0.0-20210805125648-3957e9b9dd19
|
||||||
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c
|
||||||
inet.af/netaddr v0.0.0-20210718074554-06ca8145d722
|
inet.af/netaddr v0.0.0-20210718074554-06ca8145d722
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/google/go-cmp v0.5.5 // indirect
|
||||||
|
github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||||
|
github.com/mdlayher/genetlink v1.0.0 // indirect
|
||||||
|
github.com/mdlayher/netlink v1.4.0 // indirect
|
||||||
|
github.com/miekg/dns v1.1.40 // indirect
|
||||||
|
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||||
|
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect
|
||||||
|
go4.org/intern v0.0.0-20210108033219-3eb7198706b2 // indirect
|
||||||
|
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063 // 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.0-20200313102051-9f266ea9e77c // indirect
|
||||||
|
)
|
||||||
|
|||||||
80
go.sum
80
go.sum
@@ -33,11 +33,28 @@ github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3K
|
|||||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gotify/go-api-client/v2 v2.0.4/go.mod h1:VKiah/UK20bXsr0JObE1eBVLW44zbBouzjuri9iwjFU=
|
github.com/gotify/go-api-client/v2 v2.0.4/go.mod h1:VKiah/UK20bXsr0JObE1eBVLW44zbBouzjuri9iwjFU=
|
||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
|
github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 h1:uhL5Gw7BINiiPAo24A2sxkcDI0Jt/sqp1v5xQCniEFA=
|
||||||
|
github.com/josharian/native v0.0.0-20200817173448-b6b71def0850/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||||
|
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
|
||||||
|
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
|
||||||
|
github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
|
||||||
|
github.com/jsimonetti/rtnetlink v0.0.0-20201216134343-bde56ed16391/go.mod h1:cR77jAZG3Y3bsb8hF6fHJbFoyFukLFOkQ98S0pQz3xw=
|
||||||
|
github.com/jsimonetti/rtnetlink v0.0.0-20201220180245-69540ac93943/go.mod h1:z4c53zj6Eex712ROyh8WI0ihysb5j2ROyV42iNogmAs=
|
||||||
|
github.com/jsimonetti/rtnetlink v0.0.0-20210122163228-8d122574c736/go.mod h1:ZXpIyOK59ZnN7J0BV99cZUPmsqDRZ3eq5X+st7u/oSA=
|
||||||
|
github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b h1:c3NTyLNozICy8B4mlMXemD3z/gXgQzVXZS/HqT+i3do=
|
||||||
|
github.com/jsimonetti/rtnetlink v0.0.0-20210212075122-66c871082f2b/go.mod h1:8w9Rh8m+aHZIG69YPGGem1i5VzoyRC8nw2kA8B+ik5U=
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
@@ -51,8 +68,24 @@ github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ
|
|||||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
|
github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43 h1:WgyLFv10Ov49JAQI/ZLUkCZ7VJS3r74hwFIGXJsgZlY=
|
||||||
|
github.com/mdlayher/ethtool v0.0.0-20210210192532-2b88debcdd43/go.mod h1:+t7E0lkKfbBsebllff1xdTmyJt8lH37niI6kwFk9OTo=
|
||||||
|
github.com/mdlayher/genetlink v1.0.0 h1:OoHN1OdyEIkScEmRgxLEe2M9U8ClMytqA5niynLtfj0=
|
||||||
|
github.com/mdlayher/genetlink v1.0.0/go.mod h1:0rJ0h4itni50A86M2kHcgS85ttZazNt7a8H2a2cw0Gc=
|
||||||
|
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
|
||||||
|
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
|
||||||
|
github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
|
||||||
|
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
|
||||||
|
github.com/mdlayher/netlink v1.2.0/go.mod h1:kwVW1io0AZy9A1E2YYgaD4Cj+C+GPkU6klXCMzIJ9p8=
|
||||||
|
github.com/mdlayher/netlink v1.2.1/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
|
||||||
|
github.com/mdlayher/netlink v1.2.2-0.20210123213345-5cc92139ae3e/go.mod h1:bacnNlfhqHqqLo4WsYeXSqfyXkInQ9JneWI68v1KwSU=
|
||||||
|
github.com/mdlayher/netlink v1.3.0/go.mod h1:xK/BssKuwcRXHrtN04UBkwQ6dY9VviGGuriDdoPSWys=
|
||||||
|
github.com/mdlayher/netlink v1.4.0 h1:n3ARR+Fm0dDv37dj5wSWZXDKcy+U0zwcXS3zKMnSiT0=
|
||||||
|
github.com/mdlayher/netlink v1.4.0/go.mod h1:dRJi5IABcZpBD2A3D0Mv/AiX8I9uDEu5oGkAVrekmf8=
|
||||||
github.com/miekg/dns v1.1.40 h1:pyyPFfGMnciYUk/mXpKkVmeMQjfXqt3FAJ2hy7tPiLA=
|
github.com/miekg/dns v1.1.40 h1:pyyPFfGMnciYUk/mXpKkVmeMQjfXqt3FAJ2hy7tPiLA=
|
||||||
github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
github.com/miekg/dns v1.1.40/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||||
|
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE924+mUcZuXKLBHA35U7LN621Bws=
|
||||||
|
github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||||
@@ -66,14 +99,15 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
|||||||
github.com/qdm12/dns v1.11.0 h1:jpcD5DZXXQSQe5a263PL09ghukiIdptvXFOZvyKEm6Q=
|
github.com/qdm12/dns v1.11.0 h1:jpcD5DZXXQSQe5a263PL09ghukiIdptvXFOZvyKEm6Q=
|
||||||
github.com/qdm12/dns v1.11.0/go.mod h1:FmQsNOUcrrZ4UFzWAiED56AKXeNgaX3ySbmPwEfNjjE=
|
github.com/qdm12/dns v1.11.0/go.mod h1:FmQsNOUcrrZ4UFzWAiED56AKXeNgaX3ySbmPwEfNjjE=
|
||||||
github.com/qdm12/golibs v0.0.0-20210603202746-e5494e9c2ebb/go.mod h1:15RBzkun0i8XB7ADIoLJWp9ITRgsz3LroEI2FiOXLRg=
|
github.com/qdm12/golibs v0.0.0-20210603202746-e5494e9c2ebb/go.mod h1:15RBzkun0i8XB7ADIoLJWp9ITRgsz3LroEI2FiOXLRg=
|
||||||
github.com/qdm12/golibs v0.0.0-20210723175634-a75ca7fd74c2 h1:FMeOhe/bGloI0T5Wb6QB7/rfOqgFeI//UF/N/f7PUCI=
|
|
||||||
github.com/qdm12/golibs v0.0.0-20210723175634-a75ca7fd74c2/go.mod h1:6aRbg4Z/bTbm9JfxsGXfWKHi7zsOvPfUTK1S5HuAFKg=
|
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/goshutdown v0.1.0 h1:lmwnygdXtnr2pa6VqfR/bm8077/BnBef1+7CP96B7Sw=
|
github.com/qdm12/goshutdown v0.1.0 h1:lmwnygdXtnr2pa6VqfR/bm8077/BnBef1+7CP96B7Sw=
|
||||||
github.com/qdm12/goshutdown v0.1.0/go.mod h1:/LP3MWLqI+wGH/ijfaUG+RHzBbKXIiVKnrg5vXOCf6Q=
|
github.com/qdm12/goshutdown v0.1.0/go.mod h1:/LP3MWLqI+wGH/ijfaUG+RHzBbKXIiVKnrg5vXOCf6Q=
|
||||||
github.com/qdm12/gosplash v0.1.0 h1:Sfl+zIjFZFP7b0iqf2l5UkmEY97XBnaKkH3FNY6Gf7g=
|
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/gosplash v0.1.0/go.mod h1:+A3fWW4/rUeDXhY3ieBzwghKdnIPFJgD8K3qQkenJlw=
|
||||||
github.com/qdm12/ss-server v0.2.0 h1:+togLzeeLAJ68MD1JqOWvYi9rl9t/fx1Qh7wKzZhY1g=
|
github.com/qdm12/ss-server v0.3.0 h1:BfKv4OU6dYb2KcDMYpTc7LIuO2jB73g3JCzy988GrLI=
|
||||||
github.com/qdm12/ss-server v0.2.0/go.mod h1:+1bWO1EfWNvsGM5Cuep6vneChK2OHniqtAsED9Fh1y0=
|
github.com/qdm12/ss-server v0.3.0/go.mod h1:ug+nWfuzKw/h5fxL1B6e9/OhkVuWJX4i2V1Pf0pJU1o=
|
||||||
github.com/qdm12/updated v0.0.0-20210603204757-205acfe6937e h1:4q+uFLawkaQRq3yARYLsjJPZd2wYwxn4g6G/5v0xW1g=
|
github.com/qdm12/updated v0.0.0-20210603204757-205acfe6937e h1:4q+uFLawkaQRq3yARYLsjJPZd2wYwxn4g6G/5v0xW1g=
|
||||||
github.com/qdm12/updated v0.0.0-20210603204757-205acfe6937e/go.mod h1:UvJRGkZ9XL3/D7e7JiTTVLm1F3Cymd3/gFpD6frEpBo=
|
github.com/qdm12/updated v0.0.0-20210603204757-205acfe6937e/go.mod h1:UvJRGkZ9XL3/D7e7JiTTVLm1F3Cymd3/gFpD6frEpBo=
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg=
|
||||||
@@ -105,6 +139,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
|
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
@@ -112,38 +148,67 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
|||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
|
golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
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/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201118182958-a01c418693c7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210123111255-9b0068b26619/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210216163648-f7da38b97c65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210309040221-94ec62e08169/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210503173754-0981d6026fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
@@ -152,7 +217,14 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
|||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.zx2c4.com/wireguard v0.0.0-20210427022245-097af6e1351b/go.mod h1:a057zjmoc00UN7gVkaJt2sXVK523kMJcogDTEvPIasg=
|
||||||
|
golang.zx2c4.com/wireguard v0.0.0-20210805125648-3957e9b9dd19 h1:ab2jcw2W91Rz07eHAb8Lic7sFQKO0NhBftjv6m/gL/0=
|
||||||
|
golang.zx2c4.com/wireguard v0.0.0-20210805125648-3957e9b9dd19/go.mod h1:laHzsbfMhGSobUmruXWAyMKKHSqvIcrqZJMyHD+/3O8=
|
||||||
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c h1:ADNrRDI5NR23/TUCnEmlLZLt4u9DnZ2nwRkPrAcFvto=
|
||||||
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20210803171230-4253848d036c/go.mod h1:+1XihzyZUBJcSc5WO9SwNA7v26puQwOEDwanaxfNXPQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type HealthChecker interface {
|
type HealthChecker interface {
|
||||||
HealthCheck(ctx context.Context, env params.Env, logger logging.Logger) error
|
HealthCheck(ctx context.Context, env params.Interface, logger logging.Logger) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CLI) HealthCheck(ctx context.Context, env params.Env,
|
func (c *CLI) HealthCheck(ctx context.Context, env params.Interface,
|
||||||
logger logging.Logger) error {
|
logger logging.Logger) error {
|
||||||
// Extract the health server port from the configuration.
|
// Extract the health server port from the configuration.
|
||||||
config := configuration.Health{}
|
config := configuration.Health{}
|
||||||
|
|||||||
@@ -14,26 +14,27 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type OpenvpnConfigMaker interface {
|
type OpenvpnConfigMaker interface {
|
||||||
OpenvpnConfig(logger logging.Logger) error
|
OpenvpnConfig(logger logging.Logger, env params.Interface) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CLI) OpenvpnConfig(logger logging.Logger) error {
|
func (c *CLI) OpenvpnConfig(logger logging.Logger, env params.Interface) error {
|
||||||
|
storage, err := storage.New(logger, constants.ServersData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
allServers := storage.GetServers()
|
||||||
|
|
||||||
var allSettings configuration.Settings
|
var allSettings configuration.Settings
|
||||||
err := allSettings.Read(params.NewEnv(), logger)
|
err = allSettings.Read(env, allServers, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
allServers, err := storage.New(logger, constants.ServersData).
|
providerConf := provider.New(allSettings.VPN.Provider.Name, allServers, time.Now)
|
||||||
SyncServers(constants.GetAllServers())
|
connection, err := providerConf.GetConnection(allSettings.VPN.Provider.ServerSelection)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
providerConf := provider.New(allSettings.OpenVPN.Provider.Name, allServers, time.Now)
|
lines := providerConf.BuildConf(connection, allSettings.VPN.OpenVPN)
|
||||||
connection, err := providerConf.GetOpenVPNConnection(allSettings.OpenVPN.Provider.ServerSelection)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
lines := providerConf.BuildConf(connection, "nonroortuser", allSettings.OpenVPN)
|
|
||||||
fmt.Println(strings.Join(lines, "\n"))
|
fmt.Println(strings.Join(lines, "\n"))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
ErrModeUnspecified = errors.New("at least one of -enduser or -maintainers must be specified")
|
ErrModeUnspecified = errors.New("at least one of -enduser or -maintainers must be specified")
|
||||||
ErrSyncServers = errors.New("cannot sync hardcoded and persisted servers")
|
ErrNewStorage = errors.New("cannot create storage")
|
||||||
ErrUpdateServerInformation = errors.New("cannot update server information")
|
ErrUpdateServerInformation = errors.New("cannot update server information")
|
||||||
ErrWriteToFile = errors.New("cannot write updated information to file")
|
ErrWriteToFile = errors.New("cannot write updated information to file")
|
||||||
)
|
)
|
||||||
@@ -68,11 +68,13 @@ func (c *CLI) Update(ctx context.Context, args []string, logger logging.Logger)
|
|||||||
|
|
||||||
const clientTimeout = 10 * time.Second
|
const clientTimeout = 10 * time.Second
|
||||||
httpClient := &http.Client{Timeout: clientTimeout}
|
httpClient := &http.Client{Timeout: clientTimeout}
|
||||||
storage := storage.New(logger, constants.ServersData)
|
|
||||||
currentServers, err := storage.SyncServers(constants.GetAllServers())
|
storage, err := storage.New(logger, constants.ServersData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: %s", ErrSyncServers, err)
|
return fmt.Errorf("%w: %s", ErrNewStorage, err)
|
||||||
}
|
}
|
||||||
|
currentServers := storage.GetServers()
|
||||||
|
|
||||||
updater := updater.New(options, httpClient, currentServers, logger)
|
updater := updater.New(options, httpClient, currentServers, logger)
|
||||||
allServers, err := updater.UpdateServers(ctx)
|
allServers, err := updater.UpdateServers(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -4,69 +4,47 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/golibs/params"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *Provider) cyberghostLines() (lines []string) {
|
|
||||||
lines = append(lines, lastIndent+"Server group: "+settings.ServerSelection.Group)
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Regions) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Hostnames) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
|
||||||
}
|
|
||||||
|
|
||||||
if settings.ExtraConfigOptions.ClientKey != "" {
|
|
||||||
lines = append(lines, lastIndent+"Client key is set")
|
|
||||||
}
|
|
||||||
|
|
||||||
if settings.ExtraConfigOptions.ClientCertificate != "" {
|
|
||||||
lines = append(lines, lastIndent+"Client certificate is set")
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings *Provider) readCyberghost(r reader) (err error) {
|
func (settings *Provider) readCyberghost(r reader) (err error) {
|
||||||
settings.Name = constants.Cyberghost
|
settings.Name = constants.Cyberghost
|
||||||
|
servers := r.servers.GetCyberghost()
|
||||||
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ExtraConfigOptions.ClientKey, err = readClientKey(r)
|
settings.ServerSelection.Groups, err = r.env.CSVInside("CYBERGHOST_GROUP",
|
||||||
if err != nil {
|
constants.CyberghostGroupChoices(servers))
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ExtraConfigOptions.ClientCertificate, err = readClientCertificate(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.Group, err = r.env.Inside("CYBERGHOST_GROUP",
|
|
||||||
constants.CyberghostGroupChoices(), params.Default("Premium UDP Europe"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable CYBERGHOST_GROUP: %w", err)
|
return fmt.Errorf("environment variable CYBERGHOST_GROUP: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.CyberghostRegionChoices())
|
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.CyberghostRegionChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable REGION: %w", err)
|
return fmt.Errorf("environment variable REGION: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.CyberghostHostnameChoices())
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||||
|
constants.CyberghostHostnameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return settings.ServerSelection.OpenVPN.readProtocolAndPort(r.env)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *OpenVPN) readCyberghost(r reader) (err error) {
|
||||||
|
settings.ClientKey, err = readClientKey(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ClientCrt, err = readClientCertificate(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ var (
|
|||||||
ErrDNSAddressNotAnIP = errors.New("DNS plaintext address is not an IP address")
|
ErrDNSAddressNotAnIP = errors.New("DNS plaintext address is not an IP address")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *DNS) readDNSPlaintext(env params.Env) error {
|
func (settings *DNS) readDNSPlaintext(env params.Interface) error {
|
||||||
s, err := env.Get("DNS_PLAINTEXT_ADDRESS", params.Default("1.1.1.1"))
|
s, err := env.Get("DNS_PLAINTEXT_ADDRESS", params.Default("1.1.1.1"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable DNS_PLAINTEXT_ADDRESS: %w", err)
|
return fmt.Errorf("environment variable DNS_PLAINTEXT_ADDRESS: %w", err)
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ var (
|
|||||||
ErrInvalidPrivateAddress = errors.New("private address is not a valid IP or CIDR range")
|
ErrInvalidPrivateAddress = errors.New("private address is not a valid IP or CIDR range")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *DNS) readPrivateAddresses(env params.Env) (err error) {
|
func (settings *DNS) readPrivateAddresses(env params.Interface) (err error) {
|
||||||
privateAddresses, err := env.CSV("DOT_PRIVATE_ADDRESS")
|
privateAddresses, err := env.CSV("DOT_PRIVATE_ADDRESS")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable DOT_PRIVATE_ADDRESS: %w", err)
|
return fmt.Errorf("environment variable DOT_PRIVATE_ADDRESS: %w", err)
|
||||||
|
|||||||
@@ -6,40 +6,25 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *Provider) fastestvpnLines() (lines []string) {
|
|
||||||
if len(settings.ServerSelection.Hostnames) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Countries) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Countries: "+commaJoin(settings.ServerSelection.Countries))
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings *Provider) readFastestvpn(r reader) (err error) {
|
func (settings *Provider) readFastestvpn(r reader) (err error) {
|
||||||
settings.Name = constants.Fastestvpn
|
settings.Name = constants.Fastestvpn
|
||||||
|
servers := r.servers.GetFastestvpn()
|
||||||
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.FastestvpnHostnameChoices())
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||||
|
constants.FastestvpnHostnameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.FastestvpnCountriesChoices())
|
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.FastestvpnCountriesChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return settings.ServerSelection.OpenVPN.readProtocolOnly(r.env)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ func (settings *Firewall) read(r reader) (err error) {
|
|||||||
return settings.readOutboundSubnets(r)
|
return settings.readOutboundSubnets(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (settings *Firewall) readVPNInputPorts(env params.Env) (err error) {
|
func (settings *Firewall) readVPNInputPorts(env params.Interface) (err error) {
|
||||||
settings.VPNInputPorts, err = readCSVPorts(env, "FIREWALL_VPN_INPUT_PORTS")
|
settings.VPNInputPorts, err = readCSVPorts(env, "FIREWALL_VPN_INPUT_PORTS")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable FIREWALL_VPN_INPUT_PORTS: %w", err)
|
return fmt.Errorf("environment variable FIREWALL_VPN_INPUT_PORTS: %w", err)
|
||||||
@@ -81,7 +81,7 @@ func (settings *Firewall) readVPNInputPorts(env params.Env) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (settings *Firewall) readInputPorts(env params.Env) (err error) {
|
func (settings *Firewall) readInputPorts(env params.Interface) (err error) {
|
||||||
settings.InputPorts, err = readCSVPorts(env, "FIREWALL_INPUT_PORTS")
|
settings.InputPorts, err = readCSVPorts(env, "FIREWALL_INPUT_PORTS")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable FIREWALL_INPUT_PORTS: %w", err)
|
return fmt.Errorf("environment variable FIREWALL_INPUT_PORTS: %w", err)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/params"
|
"github.com/qdm12/golibs/params"
|
||||||
)
|
)
|
||||||
@@ -32,8 +33,8 @@ func (settings *Health) lines() (lines []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read is to be used for the healthcheck query mode.
|
// Read is to be used for the healthcheck query mode.
|
||||||
func (settings *Health) Read(env params.Env, logger logging.Logger) (err error) {
|
func (settings *Health) Read(env params.Interface, logger logging.Logger) (err error) {
|
||||||
reader := newReader(env, logger)
|
reader := newReader(env, models.AllServers{}, logger) // note: no need for servers data
|
||||||
return settings.read(reader)
|
return settings.read(reader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ func Test_Health_read(t *testing.T) {
|
|||||||
|
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
|
|
||||||
env := mock_params.NewMockEnv(ctrl)
|
env := mock_params.NewMockInterface(ctrl)
|
||||||
logger := mock_logging.NewMockLogger(ctrl)
|
logger := mock_logging.NewMockLogger(ctrl)
|
||||||
|
|
||||||
env.EXPECT().ListeningAddress("HEALTH_SERVER_ADDRESS", gomock.Any()).
|
env.EXPECT().ListeningAddress("HEALTH_SERVER_ADDRESS", gomock.Any()).
|
||||||
|
|||||||
@@ -6,58 +6,35 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *Provider) hideMyAssLines() (lines []string) {
|
|
||||||
if len(settings.ServerSelection.Countries) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Countries: "+commaJoin(settings.ServerSelection.Countries))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Regions) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Cities) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Cities: "+commaJoin(settings.ServerSelection.Cities))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Hostnames) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings *Provider) readHideMyAss(r reader) (err error) {
|
func (settings *Provider) readHideMyAss(r reader) (err error) {
|
||||||
settings.Name = constants.HideMyAss
|
settings.Name = constants.HideMyAss
|
||||||
|
servers := r.servers.GetHideMyAss()
|
||||||
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.HideMyAssCountryChoices())
|
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.HideMyAssCountryChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.HideMyAssCountryChoices())
|
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.HideMyAssCountryChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable REGION: %w", err)
|
return fmt.Errorf("environment variable REGION: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.HideMyAssCityChoices())
|
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.HideMyAssCityChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable CITY: %w", err)
|
return fmt.Errorf("environment variable CITY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.HideMyAssHostnameChoices())
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||||
|
constants.HideMyAssHostnameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return settings.ServerSelection.OpenVPN.readProtocolAndPort(r.env)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,49 +6,30 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *Provider) ipvanishLines() (lines []string) {
|
|
||||||
if len(settings.ServerSelection.Countries) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Countries: "+commaJoin(settings.ServerSelection.Countries))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Cities) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Cities: "+commaJoin(settings.ServerSelection.Cities))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Hostnames) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings *Provider) readIpvanish(r reader) (err error) {
|
func (settings *Provider) readIpvanish(r reader) (err error) {
|
||||||
settings.Name = constants.Ipvanish
|
settings.Name = constants.Ipvanish
|
||||||
|
servers := r.servers.GetIpvanish()
|
||||||
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.IpvanishCountryChoices())
|
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.IpvanishCountryChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.IpvanishCityChoices())
|
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.IpvanishCityChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable CITY: %w", err)
|
return fmt.Errorf("environment variable CITY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.IpvanishHostnameChoices())
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||||
|
constants.IpvanishHostnameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return settings.ServerSelection.OpenVPN.readProtocolOnly(r.env)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,46 +7,12 @@ import (
|
|||||||
|
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/golibs/params/mock_params"
|
"github.com/qdm12/golibs/params/mock_params"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_Provider_ipvanishLines(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testCases := map[string]struct {
|
|
||||||
settings Provider
|
|
||||||
lines []string
|
|
||||||
}{
|
|
||||||
"empty settings": {},
|
|
||||||
"full settings": {
|
|
||||||
settings: Provider{
|
|
||||||
ServerSelection: ServerSelection{
|
|
||||||
Countries: []string{"A", "B"},
|
|
||||||
Cities: []string{"C", "D"},
|
|
||||||
Hostnames: []string{"E", "F"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
lines: []string{
|
|
||||||
"|--Countries: A, B",
|
|
||||||
"|--Cities: C, D",
|
|
||||||
"|--Hostnames: E, F",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for name, testCase := range testCases {
|
|
||||||
testCase := testCase
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
lines := testCase.settings.ipvanishLines()
|
|
||||||
|
|
||||||
assert.Equal(t, testCase.lines, lines)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Provider_readIpvanish(t *testing.T) {
|
func Test_Provider_readIpvanish(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -65,23 +31,15 @@ func Test_Provider_readIpvanish(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
protocol singleStringCall
|
|
||||||
targetIP singleStringCall
|
targetIP singleStringCall
|
||||||
countries sliceStringCall
|
countries sliceStringCall
|
||||||
cities sliceStringCall
|
cities sliceStringCall
|
||||||
hostnames sliceStringCall
|
hostnames sliceStringCall
|
||||||
|
protocol singleStringCall
|
||||||
settings Provider
|
settings Provider
|
||||||
err error
|
err error
|
||||||
}{
|
}{
|
||||||
"protocol error": {
|
|
||||||
protocol: singleStringCall{call: true, err: errDummy},
|
|
||||||
settings: Provider{
|
|
||||||
Name: constants.Ipvanish,
|
|
||||||
},
|
|
||||||
err: errors.New("environment variable PROTOCOL: dummy test error"),
|
|
||||||
},
|
|
||||||
"target IP error": {
|
"target IP error": {
|
||||||
protocol: singleStringCall{call: true},
|
|
||||||
targetIP: singleStringCall{call: true, value: "something", err: errDummy},
|
targetIP: singleStringCall{call: true, value: "something", err: errDummy},
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Ipvanish,
|
Name: constants.Ipvanish,
|
||||||
@@ -89,7 +47,6 @@ func Test_Provider_readIpvanish(t *testing.T) {
|
|||||||
err: errors.New("environment variable OPENVPN_TARGET_IP: dummy test error"),
|
err: errors.New("environment variable OPENVPN_TARGET_IP: dummy test error"),
|
||||||
},
|
},
|
||||||
"countries error": {
|
"countries error": {
|
||||||
protocol: singleStringCall{call: true},
|
|
||||||
targetIP: singleStringCall{call: true},
|
targetIP: singleStringCall{call: true},
|
||||||
countries: sliceStringCall{call: true, err: errDummy},
|
countries: sliceStringCall{call: true, err: errDummy},
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
@@ -98,7 +55,6 @@ func Test_Provider_readIpvanish(t *testing.T) {
|
|||||||
err: errors.New("environment variable COUNTRY: dummy test error"),
|
err: errors.New("environment variable COUNTRY: dummy test error"),
|
||||||
},
|
},
|
||||||
"cities error": {
|
"cities error": {
|
||||||
protocol: singleStringCall{call: true},
|
|
||||||
targetIP: singleStringCall{call: true},
|
targetIP: singleStringCall{call: true},
|
||||||
countries: sliceStringCall{call: true},
|
countries: sliceStringCall{call: true},
|
||||||
cities: sliceStringCall{call: true, err: errDummy},
|
cities: sliceStringCall{call: true, err: errDummy},
|
||||||
@@ -108,7 +64,6 @@ func Test_Provider_readIpvanish(t *testing.T) {
|
|||||||
err: errors.New("environment variable CITY: dummy test error"),
|
err: errors.New("environment variable CITY: dummy test error"),
|
||||||
},
|
},
|
||||||
"hostnames error": {
|
"hostnames error": {
|
||||||
protocol: singleStringCall{call: true},
|
|
||||||
targetIP: singleStringCall{call: true},
|
targetIP: singleStringCall{call: true},
|
||||||
countries: sliceStringCall{call: true},
|
countries: sliceStringCall{call: true},
|
||||||
cities: sliceStringCall{call: true},
|
cities: sliceStringCall{call: true},
|
||||||
@@ -118,26 +73,39 @@ func Test_Provider_readIpvanish(t *testing.T) {
|
|||||||
},
|
},
|
||||||
err: errors.New("environment variable SERVER_HOSTNAME: dummy test error"),
|
err: errors.New("environment variable SERVER_HOSTNAME: dummy test error"),
|
||||||
},
|
},
|
||||||
"default settings": {
|
"protocol error": {
|
||||||
protocol: singleStringCall{call: true},
|
|
||||||
targetIP: singleStringCall{call: true},
|
targetIP: singleStringCall{call: true},
|
||||||
countries: sliceStringCall{call: true},
|
countries: sliceStringCall{call: true},
|
||||||
cities: sliceStringCall{call: true},
|
cities: sliceStringCall{call: true},
|
||||||
hostnames: sliceStringCall{call: true},
|
hostnames: sliceStringCall{call: true},
|
||||||
|
protocol: singleStringCall{call: true, err: errDummy},
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Ipvanish,
|
||||||
|
},
|
||||||
|
err: errors.New("environment variable PROTOCOL: dummy test error"),
|
||||||
|
},
|
||||||
|
"default settings": {
|
||||||
|
targetIP: singleStringCall{call: true},
|
||||||
|
countries: sliceStringCall{call: true},
|
||||||
|
cities: sliceStringCall{call: true},
|
||||||
|
hostnames: sliceStringCall{call: true},
|
||||||
|
protocol: singleStringCall{call: true},
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Ipvanish,
|
Name: constants.Ipvanish,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"set settings": {
|
"set settings": {
|
||||||
protocol: singleStringCall{call: true, value: constants.TCP},
|
|
||||||
targetIP: singleStringCall{call: true, value: "1.2.3.4"},
|
targetIP: singleStringCall{call: true, value: "1.2.3.4"},
|
||||||
countries: sliceStringCall{call: true, values: []string{"A", "B"}},
|
countries: sliceStringCall{call: true, values: []string{"A", "B"}},
|
||||||
cities: sliceStringCall{call: true, values: []string{"C", "D"}},
|
cities: sliceStringCall{call: true, values: []string{"C", "D"}},
|
||||||
hostnames: sliceStringCall{call: true, values: []string{"E", "F"}},
|
hostnames: sliceStringCall{call: true, values: []string{"E", "F"}},
|
||||||
|
protocol: singleStringCall{call: true, value: constants.TCP},
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Ipvanish,
|
Name: constants.Ipvanish,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
TCP: true,
|
OpenVPN: OpenVPNSelection{
|
||||||
|
TCP: true,
|
||||||
|
},
|
||||||
TargetIP: net.IPv4(1, 2, 3, 4),
|
TargetIP: net.IPv4(1, 2, 3, 4),
|
||||||
Countries: []string{"A", "B"},
|
Countries: []string{"A", "B"},
|
||||||
Cities: []string{"C", "D"},
|
Cities: []string{"C", "D"},
|
||||||
@@ -152,29 +120,39 @@ func Test_Provider_readIpvanish(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
|
|
||||||
env := mock_params.NewMockEnv(ctrl)
|
servers := []models.IpvanishServer{{Hostname: "a"}}
|
||||||
if testCase.protocol.call {
|
allServers := models.AllServers{
|
||||||
env.EXPECT().Inside("PROTOCOL", []string{constants.TCP, constants.UDP}, gomock.Any()).
|
Ipvanish: models.IpvanishServers{
|
||||||
Return(testCase.protocol.value, testCase.protocol.err)
|
Servers: servers,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
env := mock_params.NewMockInterface(ctrl)
|
||||||
if testCase.targetIP.call {
|
if testCase.targetIP.call {
|
||||||
env.EXPECT().Get("OPENVPN_TARGET_IP").
|
env.EXPECT().Get("OPENVPN_TARGET_IP").
|
||||||
Return(testCase.targetIP.value, testCase.targetIP.err)
|
Return(testCase.targetIP.value, testCase.targetIP.err)
|
||||||
}
|
}
|
||||||
if testCase.countries.call {
|
if testCase.countries.call {
|
||||||
env.EXPECT().CSVInside("COUNTRY", constants.IpvanishCountryChoices()).
|
env.EXPECT().CSVInside("COUNTRY", constants.IpvanishCountryChoices(servers)).
|
||||||
Return(testCase.countries.values, testCase.countries.err)
|
Return(testCase.countries.values, testCase.countries.err)
|
||||||
}
|
}
|
||||||
if testCase.cities.call {
|
if testCase.cities.call {
|
||||||
env.EXPECT().CSVInside("CITY", constants.IpvanishCityChoices()).
|
env.EXPECT().CSVInside("CITY", constants.IpvanishCityChoices(servers)).
|
||||||
Return(testCase.cities.values, testCase.cities.err)
|
Return(testCase.cities.values, testCase.cities.err)
|
||||||
}
|
}
|
||||||
if testCase.hostnames.call {
|
if testCase.hostnames.call {
|
||||||
env.EXPECT().CSVInside("SERVER_HOSTNAME", constants.IpvanishHostnameChoices()).
|
env.EXPECT().CSVInside("SERVER_HOSTNAME", constants.IpvanishHostnameChoices(servers)).
|
||||||
Return(testCase.hostnames.values, testCase.hostnames.err)
|
Return(testCase.hostnames.values, testCase.hostnames.err)
|
||||||
}
|
}
|
||||||
|
if testCase.protocol.call {
|
||||||
|
env.EXPECT().Inside("PROTOCOL", []string{constants.TCP, constants.UDP}, gomock.Any()).
|
||||||
|
Return(testCase.protocol.value, testCase.protocol.err)
|
||||||
|
}
|
||||||
|
|
||||||
r := reader{env: env}
|
r := reader{
|
||||||
|
servers: allServers,
|
||||||
|
env: env,
|
||||||
|
}
|
||||||
|
|
||||||
var settings Provider
|
var settings Provider
|
||||||
err := settings.readIpvanish(r)
|
err := settings.readIpvanish(r)
|
||||||
|
|||||||
@@ -4,51 +4,67 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *Provider) ivpnLines() (lines []string) {
|
|
||||||
if len(settings.ServerSelection.Countries) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Countries: "+commaJoin(settings.ServerSelection.Countries))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Cities) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Cities: "+commaJoin(settings.ServerSelection.Cities))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Hostnames) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings *Provider) readIvpn(r reader) (err error) {
|
func (settings *Provider) readIvpn(r reader) (err error) {
|
||||||
settings.Name = constants.Ivpn
|
settings.Name = constants.Ivpn
|
||||||
|
servers := r.servers.GetIvpn()
|
||||||
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.IvpnCountryChoices())
|
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.IvpnCountryChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.IvpnCityChoices())
|
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.IvpnCityChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable CITY: %w", err)
|
return fmt.Errorf("environment variable CITY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.IvpnHostnameChoices())
|
settings.ServerSelection.ISPs, err = r.env.CSVInside("ISP", constants.IvpnISPChoices(servers))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("environment variable ISP: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.IvpnHostnameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = settings.ServerSelection.OpenVPN.readIVPN(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return settings.ServerSelection.Wireguard.readIVPN(r.env)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *OpenVPNSelection) readIVPN(env params.Interface) (err error) {
|
||||||
|
settings.TCP, err = readProtocol(env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.CustomPort, err = readOpenVPNCustomPort(env, settings.TCP,
|
||||||
|
[]uint16{80, 443, 1443}, []uint16{53, 1194, 2049, 2050})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *WireguardSelection) readIVPN(env params.Interface) (err error) {
|
||||||
|
settings.CustomPort, err = readWireguardCustomPort(env,
|
||||||
|
[]uint16{2049, 2050, 53, 30587, 41893, 48574, 58237})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,47 +7,13 @@ import (
|
|||||||
|
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/golibs/params/mock_params"
|
"github.com/qdm12/golibs/params/mock_params"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_Provider_ivpnLines(t *testing.T) {
|
func Test_Provider_readIvpn(t *testing.T) { //nolint:gocognit
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testCases := map[string]struct {
|
|
||||||
settings Provider
|
|
||||||
lines []string
|
|
||||||
}{
|
|
||||||
"empty settings": {},
|
|
||||||
"full settings": {
|
|
||||||
settings: Provider{
|
|
||||||
ServerSelection: ServerSelection{
|
|
||||||
Countries: []string{"A", "B"},
|
|
||||||
Cities: []string{"C", "D"},
|
|
||||||
Hostnames: []string{"E", "F"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
lines: []string{
|
|
||||||
"|--Countries: A, B",
|
|
||||||
"|--Cities: C, D",
|
|
||||||
"|--Hostnames: E, F",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for name, testCase := range testCases {
|
|
||||||
testCase := testCase
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
lines := testCase.settings.ivpnLines()
|
|
||||||
|
|
||||||
assert.Equal(t, testCase.lines, lines)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Provider_readIvpn(t *testing.T) {
|
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
var errDummy = errors.New("dummy test error")
|
var errDummy = errors.New("dummy test error")
|
||||||
@@ -58,6 +24,15 @@ func Test_Provider_readIvpn(t *testing.T) {
|
|||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type portCall struct {
|
||||||
|
getCall bool
|
||||||
|
getValue string // "" or "0"
|
||||||
|
getErr error
|
||||||
|
portCall bool
|
||||||
|
portValue uint16
|
||||||
|
portErr error
|
||||||
|
}
|
||||||
|
|
||||||
type sliceStringCall struct {
|
type sliceStringCall struct {
|
||||||
call bool
|
call bool
|
||||||
values []string
|
values []string
|
||||||
@@ -65,23 +40,18 @@ func Test_Provider_readIvpn(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
protocol singleStringCall
|
|
||||||
targetIP singleStringCall
|
targetIP singleStringCall
|
||||||
countries sliceStringCall
|
countries sliceStringCall
|
||||||
cities sliceStringCall
|
cities sliceStringCall
|
||||||
|
isps sliceStringCall
|
||||||
hostnames sliceStringCall
|
hostnames sliceStringCall
|
||||||
|
protocol singleStringCall
|
||||||
|
ovpnPort portCall
|
||||||
|
wgPort portCall
|
||||||
settings Provider
|
settings Provider
|
||||||
err error
|
err error
|
||||||
}{
|
}{
|
||||||
"protocol error": {
|
|
||||||
protocol: singleStringCall{call: true, err: errDummy},
|
|
||||||
settings: Provider{
|
|
||||||
Name: constants.Ivpn,
|
|
||||||
},
|
|
||||||
err: errors.New("environment variable PROTOCOL: dummy test error"),
|
|
||||||
},
|
|
||||||
"target IP error": {
|
"target IP error": {
|
||||||
protocol: singleStringCall{call: true},
|
|
||||||
targetIP: singleStringCall{call: true, value: "something", err: errDummy},
|
targetIP: singleStringCall{call: true, value: "something", err: errDummy},
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Ivpn,
|
Name: constants.Ivpn,
|
||||||
@@ -89,7 +59,6 @@ func Test_Provider_readIvpn(t *testing.T) {
|
|||||||
err: errors.New("environment variable OPENVPN_TARGET_IP: dummy test error"),
|
err: errors.New("environment variable OPENVPN_TARGET_IP: dummy test error"),
|
||||||
},
|
},
|
||||||
"countries error": {
|
"countries error": {
|
||||||
protocol: singleStringCall{call: true},
|
|
||||||
targetIP: singleStringCall{call: true},
|
targetIP: singleStringCall{call: true},
|
||||||
countries: sliceStringCall{call: true, err: errDummy},
|
countries: sliceStringCall{call: true, err: errDummy},
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
@@ -98,7 +67,6 @@ func Test_Provider_readIvpn(t *testing.T) {
|
|||||||
err: errors.New("environment variable COUNTRY: dummy test error"),
|
err: errors.New("environment variable COUNTRY: dummy test error"),
|
||||||
},
|
},
|
||||||
"cities error": {
|
"cities error": {
|
||||||
protocol: singleStringCall{call: true},
|
|
||||||
targetIP: singleStringCall{call: true},
|
targetIP: singleStringCall{call: true},
|
||||||
countries: sliceStringCall{call: true},
|
countries: sliceStringCall{call: true},
|
||||||
cities: sliceStringCall{call: true, err: errDummy},
|
cities: sliceStringCall{call: true, err: errDummy},
|
||||||
@@ -107,40 +75,102 @@ func Test_Provider_readIvpn(t *testing.T) {
|
|||||||
},
|
},
|
||||||
err: errors.New("environment variable CITY: dummy test error"),
|
err: errors.New("environment variable CITY: dummy test error"),
|
||||||
},
|
},
|
||||||
"hostnames error": {
|
"isps error": {
|
||||||
protocol: singleStringCall{call: true},
|
|
||||||
targetIP: singleStringCall{call: true},
|
targetIP: singleStringCall{call: true},
|
||||||
countries: sliceStringCall{call: true},
|
countries: sliceStringCall{call: true},
|
||||||
cities: sliceStringCall{call: true},
|
cities: sliceStringCall{call: true},
|
||||||
|
isps: sliceStringCall{call: true, err: errDummy},
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Ivpn,
|
||||||
|
},
|
||||||
|
err: errors.New("environment variable ISP: dummy test error"),
|
||||||
|
},
|
||||||
|
"hostnames error": {
|
||||||
|
targetIP: singleStringCall{call: true},
|
||||||
|
countries: sliceStringCall{call: true},
|
||||||
|
cities: sliceStringCall{call: true},
|
||||||
|
isps: sliceStringCall{call: true},
|
||||||
hostnames: sliceStringCall{call: true, err: errDummy},
|
hostnames: sliceStringCall{call: true, err: errDummy},
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Ivpn,
|
Name: constants.Ivpn,
|
||||||
},
|
},
|
||||||
err: errors.New("environment variable SERVER_HOSTNAME: dummy test error"),
|
err: errors.New("environment variable SERVER_HOSTNAME: dummy test error"),
|
||||||
},
|
},
|
||||||
"default settings": {
|
"openvpn protocol error": {
|
||||||
protocol: singleStringCall{call: true},
|
|
||||||
targetIP: singleStringCall{call: true},
|
targetIP: singleStringCall{call: true},
|
||||||
countries: sliceStringCall{call: true},
|
countries: sliceStringCall{call: true},
|
||||||
cities: sliceStringCall{call: true},
|
cities: sliceStringCall{call: true},
|
||||||
|
isps: sliceStringCall{call: true},
|
||||||
hostnames: sliceStringCall{call: true},
|
hostnames: sliceStringCall{call: true},
|
||||||
|
protocol: singleStringCall{call: true, err: errDummy},
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Ivpn,
|
||||||
|
},
|
||||||
|
err: errors.New("environment variable PROTOCOL: dummy test error"),
|
||||||
|
},
|
||||||
|
"openvpn custom port error": {
|
||||||
|
targetIP: singleStringCall{call: true},
|
||||||
|
countries: sliceStringCall{call: true},
|
||||||
|
cities: sliceStringCall{call: true},
|
||||||
|
isps: sliceStringCall{call: true},
|
||||||
|
hostnames: sliceStringCall{call: true},
|
||||||
|
protocol: singleStringCall{call: true},
|
||||||
|
ovpnPort: portCall{getCall: true, getErr: errDummy},
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Ivpn,
|
||||||
|
},
|
||||||
|
err: errors.New("environment variable PORT: dummy test error"),
|
||||||
|
},
|
||||||
|
"wireguard custom port error": {
|
||||||
|
targetIP: singleStringCall{call: true},
|
||||||
|
countries: sliceStringCall{call: true},
|
||||||
|
cities: sliceStringCall{call: true},
|
||||||
|
isps: sliceStringCall{call: true},
|
||||||
|
hostnames: sliceStringCall{call: true},
|
||||||
|
protocol: singleStringCall{call: true},
|
||||||
|
ovpnPort: portCall{getCall: true, getValue: "0"},
|
||||||
|
wgPort: portCall{getCall: true, getErr: errDummy},
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Ivpn,
|
||||||
|
},
|
||||||
|
err: errors.New("environment variable WIREGUARD_PORT: dummy test error"),
|
||||||
|
},
|
||||||
|
"default settings": {
|
||||||
|
targetIP: singleStringCall{call: true},
|
||||||
|
countries: sliceStringCall{call: true},
|
||||||
|
cities: sliceStringCall{call: true},
|
||||||
|
isps: sliceStringCall{call: true},
|
||||||
|
hostnames: sliceStringCall{call: true},
|
||||||
|
protocol: singleStringCall{call: true},
|
||||||
|
ovpnPort: portCall{getCall: true, getValue: "0"},
|
||||||
|
wgPort: portCall{getCall: true, getValue: "0"},
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Ivpn,
|
Name: constants.Ivpn,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"set settings": {
|
"set settings": {
|
||||||
protocol: singleStringCall{call: true, value: constants.TCP},
|
|
||||||
targetIP: singleStringCall{call: true, value: "1.2.3.4"},
|
targetIP: singleStringCall{call: true, value: "1.2.3.4"},
|
||||||
countries: sliceStringCall{call: true, values: []string{"A", "B"}},
|
countries: sliceStringCall{call: true, values: []string{"A", "B"}},
|
||||||
cities: sliceStringCall{call: true, values: []string{"C", "D"}},
|
cities: sliceStringCall{call: true, values: []string{"C", "D"}},
|
||||||
|
isps: sliceStringCall{call: true, values: []string{"ISP 1"}},
|
||||||
hostnames: sliceStringCall{call: true, values: []string{"E", "F"}},
|
hostnames: sliceStringCall{call: true, values: []string{"E", "F"}},
|
||||||
|
protocol: singleStringCall{call: true, value: constants.TCP},
|
||||||
|
ovpnPort: portCall{getCall: true, portCall: true, portValue: 443},
|
||||||
|
wgPort: portCall{getCall: true, portCall: true, portValue: 2049},
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Ivpn,
|
Name: constants.Ivpn,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
TCP: true,
|
OpenVPN: OpenVPNSelection{
|
||||||
|
TCP: true,
|
||||||
|
CustomPort: 443,
|
||||||
|
},
|
||||||
|
Wireguard: WireguardSelection{
|
||||||
|
CustomPort: 2049,
|
||||||
|
},
|
||||||
TargetIP: net.IPv4(1, 2, 3, 4),
|
TargetIP: net.IPv4(1, 2, 3, 4),
|
||||||
Countries: []string{"A", "B"},
|
Countries: []string{"A", "B"},
|
||||||
Cities: []string{"C", "D"},
|
Cities: []string{"C", "D"},
|
||||||
|
ISPs: []string{"ISP 1"},
|
||||||
Hostnames: []string{"E", "F"},
|
Hostnames: []string{"E", "F"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -152,29 +182,60 @@ func Test_Provider_readIvpn(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
|
|
||||||
env := mock_params.NewMockEnv(ctrl)
|
env := mock_params.NewMockInterface(ctrl)
|
||||||
if testCase.protocol.call {
|
|
||||||
env.EXPECT().Inside("PROTOCOL", []string{constants.TCP, constants.UDP}, gomock.Any()).
|
servers := []models.IvpnServer{{Hostname: "a"}}
|
||||||
Return(testCase.protocol.value, testCase.protocol.err)
|
allServers := models.AllServers{
|
||||||
|
Ivpn: models.IvpnServers{
|
||||||
|
Servers: servers,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if testCase.targetIP.call {
|
if testCase.targetIP.call {
|
||||||
env.EXPECT().Get("OPENVPN_TARGET_IP").
|
env.EXPECT().Get("OPENVPN_TARGET_IP").
|
||||||
Return(testCase.targetIP.value, testCase.targetIP.err)
|
Return(testCase.targetIP.value, testCase.targetIP.err)
|
||||||
}
|
}
|
||||||
if testCase.countries.call {
|
if testCase.countries.call {
|
||||||
env.EXPECT().CSVInside("COUNTRY", constants.IvpnCountryChoices()).
|
env.EXPECT().CSVInside("COUNTRY", constants.IvpnCountryChoices(servers)).
|
||||||
Return(testCase.countries.values, testCase.countries.err)
|
Return(testCase.countries.values, testCase.countries.err)
|
||||||
}
|
}
|
||||||
if testCase.cities.call {
|
if testCase.cities.call {
|
||||||
env.EXPECT().CSVInside("CITY", constants.IvpnCityChoices()).
|
env.EXPECT().CSVInside("CITY", constants.IvpnCityChoices(servers)).
|
||||||
Return(testCase.cities.values, testCase.cities.err)
|
Return(testCase.cities.values, testCase.cities.err)
|
||||||
}
|
}
|
||||||
|
if testCase.isps.call {
|
||||||
|
env.EXPECT().CSVInside("ISP", constants.IvpnISPChoices(servers)).
|
||||||
|
Return(testCase.isps.values, testCase.isps.err)
|
||||||
|
}
|
||||||
if testCase.hostnames.call {
|
if testCase.hostnames.call {
|
||||||
env.EXPECT().CSVInside("SERVER_HOSTNAME", constants.IvpnHostnameChoices()).
|
env.EXPECT().CSVInside("SERVER_HOSTNAME", constants.IvpnHostnameChoices(servers)).
|
||||||
Return(testCase.hostnames.values, testCase.hostnames.err)
|
Return(testCase.hostnames.values, testCase.hostnames.err)
|
||||||
}
|
}
|
||||||
|
if testCase.protocol.call {
|
||||||
|
env.EXPECT().Inside("PROTOCOL", []string{constants.TCP, constants.UDP}, gomock.Any()).
|
||||||
|
Return(testCase.protocol.value, testCase.protocol.err)
|
||||||
|
}
|
||||||
|
if testCase.ovpnPort.getCall {
|
||||||
|
env.EXPECT().Get("PORT", gomock.Any()).
|
||||||
|
Return(testCase.ovpnPort.getValue, testCase.ovpnPort.getErr)
|
||||||
|
}
|
||||||
|
if testCase.ovpnPort.portCall {
|
||||||
|
env.EXPECT().Port("PORT").
|
||||||
|
Return(testCase.ovpnPort.portValue, testCase.ovpnPort.portErr)
|
||||||
|
}
|
||||||
|
if testCase.wgPort.getCall {
|
||||||
|
env.EXPECT().Get("WIREGUARD_PORT", gomock.Any()).
|
||||||
|
Return(testCase.wgPort.getValue, testCase.wgPort.getErr)
|
||||||
|
}
|
||||||
|
if testCase.wgPort.portCall {
|
||||||
|
env.EXPECT().Port("WIREGUARD_PORT").
|
||||||
|
Return(testCase.wgPort.portValue, testCase.wgPort.portErr)
|
||||||
|
}
|
||||||
|
|
||||||
r := reader{env: env}
|
r := reader{
|
||||||
|
servers: allServers,
|
||||||
|
env: env,
|
||||||
|
}
|
||||||
|
|
||||||
var settings Provider
|
var settings Provider
|
||||||
err := settings.readIvpn(r)
|
err := settings.readIvpn(r)
|
||||||
|
|||||||
30
internal/configuration/log.go
Normal file
30
internal/configuration/log.go
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/qdm12/golibs/logging"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Log struct {
|
||||||
|
Level logging.Level `json:"level"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Log) lines() (lines []string) {
|
||||||
|
lines = append(lines, lastIndent+"Log:")
|
||||||
|
|
||||||
|
lines = append(lines, indent+lastIndent+"Level: "+settings.Level.String())
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Log) read(env params.Interface) (err error) {
|
||||||
|
defaultLevel := logging.LevelInfo.String()
|
||||||
|
settings.Level, err = env.LogLevel("LOG_LEVEL", params.Default(defaultLevel))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("environment variable LOG_LEVEL: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -2,87 +2,72 @@ package configuration
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/golibs/params"
|
"github.com/qdm12/golibs/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *Provider) mullvadLines() (lines []string) {
|
|
||||||
if len(settings.ServerSelection.Countries) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Countries: "+commaJoin(settings.ServerSelection.Countries))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Cities) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Cities: "+commaJoin(settings.ServerSelection.Cities))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Hostnames) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.ISPs) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"ISPs: "+commaJoin(settings.ServerSelection.ISPs))
|
|
||||||
}
|
|
||||||
|
|
||||||
if settings.ServerSelection.CustomPort > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Custom port: "+strconv.Itoa(int(settings.ServerSelection.CustomPort)))
|
|
||||||
}
|
|
||||||
|
|
||||||
if settings.ExtraConfigOptions.OpenVPNIPv6 {
|
|
||||||
lines = append(lines, lastIndent+"IPv6: enabled")
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings *Provider) readMullvad(r reader) (err error) {
|
func (settings *Provider) readMullvad(r reader) (err error) {
|
||||||
settings.Name = constants.Mullvad
|
settings.Name = constants.Mullvad
|
||||||
|
servers := r.servers.GetMullvad()
|
||||||
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.MullvadCountryChoices())
|
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.MullvadCountryChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.MullvadCityChoices())
|
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.MullvadCityChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable CITY: %w", err)
|
return fmt.Errorf("environment variable CITY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.MullvadHostnameChoices())
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.MullvadHostnameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.ISPs, err = r.env.CSVInside("ISP", constants.MullvadISPChoices())
|
settings.ServerSelection.ISPs, err = r.env.CSVInside("ISP", constants.MullvadISPChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable ISP: %w", err)
|
return fmt.Errorf("environment variable ISP: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.CustomPort, err = readCustomPort(r.env, settings.ServerSelection.TCP,
|
|
||||||
[]uint16{80, 443, 1401}, []uint16{53, 1194, 1195, 1196, 1197, 1300, 1301, 1302, 1303, 1400})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.Owned, err = r.env.YesNo("OWNED", params.Default("no"))
|
settings.ServerSelection.Owned, err = r.env.YesNo("OWNED", params.Default("no"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable OWNED: %w", err)
|
return fmt.Errorf("environment variable OWNED: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ExtraConfigOptions.OpenVPNIPv6, err = r.env.OnOff("OPENVPN_IPV6", params.Default("off"))
|
err = settings.ServerSelection.OpenVPN.readMullvad(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable OPENVPN_IPV6: %w", err)
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return settings.ServerSelection.Wireguard.readMullvad(r.env)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *OpenVPNSelection) readMullvad(env params.Interface) (err error) {
|
||||||
|
settings.TCP, err = readProtocol(env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.CustomPort, err = readOpenVPNCustomPort(env, settings.TCP,
|
||||||
|
[]uint16{80, 443, 1401}, []uint16{53, 1194, 1195, 1196, 1197, 1300, 1301, 1302, 1303, 1400})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *WireguardSelection) readMullvad(env params.Interface) (err error) {
|
||||||
|
settings.CustomPort, err = readWireguardCustomPort(env, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -8,54 +8,26 @@ import (
|
|||||||
"github.com/qdm12/golibs/params"
|
"github.com/qdm12/golibs/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *Provider) nordvpnLines() (lines []string) {
|
|
||||||
if len(settings.ServerSelection.Regions) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Hostnames) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Names) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Names: "+commaJoin(settings.ServerSelection.Hostnames))
|
|
||||||
}
|
|
||||||
|
|
||||||
if numbersUint16 := settings.ServerSelection.Numbers; len(numbersUint16) > 0 {
|
|
||||||
numbersString := make([]string, len(numbersUint16))
|
|
||||||
for i, numberUint16 := range numbersUint16 {
|
|
||||||
numbersString[i] = strconv.Itoa(int(numberUint16))
|
|
||||||
}
|
|
||||||
lines = append(lines, lastIndent+"Numbers: "+commaJoin(numbersString))
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings *Provider) readNordvpn(r reader) (err error) {
|
func (settings *Provider) readNordvpn(r reader) (err error) {
|
||||||
settings.Name = constants.Nordvpn
|
settings.Name = constants.Nordvpn
|
||||||
|
servers := r.servers.GetNordvpn()
|
||||||
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.NordvpnRegionChoices())
|
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.NordvpnRegionChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable REGION: %w", err)
|
return fmt.Errorf("environment variable REGION: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.NordvpnHostnameChoices())
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.NordvpnHostnameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Names, err = r.env.CSVInside("SERVER_NAME", constants.NordvpnHostnameChoices())
|
settings.ServerSelection.Names, err = r.env.CSVInside("SERVER_NAME", constants.NordvpnHostnameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_NAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_NAME: %w", err)
|
||||||
}
|
}
|
||||||
@@ -65,10 +37,10 @@ func (settings *Provider) readNordvpn(r reader) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return settings.ServerSelection.OpenVPN.readProtocolOnly(r.env)
|
||||||
}
|
}
|
||||||
|
|
||||||
func readNordVPNServerNumbers(env params.Env) (numbers []uint16, err error) {
|
func readNordVPNServerNumbers(env params.Interface) (numbers []uint16, err error) {
|
||||||
const possiblePortsCount = 65537
|
const possiblePortsCount = 65537
|
||||||
possibilities := make([]string, possiblePortsCount)
|
possibilities := make([]string, possiblePortsCount)
|
||||||
for i := range possibilities {
|
for i := range possibilities {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package configuration
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -20,9 +21,14 @@ type OpenVPN struct {
|
|||||||
Root bool `json:"run_as_root"`
|
Root bool `json:"run_as_root"`
|
||||||
Cipher string `json:"cipher"`
|
Cipher string `json:"cipher"`
|
||||||
Auth string `json:"auth"`
|
Auth string `json:"auth"`
|
||||||
Provider Provider `json:"provider"`
|
|
||||||
Config string `json:"custom_config"`
|
Config string `json:"custom_config"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
|
ClientCrt string `json:"-"` // Cyberghost
|
||||||
|
ClientKey string `json:"-"` // Cyberghost, VPNUnlimited
|
||||||
|
EncPreset string `json:"encryption_preset"` // PIA
|
||||||
|
IPv6 bool `json:"ipv6"` // Mullvad
|
||||||
|
ProcUser string `json:"procuser"` // Process username
|
||||||
|
Interface string `json:"interface"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (settings *OpenVPN) String() string {
|
func (settings *OpenVPN) String() string {
|
||||||
@@ -36,6 +42,8 @@ func (settings *OpenVPN) lines() (lines []string) {
|
|||||||
|
|
||||||
lines = append(lines, indent+lastIndent+"Verbosity level: "+strconv.Itoa(settings.Verbosity))
|
lines = append(lines, indent+lastIndent+"Verbosity level: "+strconv.Itoa(settings.Verbosity))
|
||||||
|
|
||||||
|
lines = append(lines, indent+lastIndent+"Network interface: "+settings.Interface)
|
||||||
|
|
||||||
if len(settings.Flags) > 0 {
|
if len(settings.Flags) > 0 {
|
||||||
lines = append(lines, indent+lastIndent+"Flags: "+strings.Join(settings.Flags, " "))
|
lines = append(lines, indent+lastIndent+"Flags: "+strings.Join(settings.Flags, " "))
|
||||||
}
|
}
|
||||||
@@ -55,48 +63,32 @@ func (settings *OpenVPN) lines() (lines []string) {
|
|||||||
lines = append(lines, indent+lastIndent+"Custom configuration: "+settings.Config)
|
lines = append(lines, indent+lastIndent+"Custom configuration: "+settings.Config)
|
||||||
}
|
}
|
||||||
|
|
||||||
if settings.Provider.Name == "" {
|
if settings.ClientKey != "" {
|
||||||
lines = append(lines, indent+lastIndent+"Provider: custom configuration")
|
lines = append(lines, indent+lastIndent+"Client key is set")
|
||||||
} else {
|
}
|
||||||
lines = append(lines, indent+lastIndent+"Provider:")
|
|
||||||
for _, line := range settings.Provider.lines() {
|
if settings.ClientCrt != "" {
|
||||||
lines = append(lines, indent+indent+line)
|
lines = append(lines, indent+lastIndent+"Client certificate is set")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if settings.IPv6 {
|
||||||
|
lines = append(lines, indent+lastIndent+"IPv6: enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.EncPreset != "" { // PIA only
|
||||||
|
lines = append(lines, indent+lastIndent+"Encryption preset: "+settings.EncPreset)
|
||||||
}
|
}
|
||||||
|
|
||||||
return lines
|
return lines
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
func (settings *OpenVPN) read(r reader, serviceProvider string) (err error) {
|
||||||
ErrInvalidVPNProvider = errors.New("invalid VPN provider")
|
|
||||||
)
|
|
||||||
|
|
||||||
func (settings *OpenVPN) read(r reader) (err error) {
|
|
||||||
vpnsp, err := r.env.Inside("VPNSP", []string{
|
|
||||||
"cyberghost", "fastestvpn", "hidemyass", "ipvanish", "ivpn", "mullvad", "nordvpn",
|
|
||||||
"privado", "pia", "private internet access", "privatevpn", "protonvpn",
|
|
||||||
"purevpn", "surfshark", "torguard", constants.VPNUnlimited, "vyprvpn", "windscribe"},
|
|
||||||
params.Default("private internet access"))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("environment variable VPNSP: %w", err)
|
|
||||||
}
|
|
||||||
if vpnsp == "pia" { // retro compatibility
|
|
||||||
vpnsp = "private internet access"
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.Provider.Name = vpnsp
|
|
||||||
|
|
||||||
settings.Config, err = r.env.Get("OPENVPN_CUSTOM_CONFIG", params.CaseSensitiveValue())
|
settings.Config, err = r.env.Get("OPENVPN_CUSTOM_CONFIG", params.CaseSensitiveValue())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable OPENVPN_CUSTOM_CONFIG: %w", err)
|
return fmt.Errorf("environment variable OPENVPN_CUSTOM_CONFIG: %w", err)
|
||||||
}
|
}
|
||||||
customConfig := settings.Config != ""
|
|
||||||
|
|
||||||
if customConfig {
|
credentialsRequired := settings.Config == "" && serviceProvider != constants.VPNUnlimited
|
||||||
settings.Provider.Name = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
credentialsRequired := !customConfig && settings.Provider.Name != constants.VPNUnlimited
|
|
||||||
|
|
||||||
settings.User, err = r.getFromEnvOrSecretFile("OPENVPN_USER", credentialsRequired, []string{"USER"})
|
settings.User, err = r.getFromEnvOrSecretFile("OPENVPN_USER", credentialsRequired, []string{"USER"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -105,7 +97,7 @@ func (settings *OpenVPN) read(r reader) (err error) {
|
|||||||
// Remove spaces in user ID to simplify user's life, thanks @JeordyR
|
// Remove spaces in user ID to simplify user's life, thanks @JeordyR
|
||||||
settings.User = strings.ReplaceAll(settings.User, " ", "")
|
settings.User = strings.ReplaceAll(settings.User, " ", "")
|
||||||
|
|
||||||
if settings.Provider.Name == constants.Mullvad {
|
if serviceProvider == constants.Mullvad {
|
||||||
settings.Password = "m"
|
settings.Password = "m"
|
||||||
} else {
|
} else {
|
||||||
settings.Password, err = r.getFromEnvOrSecretFile("OPENVPN_PASSWORD", credentialsRequired, []string{"PASSWORD"})
|
settings.Password, err = r.getFromEnvOrSecretFile("OPENVPN_PASSWORD", credentialsRequired, []string{"PASSWORD"})
|
||||||
@@ -155,50 +147,58 @@ func (settings *OpenVPN) read(r reader) (err error) {
|
|||||||
return fmt.Errorf("environment variable OPENVPN_MSSFIX: %w", err)
|
return fmt.Errorf("environment variable OPENVPN_MSSFIX: %w", err)
|
||||||
}
|
}
|
||||||
settings.MSSFix = uint16(mssFix)
|
settings.MSSFix = uint16(mssFix)
|
||||||
return settings.readProvider(r)
|
|
||||||
|
settings.IPv6, err = r.env.OnOff("OPENVPN_IPV6", params.Default("off"))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("environment variable OPENVPN_IPV6: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Interface, err = readInterface(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.EncPreset, err = getPIAEncryptionPreset(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch serviceProvider {
|
||||||
|
case constants.Cyberghost:
|
||||||
|
err = settings.readCyberghost(r)
|
||||||
|
case constants.VPNUnlimited:
|
||||||
|
err = settings.readVPNUnlimited(r)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (settings *OpenVPN) readProvider(r reader) error {
|
func readProtocol(env params.Interface) (tcp bool, err error) {
|
||||||
var readProvider func(r reader) error
|
protocol, err := env.Inside("PROTOCOL", []string{constants.TCP, constants.UDP}, params.Default(constants.UDP))
|
||||||
switch settings.Provider.Name {
|
if err != nil {
|
||||||
case "": // custom config
|
return false, fmt.Errorf("environment variable PROTOCOL: %w", err)
|
||||||
readProvider = func(r reader) error { return nil }
|
|
||||||
case constants.Cyberghost:
|
|
||||||
readProvider = settings.Provider.readCyberghost
|
|
||||||
case constants.Fastestvpn:
|
|
||||||
readProvider = settings.Provider.readFastestvpn
|
|
||||||
case constants.HideMyAss:
|
|
||||||
readProvider = settings.Provider.readHideMyAss
|
|
||||||
case constants.Ipvanish:
|
|
||||||
readProvider = settings.Provider.readIpvanish
|
|
||||||
case constants.Ivpn:
|
|
||||||
readProvider = settings.Provider.readIvpn
|
|
||||||
case constants.Mullvad:
|
|
||||||
readProvider = settings.Provider.readMullvad
|
|
||||||
case constants.Nordvpn:
|
|
||||||
readProvider = settings.Provider.readNordvpn
|
|
||||||
case constants.Privado:
|
|
||||||
readProvider = settings.Provider.readPrivado
|
|
||||||
case constants.PrivateInternetAccess:
|
|
||||||
readProvider = settings.Provider.readPrivateInternetAccess
|
|
||||||
case constants.Privatevpn:
|
|
||||||
readProvider = settings.Provider.readPrivatevpn
|
|
||||||
case constants.Protonvpn:
|
|
||||||
readProvider = settings.Provider.readProtonvpn
|
|
||||||
case constants.Purevpn:
|
|
||||||
readProvider = settings.Provider.readPurevpn
|
|
||||||
case constants.Surfshark:
|
|
||||||
readProvider = settings.Provider.readSurfshark
|
|
||||||
case constants.Torguard:
|
|
||||||
readProvider = settings.Provider.readTorguard
|
|
||||||
case constants.VPNUnlimited:
|
|
||||||
readProvider = settings.Provider.readVPNUnlimited
|
|
||||||
case constants.Vyprvpn:
|
|
||||||
readProvider = settings.Provider.readVyprvpn
|
|
||||||
case constants.Windscribe:
|
|
||||||
readProvider = settings.Provider.readWindscribe
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("%w: %s", ErrInvalidVPNProvider, settings.Provider.Name)
|
|
||||||
}
|
}
|
||||||
return readProvider(r)
|
return protocol == constants.TCP, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const openvpnIntfRegexString = `^.*[0-9]$`
|
||||||
|
|
||||||
|
var openvpnIntfRegexp = regexp.MustCompile(openvpnIntfRegexString)
|
||||||
|
var errInterfaceNameNotValid = errors.New("interface name is not valid")
|
||||||
|
|
||||||
|
func readInterface(env params.Interface) (intf string, err error) {
|
||||||
|
intf, err = env.Get("OPENVPN_INTERFACE", params.Default("tun0"))
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("environment variable OPENVPN_INTERFACE: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !openvpnIntfRegexp.MatchString(intf) {
|
||||||
|
return "", fmt.Errorf("%w: does not match regex %s: %s",
|
||||||
|
errInterfaceNameNotValid, openvpnIntfRegexString, intf)
|
||||||
|
}
|
||||||
|
|
||||||
|
return intf, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,6 @@ func Test_OpenVPN_JSON(t *testing.T) {
|
|||||||
in := OpenVPN{
|
in := OpenVPN{
|
||||||
Root: true,
|
Root: true,
|
||||||
Flags: []string{},
|
Flags: []string{},
|
||||||
Provider: Provider{
|
|
||||||
Name: "name",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
data, err := json.MarshalIndent(in, "", " ")
|
data, err := json.MarshalIndent(in, "", " ")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -28,35 +25,12 @@ func Test_OpenVPN_JSON(t *testing.T) {
|
|||||||
"run_as_root": true,
|
"run_as_root": true,
|
||||||
"cipher": "",
|
"cipher": "",
|
||||||
"auth": "",
|
"auth": "",
|
||||||
"provider": {
|
|
||||||
"name": "name",
|
|
||||||
"server_selection": {
|
|
||||||
"tcp": false,
|
|
||||||
"regions": null,
|
|
||||||
"group": "",
|
|
||||||
"countries": null,
|
|
||||||
"cities": null,
|
|
||||||
"hostnames": null,
|
|
||||||
"names": null,
|
|
||||||
"isps": null,
|
|
||||||
"owned": false,
|
|
||||||
"custom_port": 0,
|
|
||||||
"numbers": null,
|
|
||||||
"encryption_preset": "",
|
|
||||||
"free_only": false,
|
|
||||||
"stream_only": false
|
|
||||||
},
|
|
||||||
"extra_config": {
|
|
||||||
"encryption_preset": "",
|
|
||||||
"openvpn_ipv6": false
|
|
||||||
},
|
|
||||||
"port_forwarding": {
|
|
||||||
"enabled": false,
|
|
||||||
"filepath": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"custom_config": "",
|
"custom_config": "",
|
||||||
"version": ""
|
"version": "",
|
||||||
|
"encryption_preset": "",
|
||||||
|
"ipv6": false,
|
||||||
|
"procuser": "",
|
||||||
|
"interface": ""
|
||||||
}`, string(data))
|
}`, string(data))
|
||||||
var out OpenVPN
|
var out OpenVPN
|
||||||
err = json.Unmarshal(data, &out)
|
err = json.Unmarshal(data, &out)
|
||||||
|
|||||||
@@ -6,55 +6,31 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *Provider) privadoLines() (lines []string) {
|
|
||||||
if len(settings.ServerSelection.Countries) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Countries: "+commaJoin(settings.ServerSelection.Countries))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Regions) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Cities) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Cities: "+commaJoin(settings.ServerSelection.Cities))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Hostnames) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings *Provider) readPrivado(r reader) (err error) {
|
func (settings *Provider) readPrivado(r reader) (err error) {
|
||||||
settings.Name = constants.Privado
|
settings.Name = constants.Privado
|
||||||
|
servers := r.servers.GetPrivado()
|
||||||
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PrivadoCountryChoices())
|
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PrivadoCountryChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PrivadoRegionChoices())
|
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PrivadoRegionChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable REGION: %w", err)
|
return fmt.Errorf("environment variable REGION: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PrivadoCityChoices())
|
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PrivadoCityChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable CITY: %w", err)
|
return fmt.Errorf("environment variable CITY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PrivadoHostnameChoices())
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PrivadoHostnameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,85 +2,35 @@ package configuration
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/golibs/params"
|
"github.com/qdm12/golibs/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *Provider) privateinternetaccessLines() (lines []string) {
|
|
||||||
if len(settings.ServerSelection.Regions) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Hostnames) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Names) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Names: "+commaJoin(settings.ServerSelection.Names))
|
|
||||||
}
|
|
||||||
|
|
||||||
lines = append(lines, lastIndent+"Encryption preset: "+settings.ServerSelection.EncryptionPreset)
|
|
||||||
|
|
||||||
if settings.ServerSelection.CustomPort > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Custom port: "+strconv.Itoa(int(settings.ServerSelection.CustomPort)))
|
|
||||||
}
|
|
||||||
|
|
||||||
if settings.PortForwarding.Enabled {
|
|
||||||
lines = append(lines, lastIndent+"Port forwarding:")
|
|
||||||
for _, line := range settings.PortForwarding.lines() {
|
|
||||||
lines = append(lines, indent+line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings *Provider) readPrivateInternetAccess(r reader) (err error) {
|
func (settings *Provider) readPrivateInternetAccess(r reader) (err error) {
|
||||||
settings.Name = constants.PrivateInternetAccess
|
settings.Name = constants.PrivateInternetAccess
|
||||||
|
servers := r.servers.GetPia()
|
||||||
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
encryptionPreset, err := r.env.Inside("PIA_ENCRYPTION",
|
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PIAGeoChoices(servers))
|
||||||
[]string{constants.PIAEncryptionPresetNone, constants.PIAEncryptionPresetNormal, constants.PIAEncryptionPresetStrong},
|
|
||||||
params.RetroKeys([]string{"ENCRYPTION"}, r.onRetroActive),
|
|
||||||
params.Default(constants.PIACertificateStrong),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("environment variable PIA_ENCRYPTION: %w", err)
|
|
||||||
}
|
|
||||||
settings.ServerSelection.EncryptionPreset = encryptionPreset
|
|
||||||
settings.ExtraConfigOptions.EncryptionPreset = encryptionPreset
|
|
||||||
|
|
||||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PIAGeoChoices())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable REGION: %w", err)
|
return fmt.Errorf("environment variable REGION: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PIAHostnameChoices())
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PIAHostnameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_NAME", constants.PIANameChoices())
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_NAME", constants.PIANameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_NAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_NAME: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.CustomPort, err = readPortOrZero(r.env, "PORT")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("environment variable PORT: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.PortForwarding.Enabled, err = r.env.OnOff("PORT_FORWARDING", params.Default("off"))
|
settings.PortForwarding.Enabled, err = r.env.OnOff("PORT_FORWARDING", params.Default("off"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable PORT_FORWARDING: %w", err)
|
return fmt.Errorf("environment variable PORT_FORWARDING: %w", err)
|
||||||
@@ -94,5 +44,32 @@ func (settings *Provider) readPrivateInternetAccess(r reader) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return settings.ServerSelection.OpenVPN.readPrivateInternetAccess(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *OpenVPNSelection) readPrivateInternetAccess(r reader) (err error) {
|
||||||
|
settings.EncPreset, err = getPIAEncryptionPreset(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.CustomPort, err = readPortOrZero(r.env, "PORT")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("environment variable PORT: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getPIAEncryptionPreset(r reader) (encryptionPreset string, err error) {
|
||||||
|
encryptionPreset, err = r.env.Inside("PIA_ENCRYPTION",
|
||||||
|
[]string{constants.PIAEncryptionPresetNone, constants.PIAEncryptionPresetNormal, constants.PIAEncryptionPresetStrong},
|
||||||
|
params.RetroKeys([]string{"ENCRYPTION"}, r.onRetroActive),
|
||||||
|
params.Default(constants.PIACertificateStrong),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("environment variable PIA_ENCRYPTION: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return encryptionPreset, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,49 +6,30 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *Provider) privatevpnLines() (lines []string) {
|
|
||||||
if len(settings.ServerSelection.Countries) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Countries: "+commaJoin(settings.ServerSelection.Countries))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Cities) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Cities: "+commaJoin(settings.ServerSelection.Cities))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Hostnames) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings *Provider) readPrivatevpn(r reader) (err error) {
|
func (settings *Provider) readPrivatevpn(r reader) (err error) {
|
||||||
settings.Name = constants.Privatevpn
|
settings.Name = constants.Privatevpn
|
||||||
|
servers := r.servers.GetPrivatevpn()
|
||||||
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PrivatevpnCountryChoices())
|
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PrivatevpnCountryChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PrivatevpnCityChoices())
|
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PrivatevpnCityChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable CITY: %w", err)
|
return fmt.Errorf("environment variable CITY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PrivatevpnHostnameChoices())
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||||
|
constants.PrivatevpnHostnameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return settings.ServerSelection.OpenVPN.readProtocolAndPort(r.env)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,73 +7,37 @@ import (
|
|||||||
"github.com/qdm12/golibs/params"
|
"github.com/qdm12/golibs/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *Provider) protonvpnLines() (lines []string) {
|
|
||||||
if len(settings.ServerSelection.Countries) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Countries: "+commaJoin(settings.ServerSelection.Countries))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Regions) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Cities) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Cities: "+commaJoin(settings.ServerSelection.Cities))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Names) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Names: "+commaJoin(settings.ServerSelection.Names))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Hostnames) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
|
||||||
}
|
|
||||||
|
|
||||||
if settings.ServerSelection.FreeOnly {
|
|
||||||
lines = append(lines, lastIndent+"Free only: yes")
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings *Provider) readProtonvpn(r reader) (err error) {
|
func (settings *Provider) readProtonvpn(r reader) (err error) {
|
||||||
settings.Name = constants.Protonvpn
|
settings.Name = constants.Protonvpn
|
||||||
|
servers := r.servers.GetProtonvpn()
|
||||||
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.CustomPort, err = readPortOrZero(r.env, "PORT")
|
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.ProtonvpnCountryChoices(servers))
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("environment variable PORT: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.ProtonvpnCountryChoices())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.ProtonvpnRegionChoices())
|
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.ProtonvpnRegionChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable REGION: %w", err)
|
return fmt.Errorf("environment variable REGION: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.ProtonvpnCityChoices())
|
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.ProtonvpnCityChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable CITY: %w", err)
|
return fmt.Errorf("environment variable CITY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Names, err = r.env.CSVInside("SERVER_NAME", constants.ProtonvpnNameChoices())
|
settings.ServerSelection.Names, err = r.env.CSVInside("SERVER_NAME", constants.ProtonvpnNameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_NAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_NAME: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.ProtonvpnHostnameChoices())
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||||
|
constants.ProtonvpnHostnameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||||
}
|
}
|
||||||
@@ -83,5 +47,5 @@ func (settings *Provider) readProtonvpn(r reader) (err error) {
|
|||||||
return fmt.Errorf("environment variable FREE_ONLY: %w", err)
|
return fmt.Errorf("environment variable FREE_ONLY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return settings.ServerSelection.OpenVPN.readProtocolAndPort(r.env)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package configuration
|
package configuration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -11,81 +12,116 @@ import (
|
|||||||
|
|
||||||
// Provider contains settings specific to a VPN provider.
|
// Provider contains settings specific to a VPN provider.
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
ServerSelection ServerSelection `json:"server_selection"`
|
ServerSelection ServerSelection `json:"server_selection"`
|
||||||
ExtraConfigOptions ExtraConfigOptions `json:"extra_config"`
|
PortForwarding PortForwarding `json:"port_forwarding"`
|
||||||
PortForwarding PortForwarding `json:"port_forwarding"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (settings *Provider) lines() (lines []string) {
|
func (settings *Provider) lines() (lines []string) {
|
||||||
|
if settings.Name == "" { // custom OpenVPN configuration
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
lines = append(lines, lastIndent+strings.Title(settings.Name)+" settings:")
|
lines = append(lines, lastIndent+strings.Title(settings.Name)+" settings:")
|
||||||
|
|
||||||
selection := settings.ServerSelection
|
for _, line := range settings.ServerSelection.toLines() {
|
||||||
|
|
||||||
lines = append(lines, indent+lastIndent+"Network protocol: "+protoToString(selection.TCP))
|
|
||||||
|
|
||||||
if selection.TargetIP != nil {
|
|
||||||
lines = append(lines, indent+lastIndent+"Target IP address: "+selection.TargetIP.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
var providerLines []string
|
|
||||||
switch strings.ToLower(settings.Name) {
|
|
||||||
case "cyberghost":
|
|
||||||
providerLines = settings.cyberghostLines()
|
|
||||||
case "fastestvpn":
|
|
||||||
providerLines = settings.fastestvpnLines()
|
|
||||||
case "hidemyass":
|
|
||||||
providerLines = settings.hideMyAssLines()
|
|
||||||
case "ipvanish":
|
|
||||||
providerLines = settings.ipvanishLines()
|
|
||||||
case "ivpn":
|
|
||||||
providerLines = settings.ivpnLines()
|
|
||||||
case "mullvad":
|
|
||||||
providerLines = settings.mullvadLines()
|
|
||||||
case "nordvpn":
|
|
||||||
providerLines = settings.nordvpnLines()
|
|
||||||
case "privado":
|
|
||||||
providerLines = settings.privadoLines()
|
|
||||||
case "privatevpn":
|
|
||||||
providerLines = settings.privatevpnLines()
|
|
||||||
case "private internet access":
|
|
||||||
providerLines = settings.privateinternetaccessLines()
|
|
||||||
case "protonvpn":
|
|
||||||
providerLines = settings.protonvpnLines()
|
|
||||||
case "purevpn":
|
|
||||||
providerLines = settings.purevpnLines()
|
|
||||||
case "surfshark":
|
|
||||||
providerLines = settings.surfsharkLines()
|
|
||||||
case "torguard":
|
|
||||||
providerLines = settings.torguardLines()
|
|
||||||
case strings.ToLower(constants.VPNUnlimited):
|
|
||||||
providerLines = settings.vpnUnlimitedLines()
|
|
||||||
case "vyprvpn":
|
|
||||||
providerLines = settings.vyprvpnLines()
|
|
||||||
case "windscribe":
|
|
||||||
providerLines = settings.windscribeLines()
|
|
||||||
default:
|
|
||||||
panic(`Missing lines method for provider "` +
|
|
||||||
settings.Name + `"! Please create a Github issue.`)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, line := range providerLines {
|
|
||||||
lines = append(lines, indent+line)
|
lines = append(lines, indent+line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if settings.PortForwarding.Enabled { // PIA
|
||||||
|
lines = append(lines, indent+lastIndent+"Port forwarding:")
|
||||||
|
for _, line := range settings.PortForwarding.lines() {
|
||||||
|
lines = append(lines, indent+indent+line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return lines
|
return lines
|
||||||
}
|
}
|
||||||
|
|
||||||
func commaJoin(slice []string) string {
|
var (
|
||||||
return strings.Join(slice, ", ")
|
ErrInvalidVPNProvider = errors.New("invalid VPN provider")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *Provider) read(r reader, vpnType string) error {
|
||||||
|
err := settings.readVPNServiceProvider(r, vpnType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch settings.Name {
|
||||||
|
case constants.Cyberghost:
|
||||||
|
err = settings.readCyberghost(r)
|
||||||
|
case constants.Fastestvpn:
|
||||||
|
err = settings.readFastestvpn(r)
|
||||||
|
case constants.HideMyAss:
|
||||||
|
err = settings.readHideMyAss(r)
|
||||||
|
case constants.Ipvanish:
|
||||||
|
err = settings.readIpvanish(r)
|
||||||
|
case constants.Ivpn:
|
||||||
|
err = settings.readIvpn(r)
|
||||||
|
case constants.Mullvad:
|
||||||
|
err = settings.readMullvad(r)
|
||||||
|
case constants.Nordvpn:
|
||||||
|
err = settings.readNordvpn(r)
|
||||||
|
case constants.Privado:
|
||||||
|
err = settings.readPrivado(r)
|
||||||
|
case constants.PrivateInternetAccess:
|
||||||
|
err = settings.readPrivateInternetAccess(r)
|
||||||
|
case constants.Privatevpn:
|
||||||
|
err = settings.readPrivatevpn(r)
|
||||||
|
case constants.Protonvpn:
|
||||||
|
err = settings.readProtonvpn(r)
|
||||||
|
case constants.Purevpn:
|
||||||
|
err = settings.readPurevpn(r)
|
||||||
|
case constants.Surfshark:
|
||||||
|
err = settings.readSurfshark(r)
|
||||||
|
case constants.Torguard:
|
||||||
|
err = settings.readTorguard(r)
|
||||||
|
case constants.VPNUnlimited:
|
||||||
|
err = settings.readVPNUnlimited(r)
|
||||||
|
case constants.Vyprvpn:
|
||||||
|
err = settings.readVyprvpn(r)
|
||||||
|
case constants.Windscribe:
|
||||||
|
err = settings.readWindscribe(r)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("%w: %s", ErrInvalidVPNProvider, settings.Name)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.VPN = vpnType
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readProtocol(env params.Env) (tcp bool, err error) {
|
func (settings *Provider) readVPNServiceProvider(r reader, vpnType string) (err error) {
|
||||||
protocol, err := env.Inside("PROTOCOL", []string{constants.TCP, constants.UDP}, params.Default(constants.UDP))
|
var allowedVPNServiceProviders []string
|
||||||
if err != nil {
|
switch vpnType {
|
||||||
return false, fmt.Errorf("environment variable PROTOCOL: %w", err)
|
case constants.OpenVPN:
|
||||||
|
allowedVPNServiceProviders = []string{
|
||||||
|
"cyberghost", "fastestvpn", "hidemyass", "ipvanish", "ivpn", "mullvad", "nordvpn",
|
||||||
|
"privado", "pia", "private internet access", "privatevpn", "protonvpn",
|
||||||
|
"purevpn", "surfshark", "torguard", constants.VPNUnlimited, "vyprvpn", "windscribe"}
|
||||||
|
case constants.Wireguard:
|
||||||
|
allowedVPNServiceProviders = []string{constants.Mullvad, constants.Windscribe,
|
||||||
|
constants.Ivpn}
|
||||||
}
|
}
|
||||||
return protocol == constants.TCP, nil
|
|
||||||
|
vpnsp, err := r.env.Inside("VPNSP", allowedVPNServiceProviders,
|
||||||
|
params.Default("private internet access"))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("environment variable VPNSP: %w", err)
|
||||||
|
}
|
||||||
|
if vpnsp == "pia" { // retro compatibility
|
||||||
|
vpnsp = "private internet access"
|
||||||
|
}
|
||||||
|
settings.Name = vpnsp
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func commaJoin(slice []string) string {
|
||||||
|
return strings.Join(slice, ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func protoToString(tcp bool) string {
|
func protoToString(tcp bool) string {
|
||||||
@@ -95,7 +131,7 @@ func protoToString(tcp bool) string {
|
|||||||
return constants.UDP
|
return constants.UDP
|
||||||
}
|
}
|
||||||
|
|
||||||
func readTargetIP(env params.Env) (targetIP net.IP, err error) {
|
func readTargetIP(env params.Interface) (targetIP net.IP, err error) {
|
||||||
targetIP, err = readIP(env, "OPENVPN_TARGET_IP")
|
targetIP, err = readIP(env, "OPENVPN_TARGET_IP")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("environment variable OPENVPN_TARGET_IP: %w", err)
|
return nil, fmt.Errorf("environment variable OPENVPN_TARGET_IP: %w", err)
|
||||||
@@ -103,7 +139,7 @@ func readTargetIP(env params.Env) (targetIP net.IP, err error) {
|
|||||||
return targetIP, nil
|
return targetIP, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readCustomPort(env params.Env, tcp bool,
|
func readOpenVPNCustomPort(env params.Interface, tcp bool,
|
||||||
allowedTCP, allowedUDP []uint16) (port uint16, err error) {
|
allowedTCP, allowedUDP []uint16) (port uint16, err error) {
|
||||||
port, err = readPortOrZero(env, "PORT")
|
port, err = readPortOrZero(env, "PORT")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -118,12 +154,48 @@ func readCustomPort(env params.Env, tcp bool,
|
|||||||
return port, nil
|
return port, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0, fmt.Errorf("environment variable PORT: %w: port %d for TCP protocol", ErrInvalidPort, port)
|
return 0, fmt.Errorf(
|
||||||
|
"environment variable PORT: %w: port %d for TCP protocol, can only be one of %s",
|
||||||
|
ErrInvalidPort, port, portsToString(allowedTCP))
|
||||||
}
|
}
|
||||||
for i := range allowedUDP {
|
for i := range allowedUDP {
|
||||||
if allowedUDP[i] == port {
|
if allowedUDP[i] == port {
|
||||||
return port, nil
|
return port, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0, fmt.Errorf("environment variable PORT: %w: port %d for UDP protocol", ErrInvalidPort, port)
|
return 0, fmt.Errorf(
|
||||||
|
"environment variable PORT: %w: port %d for UDP protocol, can only be one of %s",
|
||||||
|
ErrInvalidPort, port, portsToString(allowedUDP))
|
||||||
|
}
|
||||||
|
|
||||||
|
// note: set allowed to an empty slice to allow all valid ports
|
||||||
|
func readWireguardCustomPort(env params.Interface, allowed []uint16) (port uint16, err error) {
|
||||||
|
port, err = readPortOrZero(env, "WIREGUARD_PORT")
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("environment variable WIREGUARD_PORT: %w", err)
|
||||||
|
} else if port == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(allowed) == 0 {
|
||||||
|
return port, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range allowed {
|
||||||
|
if allowed[i] == port {
|
||||||
|
return port, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, fmt.Errorf(
|
||||||
|
"environment variable WIREGUARD_PORT: %w: port %d, can only be one of %s",
|
||||||
|
ErrInvalidPort, port, portsToString(allowed))
|
||||||
|
}
|
||||||
|
|
||||||
|
func portsToString(ports []uint16) string {
|
||||||
|
slice := make([]string, len(ports))
|
||||||
|
for i := range ports {
|
||||||
|
slice[i] = fmt.Sprint(ports[i])
|
||||||
|
}
|
||||||
|
return strings.Join(slice, ", ")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,42 +24,41 @@ func Test_Provider_lines(t *testing.T) {
|
|||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Cyberghost,
|
Name: constants.Cyberghost,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
Group: "group",
|
VPN: constants.OpenVPN,
|
||||||
|
Groups: []string{"group"},
|
||||||
Regions: []string{"a", "El country"},
|
Regions: []string{"a", "El country"},
|
||||||
},
|
},
|
||||||
ExtraConfigOptions: ExtraConfigOptions{
|
|
||||||
ClientKey: "a",
|
|
||||||
ClientCertificate: "a",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"|--Cyberghost settings:",
|
"|--Cyberghost settings:",
|
||||||
" |--Network protocol: udp",
|
" |--Server groups: group",
|
||||||
" |--Server group: group",
|
|
||||||
" |--Regions: a, El country",
|
" |--Regions: a, El country",
|
||||||
" |--Client key is set",
|
" |--OpenVPN selection:",
|
||||||
" |--Client certificate is set",
|
" |--Protocol: udp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"fastestvpn": {
|
"fastestvpn": {
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Fastestvpn,
|
Name: constants.Fastestvpn,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
|
VPN: constants.OpenVPN,
|
||||||
Hostnames: []string{"a", "b"},
|
Hostnames: []string{"a", "b"},
|
||||||
Countries: []string{"c", "d"},
|
Countries: []string{"c", "d"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"|--Fastestvpn settings:",
|
"|--Fastestvpn settings:",
|
||||||
" |--Network protocol: udp",
|
|
||||||
" |--Hostnames: a, b",
|
|
||||||
" |--Countries: c, d",
|
" |--Countries: c, d",
|
||||||
|
" |--Hostnames: a, b",
|
||||||
|
" |--OpenVPN selection:",
|
||||||
|
" |--Protocol: udp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"hidemyass": {
|
"hidemyass": {
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.HideMyAss,
|
Name: constants.HideMyAss,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
|
VPN: constants.OpenVPN,
|
||||||
Countries: []string{"a", "b"},
|
Countries: []string{"a", "b"},
|
||||||
Cities: []string{"c", "d"},
|
Cities: []string{"c", "d"},
|
||||||
Hostnames: []string{"e", "f"},
|
Hostnames: []string{"e", "f"},
|
||||||
@@ -67,16 +66,18 @@ func Test_Provider_lines(t *testing.T) {
|
|||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"|--Hidemyass settings:",
|
"|--Hidemyass settings:",
|
||||||
" |--Network protocol: udp",
|
|
||||||
" |--Countries: a, b",
|
" |--Countries: a, b",
|
||||||
" |--Cities: c, d",
|
" |--Cities: c, d",
|
||||||
" |--Hostnames: e, f",
|
" |--Hostnames: e, f",
|
||||||
|
" |--OpenVPN selection:",
|
||||||
|
" |--Protocol: udp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"ipvanish": {
|
"ipvanish": {
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Ipvanish,
|
Name: constants.Ipvanish,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
|
VPN: constants.OpenVPN,
|
||||||
Countries: []string{"a", "b"},
|
Countries: []string{"a", "b"},
|
||||||
Cities: []string{"c", "d"},
|
Cities: []string{"c", "d"},
|
||||||
Hostnames: []string{"e", "f"},
|
Hostnames: []string{"e", "f"},
|
||||||
@@ -84,16 +85,18 @@ func Test_Provider_lines(t *testing.T) {
|
|||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"|--Ipvanish settings:",
|
"|--Ipvanish settings:",
|
||||||
" |--Network protocol: udp",
|
|
||||||
" |--Countries: a, b",
|
" |--Countries: a, b",
|
||||||
" |--Cities: c, d",
|
" |--Cities: c, d",
|
||||||
" |--Hostnames: e, f",
|
" |--Hostnames: e, f",
|
||||||
|
" |--OpenVPN selection:",
|
||||||
|
" |--Protocol: udp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"ivpn": {
|
"ivpn": {
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Ivpn,
|
Name: constants.Ivpn,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
|
VPN: constants.OpenVPN,
|
||||||
Countries: []string{"a", "b"},
|
Countries: []string{"a", "b"},
|
||||||
Cities: []string{"c", "d"},
|
Cities: []string{"c", "d"},
|
||||||
Hostnames: []string{"e", "f"},
|
Hostnames: []string{"e", "f"},
|
||||||
@@ -101,67 +104,73 @@ func Test_Provider_lines(t *testing.T) {
|
|||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"|--Ivpn settings:",
|
"|--Ivpn settings:",
|
||||||
" |--Network protocol: udp",
|
|
||||||
" |--Countries: a, b",
|
" |--Countries: a, b",
|
||||||
" |--Cities: c, d",
|
" |--Cities: c, d",
|
||||||
" |--Hostnames: e, f",
|
" |--Hostnames: e, f",
|
||||||
|
" |--OpenVPN selection:",
|
||||||
|
" |--Protocol: udp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"mullvad": {
|
"mullvad": {
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Mullvad,
|
Name: constants.Mullvad,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
Countries: []string{"a", "b"},
|
VPN: constants.OpenVPN,
|
||||||
Cities: []string{"c", "d"},
|
Countries: []string{"a", "b"},
|
||||||
ISPs: []string{"e", "f"},
|
Cities: []string{"c", "d"},
|
||||||
CustomPort: 1,
|
ISPs: []string{"e", "f"},
|
||||||
},
|
OpenVPN: OpenVPNSelection{
|
||||||
ExtraConfigOptions: ExtraConfigOptions{
|
CustomPort: 1,
|
||||||
OpenVPNIPv6: true,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"|--Mullvad settings:",
|
"|--Mullvad settings:",
|
||||||
" |--Network protocol: udp",
|
|
||||||
" |--Countries: a, b",
|
" |--Countries: a, b",
|
||||||
" |--Cities: c, d",
|
" |--Cities: c, d",
|
||||||
" |--ISPs: e, f",
|
" |--ISPs: e, f",
|
||||||
" |--Custom port: 1",
|
" |--OpenVPN selection:",
|
||||||
" |--IPv6: enabled",
|
" |--Protocol: udp",
|
||||||
|
" |--Custom port: 1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"nordvpn": {
|
"nordvpn": {
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Nordvpn,
|
Name: constants.Nordvpn,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
|
VPN: constants.OpenVPN,
|
||||||
Regions: []string{"a", "b"},
|
Regions: []string{"a", "b"},
|
||||||
Numbers: []uint16{1, 2},
|
Numbers: []uint16{1, 2},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"|--Nordvpn settings:",
|
"|--Nordvpn settings:",
|
||||||
" |--Network protocol: udp",
|
|
||||||
" |--Regions: a, b",
|
" |--Regions: a, b",
|
||||||
" |--Numbers: 1, 2",
|
" |--Numbers: 1, 2",
|
||||||
|
" |--OpenVPN selection:",
|
||||||
|
" |--Protocol: udp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"privado": {
|
"privado": {
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Privado,
|
Name: constants.Privado,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
|
VPN: constants.OpenVPN,
|
||||||
Hostnames: []string{"a", "b"},
|
Hostnames: []string{"a", "b"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"|--Privado settings:",
|
"|--Privado settings:",
|
||||||
" |--Network protocol: udp",
|
|
||||||
" |--Hostnames: a, b",
|
" |--Hostnames: a, b",
|
||||||
|
" |--OpenVPN selection:",
|
||||||
|
" |--Protocol: udp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"privatevpn": {
|
"privatevpn": {
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Privatevpn,
|
Name: constants.Privatevpn,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
|
VPN: constants.OpenVPN,
|
||||||
Hostnames: []string{"a", "b"},
|
Hostnames: []string{"a", "b"},
|
||||||
Countries: []string{"c", "d"},
|
Countries: []string{"c", "d"},
|
||||||
Cities: []string{"e", "f"},
|
Cities: []string{"e", "f"},
|
||||||
@@ -169,16 +178,18 @@ func Test_Provider_lines(t *testing.T) {
|
|||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"|--Privatevpn settings:",
|
"|--Privatevpn settings:",
|
||||||
" |--Network protocol: udp",
|
|
||||||
" |--Countries: c, d",
|
" |--Countries: c, d",
|
||||||
" |--Cities: e, f",
|
" |--Cities: e, f",
|
||||||
" |--Hostnames: a, b",
|
" |--Hostnames: a, b",
|
||||||
|
" |--OpenVPN selection:",
|
||||||
|
" |--Protocol: udp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"protonvpn": {
|
"protonvpn": {
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Protonvpn,
|
Name: constants.Protonvpn,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
|
VPN: constants.OpenVPN,
|
||||||
Countries: []string{"a", "b"},
|
Countries: []string{"a", "b"},
|
||||||
Regions: []string{"c", "d"},
|
Regions: []string{"c", "d"},
|
||||||
Cities: []string{"e", "f"},
|
Cities: []string{"e", "f"},
|
||||||
@@ -188,21 +199,24 @@ func Test_Provider_lines(t *testing.T) {
|
|||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"|--Protonvpn settings:",
|
"|--Protonvpn settings:",
|
||||||
" |--Network protocol: udp",
|
|
||||||
" |--Countries: a, b",
|
" |--Countries: a, b",
|
||||||
" |--Regions: c, d",
|
" |--Regions: c, d",
|
||||||
" |--Cities: e, f",
|
" |--Cities: e, f",
|
||||||
" |--Names: g, h",
|
|
||||||
" |--Hostnames: i, j",
|
" |--Hostnames: i, j",
|
||||||
|
" |--Names: g, h",
|
||||||
|
" |--OpenVPN selection:",
|
||||||
|
" |--Protocol: udp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"private internet access": {
|
"private internet access": {
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.PrivateInternetAccess,
|
Name: constants.PrivateInternetAccess,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
Regions: []string{"a", "b"},
|
VPN: constants.OpenVPN,
|
||||||
EncryptionPreset: constants.PIAEncryptionPresetStrong,
|
Regions: []string{"a", "b"},
|
||||||
CustomPort: 1,
|
OpenVPN: OpenVPNSelection{
|
||||||
|
CustomPort: 1,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
PortForwarding: PortForwarding{
|
PortForwarding: PortForwarding{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
@@ -211,10 +225,10 @@ func Test_Provider_lines(t *testing.T) {
|
|||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"|--Private Internet Access settings:",
|
"|--Private Internet Access settings:",
|
||||||
" |--Network protocol: udp",
|
|
||||||
" |--Regions: a, b",
|
" |--Regions: a, b",
|
||||||
" |--Encryption preset: strong",
|
" |--OpenVPN selection:",
|
||||||
" |--Custom port: 1",
|
" |--Protocol: udp",
|
||||||
|
" |--Custom port: 1",
|
||||||
" |--Port forwarding:",
|
" |--Port forwarding:",
|
||||||
" |--File path: /here",
|
" |--File path: /here",
|
||||||
},
|
},
|
||||||
@@ -223,6 +237,7 @@ func Test_Provider_lines(t *testing.T) {
|
|||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Purevpn,
|
Name: constants.Purevpn,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
|
VPN: constants.OpenVPN,
|
||||||
Regions: []string{"a", "b"},
|
Regions: []string{"a", "b"},
|
||||||
Countries: []string{"c", "d"},
|
Countries: []string{"c", "d"},
|
||||||
Cities: []string{"e", "f"},
|
Cities: []string{"e", "f"},
|
||||||
@@ -230,29 +245,33 @@ func Test_Provider_lines(t *testing.T) {
|
|||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"|--Purevpn settings:",
|
"|--Purevpn settings:",
|
||||||
" |--Network protocol: udp",
|
|
||||||
" |--Regions: a, b",
|
|
||||||
" |--Countries: c, d",
|
" |--Countries: c, d",
|
||||||
|
" |--Regions: a, b",
|
||||||
" |--Cities: e, f",
|
" |--Cities: e, f",
|
||||||
|
" |--OpenVPN selection:",
|
||||||
|
" |--Protocol: udp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"surfshark": {
|
"surfshark": {
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Surfshark,
|
Name: constants.Surfshark,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
|
VPN: constants.OpenVPN,
|
||||||
Regions: []string{"a", "b"},
|
Regions: []string{"a", "b"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"|--Surfshark settings:",
|
"|--Surfshark settings:",
|
||||||
" |--Network protocol: udp",
|
|
||||||
" |--Regions: a, b",
|
" |--Regions: a, b",
|
||||||
|
" |--OpenVPN selection:",
|
||||||
|
" |--Protocol: udp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"torguard": {
|
"torguard": {
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Torguard,
|
Name: constants.Torguard,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
|
VPN: constants.OpenVPN,
|
||||||
Countries: []string{"a", "b"},
|
Countries: []string{"a", "b"},
|
||||||
Cities: []string{"c", "d"},
|
Cities: []string{"c", "d"},
|
||||||
Hostnames: []string{"e"},
|
Hostnames: []string{"e"},
|
||||||
@@ -260,67 +279,72 @@ func Test_Provider_lines(t *testing.T) {
|
|||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"|--Torguard settings:",
|
"|--Torguard settings:",
|
||||||
" |--Network protocol: udp",
|
|
||||||
" |--Countries: a, b",
|
" |--Countries: a, b",
|
||||||
" |--Cities: c, d",
|
" |--Cities: c, d",
|
||||||
" |--Hostnames: e",
|
" |--Hostnames: e",
|
||||||
|
" |--OpenVPN selection:",
|
||||||
|
" |--Protocol: udp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
constants.VPNUnlimited: {
|
constants.VPNUnlimited: {
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.VPNUnlimited,
|
Name: constants.VPNUnlimited,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
|
VPN: constants.OpenVPN,
|
||||||
Countries: []string{"a", "b"},
|
Countries: []string{"a", "b"},
|
||||||
Cities: []string{"c", "d"},
|
Cities: []string{"c", "d"},
|
||||||
Hostnames: []string{"e", "f"},
|
Hostnames: []string{"e", "f"},
|
||||||
FreeOnly: true,
|
FreeOnly: true,
|
||||||
StreamOnly: true,
|
StreamOnly: true,
|
||||||
},
|
},
|
||||||
ExtraConfigOptions: ExtraConfigOptions{
|
|
||||||
ClientKey: "a",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"|--Vpn Unlimited settings:",
|
"|--Vpn Unlimited settings:",
|
||||||
" |--Network protocol: udp",
|
|
||||||
" |--Countries: a, b",
|
" |--Countries: a, b",
|
||||||
" |--Cities: c, d",
|
" |--Cities: c, d",
|
||||||
" |--Hostnames: e, f",
|
|
||||||
" |--Free servers only",
|
" |--Free servers only",
|
||||||
" |--Stream servers only",
|
" |--Stream servers only",
|
||||||
" |--Client key is set",
|
" |--Hostnames: e, f",
|
||||||
|
" |--OpenVPN selection:",
|
||||||
|
" |--Protocol: udp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"vyprvpn": {
|
"vyprvpn": {
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Vyprvpn,
|
Name: constants.Vyprvpn,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
|
VPN: constants.OpenVPN,
|
||||||
Regions: []string{"a", "b"},
|
Regions: []string{"a", "b"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"|--Vyprvpn settings:",
|
"|--Vyprvpn settings:",
|
||||||
" |--Network protocol: udp",
|
|
||||||
" |--Regions: a, b",
|
" |--Regions: a, b",
|
||||||
|
" |--OpenVPN selection:",
|
||||||
|
" |--Protocol: udp",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"windscribe": {
|
"windscribe": {
|
||||||
settings: Provider{
|
settings: Provider{
|
||||||
Name: constants.Windscribe,
|
Name: constants.Windscribe,
|
||||||
ServerSelection: ServerSelection{
|
ServerSelection: ServerSelection{
|
||||||
Regions: []string{"a", "b"},
|
VPN: constants.OpenVPN,
|
||||||
Cities: []string{"c", "d"},
|
Regions: []string{"a", "b"},
|
||||||
Hostnames: []string{"e", "f"},
|
Cities: []string{"c", "d"},
|
||||||
CustomPort: 1,
|
Hostnames: []string{"e", "f"},
|
||||||
|
OpenVPN: OpenVPNSelection{
|
||||||
|
CustomPort: 1,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"|--Windscribe settings:",
|
"|--Windscribe settings:",
|
||||||
" |--Network protocol: udp",
|
|
||||||
" |--Regions: a, b",
|
" |--Regions: a, b",
|
||||||
" |--Cities: c, d",
|
" |--Cities: c, d",
|
||||||
" |--Hostnames: e, f",
|
" |--Hostnames: e, f",
|
||||||
" |--Custom port: 1",
|
" |--OpenVPN selection:",
|
||||||
|
" |--Protocol: udp",
|
||||||
|
" |--Custom port: 1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -362,7 +386,7 @@ func Test_readProtocol(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
|
|
||||||
env := mock_params.NewMockEnv(ctrl)
|
env := mock_params.NewMockInterface(ctrl)
|
||||||
env.EXPECT().
|
env.EXPECT().
|
||||||
Inside("PROTOCOL", []string{"tcp", "udp"}, gomock.Any()).
|
Inside("PROTOCOL", []string{"tcp", "udp"}, gomock.Any()).
|
||||||
Return(testCase.mockStr, testCase.mockErr)
|
Return(testCase.mockStr, testCase.mockErr)
|
||||||
|
|||||||
@@ -6,58 +6,34 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *Provider) purevpnLines() (lines []string) {
|
|
||||||
if len(settings.ServerSelection.Regions) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Countries) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Countries: "+commaJoin(settings.ServerSelection.Countries))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Cities) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Cities: "+commaJoin(settings.ServerSelection.Cities))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Hostnames) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings *Provider) readPurevpn(r reader) (err error) {
|
func (settings *Provider) readPurevpn(r reader) (err error) {
|
||||||
settings.Name = constants.Purevpn
|
settings.Name = constants.Purevpn
|
||||||
|
servers := r.servers.GetPurevpn()
|
||||||
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PurevpnRegionChoices())
|
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.PurevpnRegionChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable REGION: %w", err)
|
return fmt.Errorf("environment variable REGION: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PurevpnCountryChoices())
|
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.PurevpnCountryChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PurevpnCityChoices())
|
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.PurevpnCityChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable CITY: %w", err)
|
return fmt.Errorf("environment variable CITY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PurevpnHostnameChoices())
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.PurevpnHostnameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return settings.ServerSelection.OpenVPN.readProtocolOnly(r.env)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,22 +7,26 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/params"
|
"github.com/qdm12/golibs/params"
|
||||||
"github.com/qdm12/golibs/verification"
|
"github.com/qdm12/golibs/verification"
|
||||||
)
|
)
|
||||||
|
|
||||||
type reader struct {
|
type reader struct {
|
||||||
env params.Env
|
servers models.AllServers
|
||||||
logger logging.Logger
|
env params.Interface
|
||||||
regex verification.Regex
|
logger logging.Logger
|
||||||
|
regex verification.Regex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newReader(env params.Env, logger logging.Logger) reader {
|
func newReader(env params.Interface,
|
||||||
|
servers models.AllServers, logger logging.Logger) reader {
|
||||||
return reader{
|
return reader{
|
||||||
env: env,
|
servers: servers,
|
||||||
logger: logger,
|
env: env,
|
||||||
regex: verification.NewRegex(),
|
logger: logger,
|
||||||
|
regex: verification.NewRegex(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +40,7 @@ var (
|
|||||||
ErrInvalidPort = errors.New("invalid port")
|
ErrInvalidPort = errors.New("invalid port")
|
||||||
)
|
)
|
||||||
|
|
||||||
func readCSVPorts(env params.Env, key string) (ports []uint16, err error) {
|
func readCSVPorts(env params.Interface, key string) (ports []uint16, err error) {
|
||||||
s, err := env.Get(key)
|
s, err := env.Get(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -63,7 +67,7 @@ var (
|
|||||||
ErrInvalidIPNet = errors.New("invalid IP network")
|
ErrInvalidIPNet = errors.New("invalid IP network")
|
||||||
)
|
)
|
||||||
|
|
||||||
func readCSVIPNets(env params.Env, key string, options ...params.OptionSetter) (
|
func readCSVIPNets(env params.Interface, key string, options ...params.OptionSetter) (
|
||||||
ipNets []net.IPNet, err error) {
|
ipNets []net.IPNet, err error) {
|
||||||
s, err := env.Get(key, options...)
|
s, err := env.Get(key, options...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -92,7 +96,7 @@ var (
|
|||||||
ErrInvalidIP = errors.New("invalid IP address")
|
ErrInvalidIP = errors.New("invalid IP address")
|
||||||
)
|
)
|
||||||
|
|
||||||
func readIP(env params.Env, key string) (ip net.IP, err error) {
|
func readIP(env params.Interface, key string) (ip net.IP, err error) {
|
||||||
s, err := env.Get(key)
|
s, err := env.Get(key)
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -108,13 +112,13 @@ func readIP(env params.Env, key string) (ip net.IP, err error) {
|
|||||||
return ip, nil
|
return ip, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readPortOrZero(env params.Env, key string) (port uint16, err error) {
|
func readPortOrZero(env params.Interface, key string) (port uint16, err error) {
|
||||||
s, err := env.Get(key)
|
s, err := env.Get(key, params.Default("0"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if s == "" || s == "0" {
|
if s == "0" {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
package configuration
|
package configuration
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServerSelection struct { //nolint:maligned
|
type ServerSelection struct { //nolint:maligned
|
||||||
// Common
|
// Common
|
||||||
TCP bool `json:"tcp"` // UDP if TCP is false
|
VPN string `json:"vpn"` // note: this is required
|
||||||
TargetIP net.IP `json:"target_ip,omitempty"`
|
TargetIP net.IP `json:"target_ip,omitempty"`
|
||||||
// TODO comments
|
// TODO comments
|
||||||
// Cyberghost, PIA, Protonvpn, Surfshark, Windscribe, Vyprvpn, NordVPN
|
// Cyberghost, PIA, Protonvpn, Surfshark, Windscribe, Vyprvpn, NordVPN
|
||||||
Regions []string `json:"regions"`
|
Regions []string `json:"regions"`
|
||||||
|
|
||||||
// Cyberghost
|
// Cyberghost
|
||||||
Group string `json:"group"`
|
Groups []string `json:"groups"`
|
||||||
|
|
||||||
// Fastestvpn, HideMyAss, IPVanish, IVPN, Mullvad, PrivateVPN, Protonvpn, PureVPN, VPNUnlimited
|
// Fastestvpn, HideMyAss, IPVanish, IVPN, Mullvad, PrivateVPN, Protonvpn, PureVPN, VPNUnlimited
|
||||||
Countries []string `json:"countries"`
|
Countries []string `json:"countries"`
|
||||||
@@ -27,27 +31,133 @@ type ServerSelection struct { //nolint:maligned
|
|||||||
ISPs []string `json:"isps"`
|
ISPs []string `json:"isps"`
|
||||||
Owned bool `json:"owned"`
|
Owned bool `json:"owned"`
|
||||||
|
|
||||||
// Mullvad, Windscribe, PIA
|
|
||||||
CustomPort uint16 `json:"custom_port"`
|
|
||||||
|
|
||||||
// NordVPN
|
// NordVPN
|
||||||
Numbers []uint16 `json:"numbers"`
|
Numbers []uint16 `json:"numbers"`
|
||||||
|
|
||||||
// PIA
|
|
||||||
EncryptionPreset string `json:"encryption_preset"`
|
|
||||||
|
|
||||||
// ProtonVPN
|
// ProtonVPN
|
||||||
FreeOnly bool `json:"free_only"`
|
FreeOnly bool `json:"free_only"`
|
||||||
|
|
||||||
// VPNUnlimited
|
// VPNUnlimited
|
||||||
StreamOnly bool `json:"stream_only"`
|
StreamOnly bool `json:"stream_only"`
|
||||||
|
|
||||||
|
// Surfshark
|
||||||
|
MultiHopOnly bool `json:"multihop_only"`
|
||||||
|
|
||||||
|
OpenVPN OpenVPNSelection `json:"openvpn"`
|
||||||
|
Wireguard WireguardSelection `json:"wireguard"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExtraConfigOptions struct {
|
func (selection ServerSelection) toLines() (lines []string) {
|
||||||
ClientCertificate string `json:"-"` // Cyberghost
|
if selection.TargetIP != nil {
|
||||||
ClientKey string `json:"-"` // Cyberghost, VPNUnlimited
|
lines = append(lines, lastIndent+"Target IP address: "+selection.TargetIP.String())
|
||||||
EncryptionPreset string `json:"encryption_preset"` // PIA
|
}
|
||||||
OpenVPNIPv6 bool `json:"openvpn_ipv6"` // Mullvad
|
|
||||||
|
if len(selection.Groups) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Server groups: "+commaJoin(selection.Groups))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(selection.Countries) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Countries: "+commaJoin(selection.Countries))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(selection.Regions) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Regions: "+commaJoin(selection.Regions))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(selection.Cities) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Cities: "+commaJoin(selection.Cities))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(selection.ISPs) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"ISPs: "+commaJoin(selection.ISPs))
|
||||||
|
}
|
||||||
|
|
||||||
|
if selection.FreeOnly {
|
||||||
|
lines = append(lines, lastIndent+"Free servers only")
|
||||||
|
}
|
||||||
|
|
||||||
|
if selection.StreamOnly {
|
||||||
|
lines = append(lines, lastIndent+"Stream servers only")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(selection.Hostnames) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(selection.Hostnames))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(selection.Names) > 0 {
|
||||||
|
lines = append(lines, lastIndent+"Names: "+commaJoin(selection.Names))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(selection.Numbers) > 0 {
|
||||||
|
numbersString := make([]string, len(selection.Numbers))
|
||||||
|
for i, numberUint16 := range selection.Numbers {
|
||||||
|
numbersString[i] = fmt.Sprint(numberUint16)
|
||||||
|
}
|
||||||
|
lines = append(lines, lastIndent+"Numbers: "+commaJoin(numbersString))
|
||||||
|
}
|
||||||
|
|
||||||
|
if selection.VPN == constants.OpenVPN {
|
||||||
|
lines = append(lines, selection.OpenVPN.lines()...)
|
||||||
|
} else { // wireguard
|
||||||
|
lines = append(lines, selection.Wireguard.lines()...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
type OpenVPNSelection struct {
|
||||||
|
TCP bool `json:"tcp"` // UDP if TCP is false
|
||||||
|
CustomPort uint16 `json:"custom_port"` // HideMyAss, Mullvad, PIA, ProtonVPN, Windscribe
|
||||||
|
EncPreset string `json:"encryption_preset"` // PIA - needed to get the port number
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *OpenVPNSelection) lines() (lines []string) {
|
||||||
|
lines = append(lines, lastIndent+"OpenVPN selection:")
|
||||||
|
|
||||||
|
lines = append(lines, indent+lastIndent+"Protocol: "+protoToString(settings.TCP))
|
||||||
|
|
||||||
|
if settings.CustomPort != 0 {
|
||||||
|
lines = append(lines, indent+lastIndent+"Custom port: "+fmt.Sprint(settings.CustomPort))
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.EncPreset != "" {
|
||||||
|
lines = append(lines, indent+lastIndent+"PIA encryption preset: "+settings.EncPreset)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *OpenVPNSelection) readProtocolOnly(env params.Interface) (err error) {
|
||||||
|
settings.TCP, err = readProtocol(env)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *OpenVPNSelection) readProtocolAndPort(env params.Interface) (err error) {
|
||||||
|
settings.TCP, err = readProtocol(env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.CustomPort, err = readPortOrZero(env, "PORT")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("environment variable PORT: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type WireguardSelection struct {
|
||||||
|
CustomPort uint16 `json:"custom_port"` // Mullvad
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *WireguardSelection) lines() (lines []string) {
|
||||||
|
lines = append(lines, lastIndent+"Wireguard selection:")
|
||||||
|
|
||||||
|
if settings.CustomPort != 0 {
|
||||||
|
lines = append(lines, indent+lastIndent+"Custom port: "+fmt.Sprint(settings.CustomPort))
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
}
|
}
|
||||||
|
|
||||||
// PortForwarding contains settings for port forwarding.
|
// PortForwarding contains settings for port forwarding.
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
"github.com/qdm12/golibs/params"
|
"github.com/qdm12/golibs/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Settings contains all settings for the program to run.
|
// Settings contains all settings for the program to run.
|
||||||
type Settings struct {
|
type Settings struct {
|
||||||
OpenVPN OpenVPN
|
VPN VPN
|
||||||
System System
|
System System
|
||||||
DNS DNS
|
DNS DNS
|
||||||
Firewall Firewall
|
Firewall Firewall
|
||||||
@@ -22,6 +23,7 @@ type Settings struct {
|
|||||||
VersionInformation bool
|
VersionInformation bool
|
||||||
ControlServer ControlServer
|
ControlServer ControlServer
|
||||||
Health Health
|
Health Health
|
||||||
|
Log Log
|
||||||
}
|
}
|
||||||
|
|
||||||
func (settings *Settings) String() string {
|
func (settings *Settings) String() string {
|
||||||
@@ -30,9 +32,10 @@ func (settings *Settings) String() string {
|
|||||||
|
|
||||||
func (settings *Settings) lines() (lines []string) {
|
func (settings *Settings) lines() (lines []string) {
|
||||||
lines = append(lines, "Settings summary below:")
|
lines = append(lines, "Settings summary below:")
|
||||||
lines = append(lines, settings.OpenVPN.lines()...)
|
lines = append(lines, settings.VPN.lines()...)
|
||||||
lines = append(lines, settings.DNS.lines()...)
|
lines = append(lines, settings.DNS.lines()...)
|
||||||
lines = append(lines, settings.Firewall.lines()...)
|
lines = append(lines, settings.Firewall.lines()...)
|
||||||
|
lines = append(lines, settings.Log.lines()...)
|
||||||
lines = append(lines, settings.System.lines()...)
|
lines = append(lines, settings.System.lines()...)
|
||||||
lines = append(lines, settings.HTTPProxy.lines()...)
|
lines = append(lines, settings.HTTPProxy.lines()...)
|
||||||
lines = append(lines, settings.ShadowSocks.lines()...)
|
lines = append(lines, settings.ShadowSocks.lines()...)
|
||||||
@@ -47,7 +50,7 @@ func (settings *Settings) lines() (lines []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrOpenvpn = errors.New("cannot read Openvpn settings")
|
ErrVPN = errors.New("cannot read VPN settings")
|
||||||
ErrSystem = errors.New("cannot read System settings")
|
ErrSystem = errors.New("cannot read System settings")
|
||||||
ErrDNS = errors.New("cannot read DNS settings")
|
ErrDNS = errors.New("cannot read DNS settings")
|
||||||
ErrFirewall = errors.New("cannot read firewall settings")
|
ErrFirewall = errors.New("cannot read firewall settings")
|
||||||
@@ -57,20 +60,22 @@ var (
|
|||||||
ErrUpdater = errors.New("cannot read Updater settings")
|
ErrUpdater = errors.New("cannot read Updater settings")
|
||||||
ErrPublicIP = errors.New("cannot read Public IP getter settings")
|
ErrPublicIP = errors.New("cannot read Public IP getter settings")
|
||||||
ErrHealth = errors.New("cannot read health settings")
|
ErrHealth = errors.New("cannot read health settings")
|
||||||
|
ErrLog = errors.New("cannot read log settings")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Read obtains all configuration options for the program and returns an error as soon
|
// Read obtains all configuration options for the program and returns an error as soon
|
||||||
// as an error is encountered reading them.
|
// as an error is encountered reading them.
|
||||||
func (settings *Settings) Read(env params.Env, logger logging.Logger) (err error) {
|
func (settings *Settings) Read(env params.Interface, servers models.AllServers,
|
||||||
r := newReader(env, logger)
|
logger logging.Logger) (err error) {
|
||||||
|
r := newReader(env, servers, logger)
|
||||||
|
|
||||||
settings.VersionInformation, err = r.env.OnOff("VERSION_INFORMATION", params.Default("on"))
|
settings.VersionInformation, err = r.env.OnOff("VERSION_INFORMATION", params.Default("on"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable VERSION_INFORMATION: %w", err)
|
return fmt.Errorf("environment variable VERSION_INFORMATION: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := settings.OpenVPN.read(r); err != nil {
|
if err := settings.VPN.read(r); err != nil {
|
||||||
return fmt.Errorf("%w: %s", ErrOpenvpn, err)
|
return fmt.Errorf("%w: %s", ErrVPN, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := settings.System.read(r); err != nil {
|
if err := settings.System.read(r); err != nil {
|
||||||
@@ -113,5 +118,9 @@ func (settings *Settings) Read(env params.Env, logger logging.Logger) (err error
|
|||||||
return fmt.Errorf("%w: %s", ErrHealth, err)
|
return fmt.Errorf("%w: %s", ErrHealth, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := settings.Log.read(r.env); err != nil {
|
||||||
|
return fmt.Errorf("%w: %s", ErrLog, err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,23 +16,35 @@ func Test_Settings_lines(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
"default settings": {
|
"default settings": {
|
||||||
settings: Settings{
|
settings: Settings{
|
||||||
OpenVPN: OpenVPN{
|
VPN: VPN{
|
||||||
Version: constants.Openvpn25,
|
Type: constants.OpenVPN,
|
||||||
Provider: Provider{
|
Provider: Provider{
|
||||||
Name: constants.Mullvad,
|
Name: constants.Mullvad,
|
||||||
|
ServerSelection: ServerSelection{
|
||||||
|
VPN: constants.OpenVPN,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
OpenVPN: OpenVPN{
|
||||||
|
Version: constants.Openvpn25,
|
||||||
|
Interface: "tun",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
lines: []string{
|
lines: []string{
|
||||||
"Settings summary below:",
|
"Settings summary below:",
|
||||||
"|--OpenVPN:",
|
"|--VPN:",
|
||||||
" |--Version: 2.5",
|
" |--Type: openvpn",
|
||||||
" |--Verbosity level: 0",
|
" |--OpenVPN:",
|
||||||
" |--Provider:",
|
" |--Version: 2.5",
|
||||||
" |--Mullvad settings:",
|
" |--Verbosity level: 0",
|
||||||
" |--Network protocol: udp",
|
" |--Network interface: tun",
|
||||||
|
" |--Mullvad settings:",
|
||||||
|
" |--OpenVPN selection:",
|
||||||
|
" |--Protocol: udp",
|
||||||
"|--DNS:",
|
"|--DNS:",
|
||||||
"|--Firewall: disabled ⚠️",
|
"|--Firewall: disabled ⚠️",
|
||||||
|
"|--Log:",
|
||||||
|
" |--Level: DEBUG",
|
||||||
"|--System:",
|
"|--System:",
|
||||||
" |--Process user ID: 0",
|
" |--Process user ID: 0",
|
||||||
" |--Process group ID: 0",
|
" |--Process group ID: 0",
|
||||||
|
|||||||
@@ -2,19 +2,16 @@ package configuration
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/qdm12/golibs/params"
|
"github.com/qdm12/golibs/params"
|
||||||
|
"github.com/qdm12/ss-server/pkg/tcpudp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ShadowSocks contains settings to configure the Shadowsocks server.
|
// ShadowSocks contains settings to configure the Shadowsocks server.
|
||||||
type ShadowSocks struct {
|
type ShadowSocks struct {
|
||||||
Method string
|
Enabled bool
|
||||||
Password string
|
tcpudp.Settings
|
||||||
Port uint16
|
|
||||||
Enabled bool
|
|
||||||
Log bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (settings *ShadowSocks) String() string {
|
func (settings *ShadowSocks) String() string {
|
||||||
@@ -28,12 +25,12 @@ func (settings *ShadowSocks) lines() (lines []string) {
|
|||||||
|
|
||||||
lines = append(lines, lastIndent+"Shadowsocks server:")
|
lines = append(lines, lastIndent+"Shadowsocks server:")
|
||||||
|
|
||||||
lines = append(lines, indent+lastIndent+"Listening port: "+strconv.Itoa(int(settings.Port)))
|
lines = append(lines, indent+lastIndent+"Listening address: "+settings.Address)
|
||||||
|
|
||||||
lines = append(lines, indent+lastIndent+"Method: "+settings.Method)
|
lines = append(lines, indent+lastIndent+"Cipher: "+settings.CipherName)
|
||||||
|
|
||||||
if settings.Log {
|
if settings.LogAddresses {
|
||||||
lines = append(lines, indent+lastIndent+"Logging: enabled")
|
lines = append(lines, indent+lastIndent+"Log addresses: enabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
return lines
|
return lines
|
||||||
@@ -52,24 +49,61 @@ func (settings *ShadowSocks) read(r reader) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.Log, err = r.env.OnOff("SHADOWSOCKS_LOG", params.Default("off"))
|
settings.LogAddresses, err = r.env.OnOff("SHADOWSOCKS_LOG", params.Default("off"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SHADOWSOCKS_LOG: %w", err)
|
return fmt.Errorf("environment variable SHADOWSOCKS_LOG: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.Method, err = r.env.Get("SHADOWSOCKS_METHOD", params.Default("chacha20-ietf-poly1305"))
|
settings.CipherName, err = r.env.Get("SHADOWSOCKS_CIPHER", params.Default("chacha20-ietf-poly1305"),
|
||||||
|
params.RetroKeys([]string{"SHADOWSOCKS_METHOD"}, r.onRetroActive))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SHADOWSOCKS_METHOD: %w", err)
|
return fmt.Errorf("environment variable SHADOWSOCKS_CIPHER (or SHADOWSOCKS_METHOD): %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var warning string
|
warning, err := settings.getAddress(r.env)
|
||||||
settings.Port, warning, err = r.env.ListeningPort("SHADOWSOCKS_PORT", params.Default("8388"))
|
if warning != "" {
|
||||||
if len(warning) > 0 {
|
|
||||||
r.logger.Warn(warning)
|
r.logger.Warn(warning)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SHADOWSOCKS_PORT: %w", err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (settings *ShadowSocks) getAddress(env params.Interface) (
|
||||||
|
warning string, err error) {
|
||||||
|
address, err := env.Get("SHADOWSOCKS_LISTENING_ADDRESS")
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("environment variable SHADOWSOCKS_LISTENING_ADDRESS: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if address != "" {
|
||||||
|
address, warning, err := env.ListeningAddress("SHADOWSOCKS_LISTENING_ADDRESS")
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("environment variable SHADOWSOCKS_LISTENING_ADDRESS: %w", err)
|
||||||
|
}
|
||||||
|
settings.Address = address
|
||||||
|
return warning, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retro-compatibility
|
||||||
|
const retroWarning = "You are using the old environment variable " +
|
||||||
|
"SHADOWSOCKS_PORT, please consider using " +
|
||||||
|
"SHADOWSOCKS_LISTENING_ADDRESS instead"
|
||||||
|
portStr, err := env.Get("SHADOWSOCKS_PORT")
|
||||||
|
if err != nil {
|
||||||
|
return retroWarning, fmt.Errorf("environment variable SHADOWSOCKS_PORT: %w", err)
|
||||||
|
} else if portStr != "" {
|
||||||
|
port, _, err := env.ListeningPort("SHADOWSOCKS_PORT")
|
||||||
|
if err != nil {
|
||||||
|
return retroWarning, fmt.Errorf("environment variable SHADOWSOCKS_PORT: %w", err)
|
||||||
|
}
|
||||||
|
settings.Address = ":" + fmt.Sprint(port)
|
||||||
|
return retroWarning, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default value
|
||||||
|
settings.Address = ":8388"
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,44 +2,101 @@ package configuration
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *Provider) surfsharkLines() (lines []string) {
|
|
||||||
if len(settings.ServerSelection.Regions) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Hostnames) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings *Provider) readSurfshark(r reader) (err error) {
|
func (settings *Provider) readSurfshark(r reader) (err error) {
|
||||||
settings.Name = constants.Surfshark
|
settings.Name = constants.Surfshark
|
||||||
|
servers := r.servers.GetSurfshark()
|
||||||
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.SurfsharkRegionChoices())
|
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.SurfsharkCountryChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable REGION: %w", err)
|
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.SurfsharkHostnameChoices())
|
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.SurfsharkCityChoices(servers))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("environment variable CITY: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||||
|
constants.SurfsharkHostnameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
regionChoices := constants.SurfsharkRegionChoices(servers)
|
||||||
|
regionChoices = append(regionChoices, constants.SurfsharkRetroLocChoices(servers)...)
|
||||||
|
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", regionChoices)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("environment variable REGION: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retro compatibility
|
||||||
|
// TODO remove in v4
|
||||||
|
settings.ServerSelection = surfsharkRetroRegion(settings.ServerSelection)
|
||||||
|
|
||||||
|
settings.ServerSelection.MultiHopOnly, err = r.env.YesNo("MULTIHOP_ONLY", params.Default("no"))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("environment variable MULTIHOP_ONLY: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return settings.ServerSelection.OpenVPN.readProtocolOnly(r.env)
|
||||||
|
}
|
||||||
|
|
||||||
|
func surfsharkRetroRegion(selection ServerSelection) (
|
||||||
|
updatedSelection ServerSelection) {
|
||||||
|
locationData := constants.SurfsharkLocationData()
|
||||||
|
|
||||||
|
retroToLocation := make(map[string]models.SurfsharkLocationData, len(locationData))
|
||||||
|
for _, data := range locationData {
|
||||||
|
if data.RetroLoc == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
retroToLocation[strings.ToLower(data.RetroLoc)] = data
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, region := range selection.Regions {
|
||||||
|
location, ok := retroToLocation[region]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
selection.Regions[i] = strings.ToLower(location.Region)
|
||||||
|
selection.Countries = append(selection.Countries, strings.ToLower(location.Country))
|
||||||
|
selection.Cities = append(selection.Cities, strings.ToLower(location.City)) // even empty string
|
||||||
|
selection.Hostnames = append(selection.Hostnames, location.Hostname)
|
||||||
|
}
|
||||||
|
|
||||||
|
selection.Regions = dedupSlice(selection.Regions)
|
||||||
|
selection.Countries = dedupSlice(selection.Countries)
|
||||||
|
selection.Cities = dedupSlice(selection.Cities)
|
||||||
|
selection.Hostnames = dedupSlice(selection.Hostnames)
|
||||||
|
|
||||||
|
return selection
|
||||||
|
}
|
||||||
|
|
||||||
|
func dedupSlice(slice []string) (deduped []string) {
|
||||||
|
if slice == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
deduped = make([]string, 0, len(slice))
|
||||||
|
seen := make(map[string]struct{}, len(slice))
|
||||||
|
for _, s := range slice {
|
||||||
|
if _, ok := seen[s]; !ok {
|
||||||
|
seen[s] = struct{}{}
|
||||||
|
deduped = append(deduped, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return deduped
|
||||||
}
|
}
|
||||||
|
|||||||
305
internal/configuration/surfshark_test.go
Normal file
305
internal/configuration/surfshark_test.go
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
|
"github.com/qdm12/golibs/params/mock_params"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Provider_readSurfshark(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
var errDummy = errors.New("dummy test error")
|
||||||
|
|
||||||
|
type stringCall struct {
|
||||||
|
call bool
|
||||||
|
value string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type boolCall struct {
|
||||||
|
call bool
|
||||||
|
value bool
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type sliceStringCall struct {
|
||||||
|
call bool
|
||||||
|
values []string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := map[string]struct {
|
||||||
|
targetIP stringCall
|
||||||
|
countries sliceStringCall
|
||||||
|
cities sliceStringCall
|
||||||
|
hostnames sliceStringCall
|
||||||
|
regions sliceStringCall
|
||||||
|
multiHop boolCall
|
||||||
|
protocol stringCall
|
||||||
|
settings Provider
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
"target IP error": {
|
||||||
|
targetIP: stringCall{call: true, value: "something", err: errDummy},
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Surfshark,
|
||||||
|
},
|
||||||
|
err: errors.New("environment variable OPENVPN_TARGET_IP: dummy test error"),
|
||||||
|
},
|
||||||
|
"countries error": {
|
||||||
|
targetIP: stringCall{call: true},
|
||||||
|
countries: sliceStringCall{call: true, err: errDummy},
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Surfshark,
|
||||||
|
},
|
||||||
|
err: errors.New("environment variable COUNTRY: dummy test error"),
|
||||||
|
},
|
||||||
|
"cities error": {
|
||||||
|
targetIP: stringCall{call: true},
|
||||||
|
countries: sliceStringCall{call: true},
|
||||||
|
cities: sliceStringCall{call: true, err: errDummy},
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Surfshark,
|
||||||
|
},
|
||||||
|
err: errors.New("environment variable CITY: dummy test error"),
|
||||||
|
},
|
||||||
|
"hostnames error": {
|
||||||
|
targetIP: stringCall{call: true},
|
||||||
|
countries: sliceStringCall{call: true},
|
||||||
|
cities: sliceStringCall{call: true},
|
||||||
|
hostnames: sliceStringCall{call: true, err: errDummy},
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Surfshark,
|
||||||
|
},
|
||||||
|
err: errors.New("environment variable SERVER_HOSTNAME: dummy test error"),
|
||||||
|
},
|
||||||
|
"regions error": {
|
||||||
|
targetIP: stringCall{call: true},
|
||||||
|
countries: sliceStringCall{call: true},
|
||||||
|
cities: sliceStringCall{call: true},
|
||||||
|
hostnames: sliceStringCall{call: true},
|
||||||
|
regions: sliceStringCall{call: true, err: errDummy},
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Surfshark,
|
||||||
|
},
|
||||||
|
err: errors.New("environment variable REGION: dummy test error"),
|
||||||
|
},
|
||||||
|
"multi hop error": {
|
||||||
|
targetIP: stringCall{call: true},
|
||||||
|
countries: sliceStringCall{call: true},
|
||||||
|
cities: sliceStringCall{call: true},
|
||||||
|
hostnames: sliceStringCall{call: true},
|
||||||
|
regions: sliceStringCall{call: true},
|
||||||
|
multiHop: boolCall{call: true, err: errDummy},
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Surfshark,
|
||||||
|
},
|
||||||
|
err: errors.New("environment variable MULTIHOP_ONLY: dummy test error"),
|
||||||
|
},
|
||||||
|
"openvpn protocol error": {
|
||||||
|
targetIP: stringCall{call: true},
|
||||||
|
countries: sliceStringCall{call: true},
|
||||||
|
cities: sliceStringCall{call: true},
|
||||||
|
hostnames: sliceStringCall{call: true},
|
||||||
|
regions: sliceStringCall{call: true},
|
||||||
|
multiHop: boolCall{call: true},
|
||||||
|
protocol: stringCall{call: true, err: errDummy},
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Surfshark,
|
||||||
|
},
|
||||||
|
err: errors.New("environment variable PROTOCOL: dummy test error"),
|
||||||
|
},
|
||||||
|
"default settings": {
|
||||||
|
targetIP: stringCall{call: true},
|
||||||
|
countries: sliceStringCall{call: true},
|
||||||
|
cities: sliceStringCall{call: true},
|
||||||
|
hostnames: sliceStringCall{call: true},
|
||||||
|
regions: sliceStringCall{call: true},
|
||||||
|
multiHop: boolCall{call: true},
|
||||||
|
protocol: stringCall{call: true},
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Surfshark,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"set settings": {
|
||||||
|
targetIP: stringCall{call: true, value: "1.2.3.4"},
|
||||||
|
countries: sliceStringCall{call: true, values: []string{"A", "B"}},
|
||||||
|
cities: sliceStringCall{call: true, values: []string{"C", "D"}},
|
||||||
|
regions: sliceStringCall{call: true, values: []string{
|
||||||
|
"E", "F", "netherlands amsterdam",
|
||||||
|
}}, // Netherlands Amsterdam is for retro compatibility test
|
||||||
|
multiHop: boolCall{call: true},
|
||||||
|
hostnames: sliceStringCall{call: true, values: []string{"E", "F"}},
|
||||||
|
protocol: stringCall{call: true, value: constants.TCP},
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Surfshark,
|
||||||
|
ServerSelection: ServerSelection{
|
||||||
|
OpenVPN: OpenVPNSelection{
|
||||||
|
TCP: true,
|
||||||
|
},
|
||||||
|
TargetIP: net.IPv4(1, 2, 3, 4),
|
||||||
|
Regions: []string{"E", "F", "europe"},
|
||||||
|
Countries: []string{"A", "B", "netherlands"},
|
||||||
|
Cities: []string{"C", "D", "amsterdam"},
|
||||||
|
Hostnames: []string{"E", "F", "nl-ams.prod.surfshark.com"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"Netherlands Amsterdam": {
|
||||||
|
targetIP: stringCall{call: true},
|
||||||
|
countries: sliceStringCall{call: true},
|
||||||
|
cities: sliceStringCall{call: true},
|
||||||
|
regions: sliceStringCall{call: true, values: []string{"netherlands amsterdam"}},
|
||||||
|
multiHop: boolCall{call: true},
|
||||||
|
hostnames: sliceStringCall{call: true},
|
||||||
|
protocol: stringCall{call: true},
|
||||||
|
settings: Provider{
|
||||||
|
Name: constants.Surfshark,
|
||||||
|
ServerSelection: ServerSelection{
|
||||||
|
Regions: []string{"europe"},
|
||||||
|
Countries: []string{"netherlands"},
|
||||||
|
Cities: []string{"amsterdam"},
|
||||||
|
Hostnames: []string{"nl-ams.prod.surfshark.com"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for name, testCase := range testCases {
|
||||||
|
testCase := testCase
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
|
||||||
|
env := mock_params.NewMockInterface(ctrl)
|
||||||
|
|
||||||
|
servers := []models.SurfsharkServer{{Hostname: "a"}}
|
||||||
|
allServers := models.AllServers{
|
||||||
|
Surfshark: models.SurfsharkServers{
|
||||||
|
Servers: servers,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if testCase.targetIP.call {
|
||||||
|
env.EXPECT().Get("OPENVPN_TARGET_IP").
|
||||||
|
Return(testCase.targetIP.value, testCase.targetIP.err)
|
||||||
|
}
|
||||||
|
if testCase.countries.call {
|
||||||
|
env.EXPECT().CSVInside("COUNTRY", constants.SurfsharkCountryChoices(servers)).
|
||||||
|
Return(testCase.countries.values, testCase.countries.err)
|
||||||
|
}
|
||||||
|
if testCase.cities.call {
|
||||||
|
env.EXPECT().CSVInside("CITY", constants.SurfsharkCityChoices(servers)).
|
||||||
|
Return(testCase.cities.values, testCase.cities.err)
|
||||||
|
}
|
||||||
|
if testCase.hostnames.call {
|
||||||
|
env.EXPECT().CSVInside("SERVER_HOSTNAME", constants.SurfsharkHostnameChoices(servers)).
|
||||||
|
Return(testCase.hostnames.values, testCase.hostnames.err)
|
||||||
|
}
|
||||||
|
if testCase.regions.call {
|
||||||
|
regionChoices := constants.SurfsharkRegionChoices(servers)
|
||||||
|
regionChoices = append(regionChoices, constants.SurfsharkRetroLocChoices(servers)...)
|
||||||
|
env.EXPECT().CSVInside("REGION", regionChoices).
|
||||||
|
Return(testCase.regions.values, testCase.regions.err)
|
||||||
|
}
|
||||||
|
if testCase.multiHop.call {
|
||||||
|
env.EXPECT().YesNo("MULTIHOP_ONLY", gomock.Any()).
|
||||||
|
Return(testCase.multiHop.value, testCase.multiHop.err)
|
||||||
|
}
|
||||||
|
if testCase.protocol.call {
|
||||||
|
env.EXPECT().Inside("PROTOCOL", []string{constants.TCP, constants.UDP}, gomock.Any()).
|
||||||
|
Return(testCase.protocol.value, testCase.protocol.err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r := reader{
|
||||||
|
servers: allServers,
|
||||||
|
env: env,
|
||||||
|
}
|
||||||
|
|
||||||
|
var settings Provider
|
||||||
|
err := settings.readSurfshark(r)
|
||||||
|
|
||||||
|
if testCase.err != nil {
|
||||||
|
require.Error(t, err)
|
||||||
|
assert.Equal(t, testCase.err.Error(), err.Error())
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, testCase.settings, settings)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_surfsharkRetroRegion(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
testCases := map[string]struct {
|
||||||
|
original ServerSelection
|
||||||
|
modified ServerSelection
|
||||||
|
}{
|
||||||
|
"empty": {},
|
||||||
|
"1 retro region": {
|
||||||
|
original: ServerSelection{
|
||||||
|
Regions: []string{"australia adelaide"},
|
||||||
|
},
|
||||||
|
modified: ServerSelection{
|
||||||
|
Regions: []string{"asia pacific"},
|
||||||
|
Countries: []string{"australia"},
|
||||||
|
Cities: []string{"adelaide"},
|
||||||
|
Hostnames: []string{"au-adl.prod.surfshark.com"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"2 overlapping retro regions": {
|
||||||
|
original: ServerSelection{
|
||||||
|
Regions: []string{"australia adelaide", "australia melbourne"},
|
||||||
|
},
|
||||||
|
modified: ServerSelection{
|
||||||
|
Regions: []string{"asia pacific"},
|
||||||
|
Countries: []string{"australia"},
|
||||||
|
Cities: []string{"adelaide", "melbourne"},
|
||||||
|
Hostnames: []string{"au-adl.prod.surfshark.com", "au-mel.prod.surfshark.com"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"2 distinct retro regions": {
|
||||||
|
original: ServerSelection{
|
||||||
|
Regions: []string{"australia adelaide", "netherlands amsterdam"},
|
||||||
|
},
|
||||||
|
modified: ServerSelection{
|
||||||
|
Regions: []string{"asia pacific", "europe"},
|
||||||
|
Countries: []string{"australia", "netherlands"},
|
||||||
|
Cities: []string{"adelaide", "amsterdam"},
|
||||||
|
Hostnames: []string{"au-adl.prod.surfshark.com", "nl-ams.prod.surfshark.com"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"retro region with existing region": {
|
||||||
|
// note TestRegion will be ignored in the filters downstream
|
||||||
|
original: ServerSelection{
|
||||||
|
Regions: []string{"TestRegion", "australia adelaide"},
|
||||||
|
},
|
||||||
|
modified: ServerSelection{
|
||||||
|
Regions: []string{"TestRegion", "asia pacific"},
|
||||||
|
Countries: []string{"australia"},
|
||||||
|
Cities: []string{"adelaide"},
|
||||||
|
Hostnames: []string{"au-adl.prod.surfshark.com"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for name, testCase := range testCases {
|
||||||
|
testCase := testCase
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
selection := surfsharkRetroRegion(testCase.original)
|
||||||
|
|
||||||
|
assert.Equal(t, testCase.modified, selection)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,49 +6,30 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *Provider) torguardLines() (lines []string) {
|
|
||||||
if len(settings.ServerSelection.Countries) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Countries: "+commaJoin(settings.ServerSelection.Countries))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Cities) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Cities: "+commaJoin(settings.ServerSelection.Cities))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Hostnames) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings *Provider) readTorguard(r reader) (err error) {
|
func (settings *Provider) readTorguard(r reader) (err error) {
|
||||||
settings.Name = constants.Torguard
|
settings.Name = constants.Torguard
|
||||||
|
servers := r.servers.GetTorguard()
|
||||||
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.TorguardCountryChoices())
|
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.TorguardCountryChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.TorguardCityChoices())
|
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.TorguardCityChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable CITY: %w", err)
|
return fmt.Errorf("environment variable CITY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.TorguardHostnameChoices())
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||||
|
constants.TorguardHostnameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return settings.ServerSelection.OpenVPN.readProtocolAndPort(r.env)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ var (
|
|||||||
ErrInvalidDNSOverTLSProvider = errors.New("invalid DNS over TLS provider")
|
ErrInvalidDNSOverTLSProvider = errors.New("invalid DNS over TLS provider")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *DNS) readUnboundProviders(env params.Env) (err error) {
|
func (settings *DNS) readUnboundProviders(env params.Interface) (err error) {
|
||||||
s, err := env.Get("DOT_PROVIDERS", params.Default("cloudflare"))
|
s, err := env.Get("DOT_PROVIDERS", params.Default("cloudflare"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable DOT_PROVIDERS: %w", err)
|
return fmt.Errorf("environment variable DOT_PROVIDERS: %w", err)
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ func Test_DNS_readUnboundProviders(t *testing.T) {
|
|||||||
|
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
|
|
||||||
env := mock_params.NewMockEnv(ctrl)
|
env := mock_params.NewMockInterface(ctrl)
|
||||||
env.EXPECT().Get("DOT_PROVIDERS", gomock.Any()).
|
env.EXPECT().Get("DOT_PROVIDERS", gomock.Any()).
|
||||||
Return(testCase.envValue, testCase.envErr)
|
Return(testCase.envValue, testCase.envErr)
|
||||||
|
|
||||||
|
|||||||
97
internal/configuration/vpn.go
Normal file
97
internal/configuration/vpn.go
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
type VPN struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
OpenVPN OpenVPN `json:"openvpn"`
|
||||||
|
Wireguard Wireguard `json:"wireguard"`
|
||||||
|
Provider Provider `json:"provider"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *VPN) String() string {
|
||||||
|
return strings.Join(settings.lines(), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *VPN) lines() (lines []string) {
|
||||||
|
lines = append(lines, lastIndent+"VPN:")
|
||||||
|
|
||||||
|
lines = append(lines, indent+lastIndent+"Type: "+settings.Type)
|
||||||
|
|
||||||
|
var vpnLines []string
|
||||||
|
switch settings.Type {
|
||||||
|
case constants.OpenVPN:
|
||||||
|
vpnLines = settings.OpenVPN.lines()
|
||||||
|
case constants.Wireguard:
|
||||||
|
vpnLines = settings.Wireguard.lines()
|
||||||
|
}
|
||||||
|
for _, line := range vpnLines {
|
||||||
|
lines = append(lines, indent+line)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, line := range settings.Provider.lines() {
|
||||||
|
lines = append(lines, indent+line)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errReadProviderSettings = errors.New("cannot read provider settings")
|
||||||
|
errReadOpenVPNSettings = errors.New("cannot read OpenVPN settings")
|
||||||
|
errReadWireguardSettings = errors.New("cannot read Wireguard settings")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (settings *VPN) read(r reader) (err error) {
|
||||||
|
vpnType, err := r.env.Inside("VPN_TYPE",
|
||||||
|
[]string{constants.OpenVPN, constants.Wireguard},
|
||||||
|
params.Default(constants.OpenVPN))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("environment variable VPN_TYPE: %w", err)
|
||||||
|
}
|
||||||
|
settings.Type = vpnType
|
||||||
|
|
||||||
|
if !settings.isOpenVPNCustomConfig(r.env) {
|
||||||
|
if err := settings.Provider.read(r, vpnType); err != nil {
|
||||||
|
return fmt.Errorf("%w: %s", errReadProviderSettings, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch settings.Type {
|
||||||
|
case constants.OpenVPN:
|
||||||
|
err = settings.OpenVPN.read(r, settings.Provider.Name)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%w: %s", errReadOpenVPNSettings, err)
|
||||||
|
}
|
||||||
|
case constants.Wireguard:
|
||||||
|
err = settings.Wireguard.read(r)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%w: %s", errReadWireguardSettings, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings VPN) isOpenVPNCustomConfig(env params.Interface) (ok bool) {
|
||||||
|
if settings.Type != constants.OpenVPN {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
s, err := env.Get("OPENVPN_CUSTOM_CONFIG")
|
||||||
|
return err == nil && s != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings VPN) VPNInterface() (intf string) {
|
||||||
|
if settings.Type == constants.Wireguard {
|
||||||
|
return settings.Wireguard.Interface
|
||||||
|
}
|
||||||
|
// OpenVPN
|
||||||
|
return settings.OpenVPN.Interface
|
||||||
|
}
|
||||||
@@ -7,68 +7,27 @@ import (
|
|||||||
"github.com/qdm12/golibs/params"
|
"github.com/qdm12/golibs/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *Provider) vpnUnlimitedLines() (lines []string) {
|
|
||||||
if len(settings.ServerSelection.Countries) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Countries: "+commaJoin(settings.ServerSelection.Countries))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Cities) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Cities: "+commaJoin(settings.ServerSelection.Cities))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Hostnames) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
|
||||||
}
|
|
||||||
|
|
||||||
if settings.ServerSelection.FreeOnly {
|
|
||||||
lines = append(lines, lastIndent+"Free servers only")
|
|
||||||
}
|
|
||||||
|
|
||||||
if settings.ServerSelection.StreamOnly {
|
|
||||||
lines = append(lines, lastIndent+"Stream servers only")
|
|
||||||
}
|
|
||||||
|
|
||||||
if settings.ExtraConfigOptions.ClientKey != "" {
|
|
||||||
lines = append(lines, lastIndent+"Client key is set")
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings *Provider) readVPNUnlimited(r reader) (err error) {
|
func (settings *Provider) readVPNUnlimited(r reader) (err error) {
|
||||||
settings.Name = constants.VPNUnlimited
|
settings.Name = constants.VPNUnlimited
|
||||||
|
servers := r.servers.GetVPNUnlimited()
|
||||||
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ExtraConfigOptions.ClientKey, err = readClientKey(r)
|
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.VPNUnlimitedCountryChoices(servers))
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ExtraConfigOptions.ClientCertificate, err = readClientCertificate(r)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.VPNUnlimitedCountryChoices())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
return fmt.Errorf("environment variable COUNTRY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.VPNUnlimitedCityChoices())
|
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.VPNUnlimitedCityChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable CITY: %w", err)
|
return fmt.Errorf("environment variable CITY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.VPNUnlimitedHostnameChoices())
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||||
|
constants.VPNUnlimitedHostnameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||||
}
|
}
|
||||||
@@ -83,5 +42,19 @@ func (settings *Provider) readVPNUnlimited(r reader) (err error) {
|
|||||||
return fmt.Errorf("environment variable STREAM_ONLY: %w", err)
|
return fmt.Errorf("environment variable STREAM_ONLY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return settings.ServerSelection.OpenVPN.readProtocolOnly(r.env)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *OpenVPN) readVPNUnlimited(r reader) (err error) {
|
||||||
|
settings.ClientKey, err = readClientKey(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.ClientCrt, err = readClientCertificate(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
package configuration
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_Provider_vpnUnlimitedLines(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testCases := map[string]struct {
|
|
||||||
settings Provider
|
|
||||||
lines []string
|
|
||||||
}{
|
|
||||||
"empty settings": {},
|
|
||||||
"full settings": {
|
|
||||||
settings: Provider{
|
|
||||||
ServerSelection: ServerSelection{
|
|
||||||
Countries: []string{"A", "B"},
|
|
||||||
Cities: []string{"C", "D"},
|
|
||||||
Hostnames: []string{"E", "F"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
lines: []string{
|
|
||||||
"|--Countries: A, B",
|
|
||||||
"|--Cities: C, D",
|
|
||||||
"|--Hostnames: E, F",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for name, testCase := range testCases {
|
|
||||||
testCase := testCase
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
lines := testCase.settings.vpnUnlimitedLines()
|
|
||||||
|
|
||||||
assert.Equal(t, testCase.lines, lines)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,28 +6,16 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *Provider) vyprvpnLines() (lines []string) {
|
|
||||||
if len(settings.ServerSelection.Regions) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions))
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings *Provider) readVyprvpn(r reader) (err error) {
|
func (settings *Provider) readVyprvpn(r reader) (err error) {
|
||||||
settings.Name = constants.Vyprvpn
|
settings.Name = constants.Vyprvpn
|
||||||
|
servers := r.servers.GetVyprvpn()
|
||||||
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.VyprvpnRegionChoices())
|
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.VyprvpnRegionChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable REGION: %w", err)
|
return fmt.Errorf("environment variable REGION: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,60 +2,51 @@ package configuration
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (settings *Provider) windscribeLines() (lines []string) {
|
|
||||||
if len(settings.ServerSelection.Regions) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Regions: "+commaJoin(settings.ServerSelection.Regions))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Cities) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Cities: "+commaJoin(settings.ServerSelection.Cities))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(settings.ServerSelection.Hostnames) > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Hostnames: "+commaJoin(settings.ServerSelection.Hostnames))
|
|
||||||
}
|
|
||||||
|
|
||||||
if settings.ServerSelection.CustomPort > 0 {
|
|
||||||
lines = append(lines, lastIndent+"Custom port: "+strconv.Itoa(int(settings.ServerSelection.CustomPort)))
|
|
||||||
}
|
|
||||||
|
|
||||||
return lines
|
|
||||||
}
|
|
||||||
|
|
||||||
func (settings *Provider) readWindscribe(r reader) (err error) {
|
func (settings *Provider) readWindscribe(r reader) (err error) {
|
||||||
settings.Name = constants.Windscribe
|
settings.Name = constants.Windscribe
|
||||||
|
servers := r.servers.GetWindscribe()
|
||||||
settings.ServerSelection.TCP, err = readProtocol(r.env)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.WindscribeRegionChoices())
|
settings.ServerSelection.Regions, err = r.env.CSVInside("REGION", constants.WindscribeRegionChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable REGION: %w", err)
|
return fmt.Errorf("environment variable REGION: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.WindscribeCityChoices())
|
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.WindscribeCityChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable CITY: %w", err)
|
return fmt.Errorf("environment variable CITY: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.WindscribeHostnameChoices())
|
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME",
|
||||||
|
constants.WindscribeHostnameChoices(servers))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
return fmt.Errorf("environment variable SERVER_HOSTNAME: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.ServerSelection.CustomPort, err = readCustomPort(r.env, settings.ServerSelection.TCP,
|
err = settings.ServerSelection.OpenVPN.readWindscribe(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return settings.ServerSelection.Wireguard.readWindscribe(r.env)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *OpenVPNSelection) readWindscribe(env params.Interface) (err error) {
|
||||||
|
settings.TCP, err = readProtocol(env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.CustomPort, err = readOpenVPNCustomPort(env, settings.TCP,
|
||||||
[]uint16{21, 22, 80, 123, 143, 443, 587, 1194, 3306, 8080, 54783},
|
[]uint16{21, 22, 80, 123, 143, 443, 587, 1194, 3306, 8080, 54783},
|
||||||
[]uint16{53, 80, 123, 443, 1194, 54783})
|
[]uint16{53, 80, 123, 443, 1194, 54783})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -64,3 +55,13 @@ func (settings *Provider) readWindscribe(r reader) (err error) {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (settings *WireguardSelection) readWindscribe(env params.Interface) (err error) {
|
||||||
|
settings.CustomPort, err = readWireguardCustomPort(env,
|
||||||
|
[]uint16{53, 80, 123, 443, 1194, 65142})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
88
internal/configuration/wireguard.go
Normal file
88
internal/configuration/wireguard.go
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
package configuration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/golibs/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Wireguard contains settings to configure the Wireguard client.
|
||||||
|
type Wireguard struct {
|
||||||
|
PrivateKey string `json:"privatekey"`
|
||||||
|
PreSharedKey string `json:"presharedkey"`
|
||||||
|
Addresses []*net.IPNet `json:"addresses"`
|
||||||
|
Interface string `json:"interface"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Wireguard) String() string {
|
||||||
|
return strings.Join(settings.lines(), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Wireguard) lines() (lines []string) {
|
||||||
|
lines = append(lines, lastIndent+"Wireguard:")
|
||||||
|
|
||||||
|
lines = append(lines, indent+lastIndent+"Network interface: "+settings.Interface)
|
||||||
|
|
||||||
|
if settings.PrivateKey != "" {
|
||||||
|
lines = append(lines, indent+lastIndent+"Private key is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.PreSharedKey != "" {
|
||||||
|
lines = append(lines, indent+lastIndent+"Pre-shared key is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(settings.Addresses) > 0 {
|
||||||
|
lines = append(lines, indent+lastIndent+"Addresses: ")
|
||||||
|
for _, address := range settings.Addresses {
|
||||||
|
lines = append(lines, indent+indent+lastIndent+address.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Wireguard) read(r reader) (err error) {
|
||||||
|
settings.PrivateKey, err = r.env.Get("WIREGUARD_PRIVATE_KEY",
|
||||||
|
params.CaseSensitiveValue(), params.Unset(), params.Compulsory())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("environment variable WIREGUARD_PRIVATE_KEY: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.PreSharedKey, err = r.env.Get("WIREGUARD_PRESHARED_KEY",
|
||||||
|
params.CaseSensitiveValue(), params.Unset())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("environment variable WIREGUARD_PRESHARED_KEY: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = settings.readAddresses(r.env)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.Interface, err = r.env.Get("WIREGUARD_INTERFACE", params.Default("wg0"))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("environment variable WIREGUARD_INTERFACE: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (settings *Wireguard) readAddresses(env params.Interface) (err error) {
|
||||||
|
addressStrings, err := env.CSV("WIREGUARD_ADDRESS", params.Compulsory())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("environment variable WIREGUARD_ADDRESS: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addressString := range addressStrings {
|
||||||
|
ip, ipNet, err := net.ParseCIDR(addressString)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("environment variable WIREGUARD_ADDRESS: address %s: %w", addressString, err)
|
||||||
|
}
|
||||||
|
ipNet.IP = ip
|
||||||
|
settings.Addresses = append(settings.Addresses, ipNet)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package constants
|
package constants
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sort"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
"github.com/qdm12/gluetun/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -9,8 +11,7 @@ const (
|
|||||||
CyberghostCertificate = "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"
|
CyberghostCertificate = "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"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CyberghostRegionChoices() (choices []string) {
|
func CyberghostRegionChoices(servers []models.CyberghostServer) (choices []string) {
|
||||||
servers := CyberghostServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Region
|
choices[i] = servers[i].Region
|
||||||
@@ -18,28 +19,27 @@ func CyberghostRegionChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func CyberghostGroupChoices() (choices []string) {
|
func CyberghostGroupChoices(servers []models.CyberghostServer) (choices []string) {
|
||||||
servers := CyberghostServers()
|
uniqueChoices := map[string]struct{}{}
|
||||||
choices = make([]string, len(servers))
|
for _, server := range servers {
|
||||||
for i := range servers {
|
uniqueChoices[server.Group] = struct{}{}
|
||||||
choices[i] = servers[i].Group
|
|
||||||
}
|
}
|
||||||
return makeUnique(choices)
|
|
||||||
|
choices = make([]string, 0, len(uniqueChoices))
|
||||||
|
for choice := range uniqueChoices {
|
||||||
|
choices = append(choices, choice)
|
||||||
|
}
|
||||||
|
|
||||||
|
sortable := sort.StringSlice(choices)
|
||||||
|
sortable.Sort()
|
||||||
|
|
||||||
|
return sortable
|
||||||
}
|
}
|
||||||
|
|
||||||
func CyberghostHostnameChoices() (choices []string) {
|
func CyberghostHostnameChoices(servers []models.CyberghostServer) (choices []string) {
|
||||||
servers := CyberghostServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Hostname
|
choices[i] = servers[i].Hostname
|
||||||
}
|
}
|
||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CyberghostServers returns a slice with the server information for each
|
|
||||||
// of the Cyberghost server.
|
|
||||||
func CyberghostServers() (servers []models.CyberghostServer) {
|
|
||||||
servers = make([]models.CyberghostServer, len(allServers.Cyberghost.Servers))
|
|
||||||
copy(servers, allServers.Cyberghost.Servers)
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|||||||
31
internal/constants/cyberghost_test.go
Normal file
31
internal/constants/cyberghost_test.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package constants
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
|
"github.com/qdm12/gluetun/internal/storage"
|
||||||
|
"github.com/qdm12/golibs/logging/mock_logging"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_CyberghostGroupChoices(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
|
||||||
|
logger := mock_logging.NewMockLogger(ctrl)
|
||||||
|
logger.EXPECT().Info(gomock.Any())
|
||||||
|
|
||||||
|
storage, err := storage.New(logger, "")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
servers := storage.GetServers()
|
||||||
|
|
||||||
|
expected := []string{"Premium TCP Asia", "Premium TCP Europe",
|
||||||
|
"Premium TCP USA", "Premium UDP Asia", "Premium UDP Europe",
|
||||||
|
"Premium UDP USA"}
|
||||||
|
choices := CyberghostGroupChoices(servers.GetCyberghost())
|
||||||
|
|
||||||
|
assert.Equal(t, expected, choices)
|
||||||
|
}
|
||||||
@@ -10,8 +10,7 @@ const (
|
|||||||
FastestvpnOpenvpnStaticKeyV1 = "697fe793b32cb5091d30f2326d5d124a9412e93d0a44ef7361395d76528fcbfc82c3859dccea70a93cfa8fae409709bff75f844cf5ff0c237f426d0c20969233db0e706edb6bdf195ec3dc11b3f76bc807a77e74662d9a800c8cd1144ebb67b7f0d3f1281d1baf522bfe03b7c3f963b1364fc0769400e413b61ca7b43ab19fac9e0f77e41efd4bda7fd77b1de2d7d7855cbbe3e620cecceac72c21a825b243e651f44d90e290e09c3ad650de8fca99c858bc7caad584bc69b11e5c9fd9381c69c505ec487a65912c672d83ed0113b5a74ddfbd3ab33b3683cec593557520a72c4d6cce46111f56f3396cc3ce7183edce553c68ea0796cf6c4375fad00aaa2a42"
|
FastestvpnOpenvpnStaticKeyV1 = "697fe793b32cb5091d30f2326d5d124a9412e93d0a44ef7361395d76528fcbfc82c3859dccea70a93cfa8fae409709bff75f844cf5ff0c237f426d0c20969233db0e706edb6bdf195ec3dc11b3f76bc807a77e74662d9a800c8cd1144ebb67b7f0d3f1281d1baf522bfe03b7c3f963b1364fc0769400e413b61ca7b43ab19fac9e0f77e41efd4bda7fd77b1de2d7d7855cbbe3e620cecceac72c21a825b243e651f44d90e290e09c3ad650de8fca99c858bc7caad584bc69b11e5c9fd9381c69c505ec487a65912c672d83ed0113b5a74ddfbd3ab33b3683cec593557520a72c4d6cce46111f56f3396cc3ce7183edce553c68ea0796cf6c4375fad00aaa2a42"
|
||||||
)
|
)
|
||||||
|
|
||||||
func FastestvpnCountriesChoices() (choices []string) {
|
func FastestvpnCountriesChoices(servers []models.FastestvpnServer) (choices []string) {
|
||||||
servers := FastestvpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Country
|
choices[i] = servers[i].Country
|
||||||
@@ -19,18 +18,10 @@ func FastestvpnCountriesChoices() (choices []string) {
|
|||||||
return choices
|
return choices
|
||||||
}
|
}
|
||||||
|
|
||||||
func FastestvpnHostnameChoices() (choices []string) {
|
func FastestvpnHostnameChoices(servers []models.FastestvpnServer) (choices []string) {
|
||||||
servers := FastestvpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Hostname
|
choices[i] = servers[i].Hostname
|
||||||
}
|
}
|
||||||
return choices
|
return choices
|
||||||
}
|
}
|
||||||
|
|
||||||
// FastestvpnServers returns the list of all VPN servers for FastestVPN.
|
|
||||||
func FastestvpnServers() (servers []models.FastestvpnServer) {
|
|
||||||
servers = make([]models.FastestvpnServer, len(allServers.Fastestvpn.Servers))
|
|
||||||
copy(servers, allServers.Fastestvpn.Servers)
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ const (
|
|||||||
HideMyAssRSAPrivateKey = "MIIEpAIBAAKCAQEA5XY3ERJYWs/YIeBoybivNlu+M32rJs+CAZsh7BnnetTxytI4ngsMRoqXETuis8udp2hsqEHsglLR9tlk9C8yCuKhxbkpdrXFWdISmUq5sa7/wqg/zJF1AZm5Jy0oHNyTHfG6XW61I/h9IN5dmcR9YLir8DVDBNllbtt0z+DnvOhYJOqC30ENahWkTmNKl1cT7EBrR5slddiBJleAb08z77pwsD310e6jWTBySsBcPy+xu/Jj2QgVil/3mstZZDI+noFzs3SkTFBkha/lNTP7NODBQ6m39iaJxz6ZR1xE3v7XU0H5WnpZIcQ2+kmu5Krk2y1GYMKL+9oaotXFPz9v+QIDAQABAoIBAQCcMcssOMOiFWc3MC3EWo4SP4MKQ9n0Uj5Z34LI151FdJyehlj54+VYQ1Cv71tCbjED2sZUBoP69mtsT/EzcsjqtfiOwgrifrs2+BOm+0HKHKiGlcbP9peiHkT10PxEITWXpYtJvGlbcfOjIxqt6B28cBjCK09ShrVQL9ylAKBearRRUacszppntMNTMtN/uG48ZR9Wm+xAczImdG6CrG5sLI/++JwM5PDChLvn5JgMGyOfQZdjNe1oSOVLmqFeG5uu/FS4oMon9+HtfjHJr4ZgA1yQ2wQh3GvEjlP8zwHxEpRJYbxpj6ZbjHZJ2HLX/Gcd9/cXiN8+fQ2zPIYQyG9dAoGBAPUUmt2nJNvl7gj0GbZZ3XR9o+hvj7bJ74W2NhMrw6kjrrzHTAUQd1sBQS8szAQCLqf2ou1aw9AMMBdsLAHydXxvbH7IBAla7rKr23iethtSfjhTNSgQLJHVZlNHfp3hzNtCQZ7j0qVjrteNotrdVF7kKPHDXAK00ICy6SPNjvrXAoGBAO+vdnO15jLeZbbi3lQNS4r8oCadyqyX7ouKE6MtKNhiPsNPGqHKiGcKs/+QylVgYvSmm7TgpsCAiEYeLSPT+Yq3y7HtwVpULlpfAhEJXmvn/6hGpOizx1WNGWhw7nHPWPDzf+jqCGzHdhK0aEZR3MZZQ+U+uKfGiJ8vrvgB7eGvAoGAWxxp5nU48rcsIw/8bxpBhgkfYk33M5EnBqKSv9XJS5wEXhIJZOiWNrLktNEGl4boKXE7aNoRacreJhcE1UR6AOS7hPZ+6atwiePyF4mJUeb9HZtxa493wk9/Vv6BR9il++1Jz/QKX4oLef8hyBP4Rb60qgxirG7kBLR+j9zfhskCgYEAzA5y5xIeuIIU0H4XUDG9dcebxSSjbwsuYIgeLdb9pjMGQhsvjjyyoh8/nT20tLkJpkXN3FFCRjNnUWLRhWYrVkkh1wqWiYOPrwqh5MU4KN/sDWSPcznTY+drkTpMFoKzsvdrl2zf3VR3FneXKv742bkXj601Ykko+XWMHcLutisCgYBSq8IrsjzfaTQiTGI9a7WWsvzK92bq7Abnfq7swAXWcJd/bnjTQKLrrvt2bmwNvlWKAb3c69BFMn0X4t4PuN0iJQ39D6aQAEaM7HwWAmjf5TbodbmgbGxdsUB4xcCIQQ1mvTkigXWrCg0YAD2GZSoaslXAAVv6nR5qWEIa0Hx9GA=="
|
HideMyAssRSAPrivateKey = "MIIEpAIBAAKCAQEA5XY3ERJYWs/YIeBoybivNlu+M32rJs+CAZsh7BnnetTxytI4ngsMRoqXETuis8udp2hsqEHsglLR9tlk9C8yCuKhxbkpdrXFWdISmUq5sa7/wqg/zJF1AZm5Jy0oHNyTHfG6XW61I/h9IN5dmcR9YLir8DVDBNllbtt0z+DnvOhYJOqC30ENahWkTmNKl1cT7EBrR5slddiBJleAb08z77pwsD310e6jWTBySsBcPy+xu/Jj2QgVil/3mstZZDI+noFzs3SkTFBkha/lNTP7NODBQ6m39iaJxz6ZR1xE3v7XU0H5WnpZIcQ2+kmu5Krk2y1GYMKL+9oaotXFPz9v+QIDAQABAoIBAQCcMcssOMOiFWc3MC3EWo4SP4MKQ9n0Uj5Z34LI151FdJyehlj54+VYQ1Cv71tCbjED2sZUBoP69mtsT/EzcsjqtfiOwgrifrs2+BOm+0HKHKiGlcbP9peiHkT10PxEITWXpYtJvGlbcfOjIxqt6B28cBjCK09ShrVQL9ylAKBearRRUacszppntMNTMtN/uG48ZR9Wm+xAczImdG6CrG5sLI/++JwM5PDChLvn5JgMGyOfQZdjNe1oSOVLmqFeG5uu/FS4oMon9+HtfjHJr4ZgA1yQ2wQh3GvEjlP8zwHxEpRJYbxpj6ZbjHZJ2HLX/Gcd9/cXiN8+fQ2zPIYQyG9dAoGBAPUUmt2nJNvl7gj0GbZZ3XR9o+hvj7bJ74W2NhMrw6kjrrzHTAUQd1sBQS8szAQCLqf2ou1aw9AMMBdsLAHydXxvbH7IBAla7rKr23iethtSfjhTNSgQLJHVZlNHfp3hzNtCQZ7j0qVjrteNotrdVF7kKPHDXAK00ICy6SPNjvrXAoGBAO+vdnO15jLeZbbi3lQNS4r8oCadyqyX7ouKE6MtKNhiPsNPGqHKiGcKs/+QylVgYvSmm7TgpsCAiEYeLSPT+Yq3y7HtwVpULlpfAhEJXmvn/6hGpOizx1WNGWhw7nHPWPDzf+jqCGzHdhK0aEZR3MZZQ+U+uKfGiJ8vrvgB7eGvAoGAWxxp5nU48rcsIw/8bxpBhgkfYk33M5EnBqKSv9XJS5wEXhIJZOiWNrLktNEGl4boKXE7aNoRacreJhcE1UR6AOS7hPZ+6atwiePyF4mJUeb9HZtxa493wk9/Vv6BR9il++1Jz/QKX4oLef8hyBP4Rb60qgxirG7kBLR+j9zfhskCgYEAzA5y5xIeuIIU0H4XUDG9dcebxSSjbwsuYIgeLdb9pjMGQhsvjjyyoh8/nT20tLkJpkXN3FFCRjNnUWLRhWYrVkkh1wqWiYOPrwqh5MU4KN/sDWSPcznTY+drkTpMFoKzsvdrl2zf3VR3FneXKv742bkXj601Ykko+XWMHcLutisCgYBSq8IrsjzfaTQiTGI9a7WWsvzK92bq7Abnfq7swAXWcJd/bnjTQKLrrvt2bmwNvlWKAb3c69BFMn0X4t4PuN0iJQ39D6aQAEaM7HwWAmjf5TbodbmgbGxdsUB4xcCIQQ1mvTkigXWrCg0YAD2GZSoaslXAAVv6nR5qWEIa0Hx9GA=="
|
||||||
)
|
)
|
||||||
|
|
||||||
func HideMyAssCountryChoices() (choices []string) {
|
func HideMyAssCountryChoices(servers []models.HideMyAssServer) (choices []string) {
|
||||||
servers := HideMyAssServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Country
|
choices[i] = servers[i].Country
|
||||||
@@ -20,8 +19,7 @@ func HideMyAssCountryChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func HideMyAssCityChoices() (choices []string) {
|
func HideMyAssCityChoices(servers []models.HideMyAssServer) (choices []string) {
|
||||||
servers := HideMyAssServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].City
|
choices[i] = servers[i].City
|
||||||
@@ -29,18 +27,10 @@ func HideMyAssCityChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func HideMyAssHostnameChoices() (choices []string) {
|
func HideMyAssHostnameChoices(servers []models.HideMyAssServer) (choices []string) {
|
||||||
servers := HideMyAssServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Hostname
|
choices[i] = servers[i].Hostname
|
||||||
}
|
}
|
||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HideMyAssServers returns a slice of all the server information for HideMyAss.
|
|
||||||
func HideMyAssServers() (servers []models.HideMyAssServer) {
|
|
||||||
servers = make([]models.HideMyAssServer, len(allServers.HideMyAss.Servers))
|
|
||||||
copy(servers, allServers.HideMyAss.Servers)
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -9,8 +9,7 @@ const (
|
|||||||
IpvanishCA = "MIIErTCCA5WgAwIBAgIJAMYKzSS8uPKDMA0GCSqGSIb3DQEBDQUAMIGVMQswCQYDVQQGEwJVUzELMAkGA1UECBMCRkwxFDASBgNVBAcTC1dpbnRlciBQYXJrMREwDwYDVQQKEwhJUFZhbmlzaDEVMBMGA1UECxMMSVBWYW5pc2ggVlBOMRQwEgYDVQQDEwtJUFZhbmlzaCBDQTEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBpcHZhbmlzaC5jb20wHhcNMTIwMTExMTkzMjIwWhcNMjgxMTAyMTkzMjIwWjCBlTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkZMMRQwEgYDVQQHEwtXaW50ZXIgUGFyazERMA8GA1UEChMISVBWYW5pc2gxFTATBgNVBAsTDElQVmFuaXNoIFZQTjEUMBIGA1UEAxMLSVBWYW5pc2ggQ0ExIzAhBgkqhkiG9w0BCQEWFHN1cHBvcnRAaXB2YW5pc2guY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt9DBWNr/IKOuY3TmDP5x7vYZR0DGxLbXU8TyAzBbjUtFFMbhxlHiXVQrZHmgzih94x7BgXM7tWpmMKYVb+gNaqMdWE680Qm3nOwmhy/dulXDkEHAwD05i/iTx4ZaUdtV2vsKBxRg1vdC4AEiwD7bqV4HOi13xcG971aQ55Mj1KeCdA0aNvpat1LWx2jjWxsfI8s2Lv5Fkoi1HO1+vTnnaEsJZrBgAkLXpItqP29Lik3/OBIvkBIxlKrhiVPixE5qNiD+eSPirsmROvsyIonoJtuY4Dw5K6pcNlKyYiwo1IOFYU3YxffwFJk+bSW4WVBhsdf5dGxq/uOHmuz5gdwxCwIDAQABo4H9MIH6MAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFEv9FCWJHefBcIPX9p8RHCVOGe6uMIHKBgNVHSMEgcIwgb+AFEv9FCWJHefBcIPX9p8RHCVOGe6uoYGbpIGYMIGVMQswCQYDVQQGEwJVUzELMAkGA1UECBMCRkwxFDASBgNVBAcTC1dpbnRlciBQYXJrMREwDwYDVQQKEwhJUFZhbmlzaDEVMBMGA1UECxMMSVBWYW5pc2ggVlBOMRQwEgYDVQQDEwtJUFZhbmlzaCBDQTEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBpcHZhbmlzaC5jb22CCQDGCs0kvLjygzANBgkqhkiG9w0BAQ0FAAOCAQEAI2dkh/43ksV2fdYpVGhYaFZPVqCJoToCez0IvOmLeLGzow+EOSrY508oyjYeNP4VJEjApqo0NrMbKl8g/8bpLBcotOCF1c1HZ+y9v7648uumh01SMjsbBeHOuQcLb+7gX6c0pEmxWv8qj5JiW3/1L1bktnjW5Yp5oFkFSMXjOnIoYKHyKLjN2jtwH6XowUNYpg4qVtKU0CXPdOznWcd9/zSfa393HwJPeeVLbKYaFMC4IEbIUmKYtWyoJ9pJ58smU3pWsHZUg9Zc0LZZNjkNlBdQSLmUHAJ33Bd7pJS0JQeiWviC+4UTmzEWRKa7pDGnYRYNu2cUo0/voStphv8EVA=="
|
IpvanishCA = "MIIErTCCA5WgAwIBAgIJAMYKzSS8uPKDMA0GCSqGSIb3DQEBDQUAMIGVMQswCQYDVQQGEwJVUzELMAkGA1UECBMCRkwxFDASBgNVBAcTC1dpbnRlciBQYXJrMREwDwYDVQQKEwhJUFZhbmlzaDEVMBMGA1UECxMMSVBWYW5pc2ggVlBOMRQwEgYDVQQDEwtJUFZhbmlzaCBDQTEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBpcHZhbmlzaC5jb20wHhcNMTIwMTExMTkzMjIwWhcNMjgxMTAyMTkzMjIwWjCBlTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkZMMRQwEgYDVQQHEwtXaW50ZXIgUGFyazERMA8GA1UEChMISVBWYW5pc2gxFTATBgNVBAsTDElQVmFuaXNoIFZQTjEUMBIGA1UEAxMLSVBWYW5pc2ggQ0ExIzAhBgkqhkiG9w0BCQEWFHN1cHBvcnRAaXB2YW5pc2guY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt9DBWNr/IKOuY3TmDP5x7vYZR0DGxLbXU8TyAzBbjUtFFMbhxlHiXVQrZHmgzih94x7BgXM7tWpmMKYVb+gNaqMdWE680Qm3nOwmhy/dulXDkEHAwD05i/iTx4ZaUdtV2vsKBxRg1vdC4AEiwD7bqV4HOi13xcG971aQ55Mj1KeCdA0aNvpat1LWx2jjWxsfI8s2Lv5Fkoi1HO1+vTnnaEsJZrBgAkLXpItqP29Lik3/OBIvkBIxlKrhiVPixE5qNiD+eSPirsmROvsyIonoJtuY4Dw5K6pcNlKyYiwo1IOFYU3YxffwFJk+bSW4WVBhsdf5dGxq/uOHmuz5gdwxCwIDAQABo4H9MIH6MAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFEv9FCWJHefBcIPX9p8RHCVOGe6uMIHKBgNVHSMEgcIwgb+AFEv9FCWJHefBcIPX9p8RHCVOGe6uoYGbpIGYMIGVMQswCQYDVQQGEwJVUzELMAkGA1UECBMCRkwxFDASBgNVBAcTC1dpbnRlciBQYXJrMREwDwYDVQQKEwhJUFZhbmlzaDEVMBMGA1UECxMMSVBWYW5pc2ggVlBOMRQwEgYDVQQDEwtJUFZhbmlzaCBDQTEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBpcHZhbmlzaC5jb22CCQDGCs0kvLjygzANBgkqhkiG9w0BAQ0FAAOCAQEAI2dkh/43ksV2fdYpVGhYaFZPVqCJoToCez0IvOmLeLGzow+EOSrY508oyjYeNP4VJEjApqo0NrMbKl8g/8bpLBcotOCF1c1HZ+y9v7648uumh01SMjsbBeHOuQcLb+7gX6c0pEmxWv8qj5JiW3/1L1bktnjW5Yp5oFkFSMXjOnIoYKHyKLjN2jtwH6XowUNYpg4qVtKU0CXPdOznWcd9/zSfa393HwJPeeVLbKYaFMC4IEbIUmKYtWyoJ9pJ58smU3pWsHZUg9Zc0LZZNjkNlBdQSLmUHAJ33Bd7pJS0JQeiWviC+4UTmzEWRKa7pDGnYRYNu2cUo0/voStphv8EVA=="
|
||||||
)
|
)
|
||||||
|
|
||||||
func IpvanishCountryChoices() (choices []string) {
|
func IpvanishCountryChoices(servers []models.IpvanishServer) (choices []string) {
|
||||||
servers := IpvanishServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Country
|
choices[i] = servers[i].Country
|
||||||
@@ -18,8 +17,7 @@ func IpvanishCountryChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IpvanishCityChoices() (choices []string) {
|
func IpvanishCityChoices(servers []models.IpvanishServer) (choices []string) {
|
||||||
servers := IpvanishServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].City
|
choices[i] = servers[i].City
|
||||||
@@ -27,18 +25,10 @@ func IpvanishCityChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IpvanishHostnameChoices() (choices []string) {
|
func IpvanishHostnameChoices(servers []models.IpvanishServer) (choices []string) {
|
||||||
servers := IpvanishServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Hostname
|
choices[i] = servers[i].Hostname
|
||||||
}
|
}
|
||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IpvanishServers returns a slice of all the server information for Ipvanish.
|
|
||||||
func IpvanishServers() (servers []models.IpvanishServer) {
|
|
||||||
servers = make([]models.IpvanishServer, len(allServers.Ipvanish.Servers))
|
|
||||||
copy(servers, allServers.Ipvanish.Servers)
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,8 +10,7 @@ const (
|
|||||||
IvpnOpenvpnStaticKeyV1 = "ac470c93ff9f5602a8aab37dee84a52814d10f20490ad23c47d5d82120c1bf859e93d0696b455d4a1b8d55d40c2685c41ca1d0aef29a3efd27274c4ef09020a3978fe45784b335da6df2d12db97bbb838416515f2a96f04715fd28949c6fe296a925cfada3f8b8928ed7fc963c1563272f5cf46e5e1d9c845d7703ca881497b7e6564a9d1dea9358adffd435295479f47d5298fabf5359613ff5992cb57ff081a04dfb81a26513a6b44a9b5490ad265f8a02384832a59cc3e075ad545461060b7bcab49bac815163cb80983dd51d5b1fd76170ffd904d8291071e96efc3fb777856c717b148d08a510f5687b8a8285dcffe737b98916dd15ef6235dee4266d3b"
|
IvpnOpenvpnStaticKeyV1 = "ac470c93ff9f5602a8aab37dee84a52814d10f20490ad23c47d5d82120c1bf859e93d0696b455d4a1b8d55d40c2685c41ca1d0aef29a3efd27274c4ef09020a3978fe45784b335da6df2d12db97bbb838416515f2a96f04715fd28949c6fe296a925cfada3f8b8928ed7fc963c1563272f5cf46e5e1d9c845d7703ca881497b7e6564a9d1dea9358adffd435295479f47d5298fabf5359613ff5992cb57ff081a04dfb81a26513a6b44a9b5490ad265f8a02384832a59cc3e075ad545461060b7bcab49bac815163cb80983dd51d5b1fd76170ffd904d8291071e96efc3fb777856c717b148d08a510f5687b8a8285dcffe737b98916dd15ef6235dee4266d3b"
|
||||||
)
|
)
|
||||||
|
|
||||||
func IvpnCountryChoices() (choices []string) {
|
func IvpnCountryChoices(servers []models.IvpnServer) (choices []string) {
|
||||||
servers := IvpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Country
|
choices[i] = servers[i].Country
|
||||||
@@ -19,8 +18,7 @@ func IvpnCountryChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IvpnCityChoices() (choices []string) {
|
func IvpnCityChoices(servers []models.IvpnServer) (choices []string) {
|
||||||
servers := IvpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].City
|
choices[i] = servers[i].City
|
||||||
@@ -28,18 +26,18 @@ func IvpnCityChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func IvpnHostnameChoices() (choices []string) {
|
func IvpnISPChoices(servers []models.IvpnServer) (choices []string) {
|
||||||
servers := IvpnServers()
|
choices = make([]string, len(servers))
|
||||||
|
for i := range servers {
|
||||||
|
choices[i] = servers[i].ISP
|
||||||
|
}
|
||||||
|
return makeUnique(choices)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IvpnHostnameChoices(servers []models.IvpnServer) (choices []string) {
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Hostname
|
choices[i] = servers[i].Hostname
|
||||||
}
|
}
|
||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IvpnServers returns a slice of all the server information for Ivpn.
|
|
||||||
func IvpnServers() (servers []models.IvpnServer) {
|
|
||||||
servers = make([]models.IvpnServer, len(allServers.Ivpn.Servers))
|
|
||||||
copy(servers, allServers.Ivpn.Servers)
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -9,8 +9,7 @@ const (
|
|||||||
MullvadCertificate = "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"
|
MullvadCertificate = "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"
|
||||||
)
|
)
|
||||||
|
|
||||||
func MullvadCountryChoices() (choices []string) {
|
func MullvadCountryChoices(servers []models.MullvadServer) (choices []string) {
|
||||||
servers := MullvadServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Country
|
choices[i] = servers[i].Country
|
||||||
@@ -18,8 +17,7 @@ func MullvadCountryChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MullvadCityChoices() (choices []string) {
|
func MullvadCityChoices(servers []models.MullvadServer) (choices []string) {
|
||||||
servers := MullvadServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].City
|
choices[i] = servers[i].City
|
||||||
@@ -27,8 +25,7 @@ func MullvadCityChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MullvadHostnameChoices() (choices []string) {
|
func MullvadHostnameChoices(servers []models.MullvadServer) (choices []string) {
|
||||||
servers := MullvadServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Hostname
|
choices[i] = servers[i].Hostname
|
||||||
@@ -36,18 +33,10 @@ func MullvadHostnameChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MullvadISPChoices() (choices []string) {
|
func MullvadISPChoices(servers []models.MullvadServer) (choices []string) {
|
||||||
servers := MullvadServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].ISP
|
choices[i] = servers[i].ISP
|
||||||
}
|
}
|
||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MullvadServers returns a slice of all the server information for Mullvad.
|
|
||||||
func MullvadServers() (servers []models.MullvadServer) {
|
|
||||||
servers = make([]models.MullvadServer, len(allServers.Mullvad.Servers))
|
|
||||||
copy(servers, allServers.Mullvad.Servers)
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,8 +10,7 @@ const (
|
|||||||
NordvpnOpenvpnStaticKeyV1 = "e685bdaf659a25a200e2b9e39e51ff030fc72cf1ce07232bd8b2be5e6c670143f51e937e670eee09d4f2ea5a6e4e69965db852c275351b86fc4ca892d78ae002d6f70d029bd79c4d1c26cf14e9588033cf639f8a74809f29f72b9d58f9b8f5fefc7938eade40e9fed6cb92184abb2cc10eb1a296df243b251df0643d53724cdb5a92a1d6cb817804c4a9319b57d53be580815bcfcb2df55018cc83fc43bc7ff82d51f9b88364776ee9d12fc85cc7ea5b9741c4f598c485316db066d52db4540e212e1518a9bd4828219e24b20d88f598a196c9de96012090e333519ae18d35099427e7b372d348d352dc4c85e18cd4b93f8a56ddb2e64eb67adfc9b337157ff4"
|
NordvpnOpenvpnStaticKeyV1 = "e685bdaf659a25a200e2b9e39e51ff030fc72cf1ce07232bd8b2be5e6c670143f51e937e670eee09d4f2ea5a6e4e69965db852c275351b86fc4ca892d78ae002d6f70d029bd79c4d1c26cf14e9588033cf639f8a74809f29f72b9d58f9b8f5fefc7938eade40e9fed6cb92184abb2cc10eb1a296df243b251df0643d53724cdb5a92a1d6cb817804c4a9319b57d53be580815bcfcb2df55018cc83fc43bc7ff82d51f9b88364776ee9d12fc85cc7ea5b9741c4f598c485316db066d52db4540e212e1518a9bd4828219e24b20d88f598a196c9de96012090e333519ae18d35099427e7b372d348d352dc4c85e18cd4b93f8a56ddb2e64eb67adfc9b337157ff4"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NordvpnRegionChoices() (choices []string) {
|
func NordvpnRegionChoices(servers []models.NordvpnServer) (choices []string) {
|
||||||
servers := NordvpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Region
|
choices[i] = servers[i].Region
|
||||||
@@ -19,8 +18,7 @@ func NordvpnRegionChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NordvpnHostnameChoices() (choices []string) {
|
func NordvpnHostnameChoices(servers []models.NordvpnServer) (choices []string) {
|
||||||
servers := NordvpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Hostname
|
choices[i] = servers[i].Hostname
|
||||||
@@ -28,18 +26,10 @@ func NordvpnHostnameChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NordvpnNameChoices() (choices []string) {
|
func NordvpnNameChoices(servers []models.NordvpnServer) (choices []string) {
|
||||||
servers := NordvpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Name
|
choices[i] = servers[i].Name
|
||||||
}
|
}
|
||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NordvpnServers returns a slice of all the server information for Nordvpn.
|
|
||||||
func NordvpnServers() (servers []models.NordvpnServer) {
|
|
||||||
servers = make([]models.NordvpnServer, len(allServers.Nordvpn.Servers))
|
|
||||||
copy(servers, allServers.Nordvpn.Servers)
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
package constants
|
package constants
|
||||||
|
|
||||||
const (
|
|
||||||
TUN = "tun0"
|
|
||||||
TAP = "tap0"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AES128cbc = "aes-128-cbc"
|
AES128cbc = "aes-128-cbc"
|
||||||
AES256cbc = "aes-256-cbc"
|
AES256cbc = "aes-256-cbc"
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ const (
|
|||||||
PIACertificateStrong = "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"
|
PIACertificateStrong = "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"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PIAGeoChoices() (choices []string) {
|
func PIAGeoChoices(servers []models.PIAServer) (choices []string) {
|
||||||
servers := PIAServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Region
|
choices[i] = servers[i].Region
|
||||||
@@ -24,8 +23,7 @@ func PIAGeoChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PIAHostnameChoices() (choices []string) {
|
func PIAHostnameChoices(servers []models.PIAServer) (choices []string) {
|
||||||
servers := PIAServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Hostname
|
choices[i] = servers[i].Hostname
|
||||||
@@ -33,8 +31,7 @@ func PIAHostnameChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PIANameChoices() (choices []string) {
|
func PIANameChoices(servers []models.PIAServer) (choices []string) {
|
||||||
servers := PIAServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].ServerName
|
choices[i] = servers[i].ServerName
|
||||||
@@ -42,9 +39,11 @@ func PIANameChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PIAServers returns a slice of all the server information for PIA.
|
func PIAServerWhereName(servers []models.PIAServer, serverName string) (server models.PIAServer) {
|
||||||
func PIAServers() (servers []models.PIAServer) {
|
for _, server := range servers {
|
||||||
servers = make([]models.PIAServer, len(allServers.Pia.Servers))
|
if server.ServerName == serverName {
|
||||||
copy(servers, allServers.Pia.Servers)
|
return server
|
||||||
return servers
|
}
|
||||||
|
}
|
||||||
|
return server
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
package constants
|
package constants
|
||||||
|
|
||||||
import (
|
import "github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
//nolint:lll
|
//nolint:lll
|
||||||
const (
|
const (
|
||||||
PrivadoCertificate = "MIIFKDCCAxCgAwIBAgIJAMtrmqZxIV/OMA0GCSqGSIb3DQEBDQUAMBIxEDAOBgNVBAMMB1ByaXZhZG8wHhcNMjAwMTA4MjEyODQ1WhcNMzUwMTA5MjEyODQ1WjASMRAwDgYDVQQDDAdQcml2YWRvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxPwOgiwNJzZTnKIXwAB0TSu/Lu2qt2U2I8obtQjwhi/7OrfmbmYykSdro70al2XPhnwAGGdCxW6LDnp0UN/IOhD11mgBPo14f5CLkBQjSJ6VN5miPbvK746LsNZl9H8rQGvDuPo4CG9BfPZMiDRGlsMxij/jztzgT1gmuxQ7WHfFRcNzBas1dHa9hV/d3TU6/t47x4SE/ljdcCtJiu7Zn6ODKQoys3mB7Luz2ngqUJWvkqsg+E4+3eJ0M8Hlbn5TPaRJBID7DAdYo6Vs6xGCYr981ThFcmoIQ10js10yANrrfGAzd03b3TnLAgko0uQMHjliMZL6L8sWOPHxyxJI0us88SFh4UgcFyRHKHPKux7w24SxAlZUYoUcTHp9VjG5XvDKYxzgV2RdM4ulBGbQRQ3y3/CyddsyQYMvA55Ets0LfPaBvDIcct70iXijGsdvlX1du3ArGpG7Vaje/RU4nbbGT6HYRdt5YyZfof288ukMOSj20nVcmS+c/4tqsxSerRb1aq5LOi1IemSkTMeC5gCbexk+L1vl7NT/58sxjGmu5bXwnvev/lIItfi2AlITrfUSEv19iDMKkeshwn/+sFJBMWYyluP+yJ56yR+MWoXvLlSWphLDTqq19yx3BZn0P1tgbXoR0g8PTdJFcz8z3RIb7myVLYulV1oGG/3rka0CAwEAAaOBgDB+MB0GA1UdDgQWBBTFtJkZCVDuDAD6k5bJzefjJdO3DTBCBgNVHSMEOzA5gBTFtJkZCVDuDAD6k5bJzefjJdO3DaEWpBQwEjEQMA4GA1UEAwwHUHJpdmFkb4IJAMtrmqZxIV/OMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBDQUAA4ICAQB7MUSXMeBb9wlSv4sUaT1JHEwE26nlBw+TKmezfuPU5pBlY0LYr6qQZY95DHqsRJ7ByUzGUrGo17dNGXlcuNc6TAaQQEDRPo6y+LVh2TWMk15TUMI+MkqryJtCret7xGvDigKYMJgBy58HN3RAVr1B7cL9youwzLgc2Y/NcFKvnQJKeiIYAJ7g0CcnJiQvgZTS7xdwkEBXfsngmUCIG320DLPEL+Ze0HiUrxwWljMRya6i40AeH3Zu2i532xX1wV5+cjA4RJWIKg6ri/Q54iFGtZrA9/nc6y9uoQHkmz8cGyVUmJxFzMrrIICVqUtVRxLhkTMe4UzwRWTBeGgtW4tS0yq1QonAKfOyjgRw/CeY55D2UGvnAFZdTadtYXS4Alu2P9zdwoEk3fzHiVmDjqfJVr5wz9383aABUFrPI3nz6ed/Z6LZflKh1k+DUDEp8NxU4klUULWsSOKoa5zGX51G8cdHxwQLImXvtGuN5eSR8jCTgxFZhdps/xes4KkyfIz9FMYG748M+uOTgKITf4zdJ9BAyiQaOufVQZ8WjhWzWk9YHec9VqPkzpWNGkVjiRI5ewuXwZzZ164tMv2hikBXSuUCnFz37/ZNwGlDi0oBdDszCk2GxccdFHHaCSmpjU5MrdJ+5IhtTKGeTx+US2hTIVHQFIO99DmacxSYvLNcSQ=="
|
PrivadoCertificate = "MIIFKDCCAxCgAwIBAgIJAMtrmqZxIV/OMA0GCSqGSIb3DQEBDQUAMBIxEDAOBgNVBAMMB1ByaXZhZG8wHhcNMjAwMTA4MjEyODQ1WhcNMzUwMTA5MjEyODQ1WjASMRAwDgYDVQQDDAdQcml2YWRvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxPwOgiwNJzZTnKIXwAB0TSu/Lu2qt2U2I8obtQjwhi/7OrfmbmYykSdro70al2XPhnwAGGdCxW6LDnp0UN/IOhD11mgBPo14f5CLkBQjSJ6VN5miPbvK746LsNZl9H8rQGvDuPo4CG9BfPZMiDRGlsMxij/jztzgT1gmuxQ7WHfFRcNzBas1dHa9hV/d3TU6/t47x4SE/ljdcCtJiu7Zn6ODKQoys3mB7Luz2ngqUJWvkqsg+E4+3eJ0M8Hlbn5TPaRJBID7DAdYo6Vs6xGCYr981ThFcmoIQ10js10yANrrfGAzd03b3TnLAgko0uQMHjliMZL6L8sWOPHxyxJI0us88SFh4UgcFyRHKHPKux7w24SxAlZUYoUcTHp9VjG5XvDKYxzgV2RdM4ulBGbQRQ3y3/CyddsyQYMvA55Ets0LfPaBvDIcct70iXijGsdvlX1du3ArGpG7Vaje/RU4nbbGT6HYRdt5YyZfof288ukMOSj20nVcmS+c/4tqsxSerRb1aq5LOi1IemSkTMeC5gCbexk+L1vl7NT/58sxjGmu5bXwnvev/lIItfi2AlITrfUSEv19iDMKkeshwn/+sFJBMWYyluP+yJ56yR+MWoXvLlSWphLDTqq19yx3BZn0P1tgbXoR0g8PTdJFcz8z3RIb7myVLYulV1oGG/3rka0CAwEAAaOBgDB+MB0GA1UdDgQWBBTFtJkZCVDuDAD6k5bJzefjJdO3DTBCBgNVHSMEOzA5gBTFtJkZCVDuDAD6k5bJzefjJdO3DaEWpBQwEjEQMA4GA1UEAwwHUHJpdmFkb4IJAMtrmqZxIV/OMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBDQUAA4ICAQB7MUSXMeBb9wlSv4sUaT1JHEwE26nlBw+TKmezfuPU5pBlY0LYr6qQZY95DHqsRJ7ByUzGUrGo17dNGXlcuNc6TAaQQEDRPo6y+LVh2TWMk15TUMI+MkqryJtCret7xGvDigKYMJgBy58HN3RAVr1B7cL9youwzLgc2Y/NcFKvnQJKeiIYAJ7g0CcnJiQvgZTS7xdwkEBXfsngmUCIG320DLPEL+Ze0HiUrxwWljMRya6i40AeH3Zu2i532xX1wV5+cjA4RJWIKg6ri/Q54iFGtZrA9/nc6y9uoQHkmz8cGyVUmJxFzMrrIICVqUtVRxLhkTMe4UzwRWTBeGgtW4tS0yq1QonAKfOyjgRw/CeY55D2UGvnAFZdTadtYXS4Alu2P9zdwoEk3fzHiVmDjqfJVr5wz9383aABUFrPI3nz6ed/Z6LZflKh1k+DUDEp8NxU4klUULWsSOKoa5zGX51G8cdHxwQLImXvtGuN5eSR8jCTgxFZhdps/xes4KkyfIz9FMYG748M+uOTgKITf4zdJ9BAyiQaOufVQZ8WjhWzWk9YHec9VqPkzpWNGkVjiRI5ewuXwZzZ164tMv2hikBXSuUCnFz37/ZNwGlDi0oBdDszCk2GxccdFHHaCSmpjU5MrdJ+5IhtTKGeTx+US2hTIVHQFIO99DmacxSYvLNcSQ=="
|
||||||
)
|
)
|
||||||
|
|
||||||
func PrivadoCountryChoices() (choices []string) {
|
func PrivadoCountryChoices(servers []models.PrivadoServer) (choices []string) {
|
||||||
servers := PrivadoServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Country
|
choices[i] = servers[i].Country
|
||||||
@@ -18,8 +15,7 @@ func PrivadoCountryChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrivadoRegionChoices() (choices []string) {
|
func PrivadoRegionChoices(servers []models.PrivadoServer) (choices []string) {
|
||||||
servers := PrivadoServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Region
|
choices[i] = servers[i].Region
|
||||||
@@ -27,8 +23,7 @@ func PrivadoRegionChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrivadoCityChoices() (choices []string) {
|
func PrivadoCityChoices(servers []models.PrivadoServer) (choices []string) {
|
||||||
servers := PrivadoServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].City
|
choices[i] = servers[i].City
|
||||||
@@ -36,18 +31,10 @@ func PrivadoCityChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrivadoHostnameChoices() (choices []string) {
|
func PrivadoHostnameChoices(servers []models.PrivadoServer) (choices []string) {
|
||||||
servers := PrivadoServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Hostname
|
choices[i] = servers[i].Hostname
|
||||||
}
|
}
|
||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrivadoServers returns a slice of all the Privado servers.
|
|
||||||
func PrivadoServers() (servers []models.PrivadoServer) {
|
|
||||||
servers = make([]models.PrivadoServer, len(allServers.Privado.Servers))
|
|
||||||
copy(servers, allServers.Privado.Servers)
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package constants
|
package constants
|
||||||
|
|
||||||
import (
|
import "github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
//nolint:lll
|
//nolint:lll
|
||||||
const (
|
const (
|
||||||
@@ -10,8 +8,7 @@ const (
|
|||||||
PrivatevpnOpenvpnStaticKeyV1 = "a49082f082ca89d6a6bb4ecc7c047c6d428a1d3c8254a95206d38a61d7fbe65984214cd7d56eacc5a60803bffd677fa7294d4bfe555036339312de2dfb1335bd9d5fd94b04bba3a15fc5192aeb02fb6d8dd2ca831fad7509be5eefa8d1eaa689dc586c831a23b589c512662652ecf1bb3a4a673816aba434a04f6857b8c2f8bb265bfe48a7b8112539729d2f7d9734a720e1035188118c73fef1824d0237d5579ca382d703b4bb252acaedc753b12199f00154d3769efbcf85ef5ad6ee755cbeaa944cb98e7654286df54c793a8443f5363078e3da548ba0beed079df633283cefb256f6a4bcfc4ab2c4affc24955c1864d5458e84a7c210d0d186269e55dcf6"
|
PrivatevpnOpenvpnStaticKeyV1 = "a49082f082ca89d6a6bb4ecc7c047c6d428a1d3c8254a95206d38a61d7fbe65984214cd7d56eacc5a60803bffd677fa7294d4bfe555036339312de2dfb1335bd9d5fd94b04bba3a15fc5192aeb02fb6d8dd2ca831fad7509be5eefa8d1eaa689dc586c831a23b589c512662652ecf1bb3a4a673816aba434a04f6857b8c2f8bb265bfe48a7b8112539729d2f7d9734a720e1035188118c73fef1824d0237d5579ca382d703b4bb252acaedc753b12199f00154d3769efbcf85ef5ad6ee755cbeaa944cb98e7654286df54c793a8443f5363078e3da548ba0beed079df633283cefb256f6a4bcfc4ab2c4affc24955c1864d5458e84a7c210d0d186269e55dcf6"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PrivatevpnCountryChoices() (choices []string) {
|
func PrivatevpnCountryChoices(servers []models.PrivatevpnServer) (choices []string) {
|
||||||
servers := PrivatevpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Country
|
choices[i] = servers[i].Country
|
||||||
@@ -19,8 +16,7 @@ func PrivatevpnCountryChoices() (choices []string) {
|
|||||||
return makeChoicesUnique(choices)
|
return makeChoicesUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrivatevpnCityChoices() (choices []string) {
|
func PrivatevpnCityChoices(servers []models.PrivatevpnServer) (choices []string) {
|
||||||
servers := PrivatevpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].City
|
choices[i] = servers[i].City
|
||||||
@@ -28,17 +24,10 @@ func PrivatevpnCityChoices() (choices []string) {
|
|||||||
return makeChoicesUnique(choices)
|
return makeChoicesUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrivatevpnHostnameChoices() (choices []string) {
|
func PrivatevpnHostnameChoices(servers []models.PrivatevpnServer) (choices []string) {
|
||||||
servers := PrivatevpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Hostname
|
choices[i] = servers[i].Hostname
|
||||||
}
|
}
|
||||||
return makeChoicesUnique(choices)
|
return makeChoicesUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrivatevpnServers() (servers []models.PrivatevpnServer) {
|
|
||||||
servers = make([]models.PrivatevpnServer, len(allServers.Privatevpn.Servers))
|
|
||||||
copy(servers, allServers.Privatevpn.Servers)
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package constants
|
package constants
|
||||||
|
|
||||||
import (
|
import "github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
//nolint:lll
|
//nolint:lll
|
||||||
const (
|
const (
|
||||||
@@ -10,8 +8,7 @@ const (
|
|||||||
ProtonvpnOpenvpnStaticKeyV1 = "6acef03f62675b4b1bbd03e53b187727423cea742242106cb2916a8a4c8297563d22c7e5cef430b1103c6f66eb1fc5b375a672f158e2e2e936c3faa48b035a6de17beaac23b5f03b10b868d53d03521d8ba115059da777a60cbfd7b2c9c5747278a15b8f6e68a3ef7fd583ec9f398c8bd4735dab40cbd1e3c62a822e97489186c30a0b48c7c38ea32ceb056d3fa5a710e10ccc7a0ddb363b08c3d2777a3395e10c0b6080f56309192ab5aacd4b45f55da61fc77af39bd81a19218a79762c33862df55785075f37d8c71dc8a42097ee43344739a0dd48d03025b0450cf1fb5e8caeb893d9a96d1f15519bb3c4dcb40ee316672ea16c012664f8a9f11255518deb"
|
ProtonvpnOpenvpnStaticKeyV1 = "6acef03f62675b4b1bbd03e53b187727423cea742242106cb2916a8a4c8297563d22c7e5cef430b1103c6f66eb1fc5b375a672f158e2e2e936c3faa48b035a6de17beaac23b5f03b10b868d53d03521d8ba115059da777a60cbfd7b2c9c5747278a15b8f6e68a3ef7fd583ec9f398c8bd4735dab40cbd1e3c62a822e97489186c30a0b48c7c38ea32ceb056d3fa5a710e10ccc7a0ddb363b08c3d2777a3395e10c0b6080f56309192ab5aacd4b45f55da61fc77af39bd81a19218a79762c33862df55785075f37d8c71dc8a42097ee43344739a0dd48d03025b0450cf1fb5e8caeb893d9a96d1f15519bb3c4dcb40ee316672ea16c012664f8a9f11255518deb"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProtonvpnCountryChoices() (choices []string) {
|
func ProtonvpnCountryChoices(servers []models.ProtonvpnServer) (choices []string) {
|
||||||
servers := ProtonvpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Country
|
choices[i] = servers[i].Country
|
||||||
@@ -19,8 +16,7 @@ func ProtonvpnCountryChoices() (choices []string) {
|
|||||||
return makeChoicesUnique(choices)
|
return makeChoicesUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProtonvpnRegionChoices() (choices []string) {
|
func ProtonvpnRegionChoices(servers []models.ProtonvpnServer) (choices []string) {
|
||||||
servers := ProtonvpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Region
|
choices[i] = servers[i].Region
|
||||||
@@ -28,8 +24,7 @@ func ProtonvpnRegionChoices() (choices []string) {
|
|||||||
return makeChoicesUnique(choices)
|
return makeChoicesUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProtonvpnCityChoices() (choices []string) {
|
func ProtonvpnCityChoices(servers []models.ProtonvpnServer) (choices []string) {
|
||||||
servers := ProtonvpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].City
|
choices[i] = servers[i].City
|
||||||
@@ -37,8 +32,7 @@ func ProtonvpnCityChoices() (choices []string) {
|
|||||||
return makeChoicesUnique(choices)
|
return makeChoicesUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProtonvpnNameChoices() (choices []string) {
|
func ProtonvpnNameChoices(servers []models.ProtonvpnServer) (choices []string) {
|
||||||
servers := ProtonvpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Name
|
choices[i] = servers[i].Name
|
||||||
@@ -46,18 +40,10 @@ func ProtonvpnNameChoices() (choices []string) {
|
|||||||
return makeChoicesUnique(choices)
|
return makeChoicesUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProtonvpnHostnameChoices() (choices []string) {
|
func ProtonvpnHostnameChoices(servers []models.ProtonvpnServer) (choices []string) {
|
||||||
servers := ProtonvpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Hostname
|
choices[i] = servers[i].Hostname
|
||||||
}
|
}
|
||||||
return makeChoicesUnique(choices)
|
return makeChoicesUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProtonvpnServers returns a slice of all the server information for Protonvpn.
|
|
||||||
func ProtonvpnServers() (servers []models.ProtonvpnServer) {
|
|
||||||
servers = make([]models.ProtonvpnServer, len(allServers.Protonvpn.Servers))
|
|
||||||
copy(servers, allServers.Protonvpn.Servers)
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package constants
|
package constants
|
||||||
|
|
||||||
import (
|
import "github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
//nolint:lll
|
//nolint:lll
|
||||||
const (
|
const (
|
||||||
@@ -12,8 +10,7 @@ const (
|
|||||||
PurevpnOpenvpnStaticKeyV1 = "e30af995f56d07426d9ba1f824730521d4283db4b4d0cdda9c6e8759a3799dcb7939b6a5989160c9660de0f6125cbb1f585b41c074b2fe88ecfcf17eab9a33be1352379cdf74952b588fb161a93e13df9135b2b29038231e02d657a6225705e6868ccb0c384ed11614690a1894bfbeb274cebf1fe9c2329bdd5c8a40fe8820624d2ea7540cd79ab76892db51fc371a3ac5fc9573afecb3fffe3281e61d72e91579d9b03d8cbf7909b3aebf4d90850321ee6b7d0a7846d15c27d8290e031e951e19438a4654663cad975e138f5bc5af89c737ad822f27e19057731f41e1e254cc9c95b7175c622422cde9f1f2cfd3510add94498b4d7133d3729dd214a16b27fb"
|
PurevpnOpenvpnStaticKeyV1 = "e30af995f56d07426d9ba1f824730521d4283db4b4d0cdda9c6e8759a3799dcb7939b6a5989160c9660de0f6125cbb1f585b41c074b2fe88ecfcf17eab9a33be1352379cdf74952b588fb161a93e13df9135b2b29038231e02d657a6225705e6868ccb0c384ed11614690a1894bfbeb274cebf1fe9c2329bdd5c8a40fe8820624d2ea7540cd79ab76892db51fc371a3ac5fc9573afecb3fffe3281e61d72e91579d9b03d8cbf7909b3aebf4d90850321ee6b7d0a7846d15c27d8290e031e951e19438a4654663cad975e138f5bc5af89c737ad822f27e19057731f41e1e254cc9c95b7175c622422cde9f1f2cfd3510add94498b4d7133d3729dd214a16b27fb"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PurevpnRegionChoices() (choices []string) {
|
func PurevpnRegionChoices(servers []models.PurevpnServer) (choices []string) {
|
||||||
servers := PurevpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Region
|
choices[i] = servers[i].Region
|
||||||
@@ -21,8 +18,7 @@ func PurevpnRegionChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PurevpnCountryChoices() (choices []string) {
|
func PurevpnCountryChoices(servers []models.PurevpnServer) (choices []string) {
|
||||||
servers := PurevpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Country
|
choices[i] = servers[i].Country
|
||||||
@@ -30,8 +26,7 @@ func PurevpnCountryChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PurevpnCityChoices() (choices []string) {
|
func PurevpnCityChoices(servers []models.PurevpnServer) (choices []string) {
|
||||||
servers := PurevpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].City
|
choices[i] = servers[i].City
|
||||||
@@ -39,18 +34,10 @@ func PurevpnCityChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PurevpnHostnameChoices() (choices []string) {
|
func PurevpnHostnameChoices(servers []models.PurevpnServer) (choices []string) {
|
||||||
servers := PurevpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Hostname
|
choices[i] = servers[i].Hostname
|
||||||
}
|
}
|
||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PurevpnServers returns a slice of all the server information for Purevpn.
|
|
||||||
func PurevpnServers() (servers []models.PurevpnServer) {
|
|
||||||
servers = make([]models.PurevpnServer, len(allServers.Purevpn.Servers))
|
|
||||||
copy(servers, allServers.Purevpn.Servers)
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
package constants
|
|
||||||
|
|
||||||
import (
|
|
||||||
"embed"
|
|
||||||
"encoding/json"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
//go:embed servers.json
|
|
||||||
var allServersEmbedFS embed.FS //nolint:gochecknoglobals
|
|
||||||
var allServers models.AllServers //nolint:gochecknoglobals
|
|
||||||
var parseOnce sync.Once //nolint:gochecknoglobals
|
|
||||||
|
|
||||||
func init() { //nolint:gochecknoinits
|
|
||||||
// error returned covered by unit test
|
|
||||||
parseOnce.Do(func() { allServers, _ = parseAllServers() })
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseAllServers() (allServers models.AllServers, err error) {
|
|
||||||
f, err := allServersEmbedFS.Open("servers.json")
|
|
||||||
if err != nil {
|
|
||||||
return allServers, err
|
|
||||||
}
|
|
||||||
decoder := json.NewDecoder(f)
|
|
||||||
err = decoder.Decode(&allServers)
|
|
||||||
return allServers, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetAllServers() models.AllServers {
|
|
||||||
parseOnce.Do(func() { allServers, _ = parseAllServers() }) // init did not execute, used in tests
|
|
||||||
return allServers
|
|
||||||
}
|
|
||||||
@@ -10,8 +10,7 @@ const (
|
|||||||
SurfsharkOpenvpnStaticKeyV1 = "b02cb1d7c6fee5d4f89b8de72b51a8d0c7b282631d6fc19be1df6ebae9e2779e6d9f097058a31c97f57f0c35526a44ae09a01d1284b50b954d9246725a1ead1ff224a102ed9ab3da0152a15525643b2eee226c37041dc55539d475183b889a10e18bb94f079a4a49888da566b99783460ece01daaf93548beea6c827d9674897e7279ff1a19cb092659e8c1860fbad0db4ad0ad5732f1af4655dbd66214e552f04ed8fd0104e1d4bf99c249ac229ce169d9ba22068c6c0ab742424760911d4636aafb4b85f0c952a9ce4275bc821391aa65fcd0d2394f006e3fba0fd34c4bc4ab260f4b45dec3285875589c97d3087c9134d3a3aa2f904512e85aa2dc2202498"
|
SurfsharkOpenvpnStaticKeyV1 = "b02cb1d7c6fee5d4f89b8de72b51a8d0c7b282631d6fc19be1df6ebae9e2779e6d9f097058a31c97f57f0c35526a44ae09a01d1284b50b954d9246725a1ead1ff224a102ed9ab3da0152a15525643b2eee226c37041dc55539d475183b889a10e18bb94f079a4a49888da566b99783460ece01daaf93548beea6c827d9674897e7279ff1a19cb092659e8c1860fbad0db4ad0ad5732f1af4655dbd66214e552f04ed8fd0104e1d4bf99c249ac229ce169d9ba22068c6c0ab742424760911d4636aafb4b85f0c952a9ce4275bc821391aa65fcd0d2394f006e3fba0fd34c4bc4ab260f4b45dec3285875589c97d3087c9134d3a3aa2f904512e85aa2dc2202498"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SurfsharkRegionChoices() (choices []string) {
|
func SurfsharkRegionChoices(servers []models.SurfsharkServer) (choices []string) {
|
||||||
servers := SurfsharkServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Region
|
choices[i] = servers[i].Region
|
||||||
@@ -19,18 +18,211 @@ func SurfsharkRegionChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SurfsharkHostnameChoices() (choices []string) {
|
func SurfsharkCountryChoices(servers []models.SurfsharkServer) (choices []string) {
|
||||||
servers := SurfsharkServers()
|
choices = make([]string, len(servers))
|
||||||
|
for i := range servers {
|
||||||
|
choices[i] = servers[i].Country
|
||||||
|
}
|
||||||
|
return makeUnique(choices)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SurfsharkCityChoices(servers []models.SurfsharkServer) (choices []string) {
|
||||||
|
choices = make([]string, len(servers))
|
||||||
|
for i := range servers {
|
||||||
|
choices[i] = servers[i].City
|
||||||
|
}
|
||||||
|
return makeUnique(choices)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO remove in v4.
|
||||||
|
func SurfsharkRetroLocChoices(servers []models.SurfsharkServer) (choices []string) {
|
||||||
|
locationData := SurfsharkLocationData()
|
||||||
|
choices = make([]string, len(locationData))
|
||||||
|
for i := range locationData {
|
||||||
|
choices[i] = locationData[i].RetroLoc
|
||||||
|
}
|
||||||
|
return makeUnique(choices)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SurfsharkHostToLocation() (hostToLocation map[string]models.SurfsharkLocationData) {
|
||||||
|
locationData := SurfsharkLocationData()
|
||||||
|
hostToLocation = make(map[string]models.SurfsharkLocationData, len(locationData))
|
||||||
|
for _, data := range locationData {
|
||||||
|
hostToLocation[data.Hostname] = data
|
||||||
|
}
|
||||||
|
return hostToLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO remove retroRegion and servers from API in v4.
|
||||||
|
func SurfsharkLocationData() (data []models.SurfsharkLocationData) {
|
||||||
|
//nolint:lll
|
||||||
|
return []models.SurfsharkLocationData{
|
||||||
|
{Region: "Asia Pacific", Country: "Australia", City: "Adelaide", RetroLoc: "Australia Adelaide", Hostname: "au-adl.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Australia", City: "Brisbane", RetroLoc: "Australia Brisbane", Hostname: "au-bne.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Australia", City: "Melbourne", RetroLoc: "Australia Melbourne", Hostname: "au-mel.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Australia", City: "Perth", RetroLoc: "Australia Perth", Hostname: "au-per.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Australia", City: "Sydney", RetroLoc: "Australia Sydney", Hostname: "au-syd.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Azerbaijan", City: "Baku", RetroLoc: "Azerbaijan", Hostname: "az-bak.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Hong Kong", City: "Hong Kong", RetroLoc: "Hong Kong", Hostname: "hk-hkg.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "India", City: "Chennai", RetroLoc: "India Chennai", Hostname: "in-chn.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "India", City: "Indore", RetroLoc: "India Indore", Hostname: "in-idr.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "India", City: "Mumbai", RetroLoc: "India Mumbai", Hostname: "in-mum.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Indonesia", City: "Jakarta", RetroLoc: "Indonesia", Hostname: "id-jak.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st001", Hostname: "jp-tok-st001.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st002", Hostname: "jp-tok-st002.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st003", Hostname: "jp-tok-st003.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st004", Hostname: "jp-tok-st004.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st005", Hostname: "jp-tok-st005.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st006", Hostname: "jp-tok-st006.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st007", Hostname: "jp-tok-st007.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st008", Hostname: "jp-tok-st008.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st009", Hostname: "jp-tok-st009.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st010", Hostname: "jp-tok-st010.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st011", Hostname: "jp-tok-st011.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st012", Hostname: "jp-tok-st012.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo st013", Hostname: "jp-tok-st013.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Japan", City: "Tokyo", RetroLoc: "Japan Tokyo", Hostname: "jp-tok.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Kazakhstan", City: "Oral", RetroLoc: "Kazakhstan", Hostname: "kz-ura.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Malaysia", City: "Kuala Lumpur", RetroLoc: "Malaysia", Hostname: "my-kul.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "New Zealand", City: "Auckland", RetroLoc: "New Zealand", Hostname: "nz-akl.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Philippines", City: "Manila", RetroLoc: "Philippines", Hostname: "ph-mnl.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Singapore Hong Kong", City: "Hong Kong", RetroLoc: "Singapore Hong Kong", Hostname: "sg-hk.prod.surfshark.com", MultiHop: true},
|
||||||
|
{Region: "Asia Pacific", Country: "Singapore in", City: "", RetroLoc: "Singapore in", Hostname: "sg-in.prod.surfshark.com", MultiHop: true},
|
||||||
|
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore mp001", Hostname: "sg-sng-mp001.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore st001", Hostname: "sg-sng-st001.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore st002", Hostname: "sg-sng-st002.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore st003", Hostname: "sg-sng-st003.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore st004", Hostname: "sg-sng-st004.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Singapore", City: "Singapore", RetroLoc: "Singapore", Hostname: "sg-sng.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "South Korea", City: "Seoul", RetroLoc: "Korea", Hostname: "kr-seo.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Taiwan", City: "Taichung City", RetroLoc: "Taiwan", Hostname: "tw-tai.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Thailand", City: "Bangkok", RetroLoc: "Thailand", Hostname: "th-bkk.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Asia Pacific", Country: "Vietnam", City: "Ho Chi Minh City", RetroLoc: "Vietnam", Hostname: "vn-hcm.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Albania", City: "Tirana", RetroLoc: "Albania", Hostname: "al-tia.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Austria", City: "Vienna", RetroLoc: "Austria", Hostname: "at-vie.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Belgium", City: "Brussels", RetroLoc: "Belgium", Hostname: "be-bru.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Bosnia and Herzegovina", City: "Sarajevo", RetroLoc: "Bosnia and Herzegovina", Hostname: "ba-sjj.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Bulgaria", City: "Sofia", RetroLoc: "Bulgaria", Hostname: "bg-sof.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Croatia", City: "Zagreb", RetroLoc: "Croatia", Hostname: "hr-zag.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Cyprus", City: "Nicosia", RetroLoc: "Cyprus", Hostname: "cy-nic.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Czech Republic", City: "Prague", RetroLoc: "Czech Republic", Hostname: "cz-prg.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Denmark", City: "Copenhagen", RetroLoc: "Denmark", Hostname: "dk-cph.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Estonia", City: "Tallinn", RetroLoc: "Estonia", Hostname: "ee-tll.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Finland", City: "Helsinki", RetroLoc: "Finland", Hostname: "fi-hel.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "France Sweden", City: "", RetroLoc: "France Sweden", Hostname: "fr-se.prod.surfshark.com", MultiHop: true},
|
||||||
|
{Region: "Europe", Country: "France", City: "Bordeaux", RetroLoc: "France Bordeaux", Hostname: "fr-bod.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "France", City: "Marseille", RetroLoc: "France Marseilles", Hostname: "fr-mrs.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "France", City: "Paris", RetroLoc: "France Paris", Hostname: "fr-par.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Germany Singapour", City: "", RetroLoc: "Germany Singapour", Hostname: "de-sg.prod.surfshark.com", MultiHop: true},
|
||||||
|
{Region: "Europe", Country: "Germany UK", City: "", RetroLoc: "Germany UK", Hostname: "de-uk.prod.surfshark.com", MultiHop: true},
|
||||||
|
{Region: "Europe", Country: "Germany", City: "Berlin", RetroLoc: "Germany Berlin", Hostname: "de-ber.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main st001", Hostname: "de-fra-st001.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main st002", Hostname: "de-fra-st002.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main st003", Hostname: "de-fra-st003.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main st004", Hostname: "de-fra-st004.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main st005", Hostname: "de-fra-st005.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt am Main", Hostname: "de-fra.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Germany", City: "Frankfurt am Main", RetroLoc: "Germany Frankfurt mp001", Hostname: "de-fra-mp001.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Greece", City: "Athens", RetroLoc: "Greece", Hostname: "gr-ath.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Hungary", City: "Budapest", RetroLoc: "Hungary", Hostname: "hu-bud.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Iceland", City: "Reykjavik", RetroLoc: "Iceland", Hostname: "is-rkv.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "India UK", City: "", RetroLoc: "India UK", Hostname: "in-uk.prod.surfshark.com", MultiHop: true},
|
||||||
|
{Region: "Europe", Country: "Ireland", City: "Dublin", RetroLoc: "Ireland", Hostname: "ie-dub.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Italy", City: "Milan", RetroLoc: "Italy Milan", Hostname: "it-mil.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Italy", City: "Rome", RetroLoc: "Italy Rome", Hostname: "it-rom.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Latvia", City: "Riga", RetroLoc: "Latvia", Hostname: "lv-rig.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Luxembourg", City: "Luxembourg", RetroLoc: "Luxembourg", Hostname: "lu-ste.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Moldova", City: "Chisinau", RetroLoc: "Moldova", Hostname: "md-chi.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Netherlands", City: "Amsterdam", RetroLoc: "Netherlands Amsterdam mp001", Hostname: "nl-ams-mp001.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Netherlands", City: "Amsterdam", RetroLoc: "Netherlands Amsterdam st001", Hostname: "nl-ams-st001.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Netherlands", City: "Amsterdam", RetroLoc: "Netherlands Amsterdam", Hostname: "nl-ams.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "North Macedonia", City: "Skopje", RetroLoc: "North Macedonia", Hostname: "mk-skp.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Norway", City: "Oslo", RetroLoc: "Norway", Hostname: "no-osl.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Poland", City: "Gdansk", RetroLoc: "Poland Gdansk", Hostname: "pl-gdn.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Poland", City: "Warsaw", RetroLoc: "Poland Warsaw", Hostname: "pl-waw.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Portugal", City: "Lisbon", RetroLoc: "Portugal Lisbon", Hostname: "pt-lis.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Portugal", City: "Porto", RetroLoc: "Portugal Porto", Hostname: "pt-opo.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Romania", City: "Bucharest", RetroLoc: "Romania", Hostname: "ro-buc.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Russia", City: "Moscow", RetroLoc: "Russia Moscow", Hostname: "ru-mos.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Serbia", City: "Belgrade", RetroLoc: "Serbia", Hostname: "rs-beg.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Singapore Netherlands", City: "", RetroLoc: "Singapore Netherlands", Hostname: "sg-nl.prod.surfshark.com", MultiHop: true},
|
||||||
|
{Region: "Europe", Country: "Slovakia", City: "Bratislava", RetroLoc: "Slovekia", Hostname: "sk-bts.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Slovenia", City: "Ljubljana", RetroLoc: "Slovenia", Hostname: "si-lju.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Spain", City: "Barcelona", RetroLoc: "Spain Barcelona", Hostname: "es-bcn.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Spain", City: "Madrid", RetroLoc: "Spain Madrid", Hostname: "es-mad.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Spain", City: "Valencia", RetroLoc: "Spain Valencia", Hostname: "es-vlc.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Sweden", City: "Stockholm", RetroLoc: "Sweden", Hostname: "se-sto.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Switzerland", City: "Zurich", RetroLoc: "Switzerland", Hostname: "ch-zur.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "Turkey", City: "Istanbul", RetroLoc: "Turkey Istanbul", Hostname: "tr-ist.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "UK France", City: "", RetroLoc: "UK France", Hostname: "uk-fr.prod.surfshark.com", MultiHop: true},
|
||||||
|
{Region: "Europe", Country: "UK Germany", City: "", RetroLoc: "UK Germany", Hostname: "uk-de.prod.surfshark.com", MultiHop: true},
|
||||||
|
{Region: "Europe", Country: "Ukraine", City: "Kyiv", RetroLoc: "Ukraine", Hostname: "ua-iev.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "United Kingdom", City: "Glasgow", RetroLoc: "UK Glasgow", Hostname: "uk-gla.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London mp001", Hostname: "uk-lon-mp001.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London st001", Hostname: "uk-lon-st001.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London st002", Hostname: "uk-lon-st002.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London st003", Hostname: "uk-lon-st003.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London st004", Hostname: "uk-lon-st004.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London st005", Hostname: "uk-lon-st005.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "United Kingdom", City: "London", RetroLoc: "UK London", Hostname: "uk-lon.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "United Kingdom", City: "Manchester", RetroLoc: "UK Manchester", Hostname: "uk-man.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "US Netherlands", City: "", RetroLoc: "US Netherlands", Hostname: "us-nl.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Europe", Country: "US Portugal", City: "", RetroLoc: "US Portugal", Hostname: "us-pt.prod.surfshark.com", MultiHop: true},
|
||||||
|
{Region: "Middle East and Africa", Country: "Israel", City: "Tel Aviv", RetroLoc: "Israel", Hostname: "il-tlv.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Middle East and Africa", Country: "Nigeria", City: "Lagos", RetroLoc: "Nigeria", Hostname: "ng-lag.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Middle East and Africa", Country: "South Africa", City: "Johannesburg", RetroLoc: "South Africa", Hostname: "za-jnb.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "Middle East and Africa", Country: "United Arab Emirates", City: "Dubai", RetroLoc: "United Arab Emirates", Hostname: "ae-dub.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "Argentina", City: "Buenos Aires", RetroLoc: "Argentina Buenos Aires", Hostname: "ar-bua.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "Australia US", City: "", RetroLoc: "Australia US", Hostname: "au-us.prod.surfshark.com", MultiHop: true},
|
||||||
|
{Region: "The Americas", Country: "Brazil", City: "Sao Paulo", RetroLoc: "Brazil", Hostname: "br-sao.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "Canada US", City: "", RetroLoc: "Canada US", Hostname: "ca-us.prod.surfshark.com", MultiHop: true},
|
||||||
|
{Region: "The Americas", Country: "Canada", City: "Montreal", RetroLoc: "Canada Montreal", Hostname: "ca-mon.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "Canada", City: "Toronto", RetroLoc: "Canada Toronto mp001", Hostname: "ca-tor-mp001.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "Canada", City: "Toronto", RetroLoc: "Canada Toronto", Hostname: "ca-tor.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "Canada", City: "Vancouver", RetroLoc: "Canada Vancouver", Hostname: "ca-van.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "Chile", City: "Santiago", RetroLoc: "Chile", Hostname: "cl-san.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "Colombia", City: "Bogota", RetroLoc: "Colombia", Hostname: "co-bog.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "Costa Rica", City: "San Jose", RetroLoc: "Costa Rica", Hostname: "cr-sjn.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "Mexico", City: "Mexico City", RetroLoc: "Mexico City Mexico", Hostname: "mx-mex.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "Netherlands US", City: "", RetroLoc: "Netherlands US", Hostname: "nl-us.prod.surfshark.com", MultiHop: true},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Atlanta", RetroLoc: "US Atlanta", Hostname: "us-atl.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Bend", RetroLoc: "US Bend", Hostname: "us-bdn.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Boston", RetroLoc: "US Boston", Hostname: "us-bos.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Buffalo", RetroLoc: "US Buffalo", Hostname: "us-buf.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Charlotte", RetroLoc: "US Charlotte", Hostname: "us-clt.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Chicago", RetroLoc: "US Chicago", Hostname: "us-chi.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Dallas", RetroLoc: "US Dallas", Hostname: "us-dal.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Denver", RetroLoc: "US Denver", Hostname: "us-den.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Detroit", RetroLoc: "US Gahanna", Hostname: "us-dtw.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Houston", RetroLoc: "US Houston", Hostname: "us-hou.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Kansas City", RetroLoc: "US Kansas City", Hostname: "us-kan.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Las Vegas", RetroLoc: "US Las Vegas", Hostname: "us-las.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Latham", RetroLoc: "US Latham", Hostname: "us-ltm.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Los Angeles", RetroLoc: "US Los Angeles", Hostname: "us-lax.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Manassas", RetroLoc: "US Maryland", Hostname: "us-mnz.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Miami", RetroLoc: "US Miami", Hostname: "us-mia.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City mp001", Hostname: "us-nyc-mp001.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City st001", Hostname: "us-nyc-st001.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City st002", Hostname: "us-nyc-st002.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City st003", Hostname: "us-nyc-st003.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City st004", Hostname: "us-nyc-st004.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City st005", Hostname: "us-nyc-st005.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "New York", RetroLoc: "US New York City", Hostname: "us-nyc.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Orlando", RetroLoc: "US Orlando", Hostname: "us-orl.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Phoenix", RetroLoc: "US Phoenix", Hostname: "us-phx.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Salt Lake City", RetroLoc: "US Salt Lake City", Hostname: "us-slc.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "San Francisco", RetroLoc: "US San Francisco mp001", Hostname: "us-sfo-mp001.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "San Francisco", RetroLoc: "US San Francisco", Hostname: "us-sfo.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Seattle", RetroLoc: "US Seatle", Hostname: "us-sea.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "St. Louis", RetroLoc: "US Saint Louis", Hostname: "us-stl.prod.surfshark.com", MultiHop: false},
|
||||||
|
{Region: "The Americas", Country: "United States", City: "Tampa", RetroLoc: "US Tampa", Hostname: "us-tpa.prod.surfshark.com", MultiHop: false},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SurfsharkHostnameChoices(servers []models.SurfsharkServer) (choices []string) {
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Hostname
|
choices[i] = servers[i].Hostname
|
||||||
}
|
}
|
||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SurfsharkServers returns a slice of all the server information for Surfshark.
|
|
||||||
func SurfsharkServers() (servers []models.SurfsharkServer) {
|
|
||||||
servers = make([]models.SurfsharkServer, len(allServers.Surfshark.Servers))
|
|
||||||
copy(servers, allServers.Surfshark.Servers)
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,8 +10,7 @@ const (
|
|||||||
TorguardOpenvpnStaticKeyV1 = "770e8de5fc56e0248cc7b5aab56be80d0e19cbf003c1b3ed68efbaf08613c3a1a019dac6a4b84f13a6198f73229ffc21fa512394e288f82aa2cf0180f01fb3eb1a71e00a077a20f6d7a83633f5b4f47f27e30617eaf8485dd8c722a8606d56b3c183f65da5d3c9001a8cbdb96c793d936251098b24fe52a6dd2472e98cfccbc466e63520d63ade7a0eacc36208c3142a1068236a52142fbb7b3ed83d785e12a28261bccfb3bcb62a8d2f6d18f5df5f3652e59c5627d8d9c8f7877c4d7b08e19a5c363556ba68d392be78b75152dd55ba0f74d45089e84f77f4492d886524ea6c82b9f4dd83d46528d4f5c3b51cfeaf2838d938bd0597c426b0e440434f2c451f"
|
TorguardOpenvpnStaticKeyV1 = "770e8de5fc56e0248cc7b5aab56be80d0e19cbf003c1b3ed68efbaf08613c3a1a019dac6a4b84f13a6198f73229ffc21fa512394e288f82aa2cf0180f01fb3eb1a71e00a077a20f6d7a83633f5b4f47f27e30617eaf8485dd8c722a8606d56b3c183f65da5d3c9001a8cbdb96c793d936251098b24fe52a6dd2472e98cfccbc466e63520d63ade7a0eacc36208c3142a1068236a52142fbb7b3ed83d785e12a28261bccfb3bcb62a8d2f6d18f5df5f3652e59c5627d8d9c8f7877c4d7b08e19a5c363556ba68d392be78b75152dd55ba0f74d45089e84f77f4492d886524ea6c82b9f4dd83d46528d4f5c3b51cfeaf2838d938bd0597c426b0e440434f2c451f"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TorguardCountryChoices() (choices []string) {
|
func TorguardCountryChoices(servers []models.TorguardServer) (choices []string) {
|
||||||
servers := TorguardServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Country
|
choices[i] = servers[i].Country
|
||||||
@@ -19,8 +18,7 @@ func TorguardCountryChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TorguardCityChoices() (choices []string) {
|
func TorguardCityChoices(servers []models.TorguardServer) (choices []string) {
|
||||||
servers := TorguardServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].City
|
choices[i] = servers[i].City
|
||||||
@@ -28,18 +26,10 @@ func TorguardCityChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TorguardHostnameChoices() (choices []string) {
|
func TorguardHostnameChoices(servers []models.TorguardServer) (choices []string) {
|
||||||
servers := TorguardServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Hostname
|
choices[i] = servers[i].Hostname
|
||||||
}
|
}
|
||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TorguardServers returns a slice of all the server information for Torguard.
|
|
||||||
func TorguardServers() (servers []models.TorguardServer) {
|
|
||||||
servers = make([]models.TorguardServer, len(allServers.Torguard.Servers))
|
|
||||||
copy(servers, allServers.Torguard.Servers)
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
package constants
|
package constants
|
||||||
|
|
||||||
|
const (
|
||||||
|
OpenVPN = "openvpn"
|
||||||
|
Wireguard = "wireguard"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Cyberghost is a VPN provider.
|
// Cyberghost is a VPN provider.
|
||||||
Cyberghost = "cyberghost"
|
Cyberghost = "cyberghost"
|
||||||
|
|||||||
@@ -9,8 +9,7 @@ const (
|
|||||||
VPNUnlimitedCertificateAuthority = "MIIEjjCCA/egAwIBAgIJAKsVbHBdakXuMA0GCSqGSIb3DQEBBQUAMIHgMQswCQYDVQQGEwJVUzELMAkGA1UECBMCTlkxETAPBgNVBAcTCE5ldyBZb3JrMR8wHQYDVQQKExZTaW1wbGV4IFNvbHV0aW9ucyBJbmMuMRYwFAYDVQQLEw1WcG4gVW5saW1pdGVkMSMwIQYDVQQDExpzZXJ2ZXIudnBudW5saW1pdGVkYXBwLmNvbTEjMCEGA1UEKRMac2VydmVyLnZwbnVubGltaXRlZGFwcC5jb20xLjAsBgkqhkiG9w0BCQEWH3N1cHBvcnRAc2ltcGxleHNvbHV0aW9uc2luYy5jb20wHhcNMTMxMjE2MTM1OTQ0WhcNMjMxMjE0MTM1OTQ0WjCB4DELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk5ZMREwDwYDVQQHEwhOZXcgWW9yazEfMB0GA1UEChMWU2ltcGxleCBTb2x1dGlvbnMgSW5jLjEWMBQGA1UECxMNVnBuIFVubGltaXRlZDEjMCEGA1UEAxMac2VydmVyLnZwbnVubGltaXRlZGFwcC5jb20xIzAhBgNVBCkTGnNlcnZlci52cG51bmxpbWl0ZWRhcHAuY29tMS4wLAYJKoZIhvcNAQkBFh9zdXBwb3J0QHNpbXBsZXhzb2x1dGlvbnNpbmMuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDADUzS8QWGvdhLFKsEzAiq5+b0ukKjBza0k6/dmCeYTvCVqGKg/h1IAtQdVVLAkmEp0zvGH7PuOhXm7zZrCouBr/RiG4tEcoRHwc6AJmowkYERlY7+xGx3OuNrD00QceNTsan0bn78jwt0zhFNmHdoTtFjgK3oqmQYSAtbEVWYgwIDAQABo4IBTDCCAUgwHQYDVR0OBBYEFKClmYP+tMNgWagUJCCHjtaui2k+MIIBFwYDVR0jBIIBDjCCAQqAFKClmYP+tMNgWagUJCCHjtaui2k+oYHmpIHjMIHgMQswCQYDVQQGEwJVUzELMAkGA1UECBMCTlkxETAPBgNVBAcTCE5ldyBZb3JrMR8wHQYDVQQKExZTaW1wbGV4IFNvbHV0aW9ucyBJbmMuMRYwFAYDVQQLEw1WcG4gVW5saW1pdGVkMSMwIQYDVQQDExpzZXJ2ZXIudnBudW5saW1pdGVkYXBwLmNvbTEjMCEGA1UEKRMac2VydmVyLnZwbnVubGltaXRlZGFwcC5jb20xLjAsBgkqhkiG9w0BCQEWH3N1cHBvcnRAc2ltcGxleHNvbHV0aW9uc2luYy5jb22CCQCrFWxwXWpF7jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBALkWhfw7SSV7it+ZYZmT+cQbExjlYgQ40zae2J2CqIYACRcfsDHvh7Q+fiwSocevv2NE0dWi6WB2H6SiudYjvDvubAX/QbzfBxtbxCCoAIlfPCm8xOnWFN7TUJAzWwHJkKgEnu29GZHu2x8J+7VeDbKH5RTMHHe8FkSxh6Zz/BMN"
|
VPNUnlimitedCertificateAuthority = "MIIEjjCCA/egAwIBAgIJAKsVbHBdakXuMA0GCSqGSIb3DQEBBQUAMIHgMQswCQYDVQQGEwJVUzELMAkGA1UECBMCTlkxETAPBgNVBAcTCE5ldyBZb3JrMR8wHQYDVQQKExZTaW1wbGV4IFNvbHV0aW9ucyBJbmMuMRYwFAYDVQQLEw1WcG4gVW5saW1pdGVkMSMwIQYDVQQDExpzZXJ2ZXIudnBudW5saW1pdGVkYXBwLmNvbTEjMCEGA1UEKRMac2VydmVyLnZwbnVubGltaXRlZGFwcC5jb20xLjAsBgkqhkiG9w0BCQEWH3N1cHBvcnRAc2ltcGxleHNvbHV0aW9uc2luYy5jb20wHhcNMTMxMjE2MTM1OTQ0WhcNMjMxMjE0MTM1OTQ0WjCB4DELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk5ZMREwDwYDVQQHEwhOZXcgWW9yazEfMB0GA1UEChMWU2ltcGxleCBTb2x1dGlvbnMgSW5jLjEWMBQGA1UECxMNVnBuIFVubGltaXRlZDEjMCEGA1UEAxMac2VydmVyLnZwbnVubGltaXRlZGFwcC5jb20xIzAhBgNVBCkTGnNlcnZlci52cG51bmxpbWl0ZWRhcHAuY29tMS4wLAYJKoZIhvcNAQkBFh9zdXBwb3J0QHNpbXBsZXhzb2x1dGlvbnNpbmMuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDADUzS8QWGvdhLFKsEzAiq5+b0ukKjBza0k6/dmCeYTvCVqGKg/h1IAtQdVVLAkmEp0zvGH7PuOhXm7zZrCouBr/RiG4tEcoRHwc6AJmowkYERlY7+xGx3OuNrD00QceNTsan0bn78jwt0zhFNmHdoTtFjgK3oqmQYSAtbEVWYgwIDAQABo4IBTDCCAUgwHQYDVR0OBBYEFKClmYP+tMNgWagUJCCHjtaui2k+MIIBFwYDVR0jBIIBDjCCAQqAFKClmYP+tMNgWagUJCCHjtaui2k+oYHmpIHjMIHgMQswCQYDVQQGEwJVUzELMAkGA1UECBMCTlkxETAPBgNVBAcTCE5ldyBZb3JrMR8wHQYDVQQKExZTaW1wbGV4IFNvbHV0aW9ucyBJbmMuMRYwFAYDVQQLEw1WcG4gVW5saW1pdGVkMSMwIQYDVQQDExpzZXJ2ZXIudnBudW5saW1pdGVkYXBwLmNvbTEjMCEGA1UEKRMac2VydmVyLnZwbnVubGltaXRlZGFwcC5jb20xLjAsBgkqhkiG9w0BCQEWH3N1cHBvcnRAc2ltcGxleHNvbHV0aW9uc2luYy5jb22CCQCrFWxwXWpF7jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBALkWhfw7SSV7it+ZYZmT+cQbExjlYgQ40zae2J2CqIYACRcfsDHvh7Q+fiwSocevv2NE0dWi6WB2H6SiudYjvDvubAX/QbzfBxtbxCCoAIlfPCm8xOnWFN7TUJAzWwHJkKgEnu29GZHu2x8J+7VeDbKH5RTMHHe8FkSxh6Zz/BMN"
|
||||||
)
|
)
|
||||||
|
|
||||||
func VPNUnlimitedCountryChoices() (choices []string) {
|
func VPNUnlimitedCountryChoices(servers []models.VPNUnlimitedServer) (choices []string) {
|
||||||
servers := VPNUnlimitedServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Country
|
choices[i] = servers[i].Country
|
||||||
@@ -18,8 +17,7 @@ func VPNUnlimitedCountryChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func VPNUnlimitedCityChoices() (choices []string) {
|
func VPNUnlimitedCityChoices(servers []models.VPNUnlimitedServer) (choices []string) {
|
||||||
servers := VPNUnlimitedServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].City
|
choices[i] = servers[i].City
|
||||||
@@ -27,18 +25,10 @@ func VPNUnlimitedCityChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func VPNUnlimitedHostnameChoices() (choices []string) {
|
func VPNUnlimitedHostnameChoices(servers []models.VPNUnlimitedServer) (choices []string) {
|
||||||
servers := VPNUnlimitedServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Hostname
|
choices[i] = servers[i].Hostname
|
||||||
}
|
}
|
||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VPNUnlimitedServers returns a slice of all the server information for VPNUnlimited.
|
|
||||||
func VPNUnlimitedServers() (servers []models.VPNUnlimitedServer) {
|
|
||||||
servers = make([]models.VPNUnlimitedServer, len(allServers.VPNUnlimited.Servers))
|
|
||||||
copy(servers, allServers.VPNUnlimited.Servers)
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -9,18 +9,10 @@ const (
|
|||||||
VyprvpnCertificate = "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"
|
VyprvpnCertificate = "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"
|
||||||
)
|
)
|
||||||
|
|
||||||
func VyprvpnRegionChoices() (choices []string) {
|
func VyprvpnRegionChoices(servers []models.VyprvpnServer) (choices []string) {
|
||||||
servers := VyprvpnServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Region
|
choices[i] = servers[i].Region
|
||||||
}
|
}
|
||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VyprvpnServers returns a slice of all the VyprVPN servers.
|
|
||||||
func VyprvpnServers() (servers []models.VyprvpnServer) {
|
|
||||||
servers = make([]models.VyprvpnServer, len(allServers.Vyprvpn.Servers))
|
|
||||||
copy(servers, allServers.Vyprvpn.Servers)
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package constants
|
package constants
|
||||||
|
|
||||||
import (
|
import "github.com/qdm12/gluetun/internal/models"
|
||||||
"github.com/qdm12/gluetun/internal/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
//nolint:lll
|
//nolint:lll
|
||||||
const (
|
const (
|
||||||
@@ -10,8 +8,7 @@ const (
|
|||||||
WindscribeOpenvpnStaticKeyV1 = "5801926a57ac2ce27e3dfd1dd6ef82042d82bd4f3f0021296f57734f6f1ea714a6623845541c4b0c3dea0a050fe6746cb66dfab14cda27e5ae09d7c155aa554f399fa4a863f0e8c1af787e5c602a801d3a2ec41e395a978d56729457fe6102d7d9e9119aa83643210b33c678f9d4109e3154ac9c759e490cb309b319cf708cae83ddadc3060a7a26564d1a24411cd552fe6620ea16b755697a4fc5e6e9d0cfc0c5c4a1874685429046a424c026db672e4c2c492898052ba59128d46200b40f880027a8b6610a4d559bdc9346d33a0a6b08e75c7fd43192b162bfd0aef0c716b31584827693f676f9a5047123466f0654eade34972586b31c6ce7e395f4b478cb"
|
WindscribeOpenvpnStaticKeyV1 = "5801926a57ac2ce27e3dfd1dd6ef82042d82bd4f3f0021296f57734f6f1ea714a6623845541c4b0c3dea0a050fe6746cb66dfab14cda27e5ae09d7c155aa554f399fa4a863f0e8c1af787e5c602a801d3a2ec41e395a978d56729457fe6102d7d9e9119aa83643210b33c678f9d4109e3154ac9c759e490cb309b319cf708cae83ddadc3060a7a26564d1a24411cd552fe6620ea16b755697a4fc5e6e9d0cfc0c5c4a1874685429046a424c026db672e4c2c492898052ba59128d46200b40f880027a8b6610a4d559bdc9346d33a0a6b08e75c7fd43192b162bfd0aef0c716b31584827693f676f9a5047123466f0654eade34972586b31c6ce7e395f4b478cb"
|
||||||
)
|
)
|
||||||
|
|
||||||
func WindscribeRegionChoices() (choices []string) {
|
func WindscribeRegionChoices(servers []models.WindscribeServer) (choices []string) {
|
||||||
servers := WindscribeServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Region
|
choices[i] = servers[i].Region
|
||||||
@@ -19,8 +16,7 @@ func WindscribeRegionChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func WindscribeCityChoices() (choices []string) {
|
func WindscribeCityChoices(servers []models.WindscribeServer) (choices []string) {
|
||||||
servers := WindscribeServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].City
|
choices[i] = servers[i].City
|
||||||
@@ -28,18 +24,10 @@ func WindscribeCityChoices() (choices []string) {
|
|||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
func WindscribeHostnameChoices() (choices []string) {
|
func WindscribeHostnameChoices(servers []models.WindscribeServer) (choices []string) {
|
||||||
servers := WindscribeServers()
|
|
||||||
choices = make([]string, len(servers))
|
choices = make([]string, len(servers))
|
||||||
for i := range servers {
|
for i := range servers {
|
||||||
choices[i] = servers[i].Hostname
|
choices[i] = servers[i].Hostname
|
||||||
}
|
}
|
||||||
return makeUnique(choices)
|
return makeUnique(choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WindscribeServers returns a slice of all the Windscribe servers.
|
|
||||||
func WindscribeServers() (servers []models.WindscribeServer) {
|
|
||||||
servers = make([]models.WindscribeServer, len(allServers.Windscribe.Servers))
|
|
||||||
copy(servers, allServers.Windscribe.Servers)
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -8,18 +9,24 @@ import (
|
|||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (l *Loop) collectLines(stdout, stderr <-chan string, done chan<- struct{}) {
|
func (l *Loop) collectLines(ctx context.Context, done chan<- struct{},
|
||||||
|
stdout, stderr chan string) {
|
||||||
defer close(done)
|
defer close(done)
|
||||||
|
|
||||||
var line string
|
var line string
|
||||||
var ok bool
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case line, ok = <-stderr:
|
case <-ctx.Done():
|
||||||
case line, ok = <-stdout:
|
// Context should only be canceled after stdout and stderr are done
|
||||||
}
|
// being written to.
|
||||||
if !ok {
|
close(stdout)
|
||||||
|
close(stderr)
|
||||||
return
|
return
|
||||||
|
case line = <-stderr:
|
||||||
|
case line = <-stdout:
|
||||||
}
|
}
|
||||||
|
|
||||||
line, level := processLogLine(line)
|
line, level := processLogLine(line)
|
||||||
switch level {
|
switch level {
|
||||||
case logging.LevelDebug:
|
case logging.LevelDebug:
|
||||||
|
|||||||
@@ -30,12 +30,13 @@ func (l *Loop) setupUnbound(ctx context.Context) (
|
|||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
collectLinesDone := make(chan struct{})
|
linesCollectionCtx, linesCollectionCancel := context.WithCancel(context.Background())
|
||||||
go l.collectLines(stdoutLines, stderrLines, collectLinesDone)
|
lineCollectionDone := make(chan struct{})
|
||||||
|
go l.collectLines(linesCollectionCtx, lineCollectionDone,
|
||||||
|
stdoutLines, stderrLines)
|
||||||
closeStreams = func() {
|
closeStreams = func() {
|
||||||
close(stdoutLines)
|
linesCollectionCancel()
|
||||||
close(stderrLines)
|
<-lineCollectionDone
|
||||||
<-collectLinesDone
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// use Unbound
|
// use Unbound
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -109,9 +107,9 @@ func (c *Config) enable(ctx context.Context) (err error) {
|
|||||||
if err = c.acceptOutputTrafficToVPN(ctx, c.defaultInterface, c.vpnConnection, remove); err != nil {
|
if err = c.acceptOutputTrafficToVPN(ctx, c.defaultInterface, c.vpnConnection, remove); err != nil {
|
||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||||
}
|
}
|
||||||
}
|
if err = c.acceptOutputThroughInterface(ctx, c.vpnIntf, remove); err != nil {
|
||||||
if err = c.acceptOutputThroughInterface(ctx, string(constants.TUN), remove); err != nil {
|
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, network := range c.localNetworks {
|
for _, network := range c.localNetworks {
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ type Config struct { //nolint:maligned
|
|||||||
|
|
||||||
// State
|
// State
|
||||||
enabled bool
|
enabled bool
|
||||||
vpnConnection models.OpenVPNConnection
|
vpnConnection models.Connection
|
||||||
|
vpnIntf string
|
||||||
outboundSubnets []net.IPNet
|
outboundSubnets []net.IPNet
|
||||||
allowedInputPorts map[uint16]string // port to interface mapping
|
allowedInputPorts map[uint16]string // port to interface mapping
|
||||||
stateMutex sync.Mutex
|
stateMutex sync.Mutex
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ func (c *Config) acceptEstablishedRelatedTraffic(ctx context.Context, remove boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) acceptOutputTrafficToVPN(ctx context.Context,
|
func (c *Config) acceptOutputTrafficToVPN(ctx context.Context,
|
||||||
defaultInterface string, connection models.OpenVPNConnection, remove bool) error {
|
defaultInterface string, connection models.Connection, remove bool) error {
|
||||||
instruction := fmt.Sprintf("%s OUTPUT -d %s -o %s -p %s -m %s --dport %d -j ACCEPT",
|
instruction := fmt.Sprintf("%s OUTPUT -d %s -o %s -p %s -m %s --dport %d -j ACCEPT",
|
||||||
appendOrDelete(remove), connection.IP, defaultInterface, connection.Protocol,
|
appendOrDelete(remove), connection.IP, defaultInterface, connection.Protocol,
|
||||||
connection.Protocol, connection.Port)
|
connection.Protocol, connection.Port)
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/subnet"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OutboundSubnetsSetter interface {
|
type OutboundSubnetsSetter interface {
|
||||||
@@ -23,8 +25,7 @@ func (c *Config) SetOutboundSubnets(ctx context.Context, subnets []net.IPNet) (e
|
|||||||
|
|
||||||
c.logger.Info("setting allowed subnets through firewall...")
|
c.logger.Info("setting allowed subnets through firewall...")
|
||||||
|
|
||||||
subnetsToAdd := findSubnetsToAdd(c.outboundSubnets, subnets)
|
subnetsToAdd, subnetsToRemove := subnet.FindSubnetsToChange(c.outboundSubnets, subnets)
|
||||||
subnetsToRemove := findSubnetsToRemove(c.outboundSubnets, subnets)
|
|
||||||
if len(subnetsToAdd) == 0 && len(subnetsToRemove) == 0 {
|
if len(subnetsToAdd) == 0 && len(subnetsToRemove) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -39,12 +40,12 @@ func (c *Config) SetOutboundSubnets(ctx context.Context, subnets []net.IPNet) (e
|
|||||||
|
|
||||||
func (c *Config) removeOutboundSubnets(ctx context.Context, subnets []net.IPNet) {
|
func (c *Config) removeOutboundSubnets(ctx context.Context, subnets []net.IPNet) {
|
||||||
const remove = true
|
const remove = true
|
||||||
for _, subnet := range subnets {
|
for _, subNet := range subnets {
|
||||||
if err := c.acceptOutputFromIPToSubnet(ctx, c.defaultInterface, c.localIP, subnet, remove); err != nil {
|
if err := c.acceptOutputFromIPToSubnet(ctx, c.defaultInterface, c.localIP, subNet, remove); err != nil {
|
||||||
c.logger.Error("cannot remove outdated outbound subnet through firewall: " + err.Error())
|
c.logger.Error("cannot remove outdated outbound subnet through firewall: " + err.Error())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c.outboundSubnets = removeSubnetFromSubnets(c.outboundSubnets, subnet)
|
c.outboundSubnets = subnet.RemoveSubnetFromSubnets(c.outboundSubnets, subNet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
package firewall
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
)
|
|
||||||
|
|
||||||
func findSubnetsToAdd(oldSubnets, newSubnets []net.IPNet) (subnetsToAdd []net.IPNet) {
|
|
||||||
for _, newSubnet := range newSubnets {
|
|
||||||
found := false
|
|
||||||
for _, oldSubnet := range oldSubnets {
|
|
||||||
if subnetsAreEqual(oldSubnet, newSubnet) {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
subnetsToAdd = append(subnetsToAdd, newSubnet)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return subnetsToAdd
|
|
||||||
}
|
|
||||||
|
|
||||||
func findSubnetsToRemove(oldSubnets, newSubnets []net.IPNet) (subnetsToRemove []net.IPNet) {
|
|
||||||
for _, oldSubnet := range oldSubnets {
|
|
||||||
found := false
|
|
||||||
for _, newSubnet := range newSubnets {
|
|
||||||
if subnetsAreEqual(oldSubnet, newSubnet) {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
subnetsToRemove = append(subnetsToRemove, oldSubnet)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return subnetsToRemove
|
|
||||||
}
|
|
||||||
|
|
||||||
func subnetsAreEqual(a, b net.IPNet) bool {
|
|
||||||
return a.IP.Equal(b.IP) && a.Mask.String() == b.Mask.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeSubnetFromSubnets(subnets []net.IPNet, subnet net.IPNet) []net.IPNet {
|
|
||||||
L := len(subnets)
|
|
||||||
for i := range subnets {
|
|
||||||
if subnetsAreEqual(subnet, subnets[i]) {
|
|
||||||
subnets[i] = subnets[L-1]
|
|
||||||
subnets = subnets[:L-1]
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return subnets
|
|
||||||
}
|
|
||||||
@@ -8,10 +8,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type VPNConnectionSetter interface {
|
type VPNConnectionSetter interface {
|
||||||
SetVPNConnection(ctx context.Context, connection models.OpenVPNConnection) error
|
SetVPNConnection(ctx context.Context,
|
||||||
|
connection models.Connection, vpnIntf string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) SetVPNConnection(ctx context.Context, connection models.OpenVPNConnection) (err error) {
|
func (c *Config) SetVPNConnection(ctx context.Context,
|
||||||
|
connection models.Connection, vpnIntf string) (err error) {
|
||||||
c.stateMutex.Lock()
|
c.stateMutex.Lock()
|
||||||
defer c.stateMutex.Unlock()
|
defer c.stateMutex.Unlock()
|
||||||
|
|
||||||
@@ -33,11 +35,26 @@ func (c *Config) SetVPNConnection(ctx context.Context, connection models.OpenVPN
|
|||||||
c.logger.Error("cannot remove outdated VPN connection through firewall: " + err.Error())
|
c.logger.Error("cannot remove outdated VPN connection through firewall: " + err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.vpnConnection = models.OpenVPNConnection{}
|
c.vpnConnection = models.Connection{}
|
||||||
|
|
||||||
|
if c.vpnIntf != "" {
|
||||||
|
if err = c.acceptOutputThroughInterface(ctx, c.vpnIntf, remove); err != nil {
|
||||||
|
c.logger.Error("cannot remove outdated VPN interface from firewall: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.vpnIntf = ""
|
||||||
|
|
||||||
remove = false
|
remove = false
|
||||||
|
|
||||||
if err := c.acceptOutputTrafficToVPN(ctx, c.defaultInterface, connection, remove); err != nil {
|
if err := c.acceptOutputTrafficToVPN(ctx, c.defaultInterface, connection, remove); err != nil {
|
||||||
return fmt.Errorf("cannot set VPN connection through firewall: %w", err)
|
return fmt.Errorf("cannot set VPN connection through firewall: %w", err)
|
||||||
}
|
}
|
||||||
c.vpnConnection = connection
|
c.vpnConnection = connection
|
||||||
|
|
||||||
|
if err = c.acceptOutputThroughInterface(ctx, vpnIntf, remove); err != nil {
|
||||||
|
return fmt.Errorf("cannot accept output traffic through interface %s: %w", vpnIntf, err)
|
||||||
|
}
|
||||||
|
c.vpnIntf = vpnIntf
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
func (s *Server) runHealthcheckLoop(ctx context.Context, done chan<- struct{}) {
|
func (s *Server) runHealthcheckLoop(ctx context.Context, done chan<- struct{}) {
|
||||||
defer close(done)
|
defer close(done)
|
||||||
|
|
||||||
s.openvpn.healthyTimer = time.NewTimer(s.openvpn.healthyWait)
|
s.vpn.healthyTimer = time.NewTimer(s.vpn.healthyWait)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
previousErr := s.handler.getErr()
|
previousErr := s.handler.getErr()
|
||||||
@@ -22,12 +22,12 @@ func (s *Server) runHealthcheckLoop(ctx context.Context, done chan<- struct{}) {
|
|||||||
|
|
||||||
if previousErr != nil && err == nil {
|
if previousErr != nil && err == nil {
|
||||||
s.logger.Info("healthy!")
|
s.logger.Info("healthy!")
|
||||||
s.openvpn.healthyTimer.Stop()
|
s.vpn.healthyTimer.Stop()
|
||||||
s.openvpn.healthyWait = s.config.OpenVPN.Initial
|
s.vpn.healthyWait = s.config.OpenVPN.Initial
|
||||||
} else if previousErr == nil && err != nil {
|
} else if previousErr == nil && err != nil {
|
||||||
s.logger.Info("unhealthy: " + err.Error())
|
s.logger.Info("unhealthy: " + err.Error())
|
||||||
s.openvpn.healthyTimer.Stop()
|
s.vpn.healthyTimer.Stop()
|
||||||
s.openvpn.healthyTimer = time.NewTimer(s.openvpn.healthyWait)
|
s.vpn.healthyTimer = time.NewTimer(s.vpn.healthyWait)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil { // try again after 1 second
|
if err != nil { // try again after 1 second
|
||||||
@@ -39,7 +39,7 @@ func (s *Server) runHealthcheckLoop(ctx context.Context, done chan<- struct{}) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
case <-s.openvpn.healthyTimer.C:
|
case <-s.vpn.healthyTimer.C:
|
||||||
s.onUnhealthyOpenvpn(ctx)
|
s.onUnhealthyOpenvpn(ctx)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -5,20 +5,20 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/constants"
|
"github.com/qdm12/gluetun/internal/constants"
|
||||||
"github.com/qdm12/gluetun/internal/openvpn"
|
"github.com/qdm12/gluetun/internal/vpn"
|
||||||
)
|
)
|
||||||
|
|
||||||
type openvpnHealth struct {
|
type vpnHealth struct {
|
||||||
looper openvpn.Looper
|
looper vpn.Looper
|
||||||
healthyWait time.Duration
|
healthyWait time.Duration
|
||||||
healthyTimer *time.Timer
|
healthyTimer *time.Timer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) onUnhealthyOpenvpn(ctx context.Context) {
|
func (s *Server) onUnhealthyOpenvpn(ctx context.Context) {
|
||||||
s.logger.Info("program has been unhealthy for " +
|
s.logger.Info("program has been unhealthy for " +
|
||||||
s.openvpn.healthyWait.String() + ": restarting OpenVPN")
|
s.vpn.healthyWait.String() + ": restarting OpenVPN")
|
||||||
_, _ = s.openvpn.looper.ApplyStatus(ctx, constants.Stopped)
|
_, _ = s.vpn.looper.ApplyStatus(ctx, constants.Stopped)
|
||||||
_, _ = s.openvpn.looper.ApplyStatus(ctx, constants.Running)
|
_, _ = s.vpn.looper.ApplyStatus(ctx, constants.Running)
|
||||||
s.openvpn.healthyWait += s.config.OpenVPN.Addition
|
s.vpn.healthyWait += s.config.OpenVPN.Addition
|
||||||
s.openvpn.healthyTimer = time.NewTimer(s.openvpn.healthyWait)
|
s.vpn.healthyTimer = time.NewTimer(s.vpn.healthyWait)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/configuration"
|
"github.com/qdm12/gluetun/internal/configuration"
|
||||||
"github.com/qdm12/gluetun/internal/openvpn"
|
"github.com/qdm12/gluetun/internal/vpn"
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,18 +20,18 @@ type Server struct {
|
|||||||
handler *handler
|
handler *handler
|
||||||
resolver *net.Resolver
|
resolver *net.Resolver
|
||||||
config configuration.Health
|
config configuration.Health
|
||||||
openvpn openvpnHealth
|
vpn vpnHealth
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(config configuration.Health,
|
func NewServer(config configuration.Health,
|
||||||
logger logging.Logger, openvpnLooper openvpn.Looper) *Server {
|
logger logging.Logger, vpnLooper vpn.Looper) *Server {
|
||||||
return &Server{
|
return &Server{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
handler: newHandler(logger),
|
handler: newHandler(logger),
|
||||||
resolver: net.DefaultResolver,
|
resolver: net.DefaultResolver,
|
||||||
config: config,
|
config: config,
|
||||||
openvpn: openvpnHealth{
|
vpn: vpnHealth{
|
||||||
looper: openvpnLooper,
|
looper: vpnLooper,
|
||||||
healthyWait: config.OpenVPN.Initial,
|
healthyWait: config.OpenVPN.Initial,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
package httpproxy
|
package httpproxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *handler) handleHTTPS(responseWriter http.ResponseWriter, request *http.Request) {
|
func (h *handler) handleHTTPS(responseWriter http.ResponseWriter, request *http.Request) {
|
||||||
@@ -38,27 +36,30 @@ func (h *handler) handleHTTPS(responseWriter http.ResponseWriter, request *http.
|
|||||||
}
|
}
|
||||||
|
|
||||||
h.wg.Add(1)
|
h.wg.Add(1)
|
||||||
ctx, cancel := context.WithCancel(h.ctx)
|
|
||||||
const transferGoroutines = 2
|
serverToClientDone := make(chan struct{})
|
||||||
wg := &sync.WaitGroup{}
|
clientToServerClientDone := make(chan struct{})
|
||||||
wg.Add(transferGoroutines)
|
go transfer(destinationConn, clientConnection, clientToServerClientDone)
|
||||||
go func() { // trigger cleanup when done
|
go transfer(clientConnection, destinationConn, serverToClientDone)
|
||||||
wg.Wait()
|
|
||||||
cancel()
|
select {
|
||||||
}()
|
case <-h.ctx.Done():
|
||||||
go func() { // cleanup
|
|
||||||
<-ctx.Done()
|
|
||||||
destinationConn.Close()
|
destinationConn.Close()
|
||||||
clientConnection.Close()
|
clientConnection.Close()
|
||||||
h.wg.Done()
|
<-serverToClientDone
|
||||||
}()
|
<-clientToServerClientDone
|
||||||
go transfer(destinationConn, clientConnection, wg)
|
case <-serverToClientDone:
|
||||||
go transfer(clientConnection, destinationConn, wg)
|
<-clientToServerClientDone
|
||||||
|
case <-clientToServerClientDone: // happens more rarely, when a connection is closed on the client side
|
||||||
|
<-serverToClientDone
|
||||||
|
}
|
||||||
|
|
||||||
|
h.wg.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
func transfer(destination io.WriteCloser, source io.ReadCloser, wg *sync.WaitGroup) {
|
func transfer(destination io.WriteCloser, source io.ReadCloser, done chan<- struct{}) {
|
||||||
_, _ = io.Copy(destination, source)
|
_, _ = io.Copy(destination, source)
|
||||||
_ = source.Close()
|
_ = source.Close()
|
||||||
_ = destination.Close()
|
_ = destination.Close()
|
||||||
wg.Done()
|
close(done)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,7 @@ import (
|
|||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Server interface {
|
type Server struct {
|
||||||
Run(ctx context.Context, errorCh chan<- error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type server struct {
|
|
||||||
address string
|
address string
|
||||||
handler http.Handler
|
handler http.Handler
|
||||||
logger logging.Logger
|
logger logging.Logger
|
||||||
@@ -21,9 +17,9 @@ type server struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func New(ctx context.Context, address string, logger logging.Logger,
|
func New(ctx context.Context, address string, logger logging.Logger,
|
||||||
stealth, verbose bool, username, password string) Server {
|
stealth, verbose bool, username, password string) *Server {
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
return &server{
|
return &Server{
|
||||||
address: address,
|
address: address,
|
||||||
handler: newHandler(ctx, wg, logger, stealth, verbose, username, password),
|
handler: newHandler(ctx, wg, logger, stealth, verbose, username, password),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
@@ -31,7 +27,7 @@ func New(ctx context.Context, address string, logger logging.Logger,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) Run(ctx context.Context, errorCh chan<- error) {
|
func (s *Server) Run(ctx context.Context, errorCh chan<- error) {
|
||||||
server := http.Server{Addr: s.address, Handler: s.handler}
|
server := http.Server{Addr: s.address, Handler: s.handler}
|
||||||
go func() {
|
go func() {
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ func (s *State) ApplyStatus(ctx context.Context, status models.LoopStatus) (
|
|||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
case newStatus = <-s.running:
|
case newStatus = <-s.running:
|
||||||
}
|
}
|
||||||
|
|
||||||
s.SetStatus(newStatus)
|
s.SetStatus(newStatus)
|
||||||
|
|
||||||
return newStatus.String(), nil
|
return newStatus.String(), nil
|
||||||
|
|||||||
51
internal/models/connection.go
Normal file
51
internal/models/connection.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Connection struct {
|
||||||
|
// Type is the connection type and can be "openvpn" or "wireguard"
|
||||||
|
Type string `json:"type"`
|
||||||
|
// IP is the VPN server IP address.
|
||||||
|
IP net.IP `json:"ip"`
|
||||||
|
// Port is the VPN server port.
|
||||||
|
Port uint16 `json:"port"`
|
||||||
|
// Protocol can be "tcp" or "udp".
|
||||||
|
Protocol string `json:"protocol"`
|
||||||
|
// Hostname is used for IPVanish, IVPN, Privado
|
||||||
|
// and Windscribe for TLS verification.
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
// PubKey is the public key of the VPN server,
|
||||||
|
// used only for Wireguard.
|
||||||
|
PubKey string `json:"pubkey"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) Equal(other Connection) bool {
|
||||||
|
return c.IP.Equal(other.IP) && c.Port == other.Port &&
|
||||||
|
c.Protocol == other.Protocol && c.Hostname == other.Hostname &&
|
||||||
|
c.PubKey == other.PubKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Connection) OpenVPNRemoteLine() (line string) {
|
||||||
|
return "remote " + c.IP.String() + " " + fmt.Sprint(c.Port)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Connection) OpenVPNProtoLine() (line string) {
|
||||||
|
return "proto " + c.Protocol
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateEmptyWith updates each field of the connection where the
|
||||||
|
// value is not set using the value given as arguments.
|
||||||
|
func (c *Connection) UpdateEmptyWith(ip net.IP, port uint16, protocol string) {
|
||||||
|
if c.IP == nil {
|
||||||
|
c.IP = ip
|
||||||
|
}
|
||||||
|
if c.Port == 0 {
|
||||||
|
c.Port = port
|
||||||
|
}
|
||||||
|
if c.Protocol == "" {
|
||||||
|
c.Protocol = protocol
|
||||||
|
}
|
||||||
|
}
|
||||||
252
internal/models/getservers.go
Normal file
252
internal/models/getservers.go
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a AllServers) GetCopy() (servers AllServers) {
|
||||||
|
servers = a // copy versions and timestamps
|
||||||
|
servers.Cyberghost.Servers = a.GetCyberghost()
|
||||||
|
servers.Fastestvpn.Servers = a.GetFastestvpn()
|
||||||
|
servers.HideMyAss.Servers = a.GetHideMyAss()
|
||||||
|
servers.Ipvanish.Servers = a.GetIpvanish()
|
||||||
|
servers.Ivpn.Servers = a.GetIvpn()
|
||||||
|
servers.Mullvad.Servers = a.GetMullvad()
|
||||||
|
servers.Nordvpn.Servers = a.GetNordvpn()
|
||||||
|
servers.Privado.Servers = a.GetPrivado()
|
||||||
|
servers.Pia.Servers = a.GetPia()
|
||||||
|
servers.Privatevpn.Servers = a.GetPrivatevpn()
|
||||||
|
servers.Protonvpn.Servers = a.GetProtonvpn()
|
||||||
|
servers.Purevpn.Servers = a.GetPurevpn()
|
||||||
|
servers.Surfshark.Servers = a.GetSurfshark()
|
||||||
|
servers.Torguard.Servers = a.GetTorguard()
|
||||||
|
servers.VPNUnlimited.Servers = a.GetVPNUnlimited()
|
||||||
|
servers.Vyprvpn.Servers = a.GetVyprvpn()
|
||||||
|
servers.Windscribe.Servers = a.GetWindscribe()
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllServers) GetCyberghost() (servers []CyberghostServer) {
|
||||||
|
if a.Cyberghost.Servers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
servers = make([]CyberghostServer, len(a.Cyberghost.Servers))
|
||||||
|
for i, serverToCopy := range a.Cyberghost.Servers {
|
||||||
|
servers[i] = serverToCopy
|
||||||
|
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllServers) GetFastestvpn() (servers []FastestvpnServer) {
|
||||||
|
if a.Fastestvpn.Servers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
servers = make([]FastestvpnServer, len(a.Fastestvpn.Servers))
|
||||||
|
for i, serverToCopy := range a.Fastestvpn.Servers {
|
||||||
|
servers[i] = serverToCopy
|
||||||
|
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllServers) GetHideMyAss() (servers []HideMyAssServer) {
|
||||||
|
if a.HideMyAss.Servers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
servers = make([]HideMyAssServer, len(a.HideMyAss.Servers))
|
||||||
|
for i, serverToCopy := range a.HideMyAss.Servers {
|
||||||
|
servers[i] = serverToCopy
|
||||||
|
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllServers) GetIpvanish() (servers []IpvanishServer) {
|
||||||
|
if a.Ipvanish.Servers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
servers = make([]IpvanishServer, len(a.Ipvanish.Servers))
|
||||||
|
for i, serverToCopy := range a.Ipvanish.Servers {
|
||||||
|
servers[i] = serverToCopy
|
||||||
|
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllServers) GetIvpn() (servers []IvpnServer) {
|
||||||
|
if a.Ivpn.Servers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
servers = make([]IvpnServer, len(a.Ivpn.Servers))
|
||||||
|
for i, serverToCopy := range a.Ivpn.Servers {
|
||||||
|
servers[i] = serverToCopy
|
||||||
|
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllServers) GetMullvad() (servers []MullvadServer) {
|
||||||
|
if a.Mullvad.Servers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
servers = make([]MullvadServer, len(a.Mullvad.Servers))
|
||||||
|
for i, serverToCopy := range a.Mullvad.Servers {
|
||||||
|
servers[i] = serverToCopy
|
||||||
|
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||||
|
servers[i].IPsV6 = copyIPs(serverToCopy.IPsV6)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllServers) GetNordvpn() (servers []NordvpnServer) {
|
||||||
|
if a.Nordvpn.Servers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
servers = make([]NordvpnServer, len(a.Nordvpn.Servers))
|
||||||
|
for i, serverToCopy := range a.Nordvpn.Servers {
|
||||||
|
servers[i] = serverToCopy
|
||||||
|
servers[i].IP = copyIP(serverToCopy.IP)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllServers) GetPia() (servers []PIAServer) {
|
||||||
|
if a.Pia.Servers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
servers = make([]PIAServer, len(a.Pia.Servers))
|
||||||
|
for i, serverToCopy := range a.Pia.Servers {
|
||||||
|
servers[i] = serverToCopy
|
||||||
|
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllServers) GetPrivado() (servers []PrivadoServer) {
|
||||||
|
if a.Privado.Servers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
servers = make([]PrivadoServer, len(a.Privado.Servers))
|
||||||
|
for i, serverToCopy := range a.Privado.Servers {
|
||||||
|
servers[i] = serverToCopy
|
||||||
|
servers[i].IP = copyIP(serverToCopy.IP)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllServers) GetPrivatevpn() (servers []PrivatevpnServer) {
|
||||||
|
if a.Privatevpn.Servers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
servers = make([]PrivatevpnServer, len(a.Privatevpn.Servers))
|
||||||
|
for i, serverToCopy := range a.Privatevpn.Servers {
|
||||||
|
servers[i] = serverToCopy
|
||||||
|
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllServers) GetProtonvpn() (servers []ProtonvpnServer) {
|
||||||
|
if a.Protonvpn.Servers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
servers = make([]ProtonvpnServer, len(a.Protonvpn.Servers))
|
||||||
|
for i, serverToCopy := range a.Protonvpn.Servers {
|
||||||
|
servers[i] = serverToCopy
|
||||||
|
servers[i].EntryIP = copyIP(serverToCopy.EntryIP)
|
||||||
|
servers[i].ExitIP = copyIP(serverToCopy.ExitIP)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllServers) GetPurevpn() (servers []PurevpnServer) {
|
||||||
|
if a.Purevpn.Servers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
servers = make([]PurevpnServer, len(a.Purevpn.Servers))
|
||||||
|
for i, serverToCopy := range a.Purevpn.Servers {
|
||||||
|
servers[i] = serverToCopy
|
||||||
|
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllServers) GetSurfshark() (servers []SurfsharkServer) {
|
||||||
|
if a.Surfshark.Servers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
servers = make([]SurfsharkServer, len(a.Surfshark.Servers))
|
||||||
|
for i, serverToCopy := range a.Surfshark.Servers {
|
||||||
|
servers[i] = serverToCopy
|
||||||
|
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllServers) GetTorguard() (servers []TorguardServer) {
|
||||||
|
if a.Torguard.Servers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
servers = make([]TorguardServer, len(a.Torguard.Servers))
|
||||||
|
for i, serverToCopy := range a.Torguard.Servers {
|
||||||
|
servers[i] = serverToCopy
|
||||||
|
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllServers) GetVPNUnlimited() (servers []VPNUnlimitedServer) {
|
||||||
|
if a.VPNUnlimited.Servers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
servers = make([]VPNUnlimitedServer, len(a.VPNUnlimited.Servers))
|
||||||
|
for i, serverToCopy := range a.VPNUnlimited.Servers {
|
||||||
|
servers[i] = serverToCopy
|
||||||
|
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllServers) GetVyprvpn() (servers []VyprvpnServer) {
|
||||||
|
if a.Vyprvpn.Servers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
servers = make([]VyprvpnServer, len(a.Vyprvpn.Servers))
|
||||||
|
for i, serverToCopy := range a.Vyprvpn.Servers {
|
||||||
|
servers[i] = serverToCopy
|
||||||
|
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AllServers) GetWindscribe() (servers []WindscribeServer) {
|
||||||
|
if a.Windscribe.Servers == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
servers = make([]WindscribeServer, len(a.Windscribe.Servers))
|
||||||
|
for i, serverToCopy := range a.Windscribe.Servers {
|
||||||
|
servers[i] = serverToCopy
|
||||||
|
servers[i].IPs = copyIPs(serverToCopy.IPs)
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyIPs(toCopy []net.IP) (copied []net.IP) {
|
||||||
|
if toCopy == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
copied = make([]net.IP, len(toCopy))
|
||||||
|
for i := range toCopy {
|
||||||
|
copied[i] = copyIP(toCopy[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return copied
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyIP(toCopy net.IP) (copied net.IP) {
|
||||||
|
copied = make(net.IP, len(toCopy))
|
||||||
|
copy(copied, toCopy)
|
||||||
|
return copied
|
||||||
|
}
|
||||||
181
internal/models/getservers_test.go
Normal file
181
internal/models/getservers_test.go
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_AllServers_GetCopy(t *testing.T) {
|
||||||
|
allServers := AllServers{
|
||||||
|
Cyberghost: CyberghostServers{
|
||||||
|
Version: 2,
|
||||||
|
Servers: []CyberghostServer{{
|
||||||
|
IPs: []net.IP{{1, 2, 3, 4}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
Fastestvpn: FastestvpnServers{
|
||||||
|
Servers: []FastestvpnServer{{
|
||||||
|
IPs: []net.IP{{1, 2, 3, 4}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
HideMyAss: HideMyAssServers{
|
||||||
|
Servers: []HideMyAssServer{{
|
||||||
|
IPs: []net.IP{{1, 2, 3, 4}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
Ipvanish: IpvanishServers{
|
||||||
|
Servers: []IpvanishServer{{
|
||||||
|
IPs: []net.IP{{1, 2, 3, 4}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
Ivpn: IvpnServers{
|
||||||
|
Servers: []IvpnServer{{
|
||||||
|
IPs: []net.IP{{1, 2, 3, 4}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
Mullvad: MullvadServers{
|
||||||
|
Servers: []MullvadServer{{
|
||||||
|
IPs: []net.IP{{1, 2, 3, 4}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
Nordvpn: NordvpnServers{
|
||||||
|
Servers: []NordvpnServer{{
|
||||||
|
IP: net.IP{1, 2, 3, 4},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
Privado: PrivadoServers{
|
||||||
|
Servers: []PrivadoServer{{
|
||||||
|
IP: net.IP{1, 2, 3, 4},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
Pia: PiaServers{
|
||||||
|
Servers: []PIAServer{{
|
||||||
|
IPs: []net.IP{{1, 2, 3, 4}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
Privatevpn: PrivatevpnServers{
|
||||||
|
Servers: []PrivatevpnServer{{
|
||||||
|
IPs: []net.IP{{1, 2, 3, 4}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
Protonvpn: ProtonvpnServers{
|
||||||
|
Servers: []ProtonvpnServer{{
|
||||||
|
EntryIP: net.IP{1, 2, 3, 4},
|
||||||
|
ExitIP: net.IP{1, 2, 3, 4},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
Purevpn: PurevpnServers{
|
||||||
|
Version: 1,
|
||||||
|
Servers: []PurevpnServer{{
|
||||||
|
IPs: []net.IP{{1, 2, 3, 4}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
Surfshark: SurfsharkServers{
|
||||||
|
Servers: []SurfsharkServer{{
|
||||||
|
IPs: []net.IP{{1, 2, 3, 4}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
Torguard: TorguardServers{
|
||||||
|
Servers: []TorguardServer{{
|
||||||
|
IPs: []net.IP{{1, 2, 3, 4}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
VPNUnlimited: VPNUnlimitedServers{
|
||||||
|
Servers: []VPNUnlimitedServer{{
|
||||||
|
IPs: []net.IP{{1, 2, 3, 4}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
Vyprvpn: VyprvpnServers{
|
||||||
|
Servers: []VyprvpnServer{{
|
||||||
|
IPs: []net.IP{{1, 2, 3, 4}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
Windscribe: WindscribeServers{
|
||||||
|
Servers: []WindscribeServer{{
|
||||||
|
IPs: []net.IP{{1, 2, 3, 4}},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
servers := allServers.GetCopy()
|
||||||
|
|
||||||
|
assert.Equal(t, allServers, servers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_AllServers_GetVyprvpn(t *testing.T) {
|
||||||
|
allServers := AllServers{
|
||||||
|
Vyprvpn: VyprvpnServers{
|
||||||
|
Servers: []VyprvpnServer{
|
||||||
|
{Hostname: "a", IPs: []net.IP{{1, 1, 1, 1}}},
|
||||||
|
{Hostname: "b", IPs: []net.IP{{2, 2, 2, 2}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
servers := allServers.GetVyprvpn()
|
||||||
|
|
||||||
|
expectedServers := []VyprvpnServer{
|
||||||
|
{Hostname: "a", IPs: []net.IP{{1, 1, 1, 1}}},
|
||||||
|
{Hostname: "b", IPs: []net.IP{{2, 2, 2, 2}}},
|
||||||
|
}
|
||||||
|
assert.Equal(t, expectedServers, servers)
|
||||||
|
|
||||||
|
allServers.Vyprvpn.Servers[0].IPs[0][0] = 9
|
||||||
|
assert.NotEqual(t, 9, servers[0].IPs[0][0])
|
||||||
|
|
||||||
|
allServers.Vyprvpn.Servers[0].IPs[0][0] = 1
|
||||||
|
servers[0].IPs[0][0] = 9
|
||||||
|
assert.NotEqual(t, 9, allServers.Vyprvpn.Servers[0].IPs[0][0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_copyIPs(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
testCases := map[string]struct {
|
||||||
|
toCopy []net.IP
|
||||||
|
copied []net.IP
|
||||||
|
}{
|
||||||
|
"nil": {},
|
||||||
|
"empty": {
|
||||||
|
toCopy: []net.IP{},
|
||||||
|
copied: []net.IP{},
|
||||||
|
},
|
||||||
|
"single IP": {
|
||||||
|
toCopy: []net.IP{{1, 1, 1, 1}},
|
||||||
|
copied: []net.IP{{1, 1, 1, 1}},
|
||||||
|
},
|
||||||
|
"two IPs": {
|
||||||
|
toCopy: []net.IP{{1, 1, 1, 1}, {2, 2, 2, 2}},
|
||||||
|
copied: []net.IP{{1, 1, 1, 1}, {2, 2, 2, 2}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, testCase := range testCases {
|
||||||
|
testCase := testCase
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// Reserver leading 9 for copy modifications below
|
||||||
|
for _, ipToCopy := range testCase.toCopy {
|
||||||
|
require.NotEqual(t, 9, ipToCopy[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
copied := copyIPs(testCase.toCopy)
|
||||||
|
|
||||||
|
assert.Equal(t, testCase.copied, copied)
|
||||||
|
|
||||||
|
if len(copied) > 0 {
|
||||||
|
original := testCase.toCopy[0][0]
|
||||||
|
testCase.toCopy[0][0] = 9
|
||||||
|
assert.NotEqual(t, 9, copied[0][0])
|
||||||
|
testCase.toCopy[0][0] = original
|
||||||
|
|
||||||
|
copied[0][0] = 9
|
||||||
|
assert.NotEqual(t, 9, testCase.toCopy[0][0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
12
internal/models/location.go
Normal file
12
internal/models/location.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
// SurfsharkLocationData is required to keep location data on Surfshark
|
||||||
|
// servers that are not obtained through their API.
|
||||||
|
type SurfsharkLocationData struct {
|
||||||
|
Region string
|
||||||
|
Country string
|
||||||
|
City string
|
||||||
|
RetroLoc string // TODO remove in v4
|
||||||
|
Hostname string
|
||||||
|
MultiHop bool
|
||||||
|
}
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
type OpenVPNConnection struct {
|
|
||||||
IP net.IP `json:"ip"`
|
|
||||||
Port uint16 `json:"port"`
|
|
||||||
Protocol string `json:"protocol"`
|
|
||||||
// Hostname is used for IPVanish, IVPN, Privado
|
|
||||||
// and Windscribe for TLS verification
|
|
||||||
Hostname string `json:"hostname"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *OpenVPNConnection) Equal(other OpenVPNConnection) bool {
|
|
||||||
return o.IP.Equal(other.IP) && o.Port == other.Port && o.Protocol == other.Protocol &&
|
|
||||||
o.Hostname == other.Hostname
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o OpenVPNConnection) RemoteLine() (line string) {
|
|
||||||
return "remote " + o.IP.String() + " " + strconv.Itoa(int(o.Port))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o OpenVPNConnection) ProtoLine() (line string) {
|
|
||||||
return "proto " + o.Protocol
|
|
||||||
}
|
|
||||||
@@ -39,15 +39,19 @@ type IpvanishServer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type IvpnServer struct {
|
type IvpnServer struct {
|
||||||
|
VPN string `json:"vpn"`
|
||||||
Country string `json:"country"`
|
Country string `json:"country"`
|
||||||
City string `json:"city"`
|
City string `json:"city"`
|
||||||
|
ISP string `json:"isp"`
|
||||||
Hostname string `json:"hostname"`
|
Hostname string `json:"hostname"`
|
||||||
|
WgPubKey string `json:"wgpubkey,omitempty"`
|
||||||
TCP bool `json:"tcp"`
|
TCP bool `json:"tcp"`
|
||||||
UDP bool `json:"udp"`
|
UDP bool `json:"udp"`
|
||||||
IPs []net.IP `json:"ips"`
|
IPs []net.IP `json:"ips"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MullvadServer struct {
|
type MullvadServer struct {
|
||||||
|
VPN string `json:"vpn"`
|
||||||
IPs []net.IP `json:"ips"`
|
IPs []net.IP `json:"ips"`
|
||||||
IPsV6 []net.IP `json:"ipsv6"`
|
IPsV6 []net.IP `json:"ipsv6"`
|
||||||
Country string `json:"country"`
|
Country string `json:"country"`
|
||||||
@@ -55,6 +59,7 @@ type MullvadServer struct {
|
|||||||
Hostname string `json:"hostname"`
|
Hostname string `json:"hostname"`
|
||||||
ISP string `json:"isp"`
|
ISP string `json:"isp"`
|
||||||
Owned bool `json:"owned"`
|
Owned bool `json:"owned"`
|
||||||
|
WgPubKey string `json:"wgpubkey,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type NordvpnServer struct { //nolint:maligned
|
type NordvpnServer struct { //nolint:maligned
|
||||||
@@ -114,7 +119,11 @@ type PurevpnServer struct {
|
|||||||
|
|
||||||
type SurfsharkServer struct {
|
type SurfsharkServer struct {
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
|
Country string `json:"country"` // Country is also used for multi-hop
|
||||||
|
City string `json:"city"`
|
||||||
|
RetroLoc string `json:"retroloc"` // TODO remove in v4
|
||||||
Hostname string `json:"hostname"`
|
Hostname string `json:"hostname"`
|
||||||
|
MultiHop bool `json:"multihop"`
|
||||||
TCP bool `json:"tcp"`
|
TCP bool `json:"tcp"`
|
||||||
UDP bool `json:"udp"`
|
UDP bool `json:"udp"`
|
||||||
IPs []net.IP `json:"ips"`
|
IPs []net.IP `json:"ips"`
|
||||||
@@ -149,9 +158,11 @@ type VyprvpnServer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WindscribeServer struct {
|
type WindscribeServer struct {
|
||||||
|
VPN string `json:"vpn"`
|
||||||
Region string `json:"region"`
|
Region string `json:"region"`
|
||||||
City string `json:"city"`
|
City string `json:"city"`
|
||||||
Hostname string `json:"hostname"`
|
Hostname string `json:"hostname"`
|
||||||
OvpnX509 string `json:"x509"`
|
OvpnX509 string `json:"x509,omitempty"`
|
||||||
|
WgPubKey string `json:"wgpubkey,omitempty"`
|
||||||
IPs []net.IP `json:"ips"`
|
IPs []net.IP `json:"ips"`
|
||||||
}
|
}
|
||||||
|
|||||||
22
internal/netlink/address.go
Normal file
22
internal/netlink/address.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package netlink
|
||||||
|
|
||||||
|
import "github.com/vishvananda/netlink"
|
||||||
|
|
||||||
|
type Addr = netlink.Addr
|
||||||
|
|
||||||
|
var _ Addresser = (*NetLink)(nil)
|
||||||
|
|
||||||
|
type Addresser interface {
|
||||||
|
AddrList(link netlink.Link, family int) (
|
||||||
|
addresses []netlink.Addr, err error)
|
||||||
|
AddrAdd(link netlink.Link, addr *netlink.Addr) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetLink) AddrList(link netlink.Link, family int) (
|
||||||
|
addresses []netlink.Addr, err error) {
|
||||||
|
return netlink.AddrList(link, family)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetLink) AddrAdd(link netlink.Link, addr *netlink.Addr) error {
|
||||||
|
return netlink.AddrAdd(link, addr)
|
||||||
|
}
|
||||||
9
internal/netlink/family.go
Normal file
9
internal/netlink/family.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package netlink
|
||||||
|
|
||||||
|
import "github.com/vishvananda/netlink"
|
||||||
|
|
||||||
|
//nolint:revive
|
||||||
|
const (
|
||||||
|
FAMILY_ALL = netlink.FAMILY_ALL
|
||||||
|
FAMILY_V4 = netlink.FAMILY_V4
|
||||||
|
)
|
||||||
12
internal/netlink/interface.go
Normal file
12
internal/netlink/interface.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package netlink
|
||||||
|
|
||||||
|
//go:generate mockgen -destination=mock_$GOPACKAGE/$GOFILE . NetLinker
|
||||||
|
|
||||||
|
var _ NetLinker = (*NetLink)(nil)
|
||||||
|
|
||||||
|
type NetLinker interface {
|
||||||
|
Addresser
|
||||||
|
Linker
|
||||||
|
Router
|
||||||
|
Ruler
|
||||||
|
}
|
||||||
11
internal/netlink/ipnet.go
Normal file
11
internal/netlink/ipnet.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package netlink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/vishvananda/netlink"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewIPNet(ip net.IP) *net.IPNet {
|
||||||
|
return netlink.NewIPNet(ip)
|
||||||
|
}
|
||||||
48
internal/netlink/link.go
Normal file
48
internal/netlink/link.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package netlink
|
||||||
|
|
||||||
|
import "github.com/vishvananda/netlink"
|
||||||
|
|
||||||
|
type (
|
||||||
|
Link = netlink.Link
|
||||||
|
Bridge = netlink.Bridge
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ Linker = (*NetLink)(nil)
|
||||||
|
|
||||||
|
type Linker interface {
|
||||||
|
LinkList() (links []netlink.Link, err error)
|
||||||
|
LinkByName(name string) (link netlink.Link, err error)
|
||||||
|
LinkByIndex(index int) (link netlink.Link, err error)
|
||||||
|
LinkAdd(link netlink.Link) (err error)
|
||||||
|
LinkDel(link netlink.Link) (err error)
|
||||||
|
LinkSetUp(link netlink.Link) (err error)
|
||||||
|
LinkSetDown(link netlink.Link) (err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetLink) LinkList() (links []netlink.Link, err error) {
|
||||||
|
return netlink.LinkList()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetLink) LinkByName(name string) (link netlink.Link, err error) {
|
||||||
|
return netlink.LinkByName(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetLink) LinkByIndex(index int) (link netlink.Link, err error) {
|
||||||
|
return netlink.LinkByIndex(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetLink) LinkAdd(link netlink.Link) (err error) {
|
||||||
|
return netlink.LinkAdd(link)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetLink) LinkDel(link netlink.Link) (err error) {
|
||||||
|
return netlink.LinkDel(link)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetLink) LinkSetUp(link netlink.Link) (err error) {
|
||||||
|
return netlink.LinkSetUp(link)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetLink) LinkSetDown(link netlink.Link) (err error) {
|
||||||
|
return netlink.LinkSetDown(link)
|
||||||
|
}
|
||||||
9
internal/netlink/linkattrs.go
Normal file
9
internal/netlink/linkattrs.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package netlink
|
||||||
|
|
||||||
|
import "github.com/vishvananda/netlink"
|
||||||
|
|
||||||
|
type LinkAttrs = netlink.LinkAttrs
|
||||||
|
|
||||||
|
func NewLinkAttrs() LinkAttrs {
|
||||||
|
return netlink.NewLinkAttrs()
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user