Compare commits

..

34 Commits

Author SHA1 Message Date
Quentin McGaw (desktop)
b4ec59f9bd Fix IPVanish TLS verification 2021-07-02 03:21:33 +00:00
Quentin McGaw (desktop)
06c8792887 Doc: clarify setup instructions 2021-06-22 15:21:49 +00:00
Quentin McGaw (desktop)
3ea376a1b2 Doc: maintenance document 2021-06-22 14:42:15 +00:00
Quentin McGaw (desktop)
9667d30907 Doc: add code highlighting how-to to issue templates 2021-06-22 14:41:48 +00:00
Quentin McGaw (desktop)
3f7ccc6c49 Feature: improve Cyberghost updater
- Waits up to 20s for resolutions
- Update server information and timestamp
2021-06-21 20:29:55 +00:00
Quentin McGaw (desktop)
dd97ff5895 Maintenance: cache xcputranslate 2021-06-21 18:50:30 +00:00
Quentin McGaw (desktop)
2e4d80d9bc Maintenance: sleep for cross building 2021-06-21 18:35:40 +00:00
Quentin McGaw (desktop)
1227dc5a2b Maintenance: upgrade xcputranslate to v0.6.0 2021-06-21 18:01:21 +00:00
Quentin McGaw (desktop)
ed828bc733 Hotfix: VPN Unlimited variable choices 2021-06-21 13:32:03 +00:00
Quentin McGaw (desktop)
c25a018c05 Maintenance: CI deduplicate base stage build 2021-06-21 13:01:53 +00:00
Quentin McGaw (desktop)
266596af68 Fix errors introduced with golangci-lint 1.41.1 2021-06-20 16:39:38 +00:00
Quentin McGaw
2c77b73ebc IPVanish support (#475)
- Fix #410 and #416
2021-06-20 09:21:48 -07:00
Quentin McGaw
d81d4bbda3 VPN Unlimited support (#499)
- Fixes #420 
- Revert to docker/build-push-action@v2.4.0
2021-06-20 09:18:03 -07:00
Quentin McGaw (desktop)
400affe429 Maintenance: add revive linter 2021-06-20 16:12:39 +00:00
Quentin McGaw (desktop)
d3c63680e8 Maintenance: ugprade golangci-lint to v1.41.1 2021-06-20 16:12:09 +00:00
Quentin McGaw (desktop)
28de8a834c Maintenance: upgrade golang/mock to v1.6.0 2021-06-19 17:24:41 +00:00
Quentin McGaw (desktop)
208374fc54 Fix: Use name prefix for TLS check for IVPN 2021-06-19 16:34:50 +00:00
Quentin McGaw (desktop)
535a136a27 Feature: add IVPN Bulgaria and Spain servers 2021-06-19 16:34:36 +00:00
Quentin McGaw (desktop)
ba4c3e30a4 Doc: docker-compose.yml does not use secrets 2021-06-17 22:46:30 +00:00
Quentin McGaw (desktop)
16d8a388cb Maintenance: better layer caching
- Install g++ in base image before copying code
- Install xcputranslate in base image before copying code
- Install golangci-lint in base image before copying code
- Install golangci-lint using go get directly
2021-06-15 12:27:32 +00:00
Quentin McGaw (desktop)
5ea31b0b64 Maintenance: set entrypoint for test Docker stage 2021-06-15 12:25:57 +00:00
Quentin McGaw (desktop)
582c6d1c43 Fix: only use and write auth file if user is set
- Apply to custom openvpn configuration without username
2021-06-14 14:25:37 +00:00
Quentin McGaw (desktop)
c63ae3f3af Fix: custom openvpn config settings log 2021-06-14 14:24:38 +00:00
Quentin McGaw (desktop)
4c0df96a95 Maintenance: use github.com/qdm12/goshutdown 2021-06-10 15:03:47 +00:00
Quentin McGaw (desktop)
05c6b9379a Maintenance: prevent exit race condition for loops 2021-06-10 14:13:08 +00:00
Quentin McGaw (desktop)
fb7fdcd925 Fix: change PureVPN default cipher to AES-256-GCM 2021-06-08 00:24:46 +00:00
Quentin McGaw (desktop)
1774e2ad88 Maintenance: update list of linters 2021-06-07 23:31:52 +00:00
Quentin McGaw (desktop)
a402d9135e Fix: remote line for custom OpenVPN config 2021-06-07 19:46:21 +00:00
Quentin McGaw (desktop)
3d2c56d9ee Fix: custom cipher for custom files on Openvpn 2.5 2021-06-07 19:45:19 +00:00
Quentin McGaw (desktop)
f9308e6fed Remove dependency on github.com/kyokomi/emoji 2021-06-06 15:38:49 +00:00
Quentin McGaw (desktop)
6710468020 Maintenance: upgrade Go dependencies
- Upgrade fatih/color to v1.12.0
- Upgrade qdm12/dns to v1.8.0
- Upgrade qdm12/golibs
- Upgrade qdm12/updated
2021-06-03 21:31:50 +00:00
Quentin McGaw (desktop)
ad1981fff6 Maintenance: update PureVPN server information 2021-06-02 14:32:15 +00:00
Quentin McGaw (desktop)
01f9e71912 Fix: none encryption preset for PIA
- Set cipher and auth to `none`
- Add `ncp-disable` OpenVPN option in every case
2021-06-01 13:52:57 +00:00
Quentin McGaw (desktop)
d41b75ee35 Documentation: add discussion link for help issues 2021-06-01 13:44:04 +00:00
101 changed files with 5013 additions and 883 deletions

View File

@@ -39,3 +39,7 @@ PASTE YOUR LOGS
IN THERE IN THERE
``` ```
<!---
💡 You can highlight your code with https://docs.github.com/en/github/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlight
-->

View File

@@ -7,6 +7,12 @@ assignees:
--- ---
<!---
⚠️ If this about a Docker configuration problem or another service:
Start a discussion at https://github.com/qdm12/gluetun/discussions/new
OR I WILL INSTA-CLOSE YOUR ISSUE.
-->
<!--- <!---
⚠️ Answer the following or I'll insta-close your issue ⚠️ Answer the following or I'll insta-close your issue
--> -->
@@ -40,6 +46,10 @@ IN THERE
**What are you using to run your container?**: Docker Compose **What are you using to run your container?**: Docker Compose
<!---
💡 You can highlight your code with https://docs.github.com/en/github/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlight
-->
Please also share your configuration file: Please also share your configuration file:
```yml ```yml

6
.github/labels.yml vendored
View File

@@ -21,6 +21,9 @@
- name: ":cloud: HideMyAss" - name: ":cloud: HideMyAss"
color: "cfe8d4" color: "cfe8d4"
description: "" description: ""
- name: ":cloud: IPVanish"
color: "cfe8d4"
description: ""
- name: ":cloud: IVPN" - name: ":cloud: IVPN"
color: "cfe8d4" color: "cfe8d4"
description: "" description: ""
@@ -53,6 +56,9 @@
- name: ":cloud: Torguard" - name: ":cloud: Torguard"
color: "cfe8d4" color: "cfe8d4"
description: "" description: ""
- name: ":cloud: VPNUnlimited"
color: "cfe8d4"
description: ""
- name: ":cloud: Vyprvpn" - name: ":cloud: Vyprvpn"
color: "cfe8d4" color: "cfe8d4"
description: "" description: ""

View File

@@ -34,13 +34,7 @@ jobs:
touch coverage.txt touch coverage.txt
docker run --rm \ docker run --rm \
-v "$(pwd)/coverage.txt:/tmp/gobuild/coverage.txt" \ -v "$(pwd)/coverage.txt:/tmp/gobuild/coverage.txt" \
test-container \ test-container
go test \
-race \
-coverpkg=./... \
-coverprofile=coverage.txt \
-covermode=atomic \
./...
- name: Code security analysis - name: Code security analysis
uses: snyk/actions/golang@master uses: snyk/actions/golang@master
@@ -92,13 +86,14 @@ jobs:
fi fi
- name: Build and push final image - name: Build and push final image
uses: docker/build-push-action@v2 uses: docker/build-push-action@v2.4.0
with: with:
platforms: ${{ steps.vars.outputs.platforms }} platforms: ${{ steps.vars.outputs.platforms }}
build-args: | build-args: |
BUILD_DATE=${{ steps.vars.outputs.build_date }} BUILD_DATE=${{ steps.vars.outputs.build_date }}
COMMIT=${{ steps.vars.outputs.commit }} COMMIT=${{ steps.vars.outputs.commit }}
VERSION=${{ steps.vars.outputs.version }} VERSION=${{ steps.vars.outputs.version }}
ALLTARGETPLATFORMS=${{ steps.vars.outputs.platforms }}
tags: | tags: |
qmcgaw/gluetun:${{ steps.vars.outputs.version }} qmcgaw/gluetun:${{ steps.vars.outputs.version }}
qmcgaw/private-internet-access:${{ steps.vars.outputs.version }} qmcgaw/private-internet-access:${{ steps.vars.outputs.version }}

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
scratch.txt

View File

@@ -17,6 +17,15 @@ issues:
- path: internal/configuration/ - path: internal/configuration/
linters: linters:
- dupl - dupl
- text: "exported: exported var Err*"
linters:
- revive
- text: "mnd: Magic number: 0644*"
linters:
- gomnd
- text: "mnd: Magic number: 0400*"
linters:
- gomnd
linters: linters:
disable-all: true disable-all: true
enable: enable:
@@ -36,12 +45,12 @@ linters:
- gocritic - gocritic
- gocyclo - gocyclo
- godot - godot
- goerr113
- goheader - goheader
- goimports - goimports
- gomnd - gomnd
- goprintffuncname - goprintffuncname
- gosec - gosec
- goerr113
- gosimple - gosimple
- govet - govet
- importas - importas
@@ -55,8 +64,8 @@ linters:
- nolintlint - nolintlint
- prealloc - prealloc
- predeclared - predeclared
- revive
- rowserrcheck - rowserrcheck
- exportloopref
- sqlclosecheck - sqlclosecheck
- staticcheck - staticcheck
- structcheck - structcheck

View File

@@ -2,9 +2,14 @@ ARG ALPINE_VERSION=3.13
ARG GO_VERSION=1.16 ARG GO_VERSION=1.16
ARG BUILDPLATFORM=linux/amd64 ARG BUILDPLATFORM=linux/amd64
FROM --platform=$BUILDPLATFORM qmcgaw/xcputranslate:v0.6.0 AS xcputranslate
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS base FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS base
RUN apk --update add git COPY --from=xcputranslate /xcputranslate /usr/local/bin/xcputranslate
RUN apk --update add git g++
ENV CGO_ENABLED=0 ENV CGO_ENABLED=0
ARG GOLANGCI_LINT_VERSION=v1.41.1
RUN go get github.com/golangci/golangci-lint/cmd/golangci-lint@${GOLANGCI_LINT_VERSION}
WORKDIR /tmp/gobuild WORKDIR /tmp/gobuild
COPY go.mod go.sum ./ COPY go.mod go.sum ./
RUN go mod download RUN go mod download
@@ -14,14 +19,11 @@ COPY internal/ ./internal/
FROM --platform=$BUILDPLATFORM base AS test FROM --platform=$BUILDPLATFORM base AS test
# Note on the go race detector: # Note on the go race detector:
# - we set CGO_ENABLED=1 to have it enabled # - we set CGO_ENABLED=1 to have it enabled
# - we install g++ to support the race detector # - we installed g++ to support the race detector
ENV CGO_ENABLED=1 ENV CGO_ENABLED=1
RUN apk --update --no-cache add g++ ENTRYPOINT go test -race -coverpkg=./... -coverprofile=coverage.txt -covermode=atomic ./...
FROM --platform=$BUILDPLATFORM base AS lint FROM --platform=$BUILDPLATFORM base AS lint
ARG GOLANGCI_LINT_VERSION=v1.40.1
RUN wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | \
sh -s -- -b /usr/local/bin ${GOLANGCI_LINT_VERSION}
COPY .golangci.yml ./ COPY .golangci.yml ./
RUN golangci-lint run --timeout=10m RUN golangci-lint run --timeout=10m
@@ -35,13 +37,14 @@ RUN git init && \
git diff --exit-code -- go.mod git diff --exit-code -- go.mod
FROM --platform=$BUILDPLATFORM base AS build FROM --platform=$BUILDPLATFORM base AS build
COPY --from=qmcgaw/xcputranslate:v0.4.0 /xcputranslate /usr/local/bin/xcputranslate
ARG TARGETPLATFORM ARG TARGETPLATFORM
ARG ALLTARGETPLATFORMS=${TARGETPLATFORM}
ARG VERSION=unknown ARG VERSION=unknown
ARG BUILD_DATE="an unknown date" ARG BUILD_DATE="an unknown date"
ARG COMMIT=unknown ARG COMMIT=unknown
RUN GOARCH="$(xcputranslate -field arch -targetplatform ${TARGETPLATFORM})" \ RUN xcputranslate sleep -targetplatform ${TARGETPLATFORM} -buildtime=10s -order=${ALLTARGETPLATFORMS}
GOARM="$(xcputranslate -field arm -targetplatform ${TARGETPLATFORM})" \ RUN GOARCH="$(xcputranslate translate -field arch -targetplatform ${TARGETPLATFORM})" \
GOARM="$(xcputranslate translate -field arm -targetplatform ${TARGETPLATFORM})" \
go build -trimpath -ldflags="-s -w \ go build -trimpath -ldflags="-s -w \
-X 'main.version=$VERSION' \ -X 'main.version=$VERSION' \
-X 'main.buildDate=$BUILD_DATE' \ -X 'main.buildDate=$BUILD_DATE' \

View File

@@ -1,8 +1,8 @@
# Gluetun VPN client # Gluetun VPN client
*Lightweight swiss-knife-like VPN client to tunnel to Cyberghost, FastestVPN, *Lightweight swiss-knife-like VPN client to tunnel to Cyberghost, FastestVPN,
HideMyAss, IVPN, Mullvad, NordVPN, Privado, Private Internet Access, PrivateVPN, HideMyAss, IPVanish, IVPN, Mullvad, NordVPN, Privado, Private Internet Access, PrivateVPN,
ProtonVPN, PureVPN, Surfshark, TorGuard, 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**:
@@ -39,7 +39,7 @@ 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.13 for a small Docker image of 54MB
- Supports: **Cyberghost**, **FastestVPN**, **HideMyAss**, **IVPN**, **Mullvad**, **NordVPN**, **Privado**, **Private Internet Access**, **PrivateVPN**, **ProtonVPN**, **PureVPN**, **Surfshark**, **TorGuard**, **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 only for now
- 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
@@ -58,9 +58,17 @@ using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
## Setup ## Setup
1. On some devices you may need to setup your tunnel kernel module on your host with `insmod /lib/modules/tun.ko` or `modprobe tun` 1. Ensure your `tun` kernel module is setup:
- [Synology users Wiki page](https://github.com/qdm12/gluetun/wiki/Synology-setup)
1. ⚠️ Raspberry Pi users running 32 bit systems: from image `v3.16.0` you need to do [this](https://github.com/alpinelinux/docker-alpine/issues/135#issuecomment-812287338) on your host to run the container. ```sh
sudo modprobe tun
# or, if you don't have modprobe, with
sudo insmod /lib/modules/tun.ko
```
1. Extra steps:
- [For Synology users](https://github.com/qdm12/gluetun/wiki/Synology-setup)
- [For 32 bit Operating systems (**Rasberry Pis**)](https://github.com/qdm12/gluetun/wiki/32-bit-setup)
1. Launch the container with: 1. Launch the container with:
```bash ```bash
@@ -74,8 +82,6 @@ using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
or use [docker-compose.yml](https://github.com/qdm12/gluetun/blob/master/docker-compose.yml) with: or use [docker-compose.yml](https://github.com/qdm12/gluetun/blob/master/docker-compose.yml) with:
```bash ```bash
echo "your openvpn username" > openvpn_user
echo "your openvpn password" > openvpn_password
docker-compose up -d docker-compose up -d
``` ```
@@ -85,12 +91,12 @@ using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
The following points are all optional but should give you insights on all the possibilities with this container. The following points are all optional but should give you insights on all the possibilities with this container.
- Use [Docker secrets](https://github.com/qdm12/gluetun/wiki/Docker-secrets) to read your credentials instead of environment variables
- [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)
- [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.
- Use [Docker secrets](https://github.com/qdm12/gluetun/wiki/Docker-secrets) to read your credentials instead of environment variables
## License ## License

View File

@@ -29,7 +29,6 @@ import (
"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/shutdown"
"github.com/qdm12/gluetun/internal/storage" "github.com/qdm12/gluetun/internal/storage"
"github.com/qdm12/gluetun/internal/unix" "github.com/qdm12/gluetun/internal/unix"
"github.com/qdm12/gluetun/internal/updater" "github.com/qdm12/gluetun/internal/updater"
@@ -38,6 +37,7 @@ import (
"github.com/qdm12/golibs/os" "github.com/qdm12/golibs/os"
"github.com/qdm12/golibs/os/user" "github.com/qdm12/golibs/os/user"
"github.com/qdm12/golibs/params" "github.com/qdm12/golibs/params"
"github.com/qdm12/goshutdown"
"github.com/qdm12/updated/pkg/dnscrypto" "github.com/qdm12/updated/pkg/dnscrypto"
) )
@@ -275,82 +275,113 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
} }
} // TODO move inside firewall? } // TODO move inside firewall?
const (
shutdownMaxTimeout = 3 * time.Second
shutdownRoutineTimeout = 400 * time.Millisecond
shutdownOpenvpnTimeout = time.Second
)
healthy := make(chan bool) healthy := make(chan bool)
controlWave := shutdown.NewWave("control")
tickerWave := shutdown.NewWave("tickers") // Shutdown settings
healthWave := shutdown.NewWave("health") const defaultShutdownTimeout = 400 * time.Millisecond
dnsWave := shutdown.NewWave("DNS") defaultShutdownOnSuccess := func(goRoutineName string) {
vpnWave := shutdown.NewWave("VPN") logger.Info(goRoutineName + ": terminated ✔️")
serverWave := shutdown.NewWave("servers") }
defaultShutdownOnFailure := func(goRoutineName string, err error) {
logger.Warn(goRoutineName + ": " + err.Error() + " ⚠️")
}
defaultGoRoutineSettings := goshutdown.GoRoutineSettings{Timeout: defaultShutdownTimeout}
defaultGroupSettings := goshutdown.GroupSettings{
Timeout: defaultShutdownTimeout,
OnFailure: defaultShutdownOnFailure,
OnSuccess: defaultShutdownOnSuccess,
}
controlGroupHandler := goshutdown.NewGroupHandler("control", defaultGroupSettings)
tickersGroupHandler := goshutdown.NewGroupHandler("tickers", defaultGroupSettings)
otherGroupHandler := goshutdown.NewGroupHandler("other", defaultGroupSettings)
openvpnLooper := openvpn.NewLooper(allSettings.OpenVPN, nonRootUsername, puid, pgid, allServers, openvpnLooper := openvpn.NewLooper(allSettings.OpenVPN, nonRootUsername, puid, pgid, allServers,
ovpnConf, firewallConf, routingConf, logger, httpClient, os.OpenFile, tunnelReadyCh, healthy) ovpnConf, firewallConf, routingConf, logger, httpClient, os.OpenFile, tunnelReadyCh, healthy)
openvpnCtx, openvpnDone := vpnWave.Add("openvpn", shutdownOpenvpnTimeout) openvpnHandler, openvpnCtx, openvpnDone := goshutdown.NewGoRoutineHandler(
"openvpn", goshutdown.GoRoutineSettings{Timeout: time.Second})
// wait for restartOpenvpn // wait for restartOpenvpn
go openvpnLooper.Run(openvpnCtx, openvpnDone) go openvpnLooper.Run(openvpnCtx, openvpnDone)
updaterLooper := updater.NewLooper(allSettings.Updater, updaterLooper := updater.NewLooper(allSettings.Updater,
allServers, storage, openvpnLooper.SetServers, httpClient, allServers, storage, openvpnLooper.SetServers, httpClient,
logger.NewChild(logging.Settings{Prefix: "updater: "})) logger.NewChild(logging.Settings{Prefix: "updater: "}))
updaterCtx, updaterDone := tickerWave.Add("updater", shutdownRoutineTimeout) updaterHandler, updaterCtx, updaterDone := goshutdown.NewGoRoutineHandler(
"updater", defaultGoRoutineSettings)
// wait for updaterLooper.Restart() or its ticket launched with RunRestartTicker // wait for updaterLooper.Restart() or its ticket launched with RunRestartTicker
go updaterLooper.Run(updaterCtx, updaterDone) 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.NewLooper(dnsConf, allSettings.DNS, httpClient, unboundLooper := dns.NewLooper(dnsConf, allSettings.DNS, httpClient,
unboundLogger, os.OpenFile) unboundLogger, os.OpenFile)
dnsCtx, dnsDone := dnsWave.Add("unbound", shutdownRoutineTimeout) dnsHandler, dnsCtx, dnsDone := goshutdown.NewGoRoutineHandler(
"unbound", defaultGoRoutineSettings)
// wait for unboundLooper.Restart or its ticker launched with RunRestartTicker // wait for unboundLooper.Restart or its ticker launched with RunRestartTicker
go unboundLooper.Run(dnsCtx, dnsDone) go unboundLooper.Run(dnsCtx, dnsDone)
otherGroupHandler.Add(dnsHandler)
publicIPLooper := publicip.NewLooper(httpClient, publicIPLooper := publicip.NewLooper(httpClient,
logger.NewChild(logging.Settings{Prefix: "ip getter: "}), logger.NewChild(logging.Settings{Prefix: "ip getter: "}),
allSettings.PublicIP, puid, pgid, os) allSettings.PublicIP, puid, pgid, os)
pubIPCtx, pubIPDone := serverWave.Add("public IP", shutdownRoutineTimeout) pubIPHandler, pubIPCtx, pubIPDone := goshutdown.NewGoRoutineHandler(
"public IP", defaultGoRoutineSettings)
go publicIPLooper.Run(pubIPCtx, pubIPDone) go publicIPLooper.Run(pubIPCtx, pubIPDone)
otherGroupHandler.Add(pubIPHandler)
pubIPTickerCtx, pubIPTickerDone := tickerWave.Add("public IP", shutdownRoutineTimeout) pubIPTickerHandler, pubIPTickerCtx, pubIPTickerDone := goshutdown.NewGoRoutineHandler(
"public IP", defaultGoRoutineSettings)
go publicIPLooper.RunRestartTicker(pubIPTickerCtx, pubIPTickerDone) go publicIPLooper.RunRestartTicker(pubIPTickerCtx, pubIPTickerDone)
tickersGroupHandler.Add(pubIPTickerHandler)
httpProxyLooper := httpproxy.NewLooper( httpProxyLooper := httpproxy.NewLooper(
logger.NewChild(logging.Settings{Prefix: "http proxy: "}), logger.NewChild(logging.Settings{Prefix: "http proxy: "}),
allSettings.HTTPProxy) allSettings.HTTPProxy)
httpProxyCtx, httpProxyDone := serverWave.Add("http proxy", shutdownRoutineTimeout) httpProxyHandler, httpProxyCtx, httpProxyDone := goshutdown.NewGoRoutineHandler(
"http proxy", defaultGoRoutineSettings)
go httpProxyLooper.Run(httpProxyCtx, httpProxyDone) go httpProxyLooper.Run(httpProxyCtx, httpProxyDone)
otherGroupHandler.Add(httpProxyHandler)
shadowsocksLooper := shadowsocks.NewLooper(allSettings.ShadowSocks, shadowsocksLooper := shadowsocks.NewLooper(allSettings.ShadowSocks,
logger.NewChild(logging.Settings{Prefix: "shadowsocks: "})) logger.NewChild(logging.Settings{Prefix: "shadowsocks: "}))
shadowsocksCtx, shadowsocksDone := serverWave.Add("shadowsocks proxy", shutdownRoutineTimeout) shadowsocksHandler, shadowsocksCtx, shadowsocksDone := goshutdown.NewGoRoutineHandler(
"shadowsocks proxy", defaultGoRoutineSettings)
go shadowsocksLooper.Run(shadowsocksCtx, shadowsocksDone) go shadowsocksLooper.Run(shadowsocksCtx, shadowsocksDone)
otherGroupHandler.Add(shadowsocksHandler)
eventsRoutingCtx, eventsRoutingDone := controlWave.Add("events routing", shutdownRoutineTimeout) eventsRoutingHandler, eventsRoutingCtx, eventsRoutingDone := goshutdown.NewGoRoutineHandler(
"events routing", defaultGoRoutineSettings)
go routeReadyEvents(eventsRoutingCtx, eventsRoutingDone, buildInfo, tunnelReadyCh, go routeReadyEvents(eventsRoutingCtx, eventsRoutingDone, buildInfo, tunnelReadyCh,
unboundLooper, updaterLooper, publicIPLooper, routingConf, logger, httpClient, unboundLooper, updaterLooper, publicIPLooper, routingConf, logger, httpClient,
allSettings.VersionInformation, allSettings.OpenVPN.Provider.PortForwarding.Enabled, openvpnLooper.PortForward, 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
httpServer := server.New(controlServerAddress, controlServerLogging, httpServer := server.New(controlServerAddress, controlServerLogging,
logger.NewChild(logging.Settings{Prefix: "http server: "}), logger.NewChild(logging.Settings{Prefix: "http server: "}),
buildInfo, openvpnLooper, unboundLooper, updaterLooper, publicIPLooper) buildInfo, openvpnLooper, unboundLooper, updaterLooper, publicIPLooper)
httpServerCtx, httpServerDone := controlWave.Add("http server", shutdownRoutineTimeout) httpServerHandler, httpServerCtx, httpServerDone := goshutdown.NewGoRoutineHandler(
"http server", defaultGoRoutineSettings)
go httpServer.Run(httpServerCtx, httpServerDone) go httpServer.Run(httpServerCtx, httpServerDone)
controlGroupHandler.Add(httpServerHandler)
healthcheckServer := healthcheck.NewServer(constants.HealthcheckAddress, healthcheckServer := healthcheck.NewServer(constants.HealthcheckAddress,
logger.NewChild(logging.Settings{Prefix: "healthcheck: "})) logger.NewChild(logging.Settings{Prefix: "healthcheck: "}))
healthServerCtx, healthServerDone := healthWave.Add("HTTP health server", shutdownRoutineTimeout) healthServerHandler, healthServerCtx, healthServerDone := goshutdown.NewGoRoutineHandler(
"HTTP health server", defaultGoRoutineSettings)
go healthcheckServer.Run(healthServerCtx, healthy, healthServerDone) go healthcheckServer.Run(healthServerCtx, healthy, healthServerDone)
shutdownOrder := shutdown.NewOrder() const orderShutdownTimeout = 3 * time.Second
shutdownOrder.Append(controlWave, tickerWave, healthWave, orderSettings := goshutdown.OrderSettings{
dnsWave, vpnWave, serverWave, Timeout: orderShutdownTimeout,
) OnFailure: defaultShutdownOnFailure,
OnSuccess: defaultShutdownOnSuccess,
}
orderHandler := goshutdown.NewOrder("gluetun", orderSettings)
orderHandler.Append(controlGroupHandler, tickersGroupHandler, healthServerHandler,
openvpnHandler, otherGroupHandler)
// Start openvpn for the first time in a blocking call // Start openvpn for the first time in a blocking call
// until openvpn is launched // until openvpn is launched
@@ -365,7 +396,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
} }
} }
return shutdownOrder.Shutdown(shutdownMaxTimeout, logger) return orderHandler.Shutdown(context.Background())
} }
type printVersionElement struct { type printVersionElement struct {

View File

@@ -14,18 +14,11 @@ services:
# command: # command:
volumes: volumes:
- /yourpath:/gluetun - /yourpath:/gluetun
secrets:
- openvpn_user
- openvpn_password
environment: environment:
# More variables are available, see the readme table # More variables are available, see the readme table
- OPENVPN_USER=
- OPENVPN_PASSWORD=
- VPNSP=private internet access - VPNSP=private internet access
# Timezone for accurate logs times # Timezone for accurate logs times
- TZ= - TZ=
restart: always restart: always
secrets:
openvpn_user:
file: ./openvpn_user
openvpn_password:
file: ./openvpn_password

12
go.mod
View File

@@ -3,13 +3,13 @@ module github.com/qdm12/gluetun
go 1.16 go 1.16
require ( require (
github.com/fatih/color v1.10.0 github.com/fatih/color v1.12.0
github.com/golang/mock v1.5.0 github.com/golang/mock v1.6.0
github.com/kyokomi/emoji v2.2.4+incompatible github.com/qdm12/dns v1.8.0
github.com/qdm12/dns v1.7.0 github.com/qdm12/golibs v0.0.0-20210603202746-e5494e9c2ebb
github.com/qdm12/golibs v0.0.0-20210402232648-cfebf1e87d1b github.com/qdm12/goshutdown v0.1.0
github.com/qdm12/ss-server v0.2.0 github.com/qdm12/ss-server v0.2.0
github.com/qdm12/updated v0.0.0-20210102012151-76b7f5994638 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-20210514084401-e8d321eab015 golang.org/x/sys v0.0.0-20210514084401-e8d321eab015

71
go.sum
View File

@@ -1,4 +1,3 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
@@ -12,9 +11,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
@@ -31,58 +29,52 @@ github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsd
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/validate v0.17.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.17.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
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/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.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
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/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/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
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=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kyokomi/emoji v2.2.4+incompatible h1:np0woGKwx9LiHAQmwZx79Oc0rHpNw3o+3evou4BEPv4=
github.com/kyokomi/emoji v2.2.4+incompatible/go.mod h1:mZ6aGCD7yk8j6QY6KICwnZ2pxoszVseX1DNoGtU2tBA= github.com/kyokomi/emoji v2.2.4+incompatible/go.mod h1:mZ6aGCD7yk8j6QY6KICwnZ2pxoszVseX1DNoGtU2tBA=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
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.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
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/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/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.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee/go.mod h1:3uODdxMgOaPYeWU7RzZLxVtJHZ/x1f/iHkBZuKJDzuY= github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee/go.mod h1:3uODdxMgOaPYeWU7RzZLxVtJHZ/x1f/iHkBZuKJDzuY=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/qdm12/dns v1.7.0 h1:R8YGDPREzsXKx0k0TUbzPoI0+1oRzAnn79hzRXPHPcg= github.com/qdm12/dns v1.8.0 h1:GZ40kptmfDHOMNxBKWSA4zrbNyGm41BA57zv2MaDtCI=
github.com/qdm12/dns v1.7.0/go.mod h1:f2zChaUVDmE1MxUx+MKMFmBSh4G6DSU0rFZ+hHExSu0= github.com/qdm12/dns v1.8.0/go.mod h1:P2mm63NDYZdx2NAd5CVLM0FBnNdi1ZgVjsRSnX+96vg=
github.com/qdm12/golibs v0.0.0-20201227203847-2fd99ffdfdba/go.mod h1:pikkTN7g7zRuuAnERwqW1yAFq6pYmxrxpjiwGvb0Ysc= github.com/qdm12/golibs v0.0.0-20210603202746-e5494e9c2ebb h1:5WkOssTWl6Tv2H7VFb2jwB08A7BxxNCebkkpvz1PzrY=
github.com/qdm12/golibs v0.0.0-20210402232648-cfebf1e87d1b h1:tSD0qWqssS8AUFTGmlP1JFfbLViOt7xrjIxGZ1AFacY= github.com/qdm12/golibs v0.0.0-20210603202746-e5494e9c2ebb/go.mod h1:15RBzkun0i8XB7ADIoLJWp9ITRgsz3LroEI2FiOXLRg=
github.com/qdm12/golibs v0.0.0-20210402232648-cfebf1e87d1b/go.mod h1:y0qNgur9dTkHK2Bb5tK0UCtYyvEiK08flVIglROmnBg= 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/ss-server v0.2.0 h1:+togLzeeLAJ68MD1JqOWvYi9rl9t/fx1Qh7wKzZhY1g= github.com/qdm12/ss-server v0.2.0 h1:+togLzeeLAJ68MD1JqOWvYi9rl9t/fx1Qh7wKzZhY1g=
github.com/qdm12/ss-server v0.2.0/go.mod h1:+1bWO1EfWNvsGM5Cuep6vneChK2OHniqtAsED9Fh1y0= github.com/qdm12/ss-server v0.2.0/go.mod h1:+1bWO1EfWNvsGM5Cuep6vneChK2OHniqtAsED9Fh1y0=
github.com/qdm12/updated v0.0.0-20210102012151-76b7f5994638 h1:dM8OO6LO+uou14C5a/LUrot0oyqzPcoiSho6cEmOROc= github.com/qdm12/updated v0.0.0-20210603204757-205acfe6937e h1:4q+uFLawkaQRq3yARYLsjJPZd2wYwxn4g6G/5v0xW1g=
github.com/qdm12/updated v0.0.0-20210102012151-76b7f5994638/go.mod h1:bbJGxEYCnsA8WU4vBcXYU6mOoHyzdP458FIKP4mfLJM= 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=
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -90,7 +82,6 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
@@ -100,10 +91,7 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g= github.com/yl2chen/cidranger v1.0.2/go.mod h1:9U1yz7WPYDwf0vpNWFaeRh0bjwz5RVgRy/9UEQfHl0g=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go4.org/intern v0.0.0-20210108033219-3eb7198706b2 h1:VFTf+jjIgsldaz/Mr00VaCSswHJrI2hIjQygE/W4IMg= go4.org/intern v0.0.0-20210108033219-3eb7198706b2 h1:VFTf+jjIgsldaz/Mr00VaCSswHJrI2hIjQygE/W4IMg=
go4.org/intern v0.0.0-20210108033219-3eb7198706b2/go.mod h1:vLqJ+12kCw61iCWsPto0EOHhBS+o4rO5VIucbc9g2Cc= go4.org/intern v0.0.0-20210108033219-3eb7198706b2/go.mod h1:vLqJ+12kCw61iCWsPto0EOHhBS+o4rO5VIucbc9g2Cc=
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222175341-b30ae309168e/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222175341-b30ae309168e/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
@@ -111,68 +99,58 @@ go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063 h1:1tk03FU
go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= go4.org/unsafe/assume-no-moving-gc v0.0.0-20201222180813-1025295fd063/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
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-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
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-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
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/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
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/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-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-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-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
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/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 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
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/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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-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-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-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-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-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-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/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.0.0-20170915032832-14c0d48ead0c/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.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/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-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
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-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
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=
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 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/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-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
@@ -181,8 +159,5 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
inet.af/netaddr v0.0.0-20210511181906-37180328850c h1:rzDy/tC8LjEdN94+i0Bu22tTo/qE9cvhKyfD0HMU0NU= inet.af/netaddr v0.0.0-20210511181906-37180328850c h1:rzDy/tC8LjEdN94+i0Bu22tTo/qE9cvhKyfD0HMU0NU=
inet.af/netaddr v0.0.0-20210511181906-37180328850c/go.mod h1:z0nx+Dh+7N7CC8V5ayHtHGpZpxLQZZxkIaaz6HN65Ls= inet.af/netaddr v0.0.0-20210511181906-37180328850c/go.mod h1:z0nx+Dh+7N7CC8V5ayHtHGpZpxLQZZxkIaaz6HN65Ls=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View File

@@ -33,6 +33,7 @@ func (c *cli) Update(ctx context.Context, args []string, os os.OS, logger loggin
flagSet.BoolVar(&options.Cyberghost, "cyberghost", false, "Update Cyberghost servers") flagSet.BoolVar(&options.Cyberghost, "cyberghost", false, "Update Cyberghost servers")
flagSet.BoolVar(&options.Fastestvpn, "fastestvpn", false, "Update FastestVPN servers") flagSet.BoolVar(&options.Fastestvpn, "fastestvpn", false, "Update FastestVPN servers")
flagSet.BoolVar(&options.HideMyAss, "hidemyass", false, "Update HideMyAss servers") flagSet.BoolVar(&options.HideMyAss, "hidemyass", false, "Update HideMyAss servers")
flagSet.BoolVar(&options.Ipvanish, "ipvanish", false, "Update IpVanish servers")
flagSet.BoolVar(&options.Ivpn, "ivpn", false, "Update IVPN servers") flagSet.BoolVar(&options.Ivpn, "ivpn", false, "Update IVPN servers")
flagSet.BoolVar(&options.Mullvad, "mullvad", false, "Update Mullvad servers") flagSet.BoolVar(&options.Mullvad, "mullvad", false, "Update Mullvad servers")
flagSet.BoolVar(&options.Nordvpn, "nordvpn", false, "Update Nordvpn servers") flagSet.BoolVar(&options.Nordvpn, "nordvpn", false, "Update Nordvpn servers")
@@ -43,6 +44,7 @@ func (c *cli) Update(ctx context.Context, args []string, os os.OS, logger loggin
flagSet.BoolVar(&options.Purevpn, "purevpn", false, "Update Purevpn servers") flagSet.BoolVar(&options.Purevpn, "purevpn", false, "Update Purevpn servers")
flagSet.BoolVar(&options.Surfshark, "surfshark", false, "Update Surfshark servers") flagSet.BoolVar(&options.Surfshark, "surfshark", false, "Update Surfshark servers")
flagSet.BoolVar(&options.Torguard, "torguard", false, "Update Torguard servers") flagSet.BoolVar(&options.Torguard, "torguard", false, "Update Torguard servers")
flagSet.BoolVar(&options.VPNUnlimited, "vpnunlimited", false, "Update VPN Unlimited servers")
flagSet.BoolVar(&options.Vyprvpn, "vyprvpn", false, "Update Vyprvpn servers") flagSet.BoolVar(&options.Vyprvpn, "vyprvpn", false, "Update Vyprvpn servers")
flagSet.BoolVar(&options.Windscribe, "windscribe", false, "Update Windscribe servers") flagSet.BoolVar(&options.Windscribe, "windscribe", false, "Update Windscribe servers")
if err := flagSet.Parse(args); err != nil { if err := flagSet.Parse(args); err != nil {

View File

@@ -1,10 +1,6 @@
package configuration package configuration
import ( import (
"encoding/pem"
"errors"
"strings"
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/golibs/params" "github.com/qdm12/golibs/params"
) )
@@ -44,12 +40,12 @@ func (settings *Provider) readCyberghost(r reader) (err error) {
return err return err
} }
settings.ExtraConfigOptions.ClientKey, err = readCyberghostClientKey(r) settings.ExtraConfigOptions.ClientKey, err = readClientKey(r)
if err != nil { if err != nil {
return err return err
} }
settings.ExtraConfigOptions.ClientCertificate, err = readCyberghostClientCertificate(r) settings.ExtraConfigOptions.ClientCertificate, err = readClientCertificate(r)
if err != nil { if err != nil {
return err return err
} }
@@ -72,49 +68,3 @@ func (settings *Provider) readCyberghost(r reader) (err error) {
return nil return nil
} }
func readCyberghostClientKey(r reader) (clientKey string, err error) {
b, err := r.getFromFileOrSecretFile("OPENVPN_CLIENTKEY", constants.ClientKey)
if err != nil {
return "", err
}
return extractClientKey(b)
}
var errDecodePEMBlockClientKey = errors.New("cannot decode PEM block from client key")
func extractClientKey(b []byte) (key string, err error) {
pemBlock, _ := pem.Decode(b)
if pemBlock == nil {
return "", errDecodePEMBlockClientKey
}
parsedBytes := pem.EncodeToMemory(pemBlock)
s := string(parsedBytes)
s = strings.ReplaceAll(s, "\n", "")
s = strings.TrimPrefix(s, "-----BEGIN PRIVATE KEY-----")
s = strings.TrimSuffix(s, "-----END PRIVATE KEY-----")
return s, nil
}
func readCyberghostClientCertificate(r reader) (clientCertificate string, err error) {
b, err := r.getFromFileOrSecretFile("OPENVPN_CLIENTCRT", constants.ClientCertificate)
if err != nil {
return "", err
}
return extractClientCertificate(b)
}
var errDecodePEMBlockClientCert = errors.New("cannot decode PEM block from client certificate")
func extractClientCertificate(b []byte) (certificate string, err error) {
pemBlock, _ := pem.Decode(b)
if pemBlock == nil {
return "", errDecodePEMBlockClientCert
}
parsedBytes := pem.EncodeToMemory(pemBlock)
s := string(parsedBytes)
s = strings.ReplaceAll(s, "\n", "")
s = strings.TrimPrefix(s, "-----BEGIN CERTIFICATE-----")
s = strings.TrimSuffix(s, "-----END CERTIFICATE-----")
return s, nil
}

View File

@@ -29,11 +29,7 @@ func (settings *DNS) readBlacklistBuilding(r reader) (err error) {
return err return err
} }
if err := settings.readBlacklistUnblockedHostnames(r); err != nil { return settings.readBlacklistUnblockedHostnames(r)
return err
}
return nil
} }
var ( var (

View File

@@ -69,11 +69,7 @@ func (settings *Firewall) read(r reader) (err error) {
return err return err
} }
if err := settings.readOutboundSubnets(r); err != nil { return settings.readOutboundSubnets(r)
return err
}
return nil
} }
func (settings *Firewall) readVPNInputPorts(env params.Env) (err error) { func (settings *Firewall) readVPNInputPorts(env params.Env) (err error) {

View File

@@ -0,0 +1,52 @@
package configuration
import (
"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) {
settings.Name = constants.Ipvanish
settings.ServerSelection.TCP, err = readProtocol(r.env)
if err != nil {
return err
}
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
if err != nil {
return err
}
settings.ServerSelection.Countries, err = r.env.CSVInside("COUNTRY", constants.IpvanishCountryChoices())
if err != nil {
return err
}
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.IpvanishCityChoices())
if err != nil {
return err
}
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.IpvanishHostnameChoices())
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,192 @@
package configuration
import (
"errors"
"net"
"testing"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/golibs/params/mock_params"
"github.com/stretchr/testify/assert"
"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) {
t.Parallel()
var errDummy = errors.New("dummy test error")
type singleStringCall struct {
call bool
value string
err error
}
type sliceStringCall struct {
call bool
values []string
err error
}
testCases := map[string]struct {
protocol singleStringCall
targetIP singleStringCall
countries sliceStringCall
cities sliceStringCall
hostnames sliceStringCall
settings Provider
err error
}{
"protocol error": {
protocol: singleStringCall{call: true, err: errDummy},
settings: Provider{
Name: constants.Ipvanish,
},
err: errDummy,
},
"target IP error": {
protocol: singleStringCall{call: true},
targetIP: singleStringCall{call: true, value: "something", err: errDummy},
settings: Provider{
Name: constants.Ipvanish,
},
err: errDummy,
},
"countries error": {
protocol: singleStringCall{call: true},
targetIP: singleStringCall{call: true},
countries: sliceStringCall{call: true, err: errDummy},
settings: Provider{
Name: constants.Ipvanish,
},
err: errDummy,
},
"cities error": {
protocol: singleStringCall{call: true},
targetIP: singleStringCall{call: true},
countries: sliceStringCall{call: true},
cities: sliceStringCall{call: true, err: errDummy},
settings: Provider{
Name: constants.Ipvanish,
},
err: errDummy,
},
"hostnames error": {
protocol: singleStringCall{call: true},
targetIP: singleStringCall{call: true},
countries: sliceStringCall{call: true},
cities: sliceStringCall{call: true},
hostnames: sliceStringCall{call: true, err: errDummy},
settings: Provider{
Name: constants.Ipvanish,
},
err: errDummy,
},
"default settings": {
protocol: singleStringCall{call: true},
targetIP: singleStringCall{call: true},
countries: sliceStringCall{call: true},
cities: sliceStringCall{call: true},
hostnames: sliceStringCall{call: true},
settings: Provider{
Name: constants.Ipvanish,
},
},
"set settings": {
protocol: singleStringCall{call: true, value: constants.TCP},
targetIP: singleStringCall{call: true, value: "1.2.3.4"},
countries: sliceStringCall{call: true, values: []string{"A", "B"}},
cities: sliceStringCall{call: true, values: []string{"C", "D"}},
hostnames: sliceStringCall{call: true, values: []string{"E", "F"}},
settings: Provider{
Name: constants.Ipvanish,
ServerSelection: ServerSelection{
TCP: true,
TargetIP: net.IPv4(1, 2, 3, 4),
Countries: []string{"A", "B"},
Cities: []string{"C", "D"},
Hostnames: []string{"E", "F"},
},
},
},
}
for name, testCase := range testCases {
testCase := testCase
t.Run(name, func(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
env := mock_params.NewMockEnv(ctrl)
if testCase.protocol.call {
env.EXPECT().Inside("PROTOCOL", []string{constants.TCP, constants.UDP}, gomock.Any()).
Return(testCase.protocol.value, testCase.protocol.err)
}
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.IpvanishCountryChoices()).
Return(testCase.countries.values, testCase.countries.err)
}
if testCase.cities.call {
env.EXPECT().CSVInside("CITY", constants.IpvanishCityChoices()).
Return(testCase.cities.values, testCase.cities.err)
}
if testCase.hostnames.call {
env.EXPECT().CSVInside("SERVER_HOSTNAME", constants.IpvanishHostnameChoices()).
Return(testCase.hostnames.values, testCase.hostnames.err)
}
r := reader{env: env}
var settings Provider
err := settings.readIpvanish(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)
})
}
}

View File

@@ -0,0 +1,55 @@
package configuration
import (
"encoding/pem"
"errors"
"strings"
"github.com/qdm12/gluetun/internal/constants"
)
func readClientKey(r reader) (clientKey string, err error) {
b, err := r.getFromFileOrSecretFile("OPENVPN_CLIENTKEY", constants.ClientKey)
if err != nil {
return "", err
}
return extractClientKey(b)
}
var errDecodePEMBlockClientKey = errors.New("cannot decode PEM block from client key")
func extractClientKey(b []byte) (key string, err error) {
pemBlock, _ := pem.Decode(b)
if pemBlock == nil {
return "", errDecodePEMBlockClientKey
}
parsedBytes := pem.EncodeToMemory(pemBlock)
s := string(parsedBytes)
s = strings.ReplaceAll(s, "\n", "")
s = strings.TrimPrefix(s, "-----BEGIN PRIVATE KEY-----")
s = strings.TrimSuffix(s, "-----END PRIVATE KEY-----")
return s, nil
}
func readClientCertificate(r reader) (clientCertificate string, err error) {
b, err := r.getFromFileOrSecretFile("OPENVPN_CLIENTCRT", constants.ClientCertificate)
if err != nil {
return "", err
}
return extractClientCertificate(b)
}
var errDecodePEMBlockClientCert = errors.New("cannot decode PEM block from client certificate")
func extractClientCertificate(b []byte) (certificate string, err error) {
pemBlock, _ := pem.Decode(b)
if pemBlock == nil {
return "", errDecodePEMBlockClientCert
}
parsedBytes := pem.EncodeToMemory(pemBlock)
s := string(parsedBytes)
s = strings.ReplaceAll(s, "\n", "")
s = strings.TrimPrefix(s, "-----BEGIN CERTIFICATE-----")
s = strings.TrimSuffix(s, "-----END CERTIFICATE-----")
return s, nil
}

View File

@@ -69,7 +69,8 @@ func (settings *Provider) readNordvpn(r reader) (err error) {
} }
func readNordVPNServerNumbers(env params.Env) (numbers []uint16, err error) { func readNordVPNServerNumbers(env params.Env) (numbers []uint16, err error) {
possibilities := make([]string, 65537) const possiblePortsCount = 65537
possibilities := make([]string, possiblePortsCount)
for i := range possibilities { for i := range possibilities {
possibilities[i] = fmt.Sprintf("%d", i) possibilities[i] = fmt.Sprintf("%d", i)
} }

View File

@@ -50,9 +50,13 @@ func (settings *OpenVPN) lines() (lines []string) {
lines = append(lines, indent+lastIndent+"Custom configuration: "+settings.Config) lines = append(lines, indent+lastIndent+"Custom configuration: "+settings.Config)
} }
lines = append(lines, indent+lastIndent+"Provider:") if settings.Provider.Name == "" {
for _, line := range settings.Provider.lines() { lines = append(lines, indent+lastIndent+"Provider: custom configuration")
lines = append(lines, indent+indent+line) } else {
lines = append(lines, indent+lastIndent+"Provider:")
for _, line := range settings.Provider.lines() {
lines = append(lines, indent+indent+line)
}
} }
return lines return lines
@@ -64,9 +68,9 @@ var (
func (settings *OpenVPN) read(r reader) (err error) { func (settings *OpenVPN) read(r reader) (err error) {
vpnsp, err := r.env.Inside("VPNSP", []string{ vpnsp, err := r.env.Inside("VPNSP", []string{
"cyberghost", "fastestvpn", "hidemyass", "ivpn", "mullvad", "nordvpn", "cyberghost", "fastestvpn", "hidemyass", "ipvanish", "ivpn", "mullvad", "nordvpn",
"privado", "pia", "private internet access", "privatevpn", "protonvpn", "privado", "pia", "private internet access", "privatevpn", "protonvpn",
"purevpn", "surfshark", "torguard", "vyprvpn", "windscribe"}, "purevpn", "surfshark", "torguard", constants.VPNUnlimited, "vyprvpn", "windscribe"},
params.Default("private internet access")) params.Default("private internet access"))
if err != nil { if err != nil {
return err return err
@@ -81,8 +85,13 @@ func (settings *OpenVPN) read(r reader) (err error) {
if err != nil { if err != nil {
return err return err
} }
customConfig := settings.Config != ""
credentialsRequired := len(settings.Config) == 0 if customConfig {
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 {
@@ -106,7 +115,7 @@ func (settings *OpenVPN) read(r reader) (err error) {
return err return err
} }
settings.Verbosity, err = r.env.IntRange("OPENVPN_VERBOSITY", 0, 6, params.Default("1")) settings.Verbosity, err = r.env.IntRange("OPENVPN_VERBOSITY", 0, 6, params.Default("1")) //nolint:gomnd
if err != nil { if err != nil {
return err return err
} }
@@ -126,20 +135,28 @@ func (settings *OpenVPN) read(r reader) (err error) {
return err return err
} }
mssFix, err := r.env.IntRange("OPENVPN_MSSFIX", 0, 10000, params.Default("0")) const maxMSSFix = 10000
mssFix, err := r.env.IntRange("OPENVPN_MSSFIX", 0, maxMSSFix, params.Default("0"))
if err != nil { if err != nil {
return err return err
} }
settings.MSSFix = uint16(mssFix) settings.MSSFix = uint16(mssFix)
return settings.readProvider(r)
}
func (settings *OpenVPN) readProvider(r reader) error {
var readProvider func(r reader) error var readProvider func(r reader) error
switch settings.Provider.Name { switch settings.Provider.Name {
case "": // custom config
readProvider = func(r reader) error { return nil }
case constants.Cyberghost: case constants.Cyberghost:
readProvider = settings.Provider.readCyberghost readProvider = settings.Provider.readCyberghost
case constants.Fastestvpn: case constants.Fastestvpn:
readProvider = settings.Provider.readFastestvpn readProvider = settings.Provider.readFastestvpn
case constants.HideMyAss: case constants.HideMyAss:
readProvider = settings.Provider.readHideMyAss readProvider = settings.Provider.readHideMyAss
case constants.Ipvanish:
readProvider = settings.Provider.readIpvanish
case constants.Ivpn: case constants.Ivpn:
readProvider = settings.Provider.readIvpn readProvider = settings.Provider.readIvpn
case constants.Mullvad: case constants.Mullvad:
@@ -160,6 +177,8 @@ func (settings *OpenVPN) read(r reader) (err error) {
readProvider = settings.Provider.readSurfshark readProvider = settings.Provider.readSurfshark
case constants.Torguard: case constants.Torguard:
readProvider = settings.Provider.readTorguard readProvider = settings.Provider.readTorguard
case constants.VPNUnlimited:
readProvider = settings.Provider.readVPNUnlimited
case constants.Vyprvpn: case constants.Vyprvpn:
readProvider = settings.Provider.readVyprvpn readProvider = settings.Provider.readVyprvpn
case constants.Windscribe: case constants.Windscribe:
@@ -167,6 +186,5 @@ func (settings *OpenVPN) read(r reader) (err error) {
default: default:
return fmt.Errorf("%w: %s", ErrInvalidVPNProvider, settings.Provider.Name) return fmt.Errorf("%w: %s", ErrInvalidVPNProvider, settings.Provider.Name)
} }
return readProvider(r) return readProvider(r)
} }

View File

@@ -41,7 +41,8 @@ func Test_OpenVPN_JSON(t *testing.T) {
"custom_port": 0, "custom_port": 0,
"numbers": null, "numbers": null,
"encryption_preset": "", "encryption_preset": "",
"free_only": false "free_only": false,
"stream_only": false
}, },
"extra_config": { "extra_config": {
"encryption_preset": "", "encryption_preset": "",

View File

@@ -36,6 +36,8 @@ func (settings *Provider) lines() (lines []string) {
providerLines = settings.fastestvpnLines() providerLines = settings.fastestvpnLines()
case "hidemyass": case "hidemyass":
providerLines = settings.hideMyAssLines() providerLines = settings.hideMyAssLines()
case "ipvanish":
providerLines = settings.ipvanishLines()
case "ivpn": case "ivpn":
providerLines = settings.ivpnLines() providerLines = settings.ivpnLines()
case "mullvad": case "mullvad":
@@ -56,6 +58,8 @@ func (settings *Provider) lines() (lines []string) {
providerLines = settings.surfsharkLines() providerLines = settings.surfsharkLines()
case "torguard": case "torguard":
providerLines = settings.torguardLines() providerLines = settings.torguardLines()
case strings.ToLower(constants.VPNUnlimited):
providerLines = settings.vpnUnlimitedLines()
case "vyprvpn": case "vyprvpn":
providerLines = settings.vyprvpnLines() providerLines = settings.vyprvpnLines()
case "windscribe": case "windscribe":

View File

@@ -73,6 +73,23 @@ func Test_Provider_lines(t *testing.T) {
" |--Hostnames: e, f", " |--Hostnames: e, f",
}, },
}, },
"ipvanish": {
settings: Provider{
Name: constants.Ipvanish,
ServerSelection: ServerSelection{
Countries: []string{"a", "b"},
Cities: []string{"c", "d"},
Hostnames: []string{"e", "f"},
},
},
lines: []string{
"|--Ipvanish settings:",
" |--Network protocol: udp",
" |--Countries: a, b",
" |--Cities: c, d",
" |--Hostnames: e, f",
},
},
"ivpn": { "ivpn": {
settings: Provider{ settings: Provider{
Name: constants.Ivpn, Name: constants.Ivpn,
@@ -249,6 +266,31 @@ func Test_Provider_lines(t *testing.T) {
" |--Hostnames: e", " |--Hostnames: e",
}, },
}, },
constants.VPNUnlimited: {
settings: Provider{
Name: constants.VPNUnlimited,
ServerSelection: ServerSelection{
Countries: []string{"a", "b"},
Cities: []string{"c", "d"},
Hostnames: []string{"e", "f"},
FreeOnly: true,
StreamOnly: true,
},
ExtraConfigOptions: ExtraConfigOptions{
ClientKey: "a",
},
},
lines: []string{
"|--Vpn Unlimited settings:",
" |--Network protocol: udp",
" |--Countries: a, b",
" |--Cities: c, d",
" |--Hostnames: e, f",
" |--Free servers only",
" |--Stream servers only",
" |--Client key is set",
},
},
"vyprvpn": { "vyprvpn": {
settings: Provider{ settings: Provider{
Name: constants.Vyprvpn, Name: constants.Vyprvpn,

View File

@@ -15,10 +15,13 @@ type ServerSelection struct { //nolint:maligned
// Cyberghost // Cyberghost
Group string `json:"group"` Group string `json:"group"`
Countries []string `json:"countries"` // Fastestvpn, HideMyAss, IVPN, Mullvad, PrivateVPN, Protonvpn, PureVPN // Fastestvpn, HideMyAss, IPVanish, IVPN, Mullvad, PrivateVPN, Protonvpn, PureVPN, VPNUnlimited
Cities []string `json:"cities"` // HideMyAss, IVPN, Mullvad, PrivateVPN, Protonvpn, PureVPN, Windscribe Countries []string `json:"countries"`
Hostnames []string `json:"hostnames"` // Fastestvpn, HideMyAss, IVPN, PrivateVPN, Windscribe, Privado, Protonvpn // HideMyAss, IPVanish, IVPN, Mullvad, PrivateVPN, Protonvpn, PureVPN, VPNUnlimited, Windscribe
Names []string `json:"names"` // Protonvpn Cities []string `json:"cities"`
// Fastestvpn, HideMyAss, IPVanish, IVPN, PrivateVPN, Windscribe, Privado, Protonvpn, VPNUnlimited
Hostnames []string `json:"hostnames"`
Names []string `json:"names"` // Protonvpn
// Mullvad // Mullvad
ISPs []string `json:"isps"` ISPs []string `json:"isps"`
@@ -35,11 +38,14 @@ type ServerSelection struct { //nolint:maligned
// ProtonVPN // ProtonVPN
FreeOnly bool `json:"free_only"` FreeOnly bool `json:"free_only"`
// VPNUnlimited
StreamOnly bool `json:"stream_only"`
} }
type ExtraConfigOptions struct { type ExtraConfigOptions struct {
ClientCertificate string `json:"-"` // Cyberghost ClientCertificate string `json:"-"` // Cyberghost
ClientKey string `json:"-"` // Cyberghost ClientKey string `json:"-"` // Cyberghost, VPNUnlimited
EncryptionPreset string `json:"encryption_preset"` // PIA EncryptionPreset string `json:"encryption_preset"` // PIA
OpenVPNIPv6 bool `json:"openvpn_ipv6"` // Mullvad OpenVPNIPv6 bool `json:"openvpn_ipv6"` // Mullvad
} }

View File

@@ -1,6 +1,8 @@
package configuration package configuration
import ( import (
"errors"
"fmt"
"strings" "strings"
"github.com/qdm12/golibs/logging" "github.com/qdm12/golibs/logging"
@@ -43,6 +45,18 @@ func (settings *Settings) lines() (lines []string) {
return lines return lines
} }
var (
ErrOpenvpn = errors.New("cannot read Openvpn settings")
ErrSystem = errors.New("cannot read System settings")
ErrDNS = errors.New("cannot read DNS settings")
ErrFirewall = errors.New("cannot read firewall settings")
ErrHTTPProxy = errors.New("cannot read HTTP proxy settings")
ErrShadowsocks = errors.New("cannot read Shadowsocks settings")
ErrControlServer = errors.New("cannot read control server settings")
ErrUpdater = errors.New("cannot read Updater settings")
ErrPublicIP = errors.New("cannot read Public IP getter 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, os os.OS, logger logging.Logger) (err error) { func (settings *Settings) Read(env params.Env, os os.OS, logger logging.Logger) (err error) {
@@ -54,35 +68,35 @@ func (settings *Settings) Read(env params.Env, os os.OS, logger logging.Logger)
} }
if err := settings.OpenVPN.read(r); err != nil { if err := settings.OpenVPN.read(r); err != nil {
return err return fmt.Errorf("%w: %s", ErrOpenvpn, err)
} }
if err := settings.System.read(r); err != nil { if err := settings.System.read(r); err != nil {
return err return fmt.Errorf("%w: %s", ErrSystem, err)
} }
if err := settings.DNS.read(r); err != nil { if err := settings.DNS.read(r); err != nil {
return err return fmt.Errorf("%w: %s", ErrDNS, err)
} }
if err := settings.Firewall.read(r); err != nil { if err := settings.Firewall.read(r); err != nil {
return err return fmt.Errorf("%w: %s", ErrFirewall, err)
} }
if err := settings.HTTPProxy.read(r); err != nil { if err := settings.HTTPProxy.read(r); err != nil {
return err return fmt.Errorf("%w: %s", ErrHTTPProxy, err)
} }
if err := settings.ShadowSocks.read(r); err != nil { if err := settings.ShadowSocks.read(r); err != nil {
return err return fmt.Errorf("%w: %s", ErrShadowsocks, err)
} }
if err := settings.ControlServer.read(r); err != nil { if err := settings.ControlServer.read(r); err != nil {
return err return fmt.Errorf("%w: %s", ErrControlServer, err)
} }
if err := settings.Updater.read(r); err != nil { if err := settings.Updater.read(r); err != nil {
return err return fmt.Errorf("%w: %s", ErrUpdater, err)
} }
if ip := settings.DNS.PlaintextAddress; ip != nil { if ip := settings.DNS.PlaintextAddress; ip != nil {
@@ -90,7 +104,7 @@ func (settings *Settings) Read(env params.Env, os os.OS, logger logging.Logger)
} }
if err := settings.PublicIP.read(r); err != nil { if err := settings.PublicIP.read(r); err != nil {
return err return fmt.Errorf("%w: %s", ErrPublicIP, err)
} }
return nil return nil

View File

@@ -32,13 +32,14 @@ func (settings *System) lines() (lines []string) {
} }
func (settings *System) read(r reader) (err error) { func (settings *System) read(r reader) (err error) {
settings.PUID, err = r.env.IntRange("PUID", 0, 65535, params.Default("1000"), const maxID = 65535
settings.PUID, err = r.env.IntRange("PUID", 0, maxID, params.Default("1000"),
params.RetroKeys([]string{"UID"}, r.onRetroActive)) params.RetroKeys([]string{"UID"}, r.onRetroActive))
if err != nil { if err != nil {
return err return err
} }
settings.PGID, err = r.env.IntRange("PGID", 0, 65535, params.Default("1000"), settings.PGID, err = r.env.IntRange("PGID", 0, maxID, params.Default("1000"),
params.RetroKeys([]string{"GID"}, r.onRetroActive)) params.RetroKeys([]string{"GID"}, r.onRetroActive))
if err != nil { if err != nil {
return err return err

View File

@@ -43,7 +43,7 @@ func (settings *Provider) readTorguard(r reader) (err error) {
return err return err
} }
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.TorguardHostnamesChoices()) settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.TorguardHostnameChoices())
if err != nil { if err != nil {
return err return err
} }

View File

@@ -29,19 +29,19 @@ func (settings *DNS) readUnbound(r reader) (err error) {
return err return err
} }
verbosityLevel, err := r.env.IntRange("DOT_VERBOSITY", 0, 5, params.Default("1")) verbosityLevel, err := r.env.IntRange("DOT_VERBOSITY", 0, 5, params.Default("1")) //nolint:gomnd
if err != nil { if err != nil {
return err return err
} }
settings.Unbound.VerbosityLevel = uint8(verbosityLevel) settings.Unbound.VerbosityLevel = uint8(verbosityLevel)
verbosityDetailsLevel, err := r.env.IntRange("DOT_VERBOSITY_DETAILS", 0, 4, params.Default("0")) verbosityDetailsLevel, err := r.env.IntRange("DOT_VERBOSITY_DETAILS", 0, 4, params.Default("0")) //nolint:gomnd
if err != nil { if err != nil {
return err return err
} }
settings.Unbound.VerbosityDetailsLevel = uint8(verbosityDetailsLevel) settings.Unbound.VerbosityDetailsLevel = uint8(verbosityDetailsLevel)
validationLogLevel, err := r.env.IntRange("DOT_VALIDATION_LOGLEVEL", 0, 2, params.Default("0")) validationLogLevel, err := r.env.IntRange("DOT_VALIDATION_LOGLEVEL", 0, 2, params.Default("0")) //nolint:gomnd
if err != nil { if err != nil {
return err return err
} }

View File

@@ -8,23 +8,25 @@ import (
) )
type Updater struct { type Updater struct {
Period time.Duration `json:"period"` Period time.Duration `json:"period"`
DNSAddress string `json:"dns_address"` DNSAddress string `json:"dns_address"`
Cyberghost bool `json:"cyberghost"` Cyberghost bool `json:"cyberghost"`
Fastestvpn bool `json:"fastestvpn"` Fastestvpn bool `json:"fastestvpn"`
HideMyAss bool `json:"hidemyass"` HideMyAss bool `json:"hidemyass"`
Ivpn bool `json:"ivpn"` Ipvanish bool `json:"ipvanish"`
Mullvad bool `json:"mullvad"` Ivpn bool `json:"ivpn"`
Nordvpn bool `json:"nordvpn"` Mullvad bool `json:"mullvad"`
PIA bool `json:"pia"` Nordvpn bool `json:"nordvpn"`
Privado bool `json:"privado"` PIA bool `json:"pia"`
Privatevpn bool `json:"privatevpn"` Privado bool `json:"privado"`
Protonvpn bool `json:"protonvpn"` Privatevpn bool `json:"privatevpn"`
Purevpn bool `json:"purevpn"` Protonvpn bool `json:"protonvpn"`
Surfshark bool `json:"surfshark"` Purevpn bool `json:"purevpn"`
Torguard bool `json:"torguard"` Surfshark bool `json:"surfshark"`
Vyprvpn bool `json:"vyprvpn"` Torguard bool `json:"torguard"`
Windscribe bool `json:"windscribe"` VPNUnlimited bool `json:"vpnunlimited"`
Vyprvpn bool `json:"vyprvpn"`
Windscribe bool `json:"windscribe"`
// The two below should be used in CLI mode only // The two below should be used in CLI mode only
Stdout bool `json:"-"` // in order to update constants file (maintainer side) Stdout bool `json:"-"` // in order to update constants file (maintainer side)
CLI bool `json:"-"` CLI bool `json:"-"`
@@ -49,6 +51,7 @@ func (settings *Updater) lines() (lines []string) {
func (settings *Updater) read(r reader) (err error) { func (settings *Updater) read(r reader) (err error) {
settings.Cyberghost = true settings.Cyberghost = true
settings.HideMyAss = true settings.HideMyAss = true
settings.Ipvanish = true
settings.Ivpn = true settings.Ivpn = true
settings.Mullvad = true settings.Mullvad = true
settings.Nordvpn = true settings.Nordvpn = true
@@ -60,6 +63,7 @@ func (settings *Updater) read(r reader) (err error) {
settings.Purevpn = true settings.Purevpn = true
settings.Surfshark = true settings.Surfshark = true
settings.Torguard = true settings.Torguard = true
settings.VPNUnlimited = true
settings.Vyprvpn = true settings.Vyprvpn = true
settings.Windscribe = true settings.Windscribe = true
settings.Stdout = false settings.Stdout = false

View File

@@ -0,0 +1,85 @@
package configuration
import (
"github.com/qdm12/gluetun/internal/constants"
"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) {
settings.Name = constants.VPNUnlimited
settings.ServerSelection.TCP, err = readProtocol(r.env)
if err != nil {
return err
}
settings.ServerSelection.TargetIP, err = readTargetIP(r.env)
if err != nil {
return err
}
settings.ExtraConfigOptions.ClientKey, err = readClientKey(r)
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 {
return err
}
settings.ServerSelection.Cities, err = r.env.CSVInside("CITY", constants.VPNUnlimitedCityChoices())
if err != nil {
return err
}
settings.ServerSelection.Hostnames, err = r.env.CSVInside("SERVER_HOSTNAME", constants.VPNUnlimitedHostnameChoices())
if err != nil {
return err
}
settings.ServerSelection.FreeOnly, err = r.env.YesNo("FREE_ONLY", params.Default("no"))
if err != nil {
return err
}
settings.ServerSelection.StreamOnly, err = r.env.YesNo("STREAM_ONLY", params.Default("no"))
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,42 @@
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)
})
}
}

View File

@@ -1,5 +1,6 @@
package constants package constants
const ( const (
// HealthcheckAddress is the default listening address for the healthcheck server.
HealthcheckAddress = "127.0.0.1:9999" HealthcheckAddress = "127.0.0.1:9999"
) )

View File

@@ -2,254 +2,255 @@ package constants
func CountryCodes() map[string]string { func CountryCodes() map[string]string {
return map[string]string{ return map[string]string{
"af": "Afghanistan", "af": "Afghanistan",
"ax": "Aland Islands", "ax": "Aland Islands",
"al": "Albania", "al": "Albania",
"dz": "Algeria", "dz": "Algeria",
"as": "American Samoa", "as": "American Samoa",
"ad": "Andorra", "ad": "Andorra",
"ao": "Angola", "ao": "Angola",
"ai": "Anguilla", "ai": "Anguilla",
"aq": "Antarctica", "aq": "Antarctica",
"ag": "Antigua and Barbuda", "ag": "Antigua and Barbuda",
"ar": "Argentina", "ar": "Argentina",
"am": "Armenia", "am": "Armenia",
"aw": "Aruba", "aw": "Aruba",
"au": "Australia", "au": "Australia",
"at": "Austria", "at": "Austria",
"az": "Azerbaijan", "az": "Azerbaijan",
"bs": "Bahamas", "bs": "Bahamas",
"bh": "Bahrain", "bh": "Bahrain",
"bd": "Bangladesh", "bd": "Bangladesh",
"bb": "Barbados", "bb": "Barbados",
"by": "Belarus", "by": "Belarus",
"be": "Belgium", "be": "Belgium",
"bz": "Belize", "bz": "Belize",
"bj": "Benin", "bj": "Benin",
"bm": "Bermuda", "bm": "Bermuda",
"bt": "Bhutan", "bt": "Bhutan",
"bo": "Bolivia", "bo": "Bolivia",
"bq": "Bonaire", "bq": "Bonaire",
"ba": "Bosnia and Herzegovina", "ba": "Bosnia and Herzegovina",
"bw": "Botswana", "bw": "Botswana",
"bv": "Bouvet Island", "bv": "Bouvet Island",
"br": "Brazil", "br": "Brazil",
"io": "British Indian Ocean Territory", "io": "British Indian Ocean Territory",
"vg": "British Virgin Islands", "vg": "British Virgin Islands",
"bn": "Brunei Darussalam", "bn": "Brunei Darussalam",
"bg": "Bulgaria", "bg": "Bulgaria",
"bf": "Burkina Faso", "bf": "Burkina Faso",
"bi": "Burundi", "bi": "Burundi",
"kh": "Cambodia", "kh": "Cambodia",
"cm": "Cameroon", "cm": "Cameroon",
"ca": "Canada", "ca": "Canada",
"cv": "Cape Verde", "cv": "Cape Verde",
"ky": "Cayman Islands", "ky": "Cayman Islands",
"cf": "Central African Republic", "cf": "Central African Republic",
"td": "Chad", "td": "Chad",
"cl": "Chile", "cl": "Chile",
"cn": "China", "cn": "China",
"cx": "Christmas Island", "cx": "Christmas Island",
"cc": "Cocos Islands", "cc": "Cocos Islands",
"co": "Colombia", "co": "Colombia",
"km": "Comoros", "km": "Comoros",
"cg": "Congo", "cg": "Congo",
"ck": "Cook Islands", "ck": "Cook Islands",
"cr": "Costa Rica", "cr": "Costa Rica",
"ci": "Cote d'Ivoire", "ci": "Cote d'Ivoire",
"hr": "Croatia", "hr": "Croatia",
"cu": "Cuba", "cu": "Cuba",
"cw": "Curacao", "cw": "Curacao",
"cy": "Cyprus", "cy": "Cyprus",
"cz": "Czech Republic", "cz": "Czech Republic",
"cd": "Democratic Republic of the Congo", "cd": "Democratic Republic of the Congo",
"dk": "Denmark", "dk": "Denmark",
"dj": "Djibouti", "dj": "Djibouti",
"dm": "Dominica", "dm": "Dominica",
"do": "Dominican Republic", "do": "Dominican Republic",
"ec": "Ecuador", "ec": "Ecuador",
"eg": "Egypt", "eg": "Egypt",
"sv": "El Salvador", "sv": "El Salvador",
"gq": "Equatorial Guinea", "gq": "Equatorial Guinea",
"er": "Eritrea", "er": "Eritrea",
"ee": "Estonia", "ee": "Estonia",
"et": "Ethiopia", "et": "Ethiopia",
"fk": "Falkland Islands", "fk": "Falkland Islands",
"fo": "Faroe Islands", "fo": "Faroe Islands",
"fj": "Fiji", "fj": "Fiji",
"fi": "Finland", "fi": "Finland",
"fr": "France", "fr": "France",
"gf": "French Guiana", "gf": "French Guiana",
"pf": "French Polynesia", "pf": "French Polynesia",
"tf": "French Southern Territories", "tf": "French Southern Territories",
"ga": "Gabon", "ga": "Gabon",
"gm": "Gambia", "gm": "Gambia",
"ge": "Georgia", "ge": "Georgia",
"de": "Germany", "de": "Germany",
"gh": "Ghana", "gh": "Ghana",
"gi": "Gibraltar", "gi": "Gibraltar",
"gr": "Greece", "gr": "Greece",
"gl": "Greenland", "gl": "Greenland",
"gd": "Grenada", "gd": "Grenada",
"gp": "Guadeloupe", "gp": "Guadeloupe",
"gu": "Guam", "gu": "Guam",
"gt": "Guatemala", "gt": "Guatemala",
"gg": "Guernsey", "gg": "Guernsey",
"gw": "Guinea-Bissau", "gw": "Guinea-Bissau",
"gn": "Guinea", "gn": "Guinea",
"gy": "Guyana", "gy": "Guyana",
"ht": "Haiti", "ht": "Haiti",
"hm": "Heard Island and McDonald Islands", "hm": "Heard Island and McDonald Islands",
"hn": "Honduras", "hn": "Honduras",
"hk": "Hong Kong", "hk": "Hong Kong",
"hu": "Hungary", "hu": "Hungary",
"is": "Iceland", "is": "Iceland",
"in": "India", "in": "India",
"id": "Indonesia", "id": "Indonesia",
"ir": "Iran", "ir": "Iran",
"iq": "Iraq", "iq": "Iraq",
"ie": "Ireland", "ie": "Ireland",
"im": "Isle of Man", "im": "Isle of Man",
"il": "Israel", "il": "Israel",
"it": "Italy", "it": "Italy",
"jm": "Jamaica", "jm": "Jamaica",
"jp": "Japan", "jp": "Japan",
"je": "Jersey", "je": "Jersey",
"jo": "Jordan", "jo": "Jordan",
"kz": "Kazakhstan", "kz": "Kazakhstan",
"ke": "Kenya", "ke": "Kenya",
"ki": "Kiribati", "ki": "Kiribati",
"kr": "Korea", "kr": "Korea",
"kw": "Kuwait", "kw": "Kuwait",
"kg": "Kyrgyzstan", "kg": "Kyrgyzstan",
"la": "Lao People's Democratic Republic", "la": "Lao People's Democratic Republic",
"lv": "Latvia", "lv": "Latvia",
"lb": "Lebanon", "lb": "Lebanon",
"ls": "Lesotho", "ls": "Lesotho",
"lr": "Liberia", "lr": "Liberia",
"ly": "Libya", "ly": "Libya",
"li": "Liechtenstein", "li": "Liechtenstein",
"lt": "Lithuania", "lt": "Lithuania",
"lu": "Luxembourg", "lu": "Luxembourg",
"mo": "Macao", "mo": "Macao",
"mk": "Macedonia", "mk": "Macedonia",
"mg": "Madagascar", "mg": "Madagascar",
"mw": "Malawi", "mw": "Malawi",
"my": "Malaysia", "my": "Malaysia",
"mv": "Maldives", "mys": "Kuala Lumpur",
"ml": "Mali", "mv": "Maldives",
"mt": "Malta", "ml": "Mali",
"mh": "Marshall Islands", "mt": "Malta",
"mq": "Martinique", "mh": "Marshall Islands",
"mr": "Mauritania", "mq": "Martinique",
"mu": "Mauritius", "mr": "Mauritania",
"yt": "Mayotte", "mu": "Mauritius",
"mx": "Mexico", "yt": "Mayotte",
"fm": "Micronesia", "mx": "Mexico",
"md": "Moldova", "fm": "Micronesia",
"mc": "Monaco", "md": "Moldova",
"mn": "Mongolia", "mc": "Monaco",
"me": "Montenegro", "mn": "Mongolia",
"ms": "Montserrat", "me": "Montenegro",
"ma": "Morocco", "ms": "Montserrat",
"mz": "Mozambique", "ma": "Morocco",
"mm": "Myanmar", "mz": "Mozambique",
"na": "Namibia", "mm": "Myanmar",
"nr": "Nauru", "na": "Namibia",
"np": "Nepal", "nr": "Nauru",
"nl": "Netherlands", "np": "Nepal",
"nc": "New Caledonia", "nl": "Netherlands",
"nz": "New Zealand", "nc": "New Caledonia",
"ni": "Nicaragua", "nz": "New Zealand",
"ne": "Niger", "ni": "Nicaragua",
"ng": "Nigeria", "ne": "Niger",
"nu": "Niue", "ng": "Nigeria",
"nf": "Norfolk Island", "nu": "Niue",
"mp": "Northern Mariana Islands", "nf": "Norfolk Island",
"no": "Norway", "mp": "Northern Mariana Islands",
"om": "Oman", "no": "Norway",
"pk": "Pakistan", "om": "Oman",
"pw": "Palau", "pk": "Pakistan",
"ps": "Palestine, State of", "pw": "Palau",
"pa": "Panama", "ps": "Palestine, State of",
"pg": "Papua New Guinea", "pa": "Panama",
"py": "Paraguay", "pg": "Papua New Guinea",
"pe": "Peru", "py": "Paraguay",
"ph": "Philippines", "pe": "Peru",
"pn": "Pitcairn", "ph": "Philippines",
"pl": "Poland", "pn": "Pitcairn",
"pt": "Portugal", "pl": "Poland",
"pr": "Puerto Rico", "pt": "Portugal",
"qa": "Qatar", "pr": "Puerto Rico",
"re": "Reunion", "qa": "Qatar",
"ro": "Romania", "re": "Reunion",
"ru": "Russian Federation", "ro": "Romania",
"rw": "Rwanda", "ru": "Russian Federation",
"bl": "Saint Barthelemy", "rw": "Rwanda",
"sh": "Saint Helena", "bl": "Saint Barthelemy",
"kn": "Saint Kitts and Nevis", "sh": "Saint Helena",
"lc": "Saint Lucia", "kn": "Saint Kitts and Nevis",
"mf": "Saint Martin", "lc": "Saint Lucia",
"pm": "Saint Pierre and Miquelon", "mf": "Saint Martin",
"vc": "Saint Vincent and the Grenadines", "pm": "Saint Pierre and Miquelon",
"ws": "Samoa", "vc": "Saint Vincent and the Grenadines",
"sm": "San Marino", "ws": "Samoa",
"st": "Sao Tome and Principe", "sm": "San Marino",
"sa": "Saudi Arabia", "st": "Sao Tome and Principe",
"sn": "Senegal", "sa": "Saudi Arabia",
"rs": "Serbia", "sn": "Senegal",
"sc": "Seychelles", "rs": "Serbia",
"sl": "Sierra Leone", "sc": "Seychelles",
"sg": "Singapore", "sl": "Sierra Leone",
"sx": "Sint Maarten", "sg": "Singapore",
"sk": "Slovakia", "sx": "Sint Maarten",
"si": "Slovenia", "sk": "Slovakia",
"sb": "Solomon Islands", "si": "Slovenia",
"so": "Somalia", "sb": "Solomon Islands",
"za": "South Africa", "so": "Somalia",
"gs": "South Georgia and the South Sandwich Islands", "za": "South Africa",
"ss": "South Sudan", "gs": "South Georgia and the South Sandwich Islands",
"es": "Spain", "ss": "South Sudan",
"lk": "Sri Lanka", "es": "Spain",
"sd": "Sudan", "lk": "Sri Lanka",
"sr": "Suriname", "sd": "Sudan",
"sj": "Svalbard and Jan Mayen", "sr": "Suriname",
"sz": "Swaziland", "sj": "Svalbard and Jan Mayen",
"se": "Sweden", "sz": "Swaziland",
"ch": "Switzerland", "se": "Sweden",
"sy": "Syrian Arab Republic", "ch": "Switzerland",
"tw": "Taiwan", "sy": "Syrian Arab Republic",
"tj": "Tajikistan", "tw": "Taiwan",
"tz": "Tanzania", "tj": "Tajikistan",
"th": "Thailand", "tz": "Tanzania",
"tl": "Timor-Leste", "th": "Thailand",
"tg": "Togo", "tl": "Timor-Leste",
"tk": "Tokelau", "tg": "Togo",
"to": "Tonga", "tk": "Tokelau",
"tt": "Trinidad and Tobago", "to": "Tonga",
"tn": "Tunisia", "tt": "Trinidad and Tobago",
"tr": "Turkey", "tn": "Tunisia",
"tm": "Turkmenistan", "tr": "Turkey",
"tc": "Turks and Caicos Islands", "tm": "Turkmenistan",
"tv": "Tuvalu", "tc": "Turks and Caicos Islands",
"ug": "Uganda", "tv": "Tuvalu",
"ua": "Ukraine", "ug": "Uganda",
"ae": "United Arab Emirates", "ua": "Ukraine",
"gb": "United Kingdom", "ae": "United Arab Emirates",
"uk": "United Kingdom", "gb": "United Kingdom",
"um": "United States Minor Outlying Islands", "uk": "United Kingdom",
"us": "United States", "um": "United States Minor Outlying Islands",
"uy": "Uruguay", "us": "United States",
"vi": "US Virgin Islands", "uy": "Uruguay",
"uz": "Uzbekistan", "vi": "US Virgin Islands",
"vu": "Vanuatu", "uz": "Uzbekistan",
"va": "Vatican City State", "vu": "Vanuatu",
"ve": "Venezuela", "va": "Vatican City State",
"vn": "Vietnam", "ve": "Venezuela",
"wf": "Wallis and Futuna", "vn": "Vietnam",
"eh": "Western Sahara", "wf": "Wallis and Futuna",
"ye": "Yemen", "eh": "Western Sahara",
"zm": "Zambia", "ye": "Yemen",
"zw": "Zimbabwe", "zm": "Zambia",
"zw": "Zimbabwe",
} }
} }

View File

@@ -43,134 +43,184 @@ func CyberghostHostnameChoices() (choices []string) {
// of the Cyberghost server. // of the Cyberghost server.
func CyberghostServers() []models.CyberghostServer { func CyberghostServers() []models.CyberghostServer {
return []models.CyberghostServer{ return []models.CyberghostServer{
{Region: "Albania", Group: "Premium UDP Europe", Hostname: "87-1-al.cg-dialup.net", IPs: []net.IP{{31, 171, 155, 3}, {31, 171, 155, 4}, {31, 171, 155, 5}, {31, 171, 155, 6}, {31, 171, 155, 7}, {31, 171, 155, 8}, {31, 171, 155, 10}, {31, 171, 155, 11}, {31, 171, 155, 13}, {31, 171, 155, 14}}}, {Region: "Albania", Group: "Premium TCP Europe", Hostname: "97-1-al.cg-dialup.net", IPs: []net.IP{{31, 171, 155, 3}, {31, 171, 155, 4}, {31, 171, 155, 7}, {31, 171, 155, 8}, {31, 171, 155, 9}, {31, 171, 155, 10}, {31, 171, 155, 11}, {31, 171, 155, 12}, {31, 171, 155, 13}, {31, 171, 155, 14}}},
{Region: "Algeria", Group: "Premium TCP Europe", Hostname: "97-1-dz.cg-dialup.net", IPs: []net.IP{{176, 125, 228, 131}, {176, 125, 228, 132}, {176, 125, 228, 134}, {176, 125, 228, 135}, {176, 125, 228, 136}, {176, 125, 228, 138}, {176, 125, 228, 141}, {176, 125, 228, 142}, {176, 125, 228, 143}, {176, 125, 228, 144}}}, {Region: "Albania", Group: "Premium UDP Europe", Hostname: "87-1-al.cg-dialup.net", IPs: []net.IP{{31, 171, 155, 4}, {31, 171, 155, 5}, {31, 171, 155, 6}, {31, 171, 155, 7}, {31, 171, 155, 8}, {31, 171, 155, 9}, {31, 171, 155, 10}, {31, 171, 155, 11}, {31, 171, 155, 13}, {31, 171, 155, 14}}},
{Region: "Argentina", Group: "Premium TCP USA", Hostname: "93-1-ar.cg-dialup.net", IPs: []net.IP{{190, 106, 130, 15}, {190, 106, 130, 18}, {190, 106, 130, 20}, {190, 106, 130, 22}, {190, 106, 130, 23}, {190, 106, 130, 36}, {190, 106, 130, 43}, {190, 106, 130, 44}, {190, 106, 130, 45}, {190, 106, 130, 52}}}, {Region: "Algeria", Group: "Premium TCP Europe", Hostname: "97-1-dz.cg-dialup.net", IPs: []net.IP{{176, 125, 228, 132}, {176, 125, 228, 134}, {176, 125, 228, 135}, {176, 125, 228, 136}, {176, 125, 228, 137}, {176, 125, 228, 138}, {176, 125, 228, 139}, {176, 125, 228, 140}, {176, 125, 228, 141}, {176, 125, 228, 142}}},
{Region: "Argentina", Group: "Premium UDP USA", Hostname: "94-1-ar.cg-dialup.net", IPs: []net.IP{{190, 106, 130, 15}, {190, 106, 130, 19}, {190, 106, 130, 20}, {190, 106, 130, 21}, {190, 106, 130, 34}, {190, 106, 130, 36}, {190, 106, 130, 38}, {190, 106, 130, 42}, {190, 106, 130, 43}, {190, 106, 130, 52}}}, {Region: "Algeria", Group: "Premium UDP Europe", Hostname: "87-1-dz.cg-dialup.net", IPs: []net.IP{{176, 125, 228, 131}, {176, 125, 228, 133}, {176, 125, 228, 134}, {176, 125, 228, 136}, {176, 125, 228, 137}, {176, 125, 228, 139}, {176, 125, 228, 140}, {176, 125, 228, 141}, {176, 125, 228, 142}, {176, 125, 228, 143}}},
{Region: "Armenia", Group: "Premium TCP Europe", Hostname: "97-1-am.cg-dialup.net", IPs: []net.IP{{185, 253, 160, 131}, {185, 253, 160, 132}, {185, 253, 160, 134}, {185, 253, 160, 138}, {185, 253, 160, 139}, {185, 253, 160, 140}, {185, 253, 160, 141}, {185, 253, 160, 142}, {185, 253, 160, 143}, {185, 253, 160, 144}}}, {Region: "Andorra", Group: "Premium TCP Europe", Hostname: "97-1-ad.cg-dialup.net", IPs: []net.IP{{188, 241, 82, 137}, {188, 241, 82, 138}, {188, 241, 82, 140}, {188, 241, 82, 142}, {188, 241, 82, 147}, {188, 241, 82, 155}, {188, 241, 82, 159}, {188, 241, 82, 160}, {188, 241, 82, 161}, {188, 241, 82, 166}}},
{Region: "Armenia", Group: "Premium UDP Europe", Hostname: "87-1-am.cg-dialup.net", IPs: []net.IP{{185, 253, 160, 131}, {185, 253, 160, 132}, {185, 253, 160, 134}, {185, 253, 160, 136}, {185, 253, 160, 137}, {185, 253, 160, 138}, {185, 253, 160, 139}, {185, 253, 160, 140}, {185, 253, 160, 141}, {185, 253, 160, 143}}}, {Region: "Andorra", Group: "Premium UDP Europe", Hostname: "87-1-ad.cg-dialup.net", IPs: []net.IP{{188, 241, 82, 133}, {188, 241, 82, 134}, {188, 241, 82, 136}, {188, 241, 82, 137}, {188, 241, 82, 146}, {188, 241, 82, 153}, {188, 241, 82, 155}, {188, 241, 82, 160}, {188, 241, 82, 164}, {188, 241, 82, 168}}},
{Region: "Australia", Group: "Premium TCP Asia", Hostname: "96-1-au.cg-dialup.net", IPs: []net.IP{{43, 242, 68, 108}, {202, 60, 80, 5}, {202, 60, 80, 41}, {202, 60, 80, 58}, {202, 60, 91, 204}, {202, 60, 91, 213}, {202, 60, 91, 221}, {202, 60, 91, 222}, {202, 60, 91, 225}, {202, 60, 91, 234}}}, {Region: "Argentina", Group: "Premium TCP USA", Hostname: "93-1-ar.cg-dialup.net", IPs: []net.IP{{146, 70, 39, 4}, {146, 70, 39, 9}, {146, 70, 39, 15}, {146, 70, 39, 19}, {146, 70, 39, 135}, {146, 70, 39, 136}, {146, 70, 39, 139}, {146, 70, 39, 142}, {146, 70, 39, 143}, {146, 70, 39, 145}}},
{Region: "Australia", Group: "Premium UDP Asia", Hostname: "95-1-au.cg-dialup.net", IPs: []net.IP{{43, 242, 68, 77}, {43, 242, 68, 95}, {43, 242, 68, 108}, {202, 60, 80, 20}, {202, 60, 80, 31}, {202, 60, 80, 47}, {202, 60, 91, 199}, {202, 60, 91, 222}, {202, 60, 91, 226}, {202, 60, 91, 253}}}, {Region: "Argentina", Group: "Premium UDP USA", Hostname: "94-1-ar.cg-dialup.net", IPs: []net.IP{{146, 70, 39, 3}, {146, 70, 39, 5}, {146, 70, 39, 6}, {146, 70, 39, 8}, {146, 70, 39, 11}, {146, 70, 39, 12}, {146, 70, 39, 131}, {146, 70, 39, 134}, {146, 70, 39, 142}, {146, 70, 39, 143}}},
{Region: "Austria", Group: "Premium UDP Europe", Hostname: "87-1-at.cg-dialup.net", IPs: []net.IP{{37, 19, 223, 112}, {37, 19, 223, 119}, {37, 120, 155, 100}, {37, 120, 155, 102}, {37, 120, 155, 104}, {37, 120, 155, 110}, {89, 187, 168, 166}, {89, 187, 168, 174}, {89, 187, 168, 175}, {89, 187, 168, 177}}}, {Region: "Armenia", Group: "Premium TCP Europe", Hostname: "97-1-am.cg-dialup.net", IPs: []net.IP{{185, 253, 160, 131}, {185, 253, 160, 134}, {185, 253, 160, 136}, {185, 253, 160, 137}, {185, 253, 160, 138}, {185, 253, 160, 139}, {185, 253, 160, 140}, {185, 253, 160, 141}, {185, 253, 160, 142}, {185, 253, 160, 143}}},
{Region: "Bahamas", Group: "Premium TCP USA", Hostname: "93-1-bs.cg-dialup.net", IPs: []net.IP{{95, 181, 238, 132}, {95, 181, 238, 133}, {95, 181, 238, 137}, {95, 181, 238, 139}, {95, 181, 238, 142}, {95, 181, 238, 144}, {95, 181, 238, 145}, {95, 181, 238, 147}, {95, 181, 238, 148}, {95, 181, 238, 153}}}, {Region: "Armenia", Group: "Premium UDP Europe", Hostname: "87-1-am.cg-dialup.net", IPs: []net.IP{{185, 253, 160, 131}, {185, 253, 160, 132}, {185, 253, 160, 133}, {185, 253, 160, 134}, {185, 253, 160, 135}, {185, 253, 160, 136}, {185, 253, 160, 137}, {185, 253, 160, 141}, {185, 253, 160, 142}, {185, 253, 160, 144}}},
{Region: "Bangladesh", Group: "Premium TCP Asia", Hostname: "96-1-bd.cg-dialup.net", IPs: []net.IP{{84, 252, 93, 131}, {84, 252, 93, 132}, {84, 252, 93, 133}, {84, 252, 93, 135}, {84, 252, 93, 138}, {84, 252, 93, 140}, {84, 252, 93, 142}, {84, 252, 93, 143}, {84, 252, 93, 144}, {84, 252, 93, 145}}}, {Region: "Australia", Group: "Premium TCP Asia", Hostname: "96-1-au.cg-dialup.net", IPs: []net.IP{{154, 16, 81, 22}, {181, 214, 215, 7}, {181, 214, 215, 15}, {181, 214, 215, 18}, {191, 101, 210, 15}, {191, 101, 210, 50}, {191, 101, 210, 60}, {202, 60, 80, 78}, {202, 60, 80, 82}, {202, 60, 80, 102}}},
{Region: "Bangladesh", Group: "Premium UDP Asia", Hostname: "95-1-bd.cg-dialup.net", IPs: []net.IP{{84, 252, 93, 131}, {84, 252, 93, 132}, {84, 252, 93, 133}, {84, 252, 93, 134}, {84, 252, 93, 135}, {84, 252, 93, 137}, {84, 252, 93, 139}, {84, 252, 93, 141}, {84, 252, 93, 143}, {84, 252, 93, 145}}}, {Region: "Australia", Group: "Premium UDP Asia", Hostname: "95-1-au.cg-dialup.net", IPs: []net.IP{{181, 214, 215, 4}, {181, 214, 215, 16}, {191, 101, 210, 18}, {191, 101, 210, 21}, {191, 101, 210, 36}, {191, 101, 210, 58}, {191, 101, 210, 60}, {202, 60, 80, 74}, {202, 60, 80, 106}, {202, 60, 80, 124}}},
{Region: "Belarus", Group: "Premium UDP Europe", Hostname: "87-1-by.cg-dialup.net", IPs: []net.IP{{45, 132, 194, 7}, {45, 132, 194, 25}, {45, 132, 194, 33}, {45, 132, 194, 36}, {45, 132, 194, 38}, {45, 132, 194, 43}, {45, 132, 194, 44}, {45, 132, 194, 45}, {45, 132, 194, 48}, {45, 132, 194, 49}}}, {Region: "Austria", Group: "Premium TCP Europe", Hostname: "97-1-at.cg-dialup.net", IPs: []net.IP{{37, 19, 223, 9}, {37, 19, 223, 16}, {37, 19, 223, 113}, {37, 19, 223, 205}, {37, 19, 223, 211}, {37, 19, 223, 218}, {37, 19, 223, 223}, {37, 19, 223, 245}, {37, 120, 155, 104}, {89, 187, 168, 174}}},
{Region: "Belgium", Group: "Premium TCP Europe", Hostname: "97-1-be.cg-dialup.net", IPs: []net.IP{{5, 253, 205, 26}, {37, 120, 143, 54}, {37, 120, 143, 57}, {185, 210, 217, 52}, {185, 232, 21, 115}, {193, 9, 114, 212}, {193, 9, 114, 227}, {193, 9, 114, 230}, {193, 9, 114, 249}, {194, 110, 115, 233}}}, {Region: "Austria", Group: "Premium UDP Europe", Hostname: "87-1-at.cg-dialup.net", IPs: []net.IP{{37, 19, 223, 202}, {37, 19, 223, 205}, {37, 19, 223, 229}, {37, 19, 223, 239}, {37, 19, 223, 241}, {37, 19, 223, 243}, {37, 120, 155, 103}, {89, 187, 168, 160}, {89, 187, 168, 174}, {89, 187, 168, 181}}},
{Region: "Bahamas", Group: "Premium TCP USA", Hostname: "93-1-bs.cg-dialup.net", IPs: []net.IP{{95, 181, 238, 131}, {95, 181, 238, 136}, {95, 181, 238, 142}, {95, 181, 238, 144}, {95, 181, 238, 146}, {95, 181, 238, 147}, {95, 181, 238, 148}, {95, 181, 238, 152}, {95, 181, 238, 153}, {95, 181, 238, 155}}},
{Region: "Bahamas", Group: "Premium UDP USA", Hostname: "94-1-bs.cg-dialup.net", IPs: []net.IP{{95, 181, 238, 131}, {95, 181, 238, 138}, {95, 181, 238, 140}, {95, 181, 238, 141}, {95, 181, 238, 146}, {95, 181, 238, 147}, {95, 181, 238, 148}, {95, 181, 238, 151}, {95, 181, 238, 153}, {95, 181, 238, 155}}},
{Region: "Bangladesh", Group: "Premium TCP Asia", Hostname: "96-1-bd.cg-dialup.net", IPs: []net.IP{{84, 252, 93, 132}, {84, 252, 93, 133}, {84, 252, 93, 135}, {84, 252, 93, 138}, {84, 252, 93, 139}, {84, 252, 93, 141}, {84, 252, 93, 142}, {84, 252, 93, 143}, {84, 252, 93, 144}, {84, 252, 93, 145}}},
{Region: "Bangladesh", Group: "Premium UDP Asia", Hostname: "95-1-bd.cg-dialup.net", IPs: []net.IP{{84, 252, 93, 131}, {84, 252, 93, 133}, {84, 252, 93, 134}, {84, 252, 93, 135}, {84, 252, 93, 136}, {84, 252, 93, 139}, {84, 252, 93, 140}, {84, 252, 93, 141}, {84, 252, 93, 143}, {84, 252, 93, 145}}},
{Region: "Belarus", Group: "Premium TCP Europe", Hostname: "97-1-by.cg-dialup.net", IPs: []net.IP{{45, 132, 194, 5}, {45, 132, 194, 6}, {45, 132, 194, 23}, {45, 132, 194, 24}, {45, 132, 194, 25}, {45, 132, 194, 27}, {45, 132, 194, 30}, {45, 132, 194, 35}, {45, 132, 194, 44}, {45, 132, 194, 49}}},
{Region: "Belarus", Group: "Premium UDP Europe", Hostname: "87-1-by.cg-dialup.net", IPs: []net.IP{{45, 132, 194, 6}, {45, 132, 194, 8}, {45, 132, 194, 9}, {45, 132, 194, 11}, {45, 132, 194, 15}, {45, 132, 194, 19}, {45, 132, 194, 20}, {45, 132, 194, 23}, {45, 132, 194, 24}, {45, 132, 194, 26}}},
{Region: "Belgium", Group: "Premium TCP Europe", Hostname: "97-1-be.cg-dialup.net", IPs: []net.IP{{37, 120, 143, 165}, {37, 120, 143, 166}, {185, 210, 217, 10}, {185, 210, 217, 248}, {193, 9, 114, 211}, {193, 9, 114, 220}, {194, 110, 115, 195}, {194, 110, 115, 199}, {194, 110, 115, 205}, {194, 110, 115, 238}}},
{Region: "Belgium", Group: "Premium UDP Europe", Hostname: "87-1-be.cg-dialup.net", IPs: []net.IP{{37, 120, 143, 163}, {37, 120, 143, 167}, {185, 210, 217, 9}, {185, 210, 217, 13}, {185, 210, 217, 55}, {185, 210, 217, 251}, {185, 232, 21, 120}, {194, 110, 115, 214}, {194, 110, 115, 218}, {194, 110, 115, 236}}},
{Region: "Bosnia and Herzegovina", Group: "Premium TCP Europe", Hostname: "97-1-ba.cg-dialup.net", IPs: []net.IP{{185, 99, 3, 57}, {185, 99, 3, 58}, {185, 99, 3, 72}, {185, 99, 3, 73}, {185, 99, 3, 74}, {185, 99, 3, 130}, {185, 99, 3, 131}, {185, 99, 3, 134}, {185, 99, 3, 135}, {185, 99, 3, 136}}}, {Region: "Bosnia and Herzegovina", Group: "Premium TCP Europe", Hostname: "97-1-ba.cg-dialup.net", IPs: []net.IP{{185, 99, 3, 57}, {185, 99, 3, 58}, {185, 99, 3, 72}, {185, 99, 3, 73}, {185, 99, 3, 74}, {185, 99, 3, 130}, {185, 99, 3, 131}, {185, 99, 3, 134}, {185, 99, 3, 135}, {185, 99, 3, 136}}},
{Region: "Bosnia and Herzegovina", Group: "Premium UDP Europe", Hostname: "87-1-ba.cg-dialup.net", IPs: []net.IP{{185, 99, 3, 57}, {185, 99, 3, 58}, {185, 99, 3, 72}, {185, 99, 3, 73}, {185, 99, 3, 74}, {185, 99, 3, 130}, {185, 99, 3, 131}, {185, 99, 3, 134}, {185, 99, 3, 135}, {185, 99, 3, 136}}}, {Region: "Bosnia and Herzegovina", Group: "Premium UDP Europe", Hostname: "87-1-ba.cg-dialup.net", IPs: []net.IP{{185, 99, 3, 57}, {185, 99, 3, 58}, {185, 99, 3, 72}, {185, 99, 3, 73}, {185, 99, 3, 74}, {185, 99, 3, 130}, {185, 99, 3, 131}, {185, 99, 3, 134}, {185, 99, 3, 135}, {185, 99, 3, 136}}},
{Region: "Brazil", Group: "Premium UDP USA", Hostname: "94-1-br.cg-dialup.net", IPs: []net.IP{{188, 241, 177, 11}, {188, 241, 177, 13}, {188, 241, 177, 19}, {188, 241, 177, 20}, {188, 241, 177, 21}, {188, 241, 177, 29}, {188, 241, 177, 30}, {188, 241, 177, 46}, {188, 241, 177, 147}, {188, 241, 177, 156}}}, {Region: "Brazil", Group: "Premium TCP USA", Hostname: "93-1-br.cg-dialup.net", IPs: []net.IP{{188, 241, 177, 5}, {188, 241, 177, 11}, {188, 241, 177, 38}, {188, 241, 177, 45}, {188, 241, 177, 132}, {188, 241, 177, 135}, {188, 241, 177, 136}, {188, 241, 177, 152}, {188, 241, 177, 153}, {188, 241, 177, 156}}},
{Region: "Bulgaria", Group: "Premium TCP Europe", Hostname: "97-1-bg.cg-dialup.net", IPs: []net.IP{{37, 120, 152, 99}, {37, 120, 152, 100}, {37, 120, 152, 101}, {37, 120, 152, 102}, {37, 120, 152, 104}, {37, 120, 152, 105}, {37, 120, 152, 106}, {37, 120, 152, 108}, {37, 120, 152, 109}, {37, 120, 152, 110}}}, {Region: "Brazil", Group: "Premium UDP USA", Hostname: "94-1-br.cg-dialup.net", IPs: []net.IP{{188, 241, 177, 8}, {188, 241, 177, 37}, {188, 241, 177, 40}, {188, 241, 177, 42}, {188, 241, 177, 45}, {188, 241, 177, 135}, {188, 241, 177, 139}, {188, 241, 177, 149}, {188, 241, 177, 152}, {188, 241, 177, 154}}},
{Region: "Bulgaria", Group: "Premium UDP Europe", Hostname: "87-1-bg.cg-dialup.net", IPs: []net.IP{{37, 120, 152, 99}, {37, 120, 152, 100}, {37, 120, 152, 101}, {37, 120, 152, 103}, {37, 120, 152, 104}, {37, 120, 152, 106}, {37, 120, 152, 107}, {37, 120, 152, 108}, {37, 120, 152, 109}, {37, 120, 152, 110}}}, {Region: "Bulgaria", Group: "Premium TCP Europe", Hostname: "97-1-bg.cg-dialup.net", IPs: []net.IP{{37, 120, 152, 99}, {37, 120, 152, 101}, {37, 120, 152, 103}, {37, 120, 152, 104}, {37, 120, 152, 105}, {37, 120, 152, 106}, {37, 120, 152, 107}, {37, 120, 152, 108}, {37, 120, 152, 109}, {37, 120, 152, 110}}},
{Region: "Cambodia", Group: "Premium TCP Asia", Hostname: "96-1-kh.cg-dialup.net", IPs: []net.IP{{188, 215, 235, 38}, {188, 215, 235, 41}, {188, 215, 235, 42}, {188, 215, 235, 47}, {188, 215, 235, 48}, {188, 215, 235, 51}, {188, 215, 235, 52}, {188, 215, 235, 54}, {188, 215, 235, 56}, {188, 215, 235, 57}}}, {Region: "Bulgaria", Group: "Premium UDP Europe", Hostname: "87-1-bg.cg-dialup.net", IPs: []net.IP{{37, 120, 152, 99}, {37, 120, 152, 100}, {37, 120, 152, 101}, {37, 120, 152, 102}, {37, 120, 152, 103}, {37, 120, 152, 105}, {37, 120, 152, 106}, {37, 120, 152, 107}, {37, 120, 152, 108}, {37, 120, 152, 109}}},
{Region: "Canada", Group: "Premium TCP USA", Hostname: "93-1-ca.cg-dialup.net", IPs: []net.IP{{104, 200, 151, 17}, {104, 200, 151, 47}, {104, 200, 151, 74}, {104, 200, 151, 89}, {104, 200, 151, 163}, {172, 98, 89, 147}, {172, 98, 89, 148}, {172, 98, 89, 164}, {172, 98, 89, 171}, {172, 98, 89, 182}}}, {Region: "Cambodia", Group: "Premium TCP Asia", Hostname: "96-1-kh.cg-dialup.net", IPs: []net.IP{{188, 215, 235, 35}, {188, 215, 235, 36}, {188, 215, 235, 38}, {188, 215, 235, 39}, {188, 215, 235, 45}, {188, 215, 235, 49}, {188, 215, 235, 51}, {188, 215, 235, 53}, {188, 215, 235, 54}, {188, 215, 235, 57}}},
{Region: "Canada", Group: "Premium UDP USA", Hostname: "94-1-ca.cg-dialup.net", IPs: []net.IP{{66, 115, 142, 190}, {104, 200, 151, 86}, {104, 200, 151, 103}, {104, 200, 151, 127}, {104, 200, 151, 128}, {104, 200, 151, 139}, {172, 98, 89, 143}, {172, 98, 89, 150}, {172, 98, 89, 156}, {172, 98, 89, 180}}}, {Region: "Cambodia", Group: "Premium UDP Asia", Hostname: "95-1-kh.cg-dialup.net", IPs: []net.IP{{188, 215, 235, 36}, {188, 215, 235, 40}, {188, 215, 235, 42}, {188, 215, 235, 44}, {188, 215, 235, 46}, {188, 215, 235, 47}, {188, 215, 235, 48}, {188, 215, 235, 50}, {188, 215, 235, 55}, {188, 215, 235, 57}}},
{Region: "Chile", Group: "Premium TCP USA", Hostname: "93-1-cl.cg-dialup.net", IPs: []net.IP{{146, 70, 11, 3}, {146, 70, 11, 4}, {146, 70, 11, 5}, {146, 70, 11, 6}, {146, 70, 11, 8}, {146, 70, 11, 9}, {146, 70, 11, 11}, {146, 70, 11, 12}, {146, 70, 11, 13}, {146, 70, 11, 14}}}, {Region: "Canada", Group: "Premium TCP USA", Hostname: "93-1-ca.cg-dialup.net", IPs: []net.IP{{66, 115, 142, 136}, {66, 115, 142, 139}, {66, 115, 142, 156}, {66, 115, 142, 162}, {66, 115, 142, 172}, {104, 200, 151, 99}, {104, 200, 151, 111}, {104, 200, 151, 153}, {104, 200, 151, 164}, {172, 98, 89, 137}}},
{Region: "Chile", Group: "Premium UDP USA", Hostname: "94-1-cl.cg-dialup.net", IPs: []net.IP{{146, 70, 11, 3}, {146, 70, 11, 4}, {146, 70, 11, 7}, {146, 70, 11, 8}, {146, 70, 11, 9}, {146, 70, 11, 10}, {146, 70, 11, 11}, {146, 70, 11, 12}, {146, 70, 11, 13}, {146, 70, 11, 14}}}, {Region: "Canada", Group: "Premium UDP USA", Hostname: "94-1-ca.cg-dialup.net", IPs: []net.IP{{66, 115, 142, 135}, {66, 115, 142, 154}, {66, 115, 142, 165}, {104, 200, 151, 32}, {104, 200, 151, 57}, {104, 200, 151, 85}, {104, 200, 151, 86}, {104, 200, 151, 147}, {172, 98, 89, 144}, {172, 98, 89, 173}}},
{Region: "China", Group: "Premium TCP Asia", Hostname: "96-1-cn.cg-dialup.net", IPs: []net.IP{{188, 241, 80, 131}, {188, 241, 80, 132}, {188, 241, 80, 133}, {188, 241, 80, 134}, {188, 241, 80, 135}, {188, 241, 80, 136}, {188, 241, 80, 137}, {188, 241, 80, 138}, {188, 241, 80, 140}, {188, 241, 80, 141}}}, {Region: "Chile", Group: "Premium TCP USA", Hostname: "93-1-cl.cg-dialup.net", IPs: []net.IP{{146, 70, 11, 3}, {146, 70, 11, 6}, {146, 70, 11, 7}, {146, 70, 11, 8}, {146, 70, 11, 9}, {146, 70, 11, 10}, {146, 70, 11, 11}, {146, 70, 11, 12}, {146, 70, 11, 13}, {146, 70, 11, 14}}},
{Region: "Colombia", Group: "Premium UDP USA", Hostname: "94-1-co.cg-dialup.net", IPs: []net.IP{{146, 70, 9, 3}, {146, 70, 9, 4}, {146, 70, 9, 5}, {146, 70, 9, 6}, {146, 70, 9, 7}, {146, 70, 9, 8}, {146, 70, 9, 9}, {146, 70, 9, 10}, {146, 70, 9, 11}, {146, 70, 9, 14}}}, {Region: "Chile", Group: "Premium UDP USA", Hostname: "94-1-cl.cg-dialup.net", IPs: []net.IP{{146, 70, 11, 3}, {146, 70, 11, 4}, {146, 70, 11, 6}, {146, 70, 11, 7}, {146, 70, 11, 8}, {146, 70, 11, 9}, {146, 70, 11, 10}, {146, 70, 11, 11}, {146, 70, 11, 13}, {146, 70, 11, 14}}},
{Region: "Costa Rica", Group: "Premium TCP USA", Hostname: "93-1-cr.cg-dialup.net", IPs: []net.IP{{146, 70, 10, 3}, {146, 70, 10, 4}, {146, 70, 10, 5}, {146, 70, 10, 6}, {146, 70, 10, 7}, {146, 70, 10, 8}, {146, 70, 10, 9}, {146, 70, 10, 11}, {146, 70, 10, 12}, {146, 70, 10, 14}}}, {Region: "China", Group: "Premium TCP Asia", Hostname: "96-1-cn.cg-dialup.net", IPs: []net.IP{{188, 241, 80, 131}, {188, 241, 80, 132}, {188, 241, 80, 133}, {188, 241, 80, 134}, {188, 241, 80, 135}, {188, 241, 80, 137}, {188, 241, 80, 139}, {188, 241, 80, 140}, {188, 241, 80, 141}, {188, 241, 80, 142}}},
{Region: "Costa Rica", Group: "Premium UDP USA", Hostname: "94-1-cr.cg-dialup.net", IPs: []net.IP{{146, 70, 10, 3}, {146, 70, 10, 4}, {146, 70, 10, 5}, {146, 70, 10, 7}, {146, 70, 10, 8}, {146, 70, 10, 9}, {146, 70, 10, 11}, {146, 70, 10, 12}, {146, 70, 10, 13}, {146, 70, 10, 14}}}, {Region: "China", Group: "Premium UDP Asia", Hostname: "95-1-cn.cg-dialup.net", IPs: []net.IP{{188, 241, 80, 131}, {188, 241, 80, 132}, {188, 241, 80, 133}, {188, 241, 80, 134}, {188, 241, 80, 135}, {188, 241, 80, 136}, {188, 241, 80, 137}, {188, 241, 80, 138}, {188, 241, 80, 139}, {188, 241, 80, 142}}},
{Region: "Croatia", Group: "Premium TCP Europe", Hostname: "97-1-hr.cg-dialup.net", IPs: []net.IP{{146, 70, 8, 3}, {146, 70, 8, 4}, {146, 70, 8, 5}, {146, 70, 8, 7}, {146, 70, 8, 8}, {146, 70, 8, 11}, {146, 70, 8, 12}, {146, 70, 8, 13}, {146, 70, 8, 14}, {146, 70, 8, 16}}}, {Region: "Colombia", Group: "Premium TCP USA", Hostname: "93-1-co.cg-dialup.net", IPs: []net.IP{{146, 70, 9, 3}, {146, 70, 9, 4}, {146, 70, 9, 5}, {146, 70, 9, 7}, {146, 70, 9, 9}, {146, 70, 9, 10}, {146, 70, 9, 11}, {146, 70, 9, 12}, {146, 70, 9, 13}, {146, 70, 9, 14}}},
{Region: "Croatia", Group: "Premium UDP Europe", Hostname: "87-1-hr.cg-dialup.net", IPs: []net.IP{{146, 70, 8, 3}, {146, 70, 8, 4}, {146, 70, 8, 5}, {146, 70, 8, 6}, {146, 70, 8, 8}, {146, 70, 8, 10}, {146, 70, 8, 11}, {146, 70, 8, 12}, {146, 70, 8, 15}, {146, 70, 8, 16}}}, {Region: "Colombia", Group: "Premium UDP USA", Hostname: "94-1-co.cg-dialup.net", IPs: []net.IP{{146, 70, 9, 3}, {146, 70, 9, 4}, {146, 70, 9, 5}, {146, 70, 9, 6}, {146, 70, 9, 7}, {146, 70, 9, 8}, {146, 70, 9, 9}, {146, 70, 9, 10}, {146, 70, 9, 11}, {146, 70, 9, 12}}},
{Region: "Cyprus", Group: "Premium TCP Europe", Hostname: "97-1-cy.cg-dialup.net", IPs: []net.IP{{185, 253, 162, 131}, {185, 253, 162, 132}, {185, 253, 162, 133}, {185, 253, 162, 134}, {185, 253, 162, 135}, {185, 253, 162, 137}, {185, 253, 162, 141}, {185, 253, 162, 142}, {185, 253, 162, 143}, {185, 253, 162, 144}}}, {Region: "Costa Rica", Group: "Premium TCP USA", Hostname: "93-1-cr.cg-dialup.net", IPs: []net.IP{{146, 70, 10, 3}, {146, 70, 10, 4}, {146, 70, 10, 5}, {146, 70, 10, 6}, {146, 70, 10, 7}, {146, 70, 10, 8}, {146, 70, 10, 10}, {146, 70, 10, 11}, {146, 70, 10, 12}, {146, 70, 10, 13}}},
{Region: "Cyprus", Group: "Premium UDP Europe", Hostname: "87-1-cy.cg-dialup.net", IPs: []net.IP{{185, 253, 162, 131}, {185, 253, 162, 132}, {185, 253, 162, 133}, {185, 253, 162, 134}, {185, 253, 162, 135}, {185, 253, 162, 137}, {185, 253, 162, 138}, {185, 253, 162, 139}, {185, 253, 162, 141}, {185, 253, 162, 143}}}, {Region: "Costa Rica", Group: "Premium UDP USA", Hostname: "94-1-cr.cg-dialup.net", IPs: []net.IP{{146, 70, 10, 3}, {146, 70, 10, 4}, {146, 70, 10, 5}, {146, 70, 10, 6}, {146, 70, 10, 7}, {146, 70, 10, 8}, {146, 70, 10, 9}, {146, 70, 10, 11}, {146, 70, 10, 12}, {146, 70, 10, 14}}},
{Region: "Czech Republic", Group: "Premium UDP Europe", Hostname: "87-1-cz.cg-dialup.net", IPs: []net.IP{{195, 181, 161, 3}, {195, 181, 161, 4}, {195, 181, 161, 7}, {195, 181, 161, 9}, {195, 181, 161, 11}, {195, 181, 161, 19}, {195, 181, 161, 20}, {195, 181, 161, 21}, {195, 181, 161, 22}, {195, 181, 161, 24}}}, {Region: "Croatia", Group: "Premium TCP Europe", Hostname: "97-1-hr.cg-dialup.net", IPs: []net.IP{{146, 70, 8, 5}, {146, 70, 8, 8}, {146, 70, 8, 9}, {146, 70, 8, 10}, {146, 70, 8, 11}, {146, 70, 8, 12}, {146, 70, 8, 13}, {146, 70, 8, 14}, {146, 70, 8, 15}, {146, 70, 8, 16}}},
{Region: "Denmark", Group: "Premium TCP Europe", Hostname: "97-1-dk.cg-dialup.net", IPs: []net.IP{{37, 120, 145, 89}, {37, 120, 145, 90}, {37, 120, 194, 42}, {37, 120, 194, 45}, {37, 120, 194, 55}, {95, 174, 65, 163}, {95, 174, 65, 166}, {185, 206, 224, 229}, {185, 206, 224, 234}, {185, 206, 224, 254}}}, {Region: "Croatia", Group: "Premium UDP Europe", Hostname: "87-1-hr.cg-dialup.net", IPs: []net.IP{{146, 70, 8, 3}, {146, 70, 8, 4}, {146, 70, 8, 5}, {146, 70, 8, 6}, {146, 70, 8, 7}, {146, 70, 8, 9}, {146, 70, 8, 11}, {146, 70, 8, 13}, {146, 70, 8, 14}, {146, 70, 8, 16}}},
{Region: "Egypt", Group: "Premium TCP Europe", Hostname: "97-1-eg.cg-dialup.net", IPs: []net.IP{{188, 214, 122, 35}, {188, 214, 122, 42}, {188, 214, 122, 48}, {188, 214, 122, 49}, {188, 214, 122, 58}, {188, 214, 122, 61}, {188, 214, 122, 62}, {188, 214, 122, 68}, {188, 214, 122, 73}, {188, 214, 122, 76}}}, {Region: "Cyprus", Group: "Premium TCP Europe", Hostname: "97-1-cy.cg-dialup.net", IPs: []net.IP{{185, 253, 162, 131}, {185, 253, 162, 133}, {185, 253, 162, 135}, {185, 253, 162, 136}, {185, 253, 162, 137}, {185, 253, 162, 139}, {185, 253, 162, 140}, {185, 253, 162, 142}, {185, 253, 162, 143}, {185, 253, 162, 144}}},
{Region: "Egypt", Group: "Premium UDP Europe", Hostname: "87-1-eg.cg-dialup.net", IPs: []net.IP{{188, 214, 122, 35}, {188, 214, 122, 36}, {188, 214, 122, 42}, {188, 214, 122, 47}, {188, 214, 122, 51}, {188, 214, 122, 52}, {188, 214, 122, 58}, {188, 214, 122, 62}, {188, 214, 122, 69}, {188, 214, 122, 78}}}, {Region: "Cyprus", Group: "Premium UDP Europe", Hostname: "87-1-cy.cg-dialup.net", IPs: []net.IP{{185, 253, 162, 131}, {185, 253, 162, 132}, {185, 253, 162, 134}, {185, 253, 162, 135}, {185, 253, 162, 137}, {185, 253, 162, 138}, {185, 253, 162, 140}, {185, 253, 162, 142}, {185, 253, 162, 143}, {185, 253, 162, 144}}},
{Region: "Estonia", Group: "Premium TCP Europe", Hostname: "97-1-ee.cg-dialup.net", IPs: []net.IP{{95, 153, 32, 83}, {95, 153, 32, 84}, {95, 153, 32, 86}, {95, 153, 32, 87}, {95, 153, 32, 88}, {95, 153, 32, 89}, {95, 153, 32, 90}, {95, 153, 32, 91}, {95, 153, 32, 92}, {95, 153, 32, 94}}}, {Region: "Czech Republic", Group: "Premium TCP Europe", Hostname: "97-1-cz.cg-dialup.net", IPs: []net.IP{{138, 199, 56, 235}, {138, 199, 56, 236}, {138, 199, 56, 237}, {138, 199, 56, 245}, {138, 199, 56, 246}, {138, 199, 56, 249}, {195, 181, 161, 12}, {195, 181, 161, 16}, {195, 181, 161, 20}, {195, 181, 161, 23}}},
{Region: "Finland", Group: "Premium UDP Europe", Hostname: "87-1-fi.cg-dialup.net", IPs: []net.IP{{188, 126, 89, 102}, {188, 126, 89, 107}, {188, 126, 89, 108}, {188, 126, 89, 109}, {188, 126, 89, 114}, {188, 126, 89, 125}, {188, 126, 89, 136}, {188, 126, 89, 147}, {188, 126, 89, 153}, {188, 126, 89, 156}}}, {Region: "Czech Republic", Group: "Premium UDP Europe", Hostname: "87-1-cz.cg-dialup.net", IPs: []net.IP{{138, 199, 56, 227}, {138, 199, 56, 229}, {138, 199, 56, 231}, {138, 199, 56, 235}, {138, 199, 56, 241}, {138, 199, 56, 247}, {195, 181, 161, 10}, {195, 181, 161, 16}, {195, 181, 161, 18}, {195, 181, 161, 22}}},
{Region: "France", Group: "Premium TCP Europe", Hostname: "97-1-fr.cg-dialup.net", IPs: []net.IP{{84, 17, 60, 53}, {84, 17, 60, 55}, {84, 17, 60, 83}, {151, 106, 8, 41}, {151, 106, 11, 189}, {191, 101, 31, 156}, {191, 101, 31, 223}, {191, 101, 217, 61}, {191, 101, 217, 94}, {191, 101, 217, 209}}}, {Region: "Denmark", Group: "Premium TCP Europe", Hostname: "97-1-dk.cg-dialup.net", IPs: []net.IP{{37, 120, 145, 83}, {37, 120, 145, 88}, {37, 120, 145, 93}, {37, 120, 194, 36}, {37, 120, 194, 56}, {37, 120, 194, 57}, {95, 174, 65, 163}, {95, 174, 65, 174}, {185, 206, 224, 238}, {185, 206, 224, 243}}},
{Region: "France", Group: "Premium UDP Europe", Hostname: "87-1-fr.cg-dialup.net", IPs: []net.IP{{84, 17, 60, 102}, {92, 204, 174, 92}, {151, 106, 10, 132}, {191, 101, 31, 121}, {191, 101, 31, 167}, {191, 101, 31, 175}, {191, 101, 31, 196}, {191, 101, 217, 86}, {191, 101, 217, 87}, {191, 101, 217, 100}}}, {Region: "Denmark", Group: "Premium UDP Europe", Hostname: "87-1-dk.cg-dialup.net", IPs: []net.IP{{37, 120, 194, 39}, {95, 174, 65, 167}, {95, 174, 65, 170}, {185, 206, 224, 227}, {185, 206, 224, 230}, {185, 206, 224, 236}, {185, 206, 224, 238}, {185, 206, 224, 245}, {185, 206, 224, 250}, {185, 206, 224, 254}}},
{Region: "Georgia", Group: "Premium UDP Europe", Hostname: "87-1-ge.cg-dialup.net", IPs: []net.IP{{95, 181, 236, 132}, {95, 181, 236, 134}, {95, 181, 236, 135}, {95, 181, 236, 136}, {95, 181, 236, 137}, {95, 181, 236, 138}, {95, 181, 236, 140}, {95, 181, 236, 141}, {95, 181, 236, 142}, {95, 181, 236, 143}}}, {Region: "Egypt", Group: "Premium TCP Europe", Hostname: "97-1-eg.cg-dialup.net", IPs: []net.IP{{188, 214, 122, 40}, {188, 214, 122, 42}, {188, 214, 122, 43}, {188, 214, 122, 45}, {188, 214, 122, 48}, {188, 214, 122, 50}, {188, 214, 122, 52}, {188, 214, 122, 60}, {188, 214, 122, 70}, {188, 214, 122, 73}}},
{Region: "Germany", Group: "Premium TCP Europe", Hostname: "97-1-de.cg-dialup.net", IPs: []net.IP{{84, 17, 48, 110}, {84, 17, 48, 133}, {84, 17, 48, 190}, {84, 17, 49, 84}, {84, 17, 49, 143}, {84, 17, 49, 205}, {154, 13, 1, 175}, {154, 28, 188, 51}, {154, 28, 188, 71}, {154, 28, 188, 80}}}, {Region: "Egypt", Group: "Premium UDP Europe", Hostname: "87-1-eg.cg-dialup.net", IPs: []net.IP{{188, 214, 122, 37}, {188, 214, 122, 38}, {188, 214, 122, 44}, {188, 214, 122, 54}, {188, 214, 122, 57}, {188, 214, 122, 59}, {188, 214, 122, 60}, {188, 214, 122, 61}, {188, 214, 122, 67}, {188, 214, 122, 69}}},
{Region: "Germany", Group: "Premium UDP Europe", Hostname: "87-1-de.cg-dialup.net", IPs: []net.IP{{84, 17, 48, 35}, {84, 17, 48, 168}, {84, 17, 49, 2}, {84, 17, 49, 6}, {84, 17, 49, 19}, {84, 17, 49, 186}, {89, 163, 151, 73}, {154, 13, 1, 176}, {154, 28, 188, 79}, {154, 28, 188, 96}}}, {Region: "Estonia", Group: "Premium TCP Europe", Hostname: "97-1-ee.cg-dialup.net", IPs: []net.IP{{95, 153, 32, 83}, {95, 153, 32, 84}, {95, 153, 32, 86}, {95, 153, 32, 88}, {95, 153, 32, 89}, {95, 153, 32, 90}, {95, 153, 32, 91}, {95, 153, 32, 92}, {95, 153, 32, 93}, {95, 153, 32, 94}}},
{Region: "Greece", Group: "Premium TCP Europe", Hostname: "97-1-gr.cg-dialup.net", IPs: []net.IP{{185, 51, 134, 163}, {185, 51, 134, 166}, {185, 51, 134, 171}, {185, 51, 134, 243}, {185, 51, 134, 246}, {185, 51, 134, 247}, {185, 51, 134, 249}, {185, 51, 134, 251}, {185, 51, 134, 252}, {185, 51, 134, 253}}}, {Region: "Estonia", Group: "Premium UDP Europe", Hostname: "87-1-ee.cg-dialup.net", IPs: []net.IP{{95, 153, 32, 83}, {95, 153, 32, 84}, {95, 153, 32, 85}, {95, 153, 32, 87}, {95, 153, 32, 88}, {95, 153, 32, 89}, {95, 153, 32, 90}, {95, 153, 32, 91}, {95, 153, 32, 92}, {95, 153, 32, 94}}},
{Region: "Greece", Group: "Premium UDP Europe", Hostname: "87-1-gr.cg-dialup.net", IPs: []net.IP{{185, 51, 134, 165}, {185, 51, 134, 166}, {185, 51, 134, 168}, {185, 51, 134, 169}, {185, 51, 134, 174}, {185, 51, 134, 246}, {185, 51, 134, 250}, {185, 51, 134, 251}, {185, 51, 134, 252}, {185, 51, 134, 254}}}, {Region: "Finland", Group: "Premium TCP Europe", Hostname: "97-1-fi.cg-dialup.net", IPs: []net.IP{{188, 126, 89, 99}, {188, 126, 89, 102}, {188, 126, 89, 105}, {188, 126, 89, 107}, {188, 126, 89, 108}, {188, 126, 89, 110}, {188, 126, 89, 112}, {188, 126, 89, 115}, {188, 126, 89, 116}, {188, 126, 89, 119}}},
{Region: "Greenland", Group: "Premium TCP Europe", Hostname: "97-1-gl.cg-dialup.net", IPs: []net.IP{{91, 90, 120, 3}, {91, 90, 120, 4}, {91, 90, 120, 5}, {91, 90, 120, 6}, {91, 90, 120, 8}, {91, 90, 120, 10}, {91, 90, 120, 11}, {91, 90, 120, 12}, {91, 90, 120, 14}, {91, 90, 120, 15}}}, {Region: "Finland", Group: "Premium UDP Europe", Hostname: "87-1-fi.cg-dialup.net", IPs: []net.IP{{188, 126, 89, 101}, {188, 126, 89, 104}, {188, 126, 89, 109}, {188, 126, 89, 110}, {188, 126, 89, 111}, {188, 126, 89, 113}, {188, 126, 89, 114}, {188, 126, 89, 115}, {188, 126, 89, 122}, {188, 126, 89, 124}}},
{Region: "Greenland", Group: "Premium UDP Europe", Hostname: "87-1-gl.cg-dialup.net", IPs: []net.IP{{91, 90, 120, 3}, {91, 90, 120, 4}, {91, 90, 120, 6}, {91, 90, 120, 7}, {91, 90, 120, 9}, {91, 90, 120, 10}, {91, 90, 120, 12}, {91, 90, 120, 13}, {91, 90, 120, 16}, {91, 90, 120, 17}}}, {Region: "France", Group: "Premium TCP Europe", Hostname: "97-1-fr.cg-dialup.net", IPs: []net.IP{{84, 17, 43, 167}, {84, 17, 60, 147}, {84, 17, 60, 155}, {151, 106, 8, 108}, {191, 101, 31, 202}, {191, 101, 31, 254}, {191, 101, 217, 45}, {191, 101, 217, 159}, {191, 101, 217, 211}, {191, 101, 217, 240}}},
{Region: "Hong Kong", Group: "Premium TCP Asia", Hostname: "96-1-hk.cg-dialup.net", IPs: []net.IP{{84, 17, 56, 132}, {84, 17, 56, 134}, {84, 17, 56, 135}, {84, 17, 56, 139}, {84, 17, 56, 143}, {84, 17, 56, 162}, {84, 17, 56, 164}, {84, 17, 56, 174}, {84, 17, 56, 182}, {84, 17, 56, 183}}}, {Region: "France", Group: "Premium UDP Europe", Hostname: "87-1-fr.cg-dialup.net", IPs: []net.IP{{84, 17, 60, 59}, {84, 17, 60, 121}, {191, 101, 31, 81}, {191, 101, 31, 84}, {191, 101, 31, 126}, {191, 101, 31, 127}, {191, 101, 217, 140}, {191, 101, 217, 201}, {191, 101, 217, 206}, {191, 101, 217, 211}}},
{Region: "Hungary", Group: "Premium TCP Europe", Hostname: "97-1-hu.cg-dialup.net", IPs: []net.IP{{86, 106, 74, 243}, {86, 106, 74, 244}, {86, 106, 74, 246}, {86, 106, 74, 247}, {86, 106, 74, 249}, {185, 189, 114, 115}, {185, 189, 114, 120}, {185, 189, 114, 122}, {185, 189, 114, 123}, {185, 189, 114, 126}}}, {Region: "Georgia", Group: "Premium TCP Europe", Hostname: "97-1-ge.cg-dialup.net", IPs: []net.IP{{95, 181, 236, 131}, {95, 181, 236, 132}, {95, 181, 236, 133}, {95, 181, 236, 134}, {95, 181, 236, 135}, {95, 181, 236, 136}, {95, 181, 236, 138}, {95, 181, 236, 139}, {95, 181, 236, 142}, {95, 181, 236, 144}}},
{Region: "Hungary", Group: "Premium UDP Europe", Hostname: "87-1-hu.cg-dialup.net", IPs: []net.IP{{86, 106, 74, 243}, {86, 106, 74, 244}, {86, 106, 74, 247}, {86, 106, 74, 250}, {86, 106, 74, 251}, {86, 106, 74, 253}, {185, 189, 114, 117}, {185, 189, 114, 120}, {185, 189, 114, 124}, {185, 189, 114, 126}}}, {Region: "Georgia", Group: "Premium UDP Europe", Hostname: "87-1-ge.cg-dialup.net", IPs: []net.IP{{95, 181, 236, 132}, {95, 181, 236, 133}, {95, 181, 236, 134}, {95, 181, 236, 136}, {95, 181, 236, 137}, {95, 181, 236, 139}, {95, 181, 236, 141}, {95, 181, 236, 142}, {95, 181, 236, 143}, {95, 181, 236, 144}}},
{Region: "Iceland", Group: "Premium TCP Europe", Hostname: "97-1-is.cg-dialup.net", IPs: []net.IP{{45, 133, 193, 3}, {45, 133, 193, 5}, {45, 133, 193, 6}, {45, 133, 193, 7}, {45, 133, 193, 9}, {45, 133, 193, 10}, {45, 133, 193, 11}, {45, 133, 193, 12}, {45, 133, 193, 13}, {45, 133, 193, 14}}}, {Region: "Germany", Group: "Premium TCP Europe", Hostname: "97-1-de.cg-dialup.net", IPs: []net.IP{{84, 17, 48, 39}, {84, 17, 48, 234}, {84, 17, 49, 106}, {84, 17, 49, 112}, {84, 17, 49, 218}, {154, 28, 188, 35}, {154, 28, 188, 66}, {154, 28, 188, 133}, {154, 28, 188, 144}, {154, 28, 188, 145}}},
{Region: "India", Group: "Premium TCP Europe", Hostname: "97-1-in.cg-dialup.net", IPs: []net.IP{{103, 13, 112, 50}, {103, 13, 112, 52}, {103, 13, 112, 59}, {103, 13, 112, 61}, {103, 13, 112, 67}, {103, 13, 112, 68}, {103, 13, 112, 74}, {103, 13, 112, 78}, {103, 13, 112, 80}, {103, 13, 112, 81}}}, {Region: "Germany", Group: "Premium UDP Europe", Hostname: "87-1-de.cg-dialup.net", IPs: []net.IP{{84, 17, 48, 41}, {84, 17, 48, 224}, {84, 17, 49, 95}, {84, 17, 49, 236}, {84, 17, 49, 241}, {138, 199, 36, 151}, {154, 13, 1, 177}, {154, 28, 188, 73}, {154, 28, 188, 76}, {154, 28, 188, 93}}},
{Region: "India", Group: "Premium UDP Europe", Hostname: "87-1-in.cg-dialup.net", IPs: []net.IP{{103, 13, 112, 50}, {103, 13, 112, 51}, {103, 13, 112, 52}, {103, 13, 112, 54}, {103, 13, 112, 59}, {103, 13, 112, 60}, {103, 13, 112, 66}, {103, 13, 112, 67}, {103, 13, 112, 71}, {103, 13, 112, 79}}}, {Region: "Greece", Group: "Premium TCP Europe", Hostname: "97-1-gr.cg-dialup.net", IPs: []net.IP{{185, 51, 134, 163}, {185, 51, 134, 165}, {185, 51, 134, 171}, {185, 51, 134, 172}, {185, 51, 134, 245}, {185, 51, 134, 246}, {185, 51, 134, 247}, {185, 51, 134, 249}, {185, 51, 134, 251}, {185, 51, 134, 254}}},
{Region: "Indonesia", Group: "Premium TCP Asia", Hostname: "96-1-id.cg-dialup.net", IPs: []net.IP{{146, 70, 14, 3}, {146, 70, 14, 5}, {146, 70, 14, 7}, {146, 70, 14, 9}, {146, 70, 14, 10}, {146, 70, 14, 11}, {146, 70, 14, 12}, {146, 70, 14, 13}, {146, 70, 14, 15}, {146, 70, 14, 16}}}, {Region: "Greece", Group: "Premium UDP Europe", Hostname: "87-1-gr.cg-dialup.net", IPs: []net.IP{{185, 51, 134, 163}, {185, 51, 134, 166}, {185, 51, 134, 173}, {185, 51, 134, 174}, {185, 51, 134, 244}, {185, 51, 134, 246}, {185, 51, 134, 247}, {185, 51, 134, 251}, {185, 51, 134, 252}, {185, 51, 134, 253}}},
{Region: "Indonesia", Group: "Premium UDP Asia", Hostname: "95-1-id.cg-dialup.net", IPs: []net.IP{{146, 70, 14, 3}, {146, 70, 14, 5}, {146, 70, 14, 7}, {146, 70, 14, 10}, {146, 70, 14, 11}, {146, 70, 14, 12}, {146, 70, 14, 13}, {146, 70, 14, 14}, {146, 70, 14, 15}, {146, 70, 14, 16}}}, {Region: "Greenland", Group: "Premium TCP Europe", Hostname: "97-1-gl.cg-dialup.net", IPs: []net.IP{{91, 90, 120, 3}, {91, 90, 120, 4}, {91, 90, 120, 5}, {91, 90, 120, 7}, {91, 90, 120, 8}, {91, 90, 120, 10}, {91, 90, 120, 12}, {91, 90, 120, 13}, {91, 90, 120, 14}, {91, 90, 120, 17}}},
{Region: "Iran", Group: "Premium TCP Asia", Hostname: "96-1-ir.cg-dialup.net", IPs: []net.IP{{62, 133, 46, 3}, {62, 133, 46, 4}, {62, 133, 46, 5}, {62, 133, 46, 7}, {62, 133, 46, 8}, {62, 133, 46, 9}, {62, 133, 46, 10}, {62, 133, 46, 12}, {62, 133, 46, 14}, {62, 133, 46, 16}}}, {Region: "Greenland", Group: "Premium UDP Europe", Hostname: "87-1-gl.cg-dialup.net", IPs: []net.IP{{91, 90, 120, 3}, {91, 90, 120, 4}, {91, 90, 120, 5}, {91, 90, 120, 7}, {91, 90, 120, 9}, {91, 90, 120, 10}, {91, 90, 120, 12}, {91, 90, 120, 14}, {91, 90, 120, 15}, {91, 90, 120, 16}}},
{Region: "Ireland", Group: "Premium UDP Europe", Hostname: "87-1-ie.cg-dialup.net", IPs: []net.IP{{37, 120, 235, 147}, {37, 120, 235, 158}, {37, 120, 235, 165}, {37, 120, 235, 166}, {84, 247, 48, 5}, {84, 247, 48, 6}, {84, 247, 48, 9}, {84, 247, 48, 23}, {84, 247, 48, 27}, {84, 247, 48, 29}}}, {Region: "Hong Kong", Group: "Premium TCP Asia", Hostname: "96-1-hk.cg-dialup.net", IPs: []net.IP{{84, 17, 56, 144}, {84, 17, 56, 148}, {84, 17, 56, 153}, {84, 17, 56, 162}, {84, 17, 56, 163}, {84, 17, 56, 169}, {84, 17, 56, 170}, {84, 17, 56, 179}, {84, 17, 56, 180}, {84, 17, 56, 181}}},
{Region: "Isle of Man", Group: "Premium TCP Europe", Hostname: "97-1-im.cg-dialup.net", IPs: []net.IP{{91, 90, 124, 147}, {91, 90, 124, 149}, {91, 90, 124, 150}, {91, 90, 124, 151}, {91, 90, 124, 153}, {91, 90, 124, 154}, {91, 90, 124, 155}, {91, 90, 124, 157}, {91, 90, 124, 158}, {91, 90, 124, 159}}}, {Region: "Hong Kong", Group: "Premium UDP Asia", Hostname: "95-1-hk.cg-dialup.net", IPs: []net.IP{{84, 17, 56, 143}, {84, 17, 56, 147}, {84, 17, 56, 150}, {84, 17, 56, 152}, {84, 17, 56, 161}, {84, 17, 56, 164}, {84, 17, 56, 168}, {84, 17, 56, 179}, {84, 17, 56, 180}, {84, 17, 56, 183}}},
{Region: "Isle of Man", Group: "Premium UDP Europe", Hostname: "87-1-im.cg-dialup.net", IPs: []net.IP{{91, 90, 124, 147}, {91, 90, 124, 148}, {91, 90, 124, 150}, {91, 90, 124, 151}, {91, 90, 124, 152}, {91, 90, 124, 153}, {91, 90, 124, 154}, {91, 90, 124, 156}, {91, 90, 124, 157}, {91, 90, 124, 158}}}, {Region: "Hungary", Group: "Premium TCP Europe", Hostname: "97-1-hu.cg-dialup.net", IPs: []net.IP{{86, 106, 74, 247}, {86, 106, 74, 251}, {86, 106, 74, 253}, {185, 189, 114, 117}, {185, 189, 114, 118}, {185, 189, 114, 119}, {185, 189, 114, 121}, {185, 189, 114, 123}, {185, 189, 114, 125}, {185, 189, 114, 126}}},
{Region: "Israel", Group: "Premium UDP Europe", Hostname: "87-1-il.cg-dialup.net", IPs: []net.IP{{160, 116, 0, 169}, {160, 116, 0, 170}, {160, 116, 0, 171}, {160, 116, 0, 172}, {185, 77, 248, 114}, {185, 77, 248, 117}, {185, 77, 248, 119}, {185, 77, 248, 121}, {185, 77, 248, 123}, {185, 77, 248, 129}}}, {Region: "Hungary", Group: "Premium UDP Europe", Hostname: "87-1-hu.cg-dialup.net", IPs: []net.IP{{86, 106, 74, 245}, {86, 106, 74, 247}, {86, 106, 74, 248}, {86, 106, 74, 249}, {86, 106, 74, 250}, {86, 106, 74, 252}, {86, 106, 74, 253}, {185, 189, 114, 120}, {185, 189, 114, 121}, {185, 189, 114, 122}}},
{Region: "Italy", Group: "Premium TCP Europe", Hostname: "97-1-it.cg-dialup.net", IPs: []net.IP{{84, 17, 58, 12}, {84, 17, 58, 94}, {84, 17, 58, 96}, {84, 17, 58, 98}, {84, 17, 58, 100}, {84, 17, 58, 105}, {185, 217, 71, 132}, {212, 102, 55, 103}, {212, 102, 55, 109}, {212, 102, 55, 113}}}, {Region: "Iceland", Group: "Premium TCP Europe", Hostname: "97-1-is.cg-dialup.net", IPs: []net.IP{{45, 133, 193, 3}, {45, 133, 193, 4}, {45, 133, 193, 6}, {45, 133, 193, 7}, {45, 133, 193, 8}, {45, 133, 193, 10}, {45, 133, 193, 11}, {45, 133, 193, 12}, {45, 133, 193, 13}, {45, 133, 193, 14}}},
{Region: "Italy", Group: "Premium UDP Europe", Hostname: "87-1-it.cg-dialup.net", IPs: []net.IP{{84, 17, 58, 10}, {84, 17, 58, 20}, {84, 17, 58, 104}, {84, 17, 58, 105}, {87, 101, 94, 67}, {87, 101, 94, 120}, {87, 101, 94, 123}, {185, 217, 71, 153}, {212, 102, 55, 111}, {212, 102, 55, 122}}}, {Region: "Iceland", Group: "Premium UDP Europe", Hostname: "87-1-is.cg-dialup.net", IPs: []net.IP{{45, 133, 193, 3}, {45, 133, 193, 5}, {45, 133, 193, 6}, {45, 133, 193, 7}, {45, 133, 193, 8}, {45, 133, 193, 9}, {45, 133, 193, 10}, {45, 133, 193, 11}, {45, 133, 193, 13}, {45, 133, 193, 14}}},
{Region: "Japan", Group: "Premium UDP Asia", Hostname: "95-1-jp.cg-dialup.net", IPs: []net.IP{{156, 146, 35, 10}, {156, 146, 35, 14}, {156, 146, 35, 17}, {156, 146, 35, 18}, {156, 146, 35, 23}, {156, 146, 35, 25}, {156, 146, 35, 30}, {156, 146, 35, 44}, {156, 146, 35, 46}, {156, 146, 35, 48}}}, {Region: "India", Group: "Premium TCP Europe", Hostname: "97-1-in.cg-dialup.net", IPs: []net.IP{{103, 13, 112, 68}, {103, 13, 112, 70}, {103, 13, 112, 72}, {103, 13, 112, 74}, {103, 13, 112, 75}, {103, 13, 113, 74}, {103, 13, 113, 79}, {103, 13, 113, 82}, {103, 13, 113, 83}, {103, 13, 113, 84}}},
{Region: "Kazakhstan", Group: "Premium TCP Europe", Hostname: "97-1-kz.cg-dialup.net", IPs: []net.IP{{62, 133, 47, 131}, {62, 133, 47, 132}, {62, 133, 47, 134}, {62, 133, 47, 135}, {62, 133, 47, 136}, {62, 133, 47, 137}, {62, 133, 47, 138}, {62, 133, 47, 139}, {62, 133, 47, 140}, {62, 133, 47, 142}}}, {Region: "India", Group: "Premium UDP Europe", Hostname: "87-1-in.cg-dialup.net", IPs: []net.IP{{103, 13, 112, 67}, {103, 13, 112, 70}, {103, 13, 112, 71}, {103, 13, 112, 77}, {103, 13, 112, 80}, {103, 13, 113, 72}, {103, 13, 113, 74}, {103, 13, 113, 75}, {103, 13, 113, 77}, {103, 13, 113, 85}}},
{Region: "Kazakhstan", Group: "Premium UDP Europe", Hostname: "87-1-kz.cg-dialup.net", IPs: []net.IP{{62, 133, 47, 131}, {62, 133, 47, 132}, {62, 133, 47, 133}, {62, 133, 47, 134}, {62, 133, 47, 135}, {62, 133, 47, 137}, {62, 133, 47, 141}, {62, 133, 47, 142}, {62, 133, 47, 143}, {62, 133, 47, 144}}}, {Region: "Indonesia", Group: "Premium TCP Asia", Hostname: "96-1-id.cg-dialup.net", IPs: []net.IP{{146, 70, 14, 3}, {146, 70, 14, 4}, {146, 70, 14, 5}, {146, 70, 14, 6}, {146, 70, 14, 7}, {146, 70, 14, 10}, {146, 70, 14, 12}, {146, 70, 14, 13}, {146, 70, 14, 15}, {146, 70, 14, 16}}},
{Region: "Indonesia", Group: "Premium UDP Asia", Hostname: "95-1-id.cg-dialup.net", IPs: []net.IP{{146, 70, 14, 3}, {146, 70, 14, 5}, {146, 70, 14, 8}, {146, 70, 14, 9}, {146, 70, 14, 10}, {146, 70, 14, 12}, {146, 70, 14, 13}, {146, 70, 14, 14}, {146, 70, 14, 15}, {146, 70, 14, 16}}},
{Region: "Iran", Group: "Premium TCP Asia", Hostname: "96-1-ir.cg-dialup.net", IPs: []net.IP{{62, 133, 46, 3}, {62, 133, 46, 4}, {62, 133, 46, 5}, {62, 133, 46, 6}, {62, 133, 46, 7}, {62, 133, 46, 8}, {62, 133, 46, 9}, {62, 133, 46, 10}, {62, 133, 46, 14}, {62, 133, 46, 15}}},
{Region: "Iran", Group: "Premium UDP Asia", Hostname: "95-1-ir.cg-dialup.net", IPs: []net.IP{{62, 133, 46, 3}, {62, 133, 46, 4}, {62, 133, 46, 7}, {62, 133, 46, 8}, {62, 133, 46, 11}, {62, 133, 46, 12}, {62, 133, 46, 13}, {62, 133, 46, 14}, {62, 133, 46, 15}, {62, 133, 46, 16}}},
{Region: "Ireland", Group: "Premium TCP Europe", Hostname: "97-1-ie.cg-dialup.net", IPs: []net.IP{{37, 120, 235, 154}, {37, 120, 235, 166}, {37, 120, 235, 174}, {77, 81, 139, 35}, {84, 247, 48, 6}, {84, 247, 48, 19}, {84, 247, 48, 22}, {84, 247, 48, 23}, {84, 247, 48, 25}, {84, 247, 48, 26}}},
{Region: "Ireland", Group: "Premium UDP Europe", Hostname: "87-1-ie.cg-dialup.net", IPs: []net.IP{{37, 120, 235, 147}, {37, 120, 235, 148}, {37, 120, 235, 153}, {37, 120, 235, 158}, {37, 120, 235, 169}, {37, 120, 235, 174}, {84, 247, 48, 8}, {84, 247, 48, 11}, {84, 247, 48, 20}, {84, 247, 48, 23}}},
{Region: "Isle of Man", Group: "Premium TCP Europe", Hostname: "97-1-im.cg-dialup.net", IPs: []net.IP{{91, 90, 124, 147}, {91, 90, 124, 149}, {91, 90, 124, 150}, {91, 90, 124, 151}, {91, 90, 124, 152}, {91, 90, 124, 153}, {91, 90, 124, 154}, {91, 90, 124, 156}, {91, 90, 124, 157}, {91, 90, 124, 158}}},
{Region: "Isle of Man", Group: "Premium UDP Europe", Hostname: "87-1-im.cg-dialup.net", IPs: []net.IP{{91, 90, 124, 147}, {91, 90, 124, 149}, {91, 90, 124, 150}, {91, 90, 124, 151}, {91, 90, 124, 152}, {91, 90, 124, 153}, {91, 90, 124, 154}, {91, 90, 124, 155}, {91, 90, 124, 156}, {91, 90, 124, 157}}},
{Region: "Israel", Group: "Premium TCP Europe", Hostname: "97-1-il.cg-dialup.net", IPs: []net.IP{{160, 116, 0, 174}, {185, 77, 248, 103}, {185, 77, 248, 111}, {185, 77, 248, 113}, {185, 77, 248, 114}, {185, 77, 248, 124}, {185, 77, 248, 125}, {185, 77, 248, 127}, {185, 77, 248, 128}, {185, 77, 248, 129}}},
{Region: "Israel", Group: "Premium UDP Europe", Hostname: "87-1-il.cg-dialup.net", IPs: []net.IP{{160, 116, 0, 163}, {160, 116, 0, 165}, {160, 116, 0, 172}, {185, 77, 248, 103}, {185, 77, 248, 106}, {185, 77, 248, 114}, {185, 77, 248, 117}, {185, 77, 248, 118}, {185, 77, 248, 126}, {185, 77, 248, 129}}},
{Region: "Italy", Group: "Premium TCP Europe", Hostname: "97-1-it.cg-dialup.net", IPs: []net.IP{{84, 17, 58, 21}, {84, 17, 58, 100}, {84, 17, 58, 106}, {84, 17, 58, 111}, {84, 17, 58, 117}, {87, 101, 94, 122}, {212, 102, 55, 100}, {212, 102, 55, 106}, {212, 102, 55, 110}, {212, 102, 55, 122}}},
{Region: "Italy", Group: "Premium UDP Europe", Hostname: "87-1-it.cg-dialup.net", IPs: []net.IP{{84, 17, 58, 19}, {84, 17, 58, 95}, {84, 17, 58, 105}, {84, 17, 58, 119}, {84, 17, 58, 120}, {87, 101, 94, 116}, {185, 217, 71, 137}, {185, 217, 71, 138}, {185, 217, 71, 153}, {212, 102, 55, 108}}},
{Region: "Japan", Group: "Premium TCP Asia", Hostname: "96-1-jp.cg-dialup.net", IPs: []net.IP{{156, 146, 35, 6}, {156, 146, 35, 10}, {156, 146, 35, 15}, {156, 146, 35, 22}, {156, 146, 35, 37}, {156, 146, 35, 39}, {156, 146, 35, 40}, {156, 146, 35, 41}, {156, 146, 35, 44}, {156, 146, 35, 50}}},
{Region: "Japan", Group: "Premium UDP Asia", Hostname: "95-1-jp.cg-dialup.net", IPs: []net.IP{{156, 146, 35, 4}, {156, 146, 35, 14}, {156, 146, 35, 15}, {156, 146, 35, 18}, {156, 146, 35, 25}, {156, 146, 35, 34}, {156, 146, 35, 36}, {156, 146, 35, 46}, {156, 146, 35, 49}, {156, 146, 35, 50}}},
{Region: "Kazakhstan", Group: "Premium TCP Europe", Hostname: "97-1-kz.cg-dialup.net", IPs: []net.IP{{62, 133, 47, 131}, {62, 133, 47, 132}, {62, 133, 47, 134}, {62, 133, 47, 136}, {62, 133, 47, 138}, {62, 133, 47, 139}, {62, 133, 47, 140}, {62, 133, 47, 142}, {62, 133, 47, 143}, {62, 133, 47, 144}}},
{Region: "Kazakhstan", Group: "Premium UDP Europe", Hostname: "87-1-kz.cg-dialup.net", IPs: []net.IP{{62, 133, 47, 131}, {62, 133, 47, 132}, {62, 133, 47, 133}, {62, 133, 47, 134}, {62, 133, 47, 135}, {62, 133, 47, 138}, {62, 133, 47, 139}, {62, 133, 47, 140}, {62, 133, 47, 142}, {62, 133, 47, 143}}},
{Region: "Kenya", Group: "Premium TCP Asia", Hostname: "96-1-ke.cg-dialup.net", IPs: []net.IP{{62, 12, 118, 195}, {62, 12, 118, 196}, {62, 12, 118, 197}, {62, 12, 118, 198}, {62, 12, 118, 199}, {62, 12, 118, 200}, {62, 12, 118, 201}, {62, 12, 118, 202}, {62, 12, 118, 203}, {62, 12, 118, 204}}}, {Region: "Kenya", Group: "Premium TCP Asia", Hostname: "96-1-ke.cg-dialup.net", IPs: []net.IP{{62, 12, 118, 195}, {62, 12, 118, 196}, {62, 12, 118, 197}, {62, 12, 118, 198}, {62, 12, 118, 199}, {62, 12, 118, 200}, {62, 12, 118, 201}, {62, 12, 118, 202}, {62, 12, 118, 203}, {62, 12, 118, 204}}},
{Region: "Kenya", Group: "Premium UDP Asia", Hostname: "95-1-ke.cg-dialup.net", IPs: []net.IP{{62, 12, 118, 195}, {62, 12, 118, 196}, {62, 12, 118, 197}, {62, 12, 118, 198}, {62, 12, 118, 199}, {62, 12, 118, 200}, {62, 12, 118, 201}, {62, 12, 118, 202}, {62, 12, 118, 203}, {62, 12, 118, 204}}}, {Region: "Kenya", Group: "Premium UDP Asia", Hostname: "95-1-ke.cg-dialup.net", IPs: []net.IP{{62, 12, 118, 195}, {62, 12, 118, 196}, {62, 12, 118, 197}, {62, 12, 118, 198}, {62, 12, 118, 199}, {62, 12, 118, 200}, {62, 12, 118, 201}, {62, 12, 118, 202}, {62, 12, 118, 203}, {62, 12, 118, 204}}},
{Region: "Korea", Group: "Premium TCP Asia", Hostname: "96-1-kr.cg-dialup.net", IPs: []net.IP{{79, 110, 55, 131}, {79, 110, 55, 135}, {79, 110, 55, 137}, {79, 110, 55, 142}, {79, 110, 55, 147}, {79, 110, 55, 148}, {79, 110, 55, 149}, {79, 110, 55, 154}, {79, 110, 55, 155}, {79, 110, 55, 158}}}, {Region: "Korea", Group: "Premium TCP Asia", Hostname: "96-1-kr.cg-dialup.net", IPs: []net.IP{{79, 110, 55, 131}, {79, 110, 55, 134}, {79, 110, 55, 141}, {79, 110, 55, 147}, {79, 110, 55, 148}, {79, 110, 55, 151}, {79, 110, 55, 152}, {79, 110, 55, 153}, {79, 110, 55, 155}, {79, 110, 55, 157}}},
{Region: "Korea", Group: "Premium UDP Asia", Hostname: "95-1-kr.cg-dialup.net", IPs: []net.IP{{79, 110, 55, 131}, {79, 110, 55, 132}, {79, 110, 55, 133}, {79, 110, 55, 141}, {79, 110, 55, 147}, {79, 110, 55, 148}, {79, 110, 55, 150}, {79, 110, 55, 154}, {79, 110, 55, 157}, {79, 110, 55, 158}}}, {Region: "Korea", Group: "Premium UDP Asia", Hostname: "95-1-kr.cg-dialup.net", IPs: []net.IP{{79, 110, 55, 131}, {79, 110, 55, 133}, {79, 110, 55, 134}, {79, 110, 55, 136}, {79, 110, 55, 138}, {79, 110, 55, 140}, {79, 110, 55, 149}, {79, 110, 55, 151}, {79, 110, 55, 152}, {79, 110, 55, 157}}},
{Region: "Liechtenstein", Group: "Premium TCP Europe", Hostname: "97-1-li.cg-dialup.net", IPs: []net.IP{{91, 90, 122, 133}, {91, 90, 122, 134}, {91, 90, 122, 135}, {91, 90, 122, 137}, {91, 90, 122, 138}, {91, 90, 122, 139}, {91, 90, 122, 140}, {91, 90, 122, 142}, {91, 90, 122, 143}, {91, 90, 122, 144}}}, {Region: "Latvia", Group: "Premium TCP Europe", Hostname: "97-1-lv.cg-dialup.net", IPs: []net.IP{{109, 248, 148, 244}, {109, 248, 148, 245}, {109, 248, 148, 246}, {109, 248, 148, 247}, {109, 248, 148, 249}, {109, 248, 148, 250}, {109, 248, 148, 253}, {109, 248, 149, 22}, {109, 248, 149, 24}, {109, 248, 149, 25}}},
{Region: "Liechtenstein", Group: "Premium UDP Europe", Hostname: "87-1-li.cg-dialup.net", IPs: []net.IP{{91, 90, 122, 131}, {91, 90, 122, 132}, {91, 90, 122, 133}, {91, 90, 122, 134}, {91, 90, 122, 138}, {91, 90, 122, 139}, {91, 90, 122, 140}, {91, 90, 122, 142}, {91, 90, 122, 143}, {91, 90, 122, 145}}}, {Region: "Latvia", Group: "Premium UDP Europe", Hostname: "87-1-lv.cg-dialup.net", IPs: []net.IP{{109, 248, 148, 248}, {109, 248, 148, 250}, {109, 248, 148, 254}, {109, 248, 149, 19}, {109, 248, 149, 20}, {109, 248, 149, 22}, {109, 248, 149, 24}, {109, 248, 149, 26}, {109, 248, 149, 28}, {109, 248, 149, 30}}},
{Region: "Lithuania", Group: "Premium TCP Europe", Hostname: "97-1-lt.cg-dialup.net", IPs: []net.IP{{85, 206, 162, 209}, {85, 206, 162, 215}, {85, 206, 162, 218}, {85, 206, 162, 221}, {85, 206, 162, 222}, {85, 206, 165, 18}, {85, 206, 165, 20}, {85, 206, 165, 23}, {85, 206, 165, 26}, {85, 206, 165, 31}}}, {Region: "Liechtenstein", Group: "Premium UDP Europe", Hostname: "87-1-li.cg-dialup.net", IPs: []net.IP{{91, 90, 122, 131}, {91, 90, 122, 134}, {91, 90, 122, 137}, {91, 90, 122, 138}, {91, 90, 122, 139}, {91, 90, 122, 140}, {91, 90, 122, 141}, {91, 90, 122, 142}, {91, 90, 122, 144}, {91, 90, 122, 145}}},
{Region: "Lithuania", Group: "Premium UDP Europe", Hostname: "87-1-lt.cg-dialup.net", IPs: []net.IP{{85, 206, 162, 209}, {85, 206, 162, 210}, {85, 206, 162, 211}, {85, 206, 162, 212}, {85, 206, 162, 218}, {85, 206, 162, 221}, {85, 206, 165, 17}, {85, 206, 165, 23}, {85, 206, 165, 24}, {85, 206, 165, 30}}}, {Region: "Lithuania", Group: "Premium TCP Europe", Hostname: "97-1-lt.cg-dialup.net", IPs: []net.IP{{85, 206, 162, 212}, {85, 206, 162, 215}, {85, 206, 162, 219}, {85, 206, 162, 222}, {85, 206, 165, 17}, {85, 206, 165, 23}, {85, 206, 165, 25}, {85, 206, 165, 26}, {85, 206, 165, 30}, {85, 206, 165, 31}}},
{Region: "Luxembourg", Group: "Premium TCP Europe", Hostname: "97-1-lu.cg-dialup.net", IPs: []net.IP{{5, 253, 204, 3}, {5, 253, 204, 14}, {5, 253, 204, 22}, {5, 253, 204, 25}, {5, 253, 204, 26}, {5, 253, 204, 28}, {5, 253, 204, 30}, {5, 253, 204, 41}, {5, 253, 204, 43}, {5, 253, 204, 45}}}, {Region: "Lithuania", Group: "Premium UDP Europe", Hostname: "87-1-lt.cg-dialup.net", IPs: []net.IP{{85, 206, 162, 209}, {85, 206, 162, 210}, {85, 206, 162, 211}, {85, 206, 162, 213}, {85, 206, 162, 214}, {85, 206, 162, 217}, {85, 206, 162, 218}, {85, 206, 162, 220}, {85, 206, 165, 26}, {85, 206, 165, 30}}},
{Region: "Luxembourg", Group: "Premium UDP Europe", Hostname: "87-1-lu.cg-dialup.net", IPs: []net.IP{{5, 253, 204, 6}, {5, 253, 204, 12}, {5, 253, 204, 13}, {5, 253, 204, 26}, {5, 253, 204, 27}, {5, 253, 204, 36}, {5, 253, 204, 39}, {5, 253, 204, 41}, {5, 253, 204, 43}, {5, 253, 204, 46}}}, {Region: "Luxembourg", Group: "Premium UDP Europe", Hostname: "87-1-lu.cg-dialup.net", IPs: []net.IP{{5, 253, 204, 7}, {5, 253, 204, 10}, {5, 253, 204, 12}, {5, 253, 204, 23}, {5, 253, 204, 26}, {5, 253, 204, 30}, {5, 253, 204, 37}, {5, 253, 204, 39}, {5, 253, 204, 44}, {5, 253, 204, 45}}},
{Region: "Macao", Group: "Premium TCP Asia", Hostname: "96-1-mo.cg-dialup.net", IPs: []net.IP{{84, 252, 92, 131}, {84, 252, 92, 132}, {84, 252, 92, 134}, {84, 252, 92, 136}, {84, 252, 92, 138}, {84, 252, 92, 140}, {84, 252, 92, 141}, {84, 252, 92, 142}, {84, 252, 92, 143}, {84, 252, 92, 145}}}, {Region: "Macao", Group: "Premium TCP Asia", Hostname: "96-1-mo.cg-dialup.net", IPs: []net.IP{{84, 252, 92, 131}, {84, 252, 92, 133}, {84, 252, 92, 135}, {84, 252, 92, 137}, {84, 252, 92, 138}, {84, 252, 92, 139}, {84, 252, 92, 141}, {84, 252, 92, 142}, {84, 252, 92, 144}, {84, 252, 92, 145}}},
{Region: "Macao", Group: "Premium UDP Asia", Hostname: "95-1-mo.cg-dialup.net", IPs: []net.IP{{84, 252, 92, 132}, {84, 252, 92, 134}, {84, 252, 92, 135}, {84, 252, 92, 136}, {84, 252, 92, 137}, {84, 252, 92, 138}, {84, 252, 92, 140}, {84, 252, 92, 141}, {84, 252, 92, 143}, {84, 252, 92, 144}}}, {Region: "Macao", Group: "Premium UDP Asia", Hostname: "95-1-mo.cg-dialup.net", IPs: []net.IP{{84, 252, 92, 132}, {84, 252, 92, 134}, {84, 252, 92, 135}, {84, 252, 92, 136}, {84, 252, 92, 137}, {84, 252, 92, 139}, {84, 252, 92, 141}, {84, 252, 92, 143}, {84, 252, 92, 144}, {84, 252, 92, 145}}},
{Region: "Macedonia", Group: "Premium TCP Europe", Hostname: "97-1-mk.cg-dialup.net", IPs: []net.IP{{185, 225, 28, 3}, {185, 225, 28, 4}, {185, 225, 28, 5}, {185, 225, 28, 6}, {185, 225, 28, 7}, {185, 225, 28, 8}, {185, 225, 28, 9}, {185, 225, 28, 10}, {185, 225, 28, 11}, {185, 225, 28, 12}}},
{Region: "Macedonia", Group: "Premium UDP Europe", Hostname: "87-1-mk.cg-dialup.net", IPs: []net.IP{{185, 225, 28, 3}, {185, 225, 28, 4}, {185, 225, 28, 5}, {185, 225, 28, 6}, {185, 225, 28, 7}, {185, 225, 28, 8}, {185, 225, 28, 9}, {185, 225, 28, 10}, {185, 225, 28, 11}, {185, 225, 28, 12}}}, {Region: "Macedonia", Group: "Premium UDP Europe", Hostname: "87-1-mk.cg-dialup.net", IPs: []net.IP{{185, 225, 28, 3}, {185, 225, 28, 4}, {185, 225, 28, 5}, {185, 225, 28, 6}, {185, 225, 28, 7}, {185, 225, 28, 8}, {185, 225, 28, 9}, {185, 225, 28, 10}, {185, 225, 28, 11}, {185, 225, 28, 12}}},
{Region: "Malaysia", Group: "Premium TCP Asia", Hostname: "96-1-my.cg-dialup.net", IPs: []net.IP{{146, 70, 15, 3}, {146, 70, 15, 4}, {146, 70, 15, 5}, {146, 70, 15, 6}, {146, 70, 15, 7}, {146, 70, 15, 10}, {146, 70, 15, 11}, {146, 70, 15, 13}, {146, 70, 15, 15}, {146, 70, 15, 16}}}, {Region: "Malaysia", Group: "Premium TCP Asia", Hostname: "96-1-my.cg-dialup.net", IPs: []net.IP{{146, 70, 15, 4}, {146, 70, 15, 6}, {146, 70, 15, 8}, {146, 70, 15, 9}, {146, 70, 15, 10}, {146, 70, 15, 11}, {146, 70, 15, 12}, {146, 70, 15, 13}, {146, 70, 15, 15}, {146, 70, 15, 16}}},
{Region: "Malta", Group: "Premium TCP Europe", Hostname: "97-1-mt.cg-dialup.net", IPs: []net.IP{{176, 125, 230, 131}, {176, 125, 230, 132}, {176, 125, 230, 134}, {176, 125, 230, 136}, {176, 125, 230, 137}, {176, 125, 230, 140}, {176, 125, 230, 141}, {176, 125, 230, 142}, {176, 125, 230, 144}, {176, 125, 230, 145}}}, {Region: "Malaysia", Group: "Premium UDP Asia", Hostname: "95-1-my.cg-dialup.net", IPs: []net.IP{{146, 70, 15, 3}, {146, 70, 15, 4}, {146, 70, 15, 5}, {146, 70, 15, 6}, {146, 70, 15, 7}, {146, 70, 15, 8}, {146, 70, 15, 10}, {146, 70, 15, 12}, {146, 70, 15, 15}, {146, 70, 15, 16}}},
{Region: "Malta", Group: "Premium UDP Europe", Hostname: "87-1-mt.cg-dialup.net", IPs: []net.IP{{176, 125, 230, 131}, {176, 125, 230, 134}, {176, 125, 230, 135}, {176, 125, 230, 138}, {176, 125, 230, 139}, {176, 125, 230, 140}, {176, 125, 230, 142}, {176, 125, 230, 143}, {176, 125, 230, 144}, {176, 125, 230, 145}}}, {Region: "Malta", Group: "Premium TCP Europe", Hostname: "97-1-mt.cg-dialup.net", IPs: []net.IP{{176, 125, 230, 133}, {176, 125, 230, 135}, {176, 125, 230, 136}, {176, 125, 230, 137}, {176, 125, 230, 138}, {176, 125, 230, 140}, {176, 125, 230, 142}, {176, 125, 230, 143}, {176, 125, 230, 144}, {176, 125, 230, 145}}},
{Region: "Mexico", Group: "Premium TCP USA", Hostname: "93-1-mx.cg-dialup.net", IPs: []net.IP{{77, 81, 142, 130}, {77, 81, 142, 136}, {77, 81, 142, 146}, {77, 81, 142, 148}, {77, 81, 142, 150}, {77, 81, 142, 151}, {77, 81, 142, 152}, {77, 81, 142, 153}, {77, 81, 142, 154}, {77, 81, 142, 155}}}, {Region: "Malta", Group: "Premium UDP Europe", Hostname: "87-1-mt.cg-dialup.net", IPs: []net.IP{{176, 125, 230, 131}, {176, 125, 230, 133}, {176, 125, 230, 134}, {176, 125, 230, 136}, {176, 125, 230, 137}, {176, 125, 230, 138}, {176, 125, 230, 139}, {176, 125, 230, 140}, {176, 125, 230, 144}, {176, 125, 230, 145}}},
{Region: "Mexico", Group: "Premium UDP USA", Hostname: "94-1-mx.cg-dialup.net", IPs: []net.IP{{77, 81, 142, 130}, {77, 81, 142, 136}, {77, 81, 142, 144}, {77, 81, 142, 146}, {77, 81, 142, 147}, {77, 81, 142, 150}, {77, 81, 142, 151}, {77, 81, 142, 153}, {77, 81, 142, 154}, {77, 81, 142, 155}}}, {Region: "Mexico", Group: "Premium TCP USA", Hostname: "93-1-mx.cg-dialup.net", IPs: []net.IP{{77, 81, 142, 132}, {77, 81, 142, 134}, {77, 81, 142, 136}, {77, 81, 142, 139}, {77, 81, 142, 142}, {77, 81, 142, 154}, {77, 81, 142, 155}, {77, 81, 142, 157}, {77, 81, 142, 158}, {77, 81, 142, 159}}},
{Region: "Monaco", Group: "Premium TCP Europe", Hostname: "97-1-mc.cg-dialup.net", IPs: []net.IP{{95, 181, 233, 131}, {95, 181, 233, 132}, {95, 181, 233, 133}, {95, 181, 233, 135}, {95, 181, 233, 136}, {95, 181, 233, 137}, {95, 181, 233, 140}, {95, 181, 233, 141}, {95, 181, 233, 143}, {95, 181, 233, 144}}}, {Region: "Mexico", Group: "Premium UDP USA", Hostname: "94-1-mx.cg-dialup.net", IPs: []net.IP{{77, 81, 142, 130}, {77, 81, 142, 131}, {77, 81, 142, 132}, {77, 81, 142, 139}, {77, 81, 142, 141}, {77, 81, 142, 142}, {77, 81, 142, 146}, {77, 81, 142, 147}, {77, 81, 142, 154}, {77, 81, 142, 159}}},
{Region: "Monaco", Group: "Premium UDP Europe", Hostname: "87-1-mc.cg-dialup.net", IPs: []net.IP{{95, 181, 233, 131}, {95, 181, 233, 132}, {95, 181, 233, 135}, {95, 181, 233, 136}, {95, 181, 233, 138}, {95, 181, 233, 139}, {95, 181, 233, 140}, {95, 181, 233, 142}, {95, 181, 233, 143}, {95, 181, 233, 144}}}, {Region: "Moldova", Group: "Premium TCP Europe", Hostname: "97-1-md.cg-dialup.net", IPs: []net.IP{{178, 175, 130, 243}, {178, 175, 130, 244}, {178, 175, 130, 245}, {178, 175, 130, 246}, {178, 175, 130, 251}, {178, 175, 130, 254}, {178, 175, 142, 131}, {178, 175, 142, 132}, {178, 175, 142, 133}, {178, 175, 142, 134}}},
{Region: "Mongolia", Group: "Premium TCP Asia", Hostname: "96-1-mn.cg-dialup.net", IPs: []net.IP{{185, 253, 163, 131}, {185, 253, 163, 132}, {185, 253, 163, 133}, {185, 253, 163, 134}, {185, 253, 163, 136}, {185, 253, 163, 138}, {185, 253, 163, 139}, {185, 253, 163, 141}, {185, 253, 163, 142}, {185, 253, 163, 145}}}, {Region: "Moldova", Group: "Premium UDP Europe", Hostname: "87-1-md.cg-dialup.net", IPs: []net.IP{{178, 175, 130, 243}, {178, 175, 130, 244}, {178, 175, 130, 246}, {178, 175, 130, 250}, {178, 175, 130, 251}, {178, 175, 130, 253}, {178, 175, 130, 254}, {178, 175, 142, 132}, {178, 175, 142, 133}, {178, 175, 142, 134}}},
{Region: "Mongolia", Group: "Premium UDP Asia", Hostname: "95-1-mn.cg-dialup.net", IPs: []net.IP{{185, 253, 163, 131}, {185, 253, 163, 132}, {185, 253, 163, 133}, {185, 253, 163, 134}, {185, 253, 163, 135}, {185, 253, 163, 136}, {185, 253, 163, 142}, {185, 253, 163, 143}, {185, 253, 163, 144}, {185, 253, 163, 145}}}, {Region: "Monaco", Group: "Premium TCP Europe", Hostname: "97-1-mc.cg-dialup.net", IPs: []net.IP{{95, 181, 233, 131}, {95, 181, 233, 132}, {95, 181, 233, 133}, {95, 181, 233, 137}, {95, 181, 233, 138}, {95, 181, 233, 139}, {95, 181, 233, 140}, {95, 181, 233, 141}, {95, 181, 233, 143}, {95, 181, 233, 144}}},
{Region: "Montenegro", Group: "Premium TCP Europe", Hostname: "97-1-me.cg-dialup.net", IPs: []net.IP{{176, 125, 229, 131}, {176, 125, 229, 133}, {176, 125, 229, 134}, {176, 125, 229, 135}, {176, 125, 229, 136}, {176, 125, 229, 138}, {176, 125, 229, 139}, {176, 125, 229, 141}, {176, 125, 229, 144}, {176, 125, 229, 145}}}, {Region: "Monaco", Group: "Premium UDP Europe", Hostname: "87-1-mc.cg-dialup.net", IPs: []net.IP{{95, 181, 233, 132}, {95, 181, 233, 135}, {95, 181, 233, 136}, {95, 181, 233, 137}, {95, 181, 233, 138}, {95, 181, 233, 139}, {95, 181, 233, 141}, {95, 181, 233, 142}, {95, 181, 233, 143}, {95, 181, 233, 144}}},
{Region: "Morocco", Group: "Premium UDP Europe", Hostname: "87-1-ma.cg-dialup.net", IPs: []net.IP{{95, 181, 232, 131}, {95, 181, 232, 132}, {95, 181, 232, 133}, {95, 181, 232, 134}, {95, 181, 232, 135}, {95, 181, 232, 136}, {95, 181, 232, 137}, {95, 181, 232, 139}, {95, 181, 232, 140}, {95, 181, 232, 143}}}, {Region: "Mongolia", Group: "Premium TCP Asia", Hostname: "96-1-mn.cg-dialup.net", IPs: []net.IP{{185, 253, 163, 132}, {185, 253, 163, 133}, {185, 253, 163, 135}, {185, 253, 163, 136}, {185, 253, 163, 139}, {185, 253, 163, 140}, {185, 253, 163, 141}, {185, 253, 163, 142}, {185, 253, 163, 143}, {185, 253, 163, 144}}},
{Region: "Netherlands", Group: "Premium TCP Europe", Hostname: "97-1-nl.cg-dialup.net", IPs: []net.IP{{181, 214, 206, 26}, {181, 214, 206, 27}, {191, 96, 168, 57}, {191, 96, 168, 147}, {195, 78, 54, 20}, {195, 78, 54, 26}, {195, 78, 54, 28}, {195, 78, 54, 50}, {195, 78, 54, 109}, {195, 78, 54, 159}}}, {Region: "Mongolia", Group: "Premium UDP Asia", Hostname: "95-1-mn.cg-dialup.net", IPs: []net.IP{{185, 253, 163, 131}, {185, 253, 163, 133}, {185, 253, 163, 134}, {185, 253, 163, 137}, {185, 253, 163, 138}, {185, 253, 163, 139}, {185, 253, 163, 140}, {185, 253, 163, 141}, {185, 253, 163, 142}, {185, 253, 163, 144}}},
{Region: "New Zealand", Group: "Premium UDP Asia", Hostname: "95-1-nz.cg-dialup.net", IPs: []net.IP{{114, 141, 194, 2}, {114, 141, 194, 3}, {114, 141, 194, 4}, {114, 141, 194, 5}, {114, 141, 194, 6}, {114, 141, 194, 7}, {114, 141, 194, 9}, {114, 141, 194, 11}, {114, 141, 194, 12}, {114, 141, 194, 13}}}, {Region: "Montenegro", Group: "Premium TCP Europe", Hostname: "97-1-me.cg-dialup.net", IPs: []net.IP{{176, 125, 229, 131}, {176, 125, 229, 135}, {176, 125, 229, 137}, {176, 125, 229, 138}, {176, 125, 229, 140}, {176, 125, 229, 141}, {176, 125, 229, 142}, {176, 125, 229, 143}, {176, 125, 229, 144}, {176, 125, 229, 145}}},
{Region: "Nigeria", Group: "Premium TCP Europe", Hostname: "97-1-ng.cg-dialup.net", IPs: []net.IP{{102, 165, 25, 68}, {102, 165, 25, 69}, {102, 165, 25, 70}, {102, 165, 25, 71}, {102, 165, 25, 72}, {102, 165, 25, 73}, {102, 165, 25, 74}, {102, 165, 25, 75}, {102, 165, 25, 76}, {102, 165, 25, 77}}}, {Region: "Montenegro", Group: "Premium UDP Europe", Hostname: "87-1-me.cg-dialup.net", IPs: []net.IP{{176, 125, 229, 131}, {176, 125, 229, 134}, {176, 125, 229, 136}, {176, 125, 229, 137}, {176, 125, 229, 138}, {176, 125, 229, 139}, {176, 125, 229, 140}, {176, 125, 229, 141}, {176, 125, 229, 143}, {176, 125, 229, 144}}},
{Region: "Nigeria", Group: "Premium UDP Europe", Hostname: "87-1-ng.cg-dialup.net", IPs: []net.IP{{102, 165, 25, 68}, {102, 165, 25, 69}, {102, 165, 25, 70}, {102, 165, 25, 71}, {102, 165, 25, 72}, {102, 165, 25, 73}, {102, 165, 25, 74}, {102, 165, 25, 76}, {102, 165, 25, 77}, {102, 165, 25, 78}}}, {Region: "Morocco", Group: "Premium TCP Europe", Hostname: "97-1-ma.cg-dialup.net", IPs: []net.IP{{95, 181, 232, 132}, {95, 181, 232, 133}, {95, 181, 232, 134}, {95, 181, 232, 136}, {95, 181, 232, 137}, {95, 181, 232, 138}, {95, 181, 232, 139}, {95, 181, 232, 140}, {95, 181, 232, 141}, {95, 181, 232, 144}}},
{Region: "Norway", Group: "Premium TCP Europe", Hostname: "97-1-no.cg-dialup.net", IPs: []net.IP{{45, 12, 223, 139}, {82, 102, 27, 91}, {82, 102, 27, 92}, {185, 206, 225, 229}, {185, 206, 225, 231}, {185, 206, 225, 236}, {185, 253, 97, 235}, {185, 253, 97, 245}, {185, 253, 97, 249}, {185, 253, 97, 251}}}, {Region: "Morocco", Group: "Premium UDP Europe", Hostname: "87-1-ma.cg-dialup.net", IPs: []net.IP{{95, 181, 232, 131}, {95, 181, 232, 132}, {95, 181, 232, 133}, {95, 181, 232, 135}, {95, 181, 232, 137}, {95, 181, 232, 139}, {95, 181, 232, 140}, {95, 181, 232, 141}, {95, 181, 232, 142}, {95, 181, 232, 143}}},
{Region: "Norway", Group: "Premium UDP Europe", Hostname: "87-1-no.cg-dialup.net", IPs: []net.IP{{45, 12, 223, 133}, {45, 12, 223, 137}, {45, 12, 223, 139}, {45, 12, 223, 140}, {185, 206, 225, 27}, {185, 206, 225, 28}, {185, 206, 225, 29}, {185, 206, 225, 230}, {185, 253, 97, 250}, {185, 253, 97, 251}}}, {Region: "Netherlands", Group: "Premium TCP Europe", Hostname: "97-1-nl.cg-dialup.net", IPs: []net.IP{{84, 17, 47, 98}, {181, 214, 206, 22}, {181, 214, 206, 27}, {181, 214, 206, 36}, {195, 78, 54, 10}, {195, 78, 54, 20}, {195, 78, 54, 43}, {195, 78, 54, 50}, {195, 78, 54, 119}, {195, 181, 172, 78}}},
{Region: "Philippines", Group: "Premium TCP Asia", Hostname: "96-1-ph.cg-dialup.net", IPs: []net.IP{{188, 214, 125, 36}, {188, 214, 125, 38}, {188, 214, 125, 40}, {188, 214, 125, 41}, {188, 214, 125, 47}, {188, 214, 125, 49}, {188, 214, 125, 51}, {188, 214, 125, 53}, {188, 214, 125, 54}, {188, 214, 125, 61}}}, {Region: "Netherlands", Group: "Premium UDP Europe", Hostname: "87-1-nl.cg-dialup.net", IPs: []net.IP{{84, 17, 47, 110}, {181, 214, 206, 29}, {181, 214, 206, 42}, {195, 78, 54, 8}, {195, 78, 54, 19}, {195, 78, 54, 47}, {195, 78, 54, 110}, {195, 78, 54, 141}, {195, 78, 54, 143}, {195, 78, 54, 157}}},
{Region: "Poland", Group: "Premium UDP Europe", Hostname: "87-1-pl.cg-dialup.net", IPs: []net.IP{{37, 120, 156, 4}, {37, 120, 156, 9}, {37, 120, 156, 10}, {37, 120, 156, 20}, {37, 120, 156, 21}, {37, 120, 156, 23}, {37, 120, 156, 26}, {51, 75, 56, 36}, {51, 75, 56, 37}, {51, 75, 56, 43}}}, {Region: "New Zealand", Group: "Premium TCP Asia", Hostname: "96-1-nz.cg-dialup.net", IPs: []net.IP{{43, 250, 207, 98}, {43, 250, 207, 99}, {43, 250, 207, 100}, {43, 250, 207, 101}, {43, 250, 207, 102}, {43, 250, 207, 103}, {43, 250, 207, 105}, {43, 250, 207, 106}, {43, 250, 207, 108}, {43, 250, 207, 109}}},
{Region: "Qatar", Group: "Premium TCP Europe", Hostname: "97-1-qa.cg-dialup.net", IPs: []net.IP{{95, 181, 234, 131}, {95, 181, 234, 132}, {95, 181, 234, 134}, {95, 181, 234, 135}, {95, 181, 234, 136}, {95, 181, 234, 137}, {95, 181, 234, 138}, {95, 181, 234, 140}, {95, 181, 234, 142}, {95, 181, 234, 143}}}, {Region: "New Zealand", Group: "Premium UDP Asia", Hostname: "95-1-nz.cg-dialup.net", IPs: []net.IP{{43, 250, 207, 98}, {43, 250, 207, 99}, {43, 250, 207, 102}, {43, 250, 207, 104}, {43, 250, 207, 105}, {43, 250, 207, 106}, {43, 250, 207, 107}, {43, 250, 207, 108}, {43, 250, 207, 109}, {43, 250, 207, 110}}},
{Region: "Qatar", Group: "Premium UDP Europe", Hostname: "87-1-qa.cg-dialup.net", IPs: []net.IP{{95, 181, 234, 132}, {95, 181, 234, 134}, {95, 181, 234, 135}, {95, 181, 234, 138}, {95, 181, 234, 139}, {95, 181, 234, 140}, {95, 181, 234, 141}, {95, 181, 234, 142}, {95, 181, 234, 143}, {95, 181, 234, 144}}}, {Region: "Nigeria", Group: "Premium TCP Europe", Hostname: "97-1-ng.cg-dialup.net", IPs: []net.IP{{102, 165, 25, 68}, {102, 165, 25, 69}, {102, 165, 25, 70}, {102, 165, 25, 71}, {102, 165, 25, 72}, {102, 165, 25, 73}, {102, 165, 25, 75}, {102, 165, 25, 76}, {102, 165, 25, 77}, {102, 165, 25, 78}}},
{Region: "Russian Federation", Group: "Premium UDP Europe", Hostname: "87-1-ru.cg-dialup.net", IPs: []net.IP{{5, 8, 16, 69}, {5, 8, 16, 87}, {5, 8, 16, 88}, {5, 8, 16, 92}, {5, 8, 16, 109}, {5, 8, 16, 116}, {5, 8, 16, 118}, {5, 8, 16, 134}, {5, 8, 16, 136}, {5, 8, 16, 141}}}, {Region: "Nigeria", Group: "Premium UDP Europe", Hostname: "87-1-ng.cg-dialup.net", IPs: []net.IP{{102, 165, 25, 68}, {102, 165, 25, 69}, {102, 165, 25, 70}, {102, 165, 25, 71}, {102, 165, 25, 72}, {102, 165, 25, 74}, {102, 165, 25, 75}, {102, 165, 25, 76}, {102, 165, 25, 77}, {102, 165, 25, 78}}},
{Region: "Saudi Arabia", Group: "Premium TCP Europe", Hostname: "97-1-sa.cg-dialup.net", IPs: []net.IP{{95, 181, 235, 132}, {95, 181, 235, 133}, {95, 181, 235, 134}, {95, 181, 235, 136}, {95, 181, 235, 137}, {95, 181, 235, 138}, {95, 181, 235, 139}, {95, 181, 235, 140}, {95, 181, 235, 141}, {95, 181, 235, 142}}}, {Region: "Norway", Group: "Premium TCP Europe", Hostname: "97-1-no.cg-dialup.net", IPs: []net.IP{{45, 12, 223, 137}, {45, 12, 223, 140}, {185, 206, 225, 29}, {185, 206, 225, 231}, {185, 253, 97, 234}, {185, 253, 97, 236}, {185, 253, 97, 238}, {185, 253, 97, 244}, {185, 253, 97, 250}, {185, 253, 97, 254}}},
{Region: "Serbia", Group: "Premium UDP Europe", Hostname: "87-1-rs.cg-dialup.net", IPs: []net.IP{{37, 120, 193, 179}, {37, 120, 193, 183}, {37, 120, 193, 187}, {37, 120, 193, 190}, {141, 98, 103, 37}, {141, 98, 103, 38}, {141, 98, 103, 39}, {141, 98, 103, 40}, {141, 98, 103, 43}, {141, 98, 103, 46}}}, {Region: "Norway", Group: "Premium UDP Europe", Hostname: "87-1-no.cg-dialup.net", IPs: []net.IP{{45, 12, 223, 133}, {45, 12, 223, 134}, {45, 12, 223, 142}, {185, 206, 225, 227}, {185, 206, 225, 228}, {185, 206, 225, 231}, {185, 206, 225, 235}, {185, 253, 97, 237}, {185, 253, 97, 246}, {185, 253, 97, 254}}},
{Region: "Pakistan", Group: "Premium TCP Asia", Hostname: "96-1-pk.cg-dialup.net", IPs: []net.IP{{146, 70, 12, 3}, {146, 70, 12, 4}, {146, 70, 12, 6}, {146, 70, 12, 8}, {146, 70, 12, 9}, {146, 70, 12, 10}, {146, 70, 12, 11}, {146, 70, 12, 12}, {146, 70, 12, 13}, {146, 70, 12, 14}}},
{Region: "Pakistan", Group: "Premium UDP Asia", Hostname: "95-1-pk.cg-dialup.net", IPs: []net.IP{{146, 70, 12, 4}, {146, 70, 12, 5}, {146, 70, 12, 6}, {146, 70, 12, 7}, {146, 70, 12, 8}, {146, 70, 12, 10}, {146, 70, 12, 11}, {146, 70, 12, 12}, {146, 70, 12, 13}, {146, 70, 12, 14}}},
{Region: "Panama", Group: "Premium TCP Europe", Hostname: "97-1-pa.cg-dialup.net", IPs: []net.IP{{91, 90, 126, 131}, {91, 90, 126, 132}, {91, 90, 126, 133}, {91, 90, 126, 134}, {91, 90, 126, 136}, {91, 90, 126, 138}, {91, 90, 126, 139}, {91, 90, 126, 141}, {91, 90, 126, 142}, {91, 90, 126, 145}}},
{Region: "Panama", Group: "Premium UDP Europe", Hostname: "87-1-pa.cg-dialup.net", IPs: []net.IP{{91, 90, 126, 131}, {91, 90, 126, 133}, {91, 90, 126, 134}, {91, 90, 126, 135}, {91, 90, 126, 136}, {91, 90, 126, 138}, {91, 90, 126, 140}, {91, 90, 126, 141}, {91, 90, 126, 142}, {91, 90, 126, 145}}},
{Region: "Philippines", Group: "Premium TCP Asia", Hostname: "96-1-ph.cg-dialup.net", IPs: []net.IP{{188, 214, 125, 37}, {188, 214, 125, 38}, {188, 214, 125, 40}, {188, 214, 125, 43}, {188, 214, 125, 44}, {188, 214, 125, 45}, {188, 214, 125, 52}, {188, 214, 125, 55}, {188, 214, 125, 61}, {188, 214, 125, 62}}},
{Region: "Philippines", Group: "Premium UDP Asia", Hostname: "95-1-ph.cg-dialup.net", IPs: []net.IP{{188, 214, 125, 37}, {188, 214, 125, 40}, {188, 214, 125, 46}, {188, 214, 125, 49}, {188, 214, 125, 52}, {188, 214, 125, 54}, {188, 214, 125, 57}, {188, 214, 125, 58}, {188, 214, 125, 61}, {188, 214, 125, 62}}},
{Region: "Poland", Group: "Premium TCP Europe", Hostname: "97-1-pl.cg-dialup.net", IPs: []net.IP{{138, 199, 59, 132}, {138, 199, 59, 136}, {138, 199, 59, 137}, {138, 199, 59, 143}, {138, 199, 59, 144}, {138, 199, 59, 152}, {138, 199, 59, 153}, {138, 199, 59, 166}, {138, 199, 59, 174}, {138, 199, 59, 175}}},
{Region: "Poland", Group: "Premium UDP Europe", Hostname: "87-1-pl.cg-dialup.net", IPs: []net.IP{{138, 199, 59, 130}, {138, 199, 59, 136}, {138, 199, 59, 148}, {138, 199, 59, 149}, {138, 199, 59, 153}, {138, 199, 59, 156}, {138, 199, 59, 157}, {138, 199, 59, 164}, {138, 199, 59, 171}, {138, 199, 59, 173}}},
{Region: "Portugal", Group: "Premium TCP Europe", Hostname: "97-1-pt.cg-dialup.net", IPs: []net.IP{{89, 26, 243, 112}, {89, 26, 243, 115}, {89, 26, 243, 195}, {89, 26, 243, 216}, {89, 26, 243, 218}, {89, 26, 243, 220}, {89, 26, 243, 222}, {89, 26, 243, 223}, {89, 26, 243, 225}, {89, 26, 243, 228}}},
{Region: "Portugal", Group: "Premium UDP Europe", Hostname: "87-1-pt.cg-dialup.net", IPs: []net.IP{{89, 26, 243, 99}, {89, 26, 243, 113}, {89, 26, 243, 115}, {89, 26, 243, 195}, {89, 26, 243, 199}, {89, 26, 243, 216}, {89, 26, 243, 219}, {89, 26, 243, 225}, {89, 26, 243, 226}, {89, 26, 243, 227}}},
{Region: "Qatar", Group: "Premium TCP Europe", Hostname: "97-1-qa.cg-dialup.net", IPs: []net.IP{{95, 181, 234, 133}, {95, 181, 234, 135}, {95, 181, 234, 136}, {95, 181, 234, 137}, {95, 181, 234, 138}, {95, 181, 234, 139}, {95, 181, 234, 140}, {95, 181, 234, 141}, {95, 181, 234, 142}, {95, 181, 234, 143}}},
{Region: "Qatar", Group: "Premium UDP Europe", Hostname: "87-1-qa.cg-dialup.net", IPs: []net.IP{{95, 181, 234, 131}, {95, 181, 234, 132}, {95, 181, 234, 133}, {95, 181, 234, 134}, {95, 181, 234, 135}, {95, 181, 234, 137}, {95, 181, 234, 138}, {95, 181, 234, 139}, {95, 181, 234, 142}, {95, 181, 234, 143}}},
{Region: "Russian Federation", Group: "Premium TCP Europe", Hostname: "97-1-ru.cg-dialup.net", IPs: []net.IP{{5, 8, 16, 72}, {5, 8, 16, 74}, {5, 8, 16, 84}, {5, 8, 16, 85}, {5, 8, 16, 123}, {5, 8, 16, 124}, {5, 8, 16, 132}, {146, 70, 52, 35}, {146, 70, 52, 44}, {146, 70, 52, 54}}},
{Region: "Russian Federation", Group: "Premium UDP Europe", Hostname: "87-1-ru.cg-dialup.net", IPs: []net.IP{{5, 8, 16, 75}, {5, 8, 16, 87}, {5, 8, 16, 99}, {5, 8, 16, 110}, {5, 8, 16, 138}, {146, 70, 52, 29}, {146, 70, 52, 52}, {146, 70, 52, 58}, {146, 70, 52, 59}, {146, 70, 52, 67}}},
{Region: "Saudi Arabia", Group: "Premium TCP Europe", Hostname: "97-1-sa.cg-dialup.net", IPs: []net.IP{{95, 181, 235, 131}, {95, 181, 235, 133}, {95, 181, 235, 134}, {95, 181, 235, 135}, {95, 181, 235, 137}, {95, 181, 235, 138}, {95, 181, 235, 139}, {95, 181, 235, 140}, {95, 181, 235, 141}, {95, 181, 235, 142}}},
{Region: "Saudi Arabia", Group: "Premium UDP Europe", Hostname: "87-1-sa.cg-dialup.net", IPs: []net.IP{{95, 181, 235, 131}, {95, 181, 235, 132}, {95, 181, 235, 134}, {95, 181, 235, 135}, {95, 181, 235, 136}, {95, 181, 235, 137}, {95, 181, 235, 138}, {95, 181, 235, 139}, {95, 181, 235, 141}, {95, 181, 235, 144}}},
{Region: "Serbia", Group: "Premium TCP Europe", Hostname: "97-1-rs.cg-dialup.net", IPs: []net.IP{{37, 120, 193, 179}, {37, 120, 193, 186}, {37, 120, 193, 188}, {37, 120, 193, 190}, {141, 98, 103, 36}, {141, 98, 103, 38}, {141, 98, 103, 39}, {141, 98, 103, 43}, {141, 98, 103, 44}, {141, 98, 103, 46}}},
{Region: "Serbia", Group: "Premium UDP Europe", Hostname: "87-1-rs.cg-dialup.net", IPs: []net.IP{{37, 120, 193, 180}, {37, 120, 193, 186}, {37, 120, 193, 187}, {37, 120, 193, 188}, {37, 120, 193, 189}, {37, 120, 193, 190}, {141, 98, 103, 35}, {141, 98, 103, 36}, {141, 98, 103, 39}, {141, 98, 103, 41}}},
{Region: "Singapore", Group: "Premium TCP Asia", Hostname: "96-1-sg.cg-dialup.net", IPs: []net.IP{{84, 17, 39, 162}, {84, 17, 39, 165}, {84, 17, 39, 168}, {84, 17, 39, 171}, {84, 17, 39, 175}, {84, 17, 39, 177}, {84, 17, 39, 178}, {84, 17, 39, 181}, {84, 17, 39, 183}, {84, 17, 39, 185}}},
{Region: "Singapore", Group: "Premium UDP Asia", Hostname: "95-1-sg.cg-dialup.net", IPs: []net.IP{{84, 17, 39, 162}, {84, 17, 39, 165}, {84, 17, 39, 166}, {84, 17, 39, 167}, {84, 17, 39, 171}, {84, 17, 39, 174}, {84, 17, 39, 175}, {84, 17, 39, 178}, {84, 17, 39, 180}, {84, 17, 39, 185}}},
{Region: "Slovakia", Group: "Premium TCP Europe", Hostname: "97-1-sk.cg-dialup.net", IPs: []net.IP{{185, 245, 85, 227}, {185, 245, 85, 228}, {185, 245, 85, 229}, {185, 245, 85, 230}, {185, 245, 85, 231}, {185, 245, 85, 232}, {185, 245, 85, 233}, {185, 245, 85, 234}, {185, 245, 85, 235}, {185, 245, 85, 236}}}, {Region: "Slovakia", Group: "Premium TCP Europe", Hostname: "97-1-sk.cg-dialup.net", IPs: []net.IP{{185, 245, 85, 227}, {185, 245, 85, 228}, {185, 245, 85, 229}, {185, 245, 85, 230}, {185, 245, 85, 231}, {185, 245, 85, 232}, {185, 245, 85, 233}, {185, 245, 85, 234}, {185, 245, 85, 235}, {185, 245, 85, 236}}},
{Region: "Slovakia", Group: "Premium UDP Europe", Hostname: "87-1-sk.cg-dialup.net", IPs: []net.IP{{185, 245, 85, 227}, {185, 245, 85, 228}, {185, 245, 85, 229}, {185, 245, 85, 230}, {185, 245, 85, 231}, {185, 245, 85, 232}, {185, 245, 85, 233}, {185, 245, 85, 234}, {185, 245, 85, 235}, {185, 245, 85, 236}}}, {Region: "Slovakia", Group: "Premium UDP Europe", Hostname: "87-1-sk.cg-dialup.net", IPs: []net.IP{{185, 245, 85, 227}, {185, 245, 85, 228}, {185, 245, 85, 229}, {185, 245, 85, 230}, {185, 245, 85, 231}, {185, 245, 85, 232}, {185, 245, 85, 233}, {185, 245, 85, 234}, {185, 245, 85, 235}, {185, 245, 85, 236}}},
{Region: "Slovenia", Group: "Premium TCP Europe", Hostname: "97-1-si.cg-dialup.net", IPs: []net.IP{{195, 80, 150, 211}, {195, 80, 150, 212}, {195, 80, 150, 213}, {195, 80, 150, 214}, {195, 80, 150, 215}, {195, 80, 150, 216}, {195, 80, 150, 219}, {195, 80, 150, 220}, {195, 80, 150, 221}, {195, 80, 150, 222}}}, {Region: "Slovenia", Group: "Premium TCP Europe", Hostname: "97-1-si.cg-dialup.net", IPs: []net.IP{{195, 80, 150, 211}, {195, 80, 150, 212}, {195, 80, 150, 214}, {195, 80, 150, 215}, {195, 80, 150, 216}, {195, 80, 150, 217}, {195, 80, 150, 218}, {195, 80, 150, 219}, {195, 80, 150, 221}, {195, 80, 150, 222}}},
{Region: "Slovenia", Group: "Premium UDP Europe", Hostname: "87-1-si.cg-dialup.net", IPs: []net.IP{{195, 80, 150, 211}, {195, 80, 150, 212}, {195, 80, 150, 213}, {195, 80, 150, 215}, {195, 80, 150, 216}, {195, 80, 150, 217}, {195, 80, 150, 218}, {195, 80, 150, 219}, {195, 80, 150, 220}, {195, 80, 150, 221}}}, {Region: "Slovenia", Group: "Premium UDP Europe", Hostname: "87-1-si.cg-dialup.net", IPs: []net.IP{{195, 80, 150, 211}, {195, 80, 150, 212}, {195, 80, 150, 214}, {195, 80, 150, 215}, {195, 80, 150, 216}, {195, 80, 150, 217}, {195, 80, 150, 219}, {195, 80, 150, 220}, {195, 80, 150, 221}, {195, 80, 150, 222}}},
{Region: "South Africa", Group: "Premium TCP Asia", Hostname: "96-1-za.cg-dialup.net", IPs: []net.IP{{154, 127, 50, 215}, {154, 127, 50, 216}, {154, 127, 50, 217}, {154, 127, 50, 220}, {154, 127, 50, 222}, {154, 127, 60, 194}, {154, 127, 60, 196}, {154, 127, 60, 198}, {154, 127, 60, 199}, {154, 127, 60, 202}}}, {Region: "South Africa", Group: "Premium TCP Asia", Hostname: "96-1-za.cg-dialup.net", IPs: []net.IP{{154, 127, 50, 212}, {154, 127, 50, 215}, {154, 127, 50, 217}, {154, 127, 50, 219}, {154, 127, 50, 220}, {154, 127, 50, 222}, {154, 127, 60, 196}, {154, 127, 60, 198}, {154, 127, 60, 199}, {154, 127, 60, 200}}},
{Region: "South Africa", Group: "Premium TCP Europe", Hostname: "97-1-za.cg-dialup.net", IPs: []net.IP{{197, 85, 7, 26}, {197, 85, 7, 27}, {197, 85, 7, 28}, {197, 85, 7, 29}, {197, 85, 7, 30}, {197, 85, 7, 31}, {197, 85, 7, 131}, {197, 85, 7, 132}, {197, 85, 7, 133}, {197, 85, 7, 134}}}, {Region: "South Africa", Group: "Premium TCP Europe", Hostname: "97-1-za.cg-dialup.net", IPs: []net.IP{{197, 85, 7, 26}, {197, 85, 7, 27}, {197, 85, 7, 28}, {197, 85, 7, 29}, {197, 85, 7, 30}, {197, 85, 7, 31}, {197, 85, 7, 131}, {197, 85, 7, 132}, {197, 85, 7, 133}, {197, 85, 7, 134}}},
{Region: "South Africa", Group: "Premium UDP Asia", Hostname: "95-1-za.cg-dialup.net", IPs: []net.IP{{154, 127, 50, 210}, {154, 127, 50, 214}, {154, 127, 50, 218}, {154, 127, 50, 219}, {154, 127, 50, 220}, {154, 127, 50, 221}, {154, 127, 50, 222}, {154, 127, 60, 195}, {154, 127, 60, 199}, {154, 127, 60, 206}}},
{Region: "South Africa", Group: "Premium UDP Europe", Hostname: "87-1-za.cg-dialup.net", IPs: []net.IP{{197, 85, 7, 26}, {197, 85, 7, 27}, {197, 85, 7, 28}, {197, 85, 7, 29}, {197, 85, 7, 30}, {197, 85, 7, 31}, {197, 85, 7, 131}, {197, 85, 7, 132}, {197, 85, 7, 133}, {197, 85, 7, 134}}}, {Region: "South Africa", Group: "Premium UDP Europe", Hostname: "87-1-za.cg-dialup.net", IPs: []net.IP{{197, 85, 7, 26}, {197, 85, 7, 27}, {197, 85, 7, 28}, {197, 85, 7, 29}, {197, 85, 7, 30}, {197, 85, 7, 31}, {197, 85, 7, 131}, {197, 85, 7, 132}, {197, 85, 7, 133}, {197, 85, 7, 134}}},
{Region: "Spain", Group: "Premium TCP Europe", Hostname: "97-1-es.cg-dialup.net", IPs: []net.IP{{37, 120, 142, 166}, {37, 120, 142, 171}, {82, 102, 26, 197}, {82, 102, 26, 199}, {82, 102, 26, 204}, {84, 17, 62, 135}, {84, 17, 62, 146}, {84, 17, 62, 153}, {185, 93, 3, 106}, {185, 253, 99, 203}}}, {Region: "Spain", Group: "Premium TCP Europe", Hostname: "97-1-es.cg-dialup.net", IPs: []net.IP{{37, 120, 142, 41}, {37, 120, 142, 52}, {37, 120, 142, 55}, {37, 120, 142, 61}, {37, 120, 142, 173}, {84, 17, 62, 131}, {84, 17, 62, 142}, {84, 17, 62, 144}, {185, 93, 3, 108}, {185, 93, 3, 114}}},
{Region: "Spain", Group: "Premium UDP Europe", Hostname: "87-1-es.cg-dialup.net", IPs: []net.IP{{37, 120, 142, 45}, {37, 120, 142, 53}, {37, 120, 142, 150}, {37, 120, 142, 151}, {82, 102, 26, 215}, {82, 102, 26, 221}, {84, 17, 62, 131}, {84, 17, 62, 153}, {185, 93, 3, 105}, {185, 93, 3, 112}}}, {Region: "Sri Lanka", Group: "Premium TCP Europe", Hostname: "97-1-lk.cg-dialup.net", IPs: []net.IP{{95, 181, 239, 131}, {95, 181, 239, 132}, {95, 181, 239, 133}, {95, 181, 239, 134}, {95, 181, 239, 135}, {95, 181, 239, 136}, {95, 181, 239, 137}, {95, 181, 239, 138}, {95, 181, 239, 140}, {95, 181, 239, 144}}},
{Region: "Sri Lanka", Group: "Premium TCP Europe", Hostname: "97-1-lk.cg-dialup.net", IPs: []net.IP{{95, 181, 239, 131}, {95, 181, 239, 132}, {95, 181, 239, 134}, {95, 181, 239, 135}, {95, 181, 239, 136}, {95, 181, 239, 137}, {95, 181, 239, 139}, {95, 181, 239, 140}, {95, 181, 239, 142}, {95, 181, 239, 144}}}, {Region: "Sri Lanka", Group: "Premium UDP Europe", Hostname: "87-1-lk.cg-dialup.net", IPs: []net.IP{{95, 181, 239, 131}, {95, 181, 239, 132}, {95, 181, 239, 133}, {95, 181, 239, 134}, {95, 181, 239, 135}, {95, 181, 239, 136}, {95, 181, 239, 140}, {95, 181, 239, 141}, {95, 181, 239, 142}, {95, 181, 239, 144}}},
{Region: "Sri Lanka", Group: "Premium UDP Europe", Hostname: "87-1-lk.cg-dialup.net", IPs: []net.IP{{95, 181, 239, 133}, {95, 181, 239, 134}, {95, 181, 239, 135}, {95, 181, 239, 138}, {95, 181, 239, 139}, {95, 181, 239, 140}, {95, 181, 239, 141}, {95, 181, 239, 142}, {95, 181, 239, 143}, {95, 181, 239, 144}}}, {Region: "Sweden", Group: "Premium TCP Europe", Hostname: "97-1-se.cg-dialup.net", IPs: []net.IP{{188, 126, 73, 207}, {188, 126, 73, 209}, {188, 126, 73, 214}, {188, 126, 73, 219}, {188, 126, 79, 6}, {188, 126, 79, 11}, {188, 126, 79, 19}, {188, 126, 79, 25}, {195, 246, 120, 148}, {195, 246, 120, 161}}},
{Region: "Sweden", Group: "Premium TCP Europe", Hostname: "97-1-se.cg-dialup.net", IPs: []net.IP{{188, 126, 73, 198}, {188, 126, 79, 5}, {188, 126, 79, 6}, {188, 126, 79, 11}, {188, 126, 79, 15}, {195, 246, 120, 144}, {195, 246, 120, 148}, {195, 246, 120, 156}, {195, 246, 120, 158}, {195, 246, 120, 165}}}, {Region: "Sweden", Group: "Premium UDP Europe", Hostname: "87-1-se.cg-dialup.net", IPs: []net.IP{{188, 126, 73, 201}, {188, 126, 73, 211}, {188, 126, 73, 213}, {188, 126, 73, 218}, {188, 126, 79, 6}, {188, 126, 79, 8}, {188, 126, 79, 19}, {195, 246, 120, 142}, {195, 246, 120, 144}, {195, 246, 120, 168}}},
{Region: "Sweden", Group: "Premium UDP Europe", Hostname: "87-1-se.cg-dialup.net", IPs: []net.IP{{188, 126, 73, 208}, {188, 126, 73, 219}, {188, 126, 73, 222}, {188, 126, 79, 5}, {188, 126, 79, 9}, {188, 126, 79, 17}, {188, 126, 79, 24}, {188, 126, 79, 25}, {195, 246, 120, 148}, {195, 246, 120, 154}}}, {Region: "Switzerland", Group: "Premium TCP Europe", Hostname: "97-1-ch.cg-dialup.net", IPs: []net.IP{{84, 17, 52, 4}, {84, 17, 52, 20}, {84, 17, 52, 44}, {84, 17, 52, 65}, {84, 17, 52, 72}, {84, 17, 52, 80}, {84, 17, 52, 83}, {84, 17, 52, 85}, {185, 32, 222, 112}, {185, 189, 150, 73}}},
{Region: "Switzerland", Group: "Premium TCP Europe", Hostname: "97-1-ch.cg-dialup.net", IPs: []net.IP{{84, 17, 52, 8}, {84, 17, 52, 33}, {84, 17, 52, 35}, {84, 17, 52, 47}, {84, 17, 52, 66}, {84, 17, 52, 72}, {185, 32, 222, 10}, {185, 32, 222, 11}, {185, 32, 222, 13}, {185, 32, 222, 113}}}, {Region: "Switzerland", Group: "Premium UDP Europe", Hostname: "87-1-ch.cg-dialup.net", IPs: []net.IP{{84, 17, 52, 5}, {84, 17, 52, 14}, {84, 17, 52, 24}, {84, 17, 52, 64}, {84, 17, 52, 73}, {84, 17, 52, 85}, {185, 32, 222, 114}, {185, 189, 150, 52}, {185, 189, 150, 57}, {195, 225, 118, 43}}},
{Region: "Taiwan", Group: "Premium TCP Asia", Hostname: "96-1-tw.cg-dialup.net", IPs: []net.IP{{45, 133, 181, 99}, {45, 133, 181, 100}, {45, 133, 181, 105}, {45, 133, 181, 106}, {45, 133, 181, 114}, {45, 133, 181, 119}, {45, 133, 181, 120}, {45, 133, 181, 121}, {45, 133, 181, 123}, {45, 133, 181, 126}}}, {Region: "Taiwan", Group: "Premium TCP Asia", Hostname: "96-1-tw.cg-dialup.net", IPs: []net.IP{{45, 133, 181, 100}, {45, 133, 181, 102}, {45, 133, 181, 103}, {45, 133, 181, 106}, {45, 133, 181, 109}, {45, 133, 181, 113}, {45, 133, 181, 115}, {45, 133, 181, 116}, {45, 133, 181, 123}, {45, 133, 181, 125}}},
{Region: "Thailand", Group: "Premium TCP Asia", Hostname: "96-1-th.cg-dialup.net", IPs: []net.IP{{146, 70, 13, 5}, {146, 70, 13, 6}, {146, 70, 13, 7}, {146, 70, 13, 8}, {146, 70, 13, 10}, {146, 70, 13, 11}, {146, 70, 13, 12}, {146, 70, 13, 13}, {146, 70, 13, 15}, {146, 70, 13, 16}}}, {Region: "Taiwan", Group: "Premium UDP Asia", Hostname: "95-1-tw.cg-dialup.net", IPs: []net.IP{{45, 133, 181, 99}, {45, 133, 181, 102}, {45, 133, 181, 107}, {45, 133, 181, 108}, {45, 133, 181, 109}, {45, 133, 181, 114}, {45, 133, 181, 116}, {45, 133, 181, 117}, {45, 133, 181, 123}, {45, 133, 181, 124}}},
{Region: "Thailand", Group: "Premium UDP Asia", Hostname: "95-1-th.cg-dialup.net", IPs: []net.IP{{146, 70, 13, 3}, {146, 70, 13, 4}, {146, 70, 13, 5}, {146, 70, 13, 6}, {146, 70, 13, 7}, {146, 70, 13, 8}, {146, 70, 13, 11}, {146, 70, 13, 13}, {146, 70, 13, 15}, {146, 70, 13, 16}}}, {Region: "Thailand", Group: "Premium TCP Asia", Hostname: "96-1-th.cg-dialup.net", IPs: []net.IP{{146, 70, 13, 3}, {146, 70, 13, 4}, {146, 70, 13, 6}, {146, 70, 13, 7}, {146, 70, 13, 8}, {146, 70, 13, 9}, {146, 70, 13, 11}, {146, 70, 13, 13}, {146, 70, 13, 15}, {146, 70, 13, 16}}},
{Region: "Turkey", Group: "Premium TCP Europe", Hostname: "97-1-tr.cg-dialup.net", IPs: []net.IP{{188, 213, 34, 5}, {188, 213, 34, 8}, {188, 213, 34, 10}, {188, 213, 34, 12}, {188, 213, 34, 29}, {188, 213, 34, 35}, {188, 213, 34, 39}, {188, 213, 34, 40}, {188, 213, 34, 41}, {188, 213, 34, 44}}}, {Region: "Thailand", Group: "Premium UDP Asia", Hostname: "95-1-th.cg-dialup.net", IPs: []net.IP{{146, 70, 13, 3}, {146, 70, 13, 4}, {146, 70, 13, 8}, {146, 70, 13, 9}, {146, 70, 13, 10}, {146, 70, 13, 11}, {146, 70, 13, 12}, {146, 70, 13, 13}, {146, 70, 13, 15}, {146, 70, 13, 16}}},
{Region: "Turkey", Group: "Premium UDP Europe", Hostname: "87-1-tr.cg-dialup.net", IPs: []net.IP{{188, 213, 34, 5}, {188, 213, 34, 13}, {188, 213, 34, 14}, {188, 213, 34, 17}, {188, 213, 34, 19}, {188, 213, 34, 27}, {188, 213, 34, 44}, {188, 213, 34, 101}, {188, 213, 34, 103}, {188, 213, 34, 108}}}, {Region: "Turkey", Group: "Premium TCP Europe", Hostname: "97-1-tr.cg-dialup.net", IPs: []net.IP{{188, 213, 34, 9}, {188, 213, 34, 11}, {188, 213, 34, 15}, {188, 213, 34, 16}, {188, 213, 34, 23}, {188, 213, 34, 25}, {188, 213, 34, 28}, {188, 213, 34, 41}, {188, 213, 34, 108}, {188, 213, 34, 110}}},
{Region: "Ukraine", Group: "Premium TCP Europe", Hostname: "97-1-ua.cg-dialup.net", IPs: []net.IP{{31, 28, 163, 39}, {31, 28, 163, 44}, {31, 28, 163, 50}, {62, 149, 7, 162}, {62, 149, 7, 169}, {62, 149, 29, 37}, {62, 149, 29, 41}, {62, 149, 29, 45}, {62, 149, 29, 50}, {62, 149, 29, 57}}}, {Region: "Turkey", Group: "Premium UDP Europe", Hostname: "87-1-tr.cg-dialup.net", IPs: []net.IP{{188, 213, 34, 8}, {188, 213, 34, 11}, {188, 213, 34, 14}, {188, 213, 34, 28}, {188, 213, 34, 35}, {188, 213, 34, 42}, {188, 213, 34, 43}, {188, 213, 34, 100}, {188, 213, 34, 103}, {188, 213, 34, 107}}},
{Region: "United Arab Emirates", Group: "Premium TCP Europe", Hostname: "97-1-ae.cg-dialup.net", IPs: []net.IP{{217, 138, 193, 179}, {217, 138, 193, 180}, {217, 138, 193, 181}, {217, 138, 193, 182}, {217, 138, 193, 185}, {217, 138, 193, 186}, {217, 138, 193, 187}, {217, 138, 193, 188}, {217, 138, 193, 189}, {217, 138, 193, 190}}}, {Region: "Ukraine", Group: "Premium TCP Europe", Hostname: "97-1-ua.cg-dialup.net", IPs: []net.IP{{31, 28, 161, 18}, {31, 28, 161, 20}, {31, 28, 161, 27}, {31, 28, 163, 34}, {31, 28, 163, 37}, {31, 28, 163, 44}, {62, 149, 7, 167}, {62, 149, 7, 172}, {62, 149, 29, 45}, {62, 149, 29, 57}}},
{Region: "United Kingdom", Group: "Premium TCP Europe", Hostname: "97-1-gb.cg-dialup.net", IPs: []net.IP{{45, 133, 172, 115}, {45, 133, 172, 137}, {95, 154, 200, 175}, {181, 215, 176, 248}, {191, 101, 209, 84}, {191, 101, 209, 111}, {191, 101, 209, 119}, {191, 101, 209, 136}, {194, 110, 13, 137}, {194, 110, 13, 149}}}, {Region: "Ukraine", Group: "Premium UDP Europe", Hostname: "87-1-ua.cg-dialup.net", IPs: []net.IP{{31, 28, 161, 27}, {31, 28, 163, 38}, {31, 28, 163, 42}, {31, 28, 163, 54}, {31, 28, 163, 61}, {62, 149, 7, 162}, {62, 149, 7, 163}, {62, 149, 29, 35}, {62, 149, 29, 38}, {62, 149, 29, 41}}},
{Region: "United States", Group: "Premium UDP USA", Hostname: "94-1-us.cg-dialup.net", IPs: []net.IP{{89, 187, 182, 22}, {108, 59, 0, 154}, {154, 21, 208, 153}, {154, 21, 208, 175}, {156, 146, 37, 17}, {156, 146, 37, 81}, {156, 146, 49, 145}, {156, 146, 59, 78}, {184, 170, 240, 202}, {199, 115, 119, 247}}}, {Region: "United Arab Emirates", Group: "Premium TCP Europe", Hostname: "97-1-ae.cg-dialup.net", IPs: []net.IP{{217, 138, 193, 179}, {217, 138, 193, 180}, {217, 138, 193, 181}, {217, 138, 193, 182}, {217, 138, 193, 183}, {217, 138, 193, 184}, {217, 138, 193, 185}, {217, 138, 193, 186}, {217, 138, 193, 188}, {217, 138, 193, 190}}},
{Region: "Venezuela", Group: "Premium TCP USA", Hostname: "93-1-ve.cg-dialup.net", IPs: []net.IP{{95, 181, 237, 131}, {95, 181, 237, 133}, {95, 181, 237, 134}, {95, 181, 237, 135}, {95, 181, 237, 136}, {95, 181, 237, 138}, {95, 181, 237, 140}, {95, 181, 237, 141}, {95, 181, 237, 143}, {95, 181, 237, 144}}}, {Region: "United Arab Emirates", Group: "Premium UDP Europe", Hostname: "87-1-ae.cg-dialup.net", IPs: []net.IP{{217, 138, 193, 179}, {217, 138, 193, 180}, {217, 138, 193, 181}, {217, 138, 193, 182}, {217, 138, 193, 183}, {217, 138, 193, 186}, {217, 138, 193, 187}, {217, 138, 193, 188}, {217, 138, 193, 189}, {217, 138, 193, 190}}},
{Region: "Venezuela", Group: "Premium UDP USA", Hostname: "94-1-ve.cg-dialup.net", IPs: []net.IP{{95, 181, 237, 131}, {95, 181, 237, 133}, {95, 181, 237, 134}, {95, 181, 237, 137}, {95, 181, 237, 138}, {95, 181, 237, 139}, {95, 181, 237, 140}, {95, 181, 237, 141}, {95, 181, 237, 142}, {95, 181, 237, 144}}}, {Region: "United Kingdom", Group: "Premium TCP Europe", Hostname: "97-1-gb.cg-dialup.net", IPs: []net.IP{{45, 133, 173, 49}, {45, 133, 173, 56}, {45, 133, 173, 82}, {45, 133, 173, 86}, {95, 154, 200, 153}, {95, 154, 200, 156}, {181, 215, 176, 103}, {181, 215, 176, 246}, {181, 215, 176, 251}, {194, 110, 13, 141}}},
{Region: "Vietnam", Group: "Premium TCP Asia", Hostname: "96-1-vn.cg-dialup.net", IPs: []net.IP{{188, 214, 152, 99}, {188, 214, 152, 100}, {188, 214, 152, 101}, {188, 214, 152, 102}, {188, 214, 152, 103}, {188, 214, 152, 104}, {188, 214, 152, 106}, {188, 214, 152, 107}, {188, 214, 152, 108}, {188, 214, 152, 109}}}, {Region: "United Kingdom", Group: "Premium UDP Europe", Hostname: "87-1-gb.cg-dialup.net", IPs: []net.IP{{45, 133, 172, 100}, {45, 133, 172, 126}, {45, 133, 173, 84}, {95, 154, 200, 174}, {181, 215, 176, 110}, {181, 215, 176, 151}, {181, 215, 176, 158}, {191, 101, 209, 142}, {194, 110, 13, 107}, {194, 110, 13, 128}}},
{Region: "Vietnam", Group: "Premium UDP Asia", Hostname: "95-1-vn.cg-dialup.net", IPs: []net.IP{{188, 214, 152, 99}, {188, 214, 152, 100}, {188, 214, 152, 101}, {188, 214, 152, 102}, {188, 214, 152, 104}, {188, 214, 152, 105}, {188, 214, 152, 106}, {188, 214, 152, 107}, {188, 214, 152, 109}, {188, 214, 152, 110}}}, {Region: "United States", Group: "Premium TCP USA", Hostname: "93-1-us.cg-dialup.net", IPs: []net.IP{{102, 129, 145, 15}, {102, 129, 152, 195}, {102, 129, 152, 248}, {154, 21, 208, 159}, {185, 242, 5, 117}, {185, 242, 5, 123}, {185, 242, 5, 229}, {191, 96, 227, 173}, {191, 96, 227, 196}, {199, 115, 119, 248}}},
{Region: "United States", Group: "Premium UDP USA", Hostname: "94-1-us.cg-dialup.net", IPs: []net.IP{{23, 82, 14, 113}, {23, 105, 177, 122}, {45, 89, 173, 222}, {84, 17, 35, 4}, {89, 187, 171, 132}, {156, 146, 37, 45}, {156, 146, 59, 86}, {184, 170, 240, 231}, {191, 96, 150, 248}, {199, 115, 119, 248}}},
{Region: "Venezuela", Group: "Premium TCP USA", Hostname: "93-1-ve.cg-dialup.net", IPs: []net.IP{{95, 181, 237, 132}, {95, 181, 237, 133}, {95, 181, 237, 134}, {95, 181, 237, 135}, {95, 181, 237, 136}, {95, 181, 237, 138}, {95, 181, 237, 139}, {95, 181, 237, 140}, {95, 181, 237, 141}, {95, 181, 237, 143}}},
{Region: "Venezuela", Group: "Premium UDP USA", Hostname: "94-1-ve.cg-dialup.net", IPs: []net.IP{{95, 181, 237, 131}, {95, 181, 237, 132}, {95, 181, 237, 134}, {95, 181, 237, 135}, {95, 181, 237, 136}, {95, 181, 237, 140}, {95, 181, 237, 141}, {95, 181, 237, 142}, {95, 181, 237, 143}, {95, 181, 237, 144}}},
{Region: "Vietnam", Group: "Premium TCP Asia", Hostname: "96-1-vn.cg-dialup.net", IPs: []net.IP{{188, 214, 152, 99}, {188, 214, 152, 101}, {188, 214, 152, 103}, {188, 214, 152, 104}, {188, 214, 152, 105}, {188, 214, 152, 106}, {188, 214, 152, 107}, {188, 214, 152, 108}, {188, 214, 152, 109}, {188, 214, 152, 110}}},
{Region: "Vietnam", Group: "Premium UDP Asia", Hostname: "95-1-vn.cg-dialup.net", IPs: []net.IP{{188, 214, 152, 99}, {188, 214, 152, 100}, {188, 214, 152, 101}, {188, 214, 152, 102}, {188, 214, 152, 103}, {188, 214, 152, 104}, {188, 214, 152, 105}, {188, 214, 152, 106}, {188, 214, 152, 107}, {188, 214, 152, 109}}},
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -47,6 +47,7 @@ func IvpnServers() []models.IvpnServer {
{Country: "Austria", City: "", Hostname: "at.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{185, 244, 212, 66}}}, {Country: "Austria", City: "", Hostname: "at.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{185, 244, 212, 66}}},
{Country: "Belgium", City: "", Hostname: "be.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{194, 187, 251, 10}}}, {Country: "Belgium", City: "", Hostname: "be.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{194, 187, 251, 10}}},
{Country: "Brazil", City: "", Hostname: "br.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{45, 162, 229, 130}}}, {Country: "Brazil", City: "", Hostname: "br.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{45, 162, 229, 130}}},
{Country: "Bulgaria", City: "", Hostname: "bg.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{82, 102, 23, 18}}},
{Country: "Canada", City: "Montreal", Hostname: "ca-qc.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{87, 101, 92, 26}}}, {Country: "Canada", City: "Montreal", Hostname: "ca-qc.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{87, 101, 92, 26}}},
{Country: "Canada", City: "Toronto", Hostname: "ca.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{104, 254, 90, 178}}}, {Country: "Canada", City: "Toronto", Hostname: "ca.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{104, 254, 90, 178}}},
{Country: "Czech Republic", City: "", Hostname: "cz.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{195, 181, 160, 167}}}, {Country: "Czech Republic", City: "", Hostname: "cz.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{195, 181, 160, 167}}},
@@ -69,6 +70,7 @@ func IvpnServers() []models.IvpnServer {
{Country: "Serbia", City: "", Hostname: "rs.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{141, 98, 103, 250}}}, {Country: "Serbia", City: "", Hostname: "rs.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{141, 98, 103, 250}}},
{Country: "Singapore", City: "", Hostname: "sg.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{185, 128, 24, 186}}}, {Country: "Singapore", City: "", Hostname: "sg.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{185, 128, 24, 186}}},
{Country: "Slovakia", City: "", Hostname: "sk.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{185, 245, 85, 250}}}, {Country: "Slovakia", City: "", Hostname: "sk.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{185, 245, 85, 250}}},
{Country: "Spain", City: "", Hostname: "es.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{185, 93, 3, 193}}},
{Country: "Sweden", City: "", Hostname: "se.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{80, 67, 10, 138}}}, {Country: "Sweden", City: "", Hostname: "se.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{80, 67, 10, 138}}},
{Country: "Switzerland", City: "", Hostname: "ch.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{185, 212, 170, 138}}}, {Country: "Switzerland", City: "", Hostname: "ch.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{185, 212, 170, 138}}},
{Country: "USA", City: "Atlanta", Hostname: "us-ga.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{104, 129, 24, 146}}}, {Country: "USA", City: "Atlanta", Hostname: "us-ga.gw.ivpn.net", TCP: false, UDP: true, IPs: []net.IP{{104, 129, 24, 146}}},

View File

@@ -21,10 +21,10 @@ const (
RootHints string = "/etc/unbound/root.hints" RootHints string = "/etc/unbound/root.hints"
// RootKey is the filepath to the root.key file used by Unbound. // RootKey is the filepath to the root.key file used by Unbound.
RootKey string = "/etc/unbound/root.key" RootKey string = "/etc/unbound/root.key"
// Client key filepath, used by Cyberghost. // ClientKey is the client key filepath.
ClientKey string = "/gluetun/client.key" ClientKey string = "/gluetun/client.key"
// Client certificate filepath, used by Cyberghost. // ClientCertificate is the client certificate filepath.
ClientCertificate string = "/gluetun/client.crt" ClientCertificate string = "/gluetun/client.crt"
// Servers information filepath. // ServersData is the server information filepath.
ServersData = "/gluetun/servers.json" ServersData = "/gluetun/servers.json"
) )

View File

@@ -48,6 +48,7 @@ func PrivadoHostnameChoices() (choices []string) {
} }
//nolint:lll //nolint:lll
// PrivadoServers returns a slice of all the Privado servers.
func PrivadoServers() []models.PrivadoServer { func PrivadoServers() []models.PrivadoServer {
return []models.PrivadoServer{ return []models.PrivadoServer{
{Country: "Argentina", Region: "Buenos Aires F.D.", City: "Buenos Aires", Hostname: "eze-001.vpn.privado.io", IP: net.IP{168, 205, 93, 211}}, {Country: "Argentina", Region: "Buenos Aires F.D.", City: "Buenos Aires", Hostname: "eze-001.vpn.privado.io", IP: net.IP{168, 205, 93, 211}},

View File

@@ -55,43 +55,39 @@ func PurevpnHostnameChoices() (choices []string) {
func PurevpnServers() []models.PurevpnServer { func PurevpnServers() []models.PurevpnServer {
return []models.PurevpnServer{ return []models.PurevpnServer{
{Country: "Australia", Region: "New South Wales", City: "Sydney", Hostname: "au-sd2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{43, 245, 163, 82}, {46, 243, 245, 4}}}, {Country: "Australia", Region: "New South Wales", City: "Sydney", Hostname: "au-sd2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{43, 245, 163, 82}, {46, 243, 245, 4}}},
{Country: "Australia", Region: "New South Wales", City: "Sydney", Hostname: "au-sd2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{43, 245, 161, 80}, {43, 245, 161, 82}, {43, 245, 161, 84}}}, {Country: "Australia", Region: "New South Wales", City: "Sydney", Hostname: "au-sd2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{43, 245, 161, 80}, {43, 245, 161, 81}, {43, 245, 161, 82}, {43, 245, 161, 86}}},
{Country: "Australia", Region: "Western Australia", City: "Perth", Hostname: "au2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{43, 250, 205, 50}}}, {Country: "Australia", Region: "Western Australia", City: "Perth", Hostname: "au2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{43, 250, 205, 50}}},
{Country: "Australia", Region: "Western Australia", City: "Perth", Hostname: "au2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{43, 250, 205, 53}, {43, 250, 205, 65}}}, {Country: "Australia", Region: "Western Australia", City: "Perth", Hostname: "au2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{43, 250, 205, 50}, {43, 250, 205, 61}}},
{Country: "Australia", Region: "Western Australia", City: "Perth", Hostname: "au2-pe-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{43, 250, 205, 50}}}, {Country: "Australia", Region: "Western Australia", City: "Perth", Hostname: "au2-pe-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{43, 250, 205, 50}, {43, 250, 205, 51}}},
{Country: "Australia", Region: "Western Australia", City: "Perth", Hostname: "au2-pe-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{43, 250, 205, 52}, {43, 250, 205, 65}}}, {Country: "Australia", Region: "Western Australia", City: "Perth", Hostname: "au2-pe-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{43, 250, 205, 34}}},
{Country: "Austria", Region: "Vienna", City: "Vienna", Hostname: "at2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{217, 64, 127, 251}, {217, 64, 127, 252}}}, {Country: "Austria", Region: "Vienna", City: "Vienna", Hostname: "at2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{217, 64, 127, 251}, {217, 64, 127, 252}}},
{Country: "Austria", Region: "Vienna", City: "Vienna", Hostname: "at2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{37, 120, 212, 218}, {37, 120, 212, 220}, {217, 64, 127, 251}}}, {Country: "Austria", Region: "Vienna", City: "Vienna", Hostname: "at2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{37, 120, 212, 219}, {217, 64, 127, 252}}},
{Country: "Belgium", Region: "Flanders", City: "Zaventem", Hostname: "vleu-be2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{217, 138, 211, 85}, {217, 138, 211, 86}, {217, 138, 211, 116}, {217, 138, 221, 114}}}, {Country: "Belgium", Region: "Flanders", City: "Zaventem", Hostname: "vleu-be2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{217, 138, 211, 87}, {217, 138, 211, 116}, {217, 138, 221, 117}}},
{Country: "Belgium", Region: "Flanders", City: "Zaventem", Hostname: "vleu-be2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{217, 138, 211, 87}, {217, 138, 211, 88}, {217, 138, 211, 114}}},
{Country: "Brazil", Region: "São Paulo", City: "São Paulo", Hostname: "br2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{181, 41, 201, 83}, {181, 41, 201, 84}}}, {Country: "Brazil", Region: "São Paulo", City: "São Paulo", Hostname: "br2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{181, 41, 201, 83}, {181, 41, 201, 84}}},
{Country: "Brazil", Region: "São Paulo", City: "São Paulo", Hostname: "br2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{138, 99, 210, 4}, {181, 41, 201, 77}, {181, 41, 201, 83}}}, {Country: "Brazil", Region: "São Paulo", City: "São Paulo", Hostname: "br2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{138, 99, 210, 4}, {181, 41, 201, 75}, {181, 41, 201, 82}, {181, 41, 201, 83}}},
{Country: "Canada", Region: "British Columbia", City: "Vancouver", Hostname: "cav2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{66, 115, 147, 34}, {66, 115, 147, 35}}}, {Country: "Bulgaria", Region: "Sofia-Capital", City: "Sofia", Hostname: "vleu-be2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{217, 138, 221, 114}}},
{Country: "Canada", Region: "British Columbia", City: "Vancouver", Hostname: "cav2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{66, 115, 147, 38}, {66, 115, 147, 39}, {66, 115, 147, 40}}}, {Country: "Canada", Region: "British Columbia", City: "Vancouver", Hostname: "cav2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{66, 115, 147, 34}}},
{Country: "Canada", Region: "Ontario", City: "Toronto", Hostname: "ca2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{104, 200, 138, 212}, {104, 200, 138, 213}}}, {Country: "Canada", Region: "British Columbia", City: "Vancouver", Hostname: "cav2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{66, 115, 147, 34}, {66, 115, 147, 35}, {66, 115, 147, 37}, {66, 115, 147, 38}, {66, 115, 147, 40}, {66, 115, 147, 43}}},
{Country: "Canada", Region: "Ontario", City: "Toronto", Hostname: "ca2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{104, 200, 138, 178}, {104, 200, 138, 212}, {104, 200, 138, 218}, {104, 200, 138, 219}}}, {Country: "Canada", Region: "Ontario", City: "Toronto", Hostname: "ca2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{104, 200, 138, 212}}},
{Country: "Czech Republic", Region: "Hlavní město Praha", City: "Prague", Hostname: "cz2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{185, 156, 174, 35}, {185, 156, 174, 36}}}, {Country: "Canada", Region: "Ontario", City: "Toronto", Hostname: "ca2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{104, 200, 138, 213}, {104, 200, 138, 214}, {104, 200, 138, 216}}},
{Country: "Czech Republic", Region: "Hlavní město Praha", City: "Prague", Hostname: "cz2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{185, 156, 174, 36}, {217, 138, 199, 252}}}, {Country: "Czech Republic", Region: "Hlavní město Praha", City: "Prague", Hostname: "cz2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{185, 156, 174, 36}}},
{Country: "France", Region: "Île-de-France", City: "Paris", Hostname: "fr2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{89, 40, 183, 148}}}, {Country: "Czech Republic", Region: "Hlavní město Praha", City: "Prague", Hostname: "cz2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{185, 156, 174, 38}, {217, 138, 199, 252}}},
{Country: "France", Region: "Île-de-France", City: "Paris", Hostname: "fr2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{45, 152, 181, 69}, {45, 152, 181, 70}}}, {Country: "France", Region: "Île-de-France", City: "Paris", Hostname: "fr2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{45, 152, 181, 68}}},
{Country: "Germany", Region: "Hesse", City: "Frankfurt am Main", Hostname: "de2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{5, 254, 88, 171}, {37, 120, 223, 50}}}, {Country: "France", Region: "Île-de-France", City: "Paris", Hostname: "fr2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{45, 152, 181, 67}, {45, 152, 181, 70}}},
{Country: "Germany", Region: "Hesse", City: "Frankfurt am Main", Hostname: "de2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{2, 57, 18, 22}, {217, 138, 194, 195}}}, {Country: "Germany", Region: "Hesse", City: "Frankfurt am Main", Hostname: "de2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{5, 254, 88, 213}}},
{Country: "Hong Kong", Region: "Central and Western", City: "Hong Kong", Hostname: "hk2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{103, 109, 103, 59}}}, {Country: "Germany", Region: "Hesse", City: "Frankfurt am Main", Hostname: "de2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{5, 254, 82, 50}, {5, 254, 82, 52}}},
{Country: "Hong Kong", Region: "Central and Western", City: "Hong Kong", Hostname: "hk2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{103, 109, 103, 60}, {172, 111, 168, 4}}}, {Country: "Hong Kong", Region: "Central and Western", City: "Hong Kong", Hostname: "hk2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{103, 109, 103, 59}, {103, 109, 103, 60}, {119, 81, 228, 109}}},
{Country: "Hong Kong", Region: "Central and Western", City: "Hong Kong", Hostname: "hk2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{172, 111, 168, 4}}},
{Country: "Hong Kong", Region: "Central and Western", City: "Hong Kong", Hostname: "vlap-ph2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{36, 255, 97, 3}, {129, 227, 119, 84}}}, {Country: "Hong Kong", Region: "Central and Western", City: "Hong Kong", Hostname: "vlap-ph2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{36, 255, 97, 3}, {129, 227, 119, 84}}},
{Country: "Hong Kong", Region: "Central and Western", City: "Hong Kong", Hostname: "vlap-ph2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{128, 1, 209, 21}}}, {Country: "Hong Kong", Region: "Central and Western", City: "Hong Kong", Hostname: "vlap-ph2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{36, 255, 97, 3}}},
{Country: "India", Region: "Tamil Nadu", City: "Tinnanūr", Hostname: "in2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{104, 250, 160, 132}, {178, 170, 141, 6}}},
{Country: "Indonesia", Region: "Aceh", City: "Bireun", Hostname: "in2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{169, 38, 97, 242}, {169, 38, 129, 21}}},
{Country: "Italy", Region: "Lombardy", City: "Milan", Hostname: "it2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{172, 111, 173, 3}}}, {Country: "Italy", Region: "Lombardy", City: "Milan", Hostname: "it2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{172, 111, 173, 3}}},
{Country: "Italy", Region: "Lombardy", City: "Milan", Hostname: "it2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{172, 111, 173, 3}}}, {Country: "Italy", Region: "Lombardy", City: "Milan", Hostname: "it2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{172, 111, 173, 3}}},
{Country: "Japan", Region: "Okinawa", City: "Hirara", Hostname: "tw2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{128, 1, 155, 178}}},
{Country: "Japan", Region: "Okinawa", City: "Hirara", Hostname: "tw2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{128, 1, 155, 178}}},
{Country: "Japan", Region: "Tokyo", City: "Tokyo", Hostname: "jp2-ovpn.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{185, 242, 4, 59}}}, {Country: "Japan", Region: "Tokyo", City: "Tokyo", Hostname: "jp2-ovpn.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{185, 242, 4, 59}}},
{Country: "Korea", Region: "Seoul", City: "Seoul", Hostname: "kr2-ovpn.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{43, 226, 231, 6}}}, {Country: "Korea", Region: "Gangwon-do", City: "Hongchŏn", Hostname: "kr2-ovpn.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{43, 226, 231, 4}, {43, 226, 231, 6}}},
{Country: "Malaysia", Region: "Kuala Lumpur", City: "Kuala Lumpur", Hostname: "my2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{103, 28, 90, 32}, {103, 55, 10, 133}}}, {Country: "Malaysia", Region: "Kuala Lumpur", City: "Kuala Lumpur", Hostname: "my2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{103, 55, 10, 134}}},
{Country: "Malaysia", Region: "Kuala Lumpur", City: "Kuala Lumpur", Hostname: "my2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{103, 55, 10, 4}, {103, 55, 10, 134}}}, {Country: "Malaysia", Region: "Kuala Lumpur", City: "Kuala Lumpur", Hostname: "my2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{103, 28, 90, 32}}},
{Country: "Netherlands", Region: "North Holland", City: "Amsterdam", Hostname: "nl2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{5, 254, 73, 253}}}, {Country: "Netherlands", Region: "North Holland", City: "Amsterdam", Hostname: "nl2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{5, 254, 73, 172}, {5, 254, 73, 252}, {92, 119, 179, 195}, {206, 123, 147, 4}}},
{Country: "Netherlands", Region: "North Holland", City: "Amsterdam", Hostname: "nl2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{5, 254, 73, 172}, {5, 254, 73, 203}}}, {Country: "Netherlands", Region: "North Holland", City: "Amsterdam", Hostname: "nl2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{5, 254, 73, 171}, {5, 254, 73, 202}, {92, 119, 179, 195}, {206, 123, 147, 4}}},
{Country: "Netherlands", Region: "North Holland", City: "Amsterdam", Hostname: "vlap-th2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{104, 37, 6, 4}}}, {Country: "Netherlands", Region: "North Holland", City: "Amsterdam", Hostname: "vlap-th2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{104, 37, 6, 4}}},
{Country: "Netherlands", Region: "North Holland", City: "Amsterdam", Hostname: "vlap-th2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{104, 37, 6, 4}}}, {Country: "Netherlands", Region: "North Holland", City: "Amsterdam", Hostname: "vlap-th2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{104, 37, 6, 4}}},
{Country: "Norway", Region: "Oslo", City: "Oslo", Hostname: "vleu-no2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{82, 102, 22, 212}}}, {Country: "Norway", Region: "Oslo", City: "Oslo", Hostname: "vleu-no2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{82, 102, 22, 212}}},
@@ -100,51 +96,55 @@ func PurevpnServers() []models.PurevpnServer {
{Country: "Portugal", Region: "Lisbon", City: "Lisbon", Hostname: "Pt2-ovpn.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{5, 154, 174, 3}}}, {Country: "Portugal", Region: "Lisbon", City: "Lisbon", Hostname: "Pt2-ovpn.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{5, 154, 174, 3}}},
{Country: "Russian Federation", Region: "St.-Petersburg", City: "Saint Petersburg", Hostname: "ru2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{94, 242, 54, 23}, {206, 123, 139, 4}}}, {Country: "Russian Federation", Region: "St.-Petersburg", City: "Saint Petersburg", Hostname: "ru2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{94, 242, 54, 23}, {206, 123, 139, 4}}},
{Country: "Russian Federation", Region: "St.-Petersburg", City: "Saint Petersburg", Hostname: "ru2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{94, 242, 54, 23}, {206, 123, 139, 4}}}, {Country: "Russian Federation", Region: "St.-Petersburg", City: "Saint Petersburg", Hostname: "ru2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{94, 242, 54, 23}, {206, 123, 139, 4}}},
{Country: "Singapore", Region: "Singapore", City: "Singapore", Hostname: "sg2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{37, 120, 208, 148}, {84, 247, 49, 180}}}, {Country: "Singapore", Region: "Singapore", City: "Singapore", Hostname: "sg2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{84, 247, 49, 181}}},
{Country: "Singapore", Region: "Singapore", City: "Singapore", Hostname: "sg2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{37, 120, 208, 147}, {37, 120, 208, 148}}}, {Country: "Singapore", Region: "Singapore", City: "Singapore", Hostname: "sg2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{37, 120, 208, 147}, {37, 120, 208, 148}}},
{Country: "Singapore", Region: "Singapore", City: "Singapore", Hostname: "vlap-vn2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{192, 253, 249, 132}}}, {Country: "South Africa", Region: "Gauteng", City: "Johannesburg", Hostname: "za2-ovpn.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{102, 165, 3, 33}, {102, 165, 3, 34}}},
{Country: "Singapore", Region: "Singapore", City: "Singapore", Hostname: "vlap-vn2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{192, 253, 249, 132}}}, {Country: "Sweden", Region: "Stockholm", City: "Stockholm", Hostname: "se2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{45, 12, 220, 123}, {86, 106, 103, 178}, {86, 106, 103, 179}}},
{Country: "South Africa", Region: "Gauteng", City: "Johannesburg", Hostname: "za2-ovpn.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{102, 165, 3, 34}}}, {Country: "Sweden", Region: "Stockholm", City: "Stockholm", Hostname: "se2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{45, 12, 220, 125}, {86, 106, 103, 183}}},
{Country: "Sweden", Region: "Stockholm", City: "Stockholm", Hostname: "se2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{45, 12, 220, 123}}},
{Country: "Sweden", Region: "Stockholm", City: "Stockholm", Hostname: "se2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{86, 106, 103, 181}, {86, 106, 103, 185}}},
{Country: "Switzerland", Region: "Zurich", City: "Zürich", Hostname: "ch2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{45, 12, 222, 98}, {45, 12, 222, 99}}}, {Country: "Switzerland", Region: "Zurich", City: "Zürich", Hostname: "ch2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{45, 12, 222, 98}, {45, 12, 222, 99}}},
{Country: "Switzerland", Region: "Zurich", City: "Zürich", Hostname: "ch2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{45, 12, 222, 100}, {45, 12, 222, 101}, {45, 12, 222, 104}, {45, 12, 222, 107}}}, {Country: "Switzerland", Region: "Zurich", City: "Zürich", Hostname: "ch2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{45, 12, 222, 100}, {45, 12, 222, 102}, {45, 12, 222, 106}, {45, 12, 222, 107}}},
{Country: "Taiwan", Region: "Taiwan", City: "Taipei", Hostname: "tw2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{128, 1, 155, 178}}},
{Country: "Taiwan", Region: "Taiwan", City: "Taipei", Hostname: "tw2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{128, 1, 155, 178}}},
{Country: "United Kingdom", Region: "England", City: "London", Hostname: "ukg2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{45, 74, 0, 4}}}, {Country: "United Kingdom", Region: "England", City: "London", Hostname: "ukg2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{45, 74, 0, 4}}},
{Country: "United Kingdom", Region: "England", City: "London", Hostname: "ukg2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{193, 9, 113, 70}}},
{Country: "United Kingdom", Region: "England", City: "London", Hostname: "ukl2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{45, 74, 0, 4}}}, {Country: "United Kingdom", Region: "England", City: "London", Hostname: "ukl2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{45, 74, 0, 4}}},
{Country: "United Kingdom", Region: "England", City: "London", Hostname: "ukl2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{89, 238, 165, 146}, {193, 9, 113, 70}}}, {Country: "United Kingdom", Region: "England", City: "Manchester", Hostname: "ukg2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{89, 238, 165, 148}, {89, 238, 165, 149}}},
{Country: "United Kingdom", Region: "England", City: "Manchester", Hostname: "ukl2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{89, 238, 165, 148}, {89, 238, 165, 149}}},
{Country: "United Kingdom", Region: "England", City: "Manchester", Hostname: "ukm2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{188, 72, 89, 4}}}, {Country: "United Kingdom", Region: "England", City: "Manchester", Hostname: "ukm2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{188, 72, 89, 4}}},
{Country: "United Kingdom", Region: "England", City: "Manchester", Hostname: "ukm2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{188, 72, 89, 4}}},
{Country: "United States", Region: "California", City: "Los Angeles", Hostname: "usla2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{89, 45, 4, 2}}}, {Country: "United States", Region: "California", City: "Los Angeles", Hostname: "usla2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{89, 45, 4, 2}}},
{Country: "United States", Region: "California", City: "Los Angeles", Hostname: "vlus-mx2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{104, 243, 243, 131}}}, {Country: "United States", Region: "California", City: "Los Angeles", Hostname: "vlus-mx2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{104, 243, 243, 131}}},
{Country: "United States", Region: "California", City: "Los Angeles", Hostname: "vlus-mx2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{104, 243, 243, 131}}}, {Country: "United States", Region: "California", City: "Los Angeles", Hostname: "vlus-mx2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{104, 243, 243, 131}}},
{Country: "United States", Region: "California", City: "Milpitas", Hostname: "usphx2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{141, 101, 166, 4}, {172, 94, 72, 4}}}, {Country: "United States", Region: "California", City: "San Jose", Hostname: "ussf2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{141, 101, 166, 4}}},
{Country: "United States", Region: "California", City: "Milpitas", Hostname: "ussf2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{141, 101, 166, 4}}}, {Country: "United States", Region: "Florida", City: "Miami", Hostname: "usfl2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{5, 254, 79, 100}, {5, 254, 79, 116}}},
{Country: "United States", Region: "California", City: "Milpitas", Hostname: "ussf2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{141, 101, 166, 4}}},
{Country: "United States", Region: "Florida", City: "Miami", Hostname: "usfl2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{5, 254, 79, 117}}},
{Country: "United States", Region: "Florida", City: "Miami", Hostname: "usfl2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{5, 254, 79, 114}, {5, 254, 79, 115}}}, {Country: "United States", Region: "Florida", City: "Miami", Hostname: "usfl2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{5, 254, 79, 114}, {5, 254, 79, 115}}},
{Country: "United States", Region: "New Jersey", City: "Harrison", Hostname: "vlus-pa2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{172, 111, 149, 4}}}, {Country: "United States", Region: "Georgia", City: "Cumming", Hostname: "in2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{169, 38, 69, 12}}},
{Country: "United States", Region: "New Jersey", City: "Harrison", Hostname: "vlus-pa2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{172, 111, 149, 4}}}, {Country: "United States", Region: "New Jersey", City: "Piscataway", Hostname: "usny2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{209, 127, 184, 71}, {209, 127, 184, 73}, {209, 127, 184, 74}, {209, 127, 184, 76}}},
{Country: "United States", Region: "New York", City: "New York City", Hostname: "usnj2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{172, 94, 72, 4}}}, {Country: "United States", Region: "New York", City: "New York City", Hostname: "usnj2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{172, 94, 72, 4}}},
{Country: "United States", Region: "New York", City: "New York City", Hostname: "usnj2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{172, 94, 72, 4}}}, {Country: "United States", Region: "New York", City: "New York City", Hostname: "usnj2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{172, 94, 72, 4}}},
{Country: "United States", Region: "New York", City: "New York City", Hostname: "usny2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{141, 101, 153, 4}}}, {Country: "United States", Region: "New York", City: "New York City", Hostname: "usny2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{141, 101, 153, 4}}},
{Country: "United States", Region: "New York", City: "New York City", Hostname: "usny2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{172, 94, 72, 4}}}, {Country: "United States", Region: "New York", City: "New York City", Hostname: "ussf2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{172, 94, 72, 4}, {172, 94, 86, 4}}},
{Country: "United States", Region: "New York", City: "New York City", Hostname: "uswdc2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{172, 94, 72, 4}, {172, 94, 86, 4}}},
{Country: "United States", Region: "New York", City: "New York City", Hostname: "vlus-pa2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{172, 111, 149, 4}}},
{Country: "United States", Region: "New York", City: "New York City", Hostname: "vlus-pa2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{172, 111, 149, 4}}},
{Country: "United States", Region: "Pennsylvania", City: "Pittsburgh", Hostname: "in2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{104, 250, 160, 132}}},
{Country: "United States", Region: "Texas", City: "Allen", Hostname: "usga2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{172, 94, 108, 4}}}, {Country: "United States", Region: "Texas", City: "Allen", Hostname: "usga2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{172, 94, 108, 4}}},
{Country: "United States", Region: "Texas", City: "Allen", Hostname: "usil2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{172, 94, 108, 4}}}, {Country: "United States", Region: "Texas", City: "Allen", Hostname: "usil2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{172, 94, 108, 4}}},
{Country: "United States", Region: "Texas", City: "Dallas", Hostname: "ukm2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{172, 94, 1, 4}, {172, 94, 72, 4}, {172, 94, 123, 4}}}, {Country: "United States", Region: "Texas", City: "Dallas", Hostname: "ustx2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{208, 84, 155, 100}, {208, 84, 155, 101}}},
{Country: "United States", Region: "Texas", City: "Dallas", Hostname: "ussa2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{172, 94, 1, 4}, {172, 94, 72, 4}}}, {Country: "United States", Region: "Texas", City: "Dallas", Hostname: "ustx2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{104, 217, 255, 185}, {104, 217, 255, 186}}},
{Country: "United States", Region: "Texas", City: "Dallas", Hostname: "ustx2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{104, 217, 255, 178}, {208, 84, 155, 100}}}, {Country: "United States", Region: "Virginia", City: "Centreville", Hostname: "usva2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{5, 254, 109, 115}, {37, 221, 173, 212}}},
{Country: "United States", Region: "Texas", City: "Dallas", Hostname: "ustx2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{104, 217, 255, 179}, {104, 217, 255, 184}, {104, 217, 255, 185}}},
{Country: "United States", Region: "Utah", City: "Salt Lake City", Hostname: "us2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{45, 74, 52, 4}}},
{Country: "United States", Region: "Utah", City: "Salt Lake City", Hostname: "usga2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{45, 74, 52, 4}, {172, 94, 1, 4}}},
{Country: "United States", Region: "Utah", City: "Salt Lake City", Hostname: "usil2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{45, 74, 52, 4}, {46, 243, 249, 4}, {172, 94, 72, 4}}},
{Country: "United States", Region: "Utah", City: "Salt Lake City", Hostname: "usla2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{45, 74, 52, 4}, {141, 101, 166, 4}, {172, 94, 1, 4}}},
{Country: "United States", Region: "Utah", City: "Salt Lake City", Hostname: "usut2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{45, 74, 52, 4}}},
{Country: "United States", Region: "Utah", City: "Salt Lake City", Hostname: "uswdc2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{45, 74, 52, 4}, {141, 101, 166, 4}, {172, 94, 72, 4}}},
{Country: "United States", Region: "Virginia", City: "Reston", Hostname: "usva2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{5, 254, 77, 26}, {5, 254, 77, 27}}}, {Country: "United States", Region: "Virginia", City: "Reston", Hostname: "usva2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{5, 254, 77, 26}, {5, 254, 77, 27}}},
{Country: "United States", Region: "Virginia", City: "Reston", Hostname: "usva2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{5, 254, 77, 26}, {5, 254, 77, 138}}}, {Country: "United States", Region: "Washington", City: "Seattle", Hostname: "ussa2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{172, 94, 86, 4}}},
{Country: "United States", Region: "Washington, D.C.", City: "Washington", Hostname: "us2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{46, 243, 249, 4}}}, {Country: "United States", Region: "Washington, D.C.", City: "Washington", Hostname: "us2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{46, 243, 249, 4}}},
{Country: "United States", Region: "Washington, D.C.", City: "Washington", Hostname: "us2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{141, 101, 169, 4}, {172, 94, 72, 4}, {172, 94, 86, 4}}},
{Country: "United States", Region: "Washington, D.C.", City: "Washington", Hostname: "usga2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{141, 101, 169, 4}, {172, 94, 86, 4}}},
{Country: "United States", Region: "Washington, D.C.", City: "Washington", Hostname: "usil2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{141, 101, 169, 4}, {172, 94, 72, 4}, {172, 94, 86, 4}}},
{Country: "United States", Region: "Washington, D.C.", City: "Washington", Hostname: "usla2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{141, 101, 169, 4}, {172, 94, 72, 4}}},
{Country: "United States", Region: "Washington, D.C.", City: "Washington", Hostname: "usphx2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{141, 101, 169, 4}}},
{Country: "United States", Region: "Washington, D.C.", City: "Washington", Hostname: "ussa2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{46, 243, 249, 4}}}, {Country: "United States", Region: "Washington, D.C.", City: "Washington", Hostname: "ussa2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{46, 243, 249, 4}}},
{Country: "United States", Region: "Washington, D.C.", City: "Washington", Hostname: "usut2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{46, 243, 249, 4}}}, {Country: "United States", Region: "Washington, D.C.", City: "Washington", Hostname: "usut2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{46, 243, 249, 4}}},
{Country: "United States", Region: "Washington, D.C.", City: "Washington", Hostname: "usut2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{141, 101, 169, 4}, {172, 94, 72, 4}, {172, 94, 86, 4}}},
{Country: "United States", Region: "Washington, D.C.", City: "Washington", Hostname: "uswdc2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{46, 243, 249, 4}}}, {Country: "United States", Region: "Washington, D.C.", City: "Washington", Hostname: "uswdc2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{46, 243, 249, 4}}},
{Country: "Vietnam", Region: "Hanoi", City: "Hanoi", Hostname: "vlap-vn2-ovpn-tcp.pointtoserver.com", TCP: true, UDP: false, IPs: []net.IP{{192, 253, 249, 132}}},
{Country: "Vietnam", Region: "Hanoi", City: "Hanoi", Hostname: "vlap-vn2-ovpn-udp.pointtoserver.com", TCP: false, UDP: true, IPs: []net.IP{{192, 253, 249, 132}}},
} }
} }

View File

@@ -8,7 +8,7 @@ func GetAllServers() (allServers models.AllServers) {
Version: 1, // used for migration of the top level scheme Version: 1, // used for migration of the top level scheme
Cyberghost: models.CyberghostServers{ Cyberghost: models.CyberghostServers{
Version: 2, // model version Version: 2, // model version
Timestamp: 1620491290, // latest takes precedence Timestamp: 1624307338, // latest takes precedence
Servers: CyberghostServers(), Servers: CyberghostServers(),
}, },
Fastestvpn: models.FastestvpnServers{ Fastestvpn: models.FastestvpnServers{
@@ -21,9 +21,14 @@ func GetAllServers() (allServers models.AllServers) {
Timestamp: 1620435633, Timestamp: 1620435633,
Servers: HideMyAssServers(), Servers: HideMyAssServers(),
}, },
Ipvanish: models.IpvanishServers{
Version: 1,
Timestamp: 1622430497,
Servers: IpvanishServers(),
},
Ivpn: models.IvpnServers{ Ivpn: models.IvpnServers{
Version: 1, Version: 1,
Timestamp: 1622421364, Timestamp: 1624120443,
Servers: IvpnServers(), Servers: IvpnServers(),
}, },
Mullvad: models.MullvadServers{ Mullvad: models.MullvadServers{
@@ -58,7 +63,7 @@ func GetAllServers() (allServers models.AllServers) {
}, },
Purevpn: models.PurevpnServers{ Purevpn: models.PurevpnServers{
Version: 2, Version: 2,
Timestamp: 1620606921, Timestamp: 1622644308,
Servers: PurevpnServers(), Servers: PurevpnServers(),
}, },
Surfshark: models.SurfsharkServers{ Surfshark: models.SurfsharkServers{
@@ -71,6 +76,11 @@ func GetAllServers() (allServers models.AllServers) {
Timestamp: 1620611129, Timestamp: 1620611129,
Servers: TorguardServers(), Servers: TorguardServers(),
}, },
VPNUnlimited: models.VPNUnlimitedServers{
Version: 1,
Timestamp: 1623950304,
Servers: VPNUnlimitedServers(),
},
Vyprvpn: models.VyprvpnServers{ Vyprvpn: models.VyprvpnServers{
Version: 2, Version: 2,
Timestamp: 1620612506, Timestamp: 1620612506,

View File

@@ -50,6 +50,11 @@ func Test_versions(t *testing.T) {
version: allServers.HideMyAss.Version, version: allServers.HideMyAss.Version,
digest: "a93b4057", digest: "a93b4057",
}, },
"Ipvanish": {
model: models.IpvanishServer{},
version: allServers.Ipvanish.Version,
digest: "2eb80d28",
},
"Ivpn": { "Ivpn": {
model: models.IvpnServer{}, model: models.IvpnServer{},
version: allServers.Ivpn.Version, version: allServers.Ivpn.Version,
@@ -100,6 +105,11 @@ func Test_versions(t *testing.T) {
version: allServers.Torguard.Version, version: allServers.Torguard.Version,
digest: "6eb9028e", digest: "6eb9028e",
}, },
"VPN Unlimited": {
model: models.VPNUnlimitedServer{},
version: allServers.VPNUnlimited.Version,
digest: "5cb51319",
},
"Vyprvpn": { "Vyprvpn": {
model: models.VyprvpnServer{}, model: models.VyprvpnServer{},
version: allServers.Vyprvpn.Version, version: allServers.Vyprvpn.Version,
@@ -150,7 +160,7 @@ func Test_timestamps(t *testing.T) {
"Cyberghost": { "Cyberghost": {
servers: allServers.Cyberghost.Servers, servers: allServers.Cyberghost.Servers,
timestamp: allServers.Cyberghost.Timestamp, timestamp: allServers.Cyberghost.Timestamp,
digest: "1de7ee68", digest: "b3ca3118",
}, },
"Fastestvpn": { "Fastestvpn": {
servers: allServers.Fastestvpn.Version, servers: allServers.Fastestvpn.Version,
@@ -162,10 +172,15 @@ func Test_timestamps(t *testing.T) {
timestamp: allServers.HideMyAss.Timestamp, timestamp: allServers.HideMyAss.Timestamp,
digest: "8f872ac4", digest: "8f872ac4",
}, },
"Ipvanish": {
servers: allServers.Ipvanish.Servers,
timestamp: allServers.Ipvanish.Timestamp,
digest: "c62dcf98",
},
"Ivpn": { "Ivpn": {
servers: allServers.Ivpn.Servers, servers: allServers.Ivpn.Servers,
timestamp: allServers.Ivpn.Timestamp, timestamp: allServers.Ivpn.Timestamp,
digest: "158630c0", digest: "42f92754",
}, },
"Mullvad": { "Mullvad": {
servers: allServers.Mullvad.Servers, servers: allServers.Mullvad.Servers,
@@ -200,7 +215,7 @@ func Test_timestamps(t *testing.T) {
"Purevpn": { "Purevpn": {
servers: allServers.Purevpn.Servers, servers: allServers.Purevpn.Servers,
timestamp: allServers.Purevpn.Timestamp, timestamp: allServers.Purevpn.Timestamp,
digest: "e48aa76d", digest: "9263cfdb",
}, },
"Surfshark": { "Surfshark": {
servers: allServers.Surfshark.Servers, servers: allServers.Surfshark.Servers,
@@ -212,6 +227,11 @@ func Test_timestamps(t *testing.T) {
timestamp: allServers.Torguard.Timestamp, timestamp: allServers.Torguard.Timestamp,
digest: "af54b9e8", digest: "af54b9e8",
}, },
"VPN Unlimited": {
servers: allServers.VPNUnlimited.Servers,
timestamp: allServers.VPNUnlimited.Timestamp,
digest: "f6ddb84c",
},
"Vyprvpn": { "Vyprvpn": {
servers: allServers.Vyprvpn.Servers, servers: allServers.Vyprvpn.Servers,
timestamp: allServers.Vyprvpn.Timestamp, timestamp: allServers.Vyprvpn.Timestamp,

View File

@@ -30,7 +30,7 @@ func TorguardCityChoices() (choices []string) {
return makeUnique(choices) return makeUnique(choices)
} }
func TorguardHostnamesChoices() (choices []string) { func TorguardHostnameChoices() (choices []string) {
servers := TorguardServers() servers := TorguardServers()
choices = make([]string, len(servers)) choices = make([]string, len(servers))
for i := range servers { for i := range servers {

View File

@@ -7,11 +7,13 @@ const (
Fastestvpn = "fastestvpn" Fastestvpn = "fastestvpn"
// HideMyAss is a VPN provider. // HideMyAss is a VPN provider.
HideMyAss = "hidemyass" HideMyAss = "hidemyass"
// Ipvanish is a VPN provider.
Ipvanish = "ipvanish"
// Ivpn is a VPN provider. // Ivpn is a VPN provider.
Ivpn = "ivpn" Ivpn = "ivpn"
// Mullvad is a VPN provider. // Mullvad is a VPN provider.
Mullvad = "mullvad" Mullvad = "mullvad"
// NordVPN is a VPN provider. // Nordvpn is a VPN provider.
Nordvpn = "nordvpn" Nordvpn = "nordvpn"
// Privado is a VPN provider. // Privado is a VPN provider.
Privado = "privado" Privado = "privado"
@@ -21,12 +23,14 @@ const (
Privatevpn = "privatevpn" Privatevpn = "privatevpn"
// Protonvpn is a VPN provider. // Protonvpn is a VPN provider.
Protonvpn = "protonvpn" Protonvpn = "protonvpn"
// PureVPN is a VPN provider. // Purevpn is a VPN provider.
Purevpn = "purevpn" Purevpn = "purevpn"
// Surfshark is a VPN provider. // Surfshark is a VPN provider.
Surfshark = "surfshark" Surfshark = "surfshark"
// Torguard is a VPN provider. // Torguard is a VPN provider.
Torguard = "torguard" Torguard = "torguard"
// VPNUnlimited is a VPN provider.
VPNUnlimited = "vpn unlimited"
// Vyprvpn is a VPN provider. // Vyprvpn is a VPN provider.
Vyprvpn = "vyprvpn" Vyprvpn = "vyprvpn"
// Windscribe is a VPN provider. // Windscribe is a VPN provider.

View File

@@ -0,0 +1,124 @@
package constants
import (
"net"
"github.com/qdm12/gluetun/internal/models"
)
//nolint:lll
const (
VPNUnlimitedCertificateAuthority = "MIIEjjCCA/egAwIBAgIJAKsVbHBdakXuMA0GCSqGSIb3DQEBBQUAMIHgMQswCQYDVQQGEwJVUzELMAkGA1UECBMCTlkxETAPBgNVBAcTCE5ldyBZb3JrMR8wHQYDVQQKExZTaW1wbGV4IFNvbHV0aW9ucyBJbmMuMRYwFAYDVQQLEw1WcG4gVW5saW1pdGVkMSMwIQYDVQQDExpzZXJ2ZXIudnBudW5saW1pdGVkYXBwLmNvbTEjMCEGA1UEKRMac2VydmVyLnZwbnVubGltaXRlZGFwcC5jb20xLjAsBgkqhkiG9w0BCQEWH3N1cHBvcnRAc2ltcGxleHNvbHV0aW9uc2luYy5jb20wHhcNMTMxMjE2MTM1OTQ0WhcNMjMxMjE0MTM1OTQ0WjCB4DELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk5ZMREwDwYDVQQHEwhOZXcgWW9yazEfMB0GA1UEChMWU2ltcGxleCBTb2x1dGlvbnMgSW5jLjEWMBQGA1UECxMNVnBuIFVubGltaXRlZDEjMCEGA1UEAxMac2VydmVyLnZwbnVubGltaXRlZGFwcC5jb20xIzAhBgNVBCkTGnNlcnZlci52cG51bmxpbWl0ZWRhcHAuY29tMS4wLAYJKoZIhvcNAQkBFh9zdXBwb3J0QHNpbXBsZXhzb2x1dGlvbnNpbmMuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDADUzS8QWGvdhLFKsEzAiq5+b0ukKjBza0k6/dmCeYTvCVqGKg/h1IAtQdVVLAkmEp0zvGH7PuOhXm7zZrCouBr/RiG4tEcoRHwc6AJmowkYERlY7+xGx3OuNrD00QceNTsan0bn78jwt0zhFNmHdoTtFjgK3oqmQYSAtbEVWYgwIDAQABo4IBTDCCAUgwHQYDVR0OBBYEFKClmYP+tMNgWagUJCCHjtaui2k+MIIBFwYDVR0jBIIBDjCCAQqAFKClmYP+tMNgWagUJCCHjtaui2k+oYHmpIHjMIHgMQswCQYDVQQGEwJVUzELMAkGA1UECBMCTlkxETAPBgNVBAcTCE5ldyBZb3JrMR8wHQYDVQQKExZTaW1wbGV4IFNvbHV0aW9ucyBJbmMuMRYwFAYDVQQLEw1WcG4gVW5saW1pdGVkMSMwIQYDVQQDExpzZXJ2ZXIudnBudW5saW1pdGVkYXBwLmNvbTEjMCEGA1UEKRMac2VydmVyLnZwbnVubGltaXRlZGFwcC5jb20xLjAsBgkqhkiG9w0BCQEWH3N1cHBvcnRAc2ltcGxleHNvbHV0aW9uc2luYy5jb22CCQCrFWxwXWpF7jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBALkWhfw7SSV7it+ZYZmT+cQbExjlYgQ40zae2J2CqIYACRcfsDHvh7Q+fiwSocevv2NE0dWi6WB2H6SiudYjvDvubAX/QbzfBxtbxCCoAIlfPCm8xOnWFN7TUJAzWwHJkKgEnu29GZHu2x8J+7VeDbKH5RTMHHe8FkSxh6Zz/BMN"
)
func VPNUnlimitedCountryChoices() (choices []string) {
servers := VPNUnlimitedServers()
choices = make([]string, len(servers))
for i := range servers {
choices[i] = servers[i].Country
}
return makeUnique(choices)
}
func VPNUnlimitedCityChoices() (choices []string) {
servers := VPNUnlimitedServers()
choices = make([]string, len(servers))
for i := range servers {
choices[i] = servers[i].City
}
return makeUnique(choices)
}
func VPNUnlimitedHostnameChoices() (choices []string) {
servers := VPNUnlimitedServers()
choices = make([]string, len(servers))
for i := range servers {
choices[i] = servers[i].Hostname
}
return makeUnique(choices)
}
//nolint:lll
// VPNUnlimitedServers returns a slice of all the server information for VPNUnlimited.
func VPNUnlimitedServers() []models.VPNUnlimitedServer {
return []models.VPNUnlimitedServer{
{Country: "Argentina", City: "", Hostname: "ar.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{131, 255, 4, 187}, {131, 255, 4, 235}}},
{Country: "Australia", City: "Sydney", Hostname: "au-syd.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{139, 99, 131, 38}, {139, 99, 130, 220}}},
{Country: "Austria", City: "", Hostname: "at.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{50, 7, 115, 19}, {185, 210, 219, 194}, {185, 210, 219, 198}}},
{Country: "Belarus", City: "", Hostname: "by.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 66, 68, 23}, {185, 66, 71, 108}, {185, 66, 71, 115}, {185, 66, 68, 84}, {185, 66, 71, 22}, {185, 66, 71, 122}, {185, 66, 71, 8}, {185, 66, 68, 18}}},
{Country: "Belgium", City: "", Hostname: "be.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{37, 120, 143, 178}, {82, 102, 19, 110}}},
{Country: "Bosnia and Herzegovina", City: "", Hostname: "ba.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 164, 35, 37}}},
{Country: "Brazil", City: "", Hostname: "br.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{66, 90, 70, 7}, {177, 67, 82, 222}, {177, 67, 82, 218}, {177, 67, 82, 228}, {177, 67, 82, 221}, {177, 67, 82, 219}, {177, 67, 82, 210}, {177, 67, 82, 223}}},
{Country: "Bulgaria", City: "", Hostname: "bg.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{37, 120, 152, 26}}},
{Country: "Canada", City: "", Hostname: "ca.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{192, 99, 7, 170}, {192, 99, 6, 164}, {192, 99, 14, 158}, {192, 99, 37, 199}, {192, 99, 6, 166}}},
{Country: "Canada", City: "Toronto", Hostname: "ca-tr.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{184, 75, 213, 154}, {162, 253, 131, 106}, {162, 219, 176, 163}, {104, 254, 90, 58}, {104, 254, 92, 42}, {184, 75, 213, 194}, {204, 187, 100, 82}, {104, 254, 90, 34}}},
{Country: "Canada", City: "Vancouver", Hostname: "ca-vn.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{162, 221, 202, 138}, {162, 221, 202, 134}, {162, 221, 202, 17}}},
{Country: "Costa Rica", City: "", Hostname: "cr.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{138, 59, 19, 8}}},
{Country: "Croatia", City: "", Hostname: "hr.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{85, 10, 56, 3}, {85, 10, 56, 100}, {85, 10, 51, 3}, {85, 10, 56, 4}}},
{Country: "Cyprus", City: "", Hostname: "cy.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{194, 30, 136, 123}, {194, 30, 136, 102}}},
{Country: "Czech Republic", City: "", Hostname: "cz.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 216, 35, 46}}},
{Country: "Denmark", City: "", Hostname: "dk.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{37, 120, 194, 174}, {89, 45, 7, 90}}},
{Country: "Estonia", City: "", Hostname: "ee.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 155, 96, 132}}},
{Country: "Finland", City: "", Hostname: "fi.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 112, 82, 26}, {91, 233, 116, 44}}},
{Country: "France", City: "", Hostname: "fr.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{195, 154, 189, 85}, {195, 154, 204, 36}, {195, 154, 211, 84}, {62, 210, 38, 83}, {195, 154, 169, 66}, {195, 154, 166, 20}, {62, 210, 204, 161}, {62, 210, 205, 16}, {62, 210, 139, 124}, {195, 154, 221, 54}, {195, 154, 199, 175}, {195, 154, 189, 212}, {195, 154, 180, 96}, {195, 154, 199, 155}, {195, 154, 209, 149}, {195, 154, 222, 168}}},
{Country: "France", City: "Roubaix", Hostname: "fr-rbx.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{151, 80, 27, 199}, {51, 255, 71, 16}, {147, 135, 137, 107}}},
{Country: "Germany", City: "", Hostname: "de.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{84, 16, 236, 168}, {178, 162, 205, 77}, {178, 162, 205, 115}, {178, 162, 205, 82}, {84, 16, 238, 220}}},
{Country: "Germany", City: "Düsseldorf", Hostname: "de-dus.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{146, 0, 42, 77}, {146, 0, 32, 121}, {85, 14, 243, 42}}},
{Country: "Greece", City: "", Hostname: "gr.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{154, 57, 3, 36}}},
{Country: "Hungary", City: "", Hostname: "hu.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{91, 219, 238, 174}}},
{Country: "Iceland", City: "", Hostname: "is.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{37, 235, 49, 75}, {151, 236, 24, 114}, {37, 235, 49, 42}, {37, 235, 49, 244}, {37, 235, 49, 70}, {37, 235, 49, 15}, {151, 236, 24, 142}}},
{Country: "India", City: "", Hostname: "in.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{103, 26, 204, 46}, {103, 26, 204, 84}}},
{Country: "India", City: "Karnataka", Hostname: "in-ka.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{139, 59, 67, 224}, {139, 59, 65, 136}, {139, 59, 24, 197}, {139, 59, 24, 198}, {139, 59, 24, 199}, {139, 59, 24, 191}, {139, 59, 16, 78}}},
{Country: "Ireland", City: "Dublin", Hostname: "ie-dub.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{188, 241, 178, 118}}},
{Country: "Isle of Man", City: "", Hostname: "im.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{192, 71, 211, 15}, {37, 235, 55, 62}, {37, 235, 55, 68}, {37, 235, 55, 14}, {37, 235, 55, 45}}},
{Country: "Israel", City: "", Hostname: "il.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{193, 182, 144, 170}, {193, 182, 144, 151}, {193, 182, 144, 23}}},
{Country: "Italy", City: "Milan", Hostname: "it-mil.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{91, 193, 5, 50}}},
{Country: "Japan", City: "", Hostname: "jp.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{172, 104, 67, 80}, {172, 104, 75, 121}, {161, 202, 97, 109}, {172, 104, 71, 35}, {172, 104, 126, 64}, {172, 104, 64, 213}, {85, 208, 110, 122}, {172, 104, 78, 67}, {172, 104, 83, 34}, {172, 104, 99, 172}, {161, 202, 97, 101}, {172, 104, 83, 13}, {172, 104, 87, 163}, {172, 104, 99, 14}}},
{Country: "Korea", City: "", Hostname: "kr.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{160, 202, 162, 60}, {160, 202, 163, 122}}},
{Country: "Kuala Lumpur", City: "", Hostname: "mys.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{111, 90, 141, 34}, {111, 90, 158, 159}}},
{Country: "Latvia", City: "", Hostname: "lv.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{195, 123, 213, 172}, {195, 123, 209, 168}}},
{Country: "Libya", City: "", Hostname: "ly.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{41, 208, 71, 39}}},
{Country: "Lithuania", City: "", Hostname: "lt.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 64, 105, 93}, {185, 64, 104, 142}, {185, 25, 48, 81}}},
{Country: "Luxembourg", City: "", Hostname: "lu.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{94, 242, 246, 45}, {94, 242, 246, 46}, {94, 242, 246, 77}, {94, 242, 246, 38}, {94, 242, 246, 47}}},
{Country: "Mexico", City: "", Hostname: "mx.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{169, 57, 35, 104}}},
{Country: "Moldova", City: "", Hostname: "md.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 163, 46, 141}}},
{Country: "Netherlands", City: "", Hostname: "nl.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{190, 2, 132, 115}, {190, 2, 132, 16}, {190, 2, 132, 52}}},
{Country: "New Zealand", City: "", Hostname: "nz.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{103, 75, 119, 109}, {103, 75, 119, 107}, {103, 75, 119, 105}, {103, 75, 119, 102}, {103, 75, 119, 103}, {103, 75, 119, 104}, {103, 75, 119, 106}, {103, 75, 119, 108}, {103, 75, 119, 101}, {103, 75, 119, 11}}},
{Country: "Norway", City: "", Hostname: "no.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 90, 61, 21}, {185, 90, 61, 74}}},
{Country: "Oman", City: "", Hostname: "om.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 226, 124, 110}}},
{Country: "Poland", City: "", Hostname: "pl.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{37, 120, 156, 234}}},
{Country: "Portugal", City: "", Hostname: "pt.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 31, 159, 110}}},
{Country: "Romania", City: "", Hostname: "ro.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 144, 83, 11}, {93, 115, 92, 207}, {185, 144, 83, 13}, {77, 81, 98, 70}, {93, 115, 92, 208}}},
{Country: "Serbia", City: "", Hostname: "rs.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{152, 89, 160, 142}}},
{Country: "Singapore", City: "", Hostname: "sg-free.vpnunlimitedapp.com", Free: true, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{178, 128, 48, 177}, {188, 166, 177, 236}, {206, 189, 80, 158}, {178, 128, 117, 139}}},
{Country: "Singapore", City: "", Hostname: "sg.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{50, 7, 60, 52}, {117, 20, 41, 9}, {117, 20, 41, 10}, {139, 99, 62, 61}}},
{Country: "Slovakia", City: "", Hostname: "sk.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{46, 29, 2, 131}}},
{Country: "Slovenia", City: "", Hostname: "si.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{192, 71, 244, 38}, {192, 71, 244, 28}}},
{Country: "South Africa", City: "", Hostname: "za.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{129, 232, 130, 187}, {129, 232, 219, 196}, {129, 232, 133, 41}, {129, 232, 129, 157}, {129, 232, 219, 195}, {129, 232, 134, 122}, {129, 232, 130, 186}, {129, 232, 130, 179}}},
{Country: "Spain", City: "", Hostname: "es.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{194, 99, 104, 58}, {195, 206, 107, 134}}},
{Country: "Sweden", City: "", Hostname: "se.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{91, 132, 138, 174}}},
{Country: "Switzerland", City: "", Hostname: "ch.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{152, 89, 162, 90}, {152, 89, 162, 86}}},
{Country: "Thailand", City: "", Hostname: "th.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{103, 159, 3, 121}}},
{Country: "Turkey", City: "", Hostname: "tr.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 17, 115, 62}, {185, 73, 202, 218}}},
{Country: "United Arab Emirates", City: "", Hostname: "ae.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{45, 9, 249, 201}, {45, 9, 249, 209}, {45, 9, 250, 147}, {45, 9, 250, 249}, {45, 9, 250, 138}, {45, 9, 249, 211}, {45, 9, 250, 144}, {45, 9, 249, 216}, {45, 9, 250, 145}, {45, 9, 250, 143}, {45, 9, 250, 134}, {45, 9, 250, 146}, {45, 9, 249, 202}}},
{Country: "United Kingdom", City: "", Hostname: "uk.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{176, 227, 198, 122}, {77, 245, 65, 2}, {109, 73, 77, 18}, {5, 152, 213, 186}, {88, 150, 224, 74}, {88, 150, 180, 82}}},
{Country: "United Kingdom", City: "London", Hostname: "uk-cv.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{5, 101, 169, 146}, {5, 101, 143, 66}, {178, 159, 10, 78}}},
{Country: "United Kingdom", City: "London", Hostname: "uk-lon.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{78, 110, 160, 6}, {50, 7, 114, 220}, {5, 101, 136, 154}, {23, 106, 33, 89}}},
{Country: "United States", City: "", Hostname: "us-stream.vpnunlimitedapp.com", Free: false, Stream: true, TCP: false, UDP: true, IPs: []net.IP{{167, 99, 96, 113}, {198, 199, 114, 155}, {192, 241, 194, 208}, {165, 227, 49, 171}, {159, 89, 128, 183}, {138, 197, 203, 142}, {64, 227, 111, 143}, {143, 110, 225, 79}, {164, 90, 144, 44}, {198, 199, 103, 243}, {198, 199, 96, 52}, {128, 199, 9, 51}, {143, 110, 156, 9}, {178, 128, 79, 75}, {198, 199, 97, 247}, {198, 199, 105, 87}, {198, 199, 103, 88}, {206, 189, 211, 205}, {206, 189, 165, 44}, {161, 35, 236, 242}}},
{Country: "United States", City: "", Hostname: "us.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{199, 115, 117, 81}, {199, 115, 115, 139}, {207, 244, 72, 212}, {199, 115, 115, 160}, {199, 115, 117, 73}}},
{Country: "United States", City: "Chicago", Hostname: "us-chi.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{66, 23, 205, 226}, {108, 62, 202, 211}, {173, 234, 41, 130}, {174, 34, 184, 130}}},
{Country: "United States", City: "Dallas", Hostname: "us-dal.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{172, 241, 115, 99}, {172, 241, 113, 19}, {172, 241, 112, 92}}},
{Country: "United States", City: "Denver", Hostname: "us-den.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{23, 237, 26, 131}, {23, 237, 26, 67}}},
{Country: "United States", City: "Houston", Hostname: "us-hou.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{162, 218, 228, 194}, {162, 218, 228, 196}, {66, 187, 75, 122}, {162, 218, 229, 106}}},
{Country: "United States", City: "Las Vegas", Hostname: "us-lv.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{185, 242, 5, 18}, {185, 242, 5, 22}}},
{Country: "United States", City: "Los Angeles", Hostname: "us-la.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{64, 31, 33, 154}, {192, 184, 48, 10}, {23, 83, 37, 209}, {23, 83, 37, 213}, {45, 136, 131, 40}, {69, 162, 99, 70}}},
{Country: "United States", City: "Miami", Hostname: "us-mia.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{186, 233, 185, 29}, {186, 233, 185, 79}, {186, 233, 185, 80}, {186, 233, 184, 187}, {186, 233, 184, 188}, {186, 233, 184, 37}, {186, 233, 184, 31}}},
{Country: "United States", City: "New York", Hostname: "us-ny-free.vpnunlimitedapp.com", Free: true, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{64, 94, 215, 66}, {64, 94, 215, 162}, {64, 94, 215, 170}}},
{Country: "United States", City: "New York", Hostname: "us-ny.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{64, 42, 178, 202}, {23, 105, 134, 162}, {64, 42, 178, 226}, {23, 237, 58, 112}, {23, 108, 31, 122}}},
{Country: "United States", City: "Saint Louis", Hostname: "us-sl.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{69, 64, 58, 110}, {69, 64, 58, 255}, {209, 239, 123, 77}, {209, 239, 123, 107}}},
{Country: "United States", City: "Salt Lake City", Hostname: "us-slc.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{209, 95, 53, 223}, {209, 95, 53, 225}}},
{Country: "United States", City: "San Francisco", Hostname: "us-sf.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{209, 58, 139, 34}, {209, 58, 135, 72}, {209, 58, 130, 210}, {209, 58, 135, 106}, {209, 58, 135, 108}, {209, 58, 135, 74}, {209, 58, 139, 35}, {209, 58, 137, 94}, {172, 241, 251, 164}, {209, 58, 135, 120}}},
{Country: "United States", City: "Seattle", Hostname: "us-sea.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{216, 244, 82, 50}, {23, 81, 209, 137}, {216, 244, 82, 210}}},
{Country: "Vietnam", City: "", Hostname: "vn.vpnunlimitedapp.com", Free: false, Stream: false, TCP: false, UDP: true, IPs: []net.IP{{103, 9, 78, 84}, {146, 196, 67, 7}}},
}
}

View File

@@ -21,6 +21,7 @@ func VyprvpnRegionChoices() (choices []string) {
} }
//nolint:lll //nolint:lll
// VyprvpnServers returns a slice of all the VyprVPN servers.
func VyprvpnServers() []models.VyprvpnServer { func VyprvpnServers() []models.VyprvpnServer {
return []models.VyprvpnServer{ return []models.VyprvpnServer{
{Region: "Algeria", Hostname: "dz1.vyprvpn.com", TCP: false, UDP: true, IPs: []net.IP{{209, 99, 75, 20}}}, {Region: "Algeria", Hostname: "dz1.vyprvpn.com", TCP: false, UDP: true, IPs: []net.IP{{209, 99, 75, 20}}},

View File

@@ -40,6 +40,7 @@ func WindscribeHostnameChoices() (choices []string) {
} }
//nolint:lll //nolint:lll
// WindscribeServers returns a slice of all the Windscribe servers.
func WindscribeServers() []models.WindscribeServer { func WindscribeServers() []models.WindscribeServer {
return []models.WindscribeServer{ return []models.WindscribeServer{
{Region: "Albania", City: "Tirana", Hostname: "al-002.whiskergalaxy.com", IPs: []net.IP{{31, 171, 152, 178}, {31, 171, 152, 179}, {31, 171, 152, 180}}}, {Region: "Albania", City: "Tirana", Hostname: "al-002.whiskergalaxy.com", IPs: []net.IP{{31, 171, 152, 178}, {31, 171, 152, 179}, {31, 171, 152, 180}}},

View File

@@ -159,6 +159,11 @@ func (l *looper) Run(ctx context.Context, done chan<- struct{}) {
stayHere = false stayHere = false
case err := <-waitError: // unexpected error case err := <-waitError: // unexpected error
unboundCancel() unboundCancel()
if ctx.Err() != nil {
close(waitError)
closeStreams()
return
}
l.state.setStatusWithLock(constants.Crashed) l.state.setStatusWithLock(constants.Crashed)
const fallback = true const fallback = true
l.useUnencryptedDNS(fallback) l.useUnencryptedDNS(fallback)

View File

@@ -6,7 +6,6 @@ import (
"strings" "strings"
"time" "time"
"github.com/kyokomi/emoji"
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
) )
@@ -36,7 +35,7 @@ func title() []string {
"=========== For tunneling to ============", "=========== For tunneling to ============",
"======== your favorite VPN server =======", "======== your favorite VPN server =======",
"=========================================", "=========================================",
"=== Made with " + emoji.Sprint(":heart:") + " by github.com/qdm12 ====", "=== Made with ❤️ by github.com/qdm12 ====",
"=========================================", "=========================================",
} }
} }
@@ -49,14 +48,14 @@ func announcement() []string {
if time.Now().After(expirationDate) { if time.Now().After(expirationDate) {
return nil return nil
} }
return []string{emoji.Sprint(":mega: ") + constants.Announcement} return []string{"📣" + constants.Announcement}
} }
func links() []string { func links() []string {
return []string{ return []string{
emoji.Sprint(":wrench: ") + "Need help? " + constants.IssueLink, "🔧 Need help? " + constants.IssueLink,
emoji.Sprint(":computer: ") + "Email? quentin.mcgaw@gmail.com", "💻 Email? quentin.mcgaw@gmail.com",
emoji.Sprint(":coffee: ") + "Slack? Join from the Slack button on Github", "Slack? Join from the Slack button on Github",
emoji.Sprint(":money_with_wings: ") + "Help me? https://github.com/sponsors/qdm12", "💰 Help me? https://github.com/sponsors/qdm12",
} }
} }

View File

@@ -47,6 +47,20 @@ func (s *HideMyAssServer) String() string {
s.Country, s.Region, s.City, s.Hostname, s.TCP, s.UDP, goStringifyIPs(s.IPs)) s.Country, s.Region, s.City, s.Hostname, s.TCP, s.UDP, goStringifyIPs(s.IPs))
} }
type IpvanishServer struct {
Country string `json:"country"`
City string `json:"city"`
Hostname string `json:"hostname"`
TCP bool `json:"tcp"`
UDP bool `json:"udp"`
IPs []net.IP `json:"ips"`
}
func (s *IpvanishServer) String() string {
return fmt.Sprintf("{Country: %q, City: %q, Hostname: %q, TCP: %t, UDP: %t, IPs: %s}",
s.Country, s.City, s.Hostname, s.TCP, s.UDP, goStringifyIPs(s.IPs))
}
type IvpnServer struct { type IvpnServer struct {
Country string `json:"country"` Country string `json:"country"`
City string `json:"city"` City string `json:"city"`
@@ -188,6 +202,22 @@ func (s *TorguardServer) String() string {
s.Country, s.City, s.Hostname, s.TCP, s.UDP, goStringifyIPs(s.IPs)) s.Country, s.City, s.Hostname, s.TCP, s.UDP, goStringifyIPs(s.IPs))
} }
type VPNUnlimitedServer struct {
Country string `json:"country"`
City string `json:"city"`
Hostname string `json:"hostname"`
Free bool `json:"free"`
Stream bool `json:"stream"`
TCP bool `json:"tcp"`
UDP bool `json:"udp"`
IPs []net.IP `json:"ips"`
}
func (s *VPNUnlimitedServer) String() string {
return fmt.Sprintf("{Country: %q, City: %q, Hostname: %q, Free: %t, Stream: %t, TCP: %t, UDP: %t, IPs: %s}",
s.Country, s.City, s.Hostname, s.Free, s.Stream, s.TCP, s.UDP, goStringifyIPs(s.IPs))
}
type VyprvpnServer struct { type VyprvpnServer struct {
Region string `json:"region"` Region string `json:"region"`
Hostname string `json:"hostname"` Hostname string `json:"hostname"`

View File

@@ -1,28 +1,31 @@
package models package models
type AllServers struct { type AllServers struct {
Version uint16 `json:"version"` Version uint16 `json:"version"`
Cyberghost CyberghostServers `json:"cyberghost"` Cyberghost CyberghostServers `json:"cyberghost"`
Fastestvpn FastestvpnServers `json:"fastestvpn"` Fastestvpn FastestvpnServers `json:"fastestvpn"`
HideMyAss HideMyAssServers `json:"hidemyass"` HideMyAss HideMyAssServers `json:"hidemyass"`
Ivpn IvpnServers `json:"ivpn"` Ipvanish IpvanishServers `json:"ipvanish"`
Mullvad MullvadServers `json:"mullvad"` Ivpn IvpnServers `json:"ivpn"`
Nordvpn NordvpnServers `json:"nordvpn"` Mullvad MullvadServers `json:"mullvad"`
Privado PrivadoServers `json:"privado"` Nordvpn NordvpnServers `json:"nordvpn"`
Pia PiaServers `json:"pia"` Privado PrivadoServers `json:"privado"`
Privatevpn PrivatevpnServers `json:"privatevpn"` Pia PiaServers `json:"pia"`
Protonvpn ProtonvpnServers `json:"protonvpn"` Privatevpn PrivatevpnServers `json:"privatevpn"`
Purevpn PurevpnServers `json:"purevpn"` Protonvpn ProtonvpnServers `json:"protonvpn"`
Surfshark SurfsharkServers `json:"surfshark"` Purevpn PurevpnServers `json:"purevpn"`
Torguard TorguardServers `json:"torguard"` Surfshark SurfsharkServers `json:"surfshark"`
Vyprvpn VyprvpnServers `json:"vyprvpn"` Torguard TorguardServers `json:"torguard"`
Windscribe WindscribeServers `json:"windscribe"` VPNUnlimited VPNUnlimitedServers `json:"vpnunlimited"`
Vyprvpn VyprvpnServers `json:"vyprvpn"`
Windscribe WindscribeServers `json:"windscribe"`
} }
func (a *AllServers) Count() int { func (a *AllServers) Count() int {
return len(a.Cyberghost.Servers) + return len(a.Cyberghost.Servers) +
len(a.Fastestvpn.Servers) + len(a.Fastestvpn.Servers) +
len(a.HideMyAss.Servers) + len(a.HideMyAss.Servers) +
len(a.Ipvanish.Servers) +
len(a.Ivpn.Servers) + len(a.Ivpn.Servers) +
len(a.Mullvad.Servers) + len(a.Mullvad.Servers) +
len(a.Nordvpn.Servers) + len(a.Nordvpn.Servers) +
@@ -33,6 +36,7 @@ func (a *AllServers) Count() int {
len(a.Purevpn.Servers) + len(a.Purevpn.Servers) +
len(a.Surfshark.Servers) + len(a.Surfshark.Servers) +
len(a.Torguard.Servers) + len(a.Torguard.Servers) +
len(a.VPNUnlimited.Servers) +
len(a.Vyprvpn.Servers) + len(a.Vyprvpn.Servers) +
len(a.Windscribe.Servers) len(a.Windscribe.Servers)
} }
@@ -52,6 +56,11 @@ type HideMyAssServers struct {
Timestamp int64 `json:"timestamp"` Timestamp int64 `json:"timestamp"`
Servers []HideMyAssServer `json:"servers"` Servers []HideMyAssServer `json:"servers"`
} }
type IpvanishServers struct {
Version uint16 `json:"version"`
Timestamp int64 `json:"timestamp"`
Servers []IpvanishServer `json:"servers"`
}
type IvpnServers struct { type IvpnServers struct {
Version uint16 `json:"version"` Version uint16 `json:"version"`
Timestamp int64 `json:"timestamp"` Timestamp int64 `json:"timestamp"`
@@ -102,6 +111,11 @@ type TorguardServers struct {
Timestamp int64 `json:"timestamp"` Timestamp int64 `json:"timestamp"`
Servers []TorguardServer `json:"servers"` Servers []TorguardServer `json:"servers"`
} }
type VPNUnlimitedServers struct {
Version uint16 `json:"version"`
Timestamp int64 `json:"timestamp"`
Servers []VPNUnlimitedServer `json:"servers"`
}
type VyprvpnServers struct { type VyprvpnServers struct {
Version uint16 `json:"version"` Version uint16 `json:"version"`
Timestamp int64 `json:"timestamp"` Timestamp int64 `json:"timestamp"`

View File

@@ -11,6 +11,7 @@ import (
"github.com/qdm12/gluetun/internal/configuration" "github.com/qdm12/gluetun/internal/configuration"
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/utils"
"github.com/qdm12/golibs/os" "github.com/qdm12/golibs/os"
) )
@@ -64,6 +65,7 @@ func modifyCustomConfig(lines []string, username string,
strings.HasPrefix(line, "verb "), strings.HasPrefix(line, "verb "),
strings.HasPrefix(line, "auth-user-pass "), strings.HasPrefix(line, "auth-user-pass "),
len(settings.Cipher) > 0 && strings.HasPrefix(line, "cipher "), len(settings.Cipher) > 0 && strings.HasPrefix(line, "cipher "),
len(settings.Cipher) > 0 && strings.HasPrefix(line, "data-ciphers"),
len(settings.Auth) > 0 && strings.HasPrefix(line, "auth "), len(settings.Auth) > 0 && strings.HasPrefix(line, "auth "),
settings.MSSFix > 0 && strings.HasPrefix(line, "mssfix "), settings.MSSFix > 0 && strings.HasPrefix(line, "mssfix "),
!settings.Provider.ExtraConfigOptions.OpenVPNIPv6 && strings.HasPrefix(line, "tun-ipv6"): !settings.Provider.ExtraConfigOptions.OpenVPNIPv6 && strings.HasPrefix(line, "tun-ipv6"):
@@ -78,10 +80,12 @@ func modifyCustomConfig(lines []string, username string,
modified = append(modified, "pull-filter ignore \"auth-token\"") // prevent auth failed loop modified = append(modified, "pull-filter ignore \"auth-token\"") // prevent auth failed loop
modified = append(modified, "auth-retry nointeract") modified = append(modified, "auth-retry nointeract")
modified = append(modified, "suppress-timestamps") modified = append(modified, "suppress-timestamps")
modified = append(modified, "auth-user-pass "+constants.OpenVPNAuthConf) if settings.User != "" {
modified = append(modified, "auth-user-pass "+constants.OpenVPNAuthConf)
}
modified = append(modified, "verb "+strconv.Itoa(settings.Verbosity)) modified = append(modified, "verb "+strconv.Itoa(settings.Verbosity))
if len(settings.Cipher) > 0 { if len(settings.Cipher) > 0 {
modified = append(modified, "cipher "+settings.Cipher) modified = append(modified, utils.CipherLines(settings.Cipher, settings.Version)...)
} }
if len(settings.Auth) > 0 { if len(settings.Auth) > 0 {
modified = append(modified, "auth "+settings.Auth) modified = append(modified, "auth "+settings.Auth)
@@ -193,10 +197,10 @@ func setConnectionToLines(lines []string, connection models.OpenVPNConnection) (
for i, line := range lines { for i, line := range lines {
switch { switch {
case strings.HasPrefix(line, "proto "): case strings.HasPrefix(line, "proto "):
lines[i] = "proto " + connection.Protocol lines[i] = connection.ProtoLine()
case strings.HasPrefix(line, "remote "): case strings.HasPrefix(line, "remote "):
lines[i] = "remote " + connection.RemoteLine() lines[i] = connection.RemoteLine()
} }
} }

View File

@@ -143,10 +143,12 @@ func (l *looper) Run(ctx context.Context, done chan<- struct{}) { //nolint:gocog
continue continue
} }
if err := l.conf.WriteAuthFile(settings.User, settings.Password, l.puid, l.pgid); err != nil { if settings.User != "" {
l.signalCrashedStatus() if err := l.conf.WriteAuthFile(settings.User, settings.Password, l.puid, l.pgid); err != nil {
l.logAndWait(ctx, err) l.signalCrashedStatus()
continue l.logAndWait(ctx, err)
continue
}
} }
if err := l.fw.SetVPNConnection(ctx, connection); err != nil { if err := l.fw.SetVPNConnection(ctx, connection); err != nil {
@@ -211,6 +213,14 @@ func (l *looper) Run(ctx context.Context, done chan<- struct{}) { //nolint:gocog
stayHere = false stayHere = false
case err := <-waitError: // unexpected error case err := <-waitError: // unexpected error
openvpnCancel() openvpnCancel()
if ctx.Err() != nil {
close(waitError)
close(stdoutLines)
close(stderrLines)
<-lineCollectionDone
<-portForwardDone
return
}
l.state.setStatusWithLock(constants.Crashed) l.state.setStatusWithLock(constants.Crashed)
l.logAndWait(ctx, err) l.logAndWait(ctx, err)
l.crashed = true l.crashed = true
@@ -317,8 +327,5 @@ func writeOpenvpnConf(lines []string, openFile os.OpenFileFunc) error {
if err != nil { if err != nil {
return err return err
} }
if err := file.Close(); err != nil { return file.Close()
return err
}
return nil
} }

View File

@@ -23,7 +23,7 @@ func (c *configurator) CheckTUN() error {
func (c *configurator) CreateTUN() error { func (c *configurator) CreateTUN() error {
c.logger.Info("creating %s", constants.TunnelDevice) c.logger.Info("creating %s", constants.TunnelDevice)
if err := c.os.MkdirAll("/dev/net", 0751); err != nil { if err := c.os.MkdirAll("/dev/net", 0751); err != nil { //nolint:gomnd
return err return err
} }
@@ -36,7 +36,7 @@ func (c *configurator) CreateTUN() error {
return err return err
} }
file, err := c.os.OpenFile(constants.TunnelDevice, os.O_WRONLY, 0666) file, err := c.os.OpenFile(constants.TunnelDevice, os.O_WRONLY, 0666) //nolint:gomnd
if err != nil { if err != nil {
return err return err
} }

View File

@@ -0,0 +1,45 @@
package ipvanish
import (
"errors"
"github.com/qdm12/gluetun/internal/configuration"
"github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/utils"
)
var ErrProtocolUnsupported = errors.New("network protocol is not supported")
func (i *Ipvanish) GetOpenVPNConnection(selection configuration.ServerSelection) (
connection models.OpenVPNConnection, err error) {
const port = 443
const protocol = constants.UDP
if selection.TCP {
return connection, ErrProtocolUnsupported
}
servers, err := i.filterServers(selection)
if err != nil {
return connection, err
}
var connections []models.OpenVPNConnection
for _, server := range servers {
for _, IP := range server.IPs {
connection := models.OpenVPNConnection{
IP: IP,
Port: port,
Protocol: protocol,
Hostname: server.Hostname,
}
connections = append(connections, connection)
}
}
if selection.TargetIP != nil {
return utils.GetTargetIPConnection(connections, selection.TargetIP)
}
return utils.PickRandomConnection(connections, i.randSource), nil
}

View File

@@ -0,0 +1,29 @@
package ipvanish
import (
"github.com/qdm12/gluetun/internal/configuration"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/utils"
)
func (i *Ipvanish) filterServers(selection configuration.ServerSelection) (
servers []models.IpvanishServer, err error) {
for _, server := range i.servers {
switch {
case
utils.FilterByPossibilities(server.Country, selection.Countries),
utils.FilterByPossibilities(server.City, selection.Cities),
utils.FilterByPossibilities(server.Hostname, selection.Hostnames),
selection.TCP && !server.TCP,
!selection.TCP && !server.UDP:
default:
servers = append(servers, server)
}
}
if len(servers) == 0 {
return nil, utils.NoServerFoundError(selection)
}
return servers, nil
}

View File

@@ -0,0 +1,65 @@
package ipvanish
import (
"strconv"
"github.com/qdm12/gluetun/internal/configuration"
"github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/utils"
)
func (i *Ipvanish) BuildConf(connection models.OpenVPNConnection,
username string, settings configuration.OpenVPN) (lines []string) {
if settings.Cipher == "" {
settings.Cipher = constants.AES256cbc
}
if settings.Auth == "" {
settings.Auth = constants.SHA256
}
lines = []string{
"client",
"dev tun",
"nobind",
"persist-key",
"ping-timer-rem",
"tls-exit",
// Ipvanish specific
"comp-lzo",
"tls-cipher TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-DSS-WITH-AES-256-CBC-SHA:TLS-RSA-WITH-AES-256-CBC-SHA",
"keysize 256",
// Added constant values
"mute-replay-warnings",
"auth-nocache",
"pull-filter ignore \"auth-token\"", // prevent auth failed loops
"auth-retry nointeract",
"suppress-timestamps",
// Modified variables
"verb " + strconv.Itoa(settings.Verbosity),
"auth-user-pass " + constants.OpenVPNAuthConf,
"proto " + connection.Protocol,
connection.RemoteLine(),
"verify-x509-name " + connection.Hostname + " name",
"auth " + settings.Auth,
}
lines = append(lines, utils.CipherLines(settings.Cipher, settings.Version)...)
if settings.MSSFix > 0 {
lines = append(lines, "mssfix "+strconv.Itoa(int(settings.MSSFix)))
}
if !settings.Root {
lines = append(lines, "user "+username)
}
lines = append(lines, utils.WrapOpenvpnCA(constants.IpvanishCA)...)
lines = append(lines, "")
return lines
}

View File

@@ -0,0 +1,17 @@
package ipvanish
import (
"context"
"net"
"net/http"
"github.com/qdm12/gluetun/internal/firewall"
"github.com/qdm12/golibs/logging"
"github.com/qdm12/golibs/os"
)
func (i *Ipvanish) PortForward(ctx context.Context, client *http.Client,
openFile os.OpenFileFunc, pfLogger logging.Logger, gateway net.IP,
fw firewall.Configurator, syncState func(port uint16) (pfFilepath string)) {
panic("port forwarding is not supported for Ipvanish")
}

View File

@@ -0,0 +1,19 @@
package ipvanish
import (
"math/rand"
"github.com/qdm12/gluetun/internal/models"
)
type Ipvanish struct {
servers []models.IpvanishServer
randSource rand.Source
}
func New(servers []models.IpvanishServer, randSource rand.Source) *Ipvanish {
return &Ipvanish{
servers: servers,
randSource: randSource,
}
}

View File

@@ -2,6 +2,7 @@ package ivpn
import ( import (
"strconv" "strconv"
"strings"
"github.com/qdm12/gluetun/internal/configuration" "github.com/qdm12/gluetun/internal/configuration"
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
@@ -15,6 +16,8 @@ func (i *Ivpn) BuildConf(connection models.OpenVPNConnection,
settings.Cipher = constants.AES256cbc settings.Cipher = constants.AES256cbc
} }
namePrefix := strings.Split(connection.Hostname, ".")[0]
lines = []string{ lines = []string{
"client", "client",
"dev tun", "dev tun",
@@ -43,7 +46,7 @@ func (i *Ivpn) BuildConf(connection models.OpenVPNConnection,
"auth-user-pass " + constants.OpenVPNAuthConf, "auth-user-pass " + constants.OpenVPNAuthConf,
"proto " + connection.Protocol, "proto " + connection.Protocol,
connection.RemoteLine(), connection.RemoteLine(),
"verify-x509-name " + connection.Hostname, // + " name-prefix" "verify-x509-name " + namePrefix + " name-prefix",
} }
lines = append(lines, utils.CipherLines(settings.Cipher, settings.Version)...) lines = append(lines, utils.CipherLines(settings.Cipher, settings.Version)...)

View File

@@ -2,7 +2,6 @@ package privateinternetaccess
import ( import (
"strconv" "strconv"
"strings"
"github.com/qdm12/gluetun/internal/configuration" "github.com/qdm12/gluetun/internal/configuration"
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
@@ -25,8 +24,8 @@ func (p *PIA) BuildConf(connection models.OpenVPNConnection,
X509CRL = constants.PiaX509CRLStrong X509CRL = constants.PiaX509CRLStrong
certificate = constants.PIACertificateStrong certificate = constants.PIACertificateStrong
default: // no encryption preset default: // no encryption preset
defaultCipher = "" defaultCipher = "none"
defaultAuth = "" defaultAuth = "none"
X509CRL = constants.PiaX509CRLNormal X509CRL = constants.PiaX509CRLNormal
certificate = constants.PIACertificateNormal certificate = constants.PIACertificateNormal
} }
@@ -49,7 +48,8 @@ func (p *PIA) BuildConf(connection models.OpenVPNConnection,
// PIA specific // PIA specific
"reneg-sec 0", "reneg-sec 0",
"disable-occ", "disable-occ",
"compress", // allow PIA server to choose the compression to use "compress", // allow PIA server to choose the compression to use
"ncp-disable", // prevent from auto-upgrading cipher to aes-256-gcm
// Added constant values // Added constant values
"auth-nocache", "auth-nocache",
@@ -73,10 +73,6 @@ func (p *PIA) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, "auth "+settings.Auth) lines = append(lines, "auth "+settings.Auth)
} }
if strings.HasSuffix(settings.Cipher, "-gcm") {
lines = append(lines, "ncp-disable")
}
if !settings.Root { if !settings.Root {
lines = append(lines, "user "+username) lines = append(lines, "user "+username)
} }

View File

@@ -25,6 +25,7 @@ var (
ErrBindPort = errors.New("cannot bind port") ErrBindPort = errors.New("cannot bind port")
) )
// PortForward obtains a VPN server side port forwarded from PIA.
//nolint:gocognit //nolint:gocognit
func (p *PIA) PortForward(ctx context.Context, client *http.Client, func (p *PIA) PortForward(ctx context.Context, client *http.Client,
openFile os.OpenFileFunc, logger logging.Logger, gateway net.IP, fw firewall.Configurator, openFile os.OpenFileFunc, logger logging.Logger, gateway net.IP, fw firewall.Configurator,

View File

@@ -15,6 +15,7 @@ import (
"github.com/qdm12/gluetun/internal/provider/cyberghost" "github.com/qdm12/gluetun/internal/provider/cyberghost"
"github.com/qdm12/gluetun/internal/provider/fastestvpn" "github.com/qdm12/gluetun/internal/provider/fastestvpn"
"github.com/qdm12/gluetun/internal/provider/hidemyass" "github.com/qdm12/gluetun/internal/provider/hidemyass"
"github.com/qdm12/gluetun/internal/provider/ipvanish"
"github.com/qdm12/gluetun/internal/provider/ivpn" "github.com/qdm12/gluetun/internal/provider/ivpn"
"github.com/qdm12/gluetun/internal/provider/mullvad" "github.com/qdm12/gluetun/internal/provider/mullvad"
"github.com/qdm12/gluetun/internal/provider/nordvpn" "github.com/qdm12/gluetun/internal/provider/nordvpn"
@@ -25,6 +26,7 @@ import (
"github.com/qdm12/gluetun/internal/provider/purevpn" "github.com/qdm12/gluetun/internal/provider/purevpn"
"github.com/qdm12/gluetun/internal/provider/surfshark" "github.com/qdm12/gluetun/internal/provider/surfshark"
"github.com/qdm12/gluetun/internal/provider/torguard" "github.com/qdm12/gluetun/internal/provider/torguard"
"github.com/qdm12/gluetun/internal/provider/vpnunlimited"
"github.com/qdm12/gluetun/internal/provider/vyprvpn" "github.com/qdm12/gluetun/internal/provider/vyprvpn"
"github.com/qdm12/gluetun/internal/provider/windscribe" "github.com/qdm12/gluetun/internal/provider/windscribe"
"github.com/qdm12/golibs/logging" "github.com/qdm12/golibs/logging"
@@ -49,6 +51,8 @@ func New(provider string, allServers models.AllServers, timeNow func() time.Time
return fastestvpn.New(allServers.Fastestvpn.Servers, randSource) return fastestvpn.New(allServers.Fastestvpn.Servers, randSource)
case constants.HideMyAss: case constants.HideMyAss:
return hidemyass.New(allServers.HideMyAss.Servers, randSource) return hidemyass.New(allServers.HideMyAss.Servers, randSource)
case constants.Ipvanish:
return ipvanish.New(allServers.Ipvanish.Servers, randSource)
case constants.Ivpn: case constants.Ivpn:
return ivpn.New(allServers.Ivpn.Servers, randSource) return ivpn.New(allServers.Ivpn.Servers, randSource)
case constants.Mullvad: case constants.Mullvad:
@@ -69,6 +73,8 @@ func New(provider string, allServers models.AllServers, timeNow func() time.Time
return surfshark.New(allServers.Surfshark.Servers, randSource) return surfshark.New(allServers.Surfshark.Servers, randSource)
case constants.Torguard: case constants.Torguard:
return torguard.New(allServers.Torguard.Servers, randSource) return torguard.New(allServers.Torguard.Servers, randSource)
case constants.VPNUnlimited:
return vpnunlimited.New(allServers.VPNUnlimited.Servers, randSource)
case constants.Vyprvpn: case constants.Vyprvpn:
return vyprvpn.New(allServers.Vyprvpn.Servers, randSource) return vyprvpn.New(allServers.Vyprvpn.Servers, randSource)
case constants.Windscribe: case constants.Windscribe:

View File

@@ -12,7 +12,7 @@ import (
func (p *Purevpn) BuildConf(connection models.OpenVPNConnection, func (p *Purevpn) BuildConf(connection models.OpenVPNConnection,
username string, settings configuration.OpenVPN) (lines []string) { username string, settings configuration.OpenVPN) (lines []string) {
if settings.Cipher == "" { if settings.Cipher == "" {
settings.Cipher = constants.AES256cbc settings.Cipher = constants.AES256gcm
} }
lines = []string{ lines = []string{

View File

@@ -0,0 +1,44 @@
package vpnunlimited
import (
"errors"
"github.com/qdm12/gluetun/internal/configuration"
"github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/utils"
)
var ErrProtocolUnsupported = errors.New("network protocol is not supported")
func (p *Provider) GetOpenVPNConnection(selection configuration.ServerSelection) (
connection models.OpenVPNConnection, err error) {
const port = 1194
const protocol = constants.UDP
if selection.TCP {
return connection, ErrProtocolUnsupported
}
servers, err := p.filterServers(selection)
if err != nil {
return connection, err
}
var connections []models.OpenVPNConnection
for _, server := range servers {
for _, IP := range server.IPs {
connection := models.OpenVPNConnection{
IP: IP,
Port: port,
Protocol: protocol,
}
connections = append(connections, connection)
}
}
if selection.TargetIP != nil {
return utils.GetTargetIPConnection(connections, selection.TargetIP)
}
return utils.PickRandomConnection(connections, p.randSource), nil
}

View File

@@ -0,0 +1,31 @@
package vpnunlimited
import (
"github.com/qdm12/gluetun/internal/configuration"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/utils"
)
func (p *Provider) filterServers(selection configuration.ServerSelection) (
servers []models.VPNUnlimitedServer, err error) {
for _, server := range p.servers {
switch {
case
utils.FilterByPossibilities(server.Country, selection.Countries),
utils.FilterByPossibilities(server.City, selection.Cities),
utils.FilterByPossibilities(server.Hostname, selection.Hostnames),
selection.FreeOnly && !server.Free,
selection.StreamOnly && !server.Stream,
selection.TCP && !server.TCP,
!selection.TCP && !server.UDP:
default:
servers = append(servers, server)
}
}
if len(servers) == 0 {
return nil, utils.NoServerFoundError(selection)
}
return servers, nil
}

View File

@@ -0,0 +1,69 @@
package vpnunlimited
import (
"strconv"
"github.com/qdm12/gluetun/internal/configuration"
"github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/utils"
)
func (p *Provider) BuildConf(connection models.OpenVPNConnection,
username string, settings configuration.OpenVPN) (lines []string) {
lines = []string{
"client",
"dev tun",
"nobind",
"persist-key",
"tls-exit",
"remote-cert-tls server",
// VPNUnlimited specific
"reneg-sec 0",
"ping 5",
"ping-exit 30",
"comp-lzo no",
"route-metric 1",
// Added constant values
"auth-nocache",
"mute-replay-warnings",
"pull-filter ignore \"auth-token\"", // prevent auth failed loops
"auth-retry nointeract",
"suppress-timestamps",
// Modified variables
"verb " + strconv.Itoa(settings.Verbosity),
// "auth-user-pass " + constants.OpenVPNAuthConf,
connection.ProtoLine(),
connection.RemoteLine(),
}
if settings.Cipher != "" {
lines = append(lines, utils.CipherLines(settings.Cipher, settings.Version)...)
}
if settings.Auth != "" {
lines = append(lines, "auth "+settings.Auth)
}
if settings.MSSFix > 0 {
lines = append(lines, "mssfix "+strconv.Itoa(int(settings.MSSFix)))
}
if !settings.Root {
lines = append(lines, "user "+username)
}
lines = append(lines, utils.WrapOpenvpnCA(
constants.VPNUnlimitedCertificateAuthority)...)
lines = append(lines, utils.WrapOpenvpnCert(
settings.Provider.ExtraConfigOptions.ClientCertificate)...)
lines = append(lines, utils.WrapOpenvpnKey(
settings.Provider.ExtraConfigOptions.ClientKey)...)
lines = append(lines, "")
return lines
}

View File

@@ -0,0 +1,17 @@
package vpnunlimited
import (
"context"
"net"
"net/http"
"github.com/qdm12/gluetun/internal/firewall"
"github.com/qdm12/golibs/logging"
"github.com/qdm12/golibs/os"
)
func (p *Provider) PortForward(ctx context.Context, client *http.Client,
openFile os.OpenFileFunc, pfLogger logging.Logger, gateway net.IP,
fw firewall.Configurator, syncState func(port uint16) (pfFilepath string)) {
panic("port forwarding is not supported for VPN Unlimited")
}

View File

@@ -0,0 +1,19 @@
package vpnunlimited
import (
"math/rand"
"github.com/qdm12/gluetun/internal/models"
)
type Provider struct {
servers []models.VPNUnlimitedServer
randSource rand.Source
}
func New(servers []models.VPNUnlimitedServer, randSource rand.Source) *Provider {
return &Provider{
servers: servers,
randSource: randSource,
}
}

View File

@@ -31,11 +31,7 @@ func (r *routing) setOutboundRoutes(outboundSubnets []net.IPNet,
} }
r.removeOutboundSubnets(subnetsToRemove, defaultInterfaceName, defaultGateway) r.removeOutboundSubnets(subnetsToRemove, defaultInterfaceName, defaultGateway)
if err := r.addOutboundSubnets(subnetsToAdd, defaultInterfaceName, defaultGateway); err != nil { return r.addOutboundSubnets(subnetsToAdd, defaultInterfaceName, defaultGateway)
return err
}
return nil
} }
func (r *routing) removeOutboundSubnets(subnets []net.IPNet, func (r *routing) removeOutboundSubnets(subnets []net.IPNet,

View File

@@ -139,6 +139,9 @@ func (l *looper) Run(ctx context.Context, done chan<- struct{}) {
case err := <-waitError: // unexpected error case err := <-waitError: // unexpected error
shadowsocksCancel() shadowsocksCancel()
close(waitError) close(waitError)
if ctx.Err() != nil {
return
}
l.state.setStatusWithLock(constants.Crashed) l.state.setStatusWithLock(constants.Crashed)
l.logAndWait(ctx, err) l.logAndWait(ctx, err)
crashed = true crashed = true

View File

@@ -1,49 +0,0 @@
package shutdown
import (
"context"
"errors"
"fmt"
"time"
"github.com/qdm12/golibs/logging"
)
type Order interface {
Append(waves ...Wave)
Shutdown(timeout time.Duration, logger logging.Logger) (err error)
}
type order struct {
waves []Wave
}
func NewOrder() Order {
return &order{}
}
var ErrIncomplete = errors.New("one or more routines did not terminate gracefully")
func (o *order) Append(waves ...Wave) {
o.waves = append(o.waves, waves...)
}
func (o *order) Shutdown(timeout time.Duration, logger logging.Logger) (err error) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
total := 0
incomplete := 0
for _, wave := range o.waves {
total += wave.size()
incomplete += wave.shutdown(ctx, logger)
}
if incomplete == 0 {
return nil
}
return fmt.Errorf("%w: %d not terminated on %d routines",
ErrIncomplete, incomplete, total)
}

View File

@@ -1,28 +0,0 @@
package shutdown
import (
"context"
"fmt"
"time"
)
type routine struct {
name string
cancel context.CancelFunc
done <-chan struct{}
timeout time.Duration
}
func (r *routine) shutdown(ctx context.Context) (err error) {
ctx, cancel := context.WithTimeout(ctx, r.timeout)
defer cancel()
r.cancel()
select {
case <-r.done:
return nil
case <-ctx.Done():
return fmt.Errorf("for routine %q: %w", r.name, ctx.Err())
}
}

View File

@@ -1,66 +0,0 @@
package shutdown
import (
"context"
"time"
"github.com/qdm12/golibs/logging"
)
type Wave interface {
Add(name string, timeout time.Duration) (
ctx context.Context, done chan struct{})
size() int
shutdown(ctx context.Context, logger logging.Logger) (incomplete int)
}
type wave struct {
name string
routines []routine
}
func NewWave(name string) Wave {
return &wave{
name: name,
}
}
func (w *wave) Add(name string, timeout time.Duration) (ctx context.Context, done chan struct{}) {
ctx, cancel := context.WithCancel(context.Background())
done = make(chan struct{})
routine := routine{
name: name,
cancel: cancel,
done: done,
timeout: timeout,
}
w.routines = append(w.routines, routine)
return ctx, done
}
func (w *wave) size() int { return len(w.routines) }
func (w *wave) shutdown(ctx context.Context, logger logging.Logger) (incomplete int) {
completed := make(chan bool)
for _, r := range w.routines {
go func(r routine) {
if err := r.shutdown(ctx); err != nil {
logger.Warn(w.name + " routines: " + err.Error() + " ⚠️")
completed <- false
} else {
logger.Info(w.name + " routines: " + r.name + " terminated ✔️")
completed <- err == nil
}
}(r)
}
for range w.routines {
c := <-completed
if !c {
incomplete++
}
}
return incomplete
}

View File

@@ -4,6 +4,7 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
) )
@@ -31,22 +32,24 @@ func (s *storage) logTimeDiff(provider string, persistedUnix, hardcodedUnix int6
func (s *storage) mergeServers(hardcoded, persisted models.AllServers) models.AllServers { func (s *storage) mergeServers(hardcoded, persisted models.AllServers) models.AllServers {
return models.AllServers{ return models.AllServers{
Version: hardcoded.Version, Version: hardcoded.Version,
Cyberghost: s.mergeCyberghost(hardcoded.Cyberghost, persisted.Cyberghost), Cyberghost: s.mergeCyberghost(hardcoded.Cyberghost, persisted.Cyberghost),
Fastestvpn: s.mergeFastestvpn(hardcoded.Fastestvpn, persisted.Fastestvpn), Fastestvpn: s.mergeFastestvpn(hardcoded.Fastestvpn, persisted.Fastestvpn),
HideMyAss: s.mergeHideMyAss(hardcoded.HideMyAss, persisted.HideMyAss), HideMyAss: s.mergeHideMyAss(hardcoded.HideMyAss, persisted.HideMyAss),
Ivpn: s.mergeIvpn(hardcoded.Ivpn, persisted.Ivpn), Ipvanish: s.mergeIpvanish(hardcoded.Ipvanish, persisted.Ipvanish),
Mullvad: s.mergeMullvad(hardcoded.Mullvad, persisted.Mullvad), Ivpn: s.mergeIvpn(hardcoded.Ivpn, persisted.Ivpn),
Nordvpn: s.mergeNordVPN(hardcoded.Nordvpn, persisted.Nordvpn), Mullvad: s.mergeMullvad(hardcoded.Mullvad, persisted.Mullvad),
Privado: s.mergePrivado(hardcoded.Privado, persisted.Privado), Nordvpn: s.mergeNordVPN(hardcoded.Nordvpn, persisted.Nordvpn),
Pia: s.mergePIA(hardcoded.Pia, persisted.Pia), Privado: s.mergePrivado(hardcoded.Privado, persisted.Privado),
Privatevpn: s.mergePrivatevpn(hardcoded.Privatevpn, persisted.Privatevpn), Pia: s.mergePIA(hardcoded.Pia, persisted.Pia),
Protonvpn: s.mergeProtonvpn(hardcoded.Protonvpn, persisted.Protonvpn), Privatevpn: s.mergePrivatevpn(hardcoded.Privatevpn, persisted.Privatevpn),
Purevpn: s.mergePureVPN(hardcoded.Purevpn, persisted.Purevpn), Protonvpn: s.mergeProtonvpn(hardcoded.Protonvpn, persisted.Protonvpn),
Surfshark: s.mergeSurfshark(hardcoded.Surfshark, persisted.Surfshark), Purevpn: s.mergePureVPN(hardcoded.Purevpn, persisted.Purevpn),
Torguard: s.mergeTorguard(hardcoded.Torguard, persisted.Torguard), Surfshark: s.mergeSurfshark(hardcoded.Surfshark, persisted.Surfshark),
Vyprvpn: s.mergeVyprvpn(hardcoded.Vyprvpn, persisted.Vyprvpn), Torguard: s.mergeTorguard(hardcoded.Torguard, persisted.Torguard),
Windscribe: s.mergeWindscribe(hardcoded.Windscribe, persisted.Windscribe), VPNUnlimited: s.mergeVPNUnlimited(hardcoded.VPNUnlimited, persisted.VPNUnlimited),
Vyprvpn: s.mergeVyprvpn(hardcoded.Vyprvpn, persisted.Vyprvpn),
Windscribe: s.mergeWindscribe(hardcoded.Windscribe, persisted.Windscribe),
} }
} }
@@ -91,6 +94,19 @@ func (s *storage) mergeHideMyAss(hardcoded, persisted models.HideMyAssServers) m
return persisted return persisted
} }
func (s *storage) mergeIpvanish(hardcoded, persisted models.IpvanishServers) models.IpvanishServers {
if persisted.Timestamp <= hardcoded.Timestamp {
return hardcoded
}
versionDiff := hardcoded.Version - persisted.Version
if versionDiff > 0 {
s.logVersionDiff("Ipvanish", versionDiff)
return hardcoded
}
s.logTimeDiff("Ipvanish", persisted.Timestamp, hardcoded.Timestamp)
return persisted
}
func (s *storage) mergeIvpn(hardcoded, persisted models.IvpnServers) models.IvpnServers { func (s *storage) mergeIvpn(hardcoded, persisted models.IvpnServers) models.IvpnServers {
if persisted.Timestamp <= hardcoded.Timestamp { if persisted.Timestamp <= hardcoded.Timestamp {
return hardcoded return hardcoded
@@ -234,6 +250,20 @@ func (s *storage) mergeTorguard(hardcoded, persisted models.TorguardServers) mod
return persisted return persisted
} }
func (s *storage) mergeVPNUnlimited(hardcoded, persisted models.VPNUnlimitedServers) models.VPNUnlimitedServers {
if persisted.Timestamp <= hardcoded.Timestamp {
return hardcoded
}
versionDiff := hardcoded.Version - persisted.Version
if versionDiff > 0 {
s.logVersionDiff(constants.VPNUnlimited, versionDiff)
return hardcoded
}
s.logTimeDiff(constants.VPNUnlimited, persisted.Timestamp, hardcoded.Timestamp)
return persisted
}
func (s *storage) mergeVyprvpn(hardcoded, persisted models.VyprvpnServers) models.VyprvpnServers { func (s *storage) mergeVyprvpn(hardcoded, persisted models.VyprvpnServers) models.VyprvpnServers {
if persisted.Timestamp <= hardcoded.Timestamp { if persisted.Timestamp <= hardcoded.Timestamp {
return hardcoded return hardcoded

View File

@@ -21,6 +21,7 @@ func countServers(allServers models.AllServers) int {
return len(allServers.Cyberghost.Servers) + return len(allServers.Cyberghost.Servers) +
len(allServers.Fastestvpn.Servers) + len(allServers.Fastestvpn.Servers) +
len(allServers.HideMyAss.Servers) + len(allServers.HideMyAss.Servers) +
len(allServers.Ipvanish.Servers) +
len(allServers.Ivpn.Servers) + len(allServers.Ivpn.Servers) +
len(allServers.Mullvad.Servers) + len(allServers.Mullvad.Servers) +
len(allServers.Nordvpn.Servers) + len(allServers.Nordvpn.Servers) +
@@ -31,6 +32,7 @@ func countServers(allServers models.AllServers) int {
len(allServers.Purevpn.Servers) + len(allServers.Purevpn.Servers) +
len(allServers.Surfshark.Servers) + len(allServers.Surfshark.Servers) +
len(allServers.Torguard.Servers) + len(allServers.Torguard.Servers) +
len(allServers.VPNUnlimited.Servers) +
len(allServers.Vyprvpn.Servers) + len(allServers.Vyprvpn.Servers) +
len(allServers.Windscribe.Servers) len(allServers.Windscribe.Servers)
} }

View File

@@ -5,5 +5,5 @@ import sysunix "golang.org/x/sys/unix"
// Constants used for convenience so "os" does not have to be imported // Constants used for convenience so "os" does not have to be imported
const ( const (
S_IFCHR = sysunix.S_IFCHR //nolint:golint S_IFCHR = sysunix.S_IFCHR //nolint:revive
) )

View File

@@ -4,9 +4,11 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/updater/providers/cyberghost" "github.com/qdm12/gluetun/internal/updater/providers/cyberghost"
"github.com/qdm12/gluetun/internal/updater/providers/fastestvpn" "github.com/qdm12/gluetun/internal/updater/providers/fastestvpn"
"github.com/qdm12/gluetun/internal/updater/providers/hidemyass" "github.com/qdm12/gluetun/internal/updater/providers/hidemyass"
"github.com/qdm12/gluetun/internal/updater/providers/ipvanish"
"github.com/qdm12/gluetun/internal/updater/providers/ivpn" "github.com/qdm12/gluetun/internal/updater/providers/ivpn"
"github.com/qdm12/gluetun/internal/updater/providers/mullvad" "github.com/qdm12/gluetun/internal/updater/providers/mullvad"
"github.com/qdm12/gluetun/internal/updater/providers/nordvpn" "github.com/qdm12/gluetun/internal/updater/providers/nordvpn"
@@ -17,6 +19,7 @@ import (
"github.com/qdm12/gluetun/internal/updater/providers/purevpn" "github.com/qdm12/gluetun/internal/updater/providers/purevpn"
"github.com/qdm12/gluetun/internal/updater/providers/surfshark" "github.com/qdm12/gluetun/internal/updater/providers/surfshark"
"github.com/qdm12/gluetun/internal/updater/providers/torguard" "github.com/qdm12/gluetun/internal/updater/providers/torguard"
"github.com/qdm12/gluetun/internal/updater/providers/vpnunlimited"
"github.com/qdm12/gluetun/internal/updater/providers/vyprvpn" "github.com/qdm12/gluetun/internal/updater/providers/vyprvpn"
"github.com/qdm12/gluetun/internal/updater/providers/windscribe" "github.com/qdm12/gluetun/internal/updater/providers/windscribe"
) )
@@ -75,6 +78,26 @@ func (u *updater) updateHideMyAss(ctx context.Context) (err error) {
return nil return nil
} }
func (u *updater) updateIpvanish(ctx context.Context) (err error) {
minServers := getMinServers(len(u.servers.Ipvanish.Servers))
servers, warnings, err := ipvanish.GetServers(
ctx, u.unzipper, u.presolver, minServers)
if u.options.CLI {
for _, warning := range warnings {
u.logger.Warn("Ipvanish: %s", warning)
}
}
if err != nil {
return err
}
if u.options.Stdout {
u.println(ipvanish.Stringify(servers))
}
u.servers.Ipvanish.Timestamp = u.timeNow().Unix()
u.servers.Ipvanish.Servers = servers
return nil
}
func (u *updater) updateIvpn(ctx context.Context) (err error) { func (u *updater) updateIvpn(ctx context.Context) (err error) {
minServers := getMinServers(len(u.servers.Ivpn.Servers)) minServers := getMinServers(len(u.servers.Ivpn.Servers))
servers, warnings, err := ivpn.GetServers( servers, warnings, err := ivpn.GetServers(
@@ -261,6 +284,26 @@ func (u *updater) updateTorguard(ctx context.Context) (err error) {
return nil return nil
} }
func (u *updater) updateVPNUnlimited(ctx context.Context) (err error) {
minServers := getMinServers(len(u.servers.VPNUnlimited.Servers))
servers, warnings, err := vpnunlimited.GetServers(
ctx, u.unzipper, u.presolver, minServers)
if u.options.CLI {
for _, warning := range warnings {
u.logger.Warn(constants.VPNUnlimited + ": " + warning)
}
}
if err != nil {
return err
}
if u.options.Stdout {
u.println(vpnunlimited.Stringify(servers))
}
u.servers.VPNUnlimited.Timestamp = u.timeNow().Unix()
u.servers.VPNUnlimited.Servers = servers
return nil
}
func (u *updater) updateVyprvpn(ctx context.Context) (err error) { func (u *updater) updateVyprvpn(ctx context.Context) (err error) {
minServers := getMinServers(len(u.servers.Vyprvpn.Servers)) minServers := getMinServers(len(u.servers.Vyprvpn.Servers))
servers, warnings, err := vyprvpn.GetServers( servers, warnings, err := vyprvpn.GetServers(

View File

@@ -13,9 +13,9 @@ func resolveHosts(ctx context.Context, presolver resolver.Parallel,
hostToIPs map[string][]net.IP, err error) { hostToIPs map[string][]net.IP, err error) {
const ( const (
maxFailRatio = 1 maxFailRatio = 1
maxDuration = 10 * time.Second maxDuration = 20 * time.Second
betweenDuration = 500 * time.Millisecond betweenDuration = time.Second
maxNoNew = 2 maxNoNew = 4
maxFails = 10 maxFails = 10
) )
settings := resolver.ParallelSettings{ settings := resolver.ParallelSettings{

View File

@@ -0,0 +1,39 @@
package ipvanish
import (
"errors"
"fmt"
"strings"
"github.com/qdm12/gluetun/internal/constants"
)
var errCountryCodeUnknown = errors.New("country code is unknown")
func parseFilename(fileName, hostname string) (
country, city string, err error) {
const prefix = "ipvanish-"
s := strings.TrimPrefix(fileName, prefix)
const ext = ".ovpn"
host := strings.Split(hostname, ".")[0]
suffix := "-" + host + ext
s = strings.TrimSuffix(s, suffix)
parts := strings.Split(s, "-")
countryCodes := constants.CountryCodes()
countryCode := strings.ToLower(parts[0])
country, ok := countryCodes[countryCode]
if !ok {
return "", "", fmt.Errorf("%w: %s", errCountryCodeUnknown, countryCode)
}
country = strings.Title(country)
if len(parts) > 1 {
city = strings.Join(parts[1:], " ")
city = strings.Title(city)
}
return country, city, nil
}

View File

@@ -0,0 +1,54 @@
package ipvanish
import (
"errors"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_parseFilename(t *testing.T) {
t.Parallel()
testCases := map[string]struct {
fileName string
hostname string
country string
city string
err error
}{
"unknown country code": {
fileName: "ipvanish-unknown-host.ovpn",
hostname: "host.ipvanish.com",
err: errors.New("country code is unknown: unknown"),
},
"country code only": {
fileName: "ipvanish-ca-host.ovpn",
hostname: "host.ipvanish.com",
country: "Canada",
},
"country code and city": {
fileName: "ipvanish-ca-sao-paulo-host.ovpn",
hostname: "host.ipvanish.com",
country: "Canada",
city: "Sao Paulo",
},
}
for name, testCase := range testCases {
testCase := testCase
t.Run(name, func(t *testing.T) {
t.Parallel()
country, city, err := parseFilename(testCase.fileName, testCase.hostname)
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.country, country)
assert.Equal(t, testCase.city, city)
})
}
}

View File

@@ -0,0 +1,58 @@
package ipvanish
import (
"net"
"sort"
"github.com/qdm12/gluetun/internal/models"
)
type hostToServer map[string]models.IpvanishServer
func (hts hostToServer) add(host, country, city string, tcp, udp bool) {
server, ok := hts[host]
if !ok {
server.Hostname = host
server.Country = country
server.City = city
}
if tcp {
server.TCP = tcp
}
if udp {
server.UDP = udp
}
hts[host] = server
}
func (hts hostToServer) toHostsSlice() (hosts []string) {
hosts = make([]string, 0, len(hts))
for host := range hts {
hosts = append(hosts, host)
}
sort.Slice(hosts, func(i, j int) bool {
return hosts[i] < hosts[j]
})
return hosts
}
func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]net.IP) {
for host, IPs := range hostToIPs {
server := hts[host]
server.IPs = IPs
hts[host] = server
}
for host, server := range hts {
if len(server.IPs) == 0 {
delete(hts, host)
}
}
}
func (hts hostToServer) toServersSlice() (servers []models.IpvanishServer) {
servers = make([]models.IpvanishServer, 0, len(hts))
for _, server := range hts {
servers = append(servers, server)
}
return servers
}

View File

@@ -0,0 +1,211 @@
package ipvanish
import (
"net"
"testing"
"github.com/qdm12/gluetun/internal/models"
"github.com/stretchr/testify/assert"
)
func Test_hostToServer_add(t *testing.T) {
t.Parallel()
testCases := map[string]struct {
initialHTS hostToServer
host string
country string
city string
tcp bool
udp bool
expectedHTS hostToServer
}{
"empty host to server": {
initialHTS: hostToServer{},
host: "host",
country: "country",
city: "city",
tcp: true,
udp: true,
expectedHTS: hostToServer{
"host": {
Hostname: "host",
Country: "country",
City: "city",
TCP: true,
UDP: true,
},
},
},
"add server": {
initialHTS: hostToServer{
"existing host": {},
},
host: "host",
country: "country",
city: "city",
tcp: true,
udp: true,
expectedHTS: hostToServer{
"existing host": {},
"host": models.IpvanishServer{
Hostname: "host",
Country: "country",
City: "city",
TCP: true,
UDP: true,
},
},
},
"extend existing server": {
initialHTS: hostToServer{
"host": models.IpvanishServer{
Hostname: "host",
Country: "country",
City: "city",
TCP: true,
},
},
host: "host",
country: "country",
city: "city",
tcp: false,
udp: true,
expectedHTS: hostToServer{
"host": models.IpvanishServer{
Hostname: "host",
Country: "country",
City: "city",
TCP: true,
UDP: true,
},
},
},
}
for name, testCase := range testCases {
testCase := testCase
t.Run(name, func(t *testing.T) {
t.Parallel()
testCase.initialHTS.add(testCase.host, testCase.country, testCase.city, testCase.tcp, testCase.udp)
assert.Equal(t, testCase.expectedHTS, testCase.initialHTS)
})
}
}
func Test_hostToServer_toHostsSlice(t *testing.T) {
t.Parallel()
testCases := map[string]struct {
hts hostToServer
hosts []string
}{
"empty host to server": {
hts: hostToServer{},
hosts: []string{},
},
"single host": {
hts: hostToServer{
"A": {},
},
hosts: []string{"A"},
},
"multiple hosts": {
hts: hostToServer{
"A": {},
"B": {},
},
hosts: []string{"A", "B"},
},
}
for name, testCase := range testCases {
testCase := testCase
t.Run(name, func(t *testing.T) {
t.Parallel()
hosts := testCase.hts.toHostsSlice()
assert.ElementsMatch(t, testCase.hosts, hosts)
})
}
}
func Test_hostToServer_adaptWithIPs(t *testing.T) {
t.Parallel()
testCases := map[string]struct {
initialHTS hostToServer
hostToIPs map[string][]net.IP
expectedHTS hostToServer
}{
"create server": {
initialHTS: hostToServer{},
hostToIPs: map[string][]net.IP{
"A": {{1, 2, 3, 4}},
},
expectedHTS: hostToServer{
"A": models.IpvanishServer{
IPs: []net.IP{{1, 2, 3, 4}},
},
},
},
"add IPs to existing server": {
initialHTS: hostToServer{
"A": models.IpvanishServer{
Country: "country",
},
},
hostToIPs: map[string][]net.IP{
"A": {{1, 2, 3, 4}},
},
expectedHTS: hostToServer{
"A": models.IpvanishServer{
Country: "country",
IPs: []net.IP{{1, 2, 3, 4}},
},
},
},
"remove server without IP": {
initialHTS: hostToServer{
"A": models.IpvanishServer{
Country: "country",
},
},
hostToIPs: map[string][]net.IP{},
expectedHTS: hostToServer{},
},
}
for name, testCase := range testCases {
testCase := testCase
t.Run(name, func(t *testing.T) {
t.Parallel()
testCase.initialHTS.adaptWithIPs(testCase.hostToIPs)
assert.Equal(t, testCase.expectedHTS, testCase.initialHTS)
})
}
}
func Test_hostToServer_toServersSlice(t *testing.T) {
t.Parallel()
testCases := map[string]struct {
hts hostToServer
servers []models.IpvanishServer
}{
"empty host to server": {
hts: hostToServer{},
servers: []models.IpvanishServer{},
},
"multiple servers": {
hts: hostToServer{
"A": {Country: "A"},
"B": {Country: "B"},
},
servers: []models.IpvanishServer{
{Country: "A"},
{Country: "B"},
},
},
}
for name, testCase := range testCases {
testCase := testCase
t.Run(name, func(t *testing.T) {
t.Parallel()
servers := testCase.hts.toServersSlice()
assert.ElementsMatch(t, testCase.servers, servers)
})
}
}

View File

@@ -0,0 +1,36 @@
package ipvanish
import (
"context"
"net"
"time"
"github.com/qdm12/gluetun/internal/updater/resolver"
)
func getResolveSettings(minServers int) (settings resolver.ParallelSettings) {
const (
maxFailRatio = 0.1
maxDuration = 20 * time.Second
betweenDuration = time.Second
maxNoNew = 2
maxFails = 2
)
return resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
MaxNoNew: maxNoNew,
MaxFails: maxFails,
},
}
}
func resolveHosts(ctx context.Context, presolver resolver.Parallel,
hosts []string, minServers int) (hostToIPs map[string][]net.IP,
warnings []string, err error) {
settings := getResolveSettings(minServers)
return presolver.Resolve(ctx, hosts, settings)
}

View File

@@ -0,0 +1,56 @@
package ipvanish
import (
"context"
"errors"
"net"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/updater/resolver"
"github.com/qdm12/gluetun/internal/updater/resolver/mock_resolver"
"github.com/stretchr/testify/assert"
)
func Test_resolveHosts(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
ctx := context.Background()
presolver := mock_resolver.NewMockParallel(ctrl)
hosts := []string{"host1", "host2"}
const minServers = 10
expectedHostToIPs := map[string][]net.IP{
"host1": {{1, 2, 3, 4}},
"host2": {{2, 3, 4, 5}},
}
expectedWarnings := []string{"warning1", "warning2"}
expectedErr := errors.New("dummy")
const (
maxFailRatio = 0.1
maxDuration = 20 * time.Second
betweenDuration = time.Second
maxNoNew = 2
maxFails = 2
)
expectedSettings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
MaxNoNew: maxNoNew,
MaxFails: maxFails,
},
}
presolver.EXPECT().Resolve(ctx, hosts, expectedSettings).
Return(expectedHostToIPs, expectedWarnings, expectedErr)
hostToIPs, warnings, err := resolveHosts(ctx, presolver, hosts, minServers)
assert.Equal(t, expectedHostToIPs, hostToIPs)
assert.Equal(t, expectedWarnings, warnings)
assert.Equal(t, expectedErr, err)
}

View File

@@ -0,0 +1,92 @@
// Package ipvanish contains code to obtain the server information
// for the Surshark provider.
package ipvanish
import (
"context"
"errors"
"fmt"
"strings"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/updater/openvpn"
"github.com/qdm12/gluetun/internal/updater/resolver"
"github.com/qdm12/gluetun/internal/updater/unzip"
)
var ErrNotEnoughServers = errors.New("not enough servers found")
func GetServers(ctx context.Context, unzipper unzip.Unzipper,
presolver resolver.Parallel, minServers int) (
servers []models.IpvanishServer, warnings []string, err error) {
const url = "https://www.ipvanish.com/software/configs/configs.zip"
contents, err := unzipper.FetchAndExtract(ctx, url)
if err != nil {
return nil, nil, err
} else if len(contents) < minServers {
return nil, nil, fmt.Errorf("%w: %d and expected at least %d",
ErrNotEnoughServers, len(contents), minServers)
}
hts := make(hostToServer)
for fileName, content := range contents {
if !strings.HasSuffix(fileName, ".ovpn") {
continue // not an OpenVPN file
}
tcp, udp, err := openvpn.ExtractProto(content)
if err != nil {
// treat error as warning and go to next file
warning := err.Error() + ": in " + fileName
warnings = append(warnings, warning)
continue
}
hostname, warning, err := openvpn.ExtractHost(content)
if warning != "" {
warnings = append(warnings, warning)
}
if err != nil {
// treat error as warning and go to next file
warning := err.Error() + " in " + fileName
warnings = append(warnings, warning)
continue
}
country, city, err := parseFilename(fileName, hostname)
if err != nil {
// treat error as warning and go to next file
warning := err.Error() + " in " + fileName
warnings = append(warnings, warning)
continue
}
hts.add(hostname, country, city, tcp, udp)
}
if len(hts) < minServers {
return nil, warnings, fmt.Errorf("%w: %d and expected at least %d",
ErrNotEnoughServers, len(hts), minServers)
}
hosts := hts.toHostsSlice()
hostToIPs, newWarnings, err := resolveHosts(ctx, presolver, hosts, minServers)
warnings = append(warnings, newWarnings...)
if err != nil {
return nil, warnings, err
}
hts.adaptWithIPs(hostToIPs)
servers = hts.toServersSlice()
if len(servers) < minServers {
return nil, warnings, fmt.Errorf("%w: %d and expected at least %d",
ErrNotEnoughServers, len(servers), minServers)
}
sortServers(servers)
return servers, warnings, nil
}

View File

@@ -0,0 +1,150 @@
package ipvanish
import (
"context"
"errors"
"net"
"testing"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/updater/resolver"
"github.com/qdm12/gluetun/internal/updater/resolver/mock_resolver"
"github.com/qdm12/gluetun/internal/updater/unzip/mock_unzip"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_GetServers(t *testing.T) {
t.Parallel()
testCases := map[string]struct {
// Inputs
minServers int
// Unzip
unzipContents map[string][]byte
unzipErr error
// Resolution
expectResolve bool
hostsToResolve []string
resolveSettings resolver.ParallelSettings
hostToIPs map[string][]net.IP
resolveWarnings []string
resolveErr error
// Output
servers []models.IpvanishServer
warnings []string
err error
}{
"unzipper error": {
unzipErr: errors.New("dummy"),
err: errors.New("dummy"),
},
"not enough unzip contents": {
minServers: 1,
unzipContents: map[string][]byte{},
err: errors.New("not enough servers found: 0 and expected at least 1"),
},
"no openvpn file": {
minServers: 1,
unzipContents: map[string][]byte{"somefile.txt": {}},
err: errors.New("not enough servers found: 0 and expected at least 1"),
},
"invalid proto": {
minServers: 1,
unzipContents: map[string][]byte{"badproto.ovpn": []byte(`proto invalid`)},
warnings: []string{"unknown protocol: invalid: in badproto.ovpn"},
err: errors.New("not enough servers found: 0 and expected at least 1"),
},
"no host": {
minServers: 1,
unzipContents: map[string][]byte{"nohost.ovpn": []byte(``)},
warnings: []string{"remote host not found in nohost.ovpn"},
err: errors.New("not enough servers found: 0 and expected at least 1"),
},
"multiple hosts": {
minServers: 1,
unzipContents: map[string][]byte{
"ipvanish-CA-City-A-hosta.ovpn": []byte("remote hosta\nremote hostb"),
},
expectResolve: true,
hostsToResolve: []string{"hosta"},
resolveSettings: getResolveSettings(1),
warnings: []string{"only using the first host \"hosta\" and discarding 1 other hosts"},
err: errors.New("not enough servers found: 0 and expected at least 1"),
},
"resolve error": {
unzipContents: map[string][]byte{
"ipvanish-CA-City-A-hosta.ovpn": []byte("remote hosta"),
},
expectResolve: true,
hostsToResolve: []string{"hosta"},
resolveSettings: getResolveSettings(0),
resolveWarnings: []string{"resolve warning"},
resolveErr: errors.New("dummy"),
warnings: []string{"resolve warning"},
err: errors.New("dummy"),
},
"filename parsing error": {
minServers: 1,
unzipContents: map[string][]byte{
"ipvanish-unknown-City-A-hosta.ovpn": []byte("remote hosta"),
},
warnings: []string{"country code is unknown: unknown in ipvanish-unknown-City-A-hosta.ovpn"},
err: errors.New("not enough servers found: 0 and expected at least 1"),
},
"success": {
minServers: 1,
unzipContents: map[string][]byte{
"ipvanish-CA-City-A-hosta.ovpn": []byte("remote hosta"),
"ipvanish-LU-City-B-hostb.ovpn": []byte("remote hostb"),
},
expectResolve: true,
hostsToResolve: []string{"hosta", "hostb"},
resolveSettings: getResolveSettings(1),
hostToIPs: map[string][]net.IP{
"hosta": {{1, 1, 1, 1}, {2, 2, 2, 2}},
"hostb": {{3, 3, 3, 3}, {4, 4, 4, 4}},
},
resolveWarnings: []string{"resolve warning"},
servers: []models.IpvanishServer{
{Country: "Canada", City: "City A", Hostname: "hosta", UDP: true, IPs: []net.IP{{1, 1, 1, 1}, {2, 2, 2, 2}}},
{Country: "Luxembourg", City: "City B", Hostname: "hostb", UDP: true, IPs: []net.IP{{3, 3, 3, 3}, {4, 4, 4, 4}}},
},
warnings: []string{"resolve warning"},
},
}
for name, testCase := range testCases {
testCase := testCase
t.Run(name, func(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
ctx := context.Background()
unzipper := mock_unzip.NewMockUnzipper(ctrl)
const zipURL = "https://www.ipvanish.com/software/configs/configs.zip"
unzipper.EXPECT().FetchAndExtract(ctx, zipURL).
Return(testCase.unzipContents, testCase.unzipErr)
presolver := mock_resolver.NewMockParallel(ctrl)
if testCase.expectResolve {
presolver.EXPECT().Resolve(ctx, testCase.hostsToResolve, testCase.resolveSettings).
Return(testCase.hostToIPs, testCase.resolveWarnings, testCase.resolveErr)
}
servers, warnings, err := GetServers(ctx, unzipper, presolver, testCase.minServers)
assert.Equal(t, testCase.servers, servers)
assert.Equal(t, testCase.warnings, warnings)
if testCase.err != nil {
require.Error(t, err)
assert.Equal(t, testCase.err.Error(), err.Error())
} else {
assert.NoError(t, err)
}
})
}
}

View File

@@ -0,0 +1,19 @@
package ipvanish
import (
"sort"
"github.com/qdm12/gluetun/internal/models"
)
func sortServers(servers []models.IpvanishServer) {
sort.Slice(servers, func(i, j int) bool {
if servers[i].Country == servers[j].Country {
if servers[i].City == servers[j].City {
return servers[i].Hostname < servers[j].Hostname
}
return servers[i].City < servers[j].City
}
return servers[i].Country < servers[j].Country
})
}

View File

@@ -0,0 +1,40 @@
package ipvanish
import (
"testing"
"github.com/qdm12/gluetun/internal/models"
"github.com/stretchr/testify/assert"
)
func Test_sortServers(t *testing.T) {
t.Parallel()
testCases := map[string]struct {
initialServers []models.IpvanishServer
sortedServers []models.IpvanishServer
}{
"no server": {},
"sorted servers": {
initialServers: []models.IpvanishServer{
{Country: "B", City: "A", Hostname: "A"},
{Country: "A", City: "A", Hostname: "B"},
{Country: "A", City: "A", Hostname: "A"},
{Country: "A", City: "B", Hostname: "A"},
},
sortedServers: []models.IpvanishServer{
{Country: "A", City: "A", Hostname: "A"},
{Country: "A", City: "A", Hostname: "B"},
{Country: "A", City: "B", Hostname: "A"},
{Country: "B", City: "A", Hostname: "A"},
},
},
}
for name, testCase := range testCases {
testCase := testCase
t.Run(name, func(t *testing.T) {
t.Parallel()
sortServers(testCase.initialServers)
assert.Equal(t, testCase.sortedServers, testCase.initialServers)
})
}
}

View File

@@ -0,0 +1,14 @@
package ipvanish
import "github.com/qdm12/gluetun/internal/models"
func Stringify(servers []models.IpvanishServer) (s string) {
s = "func IpvanishServers() []models.IpvanishServer {\n"
s += " return []models.IpvanishServer{\n"
for _, server := range servers {
s += " " + server.String() + ",\n"
}
s += " }\n"
s += "}"
return s
}

View File

@@ -0,0 +1,43 @@
package ipvanish
import (
"testing"
"github.com/qdm12/gluetun/internal/models"
"github.com/stretchr/testify/assert"
)
func Test_Stringify(t *testing.T) {
t.Parallel()
testCases := map[string]struct {
servers []models.IpvanishServer
s string
}{
"no server": {
s: `func IpvanishServers() []models.IpvanishServer {
return []models.IpvanishServer{
}
}`,
},
"multiple servers": {
servers: []models.IpvanishServer{
{Country: "A"},
{Country: "B"},
},
s: `func IpvanishServers() []models.IpvanishServer {
return []models.IpvanishServer{
{Country: "A", City: "", Hostname: "", TCP: false, UDP: false, IPs: []net.IP{}},
{Country: "B", City: "", Hostname: "", TCP: false, UDP: false, IPs: []net.IP{}},
}
}`,
},
}
for name, testCase := range testCases {
testCase := testCase
t.Run(name, func(t *testing.T) {
t.Parallel()
s := Stringify(testCase.servers)
assert.Equal(t, testCase.s, s)
})
}
}

View File

@@ -19,7 +19,7 @@ func parseServerName(serverName string) (number uint16, err error) {
} }
idString := serverName[i+1:] idString := serverName[i+1:]
idUint64, err := strconv.ParseUint(idString, 10, 16) idUint64, err := strconv.ParseUint(idString, 10, 16) //nolint:gomnd
if err != nil { if err != nil {
return 0, fmt.Errorf("%w: %s", ErrInvalidIDInServerName, serverName) return 0, fmt.Errorf("%w: %s", ErrInvalidIDInServerName, serverName)
} }

View File

@@ -0,0 +1,160 @@
package vpnunlimited
import (
"strings"
"github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/models"
)
func getHostToServer() (hts hostToServer, warnings []string) {
shortHTS := map[string]models.VPNUnlimitedServer{
"ae": {},
"ar": {},
"at": {},
"au-syd": {
City: "Sydney",
},
"ba": {},
"be": {},
"bg": {},
"br": {},
"by": {},
"ca-tr": {
City: "Toronto",
},
"ca-vn": {
City: "Vancouver",
},
"ca": {},
"ch": {},
"cr": {},
"cy": {},
"cz": {},
"de-dus": {
City: "Düsseldorf",
},
"de": {},
"dk": {},
"ee": {},
"es": {},
"fi": {},
"fr-rbx": {
City: "Roubaix",
},
"fr": {},
"gr": {},
"hr": {},
"hu": {},
"ie-dub": {
City: "Dublin",
},
"il": {},
"im": {},
"in-ka": {
City: "Karnataka",
},
"in": {},
"is": {},
"it-mil": {
City: "Milan",
},
"jp": {},
"kr": {},
"lt": {},
"lu": {},
"lv": {},
"ly": {},
"md": {},
"mx": {},
"mys": {},
"nl": {},
"no": {},
"nz": {},
"om": {},
"pl": {},
"pt": {},
"ro": {},
"rs": {},
"se": {},
"sg-free": {
Free: true,
},
"sg": {},
"si": {},
"sk": {},
"th": {},
"tr": {},
"uk-cv": {
City: "London",
},
"uk-lon": {
City: "London",
},
"uk": {},
"us-chi": {
City: "Chicago",
},
"us-dal": {
City: "Dallas",
},
"us-den": {
City: "Denver",
},
"us-hou": {
City: "Houston",
},
"us-la": {
City: "Los Angeles",
},
"us-lv": {
City: "Las Vegas",
},
"us-mia": {
City: "Miami",
},
"us-ny-free": {
City: "New York",
Free: true,
},
"us-ny": {
City: "New York",
},
"us-sea": {
City: "Seattle",
},
"us-sf": {
City: "San Francisco",
},
"us-sl": {
City: "Saint Louis",
},
"us-slc": {
City: "Salt Lake City",
},
"us-stream": {
Stream: true,
},
"us": {},
"vn": {},
"za": {},
}
hts = make(hostToServer, len(shortHTS))
countryCodesMap := constants.CountryCodes()
for shortHost, server := range shortHTS {
server.UDP = true
server.Hostname = shortHost + ".vpnunlimitedapp.com"
countryCode := strings.Split(shortHost, "-")[0]
country, ok := countryCodesMap[countryCode]
if !ok {
warnings = append(warnings, "country code not found: "+countryCode)
continue
}
server.Country = country
hts[server.Hostname] = server
}
return hts, warnings
}

View File

@@ -0,0 +1,38 @@
package vpnunlimited
import (
"net"
"github.com/qdm12/gluetun/internal/models"
)
type hostToServer map[string]models.VPNUnlimitedServer
func (hts hostToServer) toHostsSlice() (hosts []string) {
hosts = make([]string, 0, len(hts))
for host := range hts {
hosts = append(hosts, host)
}
return hosts
}
func (hts hostToServer) adaptWithIPs(hostToIPs map[string][]net.IP) {
for host, IPs := range hostToIPs {
server := hts[host]
server.IPs = IPs
hts[host] = server
}
for host, server := range hts {
if len(server.IPs) == 0 {
delete(hts, host)
}
}
}
func (hts hostToServer) toServersSlice() (servers []models.VPNUnlimitedServer) {
servers = make([]models.VPNUnlimitedServer, 0, len(hts))
for _, server := range hts {
servers = append(servers, server)
}
return servers
}

View File

@@ -0,0 +1,32 @@
package vpnunlimited
import (
"context"
"net"
"time"
"github.com/qdm12/gluetun/internal/updater/resolver"
)
func resolveHosts(ctx context.Context, presolver resolver.Parallel,
hosts []string, minServers int) (hostToIPs map[string][]net.IP,
warnings []string, err error) {
const (
maxFailRatio = 0.1
maxDuration = 20 * time.Second
betweenDuration = time.Second
maxNoNew = 2
maxFails = 2
)
settings := resolver.ParallelSettings{
MaxFailRatio: maxFailRatio,
MinFound: minServers,
Repeat: resolver.RepeatSettings{
MaxDuration: maxDuration,
BetweenDuration: betweenDuration,
MaxNoNew: maxNoNew,
MaxFails: maxFails,
},
}
return presolver.Resolve(ctx, hosts, settings)
}

View File

@@ -0,0 +1,42 @@
// Package vpnunlimited contains code to obtain the server information
// for the VPNUnlimited provider.
package vpnunlimited
import (
"context"
"errors"
"fmt"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/updater/resolver"
"github.com/qdm12/gluetun/internal/updater/unzip"
)
var ErrNotEnoughServers = errors.New("not enough servers found")
func GetServers(ctx context.Context, unzipper unzip.Unzipper,
presolver resolver.Parallel, minServers int) (
servers []models.VPNUnlimitedServer, warnings []string, err error) {
// Hardcoded data from a user provided ZIP file since it's behind a login wall
hts, warnings := getHostToServer()
hosts := hts.toHostsSlice()
hostToIPs, newWarnings, err := resolveHosts(ctx, presolver, hosts, minServers)
warnings = append(warnings, newWarnings...)
if err != nil {
return nil, warnings, err
}
hts.adaptWithIPs(hostToIPs)
servers = hts.toServersSlice()
if len(servers) < minServers {
return nil, warnings, fmt.Errorf("%w: %d and expected at least %d",
ErrNotEnoughServers, len(servers), minServers)
}
sortServers(servers)
return servers, warnings, nil
}

View File

@@ -0,0 +1,19 @@
package vpnunlimited
import (
"sort"
"github.com/qdm12/gluetun/internal/models"
)
func sortServers(servers []models.VPNUnlimitedServer) {
sort.Slice(servers, func(i, j int) bool {
if servers[i].Country == servers[j].Country {
if servers[i].City == servers[j].City {
return servers[i].Hostname < servers[j].Hostname
}
return servers[i].City < servers[j].City
}
return servers[i].Country < servers[j].Country
})
}

View File

@@ -0,0 +1,14 @@
package vpnunlimited
import "github.com/qdm12/gluetun/internal/models"
func Stringify(servers []models.VPNUnlimitedServer) (s string) {
s = "func VPNUnlimitedServers() []models.VPNUnlimitedServer {\n"
s += " return []models.VPNUnlimitedServer{\n"
for _, server := range servers {
s += " " + server.String() + ",\n"
}
s += " }\n"
s += "}"
return s
}

View File

@@ -8,6 +8,7 @@ import (
"time" "time"
"github.com/qdm12/gluetun/internal/configuration" "github.com/qdm12/gluetun/internal/configuration"
"github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/updater/resolver" "github.com/qdm12/gluetun/internal/updater/resolver"
"github.com/qdm12/gluetun/internal/updater/unzip" "github.com/qdm12/gluetun/internal/updater/unzip"
@@ -84,6 +85,16 @@ func (u *updater) UpdateServers(ctx context.Context) (allServers models.AllServe
} }
} }
if u.options.Ipvanish {
u.logger.Info("updating Ipvanish servers...")
if err := u.updateIpvanish(ctx); err != nil {
u.logger.Error(err)
}
if err := ctx.Err(); err != nil {
return allServers, err
}
}
if u.options.Ivpn { if u.options.Ivpn {
u.logger.Info("updating Ivpn servers...") u.logger.Info("updating Ivpn servers...")
if err := u.updateIvpn(ctx); err != nil { if err := u.updateIvpn(ctx); err != nil {
@@ -186,6 +197,16 @@ func (u *updater) UpdateServers(ctx context.Context) (allServers models.AllServe
} }
} }
if u.options.VPNUnlimited {
u.logger.Info("updating " + constants.VPNUnlimited + " servers...")
if err := u.updateVPNUnlimited(ctx); err != nil {
if ctxErr := ctx.Err(); ctxErr != nil {
return allServers, ctxErr
}
u.logger.Error(err)
}
}
if u.options.Vyprvpn { if u.options.Vyprvpn {
u.logger.Info("updating Vyprvpn servers...") u.logger.Info("updating Vyprvpn servers...")
if err := u.updateVyprvpn(ctx); err != nil { if err := u.updateVyprvpn(ctx); err != nil {

Some files were not shown because too many files have changed in this diff Show More