Compare commits
235 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1281026850 | ||
|
|
616ba0c538 | ||
|
|
8c7c8f7d5a | ||
|
|
78877483e9 | ||
|
|
de7f12d958 | ||
|
|
7e7312459d | ||
|
|
e3a677c22b | ||
|
|
2f955e0190 | ||
|
|
618441b008 | ||
|
|
4a7d341c57 | ||
|
|
95ad58687d | ||
|
|
0fc69e068e | ||
|
|
7252ac722c | ||
|
|
4cd6b33044 | ||
|
|
0731b1cb82 | ||
|
|
07efea612b | ||
|
|
6afa4f69a0 | ||
|
|
2acf627918 | ||
|
|
4eb7c4ac36 | ||
|
|
b4c838e6ab | ||
|
|
8b096af04e | ||
|
|
78b63174ce | ||
|
|
11fca08028 | ||
|
|
515e72a0ed | ||
|
|
2f9d1f09d3 | ||
|
|
b1596bc7e4 | ||
|
|
ccf11990f1 | ||
|
|
1ac06ee4a8 | ||
|
|
dc1c7eab81 | ||
|
|
5bf471767d | ||
|
|
3d25db1bed | ||
|
|
99e386abc8 | ||
|
|
8669748289 | ||
|
|
a39d885e34 | ||
|
|
7d36993450 | ||
|
|
0d53461706 | ||
|
|
758f316816 | ||
|
|
ad73a027f3 | ||
|
|
2c96f91043 | ||
|
|
53b7fafc49 | ||
|
|
7450ffce2b | ||
|
|
765f06e5a8 | ||
|
|
e304b4a829 | ||
|
|
3ae4523280 | ||
|
|
7a136db085 | ||
|
|
e809e178b9 | ||
|
|
dd529a48fa | ||
|
|
2c6eae4e90 | ||
|
|
18e99d07d0 | ||
|
|
a4b0e0ff86 | ||
|
|
7e36fbbd00 | ||
|
|
d228216d1c | ||
|
|
c9368e352c | ||
|
|
d947d9fe30 | ||
|
|
613ded51ab | ||
|
|
3b43b7c2f6 | ||
|
|
cdbb7bf771 | ||
|
|
5a6cf0fe3a | ||
|
|
082a5bdf51 | ||
|
|
7369808b84 | ||
|
|
4f502abcf8 | ||
|
|
bdcadf09ec | ||
|
|
8cae369186 | ||
|
|
a3d75f3d8b | ||
|
|
1a06d01ae2 | ||
|
|
634cef2bb2 | ||
|
|
6107f5c4ab | ||
|
|
6ae9dc5c2c | ||
|
|
ea3a173e3b | ||
|
|
69217f61a1 | ||
|
|
e33a6a8503 | ||
|
|
0fb065eb61 | ||
|
|
f6a2aac475 | ||
|
|
900fa261d8 | ||
|
|
cfb4dd84bc | ||
|
|
4f72f60a3e | ||
|
|
f262ee6454 | ||
|
|
20a3327815 | ||
|
|
3ab1298b1f | ||
|
|
a7739b6f5d | ||
|
|
263368af89 | ||
|
|
96e57d2c32 | ||
|
|
85a93bdd34 | ||
|
|
cc80d224c2 | ||
|
|
c85cca7fdc | ||
|
|
3f6d3d7c2a | ||
|
|
09a0ba1228 | ||
|
|
6b81ed6bde | ||
|
|
64e447b262 | ||
|
|
d0926111e0 | ||
|
|
aac4298f69 | ||
|
|
f4018d3411 | ||
|
|
0710199409 | ||
|
|
43c15b3e68 | ||
|
|
ab223a5e06 | ||
|
|
fd5e7af3ff | ||
|
|
886d4ad1a9 | ||
|
|
40a72b6189 | ||
|
|
5eb1859f41 | ||
|
|
b45fa026dd | ||
|
|
da739a0c3d | ||
|
|
0dc400b540 | ||
|
|
d12668d57f | ||
|
|
c39affeb12 | ||
|
|
d73765a5f5 | ||
|
|
37282c014b | ||
|
|
adeccf8548 | ||
|
|
a97cbcc4e4 | ||
|
|
89187b6b86 | ||
|
|
754bab9763 | ||
|
|
0d7f6dab1a | ||
|
|
507374ca4e | ||
|
|
318c3c9032 | ||
|
|
c068484fa0 | ||
|
|
7cd35737ba | ||
|
|
0247a1ff01 | ||
|
|
363fabc810 | ||
|
|
6049b10209 | ||
|
|
bc05ff34fd | ||
|
|
8e77842f1e | ||
|
|
41168f88cd | ||
|
|
88ad10d429 | ||
|
|
f4cd1896c9 | ||
|
|
944e6a107b | ||
|
|
b6135d2476 | ||
|
|
c9b6e79792 | ||
|
|
94255aaa38 | ||
|
|
ac706bd156 | ||
|
|
d864a9f580 | ||
|
|
a32318d246 | ||
|
|
45a7a5b9e2 | ||
|
|
9af2a7a640 | ||
|
|
eb62ad06db | ||
|
|
a033637e85 | ||
|
|
b0ea739c20 | ||
|
|
352af84977 | ||
|
|
eb149ee040 | ||
|
|
9b3166a2e2 | ||
|
|
e94f4283e1 | ||
|
|
ef0959a15e | ||
|
|
36424c08ac | ||
|
|
97ea5f63b8 | ||
|
|
88c9d3d687 | ||
|
|
f1569dac05 | ||
|
|
4cb32ef9dc | ||
|
|
e805d42197 | ||
|
|
cbd11bfdf2 | ||
|
|
422bd8d428 | ||
|
|
58459f0336 | ||
|
|
6f6e227b94 | ||
|
|
e015cd4a27 | ||
|
|
768147095f | ||
|
|
8f6b6306d6 | ||
|
|
fb4c9b8a58 | ||
|
|
3d7cfb125a | ||
|
|
d42de99879 | ||
|
|
68203c221d | ||
|
|
3ac3e5022c | ||
|
|
da8391e9ae | ||
|
|
ebdf241888 | ||
|
|
60cec716b2 | ||
|
|
e7a475a303 | ||
|
|
67588e0072 | ||
|
|
bfa3d749ac | ||
|
|
7e79d9696f | ||
|
|
f251c6aa4d | ||
|
|
d2117cd043 | ||
|
|
0235df74a0 | ||
|
|
e5adccd9c5 | ||
|
|
76cea56864 | ||
|
|
643745d33e | ||
|
|
3d6a580102 | ||
|
|
d4a1828c1d | ||
|
|
bdf96d864e | ||
|
|
15a549be11 | ||
|
|
d534f92432 | ||
|
|
d0c61662b5 | ||
|
|
98b076e2cb | ||
|
|
0b997fe6c8 | ||
|
|
b0c0bd6364 | ||
|
|
c61a418430 | ||
|
|
e6bbaa2ba6 | ||
|
|
17ccf98c75 | ||
|
|
4db67c70b8 | ||
|
|
3250a20ffc | ||
|
|
6c12fdff2b | ||
|
|
f033204844 | ||
|
|
e334cf6c5f | ||
|
|
9435db8e1e | ||
|
|
d2b361b998 | ||
|
|
9d786bf338 | ||
|
|
3339455a97 | ||
|
|
0eb2e5a120 | ||
|
|
d0f678c315 | ||
|
|
0c48d2d5a0 | ||
|
|
47a197be48 | ||
|
|
28edae383b | ||
|
|
939b58c457 | ||
|
|
fa0272d5ad | ||
|
|
839c6f05dd | ||
|
|
9ada201b82 | ||
|
|
dd0170afb1 | ||
|
|
9239e840c4 | ||
|
|
96713b26cb | ||
|
|
3ad60349db | ||
|
|
5ee4e2fde0 | ||
|
|
ce4fd8bc68 | ||
|
|
90fc12a941 | ||
|
|
16995e1d93 | ||
|
|
9669938703 | ||
|
|
ac60cf8ab8 | ||
|
|
f5a32e690f | ||
|
|
4e622a92a5 | ||
|
|
d1412f43fd | ||
|
|
1b3a135920 | ||
|
|
53db4813fa | ||
|
|
2f09ed9069 | ||
|
|
9202d6c15f | ||
|
|
023f1c7e8e | ||
|
|
1aebe1a4c1 | ||
|
|
f45f40eee1 | ||
|
|
ab5d60754f | ||
|
|
83e8bb780a | ||
|
|
888d8bbf87 | ||
|
|
fbf04677f1 | ||
|
|
2051aa1b04 | ||
|
|
fc88ee135d | ||
|
|
a6f9a1a3d1 | ||
|
|
f181ff0005 | ||
|
|
71dcf23013 | ||
|
|
95ee3b4276 | ||
|
|
c42d13f14f | ||
|
|
ce11745f6f | ||
|
|
f6b91bd74f | ||
|
|
5c69ddc05f |
@@ -1,13 +1,17 @@
|
||||
{
|
||||
"name": "pia-dev",
|
||||
"dockerComposeFile": ["docker-compose.yml"],
|
||||
"dockerComposeFile": [
|
||||
"docker-compose.yml"
|
||||
],
|
||||
"service": "vscode",
|
||||
"runServices": ["vscode"],
|
||||
"runServices": [
|
||||
"vscode"
|
||||
],
|
||||
"shutdownAction": "stopCompose",
|
||||
// "postCreateCommand": "go mod download",
|
||||
"postCreateCommand": "go mod download",
|
||||
"workspaceFolder": "/workspace",
|
||||
"extensions": [
|
||||
"ms-vscode.go",
|
||||
"golang.go",
|
||||
"IBM.output-colorizer",
|
||||
"eamodio.gitlens",
|
||||
"mhutchie.git-graph",
|
||||
@@ -38,10 +42,54 @@
|
||||
"deepCompletion": true,
|
||||
"usePlaceholders": false
|
||||
},
|
||||
"go.lintTool": "golangci-lint",
|
||||
"go.lintFlags": [
|
||||
"--fast",
|
||||
"--enable",
|
||||
"staticcheck",
|
||||
"--enable",
|
||||
"bodyclose",
|
||||
"--enable",
|
||||
"dogsled",
|
||||
"--enable",
|
||||
"gochecknoglobals",
|
||||
"--enable",
|
||||
"gochecknoinits",
|
||||
"--enable",
|
||||
"gocognit",
|
||||
"--enable",
|
||||
"goconst",
|
||||
"--enable",
|
||||
"gocritic",
|
||||
"--enable",
|
||||
"gocyclo",
|
||||
"--enable",
|
||||
"golint",
|
||||
"--enable",
|
||||
"gosec",
|
||||
"--enable",
|
||||
"interfacer",
|
||||
"--enable",
|
||||
"maligned",
|
||||
"--enable",
|
||||
"misspell",
|
||||
"--enable",
|
||||
"nakedret",
|
||||
"--enable",
|
||||
"prealloc",
|
||||
"--enable",
|
||||
"scopelint",
|
||||
"--enable",
|
||||
"unconvert",
|
||||
"--enable",
|
||||
"unparam",
|
||||
"--enable",
|
||||
"whitespace"
|
||||
],
|
||||
// Golang on save
|
||||
"go.buildOnSave": "package",
|
||||
"go.lintOnSave": "package",
|
||||
"go.vetOnSave": "package",
|
||||
"go.buildOnSave": "workspace",
|
||||
"go.lintOnSave": "workspace",
|
||||
"go.vetOnSave": "workspace",
|
||||
"editor.formatOnSave": true,
|
||||
"[go]": {
|
||||
"editor.codeActionsOnSave": {
|
||||
@@ -56,7 +104,12 @@
|
||||
"GOFLAGS": "-tags=integration"
|
||||
},
|
||||
"go.testEnvVars": {},
|
||||
"go.testFlags": ["-v"],
|
||||
"go.testTimeout": "600s"
|
||||
"go.testFlags": [
|
||||
"-v",
|
||||
// "-race"
|
||||
],
|
||||
"go.testTimeout": "600s",
|
||||
"go.coverOnSingleTestFile": true,
|
||||
"go.coverOnSingleTest": true
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
.devcontainer
|
||||
.git
|
||||
.github
|
||||
.vscode
|
||||
readme
|
||||
.gitignore
|
||||
.travis.yml
|
||||
ci.sh
|
||||
cmd
|
||||
!cmd/gluetun
|
||||
doc
|
||||
docker-compose.yml
|
||||
LICENSE
|
||||
README.md
|
||||
Dockerfile
|
||||
title.svg
|
||||
|
||||
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1 @@
|
||||
@qdm12
|
||||
29
.github/CONTRIBUTING.md
vendored
Normal file
29
.github/CONTRIBUTING.md
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# Contributing
|
||||
|
||||
Contributions are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [open source license of this project](../LICENSE).
|
||||
|
||||
## Submitting a pull request
|
||||
|
||||
1. [Fork](https://github.com/qdm12/private-internet-access-docker/fork) and clone the repository
|
||||
1. Create a new branch `git checkout -b my-branch-name`
|
||||
1. Modify the code
|
||||
1. Ensure the docker build succeeds `docker build .`
|
||||
1. Commit your modifications
|
||||
1. Push to your fork and [submit a pull request](https://github.com/qdm12/private-internet-access-docker/compare)
|
||||
|
||||
## Resources
|
||||
|
||||
- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/)
|
||||
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
|
||||
|
||||
## Contributors
|
||||
|
||||
Thanks for all the contributions, whether 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)
|
||||
55
.github/ISSUE_TEMPLATE/bug.md
vendored
Normal file
55
.github/ISSUE_TEMPLATE/bug.md
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
---
|
||||
name: Bug
|
||||
about: Report a bug
|
||||
title: 'Bug: ...'
|
||||
labels: ":bug: bug"
|
||||
assignees: qdm12
|
||||
|
||||
---
|
||||
|
||||
**TLDR**: *Describe your issue in a one liner here*
|
||||
|
||||
1. Is this urgent?
|
||||
|
||||
- [ ] Yes
|
||||
- [x] No
|
||||
|
||||
2. What VPN service provider are you using?
|
||||
|
||||
- [x] PIA
|
||||
- [ ] Mullvad
|
||||
- [ ] Windscribe
|
||||
- [ ] Surfshark
|
||||
- [ ] Cyberghost
|
||||
|
||||
3. What's the version of the program?
|
||||
|
||||
**See the line at the top of your logs**
|
||||
|
||||
`Running version latest built on 2020-03-13T01:30:06Z (commit d0f678c)`
|
||||
|
||||
4. What are you using to run the container?
|
||||
|
||||
- [ ] Docker run
|
||||
- [x] Docker Compose
|
||||
- [ ] Kubernetes
|
||||
- [ ] Docker stack
|
||||
- [ ] Docker swarm
|
||||
- [ ] Podman
|
||||
- [ ] Other:
|
||||
|
||||
5. Extra information
|
||||
|
||||
Logs:
|
||||
|
||||
```log
|
||||
|
||||
```
|
||||
|
||||
Configuration file:
|
||||
|
||||
```yml
|
||||
|
||||
```
|
||||
|
||||
Host OS:
|
||||
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest a feature to add to this project
|
||||
title: 'Feature request: ...'
|
||||
labels: ":bulb: feature request"
|
||||
assignees: qdm12
|
||||
|
||||
---
|
||||
|
||||
1. What's the feature?
|
||||
|
||||
2. Why do you need this feature?
|
||||
|
||||
3. Extra information?
|
||||
55
.github/ISSUE_TEMPLATE/help.md
vendored
Normal file
55
.github/ISSUE_TEMPLATE/help.md
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
---
|
||||
name: Help
|
||||
about: Ask for help
|
||||
title: 'Help: ...'
|
||||
labels: ":pray: help wanted"
|
||||
assignees:
|
||||
|
||||
---
|
||||
|
||||
**TLDR**: *Describe your issue in a one liner here*
|
||||
|
||||
1. Is this urgent?
|
||||
|
||||
- [ ] Yes
|
||||
- [x] No
|
||||
|
||||
2. What VPN service provider are you using?
|
||||
|
||||
- [x] PIA
|
||||
- [ ] Mullvad
|
||||
- [ ] Windscribe
|
||||
- [ ] Surfshark
|
||||
- [ ] Cyberghost
|
||||
|
||||
3. What's the version of the program?
|
||||
|
||||
**See the line at the top of your logs**
|
||||
|
||||
`Running version latest built on 2020-03-13T01:30:06Z (commit d0f678c)`
|
||||
|
||||
4. What are you using to run the container?
|
||||
|
||||
- [ ] Docker run
|
||||
- [x] Docker Compose
|
||||
- [ ] Kubernetes
|
||||
- [ ] Docker stack
|
||||
- [ ] Docker swarm
|
||||
- [ ] Podman
|
||||
- [ ] Other:
|
||||
|
||||
5. Extra information
|
||||
|
||||
Logs:
|
||||
|
||||
```log
|
||||
|
||||
```
|
||||
|
||||
Configuration file:
|
||||
|
||||
```yml
|
||||
|
||||
```
|
||||
|
||||
Host OS:
|
||||
51
.github/labels.yml
vendored
Normal file
51
.github/labels.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
- name: ":robot: bot"
|
||||
color: "69cde9"
|
||||
description: ""
|
||||
- name: ":bug: bug"
|
||||
color: "b60205"
|
||||
description: ""
|
||||
- name: ":game_die: dependencies"
|
||||
color: "0366d6"
|
||||
description: ""
|
||||
- name: ":memo: documentation"
|
||||
color: "c5def5"
|
||||
description: ""
|
||||
- name: ":busts_in_silhouette: duplicate"
|
||||
color: "cccccc"
|
||||
description: ""
|
||||
- name: ":sparkles: enhancement"
|
||||
color: "0054ca"
|
||||
description: ""
|
||||
- name: ":bulb: feature request"
|
||||
color: "0e8a16"
|
||||
description: ""
|
||||
- name: ":mega: feedback"
|
||||
color: "03a9f4"
|
||||
description: ""
|
||||
- name: ":rocket: future maybe"
|
||||
color: "fef2c0"
|
||||
description: ""
|
||||
- name: ":hatching_chick: good first issue"
|
||||
color: "7057ff"
|
||||
description: ""
|
||||
- name: ":pray: help wanted"
|
||||
color: "4caf50"
|
||||
description: ""
|
||||
- name: ":hand: hold"
|
||||
color: "24292f"
|
||||
description: ""
|
||||
- name: ":no_entry_sign: invalid"
|
||||
color: "e6e6e6"
|
||||
description: ""
|
||||
- name: ":interrobang: maybe bug"
|
||||
color: "ff5722"
|
||||
description: ""
|
||||
- name: ":thinking: needs more info"
|
||||
color: "795548"
|
||||
description: ""
|
||||
- name: ":question: question"
|
||||
color: "3f51b5"
|
||||
description: ""
|
||||
- name: ":coffin: wontfix"
|
||||
color: "ffffff"
|
||||
description: ""
|
||||
34
.github/workflows/build.yml
vendored
Normal file
34
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: Docker build
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master]
|
||||
paths-ignore:
|
||||
- .devcontainer
|
||||
- .github/ISSUE_TEMPLATE
|
||||
- .github/workflows/buildx-release.yml
|
||||
- .github/workflows/buildx-branch.yml
|
||||
- .github/workflows/buildx-latest.yml
|
||||
- .github/workflows/dockerhub-description.yml
|
||||
- .github/workflows/labels.yml
|
||||
- .github/workflows/misspell.yml
|
||||
- .github/CODEOWNERS
|
||||
- .github/CONTRIBUTING.md
|
||||
- .github/FUNDING.yml
|
||||
- .github/labels.yml
|
||||
- .vscode
|
||||
- cmd/ovpnparser
|
||||
- cmd/resolver
|
||||
- doc
|
||||
- .gitignore
|
||||
- docker-compose.yml
|
||||
- LICENSE
|
||||
- README.md
|
||||
- title.svg
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Build image
|
||||
run: docker build .
|
||||
50
.github/workflows/buildx-branch.yml
vendored
Normal file
50
.github/workflows/buildx-branch.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: Buildx branch
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
- '*/*'
|
||||
- '!master'
|
||||
paths-ignore:
|
||||
- .devcontainer
|
||||
- .github/ISSUE_TEMPLATE
|
||||
- .github/workflows/build.yml
|
||||
- .github/workflows/buildx-release.yml
|
||||
- .github/workflows/buildx-latest.yml
|
||||
- .github/workflows/dockerhub-description.yml
|
||||
- .github/workflows/labels.yml
|
||||
- .github/workflows/misspell.yml
|
||||
- .github/CODEOWNERS
|
||||
- .github/CONTRIBUTING.md
|
||||
- .github/FUNDING.yml
|
||||
- .github/labels.yml
|
||||
- .vscode
|
||||
- cmd/ovpnparser
|
||||
- cmd/resolver
|
||||
- doc
|
||||
- .gitignore
|
||||
- docker-compose.yml
|
||||
- LICENSE
|
||||
- README.md
|
||||
- title.svg
|
||||
jobs:
|
||||
buildx:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Buildx setup
|
||||
uses: crazy-max/ghaction-docker-buildx@v1
|
||||
- name: Dockerhub login
|
||||
run: echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login -u qmcgaw --password-stdin 2>&1
|
||||
- name: Run Buildx
|
||||
run: |
|
||||
docker buildx build \
|
||||
--progress plain \
|
||||
--platform=linux/amd64 \
|
||||
--build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \
|
||||
--build-arg VCS_REF=`git rev-parse --short HEAD` \
|
||||
--build-arg VERSION=${GITHUB_REF##*/} \
|
||||
-t qmcgaw/private-internet-access:${GITHUB_REF##*/} \
|
||||
--push \
|
||||
.
|
||||
- run: curl -X POST https://hooks.microbadger.com/images/qmcgaw/private-internet-access/tQFy7AxtSUNANPe6aoVChYdsI_I= || exit 0
|
||||
47
.github/workflows/buildx-latest.yml
vendored
Normal file
47
.github/workflows/buildx-latest.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
name: Buildx latest
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
paths-ignore:
|
||||
- .devcontainer
|
||||
- .github/ISSUE_TEMPLATE
|
||||
- .github/workflows/build.yml
|
||||
- .github/workflows/buildx-branch.yml
|
||||
- .github/workflows/buildx-release.yml
|
||||
- .github/workflows/dockerhub-description.yml
|
||||
- .github/workflows/labels.yml
|
||||
- .github/workflows/misspell.yml
|
||||
- .github/CODEOWNERS
|
||||
- .github/CONTRIBUTING.md
|
||||
- .github/FUNDING.yml
|
||||
- .github/labels.yml
|
||||
- .vscode
|
||||
- cmd/ovpnparser
|
||||
- cmd/resolver
|
||||
- doc
|
||||
- .gitignore
|
||||
- docker-compose.yml
|
||||
- LICENSE
|
||||
- README.md
|
||||
- title.svg
|
||||
jobs:
|
||||
buildx:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Buildx setup
|
||||
uses: crazy-max/ghaction-docker-buildx@v1
|
||||
- name: Dockerhub login
|
||||
run: echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login -u qmcgaw --password-stdin 2>&1
|
||||
- name: Run Buildx
|
||||
run: |
|
||||
docker buildx build \
|
||||
--progress plain \
|
||||
--platform=linux/amd64,linux/386,linux/arm64,linux/arm/v7,linux/arm/v6 \
|
||||
--build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \
|
||||
--build-arg VCS_REF=`git rev-parse --short HEAD` \
|
||||
--build-arg VERSION=latest \
|
||||
-t qmcgaw/private-internet-access:latest \
|
||||
--push \
|
||||
.
|
||||
- run: curl -X POST https://hooks.microbadger.com/images/qmcgaw/private-internet-access/tQFy7AxtSUNANPe6aoVChYdsI_I= || exit 0
|
||||
47
.github/workflows/buildx-release.yml
vendored
Normal file
47
.github/workflows/buildx-release.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
name: Buildx release
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
paths-ignore:
|
||||
- .devcontainer
|
||||
- .github/ISSUE_TEMPLATE
|
||||
- .github/workflows/build.yml
|
||||
- .github/workflows/buildx-branch.yml
|
||||
- .github/workflows/buildx-latest.yml
|
||||
- .github/workflows/dockerhub-description.yml
|
||||
- .github/workflows/labels.yml
|
||||
- .github/workflows/misspell.yml
|
||||
- .github/CODEOWNERS
|
||||
- .github/CONTRIBUTING.md
|
||||
- .github/FUNDING.yml
|
||||
- .github/labels.yml
|
||||
- .vscode
|
||||
- cmd/ovpnparser
|
||||
- cmd/resolver
|
||||
- doc
|
||||
- .gitignore
|
||||
- docker-compose.yml
|
||||
- LICENSE
|
||||
- README.md
|
||||
- title.svg
|
||||
jobs:
|
||||
buildx:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Buildx setup
|
||||
uses: crazy-max/ghaction-docker-buildx@v1
|
||||
- name: Dockerhub login
|
||||
run: echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login -u qmcgaw --password-stdin 2>&1
|
||||
- name: Run Buildx
|
||||
run: |
|
||||
docker buildx build \
|
||||
--progress plain \
|
||||
--platform=linux/amd64,linux/386,linux/arm64,linux/arm/v7,linux/arm/v6 \
|
||||
--build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \
|
||||
--build-arg VCS_REF=`git rev-parse --short HEAD` \
|
||||
--build-arg VERSION=${GITHUB_REF##*/} \
|
||||
-t qmcgaw/private-internet-access:${GITHUB_REF##*/} \
|
||||
--push \
|
||||
.
|
||||
- run: curl -X POST https://hooks.microbadger.com/images/qmcgaw/private-internet-access/tQFy7AxtSUNANPe6aoVChYdsI_I= || exit 0
|
||||
19
.github/workflows/dockerhub-description.yml
vendored
Normal file
19
.github/workflows/dockerhub-description.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: Docker Hub description
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
paths:
|
||||
- README.md
|
||||
- .github/workflows/dockerhub-description.yml
|
||||
jobs:
|
||||
dockerHubDescription:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Docker Hub Description
|
||||
uses: peter-evans/dockerhub-description@v2.1.0
|
||||
env:
|
||||
DOCKERHUB_USERNAME: qmcgaw
|
||||
DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
DOCKERHUB_REPOSITORY: qmcgaw/private-internet-access
|
||||
18
.github/workflows/labels.yml
vendored
Normal file
18
.github/workflows/labels.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: labels
|
||||
on:
|
||||
push:
|
||||
branches: ["master"]
|
||||
paths:
|
||||
- '.github/labels.yml'
|
||||
- '.github/workflows/labels.yml'
|
||||
jobs:
|
||||
labeler:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Labeler
|
||||
if: success()
|
||||
uses: crazy-max/ghaction-github-labeler@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
16
.github/workflows/misspell.yml
vendored
Normal file
16
.github/workflows/misspell.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
name: Misspells
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master]
|
||||
push:
|
||||
branches: [master]
|
||||
jobs:
|
||||
misspell:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: reviewdog/action-misspell@master
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
locale: "US"
|
||||
level: error
|
||||
50
.golangci.yml
Normal file
50
.golangci.yml
Normal file
@@ -0,0 +1,50 @@
|
||||
linters-settings:
|
||||
maligned:
|
||||
suggest-new: true
|
||||
misspell:
|
||||
locale: US
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- bodyclose
|
||||
- deadcode
|
||||
- dogsled
|
||||
- dupl
|
||||
- errcheck
|
||||
- gochecknoglobals
|
||||
- gochecknoinits
|
||||
- gocognit
|
||||
- goconst
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- goimports
|
||||
- golint
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- interfacer
|
||||
- maligned
|
||||
- misspell
|
||||
- nakedret
|
||||
- prealloc
|
||||
- rowserrcheck
|
||||
- scopelint
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- varcheck
|
||||
- whitespace
|
||||
|
||||
run:
|
||||
skip-dirs:
|
||||
- .devcontainer
|
||||
- .github
|
||||
- postgres
|
||||
|
||||
service:
|
||||
golangci-lint-version: 1.27.x # use the fixed version to not introduce new linters unexpectedly
|
||||
20
.travis.yml
20
.travis.yml
@@ -1,20 +0,0 @@
|
||||
dist: xenial
|
||||
sudo: required
|
||||
git:
|
||||
quiet: true
|
||||
depth: 1
|
||||
env:
|
||||
global:
|
||||
- DOCKER_REPO=qmcgaw/private-internet-access
|
||||
before_install:
|
||||
- curl -fsSL https://get.docker.com | sh
|
||||
- echo '{"experimental":"enabled"}' | sudo tee /etc/docker/daemon.json
|
||||
- mkdir -p $HOME/.docker
|
||||
- echo '{"experimental":"enabled"}' | sudo tee $HOME/.docker/config.json
|
||||
- sudo service docker start
|
||||
install:
|
||||
- docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
|
||||
- docker buildx create --name xbuilder --use
|
||||
script: bash ci.sh
|
||||
after_success:
|
||||
- curl -X POST https://hooks.microbadger.com/images/$DOCKER_REPO/tQFy7AxtSUNANPe6aoVChYdsI_I= || exit 0
|
||||
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@@ -3,6 +3,7 @@
|
||||
"shardulm94.trailing-spaces",
|
||||
"ms-azuretools.vscode-docker",
|
||||
"davidanson.vscode-markdownlint",
|
||||
"IBM.output-colorizer"
|
||||
"IBM.output-colorizer",
|
||||
"golang.go"
|
||||
]
|
||||
}
|
||||
91
.vscode/settings.json
vendored
Normal file
91
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
{
|
||||
// General settings
|
||||
"files.eol": "\n",
|
||||
// Docker
|
||||
"remote.extensionKind": {
|
||||
"ms-azuretools.vscode-docker": "workspace"
|
||||
},
|
||||
// Golang general settings
|
||||
"go.useLanguageServer": true,
|
||||
"go.autocompleteUnimportedPackages": true,
|
||||
"go.gotoSymbol.includeImports": true,
|
||||
"go.gotoSymbol.includeGoroot": true,
|
||||
"gopls": {
|
||||
"completeUnimported": true,
|
||||
"deepCompletion": true,
|
||||
"usePlaceholders": false
|
||||
},
|
||||
"go.lintTool": "golangci-lint",
|
||||
"go.lintFlags": [
|
||||
"--fast",
|
||||
"--enable",
|
||||
"rowserrcheck",
|
||||
"--enable",
|
||||
"bodyclose",
|
||||
"--enable",
|
||||
"dogsled",
|
||||
"--enable",
|
||||
"dupl",
|
||||
"--enable",
|
||||
"gochecknoglobals",
|
||||
"--enable",
|
||||
"gochecknoinits",
|
||||
"--enable",
|
||||
"gocognit",
|
||||
"--enable",
|
||||
"goconst",
|
||||
"--enable",
|
||||
"gocritic",
|
||||
"--enable",
|
||||
"gocyclo",
|
||||
"--enable",
|
||||
"goimports",
|
||||
"--enable",
|
||||
"golint",
|
||||
"--enable",
|
||||
"gosec",
|
||||
"--enable",
|
||||
"interfacer",
|
||||
"--enable",
|
||||
"maligned",
|
||||
"--enable",
|
||||
"misspell",
|
||||
"--enable",
|
||||
"nakedret",
|
||||
"--enable",
|
||||
"prealloc",
|
||||
"--enable",
|
||||
"scopelint",
|
||||
"--enable",
|
||||
"unconvert",
|
||||
"--enable",
|
||||
"unparam",
|
||||
"--enable",
|
||||
"whitespace"
|
||||
],
|
||||
// Golang on save
|
||||
"go.buildOnSave": "workspace",
|
||||
"go.lintOnSave": "workspace",
|
||||
"go.vetOnSave": "workspace",
|
||||
"editor.formatOnSave": true,
|
||||
"[go]": {
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
}
|
||||
},
|
||||
// Golang testing
|
||||
"go.toolsEnvVars": {
|
||||
"GOFLAGS": "-tags="
|
||||
},
|
||||
"gopls.env": {
|
||||
"GOFLAGS": "-tags="
|
||||
},
|
||||
"go.testEnvVars": {},
|
||||
"go.testFlags": [
|
||||
"-v",
|
||||
// "-race"
|
||||
],
|
||||
"go.testTimeout": "600s",
|
||||
"go.coverOnSingleTestFile": true,
|
||||
"go.coverOnSingleTest": true
|
||||
}
|
||||
83
Dockerfile
83
Dockerfile
@@ -1,15 +1,19 @@
|
||||
ARG ALPINE_VERSION=3.11
|
||||
ARG GO_VERSION=1.13.7
|
||||
ARG ALPINE_VERSION=3.12
|
||||
ARG GO_VERSION=1.14
|
||||
|
||||
FROM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS builder
|
||||
RUN apk --update add git
|
||||
WORKDIR /tmp/gobuild
|
||||
ENV CGO_ENABLED=0
|
||||
ARG GOLANGCI_LINT_VERSION=v1.27.0
|
||||
RUN wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s ${GOLANGCI_LINT_VERSION}
|
||||
WORKDIR /tmp/gobuild
|
||||
COPY .golangci.yml .
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download 2>&1
|
||||
COPY cmd/gluetun/main.go .
|
||||
COPY internal/ ./internal/
|
||||
COPY cmd/main.go .
|
||||
RUN go test ./...
|
||||
RUN golangci-lint run --timeout=10m
|
||||
RUN go build -ldflags="-s -w" -o entrypoint main.go
|
||||
|
||||
FROM alpine:${ALPINE_VERSION}
|
||||
@@ -27,13 +31,39 @@ LABEL \
|
||||
org.opencontainers.image.url="https://github.com/qdm12/private-internet-access-docker" \
|
||||
org.opencontainers.image.documentation="https://github.com/qdm12/private-internet-access-docker" \
|
||||
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 \
|
||||
org.opencontainers.image.title="VPN client for PIA, Mullvad, Windscribe, Surfshark and Cyberghost" \
|
||||
org.opencontainers.image.description="VPN client to tunnel to PIA, Mullvad, Windscribe, Surfshark and Cyberghost servers using OpenVPN, IPtables, DNS over TLS and Alpine Linux"
|
||||
ENV VPNSP=pia \
|
||||
PROTOCOL=udp \
|
||||
REGION="CA Montreal" \
|
||||
OPENVPN_VERBOSITY=1 \
|
||||
OPENVPN_ROOT=no \
|
||||
OPENVPN_TARGET_IP= \
|
||||
TZ= \
|
||||
UID=1000 \
|
||||
GID=1000 \
|
||||
IP_STATUS_FILE="/ip" \
|
||||
# PIA, Windscribe, Surfshark, Cyberghost, Vyprvpn, NordVPN only
|
||||
USER= \
|
||||
PASSWORD= \
|
||||
REGION="Austria" \
|
||||
# PIA only
|
||||
PIA_ENCRYPTION=strong \
|
||||
PORT_FORWARDING=off \
|
||||
PORT_FORWARDING_STATUS_FILE="/forwarded_port" \
|
||||
# Mullvad only
|
||||
COUNTRY=Sweden \
|
||||
CITY= \
|
||||
ISP= \
|
||||
# Mullvad and Windscribe only
|
||||
PORT= \
|
||||
# Cyberghost only
|
||||
CYBERGHOST_GROUP="Premium UDP Europe" \
|
||||
# NordVPN only
|
||||
SERVER_NUMBER= \
|
||||
# Openvpn
|
||||
OPENVPN_CIPHER= \
|
||||
OPENVPN_AUTH= \
|
||||
# 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 \
|
||||
@@ -41,31 +71,38 @@ ENV USER= \
|
||||
DOT_VERBOSITY_DETAILS=0 \
|
||||
DOT_VALIDATION_LOGLEVEL=0 \
|
||||
DOT_CACHING=on \
|
||||
DOT_IPV6=off \
|
||||
BLOCK_MALICIOUS=on \
|
||||
BLOCK_SURVEILLANCE=off \
|
||||
BLOCK_ADS=off \
|
||||
UNBLOCK= \
|
||||
DNS_UPDATE_PERIOD=24h \
|
||||
DNS_PLAINTEXT_ADDRESS=1.1.1.1 \
|
||||
DNS_KEEP_NAMESERVER=off \
|
||||
# Firewall
|
||||
FIREWALL=on \
|
||||
EXTRA_SUBNETS= \
|
||||
PORT_FORWARDING=off \
|
||||
PORT_FORWARDING_STATUS_FILE="/forwarded_port" \
|
||||
FIREWALL_DEBUG=off \
|
||||
# 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=
|
||||
ENTRYPOINT /entrypoint
|
||||
EXPOSE 8888/tcp 8388/tcp 8388/udp
|
||||
HEALTHCHECK --interval=3m --timeout=3s --start-period=20s --retries=1 CMD /entrypoint healthcheck
|
||||
RUN apk add -q --progress --no-cache --update openvpn ca-certificates iptables unbound tinyproxy tzdata && \
|
||||
SHADOWSOCKS_METHOD=chacha20-ietf-poly1305
|
||||
ENTRYPOINT ["/entrypoint"]
|
||||
EXPOSE 8000/tcp 8888/tcp 8388/tcp 8388/udp
|
||||
HEALTHCHECK --interval=10m --timeout=10s --start-period=30s --retries=2 CMD /entrypoint healthcheck
|
||||
RUN apk add -q --progress --no-cache --update openvpn ca-certificates iptables ip6tables unbound tinyproxy tzdata && \
|
||||
echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
|
||||
apk add -q --progress --no-cache --update shadowsocks-libev && \
|
||||
rm -rf /*.zip /var/cache/apk/* /etc/unbound/* /usr/sbin/unbound-anchor /usr/sbin/unbound-checkconf /usr/sbin/unbound-control /usr/sbin/unbound-control-setup /usr/sbin/unbound-host /etc/tinyproxy/tinyproxy.conf && \
|
||||
adduser nonrootuser -D -H --uid 1000 && \
|
||||
chown nonrootuser -R /etc/unbound /etc/tinyproxy && \
|
||||
chmod 700 /etc/unbound /etc/tinyproxy
|
||||
COPY --from=builder --chown=1000:1000 /tmp/gobuild/entrypoint /entrypoint
|
||||
rm -rf /var/cache/apk/* /etc/unbound/* /usr/sbin/unbound-* /etc/tinyproxy/tinyproxy.conf && \
|
||||
deluser openvpn && \
|
||||
deluser tinyproxy && \
|
||||
deluser unbound
|
||||
COPY --from=builder /tmp/gobuild/entrypoint /entrypoint
|
||||
|
||||
478
README.md
478
README.md
@@ -1,14 +1,14 @@
|
||||
# Private Internet Access Client
|
||||
# Gluetun VPN 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,
|
||||
Mullvad, Windscribe, Surfshark Cyberghost and NordVPN 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`)
|
||||
**ANNOUNCEMENT**: *[Video of the Git history of Gluetun](https://youtu.be/khipOYJtGJ0)*
|
||||
|
||||
<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">
|
||||
</a>
|
||||
<img height="250" src="https://raw.githubusercontent.com/qdm12/private-internet-access-docker/master/title.svg?sanitize=true">
|
||||
|
||||
[](https://travis-ci.org/qdm12/private-internet-access-docker)
|
||||
[](https://github.com/qdm12/private-internet-access-docker/actions?query=workflow%3A%22Buildx+latest%22)
|
||||
[](https://hub.docker.com/r/qmcgaw/private-internet-access)
|
||||
[](https://hub.docker.com/r/qmcgaw/private-internet-access)
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
|
||||
<details><summary>Click to show base components</summary><p>
|
||||
|
||||
- [Alpine 3.11](https://alpinelinux.org) for a tiny image (37MB of packages, 6.7MB of Go binary and 5.6MB for Alpine)
|
||||
- [OpenVPN 2.4.8](https://pkgs.alpinelinux.org/package/v3.11/main/x86_64/openvpn) to tunnel to PIA servers
|
||||
- [IPtables 1.8.3](https://pkgs.alpinelinux.org/package/v3.11/main/x86_64/iptables) enforces the container to communicate only through the VPN or with other containers in its virtual network (acts as a killswitch)
|
||||
- [Unbound 1.9.6](https://pkgs.alpinelinux.org/package/v3.11/main/x86_64/unbound) configured with Cloudflare's [1.1.1.1](https://1.1.1.1) DNS over TLS (configurable with 5 different providers)
|
||||
- [Alpine 3.12](https://alpinelinux.org) for a tiny image (37MB of packages, 6.7MB of Go binary and 5.6MB for Alpine)
|
||||
- [OpenVPN 2.4.9](https://pkgs.alpinelinux.org/package/v3.11/main/x86_64/openvpn) to tunnel to your VPN provider servers
|
||||
- [IPtables 1.8.4](https://pkgs.alpinelinux.org/package/v3.11/main/x86_64/iptables) enforces the container to communicate only through the VPN or with other containers in its virtual network (acts as a killswitch)
|
||||
- [Unbound 1.10.1](https://pkgs.alpinelinux.org/package/v3.11/main/x86_64/unbound) configured with Cloudflare's [1.1.1.1](https://1.1.1.1) DNS over TLS (configurable with 5 different providers)
|
||||
- [Files and blocking lists built periodically](https://github.com/qdm12/updated/tree/master/files) used with Unbound (see `BLOCK_MALICIOUS`, `BLOCK_SURVEILLANCE` and `BLOCK_ADS` environment variables)
|
||||
- [TinyProxy 1.10.0](https://pkgs.alpinelinux.org/package/v3.11/main/x86_64/tinyproxy)
|
||||
- [Shadowsocks 3.3.4](https://pkgs.alpinelinux.org/package/edge/testing/x86/shadowsocks-libev)
|
||||
@@ -34,63 +34,77 @@
|
||||
|
||||
## 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>
|
||||
- Based on Alpine 3.12 for a small Docker image of 52MB
|
||||
- Supports **Private Internet Access**, **Mullvad**, **Windscribe**,
|
||||
**Surfshark**, **Cyberghost** and **NordVPN** servers
|
||||
- DNS over TLS baked in with service provider(s) of your choice
|
||||
- DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses, with live update every 24 hours
|
||||
- Choose the vpn network protocol, `udp` or `tcp`
|
||||
- Built in firewall kill switch to allow traffic only with needed the VPN 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 🎆
|
||||
|
||||
- [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
|
||||
### Private Internet Access
|
||||
|
||||
</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
|
||||
- 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
|
||||
- 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))
|
||||
|
||||
### Windscribe
|
||||
|
||||
- Pick the [region](https://windscribe.com/status)
|
||||
- Pick the port to use
|
||||
|
||||
### Surfshark
|
||||
|
||||
- Pick the [region](https://github.com/qdm12/private-internet-access-docker/wiki/Surfshark) or a multi hop region name
|
||||
|
||||
### Cyberghost
|
||||
|
||||
- Pick the [region](https://github.com/qdm12/private-internet-access-docker/wiki/Cyberghost)
|
||||
|
||||
### Vyprvpn
|
||||
|
||||
- Pick the [region](https://www.vyprvpn.com/server-locations)
|
||||
|
||||
### 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>
|
||||
1. Requirements
|
||||
- A VPN account with one of the service providers:
|
||||
- Private Internet Access: **username** and **password** ([sign up](https://www.privateinternetaccess.com/pages/buy-vpn/))
|
||||
- Mullvad: user ID ([sign up](https://mullvad.net/en/account/))
|
||||
- Windscribe: **username** and **password** | Signup up using my affiliate link below
|
||||
|
||||
- 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`
|
||||
- <details><summary>External firewall requirements, if you have one</summary><p>
|
||||
[](https://windscribe.com/?affid=mh7nyafu)
|
||||
|
||||
- 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
|
||||
- If `SHADOWSOCKS=on`, allow inbound TCP 8388 and UDP 8388 from your LAN
|
||||
- If `TINYPROXY=on`, allow inbound TCP 8888 from your LAN
|
||||
- Surfshark: **username** and **password** ([sign up](https://order.surfshark.com/))
|
||||
- Cyberghost: **username**, **password** and **device client key file** ([sign up](https://www.cyberghostvpn.com/en_US/buy/cyberghost-vpn-4))
|
||||
- Vyprvpn: **username** and **password**
|
||||
- NordVPN: **username** and **password**
|
||||
- If you have a host or router firewall, please refer [to the firewall documentation](https://github.com/qdm12/private-internet-access-docker/blob/master/doc/firewall.md)
|
||||
|
||||
</p></details>
|
||||
|
||||
</p></details>
|
||||
1. On some devices you may need to setup your tunnel kernel module on your host with `insmod /lib/modules/tun.ko` or `modprobe tun`
|
||||
- *Synology users*: please read [this part of the Wiki](https://github.com/qdm12/private-internet-access-docker/wiki/Common-issues#synology)
|
||||
|
||||
1. Launch the container with:
|
||||
|
||||
```bash
|
||||
docker run -d --init --name=pia --cap-add=NET_ADMIN \
|
||||
docker run -d --name gluetun --cap-add=NET_ADMIN \
|
||||
-e REGION="CA Montreal" -e USER=js89ds7 -e PASSWORD=8fd9s239G \
|
||||
qmcgaw/private-internet-access
|
||||
```
|
||||
@@ -102,72 +116,196 @@
|
||||
```
|
||||
|
||||
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)
|
||||
- Use `-p 8888:8888/tcp` to access the HTTP web proxy (and put your LAN in `EXTRA_SUBNETS` environment variable, in example `192.168.1.0/24`)
|
||||
- Use `-p 8388:8388/tcp -p 8388:8388/udp` to access the SOCKS5 proxy (and put your LAN in `EXTRA_SUBNETS` environment variable, in example `192.168.1.0/24`)
|
||||
- Use `-p 8000:8000/tcp` to access the [HTTP control server](#HTTP-control-server) built-in
|
||||
|
||||
**If you encounter an issue with the tun device not being available, see [the FAQ](https://github.com/qdm12/private-internet-access-docker/blob/master/doc/faq.md#how-to-fix-openvpn-failing-to-start)**
|
||||
|
||||
1. You can update the image with `docker pull qmcgaw/private-internet-access:latest`. See the [wiki](https://github.com/qdm12/private-internet-access-docker/wiki/Common-issues#use-a-release-tag) for more information on other tags available.
|
||||
|
||||
## Testing
|
||||
|
||||
Check the PIA IP address matches your expectations
|
||||
Check the VPN 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:gluetun alpine:3.12 wget -qO- https://ipinfo.io
|
||||
```
|
||||
|
||||
Want more testing? ▶ [see the Wiki](https://github.com/qdm12/private-internet-access-docker/wiki/Testing)
|
||||
|
||||
## Environment variables
|
||||
|
||||
| Environment variable | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `REGION` | `CA Montreal` | One of the [PIA regions](https://www.privateinternetaccess.com/pages/network/) |
|
||||
| `PROTOCOL` | `udp` | `tcp` or `udp` |
|
||||
| `ENCRYPTION` | `strong` | `normal` or `strong` |
|
||||
| `USER` | | Your PIA username |
|
||||
| `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` |
|
||||
| `DOT_CACHING` | `on` | Unbound caching feature, `on` or `off` |
|
||||
| `DOT_PRIVATE_ADDRESS` | All IPv4 and IPv6 CIDRs private ranges | Comma separated list of CIDRs or single IP addresses. Note that the default setting prevents DNS rebinding |
|
||||
| `DOT_VERBOSITY` | `1` | Unbound verbosity level from `0` to `5` (full debug) |
|
||||
| `DOT_VERBOSITY_DETAILS` | `0` | Unbound details verbosity level from `0` to `4` |
|
||||
| `DOT_VALIDATION_LOGLEVEL` | `0` | Unbound validation log level from `0` to `2` |
|
||||
| `BLOCK_MALICIOUS` | `on` | `on` or `off`, blocks malicious hostnames and IPs |
|
||||
| `BLOCK_SURVEILLANCE` | `off` | `on` or `off`, blocks surveillance hostnames and IPs |
|
||||
| `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 |
|
||||
| `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_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` |
|
||||
**TLDR**; only set the 🏁 marked environment variables to get started.
|
||||
|
||||
### VPN
|
||||
|
||||
| Variable | Default | Choices | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| 🏁 `VPNSP` | `private internet access` | `private internet access`, `mullvad`, `windscribe`, `surfshark`, `vyprvpn`, `nordvpn` | VPN Service Provider |
|
||||
| `IP_STATUS_FILE` | `/ip` | Any filepath | Filepath to store the public IP address assigned |
|
||||
| `PROTOCOL` | `udp` | `udp` or `tcp` | Network protocol to use |
|
||||
| `OPENVPN_VERBOSITY` | `1` | `0` to `6` | Openvpn verbosity level |
|
||||
| `OPENVPN_ROOT` | `no` | `yes` or `no` | Run OpenVPN as root |
|
||||
| `OPENVPN_TARGET_IP` | | Valid IP address | Specify a target VPN server (or gateway) IP address to use |
|
||||
| `OPENVPN_CIPHER` | | i.e. `aes-256-gcm` | Specify a custom cipher to use. It will also set `ncp-disable` if using AES GCM for PIA |
|
||||
| `OPENVPN_AUTH` | | i.e. `sha256` | Specify a custom auth algorithm to use |
|
||||
|
||||
- Private Internet Access
|
||||
|
||||
| Variable | Default | Choices | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| 🏁 `USER` | | | Your username |
|
||||
| 🏁 `PASSWORD` | | | Your password |
|
||||
| `REGION` | `Austria` | One of the [PIA regions](https://www.privateinternetaccess.com/pages/network/) | VPN server region |
|
||||
| `PIA_ENCRYPTION` | `strong` | `normal`, `strong` | Encryption preset |
|
||||
| `PORT_FORWARDING` | `off` | `on`, `off` | Enable port forwarding on the VPN server |
|
||||
| `PORT_FORWARDING_STATUS_FILE` | `/forwarded_port` | Any filepath | Filepath to store the forwarded port number |
|
||||
|
||||
- Mullvad
|
||||
|
||||
| Variable | Default | Choices | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| 🏁 `USER` | | | Your user ID |
|
||||
| `COUNTRY` | `Sweden` | One of the [Mullvad countries](https://mullvad.net/en/servers/#openvpn) | VPN server country |
|
||||
| `CITY` | | One of the [Mullvad cities](https://mullvad.net/en/servers/#openvpn) | VPN server city |
|
||||
| `ISP` | | One of the [Mullvad ISP](https://mullvad.net/en/servers/#openvpn) | VPN server ISP |
|
||||
| `PORT` | | `80` or `443` for TCP; or `53` for UDP. Leave blank for default Mullvad server port | Custom VPN port to use |
|
||||
|
||||
- Windscribe
|
||||
|
||||
| Variable | Default | Choices | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| 🏁 `USER` | | | Your username |
|
||||
| 🏁 `PASSWORD` | | | Your password |
|
||||
| `REGION` | `Austria` | One of the [Windscribe regions](https://windscribe.com/status) | VPN server region |
|
||||
| `PORT` | | One from the [this list of ports](https://windscribe.com/getconfig/openvpn) | Custom VPN port to use |
|
||||
|
||||
- Surfshark
|
||||
|
||||
| Variable | Default | Choices | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| 🏁 `USER` | | | Your **service** username, found at the bottom of the [manual setup page](https://account.surfshark.com/setup/manual) |
|
||||
| 🏁 `PASSWORD` | | | Your **service** password |
|
||||
| `REGION` | `Austria` | One of the [Surfshark regions (subdomains)](https://github.com/qdm12/private-internet-access-docker/wiki/surfshark) | VPN server region |
|
||||
|
||||
- Cyberghost
|
||||
|
||||
| Variable | Default | Choices | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| 🏁 `USER` | | | Your username |
|
||||
| 🏁 `PASSWORD` | | | Your password |
|
||||
| 🏁 `CLIENT_KEY` | | | Your device client key content, **see below** |
|
||||
| `REGION` | `Austria` | One of the [Cyberghost countries](https://github.com/qdm12/private-internet-access-docker/wiki/Cyberghost#regions) | VPN server country |
|
||||
| `CYBERGHOST_GROUP` | `Premium UDP Europe` | One of the [server groups](https://github.com/qdm12/private-internet-access-docker/wiki/Cyberghost#server-groups) | Server group |
|
||||
|
||||
To specify your client key, you can either:
|
||||
|
||||
- Bind mount it at `/files/client.key`, for example with `-v /yourpath/client.key:/files/client.key:ro`
|
||||
- Convert it to a single line value using:
|
||||
|
||||
```sh
|
||||
docker run -it --rm -v /yourpath/client.key:/files/client.key:ro qmcgaw/private-internet-access clientkey
|
||||
```
|
||||
|
||||
And use the line produced as the value for the environment variable `CLIENT_KEY`.
|
||||
|
||||
- NordVPN
|
||||
|
||||
| Variable | Default | Choices | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| 🏁 `USER` | | | Your username |
|
||||
| 🏁 `PASSWORD` | | | Your password |
|
||||
| `REGION` | `Austria` | One of the [VyprVPN regions](https://www.vyprvpn.com/server-locations) | VPN server region |
|
||||
| `SERVER_NUMBER` | | Server integer number | Optional server number. For example `251` for `Italy #251` |
|
||||
|
||||
- NordVPN
|
||||
|
||||
| Variable | Default | Choices | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| 🏁 `USER` | | | Your username |
|
||||
| 🏁 `PASSWORD` | | | Your password |
|
||||
| 🏁 `REGION` | `Austria` (wrong) | One of the NordVPN server name, i.e. `Cyprus #12` | VPN server name |
|
||||
|
||||
### DNS over TLS
|
||||
|
||||
None of the following values are required.
|
||||
|
||||
| Variable | Default | Choices | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `DOT` | `on` | `on`, `off` | Activate DNS over TLS with Unbound |
|
||||
| `DOT_PROVIDERS` | `cloudflare` | `cloudflare`, `google`, `quad9`, `quadrant`, `cleanbrowsing`, `securedns`, `libredns` | Comma delimited list of DNS over TLS providers |
|
||||
| `DOT_CACHING` | `on` | `on`, `off` | Unbound caching |
|
||||
| `DOT_IPV6` | `off` | `on`, `off` | DNS IPv6 resolution |
|
||||
| `DOT_PRIVATE_ADDRESS` | All private CIDRs ranges | | Comma separated list of CIDRs or single IP addresses Unbound won't resolve to. Note that the default setting prevents DNS rebinding |
|
||||
| `DOT_VERBOSITY` | `1` | `0` to `5` | Unbound verbosity level |
|
||||
| `DOT_VERBOSITY_DETAILS` | `0` | `0` to `4` | Unbound details verbosity level |
|
||||
| `DOT_VALIDATION_LOGLEVEL` | `0` | `0` to `2` | Unbound validation log level |
|
||||
| `DNS_UPDATE_PERIOD` | `24h` | i.e. `0`, `30s`, `5m`, `24h` | Period to update block lists and cryptographic files and restart Unbound. Set to `0` to deactivate updates |
|
||||
| `BLOCK_MALICIOUS` | `on` | `on`, `off` | Block malicious hostnames and IPs with Unbound |
|
||||
| `BLOCK_SURVEILLANCE` | `off` | `on`, `off` | Block surveillance hostnames and IPs with Unbound |
|
||||
| `BLOCK_ADS` | `off` | `on`, `off` | Block ads hostnames and IPs with Unbound |
|
||||
| `UNBLOCK` | |i.e. `domain1.com,x.domain2.co.uk` | Comma separated list of domain names to leave unblocked with Unbound |
|
||||
| `DNS_PLAINTEXT_ADDRESS` | `1.1.1.1` | Any IP address | IP address to use as DNS resolver if `DOT` is `off` |
|
||||
| `DNS_KEEP_NAMESERVER` | `off` | `on` or `off` | Keep the nameservers in /etc/resolv.conf untouched, but disabled DNS blocking features |
|
||||
|
||||
### Firewall
|
||||
|
||||
That one is important if you want to connect to the container from your LAN for example, using Shadowsocks or Tinyproxy.
|
||||
|
||||
| Variable | Default | Choices | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `FIREWALL` | `on` | `on` or `off` | Turn on or off the container built-in firewall. You should use it for **debugging purposes** only. |
|
||||
| `EXTRA_SUBNETS` | | i.e. `192.168.1.0/24,192.168.10.121,10.0.0.5/28` | Comma separated subnets allowed in the container firewall |
|
||||
| `FIREWALL_DEBUG` | `off` | `on` or `off` | Prints every firewall related command. You should use it for **debugging purposes** only. |
|
||||
|
||||
### Shadowsocks
|
||||
|
||||
| Variable | Default | Choices | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `SHADOWSOCKS` | `off` | `on`, `off` | Enable the internal SOCKS5 proxy Shadowsocks |
|
||||
| `SHADOWSOCKS_LOG` | `off` | `on`, `off` | Enable logging |
|
||||
| `SHADOWSOCKS_PORT` | `8388` | `1024` to `65535` | Internal port number for Shadowsocks to listen on |
|
||||
| `SHADOWSOCKS_PASSWORD` | | | Password to use to connect to Shadowsocks |
|
||||
| `SHADOWSOCKS_METHOD` | `chacha20-ietf-poly1305` | One of [these ciphers](https://shadowsocks.org/en/config/quick-guide.html) | Method to use for Shadowsocks |
|
||||
|
||||
### Tinyproxy
|
||||
|
||||
| Variable | Default | Choices | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `TINYPROXY` | `off` | `on`, `off` | Enable the internal HTTP proxy tinyproxy |
|
||||
| `TINYPROXY_LOG` | `Info` | `Info`, `Connect`, `Notice`, `Warning`, `Error`, `Critical` | Tinyproxy log level |
|
||||
| `TINYPROXY_PORT` | `8888` | `1024` to `65535` | Internal port number for Tinyproxy to listen on |
|
||||
| `TINYPROXY_USER` | | | Username to use to connect to Tinyproxy |
|
||||
| `TINYPROXY_PASSWORD` | | | Password to use to connect to Tinyproxy |
|
||||
|
||||
### System
|
||||
|
||||
| Variable | Default | Choices | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `TZ` | | i.e. `Europe/London` | Specify a timezone to use to have correct log times |
|
||||
| `UID` | `1000` | | User ID to run as non root and for ownership of files written |
|
||||
| `GID` | `1000` | | Group ID to run as non root and for ownership of files written |
|
||||
|
||||
## Connect to it
|
||||
|
||||
There are various ways to achieve this, depending on your use case.
|
||||
|
||||
- <details><summary>Connect containers in the same docker-compose.yml as PIA</summary><p>
|
||||
- <details><summary>Connect containers in the same docker-compose.yml as Gluetun</summary><p>
|
||||
|
||||
Add `network_mode: "service:pia"` to your *docker-compose.yml* (no need for `depends_on`)
|
||||
Add `network_mode: "service:gluetun"` to your *docker-compose.yml* (no need for `depends_on`)
|
||||
|
||||
</p></details>
|
||||
- <details><summary>Connect other containers to PIA</summary><p>
|
||||
- <details><summary>Connect other containers to Gluetun</summary><p>
|
||||
|
||||
Add `--network=container:pia` when launching the container, provided PIA is already running
|
||||
Add `--network=container:gluetun` when launching the container, provided Gluetun is already running
|
||||
|
||||
</p></details>
|
||||
- <details><summary>Connect containers from another docker-compose.yml</summary><p>
|
||||
|
||||
Add `network_mode: "container:pia"` to your *docker-compose.yml*, provided PIA is already running
|
||||
Add `network_mode: "container:gluetun"` to your *docker-compose.yml*, provided Gluetun is already running
|
||||
|
||||
</p></details>
|
||||
- <details><summary>Connect LAN devices through the built-in HTTP proxy *Tinyproxy* (i.e. with Chrome, Kodi, etc.)</summary><p>
|
||||
@@ -175,7 +313,7 @@ There are various ways to achieve this, depending on your use case.
|
||||
You might want to use Shadowsocks instead which tunnels UDP as well as TCP, whereas Tinyproxy only tunnels TCP.
|
||||
|
||||
1. Setup a HTTP proxy client, such as [SwitchyOmega for Chrome](https://chrome.google.com/webstore/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif?hl=en)
|
||||
1. Ensure the PIA container is launched with:
|
||||
1. Ensure the Gluetun container is launched with:
|
||||
- port `8888` published `-p 8888:8888/tcp`
|
||||
- your LAN subnet, i.e. `192.168.1.0/24`, set as `-e EXTRA_SUBNETS=192.168.1.0/24`
|
||||
1. With your HTTP proxy client, connect to the Docker host (i.e. `192.168.1.10`) on port `8888`. You need to enter your credentials if you set them with `TINYPROXY_USER` and `TINYPROXY_PASSWORD`.
|
||||
@@ -185,40 +323,39 @@ There are various ways to achieve this, depending on your use case.
|
||||
- <details><summary>Connect LAN devices through the built-in SOCKS5 proxy *Shadowsocks* (per app, system wide, etc.)</summary><p>
|
||||
|
||||
1. Setup a SOCKS5 proxy client, there is a list of [ShadowSocks clients for **all platforms**](https://shadowsocks.org/en/download/clients.html)
|
||||
- **note** some clients do not tunnel UDP so your DNS queries will be done locally and not through PIA and its built in DNS over TLS
|
||||
- **note** some clients do not tunnel UDP so your DNS queries will be done locally and not through Gluetun and its built in DNS over TLS
|
||||
- Clients that support such UDP tunneling are, as far as I know:
|
||||
- iOS: Potatso Lite
|
||||
- OSX: ShadowsocksX
|
||||
- Android: Shadowsocks by Max Lv
|
||||
1. Ensure the PIA container is launched with:
|
||||
1. Ensure the Gluetun container is launched with:
|
||||
- port `8388` published `-p 8388:8388/tcp -p 8388:8388/udp`
|
||||
- your LAN subnet, i.e. `192.168.1.0/24`, set as `-e EXTRA_SUBNETS=192.168.1.0/24`
|
||||
1. With your SOCKS5 proxy client
|
||||
- Enter the Docker host (i.e. `192.168.1.10`) as the server IP
|
||||
- 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
|
||||
- Choose the encryption method/algorithm to the method you specified in `SHADOWSOCKS_METHOD`
|
||||
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>
|
||||
- <details><summary>Access ports of containers connected to Gluetun</summary><p>
|
||||
|
||||
In example, to access port `8000` of container `xyz` and `9000` of container `abc` connected to PIA,
|
||||
publish ports `8000` and `9000` for the PIA container and access them as you would with any other container
|
||||
In example, to access port `8000` of container `xyz` and `9000` of container `abc` connected to Gluetun,
|
||||
publish ports `8000` and `9000` for the Gluetun container and access them as you would with any other container
|
||||
|
||||
</p></details>
|
||||
- <details><summary>Access ports of containers connected to PIA, all in the same docker-compose.yml</summary><p>
|
||||
- <details><summary>Access ports of containers connected to Gluetun, all in the same docker-compose.yml</summary><p>
|
||||
|
||||
In example, to access port `8000` of container `xyz` and `9000` of container `abc` connected to PIA, publish port `8000` and `9000` for the PIA container.
|
||||
In example, to access port `8000` of container `xyz` and `9000` of container `abc` connected to Gluetun, publish port `8000` and `9000` for the Gluetun container.
|
||||
The docker-compose.yml file would look like:
|
||||
|
||||
```yml
|
||||
version: '3.7'
|
||||
services:
|
||||
pia:
|
||||
gluetun:
|
||||
image: qmcgaw/private-internet-access
|
||||
container_name: pia
|
||||
init: true
|
||||
container_name: gluetun
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
environment:
|
||||
@@ -230,111 +367,50 @@ There are various ways to achieve this, depending on your use case.
|
||||
abc:
|
||||
image: abc
|
||||
container_name: abc
|
||||
network_mode: "service:pia"
|
||||
network_mode: "service:gluetun"
|
||||
xyz:
|
||||
image: xyz
|
||||
container_name: xyz
|
||||
network_mode: "service:pia"
|
||||
network_mode: "service:gluetun"
|
||||
```
|
||||
|
||||
</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 VPN 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
|
||||
## HTTP control server
|
||||
|
||||
- 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:
|
||||
A built-in HTTP server listens on port `8000` to modify the state of the container. You have the following routes available:
|
||||
|
||||
```bash
|
||||
docker build -t qmcgaw/private-internet-access https://github.com/qdm12/private-internet-access-docker.git
|
||||
```
|
||||
- `http://<your-docker-host-ip>:8000/openvpn/actions/restart` restarts the openvpn process
|
||||
- `http://<your-docker-host-ip>:8000/unbound/actions/restart` re-downloads the DNS files (crypto and block lists) and restarts the unbound process
|
||||
|
||||
- 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`
|
||||
- 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)
|
||||
## Development and contributing
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- 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.)
|
||||
|
||||
- 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
|
||||
|
||||
- Fallback to a precise previous version
|
||||
1. Clone the repository on your machine
|
||||
|
||||
```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 .
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Using VSCode and Docker
|
||||
|
||||
1. Install [Docker](https://docs.docker.com/install)
|
||||
- On Windows, share a drive with Docker Desktop and have the project on that partition
|
||||
1. With [Visual Studio Code](https://code.visualstudio.com/download), install the [remote containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
|
||||
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:
|
||||
|
||||
## TODOs
|
||||
|
||||
- Support other VPN providers
|
||||
- Mullvad
|
||||
- Windscribe
|
||||
- Gotify support for notificactions
|
||||
- Periodic update of malicious block lists with Unbound restart
|
||||
- Improve healthcheck
|
||||
- Check IP address belongs to selected region
|
||||
- Check for DNS provider somehow if this is even possible
|
||||
- Support for other VPN protocols
|
||||
- Wireguard (wireguard-go)
|
||||
- Show new versions/commits at start
|
||||
- Colors & emojis
|
||||
- Setup
|
||||
- Logging streams
|
||||
- More unit tests
|
||||
- Write in Go
|
||||
- DNS over TLS to replace Unbound
|
||||
- HTTP proxy to replace tinyproxy
|
||||
- use [go-Shadowsocks2](https://github.com/shadowsocks/go-shadowsocks2)
|
||||
- DNS over HTTPS, maybe use [github.com/likexian/doh-go](https://github.com/likexian/doh-go)
|
||||
- use [iptables-go](https://github.com/coreos/go-iptables) to replace iptables
|
||||
- wireguard-go
|
||||
- Openvpn to replace openvpn
|
||||
- Contribute with code: see [the Wiki](https://github.com/qdm12/private-internet-access-docker/wiki/Contributing).
|
||||
- [The list of existing contributors 👍](https://github.com/qdm12/private-internet-access-docker/blob/master/.github/CONTRIBUTING.md#Contributors)
|
||||
- [Github workflows](https://github.com/qdm12/private-internet-access-docker/actions) to know what's building
|
||||
- [List of issues and feature requests](https://github.com/qdm12/private-internet-access-docker/issues)
|
||||
|
||||
## License
|
||||
|
||||
This repository is under an [MIT license](https://github.com/qdm12/private-internet-access-docker/master/license)
|
||||
|
||||
## Support
|
||||
|
||||
Sponsor me on [Github](https://github.com/sponsors/qdm12), donate to [paypal.me/qmcgaw](https://www.paypal.me/qmcgaw) or subscribe to a VPN provider through one of my affiliate links:
|
||||
|
||||
[](https://github.com/sponsors/qdm12)
|
||||
[](https://www.paypal.me/qmcgaw)
|
||||
|
||||
[](https://windscribe.com/?affid=mh7nyafu)
|
||||
|
||||
Feel also free to have a look at [the Kanban board](https://github.com/qdm12/private-internet-access-docker/projects/1) and [contribute](#Development-and-contributing) to the code or the issues discussion.
|
||||
|
||||
Many thanks to @Frepke, @Ralph521, G. Mendez, M. Otmar Weber, J. Perez and A. Cooper for supporting me financially 🥇👍
|
||||
|
||||
21
ci.sh
21
ci.sh
@@ -1,21 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$TRAVIS_PULL_REQUEST" = "true" ] || [ "$TRAVIS_BRANCH" != "master" ]; then
|
||||
docker buildx build \
|
||||
--progress plain \
|
||||
--platform=linux/amd64,linux/386,linux/arm64,linux/arm/v7,linux/arm/v6,linux/ppc64le,linux/s390x \
|
||||
.
|
||||
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\""
|
||||
docker buildx build \
|
||||
--progress plain \
|
||||
--platform=linux/amd64,linux/386,linux/arm64,linux/arm/v7,linux/arm/v6,linux/ppc64le,linux/s390x \
|
||||
--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 \
|
||||
-t $DOCKER_REPO:$TAG \
|
||||
--push \
|
||||
.
|
||||
310
cmd/gluetun/main.go
Normal file
310
cmd/gluetun/main.go
Normal file
@@ -0,0 +1,310 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/golibs/command"
|
||||
"github.com/qdm12/golibs/files"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/golibs/network"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/alpine"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/cli"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/dns"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/firewall"
|
||||
gluetunLogging "github.com/qdm12/private-internet-access-docker/internal/logging"
|
||||
"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/publicip"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/routing"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/server"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/settings"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/shadowsocks"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/tinyproxy"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
os.Exit(_main(ctx, os.Args))
|
||||
}
|
||||
|
||||
func _main(background context.Context, args []string) int {
|
||||
if len(args) > 1 { // cli operation
|
||||
var err error
|
||||
switch args[1] {
|
||||
case "healthcheck":
|
||||
err = cli.HealthCheck()
|
||||
case "clientkey":
|
||||
err = cli.ClientKey(args[2:])
|
||||
case "openvpnconfig":
|
||||
err = cli.OpenvpnConfig()
|
||||
default:
|
||||
err = fmt.Errorf("command %q is unknown", args[1])
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
ctx, cancel := context.WithCancel(background)
|
||||
defer cancel()
|
||||
logger := createLogger()
|
||||
wg := &sync.WaitGroup{}
|
||||
fatalOnError := makeFatalOnError(logger, cancel, wg)
|
||||
|
||||
client := network.NewClient(15 * time.Second)
|
||||
// Create configurators
|
||||
fileManager := files.NewFileManager()
|
||||
alpineConf := alpine.NewConfigurator(fileManager)
|
||||
ovpnConf := openvpn.NewConfigurator(logger, fileManager)
|
||||
dnsConf := dns.NewConfigurator(logger, client, fileManager)
|
||||
routingConf := routing.NewRouting(logger, fileManager)
|
||||
firewallConf := firewall.NewConfigurator(logger, routingConf, fileManager)
|
||||
tinyProxyConf := tinyproxy.NewConfigurator(fileManager, logger)
|
||||
shadowsocksConf := shadowsocks.NewConfigurator(fileManager, logger)
|
||||
streamMerger := command.NewStreamMerger()
|
||||
|
||||
paramsReader := params.NewReader(logger, fileManager)
|
||||
fmt.Println(gluetunLogging.Splash(
|
||||
paramsReader.GetVersion(),
|
||||
paramsReader.GetVcsRef(),
|
||||
paramsReader.GetBuildDate()))
|
||||
|
||||
printVersions(ctx, logger, map[string]func(ctx context.Context) (string, error){
|
||||
"OpenVPN": ovpnConf.Version,
|
||||
"Unbound": dnsConf.Version,
|
||||
"IPtables": firewallConf.Version,
|
||||
"TinyProxy": tinyProxyConf.Version,
|
||||
"ShadowSocks": shadowsocksConf.Version,
|
||||
})
|
||||
|
||||
allSettings, err := settings.GetAllSettings(paramsReader)
|
||||
fatalOnError(err)
|
||||
logger.Info(allSettings.String())
|
||||
|
||||
// Should never change
|
||||
uid, gid := allSettings.System.UID, allSettings.System.GID
|
||||
|
||||
err = alpineConf.CreateUser("nonrootuser", uid)
|
||||
fatalOnError(err)
|
||||
err = fileManager.SetOwnership("/etc/unbound", uid, gid)
|
||||
fatalOnError(err)
|
||||
err = fileManager.SetOwnership("/etc/tinyproxy", uid, gid)
|
||||
fatalOnError(err)
|
||||
|
||||
if allSettings.Firewall.Debug {
|
||||
firewallConf.SetDebug()
|
||||
routingConf.SetDebug()
|
||||
}
|
||||
|
||||
if err := ovpnConf.CheckTUN(); err != nil {
|
||||
logger.Warn(err)
|
||||
err = ovpnConf.CreateTUN()
|
||||
fatalOnError(err)
|
||||
}
|
||||
|
||||
connectedCh := make(chan struct{})
|
||||
signalConnected := func() {
|
||||
connectedCh <- struct{}{}
|
||||
}
|
||||
defer close(connectedCh)
|
||||
go collectStreamLines(ctx, streamMerger, logger, signalConnected)
|
||||
|
||||
if allSettings.Firewall.Enabled {
|
||||
err := firewallConf.SetEnabled(ctx, true) // disabled by default
|
||||
fatalOnError(err)
|
||||
}
|
||||
|
||||
err = firewallConf.SetAllowedSubnets(ctx, allSettings.Firewall.AllowedSubnets)
|
||||
fatalOnError(err)
|
||||
|
||||
openvpnLooper := openvpn.NewLooper(allSettings.VPNSP, allSettings.OpenVPN, uid, gid,
|
||||
ovpnConf, firewallConf, logger, client, fileManager, streamMerger, fatalOnError)
|
||||
restartOpenvpn := openvpnLooper.Restart
|
||||
portForward := openvpnLooper.PortForward
|
||||
// wait for restartOpenvpn
|
||||
go openvpnLooper.Run(ctx, wg)
|
||||
|
||||
unboundLooper := dns.NewLooper(dnsConf, allSettings.DNS, logger, streamMerger, uid, gid)
|
||||
restartUnbound := unboundLooper.Restart
|
||||
// wait for restartUnbound
|
||||
go unboundLooper.Run(ctx, wg)
|
||||
|
||||
publicIPLooper := publicip.NewLooper(client, logger, fileManager, allSettings.System.IPStatusFilepath, uid, gid)
|
||||
restartPublicIP := publicIPLooper.Restart
|
||||
go publicIPLooper.Run(ctx)
|
||||
go publicIPLooper.RunRestartTicker(ctx)
|
||||
|
||||
tinyproxyLooper := tinyproxy.NewLooper(tinyProxyConf, firewallConf, allSettings.TinyProxy, logger, streamMerger, uid, gid)
|
||||
restartTinyproxy := tinyproxyLooper.Restart
|
||||
go tinyproxyLooper.Run(ctx, wg)
|
||||
|
||||
shadowsocksLooper := shadowsocks.NewLooper(shadowsocksConf, firewallConf, allSettings.ShadowSocks, allSettings.DNS, logger, streamMerger, uid, gid)
|
||||
restartShadowsocks := shadowsocksLooper.Restart
|
||||
go shadowsocksLooper.Run(ctx, wg)
|
||||
|
||||
if allSettings.TinyProxy.Enabled {
|
||||
restartTinyproxy()
|
||||
}
|
||||
if allSettings.ShadowSocks.Enabled {
|
||||
restartShadowsocks()
|
||||
}
|
||||
|
||||
go func() {
|
||||
var restartTickerContext context.Context
|
||||
var restartTickerCancel context.CancelFunc = func() {}
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
restartTickerCancel()
|
||||
return
|
||||
case <-connectedCh: // blocks until openvpn is connected
|
||||
restartTickerCancel()
|
||||
restartTickerContext, restartTickerCancel = context.WithCancel(ctx)
|
||||
go unboundLooper.RunRestartTicker(restartTickerContext)
|
||||
onConnected(allSettings, logger, routingConf, portForward, restartUnbound, restartPublicIP)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
httpServer := server.New("0.0.0.0:8000", logger, restartOpenvpn, restartUnbound)
|
||||
go httpServer.Run(ctx, wg)
|
||||
|
||||
// Start openvpn for the first time
|
||||
restartOpenvpn()
|
||||
|
||||
signalsCh := make(chan os.Signal, 1)
|
||||
signal.Notify(signalsCh,
|
||||
syscall.SIGINT,
|
||||
syscall.SIGTERM,
|
||||
os.Interrupt,
|
||||
)
|
||||
shutdownErrorsCount := 0
|
||||
select {
|
||||
case signal := <-signalsCh:
|
||||
logger.Warn("Caught OS signal %s, shutting down", signal)
|
||||
cancel()
|
||||
case <-ctx.Done():
|
||||
logger.Warn("context canceled, shutting down")
|
||||
}
|
||||
logger.Info("Clearing ip status file %s", allSettings.System.IPStatusFilepath)
|
||||
if err := fileManager.Remove(string(allSettings.System.IPStatusFilepath)); err != nil {
|
||||
logger.Error(err)
|
||||
shutdownErrorsCount++
|
||||
}
|
||||
if allSettings.OpenVPN.Provider.PortForwarding.Enabled {
|
||||
logger.Info("Clearing forwarded port status file %s", allSettings.OpenVPN.Provider.PortForwarding.Filepath)
|
||||
if err := fileManager.Remove(string(allSettings.OpenVPN.Provider.PortForwarding.Filepath)); err != nil {
|
||||
logger.Error(err)
|
||||
shutdownErrorsCount++
|
||||
}
|
||||
}
|
||||
waiting, waited := context.WithTimeout(context.Background(), time.Second)
|
||||
go func() {
|
||||
defer waited()
|
||||
wg.Wait()
|
||||
}()
|
||||
<-waiting.Done()
|
||||
if waiting.Err() == context.DeadlineExceeded {
|
||||
if shutdownErrorsCount > 0 {
|
||||
logger.Warn("Shutdown had %d errors", shutdownErrorsCount)
|
||||
}
|
||||
logger.Warn("Shutdown timed out")
|
||||
return 1
|
||||
}
|
||||
if shutdownErrorsCount > 0 {
|
||||
logger.Warn("Shutdown had %d errors")
|
||||
return 1
|
||||
}
|
||||
logger.Info("Shutdown successful")
|
||||
return 0
|
||||
}
|
||||
|
||||
func makeFatalOnError(logger logging.Logger, cancel context.CancelFunc, wg *sync.WaitGroup) func(err error) {
|
||||
return func(err error) {
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
cancel()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
go func() {
|
||||
wg.Wait()
|
||||
cancel()
|
||||
}()
|
||||
<-ctx.Done() // either timeout or wait group completed
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createLogger() logging.Logger {
|
||||
logger, err := logging.NewLogger(logging.ConsoleEncoding, logging.InfoLevel, -1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return logger
|
||||
}
|
||||
|
||||
func printVersions(ctx context.Context, logger logging.Logger, versionFunctions map[string]func(ctx context.Context) (string, error)) {
|
||||
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
for name, f := range versionFunctions {
|
||||
version, err := f(ctx)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
} else {
|
||||
logger.Info("%s version: %s", name, version)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func collectStreamLines(ctx context.Context, streamMerger command.StreamMerger, logger logging.Logger, signalConnected func()) {
|
||||
// Blocking line merging paramsReader for all programs: openvpn, tinyproxy, unbound and shadowsocks
|
||||
logger.Info("Launching standard output merger")
|
||||
streamMerger.CollectLines(ctx, func(line string) {
|
||||
line, level := gluetunLogging.PostProcessLine(line)
|
||||
if line == "" {
|
||||
return
|
||||
}
|
||||
switch level {
|
||||
case logging.InfoLevel:
|
||||
logger.Info(line)
|
||||
case logging.WarnLevel:
|
||||
logger.Warn(line)
|
||||
case logging.ErrorLevel:
|
||||
logger.Error(line)
|
||||
}
|
||||
if strings.Contains(line, "Initialization Sequence Completed") {
|
||||
signalConnected()
|
||||
}
|
||||
}, func(err error) {
|
||||
logger.Warn(err)
|
||||
})
|
||||
}
|
||||
|
||||
func onConnected(allSettings settings.Settings, logger logging.Logger, routingConf routing.Routing,
|
||||
portForward, restartUnbound, restartPublicIP func(),
|
||||
) {
|
||||
restartUnbound()
|
||||
restartPublicIP()
|
||||
if allSettings.OpenVPN.Provider.PortForwarding.Enabled {
|
||||
time.AfterFunc(5*time.Second, portForward)
|
||||
}
|
||||
defaultInterface, _, err := routingConf.DefaultRoute()
|
||||
if err != nil {
|
||||
logger.Warn(err)
|
||||
} else {
|
||||
vpnGatewayIP, err := routingConf.VPNGatewayIP(defaultInterface)
|
||||
if err != nil {
|
||||
logger.Warn(err)
|
||||
} else {
|
||||
logger.Info("Gateway VPN IP address: %s", vpnGatewayIP)
|
||||
}
|
||||
}
|
||||
}
|
||||
365
cmd/hostfinder/main.go
Normal file
365
cmd/hostfinder/main.go
Normal file
@@ -0,0 +1,365 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
os.Exit(_main(ctx))
|
||||
}
|
||||
|
||||
func _main(ctx context.Context) int {
|
||||
fmt.Println("Host finder for Cyberghost")
|
||||
resolverAddress := flag.String("resolver", "1.1.1.1", "DNS Resolver IP address to use")
|
||||
flag.Parse()
|
||||
|
||||
resolver := newResolver(*resolverAddress)
|
||||
lookupIP := newLookupIP(resolver)
|
||||
|
||||
const domain = "cg-dialup.net"
|
||||
groups := getCyberghostGroups()
|
||||
countryCodes := getCountryCodes()
|
||||
type result struct {
|
||||
groupName string
|
||||
region string
|
||||
subdomain string
|
||||
exists bool
|
||||
}
|
||||
resultsChannel := make(chan result)
|
||||
const maxGoroutines = 10
|
||||
guard := make(chan struct{}, maxGoroutines)
|
||||
fmt.Print("Subdomains found: ")
|
||||
for groupName, groupID := range groups {
|
||||
for country, countryCode := range countryCodes {
|
||||
go func(groupName, groupID, country, countryCode string) {
|
||||
r := result{
|
||||
region: country,
|
||||
groupName: groupName,
|
||||
subdomain: fmt.Sprintf("%s-%s", groupID, countryCode),
|
||||
}
|
||||
fqdn := fmt.Sprintf("%s.%s", r.subdomain, domain)
|
||||
guard <- struct{}{}
|
||||
ips, err := lookupIP(ctx, fqdn)
|
||||
<-guard
|
||||
if err == nil && len(ips) > 0 {
|
||||
r.exists = true
|
||||
}
|
||||
resultsChannel <- r
|
||||
}(groupName, groupID, country, countryCode)
|
||||
}
|
||||
}
|
||||
results := make([]result, len(groups)*len(countryCodes))
|
||||
for i := range results {
|
||||
results[i] = <-resultsChannel
|
||||
fmt.Printf("%s ", results[i].subdomain)
|
||||
}
|
||||
fmt.Print("\n\n")
|
||||
sort.Slice(results, func(i, j int) bool {
|
||||
return results[i].region < results[j].region
|
||||
})
|
||||
for _, r := range results {
|
||||
if r.exists {
|
||||
// Use in resolver program
|
||||
fmt.Printf("{subdomain: %q, region: %q, group: %q},\n", r.subdomain, r.region, r.groupName)
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func newResolver(ip string) *net.Resolver {
|
||||
return &net.Resolver{
|
||||
PreferGo: true,
|
||||
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
d := net.Dialer{}
|
||||
return d.DialContext(ctx, "udp", net.JoinHostPort(ip, "53"))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type lookupIPFunc func(ctx context.Context, host string) (ips []net.IP, err error)
|
||||
|
||||
func newLookupIP(r *net.Resolver) lookupIPFunc {
|
||||
return func(ctx context.Context, host string) (ips []net.IP, err error) {
|
||||
addresses, err := r.LookupIPAddr(ctx, host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ips = make([]net.IP, len(addresses))
|
||||
for i := range addresses {
|
||||
ips[i] = addresses[i].IP
|
||||
}
|
||||
return ips, nil
|
||||
}
|
||||
}
|
||||
|
||||
func getCyberghostGroups() map[string]string {
|
||||
return map[string]string{
|
||||
"Premium UDP Europe": "87-1",
|
||||
"Premium UDP USA": "94-1",
|
||||
"Premium UDP Asia": "95-1",
|
||||
"NoSpy UDP Europe": "87-8",
|
||||
"Premium TCP Europe": "97-1",
|
||||
"Premium TCP USA": "93-1",
|
||||
"Premium TCP Asia": "96-1",
|
||||
"NoSpy TCP Europe": "97-8",
|
||||
}
|
||||
}
|
||||
|
||||
func getCountryCodes() map[string]string {
|
||||
return map[string]string{
|
||||
"Afghanistan": "af",
|
||||
"Aland Islands": "ax",
|
||||
"Albania": "al",
|
||||
"Algeria": "dz",
|
||||
"American Samoa": "as",
|
||||
"Andorra": "ad",
|
||||
"Angola": "ao",
|
||||
"Anguilla": "ai",
|
||||
"Antarctica": "aq",
|
||||
"Antigua and Barbuda": "ag",
|
||||
"Argentina": "ar",
|
||||
"Armenia": "am",
|
||||
"Aruba": "aw",
|
||||
"Australia": "au",
|
||||
"Austria": "at",
|
||||
"Azerbaijan": "az",
|
||||
"Bahamas": "bs",
|
||||
"Bahrain": "bh",
|
||||
"Bangladesh": "bd",
|
||||
"Barbados": "bb",
|
||||
"Belarus": "by",
|
||||
"Belgium": "be",
|
||||
"Belize": "bz",
|
||||
"Benin": "bj",
|
||||
"Bermuda": "bm",
|
||||
"Bhutan": "bt",
|
||||
"Bolivia": "bo",
|
||||
"Bonaire": "bq",
|
||||
"Bosnia and Herzegovina": "ba",
|
||||
"Botswana": "bw",
|
||||
"Bouvet Island": "bv",
|
||||
"Brazil": "br",
|
||||
"British Indian Ocean Territory": "io",
|
||||
"British Virgin Islands": "vg",
|
||||
"Brunei Darussalam": "bn",
|
||||
"Bulgaria": "bg",
|
||||
"Burkina Faso": "bf",
|
||||
"Burundi": "bi",
|
||||
"Cambodia": "kh",
|
||||
"Cameroon": "cm",
|
||||
"Canada": "ca",
|
||||
"Cape Verde": "cv",
|
||||
"Cayman Islands": "ky",
|
||||
"Central African Republic": "cf",
|
||||
"Chad": "td",
|
||||
"Chile": "cl",
|
||||
"China": "cn",
|
||||
"Christmas Island": "cx",
|
||||
"Cocos Islands": "cc",
|
||||
"Colombia": "co",
|
||||
"Comoros": "km",
|
||||
"Congo": "cg",
|
||||
"Cook Islands": "ck",
|
||||
"Costa Rica": "cr",
|
||||
"Cote d'Ivoire": "ci",
|
||||
"Croatia": "hr",
|
||||
"Cuba": "cu",
|
||||
"Curacao": "cw",
|
||||
"Cyprus": "cy",
|
||||
"Czech Republic": "cz",
|
||||
"Democratic Republic of the Congo": "cd",
|
||||
"Denmark": "dk",
|
||||
"Djibouti": "dj",
|
||||
"Dominica": "dm",
|
||||
"Dominican Republic": "do",
|
||||
"Ecuador": "ec",
|
||||
"Egypt": "eg",
|
||||
"El Salvador": "sv",
|
||||
"Equatorial Guinea": "gq",
|
||||
"Eritrea": "er",
|
||||
"Estonia": "ee",
|
||||
"Ethiopia": "et",
|
||||
"Falkland Islands": "fk",
|
||||
"Faroe Islands": "fo",
|
||||
"Fiji": "fj",
|
||||
"Finland": "fi",
|
||||
"France": "fr",
|
||||
"French Guiana": "gf",
|
||||
"French Polynesia": "pf",
|
||||
"French Southern Territories": "tf",
|
||||
"Gabon": "ga",
|
||||
"Gambia": "gm",
|
||||
"Georgia": "ge",
|
||||
"Germany": "de",
|
||||
"Ghana": "gh",
|
||||
"Gibraltar": "gi",
|
||||
"Greece": "gr",
|
||||
"Greenland": "gl",
|
||||
"Grenada": "gd",
|
||||
"Guadeloupe": "gp",
|
||||
"Guam": "gu",
|
||||
"Guatemala": "gt",
|
||||
"Guernsey": "gg",
|
||||
"Guinea-Bissau": "gw",
|
||||
"Guinea": "gn",
|
||||
"Guyana": "gy",
|
||||
"Haiti": "ht",
|
||||
"Heard Island and McDonald Islands": "hm",
|
||||
"Honduras": "hn",
|
||||
"Hong Kong": "hk",
|
||||
"Hungary": "hu",
|
||||
"Iceland": "is",
|
||||
"India": "in",
|
||||
"Indonesia": "id",
|
||||
"Iran": "ir",
|
||||
"Iraq": "iq",
|
||||
"Ireland": "ie",
|
||||
"Isle of Man": "im",
|
||||
"Israel": "il",
|
||||
"Italy": "it",
|
||||
"Jamaica": "jm",
|
||||
"Japan": "jp",
|
||||
"Jersey": "je",
|
||||
"Jordan": "jo",
|
||||
"Kazakhstan": "kz",
|
||||
"Kenya": "ke",
|
||||
"Kiribati": "ki",
|
||||
"Korea": "kr",
|
||||
"Kuwait": "kw",
|
||||
"Kyrgyzstan": "kg",
|
||||
"Lao People's Democratic Republic": "la",
|
||||
"Latvia": "lv",
|
||||
"Lebanon": "lb",
|
||||
"Lesotho": "ls",
|
||||
"Liberia": "lr",
|
||||
"Libya": "ly",
|
||||
"Liechtenstein": "li",
|
||||
"Lithuania": "lt",
|
||||
"Luxembourg": "lu",
|
||||
"Macao": "mo",
|
||||
"Macedonia": "mk",
|
||||
"Madagascar": "mg",
|
||||
"Malawi": "mw",
|
||||
"Malaysia": "my",
|
||||
"Maldives": "mv",
|
||||
"Mali": "ml",
|
||||
"Malta": "mt",
|
||||
"Marshall Islands": "mh",
|
||||
"Martinique": "mq",
|
||||
"Mauritania": "mr",
|
||||
"Mauritius": "mu",
|
||||
"Mayotte": "yt",
|
||||
"Mexico": "mx",
|
||||
"Micronesia": "fm",
|
||||
"Moldova": "md",
|
||||
"Monaco": "mc",
|
||||
"Mongolia": "mn",
|
||||
"Montenegro": "me",
|
||||
"Montserrat": "ms",
|
||||
"Morocco": "ma",
|
||||
"Mozambique": "mz",
|
||||
"Myanmar": "mm",
|
||||
"Namibia": "na",
|
||||
"Nauru": "nr",
|
||||
"Nepal": "np",
|
||||
"Netherlands": "nl",
|
||||
"New Caledonia": "nc",
|
||||
"New Zealand": "nz",
|
||||
"Nicaragua": "ni",
|
||||
"Niger": "ne",
|
||||
"Nigeria": "ng",
|
||||
"Niue": "nu",
|
||||
"Norfolk Island": "nf",
|
||||
"Northern Mariana Islands": "mp",
|
||||
"Norway": "no",
|
||||
"Oman": "om",
|
||||
"Pakistan": "pk",
|
||||
"Palau": "pw",
|
||||
"Palestine, State of": "ps",
|
||||
"Panama": "pa",
|
||||
"Papua New Guinea": "pg",
|
||||
"Paraguay": "py",
|
||||
"Peru": "pe",
|
||||
"Philippines": "ph",
|
||||
"Pitcairn": "pn",
|
||||
"Poland": "pl",
|
||||
"Portugal": "pt",
|
||||
"Puerto Rico": "pr",
|
||||
"Qatar": "qa",
|
||||
"Reunion": "re",
|
||||
"Romania": "ro",
|
||||
"Russian Federation": "ru",
|
||||
"Rwanda": "rw",
|
||||
"Saint Barthelemy": "bl",
|
||||
"Saint Helena": "sh",
|
||||
"Saint Kitts and Nevis": "kn",
|
||||
"Saint Lucia": "lc",
|
||||
"Saint Martin": "mf",
|
||||
"Saint Pierre and Miquelon": "pm",
|
||||
"Saint Vincent and the Grenadines": "vc",
|
||||
"Samoa": "ws",
|
||||
"San Marino": "sm",
|
||||
"Sao Tome and Principe": "st",
|
||||
"Saudi Arabia": "sa",
|
||||
"Senegal": "sn",
|
||||
"Serbia": "rs",
|
||||
"Seychelles": "sc",
|
||||
"Sierra Leone": "sl",
|
||||
"Singapore": "sg",
|
||||
"Sint Maarten": "sx",
|
||||
"Slovakia": "sk",
|
||||
"Slovenia": "si",
|
||||
"Solomon Islands": "sb",
|
||||
"Somalia": "so",
|
||||
"South Africa": "za",
|
||||
"South Georgia and the South Sandwich Islands": "gs",
|
||||
"South Sudan": "ss",
|
||||
"Spain": "es",
|
||||
"Sri Lanka": "lk",
|
||||
"Sudan": "sd",
|
||||
"Suriname": "sr",
|
||||
"Svalbard and Jan Mayen": "sj",
|
||||
"Swaziland": "sz",
|
||||
"Sweden": "se",
|
||||
"Switzerland": "ch",
|
||||
"Syrian Arab Republic": "sy",
|
||||
"Taiwan": "tw",
|
||||
"Tajikistan": "tj",
|
||||
"Tanzania": "tz",
|
||||
"Thailand": "th",
|
||||
"Timor-Leste": "tl",
|
||||
"Togo": "tg",
|
||||
"Tokelau": "tk",
|
||||
"Tonga": "to",
|
||||
"Trinidad and Tobago": "tt",
|
||||
"Tunisia": "tn",
|
||||
"Turkey": "tr",
|
||||
"Turkmenistan": "tm",
|
||||
"Turks and Caicos Islands": "tc",
|
||||
"Tuvalu": "tv",
|
||||
"Uganda": "ug",
|
||||
"Ukraine": "ua",
|
||||
"United Arab Emirates": "ae",
|
||||
"United Kingdom": "gb",
|
||||
"United States Minor Outlying Islands": "um",
|
||||
"United States": "us",
|
||||
"Uruguay": "uy",
|
||||
"US Virgin Islands": "vi",
|
||||
"Uzbekistan": "uz",
|
||||
"Vanuatu": "vu",
|
||||
"Vatican City State": "va",
|
||||
"Venezuela": "ve",
|
||||
"Vietnam": "vn",
|
||||
"Wallis and Futuna": "wf",
|
||||
"Western Sahara": "eh",
|
||||
"Yemen": "ye",
|
||||
"Zambia": "zm",
|
||||
"Zimbabwe": "zw",
|
||||
}
|
||||
}
|
||||
190
cmd/main.go
190
cmd/main.go
@@ -1,190 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/golibs/command"
|
||||
"github.com/qdm12/golibs/files"
|
||||
libhealthcheck "github.com/qdm12/golibs/healthcheck"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/golibs/network"
|
||||
"github.com/qdm12/golibs/signals"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/dns"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/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/openvpn"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/params"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/pia"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/settings"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/shadowsocks"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/splash"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/tinyproxy"
|
||||
)
|
||||
|
||||
const (
|
||||
uid, gid = 1000, 1000
|
||||
)
|
||||
|
||||
func main() {
|
||||
logger, err := logging.NewLogger(logging.ConsoleEncoding, logging.InfoLevel, -1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if libhealthcheck.Mode(os.Args) {
|
||||
if err := healthcheck.HealthCheck(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
paramsReader := params.NewParamsReader(logger)
|
||||
fmt.Println(splash.Splash(paramsReader))
|
||||
e := env.New(logger)
|
||||
client := network.NewClient(15 * time.Second)
|
||||
// Create configurators
|
||||
fileManager := files.NewFileManager()
|
||||
ovpnConf := openvpn.NewConfigurator(logger, fileManager)
|
||||
dnsConf := dns.NewConfigurator(logger, client, fileManager)
|
||||
firewallConf := firewall.NewConfigurator(logger, fileManager)
|
||||
piaConf := pia.NewConfigurator(client, fileManager, firewallConf, logger)
|
||||
tinyProxyConf := tinyproxy.NewConfigurator(fileManager, logger)
|
||||
shadowsocksConf := shadowsocks.NewConfigurator(fileManager, logger)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
streamMerger := command.NewStreamMerger(ctx)
|
||||
|
||||
e.PrintVersion("OpenVPN", ovpnConf.Version)
|
||||
e.PrintVersion("Unbound", dnsConf.Version)
|
||||
e.PrintVersion("IPtables", firewallConf.Version)
|
||||
e.PrintVersion("TinyProxy", tinyProxyConf.Version)
|
||||
e.PrintVersion("ShadowSocks", shadowsocksConf.Version)
|
||||
|
||||
allSettings, err := settings.GetAllSettings(paramsReader)
|
||||
e.FatalOnError(err)
|
||||
logger.Info(allSettings.String())
|
||||
|
||||
if err := ovpnConf.CheckTUN(); err != nil {
|
||||
logger.Warn(err)
|
||||
err = ovpnConf.CreateTUN()
|
||||
e.FatalOnError(err)
|
||||
}
|
||||
|
||||
err = ovpnConf.WriteAuthFile(allSettings.PIA.User, allSettings.PIA.Password, uid, gid)
|
||||
e.FatalOnError(err)
|
||||
|
||||
// Temporarily reset chain policies allowing Kubernetes sidecar to
|
||||
// successfully restart the container. Without this, the existing rules will
|
||||
// pre-exist, preventing the nslookup of the PIA region address. These will
|
||||
// simply be redundant at Docker runtime as they will already be set this way
|
||||
// Thanks to @npawelek https://github.com/npawelek
|
||||
err = firewallConf.AcceptAll()
|
||||
e.FatalOnError(err)
|
||||
|
||||
go func() {
|
||||
// Blocking line merging reader for all programs: openvpn, tinyproxy, unbound and shadowsocks
|
||||
logger.Info("Launching standard output merger")
|
||||
err = streamMerger.CollectLines(func(line string) { logger.Info(line) })
|
||||
e.FatalOnError(err)
|
||||
}()
|
||||
|
||||
if allSettings.DNS.Enabled {
|
||||
initialDNSToUse := constants.DNSProviderMapping()[allSettings.DNS.Providers[0]]
|
||||
dnsConf.UseDNSInternally(initialDNSToUse.IPs[0])
|
||||
err = dnsConf.DownloadRootHints(uid, gid)
|
||||
e.FatalOnError(err)
|
||||
err = dnsConf.DownloadRootKey(uid, gid)
|
||||
e.FatalOnError(err)
|
||||
err = dnsConf.MakeUnboundConf(allSettings.DNS, uid, gid)
|
||||
e.FatalOnError(err)
|
||||
stream, waitFn, err := dnsConf.Start(allSettings.DNS.VerbosityDetailsLevel)
|
||||
e.FatalOnError(err)
|
||||
go func() {
|
||||
e.FatalOnError(waitFn())
|
||||
}()
|
||||
go streamMerger.Merge("unbound", stream)
|
||||
dnsConf.UseDNSInternally(net.IP{127, 0, 0, 1}) // use Unbound
|
||||
err = dnsConf.UseDNSSystemWide(net.IP{127, 0, 0, 1}) // use Unbound
|
||||
e.FatalOnError(err)
|
||||
err = dnsConf.WaitForUnbound()
|
||||
e.FatalOnError(err)
|
||||
}
|
||||
|
||||
VPNIPs, port, err := piaConf.BuildConf(allSettings.PIA.Region, allSettings.OpenVPN.NetworkProtocol, allSettings.PIA.Encryption, uid, gid)
|
||||
e.FatalOnError(err)
|
||||
|
||||
defaultInterface, defaultGateway, defaultSubnet, err := firewallConf.GetDefaultRoute()
|
||||
e.FatalOnError(err)
|
||||
err = firewallConf.AddRoutesVia(allSettings.Firewall.AllowedSubnets, defaultGateway, defaultInterface)
|
||||
e.FatalOnError(err)
|
||||
err = firewallConf.Clear()
|
||||
e.FatalOnError(err)
|
||||
err = firewallConf.BlockAll()
|
||||
e.FatalOnError(err)
|
||||
err = firewallConf.CreateGeneralRules()
|
||||
e.FatalOnError(err)
|
||||
err = firewallConf.CreateVPNRules(constants.TUN, VPNIPs, defaultInterface, port, allSettings.OpenVPN.NetworkProtocol)
|
||||
e.FatalOnError(err)
|
||||
err = firewallConf.CreateLocalSubnetsRules(defaultSubnet, allSettings.Firewall.AllowedSubnets, defaultInterface)
|
||||
e.FatalOnError(err)
|
||||
|
||||
if allSettings.TinyProxy.Enabled {
|
||||
err = tinyProxyConf.MakeConf(allSettings.TinyProxy.LogLevel, allSettings.TinyProxy.Port, allSettings.TinyProxy.User, allSettings.TinyProxy.Password, uid, gid)
|
||||
e.FatalOnError(err)
|
||||
err = firewallConf.AllowAnyIncomingOnPort(allSettings.TinyProxy.Port)
|
||||
e.FatalOnError(err)
|
||||
stream, waitFn, err := tinyProxyConf.Start()
|
||||
e.FatalOnError(err)
|
||||
go func() {
|
||||
if err := waitFn(); err != nil {
|
||||
logger.Error(err)
|
||||
}
|
||||
}()
|
||||
go streamMerger.Merge("tinyproxy", stream)
|
||||
}
|
||||
|
||||
if allSettings.ShadowSocks.Enabled {
|
||||
err = shadowsocksConf.MakeConf(allSettings.ShadowSocks.Port, allSettings.ShadowSocks.Password, uid, gid)
|
||||
e.FatalOnError(err)
|
||||
err = firewallConf.AllowAnyIncomingOnPort(allSettings.ShadowSocks.Port)
|
||||
e.FatalOnError(err)
|
||||
stream, waitFn, err := shadowsocksConf.Start("0.0.0.0", allSettings.ShadowSocks.Port, allSettings.ShadowSocks.Password, allSettings.ShadowSocks.Log)
|
||||
e.FatalOnError(err)
|
||||
go func() {
|
||||
if err := waitFn(); err != nil {
|
||||
logger.Error(err)
|
||||
}
|
||||
}()
|
||||
go streamMerger.Merge("shadowsocks", stream)
|
||||
}
|
||||
|
||||
if allSettings.PIA.PortForwarding.Enabled {
|
||||
time.AfterFunc(10*time.Second, func() {
|
||||
port, err := piaConf.GetPortForward()
|
||||
if err != nil {
|
||||
logger.Error("port forwarding:", err)
|
||||
}
|
||||
if err := piaConf.WritePortForward(allSettings.PIA.PortForwarding.Filepath, port); err != nil {
|
||||
logger.Error("port forwarding:", err)
|
||||
}
|
||||
if err := piaConf.AllowPortForwardFirewall(constants.TUN, port); err != nil {
|
||||
logger.Error("port forwarding:", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
stream, waitFn, err := ovpnConf.Start()
|
||||
e.FatalOnError(err)
|
||||
go streamMerger.Merge("openvpn", stream)
|
||||
go signals.WaitForExit(func(signal string) int {
|
||||
logger.Warn("Caught OS signal %s, shutting down", signal)
|
||||
time.Sleep(100 * time.Millisecond) // wait for other processes to exit
|
||||
return 0
|
||||
})
|
||||
e.FatalOnError(waitFn())
|
||||
}
|
||||
106
cmd/mapper/main.go
Normal file
106
cmd/mapper/main.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/golibs/network"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
func main() {
|
||||
os.Exit(_main())
|
||||
}
|
||||
|
||||
func _main() int {
|
||||
provider := flag.String("provider", "nordvpn", "VPN provider to map region to IP addresses using their API, can be 'nordvpn'")
|
||||
flag.Parse()
|
||||
|
||||
client := network.NewClient(30 * time.Second) // big file so 30 seconds
|
||||
switch *provider {
|
||||
case "nordvpn":
|
||||
servers, ignoredServers, err := nordvpn(client)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return 1
|
||||
}
|
||||
for _, server := range servers {
|
||||
fmt.Printf(
|
||||
"{Region: %q, Number: %d, TCP: %t, UDP: %t, IP: net.IP{%s}},\n",
|
||||
server.Region, server.Number, server.TCP, server.UDP, strings.ReplaceAll(server.IP.String(), ".", ", "),
|
||||
)
|
||||
}
|
||||
fmt.Print("\n\n")
|
||||
for _, serverName := range ignoredServers {
|
||||
fmt.Printf("ignored server %q because it does not support both UDP and TCP\n", serverName)
|
||||
}
|
||||
default:
|
||||
fmt.Printf("Provider %q is not supported\n", *provider)
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func nordvpn(client network.Client) (servers []models.NordvpnServer, ignoredServers []string, err error) {
|
||||
content, status, err := client.GetContent("https://nordvpn.com/api/server")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
} else if status != http.StatusOK {
|
||||
return nil, nil, fmt.Errorf("HTTP status %d from NordVPN API", status)
|
||||
}
|
||||
response := []struct {
|
||||
IPAddress string `json:"ip_address"`
|
||||
Name string `json:"name"`
|
||||
Country string `json:"country"`
|
||||
Features struct {
|
||||
UDP bool `json:"openvpn_udp"`
|
||||
TCP bool `json:"openvpn_tcp"`
|
||||
} `json:"features"`
|
||||
}{}
|
||||
if err := json.Unmarshal(content, &response); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for _, element := range response {
|
||||
if !element.Features.TCP && !element.Features.UDP {
|
||||
ignoredServers = append(ignoredServers, element.Name)
|
||||
}
|
||||
ip := net.ParseIP(element.IPAddress)
|
||||
if ip == nil {
|
||||
return nil, nil, fmt.Errorf("IP address %q is not valid for server %q", element.IPAddress, element.Name)
|
||||
}
|
||||
i := strings.IndexRune(element.Name, '#')
|
||||
if i < 0 {
|
||||
return nil, nil, fmt.Errorf("No ID in server name %q", element.Name)
|
||||
}
|
||||
idString := element.Name[i+1:]
|
||||
idUint64, err := strconv.ParseUint(idString, 10, 16)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("Bad ID in server name %q", element.Name)
|
||||
}
|
||||
id := uint16(idUint64)
|
||||
server := models.NordvpnServer{
|
||||
Region: element.Country,
|
||||
Number: id,
|
||||
IP: ip,
|
||||
TCP: element.Features.TCP,
|
||||
UDP: element.Features.UDP,
|
||||
}
|
||||
servers = append(servers, server)
|
||||
}
|
||||
sort.Slice(servers, func(i, j int) bool {
|
||||
if servers[i].Region == servers[j].Region {
|
||||
return servers[i].Number < servers[j].Number
|
||||
}
|
||||
return servers[i].Region < servers[j].Region
|
||||
})
|
||||
return servers, ignoredServers, nil
|
||||
}
|
||||
152
cmd/ovpnparser/main.go
Normal file
152
cmd/ovpnparser/main.go
Normal file
@@ -0,0 +1,152 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/golibs/network"
|
||||
)
|
||||
|
||||
func main() {
|
||||
os.Exit(_main())
|
||||
}
|
||||
|
||||
// Find subdomains from .ovpn files contained in a .zip file
|
||||
func _main() int {
|
||||
provider := flag.String("provider", "surfshark", "VPN provider to parse openvpn files for, can be 'surfshark' or 'vyprvpn")
|
||||
flag.Parse()
|
||||
|
||||
var urls []string
|
||||
var suffix string
|
||||
switch *provider {
|
||||
case "surfshark":
|
||||
urls = []string{
|
||||
"https://account.surfshark.com/api/v1/server/configurations",
|
||||
"https://v2uploads.zopim.io/p/2/L/p2LbwLkvfQoSdzOl6VEltzQA6StiZqrs/12500634259669c77012765139bcfe4f4c90db1e.zip",
|
||||
}
|
||||
suffix = ".prod.surfshark.com"
|
||||
case "vyprvpn":
|
||||
urls = []string{
|
||||
"https://support.vyprvpn.com/hc/article_attachments/360052617332/Vypr_OpenVPN_20200320.zip",
|
||||
}
|
||||
suffix = ".vyprvpn.com"
|
||||
default:
|
||||
fmt.Printf("Provider %q is not supported\n", *provider)
|
||||
return 1
|
||||
}
|
||||
contents, err := fetchAndExtractFiles(urls...)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return 1
|
||||
}
|
||||
|
||||
uniqueSubdomainsToFilename := make(map[string]string)
|
||||
for fileName, content := range contents {
|
||||
subdomain, err := extractInformation(content, suffix)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return 1
|
||||
} else if len(subdomain) > 0 {
|
||||
fileName = strings.TrimSuffix(fileName, ".ovpn")
|
||||
fileName = strings.ReplaceAll(fileName, " - ", " ")
|
||||
uniqueSubdomainsToFilename[subdomain] = fileName
|
||||
}
|
||||
}
|
||||
type subdomainFilename struct {
|
||||
subdomain string
|
||||
fileName string
|
||||
}
|
||||
subdomains := make([]subdomainFilename, len(uniqueSubdomainsToFilename))
|
||||
i := 0
|
||||
for subdomain, fileName := range uniqueSubdomainsToFilename {
|
||||
subdomains[i] = subdomainFilename{
|
||||
subdomain: subdomain,
|
||||
fileName: fileName,
|
||||
}
|
||||
i++
|
||||
}
|
||||
sort.Slice(subdomains, func(i, j int) bool {
|
||||
return subdomains[i].subdomain < subdomains[j].subdomain
|
||||
})
|
||||
fmt.Println("Subdomain Filename")
|
||||
for i := range subdomains {
|
||||
fmt.Printf("%s %s\n", subdomains[i].subdomain, subdomains[i].fileName)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func fetchAndExtractFiles(urls ...string) (contents map[string][]byte, err error) {
|
||||
client := network.NewClient(10 * time.Second)
|
||||
contents = make(map[string][]byte)
|
||||
for _, url := range urls {
|
||||
zipBytes, status, err := client.GetContent(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if status != http.StatusOK {
|
||||
return nil, fmt.Errorf("Getting %s results in HTTP status code %d", url, status)
|
||||
}
|
||||
newContents, err := zipExtractAll(zipBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for fileName, content := range newContents {
|
||||
contents[fileName] = content
|
||||
}
|
||||
}
|
||||
return contents, nil
|
||||
}
|
||||
|
||||
func zipExtractAll(zipBytes []byte) (contents map[string][]byte, err error) {
|
||||
r, err := zip.NewReader(bytes.NewReader(zipBytes), int64(len(zipBytes)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
contents = map[string][]byte{}
|
||||
for _, zf := range r.File {
|
||||
fileName := filepath.Base(zf.Name)
|
||||
if !strings.HasSuffix(fileName, ".ovpn") {
|
||||
continue
|
||||
}
|
||||
f, err := zf.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
contents[fileName], err = ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return contents, nil
|
||||
}
|
||||
|
||||
func extractInformation(content []byte, suffix string) (subdomain string, err error) {
|
||||
lines := strings.Split(string(content), "\n")
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "remote ") {
|
||||
words := strings.Fields(line)
|
||||
if len(words) < 2 {
|
||||
return "", fmt.Errorf("not enough words on line %q", line)
|
||||
}
|
||||
host := words[1]
|
||||
if net.ParseIP(host) != nil {
|
||||
return "", nil // ignore IP addresses
|
||||
}
|
||||
return strings.TrimSuffix(host, suffix), nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("could not find remote line in: %s", string(content))
|
||||
}
|
||||
749
cmd/resolver/main.go
Normal file
749
cmd/resolver/main.go
Normal file
@@ -0,0 +1,749 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
os.Exit(_main(ctx))
|
||||
}
|
||||
|
||||
func _main(ctx context.Context) int {
|
||||
resolverAddress := flag.String("resolver", "1.1.1.1", "DNS Resolver IP address to use")
|
||||
provider := flag.String("provider", "pia", "VPN provider to resolve for, 'pia', 'windscribe', 'cyberghost' or 'vyprvpn'")
|
||||
region := flag.String("region", "all", "Comma separated list of VPN provider region names to resolve for, use 'all' to resolve all")
|
||||
flag.Parse()
|
||||
|
||||
resolver := newResolver(*resolverAddress)
|
||||
lookupIP := newLookupIP(resolver)
|
||||
|
||||
var domain string
|
||||
var servers []server
|
||||
switch *provider {
|
||||
case "pia":
|
||||
domain = "privateinternetaccess.com"
|
||||
servers = piaServers()
|
||||
case "windscribe":
|
||||
domain = "windscribe.com"
|
||||
servers = windscribeServers()
|
||||
case "surfshark":
|
||||
domain = "prod.surfshark.com"
|
||||
servers = surfsharkServers()
|
||||
case "cyberghost":
|
||||
domain = "cg-dialup.net"
|
||||
servers = cyberghostServers()
|
||||
case "vyprvpn":
|
||||
domain = "vyprvpn.com"
|
||||
servers = vyprvpnServers()
|
||||
default:
|
||||
fmt.Printf("Provider %q is not supported\n", *provider)
|
||||
return 1
|
||||
}
|
||||
if *region != "all" {
|
||||
regions := strings.Split(*region, ",")
|
||||
uniqueRegions := make(map[string]struct{})
|
||||
for _, r := range regions {
|
||||
uniqueRegions[r] = struct{}{}
|
||||
}
|
||||
for i := range servers {
|
||||
if _, ok := uniqueRegions[servers[i].region]; !ok {
|
||||
servers[i] = servers[len(servers)-1]
|
||||
servers = servers[:len(servers)-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stringChannel := make(chan string)
|
||||
errorChannel := make(chan error)
|
||||
const maxGoroutines = 10
|
||||
guard := make(chan struct{}, maxGoroutines)
|
||||
for _, s := range servers {
|
||||
go func(s server) {
|
||||
guard <- struct{}{}
|
||||
ips, err := resolveRepeat(ctx, lookupIP, s.subdomain+"."+domain, 3)
|
||||
<-guard
|
||||
if err != nil {
|
||||
errorChannel <- err
|
||||
return
|
||||
}
|
||||
stringChannel <- formatLine(*provider, s, ips)
|
||||
}(s)
|
||||
}
|
||||
var lines []string
|
||||
var errors []error
|
||||
for range servers {
|
||||
select {
|
||||
case err := <-errorChannel:
|
||||
errors = append(errors, err)
|
||||
case s := <-stringChannel:
|
||||
lines = append(lines, s)
|
||||
}
|
||||
}
|
||||
sort.Slice(lines, func(i, j int) bool {
|
||||
return lines[i] < lines[j]
|
||||
})
|
||||
for _, s := range lines {
|
||||
fmt.Println(s)
|
||||
}
|
||||
if len(errors) > 0 {
|
||||
fmt.Printf("\n%d errors occurred, described below\n\n", len(errors))
|
||||
for _, err := range errors {
|
||||
fmt.Println(err)
|
||||
}
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func formatLine(provider string, s server, ips []net.IP) string {
|
||||
ipStrings := make([]string, len(ips))
|
||||
for i := range ips {
|
||||
ipStrings[i] = fmt.Sprintf("{%s}", strings.ReplaceAll(ips[i].String(), ".", ", "))
|
||||
}
|
||||
ipString := strings.Join(ipStrings, ", ")
|
||||
switch provider {
|
||||
case "pia":
|
||||
return fmt.Sprintf(
|
||||
"{Region: %q, IPs: []net.IP{%s}},",
|
||||
s.region, ipString,
|
||||
)
|
||||
case "windscribe":
|
||||
return fmt.Sprintf(
|
||||
"{Region: %q, IPs: []net.IP{%s}},",
|
||||
s.region, ipString,
|
||||
)
|
||||
case "surfshark":
|
||||
return fmt.Sprintf(
|
||||
"{Region: %q, IPs: []net.IP{%s}},",
|
||||
s.region, ipString,
|
||||
)
|
||||
case "cyberghost":
|
||||
return fmt.Sprintf(
|
||||
"{Region: %q, Group: %q, IPs: []net.IP{%s}},",
|
||||
s.region, s.group, ipString,
|
||||
)
|
||||
case "vyprvpn":
|
||||
return fmt.Sprintf(
|
||||
"{Region: %q, IPs: []net.IP{%s}},",
|
||||
s.region, ipString,
|
||||
)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type lookupIPFunc func(ctx context.Context, host string) (ips []net.IP, err error)
|
||||
|
||||
func newLookupIP(r *net.Resolver) lookupIPFunc {
|
||||
return func(ctx context.Context, host string) (ips []net.IP, err error) {
|
||||
addresses, err := r.LookupIPAddr(ctx, host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ips = make([]net.IP, len(addresses))
|
||||
for i := range addresses {
|
||||
ips[i] = addresses[i].IP
|
||||
}
|
||||
return ips, nil
|
||||
}
|
||||
}
|
||||
|
||||
func newResolver(ip string) *net.Resolver {
|
||||
return &net.Resolver{
|
||||
PreferGo: true,
|
||||
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
d := net.Dialer{}
|
||||
return d.DialContext(ctx, "udp", net.JoinHostPort(ip, "53"))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resolveRepeat(ctx context.Context, lookupIP lookupIPFunc, host string, n int) (ips []net.IP, err error) {
|
||||
for i := 0; i < n; i++ {
|
||||
newIPs, err := lookupIP(ctx, host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ips = append(ips, newIPs...)
|
||||
}
|
||||
return uniqueSortedIPs(ips), nil
|
||||
}
|
||||
|
||||
func uniqueSortedIPs(ips []net.IP) []net.IP {
|
||||
uniqueIPs := make(map[string]struct{})
|
||||
for _, ip := range ips {
|
||||
uniqueIPs[ip.String()] = struct{}{}
|
||||
}
|
||||
ips = make([]net.IP, len(uniqueIPs))
|
||||
i := 0
|
||||
for ip := range uniqueIPs {
|
||||
ips[i] = net.ParseIP(ip)
|
||||
i++
|
||||
}
|
||||
sort.Slice(ips, func(i, j int) bool {
|
||||
return bytes.Compare(ips[i], ips[j]) < 0
|
||||
})
|
||||
return ips
|
||||
}
|
||||
|
||||
type server struct {
|
||||
subdomain string
|
||||
region string
|
||||
group string // only for cyberghost
|
||||
}
|
||||
|
||||
func piaServers() []server {
|
||||
return []server{
|
||||
{subdomain: "au-melbourne", region: "AU Melbourne"},
|
||||
{subdomain: "au-perth", region: "AU Perth"},
|
||||
{subdomain: "au-sydney", region: "AU Sydney"},
|
||||
{subdomain: "austria", region: "Austria"},
|
||||
{subdomain: "belgium", region: "Belgium"},
|
||||
{subdomain: "ca-montreal", region: "CA Montreal"},
|
||||
{subdomain: "ca-toronto", region: "CA Toronto"},
|
||||
{subdomain: "ca-vancouver", region: "CA Vancouver"},
|
||||
{subdomain: "czech", region: "Czech Republic"},
|
||||
{subdomain: "de-berlin", region: "DE Berlin"},
|
||||
{subdomain: "de-frankfurt", region: "DE Frankfurt"},
|
||||
{subdomain: "denmark", region: "Denmark"},
|
||||
{subdomain: "fi", region: "Finlan"},
|
||||
{subdomain: "france", region: "France"},
|
||||
{subdomain: "hk", region: "Hong Kong"},
|
||||
{subdomain: "hungary", region: "Hungary"},
|
||||
{subdomain: "in", region: "India"},
|
||||
{subdomain: "ireland", region: "Ireland"},
|
||||
{subdomain: "israel", region: "Israel"},
|
||||
{subdomain: "italy", region: "Italy"},
|
||||
{subdomain: "japan", region: "Japan"},
|
||||
{subdomain: "lu", region: "Luxembourg"},
|
||||
{subdomain: "mexico", region: "Mexico"},
|
||||
{subdomain: "nl", region: "Netherlands"},
|
||||
{subdomain: "nz", region: "New Zealand"},
|
||||
{subdomain: "no", region: "Norway"},
|
||||
{subdomain: "poland", region: "Poland"},
|
||||
{subdomain: "ro", region: "Romania"},
|
||||
{subdomain: "sg", region: "Singapore"},
|
||||
{subdomain: "spain", region: "Spain"},
|
||||
{subdomain: "sweden", region: "Sweden"},
|
||||
{subdomain: "swiss", region: "Switzerland"},
|
||||
{subdomain: "ae", region: "UAE"},
|
||||
{subdomain: "uk-london", region: "UK London"},
|
||||
{subdomain: "uk-manchester", region: "UK Manchester"},
|
||||
{subdomain: "uk-southampton", region: "UK Southampton"},
|
||||
{subdomain: "us-atlanta", region: "US Atlanta"},
|
||||
{subdomain: "us-california", region: "US California"},
|
||||
{subdomain: "us-chicago", region: "US Chicago"},
|
||||
{subdomain: "us-denver", region: "US Denver"},
|
||||
{subdomain: "us-east", region: "US East"},
|
||||
{subdomain: "us-florida", region: "US Florida"},
|
||||
{subdomain: "us-houston", region: "US Houston"},
|
||||
{subdomain: "us-lasvegas", region: "US Las Vegas"},
|
||||
{subdomain: "us-newyorkcity", region: "US New York City"},
|
||||
{subdomain: "us-seattle", region: "US Seattle"},
|
||||
{subdomain: "us-siliconvalley", region: "US Silicon Valley"},
|
||||
{subdomain: "us-texas", region: "US Texas"},
|
||||
{subdomain: "us-washingtondc", region: "US Washington DC"},
|
||||
{subdomain: "us-west", region: "US West"},
|
||||
}
|
||||
}
|
||||
|
||||
func windscribeServers() []server {
|
||||
return []server{
|
||||
{subdomain: "al", region: "Albania"},
|
||||
{subdomain: "ar", region: "Argentina"},
|
||||
{subdomain: "au", region: "Australia"},
|
||||
{subdomain: "at", region: "Austria"},
|
||||
{subdomain: "az", region: "Azerbaijan"},
|
||||
{subdomain: "be", region: "Belgium"},
|
||||
{subdomain: "ba", region: "Bosnia"},
|
||||
{subdomain: "br", region: "Brazil"},
|
||||
{subdomain: "bg", region: "Bulgaria"},
|
||||
{subdomain: "ca", region: "Canada East"},
|
||||
{subdomain: "ca-west", region: "Canada West"},
|
||||
{subdomain: "co", region: "Colombia"},
|
||||
{subdomain: "hr", region: "Croatia"},
|
||||
{subdomain: "cy", region: "Cyprus"},
|
||||
{subdomain: "cz", region: "Czech republic"},
|
||||
{subdomain: "dk", region: "Denmark"},
|
||||
{subdomain: "ee", region: "Estonia"},
|
||||
{subdomain: "aq", region: "Fake antarctica"},
|
||||
{subdomain: "fi", region: "Finland"},
|
||||
{subdomain: "fr", region: "France"},
|
||||
{subdomain: "ge", region: "Georgia"},
|
||||
{subdomain: "de", region: "Germany"},
|
||||
{subdomain: "gr", region: "Greece"},
|
||||
{subdomain: "hk", region: "Hong kong"},
|
||||
{subdomain: "hu", region: "Hungary"},
|
||||
{subdomain: "is", region: "Iceland"},
|
||||
{subdomain: "in", region: "India"},
|
||||
{subdomain: "id", region: "Indonesia"},
|
||||
{subdomain: "ie", region: "Ireland"},
|
||||
{subdomain: "il", region: "Israel"},
|
||||
{subdomain: "it", region: "Italy"},
|
||||
{subdomain: "jp", region: "Japan"},
|
||||
{subdomain: "lv", region: "Latvia"},
|
||||
{subdomain: "lt", region: "Lithuania"},
|
||||
{subdomain: "mk", region: "Macedonia"},
|
||||
{subdomain: "my", region: "Malaysia"},
|
||||
{subdomain: "mx", region: "Mexico"},
|
||||
{subdomain: "md", region: "Moldova"},
|
||||
{subdomain: "nl", region: "Netherlands"},
|
||||
{subdomain: "nz", region: "New zealand"},
|
||||
{subdomain: "no", region: "Norway"},
|
||||
{subdomain: "ph", region: "Philippines"},
|
||||
{subdomain: "pl", region: "Poland"},
|
||||
{subdomain: "pt", region: "Portugal"},
|
||||
{subdomain: "ro", region: "Romania"},
|
||||
{subdomain: "ru", region: "Russia"},
|
||||
{subdomain: "rs", region: "Serbia"},
|
||||
{subdomain: "sg", region: "Singapore"},
|
||||
{subdomain: "sk", region: "Slovakia"},
|
||||
{subdomain: "si", region: "Slovenia"},
|
||||
{subdomain: "za", region: "South Africa"},
|
||||
{subdomain: "kr", region: "South Korea"},
|
||||
{subdomain: "es", region: "Spain"},
|
||||
{subdomain: "se", region: "Sweden"},
|
||||
{subdomain: "ch", region: "Switzerland"},
|
||||
{subdomain: "th", region: "Thailand"},
|
||||
{subdomain: "tn", region: "Tunisia"},
|
||||
{subdomain: "tr", region: "Turkey"},
|
||||
{subdomain: "ua", region: "Ukraine"},
|
||||
{subdomain: "ae", region: "United Arab Emirates"},
|
||||
{subdomain: "uk", region: "United Kingdom"},
|
||||
{subdomain: "us-central", region: "US Central"},
|
||||
{subdomain: "us-east", region: "US East"},
|
||||
{subdomain: "us-west", region: "US West"},
|
||||
{subdomain: "vn", region: "Vietnam"},
|
||||
{subdomain: "wf-ca", region: "Windflix CA"},
|
||||
{subdomain: "wf-jp", region: "Windflix JP"},
|
||||
{subdomain: "wf-uk", region: "Windflix UK"},
|
||||
{subdomain: "wf-us", region: "Windflix US"},
|
||||
}
|
||||
}
|
||||
|
||||
func surfsharkServers() []server {
|
||||
return []server{
|
||||
{subdomain: "ae-dub", region: "United Arab Emirates"},
|
||||
{subdomain: "al-tia", region: "Albania"},
|
||||
{subdomain: "at-vie", region: "Austria"},
|
||||
{subdomain: "au-adl", region: "Australia Adelaide"},
|
||||
{subdomain: "au-bne", region: "Australia Brisbane"},
|
||||
{subdomain: "au-mel", region: "Australia Melbourne"},
|
||||
{subdomain: "au-per", region: "Australia Perth"},
|
||||
{subdomain: "au-syd", region: "Australia Sydney"},
|
||||
{subdomain: "au-us", region: "Australia US"},
|
||||
{subdomain: "az-bak", region: "Azerbaijan"},
|
||||
{subdomain: "ba-sjj", region: "Bosnia and Herzegovina"},
|
||||
{subdomain: "be-bru", region: "Belgium"},
|
||||
{subdomain: "bg-sof", region: "Bulgaria"},
|
||||
{subdomain: "br-sao", region: "Brazil"},
|
||||
{subdomain: "ca-mon", region: "Canada Montreal"},
|
||||
{subdomain: "ca-tor", region: "Canada Toronto"},
|
||||
{subdomain: "ca-us", region: "Canada US"},
|
||||
{subdomain: "ca-van", region: "Canada Vancouver"},
|
||||
{subdomain: "ch-zur", region: "Switzerland"},
|
||||
{subdomain: "cl-san", region: "Chile"},
|
||||
{subdomain: "co-bog", region: "Colombia"},
|
||||
{subdomain: "cr-sjn", region: "Costa Rica"},
|
||||
{subdomain: "cy-nic", region: "Cyprus"},
|
||||
{subdomain: "cz-prg", region: "Czech Republic"},
|
||||
{subdomain: "de-ber", region: "Germany Berlin"},
|
||||
{subdomain: "de-fra", region: "Germany Frankfurt am Main"},
|
||||
{subdomain: "de-fra-st001", region: "Germany Frankfurt am Main st001"},
|
||||
{subdomain: "de-fra-st002", region: "Germany Frankfurt am Main st002"},
|
||||
{subdomain: "de-fra-st003", region: "Germany Frankfurt am Main st003"},
|
||||
{subdomain: "de-muc", region: "Germany Munich"},
|
||||
{subdomain: "de-nue", region: "Germany Nuremberg"},
|
||||
{subdomain: "de-sg", region: "Germany Singapour"},
|
||||
{subdomain: "de-uk", region: "Germany UK"},
|
||||
{subdomain: "dk-cph", region: "Denmark"},
|
||||
{subdomain: "ee-tll", region: "Estonia"},
|
||||
{subdomain: "es-bcn", region: "Spain Barcelona"},
|
||||
{subdomain: "es-mad", region: "Spain Madrid"},
|
||||
{subdomain: "es-vlc", region: "Spain Valencia"},
|
||||
{subdomain: "fi-hel", region: "Finland"},
|
||||
{subdomain: "fr-bod", region: "France Bordeaux"},
|
||||
{subdomain: "fr-mrs", region: "France Marseilles"},
|
||||
{subdomain: "fr-par", region: "France Paris"},
|
||||
{subdomain: "fr-se", region: "France Sweden"},
|
||||
{subdomain: "gr-ath", region: "Greece"},
|
||||
{subdomain: "hk-hkg", region: "Hong Kong"},
|
||||
{subdomain: "hr-zag", region: "Croatia"},
|
||||
{subdomain: "hu-bud", region: "Hungary"},
|
||||
{subdomain: "id-jak", region: "Indonesia"},
|
||||
{subdomain: "ie-dub", region: "Ireland"},
|
||||
{subdomain: "il-tlv", region: "Israel"},
|
||||
{subdomain: "in-chn", region: "India Chennai"},
|
||||
{subdomain: "in-idr", region: "India Indore"},
|
||||
{subdomain: "in-mum", region: "India Mumbai"},
|
||||
{subdomain: "in-uk", region: "India UK"},
|
||||
{subdomain: "is-rkv", region: "Iceland"},
|
||||
{subdomain: "it-mil", region: "Italy Milan"},
|
||||
{subdomain: "it-rom", region: "Italy Rome"},
|
||||
{subdomain: "jp-tok", region: "Japan Tokyo"},
|
||||
{subdomain: "jp-tok-st001", region: "Japan Tokyo st001"},
|
||||
{subdomain: "jp-tok-st002", region: "Japan Tokyo st002"},
|
||||
{subdomain: "jp-tok-st003", region: "Japan Tokyo st003"},
|
||||
{subdomain: "jp-tok-st004", region: "Japan Tokyo st004"},
|
||||
{subdomain: "jp-tok-st005", region: "Japan Tokyo st005"},
|
||||
{subdomain: "jp-tok-st006", region: "Japan Tokyo st006"},
|
||||
{subdomain: "jp-tok-st007", region: "Japan Tokyo st007"},
|
||||
{subdomain: "kr-seo", region: "Korea"},
|
||||
{subdomain: "kz-ura", region: "Kazakhstan"},
|
||||
{subdomain: "lu-ste", region: "Luxembourg"},
|
||||
{subdomain: "lv-rig", region: "Latvia"},
|
||||
{subdomain: "ly-tip", region: "Libya"},
|
||||
{subdomain: "md-chi", region: "Moldova"},
|
||||
{subdomain: "mk-skp", region: "North Macedonia"},
|
||||
{subdomain: "my-kul", region: "Malaysia"},
|
||||
{subdomain: "ng-lag", region: "Nigeria"},
|
||||
{subdomain: "nl-ams", region: "Netherlands Amsterdam"},
|
||||
{subdomain: "nl-ams-st001", region: "Netherlands Amsterdam st001"},
|
||||
{subdomain: "nl-us", region: "Netherlands US"},
|
||||
{subdomain: "no-osl", region: "Norway"},
|
||||
{subdomain: "nz-akl", region: "New Zealand"},
|
||||
{subdomain: "ph-mnl", region: "Philippines"},
|
||||
{subdomain: "pl-gdn", region: "Poland Gdansk"},
|
||||
{subdomain: "pl-waw", region: "Poland Warsaw"},
|
||||
{subdomain: "pt-lis", region: "Portugal Lisbon"},
|
||||
{subdomain: "pt-lou", region: "Portugal Loule"},
|
||||
{subdomain: "pt-opo", region: "Portugal Porto"},
|
||||
{subdomain: "py-asu", region: "Paraguay"},
|
||||
{subdomain: "ro-buc", region: "Romania"},
|
||||
{subdomain: "rs-beg", region: "Serbia"},
|
||||
{subdomain: "ru-mos", region: "Russia Moscow"},
|
||||
{subdomain: "ru-spt", region: "Russia St. Petersburg"},
|
||||
{subdomain: "se-sto", region: "Sweden"},
|
||||
{subdomain: "sg-hk", region: "Singapore Hong Kong"},
|
||||
{subdomain: "sg-nl", region: "Singapore Netherlands"},
|
||||
{subdomain: "sg-sng", region: "Singapore"},
|
||||
{subdomain: "sg-sng-st001", region: "Singapore st001"},
|
||||
{subdomain: "sg-sng-st002", region: "Singapore st002"},
|
||||
{subdomain: "sg-sng-st003", region: "Singapore st003"},
|
||||
{subdomain: "sg-sng-st004", region: "Singapore st004"},
|
||||
{subdomain: "si-lju", region: "Slovenia"},
|
||||
{subdomain: "sk-bts", region: "Slovekia"},
|
||||
{subdomain: "th-bkk", region: "Thailand"},
|
||||
{subdomain: "tr-bur", region: "Turkey"},
|
||||
{subdomain: "tw-tai", region: "Taiwan"},
|
||||
{subdomain: "ua-iev", region: "Ukraine"},
|
||||
{subdomain: "uk-de", region: "UK Germany"},
|
||||
{subdomain: "uk-fr", region: "UK France"},
|
||||
{subdomain: "uk-gla", region: "UK Glasgow"},
|
||||
{subdomain: "uk-lon", region: "UK London"},
|
||||
{subdomain: "uk-lon-st001", region: "UK London st001"},
|
||||
{subdomain: "uk-lon-st002", region: "UK London st002"},
|
||||
{subdomain: "uk-lon-st003", region: "UK London st003"},
|
||||
{subdomain: "uk-lon-st004", region: "UK London st004"},
|
||||
{subdomain: "uk-lon-st005", region: "UK London st005"},
|
||||
{subdomain: "uk-man", region: "UK Manchester"},
|
||||
{subdomain: "us-atl", region: "US Atlanta"},
|
||||
{subdomain: "us-bdn", region: "US Bend"},
|
||||
{subdomain: "us-bos", region: "US Boston"},
|
||||
{subdomain: "us-buf", region: "US Buffalo"},
|
||||
{subdomain: "us-chi", region: "US Chicago"},
|
||||
{subdomain: "us-clt", region: "US Charlotte"},
|
||||
{subdomain: "us-dal", region: "US Dallas"},
|
||||
{subdomain: "us-den", region: "US Denver"},
|
||||
{subdomain: "us-dtw", region: "US Gahanna"},
|
||||
{subdomain: "us-hou", region: "US Houston"},
|
||||
{subdomain: "us-kan", region: "US Kansas City"},
|
||||
{subdomain: "us-las", region: "US Las Vegas"},
|
||||
{subdomain: "us-lax", region: "US Los Angeles"},
|
||||
{subdomain: "us-ltm", region: "US Latham"},
|
||||
{subdomain: "us-mia", region: "US Miami"},
|
||||
{subdomain: "us-mnz", region: "US Maryland"},
|
||||
{subdomain: "us-nl", region: "US Netherlands"},
|
||||
{subdomain: "us-nyc", region: "US New York City"},
|
||||
{subdomain: "us-nyc-mp001", region: "US New York City mp001"},
|
||||
{subdomain: "us-nyc-st001", region: "US New York City st001"},
|
||||
{subdomain: "us-nyc-st002", region: "US New York City st002"},
|
||||
{subdomain: "us-nyc-st003", region: "US New York City st003"},
|
||||
{subdomain: "us-nyc-st004", region: "US New York City st004"},
|
||||
{subdomain: "us-nyc-st005", region: "US New York City st005"},
|
||||
{subdomain: "us-orl", region: "US Orlando"},
|
||||
{subdomain: "us-phx", region: "US Phoenix"},
|
||||
{subdomain: "us-pt", region: "US Portugal"},
|
||||
{subdomain: "us-sea", region: "US Seatle"},
|
||||
{subdomain: "us-sfo", region: "US San Francisco"},
|
||||
{subdomain: "us-slc", region: "US Salt Lake City"},
|
||||
{subdomain: "us-stl", region: "US Saint Louis"},
|
||||
{subdomain: "us-tpa", region: "US Tampa"},
|
||||
{subdomain: "vn-hcm", region: "Vietnam"},
|
||||
{subdomain: "za-jnb", region: "South Africa"},
|
||||
}
|
||||
}
|
||||
|
||||
func cyberghostServers() []server {
|
||||
return []server{
|
||||
{subdomain: "97-1-al", region: "Albania", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-al", region: "Albania", group: "Premium UDP Europe"},
|
||||
{subdomain: "87-1-dz", region: "Algeria", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-dz", region: "Algeria", group: "Premium TCP Europe"},
|
||||
{subdomain: "97-1-ad", region: "Andorra", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-ad", region: "Andorra", group: "Premium UDP Europe"},
|
||||
{subdomain: "94-1-ar", region: "Argentina", group: "Premium UDP USA"},
|
||||
{subdomain: "93-1-ar", region: "Argentina", group: "Premium TCP USA"},
|
||||
{subdomain: "87-1-am", region: "Armenia", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-am", region: "Armenia", group: "Premium TCP Europe"},
|
||||
{subdomain: "95-1-au", region: "Australia", group: "Premium UDP Asia"},
|
||||
{subdomain: "96-1-au", region: "Australia", group: "Premium TCP Asia"},
|
||||
{subdomain: "97-1-at", region: "Austria", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-at", region: "Austria", group: "Premium UDP Europe"},
|
||||
{subdomain: "93-1-bs", region: "Bahamas", group: "Premium TCP USA"},
|
||||
{subdomain: "94-1-bs", region: "Bahamas", group: "Premium UDP USA"},
|
||||
{subdomain: "95-1-bd", region: "Bangladesh", group: "Premium UDP Asia"},
|
||||
{subdomain: "96-1-bd", region: "Bangladesh", group: "Premium TCP Asia"},
|
||||
{subdomain: "97-1-by", region: "Belarus", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-by", region: "Belarus", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-be", region: "Belgium", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-be", region: "Belgium", group: "Premium UDP Europe"},
|
||||
{subdomain: "87-1-ba", region: "Bosnia and Herzegovina", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-ba", region: "Bosnia and Herzegovina", group: "Premium TCP Europe"},
|
||||
{subdomain: "94-1-br", region: "Brazil", group: "Premium UDP USA"},
|
||||
{subdomain: "93-1-br", region: "Brazil", group: "Premium TCP USA"},
|
||||
{subdomain: "87-1-bg", region: "Bulgaria", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-bg", region: "Bulgaria", group: "Premium TCP Europe"},
|
||||
{subdomain: "96-1-kh", region: "Cambodia", group: "Premium TCP Asia"},
|
||||
{subdomain: "95-1-kh", region: "Cambodia", group: "Premium UDP Asia"},
|
||||
{subdomain: "93-1-ca", region: "Canada", group: "Premium TCP USA"},
|
||||
{subdomain: "94-1-ca", region: "Canada", group: "Premium UDP USA"},
|
||||
{subdomain: "93-1-cl", region: "Chile", group: "Premium TCP USA"},
|
||||
{subdomain: "94-1-cl", region: "Chile", group: "Premium UDP USA"},
|
||||
{subdomain: "96-1-cn", region: "China", group: "Premium TCP Asia"},
|
||||
{subdomain: "95-1-cn", region: "China", group: "Premium UDP Asia"},
|
||||
{subdomain: "94-1-co", region: "Colombia", group: "Premium UDP USA"},
|
||||
{subdomain: "93-1-co", region: "Colombia", group: "Premium TCP USA"},
|
||||
{subdomain: "93-1-cr", region: "Costa Rica", group: "Premium TCP USA"},
|
||||
{subdomain: "94-1-cr", region: "Costa Rica", group: "Premium UDP USA"},
|
||||
{subdomain: "87-1-cy", region: "Cyprus", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-cy", region: "Cyprus", group: "Premium TCP Europe"},
|
||||
{subdomain: "97-1-cz", region: "Czech Republic", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-cz", region: "Czech Republic", group: "Premium UDP Europe"},
|
||||
{subdomain: "87-1-dk", region: "Denmark", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-dk", region: "Denmark", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-eg", region: "Egypt", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-eg", region: "Egypt", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-ee", region: "Estonia", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-ee", region: "Estonia", group: "Premium TCP Europe"},
|
||||
{subdomain: "97-1-fi", region: "Finland", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-fi", region: "Finland", group: "Premium UDP Europe"},
|
||||
{subdomain: "87-1-fr", region: "France", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-fr", region: "France", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-ge", region: "Georgia", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-ge", region: "Georgia", group: "Premium TCP Europe"},
|
||||
{subdomain: "97-1-de", region: "Germany", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-de", region: "Germany", group: "Premium UDP Europe"},
|
||||
{subdomain: "87-1-gr", region: "Greece", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-gr", region: "Greece", group: "Premium TCP Europe"},
|
||||
{subdomain: "97-1-gl", region: "Greenland", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-gl", region: "Greenland", group: "Premium UDP Europe"},
|
||||
{subdomain: "96-1-hk", region: "Hong Kong", group: "Premium TCP Asia"},
|
||||
{subdomain: "95-1-hk", region: "Hong Kong", group: "Premium UDP Asia"},
|
||||
{subdomain: "87-1-hu", region: "Hungary", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-hu", region: "Hungary", group: "Premium TCP Europe"},
|
||||
{subdomain: "97-1-is", region: "Iceland", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-is", region: "Iceland", group: "Premium UDP Europe"},
|
||||
{subdomain: "87-1-in", region: "India", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-in", region: "India", group: "Premium TCP Europe"},
|
||||
{subdomain: "95-1-id", region: "Indonesia", group: "Premium UDP Asia"},
|
||||
{subdomain: "96-1-id", region: "Indonesia", group: "Premium TCP Asia"},
|
||||
{subdomain: "87-1-ir", region: "Iran", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-ir", region: "Iran", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-ie", region: "Ireland", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-ie", region: "Ireland", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-im", region: "Isle of Man", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-im", region: "Isle of Man", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-il", region: "Israel", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-il", region: "Israel", group: "Premium TCP Europe"},
|
||||
{subdomain: "97-1-it", region: "Italy", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-it", region: "Italy", group: "Premium UDP Europe"},
|
||||
{subdomain: "95-1-jp", region: "Japan", group: "Premium UDP Asia"},
|
||||
{subdomain: "96-1-jp", region: "Japan", group: "Premium TCP Asia"},
|
||||
{subdomain: "97-1-kz", region: "Kazakhstan", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-kz", region: "Kazakhstan", group: "Premium UDP Europe"},
|
||||
{subdomain: "95-1-ke", region: "Kenya", group: "Premium UDP Asia"},
|
||||
{subdomain: "96-1-ke", region: "Kenya", group: "Premium TCP Asia"},
|
||||
{subdomain: "95-1-kr", region: "Korea", group: "Premium UDP Asia"},
|
||||
{subdomain: "96-1-kr", region: "Korea", group: "Premium TCP Asia"},
|
||||
{subdomain: "97-1-lv", region: "Latvia", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-lv", region: "Latvia", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-li", region: "Liechtenstein", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-li", region: "Liechtenstein", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-lt", region: "Lithuania", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-lt", region: "Lithuania", group: "Premium UDP Europe"},
|
||||
{subdomain: "87-1-lu", region: "Luxembourg", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-lu", region: "Luxembourg", group: "Premium TCP Europe"},
|
||||
{subdomain: "96-1-mo", region: "Macao", group: "Premium TCP Asia"},
|
||||
{subdomain: "95-1-mo", region: "Macao", group: "Premium UDP Asia"},
|
||||
{subdomain: "97-1-mk", region: "Macedonia", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-mk", region: "Macedonia", group: "Premium UDP Europe"},
|
||||
{subdomain: "95-1-my", region: "Malaysia", group: "Premium UDP Asia"},
|
||||
{subdomain: "96-1-my", region: "Malaysia", group: "Premium TCP Asia"},
|
||||
{subdomain: "87-1-mt", region: "Malta", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-mt", region: "Malta", group: "Premium TCP Europe"},
|
||||
{subdomain: "93-1-mx", region: "Mexico", group: "Premium TCP USA"},
|
||||
{subdomain: "94-1-mx", region: "Mexico", group: "Premium UDP USA"},
|
||||
{subdomain: "87-1-md", region: "Moldova", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-md", region: "Moldova", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-mc", region: "Monaco", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-mc", region: "Monaco", group: "Premium TCP Europe"},
|
||||
{subdomain: "96-1-mn", region: "Mongolia", group: "Premium TCP Asia"},
|
||||
{subdomain: "95-1-mn", region: "Mongolia", group: "Premium UDP Asia"},
|
||||
{subdomain: "87-1-me", region: "Montenegro", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-me", region: "Montenegro", group: "Premium TCP Europe"},
|
||||
{subdomain: "97-1-ma", region: "Morocco", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-ma", region: "Morocco", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-nl", region: "Netherlands", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-nl", region: "Netherlands", group: "Premium UDP Europe"},
|
||||
{subdomain: "95-1-nz", region: "New Zealand", group: "Premium UDP Asia"},
|
||||
{subdomain: "96-1-nz", region: "New Zealand", group: "Premium TCP Asia"},
|
||||
{subdomain: "87-1-ng", region: "Nigeria", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-ng", region: "Nigeria", group: "Premium TCP Europe"},
|
||||
{subdomain: "97-1-no", region: "Norway", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-no", region: "Norway", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-pk", region: "Pakistan", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-pk", region: "Pakistan", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-pa", region: "Panama", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-pa", region: "Panama", group: "Premium UDP Europe"},
|
||||
{subdomain: "95-1-ph", region: "Philippines", group: "Premium UDP Asia"},
|
||||
{subdomain: "96-1-ph", region: "Philippines", group: "Premium TCP Asia"},
|
||||
{subdomain: "97-1-pl", region: "Poland", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-pl", region: "Poland", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-pt", region: "Portugal", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-pt", region: "Portugal", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-qa", region: "Qatar", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-qa", region: "Qatar", group: "Premium UDP Europe"},
|
||||
{subdomain: "87-1-ro", region: "Romania", group: "Premium UDP Europe"},
|
||||
{subdomain: "87-8-ro", region: "Romania", group: "NoSpy UDP Europe"},
|
||||
{subdomain: "97-8-ro", region: "Romania", group: "NoSpy TCP Europe"},
|
||||
{subdomain: "97-1-ro", region: "Romania", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-ru", region: "Russian Federation", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-ru", region: "Russian Federation", group: "Premium TCP Europe"},
|
||||
{subdomain: "97-1-sa", region: "Saudi Arabia", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-sa", region: "Saudi Arabia", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-rs", region: "Serbia", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-rs", region: "Serbia", group: "Premium UDP Europe"},
|
||||
{subdomain: "95-1-sg", region: "Singapore", group: "Premium UDP Asia"},
|
||||
{subdomain: "96-1-sg", region: "Singapore", group: "Premium TCP Asia"},
|
||||
{subdomain: "87-1-sk", region: "Slovakia", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-sk", region: "Slovakia", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-si", region: "Slovenia", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-si", region: "Slovenia", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-za", region: "South Africa", group: "Premium UDP Europe"},
|
||||
{subdomain: "95-1-za", region: "South Africa", group: "Premium UDP Asia"},
|
||||
{subdomain: "97-1-za", region: "South Africa", group: "Premium TCP Europe"},
|
||||
{subdomain: "96-1-za", region: "South Africa", group: "Premium TCP Asia"},
|
||||
{subdomain: "97-1-es", region: "Spain", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-es", region: "Spain", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-lk", region: "Sri Lanka", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-lk", region: "Sri Lanka", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-se", region: "Sweden", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-se", region: "Sweden", group: "Premium UDP Europe"},
|
||||
{subdomain: "87-1-ch", region: "Switzerland", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-ch", region: "Switzerland", group: "Premium TCP Europe"},
|
||||
{subdomain: "96-1-tw", region: "Taiwan", group: "Premium TCP Asia"},
|
||||
{subdomain: "95-1-tw", region: "Taiwan", group: "Premium UDP Asia"},
|
||||
{subdomain: "96-1-th", region: "Thailand", group: "Premium TCP Asia"},
|
||||
{subdomain: "95-1-th", region: "Thailand", group: "Premium UDP Asia"},
|
||||
{subdomain: "87-1-tr", region: "Turkey", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-tr", region: "Turkey", group: "Premium TCP Europe"},
|
||||
{subdomain: "97-1-ua", region: "Ukraine", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-ua", region: "Ukraine", group: "Premium UDP Europe"},
|
||||
{subdomain: "87-1-ae", region: "United Arab Emirates", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-ae", region: "United Arab Emirates", group: "Premium TCP Europe"},
|
||||
{subdomain: "97-1-gb", region: "United Kingdom", group: "Premium TCP Europe"},
|
||||
{subdomain: "87-1-gb", region: "United Kingdom", group: "Premium UDP Europe"},
|
||||
{subdomain: "94-1-us", region: "United States", group: "Premium UDP USA"},
|
||||
{subdomain: "93-1-us", region: "United States", group: "Premium TCP USA"},
|
||||
{subdomain: "87-1-ve", region: "Venezuela", group: "Premium UDP Europe"},
|
||||
{subdomain: "97-1-ve", region: "Venezuela", group: "Premium TCP Europe"},
|
||||
{subdomain: "95-1-vn", region: "Vietnam", group: "Premium UDP Asia"},
|
||||
{subdomain: "96-1-vn", region: "Vietnam", group: "Premium TCP Asia"},
|
||||
}
|
||||
}
|
||||
|
||||
func vyprvpnServers() []server {
|
||||
return []server{
|
||||
{subdomain: "ae1", region: "Dubai"},
|
||||
{subdomain: "ar1", region: "Argentina"},
|
||||
{subdomain: "at1", region: "Austria"},
|
||||
{subdomain: "au1", region: "Australia Sydney"},
|
||||
{subdomain: "au2", region: "Australia Melbourne"},
|
||||
{subdomain: "au3", region: "Australia Perth"},
|
||||
{subdomain: "be1", region: "Belgium"},
|
||||
{subdomain: "bg1", region: "Bulgaria"},
|
||||
{subdomain: "bh1", region: "Bahrain"},
|
||||
{subdomain: "br1", region: "Brazil"},
|
||||
{subdomain: "ca1", region: "Canada"},
|
||||
{subdomain: "ch1", region: "Switzerland"},
|
||||
{subdomain: "co1", region: "Columbia"},
|
||||
{subdomain: "cr1", region: "Costa Rica"},
|
||||
{subdomain: "cz1", region: "Czech Republic"},
|
||||
{subdomain: "de1", region: "Germany"},
|
||||
{subdomain: "dk1", region: "Denmark"},
|
||||
{subdomain: "dz1", region: "Algeria"},
|
||||
{subdomain: "eg1", region: "Egypt"},
|
||||
{subdomain: "es1", region: "Spain"},
|
||||
{subdomain: "eu1", region: "Netherlands"},
|
||||
{subdomain: "fi1", region: "Finland"},
|
||||
{subdomain: "fr1", region: "France"},
|
||||
{subdomain: "gr1", region: "Greece"},
|
||||
{subdomain: "hk1", region: "Hong Kong"},
|
||||
{subdomain: "id1", region: "Indonesia"},
|
||||
{subdomain: "ie1", region: "Ireland"},
|
||||
{subdomain: "il1", region: "Israel"},
|
||||
{subdomain: "in1", region: "India"},
|
||||
{subdomain: "is1", region: "Iceland"},
|
||||
{subdomain: "it1", region: "Italy"},
|
||||
{subdomain: "jp1", region: "Japan"},
|
||||
{subdomain: "kr1", region: "South Korea"},
|
||||
{subdomain: "li1", region: "Liechtenstein"},
|
||||
{subdomain: "lt1", region: "Lithuania"},
|
||||
{subdomain: "lu1", region: "Luxembourg"},
|
||||
{subdomain: "lv1", region: "Latvia"},
|
||||
{subdomain: "mh1", region: "Marshall Islands"},
|
||||
{subdomain: "mo1", region: "Macao"},
|
||||
{subdomain: "mv1", region: "Maldives"},
|
||||
{subdomain: "mx1", region: "Mexico"},
|
||||
{subdomain: "my1", region: "Malaysia"},
|
||||
{subdomain: "no1", region: "Norway"},
|
||||
{subdomain: "nz1", region: "New Zealand"},
|
||||
{subdomain: "pa1", region: "Panama"},
|
||||
{subdomain: "ph1", region: "Philippines"},
|
||||
{subdomain: "pk1", region: "Pakistan"},
|
||||
{subdomain: "pl1", region: "Poland"},
|
||||
{subdomain: "pt1", region: "Portugal"},
|
||||
{subdomain: "qa1", region: "Qatar"},
|
||||
{subdomain: "ro1", region: "Romania"},
|
||||
{subdomain: "ru1", region: "Russia"},
|
||||
{subdomain: "sa1", region: "Saudi Arabia"},
|
||||
{subdomain: "se1", region: "Sweden"},
|
||||
{subdomain: "sg1", region: "Singapore"},
|
||||
{subdomain: "si1", region: "Slovenia"},
|
||||
{subdomain: "sk1", region: "Slovakia"},
|
||||
{subdomain: "sv1", region: "El Salvador"},
|
||||
{subdomain: "th1", region: "Thailand"},
|
||||
{subdomain: "tr1", region: "Turkey"},
|
||||
{subdomain: "tw1", region: "Taiwan"},
|
||||
{subdomain: "ua1", region: "Ukraine"},
|
||||
{subdomain: "uk1", region: "United Kingdom"},
|
||||
{subdomain: "us1", region: "USA Los Angeles"},
|
||||
{subdomain: "us2", region: "USA Washington DC"},
|
||||
{subdomain: "us3", region: "USA Austin"},
|
||||
{subdomain: "us4", region: "USA Miami"},
|
||||
{subdomain: "us5", region: "USA New York"},
|
||||
{subdomain: "us6", region: "USA Chicago"},
|
||||
{subdomain: "us7", region: "USA San Francisco"},
|
||||
{subdomain: "us8", region: "USA Seattle"},
|
||||
{subdomain: "uy1", region: "Uruguay"},
|
||||
{subdomain: "vn1", region: "Vietnam"},
|
||||
}
|
||||
}
|
||||
BIN
doc/paypal.jpg
Normal file
BIN
doc/paypal.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
BIN
doc/sponsors.jpg
Normal file
BIN
doc/sponsors.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
doc/windscribe.jpg
Normal file
BIN
doc/windscribe.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -1,37 +1,39 @@
|
||||
version: "3.7"
|
||||
services:
|
||||
pia:
|
||||
build: https://github.com/qdm12/private-internet-access-docker.git
|
||||
gluetun:
|
||||
image: qmcgaw/private-internet-access
|
||||
container_name: pia
|
||||
container_name: gluetun
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
network_mode: bridge
|
||||
init: true
|
||||
ports:
|
||||
- 8888:8888/tcp
|
||||
- 8388:8388/tcp
|
||||
- 8388:8388/udp
|
||||
- 8888:8888/tcp # Tinyproxy
|
||||
- 8388:8388/tcp # Shadowsocks
|
||||
- 8388:8388/udp # Shadowsocks
|
||||
- 8000:8000/tcp # Built-in HTTP control server
|
||||
# command:
|
||||
environment:
|
||||
# More variables are available, see the readme table
|
||||
- VPNSP=private internet access
|
||||
|
||||
# Timezone for accurate logs times
|
||||
- TZ=
|
||||
|
||||
# All VPN providers
|
||||
- USER=js89ds7
|
||||
|
||||
# All VPN providers but Mullvad
|
||||
- PASSWORD=8fd9s239G
|
||||
- ENCRYPTION=strong
|
||||
- PROTOCOL=udp
|
||||
- REGION=CA Montreal
|
||||
- DOT=on
|
||||
- DOT_PROVIDERS=cloudflare
|
||||
- BLOCK_MALICIOUS=on
|
||||
- BLOCK_SURVEILLANCE=off
|
||||
- BLOCK_ADS=off
|
||||
- UNBLOCK=
|
||||
|
||||
# Cyberghost only
|
||||
- CLIENT_KEY=
|
||||
|
||||
# All VPN providers but Mullvad
|
||||
- REGION=Austria
|
||||
|
||||
# Mullvad only
|
||||
- COUNTRY=Sweden
|
||||
|
||||
# Allow for example your LAN, set to: 192.168.1.0/24
|
||||
- EXTRA_SUBNETS=
|
||||
- TINYPROXY=off
|
||||
- TINYPROXY_LOG=Info
|
||||
- TINYPROXY_USER=
|
||||
- TINYPROXY_PASSWORD=
|
||||
- SHADOWSOCKS=off
|
||||
- SHADOWSOCKS_LOG=on
|
||||
- SHADOWSOCKS_PORT=8388
|
||||
- SHADOWSOCKS_PASSWORD=
|
||||
restart: always
|
||||
|
||||
12
go.mod
12
go.mod
@@ -1,10 +1,12 @@
|
||||
module github.com/qdm12/private-internet-access-docker
|
||||
|
||||
go 1.13
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/kyokomi/emoji v2.1.0+incompatible
|
||||
github.com/qdm12/golibs v0.0.0-20200208153322-66b2eb719e21
|
||||
github.com/stretchr/testify v1.4.0
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d
|
||||
github.com/fatih/color v1.9.0
|
||||
github.com/golang/mock v1.4.3
|
||||
github.com/kyokomi/emoji v2.2.4+incompatible
|
||||
github.com/qdm12/golibs v0.0.0-20200712151944-a0325873bf5a
|
||||
github.com/stretchr/testify v1.6.1
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae
|
||||
)
|
||||
|
||||
29
go.sum
29
go.sum
@@ -10,6 +10,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb h1:D4uzjWwKYQ5XnAvUbuvHW93esHg7F8N/OYeBBcJoTr0=
|
||||
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
|
||||
@@ -35,6 +37,8 @@ github.com/go-openapi/swag v0.17.0 h1:iqrgMg7Q7SvtbWLlltPrkMs0UBJI6oTSs79JFRUi88
|
||||
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/validate v0.17.0 h1:pqoViQz3YLOGIhAmD0N4Lt6pa/3Gnj3ymKqQwq8iS6U=
|
||||
github.com/go-openapi/validate v0.17.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
|
||||
github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -46,10 +50,15 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kyokomi/emoji v2.1.0+incompatible h1:+DYU2RgpI6OHG4oQkM5KlqD3Wd3UPEsX8jamTo1Mp6o=
|
||||
github.com/kyokomi/emoji v2.1.0+incompatible/go.mod h1:mZ6aGCD7yk8j6QY6KICwnZ2pxoszVseX1DNoGtU2tBA=
|
||||
github.com/kyokomi/emoji v2.2.4+incompatible h1:np0woGKwx9LiHAQmwZx79Oc0rHpNw3o+3evou4BEPv4=
|
||||
github.com/kyokomi/emoji v2.2.4+incompatible/go.mod h1:mZ6aGCD7yk8j6QY6KICwnZ2pxoszVseX1DNoGtU2tBA=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc=
|
||||
@@ -61,8 +70,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-20200712151944-a0325873bf5a h1:IyS72qFm+iXipadmUKXmpJScKXXK2GrD8yYfxXsnIYs=
|
||||
github.com/qdm12/golibs v0.0.0-20200712151944-a0325873bf5a/go.mod h1:pikkTN7g7zRuuAnERwqW1yAFq6pYmxrxpjiwGvb0Ysc=
|
||||
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=
|
||||
@@ -70,6 +79,8 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc=
|
||||
@@ -91,11 +102,17 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwL
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
|
||||
@@ -109,5 +126,9 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
||||
25
internal/alpine/alpine.go
Normal file
25
internal/alpine/alpine.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package alpine
|
||||
|
||||
import (
|
||||
"os/user"
|
||||
|
||||
"github.com/qdm12/golibs/files"
|
||||
)
|
||||
|
||||
type Configurator interface {
|
||||
CreateUser(username string, uid int) error
|
||||
}
|
||||
|
||||
type configurator struct {
|
||||
fileManager files.FileManager
|
||||
lookupUID func(uid string) (*user.User, error)
|
||||
lookupUser func(username string) (*user.User, error)
|
||||
}
|
||||
|
||||
func NewConfigurator(fileManager files.FileManager) Configurator {
|
||||
return &configurator{
|
||||
fileManager: fileManager,
|
||||
lookupUID: user.LookupId,
|
||||
lookupUser: user.Lookup,
|
||||
}
|
||||
}
|
||||
38
internal/alpine/users.go
Normal file
38
internal/alpine/users.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package alpine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/user"
|
||||
)
|
||||
|
||||
// CreateUser creates a user in Alpine with the given UID
|
||||
func (c *configurator) CreateUser(username string, uid int) error {
|
||||
UIDStr := fmt.Sprintf("%d", uid)
|
||||
u, err := c.lookupUID(UIDStr)
|
||||
_, unknownUID := err.(user.UnknownUserIdError)
|
||||
if err != nil && !unknownUID {
|
||||
return fmt.Errorf("cannot create user: %w", err)
|
||||
} else if u != nil {
|
||||
if u.Username == username {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("user with ID %d exists with username %q instead of %q", uid, u.Username, username)
|
||||
}
|
||||
u, err = c.lookupUser(username)
|
||||
_, unknownUsername := err.(user.UnknownUserError)
|
||||
if err != nil && !unknownUsername {
|
||||
return fmt.Errorf("cannot create user: %w", err)
|
||||
} else if u != nil {
|
||||
return fmt.Errorf("cannot create user: user with name %s already exists for ID %s instead of %d", username, u.Uid, uid)
|
||||
}
|
||||
passwd, err := c.fileManager.ReadFile("/etc/passwd")
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot create user: %w", err)
|
||||
}
|
||||
passwd = append(passwd, []byte(fmt.Sprintf("%s:x:%d:::/dev/null:/sbin/nologin\n", username, uid))...)
|
||||
|
||||
if err := c.fileManager.WriteToFile("/etc/passwd", passwd); err != nil {
|
||||
return fmt.Errorf("cannot create user: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
74
internal/cli/cli.go
Normal file
74
internal/cli/cli.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"net"
|
||||
|
||||
"github.com/qdm12/golibs/files"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/params"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/provider"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/settings"
|
||||
)
|
||||
|
||||
func ClientKey(args []string) error {
|
||||
flagSet := flag.NewFlagSet("clientkey", flag.ExitOnError)
|
||||
filepath := flagSet.String("path", "/files/client.key", "file path to the client.key file")
|
||||
if err := flagSet.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
fileManager := files.NewFileManager()
|
||||
data, err := fileManager.ReadFile(*filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s := string(data)
|
||||
s = strings.ReplaceAll(s, "\n", "")
|
||||
s = strings.ReplaceAll(s, "\r", "")
|
||||
s = strings.TrimPrefix(s, "-----BEGIN PRIVATE KEY-----")
|
||||
s = strings.TrimSuffix(s, "-----END PRIVATE KEY-----")
|
||||
fmt.Println(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func HealthCheck() error {
|
||||
ips, err := net.LookupIP("github.com")
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot resolve github.com (%s)", err)
|
||||
} else if len(ips) == 0 {
|
||||
return fmt.Errorf("resolved no IP addresses for github.com")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func OpenvpnConfig() error {
|
||||
logger, err := logging.NewLogger(logging.ConsoleEncoding, logging.InfoLevel, -1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
paramsReader := params.NewReader(logger, files.NewFileManager())
|
||||
allSettings, err := settings.GetAllSettings(paramsReader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
providerConf := provider.New(allSettings.OpenVPN.Provider.Name)
|
||||
connections, err := providerConf.GetOpenVPNConnections(allSettings.OpenVPN.Provider.ServerSelection)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lines := providerConf.BuildConf(
|
||||
connections,
|
||||
allSettings.OpenVPN.Verbosity,
|
||||
allSettings.System.UID,
|
||||
allSettings.System.GID,
|
||||
allSettings.OpenVPN.Root,
|
||||
allSettings.OpenVPN.Cipher,
|
||||
allSettings.OpenVPN.Auth,
|
||||
allSettings.OpenVPN.Provider.ExtraConfigOptions,
|
||||
)
|
||||
fmt.Println(strings.Join(lines, "\n"))
|
||||
return nil
|
||||
}
|
||||
23
internal/constants/colors.go
Normal file
23
internal/constants/colors.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package constants
|
||||
|
||||
import "github.com/fatih/color"
|
||||
|
||||
func ColorUnbound() *color.Color {
|
||||
return color.New(color.FgCyan)
|
||||
}
|
||||
|
||||
func ColorTinyproxy() *color.Color {
|
||||
return color.New(color.FgHiGreen)
|
||||
}
|
||||
|
||||
func ColorShadowsocks() *color.Color {
|
||||
return color.New(color.FgHiYellow)
|
||||
}
|
||||
|
||||
func ColorShadowsocksError() *color.Color {
|
||||
return color.New(color.FgHiRed)
|
||||
}
|
||||
|
||||
func ColorOpenvpn() *color.Color {
|
||||
return color.New(color.FgHiMagenta)
|
||||
}
|
||||
230
internal/constants/cyberghost.go
Normal file
230
internal/constants/cyberghost.go
Normal file
@@ -0,0 +1,230 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sort"
|
||||
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
const (
|
||||
CyberghostCertificate = "MIIGWjCCBEKgAwIBAgIJAJxUG61mxDS7MA0GCSqGSIb3DQEBDQUAMHsxCzAJBgNVBAYTAlJPMRIwEAYDVQQHEwlCdWNoYXJlc3QxGDAWBgNVBAoTD0N5YmVyR2hvc3QgUy5BLjEbMBkGA1UEAxMSQ3liZXJHaG9zdCBSb290IENBMSEwHwYJKoZIhvcNAQkBFhJpbmZvQGN5YmVyZ2hvc3Qucm8wHhcNMTcwNjE5MDgxNzI1WhcNMzcwNjE0MDgxNzI1WjB7MQswCQYDVQQGEwJSTzESMBAGA1UEBxMJQnVjaGFyZXN0MRgwFgYDVQQKEw9DeWJlckdob3N0IFMuQS4xGzAZBgNVBAMTEkN5YmVyR2hvc3QgUm9vdCBDQTEhMB8GCSqGSIb3DQEJARYSaW5mb0BjeWJlcmdob3N0LnJvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7O8+mji2FlQhJXn/G4VLrKPjGtxgQBAdjo0dZEQzKX08q14dLkslmOLgShStWKrOiLXGAvB1rPvvk613jtA0KjQLpgyLy9lIWohQKYjj5jrJYXMZMkbSHBYI9L8L7iezBEFYrjYKdDo51nq99wRFhKdbyKKjDh3e2L2SVEZLT1ogkK5gWzjvH+mjjtjUUicK+YjGwWOz6I+KKaG4Ve/D/cE6nCLbhHIMMnargZEu7sqA6BFeS4kEP/ZdCZoTSX2n43XV1q63nJt/v0KDetbZDciFVW9h9SVPG4qT44p0550N+Mom7zTX7S/ID5T9dplgU8sRGtIMrG0cIMD9zmpFgUnMusCrR7jJFr0sMAveTbgZg95LmstV6R6WKZkSFdUrE0DHl4dHoZvTFX+1LhwhHgjgDLaosX0vhG/C/7LpoVWimd6RRQT3M9o4Fa1TuhfvBzQ20QHrmRV/yKvGNK0xckZ6EZ/QY7Z55ORU15Tgab4ebnblYPWoEmn0mIYP3LFFeoR5OS1EX7+j4kPv+bwPGsmpHjxmZyq2Y7sJBpbOCJgbkn52WZdPBIRDpPdIHQ8pAJC4T0iMK9xvAwWNl/V6EYYNpR97osyEDXn+BTdAHlhJ5fck9KlwI9mb1Kg1bhbvbmaIAiOLenSULYf3j6rI1ygo3R2cCyybtuAq8M7z0OECAwEAAaOB4DCB3TAdBgNVHQ4EFgQU6tdK1g/He5qzjeAoM5eHt4in9iUwga0GA1UdIwSBpTCBooAU6tdK1g/He5qzjeAoM5eHt4in9iWhf6R9MHsxCzAJBgNVBAYTAlJPMRIwEAYDVQQHEwlCdWNoYXJlc3QxGDAWBgNVBAoTD0N5YmVyR2hvc3QgUy5BLjEbMBkGA1UEAxMSQ3liZXJHaG9zdCBSb290IENBMSEwHwYJKoZIhvcNAQkBFhJpbmZvQGN5YmVyZ2hvc3Qucm+CCQCcVButZsQ0uzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4ICAQDNyQ92kj4qiNjnHk99qvnFw9qGfwB9ofaPL74zh0G5hEe3Wgb2o4fqUGnvUNgOu53gJksz3DcPQ8t40wfmm9I1Z8tiM9qrqvkuQ+nKcLgdooXtEsTybPIYDZ2cWR/5E0TKRvC7RFzKgQ4D77Vbi4TdaHiDV7ZNfU1iLCoBGcYm80hcUHEs5KIVLwUmcSOTmbZBySJxcSD0yUpS7nlZGwLY6VQrU+JFwDSisbXT4DXf3iSzp7FzW0/u/SFvWsPHrjE0hkPoZPalYvouaJEHKAhip0ZwSmitlxbBnmm8+K/3c9mLA5/uXrirfpuhhs8V3lyV2mczVtSiTl6gpi88gc//JY80JeHdupjO25T3XEzY9cpxecmkWaUEjLMx4wVoXQuUiPonfILM6OLwi+zUS8gQErdFeGvcQXbncPa4SdJuHkF8lgiX2i8S8fPGdXvU37E9bdAXwP5nZriYq1s0D59Qfvz+vLXVkmyZp6ztxjKjKolemPMak0Y5c1Q4RjNF6tmQoFuy/ACSkWy14Tzu2dFp7UiVbGg1FOvKhfs48zC2/IUQv1arqmPT/9LVq3B2DVT9UKXRUXX/f/jSSsVjkz4uUe2jUyL+XHX1nSmROTPHSAJ+oKf0BLnfqUxFkEUTwLnayssP2nwGgq35b7wEbTFIXdrjHGFUVQIDeERz8UThew=="
|
||||
CyberghostClientCertificate = "MIIGrDCCBJSgAwIBAgIEAdTnfTANBgkqhkiG9w0BAQsFADB7MQswCQYDVQQGEwJSTzESMBAGA1UEBxMJQnVjaGFyZXN0MRgwFgYDVQQKEw9DeWJlckdob3N0IFMuQS4xGzAZBgNVBAMTEkN5YmVyR2hvc3QgUm9vdCBDQTEhMB8GCSqGSIb3DQEJARYSaW5mb0BjeWJlcmdob3N0LnJvMB4XDTIwMDcwNDE1MjkzNloXDTMwMDcwMjE1MjkzNlowfTELMAkGA1UEBhMCUk8xEjAQBgNVBAcMCUJ1Y2hhcmVzdDEYMBYGA1UECgwPQ3liZXJHaG9zdCBTLkEuMR0wGwYDVQQDDBRjLmoua2xhdmVyQGdtYWlsLmNvbTEhMB8GCSqGSIb3DQEJARYSaW5mb0BjeWJlcmdob3N0LnJvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAobp2NlGUHMNBe08YEOnVG3QJjF3ZaXbRhE/II9rmtgJTNZtDohGChvFlNRsExKzVrKxHCeuJkVffwzQ6fYk4/M1RdYLJUh0UVw3e4WdApw8E7TJZxDYm4SHQNXUvt1Rt5TjslcXxIpDZgrMSc/kHROYEL9tdgdzPZErUJehXyJPhEzIrzmAJh501x7WwKPz9ctSVlItyavqEWFF2vyUa6X9DYmD9mQTz5c+VXNO5DkXmPFBIaEVDnvFtcjGJ56yEvFnWVukL+OUX7ezowrIOFOcp9udjgpeiHq+XvsQ6ER0DJt25MiEId3NjkxtZ8BitDftTcLN/kt81hWKT7adMVc3kpIZ80cxrwRCttMd7sHAzKI9u7pMxv10eUOsIEY87ewBe3l6KvEnjA+9uIjim6gLLebDIaEH50Ee9PzNJ8fqQ2u54Ab4bt00/H1sUnJ6Ss/+WsQDOK1BsPRKKcnHZntOlHrs2Tu5+txKNU2cOapI8SjVULUNKrRXASbpfWnLUfri/HO742bJb/TjkOJcOxta3hTPFAhaRWBusVlB41XVHeuH5DAhugYXeSNK6/6Ul8YvKUNH/7QbxuGIGXfth19Xl4QLI1umyEjZopSlt3tOiO2V1soVNSQCCfxXVoCTMESMLjhkjWdmBDhdy2GTW7S4YoJfqVKiS18rYkN7I4ZMCAwEAAaOCATQwggEwMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMDQGCWCGSAGG+EIBDQQnFiVDeWJlckdob3N0IEdlbmVyYXRlZCBVc2VyIENlcnRpZmljYXRlMBEGCWCGSAGG+EIBAQQEAwIHgDAdBgNVHQ4EFgQULwUtU5s6pL2NN9gPeEnKX0dhwiswga0GA1UdIwSBpTCBooAU6tdK1g/He5qzjeAoM5eHt4in9iWhf6R9MHsxCzAJBgNVBAYTAlJPMRIwEAYDVQQHEwlCdWNoYXJlc3QxGDAWBgNVBAoTD0N5YmVyR2hvc3QgUy5BLjEbMBkGA1UEAxMSQ3liZXJHaG9zdCBSb290IENBMSEwHwYJKoZIhvcNAQkBFhJpbmZvQGN5YmVyZ2hvc3Qucm+CCQCcVButZsQ0uzANBgkqhkiG9w0BAQsFAAOCAgEAystGIMYhQWaEdTqlnLCytrr8657t+PuidZMNNIaPB3wN2Fi2xKf14DTg03mqxjmPPb+f+PVNIOV5PdWD4jcQwOP1GEboGV0DFzlRGeAtDcvKwdee4oASJbZq1CETqDaohQTxKEWC+UBk2F36nOaEI6Sab+Mb4cR9//PAwvzOqrXuGF5NuIOX7eFtCMQSgQq6lRRqTQjekm0Dxigx4JA92Jo2qZRwCJ0T3IXBJGL831HCFJbDWv8PV3lsfFb/i2+vr54uywFQVWWp18dYi97gipfuQ4zRg2Ldx5aXSmnhhKpg5ioZvtk043QofF12YORhobElqavRbvvhZvlCouvcuoq9QKi7IPe5SJZkZ1X7ezMesCwBzwFpt6vRUAcslsNFbcYS1iSENlY/PTcDqBhbKuc9yAhq+/aUgaY/8VF5RWVzSRZufbf3BPwOkE4K0UybaobO/YX0JOkCacAD+4tdR6YSXNIMMRAOCBQvxbxFXaHzhwhzBAjdsC56FrJKwXvQrRLU3tF4P0zFMeNTay8uTtUXugDK7EnklLESuYdpUJ8bUMlAUhJBi6UFI9/icMudxXvLRvhnBW9EtKib5JnVFUovcEUt+3EJbyst05nkL4YPjQS4TC9DHdo5SyRAy1TpiOCYTbretAFZRhh6ycUN5hBeN8GMQxiMreMtDV4PEIQ="
|
||||
)
|
||||
|
||||
func CyberghostRegionChoices() (choices []string) {
|
||||
uniqueChoices := map[string]struct{}{}
|
||||
for _, server := range CyberghostServers() {
|
||||
uniqueChoices[server.Region] = struct{}{}
|
||||
}
|
||||
for choice := range uniqueChoices {
|
||||
choices = append(choices, choice)
|
||||
}
|
||||
sort.Slice(choices, func(i, j int) bool {
|
||||
return choices[i] < choices[j]
|
||||
})
|
||||
return choices
|
||||
}
|
||||
|
||||
func CyberghostGroupChoices() (choices []string) {
|
||||
uniqueChoices := map[string]struct{}{}
|
||||
for _, server := range CyberghostServers() {
|
||||
uniqueChoices[server.Group] = struct{}{}
|
||||
}
|
||||
for choice := range uniqueChoices {
|
||||
choices = append(choices, choice)
|
||||
}
|
||||
sort.Slice(choices, func(i, j int) bool {
|
||||
return choices[i] < choices[j]
|
||||
})
|
||||
return choices
|
||||
}
|
||||
|
||||
func CyberghostServers() []models.CyberghostServer {
|
||||
return []models.CyberghostServer{
|
||||
{Region: "Albania", Group: "Premium TCP Europe", IPs: []net.IP{{31, 171, 152, 99}, {31, 171, 152, 100}, {31, 171, 152, 102}, {31, 171, 152, 105}, {31, 171, 152, 107}, {31, 171, 152, 109}, {31, 171, 152, 133}, {31, 171, 152, 135}, {31, 171, 152, 136}, {31, 171, 152, 139}}},
|
||||
{Region: "Albania", Group: "Premium UDP Europe", IPs: []net.IP{{31, 171, 152, 99}, {31, 171, 152, 101}, {31, 171, 152, 103}, {31, 171, 152, 105}, {31, 171, 152, 106}, {31, 171, 152, 133}, {31, 171, 152, 135}, {31, 171, 152, 137}, {31, 171, 152, 138}, {31, 171, 152, 139}}},
|
||||
{Region: "Algeria", Group: "Premium TCP Europe", IPs: []net.IP{{45, 133, 91, 7}, {45, 133, 91, 9}, {45, 133, 91, 12}, {45, 133, 91, 15}, {45, 133, 91, 17}, {45, 133, 91, 18}, {45, 133, 91, 20}, {45, 133, 91, 23}, {45, 133, 91, 24}, {45, 133, 91, 26}}},
|
||||
{Region: "Algeria", Group: "Premium UDP Europe", IPs: []net.IP{{45, 133, 91, 7}, {45, 133, 91, 10}, {45, 133, 91, 11}, {45, 133, 91, 15}, {45, 133, 91, 17}, {45, 133, 91, 18}, {45, 133, 91, 21}, {45, 133, 91, 25}, {45, 133, 91, 26}, {45, 133, 91, 29}}},
|
||||
{Region: "Andorra", Group: "Premium TCP Europe", IPs: []net.IP{{45, 139, 49, 10}, {45, 139, 49, 14}, {45, 139, 49, 15}, {45, 139, 49, 16}, {45, 139, 49, 17}, {45, 139, 49, 18}, {45, 139, 49, 19}, {45, 139, 49, 23}, {45, 139, 49, 25}, {45, 139, 49, 28}}},
|
||||
{Region: "Andorra", Group: "Premium UDP Europe", IPs: []net.IP{{45, 139, 49, 7}, {45, 139, 49, 9}, {45, 139, 49, 10}, {45, 139, 49, 12}, {45, 139, 49, 15}, {45, 139, 49, 16}, {45, 139, 49, 17}, {45, 139, 49, 25}, {45, 139, 49, 27}, {45, 139, 49, 28}}},
|
||||
{Region: "Argentina", Group: "Premium TCP USA", IPs: []net.IP{{190, 106, 130, 16}, {190, 106, 130, 17}, {190, 106, 130, 20}, {190, 106, 130, 22}, {190, 106, 130, 23}, {190, 106, 130, 34}, {190, 106, 130, 37}, {190, 106, 130, 38}, {190, 106, 130, 44}, {190, 106, 130, 45}}},
|
||||
{Region: "Argentina", Group: "Premium UDP USA", IPs: []net.IP{{190, 106, 130, 15}, {190, 106, 130, 16}, {190, 106, 130, 18}, {190, 106, 130, 19}, {190, 106, 130, 20}, {190, 106, 130, 34}, {190, 106, 130, 36}, {190, 106, 130, 37}, {190, 106, 130, 43}, {190, 106, 130, 52}}},
|
||||
{Region: "Armenia", Group: "Premium TCP Europe", IPs: []net.IP{{45, 139, 50, 10}, {45, 139, 50, 12}, {45, 139, 50, 14}, {45, 139, 50, 18}, {45, 139, 50, 19}, {45, 139, 50, 20}, {45, 139, 50, 21}, {45, 139, 50, 26}, {45, 139, 50, 27}, {45, 139, 50, 29}}},
|
||||
{Region: "Armenia", Group: "Premium UDP Europe", IPs: []net.IP{{45, 139, 50, 8}, {45, 139, 50, 10}, {45, 139, 50, 11}, {45, 139, 50, 14}, {45, 139, 50, 18}, {45, 139, 50, 20}, {45, 139, 50, 24}, {45, 139, 50, 26}, {45, 139, 50, 27}, {45, 139, 50, 29}}},
|
||||
{Region: "Australia", Group: "Premium TCP Asia", IPs: []net.IP{{27, 50, 79, 3}, {27, 50, 79, 4}, {27, 50, 79, 5}, {27, 50, 79, 6}, {27, 50, 79, 9}, {27, 50, 79, 12}, {27, 50, 79, 14}, {103, 13, 101, 171}, {202, 130, 33, 114}, {202, 130, 33, 118}}},
|
||||
{Region: "Australia", Group: "Premium UDP Asia", IPs: []net.IP{{27, 50, 79, 3}, {27, 50, 79, 6}, {27, 50, 79, 9}, {27, 50, 79, 10}, {27, 50, 79, 11}, {27, 50, 79, 13}, {103, 13, 101, 174}, {202, 130, 33, 114}, {202, 130, 33, 117}, {202, 130, 33, 118}}},
|
||||
{Region: "Austria", Group: "Premium TCP Europe", IPs: []net.IP{{89, 187, 168, 133}, {89, 187, 168, 144}, {89, 187, 168, 150}, {89, 187, 168, 151}, {89, 187, 168, 162}, {89, 187, 168, 163}, {89, 187, 168, 164}, {89, 187, 168, 167}, {89, 187, 168, 178}, {89, 187, 168, 182}}},
|
||||
{Region: "Austria", Group: "Premium UDP Europe", IPs: []net.IP{{89, 187, 168, 138}, {89, 187, 168, 139}, {89, 187, 168, 149}, {89, 187, 168, 150}, {89, 187, 168, 161}, {89, 187, 168, 165}, {89, 187, 168, 167}, {89, 187, 168, 168}, {89, 187, 168, 174}, {89, 187, 168, 182}}},
|
||||
{Region: "Bahamas", Group: "Premium TCP USA", IPs: []net.IP{{45, 132, 143, 8}, {45, 132, 143, 10}, {45, 132, 143, 11}, {45, 132, 143, 19}, {45, 132, 143, 24}, {45, 132, 143, 28}, {45, 132, 143, 31}, {45, 132, 143, 42}, {45, 132, 143, 43}, {45, 132, 143, 44}}},
|
||||
{Region: "Bahamas", Group: "Premium UDP USA", IPs: []net.IP{{45, 132, 143, 1}, {45, 132, 143, 2}, {45, 132, 143, 3}, {45, 132, 143, 5}, {45, 132, 143, 7}, {45, 132, 143, 18}, {45, 132, 143, 23}, {45, 132, 143, 30}, {45, 132, 143, 32}, {45, 132, 143, 48}}},
|
||||
{Region: "Bangladesh", Group: "Premium TCP Asia", IPs: []net.IP{{45, 132, 142, 3}, {45, 132, 142, 8}, {45, 132, 142, 12}, {45, 132, 142, 20}, {45, 132, 142, 22}, {45, 132, 142, 26}, {45, 132, 142, 27}, {45, 132, 142, 37}, {45, 132, 142, 39}, {45, 132, 142, 42}}},
|
||||
{Region: "Bangladesh", Group: "Premium UDP Asia", IPs: []net.IP{{45, 132, 142, 6}, {45, 132, 142, 8}, {45, 132, 142, 13}, {45, 132, 142, 18}, {45, 132, 142, 33}, {45, 132, 142, 35}, {45, 132, 142, 38}, {45, 132, 142, 41}, {45, 132, 142, 42}, {45, 132, 142, 45}}},
|
||||
{Region: "Belarus", Group: "Premium TCP Europe", IPs: []net.IP{{45, 132, 194, 3}, {45, 132, 194, 4}, {45, 132, 194, 26}, {45, 132, 194, 28}, {45, 132, 194, 34}, {45, 132, 194, 38}, {45, 132, 194, 39}, {45, 132, 194, 42}, {45, 132, 194, 44}, {45, 132, 194, 48}}},
|
||||
{Region: "Belarus", Group: "Premium UDP Europe", IPs: []net.IP{{45, 132, 194, 4}, {45, 132, 194, 5}, {45, 132, 194, 9}, {45, 132, 194, 10}, {45, 132, 194, 20}, {45, 132, 194, 25}, {45, 132, 194, 29}, {45, 132, 194, 31}, {45, 132, 194, 40}, {45, 132, 194, 45}}},
|
||||
{Region: "Belgium", Group: "Premium TCP Europe", IPs: []net.IP{{37, 120, 143, 52}, {37, 120, 143, 55}, {37, 120, 143, 58}, {185, 210, 217, 10}, {185, 210, 217, 54}, {185, 210, 217, 244}, {185, 210, 217, 251}, {185, 232, 21, 119}, {193, 9, 114, 228}, {193, 9, 114, 230}}},
|
||||
{Region: "Belgium", Group: "Premium UDP Europe", IPs: []net.IP{{5, 253, 205, 22}, {5, 253, 205, 23}, {37, 120, 143, 165}, {185, 210, 217, 14}, {185, 210, 217, 248}, {185, 210, 217, 254}, {193, 9, 114, 212}, {193, 9, 114, 213}, {193, 9, 114, 219}, {193, 9, 114, 228}}},
|
||||
{Region: "Bosnia and Herzegovina", Group: "Premium TCP Europe", IPs: []net.IP{{185, 99, 3, 57}, {185, 99, 3, 58}, {185, 99, 3, 72}, {185, 99, 3, 73}, {185, 99, 3, 74}, {185, 99, 3, 130}, {185, 99, 3, 131}, {185, 99, 3, 134}, {185, 99, 3, 135}, {185, 99, 3, 136}}},
|
||||
{Region: "Bosnia and Herzegovina", Group: "Premium UDP Europe", IPs: []net.IP{{185, 99, 3, 57}, {185, 99, 3, 58}, {185, 99, 3, 72}, {185, 99, 3, 73}, {185, 99, 3, 74}, {185, 99, 3, 130}, {185, 99, 3, 131}, {185, 99, 3, 134}, {185, 99, 3, 135}, {185, 99, 3, 136}}},
|
||||
{Region: "Brazil", Group: "Premium TCP USA", IPs: []net.IP{{45, 231, 207, 65}, {45, 231, 207, 67}, {45, 231, 207, 68}, {45, 231, 207, 69}, {45, 231, 207, 75}, {177, 67, 81, 170}, {181, 41, 203, 98}, {181, 41, 203, 100}, {181, 41, 203, 102}, {181, 41, 203, 110}}},
|
||||
{Region: "Brazil", Group: "Premium UDP USA", IPs: []net.IP{{45, 231, 207, 77}, {177, 67, 81, 163}, {177, 67, 81, 164}, {177, 67, 81, 165}, {177, 67, 81, 167}, {177, 67, 81, 170}, {177, 67, 81, 173}, {177, 67, 81, 174}, {181, 41, 203, 103}, {181, 41, 203, 104}}},
|
||||
{Region: "Bulgaria", Group: "Premium TCP Europe", IPs: []net.IP{{37, 120, 152, 99}, {37, 120, 152, 102}, {37, 120, 152, 103}, {37, 120, 152, 104}, {37, 120, 152, 105}, {37, 120, 152, 106}, {37, 120, 152, 107}, {37, 120, 152, 108}, {37, 120, 152, 109}, {37, 120, 152, 110}}},
|
||||
{Region: "Bulgaria", Group: "Premium UDP Europe", IPs: []net.IP{{37, 120, 152, 99}, {37, 120, 152, 100}, {37, 120, 152, 101}, {37, 120, 152, 103}, {37, 120, 152, 104}, {37, 120, 152, 105}, {37, 120, 152, 107}, {37, 120, 152, 108}, {37, 120, 152, 109}, {37, 120, 152, 110}}},
|
||||
{Region: "Cambodia", Group: "Premium TCP Asia", IPs: []net.IP{{188, 215, 235, 36}, {188, 215, 235, 38}, {188, 215, 235, 39}, {188, 215, 235, 40}, {188, 215, 235, 43}, {188, 215, 235, 46}, {188, 215, 235, 47}, {188, 215, 235, 48}, {188, 215, 235, 51}, {188, 215, 235, 54}}},
|
||||
{Region: "Cambodia", Group: "Premium UDP Asia", IPs: []net.IP{{188, 215, 235, 35}, {188, 215, 235, 36}, {188, 215, 235, 37}, {188, 215, 235, 38}, {188, 215, 235, 45}, {188, 215, 235, 46}, {188, 215, 235, 52}, {188, 215, 235, 53}, {188, 215, 235, 55}, {188, 215, 235, 58}}},
|
||||
{Region: "Canada", Group: "Premium TCP USA", IPs: []net.IP{{37, 120, 205, 8}, {37, 120, 205, 28}, {104, 245, 145, 163}, {104, 245, 146, 38}, {104, 245, 146, 101}, {176, 113, 74, 44}, {176, 113, 74, 52}, {176, 113, 74, 67}, {176, 113, 74, 126}, {176, 113, 74, 217}}},
|
||||
{Region: "Canada", Group: "Premium UDP USA", IPs: []net.IP{{37, 120, 205, 40}, {54, 39, 11, 194}, {104, 245, 145, 164}, {104, 245, 146, 41}, {139, 28, 218, 86}, {139, 28, 218, 87}, {176, 113, 74, 19}, {176, 113, 74, 25}, {176, 113, 74, 30}, {176, 113, 74, 195}}},
|
||||
{Region: "Chile", Group: "Premium TCP USA", IPs: []net.IP{{190, 105, 239, 129}, {190, 105, 239, 130}, {190, 105, 239, 131}, {190, 105, 239, 132}, {190, 105, 239, 133}, {190, 105, 239, 134}, {190, 105, 239, 135}, {190, 105, 239, 136}, {190, 105, 239, 137}, {190, 105, 239, 138}}},
|
||||
{Region: "Chile", Group: "Premium UDP USA", IPs: []net.IP{{190, 105, 239, 129}, {190, 105, 239, 130}, {190, 105, 239, 131}, {190, 105, 239, 132}, {190, 105, 239, 133}, {190, 105, 239, 134}, {190, 105, 239, 135}, {190, 105, 239, 136}, {190, 105, 239, 137}, {190, 105, 239, 138}}},
|
||||
{Region: "China", Group: "Premium TCP Asia", IPs: []net.IP{{45, 132, 193, 2}, {45, 132, 193, 3}, {45, 132, 193, 9}, {45, 132, 193, 10}, {45, 132, 193, 12}, {45, 132, 193, 13}, {45, 132, 193, 32}, {45, 132, 193, 36}, {45, 132, 193, 43}, {45, 132, 193, 45}}},
|
||||
{Region: "China", Group: "Premium UDP Asia", IPs: []net.IP{{45, 132, 193, 2}, {45, 132, 193, 3}, {45, 132, 193, 4}, {45, 132, 193, 14}, {45, 132, 193, 19}, {45, 132, 193, 22}, {45, 132, 193, 30}, {45, 132, 193, 35}, {45, 132, 193, 36}, {45, 132, 193, 42}}},
|
||||
{Region: "Colombia", Group: "Premium TCP USA", IPs: []net.IP{{190, 105, 229, 19}, {190, 105, 229, 20}, {190, 105, 229, 21}, {190, 105, 229, 22}}},
|
||||
{Region: "Colombia", Group: "Premium UDP USA", IPs: []net.IP{{190, 105, 229, 19}, {190, 105, 229, 20}, {190, 105, 229, 21}, {190, 105, 229, 22}}},
|
||||
{Region: "Costa Rica", Group: "Premium TCP USA", IPs: []net.IP{{143, 202, 160, 67}, {143, 202, 160, 69}, {143, 202, 160, 70}, {143, 202, 160, 72}, {143, 202, 160, 73}, {143, 202, 160, 74}, {143, 202, 160, 75}, {143, 202, 160, 76}, {143, 202, 160, 77}, {143, 202, 160, 78}}},
|
||||
{Region: "Costa Rica", Group: "Premium UDP USA", IPs: []net.IP{{143, 202, 160, 67}, {143, 202, 160, 68}, {143, 202, 160, 69}, {143, 202, 160, 70}, {143, 202, 160, 71}, {143, 202, 160, 73}, {143, 202, 160, 74}, {143, 202, 160, 75}, {143, 202, 160, 76}, {143, 202, 160, 78}}},
|
||||
{Region: "Cyprus", Group: "Premium TCP Europe", IPs: []net.IP{{45, 132, 137, 8}, {45, 132, 137, 11}, {45, 132, 137, 12}, {45, 132, 137, 15}, {45, 132, 137, 17}, {45, 132, 137, 18}, {45, 132, 137, 19}, {45, 132, 137, 23}, {45, 132, 137, 26}, {45, 132, 137, 28}}},
|
||||
{Region: "Cyprus", Group: "Premium UDP Europe", IPs: []net.IP{{45, 132, 137, 8}, {45, 132, 137, 10}, {45, 132, 137, 16}, {45, 132, 137, 19}, {45, 132, 137, 20}, {45, 132, 137, 21}, {45, 132, 137, 22}, {45, 132, 137, 23}, {45, 132, 137, 25}, {45, 132, 137, 28}}},
|
||||
{Region: "Czech Republic", Group: "Premium TCP Europe", IPs: []net.IP{{195, 181, 160, 66}, {195, 181, 160, 72}, {195, 181, 161, 7}, {195, 181, 161, 9}, {195, 181, 161, 10}, {195, 181, 161, 11}, {195, 181, 161, 14}, {195, 181, 161, 17}, {195, 181, 161, 23}, {195, 181, 161, 25}}},
|
||||
{Region: "Czech Republic", Group: "Premium UDP Europe", IPs: []net.IP{{185, 216, 35, 231}, {185, 216, 35, 232}, {185, 216, 35, 235}, {195, 181, 160, 75}, {195, 181, 161, 2}, {195, 181, 161, 8}, {195, 181, 161, 15}, {195, 181, 161, 16}, {195, 181, 161, 23}, {195, 181, 161, 25}}},
|
||||
{Region: "Denmark", Group: "Premium TCP Europe", IPs: []net.IP{{37, 120, 145, 93}, {37, 120, 194, 39}, {37, 120, 194, 41}, {37, 120, 194, 53}, {95, 174, 65, 166}, {95, 174, 65, 167}, {95, 174, 65, 174}, {185, 206, 224, 230}, {185, 206, 224, 235}, {185, 206, 224, 253}}},
|
||||
{Region: "Denmark", Group: "Premium UDP Europe", IPs: []net.IP{{37, 120, 145, 84}, {37, 120, 145, 88}, {37, 120, 194, 38}, {37, 120, 194, 58}, {95, 174, 65, 163}, {95, 174, 65, 165}, {185, 206, 224, 227}, {185, 206, 224, 243}, {185, 206, 224, 245}, {185, 206, 224, 253}}},
|
||||
{Region: "Egypt", Group: "Premium TCP Europe", IPs: []net.IP{{45, 132, 139, 7}, {45, 132, 139, 22}, {45, 132, 139, 24}, {45, 132, 139, 27}, {45, 132, 139, 28}, {45, 132, 139, 29}, {188, 214, 122, 36}, {188, 214, 122, 41}, {188, 214, 122, 52}, {188, 214, 122, 56}}},
|
||||
{Region: "Egypt", Group: "Premium UDP Europe", IPs: []net.IP{{45, 132, 139, 7}, {45, 132, 139, 17}, {45, 132, 139, 18}, {45, 132, 139, 22}, {45, 132, 139, 23}, {188, 214, 122, 41}, {188, 214, 122, 48}, {188, 214, 122, 49}, {188, 214, 122, 51}, {188, 214, 122, 61}}},
|
||||
{Region: "Estonia", Group: "Premium TCP Europe", IPs: []net.IP{{77, 247, 111, 6}, {77, 247, 111, 11}, {77, 247, 111, 52}, {77, 247, 111, 53}, {77, 247, 111, 55}, {77, 247, 111, 56}, {77, 247, 111, 57}, {77, 247, 111, 60}, {77, 247, 111, 61}, {77, 247, 111, 62}}},
|
||||
{Region: "Estonia", Group: "Premium UDP Europe", IPs: []net.IP{{77, 247, 111, 3}, {77, 247, 111, 4}, {77, 247, 111, 5}, {77, 247, 111, 7}, {77, 247, 111, 11}, {77, 247, 111, 12}, {77, 247, 111, 52}, {77, 247, 111, 53}, {77, 247, 111, 55}, {77, 247, 111, 59}}},
|
||||
{Region: "Finland", Group: "Premium TCP Europe", IPs: []net.IP{{194, 34, 133, 171}, {194, 34, 133, 172}, {194, 34, 133, 176}, {194, 34, 133, 179}, {194, 34, 133, 180}, {194, 34, 133, 195}, {194, 34, 133, 196}, {194, 34, 133, 204}, {194, 34, 133, 207}, {194, 34, 133, 208}}},
|
||||
{Region: "Finland", Group: "Premium UDP Europe", IPs: []net.IP{{194, 34, 133, 163}, {194, 34, 133, 164}, {194, 34, 133, 167}, {194, 34, 133, 178}, {194, 34, 133, 192}, {194, 34, 133, 201}, {194, 34, 133, 205}, {194, 34, 133, 206}, {194, 34, 133, 208}, {194, 34, 133, 214}}},
|
||||
{Region: "France", Group: "Premium TCP Europe", IPs: []net.IP{{84, 17, 60, 21}, {84, 17, 60, 33}, {84, 17, 60, 89}, {84, 17, 60, 92}, {84, 17, 60, 114}, {84, 17, 61, 23}, {84, 17, 61, 43}, {84, 17, 61, 111}, {84, 17, 61, 235}, {151, 106, 8, 36}}},
|
||||
{Region: "France", Group: "Premium UDP Europe", IPs: []net.IP{{84, 17, 60, 8}, {84, 17, 60, 54}, {84, 17, 60, 161}, {84, 17, 60, 188}, {84, 17, 61, 32}, {84, 17, 61, 101}, {84, 17, 61, 163}, {84, 17, 61, 187}, {84, 17, 61, 213}, {151, 106, 8, 46}}},
|
||||
{Region: "Georgia", Group: "Premium TCP Europe", IPs: []net.IP{{45, 132, 138, 7}, {45, 132, 138, 8}, {45, 132, 138, 9}, {45, 132, 138, 12}, {45, 132, 138, 14}, {45, 132, 138, 18}, {45, 132, 138, 19}, {45, 132, 138, 20}, {45, 132, 138, 23}, {45, 132, 138, 27}}},
|
||||
{Region: "Georgia", Group: "Premium UDP Europe", IPs: []net.IP{{45, 132, 138, 7}, {45, 132, 138, 8}, {45, 132, 138, 9}, {45, 132, 138, 10}, {45, 132, 138, 17}, {45, 132, 138, 18}, {45, 132, 138, 25}, {45, 132, 138, 26}, {45, 132, 138, 27}, {45, 132, 138, 28}}},
|
||||
{Region: "Germany", Group: "Premium TCP Europe", IPs: []net.IP{{37, 120, 217, 110}, {84, 17, 48, 75}, {84, 17, 48, 100}, {84, 17, 48, 182}, {84, 17, 49, 129}, {154, 28, 188, 50}, {154, 28, 188, 128}, {178, 162, 208, 155}, {178, 162, 209, 72}, {178, 162, 216, 49}}},
|
||||
{Region: "Germany", Group: "Premium UDP Europe", IPs: []net.IP{{37, 120, 217, 5}, {37, 120, 217, 27}, {84, 17, 48, 20}, {84, 17, 48, 64}, {84, 17, 48, 68}, {84, 17, 48, 182}, {84, 17, 49, 141}, {84, 17, 49, 144}, {154, 28, 188, 90}, {154, 28, 188, 143}}},
|
||||
{Region: "Greece", Group: "Premium TCP Europe", IPs: []net.IP{{154, 57, 3, 130}, {154, 57, 3, 132}, {154, 57, 3, 135}, {154, 57, 3, 138}, {154, 57, 3, 140}, {188, 123, 126, 168}, {188, 123, 126, 170}, {188, 123, 126, 176}, {188, 123, 126, 177}, {188, 123, 126, 178}}},
|
||||
{Region: "Greece", Group: "Premium UDP Europe", IPs: []net.IP{{154, 57, 3, 130}, {154, 57, 3, 132}, {154, 57, 3, 133}, {154, 57, 3, 137}, {188, 123, 126, 167}, {188, 123, 126, 170}, {188, 123, 126, 172}, {188, 123, 126, 173}, {188, 123, 126, 174}, {188, 123, 126, 177}}},
|
||||
{Region: "Greenland", Group: "Premium TCP Europe", IPs: []net.IP{{45, 131, 209, 8}, {45, 131, 209, 9}, {45, 131, 209, 12}, {45, 131, 209, 16}, {45, 131, 209, 18}, {45, 131, 209, 20}, {45, 131, 209, 22}, {45, 131, 209, 23}, {45, 131, 209, 26}, {45, 131, 209, 27}}},
|
||||
{Region: "Greenland", Group: "Premium UDP Europe", IPs: []net.IP{{45, 131, 209, 6}, {45, 131, 209, 11}, {45, 131, 209, 19}, {45, 131, 209, 20}, {45, 131, 209, 21}, {45, 131, 209, 23}, {45, 131, 209, 26}, {45, 131, 209, 27}, {45, 131, 209, 28}, {45, 131, 209, 29}}},
|
||||
{Region: "Hong Kong", Group: "Premium TCP Asia", IPs: []net.IP{{84, 17, 56, 130}, {84, 17, 56, 136}, {84, 17, 56, 148}, {84, 17, 56, 149}, {84, 17, 56, 152}, {84, 17, 56, 172}, {84, 17, 56, 173}, {84, 17, 56, 175}, {84, 17, 56, 176}, {84, 17, 56, 181}}},
|
||||
{Region: "Hong Kong", Group: "Premium UDP Asia", IPs: []net.IP{{84, 17, 56, 133}, {84, 17, 56, 140}, {84, 17, 56, 146}, {84, 17, 56, 151}, {84, 17, 56, 162}, {84, 17, 56, 166}, {84, 17, 56, 172}, {84, 17, 56, 174}, {84, 17, 56, 176}, {84, 17, 56, 182}}},
|
||||
{Region: "Hungary", Group: "Premium TCP Europe", IPs: []net.IP{{185, 104, 187, 83}, {185, 104, 187, 85}, {185, 104, 187, 86}, {185, 104, 187, 92}, {185, 189, 114, 116}, {185, 189, 114, 119}, {185, 189, 114, 120}, {185, 189, 114, 121}, {185, 189, 114, 124}, {185, 189, 114, 125}}},
|
||||
{Region: "Hungary", Group: "Premium UDP Europe", IPs: []net.IP{{185, 104, 187, 83}, {185, 104, 187, 85}, {185, 104, 187, 93}, {185, 189, 114, 115}, {185, 189, 114, 118}, {185, 189, 114, 119}, {185, 189, 114, 120}, {185, 189, 114, 121}, {185, 189, 114, 123}, {185, 189, 114, 125}}},
|
||||
{Region: "Iceland", Group: "Premium TCP Europe", IPs: []net.IP{{213, 167, 139, 19}, {213, 167, 139, 20}, {213, 167, 139, 21}, {213, 167, 139, 22}, {213, 167, 139, 23}, {213, 167, 139, 24}, {213, 167, 139, 25}, {213, 167, 139, 26}, {213, 167, 139, 28}, {213, 167, 139, 30}}},
|
||||
{Region: "Iceland", Group: "Premium UDP Europe", IPs: []net.IP{{213, 167, 139, 19}, {213, 167, 139, 21}, {213, 167, 139, 22}, {213, 167, 139, 24}, {213, 167, 139, 25}, {213, 167, 139, 26}, {213, 167, 139, 27}, {213, 167, 139, 28}, {213, 167, 139, 29}, {213, 167, 139, 30}}},
|
||||
{Region: "India", Group: "Premium TCP Europe", IPs: []net.IP{{43, 241, 71, 115}, {43, 241, 71, 118}, {43, 241, 71, 120}, {43, 241, 71, 122}, {43, 241, 71, 125}, {43, 241, 71, 147}, {43, 241, 71, 148}, {43, 241, 71, 149}, {43, 241, 71, 154}, {43, 241, 71, 156}}},
|
||||
{Region: "India", Group: "Premium UDP Europe", IPs: []net.IP{{43, 241, 71, 116}, {43, 241, 71, 117}, {43, 241, 71, 118}, {43, 241, 71, 122}, {43, 241, 71, 125}, {43, 241, 71, 147}, {43, 241, 71, 148}, {43, 241, 71, 153}, {43, 241, 71, 155}, {43, 241, 71, 156}}},
|
||||
{Region: "Indonesia", Group: "Premium TCP Asia", IPs: []net.IP{{113, 20, 29, 243}, {113, 20, 29, 244}, {113, 20, 29, 246}, {113, 20, 29, 247}, {113, 20, 29, 248}, {113, 20, 29, 249}, {113, 20, 29, 250}, {113, 20, 29, 251}, {113, 20, 29, 252}, {113, 20, 29, 254}}},
|
||||
{Region: "Indonesia", Group: "Premium UDP Asia", IPs: []net.IP{{113, 20, 29, 243}, {113, 20, 29, 245}, {113, 20, 29, 246}, {113, 20, 29, 247}, {113, 20, 29, 248}, {113, 20, 29, 249}, {113, 20, 29, 250}, {113, 20, 29, 251}, {113, 20, 29, 252}, {113, 20, 29, 253}}},
|
||||
{Region: "Iran", Group: "Premium TCP Europe", IPs: []net.IP{{45, 131, 4, 10}, {45, 131, 4, 16}, {45, 131, 4, 17}, {45, 131, 4, 18}, {45, 131, 4, 20}, {45, 131, 4, 21}, {45, 131, 4, 22}, {45, 131, 4, 24}, {45, 131, 4, 25}, {45, 131, 4, 28}}},
|
||||
{Region: "Iran", Group: "Premium UDP Europe", IPs: []net.IP{{45, 131, 4, 6}, {45, 131, 4, 8}, {45, 131, 4, 12}, {45, 131, 4, 14}, {45, 131, 4, 15}, {45, 131, 4, 20}, {45, 131, 4, 23}, {45, 131, 4, 24}, {45, 131, 4, 27}, {45, 131, 4, 28}}},
|
||||
{Region: "Ireland", Group: "Premium TCP Europe", IPs: []net.IP{{84, 247, 48, 3}, {84, 247, 48, 4}, {84, 247, 48, 5}, {84, 247, 48, 8}, {84, 247, 48, 9}, {84, 247, 48, 10}, {84, 247, 48, 11}, {84, 247, 48, 12}, {84, 247, 48, 19}, {84, 247, 48, 21}}},
|
||||
{Region: "Ireland", Group: "Premium UDP Europe", IPs: []net.IP{{84, 247, 48, 3}, {84, 247, 48, 13}, {84, 247, 48, 14}, {84, 247, 48, 20}, {84, 247, 48, 21}, {84, 247, 48, 23}, {84, 247, 48, 24}, {84, 247, 48, 25}, {84, 247, 48, 26}, {84, 247, 48, 27}}},
|
||||
{Region: "Isle of Man", Group: "Premium TCP Europe", IPs: []net.IP{{45, 132, 140, 7}, {45, 132, 140, 8}, {45, 132, 140, 10}, {45, 132, 140, 11}, {45, 132, 140, 15}, {45, 132, 140, 17}, {45, 132, 140, 18}, {45, 132, 140, 19}, {45, 132, 140, 27}, {45, 132, 140, 28}}},
|
||||
{Region: "Isle of Man", Group: "Premium UDP Europe", IPs: []net.IP{{45, 132, 140, 7}, {45, 132, 140, 9}, {45, 132, 140, 10}, {45, 132, 140, 16}, {45, 132, 140, 19}, {45, 132, 140, 20}, {45, 132, 140, 21}, {45, 132, 140, 25}, {45, 132, 140, 26}, {45, 132, 140, 28}}},
|
||||
{Region: "Israel", Group: "Premium TCP Europe", IPs: []net.IP{{160, 116, 0, 163}, {160, 116, 0, 164}, {160, 116, 0, 166}, {160, 116, 0, 167}, {160, 116, 0, 169}, {160, 116, 0, 170}, {160, 116, 0, 171}, {160, 116, 0, 172}, {160, 116, 0, 173}, {160, 116, 0, 174}}},
|
||||
{Region: "Israel", Group: "Premium UDP Europe", IPs: []net.IP{{160, 116, 0, 163}, {160, 116, 0, 165}, {160, 116, 0, 166}, {160, 116, 0, 167}, {160, 116, 0, 168}, {160, 116, 0, 169}, {160, 116, 0, 170}, {160, 116, 0, 172}, {160, 116, 0, 173}, {160, 116, 0, 174}}},
|
||||
{Region: "Italy", Group: "Premium TCP Europe", IPs: []net.IP{{84, 17, 58, 11}, {84, 17, 58, 19}, {87, 101, 94, 70}, {87, 101, 94, 116}, {185, 217, 71, 133}, {185, 217, 71, 137}, {212, 102, 55, 100}, {212, 102, 55, 123}, {212, 102, 55, 139}, {212, 102, 55, 184}}},
|
||||
{Region: "Italy", Group: "Premium UDP Europe", IPs: []net.IP{{84, 17, 58, 7}, {84, 17, 58, 100}, {84, 17, 58, 103}, {84, 17, 58, 104}, {87, 101, 94, 116}, {87, 101, 94, 124}, {185, 217, 71, 132}, {185, 217, 71, 134}, {212, 102, 55, 156}, {212, 102, 55, 167}}},
|
||||
{Region: "Japan", Group: "Premium TCP Asia", IPs: []net.IP{{156, 146, 35, 5}, {156, 146, 35, 8}, {156, 146, 35, 9}, {156, 146, 35, 17}, {156, 146, 35, 20}, {156, 146, 35, 33}, {156, 146, 35, 36}, {156, 146, 35, 42}, {156, 146, 35, 45}, {156, 146, 35, 50}}},
|
||||
{Region: "Japan", Group: "Premium UDP Asia", IPs: []net.IP{{156, 146, 35, 6}, {156, 146, 35, 8}, {156, 146, 35, 19}, {156, 146, 35, 22}, {156, 146, 35, 27}, {156, 146, 35, 32}, {156, 146, 35, 35}, {156, 146, 35, 37}, {156, 146, 35, 41}, {156, 146, 35, 47}}},
|
||||
{Region: "Kazakhstan", Group: "Premium TCP Europe", IPs: []net.IP{{45, 133, 88, 7}, {45, 133, 88, 11}, {45, 133, 88, 12}, {45, 133, 88, 13}, {45, 133, 88, 14}, {45, 133, 88, 20}, {45, 133, 88, 23}, {45, 133, 88, 24}, {45, 133, 88, 26}, {45, 133, 88, 28}}},
|
||||
{Region: "Kazakhstan", Group: "Premium UDP Europe", IPs: []net.IP{{45, 133, 88, 8}, {45, 133, 88, 12}, {45, 133, 88, 13}, {45, 133, 88, 15}, {45, 133, 88, 19}, {45, 133, 88, 20}, {45, 133, 88, 24}, {45, 133, 88, 25}, {45, 133, 88, 26}, {45, 133, 88, 28}}},
|
||||
{Region: "Kenya", Group: "Premium TCP Asia", IPs: []net.IP{{62, 12, 118, 195}, {62, 12, 118, 196}, {62, 12, 118, 197}, {62, 12, 118, 198}, {62, 12, 118, 199}, {62, 12, 118, 200}, {62, 12, 118, 201}, {62, 12, 118, 202}, {62, 12, 118, 203}, {62, 12, 118, 204}}},
|
||||
{Region: "Kenya", Group: "Premium UDP Asia", IPs: []net.IP{{62, 12, 118, 195}, {62, 12, 118, 196}, {62, 12, 118, 197}, {62, 12, 118, 198}, {62, 12, 118, 199}, {62, 12, 118, 200}, {62, 12, 118, 201}, {62, 12, 118, 202}, {62, 12, 118, 203}, {62, 12, 118, 204}}},
|
||||
{Region: "Korea", Group: "Premium TCP Asia", IPs: []net.IP{{27, 255, 75, 227}, {27, 255, 75, 229}, {27, 255, 75, 233}, {27, 255, 75, 234}, {27, 255, 75, 235}, {27, 255, 75, 236}, {27, 255, 75, 248}, {27, 255, 75, 249}, {27, 255, 75, 251}, {27, 255, 75, 254}}},
|
||||
{Region: "Korea", Group: "Premium UDP Asia", IPs: []net.IP{{27, 255, 75, 228}, {27, 255, 75, 229}, {27, 255, 75, 230}, {27, 255, 75, 231}, {27, 255, 75, 234}, {27, 255, 75, 235}, {27, 255, 75, 244}, {27, 255, 75, 245}, {27, 255, 75, 246}, {27, 255, 75, 247}}},
|
||||
{Region: "Latvia", Group: "Premium TCP Europe", IPs: []net.IP{{109, 248, 148, 244}, {109, 248, 148, 251}, {109, 248, 148, 252}, {109, 248, 148, 253}, {109, 248, 149, 19}, {109, 248, 149, 20}, {109, 248, 149, 21}, {109, 248, 149, 22}, {109, 248, 149, 24}, {109, 248, 149, 27}}},
|
||||
{Region: "Latvia", Group: "Premium UDP Europe", IPs: []net.IP{{109, 248, 148, 248}, {109, 248, 148, 252}, {109, 248, 148, 253}, {109, 248, 148, 254}, {109, 248, 149, 19}, {109, 248, 149, 20}, {109, 248, 149, 21}, {109, 248, 149, 24}, {109, 248, 149, 28}, {109, 248, 149, 29}}},
|
||||
{Region: "Liechtenstein", Group: "Premium TCP Europe", IPs: []net.IP{{45, 139, 48, 6}, {45, 139, 48, 7}, {45, 139, 48, 9}, {45, 139, 48, 16}, {45, 139, 48, 17}, {45, 139, 48, 19}, {45, 139, 48, 20}, {45, 139, 48, 22}, {45, 139, 48, 23}, {45, 139, 48, 27}}},
|
||||
{Region: "Liechtenstein", Group: "Premium UDP Europe", IPs: []net.IP{{45, 139, 48, 9}, {45, 139, 48, 12}, {45, 139, 48, 15}, {45, 139, 48, 16}, {45, 139, 48, 17}, {45, 139, 48, 18}, {45, 139, 48, 24}, {45, 139, 48, 26}, {45, 139, 48, 28}, {45, 139, 48, 29}}},
|
||||
{Region: "Lithuania", Group: "Premium TCP Europe", IPs: []net.IP{{85, 206, 162, 211}, {85, 206, 162, 213}, {85, 206, 162, 214}, {85, 206, 162, 216}, {85, 206, 162, 219}, {85, 206, 162, 220}, {85, 206, 165, 18}, {85, 206, 165, 20}, {85, 206, 165, 24}, {85, 206, 165, 25}}},
|
||||
{Region: "Lithuania", Group: "Premium UDP Europe", IPs: []net.IP{{85, 206, 162, 210}, {85, 206, 162, 211}, {85, 206, 162, 214}, {85, 206, 162, 215}, {85, 206, 162, 220}, {85, 206, 162, 221}, {85, 206, 162, 222}, {85, 206, 165, 18}, {85, 206, 165, 25}, {85, 206, 165, 26}}},
|
||||
{Region: "Luxembourg", Group: "Premium TCP Europe", IPs: []net.IP{{5, 253, 204, 5}, {5, 253, 204, 6}, {5, 253, 204, 9}, {5, 253, 204, 10}, {5, 253, 204, 12}, {5, 253, 204, 14}, {5, 253, 204, 20}, {5, 253, 204, 23}, {5, 253, 204, 29}, {5, 253, 204, 30}}},
|
||||
{Region: "Luxembourg", Group: "Premium UDP Europe", IPs: []net.IP{{5, 253, 204, 7}, {5, 253, 204, 11}, {5, 253, 204, 20}, {5, 253, 204, 22}, {5, 253, 204, 23}, {5, 253, 204, 26}, {5, 253, 204, 27}, {5, 253, 204, 28}, {5, 253, 204, 29}, {5, 253, 204, 30}}},
|
||||
{Region: "Macao", Group: "Premium TCP Asia", IPs: []net.IP{{45, 137, 197, 8}, {45, 137, 197, 9}, {45, 137, 197, 12}, {45, 137, 197, 14}, {45, 137, 197, 17}, {45, 137, 197, 33}, {45, 137, 197, 35}, {45, 137, 197, 42}, {45, 137, 197, 45}, {45, 137, 197, 47}}},
|
||||
{Region: "Macao", Group: "Premium UDP Asia", IPs: []net.IP{{45, 137, 197, 2}, {45, 137, 197, 7}, {45, 137, 197, 18}, {45, 137, 197, 19}, {45, 137, 197, 28}, {45, 137, 197, 30}, {45, 137, 197, 33}, {45, 137, 197, 35}, {45, 137, 197, 44}, {45, 137, 197, 47}}},
|
||||
{Region: "Macedonia", Group: "Premium TCP Europe", IPs: []net.IP{{185, 225, 28, 3}, {185, 225, 28, 4}, {185, 225, 28, 5}, {185, 225, 28, 6}, {185, 225, 28, 7}, {185, 225, 28, 8}, {185, 225, 28, 9}, {185, 225, 28, 10}, {185, 225, 28, 11}, {185, 225, 28, 12}}},
|
||||
{Region: "Macedonia", Group: "Premium UDP Europe", IPs: []net.IP{{185, 225, 28, 3}, {185, 225, 28, 4}, {185, 225, 28, 5}, {185, 225, 28, 6}, {185, 225, 28, 7}, {185, 225, 28, 8}, {185, 225, 28, 9}, {185, 225, 28, 10}, {185, 225, 28, 11}, {185, 225, 28, 12}}},
|
||||
{Region: "Malaysia", Group: "Premium TCP Asia", IPs: []net.IP{{139, 5, 177, 69}, {139, 5, 177, 70}, {139, 5, 177, 71}, {139, 5, 177, 72}, {139, 5, 177, 73}, {139, 5, 177, 74}, {139, 5, 177, 75}, {139, 5, 177, 76}, {139, 5, 177, 77}, {139, 5, 177, 78}}},
|
||||
{Region: "Malaysia", Group: "Premium UDP Asia", IPs: []net.IP{{139, 5, 177, 69}, {139, 5, 177, 70}, {139, 5, 177, 71}, {139, 5, 177, 72}, {139, 5, 177, 73}, {139, 5, 177, 74}, {139, 5, 177, 75}, {139, 5, 177, 76}, {139, 5, 177, 77}, {139, 5, 177, 78}}},
|
||||
{Region: "Malta", Group: "Premium TCP Europe", IPs: []net.IP{{45, 137, 198, 6}, {45, 137, 198, 8}, {45, 137, 198, 9}, {45, 137, 198, 11}, {45, 137, 198, 16}, {45, 137, 198, 18}, {45, 137, 198, 22}, {45, 137, 198, 23}, {45, 137, 198, 25}, {45, 137, 198, 27}}},
|
||||
{Region: "Malta", Group: "Premium UDP Europe", IPs: []net.IP{{45, 137, 198, 8}, {45, 137, 198, 10}, {45, 137, 198, 12}, {45, 137, 198, 13}, {45, 137, 198, 16}, {45, 137, 198, 17}, {45, 137, 198, 21}, {45, 137, 198, 23}, {45, 137, 198, 26}, {45, 137, 198, 28}}},
|
||||
{Region: "Mexico", Group: "Premium TCP USA", IPs: []net.IP{{45, 133, 180, 99}, {45, 133, 180, 106}, {45, 133, 180, 107}, {45, 133, 180, 108}, {45, 133, 180, 115}, {45, 133, 180, 118}, {45, 133, 180, 119}, {45, 133, 180, 121}, {45, 133, 180, 122}, {45, 133, 180, 123}}},
|
||||
{Region: "Mexico", Group: "Premium UDP USA", IPs: []net.IP{{45, 133, 180, 99}, {45, 133, 180, 101}, {45, 133, 180, 104}, {45, 133, 180, 105}, {45, 133, 180, 106}, {45, 133, 180, 115}, {45, 133, 180, 117}, {45, 133, 180, 118}, {45, 133, 180, 120}, {45, 133, 180, 121}}},
|
||||
{Region: "Moldova", Group: "Premium TCP Europe", IPs: []net.IP{{178, 175, 130, 243}, {178, 175, 130, 245}, {178, 175, 130, 250}, {178, 175, 130, 251}, {178, 175, 130, 253}, {178, 175, 130, 254}, {178, 175, 142, 131}, {178, 175, 142, 132}, {178, 175, 142, 133}, {178, 175, 142, 134}}},
|
||||
{Region: "Moldova", Group: "Premium UDP Europe", IPs: []net.IP{{178, 175, 130, 243}, {178, 175, 130, 244}, {178, 175, 130, 245}, {178, 175, 130, 246}, {178, 175, 130, 250}, {178, 175, 130, 251}, {178, 175, 130, 253}, {178, 175, 130, 254}, {178, 175, 142, 132}, {178, 175, 142, 133}}},
|
||||
{Region: "Monaco", Group: "Premium TCP Europe", IPs: []net.IP{{45, 137, 199, 7}, {45, 137, 199, 9}, {45, 137, 199, 11}, {45, 137, 199, 12}, {45, 137, 199, 14}, {45, 137, 199, 16}, {45, 137, 199, 20}, {45, 137, 199, 24}, {45, 137, 199, 25}, {45, 137, 199, 29}}},
|
||||
{Region: "Monaco", Group: "Premium UDP Europe", IPs: []net.IP{{45, 137, 199, 6}, {45, 137, 199, 7}, {45, 137, 199, 10}, {45, 137, 199, 16}, {45, 137, 199, 18}, {45, 137, 199, 22}, {45, 137, 199, 23}, {45, 137, 199, 24}, {45, 137, 199, 25}, {45, 137, 199, 27}}},
|
||||
{Region: "Mongolia", Group: "Premium TCP Asia", IPs: []net.IP{{45, 139, 51, 4}, {45, 139, 51, 13}, {45, 139, 51, 14}, {45, 139, 51, 17}, {45, 139, 51, 18}, {45, 139, 51, 22}, {45, 139, 51, 23}, {45, 139, 51, 32}, {45, 139, 51, 44}, {45, 139, 51, 48}}},
|
||||
{Region: "Mongolia", Group: "Premium UDP Asia", IPs: []net.IP{{45, 139, 51, 3}, {45, 139, 51, 6}, {45, 139, 51, 11}, {45, 139, 51, 12}, {45, 139, 51, 17}, {45, 139, 51, 20}, {45, 139, 51, 28}, {45, 139, 51, 30}, {45, 139, 51, 37}, {45, 139, 51, 41}}},
|
||||
{Region: "Montenegro", Group: "Premium TCP Europe", IPs: []net.IP{{45, 131, 208, 6}, {45, 131, 208, 7}, {45, 131, 208, 8}, {45, 131, 208, 9}, {45, 131, 208, 10}, {45, 131, 208, 13}, {45, 131, 208, 14}, {45, 131, 208, 20}, {45, 131, 208, 24}, {45, 131, 208, 28}}},
|
||||
{Region: "Montenegro", Group: "Premium UDP Europe", IPs: []net.IP{{45, 131, 208, 6}, {45, 131, 208, 8}, {45, 131, 208, 9}, {45, 131, 208, 12}, {45, 131, 208, 16}, {45, 131, 208, 20}, {45, 131, 208, 22}, {45, 131, 208, 24}, {45, 131, 208, 26}, {45, 131, 208, 28}}},
|
||||
{Region: "Morocco", Group: "Premium TCP Europe", IPs: []net.IP{{45, 131, 211, 6}, {45, 131, 211, 9}, {45, 131, 211, 11}, {45, 131, 211, 13}, {45, 131, 211, 18}, {45, 131, 211, 21}, {45, 131, 211, 22}, {45, 131, 211, 23}, {45, 131, 211, 28}, {45, 131, 211, 29}}},
|
||||
{Region: "Morocco", Group: "Premium UDP Europe", IPs: []net.IP{{45, 131, 211, 9}, {45, 131, 211, 10}, {45, 131, 211, 13}, {45, 131, 211, 18}, {45, 131, 211, 20}, {45, 131, 211, 21}, {45, 131, 211, 25}, {45, 131, 211, 26}, {45, 131, 211, 28}, {45, 131, 211, 29}}},
|
||||
{Region: "Netherlands", Group: "Premium TCP Europe", IPs: []net.IP{{84, 17, 47, 3}, {84, 17, 47, 20}, {84, 17, 47, 39}, {84, 17, 47, 42}, {84, 17, 47, 74}, {84, 17, 47, 111}, {139, 28, 217, 199}, {185, 132, 177, 136}, {190, 2, 149, 196}, {195, 181, 172, 69}}},
|
||||
{Region: "Netherlands", Group: "Premium UDP Europe", IPs: []net.IP{{84, 17, 47, 4}, {84, 17, 47, 8}, {84, 17, 47, 12}, {84, 17, 47, 38}, {84, 17, 47, 68}, {185, 132, 177, 235}, {190, 2, 149, 28}, {190, 2, 149, 30}, {190, 2, 149, 208}, {195, 181, 172, 79}}},
|
||||
{Region: "New Zealand", Group: "Premium TCP Asia", IPs: []net.IP{{103, 231, 91, 131}, {103, 231, 91, 132}, {103, 231, 91, 133}, {103, 231, 91, 134}, {103, 231, 91, 135}, {103, 231, 91, 136}, {103, 231, 91, 137}, {103, 231, 91, 138}, {103, 231, 91, 139}, {103, 231, 91, 140}}},
|
||||
{Region: "New Zealand", Group: "Premium UDP Asia", IPs: []net.IP{{103, 231, 91, 131}, {103, 231, 91, 132}, {103, 231, 91, 133}, {103, 231, 91, 134}, {103, 231, 91, 135}, {103, 231, 91, 136}, {103, 231, 91, 137}, {103, 231, 91, 138}, {103, 231, 91, 139}, {103, 231, 91, 140}}},
|
||||
{Region: "Nigeria", Group: "Premium TCP Europe", IPs: []net.IP{{45, 137, 196, 6}, {45, 137, 196, 10}, {45, 137, 196, 12}, {45, 137, 196, 13}, {45, 137, 196, 15}, {45, 137, 196, 16}, {45, 137, 196, 17}, {45, 137, 196, 20}, {45, 137, 196, 24}, {45, 137, 196, 29}}},
|
||||
{Region: "Nigeria", Group: "Premium UDP Europe", IPs: []net.IP{{45, 137, 196, 6}, {45, 137, 196, 7}, {45, 137, 196, 8}, {45, 137, 196, 9}, {45, 137, 196, 12}, {45, 137, 196, 13}, {45, 137, 196, 14}, {45, 137, 196, 20}, {45, 137, 196, 28}, {45, 137, 196, 29}}},
|
||||
{Region: "Norway", Group: "Premium TCP Europe", IPs: []net.IP{{45, 12, 223, 131}, {45, 12, 223, 135}, {45, 12, 223, 136}, {45, 12, 223, 138}, {185, 206, 225, 231}, {185, 206, 225, 233}, {185, 253, 97, 235}, {185, 253, 97, 236}, {185, 253, 97, 247}, {185, 253, 97, 253}}},
|
||||
{Region: "Norway", Group: "Premium UDP Europe", IPs: []net.IP{{45, 12, 223, 132}, {45, 12, 223, 137}, {45, 12, 223, 138}, {45, 12, 223, 141}, {185, 206, 225, 27}, {185, 206, 225, 30}, {185, 253, 97, 245}, {185, 253, 97, 246}, {185, 253, 97, 248}, {185, 253, 97, 249}}},
|
||||
{Region: "Pakistan", Group: "Premium TCP Europe", IPs: []net.IP{{103, 76, 3, 244}, {103, 76, 3, 245}, {103, 76, 3, 246}, {103, 76, 3, 247}, {103, 76, 3, 248}, {103, 76, 3, 249}, {103, 76, 3, 250}, {103, 76, 3, 251}, {103, 76, 3, 252}, {103, 76, 3, 253}}},
|
||||
{Region: "Pakistan", Group: "Premium UDP Europe", IPs: []net.IP{{103, 76, 3, 244}, {103, 76, 3, 245}, {103, 76, 3, 246}, {103, 76, 3, 247}, {103, 76, 3, 248}, {103, 76, 3, 249}, {103, 76, 3, 250}, {103, 76, 3, 251}, {103, 76, 3, 252}, {103, 76, 3, 253}}},
|
||||
{Region: "Panama", Group: "Premium TCP Europe", IPs: []net.IP{{45, 131, 210, 9}, {45, 131, 210, 10}, {45, 131, 210, 14}, {45, 131, 210, 15}, {45, 131, 210, 16}, {45, 131, 210, 21}, {45, 131, 210, 22}, {45, 131, 210, 23}, {45, 131, 210, 24}, {45, 131, 210, 26}}},
|
||||
{Region: "Panama", Group: "Premium UDP Europe", IPs: []net.IP{{45, 131, 210, 6}, {45, 131, 210, 8}, {45, 131, 210, 9}, {45, 131, 210, 12}, {45, 131, 210, 14}, {45, 131, 210, 18}, {45, 131, 210, 19}, {45, 131, 210, 25}, {45, 131, 210, 28}, {45, 131, 210, 29}}},
|
||||
{Region: "Philippines", Group: "Premium TCP Asia", IPs: []net.IP{{188, 214, 125, 39}, {188, 214, 125, 45}, {188, 214, 125, 47}, {188, 214, 125, 49}, {188, 214, 125, 50}, {188, 214, 125, 51}, {188, 214, 125, 53}, {188, 214, 125, 57}, {188, 214, 125, 58}, {188, 214, 125, 61}}},
|
||||
{Region: "Philippines", Group: "Premium UDP Asia", IPs: []net.IP{{188, 214, 125, 35}, {188, 214, 125, 36}, {188, 214, 125, 37}, {188, 214, 125, 48}, {188, 214, 125, 55}, {188, 214, 125, 56}, {188, 214, 125, 57}, {188, 214, 125, 58}, {188, 214, 125, 59}, {188, 214, 125, 62}}},
|
||||
{Region: "Poland", Group: "Premium TCP Europe", IPs: []net.IP{{37, 120, 156, 11}, {37, 120, 156, 17}, {37, 120, 156, 23}, {37, 120, 156, 25}, {37, 120, 156, 26}, {51, 75, 56, 35}, {51, 75, 56, 37}, {51, 75, 56, 41}, {54, 37, 238, 36}, {54, 37, 238, 43}}},
|
||||
{Region: "Poland", Group: "Premium UDP Europe", IPs: []net.IP{{37, 120, 156, 8}, {37, 120, 156, 10}, {37, 120, 156, 12}, {37, 120, 156, 18}, {37, 120, 156, 19}, {37, 120, 156, 24}, {51, 75, 56, 33}, {51, 75, 56, 40}, {51, 75, 56, 41}, {54, 37, 238, 33}}},
|
||||
{Region: "Portugal", Group: "Premium TCP Europe", IPs: []net.IP{{89, 26, 243, 47}, {89, 26, 243, 48}, {89, 26, 243, 50}, {89, 26, 243, 51}, {89, 26, 243, 54}, {89, 26, 243, 58}, {89, 26, 243, 60}, {185, 90, 57, 172}, {185, 90, 57, 176}, {185, 90, 57, 179}}},
|
||||
{Region: "Portugal", Group: "Premium UDP Europe", IPs: []net.IP{{89, 26, 243, 47}, {89, 26, 243, 50}, {89, 26, 243, 51}, {89, 26, 243, 53}, {89, 26, 243, 58}, {185, 90, 57, 173}, {185, 90, 57, 175}, {185, 90, 57, 176}, {185, 90, 57, 178}, {185, 90, 57, 179}}},
|
||||
{Region: "Qatar", Group: "Premium TCP Europe", IPs: []net.IP{{45, 131, 7, 6}, {45, 131, 7, 9}, {45, 131, 7, 10}, {45, 131, 7, 13}, {45, 131, 7, 16}, {45, 131, 7, 17}, {45, 131, 7, 20}, {45, 131, 7, 22}, {45, 131, 7, 23}, {45, 131, 7, 28}}},
|
||||
{Region: "Qatar", Group: "Premium UDP Europe", IPs: []net.IP{{45, 131, 7, 8}, {45, 131, 7, 9}, {45, 131, 7, 14}, {45, 131, 7, 15}, {45, 131, 7, 16}, {45, 131, 7, 17}, {45, 131, 7, 23}, {45, 131, 7, 27}, {45, 131, 7, 28}, {45, 131, 7, 29}}},
|
||||
{Region: "Romania", Group: "NoSpy TCP Europe", IPs: []net.IP{{85, 9, 20, 134}, {85, 9, 20, 135}, {85, 9, 20, 137}, {85, 9, 20, 138}, {85, 9, 20, 139}, {85, 9, 20, 147}, {85, 9, 20, 149}, {85, 9, 20, 154}, {85, 9, 20, 248}, {85, 9, 20, 249}}},
|
||||
{Region: "Romania", Group: "NoSpy UDP Europe", IPs: []net.IP{{85, 9, 20, 134}, {85, 9, 20, 138}, {85, 9, 20, 139}, {85, 9, 20, 144}, {85, 9, 20, 145}, {85, 9, 20, 147}, {85, 9, 20, 148}, {85, 9, 20, 151}, {85, 9, 20, 248}, {85, 9, 20, 249}}},
|
||||
{Region: "Romania", Group: "Premium TCP Europe", IPs: []net.IP{{193, 176, 84, 44}, {193, 176, 84, 49}, {193, 176, 84, 51}, {193, 176, 84, 52}, {193, 176, 84, 88}, {193, 176, 84, 121}, {193, 176, 84, 126}, {193, 176, 85, 72}, {193, 176, 85, 74}, {193, 176, 85, 101}}},
|
||||
{Region: "Romania", Group: "Premium UDP Europe", IPs: []net.IP{{193, 176, 84, 46}, {193, 176, 84, 47}, {193, 176, 84, 48}, {193, 176, 84, 49}, {193, 176, 84, 90}, {193, 176, 84, 125}, {193, 176, 85, 68}, {193, 176, 85, 72}, {193, 176, 85, 78}, {193, 176, 85, 91}}},
|
||||
{Region: "Russian Federation", Group: "Premium TCP Europe", IPs: []net.IP{{45, 132, 192, 42}, {45, 132, 192, 43}, {45, 132, 192, 49}, {45, 132, 192, 60}, {45, 132, 192, 63}, {45, 132, 192, 66}, {45, 132, 192, 78}, {45, 132, 192, 80}, {45, 132, 192, 85}, {45, 132, 192, 96}}},
|
||||
{Region: "Russian Federation", Group: "Premium UDP Europe", IPs: []net.IP{{45, 132, 192, 11}, {45, 132, 192, 15}, {45, 132, 192, 24}, {45, 132, 192, 32}, {45, 132, 192, 43}, {45, 132, 192, 49}, {45, 132, 192, 55}, {45, 132, 192, 63}, {45, 132, 192, 65}, {45, 132, 192, 95}}},
|
||||
{Region: "Saudi Arabia", Group: "Premium TCP Europe", IPs: []net.IP{{45, 131, 6, 7}, {45, 131, 6, 10}, {45, 131, 6, 12}, {45, 131, 6, 13}, {45, 131, 6, 21}, {45, 131, 6, 23}, {45, 131, 6, 24}, {45, 131, 6, 25}, {45, 131, 6, 26}, {45, 131, 6, 28}}},
|
||||
{Region: "Saudi Arabia", Group: "Premium UDP Europe", IPs: []net.IP{{45, 131, 6, 7}, {45, 131, 6, 9}, {45, 131, 6, 14}, {45, 131, 6, 15}, {45, 131, 6, 18}, {45, 131, 6, 19}, {45, 131, 6, 22}, {45, 131, 6, 24}, {45, 131, 6, 28}, {45, 131, 6, 29}}},
|
||||
{Region: "Serbia", Group: "Premium TCP Europe", IPs: []net.IP{{37, 120, 193, 179}, {37, 120, 193, 181}, {37, 120, 193, 182}, {37, 120, 193, 183}, {37, 120, 193, 184}, {37, 120, 193, 186}, {37, 120, 193, 190}, {141, 98, 103, 37}, {141, 98, 103, 43}, {141, 98, 103, 46}}},
|
||||
{Region: "Serbia", Group: "Premium UDP Europe", IPs: []net.IP{{37, 120, 193, 179}, {37, 120, 193, 182}, {37, 120, 193, 183}, {37, 120, 193, 188}, {37, 120, 193, 189}, {37, 120, 193, 190}, {141, 98, 103, 35}, {141, 98, 103, 40}, {141, 98, 103, 42}, {141, 98, 103, 46}}},
|
||||
{Region: "Singapore", Group: "Premium TCP Asia", IPs: []net.IP{{37, 120, 151, 55}, {37, 120, 151, 60}, {37, 120, 151, 131}, {37, 120, 151, 139}, {84, 17, 39, 168}, {84, 17, 39, 175}, {84, 17, 39, 176}, {84, 17, 39, 179}, {84, 17, 39, 182}, {84, 17, 39, 185}}},
|
||||
{Region: "Singapore", Group: "Premium UDP Asia", IPs: []net.IP{{37, 120, 151, 51}, {37, 120, 151, 57}, {37, 120, 151, 131}, {37, 120, 151, 132}, {37, 120, 151, 140}, {37, 120, 151, 141}, {84, 17, 39, 165}, {84, 17, 39, 169}, {84, 17, 39, 171}, {84, 17, 39, 180}}},
|
||||
{Region: "Slovakia", Group: "Premium TCP Europe", IPs: []net.IP{{185, 245, 85, 227}, {185, 245, 85, 228}, {185, 245, 85, 229}, {185, 245, 85, 230}, {185, 245, 85, 231}, {185, 245, 85, 232}, {185, 245, 85, 233}, {185, 245, 85, 234}, {185, 245, 85, 235}, {185, 245, 85, 236}}},
|
||||
{Region: "Slovakia", Group: "Premium UDP Europe", IPs: []net.IP{{185, 245, 85, 227}, {185, 245, 85, 228}, {185, 245, 85, 229}, {185, 245, 85, 230}, {185, 245, 85, 231}, {185, 245, 85, 232}, {185, 245, 85, 233}, {185, 245, 85, 234}, {185, 245, 85, 235}, {185, 245, 85, 236}}},
|
||||
{Region: "Slovenia", Group: "Premium TCP Europe", IPs: []net.IP{{146, 247, 25, 79}, {146, 247, 25, 80}, {146, 247, 25, 81}, {146, 247, 25, 83}, {146, 247, 25, 84}, {146, 247, 25, 85}, {146, 247, 25, 86}, {146, 247, 25, 87}, {146, 247, 25, 88}, {146, 247, 25, 90}}},
|
||||
{Region: "Slovenia", Group: "Premium UDP Europe", IPs: []net.IP{{146, 247, 25, 80}, {146, 247, 25, 81}, {146, 247, 25, 82}, {146, 247, 25, 83}, {146, 247, 25, 84}, {146, 247, 25, 85}, {146, 247, 25, 86}, {146, 247, 25, 87}, {146, 247, 25, 88}, {146, 247, 25, 89}}},
|
||||
{Region: "South Africa", Group: "Premium TCP Asia", IPs: []net.IP{{165, 73, 248, 211}, {165, 73, 248, 214}, {165, 73, 248, 222}, {165, 73, 248, 227}, {165, 73, 248, 229}, {165, 73, 248, 230}, {165, 73, 248, 231}, {165, 73, 248, 234}, {165, 73, 248, 236}, {165, 73, 248, 237}}},
|
||||
{Region: "South Africa", Group: "Premium TCP Europe", IPs: []net.IP{{197, 85, 7, 26}, {197, 85, 7, 27}, {197, 85, 7, 28}, {197, 85, 7, 29}, {197, 85, 7, 30}, {197, 85, 7, 31}, {197, 85, 7, 131}, {197, 85, 7, 132}, {197, 85, 7, 133}, {197, 85, 7, 134}}},
|
||||
{Region: "South Africa", Group: "Premium UDP Asia", IPs: []net.IP{{165, 73, 248, 212}, {165, 73, 248, 215}, {165, 73, 248, 217}, {165, 73, 248, 218}, {165, 73, 248, 219}, {165, 73, 248, 222}, {165, 73, 248, 227}, {165, 73, 248, 230}, {165, 73, 248, 234}, {165, 73, 248, 237}}},
|
||||
{Region: "South Africa", Group: "Premium UDP Europe", IPs: []net.IP{{197, 85, 7, 26}, {197, 85, 7, 27}, {197, 85, 7, 28}, {197, 85, 7, 29}, {197, 85, 7, 30}, {197, 85, 7, 31}, {197, 85, 7, 131}, {197, 85, 7, 132}, {197, 85, 7, 133}, {197, 85, 7, 134}}},
|
||||
{Region: "Spain", Group: "Premium TCP Europe", IPs: []net.IP{{37, 120, 142, 163}, {37, 120, 142, 166}, {37, 120, 142, 167}, {84, 17, 62, 138}, {84, 17, 62, 141}, {84, 17, 62, 145}, {84, 17, 62, 147}, {84, 17, 62, 152}, {185, 93, 3, 113}, {185, 93, 182, 139}}},
|
||||
{Region: "Spain", Group: "Premium UDP Europe", IPs: []net.IP{{37, 120, 142, 150}, {37, 120, 142, 157}, {37, 120, 142, 165}, {84, 17, 62, 139}, {84, 17, 62, 142}, {185, 93, 3, 109}, {185, 93, 3, 111}, {185, 93, 3, 113}, {185, 93, 182, 136}, {185, 93, 182, 138}}},
|
||||
{Region: "Sri Lanka", Group: "Premium TCP Europe", IPs: []net.IP{{45, 132, 136, 6}, {45, 132, 136, 7}, {45, 132, 136, 8}, {45, 132, 136, 12}, {45, 132, 136, 13}, {45, 132, 136, 17}, {45, 132, 136, 21}, {45, 132, 136, 22}, {45, 132, 136, 26}, {45, 132, 136, 27}}},
|
||||
{Region: "Sri Lanka", Group: "Premium UDP Europe", IPs: []net.IP{{45, 132, 136, 7}, {45, 132, 136, 9}, {45, 132, 136, 10}, {45, 132, 136, 11}, {45, 132, 136, 12}, {45, 132, 136, 15}, {45, 132, 136, 20}, {45, 132, 136, 21}, {45, 132, 136, 27}, {45, 132, 136, 29}}},
|
||||
{Region: "Sweden", Group: "Premium TCP Europe", IPs: []net.IP{{46, 246, 65, 151}, {46, 246, 65, 156}, {46, 246, 65, 157}, {46, 246, 65, 167}, {46, 246, 65, 203}, {46, 246, 65, 221}, {91, 132, 138, 51}, {188, 126, 64, 101}, {188, 126, 66, 3}, {188, 126, 66, 8}}},
|
||||
{Region: "Sweden", Group: "Premium UDP Europe", IPs: []net.IP{{46, 246, 65, 167}, {46, 246, 65, 170}, {46, 246, 65, 172}, {46, 246, 65, 181}, {46, 246, 65, 214}, {46, 246, 65, 215}, {91, 132, 138, 57}, {188, 126, 66, 8}, {188, 126, 66, 24}, {188, 126, 66, 29}}},
|
||||
{Region: "Switzerland", Group: "Premium TCP Europe", IPs: []net.IP{{84, 17, 52, 14}, {84, 17, 52, 39}, {84, 17, 52, 68}, {84, 17, 52, 73}, {84, 17, 52, 84}, {89, 187, 165, 131}, {185, 32, 222, 8}, {185, 32, 222, 105}, {195, 225, 118, 38}, {195, 225, 118, 56}}},
|
||||
{Region: "Switzerland", Group: "Premium UDP Europe", IPs: []net.IP{{84, 17, 52, 15}, {84, 17, 52, 20}, {84, 17, 52, 36}, {84, 17, 52, 52}, {84, 17, 52, 62}, {84, 17, 52, 75}, {91, 132, 136, 174}, {91, 132, 136, 205}, {91, 132, 136, 206}, {185, 32, 222, 113}}},
|
||||
{Region: "Taiwan", Group: "Premium TCP Asia", IPs: []net.IP{{45, 133, 181, 102}, {45, 133, 181, 105}, {45, 133, 181, 106}, {45, 133, 181, 108}, {45, 133, 181, 110}, {45, 133, 181, 112}, {45, 133, 181, 114}, {45, 133, 181, 117}, {45, 133, 181, 120}, {45, 133, 181, 124}}},
|
||||
{Region: "Taiwan", Group: "Premium UDP Asia", IPs: []net.IP{{45, 133, 181, 102}, {45, 133, 181, 103}, {45, 133, 181, 110}, {45, 133, 181, 111}, {45, 133, 181, 112}, {45, 133, 181, 114}, {45, 133, 181, 118}, {45, 133, 181, 120}, {45, 133, 181, 125}, {45, 133, 181, 126}}},
|
||||
{Region: "Thailand", Group: "Premium TCP Asia", IPs: []net.IP{{119, 59, 98, 238}, {119, 59, 98, 239}, {119, 59, 98, 243}, {119, 59, 98, 244}, {119, 59, 98, 248}, {119, 59, 98, 249}, {119, 59, 121, 165}, {119, 59, 121, 166}, {119, 59, 121, 171}, {119, 59, 121, 173}}},
|
||||
{Region: "Thailand", Group: "Premium UDP Asia", IPs: []net.IP{{119, 59, 98, 214}, {119, 59, 98, 238}, {119, 59, 98, 244}, {119, 59, 98, 247}, {119, 59, 121, 163}, {119, 59, 121, 165}, {119, 59, 121, 166}, {119, 59, 121, 167}, {119, 59, 121, 173}, {119, 59, 121, 175}}},
|
||||
{Region: "Turkey", Group: "Premium TCP Europe", IPs: []net.IP{{188, 213, 34, 9}, {188, 213, 34, 22}, {188, 213, 34, 24}, {188, 213, 34, 27}, {188, 213, 34, 28}, {188, 213, 34, 35}, {188, 213, 34, 41}, {188, 213, 34, 44}, {188, 213, 34, 45}, {188, 213, 34, 46}}},
|
||||
{Region: "Turkey", Group: "Premium UDP Europe", IPs: []net.IP{{188, 213, 34, 3}, {188, 213, 34, 13}, {188, 213, 34, 18}, {188, 213, 34, 25}, {188, 213, 34, 27}, {188, 213, 34, 30}, {188, 213, 34, 35}, {188, 213, 34, 37}, {188, 213, 34, 38}, {188, 213, 34, 44}}},
|
||||
{Region: "Ukraine", Group: "Premium TCP Europe", IPs: []net.IP{{31, 28, 161, 21}, {31, 28, 163, 34}, {31, 28, 163, 35}, {31, 28, 163, 38}, {31, 28, 163, 50}, {62, 149, 7, 164}, {62, 149, 7, 167}, {62, 149, 29, 50}, {62, 149, 29, 53}, {62, 149, 29, 56}}},
|
||||
{Region: "Ukraine", Group: "Premium UDP Europe", IPs: []net.IP{{31, 28, 161, 20}, {31, 28, 161, 28}, {31, 28, 161, 30}, {31, 28, 163, 37}, {31, 28, 163, 45}, {31, 28, 163, 53}, {31, 28, 163, 56}, {31, 28, 163, 59}, {62, 149, 7, 168}, {62, 149, 29, 56}}},
|
||||
{Region: "United Arab Emirates", Group: "Premium TCP Europe", IPs: []net.IP{{45, 131, 5, 6}, {45, 131, 5, 9}, {45, 131, 5, 12}, {45, 131, 5, 14}, {45, 131, 5, 16}, {45, 131, 5, 17}, {45, 131, 5, 18}, {45, 131, 5, 27}, {45, 131, 5, 28}, {45, 131, 5, 29}}},
|
||||
{Region: "United Arab Emirates", Group: "Premium UDP Europe", IPs: []net.IP{{45, 131, 5, 8}, {45, 131, 5, 14}, {45, 131, 5, 15}, {45, 131, 5, 20}, {45, 131, 5, 22}, {45, 131, 5, 23}, {45, 131, 5, 24}, {45, 131, 5, 26}, {45, 131, 5, 28}, {45, 131, 5, 29}}},
|
||||
{Region: "United Kingdom", Group: "Premium TCP Europe", IPs: []net.IP{{37, 120, 133, 134}, {37, 120, 133, 140}, {84, 17, 51, 32}, {84, 17, 51, 75}, {89, 238, 138, 243}, {89, 238, 183, 230}, {95, 154, 200, 144}, {95, 154, 200, 186}, {141, 98, 100, 56}, {141, 98, 100, 61}}},
|
||||
{Region: "United Kingdom", Group: "Premium UDP Europe", IPs: []net.IP{{37, 120, 133, 134}, {37, 120, 159, 35}, {81, 92, 206, 172}, {84, 17, 51, 34}, {84, 17, 51, 110}, {84, 17, 51, 115}, {89, 238, 135, 59}, {95, 154, 200, 147}, {95, 154, 200, 149}, {141, 98, 100, 58}}},
|
||||
{Region: "United States", Group: "Premium TCP USA", IPs: []net.IP{{23, 105, 160, 184}, {38, 131, 126, 150}, {84, 17, 35, 32}, {89, 187, 182, 7}, {89, 187, 182, 31}, {176, 113, 72, 153}, {176, 113, 72, 167}, {192, 96, 203, 150}, {199, 115, 119, 238}, {212, 102, 41, 4}}},
|
||||
{Region: "United States", Group: "Premium UDP USA", IPs: []net.IP{{23, 19, 68, 56}, {23, 82, 78, 29}, {23, 105, 191, 36}, {23, 105, 191, 51}, {84, 17, 35, 8}, {89, 187, 171, 138}, {108, 62, 96, 33}, {176, 113, 72, 151}, {192, 96, 203, 154}, {199, 115, 117, 70}}},
|
||||
{Region: "Venezuela", Group: "Premium TCP Europe", IPs: []net.IP{{45, 133, 89, 6}, {45, 133, 89, 9}, {45, 133, 89, 11}, {45, 133, 89, 15}, {45, 133, 89, 17}, {45, 133, 89, 18}, {45, 133, 89, 22}, {45, 133, 89, 24}, {45, 133, 89, 26}, {45, 133, 89, 29}}},
|
||||
{Region: "Venezuela", Group: "Premium UDP Europe", IPs: []net.IP{{45, 133, 89, 8}, {45, 133, 89, 9}, {45, 133, 89, 15}, {45, 133, 89, 17}, {45, 133, 89, 21}, {45, 133, 89, 22}, {45, 133, 89, 25}, {45, 133, 89, 26}, {45, 133, 89, 27}, {45, 133, 89, 29}}},
|
||||
{Region: "Vietnam", Group: "Premium TCP Asia", IPs: []net.IP{{45, 117, 79, 118}, {45, 117, 79, 123}, {45, 117, 79, 124}, {45, 117, 79, 125}, {103, 238, 214, 131}, {103, 238, 214, 134}, {103, 238, 214, 135}, {103, 238, 214, 136}, {103, 238, 214, 137}, {103, 238, 214, 140}}},
|
||||
{Region: "Vietnam", Group: "Premium UDP Asia", IPs: []net.IP{{45, 117, 79, 114}, {45, 117, 79, 116}, {45, 117, 79, 117}, {45, 117, 79, 118}, {45, 117, 79, 123}, {103, 238, 214, 134}, {103, 238, 214, 135}, {103, 238, 214, 136}, {103, 238, 214, 137}, {103, 238, 214, 140}}},
|
||||
}
|
||||
}
|
||||
@@ -27,37 +27,43 @@ const (
|
||||
// to their data such as IP addresses or TLS host name.
|
||||
func DNSProviderMapping() map[models.DNSProvider]models.DNSProviderData {
|
||||
return map[models.DNSProvider]models.DNSProviderData{
|
||||
Cloudflare: models.DNSProviderData{
|
||||
IPs: []net.IP{{1, 1, 1, 1}, {1, 0, 0, 1}},
|
||||
SupportsTLS: true,
|
||||
Host: models.DNSHost("cloudflare-dns.com"),
|
||||
Cloudflare: {
|
||||
IPs: []net.IP{{1, 1, 1, 1}, {1, 0, 0, 1}, {0x26, 0x6, 0x47, 0x0, 0x47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11}, {0x26, 0x6, 0x47, 0x0, 0x47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x01}},
|
||||
SupportsTLS: true,
|
||||
SupportsIPv6: true,
|
||||
Host: models.DNSHost("cloudflare-dns.com"),
|
||||
},
|
||||
Google: models.DNSProviderData{
|
||||
IPs: []net.IP{{8, 8, 8, 8}, {8, 8, 4, 4}},
|
||||
SupportsTLS: true,
|
||||
Host: models.DNSHost("dns.google"),
|
||||
Google: {
|
||||
IPs: []net.IP{{8, 8, 8, 8}, {8, 8, 4, 4}, {0x20, 0x1, 0x48, 0x60, 0x48, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x88, 0x88}, {0x20, 0x1, 0x48, 0x60, 0x48, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x88, 0x44}},
|
||||
SupportsTLS: true,
|
||||
SupportsIPv6: true,
|
||||
Host: models.DNSHost("dns.google"),
|
||||
},
|
||||
Quad9: models.DNSProviderData{
|
||||
IPs: []net.IP{{9, 9, 9, 9}, {149, 112, 112, 112}},
|
||||
SupportsTLS: true,
|
||||
Host: models.DNSHost("dns.quad9.net"),
|
||||
Quad9: {
|
||||
IPs: []net.IP{{9, 9, 9, 9}, {149, 112, 112, 112}, {0x26, 0x20, 0x0, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe}, {0x26, 0x20, 0x0, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9}},
|
||||
SupportsTLS: true,
|
||||
SupportsIPv6: true,
|
||||
Host: models.DNSHost("dns.quad9.net"),
|
||||
},
|
||||
Quadrant: models.DNSProviderData{
|
||||
IPs: []net.IP{{12, 159, 2, 159}},
|
||||
SupportsTLS: true,
|
||||
Host: models.DNSHost("dns-tls.qis.io"),
|
||||
Quadrant: {
|
||||
IPs: []net.IP{{12, 159, 2, 159}, {0x20, 0x1, 0x18, 0x90, 0x14, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x59}},
|
||||
SupportsTLS: true,
|
||||
SupportsIPv6: true,
|
||||
Host: models.DNSHost("dns-tls.qis.io"),
|
||||
},
|
||||
CleanBrowsing: models.DNSProviderData{
|
||||
IPs: []net.IP{{185, 228, 168, 9}, {185, 228, 169, 9}},
|
||||
SupportsTLS: true,
|
||||
Host: models.DNSHost("security-filter-dns.cleanbrowsing.org"),
|
||||
CleanBrowsing: {
|
||||
IPs: []net.IP{{185, 228, 168, 9}, {185, 228, 169, 9}, {0x2a, 0xd, 0x2a, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}, {0x2a, 0xd, 0x2a, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2}},
|
||||
SupportsTLS: true,
|
||||
SupportsIPv6: true,
|
||||
Host: models.DNSHost("security-filter-dns.cleanbrowsing.org"),
|
||||
},
|
||||
SecureDNS: models.DNSProviderData{
|
||||
IPs: []net.IP{{146, 185, 167, 43}},
|
||||
SupportsTLS: true,
|
||||
Host: models.DNSHost("dot.securedns.eu"),
|
||||
SecureDNS: {
|
||||
IPs: []net.IP{{146, 185, 167, 43}, {0x2a, 0x3, 0xb0, 0xc0, 0x0, 0x0, 0x10, 0x10, 0x0, 0x0, 0x0, 0x0, 0xe, 0x9a, 0x30, 0x1}},
|
||||
SupportsTLS: true,
|
||||
SupportsIPv6: true,
|
||||
Host: models.DNSHost("dot.securedns.eu"),
|
||||
},
|
||||
LibreDNS: models.DNSProviderData{
|
||||
LibreDNS: {
|
||||
IPs: []net.IP{{116, 203, 115, 192}},
|
||||
SupportsTLS: true,
|
||||
Host: models.DNSHost("dot.libredns.gr"),
|
||||
|
||||
677
internal/constants/mullvad.go
Normal file
677
internal/constants/mullvad.go
Normal file
@@ -0,0 +1,677 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sort"
|
||||
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
const (
|
||||
MullvadCertificate = "MIIGIzCCBAugAwIBAgIJAK6BqXN9GHI0MA0GCSqGSIb3DQEBCwUAMIGfMQswCQYDVQQGEwJTRTERMA8GA1UECAwIR290YWxhbmQxEzARBgNVBAcMCkdvdGhlbmJ1cmcxFDASBgNVBAoMC0FtYWdpY29tIEFCMRAwDgYDVQQLDAdNdWxsdmFkMRswGQYDVQQDDBJNdWxsdmFkIFJvb3QgQ0EgdjIxIzAhBgkqhkiG9w0BCQEWFHNlY3VyaXR5QG11bGx2YWQubmV0MB4XDTE4MTEwMjExMTYxMVoXDTI4MTAzMDExMTYxMVowgZ8xCzAJBgNVBAYTAlNFMREwDwYDVQQIDAhHb3RhbGFuZDETMBEGA1UEBwwKR290aGVuYnVyZzEUMBIGA1UECgwLQW1hZ2ljb20gQUIxEDAOBgNVBAsMB011bGx2YWQxGzAZBgNVBAMMEk11bGx2YWQgUm9vdCBDQSB2MjEjMCEGCSqGSIb3DQEJARYUc2VjdXJpdHlAbXVsbHZhZC5uZXQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCifDn75E/Zdx1qsy31rMEzuvbTXqZVZp4bjWbmcyyXqvnayRUHHoovG+lzc+HDL3HJV+kjxKpCMkEVWwjY159lJbQbm8kkYntBBREdzRRjjJpTb6haf/NXeOtQJ9aVlCc4dM66bEmyAoXkzXVZTQJ8h2FE55KVxHi5Sdy4XC5zm0wPa4DPDokNp1qm3A9Xicq3HsflLbMZRCAGuI+Jek6caHqiKjTHtujn6Gfxv2WsZ7SjerUAk+mvBo2sfKmB7octxG7yAOFFg7YsWL0AxddBWqgq5R/1WDJ9d1Cwun9WGRRQ1TLvzF1yABUerjjKrk89RCzYISwsKcgJPscaDqZgO6RIruY/xjuTtrnZSv+FXs+Woxf87P+QgQd76LC0MstTnys+AfTMuMPOLy9fMfEzs3LP0Nz6v5yjhX8ff7+3UUI3IcMxCvyxdTPClY5IvFdW7CCmmLNzakmx5GCItBWg/EIg1K1SG0jU9F8vlNZUqLKz42hWy/xB5C4QYQQ9ILdu4araPnrXnmd1D1QKVwKQ1DpWhNbpBDfE776/4xXD/tGM5O0TImp1NXul8wYsDi8g+e0pxNgY3Pahnj1yfG75Yw82spZanUH0QSNoMVMWnmV2hXGsWqypRq0pH8mPeLzeKa82gzsAZsouRD1k8wFlYA4z9HQFxqfcntTqXuwQcQIDAQABo2AwXjAdBgNVHQ4EFgQUfaEyaBpGNzsqttiSMETq+X/GJ0YwHwYDVR0jBBgwFoAUfaEyaBpGNzsqttiSMETq+X/GJ0YwCwYDVR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBADH5izxu4V8Javal8EA4DxZxIHUsWCg5cuopB28PsyJYpyKipsBoI8+RXqbtrLLue4WQfNPZHLXlKi+A3GTrLdlnenYzXVipPd+n3vRZyofaB3Jtb03nirVWGa8FG21Xy/f4rPqwcW54lxrnnh0SA0hwuZ+b2yAWESBXPxrzVQdTWCqoFI6/aRnN8RyZn0LqRYoW7WDtKpLmfyvshBmmu4PCYSh/SYiFHgR9fsWzVcxdySDsmX8wXowuFfp8V9sFhD4TsebAaplaICOuLUgj+Yin5QzgB0F9Ci3Zh6oWwl64SL/OxxQLpzMWzr0lrWsQrS3PgC4+6JC4IpTXX5eUqfSvHPtbRKK0yLnd9hYgvZUBvvZvUFR/3/fW+mpBHbZJBu9+/1uux46M4rJ2FeaJUf9PhYCPuUj63yu0Grn0DreVKK1SkD5V6qXN0TmoxYyguhfsIPCpI1VsdaSWuNjJ+a/HIlKIU8vKp5iN/+6ZTPAg9Q7s3Ji+vfx/AhFtQyTpIYNszVzNZyobvkiMUlK+eUKGlHVQp73y6MmGIlbBbyzpEoedNU4uFu57mw4fYGHqYZmYqFaiNQv4tVrGkg6p+Ypyu1zOfIHF7eqlAOu/SyRTvZkt9VtSVEOVH7nDIGdrCC9U/g1Lqk8Td00Oj8xesyKzsG214Xd8m7/7GmJ7nXe5"
|
||||
)
|
||||
|
||||
func MullvadCountryChoices() (choices []string) {
|
||||
uniqueChoices := map[string]struct{}{}
|
||||
for _, server := range mullvadServers() {
|
||||
uniqueChoices[server.Country] = struct{}{}
|
||||
}
|
||||
for choice := range uniqueChoices {
|
||||
choices = append(choices, choice)
|
||||
}
|
||||
sort.Slice(choices, func(i, j int) bool {
|
||||
return choices[i] < choices[j]
|
||||
})
|
||||
return choices
|
||||
}
|
||||
|
||||
func MullvadCityChoices() (choices []string) {
|
||||
uniqueChoices := map[string]struct{}{}
|
||||
for _, server := range mullvadServers() {
|
||||
uniqueChoices[server.City] = struct{}{}
|
||||
}
|
||||
for choice := range uniqueChoices {
|
||||
choices = append(choices, choice)
|
||||
}
|
||||
sort.Slice(choices, func(i, j int) bool {
|
||||
return choices[i] < choices[j]
|
||||
})
|
||||
return choices
|
||||
}
|
||||
|
||||
func MullvadISPChoices() (choices []string) {
|
||||
uniqueChoices := map[string]struct{}{}
|
||||
for _, server := range mullvadServers() {
|
||||
uniqueChoices[server.ISP] = struct{}{}
|
||||
}
|
||||
for choice := range uniqueChoices {
|
||||
choices = append(choices, choice)
|
||||
}
|
||||
sort.Slice(choices, func(i, j int) bool {
|
||||
return choices[i] < choices[j]
|
||||
})
|
||||
return choices
|
||||
}
|
||||
|
||||
func MullvadServerFilter(country, city, isp string) (servers []models.MullvadServer) {
|
||||
for _, server := range mullvadServers() {
|
||||
if len(country) == 0 {
|
||||
server.Country = ""
|
||||
}
|
||||
if len(city) == 0 {
|
||||
server.City = ""
|
||||
}
|
||||
if len(isp) == 0 {
|
||||
server.ISP = ""
|
||||
}
|
||||
if server.Country == country && server.City == city && server.ISP == isp {
|
||||
servers = append(servers, server)
|
||||
}
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func mullvadServers() []models.MullvadServer {
|
||||
return []models.MullvadServer{
|
||||
{
|
||||
Country: "united arab emirates",
|
||||
City: "dubai",
|
||||
ISP: "m247",
|
||||
IPs: []net.IP{{45, 9, 249, 34}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "albania",
|
||||
City: "tirana",
|
||||
ISP: "iregister",
|
||||
IPs: []net.IP{{31, 171, 154, 210}},
|
||||
DefaultPort: 1197,
|
||||
},
|
||||
{
|
||||
Country: "austria",
|
||||
City: "wien",
|
||||
ISP: "m247",
|
||||
IPs: []net.IP{{37, 120, 155, 250}, {217, 64, 127, 138}, {217, 64, 127, 202}},
|
||||
DefaultPort: 1196,
|
||||
},
|
||||
{
|
||||
Country: "australia",
|
||||
City: "adelaide",
|
||||
ISP: "intergrid",
|
||||
IPs: []net.IP{{116, 206, 231, 58}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: "australia",
|
||||
City: "brisbane",
|
||||
ISP: "intergrid",
|
||||
IPs: []net.IP{{43, 245, 160, 162}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: "australia",
|
||||
City: "canberra",
|
||||
ISP: "intergrid",
|
||||
IPs: []net.IP{{116, 206, 229, 98}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: "australia",
|
||||
City: "melbourne",
|
||||
ISP: "intergrid",
|
||||
IPs: []net.IP{{116, 206, 228, 202}, {116, 206, 228, 242}, {116, 206, 230, 98}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: "australia",
|
||||
City: "perth",
|
||||
ISP: "intergrid",
|
||||
IPs: []net.IP{{103, 77, 235, 66}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: "australia",
|
||||
City: "sydney",
|
||||
ISP: "intergrid",
|
||||
IPs: []net.IP{{43, 245, 162, 130}, {103, 77, 232, 130}, {103, 77, 232, 146}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: "australia",
|
||||
City: "sydney",
|
||||
ISP: "m247",
|
||||
IPs: []net.IP{{217, 138, 204, 82}, {217, 138, 204, 98}, {217, 138, 204, 66}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: "belgium",
|
||||
City: "brussels",
|
||||
ISP: "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: "bulgaria",
|
||||
City: "sofia",
|
||||
ISP: "m247",
|
||||
IPs: []net.IP{{185, 94, 192, 42}, {185, 94, 192, 66}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: "brazil",
|
||||
City: "sao paulo",
|
||||
ISP: "qnax",
|
||||
IPs: []net.IP{{191, 101, 62, 178}},
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: "brazil",
|
||||
City: "sao paulo",
|
||||
ISP: "heficed",
|
||||
IPs: []net.IP{{177, 67, 80, 186}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: "canada",
|
||||
City: "montreal",
|
||||
ISP: "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: "canada",
|
||||
City: "toronto",
|
||||
ISP: "amanah",
|
||||
IPs: []net.IP{{184, 75, 214, 130}, {162, 219, 176, 250}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: "canada",
|
||||
City: "vancouver",
|
||||
ISP: "100tb",
|
||||
IPs: []net.IP{{172, 83, 40, 34}, {172, 83, 40, 38}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: "canada",
|
||||
City: "vancouver",
|
||||
ISP: "esecuredata",
|
||||
IPs: []net.IP{{71, 19, 249, 81}, {176, 113, 74, 186}, {71, 19, 248, 240}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: "switzerland",
|
||||
City: "zurich",
|
||||
ISP: "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: "zwitzerland",
|
||||
City: "zurich",
|
||||
ISP: "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: "switzerland",
|
||||
City: "zurich",
|
||||
ISP: "privateLayer",
|
||||
IPs: []net.IP{{179, 43, 128, 170}, {81, 17, 20, 34}},
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: "czech republic",
|
||||
City: "prague",
|
||||
ISP: "m247",
|
||||
IPs: []net.IP{{217, 138, 199, 82}, {217, 138, 199, 74}},
|
||||
DefaultPort: 1197,
|
||||
},
|
||||
{
|
||||
Country: "germany",
|
||||
City: "frankfurt",
|
||||
ISP: "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: "germany",
|
||||
City: "frankfurt",
|
||||
ISP: "m247",
|
||||
IPs: []net.IP{{82, 102, 16, 90}, {185, 104, 184, 186}, {77, 243, 183, 202}},
|
||||
DefaultPort: 1197,
|
||||
},
|
||||
{
|
||||
Country: "denmark",
|
||||
City: "copenhagen",
|
||||
ISP: "31173",
|
||||
IPs: []net.IP{{141, 98, 254, 71}, {141, 98, 254, 72}},
|
||||
Owned: true,
|
||||
DefaultPort: 1195,
|
||||
},
|
||||
{
|
||||
Country: "denmark",
|
||||
City: "copenhagen",
|
||||
ISP: "m247",
|
||||
IPs: []net.IP{{185, 206, 224, 114}, {185, 206, 224, 119}},
|
||||
DefaultPort: 1195,
|
||||
},
|
||||
{
|
||||
Country: "denmark",
|
||||
City: "copenhagen",
|
||||
ISP: "blix",
|
||||
IPs: []net.IP{{134, 90, 149, 138}},
|
||||
DefaultPort: 1195,
|
||||
},
|
||||
{
|
||||
Country: "denmark",
|
||||
City: "copenhagen",
|
||||
ISP: "asergo",
|
||||
IPs: []net.IP{{82, 103, 140, 213}},
|
||||
DefaultPort: 1195,
|
||||
},
|
||||
{
|
||||
Country: "spain",
|
||||
City: "madrid",
|
||||
ISP: "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: "finland",
|
||||
City: "helsinki",
|
||||
ISP: "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: "france",
|
||||
City: "paris",
|
||||
ISP: "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: "france",
|
||||
City: "paris",
|
||||
ISP: "m247",
|
||||
IPs: []net.IP{{185, 189, 113, 82}, {185, 156, 173, 218}, {185, 128, 25, 162}},
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: "uk",
|
||||
City: "london",
|
||||
ISP: "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: "uk",
|
||||
City: "london",
|
||||
ISP: "m247",
|
||||
IPs: []net.IP{{185, 200, 118, 105}, {185, 212, 168, 244}},
|
||||
DefaultPort: 1196,
|
||||
},
|
||||
{
|
||||
Country: "uk",
|
||||
City: "manchester",
|
||||
ISP: "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: "greece",
|
||||
City: "athens",
|
||||
ISP: "aweb",
|
||||
IPs: []net.IP{{185, 226, 67, 168}},
|
||||
DefaultPort: 1302,
|
||||
},
|
||||
{
|
||||
Country: "hong kong",
|
||||
City: "hong kong",
|
||||
ISP: "leaseweb",
|
||||
IPs: []net.IP{{209, 58, 185, 53}, {209, 58, 184, 146}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "hungary",
|
||||
City: "budapest",
|
||||
ISP: "m247",
|
||||
IPs: []net.IP{{185, 94, 190, 138}, {185, 189, 114, 10}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: "ireland",
|
||||
City: "dublin",
|
||||
ISP: "m247",
|
||||
IPs: []net.IP{{217, 138, 222, 90}, {217, 138, 222, 82}},
|
||||
DefaultPort: 1197,
|
||||
},
|
||||
{
|
||||
Country: "israel",
|
||||
City: "tel aviv",
|
||||
ISP: "hqserv",
|
||||
IPs: []net.IP{{185, 191, 207, 210}},
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: "italy",
|
||||
City: "milan",
|
||||
ISP: "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: "japan",
|
||||
City: "tokyo",
|
||||
ISP: "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: "luxembourg",
|
||||
City: "luxembourg",
|
||||
ISP: "evoluso",
|
||||
IPs: []net.IP{{92, 223, 89, 160}, {92, 223, 89, 182}},
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: "latvia",
|
||||
City: "riga",
|
||||
ISP: "makonix",
|
||||
IPs: []net.IP{{31, 170, 22, 2}},
|
||||
DefaultPort: 1300,
|
||||
},
|
||||
{
|
||||
Country: "moldova",
|
||||
City: "chisinau",
|
||||
ISP: "trabia",
|
||||
IPs: []net.IP{{178, 175, 142, 194}},
|
||||
DefaultPort: 1197,
|
||||
},
|
||||
{
|
||||
Country: "netherlands",
|
||||
City: "amsterdam",
|
||||
ISP: "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: "norway",
|
||||
City: "oslo",
|
||||
ISP: "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: "new zealand",
|
||||
City: "auckland",
|
||||
ISP: "intergrid",
|
||||
IPs: []net.IP{{103, 231, 91, 114}},
|
||||
DefaultPort: 1195,
|
||||
},
|
||||
{
|
||||
Country: "poland",
|
||||
City: "warsaw",
|
||||
ISP: "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: "portugal",
|
||||
City: "lisbon",
|
||||
ISP: "dotsi",
|
||||
IPs: []net.IP{{5, 206, 231, 214}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "romania",
|
||||
City: "bucharest",
|
||||
ISP: "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: "serbia",
|
||||
City: "belgrade",
|
||||
ISP: "m247",
|
||||
IPs: []net.IP{{141, 98, 103, 50}},
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: "serbia",
|
||||
City: "nis",
|
||||
ISP: "ninet",
|
||||
IPs: []net.IP{{176, 104, 107, 118}},
|
||||
DefaultPort: 1301,
|
||||
},
|
||||
{
|
||||
Country: "sweden",
|
||||
City: "gothenburg",
|
||||
ISP: "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: "sweden",
|
||||
City: "helsingborg",
|
||||
ISP: "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: "sweden",
|
||||
City: "malmo",
|
||||
ISP: "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: "sweden",
|
||||
City: "stockholm",
|
||||
ISP: "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: "singapore",
|
||||
City: "singapore",
|
||||
ISP: "m247",
|
||||
IPs: []net.IP{{37, 120, 208, 218}, {37, 120, 208, 234}, {37, 120, 208, 226}, {185, 128, 24, 50}},
|
||||
DefaultPort: 1196,
|
||||
},
|
||||
{
|
||||
Country: "singapore",
|
||||
City: "singapore",
|
||||
ISP: "leaseweb",
|
||||
IPs: []net.IP{{103, 254, 153, 82}},
|
||||
DefaultPort: 1196,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "atlanta",
|
||||
ISP: "100tb",
|
||||
IPs: []net.IP{{208, 84, 153, 142}, {107, 152, 108, 62}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "atlanta",
|
||||
ISP: "quadranet",
|
||||
IPs: []net.IP{{104, 129, 24, 242}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "atlanta",
|
||||
ISP: "micfo",
|
||||
IPs: []net.IP{{155, 254, 96, 2}, {155, 254, 96, 18}, {155, 254, 96, 34}}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "chicago",
|
||||
ISP: "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: "usa",
|
||||
City: "chicago",
|
||||
ISP: "quadranet",
|
||||
IPs: []net.IP{}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "dallas",
|
||||
ISP: "quadranet",
|
||||
IPs: []net.IP{{96, 44, 145, 18}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "dallas",
|
||||
ISP: "100tb",
|
||||
IPs: []net.IP{{104, 200, 142, 50}, {107, 152, 102, 106}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "denver",
|
||||
ISP: "tzulo",
|
||||
IPs: []net.IP{{198, 54, 128, 74}}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "los angeles",
|
||||
ISP: "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: "usa",
|
||||
City: "los angeles",
|
||||
ISP: "tzulo",
|
||||
IPs: []net.IP{{198, 54, 129, 74}}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "los angeles",
|
||||
ISP: "100tb",
|
||||
IPs: []net.IP{{104, 200, 152, 66}, {107, 181, 168, 130}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "los angeles",
|
||||
ISP: "choopa",
|
||||
IPs: []net.IP{{104, 238, 143, 58}}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "miami",
|
||||
ISP: "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: "usa",
|
||||
City: "miami",
|
||||
ISP: "100tb",
|
||||
IPs: []net.IP{{172, 98, 76, 114}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "miami",
|
||||
ISP: "micfo",
|
||||
IPs: []net.IP{}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "new york",
|
||||
ISP: "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: "usa",
|
||||
City: "new york",
|
||||
ISP: "100tb",
|
||||
IPs: []net.IP{{107, 182, 226, 206}, {107, 182, 226, 218}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "phoenix",
|
||||
ISP: "100tb",
|
||||
IPs: []net.IP{}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "phoenix",
|
||||
ISP: "micfo",
|
||||
IPs: []net.IP{{192, 200, 24, 82}}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "piscataway",
|
||||
ISP: "choopa",
|
||||
IPs: []net.IP{{108, 61, 78, 138}, {108, 61, 48, 115}, {66, 55, 147, 59}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "seattle",
|
||||
ISP: "100tb",
|
||||
IPs: []net.IP{{104, 200, 129, 202}, {104, 200, 129, 150}, {104, 200, 129, 110}}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "seattle",
|
||||
ISP: "micfo",
|
||||
IPs: []net.IP{{104, 128, 136, 146}},
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "san francisco",
|
||||
ISP: "micfo",
|
||||
IPs: []net.IP{{209, 209, 238, 34}}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
{
|
||||
Country: "usa",
|
||||
City: "salt lake city",
|
||||
ISP: "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: "usa",
|
||||
City: "secaucus",
|
||||
ISP: "quadranet",
|
||||
IPs: []net.IP{{23, 226, 131, 154}}, // 1 missing
|
||||
DefaultPort: 1194,
|
||||
},
|
||||
}
|
||||
}
|
||||
5184
internal/constants/nordvpn.go
Normal file
5184
internal/constants/nordvpn.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,88 +1,82 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"net"
|
||||
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
const (
|
||||
// PIAEncryptionNormal is the normal level of encryption for communication with PIA servers
|
||||
PIAEncryptionNormal models.PIAEncryption = "normal"
|
||||
// PIAEncryptionStrong is the strong level of encryption for communication with PIA servers
|
||||
PIAEncryptionStrong models.PIAEncryption = "strong"
|
||||
PIAEncryptionPresetNormal = "normal"
|
||||
PIAEncryptionPresetStrong = "strong"
|
||||
PiaX509CRLNormal = "MIICWDCCAUAwDQYJKoZIhvcNAQENBQAwgegxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTETMBEGA1UEBxMKTG9zQW5nZWxlczEgMB4GA1UEChMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAsTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQDExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEKRMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxLzAtBgkqhkiG9w0BCQEWIHNlY3VyZUBwcml2YXRlaW50ZXJuZXRhY2Nlc3MuY29tFw0xNjA3MDgxOTAwNDZaFw0zNjA3MDMxOTAwNDZaMCYwEQIBARcMMTYwNzA4MTkwMDQ2MBECAQYXDDE2MDcwODE5MDA0NjANBgkqhkiG9w0BAQ0FAAOCAQEAQZo9X97ci8EcPYu/uK2HB152OZbeZCINmYyluLDOdcSvg6B5jI+ffKN3laDvczsG6CxmY3jNyc79XVpEYUnq4rT3FfveW1+Ralf+Vf38HdpwB8EWB4hZlQ205+21CALLvZvR8HcPxC9KEnev1mU46wkTiov0EKc+EdRxkj5yMgv0V2Reze7AP+NQ9ykvDScH4eYCsmufNpIjBLhpLE2cuZZXBLcPhuRzVoU3l7A9lvzG9mjA5YijHJGHNjlWFqyrn1CfYS6koa4TGEPngBoAziWRbDGdhEgJABHrpoaFYaL61zqyMR6jC0K2ps9qyZAN74LEBedEfK7tBOzWMwr58A=="
|
||||
PiaX509CRLStrong = "MIIDWDCCAUAwDQYJKoZIhvcNAQENBQAwgegxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTETMBEGA1UEBxMKTG9zQW5nZWxlczEgMB4GA1UEChMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAsTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQDExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEKRMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxLzAtBgkqhkiG9w0BCQEWIHNlY3VyZUBwcml2YXRlaW50ZXJuZXRhY2Nlc3MuY29tFw0xNjA3MDgxOTAwNDZaFw0zNjA3MDMxOTAwNDZaMCYwEQIBARcMMTYwNzA4MTkwMDQ2MBECAQYXDDE2MDcwODE5MDA0NjANBgkqhkiG9w0BAQ0FAAOCAgEAppFfEpGsasjB1QgJcosGpzbf2kfRhM84o2TlqY1ua+Gi5TMdKydA3LJcNTjlI9a0TYAJfeRX5IkpoglSUuHuJgXhP3nEvX10mjXDpcu/YvM8TdE5JV2+EGqZ80kFtBeOq94WcpiVKFTR4fO+VkOK9zwspFfb1cNs9rHvgJ1QMkRUF8PpLN6AkntHY0+6DnigtSaKqldqjKTDTv2OeH3nPoh80SGrt0oCOmYKfWTJGpggMGKvIdvU3vH9+EuILZKKIskt+1dwdfA5Bkz1GLmiQG7+9ZZBQUjBG9Dos4hfX/rwJ3eU8oUIm4WoTz9rb71SOEuUUjP5NPy9HNx2vx+cVvLsTF4ZDZaUztW9o9JmIURDtbeyqxuHN3prlPWB6aj73IIm2dsDQvs3XXwRIxs8NwLbJ6CyEuvEOVCskdM8rdADWx1J0lRNlOJ0Z8ieLLEmYAA834VN1SboB6wJIAPxQU3rcBhXqO9y8aa2oRMg8NxZ5gr+PnKVMqag1x0IxbIgLxtkXQvxXxQHEMSODzvcOfK/nBRBsqTj30P+R87sU8titOoxNeRnBDRNhdEy/QGAqGh62ShPpQUCJdnKRiRTjnil9hMQHevoSuFKeEMO30FQL7BZyo37GFU+q1WPCplVZgCP9hC8Rn5K2+f6KLFo5bhtowSmu+GY1yZtg+RTtsA="
|
||||
PIACertificateNormal = "MIIFqzCCBJOgAwIBAgIJAKZ7D5Yv87qDMA0GCSqGSIb3DQEBDQUAMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTAeFw0xNDA0MTcxNzM1MThaFw0zNDA0MTIxNzM1MThaMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPXDL1L9tX6DGf36liA7UBTy5I869z0UVo3lImfOs/GSiFKPtInlesP65577nd7UNzzXlH/P/CnFPdBWlLp5ze3HRBCc/Avgr5CdMRkEsySL5GHBZsx6w2cayQ2EcRhVTwWpcdldeNO+pPr9rIgPrtXqT4SWViTQRBeGM8CDxAyTopTsobjSiYZCF9Ta1gunl0G/8Vfp+SXfYCC+ZzWvP+L1pFhPRqzQQ8k+wMZIovObK1s+nlwPaLyayzw9a8sUnvWB/5rGPdIYnQWPgoNlLN9HpSmsAcw2z8DXI9pIxbr74cb3/HSfuYGOLkRqrOk6h4RCOfuWoTrZup1uEOn+fw8CAwEAAaOCAVQwggFQMB0GA1UdDgQWBBQv63nQ/pJAt5tLy8VJcbHe22ZOsjCCAR8GA1UdIwSCARYwggESgBQv63nQ/pJAt5tLy8VJcbHe22ZOsqGB7qSB6zCB6DELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRMwEQYDVQQHEwpMb3NBbmdlbGVzMSAwHgYDVQQKExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UECxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAMTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQpExdQcml2YXRlIEludGVybmV0IEFjY2VzczEvMC0GCSqGSIb3DQEJARYgc2VjdXJlQHByaXZhdGVpbnRlcm5ldGFjY2Vzcy5jb22CCQCmew+WL/O6gzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQAna5PgrtxfwTumD4+3/SYvwoD66cB8IcK//h1mCzAduU8KgUXocLx7QgJWo9lnZ8xUryXvWab2usg4fqk7FPi00bED4f4qVQFVfGfPZIH9QQ7/48bPM9RyfzImZWUCenK37pdw4Bvgoys2rHLHbGen7f28knT2j/cbMxd78tQc20TIObGjo8+ISTRclSTRBtyCGohseKYpTS9himFERpUgNtefvYHbn70mIOzfOJFTVqfrptf9jXa9N8Mpy3ayfodz1wiqdteqFXkTYoSDctgKMiZ6GdocK9nMroQipIQtpnwd4yBDWIyC6Bvlkrq5TQUtYDQ8z9v+DMO6iwyIDRiU"
|
||||
PIACertificateStrong = "MIIHqzCCBZOgAwIBAgIJAJ0u+vODZJntMA0GCSqGSIb3DQEBDQUAMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTAeFw0xNDA0MTcxNzQwMzNaFw0zNDA0MTIxNzQwMzNaMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALVkhjumaqBbL8aSgj6xbX1QPTfTd1qHsAZd2B97m8Vw31c/2yQgZNf5qZY0+jOIHULNDe4R9TIvyBEbvnAg/OkPw8n/+ScgYOeH876VUXzjLDBnDb8DLr/+w9oVsuDeFJ9KV2UFM1OYX0SnkHnrYAN2QLF98ESK4NCSU01h5zkcgmQ+qKSfA9Ny0/UpsKPBFqsQ25NvjDWFhCpeqCHKUJ4Be27CDbSl7lAkBuHMPHJs8f8xPgAbHRXZOxVCpayZ2SNDfCwsnGWpWFoMGvdMbygngCn6jA/W1VSFOlRlfLuuGe7QFfDwA0jaLCxuWt/BgZylp7tAzYKR8lnWmtUCPm4+BtjyVDYtDCiGBD9Z4P13RFWvJHw5aapx/5W/CuvVyI7pKwvc2IT+KPxCUhH1XI8ca5RN3C9NoPJJf6qpg4g0rJH3aaWkoMRrYvQ+5PXXYUzjtRHImghRGd/ydERYoAZXuGSbPkm9Y/p2X8unLcW+F0xpJD98+ZI+tzSsI99Zs5wijSUGYr9/j18KHFTMQ8n+1jauc5bCCegN27dPeKXNSZ5riXFL2XX6BkY68y58UaNzmeGMiUL9BOV1iV+PMb7B7PYs7oFLjAhh0EdyvfHkrh/ZV9BEhtFa7yXp8XR0J6vz1YV9R6DYJmLjOEbhU8N0gc3tZm4Qz39lIIG6w3FDAgMBAAGjggFUMIIBUDAdBgNVHQ4EFgQUrsRtyWJftjpdRM0+925Y6Cl08SUwggEfBgNVHSMEggEWMIIBEoAUrsRtyWJftjpdRM0+925Y6Cl08SWhge6kgeswgegxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTETMBEGA1UEBxMKTG9zQW5nZWxlczEgMB4GA1UEChMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAsTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQDExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEKRMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxLzAtBgkqhkiG9w0BCQEWIHNlY3VyZUBwcml2YXRlaW50ZXJuZXRhY2Nlc3MuY29tggkAnS7684Nkme0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQ0FAAOCAgEAJsfhsPk3r8kLXLxY+v+vHzbr4ufNtqnL9/1Uuf8NrsCtpXAoyZ0YqfbkWx3NHTZ7OE9ZRhdMP/RqHQE1p4N4Sa1nZKhTKasV6KhHDqSCt/dvEm89xWm2MVA7nyzQxVlHa9AkcBaemcXEiyT19XdpiXOP4Vhs+J1R5m8zQOxZlV1GtF9vsXmJqWZpOVPmZ8f35BCsYPvv4yMewnrtAC8PFEK/bOPeYcKN50bol22QYaZuLfpkHfNiFTnfMh8sl/ablPyNY7DUNiP5DRcMdIwmfGQxR5WEQoHL3yPJ42LkB5zs6jIm26DGNXfwura/mi105+ENH1CaROtRYwkiHb08U6qLXXJz80mWJkT90nr8Asj35xN2cUppg74nG3YVav/38P48T56hG1NHbYF5uOCske19F6wi9maUoto/3vEr0rnXJUp2KODmKdvBI7co245lHBABWikk8VfejQSlCtDBXn644ZMtAdoxKNfR2WTFVEwJiyd1Fzx0yujuiXDROLhISLQDRjVVAvawrAtLZWYK31bY7KlezPlQnl/D9Asxe85l8jO5+0LdJ6VyOs/Hd4w52alDW/MFySDZSfQHMTIc30hLBJ8OnCEIvluVQQ2UQvoW+no177N9L2Y+M9TcTA62ZyMXShHQGeh20rb4kK8f+iFX8NxtdHVSkxMEFSfDDyQ="
|
||||
)
|
||||
|
||||
const (
|
||||
PIAX509CRL_NORMAL = "MIICWDCCAUAwDQYJKoZIhvcNAQENBQAwgegxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTETMBEGA1UEBxMKTG9zQW5nZWxlczEgMB4GA1UEChMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAsTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQDExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEKRMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxLzAtBgkqhkiG9w0BCQEWIHNlY3VyZUBwcml2YXRlaW50ZXJuZXRhY2Nlc3MuY29tFw0xNjA3MDgxOTAwNDZaFw0zNjA3MDMxOTAwNDZaMCYwEQIBARcMMTYwNzA4MTkwMDQ2MBECAQYXDDE2MDcwODE5MDA0NjANBgkqhkiG9w0BAQ0FAAOCAQEAQZo9X97ci8EcPYu/uK2HB152OZbeZCINmYyluLDOdcSvg6B5jI+ffKN3laDvczsG6CxmY3jNyc79XVpEYUnq4rT3FfveW1+Ralf+Vf38HdpwB8EWB4hZlQ205+21CALLvZvR8HcPxC9KEnev1mU46wkTiov0EKc+EdRxkj5yMgv0V2Reze7AP+NQ9ykvDScH4eYCsmufNpIjBLhpLE2cuZZXBLcPhuRzVoU3l7A9lvzG9mjA5YijHJGHNjlWFqyrn1CfYS6koa4TGEPngBoAziWRbDGdhEgJABHrpoaFYaL61zqyMR6jC0K2ps9qyZAN74LEBedEfK7tBOzWMwr58A=="
|
||||
PIAX509CRL_STRONG = "MIIDWDCCAUAwDQYJKoZIhvcNAQENBQAwgegxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTETMBEGA1UEBxMKTG9zQW5nZWxlczEgMB4GA1UEChMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAsTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQDExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEKRMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxLzAtBgkqhkiG9w0BCQEWIHNlY3VyZUBwcml2YXRlaW50ZXJuZXRhY2Nlc3MuY29tFw0xNjA3MDgxOTAwNDZaFw0zNjA3MDMxOTAwNDZaMCYwEQIBARcMMTYwNzA4MTkwMDQ2MBECAQYXDDE2MDcwODE5MDA0NjANBgkqhkiG9w0BAQ0FAAOCAgEAppFfEpGsasjB1QgJcosGpzbf2kfRhM84o2TlqY1ua+Gi5TMdKydA3LJcNTjlI9a0TYAJfeRX5IkpoglSUuHuJgXhP3nEvX10mjXDpcu/YvM8TdE5JV2+EGqZ80kFtBeOq94WcpiVKFTR4fO+VkOK9zwspFfb1cNs9rHvgJ1QMkRUF8PpLN6AkntHY0+6DnigtSaKqldqjKTDTv2OeH3nPoh80SGrt0oCOmYKfWTJGpggMGKvIdvU3vH9+EuILZKKIskt+1dwdfA5Bkz1GLmiQG7+9ZZBQUjBG9Dos4hfX/rwJ3eU8oUIm4WoTz9rb71SOEuUUjP5NPy9HNx2vx+cVvLsTF4ZDZaUztW9o9JmIURDtbeyqxuHN3prlPWB6aj73IIm2dsDQvs3XXwRIxs8NwLbJ6CyEuvEOVCskdM8rdADWx1J0lRNlOJ0Z8ieLLEmYAA834VN1SboB6wJIAPxQU3rcBhXqO9y8aa2oRMg8NxZ5gr+PnKVMqag1x0IxbIgLxtkXQvxXxQHEMSODzvcOfK/nBRBsqTj30P+R87sU8titOoxNeRnBDRNhdEy/QGAqGh62ShPpQUCJdnKRiRTjnil9hMQHevoSuFKeEMO30FQL7BZyo37GFU+q1WPCplVZgCP9hC8Rn5K2+f6KLFo5bhtowSmu+GY1yZtg+RTtsA="
|
||||
PIACertificate_NORMAL = "MIIFqzCCBJOgAwIBAgIJAKZ7D5Yv87qDMA0GCSqGSIb3DQEBDQUAMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTAeFw0xNDA0MTcxNzM1MThaFw0zNDA0MTIxNzM1MThaMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPXDL1L9tX6DGf36liA7UBTy5I869z0UVo3lImfOs/GSiFKPtInlesP65577nd7UNzzXlH/P/CnFPdBWlLp5ze3HRBCc/Avgr5CdMRkEsySL5GHBZsx6w2cayQ2EcRhVTwWpcdldeNO+pPr9rIgPrtXqT4SWViTQRBeGM8CDxAyTopTsobjSiYZCF9Ta1gunl0G/8Vfp+SXfYCC+ZzWvP+L1pFhPRqzQQ8k+wMZIovObK1s+nlwPaLyayzw9a8sUnvWB/5rGPdIYnQWPgoNlLN9HpSmsAcw2z8DXI9pIxbr74cb3/HSfuYGOLkRqrOk6h4RCOfuWoTrZup1uEOn+fw8CAwEAAaOCAVQwggFQMB0GA1UdDgQWBBQv63nQ/pJAt5tLy8VJcbHe22ZOsjCCAR8GA1UdIwSCARYwggESgBQv63nQ/pJAt5tLy8VJcbHe22ZOsqGB7qSB6zCB6DELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRMwEQYDVQQHEwpMb3NBbmdlbGVzMSAwHgYDVQQKExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UECxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAMTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQpExdQcml2YXRlIEludGVybmV0IEFjY2VzczEvMC0GCSqGSIb3DQEJARYgc2VjdXJlQHByaXZhdGVpbnRlcm5ldGFjY2Vzcy5jb22CCQCmew+WL/O6gzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQAna5PgrtxfwTumD4+3/SYvwoD66cB8IcK//h1mCzAduU8KgUXocLx7QgJWo9lnZ8xUryXvWab2usg4fqk7FPi00bED4f4qVQFVfGfPZIH9QQ7/48bPM9RyfzImZWUCenK37pdw4Bvgoys2rHLHbGen7f28knT2j/cbMxd78tQc20TIObGjo8+ISTRclSTRBtyCGohseKYpTS9himFERpUgNtefvYHbn70mIOzfOJFTVqfrptf9jXa9N8Mpy3ayfodz1wiqdteqFXkTYoSDctgKMiZ6GdocK9nMroQipIQtpnwd4yBDWIyC6Bvlkrq5TQUtYDQ8z9v+DMO6iwyIDRiU"
|
||||
PIACertificate_STRONG = "MIIHqzCCBZOgAwIBAgIJAJ0u+vODZJntMA0GCSqGSIb3DQEBDQUAMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTAeFw0xNDA0MTcxNzQwMzNaFw0zNDA0MTIxNzQwMzNaMIHoMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEzARBgNVBAcTCkxvc0FuZ2VsZXMxIDAeBgNVBAoTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQLExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEAxMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBCkTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMS8wLQYJKoZIhvcNAQkBFiBzZWN1cmVAcHJpdmF0ZWludGVybmV0YWNjZXNzLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALVkhjumaqBbL8aSgj6xbX1QPTfTd1qHsAZd2B97m8Vw31c/2yQgZNf5qZY0+jOIHULNDe4R9TIvyBEbvnAg/OkPw8n/+ScgYOeH876VUXzjLDBnDb8DLr/+w9oVsuDeFJ9KV2UFM1OYX0SnkHnrYAN2QLF98ESK4NCSU01h5zkcgmQ+qKSfA9Ny0/UpsKPBFqsQ25NvjDWFhCpeqCHKUJ4Be27CDbSl7lAkBuHMPHJs8f8xPgAbHRXZOxVCpayZ2SNDfCwsnGWpWFoMGvdMbygngCn6jA/W1VSFOlRlfLuuGe7QFfDwA0jaLCxuWt/BgZylp7tAzYKR8lnWmtUCPm4+BtjyVDYtDCiGBD9Z4P13RFWvJHw5aapx/5W/CuvVyI7pKwvc2IT+KPxCUhH1XI8ca5RN3C9NoPJJf6qpg4g0rJH3aaWkoMRrYvQ+5PXXYUzjtRHImghRGd/ydERYoAZXuGSbPkm9Y/p2X8unLcW+F0xpJD98+ZI+tzSsI99Zs5wijSUGYr9/j18KHFTMQ8n+1jauc5bCCegN27dPeKXNSZ5riXFL2XX6BkY68y58UaNzmeGMiUL9BOV1iV+PMb7B7PYs7oFLjAhh0EdyvfHkrh/ZV9BEhtFa7yXp8XR0J6vz1YV9R6DYJmLjOEbhU8N0gc3tZm4Qz39lIIG6w3FDAgMBAAGjggFUMIIBUDAdBgNVHQ4EFgQUrsRtyWJftjpdRM0+925Y6Cl08SUwggEfBgNVHSMEggEWMIIBEoAUrsRtyWJftjpdRM0+925Y6Cl08SWhge6kgeswgegxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTETMBEGA1UEBxMKTG9zQW5nZWxlczEgMB4GA1UEChMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxIDAeBgNVBAsTF1ByaXZhdGUgSW50ZXJuZXQgQWNjZXNzMSAwHgYDVQQDExdQcml2YXRlIEludGVybmV0IEFjY2VzczEgMB4GA1UEKRMXUHJpdmF0ZSBJbnRlcm5ldCBBY2Nlc3MxLzAtBgkqhkiG9w0BCQEWIHNlY3VyZUBwcml2YXRlaW50ZXJuZXRhY2Nlc3MuY29tggkAnS7684Nkme0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQ0FAAOCAgEAJsfhsPk3r8kLXLxY+v+vHzbr4ufNtqnL9/1Uuf8NrsCtpXAoyZ0YqfbkWx3NHTZ7OE9ZRhdMP/RqHQE1p4N4Sa1nZKhTKasV6KhHDqSCt/dvEm89xWm2MVA7nyzQxVlHa9AkcBaemcXEiyT19XdpiXOP4Vhs+J1R5m8zQOxZlV1GtF9vsXmJqWZpOVPmZ8f35BCsYPvv4yMewnrtAC8PFEK/bOPeYcKN50bol22QYaZuLfpkHfNiFTnfMh8sl/ablPyNY7DUNiP5DRcMdIwmfGQxR5WEQoHL3yPJ42LkB5zs6jIm26DGNXfwura/mi105+ENH1CaROtRYwkiHb08U6qLXXJz80mWJkT90nr8Asj35xN2cUppg74nG3YVav/38P48T56hG1NHbYF5uOCske19F6wi9maUoto/3vEr0rnXJUp2KODmKdvBI7co245lHBABWikk8VfejQSlCtDBXn644ZMtAdoxKNfR2WTFVEwJiyd1Fzx0yujuiXDROLhISLQDRjVVAvawrAtLZWYK31bY7KlezPlQnl/D9Asxe85l8jO5+0LdJ6VyOs/Hd4w52alDW/MFySDZSfQHMTIc30hLBJ8OnCEIvluVQQ2UQvoW+no177N9L2Y+M9TcTA62ZyMXShHQGeh20rb4kK8f+iFX8NxtdHVSkxMEFSfDDyQ="
|
||||
)
|
||||
|
||||
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() (choices []string) {
|
||||
servers := PIAServers()
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
}
|
||||
return choices
|
||||
}
|
||||
|
||||
func PIAGeoToSubdomainMapping(region models.PIARegion) (subdomain string, err error) {
|
||||
mapping := map[models.PIARegion]string{
|
||||
models.PIARegion("AU Melbourne"): "au-melbourne",
|
||||
models.PIARegion("AU Perth"): "au-perth",
|
||||
models.PIARegion("AU Sydney"): "au-sydney",
|
||||
models.PIARegion("Austria"): "austria",
|
||||
models.PIARegion("Belgium"): "belgium",
|
||||
models.PIARegion("CA Montreal"): "ca-montreal",
|
||||
models.PIARegion("CA Toronto"): "ca-toronto",
|
||||
models.PIARegion("CA Vancouver"): "ca-vancouver",
|
||||
models.PIARegion("Czech Republic"): "czech",
|
||||
models.PIARegion("DE Berlin"): "de-berlin",
|
||||
models.PIARegion("DE Frankfurt"): "de-frankfurt",
|
||||
models.PIARegion("Denmark"): "denmark",
|
||||
models.PIARegion("Finland"): "fi",
|
||||
models.PIARegion("France"): "france",
|
||||
models.PIARegion("Hong Kong"): "hk",
|
||||
models.PIARegion("Hungary"): "hungary",
|
||||
models.PIARegion("India"): "in",
|
||||
models.PIARegion("Ireland"): "ireland",
|
||||
models.PIARegion("Israel"): "israel",
|
||||
models.PIARegion("Italy"): "italy",
|
||||
models.PIARegion("Japan"): "japan",
|
||||
models.PIARegion("Luxembourg"): "lu",
|
||||
models.PIARegion("Mexico"): "mexico",
|
||||
models.PIARegion("Netherlands"): "nl",
|
||||
models.PIARegion("New Zealand"): "nz",
|
||||
models.PIARegion("Norway"): "no",
|
||||
models.PIARegion("Poland"): "poland",
|
||||
models.PIARegion("Romania"): "ro",
|
||||
models.PIARegion("Singapore"): "sg",
|
||||
models.PIARegion("Spain"): "spain",
|
||||
models.PIARegion("Sweden"): "sweden",
|
||||
models.PIARegion("Switzerland"): "swiss",
|
||||
models.PIARegion("UAE"): "ae",
|
||||
models.PIARegion("UK London"): "uk-london",
|
||||
models.PIARegion("UK Manchester"): "uk-manchester",
|
||||
models.PIARegion("UK Southampton"): "uk-southampton",
|
||||
models.PIARegion("US Atlanta"): "us-atlanta",
|
||||
models.PIARegion("US California"): "us-california",
|
||||
models.PIARegion("US Chicago"): "us-chicago",
|
||||
models.PIARegion("US Denver"): "us-denver",
|
||||
models.PIARegion("US East"): "us-east",
|
||||
models.PIARegion("US Florida"): "us-florida",
|
||||
models.PIARegion("US Houston"): "us-houston",
|
||||
models.PIARegion("US Las Vegas"): "us-lasvegas",
|
||||
models.PIARegion("US New York City"): "us-newyorkcity",
|
||||
models.PIARegion("US Seattle"): "us-seattle",
|
||||
models.PIARegion("US Silicon Valley"): "us-siliconvalley",
|
||||
models.PIARegion("US Texas"): "us-texas",
|
||||
models.PIARegion("US Washington DC"): "us-washingtondc",
|
||||
models.PIARegion("US West"): "us-west",
|
||||
func PIAServers() []models.PIAServer {
|
||||
return []models.PIAServer{
|
||||
{Region: "AU Melbourne", IPs: []net.IP{{27, 50, 82, 131}, {27, 50, 82, 133}, {43, 250, 204, 81}, {43, 250, 204, 83}, {43, 250, 204, 87}, {43, 250, 204, 89}, {43, 250, 204, 91}, {43, 250, 204, 93}, {43, 250, 204, 97}, {43, 250, 204, 99}, {43, 250, 204, 101}, {43, 250, 204, 103}, {43, 250, 204, 107}, {43, 250, 204, 111}, {43, 250, 204, 117}, {43, 250, 204, 119}, {43, 250, 204, 123}, {43, 250, 204, 125}, {118, 127, 62, 227}, {221, 121, 139, 175}}},
|
||||
{Region: "AU Perth", IPs: []net.IP{{43, 250, 205, 59}, {43, 250, 205, 89}, {43, 250, 205, 91}, {43, 250, 205, 93}, {43, 250, 205, 95}}},
|
||||
{Region: "AU Sydney", IPs: []net.IP{{27, 50, 77, 247}, {103, 13, 102, 113}, {103, 13, 102, 115}, {103, 13, 102, 117}, {103, 13, 102, 119}, {103, 13, 102, 121}, {103, 13, 102, 123}, {103, 13, 102, 127}, {118, 127, 60, 53}, {118, 127, 60, 61}, {221, 121, 145, 131}, {221, 121, 145, 133}, {221, 121, 145, 143}, {221, 121, 145, 151}, {221, 121, 146, 203}, {221, 121, 152, 215}}},
|
||||
{Region: "Austria", IPs: []net.IP{{185, 210, 219, 147}, {185, 210, 219, 154}, {185, 210, 219, 156}, {185, 216, 34, 226}, {185, 216, 34, 228}, {185, 216, 34, 229}, {185, 216, 34, 230}, {185, 216, 34, 232}, {185, 216, 34, 233}, {185, 216, 34, 236}, {185, 216, 34, 237}, {185, 216, 34, 238}}},
|
||||
{Region: "Belgium", IPs: []net.IP{{77, 243, 191, 19}, {77, 243, 191, 21}, {77, 243, 191, 22}, {77, 243, 191, 23}, {77, 243, 191, 26}, {77, 243, 191, 27}, {185, 104, 186, 26}, {185, 232, 21, 26}, {185, 232, 21, 29}}},
|
||||
{Region: "CA Montreal", IPs: []net.IP{{199, 229, 249, 142}}},
|
||||
{Region: "CA Toronto", IPs: []net.IP{{172, 98, 67, 37}, {172, 98, 67, 41}, {172, 98, 67, 45}, {172, 98, 67, 47}, {172, 98, 67, 48}, {172, 98, 67, 55}, {172, 98, 67, 56}, {172, 98, 67, 61}, {172, 98, 67, 64}, {172, 98, 67, 65}, {172, 98, 67, 68}, {172, 98, 67, 71}, {172, 98, 67, 73}, {172, 98, 67, 81}, {172, 98, 67, 85}, {172, 98, 67, 89}, {172, 98, 67, 91}, {172, 98, 67, 93}, {172, 98, 67, 95}, {172, 98, 67, 99}}},
|
||||
{Region: "CA Vancouver", IPs: []net.IP{{172, 83, 40, 107}}},
|
||||
{Region: "Czech Republic", IPs: []net.IP{{89, 238, 186, 226}, {89, 238, 186, 227}, {89, 238, 186, 228}, {89, 238, 186, 229}, {89, 238, 186, 230}, {185, 216, 35, 66}, {185, 216, 35, 67}, {185, 216, 35, 69}, {185, 216, 35, 70}, {185, 242, 6, 27}, {185, 242, 6, 28}, {185, 242, 6, 29}, {185, 242, 6, 30}}},
|
||||
{Region: "DE Berlin", IPs: []net.IP{{185, 230, 127, 227}, {185, 230, 127, 228}, {185, 230, 127, 231}, {185, 230, 127, 232}, {185, 230, 127, 233}, {185, 230, 127, 234}, {185, 230, 127, 236}, {185, 230, 127, 239}, {185, 230, 127, 240}, {185, 230, 127, 241}, {193, 176, 86, 124}, {193, 176, 86, 130}, {193, 176, 86, 142}, {193, 176, 86, 146}, {193, 176, 86, 150}, {193, 176, 86, 154}, {193, 176, 86, 166}, {193, 176, 86, 174}, {193, 176, 86, 178}, {193, 176, 86, 182}}},
|
||||
{Region: "DE Frankfurt", IPs: []net.IP{{185, 220, 70, 134}, {185, 220, 70, 135}, {185, 220, 70, 136}, {185, 220, 70, 139}, {185, 220, 70, 140}, {185, 220, 70, 141}, {185, 220, 70, 143}, {185, 220, 70, 144}, {185, 220, 70, 145}, {185, 220, 70, 147}, {185, 220, 70, 148}, {185, 220, 70, 152}, {185, 220, 70, 153}, {185, 220, 70, 155}, {185, 220, 70, 163}, {185, 220, 70, 164}, {185, 220, 70, 167}, {185, 220, 70, 170}, {185, 220, 70, 171}, {185, 220, 70, 173}}},
|
||||
{Region: "Denmark", IPs: []net.IP{{82, 102, 20, 162}, {82, 102, 20, 163}, {82, 102, 20, 164}, {82, 102, 20, 165}, {82, 102, 20, 167}, {82, 102, 20, 168}, {82, 102, 20, 169}, {82, 102, 20, 170}, {82, 102, 20, 171}, {82, 102, 20, 172}, {82, 102, 20, 173}, {82, 102, 20, 174}, {82, 102, 20, 175}, {82, 102, 20, 178}, {82, 102, 20, 179}, {82, 102, 20, 180}, {82, 102, 20, 181}, {82, 102, 20, 182}, {82, 102, 20, 183}}},
|
||||
{Region: "Finlan", IPs: []net.IP{{196, 244, 191, 2}, {196, 244, 191, 10}, {196, 244, 191, 42}, {196, 244, 191, 50}, {196, 244, 191, 58}, {196, 244, 191, 66}, {196, 244, 191, 74}, {196, 244, 191, 82}, {196, 244, 191, 90}, {196, 244, 191, 98}, {196, 244, 191, 106}, {196, 244, 191, 114}, {196, 244, 191, 138}, {196, 244, 191, 146}}},
|
||||
{Region: "France", IPs: []net.IP{{194, 187, 249, 35}, {194, 187, 249, 37}, {194, 187, 249, 39}, {194, 187, 249, 42}, {194, 187, 249, 45}, {194, 187, 249, 48}, {194, 187, 249, 49}, {194, 187, 249, 52}, {194, 187, 249, 53}, {194, 187, 249, 56}, {194, 187, 249, 59}, {194, 187, 249, 60}, {194, 187, 249, 61}, {194, 187, 249, 178}, {194, 187, 249, 179}, {194, 187, 249, 180}, {194, 187, 249, 183}, {194, 187, 249, 184}, {194, 187, 249, 187}, {194, 187, 249, 190}}},
|
||||
{Region: "Hong Kong", IPs: []net.IP{{84, 17, 37, 1}, {84, 17, 37, 45}, {119, 81, 135, 2}, {119, 81, 135, 28}, {119, 81, 135, 29}, {119, 81, 135, 47}, {119, 81, 135, 51}, {119, 81, 135, 53}, {119, 81, 253, 212}, {119, 81, 253, 218}, {119, 81, 253, 226}, {119, 81, 253, 227}, {119, 81, 253, 229}, {119, 81, 253, 230}, {119, 81, 253, 241}, {161, 202, 39, 202}, {161, 202, 39, 240}, {161, 202, 39, 251}, {161, 202, 44, 94}}},
|
||||
{Region: "Hungary", IPs: []net.IP{{185, 128, 26, 18}, {185, 128, 26, 19}, {185, 128, 26, 20}, {185, 128, 26, 21}, {185, 128, 26, 22}, {185, 128, 26, 23}, {185, 128, 26, 24}, {185, 189, 114, 98}}},
|
||||
{Region: "India", IPs: []net.IP{{150, 242, 12, 155}, {150, 242, 12, 171}, {150, 242, 12, 187}}},
|
||||
{Region: "Ireland", IPs: []net.IP{{23, 92, 127, 2}, {23, 92, 127, 10}, {23, 92, 127, 18}, {23, 92, 127, 34}, {23, 92, 127, 42}, {23, 92, 127, 58}}},
|
||||
{Region: "Israel", IPs: []net.IP{{31, 168, 172, 136}, {31, 168, 172, 142}, {31, 168, 172, 143}, {31, 168, 172, 145}, {31, 168, 172, 147}}},
|
||||
{Region: "Italy", IPs: []net.IP{{82, 102, 21, 98}, {82, 102, 21, 210}, {82, 102, 21, 211}, {82, 102, 21, 212}, {82, 102, 21, 213}, {82, 102, 21, 214}, {82, 102, 21, 215}, {82, 102, 21, 216}, {82, 102, 21, 217}, {82, 102, 21, 218}, {82, 102, 21, 219}}},
|
||||
{Region: "Japan", IPs: []net.IP{{103, 208, 220, 135}, {103, 208, 220, 136}, {103, 208, 220, 138}, {103, 208, 220, 139}, {103, 208, 220, 141}}},
|
||||
{Region: "Luxembourg", IPs: []net.IP{{92, 223, 89, 133}, {92, 223, 89, 134}, {92, 223, 89, 135}, {92, 223, 89, 136}, {92, 223, 89, 137}, {92, 223, 89, 138}, {92, 223, 89, 140}, {92, 223, 89, 142}}},
|
||||
{Region: "Mexico", IPs: []net.IP{{169, 57, 0, 197}, {169, 57, 0, 200}, {169, 57, 0, 203}, {169, 57, 0, 205}, {169, 57, 0, 207}, {169, 57, 0, 210}, {169, 57, 0, 211}, {169, 57, 0, 212}, {169, 57, 0, 213}, {169, 57, 0, 217}, {169, 57, 0, 218}, {169, 57, 0, 221}, {169, 57, 0, 229}, {169, 57, 0, 230}, {169, 57, 0, 233}, {169, 57, 0, 236}, {169, 57, 0, 238}, {169, 57, 0, 243}, {169, 57, 0, 247}, {169, 57, 0, 248}}},
|
||||
{Region: "Netherlands", IPs: []net.IP{{46, 166, 138, 145}, {46, 166, 138, 146}, {46, 166, 138, 155}, {46, 166, 138, 162}, {46, 166, 186, 248}, {46, 166, 188, 208}, {46, 166, 188, 210}, {46, 166, 188, 215}, {46, 166, 190, 178}, {46, 166, 190, 185}, {46, 166, 190, 186}, {46, 166, 190, 195}, {46, 166, 190, 230}, {109, 201, 138, 239}, {109, 201, 152, 5}, {109, 201, 152, 26}, {109, 201, 152, 227}, {109, 201, 154, 141}, {109, 201, 154, 142}, {185, 107, 44, 25}}},
|
||||
{Region: "New Zealand", IPs: []net.IP{{43, 250, 207, 3}}},
|
||||
{Region: "Norway", IPs: []net.IP{{82, 102, 27, 50}, {82, 102, 27, 51}, {82, 102, 27, 52}, {82, 102, 27, 53}, {82, 102, 27, 54}, {82, 102, 27, 56}, {82, 102, 27, 74}, {82, 102, 27, 75}, {82, 102, 27, 76}, {82, 102, 27, 77}, {82, 102, 27, 78}, {82, 102, 27, 114}, {82, 102, 27, 117}, {82, 102, 27, 118}, {82, 102, 27, 125}, {82, 102, 27, 126}, {185, 206, 225, 222}, {185, 253, 97, 226}, {185, 253, 97, 227}, {185, 253, 97, 228}}},
|
||||
{Region: "Poland", IPs: []net.IP{{185, 244, 214, 14}, {185, 244, 214, 194}, {185, 244, 214, 196}, {185, 244, 214, 197}, {185, 244, 214, 198}, {185, 244, 214, 199}, {185, 244, 214, 200}}},
|
||||
{Region: "Romania", IPs: []net.IP{{86, 105, 25, 66}, {86, 105, 25, 67}, {86, 105, 25, 68}, {86, 105, 25, 69}, {86, 105, 25, 70}, {86, 105, 25, 74}, {86, 105, 25, 75}, {86, 105, 25, 76}, {86, 105, 25, 77}, {86, 105, 25, 78}, {89, 33, 8, 42}, {94, 176, 148, 34}, {94, 176, 148, 35}, {185, 45, 12, 126}, {185, 210, 218, 100}, {185, 210, 218, 103}}},
|
||||
{Region: "Singapore", IPs: []net.IP{{37, 120, 208, 66}, {37, 120, 208, 67}, {37, 120, 208, 68}, {37, 120, 208, 70}, {37, 120, 208, 71}, {37, 120, 208, 72}, {37, 120, 208, 73}, {37, 120, 208, 74}, {37, 120, 208, 75}, {37, 120, 208, 76}, {37, 120, 208, 77}, {37, 120, 208, 78}, {37, 120, 208, 79}, {37, 120, 208, 80}, {37, 120, 208, 81}, {37, 120, 208, 82}, {37, 120, 208, 83}}},
|
||||
{Region: "Spain", IPs: []net.IP{{37, 120, 148, 86}, {185, 230, 124, 50}, {185, 230, 124, 51}, {185, 230, 124, 52}, {185, 230, 124, 53}, {185, 230, 124, 54}, {194, 99, 104, 26}, {194, 99, 104, 27}, {194, 99, 104, 28}, {194, 99, 104, 29}, {194, 99, 104, 30}, {195, 206, 107, 250}}},
|
||||
{Region: "Sweden", IPs: []net.IP{{45, 12, 220, 163}, {45, 12, 220, 168}, {45, 12, 220, 169}, {45, 12, 220, 173}, {45, 12, 220, 178}, {45, 12, 220, 180}, {45, 12, 220, 184}, {45, 12, 220, 190}, {45, 12, 220, 194}, {45, 12, 220, 197}, {45, 12, 220, 204}, {45, 12, 220, 205}, {45, 12, 220, 215}, {45, 12, 220, 218}, {45, 12, 220, 227}, {45, 12, 220, 233}, {45, 12, 220, 240}, {45, 12, 220, 254}, {45, 83, 91, 21}, {45, 83, 91, 36}}},
|
||||
{Region: "Switzerland", IPs: []net.IP{{82, 102, 24, 171}, {82, 102, 24, 250}, {82, 102, 24, 252}, {91, 132, 136, 52}, {91, 132, 136, 54}, {91, 132, 136, 210}, {185, 156, 175, 82}, {185, 156, 175, 88}, {185, 156, 175, 90}, {185, 156, 175, 94}, {185, 212, 170, 179}, {185, 212, 170, 182}, {185, 212, 170, 187}, {185, 230, 125, 34}, {185, 230, 125, 36}, {185, 230, 125, 45}, {185, 230, 125, 48}, {185, 230, 125, 52}, {185, 230, 125, 90}, {212, 102, 36, 1}}},
|
||||
{Region: "UAE", IPs: []net.IP{{45, 9, 250, 42}, {45, 9, 250, 46}, {45, 9, 250, 62}}},
|
||||
{Region: "UK London", IPs: []net.IP{{89, 238, 150, 9}, {89, 238, 150, 11}, {89, 238, 150, 15}, {89, 238, 150, 20}, {89, 238, 154, 18}, {89, 238, 154, 20}, {89, 238, 154, 23}, {89, 238, 154, 120}, {89, 238, 154, 121}, {89, 238, 154, 162}, {89, 238, 154, 167}, {89, 238, 154, 174}, {89, 238, 154, 179}, {89, 238, 154, 236}, {89, 238, 154, 243}, {89, 238, 154, 245}, {89, 238, 154, 249}, {89, 238, 154, 250}, {89, 238, 154, 251}, {89, 238, 154, 254}}},
|
||||
{Region: "UK Manchester", IPs: []net.IP{{89, 238, 137, 36}, {89, 238, 137, 37}, {89, 238, 137, 38}, {89, 238, 137, 39}, {89, 238, 137, 40}, {89, 238, 137, 41}, {89, 238, 139, 4}, {89, 238, 139, 5}, {89, 238, 139, 7}, {89, 238, 139, 8}, {89, 238, 139, 9}, {89, 238, 139, 10}, {89, 238, 139, 11}, {89, 238, 139, 13}, {89, 238, 139, 53}, {89, 238, 139, 55}, {89, 238, 139, 56}, {89, 238, 139, 57}, {89, 238, 139, 58}, {89, 249, 67, 220}}},
|
||||
{Region: "UK Southampton", IPs: []net.IP{{31, 24, 226, 141}, {31, 24, 226, 145}, {31, 24, 226, 146}, {31, 24, 226, 205}, {31, 24, 226, 207}, {31, 24, 226, 208}, {31, 24, 226, 209}, {31, 24, 226, 217}, {31, 24, 226, 220}, {31, 24, 226, 223}, {31, 24, 226, 225}, {31, 24, 226, 226}, {31, 24, 226, 228}, {31, 24, 226, 232}, {31, 24, 226, 233}, {31, 24, 226, 234}, {31, 24, 226, 237}, {31, 24, 226, 244}, {31, 24, 226, 245}, {31, 24, 231, 197}}},
|
||||
{Region: "US Atlanta", IPs: []net.IP{{66, 115, 168, 2}, {66, 115, 168, 4}, {66, 115, 168, 7}, {66, 115, 168, 10}, {66, 115, 168, 13}, {66, 115, 168, 17}, {66, 115, 168, 19}, {66, 115, 168, 21}, {66, 115, 168, 23}, {66, 115, 168, 26}, {66, 115, 168, 27}, {66, 115, 168, 28}, {66, 115, 169, 198}, {66, 115, 169, 202}, {66, 115, 169, 204}, {66, 115, 169, 226}, {66, 115, 169, 229}, {66, 115, 169, 231}, {66, 115, 169, 242}, {66, 115, 169, 244}}},
|
||||
{Region: "US California", IPs: []net.IP{{91, 207, 175, 46}, {91, 207, 175, 62}, {91, 207, 175, 100}, {91, 207, 175, 102}, {91, 207, 175, 115}, {91, 207, 175, 121}, {91, 207, 175, 170}, {91, 207, 175, 181}, {91, 207, 175, 204}, {91, 207, 175, 206}, {91, 207, 175, 213}, {91, 207, 175, 226}, {91, 207, 175, 242}, {91, 207, 175, 250}, {91, 207, 175, 252}, {185, 245, 87, 181}, {185, 245, 87, 197}, {185, 245, 87, 215}, {212, 103, 49, 164}, {212, 103, 49, 168}}},
|
||||
{Region: "US Chicago", IPs: []net.IP{{104, 200, 153, 97}, {199, 116, 115, 130}, {199, 116, 115, 131}, {199, 116, 115, 132}, {199, 116, 115, 133}, {199, 116, 115, 134}, {199, 116, 115, 135}, {199, 116, 115, 136}, {199, 116, 115, 137}, {199, 116, 115, 138}, {199, 116, 115, 139}, {199, 116, 115, 140}, {199, 116, 115, 141}, {199, 116, 115, 142}, {199, 116, 115, 143}, {199, 116, 115, 144}, {199, 116, 115, 145}, {199, 116, 115, 146}, {199, 116, 115, 147}, {199, 116, 115, 148}}},
|
||||
{Region: "US Denver", IPs: []net.IP{{174, 128, 225, 106}, {174, 128, 225, 186}, {174, 128, 226, 18}, {174, 128, 227, 226}, {174, 128, 236, 98}, {174, 128, 236, 106}, {174, 128, 242, 234}, {174, 128, 244, 74}, {174, 128, 245, 106}, {198, 148, 82, 82}, {198, 148, 90, 58}, {199, 115, 98, 146}, {199, 115, 98, 154}, {199, 115, 99, 218}}},
|
||||
{Region: "US East", IPs: []net.IP{{193, 37, 253, 38}, {193, 37, 253, 115}, {194, 59, 251, 6}, {194, 59, 251, 13}, {194, 59, 251, 14}, {194, 59, 251, 17}, {194, 59, 251, 28}, {194, 59, 251, 29}, {194, 59, 251, 58}, {194, 59, 251, 66}, {194, 59, 251, 74}, {194, 59, 251, 81}, {194, 59, 251, 104}, {194, 59, 251, 111}, {194, 59, 251, 112}, {194, 59, 251, 149}, {194, 59, 251, 166}, {194, 59, 251, 216}, {194, 59, 251, 227}, {194, 59, 251, 240}}},
|
||||
{Region: "US Florida", IPs: []net.IP{{193, 37, 252, 3}, {193, 37, 252, 12}, {193, 37, 252, 41}, {193, 37, 252, 45}, {193, 37, 252, 46}, {193, 37, 252, 52}, {193, 37, 252, 54}, {193, 37, 252, 55}, {193, 37, 252, 56}, {193, 37, 252, 58}, {193, 37, 252, 59}, {193, 37, 252, 75}, {193, 37, 252, 76}, {193, 37, 252, 102}, {193, 37, 252, 108}, {193, 37, 252, 115}, {193, 37, 252, 116}, {193, 37, 252, 118}, {193, 37, 252, 170}, {193, 37, 252, 174}}},
|
||||
{Region: "US Houston", IPs: []net.IP{{74, 81, 88, 18}, {74, 81, 88, 26}, {74, 81, 88, 66}, {74, 81, 88, 82}, {74, 81, 88, 114}, {74, 81, 88, 130}, {74, 81, 88, 162}, {205, 251, 148, 34}, {205, 251, 148, 66}, {205, 251, 148, 82}, {205, 251, 148, 98}, {205, 251, 148, 130}, {205, 251, 148, 178}, {205, 251, 150, 146}, {205, 251, 150, 154}, {205, 251, 150, 162}, {205, 251, 150, 170}, {205, 251, 150, 194}, {205, 251, 150, 218}, {205, 251, 150, 234}}},
|
||||
{Region: "US Las Vegas", IPs: []net.IP{{162, 251, 236, 2}, {162, 251, 236, 3}, {162, 251, 236, 4}, {162, 251, 236, 5}, {162, 251, 236, 7}, {162, 251, 236, 8}, {162, 251, 236, 9}, {199, 127, 56, 82}, {199, 127, 56, 83}, {199, 127, 56, 84}, {199, 127, 56, 86}, {199, 127, 56, 88}, {199, 127, 56, 89}, {199, 127, 56, 91}, {199, 127, 56, 114}, {199, 127, 56, 115}, {199, 127, 56, 118}, {199, 127, 56, 119}, {199, 127, 56, 120}, {199, 127, 56, 121}}},
|
||||
{Region: "US New York City", IPs: []net.IP{{107, 182, 231, 24}, {107, 182, 231, 34}, {173, 244, 223, 122}, {209, 95, 50, 13}, {209, 95, 50, 17}, {209, 95, 50, 18}, {209, 95, 50, 27}, {209, 95, 50, 49}, {209, 95, 50, 50}, {209, 95, 50, 56}, {209, 95, 50, 84}, {209, 95, 50, 87}, {209, 95, 50, 89}, {209, 95, 50, 93}, {209, 95, 50, 134}, {209, 95, 50, 139}, {209, 95, 50, 147}, {209, 95, 50, 148}, {209, 95, 50, 162}, {209, 95, 50, 163}}},
|
||||
{Region: "US Seattle", IPs: []net.IP{{104, 200, 154, 12}, {104, 200, 154, 38}, {104, 200, 154, 39}, {104, 200, 154, 50}, {104, 200, 154, 65}, {104, 200, 154, 66}, {104, 200, 154, 68}, {104, 200, 154, 70}, {104, 200, 154, 72}, {104, 200, 154, 73}, {104, 200, 154, 74}, {104, 200, 154, 75}, {104, 200, 154, 78}, {104, 200, 154, 79}, {104, 200, 154, 84}, {104, 200, 154, 86}, {104, 200, 154, 88}, {104, 200, 154, 90}, {104, 200, 154, 91}, {104, 200, 154, 98}}},
|
||||
{Region: "US Silicon Valley", IPs: []net.IP{{199, 116, 118, 131}, {199, 116, 118, 132}, {199, 116, 118, 133}, {199, 116, 118, 137}, {199, 116, 118, 140}, {199, 116, 118, 155}, {199, 116, 118, 156}, {199, 116, 118, 170}, {199, 116, 118, 173}, {199, 116, 118, 178}, {199, 116, 118, 184}, {199, 116, 118, 201}, {199, 116, 118, 202}, {199, 116, 118, 209}, {199, 116, 118, 210}, {199, 116, 118, 228}, {199, 116, 118, 237}, {199, 116, 118, 238}, {199, 116, 118, 244}, {199, 116, 118, 250}}},
|
||||
{Region: "US Texas", IPs: []net.IP{{162, 216, 46, 5}, {162, 216, 46, 10}, {162, 216, 46, 14}, {162, 216, 46, 18}, {162, 216, 46, 36}, {162, 216, 46, 38}, {162, 216, 46, 39}, {162, 216, 46, 42}, {162, 216, 46, 58}, {162, 216, 46, 71}, {162, 216, 46, 82}, {162, 216, 46, 85}, {162, 216, 46, 104}, {162, 216, 46, 105}, {162, 216, 46, 132}, {162, 216, 46, 138}, {162, 216, 46, 150}, {162, 216, 46, 151}, {162, 216, 46, 153}, {162, 216, 46, 170}}},
|
||||
{Region: "US Washington DC", IPs: []net.IP{{70, 32, 0, 24}, {70, 32, 0, 30}, {70, 32, 0, 54}, {70, 32, 0, 64}, {70, 32, 0, 68}, {70, 32, 0, 77}, {70, 32, 0, 111}, {70, 32, 0, 120}, {70, 32, 0, 121}, {70, 32, 0, 137}, {70, 32, 0, 153}, {70, 32, 0, 155}, {70, 32, 0, 165}, {70, 32, 0, 166}, {70, 32, 0, 167}, {70, 32, 0, 170}, {70, 32, 0, 172}, {70, 32, 0, 177}, {70, 32, 0, 178}, {70, 32, 0, 179}}},
|
||||
{Region: "US West", IPs: []net.IP{{104, 200, 151, 3}, {104, 200, 151, 11}, {104, 200, 151, 14}, {104, 200, 151, 15}, {104, 200, 151, 21}, {104, 200, 151, 28}, {104, 200, 151, 29}, {104, 200, 151, 34}, {104, 200, 151, 36}, {104, 200, 151, 42}, {104, 200, 151, 44}, {104, 200, 151, 47}, {104, 200, 151, 50}, {104, 200, 151, 51}, {104, 200, 151, 54}, {104, 200, 151, 60}, {104, 200, 151, 72}, {104, 200, 151, 75}, {104, 200, 151, 77}, {104, 200, 151, 78}}},
|
||||
}
|
||||
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 (
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
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
|
||||
// Announcement is a message announcement
|
||||
Announcement = "Video of the Git history of Gluetun (2020 is crazy): https://youtu.be/khipOYJtGJ0"
|
||||
// AnnouncementExpiration is the expiration date of the announcement in format yyyy-mm-dd
|
||||
AnnouncementExpiration = "2020-07-30"
|
||||
)
|
||||
|
||||
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_AnnouncementExpiration(t *testing.T) {
|
||||
t.Parallel()
|
||||
if len(AnnouncementExpiration) == 0 {
|
||||
return
|
||||
}
|
||||
_, err := time.Parse("2006-01-02", AnnouncementExpiration)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
174
internal/constants/surfshark.go
Normal file
174
internal/constants/surfshark.go
Normal file
@@ -0,0 +1,174 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
const (
|
||||
SurfsharkCertificate = "MIIFTTCCAzWgAwIBAgIJAMs9S3fqwv+mMA0GCSqGSIb3DQEBCwUAMD0xCzAJBgNVBAYTAlZHMRIwEAYDVQQKDAlTdXJmc2hhcmsxGjAYBgNVBAMMEVN1cmZzaGFyayBSb290IENBMB4XDTE4MDMxNDA4NTkyM1oXDTI4MDMxMTA4NTkyM1owPTELMAkGA1UEBhMCVkcxEjAQBgNVBAoMCVN1cmZzaGFyazEaMBgGA1UEAwwRU3VyZnNoYXJrIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDEGMNj0aisM63oSkmVJyZPaYX7aPsZtzsxo6m6p5Wta3MGASoryRsBuRaH6VVa0fwbI1nw5ubyxkuaNa4v3zHVwuSq6F1p8S811+1YP1av+jqDcMyojH0ujZSHIcb/i5LtaHNXBQ3qN48Cc7sqBnTIIFpmb5HthQ/4pW+a82b1guM5dZHsh7q+LKQDIGmvtMtO1+NEnmj81BApFayiaD1ggvwDI4x7o/Y3ksfWSCHnqXGyqzSFLh8QuQrTmWUm84YHGFxoI1/8AKdIyVoB6BjcaMKtKs/pbctk6vkzmYf0XmGovDKPQF6MwUekchLjB5gSBNnptSQ9kNgnTLqi0OpSwI6ixX52Ksva6UM8P01ZIhWZ6ua/T/tArgODy5JZMW+pQ1A6L0b7egIeghpwKnPRG+5CzgO0J5UE6gv000mqbmC3CbiS8xi2xuNgruAyY2hUOoV9/BuBev8ttE5ZCsJH3YlG6NtbZ9hPc61GiBSx8NJnX5QHyCnfic/X87eST/amZsZCAOJ5v4EPSaKrItt+HrEFWZQIq4fJmHJNNbYvWzCE08AL+5/6Z+lxb/Bm3dapx2zdit3x2e+miGHekuiE8lQWD0rXD4+T+nDRi3X+kyt8Ex/8qRiUfrisrSHFzVMRungIMGdO9O/zCINFrb7wahm4PqU2f12Z9TRCOTXciQIDAQABo1AwTjAdBgNVHQ4EFgQUYRpbQwyDahLMN3F2ony3+UqOYOgwHwYDVR0jBBgwFoAUYRpbQwyDahLMN3F2ony3+UqOYOgwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAn9zV7F/XVnFNZhHFrt0ZS1Yqz+qM9CojLmiyblMFh0p7t+Hh+VKVgMwrz0LwDH4UsOosXA28eJPmech6/bjfymkoXISy/NUSTFpUChGO9RabGGxJsT4dugOw9MPaIVZffny4qYOc/rXDXDSfF2b+303lLPI43y9qoe0oyZ1vtk/UKG75FkWfFUogGNbpOkuz+et5Y0aIEiyg0yh6/l5Q5h8+yom0HZnREHhqieGbkaGKLkyu7zQ4D4tRK/mBhd8nv+09GtPEG+D5LPbabFVxKjBMP4Vp24WuSUOqcGSsURHevawPVBfgmsxf1UCjelaIwngdh6WfNCRXa5QQPQTKubQvkvXONCDdhmdXQccnRX1nJWhPYi0onffvjsWUfztRypsKzX4dvM9k7xnIcGSGEnCC4RCgt1UiZIj7frcCMssbA6vJ9naM0s7JF7N3VKeHJtqe1OCRHMYnWUZt9vrqX6IoIHlZCoLlv39wFW9QNxelcAOCVbD+19MZ0ZXt7LitjIqe7yF5WxDQN4xru087FzQ4Hfj7eH1SNLLyKZkA1eecjmRoi/OoqAt7afSnwtQLtMUc2bQDg6rHt5C0e4dCLqP/9PGZTSJiwmtRHJ/N5qYWIh9ju83APvLm/AGBTR2pXmj9G3KdVOkpIC7L35dI623cSEC3Q3UZutsEm/UplsM="
|
||||
SurfsharkOpenvpnStaticKeyV1 = "b02cb1d7c6fee5d4f89b8de72b51a8d0c7b282631d6fc19be1df6ebae9e2779e6d9f097058a31c97f57f0c35526a44ae09a01d1284b50b954d9246725a1ead1ff224a102ed9ab3da0152a15525643b2eee226c37041dc55539d475183b889a10e18bb94f079a4a49888da566b99783460ece01daaf93548beea6c827d9674897e7279ff1a19cb092659e8c1860fbad0db4ad0ad5732f1af4655dbd66214e552f04ed8fd0104e1d4bf99c249ac229ce169d9ba22068c6c0ab742424760911d4636aafb4b85f0c952a9ce4275bc821391aa65fcd0d2394f006e3fba0fd34c4bc4ab260f4b45dec3285875589c97d3087c9134d3a3aa2f904512e85aa2dc2202498"
|
||||
)
|
||||
|
||||
func SurfsharkRegionChoices() (choices []string) {
|
||||
servers := SurfsharkServers()
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
}
|
||||
return choices
|
||||
}
|
||||
|
||||
func SurfsharkServers() []models.SurfsharkServer {
|
||||
return []models.SurfsharkServer{
|
||||
{Region: "Albania", IPs: []net.IP{{31, 171, 152, 197}, {31, 171, 154, 147}, {31, 171, 154, 149}, {31, 171, 154, 163}, {31, 171, 154, 165}}},
|
||||
{Region: "Australia Adelaide", IPs: []net.IP{{45, 248, 79, 19}, {45, 248, 79, 21}, {45, 248, 79, 27}, {45, 248, 79, 29}, {45, 248, 79, 51}, {45, 248, 79, 53}, {45, 248, 79, 67}, {45, 248, 79, 69}}},
|
||||
{Region: "Australia Brisbane", IPs: []net.IP{{45, 248, 77, 235}, {45, 248, 77, 237}, {144, 48, 39, 11}, {144, 48, 39, 13}, {144, 48, 39, 67}, {144, 48, 39, 69}, {144, 48, 39, 83}, {144, 48, 39, 85}, {144, 48, 39, 107}, {144, 48, 39, 109}, {144, 48, 39, 123}, {144, 48, 39, 125}, {144, 48, 39, 131}, {144, 48, 39, 133}}},
|
||||
{Region: "Australia Melbourne", IPs: []net.IP{{103, 192, 80, 131}, {103, 192, 80, 133}, {103, 192, 80, 139}, {103, 192, 80, 141}, {103, 192, 80, 147}, {103, 192, 80, 149}, {144, 48, 38, 19}, {144, 48, 38, 21}, {144, 48, 38, 139}, {144, 48, 38, 141}, {144, 48, 38, 147}, {144, 48, 38, 149}, {144, 48, 38, 179}, {144, 48, 38, 183}}},
|
||||
{Region: "Australia Perth", IPs: []net.IP{{45, 248, 78, 43}, {45, 248, 78, 45}, {124, 150, 139, 27}, {124, 150, 139, 29}, {124, 150, 139, 35}, {124, 150, 139, 37}, {124, 150, 139, 43}, {124, 150, 139, 45}, {124, 150, 139, 123}, {124, 150, 139, 125}, {124, 150, 139, 179}, {124, 150, 139, 181}}},
|
||||
{Region: "Australia Sydney", IPs: []net.IP{{45, 125, 247, 43}, {45, 125, 247, 45}, {45, 125, 247, 91}, {45, 125, 247, 93}, {45, 125, 247, 195}, {45, 125, 247, 197}, {45, 248, 76, 171}, {45, 248, 76, 173}, {103, 25, 59, 51}, {103, 25, 59, 53}, {103, 25, 59, 83}, {103, 25, 59, 85}, {180, 149, 228, 115}, {180, 149, 228, 117}}},
|
||||
{Region: "Australia US", IPs: []net.IP{{45, 76, 117, 108}}},
|
||||
{Region: "Austria", IPs: []net.IP{{5, 253, 207, 51}, {5, 253, 207, 53}, {5, 253, 207, 83}, {5, 253, 207, 85}, {37, 120, 212, 75}, {37, 120, 212, 77}, {37, 120, 212, 131}, {37, 120, 212, 133}, {37, 120, 212, 141}, {37, 120, 212, 147}, {37, 120, 212, 149}}},
|
||||
{Region: "Azerbaijan", IPs: []net.IP{{94, 20, 21, 85}, {94, 20, 21, 87}}},
|
||||
{Region: "Belgium", IPs: []net.IP{{5, 253, 205, 99}, {5, 253, 205, 101}, {5, 253, 205, 179}, {5, 253, 205, 181}, {5, 253, 205, 211}, {5, 253, 205, 213}, {5, 253, 205, 227}, {5, 253, 205, 229}, {37, 120, 218, 19}, {37, 120, 218, 21}, {37, 120, 218, 27}, {37, 120, 218, 251}, {37, 120, 218, 253}, {89, 249, 73, 195}, {89, 249, 73, 197}, {185, 104, 186, 75}, {185, 104, 186, 77}, {185, 232, 21, 51}}},
|
||||
{Region: "Bosnia and Herzegovina", IPs: []net.IP{{185, 99, 3, 7}, {185, 99, 3, 12}, {185, 99, 3, 205}, {185, 99, 3, 207}, {185, 99, 3, 212}, {185, 99, 3, 214}, {185, 212, 111, 6}, {185, 212, 111, 41}}},
|
||||
{Region: "Brazil", IPs: []net.IP{{191, 96, 73, 210}, {191, 96, 73, 212}, {191, 96, 73, 216}, {194, 41, 113, 3}, {194, 41, 113, 5}}},
|
||||
{Region: "Bulgaria", IPs: []net.IP{{37, 120, 152, 35}, {37, 120, 152, 37}, {37, 120, 152, 39}, {37, 120, 152, 195}, {37, 120, 152, 197}, {217, 138, 202, 19}, {217, 138, 202, 21}}},
|
||||
{Region: "Canada Montreal", IPs: []net.IP{{172, 98, 82, 83}, {172, 98, 82, 85}, {172, 98, 82, 229}, {172, 98, 82, 231}, {172, 98, 82, 245}, {198, 8, 85, 3}, {198, 8, 85, 5}, {198, 8, 85, 19}, {198, 8, 85, 21}, {198, 8, 85, 35}, {198, 8, 85, 37}, {198, 8, 85, 45}, {198, 8, 85, 47}, {198, 8, 85, 67}, {198, 8, 85, 69}, {198, 8, 85, 72}, {198, 8, 85, 77}, {198, 8, 85, 79}, {198, 8, 85, 82}, {198, 8, 85, 84}, {198, 8, 85, 87}, {198, 8, 85, 89}, {198, 8, 85, 131}, {198, 8, 85, 133}}},
|
||||
{Region: "Canada Toronto", IPs: []net.IP{{68, 71, 244, 131}, {68, 71, 244, 134}, {68, 71, 244, 195}, {68, 71, 244, 197}, {68, 71, 244, 200}, {68, 71, 244, 202}, {68, 71, 244, 205}, {68, 71, 244, 207}, {68, 71, 244, 210}, {68, 71, 244, 212}, {68, 71, 244, 215}, {68, 71, 244, 220}, {68, 71, 244, 222}, {104, 200, 138, 5}, {104, 200, 138, 99}, {104, 200, 138, 147}, {104, 200, 138, 149}, {104, 200, 138, 152}, {104, 200, 138, 154}, {104, 200, 138, 163}}},
|
||||
{Region: "Canada US", IPs: []net.IP{{159, 203, 57, 80}}},
|
||||
{Region: "Canada Vancouver", IPs: []net.IP{{66, 115, 147, 67}, {66, 115, 147, 69}, {66, 115, 147, 72}, {66, 115, 147, 74}, {66, 115, 147, 77}, {66, 115, 147, 79}, {66, 115, 147, 82}, {66, 115, 147, 84}, {66, 115, 147, 87}, {66, 115, 147, 89}, {66, 115, 147, 92}, {66, 115, 147, 94}, {104, 200, 132, 37}, {104, 200, 132, 39}, {107, 181, 177, 179}, {107, 181, 177, 181}, {107, 181, 177, 183}, {172, 83, 40, 147}, {172, 83, 40, 149}, {208, 78, 41, 195}, {208, 78, 41, 197}, {208, 78, 41, 200}, {208, 78, 41, 202}}},
|
||||
{Region: "Chile", IPs: []net.IP{{31, 169, 121, 16}}},
|
||||
{Region: "Colombia", IPs: []net.IP{{45, 129, 32, 3}, {45, 129, 32, 5}, {45, 129, 32, 10}, {45, 129, 32, 20}, {45, 129, 32, 22}}},
|
||||
{Region: "Costa Rica", IPs: []net.IP{{176, 227, 241, 19}, {176, 227, 241, 21}}},
|
||||
{Region: "Croatia", IPs: []net.IP{{89, 164, 99, 111}}},
|
||||
{Region: "Cyprus", IPs: []net.IP{{195, 47, 194, 34}, {195, 47, 194, 36}, {195, 47, 194, 42}}},
|
||||
{Region: "Czech Republic", IPs: []net.IP{{185, 152, 64, 151}, {185, 152, 64, 178}, {193, 9, 112, 179}, {193, 9, 112, 181}, {193, 9, 112, 183}, {193, 9, 112, 195}, {193, 9, 112, 197}}},
|
||||
{Region: "Denmark", IPs: []net.IP{{37, 120, 145, 19}, {37, 120, 145, 21}, {37, 120, 194, 91}, {37, 120, 194, 93}, {37, 120, 194, 99}, {37, 120, 194, 101}, {37, 120, 194, 107}, {37, 120, 194, 109}, {37, 120, 194, 115}, {37, 120, 194, 117}, {37, 120, 194, 123}, {37, 120, 194, 163}, {37, 120, 194, 165}, {45, 12, 221, 163}, {45, 12, 221, 165}, {45, 12, 221, 167}, {45, 12, 221, 179}, {45, 12, 221, 181}, {45, 12, 221, 183}, {95, 174, 65, 67}, {95, 174, 65, 69}, {95, 174, 65, 71}, {95, 174, 65, 73}}},
|
||||
{Region: "Estonia", IPs: []net.IP{{165, 231, 163, 3}, {165, 231, 163, 5}, {165, 231, 163, 7}, {165, 231, 163, 19}, {165, 231, 163, 21}, {165, 231, 163, 23}, {185, 174, 159, 51}, {185, 174, 159, 53}, {185, 174, 159, 59}, {185, 174, 159, 61}, {185, 174, 159, 67}, {185, 174, 159, 69}}},
|
||||
{Region: "Finland", IPs: []net.IP{{196, 244, 191, 163}, {196, 244, 191, 165}, {196, 244, 191, 181}, {196, 244, 191, 195}, {196, 244, 191, 197}}},
|
||||
{Region: "France Bordeaux", IPs: []net.IP{{185, 108, 106, 51}, {185, 108, 106, 53}, {185, 108, 106, 67}, {185, 108, 106, 69}, {185, 108, 106, 140}, {185, 108, 106, 142}, {185, 108, 106, 144}, {185, 108, 106, 146}, {185, 108, 106, 148}, {185, 108, 106, 150}, {185, 108, 106, 152}, {185, 108, 106, 154}, {185, 108, 106, 156}, {185, 108, 106, 158}, {185, 108, 106, 160}, {185, 108, 106, 162}, {185, 108, 106, 164}, {185, 108, 106, 166}}},
|
||||
{Region: "France Marseilles", IPs: []net.IP{{185, 166, 84, 3}, {185, 166, 84, 5}, {185, 166, 84, 11}, {185, 166, 84, 13}, {185, 166, 84, 17}, {185, 166, 84, 21}, {185, 166, 84, 23}, {185, 166, 84, 27}, {185, 166, 84, 29}, {185, 166, 84, 36}, {185, 166, 84, 38}, {185, 166, 84, 55}, {185, 166, 84, 61}, {185, 166, 84, 63}, {185, 166, 84, 65}, {185, 166, 84, 75}, {185, 166, 84, 77}, {185, 166, 84, 79}, {185, 166, 84, 81}, {185, 166, 84, 83}, {185, 166, 84, 85}, {185, 166, 84, 87}, {185, 166, 84, 89}, {185, 166, 84, 91}, {185, 166, 84, 93}}},
|
||||
{Region: "France Paris", IPs: []net.IP{{45, 83, 90, 179}, {45, 83, 90, 183}, {45, 89, 174, 59}, {45, 89, 174, 61}, {45, 89, 174, 83}, {45, 89, 174, 85}, {45, 89, 174, 91}, {45, 89, 174, 99}, {45, 89, 174, 101}, {45, 89, 174, 103}, {84, 17, 43, 178}, {84, 17, 43, 180}, {84, 17, 43, 183}, {84, 17, 43, 185}, {84, 17, 60, 235}, {84, 17, 60, 250}, {84, 247, 51, 235}, {84, 247, 51, 243}, {84, 247, 51, 251}, {84, 247, 51, 253}, {185, 246, 211, 69}, {217, 138, 207, 243}, {217, 138, 207, 245}, {217, 138, 207, 251}, {217, 138, 207, 253}}},
|
||||
{Region: "France Sweden", IPs: []net.IP{{199, 247, 8, 20}}},
|
||||
{Region: "Germany Berlin", IPs: []net.IP{{37, 120, 217, 131}, {37, 120, 217, 133}, {37, 120, 217, 147}, {37, 120, 217, 149}, {37, 120, 217, 179}, {37, 120, 217, 181}, {152, 89, 163, 19}, {152, 89, 163, 21}, {152, 89, 163, 23}, {152, 89, 163, 227}, {152, 89, 163, 229}, {152, 89, 163, 243}, {193, 176, 86, 195}, {193, 176, 86, 197}, {217, 138, 216, 59}, {217, 138, 216, 61}, {217, 138, 216, 219}, {217, 138, 216, 221}, {217, 138, 216, 227}, {217, 138, 216, 229}, {217, 138, 216, 235}, {217, 138, 216, 243}, {217, 138, 216, 245}, {217, 138, 216, 251}, {217, 138, 216, 253}}},
|
||||
{Region: "Germany Frankfurt am Main st001", IPs: []net.IP{{45, 87, 212, 179}}},
|
||||
{Region: "Germany Frankfurt am Main st002", IPs: []net.IP{{45, 87, 212, 181}}},
|
||||
{Region: "Germany Frankfurt am Main st003", IPs: []net.IP{{45, 87, 212, 183}}},
|
||||
{Region: "Germany Frankfurt am Main", IPs: []net.IP{{37, 120, 196, 51}, {37, 120, 196, 53}, {37, 120, 196, 59}, {37, 120, 196, 61}, {37, 120, 196, 171}, {37, 120, 197, 11}, {45, 87, 212, 211}, {45, 87, 212, 213}, {74, 119, 145, 51}, {82, 102, 16, 99}, {82, 102, 16, 101}, {84, 16, 240, 176}, {89, 187, 169, 104}, {89, 187, 169, 119}, {185, 59, 220, 144}, {185, 59, 220, 150}, {185, 59, 220, 168}, {185, 59, 220, 172}, {185, 93, 180, 99}, {185, 93, 180, 101}, {185, 102, 219, 6}, {185, 102, 219, 47}, {185, 102, 219, 49}, {185, 158, 135, 36}, {185, 220, 70, 83}}},
|
||||
{Region: "Germany Munich", IPs: []net.IP{{178, 238, 231, 49}, {178, 238, 231, 51}, {178, 238, 231, 55}}},
|
||||
{Region: "Germany Nuremberg", IPs: []net.IP{{62, 171, 151, 182}}},
|
||||
{Region: "Germany Singapour", IPs: []net.IP{{159, 89, 14, 157}}},
|
||||
{Region: "Germany UK", IPs: []net.IP{{46, 101, 250, 73}}},
|
||||
{Region: "Greece", IPs: []net.IP{{194, 150, 167, 28}, {194, 150, 167, 30}, {194, 150, 167, 32}, {194, 150, 167, 34}, {194, 150, 167, 36}, {194, 150, 167, 38}, {194, 150, 167, 40}, {194, 150, 167, 42}, {194, 150, 167, 44}, {194, 150, 167, 46}, {194, 150, 167, 48}, {194, 150, 167, 50}, {194, 150, 167, 52}, {194, 150, 167, 54}, {194, 150, 167, 58}}},
|
||||
{Region: "Hong Kong", IPs: []net.IP{{64, 120, 121, 212}, {64, 120, 121, 214}, {64, 120, 121, 232}, {64, 120, 121, 234}, {64, 120, 121, 236}, {64, 120, 121, 238}, {64, 120, 121, 244}, {64, 120, 121, 248}, {84, 17, 37, 154}, {84, 17, 37, 156}, {84, 17, 37, 158}, {84, 17, 37, 160}, {84, 17, 57, 66}, {84, 17, 57, 68}, {84, 17, 57, 71}, {84, 17, 57, 185}, {209, 58, 186, 10}, {209, 58, 186, 14}, {212, 102, 42, 194}, {212, 102, 42, 199}, {212, 102, 42, 201}, {212, 102, 42, 204}, {212, 102, 42, 206}, {212, 102, 42, 209}, {212, 102, 42, 211}}},
|
||||
{Region: "Hungary", IPs: []net.IP{{37, 120, 144, 147}, {37, 120, 144, 149}, {37, 120, 144, 151}, {37, 120, 144, 195}, {37, 120, 144, 197}, {37, 120, 144, 199}, {37, 120, 144, 211}, {37, 120, 144, 213}, {37, 120, 144, 215}, {37, 120, 144, 243}}},
|
||||
{Region: "Iceland", IPs: []net.IP{{82, 221, 128, 156}, {82, 221, 128, 166}, {82, 221, 128, 169}, {82, 221, 143, 241}, {82, 221, 143, 243}}},
|
||||
{Region: "India Chennai", IPs: []net.IP{{103, 94, 27, 99}, {103, 94, 27, 101}, {103, 94, 27, 115}, {103, 94, 27, 117}, {103, 94, 27, 179}, {103, 94, 27, 181}, {103, 94, 27, 227}, {103, 94, 27, 229}, {103, 108, 117, 116}, {103, 108, 117, 118}, {103, 108, 117, 120}, {103, 108, 117, 131}, {103, 108, 117, 133}, {103, 108, 117, 147}, {103, 108, 117, 149}}},
|
||||
{Region: "India Indore", IPs: []net.IP{{103, 39, 132, 187}, {103, 39, 132, 189}, {103, 73, 189, 219}, {103, 73, 189, 221}, {137, 59, 52, 107}, {137, 59, 52, 109}}},
|
||||
{Region: "India Mumbai", IPs: []net.IP{{103, 221, 233, 61}, {103, 221, 233, 82}, {103, 221, 233, 86}, {103, 221, 233, 88}, {103, 221, 233, 104}, {165, 231, 253, 147}}},
|
||||
{Region: "India UK", IPs: []net.IP{{134, 209, 148, 122}}},
|
||||
{Region: "Indonesia", IPs: []net.IP{{103, 120, 66, 214}, {103, 120, 66, 216}, {103, 120, 66, 219}, {103, 120, 66, 221}, {103, 227, 255, 211}, {103, 227, 255, 213}}},
|
||||
{Region: "Ireland", IPs: []net.IP{{185, 108, 128, 114}, {185, 108, 128, 118}, {185, 108, 128, 120}, {185, 108, 128, 159}, {185, 108, 128, 161}, {185, 108, 128, 183}, {217, 138, 222, 43}, {217, 138, 222, 45}, {217, 138, 222, 51}, {217, 138, 222, 53}}},
|
||||
{Region: "Israel", IPs: []net.IP{{87, 239, 255, 107}, {87, 239, 255, 109}, {87, 239, 255, 114}, {87, 239, 255, 116}, {87, 239, 255, 119}, {87, 239, 255, 121}}},
|
||||
{Region: "Italy Milan", IPs: []net.IP{{37, 120, 201, 21}, {84, 17, 58, 134}, {84, 17, 58, 150}, {84, 17, 58, 154}, {84, 17, 58, 159}, {84, 17, 58, 192}, {84, 17, 58, 195}, {84, 17, 58, 205}, {84, 17, 58, 207}, {95, 174, 64, 67}, {95, 174, 64, 71}, {95, 174, 64, 73}, {212, 102, 54, 135}, {212, 102, 54, 147}, {212, 102, 54, 150}, {212, 102, 54, 152}, {212, 102, 54, 160}, {212, 102, 54, 165}, {212, 102, 54, 167}, {212, 102, 54, 175}, {212, 102, 54, 177}, {212, 102, 54, 180}, {212, 102, 54, 182}, {212, 102, 55, 66}, {212, 102, 55, 68}}},
|
||||
{Region: "Italy Rome", IPs: []net.IP{{37, 120, 207, 3}, {37, 120, 207, 5}, {82, 102, 26, 61}, {82, 102, 26, 93}, {82, 102, 26, 99}, {82, 102, 26, 101}, {87, 101, 94, 211}, {87, 101, 94, 227}, {87, 101, 94, 229}, {87, 101, 94, 231}, {185, 217, 71, 3}, {185, 217, 71, 21}, {185, 217, 71, 51}, {185, 217, 71, 53}, {185, 217, 71, 187}, {185, 217, 71, 189}, {185, 217, 71, 195}, {185, 217, 71, 197}, {185, 217, 71, 229}, {185, 217, 71, 235}, {185, 217, 71, 237}, {185, 217, 71, 251}, {217, 138, 219, 243}, {217, 138, 219, 251}, {217, 138, 219, 253}}},
|
||||
{Region: "Japan Tokyo st001", IPs: []net.IP{{45, 87, 213, 19}}},
|
||||
{Region: "Japan Tokyo st002", IPs: []net.IP{{45, 87, 213, 21}}},
|
||||
{Region: "Japan Tokyo st003", IPs: []net.IP{{45, 87, 213, 23}}},
|
||||
{Region: "Japan Tokyo st004", IPs: []net.IP{{217, 138, 212, 19}}},
|
||||
{Region: "Japan Tokyo st005", IPs: []net.IP{{217, 138, 212, 21}}},
|
||||
{Region: "Japan Tokyo st006", IPs: []net.IP{{82, 102, 28, 123}}},
|
||||
{Region: "Japan Tokyo st007", IPs: []net.IP{{82, 102, 28, 125}}},
|
||||
{Region: "Japan Tokyo", IPs: []net.IP{{45, 87, 213, 3}, {45, 87, 213, 5}, {45, 87, 213, 7}, {45, 87, 213, 83}, {45, 87, 213, 103}, {45, 87, 213, 243}, {45, 87, 213, 245}, {84, 17, 34, 24}, {84, 17, 34, 26}, {84, 17, 34, 44}, {84, 17, 34, 46}, {89, 187, 161, 2}, {89, 187, 161, 4}, {89, 187, 161, 239}, {89, 187, 161, 241}, {103, 208, 221, 227}, {103, 208, 221, 229}, {185, 242, 4, 163}}},
|
||||
{Region: "Kazakhstan", IPs: []net.IP{{45, 136, 56, 53}, {45, 136, 56, 54}, {45, 136, 56, 57}, {45, 136, 56, 61}}},
|
||||
{Region: "Korea", IPs: []net.IP{{61, 14, 210, 227}, {61, 14, 210, 229}, {61, 14, 210, 232}, {61, 14, 210, 234}, {61, 14, 210, 237}, {61, 14, 210, 242}, {61, 14, 210, 244}, {61, 97, 243, 112}, {61, 97, 243, 119}, {61, 97, 243, 124}, {103, 249, 28, 215}, {103, 249, 28, 227}, {103, 249, 28, 229}, {103, 249, 28, 231}, {103, 249, 31, 26}, {103, 249, 31, 28}}},
|
||||
{Region: "Latvia", IPs: []net.IP{{91, 203, 70, 186}, {91, 203, 70, 188}, {188, 92, 78, 135}, {188, 92, 78, 137}, {188, 92, 78, 140}, {188, 92, 78, 142}, {188, 92, 78, 145}, {188, 92, 78, 147}}},
|
||||
{Region: "Libya", IPs: []net.IP{{41, 208, 72, 158}, {41, 208, 72, 204}, {41, 208, 72, 207}}},
|
||||
{Region: "Luxembourg", IPs: []net.IP{{185, 153, 151, 60}, {185, 153, 151, 62}, {185, 153, 151, 73}, {185, 153, 151, 75}, {185, 153, 151, 78}, {185, 153, 151, 80}, {185, 153, 151, 82}, {185, 153, 151, 83}, {185, 153, 151, 85}, {185, 153, 151, 89}, {185, 153, 151, 91}}},
|
||||
{Region: "Malaysia", IPs: []net.IP{{42, 0, 30, 162}, {42, 0, 30, 164}, {42, 0, 30, 177}, {42, 0, 30, 179}, {42, 0, 30, 209}, {42, 0, 30, 213}, {42, 0, 30, 215}, {223, 25, 247, 206}}},
|
||||
{Region: "Moldova", IPs: []net.IP{{178, 175, 128, 235}, {178, 175, 128, 237}}},
|
||||
{Region: "Netherlands Amsterdam st001", IPs: []net.IP{{81, 19, 209, 51}}},
|
||||
{Region: "Netherlands Amsterdam", IPs: []net.IP{{81, 19, 208, 56}, {81, 19, 208, 66}, {81, 19, 208, 68}, {81, 19, 209, 20}, {81, 19, 209, 57}, {81, 19, 209, 113}, {81, 19, 209, 120}, {81, 19, 209, 124}, {89, 46, 223, 72}, {89, 46, 223, 78}, {89, 46, 223, 104}, {89, 46, 223, 212}, {89, 46, 223, 214}, {89, 46, 223, 217}, {89, 46, 223, 222}, {89, 46, 223, 229}, {89, 187, 174, 229}, {89, 187, 174, 231}, {185, 59, 222, 92}, {185, 59, 222, 94}, {185, 59, 222, 166}, {185, 59, 222, 168}, {212, 102, 35, 194}, {212, 102, 35, 196}}},
|
||||
{Region: "Netherlands US", IPs: []net.IP{{188, 166, 98, 91}}},
|
||||
{Region: "New Zealand", IPs: []net.IP{{180, 149, 231, 3}, {180, 149, 231, 11}, {180, 149, 231, 13}, {180, 149, 231, 43}, {180, 149, 231, 45}, {180, 149, 231, 69}, {180, 149, 231, 115}, {180, 149, 231, 117}, {180, 149, 231, 119}, {180, 149, 231, 163}}},
|
||||
{Region: "Nigeria", IPs: []net.IP{{102, 165, 23, 38}, {102, 165, 23, 42}, {102, 165, 23, 44}}},
|
||||
{Region: "North Macedonia", IPs: []net.IP{{185, 225, 28, 67}, {185, 225, 28, 69}, {185, 225, 28, 83}, {185, 225, 28, 85}, {185, 225, 28, 91}, {185, 225, 28, 93}, {185, 225, 28, 99}, {185, 225, 28, 101}, {185, 225, 28, 107}, {185, 225, 28, 109}, {185, 225, 28, 243}, {185, 225, 28, 245}}},
|
||||
{Region: "Norway", IPs: []net.IP{{45, 12, 223, 67}, {45, 12, 223, 69}, {45, 12, 223, 71}, {45, 12, 223, 195}, {45, 12, 223, 197}, {45, 12, 223, 211}, {45, 12, 223, 213}, {84, 247, 50, 27}, {84, 247, 50, 29}, {84, 247, 50, 67}, {84, 247, 50, 69}, {95, 174, 66, 35}, {95, 174, 66, 37}, {95, 174, 66, 39}}},
|
||||
{Region: "Paraguay", IPs: []net.IP{{181, 40, 18, 47}, {181, 40, 18, 56}, {186, 16, 32, 163}, {186, 16, 32, 168}, {186, 16, 32, 173}}},
|
||||
{Region: "Philippines", IPs: []net.IP{{45, 134, 224, 10}}},
|
||||
{Region: "Poland Gdansk", IPs: []net.IP{{5, 187, 49, 187}, {5, 187, 49, 189}, {5, 187, 53, 53}, {5, 187, 53, 55}}},
|
||||
{Region: "Poland Warsaw", IPs: []net.IP{{5, 253, 206, 67}, {5, 253, 206, 69}, {5, 253, 206, 71}, {5, 253, 206, 227}, {5, 253, 206, 229}, {84, 17, 55, 132}, {185, 246, 208, 72}, {185, 246, 208, 77}, {185, 246, 208, 105}, {185, 246, 208, 107}, {185, 246, 208, 176}, {185, 246, 208, 182}}},
|
||||
{Region: "Portugal Lisbon", IPs: []net.IP{{5, 154, 174, 26}, {5, 154, 174, 65}, {5, 154, 174, 67}, {5, 154, 174, 75}, {5, 154, 174, 77}, {5, 154, 174, 99}, {5, 154, 174, 101}, {5, 154, 174, 171}, {5, 154, 174, 173}, {5, 154, 174, 181}, {5, 154, 174, 187}, {5, 154, 174, 189}, {5, 154, 174, 213}, {5, 154, 174, 219}, {5, 154, 174, 221}, {5, 154, 174, 227}, {5, 154, 174, 229}}},
|
||||
{Region: "Portugal Loule", IPs: []net.IP{{94, 126, 172, 57}, {176, 61, 146, 86}, {176, 61, 146, 95}, {176, 61, 146, 106}, {176, 61, 146, 108}, {176, 61, 146, 111}, {176, 61, 146, 113}, {176, 61, 146, 116}, {176, 61, 148, 60}}},
|
||||
{Region: "Portugal Porto", IPs: []net.IP{{194, 39, 127, 21}, {194, 39, 127, 23}, {194, 39, 127, 36}, {194, 39, 127, 38}, {194, 39, 127, 233}, {194, 39, 127, 240}, {194, 39, 127, 244}}},
|
||||
{Region: "Romania", IPs: []net.IP{{45, 89, 175, 51}, {45, 89, 175, 53}, {45, 89, 175, 55}, {86, 106, 137, 147}, {86, 106, 137, 149}}},
|
||||
{Region: "Russia Moscow", IPs: []net.IP{{213, 183, 56, 18}, {213, 183, 56, 166}}},
|
||||
{Region: "Russia St. Petersburg", IPs: []net.IP{{213, 183, 54, 23}, {213, 183, 54, 110}, {213, 183, 54, 143}, {213, 183, 54, 165}}},
|
||||
{Region: "Serbia", IPs: []net.IP{{37, 120, 193, 51}, {37, 120, 193, 53}, {152, 89, 160, 119}, {152, 89, 160, 123}, {152, 89, 160, 125}, {152, 89, 160, 211}, {152, 89, 160, 213}, {152, 89, 160, 215}}},
|
||||
{Region: "Singapore Hong Kong", IPs: []net.IP{{206, 189, 83, 129}}},
|
||||
{Region: "Singapore Netherlands", IPs: []net.IP{{104, 248, 148, 18}}},
|
||||
{Region: "Singapore st001", IPs: []net.IP{{217, 138, 201, 91}}},
|
||||
{Region: "Singapore st002", IPs: []net.IP{{217, 138, 201, 93}}},
|
||||
{Region: "Singapore st003", IPs: []net.IP{{84, 247, 49, 19}}},
|
||||
{Region: "Singapore st004", IPs: []net.IP{{84, 247, 49, 21}}},
|
||||
{Region: "Singapore", IPs: []net.IP{{89, 187, 162, 186}, {89, 187, 162, 188}, {89, 187, 163, 130}, {89, 187, 163, 132}, {89, 187, 163, 134}, {89, 187, 163, 136}, {89, 187, 163, 195}, {89, 187, 163, 197}, {89, 187, 163, 200}, {89, 187, 163, 202}, {89, 187, 163, 205}, {89, 187, 163, 207}, {89, 187, 163, 210}, {89, 187, 163, 212}, {89, 187, 163, 217}, {103, 254, 153, 169}, {103, 254, 155, 241}, {156, 146, 56, 130}, {156, 146, 56, 132}, {156, 146, 56, 137}, {209, 58, 170, 146}, {209, 58, 170, 159}, {209, 58, 170, 164}, {209, 58, 170, 169}, {209, 58, 170, 172}}},
|
||||
{Region: "Slovekia", IPs: []net.IP{{37, 120, 221, 3}, {37, 120, 221, 5}, {193, 37, 255, 35}, {193, 37, 255, 37}, {193, 37, 255, 39}, {193, 37, 255, 41}}},
|
||||
{Region: "Slovenia", IPs: []net.IP{{195, 158, 249, 36}, {195, 158, 249, 38}, {195, 158, 249, 40}, {195, 158, 249, 48}, {195, 158, 249, 50}, {195, 158, 249, 52}}},
|
||||
{Region: "South Africa", IPs: []net.IP{{154, 127, 49, 226}, {154, 127, 49, 228}, {154, 127, 49, 230}, {154, 127, 49, 232}}},
|
||||
{Region: "Spain Barcelona", IPs: []net.IP{{37, 120, 142, 131}, {37, 120, 142, 133}, {37, 120, 142, 135}, {37, 120, 142, 179}, {37, 120, 142, 181}, {185, 188, 61, 3}, {185, 188, 61, 5}, {185, 188, 61, 7}, {185, 188, 61, 13}, {185, 188, 61, 15}, {185, 188, 61, 19}, {185, 188, 61, 21}, {185, 188, 61, 23}, {185, 188, 61, 25}, {185, 188, 61, 27}}},
|
||||
{Region: "Spain Madrid", IPs: []net.IP{{37, 120, 148, 213}, {37, 120, 148, 215}, {82, 102, 17, 181}, {84, 17, 62, 163}, {84, 17, 62, 165}, {84, 17, 62, 179}, {84, 17, 62, 181}, {89, 37, 95, 9}, {89, 37, 95, 11}, {89, 37, 95, 15}, {89, 37, 95, 17}, {89, 37, 95, 19}, {89, 37, 95, 21}, {89, 37, 95, 23}, {89, 37, 95, 27}, {188, 208, 141, 114}, {188, 208, 141, 116}, {212, 102, 48, 2}, {212, 102, 48, 4}, {212, 102, 48, 8}, {212, 102, 48, 10}, {212, 102, 48, 13}, {212, 102, 48, 15}, {212, 102, 48, 18}, {212, 102, 48, 20}}},
|
||||
{Region: "Spain Valencia", IPs: []net.IP{{185, 153, 150, 44}, {185, 153, 150, 46}, {185, 153, 150, 48}, {185, 153, 150, 50}, {185, 153, 150, 52}, {185, 153, 150, 54}, {185, 153, 150, 56}, {185, 153, 150, 58}, {196, 196, 150, 67}, {196, 196, 150, 69}, {196, 196, 150, 71}, {196, 196, 150, 83}, {196, 196, 150, 99}, {196, 196, 150, 101}}},
|
||||
{Region: "Sweden", IPs: []net.IP{{45, 83, 91, 131}, {45, 83, 91, 133}, {45, 83, 91, 135}, {45, 83, 91, 147}, {45, 83, 91, 149}, {45, 83, 91, 151}, {46, 227, 69, 19}, {46, 227, 69, 21}, {185, 76, 9, 34}, {185, 76, 9, 36}}},
|
||||
{Region: "Switzerland", IPs: []net.IP{{37, 120, 213, 3}, {45, 12, 222, 243}, {45, 12, 222, 245}, {84, 17, 53, 86}, {84, 17, 53, 166}, {84, 17, 53, 168}, {84, 17, 53, 210}, {84, 17, 53, 212}, {84, 17, 53, 214}, {84, 17, 53, 216}, {84, 17, 53, 219}, {84, 17, 53, 221}, {84, 17, 53, 223}, {84, 17, 53, 227}, {84, 39, 112, 35}}},
|
||||
{Region: "Taiwan", IPs: []net.IP{{2, 58, 241, 3}, {2, 58, 241, 5}, {2, 58, 242, 43}, {2, 58, 242, 155}, {2, 58, 243, 51}, {2, 58, 243, 53}, {103, 51, 140, 70}, {103, 98, 75, 73}}},
|
||||
{Region: "Thailand", IPs: []net.IP{{45, 64, 186, 132}, {45, 64, 186, 134}, {103, 253, 74, 3}, {103, 253, 74, 7}}},
|
||||
{Region: "Turkey", IPs: []net.IP{{185, 195, 79, 3}, {185, 195, 79, 5}}},
|
||||
{Region: "UK France", IPs: []net.IP{{188, 166, 168, 247}}},
|
||||
{Region: "UK Germany", IPs: []net.IP{{45, 77, 58, 16}}},
|
||||
{Region: "UK Glasgow", IPs: []net.IP{{185, 108, 105, 3}, {185, 108, 105, 7}, {185, 108, 105, 11}, {185, 108, 105, 13}, {185, 108, 105, 15}, {185, 108, 105, 18}, {185, 108, 105, 20}, {185, 108, 105, 22}, {185, 108, 105, 31}, {185, 108, 105, 33}, {185, 108, 105, 35}, {185, 108, 105, 38}, {185, 108, 105, 40}, {185, 108, 105, 57}, {185, 108, 105, 143}, {185, 108, 105, 145}, {185, 108, 105, 151}, {185, 108, 105, 153}, {185, 108, 105, 155}, {185, 108, 105, 157}, {185, 108, 105, 159}, {185, 108, 105, 161}}},
|
||||
{Region: "UK London st001", IPs: []net.IP{{217, 146, 82, 83}}},
|
||||
{Region: "UK London st002", IPs: []net.IP{{185, 134, 22, 80}}},
|
||||
{Region: "UK London st003", IPs: []net.IP{{185, 134, 22, 92}}},
|
||||
{Region: "UK London st004", IPs: []net.IP{{185, 44, 76, 186}}},
|
||||
{Region: "UK London st005", IPs: []net.IP{{185, 44, 76, 188}}},
|
||||
{Region: "UK London", IPs: []net.IP{{5, 226, 137, 10}, {5, 226, 139, 65}, {5, 226, 139, 149}, {5, 226, 139, 225}, {81, 19, 210, 234}, {81, 19, 223, 189}, {89, 34, 99, 83}, {89, 35, 29, 71}, {178, 239, 166, 218}, {178, 239, 166, 227}, {178, 239, 166, 250}, {178, 239, 172, 111}, {185, 16, 206, 75}, {185, 38, 148, 228}, {185, 38, 150, 41}, {185, 38, 150, 88}, {185, 44, 76, 55}, {185, 44, 76, 167}, {185, 44, 76, 172}, {185, 114, 224, 53}, {185, 114, 224, 115}, {185, 125, 207, 155}, {185, 134, 22, 191}, {185, 193, 36, 212}, {195, 140, 215, 42}}},
|
||||
{Region: "UK Manchester", IPs: []net.IP{{37, 120, 200, 3}, {37, 120, 200, 5}, {37, 120, 200, 7}, {86, 106, 136, 67}, {86, 106, 136, 69}, {86, 106, 136, 75}, {86, 106, 136, 77}, {86, 106, 136, 83}, {86, 106, 136, 85}, {86, 106, 136, 93}, {89, 238, 140, 227}, {89, 238, 140, 229}, {89, 238, 143, 103}, {185, 195, 202, 197}, {193, 148, 17, 83}, {193, 148, 17, 85}, {193, 148, 17, 131}, {193, 148, 17, 133}, {195, 12, 48, 213}, {195, 12, 48, 215}, {195, 12, 48, 217}, {217, 138, 196, 51}, {217, 138, 196, 53}, {217, 138, 196, 91}, {217, 138, 196, 93}}},
|
||||
{Region: "US Atlanta", IPs: []net.IP{{66, 115, 154, 135}, {66, 115, 154, 147}, {66, 115, 154, 149}, {66, 115, 154, 151}, {66, 115, 166, 147}, {66, 115, 166, 149}, {66, 115, 166, 151}, {66, 115, 169, 35}, {66, 115, 175, 35}, {66, 115, 175, 37}, {66, 115, 175, 40}, {66, 115, 175, 42}, {66, 115, 175, 45}, {66, 115, 175, 47}, {66, 115, 175, 50}, {66, 115, 175, 52}, {185, 93, 0, 143}, {185, 93, 0, 146}}},
|
||||
{Region: "US Bend", IPs: []net.IP{{45, 43, 14, 73}, {45, 43, 14, 75}, {45, 43, 14, 83}, {45, 43, 14, 85}, {45, 43, 14, 93}, {45, 43, 14, 103}, {45, 43, 14, 105}, {154, 16, 168, 184}, {154, 16, 168, 188}}},
|
||||
{Region: "US Boston", IPs: []net.IP{{173, 237, 207, 21}, {192, 34, 83, 230}, {199, 217, 107, 22}}},
|
||||
{Region: "US Buffalo", IPs: []net.IP{{107, 174, 20, 130}, {107, 174, 20, 132}, {107, 174, 20, 134}, {107, 175, 104, 82}, {107, 175, 104, 86}, {172, 93, 153, 146}, {172, 93, 153, 148}, {172, 93, 153, 150}}},
|
||||
{Region: "US Charlotte", IPs: []net.IP{{66, 11, 124, 140}, {155, 254, 28, 141}, {155, 254, 29, 163}, {155, 254, 31, 182}, {155, 254, 31, 184}, {192, 154, 253, 67}, {192, 154, 253, 69}, {192, 154, 254, 135}, {192, 154, 254, 137}, {192, 154, 255, 52}, {192, 154, 255, 54}}},
|
||||
{Region: "US Chicago", IPs: []net.IP{{74, 119, 146, 115}, {74, 119, 146, 117}, {74, 119, 146, 119}, {74, 119, 146, 131}, {74, 119, 146, 179}, {74, 119, 146, 181}, {74, 119, 146, 195}, {74, 119, 146, 197}, {74, 119, 146, 199}, {74, 119, 146, 211}, {89, 187, 182, 173}, {89, 187, 182, 175}, {107, 152, 100, 19}, {107, 152, 100, 21}, {107, 152, 100, 26}, {184, 170, 250, 67}, {184, 170, 250, 69}, {184, 170, 250, 72}, {184, 170, 250, 74}, {184, 170, 250, 147}, {184, 170, 250, 149}, {184, 170, 250, 152}, {184, 170, 250, 154}}},
|
||||
{Region: "US Dallas", IPs: []net.IP{{66, 115, 177, 131}, {66, 115, 177, 133}, {66, 115, 177, 136}, {66, 115, 177, 138}, {66, 115, 177, 141}, {66, 115, 177, 143}, {66, 115, 177, 146}, {66, 115, 177, 148}, {66, 115, 177, 151}, {66, 115, 177, 153}, {66, 115, 177, 158}, {89, 187, 175, 165}, {89, 187, 175, 167}, {107, 181, 173, 163}, {172, 241, 114, 87}, {212, 102, 40, 66}, {212, 102, 40, 68}, {212, 102, 40, 71}, {212, 102, 40, 73}, {212, 102, 40, 76}, {212, 102, 40, 78}, {212, 102, 40, 81}}},
|
||||
{Region: "US Denver", IPs: []net.IP{{174, 128, 245, 3}, {174, 128, 245, 5}, {174, 128, 245, 149}, {174, 128, 245, 151}, {212, 102, 44, 66}, {212, 102, 44, 68}, {212, 102, 44, 71}, {212, 102, 44, 73}, {212, 102, 44, 76}, {212, 102, 44, 78}, {212, 102, 44, 81}, {212, 102, 44, 83}, {212, 102, 44, 86}, {212, 102, 44, 88}, {212, 102, 44, 93}, {212, 102, 44, 98}}},
|
||||
{Region: "US Gahanna", IPs: []net.IP{{104, 244, 208, 35}, {104, 244, 208, 37}, {104, 244, 208, 99}, {104, 244, 208, 101}, {104, 244, 208, 107}, {104, 244, 208, 109}, {104, 244, 208, 213}, {104, 244, 208, 215}, {104, 244, 208, 227}, {104, 244, 208, 229}, {104, 244, 208, 231}, {104, 244, 209, 51}, {104, 244, 209, 53}, {104, 244, 209, 99}, {104, 244, 209, 101}, {104, 244, 211, 139}, {104, 244, 211, 141}, {104, 244, 211, 171}, {104, 244, 211, 173}, {104, 244, 211, 179}}},
|
||||
{Region: "US Houston", IPs: []net.IP{{104, 148, 30, 35}, {104, 148, 30, 37}, {104, 148, 30, 39}, {104, 148, 30, 51}, {104, 148, 30, 85}, {104, 148, 30, 87}, {199, 10, 64, 69}, {199, 10, 64, 83}, {199, 10, 64, 85}, {199, 10, 64, 99}, {199, 10, 64, 101}, {199, 10, 64, 115}, {199, 10, 64, 117}}},
|
||||
{Region: "US Kansas City", IPs: []net.IP{{63, 141, 236, 243}, {63, 141, 236, 245}, {63, 141, 248, 179}, {63, 141, 248, 181}, {107, 150, 39, 43}, {107, 150, 39, 45}, {173, 208, 202, 59}, {173, 208, 202, 61}, {198, 204, 231, 147}, {198, 204, 231, 149}, {204, 12, 208, 115}, {204, 12, 208, 117}}},
|
||||
{Region: "US Las Vegas", IPs: []net.IP{{89, 187, 187, 149}, {185, 242, 5, 213}}},
|
||||
{Region: "US Latham", IPs: []net.IP{{45, 43, 19, 66}, {45, 43, 19, 68}, {45, 43, 19, 74}, {45, 43, 19, 76}, {45, 43, 19, 82}, {45, 43, 19, 84}, {45, 43, 19, 90}, {45, 43, 19, 92}, {154, 16, 169, 3}, {154, 16, 169, 5}, {154, 16, 169, 7}}},
|
||||
{Region: "US Los Angeles", IPs: []net.IP{{38, 95, 110, 73}, {89, 187, 187, 66}, {89, 187, 187, 68}, {89, 187, 187, 73}, {89, 187, 187, 78}, {89, 187, 187, 81}, {89, 187, 187, 83}, {89, 187, 187, 86}, {89, 187, 187, 88}, {172, 83, 44, 83}, {184, 170, 243, 199}, {184, 170, 243, 211}, {192, 111, 134, 67}, {192, 111, 134, 78}, {192, 111, 134, 80}, {192, 111, 134, 195}, {192, 111, 134, 200}, {192, 111, 134, 202}, {192, 111, 134, 207}, {192, 111, 134, 210}, {192, 111, 134, 212}, {192, 111, 134, 215}, {192, 111, 134, 217}, {192, 111, 134, 220}, {192, 111, 134, 222}}},
|
||||
{Region: "US Maryland", IPs: []net.IP{{23, 82, 8, 173}, {23, 105, 160, 134}, {23, 105, 163, 94}, {207, 244, 67, 147}, {207, 244, 67, 149}, {207, 244, 84, 40}, {207, 244, 84, 58}, {207, 244, 127, 116}, {207, 244, 127, 118}}},
|
||||
{Region: "US Miami", IPs: []net.IP{{89, 187, 173, 201}, {107, 181, 164, 35}, {107, 181, 164, 39}, {107, 181, 164, 211}, {172, 83, 42, 3}, {172, 83, 42, 19}, {172, 83, 42, 23}, {172, 83, 42, 35}, {172, 83, 42, 37}, {172, 83, 42, 39}, {172, 83, 42, 51}, {172, 83, 42, 53}, {172, 83, 42, 55}, {172, 83, 42, 83}, {172, 83, 42, 85}, {172, 83, 42, 133}, {172, 83, 42, 136}, {172, 83, 42, 141}, {172, 83, 42, 146}, {172, 83, 42, 148}, {172, 83, 42, 151}, {172, 83, 42, 156}, {172, 83, 42, 158}, {193, 37, 252, 197}, {212, 102, 61, 130}}},
|
||||
{Region: "US Netherlands", IPs: []net.IP{{142, 93, 58, 71}}},
|
||||
{Region: "US New York City mp001", IPs: []net.IP{{45, 55, 60, 159}}},
|
||||
{Region: "US New York City st001", IPs: []net.IP{{92, 119, 177, 19}}},
|
||||
{Region: "US New York City st002", IPs: []net.IP{{92, 119, 177, 21}}},
|
||||
{Region: "US New York City st003", IPs: []net.IP{{92, 119, 177, 23}}},
|
||||
{Region: "US New York City st004", IPs: []net.IP{{193, 148, 18, 51}}},
|
||||
{Region: "US New York City st005", IPs: []net.IP{{193, 148, 18, 53}}},
|
||||
{Region: "US New York City", IPs: []net.IP{{37, 120, 202, 3}, {84, 17, 35, 66}, {84, 17, 35, 73}, {84, 17, 35, 76}, {84, 17, 35, 78}, {84, 17, 35, 83}, {84, 17, 35, 88}, {84, 17, 35, 91}, {89, 187, 177, 120}, {89, 187, 177, 122}, {89, 187, 178, 92}, {98, 142, 220, 35}, {98, 142, 220, 37}, {107, 152, 101, 163}, {172, 98, 75, 35}, {172, 98, 78, 227}, {172, 98, 78, 229}, {192, 40, 59, 227}, {192, 40, 59, 238}, {192, 40, 59, 240}, {199, 36, 221, 83}, {199, 36, 221, 101}, {199, 36, 221, 104}}},
|
||||
{Region: "US Orlando", IPs: []net.IP{{198, 147, 22, 83}, {198, 147, 22, 85}, {198, 147, 22, 87}, {198, 147, 22, 131}, {198, 147, 22, 133}, {198, 147, 22, 135}, {198, 147, 22, 147}, {198, 147, 22, 149}, {198, 147, 22, 151}, {198, 147, 22, 163}, {198, 147, 22, 165}, {198, 147, 22, 167}, {198, 147, 22, 195}, {198, 147, 22, 197}, {198, 147, 22, 211}, {198, 147, 22, 213}}},
|
||||
{Region: "US Phoenix", IPs: []net.IP{{23, 83, 128, 235}, {23, 83, 128, 243}, {107, 181, 184, 115}, {107, 181, 184, 117}, {172, 98, 87, 35}, {172, 98, 87, 37}, {184, 170, 240, 147}, {184, 170, 240, 149}, {184, 170, 240, 151}, {184, 170, 240, 179}, {184, 170, 240, 181}, {199, 58, 187, 3}, {199, 58, 187, 5}, {199, 58, 187, 8}, {199, 58, 187, 10}, {199, 58, 187, 13}, {199, 58, 187, 15}, {199, 58, 187, 18}, {199, 58, 187, 20}, {199, 58, 187, 23}, {199, 58, 187, 25}, {199, 58, 187, 67}, {199, 58, 187, 69}}},
|
||||
{Region: "US Portugal", IPs: []net.IP{{142, 93, 81, 242}}},
|
||||
{Region: "US Saint Louis", IPs: []net.IP{{148, 72, 169, 209}, {148, 72, 169, 211}, {148, 72, 169, 213}, {148, 72, 170, 108}, {148, 72, 174, 36}, {148, 72, 174, 38}, {148, 72, 174, 41}, {148, 72, 174, 43}, {148, 72, 174, 51}, {148, 72, 174, 53}}},
|
||||
{Region: "US Salt Lake City", IPs: []net.IP{{104, 200, 131, 5}, {104, 200, 131, 9}, {104, 200, 131, 167}, {104, 200, 131, 170}, {104, 200, 131, 172}, {104, 200, 131, 229}, {104, 200, 131, 249}}},
|
||||
{Region: "US San Francisco", IPs: []net.IP{{107, 181, 166, 55}, {107, 181, 166, 83}, {107, 181, 166, 85}, {107, 181, 166, 227}, {185, 174, 157, 83}, {185, 174, 157, 85}, {198, 8, 81, 37}, {209, 58, 128, 48}, {209, 58, 128, 50}}},
|
||||
{Region: "US Seatle", IPs: []net.IP{{84, 17, 41, 71}, {84, 17, 41, 75}, {84, 17, 41, 77}, {84, 17, 41, 79}, {84, 17, 41, 81}, {84, 17, 41, 85}, {104, 200, 129, 243}, {104, 200, 129, 245}, {198, 8, 80, 87}, {198, 8, 80, 227}, {198, 8, 80, 229}, {199, 229, 250, 165}}},
|
||||
{Region: "US Tampa", IPs: []net.IP{{66, 206, 23, 3}, {74, 50, 117, 106}, {74, 50, 117, 119}, {74, 50, 117, 121}, {162, 220, 56, 98}, {162, 220, 56, 100}, {162, 220, 63, 226}, {162, 220, 63, 232}, {162, 220, 63, 246}, {162, 220, 63, 248}, {209, 216, 92, 195}, {209, 216, 92, 202}, {209, 216, 92, 205}, {209, 216, 92, 207}, {209, 216, 92, 210}, {209, 216, 92, 212}, {209, 216, 92, 215}, {209, 216, 92, 217}, {209, 216, 92, 220}, {209, 216, 92, 222}, {209, 216, 92, 225}, {209, 216, 92, 227}}},
|
||||
{Region: "Ukraine", IPs: []net.IP{{45, 9, 238, 23}, {45, 9, 238, 30}, {45, 9, 238, 38}}},
|
||||
{Region: "United Arab Emirates", IPs: []net.IP{{45, 9, 249, 243}, {45, 9, 249, 245}, {45, 9, 249, 247}, {45, 9, 250, 99}, {45, 9, 250, 101}, {45, 9, 250, 103}}},
|
||||
{Region: "Vietnam", IPs: []net.IP{{202, 143, 110, 29}, {202, 143, 110, 32}, {202, 143, 110, 34}, {202, 143, 110, 37}, {202, 143, 111, 142}, {202, 143, 111, 211}, {202, 143, 111, 213}}},
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,14 @@ const (
|
||||
Mullvad models.VPNProvider = "mullvad"
|
||||
// Windscribe is a VPN provider
|
||||
Windscribe models.VPNProvider = "windscribe"
|
||||
// Surfshark is a VPN provider
|
||||
Surfshark models.VPNProvider = "surfshark"
|
||||
// Cyberghost is a VPN provider
|
||||
Cyberghost models.VPNProvider = "cyberghost"
|
||||
// Vyprvpn is a VPN provider
|
||||
Vyprvpn models.VPNProvider = "vyprvpn"
|
||||
// NordVPN is a VPN provider
|
||||
Nordvpn models.VPNProvider = "nordvpn"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
98
internal/constants/vyprvpn.go
Normal file
98
internal/constants/vyprvpn.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
const (
|
||||
VyprvpnCertificate = "MIIGDjCCA/agAwIBAgIJAL2ON5xbane/MA0GCSqGSIb3DQEBDQUAMIGTMQswCQYDVQQGEwJDSDEQMA4GA1UECAwHTHVjZXJuZTEPMA0GA1UEBwwGTWVnZ2VuMRkwFwYDVQQKDBBHb2xkZW4gRnJvZyBHbWJIMSEwHwYDVQQDDBhHb2xkZW4gRnJvZyBHbWJIIFJvb3QgQ0ExIzAhBgkqhkiG9w0BCQEWFGFkbWluQGdvbGRlbmZyb2cuY29tMB4XDTE5MTAxNzIwMTQxMFoXDTM5MTAxMjIwMTQxMFowgZMxCzAJBgNVBAYTAkNIMRAwDgYDVQQIDAdMdWNlcm5lMQ8wDQYDVQQHDAZNZWdnZW4xGTAXBgNVBAoMEEdvbGRlbiBGcm9nIEdtYkgxITAfBgNVBAMMGEdvbGRlbiBGcm9nIEdtYkggUm9vdCBDQTEjMCEGCSqGSIb3DQEJARYUYWRtaW5AZ29sZGVuZnJvZy5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCtuddaZrpWZ+nUuJpG+ohTquO3XZtq6d4U0E2oiPeIiwm+WWLY49G+GNJb5aVrlrBojaykCAc2sU6NeUlpg3zuqrDqLcz7PAE4OdNiOdrLBF1o9ZHrcITDZN304eAY5nbyHx5V6x/QoDVCi4g+5OVTA+tZjpcl4wRIpgknWznO73IKCJ6YckpLn1BsFrVCb2ehHYZLg7Js58FzMySIxBmtkuPeHQXL61DFHh3cTFcMxqJjzh7EGsWRyXfbAaBGYnT+TZwzpLXXt8oBGpNXG8YBDrPdK0A+lzMnJ4nS0rgHDSRF0brx+QYk/6CgM510uFzB7zytw9UTD3/5TvKlCUmTGGgI84DbJ3DEvjxbgiQnJXCUZKKYSHwrK79Y4Qn+lXu4Bu0ZTCJBje0GUVMTPAvBCeDvzSe0iRcVSNMJVM68d4kD1PpSY/zWfCz5hiOjHWuXinaoZ0JJqRF8kGbJsbDlDYDtVvh/Cd4aWN6Q/2XLpszBsG5i8sdkS37nzkdlRwNEIZwsKfcXwdTOlDinR1LUG68LmzJAwfNE47xbrZUsdGGfG+HSPsrqFFiLGe7Y4e2+a7vGdSY9qR9PAzyx0ijCCrYzZDIsb2dwjLctUx6a3LNV8cpfhKX+s6tfMldGufPI7byHT1Ybf0NtMS1d1RjD6IbqedXQdCKtaw68kTX//wIDAQABo2MwYTAdBgNVHQ4EFgQU2EbQvBd1r/EADr2jCPMXsH7zEXEwHwYDVR0jBBgwFoAU2EbQvBd1r/EADr2jCPMXsH7zEXEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQENBQADggIBAAViCPieIronV+9asjZyo5oSZSNWUkWRYdezjezsf49+fwT12iRgnkSEQeoj5caqcOfNm/eRpN4G7jhhCcxy9RGF+GurIlZ4v0mChZbx1jcxqr9/3/Z2TqvHALyWngBYDv6pv1iWcd9a4+QL9kj1Tlp8vUDIcHMtDQkEHnkhC+MnjyrdsdNE5wjlLljjFR2Qy5a6/kWwZ1JQVYof1J1EzY6mU7YLMHOdjfmeci5i0vg8+9kGMsc/7Wm69L1BeqpDB3ZEAgmOtda2jwOevJ4sABmRoSThFp4DeMcxb62HW1zZCCpgzWv/33+pZdPvnZHSz7RGoxH4Ln7eBf3oo2PMlu7wCsid3HUdgkRf2Og1RJIrFfEjb7jga1JbKX2Qo/FH3txzdUimKiDRv3ccFmEOqjndUG6hP+7/EsI43oCPYOvZR+u5GdOkhYrDGZlvjXeJ1CpQxTR/EX+Vt7F8YG+i2LkO7lhPLb+LzgPAxVPCcEMHruuUlE1BYxxzRMOW4X4kjHvJjZGISxa9lgTY3e0mnoQNQVBHKfzI2vGLwvcrFcCIrVxeEbj2dryfByyhZlrNPFbXyf7P4OSfk+fVh6Is1IF1wksfLY/6gWvcmXB8JwmKFDa9s5NfzXnzP3VMrNUWXN3G8Eee6qzKKTDsJ70OrgAx9j9a+dMLfe1vP5t6GQj5"
|
||||
)
|
||||
|
||||
func VyprvpnRegionChoices() (choices []string) {
|
||||
servers := VyprvpnServers()
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
}
|
||||
return choices
|
||||
}
|
||||
|
||||
func VyprvpnServers() []models.VyprvpnServer {
|
||||
return []models.VyprvpnServer{
|
||||
{Region: "Algeria", IPs: []net.IP{{209, 99, 75, 20}}},
|
||||
{Region: "Argentina", IPs: []net.IP{{209, 99, 109, 19}}},
|
||||
{Region: "Australia Melbourne", IPs: []net.IP{{209, 99, 117, 19}}},
|
||||
{Region: "Australia Perth", IPs: []net.IP{{209, 99, 1, 19}}},
|
||||
{Region: "Australia Sydney", IPs: []net.IP{{209, 99, 117, 18}}},
|
||||
{Region: "Austria", IPs: []net.IP{{128, 90, 96, 18}}},
|
||||
{Region: "Bahrain", IPs: []net.IP{{209, 99, 115, 19}}},
|
||||
{Region: "Belgium", IPs: []net.IP{{128, 90, 96, 20}}},
|
||||
{Region: "Brazil", IPs: []net.IP{{209, 99, 109, 20}}},
|
||||
{Region: "Bulgaria", IPs: []net.IP{{128, 90, 96, 22}}},
|
||||
{Region: "Canada", IPs: []net.IP{{209, 99, 21, 18}}},
|
||||
{Region: "Columbia", IPs: []net.IP{{209, 99, 109, 21}}},
|
||||
{Region: "Costa Rica", IPs: []net.IP{{209, 99, 109, 22}}},
|
||||
{Region: "Czech Republic", IPs: []net.IP{{128, 90, 96, 24}}},
|
||||
{Region: "Denmark", IPs: []net.IP{{128, 90, 96, 28}}},
|
||||
{Region: "Dubai", IPs: []net.IP{{128, 90, 45, 104}}},
|
||||
{Region: "Egypt", IPs: []net.IP{{128, 90, 228, 43}}},
|
||||
{Region: "El Salvador", IPs: []net.IP{{209, 99, 61, 20}}},
|
||||
{Region: "Finland", IPs: []net.IP{{128, 90, 96, 32}}},
|
||||
{Region: "France", IPs: []net.IP{{128, 90, 96, 34}}},
|
||||
{Region: "Germany", IPs: []net.IP{{128, 90, 96, 26}}},
|
||||
{Region: "Greece", IPs: []net.IP{{128, 90, 228, 59}}},
|
||||
{Region: "Hong Kong", IPs: []net.IP{{128, 90, 227, 18}}},
|
||||
{Region: "Iceland", IPs: []net.IP{{209, 99, 22, 20}}},
|
||||
{Region: "India", IPs: []net.IP{{209, 99, 115, 20}}},
|
||||
{Region: "Indonesia", IPs: []net.IP{{209, 99, 1, 20}}},
|
||||
{Region: "Ireland", IPs: []net.IP{{209, 99, 22, 19}}},
|
||||
{Region: "Israel", IPs: []net.IP{{128, 90, 228, 20}}},
|
||||
{Region: "Italy", IPs: []net.IP{{128, 90, 96, 36}}},
|
||||
{Region: "Japan", IPs: []net.IP{{209, 99, 113, 18}}},
|
||||
{Region: "Latvia", IPs: []net.IP{{128, 90, 96, 44}}},
|
||||
{Region: "Liechtenstein", IPs: []net.IP{{128, 90, 96, 38}}},
|
||||
{Region: "Lithuania", IPs: []net.IP{{128, 90, 96, 40}}},
|
||||
{Region: "Luxembourg", IPs: []net.IP{{128, 90, 96, 42}}},
|
||||
{Region: "Macao", IPs: []net.IP{{128, 90, 227, 36}}},
|
||||
{Region: "Malaysia", IPs: []net.IP{{209, 99, 1, 21}}},
|
||||
{Region: "Maldives", IPs: []net.IP{{209, 99, 1, 26}}},
|
||||
{Region: "Marshall Islands", IPs: []net.IP{{209, 99, 1, 25}}},
|
||||
{Region: "Mexico", IPs: []net.IP{{209, 99, 61, 19}}},
|
||||
{Region: "Netherlands", IPs: []net.IP{{128, 90, 96, 16}}},
|
||||
{Region: "New Zealand", IPs: []net.IP{{209, 99, 117, 20}}},
|
||||
{Region: "Norway", IPs: []net.IP{{128, 90, 96, 46}}},
|
||||
{Region: "Pakistan", IPs: []net.IP{{128, 90, 228, 67}}},
|
||||
{Region: "Panama", IPs: []net.IP{{209, 99, 109, 23}}},
|
||||
{Region: "Philippines", IPs: []net.IP{{209, 99, 1, 22}}},
|
||||
{Region: "Poland", IPs: []net.IP{{128, 90, 96, 48}}},
|
||||
{Region: "Portugal", IPs: []net.IP{{128, 90, 96, 50}}},
|
||||
{Region: "Qatar", IPs: []net.IP{{209, 99, 115, 21}}},
|
||||
{Region: "Romania", IPs: []net.IP{{128, 90, 96, 52}}},
|
||||
{Region: "Russia", IPs: []net.IP{{128, 90, 96, 54}}},
|
||||
{Region: "Saudi Arabia", IPs: []net.IP{{209, 99, 115, 22}}},
|
||||
{Region: "Singapore", IPs: []net.IP{{209, 99, 1, 18}}},
|
||||
{Region: "Slovakia", IPs: []net.IP{{128, 90, 96, 60}}},
|
||||
{Region: "Slovenia", IPs: []net.IP{{128, 90, 96, 58}}},
|
||||
{Region: "South Korea", IPs: []net.IP{{209, 99, 113, 19}}},
|
||||
{Region: "Spain", IPs: []net.IP{{128, 90, 96, 30}}},
|
||||
{Region: "Sweden", IPs: []net.IP{{128, 90, 96, 56}}},
|
||||
{Region: "Switzerland", IPs: []net.IP{{209, 99, 60, 18}}},
|
||||
{Region: "Taiwan", IPs: []net.IP{{128, 90, 227, 27}}},
|
||||
{Region: "Thailand", IPs: []net.IP{{209, 99, 1, 23}}},
|
||||
{Region: "Turkey", IPs: []net.IP{{128, 90, 96, 62}}},
|
||||
{Region: "USA Austin", IPs: []net.IP{{209, 99, 61, 18}}},
|
||||
{Region: "USA Chicago", IPs: []net.IP{{209, 99, 93, 18}}},
|
||||
{Region: "USA Los Angeles", IPs: []net.IP{{209, 99, 67, 18}}},
|
||||
{Region: "USA Miami", IPs: []net.IP{{209, 99, 109, 18}}},
|
||||
{Region: "USA New York", IPs: []net.IP{{209, 99, 63, 18}}},
|
||||
{Region: "USA San Francisco", IPs: []net.IP{{209, 99, 95, 18}}},
|
||||
{Region: "USA Seattle", IPs: []net.IP{{209, 99, 94, 18}}},
|
||||
{Region: "USA Washington DC", IPs: []net.IP{{209, 99, 62, 18}}},
|
||||
{Region: "Ukraine", IPs: []net.IP{{128, 90, 96, 64}}},
|
||||
{Region: "United Kingdom", IPs: []net.IP{{209, 99, 22, 18}}},
|
||||
{Region: "Uruguay", IPs: []net.IP{{209, 99, 61, 21}}},
|
||||
{Region: "Vietnam", IPs: []net.IP{{209, 99, 1, 24}}},
|
||||
}
|
||||
}
|
||||
94
internal/constants/windscribe.go
Normal file
94
internal/constants/windscribe.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
const (
|
||||
WindscribeCertificate = "MIIF3DCCA8SgAwIBAgIJAMsOivWTmu9fMA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkNBMQswCQYDVQQIDAJPTjEQMA4GA1UEBwwHVG9yb250bzEbMBkGA1UECgwSV2luZHNjcmliZSBMaW1pdGVkMRMwEQYDVQQLDApPcGVyYXRpb25zMRswGQYDVQQDDBJXaW5kc2NyaWJlIE5vZGUgQ0EwHhcNMTYwMzA5MDMyNjIwWhcNNDAxMDI5MDMyNjIwWjB7MQswCQYDVQQGEwJDQTELMAkGA1UECAwCT04xEDAOBgNVBAcMB1Rvcm9udG8xGzAZBgNVBAoMEldpbmRzY3JpYmUgTGltaXRlZDETMBEGA1UECwwKT3BlcmF0aW9uczEbMBkGA1UEAwwSV2luZHNjcmliZSBOb2RlIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAruBtLR1Vufd71LeQEqChgHS4AQJ0fSRner0gmZPEr2TL5uWboOEWXFFoEUTthF+P/N8yy3xRZ8HhG/zKlmJ1xw+7KZRbTADD6shJPj3/uvTIO80sU+9LmsyKSWuPhQ1NkgNA7rrMTfz9eHJ2MVDs4XCpYWyX9iuAQrHSY6aPq+4TpCbUgprkM3Gwjh9RSt9IoDoc4CF2bWSaVepUcL9yz/SXLPzFx2OT9rFrDhL3ryHRzJQ/tA+VD8A7lo8bhOcDqiXgEFmVOZNMLw+r167Qq1Ck7X86yr2mnW/6HK2gJOvY0/SPKukfGJAiYZKdG+fe4ekyYcAVhDfPJg7rF9wUqPwUzejJyAs1K18JwX94Y8fnD6vQobjpC3qfHtwQP7Uj2AcI6QC8ytWDegV6UIkHXAMXBQSX5suSQoE11deG32cy7nyp5vhgy31rTyNoopqlcCAhPm6k0jVVQbvXhLcpTSL8iCCoMdrP28i/xsfvktBAkl5giHMdK6hxqWgPI+Bx9uPIhRp3fJ2z8AgFm8g1ARB2ZzQ+OZZ2RUIkJuUKhi2kUhgKSAQ+eF89aoqDjp/J1miZqGRzt4DovSZfQOeL01RkKHEibAPYCfgHG2ZSwoLoeaxE2vNZiX4dpXiOQYTOIXOwEPZzPvfTQf9T4Kxvx3jzQnt3PzjlMCqKk3Aipm8CAwEAAaNjMGEwHQYDVR0OBBYEFEH2v9F2z938Ebngsj9RkVSSgs45MB8GA1UdIwQYMBaAFEH2v9F2z938Ebngsj9RkVSSgs45MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQAgI6NgYkVo5rB6yKStgHjjZsINsgEvoMuHwkM0YaV22XtKNiHdsiOmY/PGCRemFobTEHk5XHcvcOTWv/D1qVf8fI21WAoNQVH7h8KEsr4uMGKCB6Lu8l6xALXRMjo1xb6JKBWXwIAzUu691rUD2exT1E+A5t+xw+gzqV8rWTMIoUaH7O1EKjN6ryGW71Khiik8/ETrP3YT32ZbS2P902iMKw9rpmuS0wWhnO5k/iO/6YNA1ZMV5JG5oZvZQYEDk7enLD9HvqazofMuy/Sz/n62ZCDdQsnabzxl04wwv5Y3JZbV/6bOM520GgdJEoDxviY05ax2Mz05otyBzrAVjFw9RZt/Ls8ATifu9BusZ2ootvscdIuE3x+ZCl5lvANcFEnvgGw0qpCeASLpsfxwq1dRgIn7BOiTauFv4eoeFAQvCD+l+EKGWKu3M2y19DgYX94N2+Xs2bwChroaO5e4iFemMLMuWKZvYgnqS9OAtRSYWbNX/wliiPz7u13yj+qSWgMfu8WPYNQlMZJXuGWUvKLEXCUExlu7/o8D4HpsVs30E0pUdaqN0vExB1KegxPWWrmLcYnPG3knXpkC3ZBZ5P/el/2eyhZRy9ydiITF8gM3L08E8aeqvzZMw2FDSmousydIzlXgeS5VuEf+lUFA2h8oZYGQgrLt+ot8MbLhJlkp4Q=="
|
||||
WindscribeOpenvpnStaticKeyV1 = "5801926a57ac2ce27e3dfd1dd6ef82042d82bd4f3f0021296f57734f6f1ea714a6623845541c4b0c3dea0a050fe6746cb66dfab14cda27e5ae09d7c155aa554f399fa4a863f0e8c1af787e5c602a801d3a2ec41e395a978d56729457fe6102d7d9e9119aa83643210b33c678f9d4109e3154ac9c759e490cb309b319cf708cae83ddadc3060a7a26564d1a24411cd552fe6620ea16b755697a4fc5e6e9d0cfc0c5c4a1874685429046a424c026db672e4c2c492898052ba59128d46200b40f880027a8b6610a4d559bdc9346d33a0a6b08e75c7fd43192b162bfd0aef0c716b31584827693f676f9a5047123466f0654eade34972586b31c6ce7e395f4b478cb"
|
||||
)
|
||||
|
||||
func WindscribeRegionChoices() (choices []string) {
|
||||
servers := WindscribeServers()
|
||||
choices = make([]string, len(servers))
|
||||
for i := range servers {
|
||||
choices[i] = servers[i].Region
|
||||
}
|
||||
return choices
|
||||
}
|
||||
|
||||
func WindscribeServers() []models.WindscribeServer {
|
||||
return []models.WindscribeServer{
|
||||
{Region: "Albania", IPs: []net.IP{{31, 171, 152, 179}}},
|
||||
{Region: "Argentina", IPs: []net.IP{{167, 250, 6, 121}, {190, 105, 236, 19}, {190, 105, 236, 32}, {190, 105, 236, 50}, {200, 85, 152, 110}}},
|
||||
{Region: "Australia", IPs: []net.IP{{43, 245, 160, 35}, {45, 121, 208, 160}, {45, 121, 209, 160}, {45, 121, 210, 208}, {103, 62, 50, 208}, {103, 77, 233, 67}, {103, 77, 234, 211}, {103, 108, 92, 83}, {116, 90, 72, 243}, {116, 206, 228, 67}, {116, 206, 229, 131}}},
|
||||
{Region: "Austria", IPs: []net.IP{{89, 187, 168, 66}, {217, 64, 127, 11}}},
|
||||
{Region: "Azerbaijan", IPs: []net.IP{{85, 132, 61, 123}}},
|
||||
{Region: "Belgium", IPs: []net.IP{{185, 232, 21, 131}, {194, 187, 251, 147}}},
|
||||
{Region: "Bosnia", IPs: []net.IP{{185, 99, 3, 24}}},
|
||||
{Region: "Brazil", IPs: []net.IP{{177, 54, 144, 68}, {177, 67, 80, 59}, {189, 1, 172, 12}}},
|
||||
{Region: "Bulgaria", IPs: []net.IP{{185, 94, 192, 35}}},
|
||||
{Region: "Canada East", IPs: []net.IP{{23, 154, 160, 177}, {66, 70, 148, 80}, {104, 227, 235, 129}, {104, 254, 92, 11}, {104, 254, 92, 91}, {144, 168, 163, 160}, {144, 168, 163, 193}, {184, 75, 212, 91}, {192, 190, 19, 65}, {192, 190, 19, 97}, {198, 8, 85, 195}, {198, 8, 85, 210}, {199, 204, 208, 158}}},
|
||||
{Region: "Canada West", IPs: []net.IP{{104, 218, 61, 1}, {104, 218, 61, 33}, {162, 221, 207, 95}, {208, 78, 41, 1}, {208, 78, 41, 131}, {208, 78, 41, 163}}},
|
||||
{Region: "Colombia", IPs: []net.IP{{138, 121, 203, 203}, {138, 186, 141, 155}}},
|
||||
{Region: "Croatia", IPs: []net.IP{{85, 10, 56, 252}}},
|
||||
{Region: "Cyprus", IPs: []net.IP{{157, 97, 132, 43}}},
|
||||
{Region: "Czech republic", IPs: []net.IP{{185, 156, 174, 11}, {185, 246, 210, 2}}},
|
||||
{Region: "Denmark", IPs: []net.IP{{134, 90, 149, 147}, {185, 206, 224, 195}}},
|
||||
{Region: "Estonia", IPs: []net.IP{{46, 22, 211, 251}, {196, 196, 216, 131}}},
|
||||
{Region: "Fake antarctica", IPs: []net.IP{{23, 154, 160, 212}, {23, 154, 160, 222}}},
|
||||
{Region: "Finland", IPs: []net.IP{{185, 112, 82, 227}, {194, 34, 133, 82}}},
|
||||
{Region: "France", IPs: []net.IP{{45, 89, 174, 35}, {82, 102, 18, 35}, {84, 17, 42, 2}, {84, 17, 42, 34}, {185, 156, 173, 187}}},
|
||||
{Region: "Georgia", IPs: []net.IP{{188, 93, 90, 83}}},
|
||||
{Region: "Germany", IPs: []net.IP{{45, 87, 212, 51}, {89, 249, 65, 19}, {185, 130, 184, 195}, {195, 181, 170, 66}, {195, 181, 175, 98}, {217, 138, 194, 115}}},
|
||||
{Region: "Greece", IPs: []net.IP{{78, 108, 38, 155}, {185, 226, 64, 111}, {188, 123, 126, 146}}},
|
||||
{Region: "Hong kong", IPs: []net.IP{{84, 17, 57, 114}, {103, 10, 197, 99}}},
|
||||
{Region: "Hungary", IPs: []net.IP{{185, 104, 187, 43}}},
|
||||
{Region: "Iceland", IPs: []net.IP{{82, 221, 139, 38}, {185, 165, 170, 2}}},
|
||||
{Region: "India", IPs: []net.IP{{103, 205, 140, 227}, {169, 38, 68, 188}, {169, 38, 72, 12}, {169, 38, 72, 14}}},
|
||||
{Region: "Indonesia", IPs: []net.IP{{45, 127, 134, 91}}},
|
||||
{Region: "Ireland", IPs: []net.IP{{185, 24, 232, 146}, {185, 104, 219, 2}}},
|
||||
{Region: "Israel", IPs: []net.IP{{160, 116, 0, 27}, {185, 191, 205, 139}}},
|
||||
{Region: "Italy", IPs: []net.IP{{37, 120, 135, 83}, {37, 120, 207, 19}, {84, 17, 59, 66}, {87, 101, 94, 195}, {89, 40, 182, 3}}},
|
||||
{Region: "Japan", IPs: []net.IP{{89, 187, 161, 114}, {193, 148, 16, 243}}},
|
||||
{Region: "Latvia", IPs: []net.IP{{85, 254, 72, 23}, {89, 111, 33, 220}}},
|
||||
{Region: "Lithuania", IPs: []net.IP{{85, 206, 163, 225}}},
|
||||
{Region: "Macedonia", IPs: []net.IP{{185, 225, 28, 51}}},
|
||||
{Region: "Malaysia", IPs: []net.IP{{103, 106, 250, 31}, {103, 212, 69, 232}}},
|
||||
{Region: "Mexico", IPs: []net.IP{{143, 255, 57, 67}, {190, 103, 179, 211}, {190, 103, 179, 217}, {201, 131, 125, 107}}},
|
||||
{Region: "Moldova", IPs: []net.IP{{178, 175, 144, 123}}},
|
||||
{Region: "Netherlands", IPs: []net.IP{{37, 120, 192, 19}, {46, 166, 143, 98}, {72, 11, 157, 35}, {72, 11, 157, 67}, {84, 17, 46, 2}, {185, 212, 171, 131}, {185, 253, 96, 3}}},
|
||||
{Region: "New zealand", IPs: []net.IP{{103, 62, 49, 113}, {103, 108, 94, 163}}},
|
||||
{Region: "Norway", IPs: []net.IP{{37, 120, 203, 67}, {185, 206, 225, 131}}},
|
||||
{Region: "Philippines", IPs: []net.IP{{103, 103, 0, 118}, {141, 98, 215, 211}}},
|
||||
{Region: "Poland", IPs: []net.IP{{5, 133, 11, 116}, {84, 17, 55, 98}, {185, 244, 214, 35}}},
|
||||
{Region: "Portugal", IPs: []net.IP{{94, 46, 13, 215}, {185, 15, 21, 66}}},
|
||||
{Region: "Romania", IPs: []net.IP{{89, 46, 103, 147}, {91, 207, 102, 147}}},
|
||||
{Region: "Russia", IPs: []net.IP{{94, 242, 62, 19}, {94, 242, 62, 67}, {95, 213, 193, 195}, {95, 213, 193, 227}, {185, 22, 175, 132}, {188, 124, 42, 99}, {188, 124, 42, 115}}},
|
||||
{Region: "Serbia", IPs: []net.IP{{141, 98, 103, 19}}},
|
||||
{Region: "Singapore", IPs: []net.IP{{82, 102, 25, 131}, {89, 187, 162, 130}, {103, 62, 48, 224}, {185, 200, 117, 163}}},
|
||||
{Region: "Slovakia", IPs: []net.IP{{185, 245, 85, 3}}},
|
||||
{Region: "South Africa", IPs: []net.IP{{129, 232, 167, 211}, {165, 73, 248, 91}, {197, 242, 156, 53}, {197, 242, 157, 235}}},
|
||||
{Region: "South Korea", IPs: []net.IP{{27, 255, 92, 52}, {61, 97, 244, 39}, {103, 212, 223, 3}, {218, 232, 76, 179}}},
|
||||
{Region: "Spain", IPs: []net.IP{{37, 120, 142, 227}, {89, 238, 178, 43}, {185, 253, 99, 131}, {217, 138, 218, 99}}},
|
||||
{Region: "Sweden", IPs: []net.IP{{31, 13, 191, 67}, {79, 142, 76, 198}, {195, 181, 166, 129}}},
|
||||
{Region: "Switzerland", IPs: []net.IP{{31, 7, 57, 242}, {37, 120, 213, 163}, {84, 17, 53, 2}, {89, 187, 165, 98}, {185, 156, 175, 179}}},
|
||||
{Region: "Thailand", IPs: []net.IP{{27, 254, 130, 221}, {202, 129, 16, 147}, {202, 129, 16, 155}}},
|
||||
{Region: "Tunisia", IPs: []net.IP{{41, 231, 5, 23}}},
|
||||
{Region: "Turkey", IPs: []net.IP{{45, 123, 118, 156}, {45, 123, 119, 11}, {79, 98, 131, 43}, {176, 53, 113, 163}, {185, 125, 33, 227}}},
|
||||
{Region: "US Central", IPs: []net.IP{{67, 212, 238, 196}, {69, 12, 94, 67}, {104, 129, 18, 3}, {104, 129, 18, 131}, {104, 223, 92, 163}, {107, 150, 31, 3}, {107, 150, 31, 67}, {107, 150, 31, 131}, {107, 161, 86, 131}, {107, 182, 234, 240}, {161, 129, 70, 195}, {162, 222, 198, 67}, {172, 241, 26, 78}, {172, 241, 131, 129}, {198, 12, 76, 211}, {198, 54, 128, 116}, {198, 55, 125, 195}, {199, 115, 96, 83}, {204, 44, 112, 67}, {204, 44, 112, 131}, {206, 217, 139, 19}, {206, 217, 139, 195}, {206, 217, 143, 131}}},
|
||||
{Region: "US East", IPs: []net.IP{{23, 82, 8, 143}, {23, 82, 136, 93}, {23, 83, 91, 170}, {23, 105, 170, 130}, {23, 105, 170, 139}, {23, 105, 170, 151}, {23, 226, 141, 195}, {45, 87, 214, 35}, {67, 21, 32, 145}, {67, 219, 146, 67}, {68, 235, 35, 12}, {68, 235, 35, 172}, {68, 235, 50, 227}, {76, 72, 175, 99}, {86, 106, 87, 83}, {104, 168, 34, 147}, {104, 223, 127, 195}, {107, 150, 29, 131}, {142, 234, 200, 176}, {156, 96, 59, 102}, {162, 222, 195, 67}, {167, 160, 167, 195}, {167, 160, 172, 3}, {173, 44, 36, 67}, {173, 208, 45, 33}, {185, 232, 22, 195}, {198, 12, 64, 35}, {198, 147, 22, 225}, {199, 217, 104, 227}, {199, 217, 105, 227}, {206, 217, 128, 3}, {206, 217, 129, 227}, {217, 138, 255, 163}, {217, 138, 255, 179}}},
|
||||
{Region: "US West", IPs: []net.IP{{23, 83, 130, 166}, {23, 83, 131, 187}, {23, 94, 74, 99}, {37, 120, 147, 163}, {64, 120, 2, 174}, {66, 115, 176, 3}, {82, 102, 30, 67}, {89, 187, 185, 34}, {89, 187, 187, 98}, {104, 129, 3, 67}, {104, 129, 3, 163}, {104, 129, 56, 67}, {104, 129, 56, 131}, {104, 152, 222, 33}, {167, 88, 60, 227}, {167, 88, 60, 243}, {172, 241, 214, 202}, {172, 241, 250, 131}, {172, 255, 125, 141}, {185, 236, 200, 35}, {192, 3, 20, 51}, {198, 12, 116, 195}, {198, 23, 242, 147}, {209, 58, 129, 121}, {212, 103, 49, 67}, {216, 45, 53, 131}, {217, 138, 217, 51}, {217, 138, 217, 211}}},
|
||||
{Region: "Ukraine", IPs: []net.IP{{45, 141, 156, 11}, {45, 141, 156, 50}}},
|
||||
{Region: "United Arab Emirates", IPs: []net.IP{{45, 9, 249, 43}}},
|
||||
{Region: "United Kingdom", IPs: []net.IP{{2, 58, 29, 17}, {2, 58, 29, 145}, {81, 92, 207, 69}, {84, 17, 50, 130}, {89, 44, 201, 99}, {89, 238, 135, 133}, {89, 238, 150, 229}, {185, 212, 168, 133}, {212, 102, 63, 32}, {212, 102, 63, 62}, {217, 138, 254, 51}}},
|
||||
{Region: "Vietnam", IPs: []net.IP{{103, 9, 76, 197}, {103, 9, 79, 186}, {103, 9, 79, 219}}},
|
||||
{Region: "Windflix CA", IPs: []net.IP{{104, 218, 60, 111}, {104, 254, 92, 99}}},
|
||||
{Region: "Windflix JP", IPs: []net.IP{{5, 181, 235, 67}}},
|
||||
{Region: "Windflix UK", IPs: []net.IP{{45, 9, 248, 3}, {81, 92, 200, 85}, {89, 47, 62, 83}}},
|
||||
{Region: "Windflix US", IPs: []net.IP{{38, 132, 101, 211}, {38, 132, 122, 131}, {38, 132, 122, 195}, {77, 81, 136, 99}, {185, 232, 22, 131}, {217, 138, 206, 211}}},
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
@@ -8,19 +9,19 @@ import (
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
)
|
||||
|
||||
func (c *configurator) Start(verbosityDetailsLevel uint8) (stdout io.ReadCloser, waitFn func() error, err error) {
|
||||
c.logger.Info("%s: starting unbound", logPrefix)
|
||||
func (c *configurator) Start(ctx context.Context, verbosityDetailsLevel uint8) (stdout io.ReadCloser, waitFn func() error, err error) {
|
||||
c.logger.Info("starting unbound")
|
||||
args := []string{"-d", "-c", string(constants.UnboundConf)}
|
||||
if verbosityDetailsLevel > 0 {
|
||||
args = append(args, "-"+strings.Repeat("v", int(verbosityDetailsLevel)))
|
||||
}
|
||||
// Only logs to stderr
|
||||
_, stdout, waitFn, err = c.commander.Start("unbound", args...)
|
||||
_, stdout, waitFn, err = c.commander.Start(ctx, "unbound", args...)
|
||||
return stdout, waitFn, err
|
||||
}
|
||||
|
||||
func (c *configurator) Version() (version string, err error) {
|
||||
output, err := c.commander.Run("unbound", "-V")
|
||||
func (c *configurator) Version(ctx context.Context) (version string, err error) {
|
||||
output, err := c.commander.Run(ctx, "unbound", "-V")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unbound version: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
commandMocks "github.com/qdm12/golibs/command/mocks"
|
||||
loggingMocks "github.com/qdm12/golibs/logging/mocks"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/golibs/command/mock_command"
|
||||
"github.com/qdm12/golibs/logging/mock_logging"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -14,18 +16,18 @@ import (
|
||||
|
||||
func Test_Start(t *testing.T) {
|
||||
t.Parallel()
|
||||
logger := &loggingMocks.Logger{}
|
||||
logger.On("Info", "%s: starting unbound", logPrefix).Once()
|
||||
commander := &commandMocks.Commander{}
|
||||
commander.On("Start", "unbound", "-d", "-c", string(constants.UnboundConf), "-vv").
|
||||
Return(nil, nil, nil, nil).Once()
|
||||
mockCtrl := gomock.NewController(t)
|
||||
defer mockCtrl.Finish()
|
||||
logger := mock_logging.NewMockLogger(mockCtrl)
|
||||
logger.EXPECT().Info("starting unbound").Times(1)
|
||||
commander := mock_command.NewMockCommander(mockCtrl)
|
||||
commander.EXPECT().Start(context.Background(), "unbound", "-d", "-c", string(constants.UnboundConf), "-vv").
|
||||
Return(nil, nil, nil, nil).Times(1)
|
||||
c := &configurator{commander: commander, logger: logger}
|
||||
stdout, waitFn, err := c.Start(2)
|
||||
stdout, waitFn, err := c.Start(context.Background(), 2)
|
||||
assert.Nil(t, stdout)
|
||||
assert.Nil(t, waitFn)
|
||||
assert.NoError(t, err)
|
||||
logger.AssertExpectations(t)
|
||||
commander.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func Test_Version(t *testing.T) {
|
||||
@@ -52,11 +54,13 @@ func Test_Version(t *testing.T) {
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
commander := &commandMocks.Commander{}
|
||||
commander.On("Run", "unbound", "-V").
|
||||
Return(tc.runOutput, tc.runErr).Once()
|
||||
mockCtrl := gomock.NewController(t)
|
||||
defer mockCtrl.Finish()
|
||||
commander := mock_command.NewMockCommander(mockCtrl)
|
||||
commander.EXPECT().Run(context.Background(), "unbound", "-V").
|
||||
Return(tc.runOutput, tc.runErr).Times(1)
|
||||
c := &configurator{commander: commander}
|
||||
version, err := c.Version()
|
||||
version, err := c.Version(context.Background())
|
||||
if tc.err != nil {
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, tc.err.Error(), err.Error())
|
||||
@@ -64,7 +68,6 @@ func Test_Version(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
assert.Equal(t, tc.version, version)
|
||||
commander.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package dns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@@ -13,14 +14,11 @@ import (
|
||||
)
|
||||
|
||||
func (c *configurator) MakeUnboundConf(settings settings.DNS, uid, gid int) (err error) {
|
||||
c.logger.Info("%s: generating Unbound configuration", logPrefix)
|
||||
lines, warnings, err := generateUnboundConf(settings, c.client, c.logger)
|
||||
c.logger.Info("generating Unbound configuration")
|
||||
lines, warnings := generateUnboundConf(settings, c.client, c.logger)
|
||||
for _, warning := range warnings {
|
||||
c.logger.Warn(warning)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.fileManager.WriteLinesToFile(
|
||||
string(constants.UnboundConf),
|
||||
lines,
|
||||
@@ -29,7 +27,11 @@ func (c *configurator) MakeUnboundConf(settings settings.DNS, uid, gid int) (err
|
||||
}
|
||||
|
||||
// MakeUnboundConf generates an Unbound configuration from the user provided settings
|
||||
func generateUnboundConf(settings settings.DNS, client network.Client, logger logging.Logger) (lines []string, warnings []error, err error) {
|
||||
func generateUnboundConf(settings settings.DNS, client network.Client, logger logging.Logger) (lines []string, warnings []error) {
|
||||
doIPv6 := "no"
|
||||
if settings.IPv6 {
|
||||
doIPv6 = "yes"
|
||||
}
|
||||
serverSection := map[string]string{
|
||||
// Logging
|
||||
"verbosity": fmt.Sprintf("%d", settings.VerbosityLevel),
|
||||
@@ -60,7 +62,7 @@ func generateUnboundConf(settings settings.DNS, client network.Client, logger lo
|
||||
"harden-algo-downgrade": "yes",
|
||||
// Network
|
||||
"do-ip4": "yes",
|
||||
"do-ip6": "no",
|
||||
"do-ip6": doIPv6,
|
||||
"interface": "127.0.0.1",
|
||||
"port": "53",
|
||||
// Other
|
||||
@@ -72,8 +74,8 @@ func generateUnboundConf(settings settings.DNS, client network.Client, logger lo
|
||||
settings.BlockMalicious, settings.BlockAds, settings.BlockSurveillance,
|
||||
settings.AllowedHostnames, settings.PrivateAddresses,
|
||||
)
|
||||
logger.Info("%s: %d hostnames blocked overall", logPrefix, len(hostnamesLines))
|
||||
logger.Info("%s: %d IP addresses blocked overall", logPrefix, len(ipsLines))
|
||||
logger.Info("%d hostnames blocked overall", len(hostnamesLines))
|
||||
logger.Info("%d IP addresses blocked overall", len(ipsLines))
|
||||
sort.Slice(hostnamesLines, func(i, j int) bool { // for unit tests really
|
||||
return hostnamesLines[i] < hostnamesLines[j]
|
||||
})
|
||||
@@ -83,9 +85,11 @@ func generateUnboundConf(settings settings.DNS, client network.Client, logger lo
|
||||
|
||||
// Server
|
||||
lines = append(lines, "server:")
|
||||
var serverLines []string
|
||||
serverLines := make([]string, len(serverSection))
|
||||
i := 0
|
||||
for k, v := range serverSection {
|
||||
serverLines = append(serverLines, " "+k+": "+v)
|
||||
serverLines[i] = " " + k + ": " + v
|
||||
i++
|
||||
}
|
||||
sort.Slice(serverLines, func(i, j int) bool {
|
||||
return serverLines[i] < serverLines[j]
|
||||
@@ -105,27 +109,24 @@ func generateUnboundConf(settings settings.DNS, client network.Client, logger lo
|
||||
} else {
|
||||
forwardZoneSection["forward-no-cache"] = "yes"
|
||||
}
|
||||
var forwardZoneLines []string
|
||||
forwardZoneLines := make([]string, len(forwardZoneSection))
|
||||
i = 0
|
||||
for k, v := range forwardZoneSection {
|
||||
forwardZoneLines = append(forwardZoneLines, " "+k+": "+v)
|
||||
forwardZoneLines[i] = " " + k + ": " + v
|
||||
i++
|
||||
}
|
||||
sort.Slice(forwardZoneLines, func(i, j int) bool {
|
||||
return forwardZoneLines[i] < forwardZoneLines[j]
|
||||
})
|
||||
for _, provider := range settings.Providers {
|
||||
providerData, ok := constants.DNSProviderMapping()[provider]
|
||||
if !ok {
|
||||
return nil, warnings, fmt.Errorf("DNS provider %q does not have associated data", provider)
|
||||
} else if !providerData.SupportsTLS {
|
||||
return nil, warnings, fmt.Errorf("DNS provider %q does not support DNS over TLS", provider)
|
||||
}
|
||||
providerData := constants.DNSProviderMapping()[provider]
|
||||
for _, IP := range providerData.IPs {
|
||||
forwardZoneLines = append(forwardZoneLines,
|
||||
fmt.Sprintf(" forward-addr: %s@853#%s", IP.String(), providerData.Host))
|
||||
fmt.Sprintf(" forward-addr: %s@853#%s", IP, providerData.Host))
|
||||
}
|
||||
}
|
||||
lines = append(lines, forwardZoneLines...)
|
||||
return lines, warnings, nil
|
||||
return lines, warnings
|
||||
}
|
||||
|
||||
func buildBlocked(client network.Client, blockMalicious, blockAds, blockSurveillance bool,
|
||||
@@ -158,11 +159,11 @@ func buildBlocked(client network.Client, blockMalicious, blockAds, blockSurveill
|
||||
return hostnamesLines, ipsLines, errs
|
||||
}
|
||||
|
||||
func getList(client network.Client, URL string) (results []string, err error) {
|
||||
content, status, err := client.GetContent(URL)
|
||||
func getList(client network.Client, url string) (results []string, err error) {
|
||||
content, status, err := client.GetContent(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if status != 200 {
|
||||
} else if status != http.StatusOK {
|
||||
return nil, fmt.Errorf("HTTP status code is %d and not 200", status)
|
||||
}
|
||||
results = strings.Split(string(content), "\n")
|
||||
|
||||
@@ -5,8 +5,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/golibs/network/mocks"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/golibs/logging/mock_logging"
|
||||
"github.com/qdm12/golibs/network/mock_network"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/settings"
|
||||
@@ -26,24 +27,26 @@ func Test_generateUnboundConf(t *testing.T) {
|
||||
VerbosityLevel: 2,
|
||||
ValidationLogLevel: 3,
|
||||
Caching: true,
|
||||
IPv6: true,
|
||||
}
|
||||
client := &mocks.Client{}
|
||||
client.On("GetContent", string(constants.MaliciousBlockListHostnamesURL)).
|
||||
Return([]byte("b\na\nc"), 200, nil).Once()
|
||||
client.On("GetContent", string(constants.MaliciousBlockListIPsURL)).
|
||||
Return([]byte("c\nd\n"), 200, nil).Once()
|
||||
emptyLogger, err := logging.NewEmptyLogger()
|
||||
require.NoError(t, err)
|
||||
lines, warnings, err := generateUnboundConf(settings, client, emptyLogger)
|
||||
mockCtrl := gomock.NewController(t)
|
||||
defer mockCtrl.Finish()
|
||||
client := mock_network.NewMockClient(mockCtrl)
|
||||
client.EXPECT().GetContent(string(constants.MaliciousBlockListHostnamesURL)).
|
||||
Return([]byte("b\na\nc"), 200, nil).Times(1)
|
||||
client.EXPECT().GetContent(string(constants.MaliciousBlockListIPsURL)).
|
||||
Return([]byte("c\nd\n"), 200, nil).Times(1)
|
||||
logger := mock_logging.NewMockLogger(mockCtrl)
|
||||
logger.EXPECT().Info("%d hostnames blocked overall", 2).Times(1)
|
||||
logger.EXPECT().Info("%d IP addresses blocked overall", 3).Times(1)
|
||||
lines, warnings := generateUnboundConf(settings, client, logger)
|
||||
require.Len(t, warnings, 0)
|
||||
require.NoError(t, err)
|
||||
client.AssertExpectations(t)
|
||||
expected := `
|
||||
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
|
||||
@@ -79,8 +82,12 @@ forward-zone:
|
||||
name: "."
|
||||
forward-addr: 1.1.1.1@853#cloudflare-dns.com
|
||||
forward-addr: 1.0.0.1@853#cloudflare-dns.com
|
||||
forward-addr: 2606:4700:4700::1111@853#cloudflare-dns.com
|
||||
forward-addr: 2606:4700:4700::1001@853#cloudflare-dns.com
|
||||
forward-addr: 9.9.9.9@853#dns.quad9.net
|
||||
forward-addr: 149.112.112.112@853#dns.quad9.net`
|
||||
forward-addr: 149.112.112.112@853#dns.quad9.net
|
||||
forward-addr: 2620:fe::fe@853#dns.quad9.net
|
||||
forward-addr: 2620:fe::9@853#dns.quad9.net`
|
||||
assert.Equal(t, expected, "\n"+strings.Join(lines, "\n"))
|
||||
}
|
||||
|
||||
@@ -223,24 +230,26 @@ func Test_buildBlocked(t *testing.T) {
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := &mocks.Client{}
|
||||
mockCtrl := gomock.NewController(t)
|
||||
defer mockCtrl.Finish()
|
||||
client := mock_network.NewMockClient(mockCtrl)
|
||||
if tc.malicious.blocked {
|
||||
client.On("GetContent", string(constants.MaliciousBlockListHostnamesURL)).
|
||||
Return(tc.malicious.content, 200, tc.malicious.clientErr).Once()
|
||||
client.On("GetContent", string(constants.MaliciousBlockListIPsURL)).
|
||||
Return(tc.malicious.content, 200, tc.malicious.clientErr).Once()
|
||||
client.EXPECT().GetContent(string(constants.MaliciousBlockListHostnamesURL)).
|
||||
Return(tc.malicious.content, 200, tc.malicious.clientErr).Times(1)
|
||||
client.EXPECT().GetContent(string(constants.MaliciousBlockListIPsURL)).
|
||||
Return(tc.malicious.content, 200, tc.malicious.clientErr).Times(1)
|
||||
}
|
||||
if tc.ads.blocked {
|
||||
client.On("GetContent", string(constants.AdsBlockListHostnamesURL)).
|
||||
Return(tc.ads.content, 200, tc.ads.clientErr).Once()
|
||||
client.On("GetContent", string(constants.AdsBlockListIPsURL)).
|
||||
Return(tc.ads.content, 200, tc.ads.clientErr).Once()
|
||||
client.EXPECT().GetContent(string(constants.AdsBlockListHostnamesURL)).
|
||||
Return(tc.ads.content, 200, tc.ads.clientErr).Times(1)
|
||||
client.EXPECT().GetContent(string(constants.AdsBlockListIPsURL)).
|
||||
Return(tc.ads.content, 200, tc.ads.clientErr).Times(1)
|
||||
}
|
||||
if tc.surveillance.blocked {
|
||||
client.On("GetContent", string(constants.SurveillanceBlockListHostnamesURL)).
|
||||
Return(tc.surveillance.content, 200, tc.surveillance.clientErr).Once()
|
||||
client.On("GetContent", string(constants.SurveillanceBlockListIPsURL)).
|
||||
Return(tc.surveillance.content, 200, tc.surveillance.clientErr).Once()
|
||||
client.EXPECT().GetContent(string(constants.SurveillanceBlockListHostnamesURL)).
|
||||
Return(tc.surveillance.content, 200, tc.surveillance.clientErr).Times(1)
|
||||
client.EXPECT().GetContent(string(constants.SurveillanceBlockListIPsURL)).
|
||||
Return(tc.surveillance.content, 200, tc.surveillance.clientErr).Times(1)
|
||||
}
|
||||
hostnamesLines, ipsLines, errs := buildBlocked(client, tc.malicious.blocked, tc.ads.blocked, tc.surveillance.blocked,
|
||||
tc.allowedHostnames, tc.privateAddresses)
|
||||
@@ -251,7 +260,6 @@ func Test_buildBlocked(t *testing.T) {
|
||||
assert.ElementsMatch(t, tc.errsString, errsString)
|
||||
assert.ElementsMatch(t, tc.hostnamesLines, hostnamesLines)
|
||||
assert.ElementsMatch(t, tc.ipsLines, ipsLines)
|
||||
client.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -274,10 +282,11 @@ func Test_getList(t *testing.T) {
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := &mocks.Client{}
|
||||
client.On("GetContent", "irrelevant_url").Return(
|
||||
tc.content, tc.status, tc.clientErr,
|
||||
).Once()
|
||||
mockCtrl := gomock.NewController(t)
|
||||
defer mockCtrl.Finish()
|
||||
client := mock_network.NewMockClient(mockCtrl)
|
||||
client.EXPECT().GetContent("irrelevant_url").
|
||||
Return(tc.content, tc.status, tc.clientErr).Times(1)
|
||||
results, err := getList(client, "irrelevant_url")
|
||||
if tc.err != nil {
|
||||
require.Error(t, err)
|
||||
@@ -286,7 +295,6 @@ func Test_getList(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
assert.Equal(t, tc.results, results)
|
||||
client.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -374,22 +382,24 @@ func Test_buildBlockedHostnames(t *testing.T) {
|
||||
" local-zone: \"site_d\" static"},
|
||||
},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
for name, tc := range tests { //nolint:dupl
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := &mocks.Client{}
|
||||
mockCtrl := gomock.NewController(t)
|
||||
defer mockCtrl.Finish()
|
||||
client := mock_network.NewMockClient(mockCtrl)
|
||||
if tc.malicious.blocked {
|
||||
client.On("GetContent", string(constants.MaliciousBlockListHostnamesURL)).
|
||||
Return(tc.malicious.content, 200, tc.malicious.clientErr).Once()
|
||||
client.EXPECT().GetContent(string(constants.MaliciousBlockListHostnamesURL)).
|
||||
Return(tc.malicious.content, 200, tc.malicious.clientErr).Times(1)
|
||||
}
|
||||
if tc.ads.blocked {
|
||||
client.On("GetContent", string(constants.AdsBlockListHostnamesURL)).
|
||||
Return(tc.ads.content, 200, tc.ads.clientErr).Once()
|
||||
client.EXPECT().GetContent(string(constants.AdsBlockListHostnamesURL)).
|
||||
Return(tc.ads.content, 200, tc.ads.clientErr).Times(1)
|
||||
}
|
||||
if tc.surveillance.blocked {
|
||||
client.On("GetContent", string(constants.SurveillanceBlockListHostnamesURL)).
|
||||
Return(tc.surveillance.content, 200, tc.surveillance.clientErr).Once()
|
||||
client.EXPECT().GetContent(string(constants.SurveillanceBlockListHostnamesURL)).
|
||||
Return(tc.surveillance.content, 200, tc.surveillance.clientErr).Times(1)
|
||||
}
|
||||
lines, errs := buildBlockedHostnames(client,
|
||||
tc.malicious.blocked, tc.ads.blocked, tc.surveillance.blocked, tc.allowedHostnames)
|
||||
@@ -399,7 +409,6 @@ func Test_buildBlockedHostnames(t *testing.T) {
|
||||
}
|
||||
assert.ElementsMatch(t, tc.errsString, errsString)
|
||||
assert.ElementsMatch(t, tc.lines, lines)
|
||||
client.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -489,22 +498,24 @@ func Test_buildBlockedIPs(t *testing.T) {
|
||||
" private-address: site_d"},
|
||||
},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
for name, tc := range tests { //nolint:dupl
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := &mocks.Client{}
|
||||
mockCtrl := gomock.NewController(t)
|
||||
defer mockCtrl.Finish()
|
||||
client := mock_network.NewMockClient(mockCtrl)
|
||||
if tc.malicious.blocked {
|
||||
client.On("GetContent", string(constants.MaliciousBlockListIPsURL)).
|
||||
Return(tc.malicious.content, 200, tc.malicious.clientErr).Once()
|
||||
client.EXPECT().GetContent(string(constants.MaliciousBlockListIPsURL)).
|
||||
Return(tc.malicious.content, 200, tc.malicious.clientErr).Times(1)
|
||||
}
|
||||
if tc.ads.blocked {
|
||||
client.On("GetContent", string(constants.AdsBlockListIPsURL)).
|
||||
Return(tc.ads.content, 200, tc.ads.clientErr).Once()
|
||||
client.EXPECT().GetContent(string(constants.AdsBlockListIPsURL)).
|
||||
Return(tc.ads.content, 200, tc.ads.clientErr).Times(1)
|
||||
}
|
||||
if tc.surveillance.blocked {
|
||||
client.On("GetContent", string(constants.SurveillanceBlockListIPsURL)).
|
||||
Return(tc.surveillance.content, 200, tc.surveillance.clientErr).Once()
|
||||
client.EXPECT().GetContent(string(constants.SurveillanceBlockListIPsURL)).
|
||||
Return(tc.surveillance.content, 200, tc.surveillance.clientErr).Times(1)
|
||||
}
|
||||
lines, errs := buildBlockedIPs(client,
|
||||
tc.malicious.blocked, tc.ads.blocked, tc.surveillance.blocked, tc.privateAddresses)
|
||||
@@ -514,7 +525,6 @@ func Test_buildBlockedIPs(t *testing.T) {
|
||||
}
|
||||
assert.ElementsMatch(t, tc.errsString, errsString)
|
||||
assert.ElementsMatch(t, tc.lines, lines)
|
||||
client.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
@@ -11,17 +12,15 @@ import (
|
||||
"github.com/qdm12/private-internet-access-docker/internal/settings"
|
||||
)
|
||||
|
||||
const logPrefix = "dns configurator"
|
||||
|
||||
type Configurator interface {
|
||||
DownloadRootHints(uid, gid int) error
|
||||
DownloadRootKey(uid, gid int) error
|
||||
MakeUnboundConf(settings settings.DNS, uid, gid int) (err error)
|
||||
UseDNSInternally(IP net.IP)
|
||||
UseDNSSystemWide(IP net.IP) error
|
||||
Start(logLevel uint8) (stdout io.ReadCloser, waitFn func() error, err error)
|
||||
UseDNSSystemWide(ip net.IP, keepNameserver bool) error
|
||||
Start(ctx context.Context, logLevel uint8) (stdout io.ReadCloser, waitFn func() error, err error)
|
||||
WaitForUnbound() (err error)
|
||||
Version() (version string, err error)
|
||||
Version(ctx context.Context) (version string, err error)
|
||||
}
|
||||
|
||||
type configurator struct {
|
||||
@@ -34,7 +33,7 @@ type configurator struct {
|
||||
|
||||
func NewConfigurator(logger logging.Logger, client network.Client, fileManager files.FileManager) Configurator {
|
||||
return &configurator{
|
||||
logger: logger,
|
||||
logger: logger.WithPrefix("dns configurator: "),
|
||||
client: client,
|
||||
fileManager: fileManager,
|
||||
commander: command.NewCommander(),
|
||||
|
||||
194
internal/dns/loop.go
Normal file
194
internal/dns/loop.go
Normal file
@@ -0,0 +1,194 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/golibs/command"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/settings"
|
||||
)
|
||||
|
||||
type Looper interface {
|
||||
Run(ctx context.Context, wg *sync.WaitGroup)
|
||||
RunRestartTicker(ctx context.Context)
|
||||
Restart()
|
||||
}
|
||||
|
||||
type looper struct {
|
||||
conf Configurator
|
||||
settings settings.DNS
|
||||
logger logging.Logger
|
||||
streamMerger command.StreamMerger
|
||||
uid int
|
||||
gid int
|
||||
restart chan struct{}
|
||||
}
|
||||
|
||||
func NewLooper(conf Configurator, settings settings.DNS, logger logging.Logger,
|
||||
streamMerger command.StreamMerger, uid, gid int) Looper {
|
||||
return &looper{
|
||||
conf: conf,
|
||||
settings: settings,
|
||||
logger: logger.WithPrefix("dns over tls: "),
|
||||
uid: uid,
|
||||
gid: gid,
|
||||
streamMerger: streamMerger,
|
||||
restart: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *looper) Restart() { l.restart <- struct{}{} }
|
||||
|
||||
func (l *looper) logAndWait(ctx context.Context, err error) {
|
||||
l.logger.Warn(err)
|
||||
l.logger.Info("attempting restart in 10 seconds")
|
||||
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
defer cancel()
|
||||
<-ctx.Done()
|
||||
}
|
||||
|
||||
func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
||||
wg.Add(1)
|
||||
defer wg.Done()
|
||||
l.fallbackToUnencryptedDNS()
|
||||
select {
|
||||
case <-l.restart:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
defer l.logger.Warn("loop exited")
|
||||
|
||||
var unboundCtx context.Context
|
||||
var unboundCancel context.CancelFunc = func() {}
|
||||
var waitError chan error
|
||||
triggeredRestart := false
|
||||
for ctx.Err() == nil {
|
||||
if !l.settings.Enabled {
|
||||
// wait for another restart signal to recheck if it is enabled
|
||||
select {
|
||||
case <-l.restart:
|
||||
case <-ctx.Done():
|
||||
unboundCancel()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Setup
|
||||
if err := l.conf.DownloadRootHints(l.uid, l.gid); err != nil {
|
||||
l.logAndWait(ctx, err)
|
||||
continue
|
||||
}
|
||||
if err := l.conf.DownloadRootKey(l.uid, l.gid); err != nil {
|
||||
l.logAndWait(ctx, err)
|
||||
continue
|
||||
}
|
||||
if err := l.conf.MakeUnboundConf(l.settings, l.uid, l.gid); err != nil {
|
||||
l.logAndWait(ctx, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if triggeredRestart {
|
||||
triggeredRestart = false
|
||||
unboundCancel()
|
||||
<-waitError
|
||||
close(waitError)
|
||||
}
|
||||
unboundCtx, unboundCancel = context.WithCancel(context.Background())
|
||||
stream, waitFn, err := l.conf.Start(unboundCtx, l.settings.VerbosityDetailsLevel)
|
||||
if err != nil {
|
||||
unboundCancel()
|
||||
l.fallbackToUnencryptedDNS()
|
||||
l.logAndWait(ctx, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Started successfully
|
||||
go l.streamMerger.Merge(unboundCtx, stream, command.MergeName("unbound"))
|
||||
l.conf.UseDNSInternally(net.IP{127, 0, 0, 1}) // use Unbound
|
||||
if err := l.conf.UseDNSSystemWide(net.IP{127, 0, 0, 1}, l.settings.KeepNameserver); err != nil { // use Unbound
|
||||
l.logger.Error(err)
|
||||
}
|
||||
if err := l.conf.WaitForUnbound(); err != nil {
|
||||
unboundCancel()
|
||||
l.fallbackToUnencryptedDNS()
|
||||
l.logAndWait(ctx, err)
|
||||
continue
|
||||
}
|
||||
waitError = make(chan error)
|
||||
go func() {
|
||||
err := waitFn() // blocking
|
||||
waitError <- err
|
||||
}()
|
||||
|
||||
// Wait for one of the three cases below
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
l.logger.Warn("context canceled: exiting loop")
|
||||
unboundCancel()
|
||||
<-waitError
|
||||
close(waitError)
|
||||
return
|
||||
case <-l.restart: // triggered restart
|
||||
l.logger.Info("restarting")
|
||||
// unboundCancel occurs next loop run when the setup is complete
|
||||
triggeredRestart = true
|
||||
case err := <-waitError: // unexpected error
|
||||
close(waitError)
|
||||
unboundCancel()
|
||||
l.fallbackToUnencryptedDNS()
|
||||
l.logAndWait(ctx, err)
|
||||
}
|
||||
}
|
||||
unboundCancel()
|
||||
}
|
||||
|
||||
func (l *looper) fallbackToUnencryptedDNS() {
|
||||
// Try with user provided plaintext ip address
|
||||
targetIP := l.settings.PlaintextAddress
|
||||
if targetIP != nil {
|
||||
l.logger.Info("falling back on plaintext DNS at address %s", targetIP)
|
||||
l.conf.UseDNSInternally(targetIP)
|
||||
if err := l.conf.UseDNSSystemWide(targetIP, l.settings.KeepNameserver); err != nil {
|
||||
l.logger.Error(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Try with any IPv4 address from the providers chosen
|
||||
for _, provider := range l.settings.Providers {
|
||||
data := constants.DNSProviderMapping()[provider]
|
||||
for _, targetIP = range data.IPs {
|
||||
if targetIP.To4() != nil {
|
||||
l.logger.Info("falling back on plaintext DNS at address %s", targetIP)
|
||||
l.conf.UseDNSInternally(targetIP)
|
||||
if err := l.conf.UseDNSSystemWide(targetIP, l.settings.KeepNameserver); err != nil {
|
||||
l.logger.Error(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No IPv4 address found
|
||||
l.logger.Error("no ipv4 DNS address found for providers %s", l.settings.Providers)
|
||||
}
|
||||
|
||||
func (l *looper) RunRestartTicker(ctx context.Context) {
|
||||
if l.settings.UpdatePeriod == 0 {
|
||||
return
|
||||
}
|
||||
ticker := time.NewTicker(l.settings.UpdatePeriod)
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
ticker.Stop()
|
||||
return
|
||||
case <-ticker.C:
|
||||
l.restart <- struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,20 +9,20 @@ import (
|
||||
)
|
||||
|
||||
// UseDNSInternally is to change the Go program DNS only
|
||||
func (c *configurator) UseDNSInternally(IP net.IP) {
|
||||
c.logger.Info("%s: using DNS address %s internally", logPrefix, IP.String())
|
||||
func (c *configurator) UseDNSInternally(ip net.IP) {
|
||||
c.logger.Info("using DNS address %s internally", ip.String())
|
||||
net.DefaultResolver = &net.Resolver{
|
||||
PreferGo: true,
|
||||
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
d := net.Dialer{}
|
||||
return d.DialContext(ctx, "udp", net.JoinHostPort(IP.String(), "53"))
|
||||
return d.DialContext(ctx, "udp", net.JoinHostPort(ip.String(), "53"))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// UseDNSSystemWide changes the nameserver to use for DNS system wide
|
||||
func (c *configurator) UseDNSSystemWide(IP net.IP) error {
|
||||
c.logger.Info("%s: using DNS address %s system wide", logPrefix, IP.String())
|
||||
func (c *configurator) UseDNSSystemWide(ip net.IP, keepNameserver bool) error {
|
||||
c.logger.Info("using DNS address %s system wide", ip.String())
|
||||
data, err := c.fileManager.ReadFile(string(constants.ResolvConf))
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -33,14 +33,16 @@ func (c *configurator) UseDNSSystemWide(IP net.IP) error {
|
||||
lines = nil
|
||||
}
|
||||
found := false
|
||||
for i := range lines {
|
||||
if strings.HasPrefix(lines[i], "nameserver ") {
|
||||
lines[i] = "nameserver " + IP.String()
|
||||
found = true
|
||||
if !keepNameserver { // default
|
||||
for i := range lines {
|
||||
if strings.HasPrefix(lines[i], "nameserver ") {
|
||||
lines[i] = "nameserver " + ip.String()
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
lines = append(lines, "nameserver "+IP.String())
|
||||
lines = append(lines, "nameserver "+ip.String())
|
||||
}
|
||||
data = []byte(strings.Join(lines, "\n"))
|
||||
return c.fileManager.WriteToFile(string(constants.ResolvConf), data)
|
||||
|
||||
@@ -5,8 +5,9 @@ import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
filesmocks "github.com/qdm12/golibs/files/mocks"
|
||||
loggingmocks "github.com/qdm12/golibs/logging/mocks"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/golibs/files/mock_files"
|
||||
"github.com/qdm12/golibs/logging/mock_logging"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -46,28 +47,28 @@ func Test_UseDNSSystemWide(t *testing.T) {
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
fileManager := &filesmocks.FileManager{}
|
||||
fileManager.On("ReadFile", string(constants.ResolvConf)).
|
||||
Return(tc.data, tc.readErr).Once()
|
||||
mockCtrl := gomock.NewController(t)
|
||||
defer mockCtrl.Finish()
|
||||
fileManager := mock_files.NewMockFileManager(mockCtrl)
|
||||
fileManager.EXPECT().ReadFile(string(constants.ResolvConf)).
|
||||
Return(tc.data, tc.readErr).Times(1)
|
||||
if tc.readErr == nil {
|
||||
fileManager.On("WriteToFile", string(constants.ResolvConf), tc.writtenData).
|
||||
Return(tc.writeErr).Once()
|
||||
fileManager.EXPECT().WriteToFile(string(constants.ResolvConf), tc.writtenData).
|
||||
Return(tc.writeErr).Times(1)
|
||||
}
|
||||
logger := &loggingmocks.Logger{}
|
||||
logger.On("Info", "%s: using DNS address %s system wide", logPrefix, "127.0.0.1").Once()
|
||||
logger := mock_logging.NewMockLogger(mockCtrl)
|
||||
logger.EXPECT().Info("using DNS address %s system wide", "127.0.0.1").Times(1)
|
||||
c := &configurator{
|
||||
fileManager: fileManager,
|
||||
logger: logger,
|
||||
}
|
||||
err := c.UseDNSSystemWide(net.IP{127, 0, 0, 1})
|
||||
err := c.UseDNSSystemWide(net.IP{127, 0, 0, 1}, false)
|
||||
if tc.err != nil {
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, tc.err.Error(), err.Error())
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
fileManager.AssertExpectations(t)
|
||||
logger.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,17 +2,18 @@ package dns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/qdm12/golibs/files"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
)
|
||||
|
||||
func (c *configurator) DownloadRootHints(uid, gid int) error {
|
||||
c.logger.Info("%s: downloading root hints from %s", logPrefix, constants.NamedRootURL)
|
||||
c.logger.Info("downloading root hints from %s", constants.NamedRootURL)
|
||||
content, status, err := c.client.GetContent(string(constants.NamedRootURL))
|
||||
if err != nil {
|
||||
return err
|
||||
} else if status != 200 {
|
||||
} else if status != http.StatusOK {
|
||||
return fmt.Errorf("HTTP status code is %d for %s", status, constants.NamedRootURL)
|
||||
}
|
||||
return c.fileManager.WriteToFile(
|
||||
@@ -23,11 +24,11 @@ func (c *configurator) DownloadRootHints(uid, gid int) error {
|
||||
}
|
||||
|
||||
func (c *configurator) DownloadRootKey(uid, gid int) error {
|
||||
c.logger.Info("%s: downloading root key from %s", logPrefix, constants.RootKeyURL)
|
||||
c.logger.Info("downloading root key from %s", constants.RootKeyURL)
|
||||
content, status, err := c.client.GetContent(string(constants.RootKeyURL))
|
||||
if err != nil {
|
||||
return err
|
||||
} else if status != 200 {
|
||||
} else if status != http.StatusOK {
|
||||
return fmt.Errorf("HTTP status code is %d for %s", status, constants.RootKeyURL)
|
||||
}
|
||||
return c.fileManager.WriteToFile(
|
||||
|
||||
@@ -5,17 +5,18 @@ import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
filesMocks "github.com/qdm12/golibs/files/mocks"
|
||||
loggingMocks "github.com/qdm12/golibs/logging/mocks"
|
||||
networkMocks "github.com/qdm12/golibs/network/mocks"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/golibs/files"
|
||||
"github.com/qdm12/golibs/files/mock_files"
|
||||
"github.com/qdm12/golibs/logging/mock_logging"
|
||||
"github.com/qdm12/golibs/network/mock_network"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
)
|
||||
|
||||
func Test_DownloadRootHints(t *testing.T) {
|
||||
func Test_DownloadRootHints(t *testing.T) { //nolint:dupl
|
||||
t.Parallel()
|
||||
tests := map[string]struct {
|
||||
content []byte
|
||||
@@ -49,20 +50,21 @@ func Test_DownloadRootHints(t *testing.T) {
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
logger := &loggingMocks.Logger{}
|
||||
logger.On("Info", "%s: downloading root hints from %s", logPrefix, constants.NamedRootURL).Once()
|
||||
client := &networkMocks.Client{}
|
||||
client.On("GetContent", string(constants.NamedRootURL)).
|
||||
Return(tc.content, tc.status, tc.clientErr).Once()
|
||||
fileManager := &filesMocks.FileManager{}
|
||||
mockCtrl := gomock.NewController(t)
|
||||
defer mockCtrl.Finish()
|
||||
logger := mock_logging.NewMockLogger(mockCtrl)
|
||||
logger.EXPECT().Info("downloading root hints from %s", constants.NamedRootURL).Times(1)
|
||||
client := mock_network.NewMockClient(mockCtrl)
|
||||
client.EXPECT().GetContent(string(constants.NamedRootURL)).
|
||||
Return(tc.content, tc.status, tc.clientErr).Times(1)
|
||||
fileManager := mock_files.NewMockFileManager(mockCtrl)
|
||||
if tc.clientErr == nil && tc.status == http.StatusOK {
|
||||
fileManager.On(
|
||||
"WriteToFile",
|
||||
fileManager.EXPECT().WriteToFile(
|
||||
string(constants.RootHints),
|
||||
tc.content,
|
||||
mock.AnythingOfType("files.WriteOptionSetter"),
|
||||
mock.AnythingOfType("files.WriteOptionSetter")).
|
||||
Return(tc.writeErr).Once()
|
||||
gomock.AssignableToTypeOf(files.Ownership(0, 0)),
|
||||
gomock.AssignableToTypeOf(files.Ownership(0, 0))).
|
||||
Return(tc.writeErr).Times(1)
|
||||
}
|
||||
c := &configurator{logger: logger, client: client, fileManager: fileManager}
|
||||
err := c.DownloadRootHints(1000, 1000)
|
||||
@@ -72,14 +74,11 @@ func Test_DownloadRootHints(t *testing.T) {
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
logger.AssertExpectations(t)
|
||||
client.AssertExpectations(t)
|
||||
fileManager.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_DownloadRootKey(t *testing.T) {
|
||||
func Test_DownloadRootKey(t *testing.T) { //nolint:dupl
|
||||
t.Parallel()
|
||||
tests := map[string]struct {
|
||||
content []byte
|
||||
@@ -113,20 +112,21 @@ func Test_DownloadRootKey(t *testing.T) {
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
logger := &loggingMocks.Logger{}
|
||||
logger.On("Info", "%s: downloading root key from %s", logPrefix, constants.RootKeyURL).Once()
|
||||
client := &networkMocks.Client{}
|
||||
client.On("GetContent", string(constants.RootKeyURL)).
|
||||
Return(tc.content, tc.status, tc.clientErr).Once()
|
||||
fileManager := &filesMocks.FileManager{}
|
||||
mockCtrl := gomock.NewController(t)
|
||||
defer mockCtrl.Finish()
|
||||
logger := mock_logging.NewMockLogger(mockCtrl)
|
||||
logger.EXPECT().Info("downloading root key from %s", constants.RootKeyURL).Times(1)
|
||||
client := mock_network.NewMockClient(mockCtrl)
|
||||
client.EXPECT().GetContent(string(constants.RootKeyURL)).
|
||||
Return(tc.content, tc.status, tc.clientErr).Times(1)
|
||||
fileManager := mock_files.NewMockFileManager(mockCtrl)
|
||||
if tc.clientErr == nil && tc.status == http.StatusOK {
|
||||
fileManager.On(
|
||||
"WriteToFile",
|
||||
fileManager.EXPECT().WriteToFile(
|
||||
string(constants.RootKey),
|
||||
tc.content,
|
||||
mock.AnythingOfType("files.WriteOptionSetter"),
|
||||
mock.AnythingOfType("files.WriteOptionSetter"),
|
||||
).Return(tc.writeErr).Once()
|
||||
gomock.AssignableToTypeOf(files.Ownership(0, 0)),
|
||||
gomock.AssignableToTypeOf(files.Ownership(0, 0)),
|
||||
).Return(tc.writeErr).Times(1)
|
||||
}
|
||||
c := &configurator{logger: logger, client: client, fileManager: fileManager}
|
||||
err := c.DownloadRootKey(1000, 1001)
|
||||
@@ -136,9 +136,6 @@ func Test_DownloadRootKey(t *testing.T) {
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
logger.AssertExpectations(t)
|
||||
client.AssertExpectations(t)
|
||||
fileManager.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,14 @@ import (
|
||||
func (c *configurator) WaitForUnbound() (err error) {
|
||||
const maxTries = 10
|
||||
const hostToResolve = "github.com"
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
for try := 1; try <= maxTries; try++ {
|
||||
_, err := c.lookupIP(hostToResolve)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
c.logger.Warn("could not resolve %s (try %d of %d)", hostToResolve, try, maxTries)
|
||||
time.Sleep(time.Duration(maxTries * 50 * time.Millisecond))
|
||||
c.logger.Warn("could not resolve %s (try %d of %d): %s", hostToResolve, try, maxTries, err)
|
||||
time.Sleep(maxTries * 50 * time.Millisecond)
|
||||
}
|
||||
return fmt.Errorf("Unbound does not seem to be working after %d tries", maxTries)
|
||||
}
|
||||
|
||||
40
internal/env/env.go
vendored
40
internal/env/env.go
vendored
@@ -1,40 +0,0 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/qdm12/golibs/logging"
|
||||
)
|
||||
|
||||
type Env interface {
|
||||
FatalOnError(err error)
|
||||
PrintVersion(program string, commandFn func() (string, error))
|
||||
}
|
||||
|
||||
type env struct {
|
||||
logger logging.Logger
|
||||
osExit func(n int)
|
||||
}
|
||||
|
||||
func New(logger logging.Logger) Env {
|
||||
return &env{
|
||||
logger: logger,
|
||||
osExit: os.Exit,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *env) FatalOnError(err error) {
|
||||
if err != nil {
|
||||
e.logger.Error(err)
|
||||
e.osExit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *env) PrintVersion(program string, commandFn func() (string, error)) {
|
||||
version, err := commandFn()
|
||||
if err != nil {
|
||||
e.logger.Error(err)
|
||||
} else {
|
||||
e.logger.Info("%s version: %s", program, version)
|
||||
}
|
||||
}
|
||||
90
internal/env/env_test.go
vendored
90
internal/env/env_test.go
vendored
@@ -1,90 +0,0 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/qdm12/golibs/logging/mocks"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
func Test_FatalOnError(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := map[string]struct {
|
||||
err error
|
||||
}{
|
||||
"nil": {},
|
||||
"err": {fmt.Errorf("error")},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
var logged string
|
||||
var exitCode int
|
||||
logger := &mocks.Logger{}
|
||||
if tc.err != nil {
|
||||
logger.On("Error", tc.err).
|
||||
Run(func(args mock.Arguments) {
|
||||
err := args.Get(0).(error)
|
||||
logged = err.Error()
|
||||
}).Once()
|
||||
}
|
||||
osExit := func(n int) { exitCode = n }
|
||||
e := &env{logger, osExit}
|
||||
e.FatalOnError(tc.err)
|
||||
if tc.err != nil {
|
||||
assert.Equal(t, logged, tc.err.Error())
|
||||
assert.Equal(t, exitCode, 1)
|
||||
} else {
|
||||
assert.Empty(t, logged)
|
||||
assert.Zero(t, exitCode)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_PrintVersion(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := map[string]struct {
|
||||
program string
|
||||
commandVersion string
|
||||
commandErr error
|
||||
}{
|
||||
"no data": {},
|
||||
"data": {"binu", "2.3-5", nil},
|
||||
"error": {"binu", "", fmt.Errorf("error")},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
var logged string
|
||||
logger := &mocks.Logger{}
|
||||
if tc.commandErr != nil {
|
||||
logger.On("Error", tc.commandErr).
|
||||
Run(func(args mock.Arguments) {
|
||||
err := args.Get(0).(error)
|
||||
logged = err.Error()
|
||||
}).Once()
|
||||
} else {
|
||||
logger.On("Info", "%s version: %s", tc.program, tc.commandVersion).
|
||||
Run(func(args mock.Arguments) {
|
||||
format := args.Get(0).(string)
|
||||
program := args.Get(1).(string)
|
||||
version := args.Get(2).(string)
|
||||
logged = fmt.Sprintf(format, program, version)
|
||||
}).Once()
|
||||
}
|
||||
e := &env{logger: logger}
|
||||
commandFn := func() (string, error) { return tc.commandVersion, tc.commandErr }
|
||||
e.PrintVersion(tc.program, commandFn)
|
||||
if tc.commandErr != nil {
|
||||
assert.Equal(t, logged, tc.commandErr.Error())
|
||||
} else {
|
||||
assert.Equal(t, logged, fmt.Sprintf("%s version: %s", tc.program, tc.commandVersion))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
151
internal/firewall/enable.go
Normal file
151
internal/firewall/enable.go
Normal file
@@ -0,0 +1,151 @@
|
||||
package firewall
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
)
|
||||
|
||||
func (c *configurator) SetEnabled(ctx context.Context, enabled bool) (err error) {
|
||||
c.stateMutex.Lock()
|
||||
defer c.stateMutex.Unlock()
|
||||
|
||||
if enabled == c.enabled {
|
||||
if enabled {
|
||||
c.logger.Info("already enabled")
|
||||
} else {
|
||||
c.logger.Info("already disabled")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if !enabled {
|
||||
c.logger.Info("disabling...")
|
||||
if err = c.disable(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
c.enabled = false
|
||||
c.logger.Info("disabled successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
c.logger.Info("enabling...")
|
||||
|
||||
if err := c.enable(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
c.enabled = true
|
||||
c.logger.Info("enabled successfully")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *configurator) disable(ctx context.Context) (err error) {
|
||||
if err = c.clearAllRules(ctx); err != nil {
|
||||
return fmt.Errorf("cannot disable firewall: %w", err)
|
||||
}
|
||||
if err = c.setAllPolicies(ctx, "ACCEPT"); err != nil {
|
||||
return fmt.Errorf("cannot disable firewall: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// To use in defered call when enabling the firewall
|
||||
func (c *configurator) fallbackToDisabled(ctx context.Context) {
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
if err := c.SetEnabled(ctx, false); err != nil {
|
||||
c.logger.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *configurator) enable(ctx context.Context) (err error) { //nolint:gocognit
|
||||
defaultInterface, defaultGateway, err := c.routing.DefaultRoute()
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
localSubnet, err := c.routing.LocalSubnet()
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
|
||||
if err = c.setAllPolicies(ctx, "DROP"); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
|
||||
const remove = false
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
c.fallbackToDisabled(ctx)
|
||||
}
|
||||
}()
|
||||
|
||||
// Loopback traffic
|
||||
if err = c.acceptInputThroughInterface(ctx, "lo", remove); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
if err = c.acceptOutputThroughInterface(ctx, "lo", remove); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
|
||||
if err = c.acceptEstablishedRelatedTraffic(ctx, remove); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
for _, conn := range c.vpnConnections {
|
||||
if err = c.acceptOutputTrafficToVPN(ctx, defaultInterface, conn, remove); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
}
|
||||
if err = c.acceptOutputThroughInterface(ctx, string(constants.TUN), remove); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
if err := c.acceptInputFromSubnetToSubnet(ctx, "*", localSubnet, localSubnet, remove); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
if err := c.acceptOutputFromSubnetToSubnet(ctx, "*", localSubnet, localSubnet, remove); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
for _, subnet := range c.allowedSubnets {
|
||||
if err := c.acceptInputFromSubnetToSubnet(ctx, defaultInterface, subnet, localSubnet, remove); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
if err := c.acceptOutputFromSubnetToSubnet(ctx, defaultInterface, localSubnet, subnet, remove); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
}
|
||||
// Re-ensure all routes exist
|
||||
for _, subnet := range c.allowedSubnets {
|
||||
if err := c.routing.AddRouteVia(ctx, subnet, defaultGateway, defaultInterface); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
for port := range c.allowedPorts {
|
||||
// TODO restrict interface
|
||||
if err := c.acceptInputToPort(ctx, "*", constants.TCP, port, remove); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
if err := c.acceptInputToPort(ctx, "*", constants.UDP, port, remove); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if c.portForwarded > 0 {
|
||||
const tun = string(constants.TUN)
|
||||
if err := c.acceptInputToPort(ctx, tun, constants.TCP, c.portForwarded, remove); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
if err := c.acceptInputToPort(ctx, tun, constants.UDP, c.portForwarded, remove); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := c.runUserPostRules(ctx, "/iptables/post-rules.txt", remove); err != nil {
|
||||
return fmt.Errorf("cannot enable firewall: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,43 +1,57 @@
|
||||
package firewall
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/qdm12/golibs/command"
|
||||
"github.com/qdm12/golibs/files"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/routing"
|
||||
)
|
||||
|
||||
const logPrefix = "firewall configurator"
|
||||
|
||||
// Configurator allows to change firewall rules and modify network routes
|
||||
type Configurator interface {
|
||||
Version() (string, error)
|
||||
AcceptAll() error
|
||||
Clear() error
|
||||
BlockAll() error
|
||||
CreateGeneralRules() error
|
||||
CreateVPNRules(dev models.VPNDevice, serverIPs []net.IP, defaultInterface string,
|
||||
port uint16, protocol models.NetworkProtocol) 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)
|
||||
AllowInputTrafficOnPort(device models.VPNDevice, port uint16) error
|
||||
AllowAnyIncomingOnPort(port uint16) error
|
||||
Version(ctx context.Context) (string, error)
|
||||
SetEnabled(ctx context.Context, enabled bool) (err error)
|
||||
SetVPNConnections(ctx context.Context, connections []models.OpenVPNConnection) (err error)
|
||||
SetAllowedSubnets(ctx context.Context, subnets []net.IPNet) (err error)
|
||||
SetAllowedPort(ctx context.Context, port uint16) error
|
||||
RemoveAllowedPort(ctx context.Context, port uint16) (err error)
|
||||
SetPortForward(ctx context.Context, port uint16) (err error)
|
||||
SetDebug()
|
||||
}
|
||||
|
||||
type configurator struct {
|
||||
commander command.Commander
|
||||
logger logging.Logger
|
||||
fileManager files.FileManager
|
||||
type configurator struct { //nolint:maligned
|
||||
commander command.Commander
|
||||
logger logging.Logger
|
||||
routing routing.Routing
|
||||
fileManager files.FileManager // for custom iptables rules
|
||||
iptablesMutex sync.Mutex
|
||||
debug bool
|
||||
|
||||
// State
|
||||
enabled bool
|
||||
vpnConnections []models.OpenVPNConnection
|
||||
allowedSubnets []net.IPNet
|
||||
allowedPorts map[uint16]struct{}
|
||||
portForwarded uint16
|
||||
stateMutex sync.Mutex
|
||||
}
|
||||
|
||||
// NewConfigurator creates a new Configurator instance
|
||||
func NewConfigurator(logger logging.Logger, fileManager files.FileManager) Configurator {
|
||||
func NewConfigurator(logger logging.Logger, routing routing.Routing, fileManager files.FileManager) Configurator {
|
||||
return &configurator{
|
||||
commander: command.NewCommander(),
|
||||
logger: logger,
|
||||
fileManager: fileManager,
|
||||
commander: command.NewCommander(),
|
||||
logger: logger.WithPrefix("firewall: "),
|
||||
routing: routing,
|
||||
fileManager: fileManager,
|
||||
allowedPorts: make(map[uint16]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *configurator) SetDebug() {
|
||||
c.debug = true
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package firewall
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
@@ -8,9 +9,32 @@ import (
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
func appendOrDelete(remove bool) string {
|
||||
if remove {
|
||||
return "--delete"
|
||||
}
|
||||
return "--append"
|
||||
}
|
||||
|
||||
// flipRule changes an append rule in a delete rule or a delete rule into an
|
||||
// append rule.
|
||||
func flipRule(rule string) string {
|
||||
switch {
|
||||
case strings.HasPrefix(rule, "-A"):
|
||||
return strings.Replace(rule, "-A", "-D", 1)
|
||||
case strings.HasPrefix(rule, "--append"):
|
||||
return strings.Replace(rule, "--append", "-D", 1)
|
||||
case strings.HasPrefix(rule, "-D"):
|
||||
return strings.Replace(rule, "-D", "-A", 1)
|
||||
case strings.HasPrefix(rule, "--delete"):
|
||||
return strings.Replace(rule, "--delete", "-A", 1)
|
||||
}
|
||||
return rule
|
||||
}
|
||||
|
||||
// Version obtains the version of the installed iptables
|
||||
func (c *configurator) Version() (string, error) {
|
||||
output, err := c.commander.Run("iptables", "--version")
|
||||
func (c *configurator) Version(ctx context.Context) (string, error) {
|
||||
output, err := c.commander.Run(ctx, "iptables", "--version")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -21,118 +45,139 @@ func (c *configurator) Version() (string, error) {
|
||||
return words[1], nil
|
||||
}
|
||||
|
||||
func (c *configurator) runIptablesInstructions(instructions []string) error {
|
||||
func (c *configurator) runIptablesInstructions(ctx context.Context, instructions []string) error {
|
||||
for _, instruction := range instructions {
|
||||
if err := c.runIptablesInstruction(instruction); err != nil {
|
||||
if err := c.runIptablesInstruction(ctx, instruction); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *configurator) runIptablesInstruction(instruction string) error {
|
||||
func (c *configurator) runIptablesInstruction(ctx context.Context, instruction string) error {
|
||||
c.iptablesMutex.Lock() // only one iptables command at once
|
||||
defer c.iptablesMutex.Unlock()
|
||||
if c.debug {
|
||||
fmt.Printf("iptables %s\n", instruction)
|
||||
}
|
||||
flags := strings.Fields(instruction)
|
||||
if output, err := c.commander.Run("iptables", flags...); err != nil {
|
||||
return fmt.Errorf("failed executing %q: %s: %w", instruction, output, err)
|
||||
if output, err := c.commander.Run(ctx, "iptables", flags...); err != nil {
|
||||
return fmt.Errorf("failed executing \"iptables %s\": %s: %w", instruction, output, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *configurator) Clear() error {
|
||||
c.logger.Info("%s: clearing all rules", logPrefix)
|
||||
return c.runIptablesInstructions([]string{
|
||||
"--flush",
|
||||
"--delete-chain",
|
||||
"-t nat --flush",
|
||||
"-t nat --delete-chain",
|
||||
func (c *configurator) clearAllRules(ctx context.Context) error {
|
||||
return c.runIptablesInstructions(ctx, []string{
|
||||
"--flush", // flush all chains
|
||||
"--delete-chain", // delete all chains
|
||||
})
|
||||
}
|
||||
|
||||
func (c *configurator) AcceptAll() error {
|
||||
c.logger.Info("%s: accepting all traffic", logPrefix)
|
||||
return c.runIptablesInstructions([]string{
|
||||
"-P INPUT ACCEPT",
|
||||
"-P OUTPUT ACCEPT",
|
||||
"-P FORWARD ACCEPT",
|
||||
})
|
||||
}
|
||||
|
||||
func (c *configurator) BlockAll() error {
|
||||
c.logger.Info("%s: blocking all traffic", logPrefix)
|
||||
return c.runIptablesInstructions([]string{
|
||||
"-P INPUT DROP",
|
||||
"-F OUTPUT",
|
||||
"-P OUTPUT DROP",
|
||||
"-P FORWARD DROP",
|
||||
})
|
||||
}
|
||||
|
||||
func (c *configurator) CreateGeneralRules() error {
|
||||
c.logger.Info("%s: creating general rules", logPrefix)
|
||||
return c.runIptablesInstructions([]string{
|
||||
"-A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT",
|
||||
"-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT",
|
||||
"-A OUTPUT -o lo -j ACCEPT",
|
||||
"-A INPUT -i lo -j ACCEPT",
|
||||
})
|
||||
}
|
||||
|
||||
func (c *configurator) CreateVPNRules(dev models.VPNDevice, serverIPs []net.IP,
|
||||
defaultInterface string, port uint16, protocol models.NetworkProtocol) error {
|
||||
for _, serverIP := range serverIPs {
|
||||
c.logger.Info("%s: allowing output traffic to VPN server %s through %s on port %s %d",
|
||||
logPrefix, serverIP, defaultInterface, protocol, 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 {
|
||||
return err
|
||||
}
|
||||
func (c *configurator) setAllPolicies(ctx context.Context, policy string) error {
|
||||
switch policy {
|
||||
case "ACCEPT", "DROP":
|
||||
default:
|
||||
return fmt.Errorf("policy %q not recognized", policy)
|
||||
}
|
||||
if err := c.runIptablesInstruction(fmt.Sprintf("-A OUTPUT -o %s -j ACCEPT", dev)); err != nil {
|
||||
return c.runIptablesInstructions(ctx, []string{
|
||||
fmt.Sprintf("--policy INPUT %s", policy),
|
||||
fmt.Sprintf("--policy OUTPUT %s", policy),
|
||||
fmt.Sprintf("--policy FORWARD %s", policy),
|
||||
})
|
||||
}
|
||||
|
||||
func (c *configurator) acceptInputThroughInterface(ctx context.Context, intf string, remove bool) error {
|
||||
return c.runIptablesInstruction(ctx, fmt.Sprintf(
|
||||
"%s INPUT -i %s -j ACCEPT", appendOrDelete(remove), intf,
|
||||
))
|
||||
}
|
||||
|
||||
func (c *configurator) acceptOutputThroughInterface(ctx context.Context, intf string, remove bool) error {
|
||||
return c.runIptablesInstruction(ctx, fmt.Sprintf(
|
||||
"%s OUTPUT -o %s -j ACCEPT", appendOrDelete(remove), intf,
|
||||
))
|
||||
}
|
||||
|
||||
func (c *configurator) acceptEstablishedRelatedTraffic(ctx context.Context, remove bool) error {
|
||||
return c.runIptablesInstructions(ctx, []string{
|
||||
fmt.Sprintf("%s OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT", appendOrDelete(remove)),
|
||||
fmt.Sprintf("%s INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT", appendOrDelete(remove)),
|
||||
})
|
||||
}
|
||||
|
||||
func (c *configurator) acceptOutputTrafficToVPN(ctx context.Context, defaultInterface string, connection models.OpenVPNConnection, remove bool) error {
|
||||
return c.runIptablesInstruction(ctx,
|
||||
fmt.Sprintf("%s OUTPUT -d %s -o %s -p %s -m %s --dport %d -j ACCEPT",
|
||||
appendOrDelete(remove), connection.IP, defaultInterface, connection.Protocol, connection.Protocol, connection.Port))
|
||||
}
|
||||
|
||||
func (c *configurator) acceptInputFromSubnetToSubnet(ctx context.Context, intf string, sourceSubnet, destinationSubnet net.IPNet, remove bool) error {
|
||||
interfaceFlag := "-i " + intf
|
||||
if intf == "*" { // all interfaces
|
||||
interfaceFlag = ""
|
||||
}
|
||||
return c.runIptablesInstruction(ctx, fmt.Sprintf(
|
||||
"%s INPUT %s -s %s -d %s -j ACCEPT", appendOrDelete(remove), interfaceFlag, sourceSubnet.String(), destinationSubnet.String(),
|
||||
))
|
||||
}
|
||||
|
||||
// Thanks to @npawelek
|
||||
func (c *configurator) acceptOutputFromSubnetToSubnet(ctx context.Context, intf string, sourceSubnet, destinationSubnet net.IPNet, remove bool) error {
|
||||
interfaceFlag := "-o " + intf
|
||||
if intf == "*" { // all interfaces
|
||||
interfaceFlag = ""
|
||||
}
|
||||
return c.runIptablesInstruction(ctx, fmt.Sprintf(
|
||||
"%s OUTPUT %s -s %s -d %s -j ACCEPT", appendOrDelete(remove), interfaceFlag, sourceSubnet.String(), destinationSubnet.String(),
|
||||
))
|
||||
}
|
||||
|
||||
// Used for port forwarding, with intf set to tun
|
||||
func (c *configurator) acceptInputToPort(ctx context.Context, intf string, protocol models.NetworkProtocol, port uint16, remove bool) error {
|
||||
interfaceFlag := "-i " + intf
|
||||
if intf == "*" { // all interfaces
|
||||
interfaceFlag = ""
|
||||
}
|
||||
return c.runIptablesInstruction(ctx,
|
||||
fmt.Sprintf("%s INPUT %s -p %s --dport %d -j ACCEPT", appendOrDelete(remove), interfaceFlag, protocol, port),
|
||||
)
|
||||
}
|
||||
|
||||
func (c *configurator) runUserPostRules(ctx context.Context, filepath string, remove bool) error {
|
||||
exists, err := c.fileManager.FileExists(filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
return nil
|
||||
}
|
||||
b, err := c.fileManager.ReadFile(filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *configurator) CreateLocalSubnetsRules(subnet net.IPNet, extraSubnets []net.IPNet, defaultInterface string) error {
|
||||
subnetStr := subnet.String()
|
||||
c.logger.Info("%s: accepting input and output traffic for %s", logPrefix, subnetStr)
|
||||
if err := c.runIptablesInstructions([]string{
|
||||
fmt.Sprintf("-A INPUT -s %s -d %s -j ACCEPT", subnetStr, subnetStr),
|
||||
fmt.Sprintf("-A OUTPUT -s %s -d %s -j ACCEPT", subnetStr, subnetStr),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, extraSubnet := range extraSubnets {
|
||||
extraSubnetStr := extraSubnet.String()
|
||||
c.logger.Info("%s: accepting input traffic through %s from %s to %s", logPrefix, defaultInterface, extraSubnetStr, subnetStr)
|
||||
if err := c.runIptablesInstruction(
|
||||
fmt.Sprintf("-A INPUT -i %s -s %s -d %s -j ACCEPT", defaultInterface, extraSubnetStr, subnetStr)); err != nil {
|
||||
return err
|
||||
lines := strings.Split(string(b), "\n")
|
||||
successfulRules := []string{}
|
||||
defer func() {
|
||||
// transaction-like rollback
|
||||
if err == nil || ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
// Thanks to @npawelek
|
||||
c.logger.Info("%s: accepting output traffic through %s from %s to %s", logPrefix, defaultInterface, subnetStr, extraSubnetStr)
|
||||
if err := c.runIptablesInstruction(
|
||||
fmt.Sprintf("-A OUTPUT -o %s -s %s -d %s -j ACCEPT", defaultInterface, subnetStr, extraSubnetStr)); err != nil {
|
||||
return err
|
||||
for _, rule := range successfulRules {
|
||||
_ = c.runIptablesInstruction(ctx, flipRule(rule))
|
||||
}
|
||||
}()
|
||||
for _, line := range lines {
|
||||
if !strings.HasPrefix(line, "iptables ") {
|
||||
continue
|
||||
}
|
||||
rule := strings.TrimPrefix(line, "iptables ")
|
||||
if remove {
|
||||
rule = flipRule(rule)
|
||||
}
|
||||
if err = c.runIptablesInstruction(ctx, rule); err != nil {
|
||||
return fmt.Errorf("cannot run custom rule: %w", err)
|
||||
}
|
||||
successfulRules = append(successfulRules, rule)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Used for port forwarding
|
||||
func (c *configurator) AllowInputTrafficOnPort(device models.VPNDevice, port uint16) error {
|
||||
c.logger.Info("%s: accepting input traffic through %s on port %d", logPrefix, device, port)
|
||||
return c.runIptablesInstructions([]string{
|
||||
fmt.Sprintf("-A INPUT -i %s -p tcp --dport %d -j ACCEPT", device, port),
|
||||
fmt.Sprintf("-A INPUT -i %s -p udp --dport %d -j ACCEPT", device, port),
|
||||
})
|
||||
}
|
||||
|
||||
func (c *configurator) AllowAnyIncomingOnPort(port uint16) error {
|
||||
c.logger.Info("%s: accepting any input traffic on port %d", logPrefix, port)
|
||||
return c.runIptablesInstructions([]string{
|
||||
fmt.Sprintf("-A INPUT -p tcp --dport %d -j ACCEPT", port),
|
||||
fmt.Sprintf("-A INPUT -p udp --dport %d -j ACCEPT", port),
|
||||
})
|
||||
}
|
||||
|
||||
111
internal/firewall/ports.go
Normal file
111
internal/firewall/ports.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package firewall
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
)
|
||||
|
||||
func (c *configurator) SetAllowedPort(ctx context.Context, port uint16) (err error) {
|
||||
c.stateMutex.Lock()
|
||||
defer c.stateMutex.Unlock()
|
||||
|
||||
if port == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !c.enabled {
|
||||
c.logger.Info("firewall disabled, only updating allowed ports internal list")
|
||||
c.allowedPorts[port] = struct{}{}
|
||||
return nil
|
||||
}
|
||||
|
||||
c.logger.Info("setting allowed port %d through firewall...", port)
|
||||
|
||||
if _, ok := c.allowedPorts[port]; ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
const remove = false
|
||||
if err := c.acceptInputToPort(ctx, "*", constants.TCP, port, remove); err != nil {
|
||||
return fmt.Errorf("cannot set allowed port %d through firewall: %w", port, err)
|
||||
}
|
||||
if err := c.acceptInputToPort(ctx, "*", constants.UDP, port, remove); err != nil {
|
||||
return fmt.Errorf("cannot set allowed port %d through firewall: %w", port, err)
|
||||
}
|
||||
c.allowedPorts[port] = struct{}{}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *configurator) RemoveAllowedPort(ctx context.Context, port uint16) (err error) {
|
||||
c.stateMutex.Lock()
|
||||
defer c.stateMutex.Unlock()
|
||||
|
||||
if port == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !c.enabled {
|
||||
c.logger.Info("firewall disabled, only updating allowed ports internal list")
|
||||
delete(c.allowedPorts, port)
|
||||
return nil
|
||||
}
|
||||
|
||||
c.logger.Info("removing allowed port %d through firewall...", port)
|
||||
|
||||
if _, ok := c.allowedPorts[port]; !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
const remove = true
|
||||
if err := c.acceptInputToPort(ctx, "*", constants.TCP, port, remove); err != nil {
|
||||
return fmt.Errorf("cannot remove allowed port %d through firewall: %w", port, err)
|
||||
}
|
||||
if err := c.acceptInputToPort(ctx, "*", constants.UDP, port, remove); err != nil {
|
||||
return fmt.Errorf("cannot remove allowed port %d through firewall: %w", port, err)
|
||||
}
|
||||
delete(c.allowedPorts, port)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Use 0 to remove
|
||||
func (c *configurator) SetPortForward(ctx context.Context, port uint16) (err error) {
|
||||
c.stateMutex.Lock()
|
||||
defer c.stateMutex.Unlock()
|
||||
|
||||
if port == c.portForwarded {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !c.enabled {
|
||||
c.logger.Info("firewall disabled, only updating port forwarded internally")
|
||||
c.portForwarded = port
|
||||
return nil
|
||||
}
|
||||
|
||||
const tun = string(constants.TUN)
|
||||
if c.portForwarded > 0 {
|
||||
if err := c.acceptInputToPort(ctx, tun, constants.TCP, c.portForwarded, true); err != nil {
|
||||
return fmt.Errorf("cannot remove outdated port forward rule from firewall: %w", err)
|
||||
}
|
||||
if err := c.acceptInputToPort(ctx, tun, constants.UDP, c.portForwarded, true); err != nil {
|
||||
return fmt.Errorf("cannot remove outdated port forward rule from firewall: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if port == 0 { // not changing port
|
||||
c.portForwarded = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := c.acceptInputToPort(ctx, tun, constants.TCP, port, false); err != nil {
|
||||
return fmt.Errorf("cannot accept port forwarded through firewall: %w", err)
|
||||
}
|
||||
if err := c.acceptInputToPort(ctx, tun, constants.UDP, port, false); err != nil {
|
||||
return fmt.Errorf("cannot accept port forwarded through firewall: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package firewall
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"net"
|
||||
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
)
|
||||
|
||||
func (c *configurator) AddRoutesVia(subnets []net.IPNet, defaultGateway net.IP, defaultInterface string) error {
|
||||
for _, subnet := range subnets {
|
||||
subnetStr := subnet.String()
|
||||
output, err := c.commander.Run("ip", "route", "show", subnetStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot read route %s: %s: %w", subnetStr, output, err)
|
||||
} else if len(output) > 0 { // thanks to @npawelek https://github.com/npawelek
|
||||
continue // already exists
|
||||
// TODO remove it instead and continue execution below
|
||||
}
|
||||
c.logger.Info("%s: adding %s as route via %s", logPrefix, subnetStr, defaultInterface)
|
||||
output, err = c.commander.Run("ip", "route", "add", subnetStr, "via", defaultGateway.String(), "dev", defaultInterface)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot add route for %s via %s %s %s: %s: %w", subnetStr, defaultGateway.String(), "dev", defaultInterface, output, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *configurator) GetDefaultRoute() (defaultInterface string, defaultGateway net.IP, defaultSubnet net.IPNet, err error) {
|
||||
c.logger.Info("%s: detecting default network route", logPrefix)
|
||||
data, err := c.fileManager.ReadFile(string(constants.NetRoute))
|
||||
if err != nil {
|
||||
return "", nil, defaultSubnet, err
|
||||
}
|
||||
// Verify number of lines and fields
|
||||
lines := strings.Split(string(data), "\n")
|
||||
if len(lines) < 3 {
|
||||
return "", nil, defaultSubnet, fmt.Errorf("not enough lines (%d) found in %s", len(lines), constants.NetRoute)
|
||||
}
|
||||
fieldsLine1 := strings.Fields(lines[1])
|
||||
if len(fieldsLine1) < 3 {
|
||||
return "", nil, defaultSubnet, fmt.Errorf("not enough fields in %q", lines[1])
|
||||
}
|
||||
fieldsLine2 := strings.Fields(lines[2])
|
||||
if len(fieldsLine2) < 8 {
|
||||
return "", nil, defaultSubnet, fmt.Errorf("not enough fields in %q", lines[2])
|
||||
}
|
||||
// get information
|
||||
defaultInterface = fieldsLine1[0]
|
||||
defaultGateway, err = reversedHexToIPv4(fieldsLine1[2])
|
||||
if err != nil {
|
||||
return "", nil, defaultSubnet, err
|
||||
}
|
||||
netNumber, err := reversedHexToIPv4(fieldsLine2[1])
|
||||
if err != nil {
|
||||
return "", nil, defaultSubnet, err
|
||||
}
|
||||
netMask, err := hexToIPv4Mask(fieldsLine2[7])
|
||||
if err != nil {
|
||||
return "", nil, defaultSubnet, err
|
||||
}
|
||||
subnet := net.IPNet{IP: netNumber, Mask: netMask}
|
||||
c.logger.Info("%s: default route found: interface %s, gateway %s, subnet %s", logPrefix, defaultInterface, defaultGateway.String(), subnet.String())
|
||||
return defaultInterface, defaultGateway, subnet, nil
|
||||
}
|
||||
|
||||
func reversedHexToIPv4(reversedHex string) (IP net.IP, err error) {
|
||||
bytes, err := hex.DecodeString(reversedHex)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse reversed IP hex %q: %s", reversedHex, err)
|
||||
} else if len(bytes) != 4 {
|
||||
return nil, fmt.Errorf("hex string contains %d bytes instead of 4", len(bytes))
|
||||
}
|
||||
return []byte{bytes[3], bytes[2], bytes[1], bytes[0]}, nil
|
||||
}
|
||||
|
||||
func hexToIPv4Mask(hexString string) (mask net.IPMask, err error) {
|
||||
bytes, err := hex.DecodeString(hexString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse hex mask %q: %s", hexString, err)
|
||||
} else if len(bytes) != 4 {
|
||||
return nil, fmt.Errorf("hex string contains %d bytes instead of 4", len(bytes))
|
||||
}
|
||||
return []byte{bytes[3], bytes[2], bytes[1], bytes[0]}, nil
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
package firewall
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
filesmocks "github.com/qdm12/golibs/files/mocks"
|
||||
loggingmocks "github.com/qdm12/golibs/logging/mocks"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
)
|
||||
|
||||
func Test_getDefaultRoute(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := map[string]struct {
|
||||
data []byte
|
||||
readErr error
|
||||
defaultInterface string
|
||||
defaultGateway net.IP
|
||||
defaultSubnet net.IPNet
|
||||
err error
|
||||
}{
|
||||
"no data": {
|
||||
err: fmt.Errorf("not enough lines (1) found in %s", constants.NetRoute)},
|
||||
"read error": {
|
||||
readErr: fmt.Errorf("error"),
|
||||
err: fmt.Errorf("error")},
|
||||
"not enough fields line 1": {
|
||||
data: []byte(`Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
|
||||
eth0 00000000
|
||||
eth0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0`),
|
||||
err: fmt.Errorf("not enough fields in \"eth0 00000000\"")},
|
||||
"not enough fields line 2": {
|
||||
data: []byte(`Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
|
||||
eth0 00000000 010011AC 0003 0 0 0 00000000 0 0 0
|
||||
eth0 000011AC 00000000 0001 0 0 0`),
|
||||
err: fmt.Errorf("not enough fields in \"eth0 000011AC 00000000 0001 0 0 0\"")},
|
||||
"bad gateway": {
|
||||
data: []byte(`Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
|
||||
eth0 00000000 x 0003 0 0 0 00000000 0 0 0
|
||||
eth0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0`),
|
||||
err: fmt.Errorf("cannot parse reversed IP hex \"x\": encoding/hex: invalid byte: U+0078 'x'")},
|
||||
"bad net number": {
|
||||
data: []byte(`Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
|
||||
eth0 00000000 010011AC 0003 0 0 0 00000000 0 0 0
|
||||
eth0 x 00000000 0001 0 0 0 0000FFFF 0 0 0`),
|
||||
err: fmt.Errorf("cannot parse reversed IP hex \"x\": encoding/hex: invalid byte: U+0078 'x'")},
|
||||
"bad net mask": {
|
||||
data: []byte(`Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
|
||||
eth0 00000000 010011AC 0003 0 0 0 00000000 0 0 0
|
||||
eth0 000011AC 00000000 0001 0 0 0 x 0 0 0`),
|
||||
err: fmt.Errorf("cannot parse hex mask \"x\": encoding/hex: invalid byte: U+0078 'x'")},
|
||||
"success": {
|
||||
data: []byte(`Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
|
||||
eth0 00000000 010011AC 0003 0 0 0 00000000 0 0 0
|
||||
eth0 000011AC 00000000 0001 0 0 0 0000FFFF 0 0 0`),
|
||||
defaultInterface: "eth0",
|
||||
defaultGateway: net.IP{0xac, 0x11, 0x0, 0x1},
|
||||
defaultSubnet: net.IPNet{
|
||||
IP: net.IP{0xac, 0x11, 0x0, 0x0},
|
||||
Mask: net.IPMask{0xff, 0xff, 0x0, 0x0},
|
||||
}},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
fileManager := &filesmocks.FileManager{}
|
||||
fileManager.On("ReadFile", string(constants.NetRoute)).
|
||||
Return(tc.data, tc.readErr).Once()
|
||||
logger := &loggingmocks.Logger{}
|
||||
logger.On("Info", "%s: detecting default network route", logPrefix).Once()
|
||||
if tc.err == nil {
|
||||
logger.On("Info", "%s: default route found: interface %s, gateway %s, subnet %s",
|
||||
logPrefix, tc.defaultInterface, tc.defaultGateway.String(), tc.defaultSubnet.String()).Once()
|
||||
}
|
||||
c := &configurator{logger: logger, fileManager: fileManager}
|
||||
defaultInterface, defaultGateway, defaultSubnet, err := c.GetDefaultRoute()
|
||||
if tc.err != nil {
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, tc.err.Error(), err.Error())
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
assert.Equal(t, tc.defaultInterface, defaultInterface)
|
||||
assert.Equal(t, tc.defaultGateway, defaultGateway)
|
||||
assert.Equal(t, tc.defaultSubnet, defaultSubnet)
|
||||
fileManager.AssertExpectations(t)
|
||||
logger.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_reversedHexToIPv4(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := map[string]struct {
|
||||
reversedHex string
|
||||
IP net.IP
|
||||
err error
|
||||
}{
|
||||
"empty hex": {
|
||||
err: fmt.Errorf("hex string contains 0 bytes instead of 4")},
|
||||
"bad hex": {
|
||||
reversedHex: "x",
|
||||
err: fmt.Errorf("cannot parse reversed IP hex \"x\": encoding/hex: invalid byte: U+0078 'x'")},
|
||||
"3 bytes hex": {
|
||||
reversedHex: "9abcde",
|
||||
err: fmt.Errorf("hex string contains 3 bytes instead of 4")},
|
||||
"correct hex": {
|
||||
reversedHex: "010011AC",
|
||||
IP: []byte{0xac, 0x11, 0x0, 0x1},
|
||||
err: nil},
|
||||
"correct hex 2": {
|
||||
reversedHex: "000011AC",
|
||||
IP: []byte{0xac, 0x11, 0x0, 0x0},
|
||||
err: nil},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
IP, err := reversedHexToIPv4(tc.reversedHex)
|
||||
if tc.err != nil {
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, tc.err.Error(), err.Error())
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
assert.Equal(t, tc.IP, IP)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_hexMaskToDecMask(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := map[string]struct {
|
||||
hexString string
|
||||
mask net.IPMask
|
||||
err error
|
||||
}{
|
||||
"empty hex": {
|
||||
err: fmt.Errorf("hex string contains 0 bytes instead of 4")},
|
||||
"bad hex": {
|
||||
hexString: "x",
|
||||
err: fmt.Errorf("cannot parse hex mask \"x\": encoding/hex: invalid byte: U+0078 'x'")},
|
||||
"3 bytes hex": {
|
||||
hexString: "9abcde",
|
||||
err: fmt.Errorf("hex string contains 3 bytes instead of 4")},
|
||||
"16": {
|
||||
hexString: "0000FFFF",
|
||||
mask: []byte{0xff, 0xff, 0x0, 0x0},
|
||||
err: nil},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
mask, err := hexToIPv4Mask(tc.hexString)
|
||||
if tc.err != nil {
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, tc.err.Error(), err.Error())
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
assert.Equal(t, tc.mask, mask)
|
||||
})
|
||||
}
|
||||
}
|
||||
159
internal/firewall/subnets.go
Normal file
159
internal/firewall/subnets.go
Normal file
@@ -0,0 +1,159 @@
|
||||
package firewall
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
func (c *configurator) SetAllowedSubnets(ctx context.Context, subnets []net.IPNet) (err error) {
|
||||
c.stateMutex.Lock()
|
||||
defer c.stateMutex.Unlock()
|
||||
|
||||
if !c.enabled {
|
||||
c.logger.Info("firewall disabled, only updating allowed subnets internal list and updating routes")
|
||||
if err := c.updateSubnetRoutes(ctx, c.allowedSubnets, subnets); err != nil {
|
||||
return err
|
||||
}
|
||||
c.allowedSubnets = make([]net.IPNet, len(subnets))
|
||||
copy(c.allowedSubnets, subnets)
|
||||
return nil
|
||||
}
|
||||
|
||||
c.logger.Info("setting allowed subnets through firewall...")
|
||||
|
||||
subnetsToAdd := findSubnetsToAdd(c.allowedSubnets, subnets)
|
||||
subnetsToRemove := findSubnetsToRemove(c.allowedSubnets, subnets)
|
||||
if len(subnetsToAdd) == 0 && len(subnetsToRemove) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
defaultInterface, defaultGateway, err := c.routing.DefaultRoute()
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot set allowed subnets through firewall: %w", err)
|
||||
}
|
||||
localSubnet, err := c.routing.LocalSubnet()
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot set allowed subnets through firewall: %w", err)
|
||||
}
|
||||
|
||||
c.removeSubnets(ctx, subnetsToRemove, defaultInterface, localSubnet)
|
||||
if err := c.addSubnets(ctx, subnetsToAdd, defaultInterface, defaultGateway, localSubnet); err != nil {
|
||||
return fmt.Errorf("cannot set allowed subnets through firewall: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func findSubnetsToAdd(oldSubnets, newSubnets []net.IPNet) (subnetsToAdd []net.IPNet) {
|
||||
for _, newSubnet := range newSubnets {
|
||||
found := false
|
||||
for _, oldSubnet := range oldSubnets {
|
||||
if subnetsAreEqual(oldSubnet, newSubnet) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
subnetsToAdd = append(subnetsToAdd, newSubnet)
|
||||
}
|
||||
}
|
||||
return subnetsToAdd
|
||||
}
|
||||
|
||||
func findSubnetsToRemove(oldSubnets, newSubnets []net.IPNet) (subnetsToRemove []net.IPNet) {
|
||||
for _, oldSubnet := range oldSubnets {
|
||||
found := false
|
||||
for _, newSubnet := range newSubnets {
|
||||
if subnetsAreEqual(oldSubnet, newSubnet) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
subnetsToRemove = append(subnetsToRemove, oldSubnet)
|
||||
}
|
||||
}
|
||||
return subnetsToRemove
|
||||
}
|
||||
|
||||
func subnetsAreEqual(a, b net.IPNet) bool {
|
||||
return a.IP.Equal(b.IP) && a.Mask.String() == b.Mask.String()
|
||||
}
|
||||
|
||||
func removeSubnetFromSubnets(subnets []net.IPNet, subnet net.IPNet) []net.IPNet {
|
||||
L := len(subnets)
|
||||
for i := range subnets {
|
||||
if subnetsAreEqual(subnet, subnets[i]) {
|
||||
subnets[i] = subnets[L-1]
|
||||
subnets = subnets[:L-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
return subnets
|
||||
}
|
||||
|
||||
func (c *configurator) removeSubnets(ctx context.Context, subnets []net.IPNet, defaultInterface string,
|
||||
localSubnet net.IPNet) {
|
||||
const remove = true
|
||||
for _, subnet := range subnets {
|
||||
failed := false
|
||||
if err := c.acceptInputFromSubnetToSubnet(ctx, defaultInterface, subnet, localSubnet, remove); err != nil {
|
||||
failed = true
|
||||
c.logger.Error("cannot remove outdated allowed subnet through firewall: %s", err)
|
||||
}
|
||||
if err := c.acceptOutputFromSubnetToSubnet(ctx, defaultInterface, subnet, localSubnet, remove); err != nil {
|
||||
failed = true
|
||||
c.logger.Error("cannot remove outdated allowed subnet through firewall: %s", err)
|
||||
}
|
||||
if err := c.routing.DeleteRouteVia(ctx, subnet); err != nil {
|
||||
failed = true
|
||||
c.logger.Error("cannot remove outdated allowed subnet route: %s", err)
|
||||
}
|
||||
if failed {
|
||||
continue
|
||||
}
|
||||
c.allowedSubnets = removeSubnetFromSubnets(c.allowedSubnets, subnet)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *configurator) addSubnets(ctx context.Context, subnets []net.IPNet, defaultInterface string,
|
||||
defaultGateway net.IP, localSubnet net.IPNet) error {
|
||||
const remove = false
|
||||
for _, subnet := range subnets {
|
||||
if err := c.acceptInputFromSubnetToSubnet(ctx, defaultInterface, subnet, localSubnet, remove); err != nil {
|
||||
return fmt.Errorf("cannot add allowed subnet through firewall: %w", err)
|
||||
}
|
||||
if err := c.acceptOutputFromSubnetToSubnet(ctx, defaultInterface, localSubnet, subnet, remove); err != nil {
|
||||
return fmt.Errorf("cannot add allowed subnet through firewall: %w", err)
|
||||
}
|
||||
if err := c.routing.AddRouteVia(ctx, subnet, defaultGateway, defaultInterface); err != nil {
|
||||
return fmt.Errorf("cannot add route for allowed subnet: %w", err)
|
||||
}
|
||||
c.allowedSubnets = append(c.allowedSubnets, subnet)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *configurator) updateSubnetRoutes(ctx context.Context, oldSubnets, newSubnets []net.IPNet) error {
|
||||
subnetsToAdd := findSubnetsToAdd(oldSubnets, newSubnets)
|
||||
subnetsToRemove := findSubnetsToRemove(oldSubnets, newSubnets)
|
||||
if len(subnetsToAdd) == 0 && len(subnetsToRemove) == 0 {
|
||||
return nil
|
||||
}
|
||||
defaultInterface, defaultGateway, err := c.routing.DefaultRoute()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, subnet := range subnetsToRemove {
|
||||
if err := c.routing.DeleteRouteVia(ctx, subnet); err != nil {
|
||||
c.logger.Error("cannot remove outdated route for subnet: %s", err)
|
||||
}
|
||||
}
|
||||
for _, subnet := range subnetsToAdd {
|
||||
if err := c.routing.AddRouteVia(ctx, subnet, defaultGateway, defaultInterface); err != nil {
|
||||
c.logger.Error("cannot add route for subnet: %s", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
106
internal/firewall/vpn.go
Normal file
106
internal/firewall/vpn.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package firewall
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
func (c *configurator) SetVPNConnections(ctx context.Context, connections []models.OpenVPNConnection) (err error) {
|
||||
c.stateMutex.Lock()
|
||||
defer c.stateMutex.Unlock()
|
||||
|
||||
if !c.enabled {
|
||||
c.logger.Info("firewall disabled, only updating VPN connections internal list")
|
||||
c.vpnConnections = make([]models.OpenVPNConnection, len(connections))
|
||||
copy(c.vpnConnections, connections)
|
||||
return nil
|
||||
}
|
||||
|
||||
c.logger.Info("setting VPN connections through firewall...")
|
||||
|
||||
connectionsToAdd := findConnectionsToAdd(c.vpnConnections, connections)
|
||||
connectionsToRemove := findConnectionsToRemove(c.vpnConnections, connections)
|
||||
if len(connectionsToAdd) == 0 && len(connectionsToRemove) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
defaultInterface, _, err := c.routing.DefaultRoute()
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot set VPN connections through firewall: %w", err)
|
||||
}
|
||||
|
||||
c.removeConnections(ctx, connectionsToRemove, defaultInterface)
|
||||
if err := c.addConnections(ctx, connectionsToAdd, defaultInterface); err != nil {
|
||||
return fmt.Errorf("cannot set VPN connections through firewall: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeConnectionFromConnections(connections []models.OpenVPNConnection, connection models.OpenVPNConnection) []models.OpenVPNConnection {
|
||||
L := len(connections)
|
||||
for i := range connections {
|
||||
if connection.Equal(connections[i]) {
|
||||
connections[i] = connections[L-1]
|
||||
connections = connections[:L-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
return connections
|
||||
}
|
||||
|
||||
func findConnectionsToAdd(oldConnections, newConnections []models.OpenVPNConnection) (connectionsToAdd []models.OpenVPNConnection) {
|
||||
for _, newConnection := range newConnections {
|
||||
found := false
|
||||
for _, oldConnection := range oldConnections {
|
||||
if oldConnection.Equal(newConnection) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
connectionsToAdd = append(connectionsToAdd, newConnection)
|
||||
}
|
||||
}
|
||||
return connectionsToAdd
|
||||
}
|
||||
|
||||
func findConnectionsToRemove(oldConnections, newConnections []models.OpenVPNConnection) (connectionsToRemove []models.OpenVPNConnection) {
|
||||
for _, oldConnection := range oldConnections {
|
||||
found := false
|
||||
for _, newConnection := range newConnections {
|
||||
if oldConnection.Equal(newConnection) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
connectionsToRemove = append(connectionsToRemove, oldConnection)
|
||||
}
|
||||
}
|
||||
return connectionsToRemove
|
||||
}
|
||||
|
||||
func (c *configurator) removeConnections(ctx context.Context, connections []models.OpenVPNConnection, defaultInterface string) {
|
||||
for _, conn := range connections {
|
||||
const remove = true
|
||||
if err := c.acceptOutputTrafficToVPN(ctx, defaultInterface, conn, remove); err != nil {
|
||||
c.logger.Error("cannot remove outdated VPN connection through firewall: %s", err)
|
||||
continue
|
||||
}
|
||||
c.vpnConnections = removeConnectionFromConnections(c.vpnConnections, conn)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *configurator) addConnections(ctx context.Context, connections []models.OpenVPNConnection, defaultInterface string) error {
|
||||
const remove = false
|
||||
for _, conn := range connections {
|
||||
if err := c.acceptOutputTrafficToVPN(ctx, defaultInterface, conn, remove); err != nil {
|
||||
return err
|
||||
}
|
||||
c.vpnConnections = append(c.vpnConnections, conn)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package healthcheck
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/golibs/network"
|
||||
)
|
||||
|
||||
func HealthCheck() error {
|
||||
// DNS, HTTP and HTTPs check on github.com
|
||||
connectivty := network.NewConnectivity(3 * time.Second)
|
||||
errs := connectivty.Checks("github.com")
|
||||
if len(errs) > 0 {
|
||||
var errsStr []string
|
||||
for _, err := range errs {
|
||||
errsStr = append(errsStr, err.Error())
|
||||
}
|
||||
return fmt.Errorf("Multiple errors: %s", strings.Join(errsStr, "; "))
|
||||
}
|
||||
// TODO check IP address is in the right region
|
||||
return nil
|
||||
}
|
||||
93
internal/logging/line.go
Normal file
93
internal/logging/line.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
)
|
||||
|
||||
var regularExpressions = struct { //nolint:gochecknoglobals
|
||||
unboundPrefix *regexp.Regexp
|
||||
shadowsocksPrefix *regexp.Regexp
|
||||
shadowsocksErrorPrefix *regexp.Regexp
|
||||
tinyproxyLoglevel *regexp.Regexp
|
||||
tinyproxyPrefix *regexp.Regexp
|
||||
}{
|
||||
unboundPrefix: regexp.MustCompile(`unbound: \[[0-9]{10}\] unbound\[[0-9]+:0\] `),
|
||||
shadowsocksPrefix: regexp.MustCompile(`shadowsocks:[ ]+2[0-9]{3}\-[0-1][0-9]\-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9] `),
|
||||
shadowsocksErrorPrefix: regexp.MustCompile(`shadowsocks error:[ ]+2[0-9]{3}\-[0-1][0-9]\-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9] `),
|
||||
tinyproxyLoglevel: regexp.MustCompile(`INFO|CONNECT|NOTICE|WARNING|ERROR|CRITICAL`),
|
||||
tinyproxyPrefix: regexp.MustCompile(`tinyproxy: .+[ ]+(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9] \[[0-9]+\]: `),
|
||||
}
|
||||
|
||||
func PostProcessLine(s string) (filtered string, level logging.Level) {
|
||||
switch {
|
||||
case strings.HasPrefix(s, "openvpn: "):
|
||||
filtered = constants.ColorOpenvpn().Sprintf(s)
|
||||
return filtered, logging.InfoLevel
|
||||
case strings.HasPrefix(s, "unbound: "):
|
||||
prefix := regularExpressions.unboundPrefix.FindString(s)
|
||||
filtered = s[len(prefix):]
|
||||
switch {
|
||||
case strings.HasPrefix(filtered, "notice: "):
|
||||
filtered = strings.TrimPrefix(filtered, "notice: ")
|
||||
level = logging.InfoLevel
|
||||
case strings.HasPrefix(filtered, "info: "):
|
||||
filtered = strings.TrimPrefix(filtered, "info: ")
|
||||
level = logging.InfoLevel
|
||||
case strings.HasPrefix(filtered, "warn: "):
|
||||
filtered = strings.TrimPrefix(filtered, "warn: ")
|
||||
level = logging.WarnLevel
|
||||
case strings.HasPrefix(filtered, "error: "):
|
||||
filtered = strings.TrimPrefix(filtered, "error: ")
|
||||
level = logging.ErrorLevel
|
||||
default:
|
||||
level = logging.ErrorLevel
|
||||
}
|
||||
filtered = fmt.Sprintf("unbound: %s", filtered)
|
||||
filtered = constants.ColorUnbound().Sprintf(filtered)
|
||||
return filtered, level
|
||||
case strings.HasPrefix(s, "shadowsocks: "):
|
||||
prefix := regularExpressions.shadowsocksPrefix.FindString(s)
|
||||
filtered = s[len(prefix):]
|
||||
switch {
|
||||
case strings.HasPrefix(filtered, "INFO: "):
|
||||
level = logging.InfoLevel
|
||||
filtered = strings.TrimPrefix(filtered, "INFO: ")
|
||||
default:
|
||||
level = logging.WarnLevel
|
||||
}
|
||||
filtered = fmt.Sprintf("shadowsocks: %s", filtered)
|
||||
filtered = constants.ColorShadowsocks().Sprintf(filtered)
|
||||
return filtered, level
|
||||
case strings.HasPrefix(s, "shadowsocks error: "):
|
||||
if strings.Contains(s, "ERROR: unable to resolve") { // caused by DNS blocking
|
||||
return "", logging.ErrorLevel
|
||||
}
|
||||
prefix := regularExpressions.shadowsocksErrorPrefix.FindString(s)
|
||||
filtered = s[len(prefix):]
|
||||
filtered = strings.TrimPrefix(filtered, "ERROR: ")
|
||||
filtered = fmt.Sprintf("shadowsocks: %s", filtered)
|
||||
filtered = constants.ColorShadowsocksError().Sprintf(filtered)
|
||||
return filtered, logging.ErrorLevel
|
||||
case strings.HasPrefix(s, "tinyproxy: "):
|
||||
logLevel := regularExpressions.tinyproxyLoglevel.FindString(s)
|
||||
prefix := regularExpressions.tinyproxyPrefix.FindString(s)
|
||||
filtered = fmt.Sprintf("tinyproxy: %s", s[len(prefix):])
|
||||
filtered = constants.ColorTinyproxy().Sprintf(filtered)
|
||||
switch logLevel {
|
||||
case "INFO", "CONNECT", "NOTICE":
|
||||
return filtered, logging.InfoLevel
|
||||
case "WARNING":
|
||||
return filtered, logging.WarnLevel
|
||||
case "ERROR", "CRITICAL":
|
||||
return filtered, logging.ErrorLevel
|
||||
default:
|
||||
return filtered, logging.ErrorLevel
|
||||
}
|
||||
}
|
||||
return s, logging.InfoLevel
|
||||
}
|
||||
93
internal/logging/line_test.go
Normal file
93
internal/logging/line_test.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_PostProcessLine(t *testing.T) {
|
||||
t.Parallel()
|
||||
tests := map[string]struct {
|
||||
s string
|
||||
filtered string
|
||||
level logging.Level
|
||||
}{
|
||||
"empty string": {"", "", logging.InfoLevel},
|
||||
"random string": {"asdasqdb", "asdasqdb", logging.InfoLevel},
|
||||
"unbound notice": {
|
||||
"unbound: [1594595249] unbound[75:0] notice: init module 0: validator",
|
||||
"unbound: init module 0: validator",
|
||||
logging.InfoLevel},
|
||||
"unbound info": {
|
||||
"unbound: [1594595249] unbound[75:0] info: init module 0: validator",
|
||||
"unbound: init module 0: validator",
|
||||
logging.InfoLevel},
|
||||
"unbound warn": {
|
||||
"unbound: [1594595249] unbound[75:0] warn: init module 0: validator",
|
||||
"unbound: init module 0: validator",
|
||||
logging.WarnLevel},
|
||||
"unbound error": {
|
||||
"unbound: [1594595249] unbound[75:0] error: init module 0: validator",
|
||||
"unbound: init module 0: validator",
|
||||
logging.ErrorLevel},
|
||||
"unbound unknown": {
|
||||
"unbound: [1594595249] unbound[75:0] BLA: init module 0: validator",
|
||||
"unbound: BLA: init module 0: validator",
|
||||
logging.ErrorLevel},
|
||||
"shadowsocks stdout info": {
|
||||
"shadowsocks: 2020-07-12 23:07:25 INFO: UDP relay enabled",
|
||||
"shadowsocks: UDP relay enabled",
|
||||
logging.InfoLevel},
|
||||
"shadowsocks stdout other": {
|
||||
"shadowsocks: 2020-07-12 23:07:25 BLABLA: UDP relay enabled",
|
||||
"shadowsocks: BLABLA: UDP relay enabled",
|
||||
logging.WarnLevel},
|
||||
"shadowsocks stderr": {
|
||||
"shadowsocks error: 2020-07-12 23:07:25 Some error",
|
||||
"shadowsocks: Some error",
|
||||
logging.ErrorLevel},
|
||||
"shadowsocks stderr unable to resolve muted": {
|
||||
"shadowsocks error: 2020-07-12 23:07:25 ERROR: unable to resolve",
|
||||
"",
|
||||
logging.ErrorLevel},
|
||||
"tinyproxy info": {
|
||||
"tinyproxy: INFO Jul 12 23:07:25 [32]: Reloading config file",
|
||||
"tinyproxy: Reloading config file",
|
||||
logging.InfoLevel},
|
||||
"tinyproxy connect": {
|
||||
"tinyproxy: CONNECT Jul 12 23:07:25 [32]: Reloading config file",
|
||||
"tinyproxy: Reloading config file",
|
||||
logging.InfoLevel},
|
||||
"tinyproxy notice": {
|
||||
"tinyproxy: NOTICE Jul 12 23:07:25 [32]: Reloading config file",
|
||||
"tinyproxy: Reloading config file",
|
||||
logging.InfoLevel},
|
||||
"tinyproxy warning": {
|
||||
"tinyproxy: WARNING Jul 12 23:07:25 [32]: Reloading config file",
|
||||
"tinyproxy: Reloading config file",
|
||||
logging.WarnLevel},
|
||||
"tinyproxy error": {
|
||||
"tinyproxy: ERROR Jul 12 23:07:25 [32]: Reloading config file",
|
||||
"tinyproxy: Reloading config file",
|
||||
logging.ErrorLevel},
|
||||
"tinyproxy critical": {
|
||||
"tinyproxy: CRITICAL Jul 12 23:07:25 [32]: Reloading config file",
|
||||
"tinyproxy: Reloading config file",
|
||||
logging.ErrorLevel},
|
||||
"tinyproxy unknown": {
|
||||
"tinyproxy: BLABLA Jul 12 23:07:25 [32]: Reloading config file",
|
||||
"tinyproxy: Reloading config file",
|
||||
logging.ErrorLevel},
|
||||
}
|
||||
for name, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filtered, level := PostProcessLine(tc.s)
|
||||
assert.Equal(t, tc.filtered, filtered)
|
||||
assert.Equal(t, tc.level, level)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package splash
|
||||
package logging
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -7,19 +7,15 @@ import (
|
||||
|
||||
"github.com/kyokomi/emoji"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/params"
|
||||
)
|
||||
|
||||
// Splash returns the welcome spash message
|
||||
func Splash(paramsReader params.ParamsReader) string {
|
||||
version := paramsReader.GetVersion()
|
||||
vcsRef := paramsReader.GetVcsRef()
|
||||
buildDate := paramsReader.GetBuildDate()
|
||||
func Splash(version, vcsRef, buildDate string) string {
|
||||
lines := title()
|
||||
lines = append(lines, "")
|
||||
lines = append(lines, fmt.Sprintf("Running version %s built on %s (commit %s)", version, buildDate, vcsRef))
|
||||
lines = append(lines, "")
|
||||
lines = append(lines, annoucement()...)
|
||||
lines = append(lines, announcement()...)
|
||||
lines = append(lines, "")
|
||||
lines = append(lines, links()...)
|
||||
return strings.Join(lines, "\n")
|
||||
@@ -28,22 +24,29 @@ func Splash(paramsReader params.ParamsReader) string {
|
||||
func title() []string {
|
||||
return []string{
|
||||
"=========================================",
|
||||
"============= PIA container =============",
|
||||
"========== An exquisite mix of ==========",
|
||||
"==== OpenVPN, Unbound, DNS over TLS, ====",
|
||||
"===== Shadowsocks, Tinyproxy and Go =====",
|
||||
"================ Gluetun ================",
|
||||
"=========================================",
|
||||
"==== A mix of OpenVPN, DNS over TLS, ====",
|
||||
"======= Shadowsocks and Tinyproxy =======",
|
||||
"========= all glued up with Go ==========",
|
||||
"=========================================",
|
||||
"=========== For tunneling to ============",
|
||||
"======== your favorite VPN server =======",
|
||||
"=========================================",
|
||||
"=== Made with " + emoji.Sprint(":heart:") + " by github.com/qdm12 ====",
|
||||
"=========================================",
|
||||
}
|
||||
}
|
||||
|
||||
func annoucement() []string {
|
||||
timestamp := time.Now().UnixNano() / 1000000000
|
||||
if timestamp < constants.AnnoucementExpiration {
|
||||
return []string{emoji.Sprint(":mega: ") + constants.Annoucement}
|
||||
func announcement() []string {
|
||||
if len(constants.Announcement) == 0 {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
expirationDate, _ := time.Parse("2006-01-02", constants.AnnouncementExpiration) // error covered by a unit test
|
||||
if time.Now().After(expirationDate) {
|
||||
return nil
|
||||
}
|
||||
return []string{emoji.Sprint(":mega: ") + constants.Announcement}
|
||||
}
|
||||
|
||||
func links() []string {
|
||||
@@ -7,10 +7,6 @@ type (
|
||||
DNSProvider string
|
||||
// DNSHost is the DNS host to use for TLS validation
|
||||
DNSHost string
|
||||
// PIAEncryption defines the level of encryption for communication with PIA servers
|
||||
PIAEncryption string
|
||||
// PIARegion is used to define the list of regions available for PIA
|
||||
PIARegion string
|
||||
// URL is an HTTP(s) URL address
|
||||
URL string
|
||||
// Filepath is a local filesytem file path
|
||||
@@ -18,7 +14,7 @@ type (
|
||||
// TinyProxyLogLevel is the log level for TinyProxy
|
||||
TinyProxyLogLevel string
|
||||
// VPNProvider is the name of the VPN provider to be used
|
||||
VPNProvider string
|
||||
VPNProvider string // TODO
|
||||
// NetworkProtocol contains the network protocol to be used to communicate with the VPN servers
|
||||
NetworkProtocol string
|
||||
)
|
||||
|
||||
@@ -4,7 +4,8 @@ import "net"
|
||||
|
||||
// DNSProviderData contains information for a DNS provider
|
||||
type DNSProviderData struct {
|
||||
IPs []net.IP
|
||||
SupportsTLS bool
|
||||
Host DNSHost
|
||||
IPs []net.IP
|
||||
SupportsTLS bool
|
||||
SupportsIPv6 bool
|
||||
Host DNSHost
|
||||
}
|
||||
|
||||
13
internal/models/openvpn.go
Normal file
13
internal/models/openvpn.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package models
|
||||
|
||||
import "net"
|
||||
|
||||
type OpenVPNConnection struct {
|
||||
IP net.IP
|
||||
Port uint16
|
||||
Protocol NetworkProtocol
|
||||
}
|
||||
|
||||
func (o *OpenVPNConnection) Equal(other OpenVPNConnection) bool {
|
||||
return o.IP.Equal(other.IP) && o.Port == other.Port && o.Protocol == other.Protocol
|
||||
}
|
||||
124
internal/models/selection.go
Normal file
124
internal/models/selection.go
Normal file
@@ -0,0 +1,124 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ProviderSettings contains settings specific to a VPN provider
|
||||
type ProviderSettings struct {
|
||||
Name VPNProvider
|
||||
ServerSelection ServerSelection
|
||||
ExtraConfigOptions ExtraConfigOptions
|
||||
PortForwarding PortForwarding
|
||||
}
|
||||
|
||||
type ServerSelection struct { //nolint:maligned
|
||||
// Common
|
||||
Protocol NetworkProtocol
|
||||
TargetIP net.IP
|
||||
|
||||
// Cyberghost, PIA, Surfshark, Windscribe, Vyprvpn, NordVPN
|
||||
Region string
|
||||
|
||||
// Cyberghost
|
||||
Group string
|
||||
|
||||
// Mullvad
|
||||
Country string
|
||||
City string
|
||||
ISP string
|
||||
Owned bool
|
||||
|
||||
// Mullvad, Windscribe
|
||||
CustomPort uint16
|
||||
|
||||
// PIA
|
||||
EncryptionPreset string
|
||||
|
||||
// NordVPN
|
||||
Number uint16
|
||||
}
|
||||
|
||||
type ExtraConfigOptions struct {
|
||||
ClientKey string // Cyberghost
|
||||
EncryptionPreset string // PIA
|
||||
}
|
||||
|
||||
// PortForwarding contains settings for port forwarding
|
||||
type PortForwarding struct {
|
||||
Enabled bool
|
||||
Filepath Filepath
|
||||
}
|
||||
|
||||
func (p *PortForwarding) String() string {
|
||||
if p.Enabled {
|
||||
return fmt.Sprintf("on, saved in %s", p.Filepath)
|
||||
}
|
||||
return "off"
|
||||
}
|
||||
|
||||
func (p *ProviderSettings) String() string {
|
||||
settingsList := []string{
|
||||
fmt.Sprintf("%s settings:", strings.Title(string(p.Name))),
|
||||
"Network protocol: " + string(p.ServerSelection.Protocol),
|
||||
}
|
||||
customPort := ""
|
||||
if p.ServerSelection.CustomPort > 0 {
|
||||
customPort = fmt.Sprintf("%d", p.ServerSelection.CustomPort)
|
||||
}
|
||||
number := ""
|
||||
if p.ServerSelection.Number > 0 {
|
||||
number = fmt.Sprintf("%d", p.ServerSelection.Number)
|
||||
}
|
||||
switch strings.ToLower(string(p.Name)) {
|
||||
case "private internet access":
|
||||
settingsList = append(settingsList,
|
||||
"Region: "+p.ServerSelection.Region,
|
||||
"Encryption preset: "+p.ExtraConfigOptions.EncryptionPreset,
|
||||
"Port forwarding: "+p.PortForwarding.String(),
|
||||
)
|
||||
case "mullvad":
|
||||
settingsList = append(settingsList,
|
||||
"Country: "+p.ServerSelection.Country,
|
||||
"City: "+p.ServerSelection.City,
|
||||
"ISP: "+p.ServerSelection.ISP,
|
||||
"Custom port: "+customPort,
|
||||
)
|
||||
case "windscribe":
|
||||
settingsList = append(settingsList,
|
||||
"Region: "+p.ServerSelection.Region,
|
||||
"Custom port: "+customPort,
|
||||
)
|
||||
case "surfshark":
|
||||
settingsList = append(settingsList,
|
||||
"Region: "+p.ServerSelection.Region,
|
||||
)
|
||||
case "cyberghost":
|
||||
settingsList = append(settingsList,
|
||||
"ClientKey: [redacted]",
|
||||
"Group: "+p.ServerSelection.Group,
|
||||
"Region: "+p.ServerSelection.Region,
|
||||
)
|
||||
case "vyprvpn":
|
||||
settingsList = append(settingsList,
|
||||
"Region: "+p.ServerSelection.Region,
|
||||
)
|
||||
case "nordvpn":
|
||||
settingsList = append(settingsList,
|
||||
"Region: "+p.ServerSelection.Region,
|
||||
"Number: "+number,
|
||||
)
|
||||
default:
|
||||
settingsList = append(settingsList,
|
||||
"<Missing String method, please implement me!>",
|
||||
)
|
||||
}
|
||||
if p.ServerSelection.TargetIP != nil {
|
||||
settingsList = append(settingsList,
|
||||
"Target IP address: "+string(p.ServerSelection.TargetIP),
|
||||
)
|
||||
}
|
||||
return strings.Join(settingsList, "\n |--")
|
||||
}
|
||||
46
internal/models/servers.go
Normal file
46
internal/models/servers.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package models
|
||||
|
||||
import "net"
|
||||
|
||||
type PIAServer struct {
|
||||
IPs []net.IP
|
||||
Region string
|
||||
}
|
||||
|
||||
type MullvadServer struct {
|
||||
IPs []net.IP
|
||||
Country string
|
||||
City string
|
||||
ISP string
|
||||
Owned bool
|
||||
DefaultPort uint16
|
||||
}
|
||||
|
||||
type WindscribeServer struct {
|
||||
Region string
|
||||
IPs []net.IP
|
||||
}
|
||||
|
||||
type SurfsharkServer struct {
|
||||
Region string
|
||||
IPs []net.IP
|
||||
}
|
||||
|
||||
type CyberghostServer struct {
|
||||
Region string
|
||||
Group string
|
||||
IPs []net.IP
|
||||
}
|
||||
|
||||
type VyprvpnServer struct {
|
||||
Region string
|
||||
IPs []net.IP
|
||||
}
|
||||
|
||||
type NordvpnServer struct { //nolint:maligned
|
||||
Region string
|
||||
Number uint16
|
||||
IP net.IP
|
||||
TCP bool
|
||||
UDP bool
|
||||
}
|
||||
@@ -1,20 +1,28 @@
|
||||
package openvpn
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/qdm12/golibs/files"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
)
|
||||
|
||||
// WriteAuthFile writes the OpenVPN auth file to disk with the right permissions
|
||||
func (c *configurator) WriteAuthFile(user, password string, uid, gid int) error {
|
||||
authExists, err := c.fileManager.FileExists(string(constants.OpenVPNAuthConf))
|
||||
exists, err := c.fileManager.FileExists(string(constants.OpenVPNAuthConf))
|
||||
if err != nil {
|
||||
return err
|
||||
} else if authExists { // in case of container stop/start
|
||||
c.logger.Info("%s: %s already exists", logPrefix, constants.OpenVPNAuthConf)
|
||||
return nil
|
||||
} else if exists {
|
||||
data, err := c.fileManager.ReadFile(string(constants.OpenVPNAuthConf))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lines := strings.Split(string(data), "\n")
|
||||
if len(lines) > 1 && lines[0] == user && lines[1] == password {
|
||||
return nil
|
||||
}
|
||||
c.logger.Info("username and password changed", constants.OpenVPNAuthConf)
|
||||
}
|
||||
c.logger.Info("%s: writing auth file %s", logPrefix, constants.OpenVPNAuthConf)
|
||||
return c.fileManager.WriteLinesToFile(
|
||||
string(constants.OpenVPNAuthConf),
|
||||
[]string{user, password},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package openvpn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
@@ -8,14 +9,14 @@ import (
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
)
|
||||
|
||||
func (c *configurator) Start() (stdout io.ReadCloser, waitFn func() error, err error) {
|
||||
c.logger.Info("%s: starting openvpn", logPrefix)
|
||||
stdout, _, waitFn, err = c.commander.Start("openvpn", "--config", string(constants.OpenVPNConf))
|
||||
func (c *configurator) Start(ctx context.Context) (stdout io.ReadCloser, waitFn func() error, err error) {
|
||||
c.logger.Info("starting openvpn")
|
||||
stdout, _, waitFn, err = c.commander.Start(ctx, "openvpn", "--config", string(constants.OpenVPNConf))
|
||||
return stdout, waitFn, err
|
||||
}
|
||||
|
||||
func (c *configurator) Version() (string, error) {
|
||||
output, err := c.commander.Run("openvpn", "--version")
|
||||
func (c *configurator) Version(ctx context.Context) (string, error) {
|
||||
output, err := c.commander.Run(ctx, "openvpn", "--version")
|
||||
if err != nil && err.Error() != "exit status 1" {
|
||||
return "", err
|
||||
}
|
||||
|
||||
191
internal/openvpn/loop.go
Normal file
191
internal/openvpn/loop.go
Normal file
@@ -0,0 +1,191 @@
|
||||
package openvpn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/golibs/command"
|
||||
"github.com/qdm12/golibs/files"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
"github.com/qdm12/golibs/network"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/firewall"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/provider"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/settings"
|
||||
)
|
||||
|
||||
type Looper interface {
|
||||
Run(ctx context.Context, wg *sync.WaitGroup)
|
||||
Restart()
|
||||
PortForward()
|
||||
}
|
||||
|
||||
type looper struct {
|
||||
// Variable parameters
|
||||
provider models.VPNProvider
|
||||
settings settings.OpenVPN
|
||||
// Fixed parameters
|
||||
uid int
|
||||
gid int
|
||||
// Configurators
|
||||
conf Configurator
|
||||
fw firewall.Configurator
|
||||
// Other objects
|
||||
logger logging.Logger
|
||||
client network.Client
|
||||
fileManager files.FileManager
|
||||
streamMerger command.StreamMerger
|
||||
fatalOnError func(err error)
|
||||
// Internal channels
|
||||
restart chan struct{}
|
||||
portForwardSignals chan struct{}
|
||||
}
|
||||
|
||||
func NewLooper(provider models.VPNProvider, settings settings.OpenVPN,
|
||||
uid, gid int,
|
||||
conf Configurator, fw firewall.Configurator,
|
||||
logger logging.Logger, client network.Client, fileManager files.FileManager,
|
||||
streamMerger command.StreamMerger, fatalOnError func(err error)) Looper {
|
||||
return &looper{
|
||||
provider: provider,
|
||||
settings: settings,
|
||||
uid: uid,
|
||||
gid: gid,
|
||||
conf: conf,
|
||||
fw: fw,
|
||||
logger: logger.WithPrefix("openvpn: "),
|
||||
client: client,
|
||||
fileManager: fileManager,
|
||||
streamMerger: streamMerger,
|
||||
fatalOnError: fatalOnError,
|
||||
restart: make(chan struct{}),
|
||||
portForwardSignals: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *looper) Restart() { l.restart <- struct{}{} }
|
||||
func (l *looper) PortForward() { l.portForwardSignals <- struct{}{} }
|
||||
|
||||
func (l *looper) Run(ctx context.Context, wg *sync.WaitGroup) {
|
||||
wg.Add(1)
|
||||
defer wg.Done()
|
||||
select {
|
||||
case <-l.restart:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
defer l.logger.Warn("loop exited")
|
||||
|
||||
for ctx.Err() == nil {
|
||||
providerConf := provider.New(l.provider)
|
||||
connections, err := providerConf.GetOpenVPNConnections(l.settings.Provider.ServerSelection)
|
||||
l.fatalOnError(err)
|
||||
lines := providerConf.BuildConf(
|
||||
connections,
|
||||
l.settings.Verbosity,
|
||||
l.uid,
|
||||
l.gid,
|
||||
l.settings.Root,
|
||||
l.settings.Cipher,
|
||||
l.settings.Auth,
|
||||
l.settings.Provider.ExtraConfigOptions,
|
||||
)
|
||||
err = l.fileManager.WriteLinesToFile(string(constants.OpenVPNConf), lines, files.Ownership(l.uid, l.gid), files.Permissions(0400))
|
||||
l.fatalOnError(err)
|
||||
|
||||
err = l.conf.WriteAuthFile(l.settings.User, l.settings.Password, l.uid, l.gid)
|
||||
l.fatalOnError(err)
|
||||
|
||||
if err := l.fw.SetVPNConnections(ctx, connections); err != nil {
|
||||
l.fatalOnError(err)
|
||||
}
|
||||
|
||||
openvpnCtx, openvpnCancel := context.WithCancel(context.Background())
|
||||
|
||||
stream, waitFn, err := l.conf.Start(openvpnCtx)
|
||||
if err != nil {
|
||||
openvpnCancel()
|
||||
l.logAndWait(ctx, err)
|
||||
continue
|
||||
}
|
||||
|
||||
go func(ctx context.Context) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-l.portForwardSignals:
|
||||
l.portForward(ctx, providerConf, l.client)
|
||||
}
|
||||
}
|
||||
}(openvpnCtx)
|
||||
|
||||
go l.streamMerger.Merge(openvpnCtx, stream, command.MergeName("openvpn"))
|
||||
waitError := make(chan error)
|
||||
go func() {
|
||||
err := waitFn() // blocking
|
||||
waitError <- err
|
||||
}()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
l.logger.Warn("context canceled: exiting loop")
|
||||
openvpnCancel()
|
||||
<-waitError
|
||||
close(waitError)
|
||||
return
|
||||
case <-l.restart: // triggered restart
|
||||
l.logger.Info("restarting")
|
||||
openvpnCancel()
|
||||
<-waitError
|
||||
close(waitError)
|
||||
case err := <-waitError: // unexpected error
|
||||
openvpnCancel()
|
||||
close(waitError)
|
||||
l.logAndWait(ctx, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *looper) logAndWait(ctx context.Context, err error) {
|
||||
l.logger.Error(err)
|
||||
l.logger.Info("retrying in 30 seconds")
|
||||
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
||||
defer cancel() // just for the linter
|
||||
<-ctx.Done()
|
||||
}
|
||||
|
||||
func (l *looper) portForward(ctx context.Context, providerConf provider.Provider, client network.Client) {
|
||||
if !l.settings.Provider.PortForwarding.Enabled {
|
||||
return
|
||||
}
|
||||
var port uint16
|
||||
err := fmt.Errorf("")
|
||||
for err != nil {
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
port, err = providerConf.GetPortForward(client)
|
||||
if err != nil {
|
||||
l.logAndWait(ctx, err)
|
||||
continue
|
||||
}
|
||||
l.logger.Info("port forwarded is %d", port)
|
||||
}
|
||||
|
||||
filepath := l.settings.Provider.PortForwarding.Filepath
|
||||
l.logger.Info("writing forwarded port to %s", filepath)
|
||||
err = l.fileManager.WriteLinesToFile(
|
||||
string(filepath), []string{fmt.Sprintf("%d", port)},
|
||||
files.Ownership(l.uid, l.gid), files.Permissions(0400),
|
||||
)
|
||||
if err != nil {
|
||||
l.logger.Error(err)
|
||||
}
|
||||
|
||||
if err := l.fw.SetPortForward(ctx, port); err != nil {
|
||||
l.logger.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package openvpn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
@@ -10,14 +11,12 @@ import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const logPrefix = "openvpn configurator"
|
||||
|
||||
type Configurator interface {
|
||||
Version() (string, error)
|
||||
Version(ctx context.Context) (string, error)
|
||||
WriteAuthFile(user, password string, uid, gid int) error
|
||||
CheckTUN() error
|
||||
CreateTUN() error
|
||||
Start() (stdout io.ReadCloser, waitFn func() error, err error)
|
||||
Start(ctx context.Context) (stdout io.ReadCloser, waitFn func() error, err error)
|
||||
}
|
||||
|
||||
type configurator struct {
|
||||
@@ -32,7 +31,7 @@ type configurator struct {
|
||||
func NewConfigurator(logger logging.Logger, fileManager files.FileManager) Configurator {
|
||||
return &configurator{
|
||||
fileManager: fileManager,
|
||||
logger: logger,
|
||||
logger: logger.WithPrefix("openvpn configurator: "),
|
||||
commander: command.NewCommander(),
|
||||
openFile: os.OpenFile,
|
||||
mkDev: unix.Mkdev,
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
// CheckTUN checks the tunnel device is present and accessible
|
||||
func (c *configurator) CheckTUN() error {
|
||||
c.logger.Info("%s: checking for device %s", logPrefix, constants.TunnelDevice)
|
||||
c.logger.Info("checking for device %s", constants.TunnelDevice)
|
||||
f, err := c.openFile(string(constants.TunnelDevice), os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("TUN device is not available: %w", err)
|
||||
@@ -22,7 +22,7 @@ func (c *configurator) CheckTUN() error {
|
||||
}
|
||||
|
||||
func (c *configurator) CreateTUN() error {
|
||||
c.logger.Info("%s: creating %s", logPrefix, constants.TunnelDevice)
|
||||
c.logger.Info("creating %s", constants.TunnelDevice)
|
||||
if err := c.fileManager.CreateDir("/dev/net"); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -30,7 +30,7 @@ func (c *configurator) CreateTUN() error {
|
||||
if err := c.mkNod(string(constants.TunnelDevice), unix.S_IFCHR, int(dev)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.fileManager.SetUserPermissions(string(constants.TunnelDevice), 666); err != nil {
|
||||
if err := c.fileManager.SetUserPermissions(string(constants.TunnelDevice), 0666); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
41
internal/params/cyberghost.go
Normal file
41
internal/params/cyberghost.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package params
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
libparams "github.com/qdm12/golibs/params"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
)
|
||||
|
||||
// GetCyberghostGroup obtains the server group for the Cyberghost server from the
|
||||
// environment variable CYBERGHOST_GROUP
|
||||
func (p *reader) GetCyberghostGroup() (group string, err error) {
|
||||
s, err := p.envParams.GetValueIfInside("CYBERGHOST_GROUP", constants.CyberghostGroupChoices())
|
||||
return s, err
|
||||
}
|
||||
|
||||
// GetCyberghostRegion obtains the country name for the Cyberghost server from the
|
||||
// environment variable REGION
|
||||
func (p *reader) GetCyberghostRegion() (region string, err error) {
|
||||
s, err := p.envParams.GetValueIfInside("REGION", constants.CyberghostRegionChoices())
|
||||
return s, err
|
||||
}
|
||||
|
||||
// GetCyberghostClientKey obtains the one line client key to use for openvpn from the
|
||||
// environment variable CLIENT_KEY
|
||||
func (p *reader) GetCyberghostClientKey() (clientKey string, err error) {
|
||||
clientKey, err = p.envParams.GetEnv("CLIENT_KEY", libparams.CaseSensitiveValue())
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if len(clientKey) > 0 {
|
||||
return clientKey, nil
|
||||
}
|
||||
content, err := p.fileManager.ReadFile("/files/client.key")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
s := string(content)
|
||||
s = strings.ReplaceAll(s, "\n", "")
|
||||
s = strings.ReplaceAll(s, "\r", "")
|
||||
return s, nil
|
||||
}
|
||||
@@ -2,7 +2,9 @@ package params
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
libparams "github.com/qdm12/golibs/params"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
@@ -11,14 +13,14 @@ import (
|
||||
|
||||
// GetDNSOverTLS obtains if the DNS over TLS should be enabled
|
||||
// from the environment variable DOT
|
||||
func (p *paramsReader) GetDNSOverTLS() (DNSOverTLS bool, err error) {
|
||||
return p.envParams.GetOnOff("DOT", libparams.Default("on"))
|
||||
func (r *reader) GetDNSOverTLS() (DNSOverTLS bool, err error) { //nolint:gocritic
|
||||
return r.envParams.GetOnOff("DOT", libparams.Default("on"))
|
||||
}
|
||||
|
||||
// GetDNSOverTLSProviders obtains the DNS over TLS providers to use
|
||||
// from the environment variable DOT_PROVIDERS
|
||||
func (p *paramsReader) GetDNSOverTLSProviders() (providers []models.DNSProvider, err error) {
|
||||
s, err := p.envParams.GetEnv("DOT_PROVIDERS", libparams.Default("cloudflare"))
|
||||
func (r *reader) GetDNSOverTLSProviders() (providers []models.DNSProvider, err error) {
|
||||
s, err := r.envParams.GetEnv("DOT_PROVIDERS", libparams.Default("cloudflare"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -36,65 +38,64 @@ func (p *paramsReader) GetDNSOverTLSProviders() (providers []models.DNSProvider,
|
||||
|
||||
// GetDNSOverTLSVerbosity obtains the verbosity level to use for Unbound
|
||||
// from the environment variable DOT_VERBOSITY
|
||||
func (p *paramsReader) GetDNSOverTLSVerbosity() (verbosityLevel uint8, err error) {
|
||||
n, err := p.envParams.GetEnvIntRange("DOT_VERBOSITY", 0, 5, libparams.Default("1"))
|
||||
func (r *reader) GetDNSOverTLSVerbosity() (verbosityLevel uint8, err error) {
|
||||
n, err := r.envParams.GetEnvIntRange("DOT_VERBOSITY", 0, 5, libparams.Default("1"))
|
||||
return uint8(n), err
|
||||
}
|
||||
|
||||
// GetDNSOverTLSVerbosityDetails obtains the log level to use for Unbound
|
||||
// from the environment variable DOT_VERBOSITY_DETAILS
|
||||
func (p *paramsReader) GetDNSOverTLSVerbosityDetails() (verbosityDetailsLevel uint8, err error) {
|
||||
n, err := p.envParams.GetEnvIntRange("DOT_VERBOSITY_DETAILS", 0, 4, libparams.Default("0"))
|
||||
func (r *reader) GetDNSOverTLSVerbosityDetails() (verbosityDetailsLevel uint8, err error) {
|
||||
n, err := r.envParams.GetEnvIntRange("DOT_VERBOSITY_DETAILS", 0, 4, libparams.Default("0"))
|
||||
return uint8(n), err
|
||||
}
|
||||
|
||||
// GetDNSOverTLSValidationLogLevel obtains the log level to use for Unbound DOT validation
|
||||
// from the environment variable DOT_VALIDATION_LOGLEVEL
|
||||
func (p *paramsReader) GetDNSOverTLSValidationLogLevel() (validationLogLevel uint8, err error) {
|
||||
n, err := p.envParams.GetEnvIntRange("DOT_VALIDATION_LOGLEVEL", 0, 2, libparams.Default("0"))
|
||||
func (r *reader) GetDNSOverTLSValidationLogLevel() (validationLogLevel uint8, err error) {
|
||||
n, err := r.envParams.GetEnvIntRange("DOT_VALIDATION_LOGLEVEL", 0, 2, libparams.Default("0"))
|
||||
return uint8(n), err
|
||||
}
|
||||
|
||||
// GetDNSMaliciousBlocking obtains if malicious hostnames/IPs should be blocked
|
||||
// from being resolved by Unbound, using the environment variable BLOCK_MALICIOUS
|
||||
func (p *paramsReader) GetDNSMaliciousBlocking() (blocking bool, err error) {
|
||||
return p.envParams.GetOnOff("BLOCK_MALICIOUS", libparams.Default("on"))
|
||||
func (r *reader) GetDNSMaliciousBlocking() (blocking bool, err error) {
|
||||
return r.envParams.GetOnOff("BLOCK_MALICIOUS", libparams.Default("on"))
|
||||
}
|
||||
|
||||
// GetDNSSurveillanceBlocking obtains if surveillance hostnames/IPs should be blocked
|
||||
// from being resolved by Unbound, using the environment variable BLOCK_SURVEILLANCE
|
||||
// and BLOCK_NSA for retrocompatibility
|
||||
func (p *paramsReader) GetDNSSurveillanceBlocking() (blocking bool, err error) {
|
||||
func (r *reader) GetDNSSurveillanceBlocking() (blocking bool, err error) {
|
||||
// Retro-compatibility
|
||||
s, err := p.envParams.GetEnv("BLOCK_NSA")
|
||||
s, err := r.envParams.GetEnv("BLOCK_NSA")
|
||||
if err != nil {
|
||||
return false, err
|
||||
} else if len(s) != 0 {
|
||||
p.logger.Warn("You are using the old environment variable BLOCK_NSA, please consider changing it to BLOCK_SURVEILLANCE")
|
||||
return p.envParams.GetOnOff("BLOCK_NSA", libparams.Compulsory())
|
||||
r.logger.Warn("You are using the old environment variable BLOCK_NSA, please consider changing it to BLOCK_SURVEILLANCE")
|
||||
return r.envParams.GetOnOff("BLOCK_NSA", libparams.Compulsory())
|
||||
}
|
||||
return p.envParams.GetOnOff("BLOCK_SURVEILLANCE", libparams.Default("off"))
|
||||
return r.envParams.GetOnOff("BLOCK_SURVEILLANCE", libparams.Default("off"))
|
||||
}
|
||||
|
||||
// GetDNSAdsBlocking obtains if ads hostnames/IPs should be blocked
|
||||
// from being resolved by Unbound, using the environment variable BLOCK_ADS
|
||||
func (p *paramsReader) GetDNSAdsBlocking() (blocking bool, err error) {
|
||||
return p.envParams.GetOnOff("BLOCK_ADS", libparams.Default("off"))
|
||||
func (r *reader) GetDNSAdsBlocking() (blocking bool, err error) {
|
||||
return r.envParams.GetOnOff("BLOCK_ADS", libparams.Default("off"))
|
||||
}
|
||||
|
||||
// GetDNSUnblockedHostnames obtains a list of hostnames to unblock from block lists
|
||||
// from the comma separated list for the environment variable UNBLOCK
|
||||
func (p *paramsReader) GetDNSUnblockedHostnames() (hostnames []string, err error) {
|
||||
s, err := p.envParams.GetEnv("UNBLOCK")
|
||||
func (r *reader) GetDNSUnblockedHostnames() (hostnames []string, err error) {
|
||||
s, err := r.envParams.GetEnv("UNBLOCK")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(s) == 0 {
|
||||
} else if len(s) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
hostnames = strings.Split(s, ",")
|
||||
for _, hostname := range hostnames {
|
||||
if !p.verifier.MatchHostname(hostname) {
|
||||
if !r.verifier.MatchHostname(hostname) {
|
||||
return nil, fmt.Errorf("hostname %q does not seem valid", hostname)
|
||||
}
|
||||
}
|
||||
@@ -103,16 +104,62 @@ func (p *paramsReader) GetDNSUnblockedHostnames() (hostnames []string, err error
|
||||
|
||||
// GetDNSOverTLSCaching obtains if Unbound caching should be enable or not
|
||||
// from the environment variable DOT_CACHING
|
||||
func (p *paramsReader) GetDNSOverTLSCaching() (caching bool, err error) {
|
||||
return p.envParams.GetOnOff("DOT_CACHING")
|
||||
func (r *reader) GetDNSOverTLSCaching() (caching bool, err error) {
|
||||
return r.envParams.GetOnOff("DOT_CACHING")
|
||||
}
|
||||
|
||||
// GetDNSOverTLSPrivateAddresses obtains if Unbound caching should be enable or not
|
||||
// from the environment variable DOT_PRIVATE_ADDRESS
|
||||
func (p *paramsReader) GetDNSOverTLSPrivateAddresses() (privateAddresses []string) {
|
||||
s, _ := p.envParams.GetEnv("DOT_PRIVATE_ADDRESS")
|
||||
for _, s := range strings.Split(s, ",") {
|
||||
privateAddresses = append(privateAddresses, s)
|
||||
func (r *reader) GetDNSOverTLSPrivateAddresses() (privateAddresses []string, err error) {
|
||||
s, err := r.envParams.GetEnv("DOT_PRIVATE_ADDRESS")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if len(s) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return privateAddresses
|
||||
privateAddresses = strings.Split(s, ",")
|
||||
for _, address := range privateAddresses {
|
||||
ip := net.ParseIP(address)
|
||||
_, _, err := net.ParseCIDR(address)
|
||||
if ip == nil && err != nil {
|
||||
return nil, fmt.Errorf("private address %q is not a valid IP or CIDR range", address)
|
||||
}
|
||||
}
|
||||
return privateAddresses, nil
|
||||
}
|
||||
|
||||
// GetDNSOverTLSIPv6 obtains if Unbound should resolve ipv6 addresses using ipv6 DNS over TLS
|
||||
// servers from the environment variable DOT_IPV6
|
||||
func (r *reader) GetDNSOverTLSIPv6() (ipv6 bool, err error) {
|
||||
return r.envParams.GetOnOff("DOT_IPV6", libparams.Default("off"))
|
||||
}
|
||||
|
||||
// GetDNSUpdatePeriod obtains the period to use to update the block lists and cryptographic files
|
||||
// and restart Unbound from the environment variable DNS_UPDATE_PERIOD
|
||||
func (r *reader) GetDNSUpdatePeriod() (period time.Duration, err error) {
|
||||
s, err := r.envParams.GetEnv("DNS_UPDATE_PERIOD", libparams.Default("24h"))
|
||||
if err != nil {
|
||||
return period, err
|
||||
}
|
||||
return time.ParseDuration(s)
|
||||
}
|
||||
|
||||
// GetDNSPlaintext obtains the plaintext DNS address to use if DNS over TLS is disabled
|
||||
// from the environment variable DNS_PLAINTEXT_ADDRESS
|
||||
func (r *reader) GetDNSPlaintext() (ip net.IP, err error) {
|
||||
s, err := r.envParams.GetEnv("DNS_PLAINTEXT_ADDRESS", libparams.Default("1.1.1.1"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ip = net.ParseIP(s)
|
||||
if ip == nil {
|
||||
return nil, fmt.Errorf("DNS plaintext address %q is not a valid IP address", s)
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
// GetDNSKeepNameserver obtains if the nameserver present in /etc/resolv.conf
|
||||
// should be kept instead of overridden, from the environment variable DNS_KEEP_NAMESERVER
|
||||
func (r *reader) GetDNSKeepNameserver() (on bool, err error) {
|
||||
return r.envParams.GetOnOff("DNS_KEEP_NAMESERVER", libparams.Default("off"))
|
||||
}
|
||||
|
||||
@@ -4,12 +4,19 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
libparams "github.com/qdm12/golibs/params"
|
||||
)
|
||||
|
||||
// GetFirewall obtains if the firewall should be enabled from the environment variable FIREWALL
|
||||
func (r *reader) GetFirewall() (enabled bool, err error) {
|
||||
return r.envParams.GetOnOff("FIREWALL", libparams.Default("on"))
|
||||
}
|
||||
|
||||
// GetExtraSubnets obtains the CIDR subnets from the comma separated list of the
|
||||
// environment variable EXTRA_SUBNETS
|
||||
func (p *paramsReader) GetExtraSubnets() (extraSubnets []net.IPNet, err error) {
|
||||
s, err := p.envParams.GetEnv("EXTRA_SUBNETS")
|
||||
func (r *reader) GetExtraSubnets() (extraSubnets []net.IPNet, err error) {
|
||||
s, err := r.envParams.GetEnv("EXTRA_SUBNETS")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if s == "" {
|
||||
@@ -27,3 +34,8 @@ func (p *paramsReader) GetExtraSubnets() (extraSubnets []net.IPNet, err error) {
|
||||
}
|
||||
return extraSubnets, nil
|
||||
}
|
||||
|
||||
// GetFirewallDebug obtains if the firewall should run in debug verbose mode from the environment variable FIREWALL_DEBUG
|
||||
func (r *reader) GetFirewallDebug() (debug bool, err error) {
|
||||
return r.envParams.GetOnOff("FIREWALL_DEBUG", libparams.Default("off"))
|
||||
}
|
||||
|
||||
34
internal/params/mullvad.go
Normal file
34
internal/params/mullvad.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package params
|
||||
|
||||
import (
|
||||
libparams "github.com/qdm12/golibs/params"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
)
|
||||
|
||||
// GetMullvadCountry obtains the country for the Mullvad server from the
|
||||
// environment variable COUNTRY
|
||||
func (r *reader) GetMullvadCountry() (country string, err error) {
|
||||
choices := append(constants.MullvadCountryChoices(), "")
|
||||
return r.envParams.GetValueIfInside("COUNTRY", choices)
|
||||
}
|
||||
|
||||
// GetMullvadCity obtains the city for the Mullvad server from the
|
||||
// environment variable CITY
|
||||
func (r *reader) GetMullvadCity() (country string, err error) {
|
||||
choices := append(constants.MullvadCityChoices(), "")
|
||||
return r.envParams.GetValueIfInside("CITY", choices)
|
||||
}
|
||||
|
||||
// GetMullvadISP obtains the ISP for the Mullvad server from the
|
||||
// environment variable ISP
|
||||
func (r *reader) GetMullvadISP() (isp string, err error) {
|
||||
choices := append(constants.MullvadISPChoices(), "")
|
||||
return r.envParams.GetValueIfInside("ISP", choices)
|
||||
}
|
||||
|
||||
// GetMullvadPort obtains the port to reach the Mullvad server on from the
|
||||
// environment variable PORT
|
||||
func (r *reader) GetMullvadPort() (port uint16, err error) {
|
||||
n, err := r.envParams.GetEnvIntRange("PORT", 0, 65535, libparams.Default("0"))
|
||||
return uint16(n), err
|
||||
}
|
||||
22
internal/params/nordvpn.go
Normal file
22
internal/params/nordvpn.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package params
|
||||
|
||||
import (
|
||||
libparams "github.com/qdm12/golibs/params"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
)
|
||||
|
||||
// GetNordvpnRegion obtains the region (country) for the NordVPN server from the
|
||||
// environment variable REGION
|
||||
func (r *reader) GetNordvpnRegion() (region string, err error) {
|
||||
return r.envParams.GetValueIfInside("REGION", constants.NordvpnRegionChoices())
|
||||
}
|
||||
|
||||
// GetNordvpnRegion obtains the server number (optional) for the NordVPN server from the
|
||||
// environment variable SERVER_NUMBER
|
||||
func (r *reader) GetNordvpnNumber() (number uint16, err error) {
|
||||
n, err := r.envParams.GetEnvIntRange("SERVER_NUMBER", 0, 65535, libparams.Default("0"))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint16(n), nil
|
||||
}
|
||||
@@ -1,13 +1,83 @@
|
||||
package params
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
libparams "github.com/qdm12/golibs/params"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
// GetUser obtains the user to use to connect to the VPN servers
|
||||
func (r *reader) GetUser() (s string, err error) {
|
||||
defer func() {
|
||||
unsetenvErr := r.unsetEnv("USER")
|
||||
if err == nil {
|
||||
err = unsetenvErr
|
||||
}
|
||||
}()
|
||||
return r.envParams.GetEnv("USER", libparams.CaseSensitiveValue(), libparams.Compulsory())
|
||||
}
|
||||
|
||||
// GetPassword obtains the password to use to connect to the VPN servers
|
||||
func (r *reader) GetPassword(required bool) (s string, err error) {
|
||||
defer func() {
|
||||
unsetenvErr := r.unsetEnv("PASSWORD")
|
||||
if err == nil {
|
||||
err = unsetenvErr
|
||||
}
|
||||
}()
|
||||
options := []libparams.GetEnvSetter{libparams.CaseSensitiveValue()}
|
||||
if required {
|
||||
options = append(options, libparams.Compulsory())
|
||||
}
|
||||
return r.envParams.GetEnv("PASSWORD", options...)
|
||||
}
|
||||
|
||||
// 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"))
|
||||
func (r *reader) GetNetworkProtocol() (protocol models.NetworkProtocol, err error) {
|
||||
s, err := r.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 (r *reader) GetOpenVPNVerbosity() (verbosity int, err error) {
|
||||
return r.envParams.GetEnvIntRange("OPENVPN_VERBOSITY", 0, 6, libparams.Default("1"))
|
||||
}
|
||||
|
||||
// GetOpenVPNRoot obtains if openvpn should be run as root
|
||||
// from the environment variable OPENVPN_ROOT
|
||||
func (r *reader) GetOpenVPNRoot() (root bool, err error) {
|
||||
return r.envParams.GetYesNo("OPENVPN_ROOT", libparams.Default("no"))
|
||||
}
|
||||
|
||||
// GetTargetIP obtains the IP address to choose from the list of IP addresses
|
||||
// available for a particular region, from the environment variable
|
||||
// OPENVPN_TARGET_IP
|
||||
func (r *reader) GetTargetIP() (ip net.IP, err error) {
|
||||
s, err := r.envParams.GetEnv("OPENVPN_TARGET_IP")
|
||||
if len(s) == 0 {
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ip = net.ParseIP(s)
|
||||
if ip == nil {
|
||||
return nil, fmt.Errorf("target IP address %q is not valid", s)
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
|
||||
// GetOpenVPNCipher obtains a custom cipher to use with OpenVPN
|
||||
// from the environment variable OPENVPN_CIPHER
|
||||
func (r *reader) GetOpenVPNCipher() (cipher string, err error) {
|
||||
return r.envParams.GetEnv("OPENVPN_CIPHER")
|
||||
}
|
||||
|
||||
// GetOpenVPNAuth obtains a custom auth algorithm to use with OpenVPN
|
||||
// from the environment variable OPENVPN_AUTH
|
||||
func (r *reader) GetOpenVPNAuth() (auth string, err error) {
|
||||
return r.envParams.GetEnv("OPENVPN_AUTH")
|
||||
}
|
||||
|
||||
@@ -3,15 +3,19 @@ package params
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/qdm12/golibs/files"
|
||||
"github.com/qdm12/golibs/logging"
|
||||
libparams "github.com/qdm12/golibs/params"
|
||||
"github.com/qdm12/golibs/verification"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
// ParamsReader contains methods to obtain parameters
|
||||
type ParamsReader interface {
|
||||
// Reader contains methods to obtain parameters
|
||||
type Reader interface {
|
||||
GetVPNSP() (vpnServiceProvider models.VPNProvider, err error)
|
||||
|
||||
// DNS over TLS getters
|
||||
GetDNSOverTLS() (DNSOverTLS bool, err error)
|
||||
GetDNSOverTLSProviders() (providers []models.DNSProvider, err error)
|
||||
@@ -23,27 +27,70 @@ type ParamsReader interface {
|
||||
GetDNSSurveillanceBlocking() (blocking bool, err error)
|
||||
GetDNSAdsBlocking() (blocking bool, err error)
|
||||
GetDNSUnblockedHostnames() (hostnames []string, err error)
|
||||
GetDNSOverTLSPrivateAddresses() (privateAddresses []string)
|
||||
GetDNSOverTLSPrivateAddresses() (privateAddresses []string, err error)
|
||||
GetDNSOverTLSIPv6() (ipv6 bool, err error)
|
||||
GetDNSUpdatePeriod() (period time.Duration, err error)
|
||||
GetDNSPlaintext() (ip net.IP, err error)
|
||||
GetDNSKeepNameserver() (on bool, err error)
|
||||
|
||||
// System
|
||||
GetUID() (uid int, err error)
|
||||
GetGID() (gid int, err error)
|
||||
GetTimezone() (timezone string, err error)
|
||||
GetIPStatusFilepath() (filepath models.Filepath, err error)
|
||||
|
||||
// Firewall getters
|
||||
GetFirewall() (enabled bool, err error)
|
||||
GetExtraSubnets() (extraSubnets []net.IPNet, err error)
|
||||
GetFirewallDebug() (debug bool, err error)
|
||||
|
||||
// VPN getters
|
||||
GetUser() (s string, err error)
|
||||
GetPassword(required bool) (s string, err error)
|
||||
GetNetworkProtocol() (protocol models.NetworkProtocol, err error)
|
||||
GetOpenVPNVerbosity() (verbosity int, err error)
|
||||
GetOpenVPNRoot() (root bool, err error)
|
||||
GetTargetIP() (ip net.IP, err error)
|
||||
GetOpenVPNCipher() (cipher string, err error)
|
||||
GetOpenVPNAuth() (auth string, err error)
|
||||
|
||||
// PIA getters
|
||||
GetUser() (s string, err error)
|
||||
GetPassword() (s string, err error)
|
||||
GetPortForwarding() (activated bool, err error)
|
||||
GetPortForwardingStatusFilepath() (filepath models.Filepath, err error)
|
||||
GetPIAEncryption() (models.PIAEncryption, error)
|
||||
GetPIARegion() (models.PIARegion, error)
|
||||
GetPIAEncryptionPreset() (preset string, err error)
|
||||
GetPIARegion() (region string, err error)
|
||||
|
||||
// Mullvad getters
|
||||
GetMullvadCountry() (country string, err error)
|
||||
GetMullvadCity() (country string, err error)
|
||||
GetMullvadISP() (country string, err error)
|
||||
GetMullvadPort() (port uint16, err error)
|
||||
|
||||
// Windscribe getters
|
||||
GetWindscribeRegion() (country string, err error)
|
||||
GetWindscribePort(protocol models.NetworkProtocol) (port uint16, err error)
|
||||
|
||||
// Surfshark getters
|
||||
GetSurfsharkRegion() (country string, err error)
|
||||
|
||||
// Cyberghost getters
|
||||
GetCyberghostGroup() (group string, err error)
|
||||
GetCyberghostRegion() (region string, err error)
|
||||
GetCyberghostClientKey() (clientKey string, err error)
|
||||
|
||||
// Vyprvpn getters
|
||||
GetVyprvpnRegion() (region string, err error)
|
||||
|
||||
// NordVPN getters
|
||||
GetNordvpnRegion() (region string, err error)
|
||||
GetNordvpnNumber() (number uint16, err error)
|
||||
|
||||
// Shadowsocks getters
|
||||
GetShadowSocks() (activated bool, err error)
|
||||
GetShadowSocksLog() (activated bool, err error)
|
||||
GetShadowSocksPort() (port uint16, err error)
|
||||
GetShadowSocksPassword() (password string, err error)
|
||||
GetShadowSocksMethod() (method string, err error)
|
||||
|
||||
// Tinyproxy getters
|
||||
GetTinyProxy() (activated bool, err error)
|
||||
@@ -58,20 +105,31 @@ type ParamsReader interface {
|
||||
GetVcsRef() string
|
||||
}
|
||||
|
||||
type paramsReader struct {
|
||||
envParams libparams.EnvParams
|
||||
logger logging.Logger
|
||||
verifier verification.Verifier
|
||||
unsetEnv func(key string) error
|
||||
type reader struct {
|
||||
envParams libparams.EnvParams
|
||||
logger logging.Logger
|
||||
verifier verification.Verifier
|
||||
unsetEnv func(key string) error
|
||||
fileManager files.FileManager
|
||||
}
|
||||
|
||||
// NewParamsReader returns a paramsReadeer object to read parameters from
|
||||
// Newreader returns a paramsReadeer object to read parameters from
|
||||
// environment variables
|
||||
func NewParamsReader(logger logging.Logger) ParamsReader {
|
||||
return ¶msReader{
|
||||
envParams: libparams.NewEnvParams(),
|
||||
logger: logger,
|
||||
verifier: verification.NewVerifier(),
|
||||
unsetEnv: os.Unsetenv,
|
||||
func NewReader(logger logging.Logger, fileManager files.FileManager) Reader {
|
||||
return &reader{
|
||||
envParams: libparams.NewEnvParams(),
|
||||
logger: logger,
|
||||
verifier: verification.NewVerifier(),
|
||||
unsetEnv: os.Unsetenv,
|
||||
fileManager: fileManager,
|
||||
}
|
||||
}
|
||||
|
||||
// GetVPNSP obtains the VPN service provider to use from the environment variable VPNSP
|
||||
func (r *reader) GetVPNSP() (vpnServiceProvider models.VPNProvider, err error) {
|
||||
s, err := r.envParams.GetValueIfInside("VPNSP", []string{"pia", "private internet access", "mullvad", "windscribe", "surfshark", "cyberghost", "vyprvpn", "nordvpn"})
|
||||
if s == "pia" {
|
||||
s = "private internet access"
|
||||
}
|
||||
return models.VPNProvider(s), err
|
||||
}
|
||||
|
||||
@@ -9,44 +9,10 @@ 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) {
|
||||
s, err := p.envParams.GetEnv("PORT_FORWARDING", libparams.Default("off"))
|
||||
func (r *reader) GetPortForwarding() (activated bool, err error) {
|
||||
s, err := r.envParams.GetEnv("PORT_FORWARDING", libparams.Default("off"))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -61,25 +27,42 @@ 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"))
|
||||
func (r *reader) GetPortForwardingStatusFilepath() (filepath models.Filepath, err error) {
|
||||
filepathStr, err := r.envParams.GetPath("PORT_FORWARDING_STATUS_FILE", libparams.Default("/forwarded_port"), libparams.CaseSensitiveValue())
|
||||
return models.Filepath(filepathStr), err
|
||||
}
|
||||
|
||||
// GetPIAEncryption obtains the encryption level for the PIA connection
|
||||
// from the environment variable ENCRYPTION
|
||||
func (p *paramsReader) GetPIAEncryption() (models.PIAEncryption, error) {
|
||||
s, err := p.envParams.GetValueIfInside("ENCRYPTION", []string{"normal", "strong"}, libparams.Default("strong"))
|
||||
return models.PIAEncryption(s), err
|
||||
// GetPIAEncryptionPreset obtains the encryption level for the PIA connection
|
||||
// from the environment variable PIA_ENCRYPTION, and using ENCRYPTION for
|
||||
// retro compatibility
|
||||
func (r *reader) GetPIAEncryptionPreset() (preset string, err error) {
|
||||
// Retro-compatibility
|
||||
s, err := r.envParams.GetValueIfInside("ENCRYPTION", []string{
|
||||
constants.PIAEncryptionPresetNormal,
|
||||
constants.PIAEncryptionPresetStrong,
|
||||
""})
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if len(s) != 0 {
|
||||
r.logger.Warn("You are using the old environment variable ENCRYPTION, please consider changing it to PIA_ENCRYPTION")
|
||||
return s, nil
|
||||
}
|
||||
return r.envParams.GetValueIfInside(
|
||||
"PIA_ENCRYPTION",
|
||||
[]string{
|
||||
constants.PIAEncryptionPresetNormal,
|
||||
constants.PIAEncryptionPresetStrong,
|
||||
},
|
||||
libparams.Default(constants.PIAEncryptionPresetStrong))
|
||||
}
|
||||
|
||||
// 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()
|
||||
s, err := p.envParams.GetValueIfInside("REGION", choices)
|
||||
func (r *reader) GetPIARegion() (region string, err error) {
|
||||
choices := append(constants.PIAGeoChoices(), "")
|
||||
s, err := r.envParams.GetValueIfInside("REGION", choices)
|
||||
if len(s) == 0 { // Suggestion by @rorph https://github.com/rorph
|
||||
s = choices[rand.Int()%len(choices)]
|
||||
s = choices[rand.Int()%len(choices)] //nolint:gosec
|
||||
}
|
||||
return models.PIARegion(s), err
|
||||
return s, err
|
||||
}
|
||||
|
||||
@@ -8,24 +8,24 @@ import (
|
||||
|
||||
// GetShadowSocks obtains if ShadowSocks is on from the environment variable
|
||||
// SHADOWSOCKS
|
||||
func (p *paramsReader) GetShadowSocks() (activated bool, err error) {
|
||||
return p.envParams.GetOnOff("SHADOWSOCKS", libparams.Default("off"))
|
||||
func (r *reader) GetShadowSocks() (activated bool, err error) {
|
||||
return r.envParams.GetOnOff("SHADOWSOCKS", libparams.Default("off"))
|
||||
}
|
||||
|
||||
// GetShadowSocksLog obtains the ShadowSocks log level from the environment variable
|
||||
// SHADOWSOCKS_LOG
|
||||
func (p *paramsReader) GetShadowSocksLog() (activated bool, err error) {
|
||||
return p.envParams.GetOnOff("SHADOWSOCKS_LOG", libparams.Default("off"))
|
||||
func (r *reader) GetShadowSocksLog() (activated bool, err error) {
|
||||
return r.envParams.GetOnOff("SHADOWSOCKS_LOG", libparams.Default("off"))
|
||||
}
|
||||
|
||||
// GetShadowSocksPort obtains the ShadowSocks listening port from the environment variable
|
||||
// SHADOWSOCKS_PORT
|
||||
func (p *paramsReader) GetShadowSocksPort() (port uint16, err error) {
|
||||
portStr, err := p.envParams.GetEnv("SHADOWSOCKS_PORT", libparams.Default("8388"))
|
||||
func (r *reader) GetShadowSocksPort() (port uint16, err error) {
|
||||
portStr, err := r.envParams.GetEnv("SHADOWSOCKS_PORT", libparams.Default("8388"))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := p.verifier.VerifyPort(portStr); err != nil {
|
||||
if err := r.verifier.VerifyPort(portStr); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
portUint64, err := strconv.ParseUint(portStr, 10, 16)
|
||||
@@ -34,7 +34,18 @@ func (p *paramsReader) GetShadowSocksPort() (port uint16, err error) {
|
||||
|
||||
// GetShadowSocksPassword obtains the ShadowSocks server password from the environment variable
|
||||
// SHADOWSOCKS_PASSWORD
|
||||
func (p *paramsReader) GetShadowSocksPassword() (password string, err error) {
|
||||
defer p.unsetEnv("SHADOWSOCKS_PASSWORD")
|
||||
return p.envParams.GetEnv("SHADOWSOCKS_PASSWORD")
|
||||
func (r *reader) GetShadowSocksPassword() (password string, err error) {
|
||||
defer func() {
|
||||
unsetErr := r.unsetEnv("SHADOWSOCKS_PASSWORD")
|
||||
if err == nil {
|
||||
err = unsetErr
|
||||
}
|
||||
}()
|
||||
return r.envParams.GetEnv("SHADOWSOCKS_PASSWORD", libparams.CaseSensitiveValue())
|
||||
}
|
||||
|
||||
// GetShadowSocksMethod obtains the ShadowSocks method to use from the environment variable
|
||||
// SHADOWSOCKS_METHOD
|
||||
func (r *reader) GetShadowSocksMethod() (method string, err error) {
|
||||
return r.envParams.GetEnv("SHADOWSOCKS_METHOD", libparams.Default("chacha20-ietf-poly1305"))
|
||||
}
|
||||
|
||||
12
internal/params/surfshark.go
Normal file
12
internal/params/surfshark.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package params
|
||||
|
||||
import (
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
)
|
||||
|
||||
// GetSurfsharkRegion obtains the region for the Surfshark server from the
|
||||
// environment variable REGION
|
||||
func (r *reader) GetSurfsharkRegion() (region string, err error) {
|
||||
s, err := r.envParams.GetValueIfInside("REGION", constants.SurfsharkRegionChoices())
|
||||
return s, err
|
||||
}
|
||||
28
internal/params/system.go
Normal file
28
internal/params/system.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package params
|
||||
|
||||
import (
|
||||
libparams "github.com/qdm12/golibs/params"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
// GetUID obtains the user ID to use from the environment variable UID
|
||||
func (r *reader) GetUID() (uid int, err error) {
|
||||
return r.envParams.GetEnvIntRange("UID", 0, 65535, libparams.Default("1000"))
|
||||
}
|
||||
|
||||
// GetGID obtains the group ID to use from the environment variable GID
|
||||
func (r *reader) GetGID() (gid int, err error) {
|
||||
return r.envParams.GetEnvIntRange("GID", 0, 65535, libparams.Default("1000"))
|
||||
}
|
||||
|
||||
// GetTZ obtains the timezone from the environment variable TZ
|
||||
func (r *reader) GetTimezone() (timezone string, err error) {
|
||||
return r.envParams.GetEnv("TZ")
|
||||
}
|
||||
|
||||
// GetIPStatusFilepath obtains the IP status file path
|
||||
// from the environment variable IP_STATUS_FILE
|
||||
func (r *reader) GetIPStatusFilepath() (filepath models.Filepath, err error) {
|
||||
filepathStr, err := r.envParams.GetPath("IP_STATUS_FILE", libparams.Default("/ip"), libparams.CaseSensitiveValue())
|
||||
return models.Filepath(filepathStr), err
|
||||
}
|
||||
@@ -9,50 +9,51 @@ import (
|
||||
|
||||
// GetTinyProxy obtains if TinyProxy is on from the environment variable
|
||||
// TINYPROXY, and using PROXY as a retro-compatibility name
|
||||
func (p *paramsReader) GetTinyProxy() (activated bool, err error) {
|
||||
func (r *reader) GetTinyProxy() (activated bool, err error) {
|
||||
// Retro-compatibility
|
||||
s, err := p.envParams.GetEnv("PROXY")
|
||||
s, err := r.envParams.GetEnv("PROXY")
|
||||
if err != nil {
|
||||
return false, err
|
||||
} else if len(s) != 0 {
|
||||
p.logger.Warn("You are using the old environment variable PROXY, please consider changing it to TINYPROXY")
|
||||
return p.envParams.GetOnOff("PROXY", libparams.Compulsory())
|
||||
r.logger.Warn("You are using the old environment variable PROXY, please consider changing it to TINYPROXY")
|
||||
return r.envParams.GetOnOff("PROXY", libparams.Compulsory())
|
||||
}
|
||||
return p.envParams.GetOnOff("TINYPROXY", libparams.Default("off"))
|
||||
return r.envParams.GetOnOff("TINYPROXY", libparams.Default("off"))
|
||||
}
|
||||
|
||||
// GetTinyProxyLog obtains the TinyProxy log level from the environment variable
|
||||
// TINYPROXY_LOG, and using PROXY_LOG_LEVEL as a retro-compatibility name
|
||||
func (p *paramsReader) GetTinyProxyLog() (models.TinyProxyLogLevel, error) {
|
||||
func (r *reader) GetTinyProxyLog() (models.TinyProxyLogLevel, error) {
|
||||
// Retro-compatibility
|
||||
s, err := p.envParams.GetEnv("PROXY_LOG_LEVEL")
|
||||
s, err := r.envParams.GetEnv("PROXY_LOG_LEVEL")
|
||||
if err != nil {
|
||||
return models.TinyProxyLogLevel(s), err
|
||||
} else if len(s) != 0 {
|
||||
p.logger.Warn("You are using the old environment variable PROXY_LOG_LEVEL, please consider changing it to TINYPROXY_LOG")
|
||||
s, err = p.envParams.GetValueIfInside("PROXY_LOG_LEVEL", []string{"Info", "Connect", "Notice", "Warning", "Error", "Critical"}, libparams.Compulsory())
|
||||
r.logger.Warn("You are using the old environment variable PROXY_LOG_LEVEL, please consider changing it to TINYPROXY_LOG")
|
||||
s, err = r.envParams.GetValueIfInside("PROXY_LOG_LEVEL", []string{"Info", "Connect", "Notice", "Warning", "Error", "Critical"}, libparams.Compulsory())
|
||||
return models.TinyProxyLogLevel(s), err
|
||||
}
|
||||
s, err = p.envParams.GetValueIfInside("TINYPROXY_LOG", []string{"Info", "Connect", "Notice", "Warning", "Error", "Critical"}, libparams.Default("Connect"))
|
||||
s, err = r.envParams.GetValueIfInside("TINYPROXY_LOG", []string{"Info", "Connect", "Notice", "Warning", "Error", "Critical"}, libparams.Default("Connect"))
|
||||
return models.TinyProxyLogLevel(s), err
|
||||
}
|
||||
|
||||
// GetTinyProxyPort obtains the TinyProxy listening port from the environment variable
|
||||
// TINYPROXY_PORT, and using PROXY_PORT as a retro-compatibility name
|
||||
func (p *paramsReader) GetTinyProxyPort() (port uint16, err error) {
|
||||
func (r *reader) GetTinyProxyPort() (port uint16, err error) {
|
||||
// Retro-compatibility
|
||||
portStr, err := p.envParams.GetEnv("PROXY_PORT")
|
||||
if err != nil {
|
||||
portStr, err := r.envParams.GetEnv("PROXY_PORT")
|
||||
switch {
|
||||
case err != nil:
|
||||
return 0, err
|
||||
} else if len(portStr) != 0 {
|
||||
p.logger.Warn("You are using the old environment variable PROXY_PORT, please consider changing it to TINYPROXY_PORT")
|
||||
} else {
|
||||
portStr, err = p.envParams.GetEnv("TINYPROXY_PORT", libparams.Default("8888"))
|
||||
case len(portStr) != 0:
|
||||
r.logger.Warn("You are using the old environment variable PROXY_PORT, please consider changing it to TINYPROXY_PORT")
|
||||
default:
|
||||
portStr, err = r.envParams.GetEnv("TINYPROXY_PORT", libparams.Default("8888"))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
if err := p.verifier.VerifyPort(portStr); err != nil {
|
||||
if err := r.verifier.VerifyPort(portStr); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
portUint64, err := strconv.ParseUint(portStr, 10, 16)
|
||||
@@ -61,34 +62,55 @@ func (p *paramsReader) GetTinyProxyPort() (port uint16, err error) {
|
||||
|
||||
// GetTinyProxyUser obtains the TinyProxy server user from the environment variable
|
||||
// TINYPROXY_USER, and using PROXY_USER as a retro-compatibility name
|
||||
func (p *paramsReader) GetTinyProxyUser() (user string, err error) {
|
||||
defer p.unsetEnv("PROXY_USER")
|
||||
defer p.unsetEnv("TINYPROXY_USER")
|
||||
func (r *reader) GetTinyProxyUser() (user string, err error) {
|
||||
defer func() {
|
||||
unsetErr := r.unsetEnv("PROXY_USER")
|
||||
if err == nil {
|
||||
err = unsetErr
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
unsetErr := r.unsetEnv("TINYPROXY_USER")
|
||||
if err == nil {
|
||||
err = unsetErr
|
||||
}
|
||||
}()
|
||||
// Retro-compatibility
|
||||
user, err = p.envParams.GetEnv("PROXY_USER")
|
||||
user, err = r.envParams.GetEnv("PROXY_USER", libparams.CaseSensitiveValue())
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
if len(user) != 0 {
|
||||
p.logger.Warn("You are using the old environment variable PROXY_USER, please consider changing it to TINYPROXY_USER")
|
||||
r.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 r.envParams.GetEnv("TINYPROXY_USER", libparams.CaseSensitiveValue())
|
||||
}
|
||||
|
||||
// GetTinyProxyPassword obtains the TinyProxy server password from the environment variable
|
||||
// TINYPROXY_PASSWORD, and using PROXY_PASSWORD as a retro-compatibility name
|
||||
func (p *paramsReader) GetTinyProxyPassword() (password string, err error) {
|
||||
defer p.unsetEnv("PROXY_PASSWORD")
|
||||
defer p.unsetEnv("TINYPROXY_PASSWORD")
|
||||
func (r *reader) GetTinyProxyPassword() (password string, err error) {
|
||||
defer func() {
|
||||
unsetErr := r.unsetEnv("PROXY_PASSWORD")
|
||||
if err == nil {
|
||||
err = unsetErr
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
unsetErr := r.unsetEnv("TINYPROXY_PASSWORD")
|
||||
if err == nil {
|
||||
err = unsetErr
|
||||
}
|
||||
}()
|
||||
|
||||
// Retro-compatibility
|
||||
password, err = p.envParams.GetEnv("PROXY_PASSWORD")
|
||||
password, err = r.envParams.GetEnv("PROXY_PASSWORD", libparams.CaseSensitiveValue())
|
||||
if err != nil {
|
||||
return password, err
|
||||
}
|
||||
if len(password) != 0 {
|
||||
p.logger.Warn("You are using the old environment variable PROXY_PASSWORD, please consider changing it to TINYPROXY_PASSWORD")
|
||||
r.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 r.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("?"))
|
||||
func (r *reader) GetVersion() string {
|
||||
version, _ := r.envParams.GetEnv("VERSION", libparams.Default("?"), libparams.CaseSensitiveValue())
|
||||
return version
|
||||
}
|
||||
|
||||
func (p *paramsReader) GetBuildDate() string {
|
||||
buildDate, _ := p.envParams.GetEnv("BUILD_DATE", params.Default("?"))
|
||||
func (r *reader) GetBuildDate() string {
|
||||
buildDate, _ := r.envParams.GetEnv("BUILD_DATE", libparams.Default("?"), libparams.CaseSensitiveValue())
|
||||
return buildDate
|
||||
}
|
||||
|
||||
func (p *paramsReader) GetVcsRef() string {
|
||||
buildDate, _ := p.envParams.GetEnv("VCS_REF", params.Default("?"))
|
||||
func (r *reader) GetVcsRef() string {
|
||||
buildDate, _ := r.envParams.GetEnv("VCS_REF", libparams.Default("?"), libparams.CaseSensitiveValue())
|
||||
return buildDate
|
||||
}
|
||||
|
||||
11
internal/params/vypervpn.go
Normal file
11
internal/params/vypervpn.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package params
|
||||
|
||||
import (
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
)
|
||||
|
||||
// GetVyprvpnRegion obtains the region for the Vyprvpn server from the
|
||||
// environment variable REGION
|
||||
func (r *reader) GetVyprvpnRegion() (region string, err error) {
|
||||
return r.envParams.GetValueIfInside("REGION", constants.VyprvpnRegionChoices())
|
||||
}
|
||||
43
internal/params/windscribe.go
Normal file
43
internal/params/windscribe.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package params
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
libparams "github.com/qdm12/golibs/params"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/constants"
|
||||
"github.com/qdm12/private-internet-access-docker/internal/models"
|
||||
)
|
||||
|
||||
// GetWindscribeRegion obtains the region for the Windscribe server from the
|
||||
// environment variable REGION
|
||||
func (r *reader) GetWindscribeRegion() (region string, err error) {
|
||||
s, err := r.envParams.GetValueIfInside("REGION", constants.WindscribeRegionChoices())
|
||||
return s, err
|
||||
}
|
||||
|
||||
// GetMullvadPort obtains the port to reach the Mullvad server on from the
|
||||
// environment variable PORT
|
||||
func (r *reader) GetWindscribePort(protocol models.NetworkProtocol) (port uint16, err error) {
|
||||
n, err := r.envParams.GetEnvIntRange("PORT", 0, 65535, libparams.Default("0"))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if n == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
switch protocol {
|
||||
case constants.TCP:
|
||||
switch n {
|
||||
case 21, 22, 80, 123, 143, 443, 587, 1194, 3306, 8080, 54783:
|
||||
default:
|
||||
return 0, fmt.Errorf("port %d is not valid for protocol %s", n, protocol)
|
||||
}
|
||||
case constants.UDP:
|
||||
switch n {
|
||||
case 53, 80, 123, 443, 1194, 54783:
|
||||
default:
|
||||
return 0, fmt.Errorf("port %d is not valid for protocol %s", n, protocol)
|
||||
}
|
||||
}
|
||||
return uint16(n), nil
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package pia
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"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
|
||||
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
|
||||
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",
|
||||
"dev tun",
|
||||
"nobind",
|
||||
"persist-key",
|
||||
"persist-tun",
|
||||
"tls-client",
|
||||
"remote-cert-tls server",
|
||||
"compress",
|
||||
"verb 1", // TODO env variable
|
||||
"reneg-sec 0",
|
||||
// Added constant values
|
||||
"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("auth-user-pass %s", constants.OpenVPNAuthConf),
|
||||
fmt.Sprintf("proto %s", string(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))
|
||||
}
|
||||
lines = append(lines, []string{
|
||||
"<crl-verify>",
|
||||
"-----BEGIN X509 CRL-----",
|
||||
X509CRL,
|
||||
"-----END X509 CRL-----",
|
||||
"</crl-verify>",
|
||||
}...)
|
||||
lines = append(lines, []string{
|
||||
"<ca>",
|
||||
"-----BEGIN CERTIFICATE-----",
|
||||
certificate,
|
||||
"-----END CERTIFICATE-----",
|
||||
"</ca>",
|
||||
"",
|
||||
}...)
|
||||
err = c.fileManager.WriteLinesToFile(string(constants.OpenVPNConf), lines, files.Ownership(uid, gid), files.Permissions(0400))
|
||||
return IPs, port, err
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user