Compare commits

..

1 Commits

Author SHA1 Message Date
Quentin McGaw (desktop)
b4ec59f9bd Fix IPVanish TLS verification 2021-07-02 03:21:33 +00:00
52 changed files with 1766 additions and 2187 deletions

View File

@@ -1,18 +1,15 @@
ARG ALPINE_VERSION=3.14
ARG GO_ALPINE_VERSION=3.13
ARG ALPINE_VERSION=3.13
ARG GO_VERSION=1.16
ARG XCPUTRANSLATE_VERSION=v0.6.0
ARG GOLANGCI_LINT_VERSION=v1.41.1
ARG BUILDPLATFORM=linux/amd64
FROM --platform=$BUILDPLATFORM qmcgaw/xcputranslate:${XCPUTRANSLATE_VERSION} AS xcputranslate
FROM --platform=${BUILDPLATFORM} qmcgaw/binpot:golangci-lint-${GOLANGCI_LINT_VERSION} AS golangci-lint
FROM --platform=$BUILDPLATFORM qmcgaw/xcputranslate:v0.6.0 AS xcputranslate
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine${GO_ALPINE_VERSION} AS base
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS base
COPY --from=xcputranslate /xcputranslate /usr/local/bin/xcputranslate
RUN apk --update add git g++
ENV CGO_ENABLED=0
COPY --from=golangci-lint /bin /go/bin/golangci-lint
ARG GOLANGCI_LINT_VERSION=v1.41.1
RUN go get github.com/golangci/golangci-lint/cmd/golangci-lint@${GOLANGCI_LINT_VERSION}
WORKDIR /tmp/gobuild
COPY go.mod go.sum ./
RUN go mod download

View File

