Windscribe support (#114)
This commit is contained in:
@@ -38,7 +38,7 @@ ENV VPNSP=pia \
|
|||||||
TZ= \
|
TZ= \
|
||||||
# PIA only
|
# PIA only
|
||||||
PASSWORD= \
|
PASSWORD= \
|
||||||
REGION="CA Montreal" \
|
REGION="Austria" \
|
||||||
PIA_ENCRYPTION=strong \
|
PIA_ENCRYPTION=strong \
|
||||||
OPENVPN_CIPHER= \
|
OPENVPN_CIPHER= \
|
||||||
OPENVPN_AUTH= \
|
OPENVPN_AUTH= \
|
||||||
@@ -48,6 +48,7 @@ ENV VPNSP=pia \
|
|||||||
COUNTRY=Sweden \
|
COUNTRY=Sweden \
|
||||||
CITY= \
|
CITY= \
|
||||||
ISP= \
|
ISP= \
|
||||||
|
# Mullvad and Windscribe only
|
||||||
PORT= \
|
PORT= \
|
||||||
# DNS over TLS
|
# DNS over TLS
|
||||||
DOT=on \
|
DOT=on \
|
||||||
|
|||||||
31
README.md
31
README.md
@@ -1,8 +1,8 @@
|
|||||||
# Private Internet Access Client
|
# Gluetun VPN client
|
||||||
|
|
||||||
*Lightweight swiss-knife-like VPN client to tunnel to Private Internet Access or Mullvad VPN servers, using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and Tinyproxy*
|
*Lightweight swiss-knife-like VPN client to tunnel to Private Internet Access, Mullvad and Windscribe VPN servers, using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and Tinyproxy*
|
||||||
|
|
||||||
**ANNOUNCEMENT**: *Support for [Mullvad](http://mullvad.net)*
|
**ANNOUNCEMENT**: *Support for [Windscribe](https://windscribe.com/)*
|
||||||
|
|
||||||
<img height="200" src="title.svg?sanitize=true">
|
<img height="200" src="title.svg?sanitize=true">
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Based on Alpine 3.11 for a small Docker image below 50MB
|
- Based on Alpine 3.11 for a small Docker image below 50MB
|
||||||
- Supports **Private Internet Access** and **Mullvad** servers
|
- Supports **Private Internet Access**, **Mullvad** and **Windscribe** servers
|
||||||
- DNS over TLS baked in with service provider(s) of your choice
|
- DNS over TLS baked in with service provider(s) of your choice
|
||||||
- DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses
|
- DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses
|
||||||
- Choose the vpn network protocol, `udp` or `tcp`
|
- Choose the vpn network protocol, `udp` or `tcp`
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
- Built in HTTP proxy (Tinyproxy, tunnels TCP)
|
- Built in HTTP proxy (Tinyproxy, tunnels TCP)
|
||||||
- [Connect other containers to it](https://github.com/qdm12/private-internet-access-docker#connect-to-it)
|
- [Connect other containers to it](https://github.com/qdm12/private-internet-access-docker#connect-to-it)
|
||||||
- [Connect LAN devices to it](https://github.com/qdm12/private-internet-access-docker#connect-to-it)
|
- [Connect LAN devices to it](https://github.com/qdm12/private-internet-access-docker#connect-to-it)
|
||||||
- Compatible with amd64, i686 (32 bit), **ARM** 64 bit, ARM 32 bit v6 and v7, ppc64le and even that s390x 🎆
|
- Compatible with amd64, i686 (32 bit), **ARM** 64 bit, ARM 32 bit v6 and v7 🎆
|
||||||
|
|
||||||
### Private Internet Access
|
### Private Internet Access
|
||||||
|
|
||||||
@@ -55,6 +55,10 @@
|
|||||||
- Pick the [country, city and ISP](https://mullvad.net/en/servers/#openvpn)
|
- Pick the [country, city and ISP](https://mullvad.net/en/servers/#openvpn)
|
||||||
- Pick the port to use (i.e. `53` (udp) or `80` (tcp))
|
- Pick the port to use (i.e. `53` (udp) or `80` (tcp))
|
||||||
|
|
||||||
|
### Windscribe
|
||||||
|
|
||||||
|
- Pick the [region](https://windscribe.com/status)
|
||||||
|
|
||||||
### Extra niche features
|
### Extra niche features
|
||||||
|
|
||||||
- Possibility of split horizon DNS by selecting multiple DNS over TLS providers
|
- Possibility of split horizon DNS by selecting multiple DNS over TLS providers
|
||||||
@@ -81,6 +85,8 @@
|
|||||||
- If `VPNSP=mullvad` and `PORT=53`, allow outbound UDP 53 to the corresponding VPN server IPs, which you can fine in [the mapping of Mullvad servers](https://github.com/qdm12/private-internet-access-docker/blob/master/internal/constants/mullvad.go#L64-L667)
|
- If `VPNSP=mullvad` and `PORT=53`, allow outbound UDP 53 to the corresponding VPN server IPs, which you can fine in [the mapping of Mullvad servers](https://github.com/qdm12/private-internet-access-docker/blob/master/internal/constants/mullvad.go#L64-L667)
|
||||||
- If `VPNSP=mullvad` and `PORT=80`, allow outbound TCP 80 to the corresponding VPN server IPs, which you can fine in [the mapping of Mullvad servers](https://github.com/qdm12/private-internet-access-docker/blob/master/internal/constants/mullvad.go#L64-L667)
|
- If `VPNSP=mullvad` and `PORT=80`, allow outbound TCP 80 to the corresponding VPN server IPs, which you can fine in [the mapping of Mullvad servers](https://github.com/qdm12/private-internet-access-docker/blob/master/internal/constants/mullvad.go#L64-L667)
|
||||||
- If `VPNSP=mullvad` and `PORT=443`, allow outbound TCP 443 to the corresponding VPN server IPs, which you can fine in [the mapping of Mullvad servers](https://github.com/qdm12/private-internet-access-docker/blob/master/internal/constants/mullvad.go#L64-L667)
|
- If `VPNSP=mullvad` and `PORT=443`, allow outbound TCP 443 to the corresponding VPN server IPs, which you can fine in [the mapping of Mullvad servers](https://github.com/qdm12/private-internet-access-docker/blob/master/internal/constants/mullvad.go#L64-L667)
|
||||||
|
- If `VPNSP=windscribe` and `PROTOCOL=udp`: allow outbound UDP 443 to the corresponding VPN server IPs
|
||||||
|
- If `VPNSP=windscribe` and `PROTOCOL=tcp`: allow outbound TCP 1194 to the corresponding VPN server IPs
|
||||||
- If `SHADOWSOCKS=on`, allow inbound TCP 8388 and UDP 8388 from your LAN
|
- If `SHADOWSOCKS=on`, allow inbound TCP 8388 and UDP 8388 from your LAN
|
||||||
- If `TINYPROXY=on`, allow inbound TCP 8888 from your LAN
|
- If `TINYPROXY=on`, allow inbound TCP 8888 from your LAN
|
||||||
|
|
||||||
@@ -124,16 +130,16 @@ docker run --rm --network=container:pia alpine:3.11 wget -qO- https://ipinfo.io
|
|||||||
|
|
||||||
| Environment variable | Default | Description |
|
| Environment variable | Default | Description |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `VPNSP` | `pia` | VPN Service Provider, one of `pia`, `mullvad` |
|
| `VPNSP` | `pia` | VPN Service Provider, one of `pia`, `mullvad` or `windscribe` |
|
||||||
| `REGION` | `CA Montreal` | (PIA only) one of the [PIA regions](https://www.privateinternetaccess.com/pages/network/) |
|
| `REGION` | `Austria` | (PIA & Windscribe only) one of the [PIA regions](https://www.privateinternetaccess.com/pages/network/) or one of the [Windscribe regions](https://windscribe.com/status) |
|
||||||
| `COUNTRY` | `Sweden` | (Mullvad only) one of the [Mullvad countries](https://mullvad.net/en/servers/#openvpn) |
|
| `COUNTRY` | `Sweden` | (Mullvad only) one of the [Mullvad countries](https://mullvad.net/en/servers/#openvpn) |
|
||||||
| `CITY` | | (Mullvad only, *optional*) one of the [Mullvad cities](https://mullvad.net/en/servers/#openvpn) |
|
| `CITY` | | (Mullvad only, *optional*) one of the [Mullvad cities](https://mullvad.net/en/servers/#openvpn) |
|
||||||
| `ISP` | | (Mullvad only, *optional*) one of the [Mullvad ISP](https://mullvad.net/en/servers/#openvpn) |
|
| `ISP` | | (Mullvad only, *optional*) one of the [Mullvad ISP](https://mullvad.net/en/servers/#openvpn) |
|
||||||
| `PORT` | | (Mullvad only, *optional*) For TCP, `80` or `443`, or `53` for UDP. Leave blank for default Mullvad server port |
|
| `PORT` | | (Mullvad and Windscribe only, *optional*) **Mullvad**: For TCP, `80` or `443`, or `53` for UDP. Leave blank for default Mullvad server port; **Windscribe** see [this list of ports](https://windscribe.com/getconfig/openvpn) |
|
||||||
| `PROTOCOL` | `udp` | `tcp` or `udp` |
|
| `PROTOCOL` | `udp` | `tcp` or `udp` |
|
||||||
| `PIA_ENCRYPTION` | `strong` | (PIA only) `normal` or `strong` or `custom` |
|
| `ENCRYPTION` | `strong` | (PIA only) `normal` or `strong` |
|
||||||
| `USER` | | PIA username **or** Mullvad user ID |
|
| `USER` | | PIA username **or** Mullvad user ID **or** Windscribe username |
|
||||||
| `PASSWORD` | | Your PIA password |
|
| `PASSWORD` | | Your PIA password **or** Windscribe password |
|
||||||
| `DOT` | `on` | `on` or `off`, to activate DNS over TLS to 1.1.1.1 |
|
| `DOT` | `on` | `on` or `off`, to activate DNS over TLS to 1.1.1.1 |
|
||||||
| `DOT_PROVIDERS` | `cloudflare` | Comma delimited list of DNS over TLS providers from `cloudflare`, `google`, `quad9`, `quadrant`, `cleanbrowsing`, `securedns`, `libredns` |
|
| `DOT_PROVIDERS` | `cloudflare` | Comma delimited list of DNS over TLS providers from `cloudflare`, `google`, `quad9`, `quadrant`, `cleanbrowsing`, `securedns`, `libredns` |
|
||||||
| `DOT_CACHING` | `on` | Unbound caching feature, `on` or `off` |
|
| `DOT_CACHING` | `on` | Unbound caching feature, `on` or `off` |
|
||||||
@@ -161,7 +167,7 @@ docker run --rm --network=container:pia alpine:3.11 wget -qO- https://ipinfo.io
|
|||||||
| `TZ` | | Specify a timezone to use i.e. `Europe/London` |
|
| `TZ` | | Specify a timezone to use i.e. `Europe/London` |
|
||||||
| `OPENVPN_VERBOSITY` | `1` | Openvpn verbosity level from 0 to 6 |
|
| `OPENVPN_VERBOSITY` | `1` | Openvpn verbosity level from 0 to 6 |
|
||||||
| `OPENVPN_ROOT` | `no` | Run OpenVPN as root, `yes` or `no` |
|
| `OPENVPN_ROOT` | `no` | Run OpenVPN as root, `yes` or `no` |
|
||||||
| `OPENVPN_TARGET_IP` | | Specify a target VPN server IP address to use, valid for Mullvad and Private Internet Access |
|
| `OPENVPN_TARGET_IP` | | (Optional) Specify a target VPN server IP address to use, valid for Mullvad and Private Internet Access |
|
||||||
| `OPENVPN_CIPHER` | | Specify a custom cipher to use, use at your own risk. It will also set `ncp-disable` if using AES GCM for PIA |
|
| `OPENVPN_CIPHER` | | Specify a custom cipher to use, use at your own risk. It will also set `ncp-disable` if using AES GCM for PIA |
|
||||||
| `OPENVPN_AUTH` | | Specify a custom auth algorithm to use (i.e. `sha256`) *for pia only* |
|
| `OPENVPN_AUTH` | | Specify a custom auth algorithm to use (i.e. `sha256`) *for pia only* |
|
||||||
|
|
||||||
@@ -456,7 +462,6 @@ Thanks for all the contributions, whether small or not so small!
|
|||||||
|
|
||||||
<details><summary>Expand me</summary><p>
|
<details><summary>Expand me</summary><p>
|
||||||
|
|
||||||
- Support Windscribe
|
|
||||||
- Gotify support for notificactions
|
- Gotify support for notificactions
|
||||||
- Periodic update of malicious block lists with Unbound restart
|
- Periodic update of malicious block lists with Unbound restart
|
||||||
- Improve healthcheck
|
- Improve healthcheck
|
||||||
|
|||||||
10
cmd/main.go
10
cmd/main.go
@@ -27,6 +27,7 @@ import (
|
|||||||
"github.com/qdm12/private-internet-access-docker/internal/shadowsocks"
|
"github.com/qdm12/private-internet-access-docker/internal/shadowsocks"
|
||||||
"github.com/qdm12/private-internet-access-docker/internal/splash"
|
"github.com/qdm12/private-internet-access-docker/internal/splash"
|
||||||
"github.com/qdm12/private-internet-access-docker/internal/tinyproxy"
|
"github.com/qdm12/private-internet-access-docker/internal/tinyproxy"
|
||||||
|
"github.com/qdm12/private-internet-access-docker/internal/windscribe"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -56,6 +57,7 @@ func main() {
|
|||||||
firewallConf := firewall.NewConfigurator(logger, fileManager)
|
firewallConf := firewall.NewConfigurator(logger, fileManager)
|
||||||
piaConf := pia.NewConfigurator(client, fileManager, firewallConf, logger)
|
piaConf := pia.NewConfigurator(client, fileManager, firewallConf, logger)
|
||||||
mullvadConf := mullvad.NewConfigurator(fileManager, logger)
|
mullvadConf := mullvad.NewConfigurator(fileManager, logger)
|
||||||
|
windscribeConf := windscribe.NewConfigurator(fileManager)
|
||||||
tinyProxyConf := tinyproxy.NewConfigurator(fileManager, logger)
|
tinyProxyConf := tinyproxy.NewConfigurator(fileManager, logger)
|
||||||
shadowsocksConf := shadowsocks.NewConfigurator(fileManager, logger)
|
shadowsocksConf := shadowsocks.NewConfigurator(fileManager, logger)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
@@ -86,6 +88,9 @@ func main() {
|
|||||||
case "mullvad":
|
case "mullvad":
|
||||||
openVPNUser = allSettings.Mullvad.User
|
openVPNUser = allSettings.Mullvad.User
|
||||||
openVPNPassword = "m"
|
openVPNPassword = "m"
|
||||||
|
case "windscribe":
|
||||||
|
openVPNUser = allSettings.Windscribe.User
|
||||||
|
openVPNPassword = allSettings.Windscribe.Password
|
||||||
}
|
}
|
||||||
err = ovpnConf.WriteAuthFile(openVPNUser, openVPNPassword, uid, gid)
|
err = ovpnConf.WriteAuthFile(openVPNUser, openVPNPassword, uid, gid)
|
||||||
e.FatalOnError(err)
|
e.FatalOnError(err)
|
||||||
@@ -139,6 +144,11 @@ func main() {
|
|||||||
e.FatalOnError(err)
|
e.FatalOnError(err)
|
||||||
err = mullvadConf.BuildConf(connections, allSettings.OpenVPN.Verbosity, uid, gid, allSettings.OpenVPN.Root, allSettings.OpenVPN.Cipher)
|
err = mullvadConf.BuildConf(connections, allSettings.OpenVPN.Verbosity, uid, gid, allSettings.OpenVPN.Root, allSettings.OpenVPN.Cipher)
|
||||||
e.FatalOnError(err)
|
e.FatalOnError(err)
|
||||||
|
case "windscribe":
|
||||||
|
connections, err = windscribeConf.GetOpenVPNConnections(allSettings.Windscribe.Region, allSettings.OpenVPN.NetworkProtocol, allSettings.Windscribe.Port, allSettings.OpenVPN.TargetIP)
|
||||||
|
e.FatalOnError(err)
|
||||||
|
err = windscribeConf.BuildConf(connections, allSettings.OpenVPN.Verbosity, uid, gid, allSettings.OpenVPN.Root, allSettings.OpenVPN.Cipher, allSettings.OpenVPN.Auth)
|
||||||
|
e.FatalOnError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultInterface, defaultGateway, defaultSubnet, err := firewallConf.GetDefaultRoute()
|
defaultInterface, defaultGateway, defaultSubnet, err := firewallConf.GetDefaultRoute()
|
||||||
|
|||||||
@@ -1,57 +1,58 @@
|
|||||||
version: "3.7"
|
version: "3.7"
|
||||||
services:
|
services:
|
||||||
pia:
|
pia:
|
||||||
image: qmcgaw/private-internet-access
|
image: qmcgaw/private-internet-access
|
||||||
container_name: pia
|
container_name: pia
|
||||||
cap_add:
|
cap_add:
|
||||||
- NET_ADMIN
|
- NET_ADMIN
|
||||||
network_mode: bridge
|
network_mode: bridge
|
||||||
init: true
|
init: true
|
||||||
ports:
|
ports:
|
||||||
- 8888:8888/tcp
|
- 8888:8888/tcp
|
||||||
- 8388:8388/tcp
|
- 8388:8388/tcp
|
||||||
- 8388:8388/udp
|
- 8388:8388/udp
|
||||||
# command:
|
# command:
|
||||||
environment:
|
environment:
|
||||||
# More variables are available, see the readme table
|
# More variables are available, see the readme table
|
||||||
- VPNSP=pia
|
- VPNSP=pia
|
||||||
- USER=js89ds7
|
- USER=js89ds7
|
||||||
- PROTOCOL=udp
|
- PROTOCOL=udp
|
||||||
- OPENVPN_VERBOSITY=1
|
- OPENVPN_VERBOSITY=1
|
||||||
- OPENVPN_ROOT=no
|
- OPENVPN_ROOT=no
|
||||||
- OPENVPN_TARGET_IP=
|
- OPENVPN_TARGET_IP=
|
||||||
- TZ=
|
- TZ=
|
||||||
|
|
||||||
# PIA only
|
# PIA and Windscribe only
|
||||||
- REGION=CA Montreal
|
- REGION=Austria
|
||||||
- PASSWORD=8fd9s239G
|
- PASSWORD=8fd9s239G
|
||||||
- PIA_ENCRYPTION=strong
|
|
||||||
- PORT_FORWARDING=off
|
# PIA only
|
||||||
- OPENVPN_CIPHER=
|
- PASSWORD=8fd9s239G
|
||||||
- OPENVPN_AUTH=
|
- PIA_ENCRYPTION=strong
|
||||||
|
- PORT_FORWARDING=off
|
||||||
# Mullvad only
|
|
||||||
- COUNTRY=Sweden
|
# Mullvad only
|
||||||
- CITY=
|
- COUNTRY=Sweden
|
||||||
- ISP=
|
- CITY=
|
||||||
- PORT=
|
- ISP=
|
||||||
|
- PORT=
|
||||||
# DNS over TLS
|
|
||||||
- DOT=on
|
# DNS over TLS
|
||||||
- DOT_PROVIDERS=cloudflare
|
- DOT=on
|
||||||
- DOT_IPV6=on
|
- DOT_PROVIDERS=cloudflare
|
||||||
- DOT_VERBOSITY=1
|
- DOT_IPV6=on
|
||||||
- BLOCK_MALICIOUS=on
|
- DOT_VERBOSITY=1
|
||||||
- BLOCK_SURVEILLANCE=off
|
- BLOCK_MALICIOUS=on
|
||||||
- BLOCK_ADS=off
|
- BLOCK_SURVEILLANCE=off
|
||||||
- UNBLOCK=
|
- BLOCK_ADS=off
|
||||||
# Firewall
|
- UNBLOCK=
|
||||||
- EXTRA_SUBNETS=
|
# Firewall
|
||||||
# Shadowsocks
|
- EXTRA_SUBNETS=
|
||||||
- SHADOWSOCKS=off
|
# Shadowsocks
|
||||||
- SHADOWSOCKS_PASSWORD=
|
- SHADOWSOCKS=off
|
||||||
# Tinyproxy
|
- SHADOWSOCKS_PASSWORD=
|
||||||
- TINYPROXY=off
|
# Tinyproxy
|
||||||
- TINYPROXY_USER=
|
- TINYPROXY=off
|
||||||
- TINYPROXY_PASSWORD=
|
- TINYPROXY_USER=
|
||||||
restart: always
|
- TINYPROXY_PASSWORD=
|
||||||
|
restart: always
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ package constants
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// Announcement is a message announcement
|
// Announcement is a message announcement
|
||||||
Announcement = "Support for Mullvad (a bit unstable)"
|
Announcement = "Support for Windscribe"
|
||||||
// AnnouncementExpiration is the expiration date of the announcement in format yyyy-mm-dd
|
// AnnouncementExpiration is the expiration date of the announcement in format yyyy-mm-dd
|
||||||
AnnouncementExpiration = "2020-03-15"
|
AnnouncementExpiration = "2020-04-15"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
310
internal/constants/windscribe.go
Normal file
310
internal/constants/windscribe.go
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
package constants
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
WindscribeCertificate = "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"
|
||||||
|
WindscribeOpenvpnStaticKeyV1 = "5801926a57ac2ce27e3dfd1dd6ef82042d82bd4f3f0021296f57734f6f1ea714a6623845541c4b0c3dea0a050fe6746cb66dfab14cda27e5ae09d7c155aa554f399fa4a863f0e8c1af787e5c602a801d3a2ec41e395a978d56729457fe6102d7d9e9119aa83643210b33c678f9d4109e3154ac9c759e490cb309b319cf708cae83ddadc3060a7a26564d1a24411cd552fe6620ea16b755697a4fc5e6e9d0cfc0c5c4a1874685429046a424c026db672e4c2c492898052ba59128d46200b40f880027a8b6610a4d559bdc9346d33a0a6b08e75c7fd43192b162bfd0aef0c716b31584827693f676f9a5047123466f0654eade34972586b31c6ce7e395f4b478cb"
|
||||||
|
)
|
||||||
|
|
||||||
|
func WindscribeRegionChoices() (choices []string) {
|
||||||
|
uniqueChoices := map[string]struct{}{}
|
||||||
|
for _, server := range WindscribeServers() {
|
||||||
|
uniqueChoices[string(server.Region)] = struct{}{}
|
||||||
|
}
|
||||||
|
for choice := range uniqueChoices {
|
||||||
|
choices = append(choices, choice)
|
||||||
|
}
|
||||||
|
return choices
|
||||||
|
}
|
||||||
|
|
||||||
|
func WindscribeServers() []models.WindscribeServer {
|
||||||
|
return []models.WindscribeServer{
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("albania"),
|
||||||
|
Subdomain: "al",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("argentina"),
|
||||||
|
Subdomain: "ar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("argentina"),
|
||||||
|
Subdomain: "ar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("australia"),
|
||||||
|
Subdomain: "au",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("austria"),
|
||||||
|
Subdomain: "at",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("azerbaijan"),
|
||||||
|
Subdomain: "az",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("belgium"),
|
||||||
|
Subdomain: "be",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("bosnia"),
|
||||||
|
Subdomain: "ba",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("brazil"),
|
||||||
|
Subdomain: "br",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("bulgaria"),
|
||||||
|
Subdomain: "bg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("canada east"),
|
||||||
|
Subdomain: "ca",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("canada west"),
|
||||||
|
Subdomain: "ca-west",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("colombia"),
|
||||||
|
Subdomain: "co",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("croatia"),
|
||||||
|
Subdomain: "hr",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("cyprus"),
|
||||||
|
Subdomain: "cy",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("czech republic"),
|
||||||
|
Subdomain: "cz",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("denmark"),
|
||||||
|
Subdomain: "dk",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("estonia"),
|
||||||
|
Subdomain: "ee",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("egypt"),
|
||||||
|
Subdomain: "eg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("fake antarctica"),
|
||||||
|
Subdomain: "aq",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("finland"),
|
||||||
|
Subdomain: "fi",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("france"),
|
||||||
|
Subdomain: "fr",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("georgia"),
|
||||||
|
Subdomain: "ge",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("germany"),
|
||||||
|
Subdomain: "de",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("greece"),
|
||||||
|
Subdomain: "gr",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("hong kong"),
|
||||||
|
Subdomain: "hk",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("hungary"),
|
||||||
|
Subdomain: "hu",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("iceland"),
|
||||||
|
Subdomain: "is",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("india"),
|
||||||
|
Subdomain: "in",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("indonesia"),
|
||||||
|
Subdomain: "id",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("ireland"),
|
||||||
|
Subdomain: "ie",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("israel"),
|
||||||
|
Subdomain: "il",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("italy"),
|
||||||
|
Subdomain: "it",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("japan"),
|
||||||
|
Subdomain: "jp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("latvia"),
|
||||||
|
Subdomain: "lv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("lithuania"),
|
||||||
|
Subdomain: "lt",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("macedonia"),
|
||||||
|
Subdomain: "mk",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("malaysia"),
|
||||||
|
Subdomain: "my",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("mexico"),
|
||||||
|
Subdomain: "mx",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("moldova"),
|
||||||
|
Subdomain: "md",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("netherlands"),
|
||||||
|
Subdomain: "nl",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("new zealand"),
|
||||||
|
Subdomain: "nz",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("norway"),
|
||||||
|
Subdomain: "no",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("philippines"),
|
||||||
|
Subdomain: "ph",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("poland"),
|
||||||
|
Subdomain: "pl",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("portugal"),
|
||||||
|
Subdomain: "pt",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("romania"),
|
||||||
|
Subdomain: "ro",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("russia"),
|
||||||
|
Subdomain: "ru",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("serbia"),
|
||||||
|
Subdomain: "rs",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("singapore"),
|
||||||
|
Subdomain: "sg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("slovakia"),
|
||||||
|
Subdomain: "sk",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("slovenia"),
|
||||||
|
Subdomain: "si",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("south africa"),
|
||||||
|
Subdomain: "za",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("south korea"),
|
||||||
|
Subdomain: "kr",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("spain"),
|
||||||
|
Subdomain: "es",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("sweden"),
|
||||||
|
Subdomain: "se",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("switzerland"),
|
||||||
|
Subdomain: "ch",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("thailand"),
|
||||||
|
Subdomain: "th",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("tunisia"),
|
||||||
|
Subdomain: "tn",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("turkey"),
|
||||||
|
Subdomain: "tr",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("ukraine"),
|
||||||
|
Subdomain: "ua",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("united arab emirates"),
|
||||||
|
Subdomain: "ae",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("united kingdom"),
|
||||||
|
Subdomain: "uk",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("us central"),
|
||||||
|
Subdomain: "us-central",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("us east"),
|
||||||
|
Subdomain: "us-east",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("us west"),
|
||||||
|
Subdomain: "us-west",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("vietnam"),
|
||||||
|
Subdomain: "vn",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("windflix ca"),
|
||||||
|
Subdomain: "wf-ca",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("windflix jp"),
|
||||||
|
Subdomain: "wf-jp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("windflix uk"),
|
||||||
|
Subdomain: "wf-uk",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Region: models.WindscribeRegion("windflix us"),
|
||||||
|
Subdomain: "wf-us",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,8 @@ type (
|
|||||||
MullvadCity string
|
MullvadCity string
|
||||||
// MullvadProvider is used as the Internet service provider for a Mullvad server
|
// MullvadProvider is used as the Internet service provider for a Mullvad server
|
||||||
MullvadProvider string
|
MullvadProvider string
|
||||||
|
// WindscribeCity is used as the region for a Windscribe server
|
||||||
|
WindscribeRegion string
|
||||||
// URL is an HTTP(s) URL address
|
// URL is an HTTP(s) URL address
|
||||||
URL string
|
URL string
|
||||||
// Filepath is a local filesytem file path
|
// Filepath is a local filesytem file path
|
||||||
|
|||||||
6
internal/models/windscribe.go
Normal file
6
internal/models/windscribe.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
type WindscribeServer struct {
|
||||||
|
Region WindscribeRegion
|
||||||
|
Subdomain string
|
||||||
|
}
|
||||||
@@ -53,6 +53,10 @@ type ParamsReader interface {
|
|||||||
GetMullvadISP() (country models.MullvadProvider, err error)
|
GetMullvadISP() (country models.MullvadProvider, err error)
|
||||||
GetMullvadPort() (port uint16, err error)
|
GetMullvadPort() (port uint16, err error)
|
||||||
|
|
||||||
|
// Windscribe getters
|
||||||
|
GetWindscribeRegion() (country models.WindscribeRegion, err error)
|
||||||
|
GetWindscribePort(protocol models.NetworkProtocol) (port uint16, err error)
|
||||||
|
|
||||||
// Shadowsocks getters
|
// Shadowsocks getters
|
||||||
GetShadowSocks() (activated bool, err error)
|
GetShadowSocks() (activated bool, err error)
|
||||||
GetShadowSocksLog() (activated bool, err error)
|
GetShadowSocksLog() (activated bool, err error)
|
||||||
@@ -92,6 +96,6 @@ func NewParamsReader(logger logging.Logger) ParamsReader {
|
|||||||
|
|
||||||
// GetVPNSP obtains the VPN service provider to use from the environment variable VPNSP
|
// GetVPNSP obtains the VPN service provider to use from the environment variable VPNSP
|
||||||
func (p *paramsReader) GetVPNSP() (vpnServiceProvider string, err error) {
|
func (p *paramsReader) GetVPNSP() (vpnServiceProvider string, err error) {
|
||||||
s, err := p.envParams.GetValueIfInside("VPNSP", []string{"pia", "mullvad"})
|
s, err := p.envParams.GetValueIfInside("VPNSP", []string{"pia", "mullvad", "windscribe"})
|
||||||
return s, err
|
return s, err
|
||||||
}
|
}
|
||||||
|
|||||||
45
internal/params/windscribe.go
Normal file
45
internal/params/windscribe.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package params
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
libparams "github.com/qdm12/golibs/params"
|
||||||
|
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||||
|
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetWindscribeRegion obtains the region for the Windscribe server from the
|
||||||
|
// environment variable REGION
|
||||||
|
func (p *paramsReader) GetWindscribeRegion() (country models.WindscribeRegion, err error) {
|
||||||
|
choices := append(constants.WindscribeRegionChoices())
|
||||||
|
s, err := p.envParams.GetValueIfInside("REGION", choices)
|
||||||
|
return models.WindscribeRegion(strings.ToLower(s)), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMullvadPort obtains the port to reach the Mullvad server on from the
|
||||||
|
// environment variable PORT
|
||||||
|
func (p *paramsReader) GetWindscribePort(protocol models.NetworkProtocol) (port uint16, err error) {
|
||||||
|
n, err := p.envParams.GetEnvIntRange("PORT", 0, 65535, libparams.Default("0"))
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
switch protocol {
|
||||||
|
case constants.TCP:
|
||||||
|
switch n {
|
||||||
|
case 21, 22, 80, 123, 143, 443, 587, 1194, 3306, 8080, 54783:
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("port %d is not valid for protocol %s", n, protocol)
|
||||||
|
}
|
||||||
|
case constants.UDP:
|
||||||
|
switch n {
|
||||||
|
case 53, 80, 123, 443, 1194, 54783:
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("port %d is not valid for protocol %s", n, protocol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uint16(n), nil
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ type Settings struct {
|
|||||||
OpenVPN OpenVPN
|
OpenVPN OpenVPN
|
||||||
PIA PIA
|
PIA PIA
|
||||||
Mullvad Mullvad
|
Mullvad Mullvad
|
||||||
|
Windscribe Windscribe
|
||||||
DNS DNS
|
DNS DNS
|
||||||
Firewall Firewall
|
Firewall Firewall
|
||||||
TinyProxy TinyProxy
|
TinyProxy TinyProxy
|
||||||
@@ -26,6 +27,8 @@ func (s *Settings) String() string {
|
|||||||
vpnServiceProvider = s.PIA.String()
|
vpnServiceProvider = s.PIA.String()
|
||||||
case "mullvad":
|
case "mullvad":
|
||||||
vpnServiceProvider = s.Mullvad.String()
|
vpnServiceProvider = s.Mullvad.String()
|
||||||
|
case "windscribe":
|
||||||
|
vpnServiceProvider = s.Windscribe.String()
|
||||||
}
|
}
|
||||||
return strings.Join([]string{
|
return strings.Join([]string{
|
||||||
"Settings summary below:",
|
"Settings summary below:",
|
||||||
@@ -75,8 +78,23 @@ func GetAllSettings(params params.ParamsReader) (settings Settings, err error) {
|
|||||||
return settings, fmt.Errorf("auth algorithm %q is not supported by Mullvad (not using auth at all)", settings.OpenVPN.Auth)
|
return settings, fmt.Errorf("auth algorithm %q is not supported by Mullvad (not using auth at all)", settings.OpenVPN.Auth)
|
||||||
}
|
}
|
||||||
settings.Mullvad, err = GetMullvadSettings(params)
|
settings.Mullvad, err = GetMullvadSettings(params)
|
||||||
|
case "windscribe":
|
||||||
|
switch settings.OpenVPN.Cipher {
|
||||||
|
case "", "aes-256-cbc", "aes-256-gcm": // TODO check inside params getters
|
||||||
|
default:
|
||||||
|
return settings, fmt.Errorf("cipher %q is not supported by Windscribe", settings.OpenVPN.Cipher)
|
||||||
|
}
|
||||||
|
switch settings.OpenVPN.Auth {
|
||||||
|
case "", "sha512":
|
||||||
|
default:
|
||||||
|
return settings, fmt.Errorf("auth algorithm %q is not supported by Windscribe", settings.OpenVPN.Auth)
|
||||||
|
}
|
||||||
|
settings.Windscribe, err = GetWindscribeSettings(params, settings.OpenVPN.NetworkProtocol)
|
||||||
default:
|
default:
|
||||||
return settings, fmt.Errorf("VPN service provider %q is not valid", settings.VPNSP)
|
err = fmt.Errorf("VPN service provider %q is not valid", settings.VPNSP)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return settings, err
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return settings, err
|
return settings, err
|
||||||
|
|||||||
49
internal/settings/windscribe.go
Normal file
49
internal/settings/windscribe.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package settings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||||
|
"github.com/qdm12/private-internet-access-docker/internal/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Windscribe contains the settings to connect to a Windscribe server
|
||||||
|
type Windscribe struct {
|
||||||
|
User string
|
||||||
|
Password string
|
||||||
|
Region models.WindscribeRegion
|
||||||
|
Port uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Windscribe) String() string {
|
||||||
|
settingsList := []string{
|
||||||
|
"Windscribe settings:",
|
||||||
|
"User: [redacted]",
|
||||||
|
"Password: [redacted]",
|
||||||
|
"Region: " + string(w.Region),
|
||||||
|
"Custom port: " + fmt.Sprintf("%d", w.Port),
|
||||||
|
}
|
||||||
|
return strings.Join(settingsList, "\n |--")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWindscribeSettings obtains Windscribe settings from environment variables using the params package.
|
||||||
|
func GetWindscribeSettings(params params.ParamsReader, protocol models.NetworkProtocol) (settings Windscribe, err error) {
|
||||||
|
settings.User, err = params.GetUser()
|
||||||
|
if err != nil {
|
||||||
|
return settings, err
|
||||||
|
}
|
||||||
|
settings.Password, err = params.GetPassword()
|
||||||
|
if err != nil {
|
||||||
|
return settings, err
|
||||||
|
}
|
||||||
|
settings.Region, err = params.GetWindscribeRegion()
|
||||||
|
if err != nil {
|
||||||
|
return settings, err
|
||||||
|
}
|
||||||
|
settings.Port, err = params.GetWindscribePort(protocol)
|
||||||
|
if err != nil {
|
||||||
|
return settings, err
|
||||||
|
}
|
||||||
|
return settings, nil
|
||||||
|
}
|
||||||
118
internal/windscribe/conf.go
Normal file
118
internal/windscribe/conf.go
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
package windscribe
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/golibs/files"
|
||||||
|
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||||
|
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *configurator) GetOpenVPNConnections(region models.WindscribeRegion, protocol models.NetworkProtocol, customPort uint16, targetIP net.IP) (connections []models.OpenVPNConnection, err error) {
|
||||||
|
var subdomain string
|
||||||
|
for _, server := range constants.WindscribeServers() {
|
||||||
|
if server.Region == region {
|
||||||
|
subdomain = server.Subdomain
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(subdomain) == 0 {
|
||||||
|
return nil, fmt.Errorf("no server found for region %q", region)
|
||||||
|
}
|
||||||
|
hostname := subdomain + ".windscribe.com"
|
||||||
|
IPs, err := c.lookupIP(hostname)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if targetIP != nil {
|
||||||
|
found := false
|
||||||
|
for i := range IPs {
|
||||||
|
if IPs[i].Equal(targetIP) {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return nil, fmt.Errorf("target IP address %q not found from IP addresses resolved from %s", targetIP, hostname)
|
||||||
|
}
|
||||||
|
IPs = []net.IP{targetIP}
|
||||||
|
}
|
||||||
|
var port uint16
|
||||||
|
switch {
|
||||||
|
case customPort > 0:
|
||||||
|
port = customPort
|
||||||
|
case protocol == constants.TCP:
|
||||||
|
port = 1194
|
||||||
|
case protocol == constants.UDP:
|
||||||
|
port = 443
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("protocol %q is unknown", protocol)
|
||||||
|
}
|
||||||
|
for _, IP := range IPs {
|
||||||
|
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: protocol})
|
||||||
|
}
|
||||||
|
return connections, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *configurator) BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string) (err error) {
|
||||||
|
if len(cipher) == 0 {
|
||||||
|
cipher = "AES-256-CBC"
|
||||||
|
}
|
||||||
|
if len(auth) == 0 {
|
||||||
|
auth = "sha512"
|
||||||
|
}
|
||||||
|
lines := []string{
|
||||||
|
"client",
|
||||||
|
"dev tun",
|
||||||
|
"nobind",
|
||||||
|
"persist-key",
|
||||||
|
"persist-tun",
|
||||||
|
|
||||||
|
// Windscribe specific
|
||||||
|
"resolv-retry infinite",
|
||||||
|
"comp-lzo",
|
||||||
|
"remote-cert-tls server",
|
||||||
|
"key-direction 1",
|
||||||
|
|
||||||
|
// Added constant values
|
||||||
|
"auth-nocache",
|
||||||
|
"mute-replay-warnings",
|
||||||
|
"pull-filter ignore \"auth-token\"", // prevent auth failed loops
|
||||||
|
"auth-retry nointeract",
|
||||||
|
"remote-random",
|
||||||
|
|
||||||
|
// Modified variables
|
||||||
|
fmt.Sprintf("verb %d", verbosity),
|
||||||
|
fmt.Sprintf("auth-user-pass %s", constants.OpenVPNAuthConf),
|
||||||
|
fmt.Sprintf("proto %s", string(connections[0].Protocol)),
|
||||||
|
fmt.Sprintf("cipher %s", cipher),
|
||||||
|
fmt.Sprintf("auth %s", auth),
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(cipher, "-gcm") {
|
||||||
|
lines = append(lines, "ncp-ciphers AES-256-GCM:AES-256-CBC:AES-128-GCM")
|
||||||
|
}
|
||||||
|
if !root {
|
||||||
|
lines = append(lines, "user nonrootuser")
|
||||||
|
}
|
||||||
|
for _, connection := range connections {
|
||||||
|
lines = append(lines, fmt.Sprintf("remote %s %d", connection.IP.String(), connection.Port))
|
||||||
|
}
|
||||||
|
lines = append(lines, []string{
|
||||||
|
"<ca>",
|
||||||
|
"-----BEGIN CERTIFICATE-----",
|
||||||
|
constants.WindscribeCertificate,
|
||||||
|
"-----END CERTIFICATE-----",
|
||||||
|
"</ca>",
|
||||||
|
}...)
|
||||||
|
lines = append(lines, []string{
|
||||||
|
"<tls-auth>",
|
||||||
|
"-----BEGIN OpenVPN Static key V1-----",
|
||||||
|
constants.WindscribeOpenvpnStaticKeyV1,
|
||||||
|
"-----END OpenVPN Static key V1-----",
|
||||||
|
"</tls-auth>",
|
||||||
|
"",
|
||||||
|
}...)
|
||||||
|
return c.fileManager.WriteLinesToFile(string(constants.OpenVPNConf), lines, files.Ownership(uid, gid), files.Permissions(0400))
|
||||||
|
}
|
||||||
24
internal/windscribe/windscribe.go
Normal file
24
internal/windscribe/windscribe.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package windscribe
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/qdm12/golibs/files"
|
||||||
|
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Configurator contains methods to download, read and modify the openvpn configuration to connect as a client
|
||||||
|
type Configurator interface {
|
||||||
|
GetOpenVPNConnections(region models.WindscribeRegion, protocol models.NetworkProtocol, customPort uint16, targetIP net.IP) (connections []models.OpenVPNConnection, err error)
|
||||||
|
BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string) (err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type configurator struct {
|
||||||
|
fileManager files.FileManager
|
||||||
|
lookupIP func(host string) ([]net.IP, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConfigurator returns a new Configurator object
|
||||||
|
func NewConfigurator(fileManager files.FileManager) Configurator {
|
||||||
|
return &configurator{fileManager, net.LookupIP}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user