Support Mullvad over openvpn (#85)
Additional changes: - Allow empty value for PIA region - Most settings are lowercased - `OPENVPN_VERBOSITY` environment variable - openvpn also tunnels IPv6, and unbound supports ipv6 - auth kept only on disk, not in memory - readme reworked - CI script fixed and improved - Added v2 Docker tag - Shadowsocks log defaults to `off`
This commit is contained in:
30
Dockerfile
30
Dockerfile
@@ -7,8 +7,8 @@ WORKDIR /tmp/gobuild
|
||||
ENV CGO_ENABLED=0
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download 2>&1
|
||||
COPY internal/ ./internal/
|
||||
COPY cmd/main.go .
|
||||
COPY internal/ ./internal/
|
||||
RUN go test ./...
|
||||
RUN go build -ldflags="-s -w" -o entrypoint main.go
|
||||
|
||||
@@ -29,11 +29,23 @@ LABEL \
|
||||
org.opencontainers.image.source="https://github.com/qdm12/private-internet-access-docker" \
|
||||
org.opencontainers.image.title="PIA client" \
|
||||
org.opencontainers.image.description="VPN client to tunnel to private internet access servers using OpenVPN, IPtables, DNS over TLS and Alpine Linux"
|
||||
ENV USER= \
|
||||
PASSWORD= \
|
||||
ENCRYPTION=strong \
|
||||
ENV VPNSP=pia \
|
||||
USER= \
|
||||
PROTOCOL=udp \
|
||||
OPENVPN_VERBOSITY=1 \
|
||||
TZ= \
|
||||
# PIA only
|
||||
PASSWORD= \
|
||||
REGION="CA Montreal" \
|
||||
ENCRYPTION=strong \
|
||||
PORT_FORWARDING=off \
|
||||
PORT_FORWARDING_STATUS_FILE="/forwarded_port" \
|
||||
# Mullvad only
|
||||
COUNTRY=Sweden \
|
||||
CITY= \
|
||||
ISP= \
|
||||
PORT= \
|
||||
# DNS over TLS
|
||||
DOT=on \
|
||||
DOT_PROVIDERS=cloudflare \
|
||||
DOT_PRIVATE_ADDRESS=127.0.0.1/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,169.254.0.0/16,::1/128,fc00::/7,fe80::/10,::ffff:0:0/96 \
|
||||
@@ -45,19 +57,19 @@ ENV USER= \
|
||||
BLOCK_SURVEILLANCE=off \
|
||||
BLOCK_ADS=off \
|
||||
UNBLOCK= \
|
||||
# Firewall
|
||||
EXTRA_SUBNETS= \
|
||||
PORT_FORWARDING=off \
|
||||
PORT_FORWARDING_STATUS_FILE="/forwarded_port" \
|
||||
# Tinyproxy
|
||||
TINYPROXY=off \
|
||||
TINYPROXY_LOG=Info \
|
||||
TINYPROXY_PORT=8888 \
|
||||
TINYPROXY_USER= \
|
||||
TINYPROXY_PASSWORD= \
|
||||
# Shadowsocks
|
||||
SHADOWSOCKS=off \
|
||||
SHADOWSOCKS_LOG=on \
|
||||
SHADOWSOCKS_LOG=off \
|
||||
SHADOWSOCKS_PORT=8388 \
|
||||
SHADOWSOCKS_PASSWORD= \
|
||||
TZ=
|
||||
SHADOWSOCKS_PASSWORD=
|
||||
ENTRYPOINT /entrypoint
|
||||
EXPOSE 8888/tcp 8388/tcp 8388/udp
|
||||
HEALTHCHECK --interval=3m --timeout=3s --start-period=20s --retries=1 CMD /entrypoint healthcheck
|
||||
|
||||
267
README.md
267
README.md
@@ -1,8 +1,8 @@
|
||||
# Private Internet Access Client
|
||||
|
||||
*Lightweight swiss-knife-like VPN client to tunnel to private internet access servers, using OpenVPN, iptables, DNS over TLS, ShadowSocks, Tinyproxy and more*
|
||||
*Lightweight swiss-knife-like VPN client to tunnel to Private Internet Access or Mullvad VPN servers, using Go, OpenVPN, iptables, DNS over TLS, ShadowSocks and Tinyproxy*
|
||||
|
||||
**ANNOUCEMENT**: *Total rewrite in Go: see the new features [below](#Features)* (in case something break use the image with tag `:old`)
|
||||
**ANNOUCEMENT**: *Support for [Mullvad](http://mullvad.net)*
|
||||
|
||||
<a href="https://hub.docker.com/r/qmcgaw/private-internet-access">
|
||||
<img width="100%" height="320" src="https://raw.githubusercontent.com/qdm12/private-internet-access-docker/master/title.svg?sanitize=true">
|
||||
@@ -34,59 +34,60 @@
|
||||
|
||||
## Features
|
||||
|
||||
- **New features**
|
||||
- Choice to block ads, malicious and surveillance at the DNS level
|
||||
- All program output streams are merged (openvpn, unbound, shadowsocks, tinyproxy, etc.)
|
||||
- Choice of DNS over TLS provider(s)
|
||||
- Possibility of split horizon DNS by selecting multiple DNS over TLS providers
|
||||
- Download block lists and cryptographic files at start instead of at build time
|
||||
- Can work as a Kubernetes sidecar container, thanks @rorph
|
||||
- Pick a random region if no region is given, thanks @rorph
|
||||
- <details><summary>Configure everything with environment variables</summary><p>
|
||||
|
||||
- [Destination region](https://www.privateinternetaccess.com/pages/network)
|
||||
- Internet protocol
|
||||
- Level of encryption
|
||||
- PIA Username and password
|
||||
- DNS over TLS
|
||||
- DNS blocking: ads, malicious, surveillance
|
||||
- Internal firewall
|
||||
- Socks5 proxy
|
||||
- Web HTTP proxy
|
||||
|
||||
</p></details>
|
||||
- Connect
|
||||
- [Other containers to it](https://github.com/qdm12/private-internet-access-docker#connect-to-it)
|
||||
- [LAN devices to it](https://github.com/qdm12/private-internet-access-docker#connect-to-it)
|
||||
- Killswitch using *iptables* to allow traffic only with needed PIA servers and LAN devices
|
||||
- Port forwarding
|
||||
- Based on Alpine 3.11 for a small Docker image below 50MB
|
||||
- Supports **Private Internet Access** and **Mullvad** servers
|
||||
- DNS over TLS baked in with service provider(s) of your choice
|
||||
- DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses
|
||||
- Choose the vpn network protocol, `udp` or `tcp`
|
||||
- Built in firewall kill switch to allow traffic only with needed PIA servers and LAN devices
|
||||
- Built in SOCKS5 proxy (Shadowsocks, tunnels TCP+UDP)
|
||||
- Built in HTTP proxy (Tinyproxy, tunnels TCP)
|
||||
- [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)
|
||||
- Compatible with amd64, i686 (32 bit), **ARM** 64 bit, ARM 32 bit v6 and v7, ppc64le and even that s390x 🎆
|
||||
- Sub programs drop root privileges once launched: Openvpn, Unbound, Shadowsocks, Tinyproxy
|
||||
|
||||
### Private Internet Access
|
||||
|
||||
- Pick the [region](https://www.privateinternetaccess.com/pages/network/)
|
||||
- Pick the level of encryption
|
||||
- Enable port forwarding
|
||||
|
||||
### Mullvad
|
||||
|
||||
- Pick the [country, city and ISP](https://mullvad.net/en/servers/#openvpn)
|
||||
- Pick the port to use (i.e. `53` (udp) or `80` (tcp))
|
||||
|
||||
### Extra niche features
|
||||
|
||||
- Possibility of split horizon DNS by selecting multiple DNS over TLS providers
|
||||
- Subprograms all drop root privileges once launched
|
||||
- Subprograms output streams are all merged together
|
||||
- Can work as a Kubernetes sidecar container, thanks @rorph
|
||||
|
||||
## Setup
|
||||
|
||||
1. <details><summary>Requirements</summary><p>
|
||||
|
||||
- A Private Internet Access **username** and **password** - [Sign up](https://www.privateinternetaccess.com/pages/buy-vpn/)
|
||||
- Docker API 1.25 to support `init`
|
||||
- If you use Docker Compose, docker-compose >= 1.22.0, to support `init: true`
|
||||
1. Requirements
|
||||
- Docker 1.13, in order to have Docker API 1.25 which supports `init` (and, if you use docker-compose, docker-compose version 1.22.0)
|
||||
- A Private Internet Access **username** and **password** ([sign up](https://www.privateinternetaccess.com/pages/buy-vpn/)) or Mullvad user ID ([sign up](https://mullvad.net/en/account/))
|
||||
- <details><summary>External firewall requirements, if you have one</summary><p>
|
||||
|
||||
- At start only
|
||||
- Allow outbound TCP 443 to github.com and privateinternetaccess.com
|
||||
- If `DOT=on`, allow outbound TCP 853 to 1.1.1.1 to allow Unbound to resolve the PIA domain name.
|
||||
- If `DOT=off`, allow outbound UDP 53 to your DNS provider to resolve the PIA domain name.
|
||||
- For UDP strong encryption, allow outbound UDP 1197 to the corresponding VPN server IPs
|
||||
- For UDP normal encryption, allow outbound UDP 1198 to the corresponding VPN server IPs
|
||||
- For TCP strong encryption, allow outbound TCP 501 to the corresponding VPN server IPs
|
||||
- For TCP normal encryption, allow outbound TCP 502 to the corresponding VPN server IPs
|
||||
- Allow outbound TCP 443 to github.com
|
||||
- If `DOT=on`, allow outbound TCP 853 to allow Unbound to resolve github.com and the PIA subdomain name if you use PIA.
|
||||
- If `DOT=off` and `VPNSP=pia`, allow outbound UDP 53 to your DNS provider to resolve the PIA subdomain name.
|
||||
- If `VPNSP=pia`, `ENCRYPTION=strong` and `PROTOCOL=udp`: allow outbound UDP 1197 to the corresponding VPN server IPs
|
||||
- If `VPNSP=pia`, `ENCRYPTION=normal` and `PROTOCOL=udp`: allow outbound UDP 1198 to the corresponding VPN server IPs
|
||||
- If `VPNSP=pia`, `ENCRYPTION=strong` and `PROTOCOL=tcp`: allow outbound TCP 501 to the corresponding VPN server IPs
|
||||
- If `VPNSP=pia`, `ENCRYPTION=normal` and `PROTOCOL=tcp`: allow outbound TCP 502 to the corresponding VPN server IPs
|
||||
- If `VPNSP=mullvad` and `PORT=`, please refer to the mapping of Mullvad servers in [these source code lines](https://github.com/qdm12/private-internet-access-docker/blob/master/internal/constants/mullvad.go#L64-L667) to find the corresponding UDP port number and IP address(es) of your choice
|
||||
- If `VPNSP=mullvad` and `PORT=53`, allow outbound UDP 53 to the corresponding VPN server IPs, which you can fine in [the mapping of Mullvad servers](https://github.com/qdm12/private-internet-access-docker/blob/master/internal/constants/mullvad.go#L64-L667)
|
||||
- If `VPNSP=mullvad` and `PORT=80`, allow outbound TCP 80 to the corresponding VPN server IPs, which you can fine in [the mapping of Mullvad servers](https://github.com/qdm12/private-internet-access-docker/blob/master/internal/constants/mullvad.go#L64-L667)
|
||||
- If `VPNSP=mullvad` and `PORT=443`, allow outbound TCP 443 to the corresponding VPN server IPs, which you can fine in [the mapping of Mullvad servers](https://github.com/qdm12/private-internet-access-docker/blob/master/internal/constants/mullvad.go#L64-L667)
|
||||
- If `SHADOWSOCKS=on`, allow inbound TCP 8388 and UDP 8388 from your LAN
|
||||
- If `TINYPROXY=on`, allow inbound TCP 8888 from your LAN
|
||||
|
||||
</p></details>
|
||||
|
||||
</p></details>
|
||||
|
||||
1. Launch the container with:
|
||||
|
||||
```bash
|
||||
@@ -102,29 +103,38 @@
|
||||
```
|
||||
|
||||
Note that you can:
|
||||
|
||||
- Change the many [environment variables](#environment-variables) available
|
||||
- Use `-p 8888:8888/tcp` to access the HTTP web proxy (and put your LAN in `EXTRA_SUBNETS` environment variable)
|
||||
- Use `-p 8388:8388/tcp -p 8388:8388/udp` to access the SOCKS5 proxy (and put your LAN in `EXTRA_SUBNETS` environment variable)
|
||||
- Pass additional arguments to *openvpn* using Docker's command function (commands after the image name)
|
||||
1. You can update the image with `docker pull qmcgaw/private-internet-access:latest`. There are also docker tags available:
|
||||
- `qmcgaw/private-internet-access:v1` linked to the [v1 release](https://github.com/qdm12/private-internet-access-docker/releases/tag/v1.0)
|
||||
|
||||
1. You can update the image with `docker pull qmcgaw/private-internet-access:latest`. There are also docker tags for older versions available:
|
||||
- `qmcgaw/private-internet-access:v2` linked to the [v2 release](https://github.com/qdm12/private-internet-access-docker/releases/tag/v2.0) (Golang based, only PIA)
|
||||
- `qmcgaw/private-internet-access:v1` linked to the [v1 release](https://github.com/qdm12/private-internet-access-docker/releases/tag/v1.0) (shell scripting based, no support, only PIA)
|
||||
- `qmcgaw/private-internet-access:old` tag, which is the latest shell scripting version (shell scripting based, no support, only PIA)
|
||||
|
||||
## Testing
|
||||
|
||||
Check the PIA IP address matches your expectations
|
||||
|
||||
```sh
|
||||
docker run --rm --network=container:pia alpine:3.10 wget -qO- https://ipinfo.io
|
||||
docker run --rm --network=container:pia alpine:3.11 wget -qO- https://ipinfo.io
|
||||
```
|
||||
|
||||
## Environment variables
|
||||
|
||||
| Environment variable | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `REGION` | `CA Montreal` | One of the [PIA regions](https://www.privateinternetaccess.com/pages/network/) |
|
||||
| `VPNSP` | `pia` | VPN Service Provider, one of `pia`, `mullvad` |
|
||||
| `REGION` | `CA Montreal` | (PIA only) one of the [PIA regions](https://www.privateinternetaccess.com/pages/network/) |
|
||||
| `COUNTRY` | `Sweden` | (Mullvad only) one of the [Mullvad countries](https://mullvad.net/en/servers/#openvpn) |
|
||||
| `CITY` | | (Mullvad only, *optional*) one of the [Mullvad cities](https://mullvad.net/en/servers/#openvpn) |
|
||||
| `ISP` | | (Mullvad only, *optional*) one of the [Mullvad ISP](https://mullvad.net/en/servers/#openvpn) |
|
||||
| `PORT` | | (Mullvad only, *optional*) For TCP, `80` or `443`, or `53` for UDP. Leave blank for default Mullvad server port |
|
||||
| `PROTOCOL` | `udp` | `tcp` or `udp` |
|
||||
| `ENCRYPTION` | `strong` | `normal` or `strong` |
|
||||
| `USER` | | Your PIA username |
|
||||
| `ENCRYPTION` | `strong` | (PIA only) `normal` or `strong` |
|
||||
| `USER` | | PIA username **or** Mullvad user ID |
|
||||
| `PASSWORD` | | Your PIA password |
|
||||
| `DOT` | `on` | `on` or `off`, to activate DNS over TLS to 1.1.1.1 |
|
||||
| `DOT_PROVIDERS` | `cloudflare` | Comma delimited list of DNS over TLS providers from `cloudflare`, `google`, `quad9`, `quadrant`, `cleanbrowsing`, `securedns`, `libredns` |
|
||||
@@ -138,18 +148,19 @@ docker run --rm --network=container:pia alpine:3.10 wget -qO- https://ipinfo.io
|
||||
| `BLOCK_ADS` | `off` | `on` or `off`, blocks ads hostnames and IPs |
|
||||
| `UNBLOCK` | | comma separated string (i.e. `web.com,web2.ca`) to unblock hostnames |
|
||||
| `EXTRA_SUBNETS` | | comma separated subnets allowed in the container firewall (i.e. `192.168.1.0/24,192.168.10.121,10.0.0.5/28`) |
|
||||
| `PORT_FORWARDING` | `off` | Set to `on` to forward a port on PIA server |
|
||||
| `PORT_FORWARDING_STATUS_FILE` | `/forwarded_port` | File path to store the forwarded port number |
|
||||
| `PORT_FORWARDING` | `off` | (PIA only) Set to `on` to forward a port on PIA server |
|
||||
| `PORT_FORWARDING_STATUS_FILE` | `/forwarded_port` | (PIA only) File path to store the forwarded port number |
|
||||
| `TINYPROXY` | `off` | `on` or `off`, to enable the internal HTTP proxy tinyproxy |
|
||||
| `TINYPROXY_LOG` | `Info` | `Info`, `Connect`, `Notice`, `Warning`, `Error` or `Critical` |
|
||||
| `TINYPROXY_PORT` | `8888` | `1024` to `65535` internal port for HTTP proxy |
|
||||
| `TINYPROXY_USER` | | Username to use to connect to the HTTP proxy |
|
||||
| `TINYPROXY_PASSWORD` | | Passsword to use to connect to the HTTP proxy |
|
||||
| `SHADOWSOCKS` | `off` | `on` or `off`, to enable the internal SOCKS5 proxy Shadowsocks |
|
||||
| `SHADOWSOCKS_LOG` | `on` | `on` or `off` to enable logging for Shadowsocks |
|
||||
| `SHADOWSOCKS_LOG` | `off` | `on` or `off` to enable logging for Shadowsocks |
|
||||
| `SHADOWSOCKS_PORT` | `8388` | `1024` to `65535` internal port for SOCKS5 proxy |
|
||||
| `SHADOWSOCKS_PASSWORD` | | Passsword to use to connect to the SOCKS5 proxy |
|
||||
| `TZ` | | Specify a timezone to use i.e. `Europe/London` |
|
||||
| `OPENVPN_VERBOSITY` | `1` | Openvpn verbosity level from 0 to 6 |
|
||||
|
||||
## Connect to it
|
||||
|
||||
@@ -198,7 +209,7 @@ There are various ways to achieve this, depending on your use case.
|
||||
- Enter port TCP (and UDP, if available) `8388` as the server port
|
||||
- Use the password you have set with `SHADOWSOCKS_PASSWORD`
|
||||
- Choose the encryption method/algorithm `chacha20-ietf-poly1305`
|
||||
1. If you set `SHADOWSOCKS_LOG` to `on`, more information will be logged in the Docker logs
|
||||
1. If you set `SHADOWSOCKS_LOG` to `on`, (a lot) more information will be logged in the Docker logs
|
||||
|
||||
</p></details>
|
||||
- <details><summary>Access ports of containers connected to PIA</summary><p>
|
||||
@@ -239,65 +250,104 @@ There are various ways to achieve this, depending on your use case.
|
||||
|
||||
</p></details>
|
||||
|
||||
## Port forwarding
|
||||
## Private Internet Access port forwarding
|
||||
|
||||
By setting `PORT_FORWARDING` environment variable to `on`, the forwarded port will be read and written to the file specified in `PORT_FORWARDING_STATUS_FILE` (by default, this is set to `/forwarded_port`). If the location for this file does not exist, it will be created automatically.
|
||||
Note that [not all regions support port forwarding](https://www.privateinternetaccess.com/helpdesk/kb/articles/how-do-i-enable-port-forwarding-on-my-vpn).
|
||||
|
||||
You can mount this file as a volume to read it from other containers.
|
||||
When `PORT_FORWARDING=on`, a port will be forwarded on the PIA server side and written to the file specified by `PORT_FORWARDING_STATUS_FILE=/forwarded_port`.
|
||||
|
||||
Note that not all regions support port forwarding.
|
||||
It can be useful to mount this file as a volume to read it from other containers, for example to configure a torrenting client.
|
||||
|
||||
## For the paranoids
|
||||
## FAQ
|
||||
|
||||
- You can review the code which consists in:
|
||||
- [Dockerfile](https://github.com/qdm12/private-internet-access-docker/blob/master/Dockerfile)
|
||||
- [main.go](https://github.com/qdm12/private-internet-access-docker/blob/master/cmd/main.go), the main code entrypoint
|
||||
- [internal package](https://github.com/qdm12/private-internet-access-docker/blob/master/internal)
|
||||
- [github.com/qdm12/golibs](https://github.com/qdm12/golibs) dependency
|
||||
- [github.com/qdm12/files](https://github.com/qdm12/files) for files downloaded at start (DNS root hints, block lists, etc.)
|
||||
- Build the image yourself:
|
||||
<details><summary>Private Internet Access: Why do I see openvpn warnings at start?</summary><p>
|
||||
|
||||
```bash
|
||||
You might see some warnings similar to:
|
||||
|
||||
```s
|
||||
openvpn: Sat Feb 22 15:55:02 2020 WARNING: this configuration may cache passwords in memory -- use the auth-nocache option to prevent this
|
||||
openvpn: Sat Feb 22 15:55:02 2020 WARNING: 'link-mtu' is used inconsistently, local='link-mtu 1569', remote='link-mtu 1542'
|
||||
openvpn: Sat Feb 22 15:55:02 2020 WARNING: 'cipher' is used inconsistently, local='cipher AES-256-CBC', remote='cipher BF-CBC'
|
||||
openvpn: Sat Feb 22 15:55:02 2020 WARNING: 'auth' is used inconsistently, local='auth SHA256', remote='auth SHA1'
|
||||
openvpn: Sat Feb 22 15:55:02 2020 WARNING: 'keysize' is used inconsistently, local='keysize 256', remote='keysize 128'
|
||||
openvpn: Sat Feb 22 15:55:02 2020 WARNING: 'comp-lzo' is present in remote config but missing in local config, remote='comp-lzo'
|
||||
openvpn: Sat Feb 22 15:55:02 2020 [a121ce520d670b71bfd3aa475485539b] Peer Connection Initiated with [AF_INET]xx.xx.xx.xx:1197
|
||||
```
|
||||
|
||||
It is mainly because the option [disable-occ](https://openvpn.net/community-resources/reference-manual-for-openvpn-2-4/) was removed for transparency with you.
|
||||
|
||||
Private Internet Access explains [here why](https://www.privateinternetaccess.com/helpdesk/kb/articles/why-do-i-get-cipher-auth-warnings-when-i-connect) the warnings show up.
|
||||
|
||||
</p></details>
|
||||
|
||||
<details><summary>What files does it download at start before tunneling?</summary><p>
|
||||
|
||||
At start, the Go entrypoint only downloads, depending on your settings:
|
||||
|
||||
- If `DOT=on`: [DNS over TLS named root](https://github.com/qdm12/files/blob/master/named.root.updated) for Unbound
|
||||
- If `DOT=on`: [DNS over TLS root key](https://github.com/qdm12/files/blob/master/root.key.updated) for Unbound
|
||||
- If `BLOCK_MALICIOUS=on`: [Malicious hostnames and IP addresses block lists](https://github.com/qdm12/files) for Unbound
|
||||
- If `BLOCK_SURVEILLANCE=on`: [Surveillance hostnames and IP addresses block lists](https://github.com/qdm12/files) for Unbound
|
||||
- If `BLOCK_ADS=on`: [Ads hostnames and IP addresses block lists](https://github.com/qdm12/files) for Unbound
|
||||
|
||||
</p></details>
|
||||
|
||||
<details><summary>How to build Docker images of older or alternate versions</summary><p>
|
||||
|
||||
First, install [Git](https://git-scm.com/).
|
||||
|
||||
The following will build the Docker image locally and replace the previous one you built or pulled.
|
||||
|
||||
- Build the latest image
|
||||
|
||||
```sh
|
||||
docker build -t qmcgaw/private-internet-access https://github.com/qdm12/private-internet-access-docker.git
|
||||
```
|
||||
|
||||
- The download and parsing of all needed files is done at start (openvpn config files, Unbound files, block lists, etc.)
|
||||
- Use `-e ENCRYPTION=strong -e BLOCK_MALICIOUS=on`
|
||||
- Find a [commit](https://github.com/qdm12/private-internet-access-docker/commits/master) you want to build for, in example `095623925a9cc0e5cf89d5b9b510714792267d9b`, then:
|
||||
|
||||
```sh
|
||||
docker build -t qmcgaw/private-internet-access https://github.com/qdm12/private-internet-access-docker.git#095623925a9cc0e5cf89d5b9b510714792267d9b
|
||||
```
|
||||
|
||||
- Find a [branch](https://github.com/qdm12/private-internet-access-docker/branches) you want to build for, in example `mullvad`, then:
|
||||
|
||||
```sh
|
||||
docker build -t qmcgaw/private-internet-access https://github.com/qdm12/private-internet-access-docker.git#mullvad
|
||||
```
|
||||
|
||||
</p></details>
|
||||
|
||||
<details><summary>What's all this Go code?</summary><p>
|
||||
|
||||
The Go code is a big rewrite of the previous shell entrypoint, it allows for:
|
||||
|
||||
- better testing
|
||||
- better maintainability
|
||||
- ease of implementing new features
|
||||
- faster boot
|
||||
- asynchronous/parallel operations
|
||||
|
||||
It is mostly made of the [internal directory](https://github.com/qdm12/private-internet-access-docker/tree/master/internal) and the entry Go file [cmd/main.go](https://github.com/qdm12/private-internet-access-docker/blob/master/cmd/main.go).
|
||||
|
||||
</p></details>
|
||||
|
||||
<details><summary>How to test DNS over TLS?</summary><p>
|
||||
|
||||
- You can test DNSSEC using [internet.nl/connection](https://www.internet.nl/connection/)
|
||||
- Check DNS leak tests with [https://www.dnsleaktest.com](https://www.dnsleaktest.com)
|
||||
- DNS Leaks tests might not work because of [this](https://github.com/qdm12/cloudflare-dns-server#verify-dns-connection) (*TLDR*: DNS server is a local caching intermediary)
|
||||
- Some other DNS leaks tests might not work because of [this](https://github.com/qdm12/cloudflare-dns-server#verify-dns-connection) (*TLDR*: Unbound DNS server is a local caching intermediary)
|
||||
|
||||
## Troubleshooting
|
||||
</p></details>
|
||||
|
||||
- If openvpn fails to start, you may need to:
|
||||
- Install the tun kernel module on your host with `insmod /lib/modules/tun.ko` or `modprobe tun`
|
||||
- Add `--device=/dev/net/tun` to your docker run command (equivalent for docker-compose, kubernetes, etc.)
|
||||
<details><summary>How to fix OpenVPN failing to start?</summary><p>
|
||||
|
||||
- Fallback to a previous Docker image tags:
|
||||
- `v1` tag, stable shell scripting based (no support)
|
||||
- `old` tag, latest shell scripting version (no support)
|
||||
- `v2`... waiting for `latest` to become more stable
|
||||
You can try:
|
||||
|
||||
- Fallback to a precise previous version
|
||||
1. Clone the repository on your machine
|
||||
- Installing the tun kernel module on your host with `insmod /lib/modules/tun.ko` or `modprobe tun`
|
||||
- Adding `--device=/dev/net/tun` to your docker run command (equivalent for docker-compose, kubernetes, etc.)
|
||||
|
||||
```sh
|
||||
git clone https://github.com/qdm12/private-internet-access-docker.git pia
|
||||
cd pia
|
||||
```
|
||||
|
||||
1. Look up which commit you want to go back to [here](https://github.com/qdm12/private-internet-access-docker/commits/master), i.e. `942cc7d4d10545b6f5f89c907b7dd1dbc39368e0`
|
||||
1. Revert to this commit locally
|
||||
|
||||
```sh
|
||||
git reset --hard 942cc7d4d10545b6f5f89c907b7dd1dbc39368e0
|
||||
```
|
||||
|
||||
1. Build the Docker image
|
||||
|
||||
```sh
|
||||
docker build -t qmcgaw/private-internet-access .
|
||||
```
|
||||
</p></details>
|
||||
|
||||
## Development
|
||||
|
||||
@@ -309,11 +359,26 @@ Note that not all regions support port forwarding.
|
||||
1. In Visual Studio Code, press on `F1` and select `Remote-Containers: Open Folder in Container...`
|
||||
1. Your dev environment is ready to go!... and it's running in a container :+1:
|
||||
|
||||
The Go code is in the Go file [cmd/main.go](https://github.com/qdm12/private-internet-access-docker/blob/master/cmd/main.go) and the [internal directory](https://github.com/qdm12/private-internet-access-docker/tree/master/internal),
|
||||
you might want to start reading the main.go file.
|
||||
|
||||
### Contributors
|
||||
|
||||
Thanks for all the contributions, wether small or not so small!
|
||||
|
||||
- [@JeordyR](https://github.com/JeordyR) for testing the Mullvad version and opening a [PR with a few fixes](https://github.com/qdm12/private-internet-access-docker/pull/84/files) 👍
|
||||
- [@rorph](https://github.com/rorph) for a [PR to pick a random region for PIA](https://github.com/qdm12/private-internet-access-docker/pull/70) and a [PR to make the container work with kubernetes](https://github.com/qdm12/private-internet-access-docker/pull/69)
|
||||
- [@JesterEE](https://github.com/JesterEE) for a [PR to fix silly line endings in block lists back then](https://github.com/qdm12/private-internet-access-docker/pull/55) 📎
|
||||
- [@elmerfdz](https://github.com/elmerfdz) for a [PR to add timezone information to have correct log timestampts](https://github.com/qdm12/private-internet-access-docker/pull/51) 🕙
|
||||
- [@Juggels](https://github.com/Juggels) for a [PR to write the PIA forwarded port to a file](https://github.com/qdm12/private-internet-access-docker/pull/43)
|
||||
- [@gdlx](https://github.com/gdlx) for a [PR to fix and improve PIA port forwarding script](https://github.com/qdm12/private-internet-access-docker/pull/32)
|
||||
- [@janaz](https://github.com/janaz) for keeping an eye on [updating things in the Dockerfile](https://github.com/qdm12/private-internet-access-docker/pull/8)
|
||||
|
||||
## TODOs
|
||||
|
||||
- Support other VPN providers
|
||||
- Mullvad
|
||||
- Windscribe
|
||||
<details><summary>Expand me</summary><p>
|
||||
|
||||
- Support Windscribe
|
||||
- Gotify support for notificactions
|
||||
- Periodic update of malicious block lists with Unbound restart
|
||||
- Improve healthcheck
|
||||
@@ -321,7 +386,7 @@ Note that not all regions support port forwarding.
|
||||
- Check for DNS provider somehow if this is even possible
|
||||
- Support for other VPN protocols
|
||||
- Wireguard (wireguard-go)
|
||||
- Show new versions/commits at start
|
||||
- Show new versions/commits available at start
|
||||
- Colors & emojis
|
||||
- Setup
|
||||
- Logging streams
|
||||
@@ -335,6 +400,8 @@ Note that not all regions support port forwarding.
|
||||
- wireguard-go
|
||||
- Openvpn to replace openvpn
|
||||
|
||||
</p></details>
|
||||
|
||||
## License
|
||||
|
||||
This repository is under an [MIT license](https://github.com/qdm12/private-internet-access-docker/master/license)
|
||||
|
||||
26
ci.sh
26
ci.sh
@@ -1,18 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$TRAVIS_PULL_REQUEST" = "true" ] || [ "$TRAVIS_BRANCH" != "master" ]; then
|
||||
ARCHS=linux/amd64,linux/386,linux/arm64,linux/arm/v7,linux/arm/v6,linux/ppc64le,linux/s390x
|
||||
|
||||
echo -e "\n\nPull request: $TRAVIS_PULL_REQUEST\nRelease tag: $TRAVIS_TAG\nBranch: $TRAVIS_BRANCH\n\nTarget arch: $ARCHS\n\n"
|
||||
|
||||
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
|
||||
echo -e "\n\nBuilding pull request without pushing to Docker Hub\n\n"
|
||||
docker buildx build \
|
||||
--progress plain \
|
||||
--platform=linux/amd64,linux/386,linux/arm64,linux/arm/v7,linux/arm/v6,linux/ppc64le,linux/s390x \
|
||||
--platform="$ARCHS" \
|
||||
.
|
||||
exit $?
|
||||
fi
|
||||
echo $DOCKER_PASSWORD | docker login -u qmcgaw --password-stdin &> /dev/null
|
||||
TAG="${TRAVIS_TAG:-latest}"
|
||||
echo "Building Docker images for \"$DOCKER_REPO:$TAG\""
|
||||
|
||||
echo $DOCKER_PASSWORD | docker login -u qmcgaw --password-stdin 2>&1
|
||||
|
||||
TAG="$TRAVIS_TAG"
|
||||
if [ -z "$TAG" ]; then
|
||||
TAG=latest
|
||||
if [ "$TRAVIS_BRANCH" != "master" ]; then
|
||||
TAG="$TRAVIS_BRANCH"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "\n\nBuilding Docker images for \"$DOCKER_REPO:$TAG\"\n\n"
|
||||
docker buildx build \
|
||||
--progress plain \
|
||||
--platform=linux/amd64,linux/386,linux/arm64,linux/arm/v7,linux/arm/v6,linux/ppc64le,linux/s390x \
|
||||
--platform="$ARCHS" \
|
||||
--build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \
|
||||
--build-arg VCS_REF=`git rev-parse --short HEAD` \
|
||||
--build-arg VERSION=$TAG \
|
||||
|
||||
33
cmd/main.go
33
cmd/main.go
@@ -18,6 +18,8 @@ import (
|
||||
"github.com/qdm12/private-internet-access-docker/internal/env"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/firewall"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/healthcheck"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/mullvad"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/openvpn"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/params"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/pia"
|
||||
@@ -53,6 +55,7 @@ func main() {
|
||||
dnsConf := dns.NewConfigurator(logger, client, fileManager)
|
||||
firewallConf := firewall.NewConfigurator(logger, fileManager)
|
||||
piaConf := pia.NewConfigurator(client, fileManager, firewallConf, logger)
|
||||
mullvadConf := mullvad.NewConfigurator(client, fileManager, logger)
|
||||
tinyProxyConf := tinyproxy.NewConfigurator(fileManager, logger)
|
||||
shadowsocksConf := shadowsocks.NewConfigurator(fileManager, logger)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
@@ -75,7 +78,16 @@ func main() {
|
||||
e.FatalOnError(err)
|
||||
}
|
||||
|
||||
err = ovpnConf.WriteAuthFile(allSettings.PIA.User, allSettings.PIA.Password, uid, gid)
|
||||
var openVPNUser, openVPNPassword string
|
||||
switch allSettings.VPNSP {
|
||||
case "pia":
|
||||
openVPNUser = allSettings.PIA.User
|
||||
openVPNPassword = allSettings.PIA.Password
|
||||
case "mullvad":
|
||||
openVPNUser = allSettings.Mullvad.User
|
||||
openVPNPassword = "m"
|
||||
}
|
||||
err = ovpnConf.WriteAuthFile(openVPNUser, openVPNPassword, uid, gid)
|
||||
e.FatalOnError(err)
|
||||
|
||||
// Temporarily reset chain policies allowing Kubernetes sidecar to
|
||||
@@ -115,8 +127,19 @@ func main() {
|
||||
e.FatalOnError(err)
|
||||
}
|
||||
|
||||
VPNIPs, port, err := piaConf.BuildConf(allSettings.PIA.Region, allSettings.OpenVPN.NetworkProtocol, allSettings.PIA.Encryption, uid, gid)
|
||||
e.FatalOnError(err)
|
||||
var connections []models.OpenVPNConnection
|
||||
switch allSettings.VPNSP {
|
||||
case "pia":
|
||||
connections, err = piaConf.GetOpenVPNConnections(allSettings.PIA.Region, allSettings.OpenVPN.NetworkProtocol, allSettings.PIA.Encryption)
|
||||
e.FatalOnError(err)
|
||||
err = piaConf.BuildConf(connections, allSettings.PIA.Encryption, allSettings.OpenVPN.Verbosity, uid, gid)
|
||||
e.FatalOnError(err)
|
||||
case "mullvad":
|
||||
connections, err = mullvadConf.GetOpenVPNConnections(allSettings.Mullvad.Country, allSettings.Mullvad.City, allSettings.Mullvad.ISP, allSettings.OpenVPN.NetworkProtocol, allSettings.Mullvad.Port)
|
||||
e.FatalOnError(err)
|
||||
err = mullvadConf.BuildConf(connections, allSettings.OpenVPN.Verbosity, uid, gid)
|
||||
e.FatalOnError(err)
|
||||
}
|
||||
|
||||
defaultInterface, defaultGateway, defaultSubnet, err := firewallConf.GetDefaultRoute()
|
||||
e.FatalOnError(err)
|
||||
@@ -128,7 +151,7 @@ func main() {
|
||||
e.FatalOnError(err)
|
||||
err = firewallConf.CreateGeneralRules()
|
||||
e.FatalOnError(err)
|
||||
err = firewallConf.CreateVPNRules(constants.TUN, VPNIPs, defaultInterface, port, allSettings.OpenVPN.NetworkProtocol)
|
||||
err = firewallConf.CreateVPNRules(constants.TUN, defaultInterface, connections)
|
||||
e.FatalOnError(err)
|
||||
err = firewallConf.CreateLocalSubnetsRules(defaultSubnet, allSettings.Firewall.AllowedSubnets, defaultInterface)
|
||||
e.FatalOnError(err)
|
||||
@@ -163,7 +186,7 @@ func main() {
|
||||
go streamMerger.Merge("shadowsocks", stream)
|
||||
}
|
||||
|
||||
if allSettings.PIA.PortForwarding.Enabled {
|
||||
if allSettings.VPNSP == "pia" && allSettings.PIA.PortForwarding.Enabled {
|
||||
time.AfterFunc(10*time.Second, func() {
|
||||
port, err := piaConf.GetPortForward()
|
||||
if err != nil {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
version: "3.7"
|
||||
services:
|
||||
pia:
|
||||
build: https://github.com/qdm12/private-internet-access-docker.git
|
||||
image: qmcgaw/private-internet-access
|
||||
container_name: pia
|
||||
cap_add:
|
||||
@@ -14,24 +13,40 @@ services:
|
||||
- 8388:8388/udp
|
||||
# command:
|
||||
environment:
|
||||
# More variables are available, see the readme table
|
||||
- VPNSP=pia
|
||||
- USER=js89ds7
|
||||
- PROTOCOL=udp
|
||||
- OPENVPN_VERBOSITY=1
|
||||
- TZ=
|
||||
|
||||
# PIA only
|
||||
- REGION=CA Montreal
|
||||
- PASSWORD=8fd9s239G
|
||||
- ENCRYPTION=strong
|
||||
- PROTOCOL=udp
|
||||
- REGION=CA Montreal
|
||||
- PORT_FORWARDING=off
|
||||
|
||||
# Mullvad only
|
||||
- COUNTRY=Sweden
|
||||
- CITY=
|
||||
- ISP=
|
||||
- PORT=
|
||||
|
||||
# DNS over TLS
|
||||
- DOT=on
|
||||
- DOT_PROVIDERS=cloudflare
|
||||
- DOT_VERBOSITY=1
|
||||
- BLOCK_MALICIOUS=on
|
||||
- BLOCK_SURVEILLANCE=off
|
||||
- BLOCK_ADS=off
|
||||
- UNBLOCK=
|
||||
# Firewall
|
||||
- EXTRA_SUBNETS=
|
||||
# Shadowsocks
|
||||
- SHADOWSOCKS=off
|
||||
- SHADOWSOCKS_PASSWORD=
|
||||
# Tinyproxy
|
||||
- TINYPROXY=off
|
||||
- TINYPROXY_LOG=Info
|
||||
- TINYPROXY_USER=
|
||||
- TINYPROXY_PASSWORD=
|
||||
- SHADOWSOCKS=off
|
||||
- SHADOWSOCKS_LOG=on
|
||||
- SHADOWSOCKS_PORT=8388
|
||||
- SHADOWSOCKS_PASSWORD=
|
||||
restart: always
|
||||
|
||||
2
go.mod
2
go.mod
@@ -4,7 +4,7 @@ go 1.13
|
||||
|
||||
require (
|
||||
github.com/kyokomi/emoji v2.1.0+incompatible
|
||||
github.com/qdm12/golibs v0.0.0-20200208153322-66b2eb719e21
|
||||
github.com/qdm12/golibs v0.0.0-20200224235252-bc16caae82ea
|
||||
github.com/stretchr/testify v1.4.0
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d
|
||||
)
|
||||
|
||||
4
go.sum
4
go.sum
@@ -61,8 +61,8 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/qdm12/golibs v0.0.0-20200208153322-66b2eb719e21 h1:Nza/Ar6tPYhDzkiNzbaJZHl4+GUXTqbtjGXuWenkqpQ=
|
||||
github.com/qdm12/golibs v0.0.0-20200208153322-66b2eb719e21/go.mod h1:YULaFjj6VGmhjak6f35sUWwEleHUmngN5IQ3kdvd6XE=
|
||||
github.com/qdm12/golibs v0.0.0-20200224235252-bc16caae82ea h1:ILUt8UU795dKZ2r7p3G44w1/vcGM/FUFXCcePYXYfS8=
|
||||
github.com/qdm12/golibs v0.0.0-20200224235252-bc16caae82ea/go.mod h1:YULaFjj6VGmhjak6f35sUWwEleHUmngN5IQ3kdvd6XE=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
|
||||
667
internal/constants/mullvad.go
Normal file
667
internal/constants/mullvad.go
Normal file
@@ -0,0 +1,667 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
const (
|
||||
MullvadCertificate = "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"
|
||||
)
|
||||
|
||||
func MullvadCountryChoices() (choices []string) {
|
||||
uniqueChoices := map[string]struct{}{}
|
||||
for _, server := range mullvadServers() {
|
||||
uniqueChoices[string(server.Country)] = struct{}{}
|
||||
}
|
||||
for choice := range uniqueChoices {
|
||||
choices = append(choices, choice)
|
||||
}
|
||||
return choices
|
||||
}
|
||||
|
||||
func MullvadCityChoices() (choices []string) {
|
||||
uniqueChoices := map[string]struct{}{}
|
||||
for _, server := range mullvadServers() {
|
||||
uniqueChoices[string(server.City)] = struct{}{}
|
||||
}
|
||||
for choice := range uniqueChoices {
|
||||
choices = append(choices, choice)
|
||||
}
|
||||
return choices
|
||||
}
|
||||
|
||||
func MullvadProviderChoices() (choices []string) {
|
||||
uniqueChoices := map[string]struct{}{}
|
||||
for _, server := range mullvadServers() {
|
||||
uniqueChoices[string(server.Provider)] = struct{}{}
|
||||
}
|
||||
for choice := range uniqueChoices {
|
||||
choices = append(choices, choice)
|
||||
}
|
||||
return choices
|
||||
}
|
||||
|
||||
func MullvadServerFilter(country models.MullvadCountry, city models.MullvadCity, provider models.MullvadProvider) (servers []models.MullvadServer) {
|
||||
for _, server := range mullvadServers() {
|
||||
if len(country) == 0 {
|
||||
server.Country = ""
|
||||
}
|
||||
if len(city) == 0 {
|
||||
server.City = ""
|
||||
}
|
||||
if len(provider) == 0 {
|
||||
server.Provider = ""
|
||||
}
|
||||
if server.Country == country && server.City == city && server.Provider == provider {
|
||||
servers = append(servers, server)
|
||||
}
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func mullvadServers() []models.MullvadServer {
|
||||
return []models.MullvadServer{
|
||||
{
|
||||
Country: models.MullvadCountry("united arab emirates"),
|
||||
City: models.MullvadCity("dubai"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{45, 9, 249, 34}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("albania"),
|
||||
City: models.MullvadCity("tirana"),
|
||||
Provider: models.MullvadProvider("iregister"),
|
||||
IPs: []net.IP{{31, 171, 154, 210}},
|
||||
DefaultPort: 1197,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("austria"),
|
||||
City: models.MullvadCity("wien"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{37, 120, 155, 250}, {217, 64, 127, 138}, {217, 64, 127, 202}},
|
||||
DefaultPort: 1196,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("australia"),
|
||||
City: models.MullvadCity("adelaide"),
|
||||
Provider: models.MullvadProvider("intergrid"),
|
||||
IPs: []net.IP{{116, 206, 231, 58}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("australia"),
|
||||
City: models.MullvadCity("brisbane"),
|
||||
Provider: models.MullvadProvider("intergrid"),
|
||||
IPs: []net.IP{{43, 245, 160, 162}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("australia"),
|
||||
City: models.MullvadCity("canberra"),
|
||||
Provider: models.MullvadProvider("intergrid"),
|
||||
IPs: []net.IP{{116, 206, 229, 98}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("australia"),
|
||||
City: models.MullvadCity("melbourne"),
|
||||
Provider: models.MullvadProvider("intergrid"),
|
||||
IPs: []net.IP{{116, 206, 228, 202}, {116, 206, 228, 242}, {116, 206, 230, 98}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("australia"),
|
||||
City: models.MullvadCity("perth"),
|
||||
Provider: models.MullvadProvider("intergrid"),
|
||||
IPs: []net.IP{{103, 77, 235, 66}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("australia"),
|
||||
City: models.MullvadCity("sydney"),
|
||||
Provider: models.MullvadProvider("intergrid"),
|
||||
IPs: []net.IP{{43, 245, 162, 130}, {103, 77, 232, 130}, {103, 77, 232, 146}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("australia"),
|
||||
City: models.MullvadCity("sydney"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{217, 138, 204, 82}, {217, 138, 204, 98}, {217, 138, 204, 66}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("belgium"),
|
||||
City: models.MullvadCity("brussels"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{37, 120, 218, 146}, {37, 120, 218, 138}, {91, 207, 57, 50}, {37, 120, 143, 138}, {185, 104, 186, 202}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("bulgaria"),
|
||||
City: models.MullvadCity("sofia"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{185, 94, 192, 42}, {185, 94, 192, 66}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("brazil"),
|
||||
City: models.MullvadCity("sao paulo"),
|
||||
Provider: models.MullvadProvider("qnax"),
|
||||
IPs: []net.IP{{191, 101, 62, 178}},
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("brazil"),
|
||||
City: models.MullvadCity("sao paulo"),
|
||||
Provider: models.MullvadProvider("heficed"),
|
||||
IPs: []net.IP{{177, 67, 80, 186}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("canada"),
|
||||
City: models.MullvadCity("montreal"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{139, 28, 218, 114}, {217, 138, 200, 194}, {217, 138, 200, 186}, {87, 101, 92, 146}, {176, 113, 74, 178}, {37, 120, 205, 114}, {87, 101, 92, 138}, {37, 120, 205, 122}, {217, 138, 200, 210}, {217, 138, 200, 202}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("canada"),
|
||||
City: models.MullvadCity("toronto"),
|
||||
Provider: models.MullvadProvider("amanah"),
|
||||
IPs: []net.IP{{184, 75, 214, 130}, {162, 219, 176, 250}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("canada"),
|
||||
City: models.MullvadCity("vancouver"),
|
||||
Provider: models.MullvadProvider("100tb"),
|
||||
IPs: []net.IP{{172, 83, 40, 34}, {172, 83, 40, 38}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("canada"),
|
||||
City: models.MullvadCity("vancouver"),
|
||||
Provider: models.MullvadProvider("esecuredata"),
|
||||
IPs: []net.IP{{71, 19, 249, 81}, {176, 113, 74, 186}, {71, 19, 248, 240}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("switzerland"),
|
||||
City: models.MullvadCity("zurich"),
|
||||
Provider: models.MullvadProvider("31173"),
|
||||
IPs: []net.IP{{193, 32, 127, 82}, {193, 32, 127, 81}, {193, 32, 127, 83}, {193, 32, 127, 84}},
|
||||
Owned: true,
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("zwitzerland"),
|
||||
City: models.MullvadCity("zurich"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{185, 212, 170, 50}, {185, 183, 104, 82}, {185, 9, 18, 98}, {82, 102, 24, 130}, {82, 102, 24, 186}, {185, 212, 170, 162}, {185, 9, 18, 114}},
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("switzerland"),
|
||||
City: models.MullvadCity("zurich"),
|
||||
Provider: models.MullvadProvider("privateLayer"),
|
||||
IPs: []net.IP{{179, 43, 128, 170}, {81, 17, 20, 34}},
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("czech republic"),
|
||||
City: models.MullvadCity("prague"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{217, 138, 199, 82}, {217, 138, 199, 74}},
|
||||
DefaultPort: 1197,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("germany"),
|
||||
City: models.MullvadCity("frankfurt"),
|
||||
Provider: models.MullvadProvider("31173"),
|
||||
IPs: []net.IP{{185, 213, 155, 132}, {185, 213, 155, 140}, {185, 213, 155, 136}, {185, 213, 155, 133}, {185, 213, 155, 144}, {185, 213, 155, 143}, {185, 213, 155, 138}, {185, 213, 155, 142}, {185, 213, 155, 139}, {185, 213, 155, 135}, {185, 213, 155, 145}, {185, 213, 155, 137}, {185, 213, 155, 131}, {185, 213, 155, 134}, {185, 213, 155, 141}},
|
||||
Owned: true,
|
||||
DefaultPort: 1197,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("germany"),
|
||||
City: models.MullvadCity("frankfurt"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{82, 102, 16, 90}, {185, 104, 184, 186}, {77, 243, 183, 202}},
|
||||
DefaultPort: 1197,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("denmark"),
|
||||
City: models.MullvadCity("copenhagen"),
|
||||
Provider: models.MullvadProvider("31173"),
|
||||
IPs: []net.IP{{141, 98, 254, 71}, {141, 98, 254, 72}},
|
||||
Owned: true,
|
||||
DefaultPort: 1195,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("denmark"),
|
||||
City: models.MullvadCity("copenhagen"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{185, 206, 224, 114}, {185, 206, 224, 119}},
|
||||
DefaultPort: 1195,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("denmark"),
|
||||
City: models.MullvadCity("copenhagen"),
|
||||
Provider: models.MullvadProvider("blix"),
|
||||
IPs: []net.IP{{134, 90, 149, 138}},
|
||||
DefaultPort: 1195,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("denmark"),
|
||||
City: models.MullvadCity("copenhagen"),
|
||||
Provider: models.MullvadProvider("asergo"),
|
||||
IPs: []net.IP{{82, 103, 140, 213}},
|
||||
DefaultPort: 1195,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("spain"),
|
||||
City: models.MullvadCity("madrid"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{195, 206, 107, 146}, {45, 152, 183, 42}, {89, 238, 178, 74}, {45, 152, 183, 26}, {89, 238, 178, 34}},
|
||||
DefaultPort: 1195,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("finland"),
|
||||
City: models.MullvadCity("helsinki"),
|
||||
Provider: models.MullvadProvider("creanova"),
|
||||
IPs: []net.IP{{185, 204, 1, 174}, {185, 204, 1, 176}, {185, 212, 149, 201}, {185, 204, 1, 175}, {185, 204, 1, 173}, {185, 204, 1, 172}, {185, 204, 1, 171}},
|
||||
Owned: true,
|
||||
DefaultPort: 1196,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("france"),
|
||||
City: models.MullvadCity("paris"),
|
||||
Provider: models.MullvadProvider("31173"),
|
||||
IPs: []net.IP{{193, 32, 126, 83}, {193, 32, 126, 82}, {193, 32, 126, 81}, {193, 32, 126, 84}},
|
||||
Owned: true,
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("france"),
|
||||
City: models.MullvadCity("paris"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{185, 189, 113, 82}, {185, 156, 173, 218}, {185, 128, 25, 162}},
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("uk"),
|
||||
City: models.MullvadCity("london"),
|
||||
Provider: models.MullvadProvider("31173"),
|
||||
IPs: []net.IP{{141, 98, 252, 133}, {141, 98, 252, 139}, {141, 98, 252, 137}, {141, 98, 252, 143}, {141, 98, 252, 142}, {141, 98, 252, 132}, {141, 98, 252, 134}, {141, 98, 252, 140}, {141, 98, 252, 141}, {141, 98, 252, 136}, {141, 98, 252, 144}, {141, 98, 252, 131}, {141, 98, 252, 135}, {141, 98, 252, 138}},
|
||||
Owned: true,
|
||||
DefaultPort: 1196,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("uk"),
|
||||
City: models.MullvadCity("london"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{185, 200, 118, 105}, {185, 212, 168, 244}},
|
||||
DefaultPort: 1196,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("uk"),
|
||||
City: models.MullvadCity("manchester"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{89, 238, 130, 66}, {81, 92, 205, 10}, {89, 238, 130, 74}, {81, 92, 205, 18}, {81, 92, 205, 26}, {89, 238, 183, 244}, {89, 238, 132, 36}, {217, 151, 98, 68}, {37, 120, 159, 164}, {89, 238, 183, 60}},
|
||||
DefaultPort: 1196,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("greece"),
|
||||
City: models.MullvadCity("athens"),
|
||||
Provider: models.MullvadProvider("aweb"),
|
||||
IPs: []net.IP{{185, 226, 67, 168}},
|
||||
DefaultPort: 1302,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("hong kong"),
|
||||
City: models.MullvadCity("hong kong"),
|
||||
Provider: models.MullvadProvider("leaseweb"),
|
||||
IPs: []net.IP{{209, 58, 185, 53}, {209, 58, 184, 146}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("hungary"),
|
||||
City: models.MullvadCity("budapest"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{185, 94, 190, 138}, {185, 189, 114, 10}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("ireland"),
|
||||
City: models.MullvadCity("dublin"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{217, 138, 222, 90}, {217, 138, 222, 82}},
|
||||
DefaultPort: 1197,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("israel"),
|
||||
City: models.MullvadCity("tel aviv"),
|
||||
Provider: models.MullvadProvider("hqserv"),
|
||||
IPs: []net.IP{{185, 191, 207, 210}},
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("italy"),
|
||||
City: models.MullvadCity("milan"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{217, 138, 197, 106}, {217, 64, 113, 180}, {217, 138, 197, 98}, {217, 138, 197, 114}, {217, 64, 113, 183}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("japan"),
|
||||
City: models.MullvadCity("tokyo"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{37, 120, 210, 138}, {193, 148, 16, 218}, {37, 120, 210, 146}, {185, 242, 4, 50}, {37, 120, 210, 122}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("luxembourg"),
|
||||
City: models.MullvadCity("luxembourg"),
|
||||
Provider: models.MullvadProvider("evoluso"),
|
||||
IPs: []net.IP{{92, 223, 89, 160}, {92, 223, 89, 182}},
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("latvia"),
|
||||
City: models.MullvadCity("riga"),
|
||||
Provider: models.MullvadProvider("makonix"),
|
||||
IPs: []net.IP{{31, 170, 22, 2}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("moldova"),
|
||||
City: models.MullvadCity("chisinau"),
|
||||
Provider: models.MullvadProvider("trabia"),
|
||||
IPs: []net.IP{{178, 175, 142, 194}},
|
||||
DefaultPort: 1197,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("netherlands"),
|
||||
City: models.MullvadCity("amsterdam"),
|
||||
Provider: models.MullvadProvider("31173"),
|
||||
IPs: []net.IP{{185, 65, 134, 139}, {185, 65, 134, 133}, {185, 65, 134, 148}, {185, 65, 134, 147}, {185, 65, 134, 141}, {185, 65, 134, 140}, {185, 65, 134, 145}, {185, 65, 134, 132}, {185, 65, 134, 146}, {185, 65, 134, 143}, {185, 65, 134, 134}, {185, 65, 134, 136}, {185, 65, 134, 135}, {185, 65, 134, 142}, {185, 65, 134, 144}},
|
||||
Owned: true,
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("norway"),
|
||||
City: models.MullvadCity("oslo"),
|
||||
Provider: models.MullvadProvider("blix"),
|
||||
IPs: []net.IP{{91, 90, 44, 13}, {91, 90, 44, 18}, {91, 90, 44, 12}, {91, 90, 44, 15}, {91, 90, 44, 16}, {91, 90, 44, 17}, {91, 90, 44, 14}, {91, 90, 44, 11}},
|
||||
Owned: true,
|
||||
DefaultPort: 1302,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("new zealand"),
|
||||
City: models.MullvadCity("auckland"),
|
||||
Provider: models.MullvadProvider("intergrid"),
|
||||
IPs: []net.IP{{103, 231, 91, 114}},
|
||||
DefaultPort: 1195,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("poland"),
|
||||
City: models.MullvadCity("warsaw"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{37, 120, 211, 202}, {37, 120, 156, 162}, {185, 244, 214, 210}, {37, 120, 211, 186}, {185, 244, 214, 215}, {37, 120, 211, 194}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("portugal"),
|
||||
City: models.MullvadCity("lisbon"),
|
||||
Provider: models.MullvadProvider("dotsi"),
|
||||
IPs: []net.IP{{5, 206, 231, 214}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("romania"),
|
||||
City: models.MullvadCity("bucharest"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{89, 40, 181, 146}, {185, 181, 100, 202}, {89, 40, 181, 82}, {185, 45, 13, 10}, {89, 40, 181, 210}},
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("serbia"),
|
||||
City: models.MullvadCity("belgrade"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{141, 98, 103, 50}},
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("serbia"),
|
||||
City: models.MullvadCity("nis"),
|
||||
Provider: models.MullvadProvider("ninet"),
|
||||
IPs: []net.IP{{176, 104, 107, 118}},
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("sweden"),
|
||||
City: models.MullvadCity("gothenburg"),
|
||||
Provider: models.MullvadProvider("31173"),
|
||||
IPs: []net.IP{{185, 213, 154, 139}, {185, 213, 154, 141}, {185, 213, 154, 140}, {185, 213, 154, 132}, {185, 213, 154, 135}, {185, 213, 154, 138}, {185, 213, 154, 133}, {185, 213, 154, 131}, {185, 213, 154, 134}, {185, 213, 154, 142}, {185, 213, 154, 137}},
|
||||
Owned: true,
|
||||
DefaultPort: 1302,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("sweden"),
|
||||
City: models.MullvadCity("helsingborg"),
|
||||
Provider: models.MullvadProvider("31173"),
|
||||
IPs: []net.IP{{185, 213, 152, 133}, {185, 213, 152, 132}, {185, 213, 152, 138}, {185, 213, 152, 131}, {185, 213, 152, 137}},
|
||||
Owned: true,
|
||||
DefaultPort: 1302,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("sweden"),
|
||||
City: models.MullvadCity("malmo"),
|
||||
Provider: models.MullvadProvider("31173"),
|
||||
IPs: []net.IP{{193, 138, 218, 138}, {45, 83, 220, 87}, {141, 98, 255, 94}, {141, 98, 255, 85}, {141, 98, 255, 87}, {141, 98, 255, 92}, {45, 83, 220, 84}, {141, 98, 255, 86}, {45, 83, 220, 81}, {193, 138, 218, 135}, {193, 138, 218, 131}, {193, 138, 218, 136}, {141, 98, 255, 88}, {141, 98, 255, 91}, {193, 138, 218, 133}, {45, 83, 220, 89}, {45, 83, 220, 88}, {141, 98, 255, 84}, {141, 98, 255, 89}, {193, 138, 218, 134}, {45, 83, 220, 86}, {141, 98, 255, 83}, {45, 83, 220, 85}, {141, 98, 255, 90}, {141, 98, 255, 93}, {193, 138, 218, 132}, {193, 138, 218, 137}, {45, 83, 220, 91}},
|
||||
Owned: true,
|
||||
DefaultPort: 1302,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("sweden"),
|
||||
City: models.MullvadCity("stockholm"),
|
||||
Provider: models.MullvadProvider("31173"),
|
||||
IPs: []net.IP{{185, 65, 135, 150}, {185, 65, 135, 153}, {185, 65, 135, 151}, {185, 65, 135, 149}, {185, 65, 135, 141}, {185, 65, 135, 144}, {185, 65, 135, 145}, {185, 65, 135, 140}, {185, 65, 135, 134}, {185, 65, 135, 139}, {185, 65, 135, 131}, {185, 65, 135, 152}, {185, 65, 135, 146}, {185, 65, 135, 138}, {185, 65, 135, 143}, {185, 65, 135, 135}, {185, 65, 135, 154}, {185, 65, 135, 136}, {185, 65, 135, 133}, {185, 65, 135, 132}},
|
||||
Owned: true,
|
||||
DefaultPort: 1302,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("singapore"),
|
||||
City: models.MullvadCity("singapore"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{37, 120, 208, 218}, {37, 120, 208, 234}, {37, 120, 208, 226}, {185, 128, 24, 50}},
|
||||
DefaultPort: 1196,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("singapore"),
|
||||
City: models.MullvadCity("singapore"),
|
||||
Provider: models.MullvadProvider("leaseweb"),
|
||||
IPs: []net.IP{{103, 254, 153, 82}},
|
||||
DefaultPort: 1196,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("atlanta"),
|
||||
Provider: models.MullvadProvider("100tb"),
|
||||
IPs: []net.IP{{208, 84, 153, 142}, {107, 152, 108, 62}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("atlanta"),
|
||||
Provider: models.MullvadProvider("quadranet"),
|
||||
IPs: []net.IP{{104, 129, 24, 242}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("atlanta"),
|
||||
Provider: models.MullvadProvider("micfo"),
|
||||
IPs: []net.IP{{155, 254, 96, 2}, {155, 254, 96, 18}, {155, 254, 96, 34}}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("chicago"),
|
||||
Provider: models.MullvadProvider("tzulo"),
|
||||
IPs: []net.IP{{68, 235, 43, 18}, {68, 235, 43, 26}, {68, 235, 43, 42}, {68, 235, 43, 50}, {68, 235, 43, 58}, {68, 235, 43, 66}, {68, 235, 43, 74}}, // 3 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("chicago"),
|
||||
Provider: models.MullvadProvider("quadranet"),
|
||||
IPs: []net.IP{}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("dallas"),
|
||||
Provider: models.MullvadProvider("quadranet"),
|
||||
IPs: []net.IP{{96, 44, 145, 18}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("dallas"),
|
||||
Provider: models.MullvadProvider("100tb"),
|
||||
IPs: []net.IP{{104, 200, 142, 50}, {107, 152, 102, 106}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("denver"),
|
||||
Provider: models.MullvadProvider("tzulo"),
|
||||
IPs: []net.IP{{198, 54, 128, 74}}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("los angeles"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{45, 152, 182, 66}, {45, 152, 182, 74}, {45, 83, 89, 162}, {185, 230, 126, 146}}, // 7 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("los angeles"),
|
||||
Provider: models.MullvadProvider("tzulo"),
|
||||
IPs: []net.IP{{198, 54, 129, 74}}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("los angeles"),
|
||||
Provider: models.MullvadProvider("100tb"),
|
||||
IPs: []net.IP{{104, 200, 152, 66}, {107, 181, 168, 130}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("los angeles"),
|
||||
Provider: models.MullvadProvider("choopa"),
|
||||
IPs: []net.IP{{104, 238, 143, 58}}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("miami"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{37, 120, 215, 130}, {193, 37, 252, 138}, {193, 37, 252, 154}, {37, 120, 215, 138}}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("miami"),
|
||||
Provider: models.MullvadProvider("100tb"),
|
||||
IPs: []net.IP{{172, 98, 76, 114}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("miami"),
|
||||
Provider: models.MullvadProvider("micfo"),
|
||||
IPs: []net.IP{}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("new york"),
|
||||
Provider: models.MullvadProvider("m247"),
|
||||
IPs: []net.IP{{185, 232, 22, 66}, {185, 232, 22, 98}, {193, 148, 18, 250}, {185, 232, 22, 10}, {217, 138, 206, 10}, {193, 148, 18, 218}, {193, 148, 18, 226}, {193, 148, 18, 194}, {87, 101, 95, 98}, {87, 101, 95, 114}, {87, 101, 95, 122}, {212, 103, 48, 226}, {176, 113, 72, 226}, {217, 138, 198, 250}, {217, 138, 206, 58}}, // 5 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("new york"),
|
||||
Provider: models.MullvadProvider("100tb"),
|
||||
IPs: []net.IP{{107, 182, 226, 206}, {107, 182, 226, 218}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("phoenix"),
|
||||
Provider: models.MullvadProvider("100tb"),
|
||||
IPs: []net.IP{}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("phoenix"),
|
||||
Provider: models.MullvadProvider("micfo"),
|
||||
IPs: []net.IP{{192, 200, 24, 82}}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("piscataway"),
|
||||
Provider: models.MullvadProvider("choopa"),
|
||||
IPs: []net.IP{{108, 61, 78, 138}, {108, 61, 48, 115}, {66, 55, 147, 59}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("seattle"),
|
||||
Provider: models.MullvadProvider("100tb"),
|
||||
IPs: []net.IP{{104, 200, 129, 202}, {104, 200, 129, 150}, {104, 200, 129, 110}}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("seattle"),
|
||||
Provider: models.MullvadProvider("micfo"),
|
||||
IPs: []net.IP{{104, 128, 136, 146}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("san francisco"),
|
||||
Provider: models.MullvadProvider("micfo"),
|
||||
IPs: []net.IP{{209, 209, 238, 34}}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("salt lake city"),
|
||||
Provider: models.MullvadProvider("100tb"),
|
||||
IPs: []net.IP{{107, 182, 238, 229}, {107, 182, 235, 233}, {67, 212, 238, 236}, {67, 212, 238, 237}, {67, 212, 238, 239}, {107, 182, 239, 185}, {107, 182, 239, 170}}, // 2 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: models.MullvadCountry("usa"),
|
||||
City: models.MullvadCity("secaucus"),
|
||||
Provider: models.MullvadProvider("quadranet"),
|
||||
IPs: []net.IP{{23, 226, 131, 154}}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
@@ -21,12 +18,15 @@ const (
|
||||
PIACertificate_STRONG = "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"
|
||||
)
|
||||
|
||||
func PIAGeoChoices() []string {
|
||||
return []string{"AU Melbourne", "AU Perth", "AU Sydney", "Austria", "Belgium", "CA Montreal", "CA Toronto", "CA Vancouver", "Czech Republic", "DE Berlin", "DE Frankfurt", "Denmark", "Finland", "France", "Hong Kong", "Hungary", "India", "Ireland", "Israel", "Italy", "Japan", "Luxembourg", "Mexico", "Netherlands", "New Zealand", "Norway", "Poland", "Romania", "Singapore", "Spain", "Sweden", "Switzerland", "UAE", "UK London", "UK Manchester", "UK Southampton", "US Atlanta", "US California", "US Chicago", "US Denver", "US East", "US Florida", "US Houston", "US Las Vegas", "US New York City", "US Seattle", "US Silicon Valley", "US Texas", "US Washington DC", "US West"}
|
||||
func PIAGeoChoices() (regions []string) {
|
||||
for region := range PIAGeoToSubdomainMapping() {
|
||||
regions = append(regions, string(region))
|
||||
}
|
||||
return regions
|
||||
}
|
||||
|
||||
func PIAGeoToSubdomainMapping(region models.PIARegion) (subdomain string, err error) {
|
||||
mapping := map[models.PIARegion]string{
|
||||
func PIAGeoToSubdomainMapping() map[models.PIARegion]string {
|
||||
return map[models.PIARegion]string{
|
||||
models.PIARegion("AU Melbourne"): "au-melbourne",
|
||||
models.PIARegion("AU Perth"): "au-perth",
|
||||
models.PIARegion("AU Sydney"): "au-sydney",
|
||||
@@ -78,11 +78,6 @@ func PIAGeoToSubdomainMapping(region models.PIARegion) (subdomain string, err er
|
||||
models.PIARegion("US Washington DC"): "us-washingtondc",
|
||||
models.PIARegion("US West"): "us-west",
|
||||
}
|
||||
subdomain, ok := mapping[region]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("PIA region %q does not exist and can only be one of ", strings.Join(PIAGeoChoices(), ","))
|
||||
}
|
||||
return subdomain, nil
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
@@ -2,9 +2,9 @@ package constants
|
||||
|
||||
const (
|
||||
// Annoucement is a message annoucement
|
||||
Annoucement = "Total rewrite in Go with many new features"
|
||||
// AnnoucementExpiration is the expiration time of the annoucement in unix timestamp
|
||||
AnnoucementExpiration = 1582761600
|
||||
Annoucement = "Support for Mullvad"
|
||||
// AnnoucementExpiration is the expiration date of the annoucement in format yyyy-mm-dd
|
||||
AnnoucementExpiration = "2020-03-15"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
17
internal/constants/splash_test.go
Normal file
17
internal/constants/splash_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_AnnoucementExpiration(t *testing.T) {
|
||||
t.Parallel()
|
||||
if len(AnnoucementExpiration) == 0 {
|
||||
return
|
||||
}
|
||||
_, err := time.Parse("2006-01-02", AnnoucementExpiration)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@@ -60,7 +60,7 @@ func generateUnboundConf(settings settings.DNS, client network.Client, logger lo
|
||||
"harden-algo-downgrade": "yes",
|
||||
// Network
|
||||
"do-ip4": "yes",
|
||||
"do-ip6": "no",
|
||||
"do-ip6": "yes",
|
||||
"interface": "127.0.0.1",
|
||||
"port": "53",
|
||||
// Other
|
||||
|
||||
@@ -43,7 +43,7 @@ server:
|
||||
cache-max-ttl: 9000
|
||||
cache-min-ttl: 3600
|
||||
do-ip4: yes
|
||||
do-ip6: no
|
||||
do-ip6: yes
|
||||
harden-algo-downgrade: yes
|
||||
harden-below-nxdomain: yes
|
||||
harden-referral-path: yes
|
||||
|
||||
@@ -18,8 +18,7 @@ type Configurator interface {
|
||||
Clear() error
|
||||
BlockAll() error
|
||||
CreateGeneralRules() error
|
||||
CreateVPNRules(dev models.VPNDevice, serverIPs []net.IP, defaultInterface string,
|
||||
port uint16, protocol models.NetworkProtocol) error
|
||||
CreateVPNRules(dev models.VPNDevice, defaultInterface string, connections []models.OpenVPNConnection) error
|
||||
CreateLocalSubnetsRules(subnet net.IPNet, extraSubnets []net.IPNet, defaultInterface string) error
|
||||
AddRoutesVia(subnets []net.IPNet, defaultGateway net.IP, defaultInterface string) error
|
||||
GetDefaultRoute() (defaultInterface string, defaultGateway net.IP, defaultSubnet net.IPNet, err error)
|
||||
|
||||
@@ -77,14 +77,13 @@ func (c *configurator) CreateGeneralRules() error {
|
||||
})
|
||||
}
|
||||
|
||||
func (c *configurator) CreateVPNRules(dev models.VPNDevice, serverIPs []net.IP,
|
||||
defaultInterface string, port uint16, protocol models.NetworkProtocol) error {
|
||||
for _, serverIP := range serverIPs {
|
||||
func (c *configurator) CreateVPNRules(dev models.VPNDevice, defaultInterface string, connections []models.OpenVPNConnection) error {
|
||||
for _, connection := range connections {
|
||||
c.logger.Info("%s: allowing output traffic to VPN server %s through %s on port %s %d",
|
||||
logPrefix, serverIP, defaultInterface, protocol, port)
|
||||
logPrefix, connection.IP, defaultInterface, connection.Protocol, connection.Port)
|
||||
if err := c.runIptablesInstruction(
|
||||
fmt.Sprintf("-A OUTPUT -d %s -o %s -p %s -m %s --dport %d -j ACCEPT",
|
||||
serverIP, defaultInterface, protocol, protocol, port)); err != nil {
|
||||
connection.IP, defaultInterface, connection.Protocol, connection.Protocol, connection.Port)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,12 @@ type (
|
||||
PIAEncryption string
|
||||
// PIARegion is used to define the list of regions available for PIA
|
||||
PIARegion string
|
||||
// MullvadCountry is used as the country for a Mullvad server
|
||||
MullvadCountry string
|
||||
// MullvadCity is used as the city for a Mullvad server
|
||||
MullvadCity string
|
||||
// MullvadProvider is used as the Internet service provider for a Mullvad server
|
||||
MullvadProvider string
|
||||
// URL is an HTTP(s) URL address
|
||||
URL string
|
||||
// Filepath is a local filesytem file path
|
||||
|
||||
12
internal/models/mullvad.go
Normal file
12
internal/models/mullvad.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package models
|
||||
|
||||
import "net"
|
||||
|
||||
type MullvadServer struct {
|
||||
Country MullvadCountry
|
||||
City MullvadCity
|
||||
Provider MullvadProvider
|
||||
Owned bool
|
||||
IPs []net.IP
|
||||
DefaultPort uint16
|
||||
}
|
||||
9
internal/models/openvpn.go
Normal file
9
internal/models/openvpn.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package models
|
||||
|
||||
import "net"
|
||||
|
||||
type OpenVPNConnection struct {
|
||||
IP net.IP
|
||||
Port uint16
|
||||
Protocol NetworkProtocol
|
||||
}
|
||||
74
internal/mullvad/conf.go
Normal file
74
internal/mullvad/conf.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package mullvad
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/golibs/files"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
func (c *configurator) GetOpenVPNConnections(country models.MullvadCountry, city models.MullvadCity, provider models.MullvadProvider, protocol models.NetworkProtocol, customPort uint16) (connections []models.OpenVPNConnection, err error) {
|
||||
servers := constants.MullvadServerFilter(country, city, provider)
|
||||
if len(servers) == 0 {
|
||||
return nil, fmt.Errorf("no server found for country %q, city %q and ISP %q", country, city, provider)
|
||||
}
|
||||
for _, server := range servers {
|
||||
port := server.DefaultPort
|
||||
if customPort > 0 {
|
||||
port = customPort
|
||||
}
|
||||
for _, IP := range server.IPs {
|
||||
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: protocol})
|
||||
}
|
||||
}
|
||||
return connections, nil
|
||||
}
|
||||
|
||||
func (c *configurator) BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int) (err error) {
|
||||
if len(connections) == 0 {
|
||||
return fmt.Errorf("at least one connection string is expected")
|
||||
}
|
||||
lines := []string{
|
||||
"client",
|
||||
"dev tun",
|
||||
"nobind",
|
||||
"persist-key",
|
||||
"persist-tun",
|
||||
"tls-client",
|
||||
"remote-cert-tls server",
|
||||
"ping 300",
|
||||
|
||||
// Mullvad specific
|
||||
// "sndbuf 524288"
|
||||
// "rcvbuf 524288"
|
||||
"cipher AES-256-CBC",
|
||||
"tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA",
|
||||
"tun-ipv6",
|
||||
|
||||
// Added constant values
|
||||
"mute-replay-warnings",
|
||||
"auth-nocache",
|
||||
"user nonrootuser",
|
||||
"pull-filter ignore \"auth-token\"", // prevent auth failed loops
|
||||
"auth-retry nointeract",
|
||||
"remote-random",
|
||||
|
||||
// Modified variables
|
||||
fmt.Sprintf("verb %d", verbosity),
|
||||
fmt.Sprintf("auth-user-pass %s", constants.OpenVPNAuthConf),
|
||||
fmt.Sprintf("proto %s", string(connections[0].Protocol)),
|
||||
}
|
||||
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.MullvadCertificate,
|
||||
"-----END CERTIFICATE-----",
|
||||
"</ca>",
|
||||
"",
|
||||
}...)
|
||||
return c.fileManager.WriteLinesToFile(string(constants.OpenVPNConf), lines, files.Ownership(uid, gid), files.Permissions(0400))
|
||||
}
|
||||
27
internal/mullvad/mullvad.go
Normal file
27
internal/mullvad/mullvad.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package mullvad
|
||||
|
||||
import (
|
||||
"github.com/qdm12/golibs/files"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/golibs/network"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
const logPrefix = "Mullvad configurator"
|
||||
|
||||
// Configurator contains methods to download, read and modify the openvpn configuration to connect as a client
|
||||
type Configurator interface {
|
||||
GetOpenVPNConnections(country models.MullvadCountry, city models.MullvadCity, provider models.MullvadProvider, protocol models.NetworkProtocol, customPort uint16) (connections []models.OpenVPNConnection, err error)
|
||||
BuildConf(connections []models.OpenVPNConnection, verbosity, uid, gid int) (err error)
|
||||
}
|
||||
|
||||
type configurator struct {
|
||||
client network.Client
|
||||
fileManager files.FileManager
|
||||
logger logging.Logger
|
||||
}
|
||||
|
||||
// NewConfigurator returns a new Configurator object
|
||||
func NewConfigurator(client network.Client, fileManager files.FileManager, logger logging.Logger) Configurator {
|
||||
return &configurator{client, fileManager, logger}
|
||||
}
|
||||
40
internal/params/mullvad.go
Normal file
40
internal/params/mullvad.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package params
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
libparams "github.com/qdm12/golibs/params"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
// GetMullvadCountry obtains the country for the Mullvad server from the
|
||||
// environment variable COUNTRY
|
||||
func (p *paramsReader) GetMullvadCountry() (country models.MullvadCountry, err error) {
|
||||
choices := append(constants.MullvadCountryChoices(), "")
|
||||
s, err := p.envParams.GetValueIfInside("COUNTRY", choices)
|
||||
return models.MullvadCountry(strings.ToLower(s)), err
|
||||
}
|
||||
|
||||
// GetMullvadCity obtains the city for the Mullvad server from the
|
||||
// environment variable CITY
|
||||
func (p *paramsReader) GetMullvadCity() (country models.MullvadCity, err error) {
|
||||
choices := append(constants.MullvadCityChoices(), "")
|
||||
s, err := p.envParams.GetValueIfInside("CITY", choices)
|
||||
return models.MullvadCity(strings.ToLower(s)), err
|
||||
}
|
||||
|
||||
// GetMullvadISP obtains the ISP for the Mullvad server from the
|
||||
// environment variable ISP
|
||||
func (p *paramsReader) GetMullvadISP() (country models.MullvadProvider, err error) {
|
||||
choices := append(constants.MullvadProviderChoices(), "")
|
||||
s, err := p.envParams.GetValueIfInside("ISP", choices)
|
||||
return models.MullvadProvider(strings.ToLower(s)), err
|
||||
}
|
||||
|
||||
// GetMullvadPort obtains the port to reach the Mullvad server on from the
|
||||
// environment variable PORT
|
||||
func (p *paramsReader) GetMullvadPort() (port uint16, err error) {
|
||||
n, err := p.envParams.GetEnvIntRange("PORT", 0, 65535, libparams.Default("0"))
|
||||
return uint16(n), err
|
||||
}
|
||||
@@ -5,9 +5,37 @@ import (
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
// GetUser obtains the user to use to connect to the VPN servers
|
||||
func (p *paramsReader) GetUser() (s string, err error) {
|
||||
defer func() {
|
||||
unsetenvErr := p.unsetEnv("USER")
|
||||
if err == nil {
|
||||
err = unsetenvErr
|
||||
}
|
||||
}()
|
||||
return p.envParams.GetEnv("USER", libparams.CaseSensitiveValue(), libparams.Compulsory())
|
||||
}
|
||||
|
||||
// GetPassword obtains the password to use to connect to the VPN servers
|
||||
func (p *paramsReader) GetPassword() (s string, err error) {
|
||||
defer func() {
|
||||
unsetenvErr := p.unsetEnv("PASSWORD")
|
||||
if err == nil {
|
||||
err = unsetenvErr
|
||||
}
|
||||
}()
|
||||
return p.envParams.GetEnv("PASSWORD", libparams.CaseSensitiveValue(), libparams.Compulsory())
|
||||
}
|
||||
|
||||
// GetNetworkProtocol obtains the network protocol to use to connect to the
|
||||
// VPN servers from the environment variable PROTOCOL
|
||||
func (p *paramsReader) GetNetworkProtocol() (protocol models.NetworkProtocol, err error) {
|
||||
s, err := p.envParams.GetValueIfInside("PROTOCOL", []string{"tcp", "udp"}, libparams.Default("udp"))
|
||||
return models.NetworkProtocol(s), err
|
||||
}
|
||||
|
||||
// GetOpenVPNVerbosity obtains the verbosity level for verbosity between 0 and 6
|
||||
// from the environment variable OPENVPN_VERBOSITY
|
||||
func (p *paramsReader) GetOpenVPNVerbosity() (verbosity int, err error) {
|
||||
return p.envParams.GetEnvIntRange("OPENVPN_VERBOSITY", 0, 6, libparams.Default("1"))
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
|
||||
// ParamsReader contains methods to obtain parameters
|
||||
type ParamsReader interface {
|
||||
GetVPNSP() (vpnServiceProvider string, err error)
|
||||
|
||||
// DNS over TLS getters
|
||||
GetDNSOverTLS() (DNSOverTLS bool, err error)
|
||||
GetDNSOverTLSProviders() (providers []models.DNSProvider, err error)
|
||||
@@ -29,16 +31,23 @@ type ParamsReader interface {
|
||||
GetExtraSubnets() (extraSubnets []net.IPNet, err error)
|
||||
|
||||
// VPN getters
|
||||
GetNetworkProtocol() (protocol models.NetworkProtocol, err error)
|
||||
|
||||
// PIA getters
|
||||
GetUser() (s string, err error)
|
||||
GetPassword() (s string, err error)
|
||||
GetNetworkProtocol() (protocol models.NetworkProtocol, err error)
|
||||
GetOpenVPNVerbosity() (verbosity int, err error)
|
||||
|
||||
// PIA getters
|
||||
GetPortForwarding() (activated bool, err error)
|
||||
GetPortForwardingStatusFilepath() (filepath models.Filepath, err error)
|
||||
GetPIAEncryption() (models.PIAEncryption, error)
|
||||
GetPIARegion() (models.PIARegion, error)
|
||||
|
||||
// Mullvad getters
|
||||
GetMullvadCountry() (country models.MullvadCountry, err error)
|
||||
GetMullvadCity() (country models.MullvadCity, err error)
|
||||
GetMullvadISP() (country models.MullvadProvider, err error)
|
||||
GetMullvadPort() (port uint16, err error)
|
||||
|
||||
// Shadowsocks getters
|
||||
GetShadowSocks() (activated bool, err error)
|
||||
GetShadowSocksLog() (activated bool, err error)
|
||||
@@ -75,3 +84,9 @@ func NewParamsReader(logger logging.Logger) ParamsReader {
|
||||
unsetEnv: os.Unsetenv,
|
||||
}
|
||||
}
|
||||
|
||||
// GetVPNSP obtains the VPN service provider to use from the environment variable VPNSP
|
||||
func (p *paramsReader) GetVPNSP() (vpnServiceProvider string, err error) {
|
||||
s, err := p.envParams.GetValueIfInside("VPNSP", []string{"pia", "mullvad"})
|
||||
return s, err
|
||||
}
|
||||
|
||||
@@ -9,40 +9,6 @@ import (
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
// GetUser obtains the user to use to connect to the VPN servers
|
||||
func (p *paramsReader) GetUser() (s string, err error) {
|
||||
defer func() {
|
||||
unsetenvErr := p.unsetEnv("USER")
|
||||
if err == nil {
|
||||
err = unsetenvErr
|
||||
}
|
||||
}()
|
||||
s, err = p.envParams.GetEnv("USER")
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if len(s) == 0 {
|
||||
return s, fmt.Errorf("USER environment variable cannot be empty")
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// GetPassword obtains the password to use to connect to the VPN servers
|
||||
func (p *paramsReader) GetPassword() (s string, err error) {
|
||||
defer func() {
|
||||
unsetenvErr := p.unsetEnv("PASSWORD")
|
||||
if err == nil {
|
||||
err = unsetenvErr
|
||||
}
|
||||
}()
|
||||
s, err = p.envParams.GetEnv("PASSWORD")
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if len(s) == 0 {
|
||||
return s, fmt.Errorf("PASSWORD environment variable cannot be empty")
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// GetPortForwarding obtains if port forwarding on the VPN provider server
|
||||
// side is enabled or not from the environment variable PORT_FORWARDING
|
||||
func (p *paramsReader) GetPortForwarding() (activated bool, err error) {
|
||||
@@ -62,7 +28,7 @@ func (p *paramsReader) GetPortForwarding() (activated bool, err error) {
|
||||
// GetPortForwardingStatusFilepath obtains the port forwarding status file path
|
||||
// from the environment variable PORT_FORWARDING_STATUS_FILE
|
||||
func (p *paramsReader) GetPortForwardingStatusFilepath() (filepath models.Filepath, err error) {
|
||||
filepathStr, err := p.envParams.GetPath("PORT_FORWARDING_STATUS_FILE", libparams.Default("/forwarded_port"))
|
||||
filepathStr, err := p.envParams.GetPath("PORT_FORWARDING_STATUS_FILE", libparams.Default("/forwarded_port"), libparams.CaseSensitiveValue())
|
||||
return models.Filepath(filepathStr), err
|
||||
}
|
||||
|
||||
@@ -76,7 +42,7 @@ func (p *paramsReader) GetPIAEncryption() (models.PIAEncryption, error) {
|
||||
// GetPIARegion obtains the region for the PIA server from the
|
||||
// environment variable REGION
|
||||
func (p *paramsReader) GetPIARegion() (region models.PIARegion, err error) {
|
||||
choices := constants.PIAGeoChoices()
|
||||
choices := append(constants.PIAGeoChoices(), "")
|
||||
s, err := p.envParams.GetValueIfInside("REGION", choices)
|
||||
if len(s) == 0 { // Suggestion by @rorph https://github.com/rorph
|
||||
s = choices[rand.Int()%len(choices)]
|
||||
|
||||
@@ -36,5 +36,5 @@ func (p *paramsReader) GetShadowSocksPort() (port uint16, err error) {
|
||||
// SHADOWSOCKS_PASSWORD
|
||||
func (p *paramsReader) GetShadowSocksPassword() (password string, err error) {
|
||||
defer p.unsetEnv("SHADOWSOCKS_PASSWORD")
|
||||
return p.envParams.GetEnv("SHADOWSOCKS_PASSWORD")
|
||||
return p.envParams.GetEnv("SHADOWSOCKS_PASSWORD", libparams.CaseSensitiveValue())
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ func (p *paramsReader) GetTinyProxyUser() (user string, err error) {
|
||||
defer p.unsetEnv("PROXY_USER")
|
||||
defer p.unsetEnv("TINYPROXY_USER")
|
||||
// Retro-compatibility
|
||||
user, err = p.envParams.GetEnv("PROXY_USER")
|
||||
user, err = p.envParams.GetEnv("PROXY_USER", libparams.CaseSensitiveValue())
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
@@ -73,7 +73,7 @@ func (p *paramsReader) GetTinyProxyUser() (user string, err error) {
|
||||
p.logger.Warn("You are using the old environment variable PROXY_USER, please consider changing it to TINYPROXY_USER")
|
||||
return user, nil
|
||||
}
|
||||
return p.envParams.GetEnv("TINYPROXY_USER")
|
||||
return p.envParams.GetEnv("TINYPROXY_USER", libparams.CaseSensitiveValue())
|
||||
}
|
||||
|
||||
// GetTinyProxyPassword obtains the TinyProxy server password from the environment variable
|
||||
@@ -82,7 +82,7 @@ func (p *paramsReader) GetTinyProxyPassword() (password string, err error) {
|
||||
defer p.unsetEnv("PROXY_PASSWORD")
|
||||
defer p.unsetEnv("TINYPROXY_PASSWORD")
|
||||
// Retro-compatibility
|
||||
password, err = p.envParams.GetEnv("PROXY_PASSWORD")
|
||||
password, err = p.envParams.GetEnv("PROXY_PASSWORD", libparams.CaseSensitiveValue())
|
||||
if err != nil {
|
||||
return password, err
|
||||
}
|
||||
@@ -90,5 +90,5 @@ func (p *paramsReader) GetTinyProxyPassword() (password string, err error) {
|
||||
p.logger.Warn("You are using the old environment variable PROXY_PASSWORD, please consider changing it to TINYPROXY_PASSWORD")
|
||||
return password, nil
|
||||
}
|
||||
return p.envParams.GetEnv("TINYPROXY_PASSWORD")
|
||||
return p.envParams.GetEnv("TINYPROXY_PASSWORD", libparams.CaseSensitiveValue())
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
package params
|
||||
|
||||
import (
|
||||
"github.com/qdm12/golibs/params"
|
||||
libparams "github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
func (p *paramsReader) GetVersion() string {
|
||||
version, _ := p.envParams.GetEnv("VERSION", params.Default("?"))
|
||||
version, _ := p.envParams.GetEnv("VERSION", libparams.Default("?"), libparams.CaseSensitiveValue())
|
||||
return version
|
||||
}
|
||||
|
||||
func (p *paramsReader) GetBuildDate() string {
|
||||
buildDate, _ := p.envParams.GetEnv("BUILD_DATE", params.Default("?"))
|
||||
buildDate, _ := p.envParams.GetEnv("BUILD_DATE", libparams.Default("?"), libparams.CaseSensitiveValue())
|
||||
return buildDate
|
||||
}
|
||||
|
||||
func (p *paramsReader) GetVcsRef() string {
|
||||
buildDate, _ := p.envParams.GetEnv("VCS_REF", params.Default("?"))
|
||||
buildDate, _ := p.envParams.GetEnv("VCS_REF", libparams.Default("?"), libparams.CaseSensitiveValue())
|
||||
return buildDate
|
||||
}
|
||||
|
||||
@@ -2,45 +2,70 @@ package pia
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/golibs/files"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
func (c *configurator) BuildConf(region models.PIARegion, protocol models.NetworkProtocol,
|
||||
encryption models.PIAEncryption, uid, gid int) (IPs []net.IP, port uint16, err error) {
|
||||
var X509CRL, certificate string // depends on encryption
|
||||
var cipherAlgo, authAlgo string // depends on encryption
|
||||
func (c *configurator) GetOpenVPNConnections(region models.PIARegion, protocol models.NetworkProtocol, encryption models.PIAEncryption) (connections []models.OpenVPNConnection, err error) {
|
||||
geoMapping := constants.PIAGeoToSubdomainMapping()
|
||||
var subdomain string
|
||||
for r, s := range geoMapping {
|
||||
if strings.ToLower(string(region)) == strings.ToLower(string(r)) {
|
||||
subdomain = s
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(subdomain) == 0 {
|
||||
return nil, fmt.Errorf("region %q has no associated PIA subdomain", region)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
IPs, err := c.lookupIP(subdomain + ".privateinternetaccess.com")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var port uint16
|
||||
switch protocol {
|
||||
case constants.TCP:
|
||||
switch encryption {
|
||||
case constants.PIAEncryptionNormal:
|
||||
port = 502
|
||||
case constants.PIAEncryptionStrong:
|
||||
port = 501
|
||||
}
|
||||
case constants.UDP:
|
||||
switch encryption {
|
||||
case constants.PIAEncryptionNormal:
|
||||
port = 1198
|
||||
case constants.PIAEncryptionStrong:
|
||||
port = 1197
|
||||
}
|
||||
}
|
||||
if port == 0 {
|
||||
return nil, fmt.Errorf("combination of protocol %q and encryption %q does not yield any port number", protocol, encryption)
|
||||
}
|
||||
for _, IP := range IPs {
|
||||
connections = append(connections, models.OpenVPNConnection{IP: IP, Port: port, Protocol: protocol})
|
||||
}
|
||||
return connections, nil
|
||||
}
|
||||
|
||||
func (c *configurator) BuildConf(connections []models.OpenVPNConnection, encryption models.PIAEncryption, verbosity, uid, gid int) (err error) {
|
||||
var X509CRL, certificate, cipherAlgo, authAlgo string
|
||||
if encryption == constants.PIAEncryptionNormal {
|
||||
cipherAlgo = "aes-128-cbc"
|
||||
authAlgo = "sha1"
|
||||
X509CRL = constants.PIAX509CRL_NORMAL
|
||||
certificate = constants.PIACertificate_NORMAL
|
||||
if protocol == constants.UDP {
|
||||
port = 1198
|
||||
} else {
|
||||
port = 502
|
||||
}
|
||||
} else { // strong
|
||||
} else { // strong encryption
|
||||
cipherAlgo = "aes-256-cbc"
|
||||
authAlgo = "sha256"
|
||||
X509CRL = constants.PIAX509CRL_STRONG
|
||||
certificate = constants.PIACertificate_STRONG
|
||||
if protocol == constants.UDP {
|
||||
port = 1197
|
||||
} else {
|
||||
port = 501
|
||||
}
|
||||
}
|
||||
subdomain, err := constants.PIAGeoToSubdomainMapping(region)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
IPs, err = c.lookupIP(subdomain + ".privateinternetaccess.com")
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
lines := []string{
|
||||
"client",
|
||||
@@ -50,25 +75,30 @@ func (c *configurator) BuildConf(region models.PIARegion, protocol models.Networ
|
||||
"persist-tun",
|
||||
"tls-client",
|
||||
"remote-cert-tls server",
|
||||
"compress",
|
||||
"verb 1", // TODO env variable
|
||||
"ping 300", // Ping every 5 minutes to prevent a timeout error
|
||||
|
||||
// PIA specific
|
||||
"reneg-sec 0",
|
||||
"compress", // allow PIA server to choose the compression to use
|
||||
|
||||
// Added constant values
|
||||
"tun-ipv6",
|
||||
"auth-nocache",
|
||||
"mute-replay-warnings",
|
||||
"user nonrootuser",
|
||||
"pull-filter ignore \"auth-token\"", // prevent auth failed loops
|
||||
"auth-retry nointeract",
|
||||
"disable-occ",
|
||||
"remote-random",
|
||||
|
||||
// Modified variables
|
||||
fmt.Sprintf("verb %d", verbosity),
|
||||
fmt.Sprintf("auth-user-pass %s", constants.OpenVPNAuthConf),
|
||||
fmt.Sprintf("proto %s", string(protocol)),
|
||||
fmt.Sprintf("proto %s", string(connections[0].Protocol)),
|
||||
fmt.Sprintf("cipher %s", cipherAlgo),
|
||||
fmt.Sprintf("auth %s", authAlgo),
|
||||
}
|
||||
for _, IP := range IPs {
|
||||
lines = append(lines, fmt.Sprintf("remote %s %d", IP.String(), port))
|
||||
for _, connection := range connections {
|
||||
lines = append(lines, fmt.Sprintf("remote %s %d", connection.IP.String(), connection.Port))
|
||||
}
|
||||
lines = append(lines, []string{
|
||||
"<crl-verify>",
|
||||
@@ -85,6 +115,5 @@ func (c *configurator) BuildConf(region models.PIARegion, protocol models.Networ
|
||||
"</ca>",
|
||||
"",
|
||||
}...)
|
||||
err = c.fileManager.WriteLinesToFile(string(constants.OpenVPNConf), lines, files.Ownership(uid, gid), files.Permissions(0400))
|
||||
return IPs, port, err
|
||||
return c.fileManager.WriteLinesToFile(string(constants.OpenVPNConf), lines, files.Ownership(uid, gid), files.Permissions(0400))
|
||||
}
|
||||
|
||||
@@ -16,8 +16,9 @@ const logPrefix = "PIA configurator"
|
||||
|
||||
// Configurator contains methods to download, read and modify the openvpn configuration to connect as a client
|
||||
type Configurator interface {
|
||||
BuildConf(region models.PIARegion, protocol models.NetworkProtocol,
|
||||
encryption models.PIAEncryption, uid, gid int) (IPs []net.IP, port uint16, err error)
|
||||
GetOpenVPNConnections(region models.PIARegion, protocol models.NetworkProtocol,
|
||||
encryption models.PIAEncryption) (connections []models.OpenVPNConnection, err error)
|
||||
BuildConf(connections []models.OpenVPNConnection, encryption models.PIAEncryption, verbosity, uid, gid int) (err error)
|
||||
GetPortForward() (port uint16, err error)
|
||||
WritePortForward(filepath models.Filepath, port uint16) (err error)
|
||||
AllowPortForwardFirewall(device models.VPNDevice, port uint16) (err error)
|
||||
|
||||
57
internal/settings/mullvad.go
Normal file
57
internal/settings/mullvad.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/params"
|
||||
)
|
||||
|
||||
// Mullvad contains the settings to connect to a Mullvad server
|
||||
type Mullvad struct {
|
||||
User string
|
||||
Country models.MullvadCountry
|
||||
City models.MullvadCity
|
||||
ISP models.MullvadProvider
|
||||
Port uint16
|
||||
}
|
||||
|
||||
func (m *Mullvad) String() string {
|
||||
|
||||
settingsList := []string{
|
||||
"Mullvad settings:",
|
||||
"User: [redacted]",
|
||||
"Country: " + string(m.Country),
|
||||
"City: " + string(m.City),
|
||||
"ISP: " + string(m.ISP),
|
||||
"Port: " + string(m.Port),
|
||||
}
|
||||
return strings.Join(settingsList, "\n |--")
|
||||
}
|
||||
|
||||
// GetMullvadSettings obtains Mullvad settings from environment variables using the params package.
|
||||
func GetMullvadSettings(params params.ParamsReader) (settings Mullvad, err error) {
|
||||
settings.User, err = params.GetUser()
|
||||
if err != nil {
|
||||
return settings, err
|
||||
}
|
||||
// Remove spaces in user ID to simplify user's life, thanks @JeordyR
|
||||
settings.User = strings.ReplaceAll(settings.User, " ", "")
|
||||
settings.Country, err = params.GetMullvadCountry()
|
||||
if err != nil {
|
||||
return settings, err
|
||||
}
|
||||
settings.City, err = params.GetMullvadCity()
|
||||
if err != nil {
|
||||
return settings, err
|
||||
}
|
||||
settings.ISP, err = params.GetMullvadISP()
|
||||
if err != nil {
|
||||
return settings, err
|
||||
}
|
||||
settings.Port, err = params.GetMullvadPort()
|
||||
if err != nil {
|
||||
return settings, err
|
||||
}
|
||||
return settings, nil
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
// OpenVPN contains settings to configure the OpenVPN client
|
||||
type OpenVPN struct {
|
||||
NetworkProtocol models.NetworkProtocol
|
||||
Verbosity int
|
||||
}
|
||||
|
||||
// GetOpenVPNSettings obtains the OpenVPN settings using the params functions
|
||||
@@ -18,6 +20,10 @@ func GetOpenVPNSettings(params params.ParamsReader) (settings OpenVPN, err error
|
||||
if err != nil {
|
||||
return settings, err
|
||||
}
|
||||
settings.Verbosity, err = params.GetOpenVPNVerbosity()
|
||||
if err != nil {
|
||||
return settings, err
|
||||
}
|
||||
return settings, nil
|
||||
}
|
||||
|
||||
@@ -25,6 +31,7 @@ func (o *OpenVPN) String() string {
|
||||
settingsList := []string{
|
||||
"OpenVPN settings:",
|
||||
"Network protocol: " + string(o.NetworkProtocol),
|
||||
"Verbosity level: " + fmt.Sprintf("%d", o.Verbosity),
|
||||
}
|
||||
return strings.Join(settingsList, "\n|--")
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/private-internet-access-docker/internal/params"
|
||||
@@ -8,8 +9,10 @@ import (
|
||||
|
||||
// Settings contains all settings for the program to run
|
||||
type Settings struct {
|
||||
VPNSP string
|
||||
OpenVPN OpenVPN
|
||||
PIA PIA
|
||||
Mullvad Mullvad
|
||||
DNS DNS
|
||||
Firewall Firewall
|
||||
TinyProxy TinyProxy
|
||||
@@ -17,10 +20,17 @@ type Settings struct {
|
||||
}
|
||||
|
||||
func (s *Settings) String() string {
|
||||
var vpnServiceProvider string
|
||||
switch s.VPNSP {
|
||||
case "pia":
|
||||
vpnServiceProvider = s.PIA.String()
|
||||
case "mullvad":
|
||||
vpnServiceProvider = s.Mullvad.String()
|
||||
}
|
||||
return strings.Join([]string{
|
||||
"Settings summary below:",
|
||||
s.OpenVPN.String(),
|
||||
s.PIA.String(),
|
||||
vpnServiceProvider,
|
||||
s.DNS.String(),
|
||||
s.Firewall.String(),
|
||||
s.TinyProxy.String(),
|
||||
@@ -32,13 +42,27 @@ func (s *Settings) String() string {
|
||||
// GetAllSettings obtains all settings for the program and returns an error as soon
|
||||
// as an error is encountered reading them.
|
||||
func GetAllSettings(params params.ParamsReader) (settings Settings, err error) {
|
||||
settings.VPNSP, err = params.GetVPNSP()
|
||||
if err != nil {
|
||||
return settings, err
|
||||
}
|
||||
settings.OpenVPN, err = GetOpenVPNSettings(params)
|
||||
if err != nil {
|
||||
return settings, err
|
||||
}
|
||||
settings.PIA, err = GetPIASettings(params)
|
||||
if err != nil {
|
||||
return settings, err
|
||||
switch settings.VPNSP {
|
||||
case "pia":
|
||||
settings.PIA, err = GetPIASettings(params)
|
||||
if err != nil {
|
||||
return settings, err
|
||||
}
|
||||
case "mullvad":
|
||||
settings.Mullvad, err = GetMullvadSettings(params)
|
||||
if err != nil {
|
||||
return settings, err
|
||||
}
|
||||
default:
|
||||
return settings, fmt.Errorf("VPN service provider %q is not valid", settings.VPNSP)
|
||||
}
|
||||
settings.DNS, err = GetDNSSettings(params)
|
||||
if err != nil {
|
||||
|
||||
@@ -39,11 +39,14 @@ func title() []string {
|
||||
}
|
||||
|
||||
func annoucement() []string {
|
||||
timestamp := time.Now().UnixNano() / 1000000000
|
||||
if timestamp < constants.AnnoucementExpiration {
|
||||
return []string{emoji.Sprint(":mega: ") + constants.Annoucement}
|
||||
if len(constants.Annoucement) == 0 {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
expirationDate, _ := time.Parse("2006-01-02", constants.AnnoucementExpiration) // error covered by a unit test
|
||||
if time.Now().After(expirationDate) {
|
||||
return nil
|
||||
}
|
||||
return []string{emoji.Sprint(":mega: ") + constants.Annoucement}
|
||||
}
|
||||
|
||||
func links() []string {
|
||||
|
||||
Reference in New Issue
Block a user