Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90e5742211 | ||
|
|
8f547500d0 | ||
|
|
0811b8b099 | ||
|
|
c5c53a2ff8 | ||
|
|
0ce129b63d | ||
|
|
fec1249293 | ||
|
|
a5c35455d1 | ||
|
|
28e0abc922 | ||
|
|
a13be8f45e | ||
|
|
85bd4f2e8d | ||
|
|
4baf0420d6 | ||
|
|
29f74df450 | ||
|
|
fab9939b26 |
12
Dockerfile
12
Dockerfile
@@ -42,17 +42,18 @@ ENV VPNSP=pia \
|
|||||||
UID=1000 \
|
UID=1000 \
|
||||||
GID=1000 \
|
GID=1000 \
|
||||||
IP_STATUS_FILE="/ip" \
|
IP_STATUS_FILE="/ip" \
|
||||||
# PIA, Windscribe, Surfshark, Cyberghost, Vyprvpn, NordVPN only
|
# PIA, Windscribe, Surfshark, Cyberghost, Vyprvpn, NordVPN, PureVPN only
|
||||||
USER= \
|
USER= \
|
||||||
PASSWORD= \
|
PASSWORD= \
|
||||||
REGION="Austria" \
|
REGION= \
|
||||||
# PIA only
|
# PIA only
|
||||||
PIA_ENCRYPTION=strong \
|
PIA_ENCRYPTION=strong \
|
||||||
PORT_FORWARDING=off \
|
PORT_FORWARDING=off \
|
||||||
PORT_FORWARDING_STATUS_FILE="/forwarded_port" \
|
PORT_FORWARDING_STATUS_FILE="/forwarded_port" \
|
||||||
# Mullvad only
|
# Mullvad and PureVPN only
|
||||||
COUNTRY=Sweden \
|
COUNTRY= \
|
||||||
CITY= \
|
CITY= \
|
||||||
|
# Mullvad only
|
||||||
ISP= \
|
ISP= \
|
||||||
# Mullvad and Windscribe only
|
# Mullvad and Windscribe only
|
||||||
PORT= \
|
PORT= \
|
||||||
@@ -82,6 +83,7 @@ ENV VPNSP=pia \
|
|||||||
# Firewall
|
# Firewall
|
||||||
FIREWALL=on \
|
FIREWALL=on \
|
||||||
EXTRA_SUBNETS= \
|
EXTRA_SUBNETS= \
|
||||||
|
FIREWALL_VPN_INPUT_PORTS= \
|
||||||
FIREWALL_DEBUG=off \
|
FIREWALL_DEBUG=off \
|
||||||
# Tinyproxy
|
# Tinyproxy
|
||||||
TINYPROXY=off \
|
TINYPROXY=off \
|
||||||
@@ -99,7 +101,7 @@ ENTRYPOINT ["/entrypoint"]
|
|||||||
EXPOSE 8000/tcp 8888/tcp 8388/tcp 8388/udp
|
EXPOSE 8000/tcp 8888/tcp 8388/tcp 8388/udp
|
||||||
HEALTHCHECK --interval=10m --timeout=10s --start-period=30s --retries=2 CMD /entrypoint healthcheck
|
HEALTHCHECK --interval=10m --timeout=10s --start-period=30s --retries=2 CMD /entrypoint healthcheck
|
||||||
RUN apk add -q --progress --no-cache --update openvpn ca-certificates iptables ip6tables unbound tinyproxy tzdata && \
|
RUN apk add -q --progress --no-cache --update openvpn ca-certificates iptables ip6tables unbound tinyproxy tzdata && \
|
||||||
echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
|
echo "http://nl.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
|
||||||
apk add -q --progress --no-cache --update shadowsocks-libev && \
|
apk add -q --progress --no-cache --update shadowsocks-libev && \
|
||||||
rm -rf /var/cache/apk/* /etc/unbound/* /usr/sbin/unbound-* /etc/tinyproxy/tinyproxy.conf && \
|
rm -rf /var/cache/apk/* /etc/unbound/* /usr/sbin/unbound-* /etc/tinyproxy/tinyproxy.conf && \
|
||||||
deluser openvpn && \
|
deluser openvpn && \
|
||||||
|
|||||||
81
README.md
81
README.md
@@ -1,7 +1,7 @@
|
|||||||
# Gluetun VPN client
|
# Gluetun VPN client
|
||||||
|
|
||||||
*Lightweight swiss-knife-like VPN client to tunnel to Private Internet Access,
|
*Lightweight swiss-knife-like VPN client to tunnel to Private Internet Access,
|
||||||
Mullvad, Windscribe, Surfshark Cyberghost, VyprVPN and NordVPN VPN servers, using Go, OpenVPN,
|
Mullvad, Windscribe, Surfshark Cyberghost, VyprVPN, NordVPN and PureVPN VPN servers, using Go, OpenVPN,
|
||||||
iptables, DNS over TLS, ShadowSocks and Tinyproxy*
|
iptables, DNS over TLS, ShadowSocks and Tinyproxy*
|
||||||
|
|
||||||
**ANNOUNCEMENT**: *[Video of the Git history of Gluetun](https://youtu.be/khipOYJtGJ0)*
|
**ANNOUNCEMENT**: *[Video of the Git history of Gluetun](https://youtu.be/khipOYJtGJ0)*
|
||||||
@@ -20,22 +20,11 @@ iptables, DNS over TLS, ShadowSocks and Tinyproxy*
|
|||||||
[](https://microbadger.com/images/qmcgaw/private-internet-access)
|
[](https://microbadger.com/images/qmcgaw/private-internet-access)
|
||||||
[](https://join.slack.com/t/qdm12/shared_invite/enQtOTE0NjcxNTM1ODc5LTYyZmVlOTM3MGI4ZWU0YmJkMjUxNmQ4ODQ2OTAwYzMxMTlhY2Q1MWQyOWUyNjc2ODliNjFjMDUxNWNmNzk5MDk)
|
[](https://join.slack.com/t/qdm12/shared_invite/enQtOTE0NjcxNTM1ODc5LTYyZmVlOTM3MGI4ZWU0YmJkMjUxNmQ4ODQ2OTAwYzMxMTlhY2Q1MWQyOWUyNjc2ODliNjFjMDUxNWNmNzk5MDk)
|
||||||
|
|
||||||
<details><summary>Click to show base components</summary><p>
|
|
||||||
|
|
||||||
- [Alpine 3.12](https://alpinelinux.org) for a tiny image (37MB of packages, 6.7MB of Go binary and 5.6MB for Alpine)
|
|
||||||
- [OpenVPN 2.4.9](https://pkgs.alpinelinux.org/package/v3.11/main/x86_64/openvpn) to tunnel to your VPN provider servers
|
|
||||||
- [IPtables 1.8.4](https://pkgs.alpinelinux.org/package/v3.11/main/x86_64/iptables) enforces the container to communicate only through the VPN or with other containers in its virtual network (acts as a killswitch)
|
|
||||||
- [Unbound 1.10.1](https://pkgs.alpinelinux.org/package/v3.11/main/x86_64/unbound) configured with Cloudflare's [1.1.1.1](https://1.1.1.1) DNS over TLS (configurable with 5 different providers)
|
|
||||||
- [Files and blocking lists built periodically](https://github.com/qdm12/updated/tree/master/files) used with Unbound (see `BLOCK_MALICIOUS`, `BLOCK_SURVEILLANCE` and `BLOCK_ADS` environment variables)
|
|
||||||
- [TinyProxy 1.10.0](https://pkgs.alpinelinux.org/package/v3.11/main/x86_64/tinyproxy)
|
|
||||||
- [Shadowsocks 3.3.4](https://pkgs.alpinelinux.org/package/edge/testing/x86/shadowsocks-libev)
|
|
||||||
|
|
||||||
</p></details>
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Based on Alpine 3.12 for a small Docker image of 52MB
|
- Based on Alpine 3.12 for a small Docker image of 52MB
|
||||||
- Supports **Private Internet Access**, **Mullvad**, **Windscribe**, **Surfshark**, **Cyberghost**, **Vyprvpn** and **NordVPN** servers
|
- Supports **Private Internet Access**, **Mullvad**, **Windscribe**, **Surfshark**, **Cyberghost**, **Vyprvpn**, **NordVPN** and **PureVPN** servers
|
||||||
|
- Supports Openvpn only for now
|
||||||
- DNS over TLS baked in with service provider(s) of your choice
|
- DNS over TLS baked in with service provider(s) of your choice
|
||||||
- DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses, with live update every 24 hours
|
- DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses, with live update every 24 hours
|
||||||
- Choose the vpn network protocol, `udp` or `tcp`
|
- Choose the vpn network protocol, `udp` or `tcp`
|
||||||
@@ -45,19 +34,7 @@ iptables, DNS over TLS, ShadowSocks and Tinyproxy*
|
|||||||
- [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 🎆
|
- Compatible with amd64, i686 (32 bit), **ARM** 64 bit, ARM 32 bit v6 and v7 🎆
|
||||||
|
- VPN server side port forwarding for Private Internet Access and Vyprvpn
|
||||||
### VPN provider specifics
|
|
||||||
|
|
||||||
- **Private Internet Access**: pick the [region](https://www.privateinternetaccess.com/pages/network/), the level of encryption and enable port forwarding
|
|
||||||
- **Mullvad**: Pick the [country, city and ISP](https://mullvad.net/en/servers/#openvpn) and optionally a custom port to use (i.e. `53` (udp) or `80` (tcp))
|
|
||||||
- **Windscribe**: Pick the [region](https://windscribe.com/status), and optionally a custom port to use
|
|
||||||
- **Surfshark**: Pick the [region](https://github.com/qdm12/private-internet-access-docker/wiki/Surfshark) or a multi hop region name
|
|
||||||
- **Cyberghost**: Pick the [region](https://github.com/qdm12/private-internet-access-docker/wiki/Cyberghost) and server group.
|
|
||||||
- **VyprVPN**: Pick the [region](https://www.vyprvpn.com/server-locations), port forwarding works by default
|
|
||||||
- **NordVPN**: Pick the region and optionally the server number
|
|
||||||
|
|
||||||
### 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
|
||||||
- Subprograms all drop root privileges once launched
|
- Subprograms all drop root privileges once launched
|
||||||
- Subprograms output streams are all merged together
|
- Subprograms output streams are all merged together
|
||||||
@@ -66,22 +43,10 @@ iptables, DNS over TLS, ShadowSocks and Tinyproxy*
|
|||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
1. Requirements
|
1. Requirements
|
||||||
- A VPN account with one of the service providers:
|
- A VPN account with one of the service providers supported
|
||||||
- Private Internet Access: **username** and **password** ([sign up](https://www.privateinternetaccess.com/pages/buy-vpn/))
|
|
||||||
- Mullvad: user ID ([sign up](https://mullvad.net/en/account/))
|
|
||||||
- Windscribe: **username** and **password** | Signup up using my affiliate link below
|
|
||||||
|
|
||||||
[](https://windscribe.com/?affid=mh7nyafu)
|
|
||||||
|
|
||||||
- Surfshark: **username** and **password** ([sign up](https://order.surfshark.com/))
|
|
||||||
- Cyberghost: **username**, **password** and **device client key file** ([sign up](https://www.cyberghostvpn.com/en_US/buy/cyberghost-vpn-4))
|
|
||||||
- Vyprvpn: **username** and **password**
|
|
||||||
- NordVPN: **username** and **password**
|
|
||||||
- If you have a host or router firewall, please refer [to the firewall documentation](https://github.com/qdm12/private-internet-access-docker/blob/master/doc/firewall.md)
|
- If you have a host or router firewall, please refer [to the firewall documentation](https://github.com/qdm12/private-internet-access-docker/blob/master/doc/firewall.md)
|
||||||
|
|
||||||
1. On some devices you may need to setup your tunnel kernel module on your host with `insmod /lib/modules/tun.ko` or `modprobe tun`
|
1. On some devices you may need to setup your tunnel kernel module on your host with `insmod /lib/modules/tun.ko` or `modprobe tun`
|
||||||
- *Synology users*: please read [this part of the Wiki](https://github.com/qdm12/private-internet-access-docker/wiki/Common-issues#synology)
|
- *Synology users*: please read [this part of the Wiki](https://github.com/qdm12/private-internet-access-docker/wiki/Common-issues#synology)
|
||||||
|
|
||||||
1. Launch the container with:
|
1. Launch the container with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -125,7 +90,7 @@ Want more testing? ▶ [see the Wiki](https://github.com/qdm12/private-internet-
|
|||||||
|
|
||||||
| Variable | Default | Choices | Description |
|
| Variable | Default | Choices | Description |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| 🏁 `VPNSP` | `private internet access` | `private internet access`, `mullvad`, `windscribe`, `surfshark`, `vyprvpn`, `nordvpn` | VPN Service Provider |
|
| 🏁 `VPNSP` | `private internet access` | `private internet access`, `mullvad`, `windscribe`, `surfshark`, `vyprvpn`, `nordvpn`, `purevpn` | VPN Service Provider |
|
||||||
| `IP_STATUS_FILE` | `/ip` | Any filepath | Filepath to store the public IP address assigned |
|
| `IP_STATUS_FILE` | `/ip` | Any filepath | Filepath to store the public IP address assigned |
|
||||||
| `PROTOCOL` | `udp` | `udp` or `tcp` | Network protocol to use |
|
| `PROTOCOL` | `udp` | `udp` or `tcp` | Network protocol to use |
|
||||||
| `OPENVPN_VERBOSITY` | `1` | `0` to `6` | Openvpn verbosity level |
|
| `OPENVPN_VERBOSITY` | `1` | `0` to `6` | Openvpn verbosity level |
|
||||||
@@ -134,13 +99,15 @@ Want more testing? ▶ [see the Wiki](https://github.com/qdm12/private-internet-
|
|||||||
| `OPENVPN_CIPHER` | | i.e. `aes-256-gcm` | Specify a custom cipher to use. It will also set `ncp-disable` if using AES GCM for PIA |
|
| `OPENVPN_CIPHER` | | i.e. `aes-256-gcm` | Specify a custom cipher to use. It will also set `ncp-disable` if using AES GCM for PIA |
|
||||||
| `OPENVPN_AUTH` | | i.e. `sha256` | Specify a custom auth algorithm to use |
|
| `OPENVPN_AUTH` | | i.e. `sha256` | Specify a custom auth algorithm to use |
|
||||||
|
|
||||||
|
*For all providers below, server location parameters are all optional. By default a random server is picked using the filter settings provided.*
|
||||||
|
|
||||||
- Private Internet Access
|
- Private Internet Access
|
||||||
|
|
||||||
| Variable | Default | Choices | Description |
|
| Variable | Default | Choices | Description |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| 🏁 `USER` | | | Your username |
|
| 🏁 `USER` | | | Your username |
|
||||||
| 🏁 `PASSWORD` | | | Your password |
|
| 🏁 `PASSWORD` | | | Your password |
|
||||||
| `REGION` | `Austria` | One of the [PIA regions](https://www.privateinternetaccess.com/pages/network/) | VPN server region |
|
| `REGION` | | One of the [PIA regions](https://www.privateinternetaccess.com/pages/network/) | VPN server region |
|
||||||
| `PIA_ENCRYPTION` | `strong` | `normal`, `strong` | Encryption preset |
|
| `PIA_ENCRYPTION` | `strong` | `normal`, `strong` | Encryption preset |
|
||||||
| `PORT_FORWARDING` | `off` | `on`, `off` | Enable port forwarding on the VPN server |
|
| `PORT_FORWARDING` | `off` | `on`, `off` | Enable port forwarding on the VPN server |
|
||||||
| `PORT_FORWARDING_STATUS_FILE` | `/forwarded_port` | Any filepath | Filepath to store the forwarded port number |
|
| `PORT_FORWARDING_STATUS_FILE` | `/forwarded_port` | Any filepath | Filepath to store the forwarded port number |
|
||||||
@@ -150,7 +117,7 @@ Want more testing? ▶ [see the Wiki](https://github.com/qdm12/private-internet-
|
|||||||
| Variable | Default | Choices | Description |
|
| Variable | Default | Choices | Description |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| 🏁 `USER` | | | Your user ID |
|
| 🏁 `USER` | | | Your user ID |
|
||||||
| `COUNTRY` | `Sweden` | One of the [Mullvad countries](https://mullvad.net/en/servers/#openvpn) | VPN server country |
|
| `COUNTRY` | | One of the [Mullvad countries](https://mullvad.net/en/servers/#openvpn) | VPN server country |
|
||||||
| `CITY` | | One of the [Mullvad cities](https://mullvad.net/en/servers/#openvpn) | VPN server city |
|
| `CITY` | | One of the [Mullvad cities](https://mullvad.net/en/servers/#openvpn) | VPN server city |
|
||||||
| `ISP` | | One of the [Mullvad ISP](https://mullvad.net/en/servers/#openvpn) | VPN server ISP |
|
| `ISP` | | One of the [Mullvad ISP](https://mullvad.net/en/servers/#openvpn) | VPN server ISP |
|
||||||
| `PORT` | | `80` or `443` for TCP; or `53` for UDP. Leave blank for default Mullvad server port | Custom VPN port to use |
|
| `PORT` | | `80` or `443` for TCP; or `53` for UDP. Leave blank for default Mullvad server port | Custom VPN port to use |
|
||||||
@@ -161,7 +128,7 @@ Want more testing? ▶ [see the Wiki](https://github.com/qdm12/private-internet-
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| 🏁 `USER` | | | Your username |
|
| 🏁 `USER` | | | Your username |
|
||||||
| 🏁 `PASSWORD` | | | Your password |
|
| 🏁 `PASSWORD` | | | Your password |
|
||||||
| `REGION` | `Austria` | One of the [Windscribe regions](https://windscribe.com/status) | VPN server region |
|
| `REGION` | | One of the [Windscribe regions](https://windscribe.com/status) | VPN server region |
|
||||||
| `PORT` | | One from the [this list of ports](https://windscribe.com/getconfig/openvpn) | Custom VPN port to use |
|
| `PORT` | | One from the [this list of ports](https://windscribe.com/getconfig/openvpn) | Custom VPN port to use |
|
||||||
|
|
||||||
- Surfshark
|
- Surfshark
|
||||||
@@ -170,7 +137,7 @@ Want more testing? ▶ [see the Wiki](https://github.com/qdm12/private-internet-
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| 🏁 `USER` | | | Your **service** username, found at the bottom of the [manual setup page](https://account.surfshark.com/setup/manual) |
|
| 🏁 `USER` | | | Your **service** username, found at the bottom of the [manual setup page](https://account.surfshark.com/setup/manual) |
|
||||||
| 🏁 `PASSWORD` | | | Your **service** password |
|
| 🏁 `PASSWORD` | | | Your **service** password |
|
||||||
| `REGION` | `Austria` | One of the [Surfshark regions (subdomains)](https://github.com/qdm12/private-internet-access-docker/wiki/surfshark) | VPN server region |
|
| `REGION` | | One of the [Surfshark regions](https://github.com/qdm12/private-internet-access-docker/wiki/surfshark) | VPN server region |
|
||||||
|
|
||||||
- Cyberghost
|
- Cyberghost
|
||||||
|
|
||||||
@@ -179,7 +146,7 @@ Want more testing? ▶ [see the Wiki](https://github.com/qdm12/private-internet-
|
|||||||
| 🏁 `USER` | | | Your username |
|
| 🏁 `USER` | | | Your username |
|
||||||
| 🏁 `PASSWORD` | | | Your password |
|
| 🏁 `PASSWORD` | | | Your password |
|
||||||
| 🏁 `CLIENT_KEY` | | | Your device client key content, **see below** |
|
| 🏁 `CLIENT_KEY` | | | Your device client key content, **see below** |
|
||||||
| `REGION` | `Austria` | One of the [Cyberghost countries](https://github.com/qdm12/private-internet-access-docker/wiki/Cyberghost#regions) | VPN server country |
|
| `REGION` | | One of the [Cyberghost countries](https://github.com/qdm12/private-internet-access-docker/wiki/Cyberghost#regions) | VPN server country |
|
||||||
| `CYBERGHOST_GROUP` | `Premium UDP Europe` | One of the [server groups](https://github.com/qdm12/private-internet-access-docker/wiki/Cyberghost#server-groups) | Server group |
|
| `CYBERGHOST_GROUP` | `Premium UDP Europe` | One of the [server groups](https://github.com/qdm12/private-internet-access-docker/wiki/Cyberghost#server-groups) | Server group |
|
||||||
|
|
||||||
To specify your client key, you can either:
|
To specify your client key, you can either:
|
||||||
@@ -199,7 +166,7 @@ Want more testing? ▶ [see the Wiki](https://github.com/qdm12/private-internet-
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| 🏁 `USER` | | | Your username |
|
| 🏁 `USER` | | | Your username |
|
||||||
| 🏁 `PASSWORD` | | | Your password |
|
| 🏁 `PASSWORD` | | | Your password |
|
||||||
| `REGION` | `Austria` | One of the [VyprVPN regions](https://www.vyprvpn.com/server-locations) | VPN server region |
|
| `REGION` | | One of the [VyprVPN regions](https://www.vyprvpn.com/server-locations) | VPN server region |
|
||||||
|
|
||||||
- NordVPN
|
- NordVPN
|
||||||
|
|
||||||
@@ -207,9 +174,18 @@ Want more testing? ▶ [see the Wiki](https://github.com/qdm12/private-internet-
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| 🏁 `USER` | | | Your username |
|
| 🏁 `USER` | | | Your username |
|
||||||
| 🏁 `PASSWORD` | | | Your password |
|
| 🏁 `PASSWORD` | | | Your password |
|
||||||
| 🏁 `REGION` | `Austria` (wrong) | One of the NordVPN server country, i.e. `Switzerland` | VPN server country |
|
| `REGION` | | One of the NordVPN server country, i.e. `Switzerland` | VPN server country |
|
||||||
| `SERVER_NUMBER` | | Server integer number | Optional server number. For example `251` for `Italy #251` |
|
| `SERVER_NUMBER` | | Server integer number | Optional server number. For example `251` for `Italy #251` |
|
||||||
|
|
||||||
|
- PureVPN
|
||||||
|
|
||||||
|
| Variable | Default | Choices | Description |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 🏁 `USER` | | | Your user ID |
|
||||||
|
| 🏁 `REGION` | | One of the [PureVPN regions](https://support.purevpn.com/vpn-servers) | VPN server region |
|
||||||
|
| `COUNTRY` | | One of the [PureVPN countries](https://support.purevpn.com/vpn-servers) | VPN server country |
|
||||||
|
| `CITY` | | One of the [PureVPN cities](https://support.purevpn.com/vpn-servers) | VPN server city |
|
||||||
|
|
||||||
### DNS over TLS
|
### DNS over TLS
|
||||||
|
|
||||||
None of the following values are required.
|
None of the following values are required.
|
||||||
@@ -240,6 +216,7 @@ That one is important if you want to connect to the container from your LAN for
|
|||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| `FIREWALL` | `on` | `on` or `off` | Turn on or off the container built-in firewall. You should use it for **debugging purposes** only. |
|
| `FIREWALL` | `on` | `on` or `off` | Turn on or off the container built-in firewall. You should use it for **debugging purposes** only. |
|
||||||
| `EXTRA_SUBNETS` | | i.e. `192.168.1.0/24,192.168.10.121,10.0.0.5/28` | Comma separated subnets allowed in the container firewall |
|
| `EXTRA_SUBNETS` | | i.e. `192.168.1.0/24,192.168.10.121,10.0.0.5/28` | Comma separated subnets allowed in the container firewall |
|
||||||
|
| `FIREWALL_VPN_INPUT_PORTS` | | i.e. `1000,8080` | Comma separated list of ports to allow from the VPN server side (useful for **vyprvpn** port forwarding) |
|
||||||
| `FIREWALL_DEBUG` | `off` | `on` or `off` | Prints every firewall related command. You should use it for **debugging purposes** only. |
|
| `FIREWALL_DEBUG` | `off` | `on` or `off` | Prints every firewall related command. You should use it for **debugging purposes** only. |
|
||||||
|
|
||||||
### Shadowsocks
|
### Shadowsocks
|
||||||
@@ -368,15 +345,13 @@ There are various ways to achieve this, depending on your use case.
|
|||||||
Note that [not all regions support port forwarding](https://www.privateinternetaccess.com/helpdesk/kb/articles/how-do-i-enable-port-forwarding-on-my-vpn).
|
Note that [not all regions support port forwarding](https://www.privateinternetaccess.com/helpdesk/kb/articles/how-do-i-enable-port-forwarding-on-my-vpn).
|
||||||
|
|
||||||
When `PORT_FORWARDING=on`, a port will be forwarded on the VPN server side and written to the file specified by `PORT_FORWARDING_STATUS_FILE=/forwarded_port`.
|
When `PORT_FORWARDING=on`, a port will be forwarded on the VPN server side and written to the file specified by `PORT_FORWARDING_STATUS_FILE=/forwarded_port`.
|
||||||
|
|
||||||
It can be useful to mount this file as a volume to read it from other containers, for example to configure a torrenting client.
|
It can be useful to mount this file as a volume to read it from other containers, for example to configure a torrenting client.
|
||||||
|
|
||||||
|
You can also use the HTTP control server (see below) to get the port forwarded.
|
||||||
|
|
||||||
## HTTP control server
|
## HTTP control server
|
||||||
|
|
||||||
A built-in HTTP server listens on port `8000` to modify the state of the container. You have the following routes available:
|
See [its Wiki page](https://github.com/qdm12/private-internet-access-docker/wiki/HTTP-control-server)
|
||||||
|
|
||||||
- `http://<your-docker-host-ip>:8000/openvpn/actions/restart` restarts the openvpn process
|
|
||||||
- `http://<your-docker-host-ip>:8000/unbound/actions/restart` re-downloads the DNS files (crypto and block lists) and restarts the unbound process
|
|
||||||
|
|
||||||
## Development and contributing
|
## Development and contributing
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/qdm12/golibs/network"
|
"github.com/qdm12/golibs/network"
|
||||||
"github.com/qdm12/private-internet-access-docker/internal/alpine"
|
"github.com/qdm12/private-internet-access-docker/internal/alpine"
|
||||||
"github.com/qdm12/private-internet-access-docker/internal/cli"
|
"github.com/qdm12/private-internet-access-docker/internal/cli"
|
||||||
|
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||||
"github.com/qdm12/private-internet-access-docker/internal/dns"
|
"github.com/qdm12/private-internet-access-docker/internal/dns"
|
||||||
"github.com/qdm12/private-internet-access-docker/internal/firewall"
|
"github.com/qdm12/private-internet-access-docker/internal/firewall"
|
||||||
gluetunLogging "github.com/qdm12/private-internet-access-docker/internal/logging"
|
gluetunLogging "github.com/qdm12/private-internet-access-docker/internal/logging"
|
||||||
@@ -56,8 +57,8 @@ func _main(background context.Context, args []string) int {
|
|||||||
ctx, cancel := context.WithCancel(background)
|
ctx, cancel := context.WithCancel(background)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
logger := createLogger()
|
logger := createLogger()
|
||||||
wg := &sync.WaitGroup{}
|
|
||||||
fatalOnError := makeFatalOnError(logger, cancel, wg)
|
fatalOnError := makeFatalOnError(logger, cancel)
|
||||||
|
|
||||||
client := network.NewClient(15 * time.Second)
|
client := network.NewClient(15 * time.Second)
|
||||||
// Create configurators
|
// Create configurators
|
||||||
@@ -104,6 +105,18 @@ func _main(background context.Context, args []string) int {
|
|||||||
routingConf.SetDebug()
|
routingConf.SetDebug()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defaultInterface, defaultGateway, err := routingConf.DefaultRoute()
|
||||||
|
if err != nil {
|
||||||
|
fatalOnError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
localSubnet, err := routingConf.LocalSubnet()
|
||||||
|
if err != nil {
|
||||||
|
fatalOnError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
firewallConf.SetNetworkInformation(defaultInterface, defaultGateway, localSubnet)
|
||||||
|
|
||||||
if err := ovpnConf.CheckTUN(); err != nil {
|
if err := ovpnConf.CheckTUN(); err != nil {
|
||||||
logger.Warn(err)
|
logger.Warn(err)
|
||||||
err = ovpnConf.CreateTUN()
|
err = ovpnConf.CreateTUN()
|
||||||
@@ -125,10 +138,19 @@ func _main(background context.Context, args []string) int {
|
|||||||
err = firewallConf.SetAllowedSubnets(ctx, allSettings.Firewall.AllowedSubnets)
|
err = firewallConf.SetAllowedSubnets(ctx, allSettings.Firewall.AllowedSubnets)
|
||||||
fatalOnError(err)
|
fatalOnError(err)
|
||||||
|
|
||||||
|
for _, vpnPort := range allSettings.Firewall.VPNInputPorts {
|
||||||
|
err = firewallConf.SetAllowedPort(ctx, vpnPort, string(constants.TUN))
|
||||||
|
fatalOnError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
|
||||||
openvpnLooper := openvpn.NewLooper(allSettings.VPNSP, allSettings.OpenVPN, uid, gid,
|
openvpnLooper := openvpn.NewLooper(allSettings.VPNSP, allSettings.OpenVPN, uid, gid,
|
||||||
ovpnConf, firewallConf, logger, client, fileManager, streamMerger, fatalOnError)
|
ovpnConf, firewallConf, logger, client, fileManager, streamMerger, fatalOnError)
|
||||||
restartOpenvpn := openvpnLooper.Restart
|
restartOpenvpn := openvpnLooper.Restart
|
||||||
portForward := openvpnLooper.PortForward
|
portForward := openvpnLooper.PortForward
|
||||||
|
getOpenvpnSettings := openvpnLooper.GetSettings
|
||||||
|
getPortForwarded := openvpnLooper.GetPortForwarded
|
||||||
// wait for restartOpenvpn
|
// wait for restartOpenvpn
|
||||||
go openvpnLooper.Run(ctx, wg)
|
go openvpnLooper.Run(ctx, wg)
|
||||||
|
|
||||||
@@ -144,11 +166,11 @@ func _main(background context.Context, args []string) int {
|
|||||||
go publicIPLooper.RunRestartTicker(ctx)
|
go publicIPLooper.RunRestartTicker(ctx)
|
||||||
setPublicIPPeriod(allSettings.PublicIPPeriod) // call after RunRestartTicker
|
setPublicIPPeriod(allSettings.PublicIPPeriod) // call after RunRestartTicker
|
||||||
|
|
||||||
tinyproxyLooper := tinyproxy.NewLooper(tinyProxyConf, firewallConf, allSettings.TinyProxy, logger, streamMerger, uid, gid)
|
tinyproxyLooper := tinyproxy.NewLooper(tinyProxyConf, firewallConf, allSettings.TinyProxy, logger, streamMerger, uid, gid, defaultInterface)
|
||||||
restartTinyproxy := tinyproxyLooper.Restart
|
restartTinyproxy := tinyproxyLooper.Restart
|
||||||
go tinyproxyLooper.Run(ctx, wg)
|
go tinyproxyLooper.Run(ctx, wg)
|
||||||
|
|
||||||
shadowsocksLooper := shadowsocks.NewLooper(shadowsocksConf, firewallConf, allSettings.ShadowSocks, allSettings.DNS, logger, streamMerger, uid, gid)
|
shadowsocksLooper := shadowsocks.NewLooper(shadowsocksConf, firewallConf, allSettings.ShadowSocks, allSettings.DNS, logger, streamMerger, uid, gid, defaultInterface)
|
||||||
restartShadowsocks := shadowsocksLooper.Restart
|
restartShadowsocks := shadowsocksLooper.Restart
|
||||||
go shadowsocksLooper.Run(ctx, wg)
|
go shadowsocksLooper.Run(ctx, wg)
|
||||||
|
|
||||||
@@ -176,7 +198,7 @@ func _main(background context.Context, args []string) int {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
httpServer := server.New("0.0.0.0:8000", logger, restartOpenvpn, restartUnbound)
|
httpServer := server.New("0.0.0.0:8000", logger, restartOpenvpn, restartUnbound, getOpenvpnSettings, getPortForwarded)
|
||||||
go httpServer.Run(ctx, wg)
|
go httpServer.Run(ctx, wg)
|
||||||
|
|
||||||
// Start openvpn for the first time
|
// Start openvpn for the first time
|
||||||
@@ -229,18 +251,11 @@ func _main(background context.Context, args []string) int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeFatalOnError(logger logging.Logger, cancel context.CancelFunc, wg *sync.WaitGroup) func(err error) {
|
func makeFatalOnError(logger logging.Logger, cancel context.CancelFunc) func(err error) {
|
||||||
return func(err error) {
|
return func(err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
cancel()
|
cancel()
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
|
||||||
go func() {
|
|
||||||
wg.Wait()
|
|
||||||
cancel()
|
|
||||||
}()
|
|
||||||
<-ctx.Done() // either timeout or wait group completed
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
111
cmd/locationToSubdomain/main.go
Normal file
111
cmd/locationToSubdomain/main.go
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/qdm12/golibs/network"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
os.Exit(_main())
|
||||||
|
}
|
||||||
|
|
||||||
|
func _main() int {
|
||||||
|
provider := flag.String("provider", "purevpn", "VPN provider to map location to subdomain, can be 'purevpn'")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
client := network.NewClient(5 * time.Second)
|
||||||
|
switch *provider {
|
||||||
|
case "purevpn":
|
||||||
|
servers, warnings, err := purevpn(client)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
for _, server := range servers {
|
||||||
|
fmt.Printf(
|
||||||
|
"{subdomain: %q, region: %q, country: %q, city: %q},\n",
|
||||||
|
server.subdomain, server.region, server.country, server.city,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fmt.Print("\n\n")
|
||||||
|
for _, warning := range warnings {
|
||||||
|
fmt.Println(warning)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
fmt.Printf("Provider %q is not supported\n", *provider)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type purevpnServer struct {
|
||||||
|
region string
|
||||||
|
country string
|
||||||
|
city string
|
||||||
|
subdomain string // without -tcp or -udp suffix
|
||||||
|
}
|
||||||
|
|
||||||
|
func purevpn(client network.Client) (servers []purevpnServer, warnings []string, err error) {
|
||||||
|
content, status, err := client.GetContent("https://support.purevpn.com/vpn-servers")
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
} else if status != http.StatusOK {
|
||||||
|
return nil, nil, fmt.Errorf("HTTP status %d from Purevpn", status)
|
||||||
|
}
|
||||||
|
const jsonPrefix = "<script>var servers = "
|
||||||
|
const jsonSuffix = "</script>"
|
||||||
|
s := string(content)
|
||||||
|
jsonPrefixIndex := strings.Index(s, jsonPrefix)
|
||||||
|
if jsonPrefixIndex == -1 {
|
||||||
|
return nil, nil, fmt.Errorf("cannot find prefix %s in html", jsonPrefix)
|
||||||
|
}
|
||||||
|
if len(s[jsonPrefixIndex:]) == len(jsonPrefix) {
|
||||||
|
return nil, nil, fmt.Errorf("no body after json prefix %s", jsonPrefix)
|
||||||
|
}
|
||||||
|
s = s[jsonPrefixIndex+len(jsonPrefix):]
|
||||||
|
endIndex := strings.Index(s, jsonSuffix)
|
||||||
|
s = s[:endIndex]
|
||||||
|
var data []struct {
|
||||||
|
Region string `json:"region_name"`
|
||||||
|
Country string `json:"country_name"`
|
||||||
|
City string `json:"city_name"`
|
||||||
|
TCP string `json:"tcp"`
|
||||||
|
UDP string `json:"udp"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal([]byte(s), &data); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
sort.Slice(data, func(i, j int) bool {
|
||||||
|
if data[i].Region == data[j].Region {
|
||||||
|
if data[i].Country == data[j].Country {
|
||||||
|
return data[i].City < data[j].City
|
||||||
|
}
|
||||||
|
return data[i].Country < data[j].Country
|
||||||
|
}
|
||||||
|
return data[i].Region < data[j].Region
|
||||||
|
})
|
||||||
|
for i := range data {
|
||||||
|
if data[i].UDP == "" && data[i].TCP == "" {
|
||||||
|
warnings = append(warnings, fmt.Sprintf("server %s %s %s does not support TCP and UDP for openvpn", data[i].Region, data[i].Country, data[i].City))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if data[i].UDP == "" || data[i].TCP == "" {
|
||||||
|
warnings = append(warnings, fmt.Sprintf("server %s %s %s does not support TCP or udp for openvpn", data[i].Region, data[i].Country, data[i].City))
|
||||||
|
}
|
||||||
|
servers = append(servers, purevpnServer{
|
||||||
|
region: data[i].Region,
|
||||||
|
country: data[i].Country,
|
||||||
|
city: data[i].City,
|
||||||
|
subdomain: strings.TrimSuffix(data[i].TCP, "-tcp.pointtoserver.com"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return servers, warnings, nil
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ func main() {
|
|||||||
|
|
||||||
func _main(ctx context.Context) int {
|
func _main(ctx context.Context) int {
|
||||||
resolverAddress := flag.String("resolver", "1.1.1.1", "DNS Resolver IP address to use")
|
resolverAddress := flag.String("resolver", "1.1.1.1", "DNS Resolver IP address to use")
|
||||||
provider := flag.String("provider", "pia", "VPN provider to resolve for, 'pia', 'windscribe', 'cyberghost' or 'vyprvpn'")
|
provider := flag.String("provider", "pia", "VPN provider to resolve for, 'pia', 'windscribe', 'cyberghost', 'vyprvpn' or 'purevpn'")
|
||||||
region := flag.String("region", "all", "Comma separated list of VPN provider region names to resolve for, use 'all' to resolve all")
|
region := flag.String("region", "all", "Comma separated list of VPN provider region names to resolve for, use 'all' to resolve all")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
@@ -43,6 +43,9 @@ func _main(ctx context.Context) int {
|
|||||||
case "vyprvpn":
|
case "vyprvpn":
|
||||||
domain = "vyprvpn.com"
|
domain = "vyprvpn.com"
|
||||||
servers = vyprvpnServers()
|
servers = vyprvpnServers()
|
||||||
|
case "purevpn":
|
||||||
|
domain = "pointtoserver.com"
|
||||||
|
servers = purevpnServers()
|
||||||
default:
|
default:
|
||||||
fmt.Printf("Provider %q is not supported\n", *provider)
|
fmt.Printf("Provider %q is not supported\n", *provider)
|
||||||
return 1
|
return 1
|
||||||
@@ -135,6 +138,11 @@ func formatLine(provider string, s server, ips []net.IP) string {
|
|||||||
"{Region: %q, IPs: []net.IP{%s}},",
|
"{Region: %q, IPs: []net.IP{%s}},",
|
||||||
s.region, ipString,
|
s.region, ipString,
|
||||||
)
|
)
|
||||||
|
case "purevpn":
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"{Region: %q, Country: %q, City: %q, IPs: []net.IP{%s}},",
|
||||||
|
s.region, s.country, s.city, ipString,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -197,6 +205,8 @@ type server struct {
|
|||||||
subdomain string
|
subdomain string
|
||||||
region string
|
region string
|
||||||
group string // only for cyberghost
|
group string // only for cyberghost
|
||||||
|
country string // only for purevpn
|
||||||
|
city string // only for purevpn
|
||||||
}
|
}
|
||||||
|
|
||||||
func piaServers() []server {
|
func piaServers() []server {
|
||||||
@@ -747,3 +757,164 @@ func vyprvpnServers() []server {
|
|||||||
{subdomain: "vn1", region: "Vietnam"},
|
{subdomain: "vn1", region: "Vietnam"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func purevpnServers() []server {
|
||||||
|
servers := []server{
|
||||||
|
{subdomain: "vlus-dz1-ovpn", region: "Africa", country: "Algeria", city: "Algiers"},
|
||||||
|
{subdomain: "vlus-ao1-ovpn", region: "Africa", country: "Angola", city: "Benguela"},
|
||||||
|
{subdomain: "vleu-cv-ovpn", region: "Africa", country: "Cape Verde", city: "Praia"},
|
||||||
|
{subdomain: "vlus-eg1-ovpn", region: "Africa", country: "Egypt", city: "Cairo"},
|
||||||
|
{subdomain: "et1-ovpn", region: "Africa", country: "Ethiopia", city: "Addis Ababa"},
|
||||||
|
{subdomain: "gh1-ovpn", region: "Africa", country: "Ghana", city: "Accra"},
|
||||||
|
{subdomain: "ke1-ovpn", region: "Africa", country: "Kenya", city: "Mombasa"},
|
||||||
|
{subdomain: "vlus-mg1-ovpn", region: "Africa", country: "Madagascar", city: "Antananarivo"},
|
||||||
|
{subdomain: "vlus-mr1-ovpn", region: "Africa", country: "Mauritania", city: "Nouakchott"},
|
||||||
|
{subdomain: "mu1-ovpn", region: "Africa", country: "Mauritius", city: "Port Louis"},
|
||||||
|
{subdomain: "ma1-ovpn", region: "Africa", country: "Morocco", city: "Rabat"},
|
||||||
|
{subdomain: "vlus-ne1-ovpn", region: "Africa", country: "Niger", city: "Niamey"},
|
||||||
|
{subdomain: "ng1-ovpn", region: "Africa", country: "Nigeria", city: "Suleja"},
|
||||||
|
{subdomain: "vlus-sn1-ovpn", region: "Africa", country: "Senegal", city: "Dakar"},
|
||||||
|
{subdomain: "sc1-ovpn", region: "Africa", country: "Seychelles", city: "Victoria"},
|
||||||
|
{subdomain: "za2-ovpn", region: "Africa", country: "South Africa", city: "Johannesburg"},
|
||||||
|
{subdomain: "vlus-tz1-ovpn", region: "Africa", country: "Tanzania", city: "Dar Es Salaam"},
|
||||||
|
{subdomain: "vlus-tn1-ovpn", region: "Africa", country: "Tunisia", city: "Tunis"},
|
||||||
|
{subdomain: "vlus-af1-ovpn", region: "Asia", country: "Afghanistan", city: "Kabul"},
|
||||||
|
{subdomain: "sg2-ovpn", region: "Asia", country: "Armenia", city: "Singapore"},
|
||||||
|
{subdomain: "az1-ovpn", region: "Asia", country: "Azerbaijan", city: "Baku"},
|
||||||
|
{subdomain: "vlus-bd1-ovpn", region: "Asia", country: "Bangladesh", city: "Dhaka"},
|
||||||
|
{subdomain: "bn2-ovpn", region: "Asia", country: "Brunei Darussalam", city: "Bandar Seri Begawan"},
|
||||||
|
{subdomain: "kh1-ovpn", region: "Asia", country: "Cambodia", city: "Phnom Penh"},
|
||||||
|
{subdomain: "hk2-ovpn", region: "Asia", country: "Hong Kong (SAR)", city: "Hong Kong"},
|
||||||
|
{subdomain: "in2-ovpn", region: "Asia", country: "India", city: "Chennai"},
|
||||||
|
{subdomain: "idn1-ovpn", region: "Asia", country: "Indonesia", city: "Jakarta"},
|
||||||
|
{subdomain: "jp-tk1-ovpn", region: "Asia", country: "Japan", city: "Tokyo"},
|
||||||
|
{subdomain: "vlus-kz1-ovpn", region: "Asia", country: "Kazakhstan", city: "Almaty"},
|
||||||
|
{subdomain: "kr2-ovpn", region: "Asia", country: "Korea, South", city: "Seoul"},
|
||||||
|
{subdomain: "vlus-kg1-ovpn", region: "Asia", country: "Kyrgyzstan", city: "Bishkek"},
|
||||||
|
{subdomain: "vlus-la1-ovpn", region: "Asia", country: "Laos", city: "Vientiane"},
|
||||||
|
{subdomain: "mo1-ovpn", region: "Asia", country: "Macao", city: "Beyrouth"},
|
||||||
|
{subdomain: "my2-ovpn", region: "Asia", country: "Malaysia", city: "Johor Baharu"},
|
||||||
|
{subdomain: "my-kl2-ovpn", region: "Asia", country: "Malaysia", city: "Kuala Lumpur"},
|
||||||
|
{subdomain: "vlus-mn1-ovpn", region: "Asia", country: "Mongolia", city: "Ulaanbaatar"},
|
||||||
|
{subdomain: "pk1-ovpn", region: "Asia", country: "Pakistan", city: "Islamabad"},
|
||||||
|
{subdomain: "vlus-pg1-ovpn", region: "Asia", country: "Papua New Guinea", city: "Port Moresby"},
|
||||||
|
{subdomain: "vlap-ph2-ovpn", region: "Asia", country: "Philippines", city: "Manila"},
|
||||||
|
{subdomain: "vlus-lk1-ovpn", region: "Asia", country: "Sri Lanka", city: "Colombo"},
|
||||||
|
{subdomain: "tw2-ovpn", region: "Asia", country: "Taiwan", city: "Taipei"},
|
||||||
|
{subdomain: "vlus-tj-ovpn", region: "Asia", country: "Tajikistan", city: "Dushanbe"},
|
||||||
|
{subdomain: "vlap-th2-ovpn", region: "Asia", country: "Thailand", city: "Bangkok"},
|
||||||
|
{subdomain: "tr2-ovpn", region: "Asia", country: "Turkey", city: "Istanbul"},
|
||||||
|
{subdomain: "vlus-tm1-ovpn", region: "Asia", country: "Turkmenistan", city: "Ashgabat"},
|
||||||
|
{subdomain: "vlus-uz-ovpn", region: "Asia", country: "Uzbekistan", city: "Tashkent"},
|
||||||
|
{subdomain: "vlap-vn2-ovpn", region: "Asia", country: "Vietnam", city: "Hanoi"},
|
||||||
|
{subdomain: "al1-ovpn", region: "Europe", country: "Albania", city: "Tirane"},
|
||||||
|
{subdomain: "vleu-am1-ovpn", region: "Europe", country: "Armenia", city: "Yerevan"},
|
||||||
|
{subdomain: "at2-ovpn", region: "Europe", country: "Austria", city: "Vienna"},
|
||||||
|
{subdomain: "vleu-be2-ovpn", region: "Europe", country: "Belgium", city: "Brussels"},
|
||||||
|
{subdomain: "ba1-ovpn", region: "Europe", country: "Bosnia and Herzegovina", city: "Sarajevo"},
|
||||||
|
{subdomain: "bg2-ovpn", region: "Europe", country: "Bulgaria", city: "Sofia"},
|
||||||
|
{subdomain: "vlus-hr1-ovpn", region: "Europe", country: "Croatia", city: "Zagreb"},
|
||||||
|
{subdomain: "cy1-ovpn", region: "Europe", country: "Cyprus", city: "Nicosia"},
|
||||||
|
{subdomain: "dk2-ovpn", region: "Europe", country: "Denmark", city: "Copenhagen"},
|
||||||
|
{subdomain: "ee1-ovpn", region: "Europe", country: "Estonia", city: "Tallinn"},
|
||||||
|
{subdomain: "fr2-ovpn", region: "Europe", country: "France", city: "Paris"},
|
||||||
|
{subdomain: "vlus-ge1-ovpn", region: "Europe", country: "Georgia", city: "Tbilisi"},
|
||||||
|
{subdomain: "de2-ovpn", region: "Europe", country: "Germany", city: "Frankfurt"},
|
||||||
|
{subdomain: "de2-ovpn", region: "Europe", country: "Germany", city: "Munich"},
|
||||||
|
{subdomain: "de-ao1-ovpn", region: "Europe", country: "Germany", city: "Nuremberg"},
|
||||||
|
{subdomain: "gr2-ovpn", region: "Europe", country: "Greece", city: "Thessaloniki"},
|
||||||
|
{subdomain: "hu2-ovpn", region: "Europe", country: "Hungary", city: "Budapest"},
|
||||||
|
{subdomain: "is1-ovpn", region: "Europe", country: "Iceland", city: "Reykjavik"},
|
||||||
|
{subdomain: "ie2-ovpn", region: "Europe", country: "Ireland", city: "Dublin"},
|
||||||
|
{subdomain: "im1-ovpn", region: "Europe", country: "Isle of Man", city: "Onchan"},
|
||||||
|
{subdomain: "vlus-it1-ovpn", region: "Europe", country: "Italy", city: "Milano"},
|
||||||
|
{subdomain: "lv1-ovpn", region: "Europe", country: "Latvia", city: "RIGA"},
|
||||||
|
{subdomain: "li1-ovpn", region: "Europe", country: "Liechtenstein", city: "Vaduz"},
|
||||||
|
{subdomain: "lt1-ovpn", region: "Europe", country: "Lithuania", city: "Vilnius"},
|
||||||
|
{subdomain: "lu2-ovpn", region: "Europe", country: "Luxembourg", city: "Luxembourg"},
|
||||||
|
{subdomain: "mt1-ovpn", region: "Europe", country: "Malta", city: "Sliema"},
|
||||||
|
{subdomain: "mn1-ovpn", region: "Europe", country: "Monaco", city: "Monaco"},
|
||||||
|
{subdomain: "vleu-me1-ovpn", region: "Europe", country: "Montenegro", city: "Podgorica"},
|
||||||
|
{subdomain: "nl2-ovpn", region: "Europe", country: "Netherlands", city: "Amsterdam"},
|
||||||
|
{subdomain: "vleu-no2-ovpn", region: "Europe", country: "Norway", city: "Oslo"},
|
||||||
|
{subdomain: "pl2-ovpn", region: "Europe", country: "Poland", city: "Warsaw"},
|
||||||
|
{subdomain: "pt2-ovpn", region: "Europe", country: "Portugal", city: "Lisbon"},
|
||||||
|
{subdomain: "ro2-ovpn", region: "Europe", country: "Romania", city: "Bucharest"},
|
||||||
|
{subdomain: "rs2-ovpn", region: "Europe", country: "Serbia", city: "Niš"},
|
||||||
|
{subdomain: "sk1-ovpn", region: "Europe", country: "Slovakia", city: "Bratislava"},
|
||||||
|
{subdomain: "si1-ovpn", region: "Europe", country: "Slovenia", city: "Ljubljana"},
|
||||||
|
{subdomain: "es-ovpn", region: "Europe", country: "Spain", city: "Barcelona"},
|
||||||
|
{subdomain: "vlus-se1-ovpn", region: "Europe", country: "Sweden", city: "Stockholm"},
|
||||||
|
{subdomain: "ch2-ovpn", region: "Europe", country: "Switzerland", city: "Zurich"},
|
||||||
|
{subdomain: "ukg2-ovpn", region: "Europe", country: "United Kingdom", city: "Gosport"},
|
||||||
|
{subdomain: "ukl2-ovpn", region: "Europe", country: "United Kingdom", city: "London"},
|
||||||
|
{subdomain: "ukm2-ovpn", region: "Europe", country: "United Kingdom", city: "Maidenhead"},
|
||||||
|
{subdomain: "vlus-uk-man1-ovpn", region: "Europe", country: "United Kingdom", city: "Manchester"},
|
||||||
|
{subdomain: "bh-ovpn", region: "Middle East", country: "Bahrain", city: "Manama"},
|
||||||
|
{subdomain: "vlus-jo1-ovpn", region: "Middle East", country: "Jordan", city: "Amman"},
|
||||||
|
{subdomain: "vlus-kw1-ovpn", region: "Middle East", country: "Kuwait", city: "Kuwait"},
|
||||||
|
{subdomain: "om1-ovpn", region: "Middle East", country: "Oman", city: "Salalah"},
|
||||||
|
{subdomain: "qa1-ovpn", region: "Middle East", country: "Qatar", city: "Doha"},
|
||||||
|
{subdomain: "sa1-ovpn", region: "Middle East", country: "Saudi Arabia", city: "Jeddah"},
|
||||||
|
{subdomain: "ae2-ovpn", region: "Middle East", country: "United Arab Emirates", city: "Dubai"},
|
||||||
|
{subdomain: "aw1-ovpn", region: "North America", country: "Aruba", city: "Oranjestad"},
|
||||||
|
{subdomain: "vleu-bb-ovpn", region: "North America", country: "Barbados", city: "Bridgetown"},
|
||||||
|
{subdomain: "bz1-ovpn", region: "North America", country: "Belize", city: "Belmopan"},
|
||||||
|
{subdomain: "vleu-bm-ovpn", region: "North America", country: "Bermuda", city: "Hamilton"},
|
||||||
|
{subdomain: "caq1-ovpn", region: "North America", country: "Canada", city: "Montreal"},
|
||||||
|
{subdomain: "cato-ovpn", region: "North America", country: "Canada", city: "Toronto"},
|
||||||
|
{subdomain: "cav2-ovpn", region: "North America", country: "Canada", city: "Vancouver"},
|
||||||
|
{subdomain: "vleu-ky-ovpn", region: "North America", country: "Cayman Islands", city: "George Town"},
|
||||||
|
{subdomain: "vlus-cr1-ovpn", region: "North America", country: "Costa Rica", city: "San Jose"},
|
||||||
|
{subdomain: "vleu-dm-ovpn", region: "North America", country: "Dominica", city: "Roseau"},
|
||||||
|
{subdomain: "vleu-do-ovpn", region: "North America", country: "Dominican Republic", city: "Santo Domingo"},
|
||||||
|
{subdomain: "vleu-sv-ovpn", region: "North America", country: "El Salvador", city: "San Salvador"},
|
||||||
|
{subdomain: "vleu-gd-ovpn", region: "North America", country: "Grenada", city: "St George's"},
|
||||||
|
{subdomain: "vleu-gt-ovpn", region: "North America", country: "Guatemala", city: "Guatemala"},
|
||||||
|
{subdomain: "vleu-ht1-ovpn", region: "North America", country: "Haiti", city: "PORT-AU-PRINCE"},
|
||||||
|
{subdomain: "vleu-hn-ovpn", region: "North America", country: "Honduras", city: "TEGUCIGALPA"},
|
||||||
|
{subdomain: "jm1-ovpn", region: "North America", country: "Jamaica", city: "Kingston"},
|
||||||
|
{subdomain: "vlus-mx2-ovpn", region: "North America", country: "Mexico", city: "Mexico City"},
|
||||||
|
{subdomain: "vleu-ms-ovpn", region: "North America", country: "Montserrat", city: "plymouth"},
|
||||||
|
{subdomain: "pr1-ovpn", region: "North America", country: "Puerto Rico", city: "San Juan"},
|
||||||
|
{subdomain: "vleu-lc-ovpn", region: "North America", country: "Saint Lucia", city: "Castries"},
|
||||||
|
{subdomain: "bs1-ovpn", region: "North America", country: "The Bahamas", city: "Freeport"},
|
||||||
|
{subdomain: "vleu-tt-ovpn", region: "North America", country: "Trinidad and Tobago", city: "Port of Spain"},
|
||||||
|
{subdomain: "vleu-tc-ovpn", region: "North America", country: "Turks and Caicos Islands", city: "Balfour Town"},
|
||||||
|
{subdomain: "usva-ovpn", region: "North America", country: "United States", city: "Ashburn"},
|
||||||
|
{subdomain: "usil2-ovpn", region: "North America", country: "United States", city: "Chicago"},
|
||||||
|
{subdomain: "usoh1-ovpn", region: "North America", country: "United States", city: "Columbus"},
|
||||||
|
{subdomain: "usga2-ovpn", region: "North America", country: "United States", city: "Georgia"},
|
||||||
|
{subdomain: "ustx2-ovpn", region: "North America", country: "United States", city: "Houston"},
|
||||||
|
{subdomain: "usla2-ovpn", region: "North America", country: "United States", city: "Los Angeles"},
|
||||||
|
{subdomain: "usfl2-ovpn", region: "North America", country: "United States", city: "Miami"},
|
||||||
|
{subdomain: "usnj2-ovpn", region: "North America", country: "United States", city: "New Jersey"},
|
||||||
|
{subdomain: "usny2-ovpn", region: "North America", country: "United States", city: "New York"},
|
||||||
|
{subdomain: "usphx2-ovpn", region: "North America", country: "United States", city: "Phoenix"},
|
||||||
|
{subdomain: "usut2-ovpn", region: "North America", country: "United States", city: "Salt Lake City"},
|
||||||
|
{subdomain: "ussf2-ovpn", region: "North America", country: "United States", city: "San Francisco"},
|
||||||
|
{subdomain: "ussa-ovpn", region: "North America", country: "United States", city: "Seattle"},
|
||||||
|
{subdomain: "uswdc2-ovpn", region: "North America", country: "United States", city: "Washington, D.C."},
|
||||||
|
{subdomain: "au-bn-ovpn", region: "Oceania", country: "Australia", city: "Brisbane"},
|
||||||
|
{subdomain: "au-me1-ovpn", region: "Oceania", country: "Australia", city: "Melbourne"},
|
||||||
|
{subdomain: "au2-pe-ovpn", region: "Oceania", country: "Australia", city: "Perth"},
|
||||||
|
{subdomain: "au-sd2-ovpn", region: "Oceania", country: "Australia", city: "Sydney"},
|
||||||
|
{subdomain: "nz2-ovpn", region: "Oceania", country: "New Zealand", city: "Auckland"},
|
||||||
|
{subdomain: "vlus-ar1-ovpn", region: "South America", country: "Argentina", city: "Buenos Aires"},
|
||||||
|
{subdomain: "vleu-bo-ovpn", region: "South America", country: "Bolivia", city: "Sucre"},
|
||||||
|
{subdomain: "br2-ovpn", region: "South America", country: "Brazil", city: "Sao Paulo"},
|
||||||
|
{subdomain: "vg1-ovpn", region: "South America", country: "British Virgin Island", city: "Road Town"},
|
||||||
|
{subdomain: "vlbr-cl-ovpn", region: "South America", country: "Chile", city: "Santiago"},
|
||||||
|
{subdomain: "co1-ovpn", region: "South America", country: "Colombia", city: "Bogota"},
|
||||||
|
{subdomain: "ec1-ovpn", region: "South America", country: "Ecuador", city: "Quito"},
|
||||||
|
{subdomain: "vleu-gy-ovpn", region: "South America", country: "Guyana", city: "Georgetown"},
|
||||||
|
{subdomain: "pa2-ovpn", region: "South America", country: "Panama", city: "Panama City"},
|
||||||
|
{subdomain: "vleu-py-ovpn", region: "South America", country: "Paraguay", city: "Asuncion"},
|
||||||
|
{subdomain: "pe1-ovpn", region: "South America", country: "Peru", city: "Lima"},
|
||||||
|
{subdomain: "vleu-sr-ovpn", region: "South America", country: "Suriname", city: "Paramaribo"},
|
||||||
|
}
|
||||||
|
for i := range servers {
|
||||||
|
servers[i].subdomain += "-udp"
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const (
|
|||||||
|
|
||||||
func MullvadCountryChoices() (choices []string) {
|
func MullvadCountryChoices() (choices []string) {
|
||||||
uniqueChoices := map[string]struct{}{}
|
uniqueChoices := map[string]struct{}{}
|
||||||
for _, server := range mullvadServers() {
|
for _, server := range MullvadServers() {
|
||||||
uniqueChoices[server.Country] = struct{}{}
|
uniqueChoices[server.Country] = struct{}{}
|
||||||
}
|
}
|
||||||
for choice := range uniqueChoices {
|
for choice := range uniqueChoices {
|
||||||
@@ -27,7 +27,7 @@ func MullvadCountryChoices() (choices []string) {
|
|||||||
|
|
||||||
func MullvadCityChoices() (choices []string) {
|
func MullvadCityChoices() (choices []string) {
|
||||||
uniqueChoices := map[string]struct{}{}
|
uniqueChoices := map[string]struct{}{}
|
||||||
for _, server := range mullvadServers() {
|
for _, server := range MullvadServers() {
|
||||||
uniqueChoices[server.City] = struct{}{}
|
uniqueChoices[server.City] = struct{}{}
|
||||||
}
|
}
|
||||||
for choice := range uniqueChoices {
|
for choice := range uniqueChoices {
|
||||||
@@ -41,7 +41,7 @@ func MullvadCityChoices() (choices []string) {
|
|||||||
|
|
||||||
func MullvadISPChoices() (choices []string) {
|
func MullvadISPChoices() (choices []string) {
|
||||||
uniqueChoices := map[string]struct{}{}
|
uniqueChoices := map[string]struct{}{}
|
||||||
for _, server := range mullvadServers() {
|
for _, server := range MullvadServers() {
|
||||||
uniqueChoices[server.ISP] = struct{}{}
|
uniqueChoices[server.ISP] = struct{}{}
|
||||||
}
|
}
|
||||||
for choice := range uniqueChoices {
|
for choice := range uniqueChoices {
|
||||||
@@ -53,25 +53,7 @@ func MullvadISPChoices() (choices []string) {
|
|||||||
return choices
|
return choices
|
||||||
}
|
}
|
||||||
|
|
||||||
func MullvadServerFilter(country, city, isp string) (servers []models.MullvadServer) {
|
func MullvadServers() []models.MullvadServer {
|
||||||
for _, server := range mullvadServers() {
|
|
||||||
if len(country) == 0 {
|
|
||||||
server.Country = ""
|
|
||||||
}
|
|
||||||
if len(city) == 0 {
|
|
||||||
server.City = ""
|
|
||||||
}
|
|
||||||
if len(isp) == 0 {
|
|
||||||
server.ISP = ""
|
|
||||||
}
|
|
||||||
if server.Country == country && server.City == city && server.ISP == isp {
|
|
||||||
servers = append(servers, server)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return servers
|
|
||||||
}
|
|
||||||
|
|
||||||
func mullvadServers() []models.MullvadServer {
|
|
||||||
return []models.MullvadServer{
|
return []models.MullvadServer{
|
||||||
{
|
{
|
||||||
Country: "united arab emirates",
|
Country: "united arab emirates",
|
||||||
|
|||||||
@@ -26,56 +26,56 @@ func PIAGeoChoices() (choices []string) {
|
|||||||
|
|
||||||
func PIAServers() []models.PIAServer {
|
func PIAServers() []models.PIAServer {
|
||||||
return []models.PIAServer{
|
return []models.PIAServer{
|
||||||
{Region: "AU Melbourne", IPs: []net.IP{{27, 50, 82, 131}, {27, 50, 82, 133}, {43, 250, 204, 81}, {43, 250, 204, 83}, {43, 250, 204, 87}, {43, 250, 204, 89}, {43, 250, 204, 91}, {43, 250, 204, 93}, {43, 250, 204, 97}, {43, 250, 204, 99}, {43, 250, 204, 101}, {43, 250, 204, 103}, {43, 250, 204, 107}, {43, 250, 204, 111}, {43, 250, 204, 117}, {43, 250, 204, 119}, {43, 250, 204, 123}, {43, 250, 204, 125}, {118, 127, 62, 227}, {221, 121, 139, 175}}},
|
{Region: "AU Melbourne", IPs: []net.IP{{27, 50, 82, 131}, {27, 50, 82, 133}, {43, 250, 204, 83}, {43, 250, 204, 87}, {43, 250, 204, 89}, {43, 250, 204, 91}, {43, 250, 204, 93}, {43, 250, 204, 95}, {43, 250, 204, 97}, {43, 250, 204, 101}, {43, 250, 204, 103}, {43, 250, 204, 105}, {43, 250, 204, 107}, {43, 250, 204, 109}, {43, 250, 204, 111}, {43, 250, 204, 113}, {43, 250, 204, 115}, {43, 250, 204, 117}, {43, 250, 204, 123}, {43, 250, 204, 125}, {118, 127, 62, 227}, {221, 121, 139, 175}}},
|
||||||
{Region: "AU Perth", IPs: []net.IP{{43, 250, 205, 59}, {43, 250, 205, 89}, {43, 250, 205, 91}, {43, 250, 205, 93}, {43, 250, 205, 95}}},
|
{Region: "AU Perth", IPs: []net.IP{{43, 250, 205, 59}, {43, 250, 205, 91}, {43, 250, 205, 95}}},
|
||||||
{Region: "AU Sydney", IPs: []net.IP{{27, 50, 77, 247}, {103, 13, 102, 113}, {103, 13, 102, 115}, {103, 13, 102, 117}, {103, 13, 102, 119}, {103, 13, 102, 121}, {103, 13, 102, 123}, {103, 13, 102, 127}, {118, 127, 60, 53}, {118, 127, 60, 61}, {221, 121, 145, 131}, {221, 121, 145, 133}, {221, 121, 145, 143}, {221, 121, 145, 151}, {221, 121, 146, 203}, {221, 121, 152, 215}}},
|
{Region: "AU Sydney", IPs: []net.IP{{103, 13, 102, 113}, {103, 13, 102, 115}, {103, 13, 102, 117}, {103, 13, 102, 119}, {103, 13, 102, 121}, {103, 13, 102, 123}, {103, 13, 102, 127}, {118, 127, 60, 53}, {118, 127, 60, 61}, {221, 121, 145, 133}, {221, 121, 145, 143}, {221, 121, 146, 203}, {221, 121, 152, 215}}},
|
||||||
{Region: "Austria", IPs: []net.IP{{185, 210, 219, 147}, {185, 210, 219, 154}, {185, 210, 219, 156}, {185, 216, 34, 226}, {185, 216, 34, 228}, {185, 216, 34, 229}, {185, 216, 34, 230}, {185, 216, 34, 232}, {185, 216, 34, 233}, {185, 216, 34, 236}, {185, 216, 34, 237}, {185, 216, 34, 238}}},
|
{Region: "Austria", IPs: []net.IP{{185, 210, 219, 147}, {185, 210, 219, 154}, {185, 210, 219, 155}, {185, 210, 219, 156}, {185, 216, 34, 226}, {185, 216, 34, 227}, {185, 216, 34, 228}, {185, 216, 34, 229}, {185, 216, 34, 230}, {185, 216, 34, 232}, {185, 216, 34, 236}, {185, 216, 34, 237}, {185, 216, 34, 238}}},
|
||||||
{Region: "Belgium", IPs: []net.IP{{77, 243, 191, 19}, {77, 243, 191, 21}, {77, 243, 191, 22}, {77, 243, 191, 23}, {77, 243, 191, 26}, {77, 243, 191, 27}, {185, 104, 186, 26}, {185, 232, 21, 26}, {185, 232, 21, 29}}},
|
{Region: "Belgium", IPs: []net.IP{{77, 243, 191, 19}, {77, 243, 191, 20}, {77, 243, 191, 21}, {77, 243, 191, 22}, {77, 243, 191, 26}, {77, 243, 191, 27}, {185, 232, 21, 26}, {185, 232, 21, 27}, {185, 232, 21, 28}, {185, 232, 21, 29}}},
|
||||||
{Region: "CA Montreal", IPs: []net.IP{{199, 229, 249, 142}}},
|
{Region: "CA Montreal", IPs: []net.IP{{199, 229, 249, 132}, {199, 229, 249, 134}, {199, 229, 249, 137}, {199, 229, 249, 142}, {199, 229, 249, 144}, {199, 229, 249, 146}, {199, 229, 249, 149}, {199, 229, 249, 151}, {199, 229, 249, 152}, {199, 229, 249, 155}, {199, 229, 249, 159}, {199, 229, 249, 165}, {199, 229, 249, 169}, {199, 229, 249, 172}, {199, 229, 249, 176}, {199, 229, 249, 182}, {199, 229, 249, 183}, {199, 229, 249, 184}, {199, 229, 249, 185}, {199, 229, 249, 191}}},
|
||||||
{Region: "CA Toronto", IPs: []net.IP{{172, 98, 67, 37}, {172, 98, 67, 41}, {172, 98, 67, 45}, {172, 98, 67, 47}, {172, 98, 67, 48}, {172, 98, 67, 55}, {172, 98, 67, 56}, {172, 98, 67, 61}, {172, 98, 67, 64}, {172, 98, 67, 65}, {172, 98, 67, 68}, {172, 98, 67, 71}, {172, 98, 67, 73}, {172, 98, 67, 81}, {172, 98, 67, 85}, {172, 98, 67, 89}, {172, 98, 67, 91}, {172, 98, 67, 93}, {172, 98, 67, 95}, {172, 98, 67, 99}}},
|
{Region: "CA Toronto", IPs: []net.IP{{172, 98, 67, 53}, {172, 98, 67, 71}, {172, 98, 67, 87}, {172, 98, 67, 100}}},
|
||||||
{Region: "CA Vancouver", IPs: []net.IP{{172, 83, 40, 107}}},
|
{Region: "CA Vancouver", IPs: []net.IP{{107, 181, 189, 71}, {107, 181, 189, 74}, {107, 181, 189, 75}, {107, 181, 189, 85}, {107, 181, 189, 86}, {172, 83, 40, 18}, {172, 83, 40, 20}, {172, 83, 40, 23}, {172, 83, 40, 24}, {172, 83, 40, 98}, {172, 83, 40, 99}, {172, 83, 40, 100}, {172, 83, 40, 101}, {172, 83, 40, 105}, {172, 83, 40, 106}, {172, 83, 40, 109}, {172, 83, 40, 110}, {172, 83, 40, 111}, {172, 83, 40, 113}, {172, 83, 40, 115}}},
|
||||||
{Region: "Czech Republic", IPs: []net.IP{{89, 238, 186, 226}, {89, 238, 186, 227}, {89, 238, 186, 228}, {89, 238, 186, 229}, {89, 238, 186, 230}, {185, 216, 35, 66}, {185, 216, 35, 67}, {185, 216, 35, 69}, {185, 216, 35, 70}, {185, 242, 6, 27}, {185, 242, 6, 28}, {185, 242, 6, 29}, {185, 242, 6, 30}}},
|
{Region: "Czech Republic", IPs: []net.IP{{89, 238, 186, 226}, {89, 238, 186, 227}, {89, 238, 186, 228}, {89, 238, 186, 230}, {185, 216, 35, 66}, {185, 216, 35, 67}, {185, 216, 35, 68}, {185, 216, 35, 69}, {185, 216, 35, 70}, {185, 242, 6, 26}, {185, 242, 6, 27}, {185, 242, 6, 28}, {185, 242, 6, 29}, {185, 242, 6, 30}}},
|
||||||
{Region: "DE Berlin", IPs: []net.IP{{185, 230, 127, 227}, {185, 230, 127, 228}, {185, 230, 127, 231}, {185, 230, 127, 232}, {185, 230, 127, 233}, {185, 230, 127, 234}, {185, 230, 127, 236}, {185, 230, 127, 239}, {185, 230, 127, 240}, {185, 230, 127, 241}, {193, 176, 86, 124}, {193, 176, 86, 130}, {193, 176, 86, 142}, {193, 176, 86, 146}, {193, 176, 86, 150}, {193, 176, 86, 154}, {193, 176, 86, 166}, {193, 176, 86, 174}, {193, 176, 86, 178}, {193, 176, 86, 182}}},
|
{Region: "DE Berlin", IPs: []net.IP{{185, 230, 127, 226}, {185, 230, 127, 229}, {185, 230, 127, 230}, {185, 230, 127, 233}, {185, 230, 127, 234}, {185, 230, 127, 235}, {185, 230, 127, 237}, {185, 230, 127, 239}, {185, 230, 127, 240}, {185, 230, 127, 242}, {185, 230, 127, 243}, {193, 176, 86, 122}, {193, 176, 86, 125}, {193, 176, 86, 134}, {193, 176, 86, 146}, {193, 176, 86, 150}, {193, 176, 86, 154}, {193, 176, 86, 162}, {193, 176, 86, 166}, {193, 176, 86, 174}}},
|
||||||
{Region: "DE Frankfurt", IPs: []net.IP{{185, 220, 70, 134}, {185, 220, 70, 135}, {185, 220, 70, 136}, {185, 220, 70, 139}, {185, 220, 70, 140}, {185, 220, 70, 141}, {185, 220, 70, 143}, {185, 220, 70, 144}, {185, 220, 70, 145}, {185, 220, 70, 147}, {185, 220, 70, 148}, {185, 220, 70, 152}, {185, 220, 70, 153}, {185, 220, 70, 155}, {185, 220, 70, 163}, {185, 220, 70, 164}, {185, 220, 70, 167}, {185, 220, 70, 170}, {185, 220, 70, 171}, {185, 220, 70, 173}}},
|
{Region: "DE Frankfurt", IPs: []net.IP{{185, 220, 70, 133}, {185, 220, 70, 134}, {185, 220, 70, 135}, {185, 220, 70, 136}, {185, 220, 70, 137}, {185, 220, 70, 138}, {185, 220, 70, 141}, {185, 220, 70, 143}, {185, 220, 70, 144}, {185, 220, 70, 147}, {185, 220, 70, 148}, {185, 220, 70, 149}, {185, 220, 70, 150}, {185, 220, 70, 152}, {185, 220, 70, 163}, {185, 220, 70, 167}, {185, 220, 70, 170}, {185, 220, 70, 171}, {185, 220, 70, 172}, {185, 220, 70, 173}}},
|
||||||
{Region: "Denmark", IPs: []net.IP{{82, 102, 20, 162}, {82, 102, 20, 163}, {82, 102, 20, 164}, {82, 102, 20, 165}, {82, 102, 20, 167}, {82, 102, 20, 168}, {82, 102, 20, 169}, {82, 102, 20, 170}, {82, 102, 20, 171}, {82, 102, 20, 172}, {82, 102, 20, 173}, {82, 102, 20, 174}, {82, 102, 20, 175}, {82, 102, 20, 178}, {82, 102, 20, 179}, {82, 102, 20, 180}, {82, 102, 20, 181}, {82, 102, 20, 182}, {82, 102, 20, 183}}},
|
{Region: "Denmark", IPs: []net.IP{{82, 102, 20, 162}, {82, 102, 20, 164}, {82, 102, 20, 165}, {82, 102, 20, 167}, {82, 102, 20, 169}, {82, 102, 20, 170}, {82, 102, 20, 171}, {82, 102, 20, 172}, {82, 102, 20, 173}, {82, 102, 20, 174}, {82, 102, 20, 175}, {82, 102, 20, 176}, {82, 102, 20, 177}, {82, 102, 20, 178}, {82, 102, 20, 179}, {82, 102, 20, 180}, {82, 102, 20, 181}, {82, 102, 20, 183}, {82, 102, 20, 184}, {82, 102, 20, 230}}},
|
||||||
{Region: "Finlan", IPs: []net.IP{{196, 244, 191, 2}, {196, 244, 191, 10}, {196, 244, 191, 42}, {196, 244, 191, 50}, {196, 244, 191, 58}, {196, 244, 191, 66}, {196, 244, 191, 74}, {196, 244, 191, 82}, {196, 244, 191, 90}, {196, 244, 191, 98}, {196, 244, 191, 106}, {196, 244, 191, 114}, {196, 244, 191, 138}, {196, 244, 191, 146}}},
|
{Region: "Finlan", IPs: []net.IP{{196, 244, 191, 2}, {196, 244, 191, 10}, {196, 244, 191, 18}, {196, 244, 191, 26}, {196, 244, 191, 34}, {196, 244, 191, 42}, {196, 244, 191, 50}, {196, 244, 191, 58}, {196, 244, 191, 66}, {196, 244, 191, 82}, {196, 244, 191, 90}, {196, 244, 191, 98}, {196, 244, 191, 106}, {196, 244, 191, 114}, {196, 244, 191, 122}, {196, 244, 191, 138}, {196, 244, 191, 146}}},
|
||||||
{Region: "France", IPs: []net.IP{{194, 187, 249, 35}, {194, 187, 249, 37}, {194, 187, 249, 39}, {194, 187, 249, 42}, {194, 187, 249, 45}, {194, 187, 249, 48}, {194, 187, 249, 49}, {194, 187, 249, 52}, {194, 187, 249, 53}, {194, 187, 249, 56}, {194, 187, 249, 59}, {194, 187, 249, 60}, {194, 187, 249, 61}, {194, 187, 249, 178}, {194, 187, 249, 179}, {194, 187, 249, 180}, {194, 187, 249, 183}, {194, 187, 249, 184}, {194, 187, 249, 187}, {194, 187, 249, 190}}},
|
{Region: "France", IPs: []net.IP{{194, 99, 106, 147}, {194, 99, 106, 148}, {194, 99, 106, 149}, {194, 187, 249, 35}, {194, 187, 249, 36}, {194, 187, 249, 37}, {194, 187, 249, 38}, {194, 187, 249, 44}, {194, 187, 249, 46}, {194, 187, 249, 50}, {194, 187, 249, 53}, {194, 187, 249, 57}, {194, 187, 249, 58}, {194, 187, 249, 60}, {194, 187, 249, 61}, {194, 187, 249, 62}, {194, 187, 249, 178}, {194, 187, 249, 183}, {194, 187, 249, 184}, {194, 187, 249, 186}}},
|
||||||
{Region: "Hong Kong", IPs: []net.IP{{84, 17, 37, 1}, {84, 17, 37, 45}, {119, 81, 135, 2}, {119, 81, 135, 28}, {119, 81, 135, 29}, {119, 81, 135, 47}, {119, 81, 135, 51}, {119, 81, 135, 53}, {119, 81, 253, 212}, {119, 81, 253, 218}, {119, 81, 253, 226}, {119, 81, 253, 227}, {119, 81, 253, 229}, {119, 81, 253, 230}, {119, 81, 253, 241}, {161, 202, 39, 202}, {161, 202, 39, 240}, {161, 202, 39, 251}, {161, 202, 44, 94}}},
|
{Region: "Hong Kong", IPs: []net.IP{{84, 17, 37, 23}, {84, 17, 37, 45}, {119, 81, 135, 5}, {119, 81, 135, 18}, {119, 81, 135, 26}, {119, 81, 135, 28}, {119, 81, 135, 29}, {119, 81, 135, 47}, {119, 81, 135, 51}, {119, 81, 135, 53}, {119, 81, 253, 214}, {119, 81, 253, 218}, {119, 81, 253, 229}, {119, 81, 253, 230}, {119, 81, 253, 241}, {119, 81, 253, 242}, {161, 202, 39, 202}, {161, 202, 39, 240}, {161, 202, 39, 251}, {161, 202, 44, 94}}},
|
||||||
{Region: "Hungary", IPs: []net.IP{{185, 128, 26, 18}, {185, 128, 26, 19}, {185, 128, 26, 20}, {185, 128, 26, 21}, {185, 128, 26, 22}, {185, 128, 26, 23}, {185, 128, 26, 24}, {185, 189, 114, 98}}},
|
{Region: "Hungary", IPs: []net.IP{{185, 128, 26, 18}, {185, 128, 26, 19}, {185, 128, 26, 20}, {185, 128, 26, 21}, {185, 128, 26, 22}, {185, 128, 26, 23}, {185, 128, 26, 24}, {185, 189, 114, 98}}},
|
||||||
{Region: "India", IPs: []net.IP{{150, 242, 12, 155}, {150, 242, 12, 171}, {150, 242, 12, 187}}},
|
{Region: "India", IPs: []net.IP{{150, 242, 12, 155}, {150, 242, 12, 171}, {150, 242, 12, 187}}},
|
||||||
{Region: "Ireland", IPs: []net.IP{{23, 92, 127, 2}, {23, 92, 127, 10}, {23, 92, 127, 18}, {23, 92, 127, 34}, {23, 92, 127, 42}, {23, 92, 127, 58}}},
|
{Region: "Ireland", IPs: []net.IP{{23, 92, 127, 2}, {23, 92, 127, 10}, {23, 92, 127, 18}, {23, 92, 127, 34}, {23, 92, 127, 42}, {23, 92, 127, 50}, {23, 92, 127, 58}, {23, 92, 127, 66}}},
|
||||||
{Region: "Israel", IPs: []net.IP{{31, 168, 172, 136}, {31, 168, 172, 142}, {31, 168, 172, 143}, {31, 168, 172, 145}, {31, 168, 172, 147}}},
|
{Region: "Israel", IPs: []net.IP{{31, 168, 172, 136}, {31, 168, 172, 142}, {31, 168, 172, 143}, {31, 168, 172, 145}, {31, 168, 172, 146}, {31, 168, 172, 147}}},
|
||||||
{Region: "Italy", IPs: []net.IP{{82, 102, 21, 98}, {82, 102, 21, 210}, {82, 102, 21, 211}, {82, 102, 21, 212}, {82, 102, 21, 213}, {82, 102, 21, 214}, {82, 102, 21, 215}, {82, 102, 21, 216}, {82, 102, 21, 217}, {82, 102, 21, 218}, {82, 102, 21, 219}}},
|
{Region: "Italy", IPs: []net.IP{{82, 102, 21, 98}, {82, 102, 21, 210}, {82, 102, 21, 212}, {82, 102, 21, 213}, {82, 102, 21, 214}, {82, 102, 21, 215}, {82, 102, 21, 216}, {82, 102, 21, 217}, {82, 102, 21, 218}, {82, 102, 21, 219}}},
|
||||||
{Region: "Japan", IPs: []net.IP{{103, 208, 220, 135}, {103, 208, 220, 136}, {103, 208, 220, 138}, {103, 208, 220, 139}, {103, 208, 220, 141}}},
|
{Region: "Japan", IPs: []net.IP{{103, 208, 220, 130}, {103, 208, 220, 131}, {103, 208, 220, 132}, {103, 208, 220, 133}, {103, 208, 220, 134}, {103, 208, 220, 135}, {103, 208, 220, 136}, {103, 208, 220, 137}, {103, 208, 220, 138}, {103, 208, 220, 139}, {103, 208, 220, 140}, {103, 208, 220, 141}, {103, 208, 220, 142}, {103, 208, 220, 143}}},
|
||||||
{Region: "Luxembourg", IPs: []net.IP{{92, 223, 89, 133}, {92, 223, 89, 134}, {92, 223, 89, 135}, {92, 223, 89, 136}, {92, 223, 89, 137}, {92, 223, 89, 138}, {92, 223, 89, 140}, {92, 223, 89, 142}}},
|
{Region: "Luxembourg", IPs: []net.IP{{92, 223, 89, 133}, {92, 223, 89, 134}, {92, 223, 89, 135}, {92, 223, 89, 136}, {92, 223, 89, 137}, {92, 223, 89, 138}, {92, 223, 89, 140}, {92, 223, 89, 142}}},
|
||||||
{Region: "Mexico", IPs: []net.IP{{169, 57, 0, 197}, {169, 57, 0, 200}, {169, 57, 0, 203}, {169, 57, 0, 205}, {169, 57, 0, 207}, {169, 57, 0, 210}, {169, 57, 0, 211}, {169, 57, 0, 212}, {169, 57, 0, 213}, {169, 57, 0, 217}, {169, 57, 0, 218}, {169, 57, 0, 221}, {169, 57, 0, 229}, {169, 57, 0, 230}, {169, 57, 0, 233}, {169, 57, 0, 236}, {169, 57, 0, 238}, {169, 57, 0, 243}, {169, 57, 0, 247}, {169, 57, 0, 248}}},
|
{Region: "Mexico", IPs: []net.IP{{169, 57, 0, 197}, {169, 57, 0, 200}, {169, 57, 0, 203}, {169, 57, 0, 205}, {169, 57, 0, 207}, {169, 57, 0, 210}, {169, 57, 0, 211}, {169, 57, 0, 212}, {169, 57, 0, 213}, {169, 57, 0, 217}, {169, 57, 0, 218}, {169, 57, 0, 221}, {169, 57, 0, 229}, {169, 57, 0, 230}, {169, 57, 0, 233}, {169, 57, 0, 236}, {169, 57, 0, 238}, {169, 57, 0, 243}, {169, 57, 0, 247}, {169, 57, 0, 248}}},
|
||||||
{Region: "Netherlands", IPs: []net.IP{{46, 166, 138, 145}, {46, 166, 138, 146}, {46, 166, 138, 155}, {46, 166, 138, 162}, {46, 166, 186, 248}, {46, 166, 188, 208}, {46, 166, 188, 210}, {46, 166, 188, 215}, {46, 166, 190, 178}, {46, 166, 190, 185}, {46, 166, 190, 186}, {46, 166, 190, 195}, {46, 166, 190, 230}, {109, 201, 138, 239}, {109, 201, 152, 5}, {109, 201, 152, 26}, {109, 201, 152, 227}, {109, 201, 154, 141}, {109, 201, 154, 142}, {185, 107, 44, 25}}},
|
{Region: "Netherlands", IPs: []net.IP{{46, 166, 137, 219}, {46, 166, 138, 131}, {46, 166, 186, 218}, {46, 166, 186, 238}, {46, 166, 186, 249}, {46, 166, 188, 214}, {46, 166, 188, 241}, {46, 166, 190, 215}, {85, 159, 236, 219}, {109, 201, 152, 15}, {109, 201, 152, 16}, {109, 201, 152, 25}, {109, 201, 152, 238}, {109, 201, 154, 147}}},
|
||||||
{Region: "New Zealand", IPs: []net.IP{{43, 250, 207, 3}}},
|
{Region: "New Zealand", IPs: []net.IP{{43, 250, 207, 3}, {43, 250, 207, 7}}},
|
||||||
{Region: "Norway", IPs: []net.IP{{82, 102, 27, 50}, {82, 102, 27, 51}, {82, 102, 27, 52}, {82, 102, 27, 53}, {82, 102, 27, 54}, {82, 102, 27, 56}, {82, 102, 27, 74}, {82, 102, 27, 75}, {82, 102, 27, 76}, {82, 102, 27, 77}, {82, 102, 27, 78}, {82, 102, 27, 114}, {82, 102, 27, 117}, {82, 102, 27, 118}, {82, 102, 27, 125}, {82, 102, 27, 126}, {185, 206, 225, 222}, {185, 253, 97, 226}, {185, 253, 97, 227}, {185, 253, 97, 228}}},
|
{Region: "Norway", IPs: []net.IP{{82, 102, 27, 50}, {82, 102, 27, 51}, {82, 102, 27, 52}, {82, 102, 27, 53}, {82, 102, 27, 55}, {82, 102, 27, 56}, {82, 102, 27, 57}, {82, 102, 27, 74}, {82, 102, 27, 77}, {82, 102, 27, 78}, {82, 102, 27, 114}, {82, 102, 27, 115}, {82, 102, 27, 116}, {82, 102, 27, 117}, {82, 102, 27, 124}, {82, 102, 27, 125}, {82, 102, 27, 126}, {185, 206, 225, 222}, {185, 253, 97, 227}, {185, 253, 97, 228}}},
|
||||||
{Region: "Poland", IPs: []net.IP{{185, 244, 214, 14}, {185, 244, 214, 194}, {185, 244, 214, 196}, {185, 244, 214, 197}, {185, 244, 214, 198}, {185, 244, 214, 199}, {185, 244, 214, 200}}},
|
{Region: "Poland", IPs: []net.IP{{185, 244, 214, 14}, {185, 244, 214, 194}, {185, 244, 214, 196}, {185, 244, 214, 197}, {185, 244, 214, 198}, {185, 244, 214, 199}, {185, 244, 214, 200}}},
|
||||||
{Region: "Romania", IPs: []net.IP{{86, 105, 25, 66}, {86, 105, 25, 67}, {86, 105, 25, 68}, {86, 105, 25, 69}, {86, 105, 25, 70}, {86, 105, 25, 74}, {86, 105, 25, 75}, {86, 105, 25, 76}, {86, 105, 25, 77}, {86, 105, 25, 78}, {89, 33, 8, 42}, {94, 176, 148, 34}, {94, 176, 148, 35}, {185, 45, 12, 126}, {185, 210, 218, 100}, {185, 210, 218, 103}}},
|
{Region: "Romania", IPs: []net.IP{{86, 105, 25, 66}, {86, 105, 25, 67}, {86, 105, 25, 68}, {86, 105, 25, 69}, {86, 105, 25, 70}, {86, 105, 25, 74}, {86, 105, 25, 75}, {86, 105, 25, 76}, {86, 105, 25, 77}, {86, 105, 25, 78}, {94, 176, 148, 34}, {185, 45, 12, 126}, {185, 210, 218, 98}, {185, 210, 218, 99}, {185, 210, 218, 100}, {185, 210, 218, 101}, {185, 210, 218, 104}, {185, 210, 218, 105}, {185, 210, 218, 108}}},
|
||||||
{Region: "Singapore", IPs: []net.IP{{37, 120, 208, 66}, {37, 120, 208, 67}, {37, 120, 208, 68}, {37, 120, 208, 70}, {37, 120, 208, 71}, {37, 120, 208, 72}, {37, 120, 208, 73}, {37, 120, 208, 74}, {37, 120, 208, 75}, {37, 120, 208, 76}, {37, 120, 208, 77}, {37, 120, 208, 78}, {37, 120, 208, 79}, {37, 120, 208, 80}, {37, 120, 208, 81}, {37, 120, 208, 82}, {37, 120, 208, 83}}},
|
{Region: "Singapore", IPs: []net.IP{{37, 120, 208, 66}, {37, 120, 208, 67}, {37, 120, 208, 68}, {37, 120, 208, 70}, {37, 120, 208, 72}, {37, 120, 208, 73}, {37, 120, 208, 74}, {37, 120, 208, 75}, {37, 120, 208, 76}, {37, 120, 208, 77}, {37, 120, 208, 78}, {37, 120, 208, 79}, {37, 120, 208, 81}, {37, 120, 208, 82}, {37, 120, 208, 83}}},
|
||||||
{Region: "Spain", IPs: []net.IP{{37, 120, 148, 86}, {185, 230, 124, 50}, {185, 230, 124, 51}, {185, 230, 124, 52}, {185, 230, 124, 53}, {185, 230, 124, 54}, {194, 99, 104, 26}, {194, 99, 104, 27}, {194, 99, 104, 28}, {194, 99, 104, 29}, {194, 99, 104, 30}, {195, 206, 107, 250}}},
|
{Region: "Spain", IPs: []net.IP{{185, 230, 124, 53}, {194, 99, 104, 26}, {194, 99, 104, 30}}},
|
||||||
{Region: "Sweden", IPs: []net.IP{{45, 12, 220, 163}, {45, 12, 220, 168}, {45, 12, 220, 169}, {45, 12, 220, 173}, {45, 12, 220, 178}, {45, 12, 220, 180}, {45, 12, 220, 184}, {45, 12, 220, 190}, {45, 12, 220, 194}, {45, 12, 220, 197}, {45, 12, 220, 204}, {45, 12, 220, 205}, {45, 12, 220, 215}, {45, 12, 220, 218}, {45, 12, 220, 227}, {45, 12, 220, 233}, {45, 12, 220, 240}, {45, 12, 220, 254}, {45, 83, 91, 21}, {45, 83, 91, 36}}},
|
{Region: "Sweden", IPs: []net.IP{{45, 12, 220, 182}, {45, 12, 220, 183}, {45, 12, 220, 194}, {45, 12, 220, 195}, {45, 12, 220, 203}, {45, 12, 220, 206}, {45, 12, 220, 209}, {45, 12, 220, 217}, {45, 12, 220, 228}, {45, 12, 220, 234}, {45, 12, 220, 240}, {45, 12, 220, 243}, {45, 12, 220, 245}, {45, 12, 220, 248}, {45, 12, 220, 250}, {45, 12, 220, 253}}},
|
||||||
{Region: "Switzerland", IPs: []net.IP{{82, 102, 24, 171}, {82, 102, 24, 250}, {82, 102, 24, 252}, {91, 132, 136, 52}, {91, 132, 136, 54}, {91, 132, 136, 210}, {185, 156, 175, 82}, {185, 156, 175, 88}, {185, 156, 175, 90}, {185, 156, 175, 94}, {185, 212, 170, 179}, {185, 212, 170, 182}, {185, 212, 170, 187}, {185, 230, 125, 34}, {185, 230, 125, 36}, {185, 230, 125, 45}, {185, 230, 125, 48}, {185, 230, 125, 52}, {185, 230, 125, 90}, {212, 102, 36, 1}}},
|
{Region: "Switzerland", IPs: []net.IP{{82, 102, 24, 174}, {82, 102, 24, 250}, {91, 132, 136, 42}, {91, 132, 136, 43}, {91, 132, 136, 52}, {185, 156, 175, 83}, {185, 156, 175, 84}, {185, 156, 175, 85}, {185, 156, 175, 91}, {185, 156, 175, 92}, {185, 156, 175, 93}, {185, 230, 125, 36}, {185, 230, 125, 46}, {185, 230, 125, 48}, {185, 230, 125, 50}, {185, 230, 125, 52}, {185, 230, 125, 86}, {185, 230, 125, 90}, {195, 206, 105, 210}, {212, 102, 36, 1}}},
|
||||||
{Region: "UAE", IPs: []net.IP{{45, 9, 250, 42}, {45, 9, 250, 46}, {45, 9, 250, 62}}},
|
{Region: "UAE", IPs: []net.IP{{45, 9, 250, 42}, {45, 9, 250, 46}, {45, 9, 250, 62}}},
|
||||||
{Region: "UK London", IPs: []net.IP{{89, 238, 150, 9}, {89, 238, 150, 11}, {89, 238, 150, 15}, {89, 238, 150, 20}, {89, 238, 154, 18}, {89, 238, 154, 20}, {89, 238, 154, 23}, {89, 238, 154, 120}, {89, 238, 154, 121}, {89, 238, 154, 162}, {89, 238, 154, 167}, {89, 238, 154, 174}, {89, 238, 154, 179}, {89, 238, 154, 236}, {89, 238, 154, 243}, {89, 238, 154, 245}, {89, 238, 154, 249}, {89, 238, 154, 250}, {89, 238, 154, 251}, {89, 238, 154, 254}}},
|
{Region: "UK London", IPs: []net.IP{{89, 238, 150, 7}, {89, 238, 150, 13}, {89, 238, 150, 18}, {89, 238, 154, 18}, {89, 238, 154, 19}, {89, 238, 154, 20}, {89, 238, 154, 24}, {89, 238, 154, 115}, {89, 238, 154, 118}, {89, 238, 154, 120}, {89, 238, 154, 165}, {89, 238, 154, 166}, {89, 238, 154, 171}, {89, 238, 154, 233}, {89, 238, 154, 238}, {89, 238, 154, 243}, {89, 238, 154, 245}, {89, 238, 154, 250}, {89, 238, 154, 251}, {89, 238, 154, 254}}},
|
||||||
{Region: "UK Manchester", IPs: []net.IP{{89, 238, 137, 36}, {89, 238, 137, 37}, {89, 238, 137, 38}, {89, 238, 137, 39}, {89, 238, 137, 40}, {89, 238, 137, 41}, {89, 238, 139, 4}, {89, 238, 139, 5}, {89, 238, 139, 7}, {89, 238, 139, 8}, {89, 238, 139, 9}, {89, 238, 139, 10}, {89, 238, 139, 11}, {89, 238, 139, 13}, {89, 238, 139, 53}, {89, 238, 139, 55}, {89, 238, 139, 56}, {89, 238, 139, 57}, {89, 238, 139, 58}, {89, 249, 67, 220}}},
|
{Region: "UK Manchester", IPs: []net.IP{{89, 238, 137, 36}, {89, 238, 137, 37}, {89, 238, 137, 39}, {89, 238, 137, 40}, {89, 238, 137, 42}, {89, 238, 139, 4}, {89, 238, 139, 5}, {89, 238, 139, 6}, {89, 238, 139, 8}, {89, 238, 139, 9}, {89, 238, 139, 10}, {89, 238, 139, 11}, {89, 238, 139, 12}, {89, 238, 139, 13}, {89, 238, 139, 52}, {89, 238, 139, 54}, {89, 238, 139, 55}, {89, 238, 139, 57}, {89, 238, 139, 58}, {89, 249, 67, 220}}},
|
||||||
{Region: "UK Southampton", IPs: []net.IP{{31, 24, 226, 141}, {31, 24, 226, 145}, {31, 24, 226, 146}, {31, 24, 226, 205}, {31, 24, 226, 207}, {31, 24, 226, 208}, {31, 24, 226, 209}, {31, 24, 226, 217}, {31, 24, 226, 220}, {31, 24, 226, 223}, {31, 24, 226, 225}, {31, 24, 226, 226}, {31, 24, 226, 228}, {31, 24, 226, 232}, {31, 24, 226, 233}, {31, 24, 226, 234}, {31, 24, 226, 237}, {31, 24, 226, 244}, {31, 24, 226, 245}, {31, 24, 231, 197}}},
|
{Region: "UK Southampton", IPs: []net.IP{{31, 24, 226, 134}, {31, 24, 226, 188}, {31, 24, 226, 189}, {31, 24, 226, 202}, {31, 24, 226, 204}, {31, 24, 226, 205}, {31, 24, 226, 209}, {31, 24, 226, 220}, {31, 24, 226, 222}, {31, 24, 226, 226}, {31, 24, 226, 227}, {31, 24, 226, 228}, {31, 24, 226, 230}, {31, 24, 226, 234}, {31, 24, 226, 237}, {31, 24, 226, 240}, {31, 24, 226, 241}, {31, 24, 226, 244}, {31, 24, 226, 245}, {31, 24, 226, 246}}},
|
||||||
{Region: "US Atlanta", IPs: []net.IP{{66, 115, 168, 2}, {66, 115, 168, 4}, {66, 115, 168, 7}, {66, 115, 168, 10}, {66, 115, 168, 13}, {66, 115, 168, 17}, {66, 115, 168, 19}, {66, 115, 168, 21}, {66, 115, 168, 23}, {66, 115, 168, 26}, {66, 115, 168, 27}, {66, 115, 168, 28}, {66, 115, 169, 198}, {66, 115, 169, 202}, {66, 115, 169, 204}, {66, 115, 169, 226}, {66, 115, 169, 229}, {66, 115, 169, 231}, {66, 115, 169, 242}, {66, 115, 169, 244}}},
|
{Region: "US Atlanta", IPs: []net.IP{{156, 146, 46, 1}, {156, 146, 46, 198}}},
|
||||||
{Region: "US California", IPs: []net.IP{{91, 207, 175, 46}, {91, 207, 175, 62}, {91, 207, 175, 100}, {91, 207, 175, 102}, {91, 207, 175, 115}, {91, 207, 175, 121}, {91, 207, 175, 170}, {91, 207, 175, 181}, {91, 207, 175, 204}, {91, 207, 175, 206}, {91, 207, 175, 213}, {91, 207, 175, 226}, {91, 207, 175, 242}, {91, 207, 175, 250}, {91, 207, 175, 252}, {185, 245, 87, 181}, {185, 245, 87, 197}, {185, 245, 87, 215}, {212, 103, 49, 164}, {212, 103, 49, 168}}},
|
{Region: "US California", IPs: []net.IP{{91, 207, 175, 38}, {91, 207, 175, 42}, {91, 207, 175, 55}, {91, 207, 175, 60}, {91, 207, 175, 71}, {91, 207, 175, 109}, {91, 207, 175, 110}, {91, 207, 175, 118}, {91, 207, 175, 125}, {91, 207, 175, 163}, {91, 207, 175, 172}, {91, 207, 175, 182}, {91, 207, 175, 204}, {91, 207, 175, 205}, {91, 207, 175, 234}, {185, 245, 87, 170}, {185, 245, 87, 181}, {185, 245, 87, 195}, {185, 245, 87, 199}, {185, 245, 87, 220}}},
|
||||||
{Region: "US Chicago", IPs: []net.IP{{104, 200, 153, 97}, {199, 116, 115, 130}, {199, 116, 115, 131}, {199, 116, 115, 132}, {199, 116, 115, 133}, {199, 116, 115, 134}, {199, 116, 115, 135}, {199, 116, 115, 136}, {199, 116, 115, 137}, {199, 116, 115, 138}, {199, 116, 115, 139}, {199, 116, 115, 140}, {199, 116, 115, 141}, {199, 116, 115, 142}, {199, 116, 115, 143}, {199, 116, 115, 144}, {199, 116, 115, 145}, {199, 116, 115, 146}, {199, 116, 115, 147}, {199, 116, 115, 148}}},
|
{Region: "US Chicago", IPs: []net.IP{{156, 146, 50, 65}, {156, 146, 50, 134}, {156, 146, 50, 198}, {156, 146, 51, 11}, {212, 102, 58, 113}, {212, 102, 59, 54}}},
|
||||||
{Region: "US Denver", IPs: []net.IP{{174, 128, 225, 106}, {174, 128, 225, 186}, {174, 128, 226, 18}, {174, 128, 227, 226}, {174, 128, 236, 98}, {174, 128, 236, 106}, {174, 128, 242, 234}, {174, 128, 244, 74}, {174, 128, 245, 106}, {198, 148, 82, 82}, {198, 148, 90, 58}, {199, 115, 98, 146}, {199, 115, 98, 154}, {199, 115, 99, 218}}},
|
{Region: "US Denver", IPs: []net.IP{{174, 128, 225, 186}, {174, 128, 226, 18}, {174, 128, 236, 98}, {174, 128, 242, 234}, {174, 128, 243, 98}, {174, 128, 243, 106}, {174, 128, 244, 66}, {174, 128, 244, 74}, {174, 128, 245, 106}, {174, 128, 245, 122}, {174, 128, 250, 18}, {174, 128, 250, 26}, {198, 148, 90, 58}, {199, 115, 97, 202}, {199, 115, 98, 154}, {199, 115, 99, 82}, {199, 115, 99, 218}, {199, 115, 101, 178}, {199, 115, 101, 186}, {199, 115, 103, 10}}},
|
||||||
{Region: "US East", IPs: []net.IP{{193, 37, 253, 38}, {193, 37, 253, 115}, {194, 59, 251, 6}, {194, 59, 251, 13}, {194, 59, 251, 14}, {194, 59, 251, 17}, {194, 59, 251, 28}, {194, 59, 251, 29}, {194, 59, 251, 58}, {194, 59, 251, 66}, {194, 59, 251, 74}, {194, 59, 251, 81}, {194, 59, 251, 104}, {194, 59, 251, 111}, {194, 59, 251, 112}, {194, 59, 251, 149}, {194, 59, 251, 166}, {194, 59, 251, 216}, {194, 59, 251, 227}, {194, 59, 251, 240}}},
|
{Region: "US East", IPs: []net.IP{{193, 37, 253, 38}, {193, 37, 253, 86}, {194, 59, 251, 7}, {194, 59, 251, 13}, {194, 59, 251, 22}, {194, 59, 251, 48}, {194, 59, 251, 59}, {194, 59, 251, 103}, {194, 59, 251, 131}, {194, 59, 251, 133}, {194, 59, 251, 136}, {194, 59, 251, 137}, {194, 59, 251, 152}, {194, 59, 251, 169}, {194, 59, 251, 174}, {194, 59, 251, 190}, {194, 59, 251, 213}, {194, 59, 251, 219}, {194, 59, 251, 233}, {194, 59, 251, 239}}},
|
||||||
{Region: "US Florida", IPs: []net.IP{{193, 37, 252, 3}, {193, 37, 252, 12}, {193, 37, 252, 41}, {193, 37, 252, 45}, {193, 37, 252, 46}, {193, 37, 252, 52}, {193, 37, 252, 54}, {193, 37, 252, 55}, {193, 37, 252, 56}, {193, 37, 252, 58}, {193, 37, 252, 59}, {193, 37, 252, 75}, {193, 37, 252, 76}, {193, 37, 252, 102}, {193, 37, 252, 108}, {193, 37, 252, 115}, {193, 37, 252, 116}, {193, 37, 252, 118}, {193, 37, 252, 170}, {193, 37, 252, 174}}},
|
{Region: "US Florida", IPs: []net.IP{{193, 37, 252, 7}, {193, 37, 252, 8}, {193, 37, 252, 9}, {193, 37, 252, 17}, {193, 37, 252, 19}, {193, 37, 252, 34}, {193, 37, 252, 39}, {193, 37, 252, 45}, {193, 37, 252, 58}, {193, 37, 252, 59}, {193, 37, 252, 67}, {193, 37, 252, 68}, {193, 37, 252, 76}, {193, 37, 252, 82}, {193, 37, 252, 106}, {193, 37, 252, 115}, {193, 37, 252, 116}, {193, 37, 252, 117}, {193, 37, 252, 125}, {193, 37, 252, 126}}},
|
||||||
{Region: "US Houston", IPs: []net.IP{{74, 81, 88, 18}, {74, 81, 88, 26}, {74, 81, 88, 66}, {74, 81, 88, 82}, {74, 81, 88, 114}, {74, 81, 88, 130}, {74, 81, 88, 162}, {205, 251, 148, 34}, {205, 251, 148, 66}, {205, 251, 148, 82}, {205, 251, 148, 98}, {205, 251, 148, 130}, {205, 251, 148, 178}, {205, 251, 150, 146}, {205, 251, 150, 154}, {205, 251, 150, 162}, {205, 251, 150, 170}, {205, 251, 150, 194}, {205, 251, 150, 218}, {205, 251, 150, 234}}},
|
{Region: "US Houston", IPs: []net.IP{{74, 81, 88, 18}, {74, 81, 88, 26}, {74, 81, 88, 42}, {74, 81, 88, 58}, {74, 81, 88, 66}, {74, 81, 88, 82}, {74, 81, 88, 90}, {74, 81, 88, 114}, {74, 81, 88, 162}, {205, 251, 148, 50}, {205, 251, 148, 58}, {205, 251, 148, 98}, {205, 251, 148, 138}, {205, 251, 148, 178}, {205, 251, 150, 154}, {205, 251, 150, 162}, {205, 251, 150, 194}, {205, 251, 150, 218}, {205, 251, 150, 226}, {205, 251, 151, 26}}},
|
||||||
{Region: "US Las Vegas", IPs: []net.IP{{162, 251, 236, 2}, {162, 251, 236, 3}, {162, 251, 236, 4}, {162, 251, 236, 5}, {162, 251, 236, 7}, {162, 251, 236, 8}, {162, 251, 236, 9}, {199, 127, 56, 82}, {199, 127, 56, 83}, {199, 127, 56, 84}, {199, 127, 56, 86}, {199, 127, 56, 88}, {199, 127, 56, 89}, {199, 127, 56, 91}, {199, 127, 56, 114}, {199, 127, 56, 115}, {199, 127, 56, 118}, {199, 127, 56, 119}, {199, 127, 56, 120}, {199, 127, 56, 121}}},
|
{Region: "US Las Vegas", IPs: []net.IP{{162, 251, 236, 2}, {162, 251, 236, 3}, {162, 251, 236, 4}, {162, 251, 236, 7}, {162, 251, 236, 8}, {162, 251, 236, 9}, {199, 127, 56, 83}, {199, 127, 56, 84}, {199, 127, 56, 86}, {199, 127, 56, 87}, {199, 127, 56, 88}, {199, 127, 56, 89}, {199, 127, 56, 91}, {199, 127, 56, 114}, {199, 127, 56, 115}, {199, 127, 56, 116}, {199, 127, 56, 117}, {199, 127, 56, 118}, {199, 127, 56, 119}, {199, 127, 56, 120}}},
|
||||||
{Region: "US New York City", IPs: []net.IP{{107, 182, 231, 24}, {107, 182, 231, 34}, {173, 244, 223, 122}, {209, 95, 50, 13}, {209, 95, 50, 17}, {209, 95, 50, 18}, {209, 95, 50, 27}, {209, 95, 50, 49}, {209, 95, 50, 50}, {209, 95, 50, 56}, {209, 95, 50, 84}, {209, 95, 50, 87}, {209, 95, 50, 89}, {209, 95, 50, 93}, {209, 95, 50, 134}, {209, 95, 50, 139}, {209, 95, 50, 147}, {209, 95, 50, 148}, {209, 95, 50, 162}, {209, 95, 50, 163}}},
|
{Region: "US New York City", IPs: []net.IP{{107, 182, 230, 194}, {107, 182, 231, 24}, {107, 182, 231, 30}, {107, 182, 231, 34}, {107, 182, 231, 37}, {107, 182, 231, 38}, {107, 182, 231, 51}, {209, 95, 50, 12}, {209, 95, 50, 27}, {209, 95, 50, 50}, {209, 95, 50, 65}, {209, 95, 50, 66}, {209, 95, 50, 90}, {209, 95, 50, 93}, {209, 95, 50, 103}, {209, 95, 50, 104}, {209, 95, 50, 133}, {209, 95, 50, 144}, {209, 95, 50, 146}, {209, 95, 50, 162}}},
|
||||||
{Region: "US Seattle", IPs: []net.IP{{104, 200, 154, 12}, {104, 200, 154, 38}, {104, 200, 154, 39}, {104, 200, 154, 50}, {104, 200, 154, 65}, {104, 200, 154, 66}, {104, 200, 154, 68}, {104, 200, 154, 70}, {104, 200, 154, 72}, {104, 200, 154, 73}, {104, 200, 154, 74}, {104, 200, 154, 75}, {104, 200, 154, 78}, {104, 200, 154, 79}, {104, 200, 154, 84}, {104, 200, 154, 86}, {104, 200, 154, 88}, {104, 200, 154, 90}, {104, 200, 154, 91}, {104, 200, 154, 98}}},
|
{Region: "US Seattle", IPs: []net.IP{{104, 200, 154, 11}, {104, 200, 154, 21}, {104, 200, 154, 22}, {104, 200, 154, 44}, {104, 200, 154, 47}, {104, 200, 154, 56}, {104, 200, 154, 59}, {104, 200, 154, 62}, {104, 200, 154, 66}, {104, 200, 154, 67}, {104, 200, 154, 70}, {104, 200, 154, 81}, {104, 200, 154, 84}, {104, 200, 154, 87}, {104, 200, 154, 90}, {104, 200, 154, 91}, {104, 200, 154, 96}, {104, 200, 154, 97}, {104, 200, 154, 98}, {104, 200, 154, 99}}},
|
||||||
{Region: "US Silicon Valley", IPs: []net.IP{{199, 116, 118, 131}, {199, 116, 118, 132}, {199, 116, 118, 133}, {199, 116, 118, 137}, {199, 116, 118, 140}, {199, 116, 118, 155}, {199, 116, 118, 156}, {199, 116, 118, 170}, {199, 116, 118, 173}, {199, 116, 118, 178}, {199, 116, 118, 184}, {199, 116, 118, 201}, {199, 116, 118, 202}, {199, 116, 118, 209}, {199, 116, 118, 210}, {199, 116, 118, 228}, {199, 116, 118, 237}, {199, 116, 118, 238}, {199, 116, 118, 244}, {199, 116, 118, 250}}},
|
{Region: "US Silicon Valley", IPs: []net.IP{{199, 116, 118, 130}, {199, 116, 118, 133}, {199, 116, 118, 137}, {199, 116, 118, 145}, {199, 116, 118, 159}, {199, 116, 118, 160}, {199, 116, 118, 178}, {199, 116, 118, 181}, {199, 116, 118, 182}, {199, 116, 118, 202}, {199, 116, 118, 205}, {199, 116, 118, 209}, {199, 116, 118, 211}, {199, 116, 118, 213}, {199, 116, 118, 217}, {199, 116, 118, 218}, {199, 116, 118, 236}, {199, 116, 118, 238}, {199, 116, 118, 244}, {199, 116, 118, 252}}},
|
||||||
{Region: "US Texas", IPs: []net.IP{{162, 216, 46, 5}, {162, 216, 46, 10}, {162, 216, 46, 14}, {162, 216, 46, 18}, {162, 216, 46, 36}, {162, 216, 46, 38}, {162, 216, 46, 39}, {162, 216, 46, 42}, {162, 216, 46, 58}, {162, 216, 46, 71}, {162, 216, 46, 82}, {162, 216, 46, 85}, {162, 216, 46, 104}, {162, 216, 46, 105}, {162, 216, 46, 132}, {162, 216, 46, 138}, {162, 216, 46, 150}, {162, 216, 46, 151}, {162, 216, 46, 153}, {162, 216, 46, 170}}},
|
{Region: "US Texas", IPs: []net.IP{{162, 216, 46, 33}, {162, 216, 46, 40}, {162, 216, 46, 44}, {162, 216, 46, 57}, {162, 216, 46, 58}, {162, 216, 46, 70}, {162, 216, 46, 81}, {162, 216, 46, 96}, {162, 216, 46, 101}, {162, 216, 46, 112}, {162, 216, 46, 119}, {162, 216, 46, 123}, {162, 216, 46, 129}, {162, 216, 46, 132}, {162, 216, 46, 133}, {162, 216, 46, 141}, {162, 216, 46, 148}, {162, 216, 46, 154}, {162, 216, 46, 156}, {162, 216, 46, 168}}},
|
||||||
{Region: "US Washington DC", IPs: []net.IP{{70, 32, 0, 24}, {70, 32, 0, 30}, {70, 32, 0, 54}, {70, 32, 0, 64}, {70, 32, 0, 68}, {70, 32, 0, 77}, {70, 32, 0, 111}, {70, 32, 0, 120}, {70, 32, 0, 121}, {70, 32, 0, 137}, {70, 32, 0, 153}, {70, 32, 0, 155}, {70, 32, 0, 165}, {70, 32, 0, 166}, {70, 32, 0, 167}, {70, 32, 0, 170}, {70, 32, 0, 172}, {70, 32, 0, 177}, {70, 32, 0, 178}, {70, 32, 0, 179}}},
|
{Region: "US Washington DC", IPs: []net.IP{{70, 32, 0, 24}, {70, 32, 0, 46}, {70, 32, 0, 53}, {70, 32, 0, 55}, {70, 32, 0, 61}, {70, 32, 0, 74}, {70, 32, 0, 97}, {70, 32, 0, 103}, {70, 32, 0, 104}, {70, 32, 0, 133}, {70, 32, 0, 135}, {70, 32, 0, 140}, {70, 32, 0, 153}, {70, 32, 0, 155}, {70, 32, 0, 166}, {70, 32, 0, 167}, {70, 32, 0, 168}, {70, 32, 0, 172}, {70, 32, 0, 177}, {70, 32, 0, 179}}},
|
||||||
{Region: "US West", IPs: []net.IP{{104, 200, 151, 3}, {104, 200, 151, 11}, {104, 200, 151, 14}, {104, 200, 151, 15}, {104, 200, 151, 21}, {104, 200, 151, 28}, {104, 200, 151, 29}, {104, 200, 151, 34}, {104, 200, 151, 36}, {104, 200, 151, 42}, {104, 200, 151, 44}, {104, 200, 151, 47}, {104, 200, 151, 50}, {104, 200, 151, 51}, {104, 200, 151, 54}, {104, 200, 151, 60}, {104, 200, 151, 72}, {104, 200, 151, 75}, {104, 200, 151, 77}, {104, 200, 151, 78}}},
|
{Region: "US West", IPs: []net.IP{{104, 200, 151, 4}, {104, 200, 151, 10}, {104, 200, 151, 11}, {104, 200, 151, 14}, {104, 200, 151, 15}, {104, 200, 151, 17}, {104, 200, 151, 18}, {104, 200, 151, 21}, {104, 200, 151, 26}, {104, 200, 151, 30}, {104, 200, 151, 34}, {104, 200, 151, 42}, {104, 200, 151, 48}, {104, 200, 151, 54}, {104, 200, 151, 55}, {104, 200, 151, 73}, {104, 200, 151, 78}, {104, 200, 151, 82}, {104, 200, 151, 84}, {104, 200, 151, 86}}},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
198
internal/constants/purevpn.go
Normal file
198
internal/constants/purevpn.go
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
package constants
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PurevpnCertificateAuthority = "MIIE6DCCA9CgAwIBAgIJAMjXFoeo5uSlMA0GCSqGSIb3DQEBCwUAMIGoMQswCQYDVQQGEwJISzEQMA4GA1UECBMHQ2VudHJhbDELMAkGA1UEBxMCSEsxGDAWBgNVBAoTD1NlY3VyZS1TZXJ2ZXJDQTELMAkGA1UECxMCSVQxGDAWBgNVBAMTD1NlY3VyZS1TZXJ2ZXJDQTEYMBYGA1UEKRMPU2VjdXJlLVNlcnZlckNBMR8wHQYJKoZIhvcNAQkBFhBtYWlsQGhvc3QuZG9tYWluMB4XDTE2MDExNTE1MzQwOVoXDTI2MDExMjE1MzQwOVowgagxCzAJBgNVBAYTAkhLMRAwDgYDVQQIEwdDZW50cmFsMQswCQYDVQQHEwJISzEYMBYGA1UEChMPU2VjdXJlLVNlcnZlckNBMQswCQYDVQQLEwJJVDEYMBYGA1UEAxMPU2VjdXJlLVNlcnZlckNBMRgwFgYDVQQpEw9TZWN1cmUtU2VydmVyQ0ExHzAdBgkqhkiG9w0BCQEWEG1haWxAaG9zdC5kb21haW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDluufhyLlyvXzPUL16kAWAdivl1roQv3QHbuRshyKacf/1Er1JqEbtW3Mx9Fvr/u27qU2W8lQI6DaJhU2BfijPe/KHkib55mvHzIVvoexxya26nk79F2c+d9PnuuMdThWQO3El5a/i2AASnM7T7piIBT2WRZW2i8RbfJaTT7G7LP7OpMKIV1qyBg/cWoO7cIWQW4jmzqrNryIkF0AzStLN1DxvnQZwgXBGv0CwuAkfQuNSLu0PQgPp0PhdukNZFllv5D29IhPr0Z+kwPtrAgPQo+lHlOBHBMUpDT4XChTPeAvMaUSBsqmonAE8UUHEabWrqYN/kWNHCNkYXMkiVmK1AgMBAAGjggERMIIBDTAdBgNVHQ4EFgQU456ijsFrYnzHBShLAPpOUqQ+Z2cwgd0GA1UdIwSB1TCB0oAU456ijsFrYnzHBShLAPpOUqQ+Z2ehga6kgaswgagxCzAJBgNVBAYTAkhLMRAwDgYDVQQIEwdDZW50cmFsMQswCQYDVQQHEwJISzEYMBYGA1UEChMPU2VjdXJlLVNlcnZlckNBMQswCQYDVQQLEwJJVDEYMBYGA1UEAxMPU2VjdXJlLVNlcnZlckNBMRgwFgYDVQQpEw9TZWN1cmUtU2VydmVyQ0ExHzAdBgkqhkiG9w0BCQEWEG1haWxAaG9zdC5kb21haW6CCQDI1xaHqObkpTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCvga2HMwOtUxWH/inL2qk24KX2pxLg939JNhqoyNrUpbDHag5xPQYXUmUpKrNJZ0z+o/ZnNUPHydTSXE7Z7E45J0GDN5E7g4pakndKnDLSjp03NgGsCGW+cXnz6UBPM5FStFvGdDeModeSUyoS9fjk+mYROvmiy5EiVDP91sKGcPLR7Ym0M7zl2aaqV7bb98HmMoBOxpeZQinof67nKrCsgz/xjktWFgcmPl4/PQSsmqQD0fTtWxGuRX+FzwvF2OCMCAJgp1RqJNlk2g50/kBIoJVPPCfjDFeDU5zGaWGSQ9+z1L6/z7VXdjUiHL0ouOcHwbiS4ZjTr9nMn6WdAHU2"
|
||||||
|
PurevpnCertificate = "MIIEnzCCA4egAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBqDELMAkGA1UEBhMCSEsxEDAOBgNVBAgTB0NlbnRyYWwxCzAJBgNVBAcTAkhLMRgwFgYDVQQKEw9TZWN1cmUtU2VydmVyQ0ExCzAJBgNVBAsTAklUMRgwFgYDVQQDEw9TZWN1cmUtU2VydmVyQ0ExGDAWBgNVBCkTD1NlY3VyZS1TZXJ2ZXJDQTEfMB0GCSqGSIb3DQEJARYQbWFpbEBob3N0LmRvbWFpbjAeFw0xNjAxMTUxNjE1MzhaFw0yNjAxMTIxNjE1MzhaMIGdMQswCQYDVQQGEwJISzEQMA4GA1UECBMHQ2VudHJhbDELMAkGA1UEBxMCSEsxFjAUBgNVBAoTDVNlY3VyZS1DbGllbnQxCzAJBgNVBAsTAklUMRYwFAYDVQQDEw1TZWN1cmUtQ2xpZW50MREwDwYDVQQpEwhjaGFuZ2VtZTEfMB0GCSqGSIb3DQEJARYQbWFpbEBob3N0LmRvbWFpbjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxsnyn4v6xxDPnuDaYS0b9M1N8nxgg7OBPBlK+FWRxdTQ8yxt5U5CZGm7riVp7fya2J2iPZIgmHQEv/KbxztsHAVlYSfYYlalrnhEL3bDP2tY+N43AwB1k5BrPq2s1pPLT2XG951drDKG4PUuFHUP1sHzW5oQlfVCmxgIMAP8OYkCAwEAAaOCAV8wggFbMAkGA1UdEwQCMAAwLQYJYIZIAYb4QgENBCAWHkVhc3ktUlNBIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQU9MwUnUDbQKKZKjoeieD2OD5NlAEwgd0GA1UdIwSB1TCB0oAU456ijsFrYnzHBShLAPpOUqQ+Z2ehga6kgaswgagxCzAJBgNVBAYTAkhLMRAwDgYDVQQIEwdDZW50cmFsMQswCQYDVQQHEwJISzEYMBYGA1UEChMPU2VjdXJlLVNlcnZlckNBMQswCQYDVQQLEwJJVDEYMBYGA1UEAxMPU2VjdXJlLVNlcnZlckNBMRgwFgYDVQQpEw9TZWN1cmUtU2VydmVyQ0ExHzAdBgkqhkiG9w0BCQEWEG1haWxAaG9zdC5kb21haW6CCQDI1xaHqObkpTATBgNVHSUEDDAKBggrBgEFBQcDAjALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQELBQADggEBAFyFo2VUX/UFixsdPdK9/Yt6mkCWc+XS1xbapGXXb9U1d+h1iBCIV9odUHgNCXWpz1hR5Uu/OCzaZ0asLE4IFMZlQmJs8sMT0c1tfPPGW45vxbL0lhqnQ8PNcBH7huNK7VFjUh4szXRKmaQPaM4S91R3L4CaNfVeHfAg7mN2m9Zn5Gto1Q1/CFMGKu2hxwGEw5p+X1czBWEvg/O09ckx/ggkkI1NcZsNiYQ+6Pz8DdGGX3+05YwLZu94+O6iIMrzxl/il0eK83g3YPbsOrASARvw6w/8sOnJCK5eOacl21oww875KisnYdWjHB1FiI+VzQ1/gyoDsL5kPTJVuu2CoG8="
|
||||||
|
PurevpnKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMbJ8p+L+scQz57g2mEtG/TNTfJ8YIOzgTwZSvhVkcXU0PMsbeVOQmRpu64lae38mtidoj2SIJh0BL/ym8c7bBwFZWEn2GJWpa54RC92wz9rWPjeNwMAdZOQaz6trNaTy09lxvedXawyhuD1LhR1D9bB81uaEJX1QpsYCDAD/DmJAgMBAAECgYEAvTHbDupE5U0krUvHzBEIuHblptGlcfNYHoDcD3oxYR3pOGeiuElBexv+mgHVzcFLBrsQfJUlHLPfCWi3xmjRvDQcr7N7U1u7NIzazy/PpRBaKolMRiM1KMYi2DG0i4ZONwFT8bvNHOIrZzCLY54KDrqOn55OzC70WYjWh4t5evkCQQDkkzZUAeskBC9+JP/zLps8jhwfoLBWGw/zbC9ePDmX0N8MTZdcUpg6KUTf1wbkLUyVtIRjS2ao6qu1jWG6K0x3AkEA3qPWyaWQWCynhNDqu2U1cPb2kh5AJip+gqxO3emikAdajsSxeoyEC2AfyBITbeB1tvCUZH17J4i/0+OFTEQp/wJAb/zEOGJ8PzghwK8GC7JA8mk51DEZVAaMSRovFv9wxDXcoh191AjPdmdzzCuAv9iF1i8MUc3GbWoUWK39PIYsPwJAWh63sqfx5b8tj/WBDpnJKBDPfhYAoXJSA1L8GZeY1fQkE+ZKcPCwAmrGcpXeh3t0Krj3WDXyw+32uC5Apr5wwQJAPZwOOReaC4YNfBPZN9BdHvVjOYGGUffpI+X+hWpLRnQFJteAi+eqwyk0Oi0SkJB+a7jcerK2d7q7xhec5WHlng=="
|
||||||
|
PurevpnOpenvpnStaticKeyV1 = "e30af995f56d07426d9ba1f824730521d4283db4b4d0cdda9c6e8759a3799dcb7939b6a5989160c9660de0f6125cbb1f585b41c074b2fe88ecfcf17eab9a33be1352379cdf74952b588fb161a93e13df9135b2b29038231e02d657a6225705e6868ccb0c384ed11614690a1894bfbeb274cebf1fe9c2329bdd5c8a40fe8820624d2ea7540cd79ab76892db51fc371a3ac5fc9573afecb3fffe3281e61d72e91579d9b03d8cbf7909b3aebf4d90850321ee6b7d0a7846d15c27d8290e031e951e19438a4654663cad975e138f5bc5af89c737ad822f27e19057731f41e1e254cc9c95b7175c622422cde9f1f2cfd3510add94498b4d7133d3729dd214a16b27fb"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PurevpnRegionChoices() (choices []string) {
|
||||||
|
servers := PurevpnServers()
|
||||||
|
choices = make([]string, len(servers))
|
||||||
|
for i := range servers {
|
||||||
|
choices[i] = servers[i].Region
|
||||||
|
}
|
||||||
|
return choices
|
||||||
|
}
|
||||||
|
|
||||||
|
func PurevpnCountryChoices() (choices []string) {
|
||||||
|
servers := PurevpnServers()
|
||||||
|
choices = make([]string, len(servers))
|
||||||
|
for i := range servers {
|
||||||
|
choices[i] = servers[i].Country
|
||||||
|
}
|
||||||
|
return choices
|
||||||
|
}
|
||||||
|
|
||||||
|
func PurevpnCityChoices() (choices []string) {
|
||||||
|
servers := PurevpnServers()
|
||||||
|
choices = make([]string, len(servers))
|
||||||
|
for i := range servers {
|
||||||
|
choices[i] = servers[i].City
|
||||||
|
}
|
||||||
|
return choices
|
||||||
|
}
|
||||||
|
|
||||||
|
func PurevpnServers() []models.PurevpnServer {
|
||||||
|
return []models.PurevpnServer{
|
||||||
|
{Region: "Africa", Country: "Algeria", City: "Algiers", IPs: []net.IP{{172, 94, 64, 2}}},
|
||||||
|
{Region: "Africa", Country: "Angola", City: "Benguela", IPs: []net.IP{{45, 115, 26, 2}}},
|
||||||
|
{Region: "Africa", Country: "Cape Verde", City: "Praia", IPs: []net.IP{{45, 74, 25, 2}}},
|
||||||
|
{Region: "Africa", Country: "Egypt", City: "Cairo", IPs: []net.IP{{192, 198, 120, 122}}},
|
||||||
|
{Region: "Africa", Country: "Ethiopia", City: "Addis Ababa", IPs: []net.IP{{104, 250, 178, 4}}},
|
||||||
|
{Region: "Africa", Country: "Ghana", City: "Accra", IPs: []net.IP{{196, 251, 67, 4}}},
|
||||||
|
{Region: "Africa", Country: "Kenya", City: "Mombasa", IPs: []net.IP{{154, 127, 57, 151}}},
|
||||||
|
{Region: "Africa", Country: "Madagascar", City: "Antananarivo", IPs: []net.IP{{206, 123, 156, 131}}},
|
||||||
|
{Region: "Africa", Country: "Mauritania", City: "Nouakchott", IPs: []net.IP{{206, 123, 158, 63}}},
|
||||||
|
{Region: "Africa", Country: "Mauritius", City: "Port Louis", IPs: []net.IP{{104, 250, 181, 4}}},
|
||||||
|
{Region: "Africa", Country: "Morocco", City: "Rabat", IPs: []net.IP{{104, 243, 250, 126}}},
|
||||||
|
{Region: "Africa", Country: "Niger", City: "Niamey", IPs: []net.IP{{206, 123, 157, 131}}},
|
||||||
|
{Region: "Africa", Country: "Nigeria", City: "Suleja", IPs: []net.IP{{102, 165, 25, 38}}},
|
||||||
|
{Region: "Africa", Country: "Senegal", City: "Dakar", IPs: []net.IP{{206, 123, 158, 131}}},
|
||||||
|
{Region: "Africa", Country: "Seychelles", City: "Victoria", IPs: []net.IP{{172, 111, 128, 126}}},
|
||||||
|
{Region: "Africa", Country: "South Africa", City: "Johannesburg", IPs: []net.IP{{102, 165, 3, 34}}},
|
||||||
|
{Region: "Africa", Country: "Tanzania", City: "Dar Es Salaam", IPs: []net.IP{{102, 135, 0, 2}}},
|
||||||
|
{Region: "Africa", Country: "Tunisia", City: "Tunis", IPs: []net.IP{{206, 123, 159, 4}}},
|
||||||
|
{Region: "Asia", Country: "Afghanistan", City: "Kabul", IPs: []net.IP{{172, 111, 208, 2}}},
|
||||||
|
{Region: "Asia", Country: "Armenia", City: "Singapore", IPs: []net.IP{{37, 120, 208, 147}}},
|
||||||
|
{Region: "Asia", Country: "Azerbaijan", City: "Baku", IPs: []net.IP{{104, 250, 177, 4}}},
|
||||||
|
{Region: "Asia", Country: "Bangladesh", City: "Dhaka", IPs: []net.IP{{206, 123, 154, 190}}},
|
||||||
|
{Region: "Asia", Country: "Brunei Darussalam", City: "Bandar Seri Begawan", IPs: []net.IP{{119, 81, 75, 84}, {119, 81, 242, 8}}},
|
||||||
|
{Region: "Asia", Country: "Cambodia", City: "Phnom Penh", IPs: []net.IP{{104, 250, 176, 122}}},
|
||||||
|
{Region: "Asia", Country: "Hong Kong (SAR)", City: "Hong Kong", IPs: []net.IP{{46, 243, 250, 4}}},
|
||||||
|
{Region: "Asia", Country: "India", City: "Chennai", IPs: []net.IP{{129, 227, 107, 242}}},
|
||||||
|
{Region: "Asia", Country: "Indonesia", City: "Jakarta", IPs: []net.IP{{103, 55, 9, 2}}},
|
||||||
|
{Region: "Asia", Country: "Japan", City: "Tokyo", IPs: []net.IP{{172, 94, 56, 2}}},
|
||||||
|
{Region: "Asia", Country: "Kazakhstan", City: "Almaty", IPs: []net.IP{{206, 123, 152, 4}}},
|
||||||
|
{Region: "Asia", Country: "Korea, South", City: "Seoul", IPs: []net.IP{{45, 115, 25, 2}}},
|
||||||
|
{Region: "Asia", Country: "Kyrgyzstan", City: "Bishkek", IPs: []net.IP{{206, 123, 151, 131}}},
|
||||||
|
{Region: "Asia", Country: "Laos", City: "Vientiane", IPs: []net.IP{{206, 123, 153, 4}}},
|
||||||
|
{Region: "Asia", Country: "Macao", City: "Beyrouth", IPs: []net.IP{{104, 243, 240, 121}}},
|
||||||
|
{Region: "Asia", Country: "Malaysia", City: "Johor Baharu", IPs: []net.IP{{43, 226, 230, 4}}},
|
||||||
|
{Region: "Asia", Country: "Malaysia", City: "Kuala Lumpur", IPs: []net.IP{{104, 250, 160, 4}}},
|
||||||
|
{Region: "Asia", Country: "Mongolia", City: "Ulaanbaatar", IPs: []net.IP{{206, 123, 153, 131}}},
|
||||||
|
{Region: "Asia", Country: "Pakistan", City: "Islamabad", IPs: []net.IP{{104, 250, 187, 3}}},
|
||||||
|
{Region: "Asia", Country: "Papua New Guinea", City: "Port Moresby", IPs: []net.IP{{206, 123, 155, 131}}},
|
||||||
|
{Region: "Asia", Country: "Philippines", City: "Manila", IPs: []net.IP{{36, 255, 97, 3}}},
|
||||||
|
{Region: "Asia", Country: "Sri Lanka", City: "Colombo", IPs: []net.IP{{206, 123, 154, 4}}},
|
||||||
|
{Region: "Asia", Country: "Taiwan", City: "Taipei", IPs: []net.IP{{203, 69, 105, 5}}},
|
||||||
|
{Region: "Asia", Country: "Tajikistan", City: "Dushanbe", IPs: []net.IP{{206, 123, 151, 4}}},
|
||||||
|
{Region: "Asia", Country: "Thailand", City: "Bangkok", IPs: []net.IP{{104, 37, 6, 4}}},
|
||||||
|
{Region: "Asia", Country: "Turkey", City: "Istanbul", IPs: []net.IP{{82, 102, 22, 212}}},
|
||||||
|
{Region: "Asia", Country: "Turkmenistan", City: "Ashgabat", IPs: []net.IP{{206, 123, 152, 131}}},
|
||||||
|
{Region: "Asia", Country: "Uzbekistan", City: "Tashkent", IPs: []net.IP{{206, 123, 150, 131}}},
|
||||||
|
{Region: "Asia", Country: "Vietnam", City: "Hanoi", IPs: []net.IP{{192, 253, 249, 132}}},
|
||||||
|
{Region: "Europe", Country: "Albania", City: "Tirane", IPs: []net.IP{{46, 243, 224, 2}}},
|
||||||
|
{Region: "Europe", Country: "Armenia", City: "Yerevan", IPs: []net.IP{{172, 94, 35, 4}}},
|
||||||
|
{Region: "Europe", Country: "Austria", City: "Vienna", IPs: []net.IP{{172, 94, 125, 4}}},
|
||||||
|
{Region: "Europe", Country: "Belgium", City: "Brussels", IPs: []net.IP{{172, 111, 223, 4}, {172, 111, 244, 4}}},
|
||||||
|
{Region: "Europe", Country: "Bosnia and Herzegovina", City: "Sarajevo", IPs: []net.IP{{104, 250, 169, 122}}},
|
||||||
|
{Region: "Europe", Country: "Bulgaria", City: "Sofia", IPs: []net.IP{{37, 120, 152, 52}}},
|
||||||
|
{Region: "Europe", Country: "Croatia", City: "Zagreb", IPs: []net.IP{{104, 250, 163, 2}}},
|
||||||
|
{Region: "Europe", Country: "Cyprus", City: "Nicosia", IPs: []net.IP{{188, 72, 119, 4}}},
|
||||||
|
{Region: "Europe", Country: "Denmark", City: "Copenhagen", IPs: []net.IP{{172, 111, 223, 4}}},
|
||||||
|
{Region: "Europe", Country: "Estonia", City: "Tallinn", IPs: []net.IP{{185, 166, 87, 2}, {188, 72, 111, 4}}},
|
||||||
|
{Region: "Europe", Country: "France", City: "Paris", IPs: []net.IP{{172, 111, 223, 4}}},
|
||||||
|
{Region: "Europe", Country: "Georgia", City: "Tbilisi", IPs: []net.IP{{141, 101, 156, 2}}},
|
||||||
|
{Region: "Europe", Country: "Germany", City: "Frankfurt", IPs: []net.IP{{82, 102, 16, 107}}},
|
||||||
|
{Region: "Europe", Country: "Germany", City: "Munich", IPs: []net.IP{{82, 102, 16, 107}}},
|
||||||
|
{Region: "Europe", Country: "Germany", City: "Nuremberg", IPs: []net.IP{{172, 94, 125, 2}}},
|
||||||
|
{Region: "Europe", Country: "Greece", City: "Thessaloniki", IPs: []net.IP{{5, 172, 199, 2}}},
|
||||||
|
{Region: "Europe", Country: "Hungary", City: "Budapest", IPs: []net.IP{{217, 138, 192, 136}}},
|
||||||
|
{Region: "Europe", Country: "Iceland", City: "Reykjavik", IPs: []net.IP{{192, 253, 250, 1}}},
|
||||||
|
{Region: "Europe", Country: "Ireland", City: "Dublin", IPs: []net.IP{{78, 153, 208, 173}}},
|
||||||
|
{Region: "Europe", Country: "Isle of Man", City: "Onchan", IPs: []net.IP{{46, 243, 144, 2}}},
|
||||||
|
{Region: "Europe", Country: "Italy", City: "Milano", IPs: []net.IP{{45, 9, 251, 2}}},
|
||||||
|
{Region: "Europe", Country: "Latvia", City: "RIGA", IPs: []net.IP{{185, 118, 76, 5}}},
|
||||||
|
{Region: "Europe", Country: "Liechtenstein", City: "Vaduz", IPs: []net.IP{{104, 250, 164, 4}}},
|
||||||
|
{Region: "Europe", Country: "Lithuania", City: "Vilnius", IPs: []net.IP{{188, 72, 116, 3}}},
|
||||||
|
{Region: "Europe", Country: "Luxembourg", City: "Luxembourg", IPs: []net.IP{{94, 242, 225, 132}}},
|
||||||
|
{Region: "Europe", Country: "Malta", City: "Sliema", IPs: []net.IP{{46, 243, 241, 4}}},
|
||||||
|
{Region: "Europe", Country: "Monaco", City: "Monaco", IPs: []net.IP{{104, 250, 168, 132}}},
|
||||||
|
{Region: "Europe", Country: "Montenegro", City: "Podgorica", IPs: []net.IP{{104, 250, 165, 121}}},
|
||||||
|
{Region: "Europe", Country: "Netherlands", City: "Amsterdam", IPs: []net.IP{{37, 120, 192, 212}}},
|
||||||
|
{Region: "Europe", Country: "Norway", City: "Oslo", IPs: []net.IP{{82, 102, 22, 212}}},
|
||||||
|
{Region: "Europe", Country: "Poland", City: "Warsaw", IPs: []net.IP{{5, 253, 206, 251}}},
|
||||||
|
{Region: "Europe", Country: "Portugal", City: "Lisbon", IPs: []net.IP{{5, 154, 174, 3}}},
|
||||||
|
{Region: "Europe", Country: "Romania", City: "Bucharest", IPs: []net.IP{{188, 240, 220, 35}}},
|
||||||
|
{Region: "Europe", Country: "Serbia", City: "Niš", IPs: []net.IP{{152, 89, 160, 201}}},
|
||||||
|
{Region: "Europe", Country: "Slovakia", City: "Bratislava", IPs: []net.IP{{188, 72, 112, 3}}},
|
||||||
|
{Region: "Europe", Country: "Slovenia", City: "Ljubljana", IPs: []net.IP{{104, 243, 246, 129}}},
|
||||||
|
{Region: "Europe", Country: "Spain", City: "Barcelona", IPs: []net.IP{{185, 230, 124, 147}}},
|
||||||
|
{Region: "Europe", Country: "Sweden", City: "Stockholm", IPs: []net.IP{{45, 74, 46, 2}}},
|
||||||
|
{Region: "Europe", Country: "Switzerland", City: "Zurich", IPs: []net.IP{{45, 12, 222, 98}, {45, 12, 222, 99}}},
|
||||||
|
{Region: "Europe", Country: "United Kingdom", City: "Gosport", IPs: []net.IP{{45, 141, 154, 70}}},
|
||||||
|
{Region: "Europe", Country: "United Kingdom", City: "London", IPs: []net.IP{{193, 9, 113, 66}}},
|
||||||
|
{Region: "Europe", Country: "United Kingdom", City: "Maidenhead", IPs: []net.IP{{188, 72, 89, 4}}},
|
||||||
|
{Region: "Europe", Country: "United Kingdom", City: "Manchester", IPs: []net.IP{{172, 111, 183, 2}}},
|
||||||
|
{Region: "Middle East", Country: "Bahrain", City: "Manama", IPs: []net.IP{{46, 243, 150, 4}}},
|
||||||
|
{Region: "Middle East", Country: "Jordan", City: "Amman", IPs: []net.IP{{172, 111, 152, 3}}},
|
||||||
|
{Region: "Middle East", Country: "Kuwait", City: "Kuwait", IPs: []net.IP{{206, 123, 146, 4}}},
|
||||||
|
{Region: "Middle East", Country: "Oman", City: "Salalah", IPs: []net.IP{{46, 243, 148, 125}}},
|
||||||
|
{Region: "Middle East", Country: "Qatar", City: "Doha", IPs: []net.IP{{46, 243, 147, 2}}},
|
||||||
|
{Region: "Middle East", Country: "Saudi Arabia", City: "Jeddah", IPs: []net.IP{{45, 74, 1, 4}}},
|
||||||
|
{Region: "Middle East", Country: "United Arab Emirates", City: "Dubai", IPs: []net.IP{{104, 37, 6, 4}}},
|
||||||
|
{Region: "North America", Country: "Aruba", City: "Oranjestad", IPs: []net.IP{{104, 243, 246, 129}}},
|
||||||
|
{Region: "North America", Country: "Barbados", City: "Bridgetown", IPs: []net.IP{{172, 94, 97, 2}}},
|
||||||
|
{Region: "North America", Country: "Belize", City: "Belmopan", IPs: []net.IP{{104, 243, 241, 4}}},
|
||||||
|
{Region: "North America", Country: "Bermuda", City: "Hamilton", IPs: []net.IP{{172, 94, 76, 2}}},
|
||||||
|
{Region: "North America", Country: "Canada", City: "Montreal", IPs: []net.IP{{172, 94, 7, 2}}},
|
||||||
|
{Region: "North America", Country: "Canada", City: "Toronto", IPs: []net.IP{{172, 94, 7, 2}}},
|
||||||
|
{Region: "North America", Country: "Canada", City: "Vancouver", IPs: []net.IP{{172, 94, 34, 4}}},
|
||||||
|
{Region: "North America", Country: "Cayman Islands", City: "George Town", IPs: []net.IP{{172, 94, 113, 2}}},
|
||||||
|
{Region: "North America", Country: "Costa Rica", City: "San Jose", IPs: []net.IP{{104, 243, 245, 1}}},
|
||||||
|
{Region: "North America", Country: "Dominica", City: "Roseau", IPs: []net.IP{{45, 74, 22, 2}}},
|
||||||
|
{Region: "North America", Country: "Dominican Republic", City: "Santo Domingo", IPs: []net.IP{{45, 74, 23, 129}}},
|
||||||
|
{Region: "North America", Country: "El Salvador", City: "San Salvador", IPs: []net.IP{{45, 74, 17, 129}}},
|
||||||
|
{Region: "North America", Country: "Grenada", City: "St George's", IPs: []net.IP{{45, 74, 21, 129}}},
|
||||||
|
{Region: "North America", Country: "Guatemala", City: "Guatemala", IPs: []net.IP{{45, 74, 17, 129}}},
|
||||||
|
{Region: "North America", Country: "Haiti", City: "PORT-AU-PRINCE", IPs: []net.IP{{45, 74, 24, 2}}},
|
||||||
|
{Region: "North America", Country: "Honduras", City: "TEGUCIGALPA", IPs: []net.IP{{45, 74, 18, 2}}},
|
||||||
|
{Region: "North America", Country: "Jamaica", City: "Kingston", IPs: []net.IP{{104, 250, 182, 126}}},
|
||||||
|
{Region: "North America", Country: "Mexico", City: "Mexico City", IPs: []net.IP{{104, 243, 243, 131}}},
|
||||||
|
{Region: "North America", Country: "Montserrat", City: "plymouth", IPs: []net.IP{{45, 74, 26, 190}}},
|
||||||
|
{Region: "North America", Country: "Puerto Rico", City: "San Juan", IPs: []net.IP{{104, 37, 2, 2}}},
|
||||||
|
{Region: "North America", Country: "Saint Lucia", City: "Castries", IPs: []net.IP{{45, 74, 23, 2}}},
|
||||||
|
{Region: "North America", Country: "The Bahamas", City: "Freeport", IPs: []net.IP{{104, 243, 242, 2}}},
|
||||||
|
{Region: "North America", Country: "Trinidad and Tobago", City: "Port of Spain", IPs: []net.IP{{45, 74, 21, 2}}},
|
||||||
|
{Region: "North America", Country: "Turks and Caicos Islands", City: "Balfour Town", IPs: []net.IP{{172, 94, 60, 4}}},
|
||||||
|
{Region: "North America", Country: "United States", City: "Ashburn", IPs: []net.IP{{46, 243, 249, 2}}},
|
||||||
|
{Region: "North America", Country: "United States", City: "Chicago", IPs: []net.IP{{37, 230, 169, 4}}},
|
||||||
|
{Region: "North America", Country: "United States", City: "Columbus", IPs: []net.IP{{172, 94, 115, 2}}},
|
||||||
|
{Region: "North America", Country: "United States", City: "Georgia", IPs: []net.IP{{141, 101, 168, 4}}},
|
||||||
|
{Region: "North America", Country: "United States", City: "Houston", IPs: []net.IP{{172, 94, 1, 4}}},
|
||||||
|
{Region: "North America", Country: "United States", City: "Los Angeles", IPs: []net.IP{{172, 111, 147, 4}}},
|
||||||
|
{Region: "North America", Country: "United States", City: "Miami", IPs: []net.IP{{172, 94, 108, 4}}},
|
||||||
|
{Region: "North America", Country: "United States", City: "New Jersey", IPs: []net.IP{{141, 101, 168, 4}}},
|
||||||
|
{Region: "North America", Country: "United States", City: "New York", IPs: []net.IP{{172, 111, 147, 4}}},
|
||||||
|
{Region: "North America", Country: "United States", City: "Phoenix", IPs: []net.IP{{172, 94, 26, 4}}},
|
||||||
|
{Region: "North America", Country: "United States", City: "Salt Lake City", IPs: []net.IP{{141, 101, 168, 4}}},
|
||||||
|
{Region: "North America", Country: "United States", City: "San Francisco", IPs: []net.IP{{172, 111, 147, 4}}},
|
||||||
|
{Region: "North America", Country: "United States", City: "Seattle", IPs: []net.IP{{172, 94, 86, 2}}},
|
||||||
|
{Region: "North America", Country: "United States", City: "Washington, D.C.", IPs: []net.IP{{37, 230, 169, 4}}},
|
||||||
|
{Region: "Oceania", Country: "Australia", City: "Brisbane", IPs: []net.IP{{172, 111, 236, 2}}},
|
||||||
|
{Region: "Oceania", Country: "Australia", City: "Melbourne", IPs: []net.IP{{118, 127, 62, 2}}},
|
||||||
|
{Region: "Oceania", Country: "Australia", City: "Perth", IPs: []net.IP{{172, 94, 123, 4}}},
|
||||||
|
{Region: "Oceania", Country: "Australia", City: "Sydney", IPs: []net.IP{{46, 243, 245, 4}}},
|
||||||
|
{Region: "Oceania", Country: "New Zealand", City: "Auckland", IPs: []net.IP{{43, 228, 156, 4}}},
|
||||||
|
{Region: "South America", Country: "Argentina", City: "Buenos Aires", IPs: []net.IP{{104, 243, 244, 1}}},
|
||||||
|
{Region: "South America", Country: "Bolivia", City: "Sucre", IPs: []net.IP{{172, 94, 77, 2}}},
|
||||||
|
{Region: "South America", Country: "Brazil", City: "Sao Paulo", IPs: []net.IP{{104, 243, 244, 2}}},
|
||||||
|
{Region: "South America", Country: "British Virgin Island", City: "Road Town", IPs: []net.IP{{104, 250, 184, 130}}},
|
||||||
|
{Region: "South America", Country: "Chile", City: "Santiago", IPs: []net.IP{{191, 96, 183, 251}}},
|
||||||
|
{Region: "South America", Country: "Colombia", City: "Bogota", IPs: []net.IP{{172, 111, 132, 1}}},
|
||||||
|
{Region: "South America", Country: "Ecuador", City: "Quito", IPs: []net.IP{{104, 250, 180, 126}}},
|
||||||
|
{Region: "South America", Country: "Guyana", City: "Georgetown", IPs: []net.IP{{45, 74, 20, 129}}},
|
||||||
|
{Region: "South America", Country: "Panama", City: "Panama City", IPs: []net.IP{{104, 243, 243, 131}}},
|
||||||
|
{Region: "South America", Country: "Paraguay", City: "Asuncion", IPs: []net.IP{{45, 74, 19, 129}}},
|
||||||
|
{Region: "South America", Country: "Peru", City: "Lima", IPs: []net.IP{{172, 111, 131, 1}}},
|
||||||
|
{Region: "South America", Country: "Suriname", City: "Paramaribo", IPs: []net.IP{{45, 74, 20, 4}}},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,8 @@ const (
|
|||||||
Vyprvpn models.VPNProvider = "vyprvpn"
|
Vyprvpn models.VPNProvider = "vyprvpn"
|
||||||
// NordVPN is a VPN provider
|
// NordVPN is a VPN provider
|
||||||
Nordvpn models.VPNProvider = "nordvpn"
|
Nordvpn models.VPNProvider = "nordvpn"
|
||||||
|
// PureVPN is a VPN provider
|
||||||
|
Purevpn models.VPNProvider = "purevpn"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -93,23 +93,59 @@ func (l *looper) logAndWait(ctx context.Context, err error) {
|
|||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *looper) waitForFirstStart(ctx context.Context) {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-l.stop:
|
||||||
|
l.setEnabled(false)
|
||||||
|
l.logger.Info("not started yet")
|
||||||
|
case <-l.restart:
|
||||||
|
if l.isEnabled() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
l.logger.Info("not restarting because disabled")
|
||||||
|
case <-l.start:
|
||||||
|
l.setEnabled(true)
|
||||||
|
return
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *looper) waitForSubsequentStart(ctx context.Context, unboundCancel context.CancelFunc) {
|
||||||
|
if l.isEnabled() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
// wait for a signal to re-enable
|
||||||
|
select {
|
||||||
|
case <-l.stop:
|
||||||
|
l.logger.Info("already disabled")
|
||||||
|
case <-l.restart:
|
||||||
|
if !l.isEnabled() {
|
||||||
|
l.logger.Info("not restarting because disabled")
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case <-l.start:
|
||||||
|
l.setEnabled(true)
|
||||||
|
return
|
||||||
|
case <-ctx.Done():
|
||||||
|
unboundCancel()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
l.fallbackToUnencryptedDNS()
|
l.fallbackToUnencryptedDNS()
|
||||||
waitForStart := true
|
l.waitForFirstStart(ctx)
|
||||||
for waitForStart {
|
if ctx.Err() != nil {
|
||||||
select {
|
|
||||||
case <-l.stop:
|
|
||||||
l.logger.Info("not started yet")
|
|
||||||
case <-l.restart:
|
|
||||||
waitForStart = false
|
|
||||||
case <-l.start:
|
|
||||||
waitForStart = false
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
defer l.logger.Warn("loop exited")
|
defer l.logger.Warn("loop exited")
|
||||||
|
|
||||||
var unboundCtx context.Context
|
var unboundCtx context.Context
|
||||||
@@ -118,20 +154,7 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
|||||||
triggeredRestart := false
|
triggeredRestart := false
|
||||||
l.setEnabled(true)
|
l.setEnabled(true)
|
||||||
for ctx.Err() == nil {
|
for ctx.Err() == nil {
|
||||||
for !l.isEnabled() {
|
l.waitForSubsequentStart(ctx, unboundCancel)
|
||||||
// wait for a signal to re-enable
|
|
||||||
select {
|
|
||||||
case <-l.stop:
|
|
||||||
l.logger.Info("already disabled")
|
|
||||||
case <-l.restart:
|
|
||||||
l.setEnabled(true)
|
|
||||||
case <-l.start:
|
|
||||||
l.setEnabled(true)
|
|
||||||
case <-ctx.Done():
|
|
||||||
unboundCancel()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
settings := l.GetSettings()
|
settings := l.GetSettings()
|
||||||
|
|
||||||
|
|||||||
@@ -62,15 +62,6 @@ func (c *configurator) fallbackToDisabled(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *configurator) enable(ctx context.Context) (err error) { //nolint:gocognit
|
func (c *configurator) enable(ctx context.Context) (err error) { //nolint:gocognit
|
||||||
defaultInterface, defaultGateway, err := c.routing.DefaultRoute()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
|
||||||
}
|
|
||||||
localSubnet, err := c.routing.LocalSubnet()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = c.setAllPolicies(ctx, "DROP"); err != nil {
|
if err = c.setAllPolicies(ctx, "DROP"); err != nil {
|
||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||||
}
|
}
|
||||||
@@ -95,50 +86,36 @@ func (c *configurator) enable(ctx context.Context) (err error) { //nolint:gocogn
|
|||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||||
}
|
}
|
||||||
for _, conn := range c.vpnConnections {
|
for _, conn := range c.vpnConnections {
|
||||||
if err = c.acceptOutputTrafficToVPN(ctx, defaultInterface, conn, remove); err != nil {
|
if err = c.acceptOutputTrafficToVPN(ctx, c.defaultInterface, conn, remove); err != nil {
|
||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err = c.acceptOutputThroughInterface(ctx, string(constants.TUN), remove); err != nil {
|
if err = c.acceptOutputThroughInterface(ctx, string(constants.TUN), remove); err != nil {
|
||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||||
}
|
}
|
||||||
if err := c.acceptInputFromSubnetToSubnet(ctx, "*", localSubnet, localSubnet, remove); err != nil {
|
if err := c.acceptInputFromSubnetToSubnet(ctx, "*", c.localSubnet, c.localSubnet, remove); err != nil {
|
||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||||
}
|
}
|
||||||
if err := c.acceptOutputFromSubnetToSubnet(ctx, "*", localSubnet, localSubnet, remove); err != nil {
|
if err := c.acceptOutputFromSubnetToSubnet(ctx, "*", c.localSubnet, c.localSubnet, remove); err != nil {
|
||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||||
}
|
}
|
||||||
for _, subnet := range c.allowedSubnets {
|
for _, subnet := range c.allowedSubnets {
|
||||||
if err := c.acceptInputFromSubnetToSubnet(ctx, defaultInterface, subnet, localSubnet, remove); err != nil {
|
if err := c.acceptInputFromSubnetToSubnet(ctx, c.defaultInterface, subnet, c.localSubnet, remove); err != nil {
|
||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||||
}
|
}
|
||||||
if err := c.acceptOutputFromSubnetToSubnet(ctx, defaultInterface, localSubnet, subnet, remove); err != nil {
|
if err := c.acceptOutputFromSubnetToSubnet(ctx, c.defaultInterface, c.localSubnet, subnet, remove); err != nil {
|
||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Re-ensure all routes exist
|
// Re-ensure all routes exist
|
||||||
for _, subnet := range c.allowedSubnets {
|
for _, subnet := range c.allowedSubnets {
|
||||||
if err := c.routing.AddRouteVia(ctx, subnet, defaultGateway, defaultInterface); err != nil {
|
if err := c.routing.AddRouteVia(ctx, subnet, c.defaultGateway, c.defaultInterface); err != nil {
|
||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for port := range c.allowedPorts {
|
for port, intf := range c.allowedInputPorts {
|
||||||
// TODO restrict interface
|
if err := c.acceptInputToPort(ctx, intf, port, remove); err != nil {
|
||||||
if err := c.acceptInputToPort(ctx, "*", constants.TCP, port, remove); err != nil {
|
|
||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
|
||||||
}
|
|
||||||
if err := c.acceptInputToPort(ctx, "*", constants.UDP, port, remove); err != nil {
|
|
||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.portForwarded > 0 {
|
|
||||||
const tun = string(constants.TUN)
|
|
||||||
if err := c.acceptInputToPort(ctx, tun, constants.TCP, c.portForwarded, remove); err != nil {
|
|
||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
|
||||||
}
|
|
||||||
if err := c.acceptInputToPort(ctx, tun, constants.UDP, c.portForwarded, remove); err != nil {
|
|
||||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,10 +18,11 @@ type Configurator interface {
|
|||||||
SetEnabled(ctx context.Context, enabled bool) (err error)
|
SetEnabled(ctx context.Context, enabled bool) (err error)
|
||||||
SetVPNConnections(ctx context.Context, connections []models.OpenVPNConnection) (err error)
|
SetVPNConnections(ctx context.Context, connections []models.OpenVPNConnection) (err error)
|
||||||
SetAllowedSubnets(ctx context.Context, subnets []net.IPNet) (err error)
|
SetAllowedSubnets(ctx context.Context, subnets []net.IPNet) (err error)
|
||||||
SetAllowedPort(ctx context.Context, port uint16) error
|
SetAllowedPort(ctx context.Context, port uint16, intf string) (err error)
|
||||||
RemoveAllowedPort(ctx context.Context, port uint16) (err error)
|
RemoveAllowedPort(ctx context.Context, port uint16) (err error)
|
||||||
SetPortForward(ctx context.Context, port uint16) (err error)
|
|
||||||
SetDebug()
|
SetDebug()
|
||||||
|
// SetNetworkInformation is meant to be called only once
|
||||||
|
SetNetworkInformation(defaultInterface string, defaultGateway net.IP, localSubnet net.IPNet)
|
||||||
}
|
}
|
||||||
|
|
||||||
type configurator struct { //nolint:maligned
|
type configurator struct { //nolint:maligned
|
||||||
@@ -31,13 +32,16 @@ type configurator struct { //nolint:maligned
|
|||||||
fileManager files.FileManager // for custom iptables rules
|
fileManager files.FileManager // for custom iptables rules
|
||||||
iptablesMutex sync.Mutex
|
iptablesMutex sync.Mutex
|
||||||
debug bool
|
debug bool
|
||||||
|
defaultInterface string
|
||||||
|
defaultGateway net.IP
|
||||||
|
localSubnet net.IPNet
|
||||||
|
networkInfoMutex sync.Mutex
|
||||||
|
|
||||||
// State
|
// State
|
||||||
enabled bool
|
enabled bool
|
||||||
vpnConnections []models.OpenVPNConnection
|
vpnConnections []models.OpenVPNConnection
|
||||||
allowedSubnets []net.IPNet
|
allowedSubnets []net.IPNet
|
||||||
allowedPorts map[uint16]struct{}
|
allowedInputPorts map[uint16]string // port to interface mapping
|
||||||
portForwarded uint16
|
|
||||||
stateMutex sync.Mutex
|
stateMutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,10 +52,18 @@ func NewConfigurator(logger logging.Logger, routing routing.Routing, fileManager
|
|||||||
logger: logger.WithPrefix("firewall: "),
|
logger: logger.WithPrefix("firewall: "),
|
||||||
routing: routing,
|
routing: routing,
|
||||||
fileManager: fileManager,
|
fileManager: fileManager,
|
||||||
allowedPorts: make(map[uint16]struct{}),
|
allowedInputPorts: make(map[uint16]string),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *configurator) SetDebug() {
|
func (c *configurator) SetDebug() {
|
||||||
c.debug = true
|
c.debug = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *configurator) SetNetworkInformation(defaultInterface string, defaultGateway net.IP, localSubnet net.IPNet) {
|
||||||
|
c.networkInfoMutex.Lock()
|
||||||
|
defer c.networkInfoMutex.Unlock()
|
||||||
|
c.defaultInterface = defaultInterface
|
||||||
|
c.defaultGateway = defaultGateway
|
||||||
|
c.localSubnet = localSubnet
|
||||||
|
}
|
||||||
|
|||||||
@@ -134,14 +134,15 @@ func (c *configurator) acceptOutputFromSubnetToSubnet(ctx context.Context, intf
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Used for port forwarding, with intf set to tun
|
// Used for port forwarding, with intf set to tun
|
||||||
func (c *configurator) acceptInputToPort(ctx context.Context, intf string, protocol models.NetworkProtocol, port uint16, remove bool) error {
|
func (c *configurator) acceptInputToPort(ctx context.Context, intf string, port uint16, remove bool) error {
|
||||||
interfaceFlag := "-i " + intf
|
interfaceFlag := "-i " + intf
|
||||||
if intf == "*" { // all interfaces
|
if intf == "*" { // all interfaces
|
||||||
interfaceFlag = ""
|
interfaceFlag = ""
|
||||||
}
|
}
|
||||||
return c.runIptablesInstruction(ctx,
|
return c.runIptablesInstructions(ctx, []string{
|
||||||
fmt.Sprintf("%s INPUT %s -p %s --dport %d -j ACCEPT", appendOrDelete(remove), interfaceFlag, protocol, port),
|
fmt.Sprintf("%s INPUT %s -p tcp --dport %d -j ACCEPT", appendOrDelete(remove), interfaceFlag, port),
|
||||||
)
|
fmt.Sprintf("%s INPUT %s -p udp --dport %d -j ACCEPT", appendOrDelete(remove), interfaceFlag, port),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *configurator) runUserPostRules(ctx context.Context, filepath string, remove bool) error {
|
func (c *configurator) runUserPostRules(ctx context.Context, filepath string, remove bool) error {
|
||||||
|
|||||||
@@ -3,11 +3,9 @@ package firewall
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *configurator) SetAllowedPort(ctx context.Context, port uint16) (err error) {
|
func (c *configurator) SetAllowedPort(ctx context.Context, port uint16, intf string) (err error) {
|
||||||
c.stateMutex.Lock()
|
c.stateMutex.Lock()
|
||||||
defer c.stateMutex.Unlock()
|
defer c.stateMutex.Unlock()
|
||||||
|
|
||||||
@@ -16,25 +14,28 @@ func (c *configurator) SetAllowedPort(ctx context.Context, port uint16) (err err
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !c.enabled {
|
if !c.enabled {
|
||||||
c.logger.Info("firewall disabled, only updating allowed ports internal list")
|
c.logger.Info("firewall disabled, only updating allowed ports internal state")
|
||||||
c.allowedPorts[port] = struct{}{}
|
c.allowedInputPorts[port] = intf
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
c.logger.Info("setting allowed port %d through firewall...", port)
|
c.logger.Info("setting allowed input port %d through interface %s...", port, intf)
|
||||||
|
|
||||||
if _, ok := c.allowedPorts[port]; ok {
|
if existingIntf, ok := c.allowedInputPorts[port]; ok {
|
||||||
|
if intf == existingIntf {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
const remove = true
|
||||||
|
if err := c.acceptInputToPort(ctx, existingIntf, port, remove); err != nil {
|
||||||
|
return fmt.Errorf("cannot remove old allowed port %d through interface %s: %w", port, existingIntf, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const remove = false
|
const remove = false
|
||||||
if err := c.acceptInputToPort(ctx, "*", constants.TCP, port, remove); err != nil {
|
if err := c.acceptInputToPort(ctx, intf, port, remove); err != nil {
|
||||||
return fmt.Errorf("cannot set allowed port %d through firewall: %w", port, err)
|
return fmt.Errorf("cannot set allowed port %d through interface %s: %w", port, intf, err)
|
||||||
}
|
}
|
||||||
if err := c.acceptInputToPort(ctx, "*", constants.UDP, port, remove); err != nil {
|
c.allowedInputPorts[port] = intf
|
||||||
return fmt.Errorf("cannot set allowed port %d through firewall: %w", port, err)
|
|
||||||
}
|
|
||||||
c.allowedPorts[port] = struct{}{}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -49,63 +50,22 @@ func (c *configurator) RemoveAllowedPort(ctx context.Context, port uint16) (err
|
|||||||
|
|
||||||
if !c.enabled {
|
if !c.enabled {
|
||||||
c.logger.Info("firewall disabled, only updating allowed ports internal list")
|
c.logger.Info("firewall disabled, only updating allowed ports internal list")
|
||||||
delete(c.allowedPorts, port)
|
delete(c.allowedInputPorts, port)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
c.logger.Info("removing allowed port %d through firewall...", port)
|
c.logger.Info("removing allowed port %d through firewall...", port)
|
||||||
|
|
||||||
if _, ok := c.allowedPorts[port]; !ok {
|
intf, ok := c.allowedInputPorts[port]
|
||||||
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const remove = true
|
const remove = true
|
||||||
if err := c.acceptInputToPort(ctx, "*", constants.TCP, port, remove); err != nil {
|
if err := c.acceptInputToPort(ctx, intf, port, remove); err != nil {
|
||||||
return fmt.Errorf("cannot remove allowed port %d through firewall: %w", port, err)
|
return fmt.Errorf("cannot remove allowed port %d through interface %s: %w", port, intf, err)
|
||||||
}
|
}
|
||||||
if err := c.acceptInputToPort(ctx, "*", constants.UDP, port, remove); err != nil {
|
delete(c.allowedInputPorts, port)
|
||||||
return fmt.Errorf("cannot remove allowed port %d through firewall: %w", port, err)
|
|
||||||
}
|
|
||||||
delete(c.allowedPorts, port)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use 0 to remove
|
|
||||||
func (c *configurator) SetPortForward(ctx context.Context, port uint16) (err error) {
|
|
||||||
c.stateMutex.Lock()
|
|
||||||
defer c.stateMutex.Unlock()
|
|
||||||
|
|
||||||
if port == c.portForwarded {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !c.enabled {
|
|
||||||
c.logger.Info("firewall disabled, only updating port forwarded internally")
|
|
||||||
c.portForwarded = port
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const tun = string(constants.TUN)
|
|
||||||
if c.portForwarded > 0 {
|
|
||||||
if err := c.acceptInputToPort(ctx, tun, constants.TCP, c.portForwarded, true); err != nil {
|
|
||||||
return fmt.Errorf("cannot remove outdated port forward rule from firewall: %w", err)
|
|
||||||
}
|
|
||||||
if err := c.acceptInputToPort(ctx, tun, constants.UDP, c.portForwarded, true); err != nil {
|
|
||||||
return fmt.Errorf("cannot remove outdated port forward rule from firewall: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if port == 0 { // not changing port
|
|
||||||
c.portForwarded = 0
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.acceptInputToPort(ctx, tun, constants.TCP, port, false); err != nil {
|
|
||||||
return fmt.Errorf("cannot accept port forwarded through firewall: %w", err)
|
|
||||||
}
|
|
||||||
if err := c.acceptInputToPort(ctx, tun, constants.UDP, port, false); err != nil {
|
|
||||||
return fmt.Errorf("cannot accept port forwarded through firewall: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -12,9 +12,7 @@ func (c *configurator) SetAllowedSubnets(ctx context.Context, subnets []net.IPNe
|
|||||||
|
|
||||||
if !c.enabled {
|
if !c.enabled {
|
||||||
c.logger.Info("firewall disabled, only updating allowed subnets internal list and updating routes")
|
c.logger.Info("firewall disabled, only updating allowed subnets internal list and updating routes")
|
||||||
if err := c.updateSubnetRoutes(ctx, c.allowedSubnets, subnets); err != nil {
|
c.updateSubnetRoutes(ctx, c.allowedSubnets, subnets)
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.allowedSubnets = make([]net.IPNet, len(subnets))
|
c.allowedSubnets = make([]net.IPNet, len(subnets))
|
||||||
copy(c.allowedSubnets, subnets)
|
copy(c.allowedSubnets, subnets)
|
||||||
return nil
|
return nil
|
||||||
@@ -28,17 +26,8 @@ func (c *configurator) SetAllowedSubnets(ctx context.Context, subnets []net.IPNe
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultInterface, defaultGateway, err := c.routing.DefaultRoute()
|
c.removeSubnets(ctx, subnetsToRemove, c.defaultInterface, c.localSubnet)
|
||||||
if err != nil {
|
if err := c.addSubnets(ctx, subnetsToAdd, c.defaultInterface, c.defaultGateway, c.localSubnet); err != nil {
|
||||||
return fmt.Errorf("cannot set allowed subnets through firewall: %w", err)
|
|
||||||
}
|
|
||||||
localSubnet, err := c.routing.LocalSubnet()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot set allowed subnets through firewall: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.removeSubnets(ctx, subnetsToRemove, defaultInterface, localSubnet)
|
|
||||||
if err := c.addSubnets(ctx, subnetsToAdd, defaultInterface, defaultGateway, localSubnet); err != nil {
|
|
||||||
return fmt.Errorf("cannot set allowed subnets through firewall: %w", err)
|
return fmt.Errorf("cannot set allowed subnets through firewall: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,15 +124,12 @@ func (c *configurator) addSubnets(ctx context.Context, subnets []net.IPNet, defa
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *configurator) updateSubnetRoutes(ctx context.Context, oldSubnets, newSubnets []net.IPNet) error {
|
// updateSubnetRoutes does not return an error in order to try to run as many route commands as possible
|
||||||
|
func (c *configurator) updateSubnetRoutes(ctx context.Context, oldSubnets, newSubnets []net.IPNet) {
|
||||||
subnetsToAdd := findSubnetsToAdd(oldSubnets, newSubnets)
|
subnetsToAdd := findSubnetsToAdd(oldSubnets, newSubnets)
|
||||||
subnetsToRemove := findSubnetsToRemove(oldSubnets, newSubnets)
|
subnetsToRemove := findSubnetsToRemove(oldSubnets, newSubnets)
|
||||||
if len(subnetsToAdd) == 0 && len(subnetsToRemove) == 0 {
|
if len(subnetsToAdd) == 0 && len(subnetsToRemove) == 0 {
|
||||||
return nil
|
return
|
||||||
}
|
|
||||||
defaultInterface, defaultGateway, err := c.routing.DefaultRoute()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
for _, subnet := range subnetsToRemove {
|
for _, subnet := range subnetsToRemove {
|
||||||
if err := c.routing.DeleteRouteVia(ctx, subnet); err != nil {
|
if err := c.routing.DeleteRouteVia(ctx, subnet); err != nil {
|
||||||
@@ -151,9 +137,8 @@ func (c *configurator) updateSubnetRoutes(ctx context.Context, oldSubnets, newSu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, subnet := range subnetsToAdd {
|
for _, subnet := range subnetsToAdd {
|
||||||
if err := c.routing.AddRouteVia(ctx, subnet, defaultGateway, defaultInterface); err != nil {
|
if err := c.routing.AddRouteVia(ctx, subnet, c.defaultGateway, c.defaultInterface); err != nil {
|
||||||
c.logger.Error("cannot add route for subnet: %s", err)
|
c.logger.Error("cannot add route for subnet: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,13 +26,8 @@ func (c *configurator) SetVPNConnections(ctx context.Context, connections []mode
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultInterface, _, err := c.routing.DefaultRoute()
|
c.removeConnections(ctx, connectionsToRemove, c.defaultInterface)
|
||||||
if err != nil {
|
if err := c.addConnections(ctx, connectionsToAdd, c.defaultInterface); err != nil {
|
||||||
return fmt.Errorf("cannot set VPN connections through firewall: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.removeConnections(ctx, connectionsToRemove, defaultInterface)
|
|
||||||
if err := c.addConnections(ctx, connectionsToAdd, defaultInterface); err != nil {
|
|
||||||
return fmt.Errorf("cannot set VPN connections through firewall: %w", err)
|
return fmt.Errorf("cannot set VPN connections through firewall: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// VPNDevice is the device name used to tunnel using Openvpn
|
// VPNDevice is the device name used to tunnel using Openvpn
|
||||||
VPNDevice string
|
VPNDevice string
|
||||||
@@ -14,7 +19,45 @@ type (
|
|||||||
// TinyProxyLogLevel is the log level for TinyProxy
|
// TinyProxyLogLevel is the log level for TinyProxy
|
||||||
TinyProxyLogLevel string
|
TinyProxyLogLevel string
|
||||||
// VPNProvider is the name of the VPN provider to be used
|
// VPNProvider is the name of the VPN provider to be used
|
||||||
VPNProvider string // TODO
|
VPNProvider string
|
||||||
// NetworkProtocol contains the network protocol to be used to communicate with the VPN servers
|
// NetworkProtocol contains the network protocol to be used to communicate with the VPN servers
|
||||||
NetworkProtocol string
|
NetworkProtocol string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func marshalJSONString(s string) (data []byte, err error) {
|
||||||
|
return []byte(fmt.Sprintf("%q", s)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unmarshalJSONString(data []byte) (s string) {
|
||||||
|
s = string(data)
|
||||||
|
s = strings.TrimPrefix(s, "\"")
|
||||||
|
s = strings.TrimSuffix(s, "\"")
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *VPNProvider) MarshalJSON() ([]byte, error) {
|
||||||
|
return marshalJSONString(string(*v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *VPNProvider) UnmarshalJSON(data []byte) error {
|
||||||
|
*v = VPNProvider(unmarshalJSONString(data))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkProtocol) MarshalJSON() ([]byte, error) {
|
||||||
|
return marshalJSONString(string(*n))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *NetworkProtocol) UnmarshalJSON(data []byte) error {
|
||||||
|
*n = NetworkProtocol(unmarshalJSONString(data))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Filepath) MarshalJSON() ([]byte, error) {
|
||||||
|
return marshalJSONString(string(*f))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Filepath) UnmarshalJSON(data []byte) error {
|
||||||
|
*f = Filepath(unmarshalJSONString(data))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
41
internal/models/alias_test.go
Normal file
41
internal/models/alias_test.go
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_VPNProvider_JSON(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
v := VPNProvider("name")
|
||||||
|
data, err := v.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte{0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22}, data)
|
||||||
|
err = v.UnmarshalJSON(data)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, VPNProvider("name"), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_NetworkProtocol_JSON(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
v := NetworkProtocol("name")
|
||||||
|
data, err := v.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte{0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22}, data)
|
||||||
|
err = v.UnmarshalJSON(data)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, NetworkProtocol("name"), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Filepath_JSON(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
v := Filepath("name")
|
||||||
|
data, err := v.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, []byte{0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22}, data)
|
||||||
|
err = v.UnmarshalJSON(data)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, Filepath("name"), v)
|
||||||
|
}
|
||||||
@@ -8,48 +8,50 @@ import (
|
|||||||
|
|
||||||
// ProviderSettings contains settings specific to a VPN provider
|
// ProviderSettings contains settings specific to a VPN provider
|
||||||
type ProviderSettings struct {
|
type ProviderSettings struct {
|
||||||
Name VPNProvider
|
Name VPNProvider `json:"name"`
|
||||||
ServerSelection ServerSelection
|
ServerSelection ServerSelection `json:"serverSelection"`
|
||||||
ExtraConfigOptions ExtraConfigOptions
|
ExtraConfigOptions ExtraConfigOptions `json:"extraConfig"`
|
||||||
PortForwarding PortForwarding
|
PortForwarding PortForwarding `json:"portForwarding"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServerSelection struct { //nolint:maligned
|
type ServerSelection struct { //nolint:maligned
|
||||||
// Common
|
// Common
|
||||||
Protocol NetworkProtocol
|
Protocol NetworkProtocol `json:"networkProtocol"`
|
||||||
TargetIP net.IP
|
TargetIP net.IP `json:"targetIP,omitempty"`
|
||||||
|
|
||||||
// Cyberghost, PIA, Surfshark, Windscribe, Vyprvpn, NordVPN
|
// Cyberghost, PIA, Surfshark, Windscribe, Vyprvpn, NordVPN
|
||||||
Region string
|
Region string `json:"region"`
|
||||||
|
|
||||||
// Cyberghost
|
// Cyberghost
|
||||||
Group string
|
Group string `json:"group"`
|
||||||
|
|
||||||
|
// Mullvad, PureVPN
|
||||||
|
Country string `json:"country"`
|
||||||
|
City string `json:"city"`
|
||||||
|
|
||||||
// Mullvad
|
// Mullvad
|
||||||
Country string
|
ISP string `json:"isp"`
|
||||||
City string
|
Owned bool `json:"owned"`
|
||||||
ISP string
|
|
||||||
Owned bool
|
|
||||||
|
|
||||||
// Mullvad, Windscribe
|
// Mullvad, Windscribe
|
||||||
CustomPort uint16
|
CustomPort uint16 `json:"customPort"`
|
||||||
|
|
||||||
// PIA
|
|
||||||
EncryptionPreset string
|
|
||||||
|
|
||||||
// NordVPN
|
// NordVPN
|
||||||
Number uint16
|
Number uint16 `json:"number"`
|
||||||
|
|
||||||
|
// PIA
|
||||||
|
EncryptionPreset string `json:"encryptionPreset"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExtraConfigOptions struct {
|
type ExtraConfigOptions struct {
|
||||||
ClientKey string // Cyberghost
|
ClientKey string `json:"-"` // Cyberghost
|
||||||
EncryptionPreset string // PIA
|
EncryptionPreset string `json:"encryptionPreset"` // PIA
|
||||||
}
|
}
|
||||||
|
|
||||||
// PortForwarding contains settings for port forwarding
|
// PortForwarding contains settings for port forwarding
|
||||||
type PortForwarding struct {
|
type PortForwarding struct {
|
||||||
Enabled bool
|
Enabled bool `json:"enabled"`
|
||||||
Filepath Filepath
|
Filepath Filepath `json:"filepath"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PortForwarding) String() string {
|
func (p *PortForwarding) String() string {
|
||||||
@@ -110,6 +112,12 @@ func (p *ProviderSettings) String() string {
|
|||||||
"Region: "+p.ServerSelection.Region,
|
"Region: "+p.ServerSelection.Region,
|
||||||
"Number: "+number,
|
"Number: "+number,
|
||||||
)
|
)
|
||||||
|
case "purevpn":
|
||||||
|
settingsList = append(settingsList,
|
||||||
|
"Region: "+p.ServerSelection.Region,
|
||||||
|
"Country: "+p.ServerSelection.Country,
|
||||||
|
"City: "+p.ServerSelection.City,
|
||||||
|
)
|
||||||
default:
|
default:
|
||||||
settingsList = append(settingsList,
|
settingsList = append(settingsList,
|
||||||
"<Missing String method, please implement me!>",
|
"<Missing String method, please implement me!>",
|
||||||
|
|||||||
@@ -44,3 +44,10 @@ type NordvpnServer struct { //nolint:maligned
|
|||||||
TCP bool
|
TCP bool
|
||||||
UDP bool
|
UDP bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PurevpnServer struct {
|
||||||
|
Region string
|
||||||
|
Country string
|
||||||
|
City string
|
||||||
|
IPs []net.IP
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ type Looper interface {
|
|||||||
PortForward()
|
PortForward()
|
||||||
GetSettings() (settings settings.OpenVPN)
|
GetSettings() (settings settings.OpenVPN)
|
||||||
SetSettings(settings settings.OpenVPN)
|
SetSettings(settings settings.OpenVPN)
|
||||||
|
GetPortForwarded() (portForwarded uint16)
|
||||||
}
|
}
|
||||||
|
|
||||||
type looper struct {
|
type looper struct {
|
||||||
@@ -30,6 +31,8 @@ type looper struct {
|
|||||||
provider models.VPNProvider
|
provider models.VPNProvider
|
||||||
settings settings.OpenVPN
|
settings settings.OpenVPN
|
||||||
settingsMutex sync.RWMutex
|
settingsMutex sync.RWMutex
|
||||||
|
portForwarded uint16
|
||||||
|
portForwardedMutex sync.RWMutex
|
||||||
// Fixed parameters
|
// Fixed parameters
|
||||||
uid int
|
uid int
|
||||||
gid int
|
gid int
|
||||||
@@ -98,7 +101,10 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
|||||||
settings := l.GetSettings()
|
settings := l.GetSettings()
|
||||||
providerConf := provider.New(l.provider)
|
providerConf := provider.New(l.provider)
|
||||||
connections, err := providerConf.GetOpenVPNConnections(settings.Provider.ServerSelection)
|
connections, err := providerConf.GetOpenVPNConnections(settings.Provider.ServerSelection)
|
||||||
|
if err != nil {
|
||||||
l.fatalOnError(err)
|
l.fatalOnError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
lines := providerConf.BuildConf(
|
lines := providerConf.BuildConf(
|
||||||
connections,
|
connections,
|
||||||
settings.Verbosity,
|
settings.Verbosity,
|
||||||
@@ -109,14 +115,19 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
|||||||
settings.Auth,
|
settings.Auth,
|
||||||
settings.Provider.ExtraConfigOptions,
|
settings.Provider.ExtraConfigOptions,
|
||||||
)
|
)
|
||||||
err = l.fileManager.WriteLinesToFile(string(constants.OpenVPNConf), lines, files.Ownership(l.uid, l.gid), files.Permissions(0400))
|
if err := l.fileManager.WriteLinesToFile(string(constants.OpenVPNConf), lines, files.Ownership(l.uid, l.gid), files.Permissions(0400)); err != nil {
|
||||||
l.fatalOnError(err)
|
l.fatalOnError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err = l.conf.WriteAuthFile(settings.User, settings.Password, l.uid, l.gid)
|
if err := l.conf.WriteAuthFile(settings.User, settings.Password, l.uid, l.gid); err != nil {
|
||||||
l.fatalOnError(err)
|
l.fatalOnError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err := l.fw.SetVPNConnections(ctx, connections); err != nil {
|
if err := l.fw.SetVPNConnections(ctx, connections); err != nil {
|
||||||
l.fatalOnError(err)
|
l.fatalOnError(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
openvpnCtx, openvpnCancel := context.WithCancel(context.Background())
|
openvpnCtx, openvpnCancel := context.WithCancel(context.Background())
|
||||||
@@ -187,10 +198,19 @@ func (l *looper) portForward(ctx context.Context, providerConf provider.Provider
|
|||||||
port, err = providerConf.GetPortForward(client)
|
port, err = providerConf.GetPortForward(client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.logAndWait(ctx, err)
|
l.logAndWait(ctx, err)
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
l.logger.Info("port forwarded is %d", port)
|
l.logger.Info("port forwarded is %d", port)
|
||||||
|
l.portForwardedMutex.Lock()
|
||||||
|
if err := l.fw.RemoveAllowedPort(ctx, l.portForwarded); err != nil {
|
||||||
|
l.logger.Error(err)
|
||||||
}
|
}
|
||||||
|
if err := l.fw.SetAllowedPort(ctx, port, string(constants.TUN)); err != nil {
|
||||||
|
l.logger.Error(err)
|
||||||
|
}
|
||||||
|
l.portForwarded = port
|
||||||
|
l.portForwardedMutex.Unlock()
|
||||||
|
|
||||||
filepath := settings.Provider.PortForwarding.Filepath
|
filepath := settings.Provider.PortForwarding.Filepath
|
||||||
l.logger.Info("writing forwarded port to %s", filepath)
|
l.logger.Info("writing forwarded port to %s", filepath)
|
||||||
@@ -201,8 +221,10 @@ func (l *looper) portForward(ctx context.Context, providerConf provider.Provider
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
l.logger.Error(err)
|
l.logger.Error(err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := l.fw.SetPortForward(ctx, port); err != nil {
|
func (l *looper) GetPortForwarded() (portForwarded uint16) {
|
||||||
l.logger.Error(err)
|
l.portForwardedMutex.RLock()
|
||||||
}
|
defer l.portForwardedMutex.RUnlock()
|
||||||
|
return l.portForwarded
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,14 +10,15 @@ import (
|
|||||||
// GetCyberghostGroup obtains the server group for the Cyberghost server from the
|
// GetCyberghostGroup obtains the server group for the Cyberghost server from the
|
||||||
// environment variable CYBERGHOST_GROUP
|
// environment variable CYBERGHOST_GROUP
|
||||||
func (p *reader) GetCyberghostGroup() (group string, err error) {
|
func (p *reader) GetCyberghostGroup() (group string, err error) {
|
||||||
s, err := p.envParams.GetValueIfInside("CYBERGHOST_GROUP", constants.CyberghostGroupChoices())
|
s, err := p.envParams.GetValueIfInside("CYBERGHOST_GROUP", constants.CyberghostGroupChoices(), libparams.Default("Premium UDP Europe"))
|
||||||
return s, err
|
return s, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCyberghostRegion obtains the country name for the Cyberghost server from the
|
// GetCyberghostRegion obtains the country name for the Cyberghost server from the
|
||||||
// environment variable REGION
|
// environment variable REGION
|
||||||
func (p *reader) GetCyberghostRegion() (region string, err error) {
|
func (p *reader) GetCyberghostRegion() (region string, err error) {
|
||||||
s, err := p.envParams.GetValueIfInside("REGION", constants.CyberghostRegionChoices())
|
choices := append(constants.CyberghostRegionChoices(), "")
|
||||||
|
s, err := p.envParams.GetValueIfInside("REGION", choices)
|
||||||
return s, err
|
return s, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package params
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
libparams "github.com/qdm12/golibs/params"
|
||||||
@@ -35,6 +36,30 @@ func (r *reader) GetExtraSubnets() (extraSubnets []net.IPNet, err error) {
|
|||||||
return extraSubnets, nil
|
return extraSubnets, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAllowedVPNInputPorts obtains a list of input ports to allow from the
|
||||||
|
// VPN server side in the firewall, from the environment variable FIREWALL_VPN_INPUT_PORTS
|
||||||
|
func (r *reader) GetVPNInputPorts() (ports []uint16, err error) {
|
||||||
|
s, err := r.envParams.GetEnv("FIREWALL_VPN_INPUT_PORTS", libparams.Default(""))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(s) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
portsStr := strings.Split(s, ",")
|
||||||
|
ports = make([]uint16, len(portsStr))
|
||||||
|
for i := range portsStr {
|
||||||
|
portInt, err := strconv.Atoi(portsStr[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("VPN input port %q is not valid (%s)", portInt, err)
|
||||||
|
} else if portInt <= 0 || portInt > 65535 {
|
||||||
|
return nil, fmt.Errorf("VPN input port %d must be between 1 and 65535", portInt)
|
||||||
|
}
|
||||||
|
ports[i] = uint16(portInt)
|
||||||
|
}
|
||||||
|
return ports, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetFirewallDebug obtains if the firewall should run in debug verbose mode from the environment variable FIREWALL_DEBUG
|
// GetFirewallDebug obtains if the firewall should run in debug verbose mode from the environment variable FIREWALL_DEBUG
|
||||||
func (r *reader) GetFirewallDebug() (debug bool, err error) {
|
func (r *reader) GetFirewallDebug() (debug bool, err error) {
|
||||||
return r.envParams.GetOnOff("FIREWALL_DEBUG", libparams.Default("off"))
|
return r.envParams.GetOnOff("FIREWALL_DEBUG", libparams.Default("off"))
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import (
|
|||||||
// GetNordvpnRegion obtains the region (country) for the NordVPN server from the
|
// GetNordvpnRegion obtains the region (country) for the NordVPN server from the
|
||||||
// environment variable REGION
|
// environment variable REGION
|
||||||
func (r *reader) GetNordvpnRegion() (region string, err error) {
|
func (r *reader) GetNordvpnRegion() (region string, err error) {
|
||||||
return r.envParams.GetValueIfInside("REGION", constants.NordvpnRegionChoices())
|
choices := append(constants.NordvpnRegionChoices(), "")
|
||||||
|
return r.envParams.GetValueIfInside("REGION", choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNordvpnRegion obtains the server number (optional) for the NordVPN server from the
|
// GetNordvpnRegion obtains the server number (optional) for the NordVPN server from the
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ type Reader interface {
|
|||||||
// Firewall getters
|
// Firewall getters
|
||||||
GetFirewall() (enabled bool, err error)
|
GetFirewall() (enabled bool, err error)
|
||||||
GetExtraSubnets() (extraSubnets []net.IPNet, err error)
|
GetExtraSubnets() (extraSubnets []net.IPNet, err error)
|
||||||
|
GetVPNInputPorts() (ports []uint16, err error)
|
||||||
GetFirewallDebug() (debug bool, err error)
|
GetFirewallDebug() (debug bool, err error)
|
||||||
|
|
||||||
// VPN getters
|
// VPN getters
|
||||||
@@ -85,6 +86,11 @@ type Reader interface {
|
|||||||
GetNordvpnRegion() (region string, err error)
|
GetNordvpnRegion() (region string, err error)
|
||||||
GetNordvpnNumber() (number uint16, err error)
|
GetNordvpnNumber() (number uint16, err error)
|
||||||
|
|
||||||
|
// PureVPN getters
|
||||||
|
GetPurevpnRegion() (region string, err error)
|
||||||
|
GetPurevpnCountry() (country string, err error)
|
||||||
|
GetPurevpnCity() (city string, 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)
|
||||||
@@ -130,7 +136,7 @@ func NewReader(logger logging.Logger, fileManager files.FileManager) Reader {
|
|||||||
|
|
||||||
// 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 (r *reader) GetVPNSP() (vpnServiceProvider models.VPNProvider, err error) {
|
func (r *reader) GetVPNSP() (vpnServiceProvider models.VPNProvider, err error) {
|
||||||
s, err := r.envParams.GetValueIfInside("VPNSP", []string{"pia", "private internet access", "mullvad", "windscribe", "surfshark", "cyberghost", "vyprvpn", "nordvpn"})
|
s, err := r.envParams.GetValueIfInside("VPNSP", []string{"pia", "private internet access", "mullvad", "windscribe", "surfshark", "cyberghost", "vyprvpn", "nordvpn", "purevpn"})
|
||||||
if s == "pia" {
|
if s == "pia" {
|
||||||
s = "private internet access"
|
s = "private internet access"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package params
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
|
||||||
|
|
||||||
libparams "github.com/qdm12/golibs/params"
|
libparams "github.com/qdm12/golibs/params"
|
||||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||||
@@ -60,9 +59,5 @@ func (r *reader) GetPIAEncryptionPreset() (preset string, err error) {
|
|||||||
// environment variable REGION
|
// environment variable REGION
|
||||||
func (r *reader) GetPIARegion() (region string, err error) {
|
func (r *reader) GetPIARegion() (region string, err error) {
|
||||||
choices := append(constants.PIAGeoChoices(), "")
|
choices := append(constants.PIAGeoChoices(), "")
|
||||||
s, err := r.envParams.GetValueIfInside("REGION", choices)
|
return r.envParams.GetValueIfInside("REGION", choices)
|
||||||
if len(s) == 0 { // Suggestion by @rorph https://github.com/rorph
|
|
||||||
s = choices[rand.Int()%len(choices)] //nolint:gosec
|
|
||||||
}
|
|
||||||
return s, err
|
|
||||||
}
|
}
|
||||||
|
|||||||
26
internal/params/purevpn.go
Normal file
26
internal/params/purevpn.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package params
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetPurevpnRegion obtains the region (continent) for the PureVPN server from the
|
||||||
|
// environment variable REGION
|
||||||
|
func (r *reader) GetPurevpnRegion() (region string, err error) {
|
||||||
|
choices := append(constants.PurevpnRegionChoices(), "")
|
||||||
|
return r.envParams.GetValueIfInside("REGION", choices)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPurevpnCountry obtains the country for the PureVPN server from the
|
||||||
|
// environment variable COUNTRY
|
||||||
|
func (r *reader) GetPurevpnCountry() (country string, err error) {
|
||||||
|
choices := append(constants.PurevpnCountryChoices(), "")
|
||||||
|
return r.envParams.GetValueIfInside("COUNTRY", choices)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPurevpnCity obtains the city for the PureVPN server from the
|
||||||
|
// environment variable CITY
|
||||||
|
func (r *reader) GetPurevpnCity() (city string, err error) {
|
||||||
|
choices := append(constants.PurevpnCityChoices(), "")
|
||||||
|
return r.envParams.GetValueIfInside("CITY", choices)
|
||||||
|
}
|
||||||
@@ -7,6 +7,6 @@ import (
|
|||||||
// GetSurfsharkRegion obtains the region for the Surfshark server from the
|
// GetSurfsharkRegion obtains the region for the Surfshark server from the
|
||||||
// environment variable REGION
|
// environment variable REGION
|
||||||
func (r *reader) GetSurfsharkRegion() (region string, err error) {
|
func (r *reader) GetSurfsharkRegion() (region string, err error) {
|
||||||
s, err := r.envParams.GetValueIfInside("REGION", constants.SurfsharkRegionChoices())
|
choices := append(constants.SurfsharkRegionChoices(), "")
|
||||||
return s, err
|
return r.envParams.GetValueIfInside("REGION", choices)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,5 +7,6 @@ import (
|
|||||||
// GetVyprvpnRegion obtains the region for the Vyprvpn server from the
|
// GetVyprvpnRegion obtains the region for the Vyprvpn server from the
|
||||||
// environment variable REGION
|
// environment variable REGION
|
||||||
func (r *reader) GetVyprvpnRegion() (region string, err error) {
|
func (r *reader) GetVyprvpnRegion() (region string, err error) {
|
||||||
return r.envParams.GetValueIfInside("REGION", constants.VyprvpnRegionChoices())
|
choices := append(constants.VyprvpnRegionChoices(), "")
|
||||||
|
return r.envParams.GetValueIfInside("REGION", choices)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import (
|
|||||||
// GetWindscribeRegion obtains the region for the Windscribe server from the
|
// GetWindscribeRegion obtains the region for the Windscribe server from the
|
||||||
// environment variable REGION
|
// environment variable REGION
|
||||||
func (r *reader) GetWindscribeRegion() (region string, err error) {
|
func (r *reader) GetWindscribeRegion() (region string, err error) {
|
||||||
s, err := r.envParams.GetValueIfInside("REGION", constants.WindscribeRegionChoices())
|
choices := append(constants.WindscribeRegionChoices(), "")
|
||||||
return s, err
|
return r.envParams.GetValueIfInside("REGION", choices)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMullvadPort obtains the port to reach the Mullvad server on from the
|
// GetMullvadPort obtains the port to reach the Mullvad server on from the
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package provider
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/qdm12/golibs/network"
|
"github.com/qdm12/golibs/network"
|
||||||
@@ -16,32 +15,48 @@ func newCyberghost() *cyberghost {
|
|||||||
return &cyberghost{}
|
return &cyberghost{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *cyberghost) filterServers(region, group string) (servers []models.CyberghostServer) {
|
||||||
|
allServers := constants.CyberghostServers()
|
||||||
|
for i, server := range allServers {
|
||||||
|
if len(region) == 0 {
|
||||||
|
server.Region = ""
|
||||||
|
}
|
||||||
|
if len(group) == 0 {
|
||||||
|
server.Group = ""
|
||||||
|
}
|
||||||
|
if strings.EqualFold(server.Region, region) && strings.EqualFold(server.Group, group) {
|
||||||
|
servers = append(servers, allServers[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
func (c *cyberghost) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) {
|
func (c *cyberghost) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) {
|
||||||
var IPs []net.IP
|
servers := c.filterServers(selection.Region, selection.Group)
|
||||||
for _, server := range constants.CyberghostServers() {
|
if len(servers) == 0 {
|
||||||
if strings.EqualFold(server.Region, selection.Region) && strings.EqualFold(server.Group, selection.Group) {
|
return nil, fmt.Errorf("no server found for region %q and group %q", selection.Region, selection.Group)
|
||||||
IPs = server.IPs
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(IPs) == 0 {
|
|
||||||
return nil, fmt.Errorf("no IP found for group %q and region %q", selection.Group, selection.Region)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, server := range servers {
|
||||||
|
for _, IP := range server.IPs {
|
||||||
if selection.TargetIP != nil {
|
if selection.TargetIP != nil {
|
||||||
found := false
|
if selection.TargetIP.Equal(IP) {
|
||||||
for i := range IPs {
|
return []models.OpenVPNConnection{{IP: IP, Port: 443, Protocol: selection.Protocol}}, nil
|
||||||
if IPs[i].Equal(selection.TargetIP) {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
if !found {
|
|
||||||
return nil, fmt.Errorf("target IP address %q not found in IP addresses", selection.TargetIP)
|
|
||||||
}
|
|
||||||
IPs = []net.IP{selection.TargetIP}
|
|
||||||
}
|
|
||||||
for _, IP := range IPs {
|
|
||||||
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: 443, Protocol: selection.Protocol})
|
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: 443, Protocol: selection.Protocol})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if selection.TargetIP != nil {
|
||||||
|
return nil, fmt.Errorf("target IP %s not found in IP addresses", selection.TargetIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(connections) > 64 {
|
||||||
|
connections = connections[:64]
|
||||||
|
}
|
||||||
|
|
||||||
return connections, nil
|
return connections, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package provider
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/qdm12/golibs/network"
|
"github.com/qdm12/golibs/network"
|
||||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||||
@@ -14,11 +15,33 @@ func newMullvad() *mullvad {
|
|||||||
return &mullvad{}
|
return &mullvad{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mullvad) filterServers(country, city, isp string) (servers []models.MullvadServer) {
|
||||||
|
allServers := constants.MullvadServers()
|
||||||
|
for i, server := range allServers {
|
||||||
|
if len(country) == 0 {
|
||||||
|
server.Country = ""
|
||||||
|
}
|
||||||
|
if len(city) == 0 {
|
||||||
|
server.City = ""
|
||||||
|
}
|
||||||
|
if len(isp) == 0 {
|
||||||
|
server.ISP = ""
|
||||||
|
}
|
||||||
|
if strings.EqualFold(server.Country, country) &&
|
||||||
|
strings.EqualFold(server.City, city) &&
|
||||||
|
strings.EqualFold(server.ISP, isp) {
|
||||||
|
servers = append(servers, allServers[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
func (m *mullvad) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) {
|
func (m *mullvad) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) {
|
||||||
servers := constants.MullvadServerFilter(selection.Country, selection.City, selection.ISP)
|
servers := m.filterServers(selection.Country, selection.City, selection.ISP)
|
||||||
if len(servers) == 0 {
|
if len(servers) == 0 {
|
||||||
return nil, fmt.Errorf("no server found for country %q, city %q and ISP %q", selection.Country, selection.City, selection.ISP)
|
return nil, fmt.Errorf("no server found for country %q, city %q and ISP %q", selection.Country, selection.City, selection.ISP)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, server := range servers {
|
for _, server := range servers {
|
||||||
port := server.DefaultPort
|
port := server.DefaultPort
|
||||||
if selection.CustomPort > 0 {
|
if selection.CustomPort > 0 {
|
||||||
@@ -34,9 +57,15 @@ func (m *mullvad) GetOpenVPNConnections(selection models.ServerSelection) (conne
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if selection.TargetIP != nil {
|
if selection.TargetIP != nil {
|
||||||
return nil, fmt.Errorf("target IP address %q not found in IP addresses", selection.TargetIP)
|
return nil, fmt.Errorf("target IP address %q not found in IP addresses", selection.TargetIP)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(connections) > 64 {
|
||||||
|
connections = connections[:64]
|
||||||
|
}
|
||||||
|
|
||||||
return connections, nil
|
return connections, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package provider
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/qdm12/golibs/network"
|
"github.com/qdm12/golibs/network"
|
||||||
@@ -16,60 +15,34 @@ func newNordvpn() *nordvpn {
|
|||||||
return &nordvpn{}
|
return &nordvpn{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func findServers(selection models.ServerSelection) (servers []models.NordvpnServer) {
|
func (n *nordvpn) filterServers(region string, protocol models.NetworkProtocol, number uint16) (servers []models.NordvpnServer) {
|
||||||
for _, server := range constants.NordvpnServers() {
|
allServers := constants.NordvpnServers()
|
||||||
if strings.EqualFold(server.Region, selection.Region) {
|
for i, server := range allServers {
|
||||||
if (selection.Protocol == constants.TCP && !server.TCP) || (selection.Protocol == constants.UDP && !server.UDP) {
|
if len(region) == 0 {
|
||||||
|
server.Region = ""
|
||||||
|
}
|
||||||
|
if number == 0 {
|
||||||
|
server.Number = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if protocol == constants.TCP && !server.TCP {
|
||||||
|
continue
|
||||||
|
} else if protocol == constants.UDP && !server.UDP {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if selection.Number > 0 && server.Number == selection.Number {
|
if strings.EqualFold(server.Region, region) && server.Number == number {
|
||||||
return []models.NordvpnServer{server}
|
servers = append(servers, allServers[i])
|
||||||
}
|
|
||||||
servers = append(servers, server)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return servers
|
return servers
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractIPsFromServers(servers []models.NordvpnServer) (ips []net.IP) {
|
|
||||||
ips = make([]net.IP, len(servers))
|
|
||||||
for i := range servers {
|
|
||||||
ips[i] = servers[i].IP
|
|
||||||
}
|
|
||||||
return ips
|
|
||||||
}
|
|
||||||
|
|
||||||
func targetIPInIps(targetIP net.IP, ips []net.IP) error {
|
|
||||||
for i := range ips {
|
|
||||||
if targetIP.Equal(ips[i]) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ipsString := make([]string, len(ips))
|
|
||||||
for i := range ips {
|
|
||||||
ipsString[i] = ips[i].String()
|
|
||||||
}
|
|
||||||
return fmt.Errorf("target IP address %s not found in IP addresses %s", targetIP, strings.Join(ipsString, ", "))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *nordvpn) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) { //nolint:dupl
|
func (n *nordvpn) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) { //nolint:dupl
|
||||||
servers := findServers(selection)
|
servers := n.filterServers(selection.Region, selection.Protocol, selection.Number)
|
||||||
ips := extractIPsFromServers(servers)
|
if len(servers) == 0 {
|
||||||
if len(ips) == 0 {
|
return nil, fmt.Errorf("no server found for region %q, protocol %s and number %d", selection.Region, selection.Protocol, selection.Number)
|
||||||
if selection.Number > 0 {
|
|
||||||
return nil, fmt.Errorf("no IP found for region %q, protocol %s and number %d", selection.Region, selection.Protocol, selection.Number)
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("no IP found for region %q, protocol %s", selection.Region, selection.Protocol)
|
|
||||||
}
|
|
||||||
var IP net.IP
|
|
||||||
if selection.TargetIP != nil {
|
|
||||||
if err := targetIPInIps(selection.TargetIP, ips); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
IP = selection.TargetIP
|
|
||||||
} else {
|
|
||||||
IP = ips[0]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var port uint16
|
var port uint16
|
||||||
switch {
|
switch {
|
||||||
case selection.Protocol == constants.UDP:
|
case selection.Protocol == constants.UDP:
|
||||||
@@ -79,7 +52,26 @@ func (n *nordvpn) GetOpenVPNConnections(selection models.ServerSelection) (conne
|
|||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol)
|
return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol)
|
||||||
}
|
}
|
||||||
return []models.OpenVPNConnection{{IP: IP, Port: port, Protocol: selection.Protocol}}, nil
|
|
||||||
|
for _, server := range servers {
|
||||||
|
if selection.TargetIP != nil {
|
||||||
|
if selection.TargetIP.Equal(server.IP) {
|
||||||
|
return []models.OpenVPNConnection{{IP: server.IP, Port: port, Protocol: selection.Protocol}}, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
connections = append(connections, models.OpenVPNConnection{IP: server.IP, Port: port, Protocol: selection.Protocol})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if selection.TargetIP != nil {
|
||||||
|
return nil, fmt.Errorf("target IP %s not found in IP addresses", selection.TargetIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(connections) > 64 {
|
||||||
|
connections = connections[:64]
|
||||||
|
}
|
||||||
|
|
||||||
|
return connections, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *nordvpn) BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) { //nolint:dupl
|
func (n *nordvpn) BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) { //nolint:dupl
|
||||||
@@ -97,7 +89,6 @@ func (n *nordvpn) BuildConf(connections []models.OpenVPNConnection, verbosity, u
|
|||||||
"remote-cert-tls server",
|
"remote-cert-tls server",
|
||||||
|
|
||||||
// Nordvpn specific
|
// Nordvpn specific
|
||||||
"resolv-retry infinite",
|
|
||||||
"tun-mtu 1500",
|
"tun-mtu 1500",
|
||||||
"tun-mtu-extra 32",
|
"tun-mtu-extra 32",
|
||||||
"mssfix 1450",
|
"mssfix 1450",
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -24,29 +23,24 @@ func newPrivateInternetAccess() *pia {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *pia) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) {
|
func (p *pia) filterServers(region string) (servers []models.PIAServer) {
|
||||||
var IPs []net.IP
|
if len(region) == 0 {
|
||||||
|
return constants.PIAServers()
|
||||||
|
}
|
||||||
for _, server := range constants.PIAServers() {
|
for _, server := range constants.PIAServers() {
|
||||||
if strings.EqualFold(server.Region, selection.Region) {
|
if strings.EqualFold(server.Region, region) {
|
||||||
IPs = server.IPs
|
return []models.PIAServer{server}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(IPs) == 0 {
|
return nil
|
||||||
return nil, fmt.Errorf("no IP found for region %q", selection.Region)
|
|
||||||
}
|
}
|
||||||
if selection.TargetIP != nil {
|
|
||||||
found := false
|
func (p *pia) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) {
|
||||||
for i := range IPs {
|
servers := p.filterServers(selection.Region)
|
||||||
if IPs[i].Equal(selection.TargetIP) {
|
if len(servers) == 0 {
|
||||||
found = true
|
return nil, fmt.Errorf("no server found for region %q", selection.Region)
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
return nil, fmt.Errorf("target IP address %q not found in IP addresses", selection.TargetIP)
|
|
||||||
}
|
|
||||||
IPs = []net.IP{selection.TargetIP}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var port uint16
|
var port uint16
|
||||||
switch selection.Protocol {
|
switch selection.Protocol {
|
||||||
case constants.TCP:
|
case constants.TCP:
|
||||||
@@ -67,9 +61,27 @@ func (p *pia) GetOpenVPNConnections(selection models.ServerSelection) (connectio
|
|||||||
if port == 0 {
|
if port == 0 {
|
||||||
return nil, fmt.Errorf("combination of protocol %q and encryption %q does not yield any port number", selection.Protocol, selection.EncryptionPreset)
|
return nil, fmt.Errorf("combination of protocol %q and encryption %q does not yield any port number", selection.Protocol, selection.EncryptionPreset)
|
||||||
}
|
}
|
||||||
for _, IP := range IPs {
|
|
||||||
|
for _, server := range servers {
|
||||||
|
for _, IP := range server.IPs {
|
||||||
|
if selection.TargetIP != nil {
|
||||||
|
if selection.TargetIP.Equal(IP) {
|
||||||
|
return []models.OpenVPNConnection{{IP: IP, Port: port, Protocol: selection.Protocol}}, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol})
|
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if selection.TargetIP != nil {
|
||||||
|
return nil, fmt.Errorf("target IP %s not found in IP addresses", selection.TargetIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(connections) > 64 {
|
||||||
|
connections = connections[:64]
|
||||||
|
}
|
||||||
|
|
||||||
return connections, nil
|
return connections, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ func New(provider models.VPNProvider) Provider {
|
|||||||
return newVyprvpn()
|
return newVyprvpn()
|
||||||
case constants.Nordvpn:
|
case constants.Nordvpn:
|
||||||
return newNordvpn()
|
return newNordvpn()
|
||||||
|
case constants.Purevpn:
|
||||||
|
return newPurevpn()
|
||||||
default:
|
default:
|
||||||
return nil // should never occur
|
return nil // should never occur
|
||||||
}
|
}
|
||||||
|
|||||||
159
internal/provider/purevpn.go
Normal file
159
internal/provider/purevpn.go
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
package provider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/qdm12/golibs/network"
|
||||||
|
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||||
|
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type purevpn struct{}
|
||||||
|
|
||||||
|
func newPurevpn() *purevpn {
|
||||||
|
return &purevpn{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *purevpn) filterServers(region, country, city string) (servers []models.PurevpnServer) {
|
||||||
|
allServers := constants.PurevpnServers()
|
||||||
|
for i, server := range allServers {
|
||||||
|
if len(region) == 0 {
|
||||||
|
server.Region = ""
|
||||||
|
}
|
||||||
|
if len(country) == 0 {
|
||||||
|
server.Country = ""
|
||||||
|
}
|
||||||
|
if len(city) == 0 {
|
||||||
|
server.City = ""
|
||||||
|
}
|
||||||
|
if strings.EqualFold(server.Region, region) &&
|
||||||
|
strings.EqualFold(server.Country, country) &&
|
||||||
|
strings.EqualFold(server.City, city) {
|
||||||
|
servers = append(servers, allServers[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return servers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *purevpn) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) { //nolint:dupl
|
||||||
|
servers := p.filterServers(selection.Region, selection.Country, selection.City)
|
||||||
|
if len(servers) == 0 {
|
||||||
|
return nil, fmt.Errorf("no server found for region %q, country %q and city %q", selection.Region, selection.Country, selection.City)
|
||||||
|
}
|
||||||
|
|
||||||
|
var port uint16
|
||||||
|
switch {
|
||||||
|
case selection.Protocol == constants.UDP:
|
||||||
|
port = 53
|
||||||
|
case selection.Protocol == constants.TCP:
|
||||||
|
port = 80
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, server := range servers {
|
||||||
|
for _, IP := range server.IPs {
|
||||||
|
if selection.TargetIP != nil {
|
||||||
|
if IP.Equal(selection.TargetIP) {
|
||||||
|
return []models.OpenVPNConnection{{IP: IP, Port: port, Protocol: selection.Protocol}}, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if selection.TargetIP != nil {
|
||||||
|
return nil, fmt.Errorf("target IP address %q not found in IP addresses", selection.TargetIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(connections) > 64 {
|
||||||
|
connections = connections[:64]
|
||||||
|
}
|
||||||
|
|
||||||
|
return connections, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *purevpn) BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) { //nolint:dupl
|
||||||
|
if len(cipher) == 0 {
|
||||||
|
cipher = aes256cbc
|
||||||
|
}
|
||||||
|
lines = []string{
|
||||||
|
"client",
|
||||||
|
"dev tun",
|
||||||
|
"nobind",
|
||||||
|
"persist-key",
|
||||||
|
"remote-cert-tls server",
|
||||||
|
|
||||||
|
// Purevpn specific
|
||||||
|
"key-direction 1",
|
||||||
|
"remote-cert-tls server",
|
||||||
|
"cipher AES-256-CBC",
|
||||||
|
"route-method exe",
|
||||||
|
"route-delay 0",
|
||||||
|
"route 0.0.0.0 0.0.0.0",
|
||||||
|
"script-security 2",
|
||||||
|
|
||||||
|
// Added constant values
|
||||||
|
"auth-nocache",
|
||||||
|
"mute-replay-warnings",
|
||||||
|
"pull-filter ignore \"auth-token\"", // prevent auth failed loops
|
||||||
|
"auth-retry nointeract",
|
||||||
|
"remote-random",
|
||||||
|
"suppress-timestamps",
|
||||||
|
|
||||||
|
// 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),
|
||||||
|
}
|
||||||
|
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.PurevpnCertificateAuthority,
|
||||||
|
"-----END CERTIFICATE-----",
|
||||||
|
"</ca>",
|
||||||
|
}...)
|
||||||
|
lines = append(lines, []string{
|
||||||
|
"<cert>",
|
||||||
|
"-----BEGIN CERTIFICATE-----",
|
||||||
|
constants.PurevpnCertificate,
|
||||||
|
"-----END CERTIFICATE-----",
|
||||||
|
"</cert>",
|
||||||
|
}...)
|
||||||
|
lines = append(lines, []string{
|
||||||
|
"<key>",
|
||||||
|
"-----BEGIN PRIVATE KEY-----",
|
||||||
|
constants.PurevpnKey,
|
||||||
|
"-----END PRIVATE KEY-----",
|
||||||
|
"</key>",
|
||||||
|
"",
|
||||||
|
}...)
|
||||||
|
lines = append(lines, []string{
|
||||||
|
"<tls-auth>",
|
||||||
|
"-----BEGIN OpenVPN Static key V1-----",
|
||||||
|
constants.PurevpnOpenvpnStaticKeyV1,
|
||||||
|
"-----END OpenVPN Static key V1-----",
|
||||||
|
"</tls-auth>",
|
||||||
|
"",
|
||||||
|
}...)
|
||||||
|
if len(auth) > 0 {
|
||||||
|
lines = append(lines, "auth "+auth)
|
||||||
|
}
|
||||||
|
if connections[0].Protocol == constants.UDP {
|
||||||
|
lines = append(lines, "explicit-exit-notify")
|
||||||
|
}
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *purevpn) GetPortForward(client network.Client) (port uint16, err error) {
|
||||||
|
panic("port forwarding is not supported for purevpn")
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@ package provider
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/qdm12/golibs/network"
|
"github.com/qdm12/golibs/network"
|
||||||
@@ -16,29 +15,24 @@ func newSurfshark() *surfshark {
|
|||||||
return &surfshark{}
|
return &surfshark{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *surfshark) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) { //nolint:dupl
|
func (s *surfshark) filterServers(region string) (servers []models.SurfsharkServer) {
|
||||||
var IPs []net.IP
|
if len(region) == 0 {
|
||||||
|
return constants.SurfsharkServers()
|
||||||
|
}
|
||||||
for _, server := range constants.SurfsharkServers() {
|
for _, server := range constants.SurfsharkServers() {
|
||||||
if strings.EqualFold(server.Region, selection.Region) {
|
if strings.EqualFold(server.Region, region) {
|
||||||
IPs = server.IPs
|
return []models.SurfsharkServer{server}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(IPs) == 0 {
|
return nil
|
||||||
return nil, fmt.Errorf("no IP found for region %q", selection.Region)
|
|
||||||
}
|
}
|
||||||
if selection.TargetIP != nil {
|
|
||||||
found := false
|
func (s *surfshark) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) { //nolint:dupl
|
||||||
for i := range IPs {
|
servers := s.filterServers(selection.Region)
|
||||||
if IPs[i].Equal(selection.TargetIP) {
|
if len(servers) == 0 {
|
||||||
found = true
|
return nil, fmt.Errorf("no server found for region %q", selection.Region)
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
return nil, fmt.Errorf("target IP address %q not found in IP addresses", selection.TargetIP)
|
|
||||||
}
|
|
||||||
IPs = []net.IP{selection.TargetIP}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var port uint16
|
var port uint16
|
||||||
switch {
|
switch {
|
||||||
case selection.Protocol == constants.TCP:
|
case selection.Protocol == constants.TCP:
|
||||||
@@ -48,9 +42,27 @@ func (s *surfshark) GetOpenVPNConnections(selection models.ServerSelection) (con
|
|||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol)
|
return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol)
|
||||||
}
|
}
|
||||||
for _, IP := range IPs {
|
|
||||||
|
for _, server := range servers {
|
||||||
|
for _, IP := range server.IPs {
|
||||||
|
if selection.TargetIP != nil {
|
||||||
|
if selection.TargetIP.Equal(IP) {
|
||||||
|
return []models.OpenVPNConnection{{IP: IP, Port: port, Protocol: selection.Protocol}}, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol})
|
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if selection.TargetIP != nil {
|
||||||
|
return nil, fmt.Errorf("target IP %s not found in IP addresses", selection.TargetIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(connections) > 64 {
|
||||||
|
connections = connections[:64]
|
||||||
|
}
|
||||||
|
|
||||||
return connections, nil
|
return connections, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package provider
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/qdm12/golibs/network"
|
"github.com/qdm12/golibs/network"
|
||||||
@@ -16,29 +15,24 @@ func newVyprvpn() *vyprvpn {
|
|||||||
return &vyprvpn{}
|
return &vyprvpn{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vyprvpn) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) {
|
func (v *vyprvpn) filterServers(region string) (servers []models.VyprvpnServer) {
|
||||||
var IPs []net.IP
|
if len(region) == 0 {
|
||||||
|
return constants.VyprvpnServers()
|
||||||
|
}
|
||||||
for _, server := range constants.VyprvpnServers() {
|
for _, server := range constants.VyprvpnServers() {
|
||||||
if strings.EqualFold(server.Region, selection.Region) {
|
if strings.EqualFold(server.Region, region) {
|
||||||
IPs = server.IPs
|
return []models.VyprvpnServer{server}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(IPs) == 0 {
|
return nil
|
||||||
return nil, fmt.Errorf("no IP found for region %q", selection.Region)
|
|
||||||
}
|
}
|
||||||
if selection.TargetIP != nil {
|
|
||||||
found := false
|
func (v *vyprvpn) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) {
|
||||||
for i := range IPs {
|
servers := v.filterServers(selection.Region)
|
||||||
if IPs[i].Equal(selection.TargetIP) {
|
if len(servers) == 0 {
|
||||||
found = true
|
return nil, fmt.Errorf("no server found for region %q", selection.Region)
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
return nil, fmt.Errorf("target IP address %q not found in IP addresses", selection.TargetIP)
|
|
||||||
}
|
|
||||||
IPs = []net.IP{selection.TargetIP}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var port uint16
|
var port uint16
|
||||||
switch {
|
switch {
|
||||||
case selection.Protocol == constants.TCP:
|
case selection.Protocol == constants.TCP:
|
||||||
@@ -48,13 +42,31 @@ func (s *vyprvpn) GetOpenVPNConnections(selection models.ServerSelection) (conne
|
|||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol)
|
return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol)
|
||||||
}
|
}
|
||||||
for _, IP := range IPs {
|
|
||||||
|
for _, server := range servers {
|
||||||
|
for _, IP := range server.IPs {
|
||||||
|
if selection.TargetIP != nil {
|
||||||
|
if selection.TargetIP.Equal(IP) {
|
||||||
|
return []models.OpenVPNConnection{{IP: IP, Port: port, Protocol: selection.Protocol}}, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol})
|
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if selection.TargetIP != nil {
|
||||||
|
return nil, fmt.Errorf("target IP %s not found in IP addresses", selection.TargetIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(connections) > 64 {
|
||||||
|
connections = connections[:64]
|
||||||
|
}
|
||||||
|
|
||||||
return connections, nil
|
return connections, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vyprvpn) BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
func (v *vyprvpn) BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int, root bool, cipher, auth string, extras models.ExtraConfigOptions) (lines []string) {
|
||||||
if len(cipher) == 0 {
|
if len(cipher) == 0 {
|
||||||
cipher = aes256cbc
|
cipher = aes256cbc
|
||||||
}
|
}
|
||||||
@@ -105,6 +117,6 @@ func (s *vyprvpn) BuildConf(connections []models.OpenVPNConnection, verbosity, u
|
|||||||
return lines
|
return lines
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *vyprvpn) GetPortForward(client network.Client) (port uint16, err error) {
|
func (v *vyprvpn) GetPortForward(client network.Client) (port uint16, err error) {
|
||||||
panic("port forwarding is not supported for vyprvpn")
|
panic("port forwarding is not supported for vyprvpn")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package provider
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/qdm12/golibs/network"
|
"github.com/qdm12/golibs/network"
|
||||||
@@ -16,29 +15,24 @@ func newWindscribe() *windscribe {
|
|||||||
return &windscribe{}
|
return &windscribe{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *windscribe) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) {
|
func (w *windscribe) filterServers(region string) (servers []models.WindscribeServer) {
|
||||||
var IPs []net.IP
|
if len(region) == 0 {
|
||||||
|
return constants.WindscribeServers()
|
||||||
|
}
|
||||||
for _, server := range constants.WindscribeServers() {
|
for _, server := range constants.WindscribeServers() {
|
||||||
if strings.EqualFold(server.Region, selection.Region) {
|
if strings.EqualFold(server.Region, region) {
|
||||||
IPs = server.IPs
|
return []models.WindscribeServer{server}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(IPs) == 0 {
|
return nil
|
||||||
return nil, fmt.Errorf("no IP found for region %q", selection.Region)
|
|
||||||
}
|
}
|
||||||
if selection.TargetIP != nil {
|
|
||||||
found := false
|
func (w *windscribe) GetOpenVPNConnections(selection models.ServerSelection) (connections []models.OpenVPNConnection, err error) {
|
||||||
for i := range IPs {
|
servers := w.filterServers(selection.Region)
|
||||||
if IPs[i].Equal(selection.TargetIP) {
|
if len(servers) == 0 {
|
||||||
found = true
|
return nil, fmt.Errorf("no server found for region %q", selection.Region)
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
return nil, fmt.Errorf("target IP address %q not found in IP addresses", selection.TargetIP)
|
|
||||||
}
|
|
||||||
IPs = []net.IP{selection.TargetIP}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var port uint16
|
var port uint16
|
||||||
switch {
|
switch {
|
||||||
case selection.CustomPort > 0:
|
case selection.CustomPort > 0:
|
||||||
@@ -50,9 +44,27 @@ func (w *windscribe) GetOpenVPNConnections(selection models.ServerSelection) (co
|
|||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol)
|
return nil, fmt.Errorf("protocol %q is unknown", selection.Protocol)
|
||||||
}
|
}
|
||||||
for _, IP := range IPs {
|
|
||||||
|
for _, server := range servers {
|
||||||
|
for _, IP := range server.IPs {
|
||||||
|
if selection.TargetIP != nil {
|
||||||
|
if selection.TargetIP.Equal(IP) {
|
||||||
|
return []models.OpenVPNConnection{{IP: IP, Port: port, Protocol: selection.Protocol}}, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol})
|
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: selection.Protocol})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if selection.TargetIP != nil {
|
||||||
|
return nil, fmt.Errorf("target IP %s not found in IP addresses", selection.TargetIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(connections) > 64 {
|
||||||
|
connections = connections[:64]
|
||||||
|
}
|
||||||
|
|
||||||
return connections, nil
|
return connections, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
36
internal/server/openvpn.go
Normal file
36
internal/server/openvpn.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *server) handleGetPortForwarded(w http.ResponseWriter) {
|
||||||
|
port := s.getPortForwarded()
|
||||||
|
data, err := json.Marshal(struct {
|
||||||
|
Port uint16 `json:"port"`
|
||||||
|
}{port})
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Warn(err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err := w.Write(data); err != nil {
|
||||||
|
s.logger.Warn(err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) handleGetOpenvpnSettings(w http.ResponseWriter) {
|
||||||
|
settings := s.getOpenvpnSettings()
|
||||||
|
data, err := json.Marshal(settings)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Warn(err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err := w.Write(data); err != nil {
|
||||||
|
s.logger.Warn(err)
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/qdm12/golibs/logging"
|
"github.com/qdm12/golibs/logging"
|
||||||
|
"github.com/qdm12/private-internet-access-docker/internal/settings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Server interface {
|
type Server interface {
|
||||||
@@ -19,14 +20,19 @@ type server struct {
|
|||||||
logger logging.Logger
|
logger logging.Logger
|
||||||
restartOpenvpn func()
|
restartOpenvpn func()
|
||||||
restartUnbound func()
|
restartUnbound func()
|
||||||
|
getOpenvpnSettings func() settings.OpenVPN
|
||||||
|
getPortForwarded func() uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(address string, logger logging.Logger, restartOpenvpn, restartUnbound func()) Server {
|
func New(address string, logger logging.Logger, restartOpenvpn, restartUnbound func(),
|
||||||
|
getOpenvpnSettings func() settings.OpenVPN, getPortForwarded func() uint16) Server {
|
||||||
return &server{
|
return &server{
|
||||||
address: address,
|
address: address,
|
||||||
logger: logger.WithPrefix("http server: "),
|
logger: logger.WithPrefix("http server: "),
|
||||||
restartOpenvpn: restartOpenvpn,
|
restartOpenvpn: restartOpenvpn,
|
||||||
restartUnbound: restartUnbound,
|
restartUnbound: restartUnbound,
|
||||||
|
getOpenvpnSettings: getOpenvpnSettings,
|
||||||
|
getPortForwarded: getPortForwarded,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,6 +67,10 @@ func (s *server) makeHandler() http.HandlerFunc {
|
|||||||
s.restartOpenvpn()
|
s.restartOpenvpn()
|
||||||
case "/unbound/actions/restart":
|
case "/unbound/actions/restart":
|
||||||
s.restartUnbound()
|
s.restartUnbound()
|
||||||
|
case "/openvpn/portforwarded":
|
||||||
|
s.handleGetPortForwarded(w)
|
||||||
|
case "/openvpn/settings":
|
||||||
|
s.handleGetOpenvpnSettings(w)
|
||||||
default:
|
default:
|
||||||
routeDoesNotExist(s.logger, w, r)
|
routeDoesNotExist(s.logger, w, r)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package settings
|
package settings
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -10,6 +11,7 @@ import (
|
|||||||
// Firewall contains settings to customize the firewall operation
|
// Firewall contains settings to customize the firewall operation
|
||||||
type Firewall struct {
|
type Firewall struct {
|
||||||
AllowedSubnets []net.IPNet
|
AllowedSubnets []net.IPNet
|
||||||
|
VPNInputPorts []uint16
|
||||||
Enabled bool
|
Enabled bool
|
||||||
Debug bool
|
Debug bool
|
||||||
}
|
}
|
||||||
@@ -22,9 +24,15 @@ func (f *Firewall) String() string {
|
|||||||
if !f.Enabled {
|
if !f.Enabled {
|
||||||
return "Firewall settings: disabled"
|
return "Firewall settings: disabled"
|
||||||
}
|
}
|
||||||
|
vpnInputPorts := make([]string, len(f.VPNInputPorts))
|
||||||
|
for i, port := range f.VPNInputPorts {
|
||||||
|
vpnInputPorts[i] = fmt.Sprintf("%d", port)
|
||||||
|
}
|
||||||
|
|
||||||
settingsList := []string{
|
settingsList := []string{
|
||||||
"Firewall settings:",
|
"Firewall settings:",
|
||||||
"Allowed subnets: " + strings.Join(allowedSubnets, ", "),
|
"Allowed subnets: " + strings.Join(allowedSubnets, ", "),
|
||||||
|
"VPN input ports: " + strings.Join(vpnInputPorts, ", "),
|
||||||
}
|
}
|
||||||
if f.Debug {
|
if f.Debug {
|
||||||
settingsList = append(settingsList, "Debug: on")
|
settingsList = append(settingsList, "Debug: on")
|
||||||
@@ -38,6 +46,10 @@ func GetFirewallSettings(paramsReader params.Reader) (settings Firewall, err err
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return settings, err
|
return settings, err
|
||||||
}
|
}
|
||||||
|
settings.VPNInputPorts, err = paramsReader.GetVPNInputPorts()
|
||||||
|
if err != nil {
|
||||||
|
return settings, err
|
||||||
|
}
|
||||||
settings.Enabled, err = paramsReader.GetFirewall()
|
settings.Enabled, err = paramsReader.GetFirewall()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return settings, err
|
return settings, err
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ import (
|
|||||||
|
|
||||||
// OpenVPN contains settings to configure the OpenVPN client
|
// OpenVPN contains settings to configure the OpenVPN client
|
||||||
type OpenVPN struct {
|
type OpenVPN struct {
|
||||||
User string
|
User string `json:"user"`
|
||||||
Password string
|
Password string `json:"-"`
|
||||||
Verbosity int
|
Verbosity int `json:"verbosity"`
|
||||||
Root bool
|
Root bool `json:"runAsRoot"`
|
||||||
Cipher string
|
Cipher string `json:"cipher"`
|
||||||
Auth string
|
Auth string `json:"auth"`
|
||||||
Provider models.ProviderSettings
|
Provider models.ProviderSettings `json:"provider"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOpenVPNSettings obtains the OpenVPN settings using the params functions
|
// GetOpenVPNSettings obtains the OpenVPN settings using the params functions
|
||||||
@@ -66,6 +66,8 @@ func GetOpenVPNSettings(paramsReader params.Reader, vpnProvider models.VPNProvid
|
|||||||
settings.Provider, err = GetVyprvpnSettings(paramsReader)
|
settings.Provider, err = GetVyprvpnSettings(paramsReader)
|
||||||
case constants.Nordvpn:
|
case constants.Nordvpn:
|
||||||
settings.Provider, err = GetNordvpnSettings(paramsReader)
|
settings.Provider, err = GetNordvpnSettings(paramsReader)
|
||||||
|
case constants.Purevpn:
|
||||||
|
settings.Provider, err = GetPurevpnSettings(paramsReader)
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("VPN service provider %q is not valid", vpnProvider)
|
err = fmt.Errorf("VPN service provider %q is not valid", vpnProvider)
|
||||||
}
|
}
|
||||||
|
|||||||
27
internal/settings/openvpn_test.go
Normal file
27
internal/settings/openvpn_test.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package settings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_OpenVPN_JSON(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
in := OpenVPN{
|
||||||
|
Root: true,
|
||||||
|
Provider: models.ProviderSettings{
|
||||||
|
Name: "name",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
data, err := json.Marshal(in)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, `{"user":"","verbosity":0,"runAsRoot":true,"cipher":"","auth":"","provider":{"name":"name","serverSelection":{"networkProtocol":"","region":"","group":"","country":"","city":"","isp":"","owned":false,"customPort":0,"number":0,"encryptionPreset":""},"extraConfig":{"encryptionPreset":""},"portForwarding":{"enabled":false,"filepath":""}}}`, string(data))
|
||||||
|
var out OpenVPN
|
||||||
|
err = json.Unmarshal(data, &out)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, in, out)
|
||||||
|
}
|
||||||
@@ -175,3 +175,29 @@ func GetNordvpnSettings(paramsReader params.Reader) (settings models.ProviderSet
|
|||||||
}
|
}
|
||||||
return settings, nil
|
return settings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPurevpnSettings obtains Purevpn settings from environment variables using the params package.
|
||||||
|
func GetPurevpnSettings(paramsReader params.Reader) (settings models.ProviderSettings, err error) {
|
||||||
|
settings.Name = constants.Mullvad
|
||||||
|
settings.ServerSelection.Protocol, err = paramsReader.GetNetworkProtocol()
|
||||||
|
if err != nil {
|
||||||
|
return settings, err
|
||||||
|
}
|
||||||
|
settings.ServerSelection.TargetIP, err = paramsReader.GetTargetIP()
|
||||||
|
if err != nil {
|
||||||
|
return settings, err
|
||||||
|
}
|
||||||
|
settings.ServerSelection.Region, err = paramsReader.GetPurevpnRegion()
|
||||||
|
if err != nil {
|
||||||
|
return settings, err
|
||||||
|
}
|
||||||
|
settings.ServerSelection.Country, err = paramsReader.GetPurevpnCountry()
|
||||||
|
if err != nil {
|
||||||
|
return settings, err
|
||||||
|
}
|
||||||
|
settings.ServerSelection.City, err = paramsReader.GetPurevpnCity()
|
||||||
|
if err != nil {
|
||||||
|
return settings, err
|
||||||
|
}
|
||||||
|
return settings, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ type looper struct {
|
|||||||
streamMerger command.StreamMerger
|
streamMerger command.StreamMerger
|
||||||
uid int
|
uid int
|
||||||
gid int
|
gid int
|
||||||
|
defaultInterface string
|
||||||
restart chan struct{}
|
restart chan struct{}
|
||||||
start chan struct{}
|
start chan struct{}
|
||||||
stop chan struct{}
|
stop chan struct{}
|
||||||
@@ -44,7 +45,7 @@ func (l *looper) logAndWait(ctx context.Context, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewLooper(conf Configurator, firewallConf firewall.Configurator, settings settings.ShadowSocks, dnsSettings settings.DNS,
|
func NewLooper(conf Configurator, firewallConf firewall.Configurator, settings settings.ShadowSocks, dnsSettings settings.DNS,
|
||||||
logger logging.Logger, streamMerger command.StreamMerger, uid, gid int) Looper {
|
logger logging.Logger, streamMerger command.StreamMerger, uid, gid int, defaultInterface string) Looper {
|
||||||
return &looper{
|
return &looper{
|
||||||
conf: conf,
|
conf: conf,
|
||||||
firewallConf: firewallConf,
|
firewallConf: firewallConf,
|
||||||
@@ -54,6 +55,7 @@ func NewLooper(conf Configurator, firewallConf firewall.Configurator, settings s
|
|||||||
streamMerger: streamMerger,
|
streamMerger: streamMerger,
|
||||||
uid: uid,
|
uid: uid,
|
||||||
gid: gid,
|
gid: gid,
|
||||||
|
defaultInterface: defaultInterface,
|
||||||
restart: make(chan struct{}),
|
restart: make(chan struct{}),
|
||||||
start: make(chan struct{}),
|
start: make(chan struct{}),
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
@@ -141,7 +143,7 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := l.firewallConf.SetAllowedPort(ctx, settings.Port); err != nil {
|
if err := l.firewallConf.SetAllowedPort(ctx, settings.Port, l.defaultInterface); err != nil {
|
||||||
l.logger.Error(err)
|
l.logger.Error(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ type looper struct {
|
|||||||
streamMerger command.StreamMerger
|
streamMerger command.StreamMerger
|
||||||
uid int
|
uid int
|
||||||
gid int
|
gid int
|
||||||
|
defaultInterface string
|
||||||
restart chan struct{}
|
restart chan struct{}
|
||||||
start chan struct{}
|
start chan struct{}
|
||||||
stop chan struct{}
|
stop chan struct{}
|
||||||
@@ -43,7 +44,7 @@ func (l *looper) logAndWait(ctx context.Context, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewLooper(conf Configurator, firewallConf firewall.Configurator, settings settings.TinyProxy,
|
func NewLooper(conf Configurator, firewallConf firewall.Configurator, settings settings.TinyProxy,
|
||||||
logger logging.Logger, streamMerger command.StreamMerger, uid, gid int) Looper {
|
logger logging.Logger, streamMerger command.StreamMerger, uid, gid int, defaultInterface string) Looper {
|
||||||
return &looper{
|
return &looper{
|
||||||
conf: conf,
|
conf: conf,
|
||||||
firewallConf: firewallConf,
|
firewallConf: firewallConf,
|
||||||
@@ -52,6 +53,7 @@ func NewLooper(conf Configurator, firewallConf firewall.Configurator, settings s
|
|||||||
streamMerger: streamMerger,
|
streamMerger: streamMerger,
|
||||||
uid: uid,
|
uid: uid,
|
||||||
gid: gid,
|
gid: gid,
|
||||||
|
defaultInterface: defaultInterface,
|
||||||
restart: make(chan struct{}),
|
restart: make(chan struct{}),
|
||||||
start: make(chan struct{}),
|
start: make(chan struct{}),
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
@@ -133,7 +135,7 @@ func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := l.firewallConf.SetAllowedPort(ctx, settings.Port); err != nil {
|
if err := l.firewallConf.SetAllowedPort(ctx, settings.Port, l.defaultInterface); err != nil {
|
||||||
l.logger.Error(err)
|
l.logger.Error(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user