@@ -7,36 +7,22 @@ using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
**ANNOUNCEMENT**:
![Title image](https://raw.githubusercontent.com/qdm12/gluetun/master/title.svg)
<img height="250" src="https://raw.githubusercontent.com/qdm12/gluetun/master/title.svg?sanitize=true">
[![Build status](https://github.com/qdm12/gluetun/workflows/CI/badge.svg)](https://github.com/qdm12/gluetun/actions?query=workflow%3ACI)
[![Size](https://img.shields.io/docker/image-size/qmcgaw/gluetun?sort=semver&label=Last%20released%20image)](https://hub.docker.com/r/qmcgaw/gluetun/tags?page=1&ordering=last_updated)
[![Size](https://img.shields.io/docker/image-size/qmcgaw/gluetun/latest?label=Latest%20image)](https://hub.docker.com/r/qmcgaw/gluetun/tags)
[![Docker pulls qmcgaw/gluetun](https://img.shields.io/docker/pulls/qmcgaw/gluetun.svg)](https://hub.docker.com/r/qmcgaw/gluetun)
[![Docker pulls qmcgaw/private-internet-access](https://img.shields.io/docker/pulls/qmcgaw/private-internet-access.svg)](https://hub.docker.com/r/qmcgaw/gluetun)
[![Docker stars qmcgaw/gluetun](https://img.shields.io/docker/stars/qmcgaw/gluetun.svg)](https://hub.docker.com/r/qmcgaw/gluetun)
[![Docker stars qmcgaw/private-internet-access](https://img.shields.io/docker/stars/qmcgaw/private-internet-access.svg)](https://hub.docker.com/r/qmcgaw/gluetun)
[![Docker Pulls](https://img.shields.io/docker/pulls/qmcgaw/private-internet-access.svg)](https://hub.docker.com/r/qmcgaw/private-internet-access)
[![Docker Pulls](https://img.shields.io/docker/pulls/qmcgaw/gluetun.svg)](https://hub.docker.com/r/qmcgaw/gluetun)
![Last release](https://img.shields.io/github/release/qdm12/gluetun?label=Last%20release)
![Last Docker tag](https://img.shields.io/docker/v/qmcgaw/gluetun?sort=semver&label=Last%20Docker%20tag)
[![Last release size](https://img.shields.io/docker/image-size/qmcgaw/gluetun?sort=semver&label=Last%20released%20image)](https://hub.docker.com/r/qmcgaw/gluetun/tags?page=1&ordering=last_updated)
![GitHub last release date](https://img.shields.io/github/release-date/qdm12/gluetun?label=Last%20release%20date)
![GitHub Release Date](https://img.shields.io/github/release-date/qdm12/gluetun?label=Last%20release%20date)
![Commits since release](https://img.shields.io/github/commits-since/qdm12/gluetun/latest?sort=semver)
[![Latest size](https://img.shields.io/docker/image-size/qmcgaw/gluetun/latest?label=Latest%20image)](https://hub.docker.com/r/qmcgaw/gluetun/tags)
[![GitHub last commit](https://img.shields.io/github/last-commit/qdm12/gluetun.svg)](https://github.com/qdm12/gluetun/commits/master)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/qdm12/gluetun.svg)](https://github.com/qdm12/gluetun/graphs/contributors)
[![GitHub closed PRs](https://img.shields.io/github/issues-pr-closed/qdm12/gluetun.svg)](https://github.com/qdm12/gluetun/pulls?q=is%3Apr+is%3Aclosed)
[![GitHub issues](https://img.shields.io/github/issues/qdm12/gluetun.svg)](https://github.com/qdm12/gluetun/issues)
[![GitHub closed issues](https://img.shields.io/github/issues-closed/qdm12/gluetun.svg)](https://github.com/qdm12/gluetun/issues?q=is%3Aissue+is%3Aclosed)
[![GitHub last commit](https://img.shields.io/github/last-commit/qdm12/gluetun.svg)](https://github.com/qdm12/gluetun/commits)
[![Lines of code](https://img.shields.io/tokei/lines/github/qdm12/gluetun)](https://github.com/qdm12/gluetun)
![Code size](https://img.shields.io/github/languages/code-size/qdm12/gluetun)
![GitHub repo size](https://img.shields.io/github/repo-size/qdm12/gluetun)
![Go version](https://img.shields.io/github/go-mod/go-version/qdm12/gluetun)
![Visitors count](https://visitor-badge.laobi.icu/badge?page_id=gluetun.readme)
## Quick links
@@ -49,9 +35,6 @@ using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and an HTTP proxy*
- Sponsor me on [github.com/sponsors/qdm12](https://github.com/sponsors/qdm12)
- Donate to [paypal.me/qmcgaw](https://www.paypal.me/qmcgaw)
- Drop me [an email](mailto:quentin.mcgaw@gmail.com)
- Video:
[![Video Gif](https://i.imgur.com/CetWunc.gif)](https://youtu.be/0F6I03LQcI4)
## Features
@@ -118,3 +101,25 @@ The following points are all optional but should give you insights on all the po
## License
[![MIT](https://img.shields.io/github/license/qdm12/gluetun)](https://github.com/qdm12/gluetun/master/LICENSE)
## Metadata
[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/qdm12/gluetun.svg)](https://github.com/qdm12/gluetun/commits)
[![GitHub closed PRs](https://img.shields.io/github/issues-pr-closed/qdm12/gluetun.svg)](https://github.com/qdm12/gluetun/pulls?q=is%3Apr+is%3Aclosed)
[![GitHub issues](https://img.shields.io/github/issues/qdm12/gluetun.svg)](https://github.com/qdm12/gluetun/issues)
[![GitHub closed issues](https://img.shields.io/github/issues-closed/qdm12/gluetun.svg)](https://github.com/qdm12/gluetun/issues?q=is%3Aissue+is%3Aclosed)
![Visitors count](https://visitor-badge.laobi.icu/badge?page_id=gluetun.readme)
![GitHub stars](https://img.shields.io/github/stars/qdm12/gluetun?style=social)
![GitHub watchers](https://img.shields.io/github/watchers/qdm12/gluetun?style=social)
![Contributors](https://img.shields.io/github/contributors/qdm12/gluetun)
![GitHub forks](https://img.shields.io/github/forks/qdm12/gluetun?style=social)
![Code size](https://img.shields.io/github/languages/code-size/qdm12/gluetun)
![GitHub repo size](https://img.shields.io/github/repo-size/qdm12/gluetun)
[![dockeri.co](https://dockeri.co/image/qmcgaw/gluetun)](https://hub.docker.com/r/qmcgaw/gluetun)
![Docker Layers for latest](https://img.shields.io/microbadger/layers/qmcgaw/gluetun/latest?label=Docker%20image%20layers)
![Go version](https://img.shields.io/github/go-mod/go-version/qdm12/gluetun)

View File

@@ -275,6 +275,8 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
}
} // TODO move inside firewall?
healthy := make(chan bool)
// Shutdown settings
const defaultShutdownTimeout = 400 * time.Millisecond
defaultShutdownOnSuccess := func(goRoutineName string) {
@@ -286,6 +288,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
defaultGoRoutineSettings := goshutdown.GoRoutineSettings{Timeout: defaultShutdownTimeout}
defaultGroupSettings := goshutdown.GroupSettings{
Timeout: defaultShutdownTimeout,
OnFailure: defaultShutdownOnFailure,
OnSuccess: defaultShutdownOnSuccess,
}
@@ -294,7 +297,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
otherGroupHandler := goshutdown.NewGroupHandler("other", defaultGroupSettings)
openvpnLooper := openvpn.NewLooper(allSettings.OpenVPN, nonRootUsername, puid, pgid, allServers,
ovpnConf, firewallConf, routingConf, logger, httpClient, os.OpenFile, tunnelReadyCh)
ovpnConf, firewallConf, routingConf, logger, httpClient, os.OpenFile, tunnelReadyCh, healthy)
openvpnHandler, openvpnCtx, openvpnDone := goshutdown.NewGoRoutineHandler(
"openvpn", goshutdown.GoRoutineSettings{Timeout: time.Second})
// wait for restartOpenvpn
@@ -356,20 +359,19 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
controlServerAddress := ":" + strconv.Itoa(int(allSettings.ControlServer.Port))
controlServerLogging := allSettings.ControlServer.Log
httpServerHandler, httpServerCtx, httpServerDone := goshutdown.NewGoRoutineHandler(
"http server", defaultGoRoutineSettings)
httpServer := server.New(httpServerCtx, controlServerAddress, controlServerLogging,
httpServer := server.New(controlServerAddress, controlServerLogging,
logger.NewChild(logging.Settings{Prefix: "http server: "}),
buildInfo, openvpnLooper, unboundLooper, updaterLooper, publicIPLooper)
httpServerHandler, httpServerCtx, httpServerDone := goshutdown.NewGoRoutineHandler(
"http server", defaultGoRoutineSettings)
go httpServer.Run(httpServerCtx, httpServerDone)
controlGroupHandler.Add(httpServerHandler)
healthLogger := logger.NewChild(logging.Settings{Prefix: "healthcheck: "})
healthcheckServer := healthcheck.NewServer(
constants.HealthcheckAddress, healthLogger, openvpnLooper)
healthcheckServer := healthcheck.NewServer(constants.HealthcheckAddress,
logger.NewChild(logging.Settings{Prefix: "healthcheck: "}))
healthServerHandler, healthServerCtx, healthServerDone := goshutdown.NewGoRoutineHandler(
"HTTP health server", defaultGoRoutineSettings)
go healthcheckServer.Run(healthServerCtx, healthServerDone)
go healthcheckServer.Run(healthServerCtx, healthy, healthServerDone)
const orderShutdownTimeout = 3 * time.Second
orderSettings := goshutdown.OrderSettings{
@@ -383,7 +385,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
// Start openvpn for the first time in a blocking call
// until openvpn is launched
_, _ = openvpnLooper.ApplyStatus(ctx, constants.Running) // TODO option to disable with variable
_, _ = openvpnLooper.SetStatus(constants.Running) // TODO option to disable with variable
<-ctx.Done()
@@ -452,7 +454,7 @@ func routeReadyEvents(ctx context.Context, done chan<- struct{}, buildInfo model
}
if unboundLooper.GetSettings().Enabled {
_, _ = unboundLooper.ApplyStatus(ctx, constants.Running)
_, _ = unboundLooper.SetStatus(constants.Running)
}
restartTickerCancel() // stop previous restart tickers
@@ -461,8 +463,12 @@ func routeReadyEvents(ctx context.Context, done chan<- struct{}, buildInfo model
restartTickerContext, restartTickerCancel = context.WithCancel(ctx)
// Runs the Public IP getter job once
_, _ = publicIPLooper.SetStatus(ctx, constants.Running)
if versionInformation && first {
_, _ = publicIPLooper.SetStatus(constants.Running)
if !versionInformation {
break
}
if first {
first = false
message, err := versionpkg.GetMessage(ctx, buildInfo, httpClient)
if err != nil {

4
go.mod
View File

@@ -5,8 +5,8 @@ go 1.16
require (
github.com/fatih/color v1.12.0
github.com/golang/mock v1.6.0
github.com/qdm12/dns v1.9.0
github.com/qdm12/golibs v0.0.0-20210716185557-66793f4ddd80
github.com/qdm12/dns v1.8.0
github.com/qdm12/golibs v0.0.0-20210603202746-e5494e9c2ebb
github.com/qdm12/goshutdown v0.1.0
github.com/qdm12/ss-server v0.2.0
github.com/qdm12/updated v0.0.0-20210603204757-205acfe6937e

7
go.sum
View File

@@ -63,11 +63,10 @@ github.com/phayes/permbits v0.0.0-20190612203442-39d7c581d2ee/go.mod h1:3uODdxMg
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/qdm12/dns v1.9.0 h1:p4g/BfbpQ+gJRpQdklDAnybkjds+OuenF0wEGoZ8/AI=
github.com/qdm12/dns v1.9.0/go.mod h1:fqZoDf3VzddnKBMNI/OzZUp5H4dO0VBw1fp4qPkolOg=
github.com/qdm12/dns v1.8.0 h1:GZ40kptmfDHOMNxBKWSA4zrbNyGm41BA57zv2MaDtCI=
github.com/qdm12/dns v1.8.0/go.mod h1:P2mm63NDYZdx2NAd5CVLM0FBnNdi1ZgVjsRSnX+96vg=
github.com/qdm12/golibs v0.0.0-20210603202746-e5494e9c2ebb h1:5WkOssTWl6Tv2H7VFb2jwB08A7BxxNCebkkpvz1PzrY=
github.com/qdm12/golibs v0.0.0-20210603202746-e5494e9c2ebb/go.mod h1:15RBzkun0i8XB7ADIoLJWp9ITRgsz3LroEI2FiOXLRg=
github.com/qdm12/golibs v0.0.0-20210716185557-66793f4ddd80 h1:rvH2MSs8RXEfuXivzoYCim6tRNPzdqjBzqJq8w4Tc0k=
github.com/qdm12/golibs v0.0.0-20210716185557-66793f4ddd80/go.mod h1:15RBzkun0i8XB7ADIoLJWp9ITRgsz3LroEI2FiOXLRg=
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=

View File

@@ -18,12 +18,6 @@ var (
ErrFilesDoNotExist = errors.New("files do not exist")
)
func cleanSuffix(value string) string {
value = strings.TrimSuffix(value, "\n")
value = strings.TrimSuffix(value, "\r")
return value
}
func (r *reader) getFromEnvOrSecretFile(envKey string, compulsory bool, retroKeys []string) (value string, err error) {
envOptions := []params.OptionSetter{
params.Compulsory(), // to fallback on file reading
@@ -33,7 +27,6 @@ func (r *reader) getFromEnvOrSecretFile(envKey string, compulsory bool, retroKey
}
value, envErr := r.env.Get(envKey, envOptions...)
if envErr == nil {
value = cleanSuffix(value)
return value, nil
}
@@ -62,7 +55,7 @@ func (r *reader) getFromEnvOrSecretFile(envKey string, compulsory bool, retroKey
}
value = string(b)
value = cleanSuffix(value)
value = strings.TrimSuffix(value, "\n")
if compulsory && len(value) == 0 {
return "", ErrSecretFileIsEmpty
}

View File

@@ -45,6 +45,7 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "Albania", City: "Tirana", Hostname: "tia-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{80, 246, 28, 3}}},
{Country: "Albania", City: "Tirana", Hostname: "tia-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{80, 246, 28, 5}}},
{Country: "Albania", City: "Tirana", Hostname: "tia-c04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{80, 246, 28, 7}}},
{Country: "Albania", City: "Tirana", Hostname: "tia-c05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{80, 246, 28, 9}}},
{Country: "Argentina", City: "Buenos Aires", Hostname: "eze-c01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{199, 33, 69, 10}}},
{Country: "Argentina", City: "Buenos Aires", Hostname: "eze-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{199, 33, 69, 16}}},
{Country: "Argentina", City: "Buenos Aires", Hostname: "eze-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{199, 33, 69, 22}}},
@@ -62,6 +63,7 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "Australia", City: "Melbourne", Hostname: "mel-a02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{103, 209, 252, 17}}},
{Country: "Australia", City: "Melbourne", Hostname: "mel-a03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{103, 209, 252, 11}}},
{Country: "Australia", City: "Melbourne", Hostname: "mel-a04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{103, 209, 252, 19}}},
{Country: "Australia", City: "Melbourne", Hostname: "mel-a05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{103, 209, 252, 13}}},
{Country: "Australia", City: "Melbourne", Hostname: "mel-a06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{103, 209, 252, 21}}},
{Country: "Australia", City: "Melbourne", Hostname: "mel-a07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{103, 209, 252, 15}}},
{Country: "Australia", City: "Perth", Hostname: "per-c01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{103, 107, 197, 36}}},
@@ -100,18 +102,19 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "Australia", City: "Sydney", Hostname: "syd-a28.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{173, 245, 209, 164}}},
{Country: "Australia", City: "Sydney", Hostname: "syd-a29.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{173, 245, 209, 170}}},
{Country: "Australia", City: "Sydney", Hostname: "syd-a30.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{173, 245, 209, 176}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 110, 2}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 110, 8}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 110, 14}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 110, 20}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 110, 26}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 110, 130}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 110, 136}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c08.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 110, 142}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 110, 148}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 110, 154}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 110, 160}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 110, 166}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 44, 2}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 44, 8}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 44, 14}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 44, 20}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c08.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 44, 26}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 44, 32}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 44, 140}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 44, 150}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 44, 160}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c13.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 44, 170}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c14.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 44, 180}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c15.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 44, 190}}},
{Country: "Austria", City: "Vienna", Hostname: "vie-c16.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 44, 200}}},
{Country: "Belgium", City: "Brussels", Hostname: "bru-c01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{37, 120, 218, 99}}},
{Country: "Belgium", City: "Brussels", Hostname: "bru-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{37, 120, 218, 101}}},
{Country: "Belgium", City: "Brussels", Hostname: "bru-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{37, 120, 218, 103}}},
@@ -198,11 +201,6 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "Canada", City: "Vancouver", Hostname: "yvr-c05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{107, 181, 189, 138}}},
{Country: "Canada", City: "Vancouver", Hostname: "yvr-c06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{107, 181, 189, 186}}},
{Country: "Canada", City: "Vancouver", Hostname: "yvr-c07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{107, 181, 189, 227}}},
{Country: "Chile", City: "Santiago", Hostname: "scl-c01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{191, 101, 28, 5}}},
{Country: "Chile", City: "Santiago", Hostname: "scl-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{191, 101, 28, 9}}},
{Country: "Chile", City: "Santiago", Hostname: "scl-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{191, 101, 28, 13}}},
{Country: "Chile", City: "Santiago", Hostname: "scl-c04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{191, 101, 28, 17}}},
{Country: "Chile", City: "Santiago", Hostname: "scl-c05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{191, 101, 28, 21}}},
{Country: "Colombia", City: "Bogota", Hostname: "bog-c01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{199, 33, 68, 11}}},
{Country: "Colombia", City: "Bogota", Hostname: "bog-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{199, 33, 68, 17}}},
{Country: "Colombia", City: "Bogota", Hostname: "bog-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{199, 33, 68, 23}}},
@@ -215,23 +213,20 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "Croatia", City: "Zagreb", Hostname: "zag-c06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{85, 10, 57, 221}}},
{Country: "Croatia", City: "Zagreb", Hostname: "zag-c07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{85, 10, 57, 227}}},
{Country: "Croatia", City: "Zagreb", Hostname: "zag-c08.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{85, 10, 57, 233}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 109, 39}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 109, 45}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 109, 51}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 109, 57}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c13.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 109, 63}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c15.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 109, 130}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c16.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 109, 136}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c17.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 109, 142}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c18.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 109, 148}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c19.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 109, 154}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c20.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 109, 160}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c21.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 109, 3}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c22.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 109, 9}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c23.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 109, 15}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c24.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 109, 21}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c25.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 109, 27}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c26.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 109, 33}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 39, 150}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 39, 170}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 39, 190}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c13.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 39, 210}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c15.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 39, 2}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c16.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 39, 8}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c17.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 39, 14}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c18.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 39, 20}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c21.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 39, 39}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c22.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 39, 45}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c23.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 39, 51}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c24.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 39, 57}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c25.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 39, 63}}},
{Country: "Czech Republic", City: "Prague", Hostname: "prg-c26.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{104, 238, 39, 69}}},
{Country: "Denmark", City: "Copenhagen", Hostname: "cph-c09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 245, 84, 8}}},
{Country: "Denmark", City: "Copenhagen", Hostname: "cph-c10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 245, 84, 10}}},
{Country: "Denmark", City: "Copenhagen", Hostname: "cph-c11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 245, 84, 12}}},
@@ -273,20 +268,20 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "France", City: "Marseille", Hostname: "mrs-c06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{176, 67, 82, 8}}},
{Country: "France", City: "Marseille", Hostname: "mrs-c07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{176, 67, 82, 14}}},
{Country: "France", City: "Marseille", Hostname: "mrs-c08.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{176, 67, 82, 20}}},
{Country: "France", City: "Paris", Hostname: "par-a01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 212, 17}}},
{Country: "France", City: "Paris", Hostname: "par-a02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 212, 21}}},
{Country: "France", City: "Paris", Hostname: "par-a03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 212, 25}}},
{Country: "France", City: "Paris", Hostname: "par-a04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 212, 29}}},
{Country: "France", City: "Paris", Hostname: "par-a05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 212, 33}}},
{Country: "France", City: "Paris", Hostname: "par-a06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 212, 37}}},
{Country: "France", City: "Paris", Hostname: "par-a07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 212, 41}}},
{Country: "France", City: "Paris", Hostname: "par-a08.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 212, 45}}},
{Country: "France", City: "Paris", Hostname: "par-a09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 212, 49}}},
{Country: "France", City: "Paris", Hostname: "par-a10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 212, 53}}},
{Country: "France", City: "Paris", Hostname: "par-a11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 212, 57}}},
{Country: "France", City: "Paris", Hostname: "par-a12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 212, 61}}},
{Country: "France", City: "Paris", Hostname: "par-a13.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 212, 65}}},
{Country: "France", City: "Paris", Hostname: "par-a14.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 212, 69}}},
{Country: "France", City: "Paris", Hostname: "par-a01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 10, 232, 13}}},
{Country: "France", City: "Paris", Hostname: "par-a02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 10, 232, 19}}},
{Country: "France", City: "Paris", Hostname: "par-a03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 10, 232, 25}}},
{Country: "France", City: "Paris", Hostname: "par-a04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 10, 232, 31}}},
{Country: "France", City: "Paris", Hostname: "par-a05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 10, 232, 37}}},
{Country: "France", City: "Paris", Hostname: "par-a06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 10, 232, 43}}},
{Country: "France", City: "Paris", Hostname: "par-a07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 10, 232, 49}}},
{Country: "France", City: "Paris", Hostname: "par-a08.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 10, 232, 55}}},
{Country: "France", City: "Paris", Hostname: "par-a09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 10, 232, 61}}},
{Country: "France", City: "Paris", Hostname: "par-a10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 10, 232, 67}}},
{Country: "France", City: "Paris", Hostname: "par-a11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 10, 232, 73}}},
{Country: "France", City: "Paris", Hostname: "par-a12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 10, 232, 79}}},
{Country: "France", City: "Paris", Hostname: "par-a13.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 10, 232, 85}}},
{Country: "France", City: "Paris", Hostname: "par-a14.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 10, 232, 91}}},
{Country: "France", City: "Paris", Hostname: "par-a15.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 10, 232, 97}}},
{Country: "France", City: "Paris", Hostname: "par-a16.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 10, 232, 103}}},
{Country: "France", City: "Paris", Hostname: "par-a17.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 10, 232, 109}}},
@@ -343,22 +338,22 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "Germany", City: "Frankfurt", Hostname: "fra-a42.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 93, 19}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-a43.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 93, 25}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-a44.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 93, 31}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 111, 2}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 111, 8}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 111, 14}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 111, 20}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 111, 26}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 111, 32}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 111, 38}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c08.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 111, 44}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 111, 130}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 111, 136}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 111, 142}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 111, 148}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c13.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 111, 154}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c14.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 111, 160}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c15.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 111, 166}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c16.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 111, 172}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 94, 2}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 94, 4}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 94, 6}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 94, 8}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 94, 10}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 94, 12}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 94, 38}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 94, 42}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 94, 44}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 94, 46}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 94, 48}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c13.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 94, 74}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c14.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 94, 76}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c15.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 94, 78}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c16.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 94, 80}}},
{Country: "Germany", City: "Frankfurt", Hostname: "fra-c17.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 183, 94, 82}}},
{Country: "Greece", City: "Athens", Hostname: "ath-c01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{194, 150, 167, 98}}},
{Country: "Greece", City: "Athens", Hostname: "ath-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{194, 150, 167, 100}}},
{Country: "Greece", City: "Athens", Hostname: "ath-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{194, 150, 167, 102}}},
@@ -398,32 +393,18 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "Israel", City: "Tel Aviv", Hostname: "tlv-c08.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{87, 239, 255, 73}}},
{Country: "Israel", City: "Tel Aviv", Hostname: "tlv-c09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{87, 239, 255, 75}}},
{Country: "Israel", City: "Tel Aviv", Hostname: "tlv-c10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{87, 239, 255, 77}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a13.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 4}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a14.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 10}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a15.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 16}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a16.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 22}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a17.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 28}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a18.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 34}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a19.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 40}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a20.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 46}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a21.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 52}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a22.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 58}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a23.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 64}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a24.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 70}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a25.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 76}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a26.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 82}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a27.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 88}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a28.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 94}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a29.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 100}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a30.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 106}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a31.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 112}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a32.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 118}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a33.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 124}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a34.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 130}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a35.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 136}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a36.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 142}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a37.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 148}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a38.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{69, 16, 157, 154}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 56, 137, 24}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 56, 137, 26}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 56, 137, 4}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 56, 137, 6}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 56, 137, 44}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 56, 137, 46}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 56, 137, 48}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a08.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 56, 137, 50}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 56, 137, 76}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 56, 137, 78}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 56, 137, 80}}},
{Country: "Italy", City: "Milan", Hostname: "lin-a12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 56, 137, 82}}},
{Country: "Japan", City: "Tokyo", Hostname: "nrt-a01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{173, 245, 217, 3}}},
{Country: "Japan", City: "Tokyo", Hostname: "nrt-a02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{173, 245, 217, 7}}},
{Country: "Japan", City: "Tokyo", Hostname: "nrt-a03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{173, 245, 217, 11}}},
@@ -454,6 +435,7 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "Latvia", City: "Riga", Hostname: "rix-c04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{80, 246, 31, 23}}},
{Country: "Latvia", City: "Riga", Hostname: "rix-c05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{80, 246, 31, 25}}},
{Country: "Luxembourg", City: "Luxembourg", Hostname: "lux-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 153, 151, 3}}},
{Country: "Luxembourg", City: "Luxembourg", Hostname: "lux-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 153, 151, 5}}},
{Country: "Malaysia", City: "Kuala Lumpur", Hostname: "kul-c01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{202, 73, 14, 57}}},
{Country: "Malaysia", City: "Kuala Lumpur", Hostname: "kul-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{202, 73, 14, 53}}},
{Country: "Malaysia", City: "Kuala Lumpur", Hostname: "kul-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{103, 246, 112, 197}}},
@@ -466,52 +448,56 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "Mexico", City: "Guadalajara", Hostname: "gdl-c12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{143, 255, 58, 53}}},
{Country: "Moldova", City: "Chisinau", Hostname: "kiv-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 163, 46, 147}}},
{Country: "Moldova", City: "Chisinau", Hostname: "kiv-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 163, 46, 153}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 3}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 9}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 15}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 21}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 27}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 33}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 39}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a08.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 45}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 51}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 57}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 63}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 69}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a13.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 75}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a14.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 81}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a15.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 87}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a16.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 91}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a17.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 97}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a18.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 103}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a19.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 109}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a20.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 115}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a21.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 121}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a22.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 127}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a23.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 133}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a24.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 139}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a25.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 145}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a26.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 151}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a27.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 157}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a28.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 163}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a29.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 170}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a30.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 176}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a31.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 182}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a32.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 188}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a33.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 194}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a34.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 200}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a35.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 206}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a36.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 212}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a37.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 218}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a38.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 224}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a39.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 88, 230}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 24}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 30}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 36}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 42}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 48}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a08.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 54}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 60}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 66}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 72}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 78}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a13.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 84}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a14.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 90}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a15.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 96}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a16.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 102}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a17.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 108}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a18.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 114}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a19.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 120}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a20.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 126}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a21.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 132}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a22.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 138}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a23.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 144}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a24.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 150}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a25.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 156}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a26.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 162}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a27.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 168}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a28.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 174}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a29.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 180}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a30.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 186}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a31.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 192}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a32.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 198}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a33.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 204}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a34.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 210}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a35.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 216}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a36.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 222}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a37.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 228}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a38.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 234}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a39.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 240}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a40.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 12, 246}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a41.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 13, 7}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a50.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 13, 61}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a51.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 13, 67}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a52.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 13, 73}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a54.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 13, 85}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a55.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 13, 91}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a56.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 13, 97}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a57.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 13, 103}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a58.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 13, 109}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a59.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 13, 115}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a60.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 13, 121}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-a61.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{2, 58, 13, 127}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-c37.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{172, 83, 45, 131}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-c38.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{172, 83, 45, 137}}},
{Country: "Netherlands", City: "Amsterdam", Hostname: "ams-c39.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{172, 83, 45, 143}}},
@@ -604,6 +590,7 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "Slovakia", City: "Bratislava", Hostname: "bts-c07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{176, 67, 87, 28}}},
{Country: "Slovakia", City: "Bratislava", Hostname: "bts-c08.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{176, 67, 87, 38}}},
{Country: "Slovakia", City: "Bratislava", Hostname: "bts-c09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{176, 67, 87, 48}}},
{Country: "Slovenia", City: "Ljubljana", Hostname: "lju-c01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{195, 158, 249, 68}}},
{Country: "Slovenia", City: "Ljubljana", Hostname: "lju-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{195, 158, 249, 70}}},
{Country: "Slovenia", City: "Ljubljana", Hostname: "lju-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{195, 158, 249, 72}}},
{Country: "Slovenia", City: "Ljubljana", Hostname: "lju-c04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{195, 158, 249, 74}}},
@@ -645,10 +632,6 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "Spain", City: "Madrid", Hostname: "mad-a28.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 214, 182}}},
{Country: "Spain", City: "Madrid", Hostname: "mad-a29.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 214, 188}}},
{Country: "Spain", City: "Madrid", Hostname: "mad-a30.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 214, 194}}},
{Country: "Spain", City: "Valencia", Hostname: "vlc-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 153, 150, 3}}},
{Country: "Spain", City: "Valencia", Hostname: "vlc-c04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 153, 150, 5}}},
{Country: "Spain", City: "Valencia", Hostname: "vlc-c05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 153, 150, 7}}},
{Country: "Spain", City: "Valencia", Hostname: "vlc-c06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 153, 150, 9}}},
{Country: "Sweden", City: "Stockholm", Hostname: "sto-a01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 213, 18}}},
{Country: "Sweden", City: "Stockholm", Hostname: "sto-a02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 213, 24}}},
{Country: "Sweden", City: "Stockholm", Hostname: "sto-a03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 213, 30}}},
@@ -679,18 +662,18 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "Sweden", City: "Stockholm", Hostname: "sto-a28.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 213, 180}}},
{Country: "Sweden", City: "Stockholm", Hostname: "sto-a29.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 213, 186}}},
{Country: "Sweden", City: "Stockholm", Hostname: "sto-a30.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 147, 213, 192}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 108, 2}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 108, 8}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 108, 14}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 108, 20}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 108, 26}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 108, 32}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 108, 130}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c08.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 108, 136}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 108, 142}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 108, 148}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 108, 154}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 108, 160}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 82, 223, 5}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 82, 223, 7}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 82, 223, 9}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 82, 223, 11}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 82, 223, 15}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 82, 223, 121}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 82, 223, 141}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c13.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 82, 223, 151}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c14.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 82, 223, 161}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c15.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 82, 223, 171}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c16.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 82, 223, 181}}},
{Country: "Switzerland", City: "Zurich", Hostname: "zrh-c17.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 82, 223, 191}}},
{Country: "Taiwan", City: "Taipei", Hostname: "tpe-c01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{103, 4, 31, 133}}},
{Country: "Taiwan", City: "Taipei", Hostname: "tpe-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{103, 4, 31, 135}}},
{Country: "Ukraine", City: "Kiev", Hostname: "iev-c01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{139, 28, 38, 28}}},
@@ -718,68 +701,65 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "United Kingdom", City: "Glasgow", Hostname: "gla-c01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 108, 105, 164}}},
{Country: "United Kingdom", City: "Glasgow", Hostname: "gla-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 108, 105, 170}}},
{Country: "United Kingdom", City: "Glasgow", Hostname: "gla-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 108, 105, 176}}},
{Country: "United Kingdom", City: "Glasgow", Hostname: "gla-c04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 108, 105, 196}}},
{Country: "United Kingdom", City: "Glasgow", Hostname: "gla-c05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 108, 105, 202}}},
{Country: "United Kingdom", City: "Glasgow", Hostname: "gla-c06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 108, 105, 208}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 86}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 92}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 98}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 104}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 110}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 116}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 122}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a08.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 128}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 134}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 140}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 2}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 8}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a13.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 14}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a14.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 20}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a15.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 26}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a16.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 32}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a17.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 38}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a18.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 44}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a19.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 50}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a20.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 56}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a21.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 62}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a22.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 68}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a23.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 74}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a24.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 80}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a25.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 146}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a26.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 152}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a27.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 158}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a28.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 164}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a29.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 170}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a30.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 176}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a31.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 182}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a32.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 188}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a33.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 194}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a34.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 200}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a35.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 206}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a36.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 212}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a37.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 218}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a38.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 224}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a39.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 230}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a40.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 236}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a41.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 242}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a42.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 248}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a43.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 116, 254}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a44.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 117, 6}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a45.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 117, 12}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a46.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 117, 18}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a47.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 117, 24}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a48.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 117, 30}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a49.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 117, 36}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a50.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 117, 42}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a51.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 117, 48}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a52.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 117, 54}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a53.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 117, 60}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a54.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 117, 66}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a55.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 117, 72}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a56.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 117, 78}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a57.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 117, 84}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a58.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 117, 90}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a59.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 117, 96}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 9}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 15}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 21}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 27}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 33}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 39}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 45}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a08.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 51}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 57}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 63}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 69}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 75}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a13.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 81}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a14.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 87}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a15.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 93}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a16.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 99}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a17.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 105}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a18.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 111}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a19.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 117}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a20.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 123}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a21.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 129}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a22.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 135}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a23.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 141}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a24.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 147}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a25.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 153}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a26.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 159}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a27.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 165}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a28.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 171}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a29.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 177}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a30.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 183}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a31.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 189}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a32.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 195}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a33.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 201}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a34.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 207}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a35.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 213}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a36.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 219}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a37.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 225}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a38.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 231}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a39.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 237}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a40.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 220, 243}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a41.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 4}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a42.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 10}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a43.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 16}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a44.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 22}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a45.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 28}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a46.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 34}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a47.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 40}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a48.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 46}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a49.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 52}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a50.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 58}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a51.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 64}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a52.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 70}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a53.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 76}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a54.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 82}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a55.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 88}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a56.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 94}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a57.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 100}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a58.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 106}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a59.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{5, 180, 221, 112}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a60.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{176, 67, 85, 10}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a61.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{176, 67, 85, 12}}},
{Country: "United Kingdom", City: "London", Hostname: "lon-a62.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{176, 67, 85, 14}}},
@@ -803,15 +783,15 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c07.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 242, 7, 10}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c08.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{89, 238, 142, 242}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{89, 238, 142, 244}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 121, 50}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 121, 44}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 121, 38}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c13.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 121, 32}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c14.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 121, 26}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c15.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 121, 20}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c16.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 121, 14}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c17.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 121, 8}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c18.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 121, 2}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 244, 9, 5}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 244, 9, 7}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 244, 9, 9}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c13.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 244, 9, 11}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c14.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 244, 9, 13}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c15.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 244, 9, 15}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c16.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 244, 9, 17}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c17.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 244, 9, 19}}},
{Country: "United Kingdom", City: "Manchester", Hostname: "man-c18.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{185, 244, 9, 21}}},
{Country: "United States", City: "Ashburn", Hostname: "iad-a01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{173, 245, 203, 2}}},
{Country: "United States", City: "Ashburn", Hostname: "iad-a02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{173, 245, 203, 8}}},
{Country: "United States", City: "Ashburn", Hostname: "iad-a03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{173, 245, 203, 14}}},
@@ -918,7 +898,6 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "United States", City: "Ashburn", Hostname: "iad-b26.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 73, 69}}},
{Country: "United States", City: "Ashburn", Hostname: "iad-b27.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 73, 75}}},
{Country: "United States", City: "Ashburn", Hostname: "iad-b28.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 73, 81}}},
{Country: "United States", City: "Atlanta", Hostname: "atl-a01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{64, 145, 67, 7}}},
{Country: "United States", City: "Atlanta", Hostname: "atl-a02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{64, 145, 67, 21}}},
{Country: "United States", City: "Atlanta", Hostname: "atl-a03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{64, 145, 67, 30}}},
{Country: "United States", City: "Atlanta", Hostname: "atl-a04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{64, 145, 67, 36}}},
@@ -940,7 +919,6 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "United States", City: "Atlanta", Hostname: "atl-a20.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{209, 107, 196, 32}}},
{Country: "United States", City: "Atlanta", Hostname: "atl-a21.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{209, 107, 196, 38}}},
{Country: "United States", City: "Atlanta", Hostname: "atl-a22.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{209, 107, 196, 44}}},
{Country: "United States", City: "Atlanta", Hostname: "atl-a23.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{209, 107, 196, 128}}},
{Country: "United States", City: "Atlanta", Hostname: "atl-a24.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{209, 107, 196, 134}}},
{Country: "United States", City: "Atlanta", Hostname: "atl-a25.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{209, 107, 196, 140}}},
{Country: "United States", City: "Atlanta", Hostname: "atl-a26.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{209, 107, 196, 146}}},
@@ -1091,6 +1069,7 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "United States", City: "Boston", Hostname: "bos-c49.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{198, 181, 163, 169}}},
{Country: "United States", City: "Boston", Hostname: "bos-c50.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{198, 181, 163, 171}}},
{Country: "United States", City: "Boston", Hostname: "bos-c51.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{198, 181, 163, 209}}},
{Country: "United States", City: "Boston", Hostname: "bos-c52.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{198, 181, 163, 211}}},
{Country: "United States", City: "Boston", Hostname: "bos-c54.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{198, 181, 163, 215}}},
{Country: "United States", City: "Boston", Hostname: "bos-c55.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{198, 181, 163, 217}}},
{Country: "United States", City: "Boston", Hostname: "bos-c56.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{198, 181, 163, 219}}},
@@ -1107,6 +1086,8 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "United States", City: "Boston", Hostname: "bos-c68.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 56, 171, 20}}},
{Country: "United States", City: "Boston", Hostname: "bos-c69.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 56, 171, 22}}},
{Country: "United States", City: "Boston", Hostname: "bos-c70.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 56, 171, 24}}},
{Country: "United States", City: "Boston", Hostname: "bos-c71.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 56, 171, 26}}},
{Country: "United States", City: "Boston", Hostname: "bos-c72.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{45, 56, 171, 28}}},
{Country: "United States", City: "Charlotte", Hostname: "clt-c01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{173, 213, 88, 2}}},
{Country: "United States", City: "Charlotte", Hostname: "clt-c02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{173, 213, 88, 4}}},
{Country: "United States", City: "Charlotte", Hostname: "clt-c03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{173, 213, 88, 6}}},
@@ -1233,26 +1214,31 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "United States", City: "Chicago", Hostname: "chi-b39.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 77, 68}}},
{Country: "United States", City: "Chicago", Hostname: "chi-b40.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 77, 74}}},
{Country: "United States", City: "Chicago", Hostname: "chi-b41.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 77, 80}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 7}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 13}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 19}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 25}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b05.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 31}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b06.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 37}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b08.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 49}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b09.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 55}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b10.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 61}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b11.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 67}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b12.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 73}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b13.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 79}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b14.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 85}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b15.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 91}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b16.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 97}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b17.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 103}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b18.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 109}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b19.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 115}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b20.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 121}}},
{Country: "United States", City: "Cincinnati", Hostname: "cvg-b21.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 84, 127}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c17.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 2}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c18.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 4}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c19.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 6}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c20.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 8}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c21.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 26}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c22.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 28}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c23.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 30}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c24.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 44}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c25.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 46}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c26.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 48}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c27.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 50}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c28.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 52}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c29.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 54}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c30.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 80}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c31.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 82}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c32.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 84}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c33.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 86}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c34.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 88}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c35.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 90}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c36.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 116}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c37.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 118}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c38.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 120}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c39.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 122}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c40.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 124}}},
{Country: "United States", City: "Chicago", Hostname: "chi-c41.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 193, 126}}},
{Country: "United States", City: "Dallas", Hostname: "dal-a01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 214, 48}}},
{Country: "United States", City: "Dallas", Hostname: "dal-a02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 214, 52}}},
{Country: "United States", City: "Dallas", Hostname: "dal-a03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 214, 5}}},
@@ -1606,6 +1592,7 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "United States", City: "Miami", Hostname: "mia-a51.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{173, 255, 191, 2}}},
{Country: "United States", City: "Miami", Hostname: "mia-a52.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{173, 255, 191, 4}}},
{Country: "United States", City: "Miami", Hostname: "mia-a53.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{173, 255, 191, 6}}},
{Country: "United States", City: "Miami", Hostname: "mia-a54.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{173, 255, 191, 20}}},
{Country: "United States", City: "Miami", Hostname: "mia-b01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 87, 3}}},
{Country: "United States", City: "Miami", Hostname: "mia-b02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 87, 9}}},
{Country: "United States", City: "Miami", Hostname: "mia-b03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 87, 15}}},
@@ -1874,20 +1861,6 @@ func IpvanishServers() []models.IpvanishServer {
{Country: "United States", City: "San Jose", Hostname: "sjc-a39.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 151, 183, 230}}},
{Country: "United States", City: "San Jose", Hostname: "sjc-a40.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 151, 183, 236}}},
{Country: "United States", City: "San Jose", Hostname: "sjc-a41.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 151, 183, 242}}},
{Country: "United States", City: "San Jose", Hostname: "sjc-a42.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 122, 7}}},
{Country: "United States", City: "San Jose", Hostname: "sjc-a43.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 122, 8}}},
{Country: "United States", City: "San Jose", Hostname: "sjc-a44.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 122, 14}}},
{Country: "United States", City: "San Jose", Hostname: "sjc-a45.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 122, 20}}},
{Country: "United States", City: "San Jose", Hostname: "sjc-a46.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 122, 26}}},
{Country: "United States", City: "San Jose", Hostname: "sjc-a47.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 122, 32}}},
{Country: "United States", City: "San Jose", Hostname: "sjc-a48.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 122, 38}}},
{Country: "United States", City: "San Jose", Hostname: "sjc-a49.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 122, 44}}},
{Country: "United States", City: "San Jose", Hostname: "sjc-a50.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 122, 50}}},
{Country: "United States", City: "San Jose", Hostname: "sjc-a51.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 122, 56}}},
{Country: "United States", City: "San Jose", Hostname: "sjc-a52.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 122, 62}}},
{Country: "United States", City: "San Jose", Hostname: "sjc-a53.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 122, 68}}},
{Country: "United States", City: "San Jose", Hostname: "sjc-a54.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{216, 131, 122, 74}}},
{Country: "United States", City: "Seattle", Hostname: "sea-a01.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 223, 2}}},
{Country: "United States", City: "Seattle", Hostname: "sea-a02.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 223, 8}}},
{Country: "United States", City: "Seattle", Hostname: "sea-a03.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 223, 14}}},
{Country: "United States", City: "Seattle", Hostname: "sea-a04.ipvanish.com", TCP: false, UDP: true, IPs: []net.IP{{205, 185, 223, 35}}},

File diff suppressed because it is too large Load Diff

View File

@@ -23,7 +23,7 @@ func GetAllServers() (allServers models.AllServers) {
},
Ipvanish: models.IpvanishServers{
Version: 1,
Timestamp: 1625164062,
Timestamp: 1622430497,
Servers: IpvanishServers(),
},
Ivpn: models.IvpnServers{
@@ -53,7 +53,7 @@ func GetAllServers() (allServers models.AllServers) {
},
Protonvpn: models.ProtonvpnServers{
Version: 1,
Timestamp: 1624894186,
Timestamp: 1621791438,
Servers: ProtonvpnServers(),
},
Pia: models.PiaServers{

View File

@@ -175,7 +175,7 @@ func Test_timestamps(t *testing.T) {
"Ipvanish": {
servers: allServers.Ipvanish.Servers,
timestamp: allServers.Ipvanish.Timestamp,
digest: "7c60dc5d",
digest: "c62dcf98",
},
"Ivpn": {
servers: allServers.Ivpn.Servers,
@@ -210,7 +210,7 @@ func Test_timestamps(t *testing.T) {
"Protonvpn": {
servers: allServers.Protonvpn.Servers,
timestamp: allServers.Protonvpn.Timestamp,
digest: "3b86393e",
digest: "e7180296",
},
"Purevpn": {
servers: allServers.Purevpn.Servers,

View File

@@ -6,6 +6,7 @@ import (
"errors"
"net"
"net/http"
"sync"
"time"
"github.com/qdm12/dns/pkg/blacklist"
@@ -23,25 +24,23 @@ type Looper interface {
Run(ctx context.Context, done chan<- struct{})
RunRestartTicker(ctx context.Context, done chan<- struct{})
GetStatus() (status models.LoopStatus)
ApplyStatus(ctx context.Context, status models.LoopStatus) (
outcome string, err error)
SetStatus(status models.LoopStatus) (outcome string, err error)
GetSettings() (settings configuration.DNS)
SetSettings(ctx context.Context, settings configuration.DNS) (
outcome string)
SetSettings(settings configuration.DNS) (outcome string)
}
type looper struct {
state *state
state state
conf unbound.Configurator
blockBuilder blacklist.Builder
client *http.Client
logger logging.Logger
userTrigger bool
start <-chan struct{}
running chan<- models.LoopStatus
stop <-chan struct{}
stopped chan<- struct{}
updateTicker <-chan struct{}
loopLock sync.Mutex
start chan struct{}
running chan models.LoopStatus
stop chan struct{}
stopped chan struct{}
updateTicker chan struct{}
backoffTime time.Duration
timeNow func() time.Time
timeSince func(time.Time) time.Duration
@@ -52,26 +51,20 @@ const defaultBackoffTime = 10 * time.Second
func NewLooper(conf unbound.Configurator, settings configuration.DNS, client *http.Client,
logger logging.Logger, openFile os.OpenFileFunc) Looper {
start := make(chan struct{})
running := make(chan models.LoopStatus)
stop := make(chan struct{})
stopped := make(chan struct{})
updateTicker := make(chan struct{})
state := newState(constants.Stopped, settings, start, running, stop, stopped, updateTicker)
return &looper{
state: state,
state: state{
status: constants.Stopped,
settings: settings,
},
conf: conf,
blockBuilder: blacklist.NewBuilder(client),
client: client,
logger: logger,
userTrigger: true,
start: start,
running: running,
stop: stop,
stopped: stopped,
updateTicker: updateTicker,
start: make(chan struct{}),
running: make(chan models.LoopStatus),
stop: make(chan struct{}),
stopped: make(chan struct{}),
updateTicker: make(chan struct{}),
backoffTime: defaultBackoffTime,
timeNow: time.Now,
timeSince: time.Since,
@@ -83,7 +76,7 @@ func (l *looper) logAndWait(ctx context.Context, err error) {
if err != nil {
l.logger.Warn(err)
}
l.logger.Info("attempting restart in " + l.backoffTime.String())
l.logger.Info("attempting restart in %s", l.backoffTime)
timer := time.NewTimer(l.backoffTime)
l.backoffTime *= 2
select {
@@ -95,18 +88,6 @@ func (l *looper) logAndWait(ctx context.Context, err error) {
}
}
func (l *looper) signalOrSetStatus(status models.LoopStatus) {
if l.userTrigger {
l.userTrigger = false
select {
case l.running <- status:
default: // receiver droppped out - avoid deadlock on events routing when shutting down
}
} else {
l.state.SetStatus(status)
}
}
func (l *looper) Run(ctx context.Context, done chan<- struct{}) {
defer close(done)
@@ -120,43 +101,43 @@ func (l *looper) Run(ctx context.Context, done chan<- struct{}) {
return
}
crashed := false
l.backoffTime = defaultBackoffTime
for ctx.Err() == nil {
// Upper scope variables for Unbound only
// Their values are to be used if DOT=off
waitError := make(chan error)
unboundCancel := func() { waitError <- nil }
closeStreams := func() {}
var waitError chan error
var unboundCancel context.CancelFunc
var closeStreams func()
for l.GetSettings().Enabled {
var err error
unboundCancel, waitError, closeStreams, err = l.setupUnbound(ctx)
if err == nil {
l.backoffTime = defaultBackoffTime
l.logger.Info("ready")
l.signalOrSetStatus(constants.Running)
break
}
l.signalOrSetStatus(constants.Crashed)
if ctx.Err() != nil {
if !crashed {
l.running <- constants.Stopped
}
return
}
if !errors.Is(err, errUpdateFiles) {
const fallback = true
l.useUnencryptedDNS(fallback)
var err error
unboundCancel, waitError, closeStreams, err = l.setupUnbound(ctx, crashed)
if err != nil {
if !errors.Is(err, errUpdateFiles) {
const fallback = true
l.useUnencryptedDNS(fallback)
}
l.logAndWait(ctx, err)
continue
}
l.logAndWait(ctx, err)
break
}
if !l.GetSettings().Enabled {
const fallback = false
l.useUnencryptedDNS(fallback)
waitError := make(chan error)
unboundCancel = func() { waitError <- nil }
closeStreams = func() {}
}
l.userTrigger = false
stayHere := true
for stayHere {
select {
@@ -167,32 +148,31 @@ func (l *looper) Run(ctx context.Context, done chan<- struct{}) {
closeStreams()
return
case <-l.stop:
l.userTrigger = true
l.logger.Info("stopping")
const fallback = false
l.useUnencryptedDNS(fallback)
unboundCancel()
<-waitError
// do not close waitError or the waitError
// select case will trigger
closeStreams()
l.stopped <- struct{}{}
case <-l.start:
l.userTrigger = true
l.logger.Info("starting")
stayHere = false
case err := <-waitError: // unexpected error
close(waitError)
closeStreams()
unboundCancel()
l.state.SetStatus(constants.Crashed)
if ctx.Err() != nil {
close(waitError)
closeStreams()
return
}
l.state.setStatusWithLock(constants.Crashed)
const fallback = true
l.useUnencryptedDNS(fallback)
l.logAndWait(ctx, err)
stayHere = false
}
}
close(waitError)
closeStreams()
}
}
@@ -201,10 +181,11 @@ var errUpdateFiles = errors.New("cannot update files")
// Returning cancel == nil signals we want to re-run setupUnbound
// Returning err == errUpdateFiles signals we should not fall back
// on the plaintext DNS as DOT is still up and running.
func (l *looper) setupUnbound(ctx context.Context) (
func (l *looper) setupUnbound(ctx context.Context, previousCrashed bool) (
cancel context.CancelFunc, waitError chan error, closeStreams func(), err error) {
err = l.updateFiles(ctx)
if err != nil {
l.state.setStatusWithLock(constants.Crashed)
return nil, nil, nil, errUpdateFiles
}
@@ -214,16 +195,14 @@ func (l *looper) setupUnbound(ctx context.Context) (
stdoutLines, stderrLines, waitError, err := l.conf.Start(unboundCtx, settings.Unbound.VerbosityDetailsLevel)
if err != nil {
cancel()
if !previousCrashed {
l.running <- constants.Crashed
}
return nil, nil, nil, err
}
collectLinesDone := make(chan struct{})
go l.collectLines(stdoutLines, stderrLines, collectLinesDone)
closeStreams = func() {
close(stdoutLines)
close(stderrLines)
<-collectLinesDone
}
// use Unbound
nameserver.UseDNSInternally(net.IP{127, 0, 0, 1})
@@ -234,13 +213,32 @@ func (l *looper) setupUnbound(ctx context.Context) (
}
if err := check.WaitForDNS(ctx, net.DefaultResolver); err != nil {
if !previousCrashed {
l.running <- constants.Crashed
}
cancel()
<-waitError
close(waitError)
closeStreams()
close(stdoutLines)
close(stderrLines)
<-collectLinesDone
return nil, nil, nil, err
}
l.logger.Info("ready")
if !previousCrashed {
l.running <- constants.Running
} else {
l.backoffTime = defaultBackoffTime
l.state.setStatusWithLock(constants.Running)
}
closeStreams = func() {
close(stdoutLines)
close(stderrLines)
<-collectLinesDone
}
return cancel, waitError, closeStreams, nil
}
@@ -301,15 +299,15 @@ func (l *looper) RunRestartTicker(ctx context.Context, done chan<- struct{}) {
status := l.GetStatus()
if status == constants.Running {
if err := l.updateFiles(ctx); err != nil {
l.state.SetStatus(constants.Crashed)
l.state.setStatusWithLock(constants.Crashed)
l.logger.Error(err)
l.logger.Warn("skipping Unbound restart due to failed files update")
continue
}
}
_, _ = l.ApplyStatus(ctx, constants.Stopped)
_, _ = l.ApplyStatus(ctx, constants.Running)
_, _ = l.SetStatus(constants.Stopped)
_, _ = l.SetStatus(constants.Running)
settings := l.GetSettings()
timer.Reset(settings.UpdatePeriod)
@@ -355,14 +353,3 @@ func (l *looper) updateFiles(ctx context.Context) (err error) {
return l.conf.MakeUnboundConf(settings.Unbound)
}
func (l *looper) GetStatus() (status models.LoopStatus) { return l.state.GetStatus() }
func (l *looper) ApplyStatus(ctx context.Context, status models.LoopStatus) (
outcome string, err error) {
return l.state.ApplyStatus(ctx, status)
}
func (l *looper) GetSettings() (settings configuration.DNS) { return l.state.GetSettings() }
func (l *looper) SetSettings(ctx context.Context, settings configuration.DNS) (
outcome string) {
return l.state.SetSettings(ctx, settings)
}

View File

@@ -1,7 +1,6 @@
package dns
import (
"context"
"errors"
"fmt"
"reflect"
@@ -12,153 +11,92 @@ import (
"github.com/qdm12/gluetun/internal/models"
)
func newState(status models.LoopStatus, settings configuration.DNS,
start chan<- struct{}, running <-chan models.LoopStatus,
stop chan<- struct{}, stopped <-chan struct{},
updateTicker chan<- struct{}) *state {
return &state{
status: status,
settings: settings,
start: start,
running: running,
stop: stop,
stopped: stopped,
updateTicker: updateTicker,
}
}
type state struct {
loopMu sync.RWMutex
status models.LoopStatus
statusMu sync.RWMutex
status models.LoopStatus
settings configuration.DNS
statusMu sync.RWMutex
settingsMu sync.RWMutex
start chan<- struct{}
running <-chan models.LoopStatus
stop chan<- struct{}
stopped <-chan struct{}
updateTicker chan<- struct{}
}
func (s *state) Lock() { s.loopMu.Lock() }
func (s *state) Unlock() { s.loopMu.Unlock() }
// SetStatus sets the status thread safely.
// It should only be called by the loop internal code since
// it does not interact with the loop code directly.
func (s *state) SetStatus(status models.LoopStatus) {
func (s *state) setStatusWithLock(status models.LoopStatus) {
s.statusMu.Lock()
defer s.statusMu.Unlock()
s.status = status
}
// GetStatus gets the status thread safely.
func (s *state) GetStatus() (status models.LoopStatus) {
s.statusMu.RLock()
defer s.statusMu.RUnlock()
return s.status
func (l *looper) GetStatus() (status models.LoopStatus) {
l.state.statusMu.RLock()
defer l.state.statusMu.RUnlock()
return l.state.status
}
var ErrInvalidStatus = errors.New("invalid status")
// ApplyStatus sends signals to the running loop depending on the
// current status and status requested, such that its next status
// matches the requested one. It is thread safe and a synchronous call
// since it waits to the loop to fully change its status.
func (s *state) ApplyStatus(ctx context.Context, status models.LoopStatus) (
outcome string, err error) {
// prevent simultaneous loop changes by restricting
// multiple SetStatus calls to run sequentially.
s.loopMu.Lock()
defer s.loopMu.Unlock()
// not a read lock as we want to modify it eventually in
// the code below before any other call.
s.statusMu.Lock()
existingStatus := s.status
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
l.state.statusMu.Lock()
defer l.state.statusMu.Unlock()
existingStatus := l.state.status
switch status {
case constants.Running:
if existingStatus != constants.Stopped {
// starting, running, stopping, crashed
s.statusMu.Unlock()
return "already " + existingStatus.String(), nil
switch existingStatus {
case constants.Starting, constants.Running, constants.Stopping, constants.Crashed:
return fmt.Sprintf("already %s", existingStatus), nil
}
s.status = constants.Starting
s.statusMu.Unlock()
s.start <- struct{}{}
// Wait for the loop to react to the start signal
newStatus := constants.Starting // for canceled context
select {
case <-ctx.Done():
case newStatus = <-s.running:
}
s.SetStatus(newStatus)
l.loopLock.Lock()
defer l.loopLock.Unlock()
l.state.status = constants.Starting
l.state.statusMu.Unlock()
l.start <- struct{}{}
newStatus := <-l.running
l.state.statusMu.Lock()
l.state.status = newStatus
return newStatus.String(), nil
case constants.Stopped:
if existingStatus != constants.Running {
return "already " + existingStatus.String(), nil
switch existingStatus {
case constants.Starting, constants.Stopping, constants.Stopped, constants.Crashed:
return fmt.Sprintf("already %s", existingStatus), nil
}
s.status = constants.Stopping
s.statusMu.Unlock()
s.stop <- struct{}{}
// Wait for the loop to react to the stop signal
newStatus := constants.Stopping // for canceled context
select {
case <-ctx.Done():
case <-s.stopped:
newStatus = constants.Stopped
}
s.SetStatus(newStatus)
return newStatus.String(), nil
l.loopLock.Lock()
defer l.loopLock.Unlock()
l.state.status = constants.Stopping
l.state.statusMu.Unlock()
l.stop <- struct{}{}
<-l.stopped
l.state.statusMu.Lock()
l.state.status = constants.Stopped
return status.String(), nil
default:
return "", fmt.Errorf("%w: %s: it can only be one of: %s, %s",
ErrInvalidStatus, status, constants.Running, constants.Stopped)
}
}
func (s *state) GetSettings() (settings configuration.DNS) {
s.settingsMu.RLock()
defer s.settingsMu.RUnlock()
return s.settings
func (l *looper) GetSettings() (settings configuration.DNS) {
l.state.settingsMu.RLock()
defer l.state.settingsMu.RUnlock()
return l.state.settings
}
func (s *state) SetSettings(ctx context.Context, settings configuration.DNS) (
outcome string) {
s.settingsMu.Lock()
defer s.settingsMu.Unlock()
settingsUnchanged := reflect.DeepEqual(s.settings, settings)
func (l *looper) SetSettings(settings configuration.DNS) (outcome string) {
l.state.settingsMu.Lock()
settingsUnchanged := reflect.DeepEqual(l.state.settings, settings)
if settingsUnchanged {
l.state.settingsMu.Unlock()
return "settings left unchanged"
}
// Check for only update period change
tempSettings := s.settings
tempSettings := l.state.settings
tempSettings.UpdatePeriod = settings.UpdatePeriod
onlyUpdatePeriodChanged := reflect.DeepEqual(tempSettings, settings)
s.settings = settings
l.state.settings = settings
l.state.settingsMu.Unlock()
if onlyUpdatePeriodChanged {
s.updateTicker <- struct{}{}
l.updateTicker <- struct{}{}
return "update period changed"
}
// Restart
_, _ = s.ApplyStatus(ctx, constants.Stopped)
_, _ = l.SetStatus(constants.Stopped)
if settings.Enabled {
outcome, _ = s.ApplyStatus(ctx, constants.Running)
outcome, _ = l.SetStatus(constants.Running)
}
return outcome
}

View File

@@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"os/exec"
"strings"
"github.com/qdm12/golibs/command"
@@ -16,8 +15,7 @@ var (
)
func ip6tablesSupported(ctx context.Context, commander command.Commander) (supported bool) {
cmd := exec.CommandContext(ctx, "ip6tables", "-L")
if _, err := commander.Run(cmd); err != nil {
if _, err := commander.Run(ctx, "ip6tables", "-L"); err != nil {
return false
}
return true
@@ -42,8 +40,7 @@ func (c *configurator) runIP6tablesInstruction(ctx context.Context, instruction
fmt.Println("ip6tables " + instruction)
}
flags := strings.Fields(instruction)
cmd := exec.CommandContext(ctx, "ip6tables", flags...)
if output, err := c.commander.Run(cmd); err != nil {
if output, err := c.commander.Run(ctx, "ip6tables", flags...); err != nil {
return fmt.Errorf("%w: \"ip6tables %s\": %s: %s", ErrIP6Tables, instruction, output, err)
}
return nil

View File

@@ -7,7 +7,6 @@ import (
"io"
"net"
"os"
"os/exec"
"strings"
"github.com/qdm12/gluetun/internal/models"
@@ -47,8 +46,7 @@ func flipRule(rule string) string {
// Version obtains the version of the installed iptables.
func (c *configurator) Version(ctx context.Context) (string, error) {
cmd := exec.CommandContext(ctx, "iptables", "--version")
output, err := c.commander.Run(cmd)
output, err := c.commander.Run(ctx, "iptables", "--version")
if err != nil {
return "", err
}
@@ -76,8 +74,7 @@ func (c *configurator) runIptablesInstruction(ctx context.Context, instruction s
fmt.Printf("iptables %s\n", instruction)
}
flags := strings.Fields(instruction)
cmd := exec.CommandContext(ctx, "iptables", flags...)
if output, err := c.commander.Run(cmd); err != nil {
if output, err := c.commander.Run(ctx, "iptables", flags...); err != nil {
return fmt.Errorf("%w \"iptables %s\": %s: %s", ErrIPTables, instruction, output, err)
}
return nil

View File

@@ -9,24 +9,24 @@ import (
"time"
)
func (s *server) runHealthcheckLoop(ctx context.Context, done chan<- struct{}) {
func (s *server) runHealthcheckLoop(ctx context.Context, healthy chan<- bool, done chan<- struct{}) {
defer close(done)
s.openvpn.healthyTimer = time.NewTimer(defaultOpenvpnHealthyWaitTime)
for {
previousErr := s.handler.getErr()
err := healthCheck(ctx, s.resolver)
s.handler.setErr(err)
// Notify the healthy channel, or not if it's already full
select {
case healthy <- err == nil:
default:
}
if previousErr != nil && err == nil {
s.logger.Info("healthy!")
s.openvpn.healthyTimer.Stop()
s.openvpn.healthyWaitTime = defaultOpenvpnHealthyWaitTime
} else if previousErr == nil && err != nil {
s.logger.Info("unhealthy: " + err.Error())
s.openvpn.healthyTimer = time.NewTimer(s.openvpn.healthyWaitTime)
}
if err != nil { // try again after 1 second
@@ -38,12 +38,9 @@ func (s *server) runHealthcheckLoop(ctx context.Context, done chan<- struct{}) {
}
return
case <-timer.C:
case <-s.openvpn.healthyTimer.C:
s.onUnhealthyOpenvpn(ctx)
}
continue
}
// Success, check again in 5 seconds
const period = 5 * time.Second
timer := time.NewTimer(period)

View File

@@ -1,17 +0,0 @@
package healthcheck
import (
"context"
"time"
"github.com/qdm12/gluetun/internal/constants"
)
func (s *server) onUnhealthyOpenvpn(ctx context.Context) {
s.logger.Info("program has been unhealthy for " +
s.openvpn.healthyWaitTime.String() + ": restarting OpenVPN")
_, _ = s.openvpn.looper.ApplyStatus(ctx, constants.Stopped)
_, _ = s.openvpn.looper.ApplyStatus(ctx, constants.Running)
s.openvpn.healthyWaitTime += openvpnHealthyWaitTimeAdd
s.openvpn.healthyTimer = time.NewTimer(s.openvpn.healthyWaitTime)
}

View File

@@ -7,12 +7,11 @@ import (
"net/http"
"time"
"github.com/qdm12/gluetun/internal/openvpn"
"github.com/qdm12/golibs/logging"
)
type Server interface {
Run(ctx context.Context, done chan<- struct{})
Run(ctx context.Context, healthy chan<- bool, done chan<- struct{})
}
type server struct {
@@ -20,40 +19,22 @@ type server struct {
logger logging.Logger
handler *handler
resolver *net.Resolver
openvpn openvpnHealth
}
type openvpnHealth struct {
looper openvpn.Looper
healthyWaitTime time.Duration
healthyTimer *time.Timer
}
const (
defaultOpenvpnHealthyWaitTime = 6 * time.Second
openvpnHealthyWaitTimeAdd = 5 * time.Second
)
func NewServer(address string, logger logging.Logger,
openvpnLooper openvpn.Looper) Server {
func NewServer(address string, logger logging.Logger) Server {
return &server{
address: address,
logger: logger,
handler: newHandler(logger),
resolver: net.DefaultResolver,
openvpn: openvpnHealth{
looper: openvpnLooper,
healthyWaitTime: defaultOpenvpnHealthyWaitTime,
},
}
}
func (s *server) Run(ctx context.Context, done chan<- struct{}) {
func (s *server) Run(ctx context.Context, healthy chan<- bool, done chan<- struct{}) {
defer close(done)
s.logger.Debug("here 0")
loopDone := make(chan struct{})
go s.runHealthcheckLoop(ctx, loopDone)
go s.runHealthcheckLoop(ctx, healthy, loopDone)
server := http.Server{
Addr: s.address,

View File

@@ -15,12 +15,10 @@ import (
type Looper interface {
Run(ctx context.Context, done chan<- struct{})
SetStatus(ctx context.Context, status models.LoopStatus) (
outcome string, err error)
SetStatus(status models.LoopStatus) (outcome string, err error)
GetStatus() (status models.LoopStatus)
GetSettings() (settings configuration.HTTPProxy)
SetSettings(ctx context.Context, settings configuration.HTTPProxy) (
outcome string)
SetSettings(settings configuration.HTTPProxy) (outcome string)
}
type looper struct {
@@ -59,7 +57,7 @@ func (l *looper) Run(ctx context.Context, done chan<- struct{}) {
if l.GetSettings().Enabled {
go func() {
_, _ = l.SetStatus(ctx, constants.Running)
_, _ = l.SetStatus(constants.Running)
}()
}

View File

@@ -1,7 +1,6 @@
package httpproxy
import (
"context"
"errors"
"fmt"
"reflect"
@@ -33,8 +32,7 @@ func (l *looper) GetStatus() (status models.LoopStatus) {
var ErrInvalidStatus = errors.New("invalid status")
func (l *looper) SetStatus(ctx context.Context, status models.LoopStatus) (
outcome string, err error) {
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
l.state.statusMu.Lock()
defer l.state.statusMu.Unlock()
existingStatus := l.state.status
@@ -50,12 +48,7 @@ func (l *looper) SetStatus(ctx context.Context, status models.LoopStatus) (
l.state.status = constants.Starting
l.state.statusMu.Unlock()
l.start <- struct{}{}
newStatus := constants.Starting // for canceled context
select {
case <-ctx.Done():
case newStatus = <-l.running:
}
newStatus := <-l.running
l.state.statusMu.Lock()
l.state.status = newStatus
return newStatus.String(), nil
@@ -69,15 +62,9 @@ func (l *looper) SetStatus(ctx context.Context, status models.LoopStatus) (
l.state.status = constants.Stopping
l.state.statusMu.Unlock()
l.stop <- struct{}{}
newStatus := constants.Stopping // for canceled context
select {
case <-ctx.Done():
case <-l.stopped:
newStatus = constants.Stopped
}
<-l.stopped
l.state.statusMu.Lock()
l.state.status = newStatus
l.state.status = status
return status.String(), nil
default:
return "", fmt.Errorf("%w: %s: it can only be one of: %s, %s",
@@ -91,8 +78,7 @@ func (l *looper) GetSettings() (settings configuration.HTTPProxy) {
return l.state.settings
}
func (l *looper) SetSettings(ctx context.Context, settings configuration.HTTPProxy) (
outcome string) {
func (l *looper) SetSettings(settings configuration.HTTPProxy) (outcome string) {
l.state.settingsMu.Lock()
settingsUnchanged := reflect.DeepEqual(settings, l.state.settings)
if settingsUnchanged {
@@ -107,12 +93,12 @@ func (l *looper) SetSettings(ctx context.Context, settings configuration.HTTPPro
switch {
case !newEnabled && !previousEnabled:
case newEnabled && previousEnabled:
_, _ = l.SetStatus(ctx, constants.Stopped)
_, _ = l.SetStatus(ctx, constants.Running)
_, _ = l.SetStatus(constants.Stopped)
_, _ = l.SetStatus(constants.Running)
case newEnabled && !previousEnabled:
_, _ = l.SetStatus(ctx, constants.Running)
_, _ = l.SetStatus(constants.Running)
case !newEnabled && previousEnabled:
_, _ = l.SetStatus(ctx, constants.Stopped)
_, _ = l.SetStatus(constants.Stopped)
}
return "settings updated"
}

View File

@@ -4,9 +4,7 @@ import (
"context"
"errors"
"fmt"
"os/exec"
"strings"
"syscall"
"github.com/qdm12/gluetun/internal/constants"
)
@@ -32,10 +30,7 @@ func (c *configurator) Start(ctx context.Context, version string) (
c.logger.Info("starting OpenVPN " + version)
cmd := exec.CommandContext(ctx, bin, "--config", constants.OpenVPNConf)
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
return c.commander.Start(cmd)
return c.commander.Start(ctx, bin, "--config", constants.OpenVPNConf)
}
func (c *configurator) Version24(ctx context.Context) (version string, err error) {
@@ -49,8 +44,7 @@ func (c *configurator) Version25(ctx context.Context) (version string, err error
var ErrVersionTooShort = errors.New("version output is too short")
func (c *configurator) version(ctx context.Context, binName string) (version string, err error) {
cmd := exec.CommandContext(ctx, binName, "--version")
output, err := c.commander.Run(cmd)
output, err := c.commander.Run(ctx, binName, "--version")
if err != nil && err.Error() != "exit status 1" {
return "", err
}

View File

@@ -72,6 +72,8 @@ func processLogLine(s string) (filtered string, level logging.Level) {
Your credentials might be wrong 🤨
💡 If you use Private Internet Access, check https://github.com/qdm12/gluetun/issues/265
`
level = logging.LevelError
case strings.Contains(s, "TLS Error: TLS key negotiation failed to occur within 60 seconds (check your network connectivity)"): //nolint:lll

View File

@@ -42,7 +42,7 @@ func Test_processLogLine(t *testing.T) {
logging.LevelInfo},
"openvpn auth failed": {
"AUTH: Received control message: AUTH_FAILED",
"AUTH: Received control message: AUTH_FAILED\n\nYour credentials might be wrong 🤨\n\n",
"AUTH: Received control message: AUTH_FAILED\n\nYour credentials might be wrong 🤨\n\n💡 If you use Private Internet Access, check https://github.com/qdm12/gluetun/issues/265\n\n", //nolint:lll
logging.LevelError},
}
for name, tc := range tests {

View File

@@ -5,6 +5,7 @@ import (
"net"
"net/http"
"strings"
"sync"
"time"
"github.com/qdm12/gluetun/internal/configuration"
@@ -20,11 +21,9 @@ import (
type Looper interface {
Run(ctx context.Context, done chan<- struct{})
GetStatus() (status models.LoopStatus)
ApplyStatus(ctx context.Context, status models.LoopStatus) (
outcome string, err error)
SetStatus(status models.LoopStatus) (outcome string, err error)
GetSettings() (settings configuration.OpenVPN)
SetSettings(ctx context.Context, settings configuration.OpenVPN) (
outcome string)
SetSettings(settings configuration.OpenVPN) (outcome string)
GetServers() (servers models.AllServers)
SetServers(servers models.AllServers)
GetPortForwarded() (port uint16)
@@ -32,7 +31,7 @@ type Looper interface {
}
type looper struct {
state *state
state state
// Fixed parameters
username string
puid int
@@ -46,36 +45,34 @@ type looper struct {
client *http.Client
openFile os.OpenFileFunc
tunnelReady chan<- struct{}
// Internal channels and values
stop <-chan struct{}
stopped chan<- struct{}
start <-chan struct{}
running chan<- models.LoopStatus
healthy <-chan bool
// Internal channels and locks
loopLock sync.Mutex
running chan models.LoopStatus
stop, stopped chan struct{}
start chan struct{}
portForwardSignals chan net.IP
userTrigger bool
// Internal constant values
backoffTime time.Duration
crashed bool
backoffTime time.Duration
healthWaitTime time.Duration
}
const (
defaultBackoffTime = 15 * time.Second
defaultBackoffTime = 15 * time.Second
defaultHealthWaitTime = 6 * time.Second
)
func NewLooper(settings configuration.OpenVPN,
username string, puid, pgid int, allServers models.AllServers,
conf Configurator, fw firewall.Configurator, routing routing.Routing,
logger logging.ParentLogger, client *http.Client, openFile os.OpenFileFunc,
tunnelReady chan<- struct{}) Looper {
start := make(chan struct{})
running := make(chan models.LoopStatus)
stop := make(chan struct{})
stopped := make(chan struct{})
state := newState(constants.Stopped, settings, allServers,
start, running, stop, stopped)
tunnelReady chan<- struct{}, healthy <-chan bool) Looper {
return &looper{
state: state,
state: state{
status: constants.Stopped,
settings: settings,
allServers: allServers,
},
username: username,
puid: puid,
pgid: pgid,
@@ -87,33 +84,28 @@ func NewLooper(settings configuration.OpenVPN,
client: client,
openFile: openFile,
tunnelReady: tunnelReady,
start: start,
running: running,
stop: stop,
stopped: stopped,
healthy: healthy,
start: make(chan struct{}),
running: make(chan models.LoopStatus),
stop: make(chan struct{}),
stopped: make(chan struct{}),
portForwardSignals: make(chan net.IP),
userTrigger: true,
backoffTime: defaultBackoffTime,
healthWaitTime: defaultHealthWaitTime,
}
}
func (l *looper) PortForward(vpnGateway net.IP) { l.portForwardSignals <- vpnGateway }
func (l *looper) signalOrSetStatus(status models.LoopStatus) {
if l.userTrigger {
l.userTrigger = false
select {
case l.running <- status:
default: // receiver calling ApplyStatus droppped out
}
} else {
l.state.SetStatus(status)
func (l *looper) signalCrashedStatus() {
if !l.crashed {
l.crashed = true
l.running <- constants.Crashed
}
}
func (l *looper) Run(ctx context.Context, done chan<- struct{}) {
func (l *looper) Run(ctx context.Context, done chan<- struct{}) { //nolint:gocognit
defer close(done)
select {
case <-l.start:
case <-ctx.Done():
@@ -121,17 +113,17 @@ func (l *looper) Run(ctx context.Context, done chan<- struct{}) {
}
for ctx.Err() == nil {
settings, allServers := l.state.GetSettingsAndServers()
settings, allServers := l.state.getSettingsAndServers()
providerConf := provider.New(settings.Provider.Name, allServers, time.Now)
var connection models.OpenVPNConnection
var lines []string
var err error
if settings.Config == "" {
if len(settings.Config) == 0 {
connection, err = providerConf.GetOpenVPNConnection(settings.Provider.ServerSelection)
if err != nil {
l.signalOrSetStatus(constants.Crashed)
l.signalCrashedStatus()
l.logAndWait(ctx, err)
continue
}
@@ -139,30 +131,28 @@ func (l *looper) Run(ctx context.Context, done chan<- struct{}) {
} else {
lines, connection, err = l.processCustomConfig(settings)
if err != nil {
l.signalOrSetStatus(constants.Crashed)
l.signalCrashedStatus()
l.logAndWait(ctx, err)
continue
}
}
if err := writeOpenvpnConf(lines, l.openFile); err != nil {
l.signalOrSetStatus(constants.Crashed)
l.signalCrashedStatus()
l.logAndWait(ctx, err)
continue
}
if settings.User != "" {
err := l.conf.WriteAuthFile(
settings.User, settings.Password, l.puid, l.pgid)
if err != nil {
l.signalOrSetStatus(constants.Crashed)
if err := l.conf.WriteAuthFile(settings.User, settings.Password, l.puid, l.pgid); err != nil {
l.signalCrashedStatus()
l.logAndWait(ctx, err)
continue
}
}
if err := l.fw.SetVPNConnection(ctx, connection); err != nil {
l.signalOrSetStatus(constants.Crashed)
l.signalCrashedStatus()
l.logAndWait(ctx, err)
continue
}
@@ -172,18 +162,13 @@ func (l *looper) Run(ctx context.Context, done chan<- struct{}) {
stdoutLines, stderrLines, waitError, err := l.conf.Start(openvpnCtx, settings.Version)
if err != nil {
openvpnCancel()
l.signalOrSetStatus(constants.Crashed)
l.signalCrashedStatus()
l.logAndWait(ctx, err)
continue
}
lineCollectionDone := make(chan struct{})
go l.collectLines(stdoutLines, stderrLines, lineCollectionDone)
closeStreams := func() {
close(stdoutLines)
close(stderrLines)
<-lineCollectionDone
}
// Needs the stream line from main.go to know when the tunnel is up
portForwardDone := make(chan struct{})
@@ -198,8 +183,13 @@ func (l *looper) Run(ctx context.Context, done chan<- struct{}) {
}
}(openvpnCtx)
l.backoffTime = defaultBackoffTime
l.signalOrSetStatus(constants.Running)
if l.crashed {
l.crashed = false
l.backoffTime = defaultBackoffTime
l.state.setStatusWithLock(constants.Running)
} else {
l.running <- constants.Running
}
stayHere := true
for stayHere {
@@ -208,39 +198,55 @@ func (l *looper) Run(ctx context.Context, done chan<- struct{}) {
openvpnCancel()
<-waitError
close(waitError)
closeStreams()
close(stdoutLines)
close(stderrLines)
<-lineCollectionDone
<-portForwardDone
return
case <-l.stop:
l.userTrigger = true
l.logger.Info("stopping")
openvpnCancel()
<-waitError
// do not close waitError or the waitError
// select case will trigger
closeStreams()
<-portForwardDone
l.stopped <- struct{}{}
case <-l.start:
l.userTrigger = true
l.logger.Info("starting")
stayHere = false
case err := <-waitError: // unexpected error
close(waitError)
closeStreams()
l.state.Lock() // prevent SetStatus from running in parallel
openvpnCancel()
l.state.SetStatus(constants.Crashed)
<-portForwardDone
if ctx.Err() != nil {
close(waitError)
close(stdoutLines)
close(stderrLines)
<-lineCollectionDone
<-portForwardDone
return
}
l.state.setStatusWithLock(constants.Crashed)
l.logAndWait(ctx, err)
l.crashed = true
stayHere = false
case healthy := <-l.healthy:
if healthy {
continue
}
// ensure it stays unhealthy for some time before restarting it
healthy = l.waitForHealth(ctx)
if healthy || ctx.Err() != nil {
continue
}
l.crashed = true // flag as crashed
l.state.setStatusWithLock(constants.Stopping)
l.logger.Warn("unhealthy program: restarting openvpn")
openvpnCancel()
<-waitError
l.state.setStatusWithLock(constants.Stopped)
stayHere = false
l.state.Unlock()
}
}
openvpnCancel()
close(waitError)
close(stdoutLines)
close(stderrLines)
openvpnCancel() // just for the linter
}
}
@@ -248,7 +254,7 @@ func (l *looper) logAndWait(ctx context.Context, err error) {
if err != nil {
l.logger.Error(err)
}
l.logger.Info("retrying in " + l.backoffTime.String())
l.logger.Info("retrying in %s", l.backoffTime)
timer := time.NewTimer(l.backoffTime)
l.backoffTime *= 2
select {
@@ -260,6 +266,35 @@ func (l *looper) logAndWait(ctx context.Context, err error) {
}
}
// waitForHealth waits for a true healthy signal
// after restarting openvpn in order to avoid restarting
// openvpn in a loop as it requires a few seconds to connect.
func (l *looper) waitForHealth(ctx context.Context) (healthy bool) {
l.logger.Info("unhealthy program: waiting %s for it to change to healthy", l.healthWaitTime)
timer := time.NewTimer(l.healthWaitTime)
l.healthWaitTime *= 2
for {
select {
case healthy = <-l.healthy:
if !healthy {
break
}
if !timer.Stop() {
<-timer.C
}
l.healthWaitTime = defaultHealthWaitTime
return true
case <-timer.C:
return false
case <-ctx.Done():
if !timer.Stop() {
<-timer.C
}
return false
}
}
}
// portForward is a blocking operation which may or may not be infinite.
// You should therefore always call it in a goroutine.
func (l *looper) portForward(ctx context.Context,
@@ -294,27 +329,3 @@ func writeOpenvpnConf(lines []string, openFile os.OpenFileFunc) error {
}
return file.Close()
}
func (l *looper) GetStatus() (status models.LoopStatus) {
return l.state.GetStatus()
}
func (l *looper) ApplyStatus(ctx context.Context, status models.LoopStatus) (
outcome string, err error) {
return l.state.ApplyStatus(ctx, status)
}
func (l *looper) GetSettings() (settings configuration.OpenVPN) {
return l.state.GetSettings()
}
func (l *looper) SetSettings(ctx context.Context, settings configuration.OpenVPN) (
outcome string) {
return l.state.SetSettings(ctx, settings)
}
func (l *looper) GetServers() (servers models.AllServers) {
return l.state.GetServers()
}
func (l *looper) SetServers(servers models.AllServers) {
l.state.SetServers(servers)
}
func (l *looper) GetPortForwarded() (port uint16) {
return l.state.GetPortForwarded()
}

View File

@@ -1,7 +1,6 @@
package openvpn
import (
"context"
"errors"
"fmt"
"reflect"
@@ -12,63 +11,24 @@ import (
"github.com/qdm12/gluetun/internal/models"
)
func newState(status models.LoopStatus,
settings configuration.OpenVPN, allServers models.AllServers,
start chan<- struct{}, running <-chan models.LoopStatus,
stop chan<- struct{}, stopped <-chan struct{}) *state {
return &state{
status: status,
settings: settings,
allServers: allServers,
start: start,
running: running,
stop: stop,
stopped: stopped,
}
}
type state struct {
loopMu sync.RWMutex
status models.LoopStatus
statusMu sync.RWMutex
settings configuration.OpenVPN
settingsMu sync.RWMutex
allServers models.AllServers
allServersMu sync.RWMutex
status models.LoopStatus
settings configuration.OpenVPN
allServers models.AllServers
portForwarded uint16
statusMu sync.RWMutex
settingsMu sync.RWMutex
allServersMu sync.RWMutex
portForwardedMu sync.RWMutex
start chan<- struct{}
running <-chan models.LoopStatus
stop chan<- struct{}
stopped <-chan struct{}
}
func (s *state) Lock() { s.loopMu.Lock() }
func (s *state) Unlock() { s.loopMu.Unlock() }
// SetStatus sets the status thread safely.
// It should only be called by the loop internal code since
// it does not interact with the loop code directly.
func (s *state) SetStatus(status models.LoopStatus) {
func (s *state) setStatusWithLock(status models.LoopStatus) {
s.statusMu.Lock()
defer s.statusMu.Unlock()
s.status = status
}
// GetStatus gets the status thread safely.
func (s *state) GetStatus() (status models.LoopStatus) {
s.statusMu.RLock()
defer s.statusMu.RUnlock()
return s.status
}
func (s *state) GetSettingsAndServers() (settings configuration.OpenVPN,
allServers models.AllServers) {
func (s *state) getSettingsAndServers() (settings configuration.OpenVPN, allServers models.AllServers) {
s.settingsMu.RLock()
s.allServersMu.RLock()
settings = s.settings
@@ -78,102 +38,87 @@ func (s *state) GetSettingsAndServers() (settings configuration.OpenVPN,
return settings, allServers
}
func (l *looper) GetStatus() (status models.LoopStatus) {
l.state.statusMu.RLock()
defer l.state.statusMu.RUnlock()
return l.state.status
}
var ErrInvalidStatus = errors.New("invalid status")
// ApplyStatus sends signals to the running loop depending on the
// current status and status requested, such that its next status
// matches the requested one. It is thread safe and a synchronous call
// since it waits to the loop to fully change its status.
func (s *state) ApplyStatus(ctx context.Context, status models.LoopStatus) (
outcome string, err error) {
// prevent simultaneous loop changes by restricting
// multiple SetStatus calls to run sequentially.
s.loopMu.Lock()
defer s.loopMu.Unlock()
// not a read lock as we want to modify it eventually in
// the code below before any other call.
s.statusMu.Lock()
existingStatus := s.status
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
l.state.statusMu.Lock()
defer l.state.statusMu.Unlock()
existingStatus := l.state.status
switch status {
case constants.Running:
if existingStatus != constants.Stopped {
return "already " + existingStatus.String(), nil
switch existingStatus {
case constants.Starting, constants.Running, constants.Stopping, constants.Crashed:
return fmt.Sprintf("already %s", existingStatus), nil
}
s.status = constants.Starting
s.statusMu.Unlock()
s.start <- struct{}{}
// Wait for the loop to react to the start signal
newStatus := constants.Starting // for canceled context
select {
case <-ctx.Done():
case newStatus = <-s.running:
}
s.SetStatus(newStatus)
l.loopLock.Lock()
defer l.loopLock.Unlock()
l.state.status = constants.Starting
l.state.statusMu.Unlock()
l.start <- struct{}{}
newStatus := <-l.running
l.state.statusMu.Lock()
l.state.status = newStatus
return newStatus.String(), nil
case constants.Stopped:
if existingStatus != constants.Running {
return "already " + existingStatus.String(), nil
switch existingStatus {
case constants.Starting, constants.Stopping, constants.Stopped, constants.Crashed:
return fmt.Sprintf("already %s", existingStatus), nil
}
s.status = constants.Stopping
s.statusMu.Unlock()
s.stop <- struct{}{}
// Wait for the loop to react to the stop signal
newStatus := constants.Stopping // for canceled context
select {
case <-ctx.Done():
case <-s.stopped:
newStatus = constants.Stopped
}
s.SetStatus(newStatus)
return newStatus.String(), nil
l.loopLock.Lock()
defer l.loopLock.Unlock()
l.state.status = constants.Stopping
l.state.statusMu.Unlock()
l.stop <- struct{}{}
<-l.stopped
l.state.statusMu.Lock()
l.state.status = constants.Stopped
return status.String(), nil
default:
return "", fmt.Errorf("%w: %s: it can only be one of: %s, %s",
ErrInvalidStatus, status, constants.Running, constants.Stopped)
}
}
func (s *state) GetSettings() (settings configuration.OpenVPN) {
s.settingsMu.RLock()
defer s.settingsMu.RUnlock()
return s.settings
func (l *looper) GetSettings() (settings configuration.OpenVPN) {
l.state.settingsMu.RLock()
defer l.state.settingsMu.RUnlock()
return l.state.settings
}
func (s *state) SetSettings(ctx context.Context, settings configuration.OpenVPN) (
outcome string) {
s.settingsMu.Lock()
defer s.settingsMu.Unlock()
settingsUnchanged := reflect.DeepEqual(s.settings, settings)
func (l *looper) SetSettings(settings configuration.OpenVPN) (outcome string) {
l.state.settingsMu.Lock()
settingsUnchanged := reflect.DeepEqual(l.state.settings, settings)
if settingsUnchanged {
l.state.settingsMu.Unlock()
return "settings left unchanged"
}
s.settings = settings
_, _ = s.ApplyStatus(ctx, constants.Stopped)
outcome, _ = s.ApplyStatus(ctx, constants.Running)
l.state.settings = settings
_, _ = l.SetStatus(constants.Stopped)
outcome, _ = l.SetStatus(constants.Running)
return outcome
}
func (s *state) GetServers() (servers models.AllServers) {
s.allServersMu.RLock()
defer s.allServersMu.RUnlock()
return s.allServers
func (l *looper) GetServers() (servers models.AllServers) {
l.state.allServersMu.RLock()
defer l.state.allServersMu.RUnlock()
return l.state.allServers
}
func (s *state) SetServers(servers models.AllServers) {
s.allServersMu.Lock()
defer s.allServersMu.Unlock()
s.allServers = servers
func (l *looper) SetServers(servers models.AllServers) {
l.state.allServersMu.Lock()
defer l.state.allServersMu.Unlock()
l.state.allServers = servers
}
func (s *state) GetPortForwarded() (port uint16) {
s.portForwardedMu.RLock()
defer s.portForwardedMu.RUnlock()
return s.portForwarded
func (l *looper) GetPortForwarded() (port uint16) {
l.state.portForwardedMu.RLock()
defer l.state.portForwardedMu.RUnlock()
return l.state.portForwarded
}

View File

@@ -68,13 +68,6 @@ func (c *Cyberghost) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, "mssfix "+strconv.Itoa(int(settings.MSSFix)))
}
if settings.Provider.ExtraConfigOptions.OpenVPNIPv6 {
lines = append(lines, "tun-ipv6")
} else {
lines = append(lines, `pull-filter ignore "route-ipv6"`)
lines = append(lines, `pull-filter ignore "ifconfig-ipv6"`)
}
lines = append(lines, utils.WrapOpenvpnCA(
constants.CyberghostCertificate)...)
lines = append(lines, utils.WrapOpenvpnCert(

View File

@@ -62,13 +62,6 @@ func (f *Fastestvpn) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, "user "+username)
}
if settings.Provider.ExtraConfigOptions.OpenVPNIPv6 {
lines = append(lines, "tun-ipv6")
} else {
lines = append(lines, `pull-filter ignore "route-ipv6"`)
lines = append(lines, `pull-filter ignore "ifconfig-ipv6"`)
}
lines = append(lines, utils.WrapOpenvpnCA(
constants.FastestvpnCertificate)...)
lines = append(lines, utils.WrapOpenvpnTLSAuth(

View File

@@ -59,13 +59,6 @@ func (h *HideMyAss) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, "user "+username)
}
if settings.Provider.ExtraConfigOptions.OpenVPNIPv6 {
lines = append(lines, "tun-ipv6")
} else {
lines = append(lines, `pull-filter ignore "route-ipv6"`)
lines = append(lines, `pull-filter ignore "ifconfig-ipv6"`)
}
lines = append(lines, utils.WrapOpenvpnCA(
constants.HideMyAssCA)...)
lines = append(lines, utils.WrapOpenvpnCert(

View File

@@ -57,13 +57,6 @@ func (i *Ipvanish) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, "user "+username)
}
if settings.Provider.ExtraConfigOptions.OpenVPNIPv6 {
lines = append(lines, "tun-ipv6")
} else {
lines = append(lines, `pull-filter ignore "route-ipv6"`)
lines = append(lines, `pull-filter ignore "ifconfig-ipv6"`)
}
lines = append(lines, utils.WrapOpenvpnCA(constants.IpvanishCA)...)
lines = append(lines, "")

View File

@@ -63,13 +63,6 @@ func (i *Ivpn) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, "user "+username)
}
if settings.Provider.ExtraConfigOptions.OpenVPNIPv6 {
lines = append(lines, "tun-ipv6")
} else {
lines = append(lines, `pull-filter ignore "route-ipv6"`)
lines = append(lines, `pull-filter ignore "ifconfig-ipv6"`)
}
lines = append(lines, utils.WrapOpenvpnCA(
constants.IvpnCA)...)
lines = append(lines, utils.WrapOpenvpnTLSAuth(

View File

@@ -71,13 +71,6 @@ func (m *Mullvad) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, "mssfix "+strconv.Itoa(int(settings.MSSFix)))
}
if settings.Provider.ExtraConfigOptions.OpenVPNIPv6 {
lines = append(lines, "tun-ipv6")
} else {
lines = append(lines, `pull-filter ignore "route-ipv6"`)
lines = append(lines, `pull-filter ignore "ifconfig-ipv6"`)
}
lines = append(lines, utils.WrapOpenvpnCA(
constants.MullvadCertificate)...)

View File

@@ -67,13 +67,6 @@ func (n *Nordvpn) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, "user "+username)
}
if settings.Provider.ExtraConfigOptions.OpenVPNIPv6 {
lines = append(lines, "tun-ipv6")
} else {
lines = append(lines, `pull-filter ignore "route-ipv6"`)
lines = append(lines, `pull-filter ignore "ifconfig-ipv6"`)
}
lines = append(lines, utils.WrapOpenvpnCA(
constants.NordvpnCertificate)...)
lines = append(lines, utils.WrapOpenvpnTLSAuth(

View File

@@ -58,13 +58,6 @@ func (p *Privado) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, "mssfix "+strconv.Itoa(int(settings.MSSFix)))
}
if settings.Provider.ExtraConfigOptions.OpenVPNIPv6 {
lines = append(lines, "tun-ipv6")
} else {
lines = append(lines, `pull-filter ignore "route-ipv6"`)
lines = append(lines, `pull-filter ignore "ifconfig-ipv6"`)
}
lines = append(lines, utils.WrapOpenvpnCA(
constants.PrivadoCertificate)...)

View File

@@ -81,13 +81,6 @@ func (p *PIA) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, "mssfix "+strconv.Itoa(int(settings.MSSFix)))
}
if settings.Provider.ExtraConfigOptions.OpenVPNIPv6 {
lines = append(lines, "tun-ipv6")
} else {
lines = append(lines, `pull-filter ignore "route-ipv6"`)
lines = append(lines, `pull-filter ignore "ifconfig-ipv6"`)
}
lines = append(lines, utils.WrapOpenvpnCA(certificate)...)
lines = append(lines, utils.WrapOpenvpnCRLVerify(X509CRL)...)

View File

@@ -29,6 +29,7 @@ func (p *Privatevpn) BuildConf(connection models.OpenVPNConnection,
// Privatevpn specific
"comp-lzo",
"tun-ipv6",
// Added constant values
"auth-nocache",
@@ -59,13 +60,6 @@ func (p *Privatevpn) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, "mssfix "+strconv.Itoa(int(settings.MSSFix)))
}
if settings.Provider.ExtraConfigOptions.OpenVPNIPv6 {
lines = append(lines, "tun-ipv6")
} else {
lines = append(lines, `pull-filter ignore "route-ipv6"`)
lines = append(lines, `pull-filter ignore "ifconfig-ipv6"`)
}
lines = append(lines, utils.WrapOpenvpnCA(
constants.PrivatevpnCertificate)...)
lines = append(lines, utils.WrapOpenvpnTLSCrypt(

View File

@@ -66,13 +66,6 @@ func (p *Protonvpn) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, "user "+username)
}
if settings.Provider.ExtraConfigOptions.OpenVPNIPv6 {
lines = append(lines, "tun-ipv6")
} else {
lines = append(lines, `pull-filter ignore "route-ipv6"`)
lines = append(lines, `pull-filter ignore "ifconfig-ipv6"`)
}
lines = append(lines, utils.WrapOpenvpnCA(
constants.ProtonvpnCertificate)...)
lines = append(lines, utils.WrapOpenvpnTLSAuth(

View File

@@ -66,13 +66,6 @@ func (p *Purevpn) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, "user "+username)
}
if settings.Provider.ExtraConfigOptions.OpenVPNIPv6 {
lines = append(lines, "tun-ipv6")
} else {
lines = append(lines, `pull-filter ignore "route-ipv6"`)
lines = append(lines, `pull-filter ignore "ifconfig-ipv6"`)
}
lines = append(lines, utils.WrapOpenvpnCA(
constants.PurevpnCertificateAuthority)...)
lines = append(lines, utils.WrapOpenvpnCert(

View File

@@ -64,13 +64,6 @@ func (s *Surfshark) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, "user "+username)
}
if settings.Provider.ExtraConfigOptions.OpenVPNIPv6 {
lines = append(lines, "tun-ipv6")
} else {
lines = append(lines, `pull-filter ignore "route-ipv6"`)
lines = append(lines, `pull-filter ignore "ifconfig-ipv6"`)
}
lines = append(lines, utils.WrapOpenvpnCA(
constants.SurfsharkCertificate)...)
lines = append(lines, utils.WrapOpenvpnTLSAuth(

View File

@@ -70,13 +70,6 @@ func (t *Torguard) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, "fast-io")
}
if settings.Provider.ExtraConfigOptions.OpenVPNIPv6 {
lines = append(lines, "tun-ipv6")
} else {
lines = append(lines, `pull-filter ignore "route-ipv6"`)
lines = append(lines, `pull-filter ignore "ifconfig-ipv6"`)
}
lines = append(lines, utils.WrapOpenvpnCA(
constants.TorguardCertificate)...)
lines = append(lines, utils.WrapOpenvpnTLSAuth(

View File

@@ -35,6 +35,7 @@ func (p *Provider) BuildConf(connection models.OpenVPNConnection,
// Modified variables
"verb " + strconv.Itoa(settings.Verbosity),
// "auth-user-pass " + constants.OpenVPNAuthConf,
connection.ProtoLine(),
connection.RemoteLine(),
}
@@ -55,13 +56,6 @@ func (p *Provider) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, "user "+username)
}
if settings.Provider.ExtraConfigOptions.OpenVPNIPv6 {
lines = append(lines, "tun-ipv6")
} else {
lines = append(lines, `pull-filter ignore "route-ipv6"`)
lines = append(lines, `pull-filter ignore "ifconfig-ipv6"`)
}
lines = append(lines, utils.WrapOpenvpnCA(
constants.VPNUnlimitedCertificateAuthority)...)
lines = append(lines, utils.WrapOpenvpnCert(

View File

@@ -67,13 +67,6 @@ func (w *Windscribe) BuildConf(connection models.OpenVPNConnection,
lines = append(lines, "mssfix "+strconv.Itoa(int(settings.MSSFix)))
}
if settings.Provider.ExtraConfigOptions.OpenVPNIPv6 {
lines = append(lines, "tun-ipv6")
} else {
lines = append(lines, `pull-filter ignore "route-ipv6"`)
lines = append(lines, `pull-filter ignore "ifconfig-ipv6"`)
}
lines = append(lines, utils.WrapOpenvpnCA(
constants.WindscribeCertificate)...)
lines = append(lines, utils.WrapOpenvpnTLSAuth(

View File

@@ -18,8 +18,7 @@ type Looper interface {
Run(ctx context.Context, done chan<- struct{})
RunRestartTicker(ctx context.Context, done chan<- struct{})
GetStatus() (status models.LoopStatus)
SetStatus(ctx context.Context, status models.LoopStatus) (
outcome string, err error)
SetStatus(status models.LoopStatus) (outcome string, err error)
GetSettings() (settings configuration.PublicIP)
SetSettings(settings configuration.PublicIP) (outcome string)
GetPublicIP() (publicIP net.IP)

View File

@@ -1,7 +1,6 @@
package publicip
import (
"context"
"errors"
"fmt"
"net"
@@ -36,8 +35,7 @@ func (l *looper) GetStatus() (status models.LoopStatus) {
var ErrInvalidStatus = errors.New("invalid status")
func (l *looper) SetStatus(ctx context.Context, status models.LoopStatus) (
outcome string, err error) {
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
l.state.statusMu.Lock()
defer l.state.statusMu.Unlock()
existingStatus := l.state.status
@@ -53,12 +51,7 @@ func (l *looper) SetStatus(ctx context.Context, status models.LoopStatus) (
l.state.status = constants.Starting
l.state.statusMu.Unlock()
l.start <- struct{}{}
newStatus := constants.Starting // for canceled context
select {
case <-ctx.Done():
case newStatus = <-l.running:
}
newStatus := <-l.running
l.state.statusMu.Lock()
l.state.status = newStatus
return newStatus.String(), nil
@@ -72,15 +65,9 @@ func (l *looper) SetStatus(ctx context.Context, status models.LoopStatus) (
l.state.status = constants.Stopping
l.state.statusMu.Unlock()
l.stop <- struct{}{}
newStatus := constants.Stopping // for canceled context
select {
case <-ctx.Done():
case <-l.stopped:
newStatus = constants.Stopped
}
<-l.stopped
l.state.statusMu.Lock()
l.state.status = newStatus
l.state.status = status
return status.String(), nil
default:
return "", fmt.Errorf("%w: %s: it can only be one of: %s, %s",
@@ -94,8 +81,7 @@ func (l *looper) GetSettings() (settings configuration.PublicIP) {
return l.state.settings
}
func (l *looper) SetSettings(settings configuration.PublicIP) (
outcome string) {
func (l *looper) SetSettings(settings configuration.PublicIP) (outcome string) {
l.state.settingsMu.Lock()
defer l.state.settingsMu.Unlock()
settingsUnchanged := reflect.DeepEqual(settings, l.state.settings)

View File

@@ -1,7 +1,6 @@
package server
import (
"context"
"encoding/json"
"net/http"
"strings"
@@ -10,17 +9,14 @@ import (
"github.com/qdm12/golibs/logging"
)
func newDNSHandler(ctx context.Context, looper dns.Looper,
logger logging.Logger) http.Handler {
func newDNSHandler(looper dns.Looper, logger logging.Logger) http.Handler {
return &dnsHandler{
ctx: ctx,
looper: looper,
logger: logger,
}
}
type dnsHandler struct {
ctx context.Context
looper dns.Looper
logger logging.Logger
}
@@ -65,7 +61,7 @@ func (h *dnsHandler) setStatus(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
outcome, err := h.looper.ApplyStatus(h.ctx, status)
outcome, err := h.looper.SetStatus(status)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return

View File

@@ -1,7 +1,6 @@
package server
import (
"context"
"net/http"
"strings"
@@ -13,7 +12,7 @@ import (
"github.com/qdm12/golibs/logging"
)
func newHandler(ctx context.Context, logger logging.Logger, logging bool,
func newHandler(logger logging.Logger, logging bool,
buildInfo models.BuildInformation,
openvpnLooper openvpn.Looper,
unboundLooper dns.Looper,
@@ -22,12 +21,12 @@ func newHandler(ctx context.Context, logger logging.Logger, logging bool,
) http.Handler {
handler := &handler{}
openvpn := newOpenvpnHandler(ctx, openvpnLooper, logger)
dns := newDNSHandler(ctx, unboundLooper, logger)
updater := newUpdaterHandler(ctx, updaterLooper, logger)
openvpn := newOpenvpnHandler(openvpnLooper, logger)
dns := newDNSHandler(unboundLooper, logger)
updater := newUpdaterHandler(updaterLooper, logger)
publicip := newPublicIPHandler(publicIPLooper, logger)
handler.v0 = newHandlerV0(ctx, logger, openvpnLooper, unboundLooper, updaterLooper)
handler.v0 = newHandlerV0(logger, openvpnLooper, unboundLooper, updaterLooper)
handler.v1 = newHandlerV1(logger, buildInfo, openvpn, dns, updater, publicip)
handlerWithLog := withLogMiddleware(handler, logger, logging)

View File

@@ -1,7 +1,6 @@
package server
import (
"context"
"net/http"
"github.com/qdm12/gluetun/internal/constants"
@@ -11,10 +10,9 @@ import (
"github.com/qdm12/golibs/logging"
)
func newHandlerV0(ctx context.Context, logger logging.Logger,
func newHandlerV0(logger logging.Logger,
openvpn openvpn.Looper, dns dns.Looper, updater updater.Looper) http.Handler {
return &handlerV0{
ctx: ctx,
logger: logger,
openvpn: openvpn,
dns: dns,
@@ -23,7 +21,6 @@ func newHandlerV0(ctx context.Context, logger logging.Logger,
}
type handlerV0 struct {
ctx context.Context
logger logging.Logger
openvpn openvpn.Looper
dns dns.Looper
@@ -39,17 +36,17 @@ func (h *handlerV0) ServeHTTP(w http.ResponseWriter, r *http.Request) {
case "/version":
http.Redirect(w, r, "/v1/version", http.StatusPermanentRedirect)
case "/openvpn/actions/restart":
outcome, _ := h.openvpn.ApplyStatus(h.ctx, constants.Stopped)
outcome, _ := h.openvpn.SetStatus(constants.Stopped)
h.logger.Info("openvpn: %s", outcome)
outcome, _ = h.openvpn.ApplyStatus(h.ctx, constants.Running)
outcome, _ = h.openvpn.SetStatus(constants.Running)
h.logger.Info("openvpn: %s", outcome)
if _, err := w.Write([]byte("openvpn restarted, please consider using the /v1/ API in the future.")); err != nil {
h.logger.Warn(err)
}
case "/unbound/actions/restart":
outcome, _ := h.dns.ApplyStatus(h.ctx, constants.Stopped)
outcome, _ := h.dns.SetStatus(constants.Stopped)
h.logger.Info("dns: %s", outcome)
outcome, _ = h.dns.ApplyStatus(h.ctx, constants.Running)
outcome, _ = h.dns.SetStatus(constants.Running)
h.logger.Info("dns: %s", outcome)
if _, err := w.Write([]byte("dns restarted, please consider using the /v1/ API in the future.")); err != nil {
h.logger.Warn(err)
@@ -59,9 +56,9 @@ func (h *handlerV0) ServeHTTP(w http.ResponseWriter, r *http.Request) {
case "/openvpn/settings":
http.Redirect(w, r, "/v1/openvpn/settings", http.StatusPermanentRedirect)
case "/updater/restart":
outcome, _ := h.updater.SetStatus(h.ctx, constants.Stopped)
outcome, _ := h.updater.SetStatus(constants.Stopped)
h.logger.Info("updater: %s", outcome)
outcome, _ = h.updater.SetStatus(h.ctx, constants.Running)
outcome, _ = h.updater.SetStatus(constants.Running)
h.logger.Info("updater: %s", outcome)
if _, err := w.Write([]byte("updater restarted, please consider using the /v1/ API in the future.")); err != nil {
h.logger.Warn(err)

View File

@@ -1,7 +1,6 @@
package server
import (
"context"
"encoding/json"
"net/http"
"strings"
@@ -10,17 +9,14 @@ import (
"github.com/qdm12/golibs/logging"
)
func newOpenvpnHandler(ctx context.Context, looper openvpn.Looper,
logger logging.Logger) http.Handler {
func newOpenvpnHandler(looper openvpn.Looper, logger logging.Logger) http.Handler {
return &openvpnHandler{
ctx: ctx,
looper: looper,
logger: logger,
}
}
type openvpnHandler struct {
ctx context.Context
looper openvpn.Looper
logger logging.Logger
}
@@ -79,7 +75,7 @@ func (h *openvpnHandler) setStatus(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
outcome, err := h.looper.ApplyStatus(h.ctx, status)
outcome, err := h.looper.SetStatus(status)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return

View File

@@ -25,11 +25,11 @@ type server struct {
handler http.Handler
}
func New(ctx context.Context, address string, logEnabled bool, logger logging.Logger,
func New(address string, logEnabled bool, logger logging.Logger,
buildInfo models.BuildInformation,
openvpnLooper openvpn.Looper, unboundLooper dns.Looper,
updaterLooper updater.Looper, publicIPLooper publicip.Looper) Server {
handler := newHandler(ctx, logger, logEnabled, buildInfo,
handler := newHandler(logger, logEnabled, buildInfo,
openvpnLooper, unboundLooper, updaterLooper, publicIPLooper)
return &server{
address: address,

View File

@@ -1,7 +1,6 @@
package server
import (
"context"
"encoding/json"
"net/http"
"strings"
@@ -11,18 +10,15 @@ import (
)
func newUpdaterHandler(
ctx context.Context,
looper updater.Looper,
logger logging.Logger) http.Handler {
return &updaterHandler{
ctx: ctx,
looper: looper,
logger: logger,
}
}
type updaterHandler struct {
ctx context.Context
looper updater.Looper
logger logging.Logger
}
@@ -67,7 +63,7 @@ func (h *updaterHandler) setStatus(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
outcome, err := h.looper.SetStatus(h.ctx, status)
outcome, err := h.looper.SetStatus(status)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return

View File

@@ -16,12 +16,10 @@ import (
type Looper interface {
Run(ctx context.Context, done chan<- struct{})
SetStatus(ctx context.Context, status models.LoopStatus) (
outcome string, err error)
SetStatus(status models.LoopStatus) (outcome string, err error)
GetStatus() (status models.LoopStatus)
GetSettings() (settings configuration.ShadowSocks)
SetSettings(ctx context.Context, settings configuration.ShadowSocks) (
outcome string)
SetSettings(settings configuration.ShadowSocks) (outcome string)
}
type looper struct {
@@ -76,7 +74,7 @@ func (l *looper) Run(ctx context.Context, done chan<- struct{}) {
if l.GetSettings().Enabled {
go func() {
_, _ = l.SetStatus(ctx, constants.Running)
_, _ = l.SetStatus(constants.Running)
}()
}

View File

@@ -1,7 +1,6 @@
package shadowsocks
import (
"context"
"errors"
"fmt"
"reflect"
@@ -33,8 +32,7 @@ func (l *looper) GetStatus() (status models.LoopStatus) {
var ErrInvalidStatus = errors.New("invalid status")
func (l *looper) SetStatus(ctx context.Context, status models.LoopStatus) (
outcome string, err error) {
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
l.state.statusMu.Lock()
defer l.state.statusMu.Unlock()
existingStatus := l.state.status
@@ -50,12 +48,7 @@ func (l *looper) SetStatus(ctx context.Context, status models.LoopStatus) (
l.state.status = constants.Starting
l.state.statusMu.Unlock()
l.start <- struct{}{}
newStatus := constants.Starting // for canceled context
select {
case <-ctx.Done():
case newStatus = <-l.running:
}
newStatus := <-l.running
l.state.statusMu.Lock()
l.state.status = newStatus
return newStatus.String(), nil
@@ -69,14 +62,9 @@ func (l *looper) SetStatus(ctx context.Context, status models.LoopStatus) (
l.state.status = constants.Stopping
l.state.statusMu.Unlock()
l.stop <- struct{}{}
newStatus := constants.Stopping // for canceled context
select {
case <-ctx.Done():
case <-l.stopped:
newStatus = constants.Stopped
}
<-l.stopped
l.state.statusMu.Lock()
l.state.status = newStatus
l.state.status = status
return status.String(), nil
default:
return "", fmt.Errorf("%w: %s: it can only be one of: %s, %s",
@@ -90,8 +78,7 @@ func (l *looper) GetSettings() (settings configuration.ShadowSocks) {
return l.state.settings
}
func (l *looper) SetSettings(ctx context.Context, settings configuration.ShadowSocks) (
outcome string) {
func (l *looper) SetSettings(settings configuration.ShadowSocks) (outcome string) {
l.state.settingsMu.Lock()
settingsUnchanged := reflect.DeepEqual(settings, l.state.settings)
if settingsUnchanged {
@@ -106,12 +93,12 @@ func (l *looper) SetSettings(ctx context.Context, settings configuration.ShadowS
switch {
case !newEnabled && !previousEnabled:
case newEnabled && previousEnabled:
_, _ = l.SetStatus(ctx, constants.Stopped)
_, _ = l.SetStatus(ctx, constants.Running)
_, _ = l.SetStatus(constants.Stopped)
_, _ = l.SetStatus(constants.Running)
case newEnabled && !previousEnabled:
_, _ = l.SetStatus(ctx, constants.Running)
_, _ = l.SetStatus(constants.Running)
case !newEnabled && previousEnabled:
_, _ = l.SetStatus(ctx, constants.Stopped)
_, _ = l.SetStatus(constants.Stopped)
}
return "settings updated"
}

View File

@@ -17,8 +17,7 @@ type Looper interface {
Run(ctx context.Context, done chan<- struct{})
RunRestartTicker(ctx context.Context, done chan<- struct{})
GetStatus() (status models.LoopStatus)
SetStatus(ctx context.Context, status models.LoopStatus) (
outcome string, err error)
SetStatus(status models.LoopStatus) (outcome string, err error)
GetSettings() (settings configuration.Updater)
SetSettings(settings configuration.Updater) (outcome string)
}

View File

@@ -1,7 +1,6 @@
package updater
import (
"context"
"errors"
"fmt"
"reflect"
@@ -33,7 +32,7 @@ func (l *looper) GetStatus() (status models.LoopStatus) {
var ErrInvalidStatus = errors.New("invalid status")
func (l *looper) SetStatus(ctx context.Context, status models.LoopStatus) (outcome string, err error) {
func (l *looper) SetStatus(status models.LoopStatus) (outcome string, err error) {
l.state.statusMu.Lock()
defer l.state.statusMu.Unlock()
existingStatus := l.state.status
@@ -49,12 +48,7 @@ func (l *looper) SetStatus(ctx context.Context, status models.LoopStatus) (outco
l.state.status = constants.Starting
l.state.statusMu.Unlock()
l.start <- struct{}{}
newStatus := constants.Starting // for canceled context
select {
case <-ctx.Done():
case newStatus = <-l.running:
}
newStatus := <-l.running
l.state.statusMu.Lock()
l.state.status = newStatus
return newStatus.String(), nil
@@ -68,15 +62,9 @@ func (l *looper) SetStatus(ctx context.Context, status models.LoopStatus) (outco
l.state.status = constants.Stopping
l.state.statusMu.Unlock()
l.stop <- struct{}{}
newStatus := constants.Stopping // for canceled context
select {
case <-ctx.Done():
case <-l.stopped:
newStatus = constants.Stopped
}
<-l.stopped
l.state.statusMu.Lock()
l.state.status = newStatus
l.state.status = status
return status.String(), nil
default:
return "", fmt.Errorf("%w: %s: it can only be one of: %s, %s",