mirror of
https://github.com/qdm12/gluetun.git
synced 2026-07-31 09:23:25 +02:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dff469cc70 |
+4
-55
@@ -4,63 +4,12 @@ updates:
|
|||||||
- package-ecosystem: "github-actions"
|
- package-ecosystem: "github-actions"
|
||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "weekly"
|
interval: "daily"
|
||||||
- package-ecosystem: docker
|
- package-ecosystem: docker
|
||||||
directory: /
|
directory: /
|
||||||
schedule:
|
schedule:
|
||||||
interval: "weekly"
|
interval: "daily"
|
||||||
- # Servers data dependency that should be updated as soon as
|
- package-ecosystem: gomod
|
||||||
# possible when a new version is released, to have the latest
|
directory: /
|
||||||
# servers available
|
|
||||||
package-ecosystem: "gomod"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
allow:
|
|
||||||
- dependency-name: "github.com/qdm12/gluetun-servers"
|
|
||||||
- # non important dependencies that do not need to be updated.
|
|
||||||
package-ecosystem: gomod
|
|
||||||
directory: /
|
|
||||||
schedule:
|
|
||||||
interval: "quarterly"
|
|
||||||
allow:
|
|
||||||
- dependency-name: "github.com/breml/rootcerts"
|
|
||||||
- dependency-name: "github.com/fatih/color"
|
|
||||||
- dependency-name: "github.com/golang/mock"
|
|
||||||
- dependency-name: "github.com/klauspost/compress"
|
|
||||||
- dependency-name: "github.com/klauspost/pgzip"
|
|
||||||
- dependency-name: "github.com/pelletier/go-toml/v2"
|
|
||||||
- dependency-name: "github.com/qdm12/goshutdown"
|
|
||||||
- dependency-name: "github.com/qdm12/gosplash"
|
|
||||||
- dependency-name: "github.com/qdm12/gotree"
|
|
||||||
- dependency-name: "github.com/qdm12/log"
|
|
||||||
- dependency-name: "github.com/stretchr/testify"
|
|
||||||
- dependency-name: "github.com/ulikunitz/xz"
|
|
||||||
- dependency-name: "gopkg.in/ini.v1"
|
|
||||||
- # The rest of Go modules are important and should be checked every week,
|
|
||||||
# instead of daily, to give a bit of time to avoid supply chain attacks.
|
|
||||||
package-ecosystem: gomod
|
|
||||||
directory: /
|
|
||||||
schedule:
|
|
||||||
interval: "weekly"
|
|
||||||
ignore:
|
|
||||||
- # In particular avoid amneziawg-go which have v1.x.y versions available
|
|
||||||
# on the Go modules proxy, but are not in the Github repository tags
|
|
||||||
# and are not the latest releases either. Most likely a mistake from the
|
|
||||||
# maintainers, which is persisted on the Go proxy.
|
|
||||||
dependency-name: "github.com/amnezia-vpn/amneziawg-go"
|
|
||||||
versions: ["1.x"]
|
|
||||||
- dependency-name: "github.com/qdm12/gluetun-servers"
|
|
||||||
- dependency-name: "github.com/breml/rootcerts"
|
|
||||||
- dependency-name: "github.com/fatih/color"
|
|
||||||
- dependency-name: "github.com/golang/mock"
|
|
||||||
- dependency-name: "github.com/klauspost/compress"
|
|
||||||
- dependency-name: "github.com/klauspost/pgzip"
|
|
||||||
- dependency-name: "github.com/pelletier/go-toml/v2"
|
|
||||||
- dependency-name: "github.com/qdm12/goshutdown"
|
|
||||||
- dependency-name: "github.com/qdm12/gosplash"
|
|
||||||
- dependency-name: "github.com/qdm12/gotree"
|
|
||||||
- dependency-name: "github.com/qdm12/log"
|
|
||||||
- dependency-name: "github.com/stretchr/testify"
|
|
||||||
- dependency-name: "github.com/ulikunitz/xz"
|
|
||||||
- dependency-name: "gopkg.in/ini.v1"
|
|
||||||
|
|||||||
@@ -8,4 +8,5 @@
|
|||||||
|
|
||||||
# Assertions
|
# Assertions
|
||||||
|
|
||||||
|
* [ ] I am aware that we do not accept manual changes to the servers.json file <!-- If this is your goal, please consult https://github.com/qdm12/gluetun-wiki/blob/main/setup/servers.md#update-using-the-command-line -->
|
||||||
* [ ] I am aware that any changes to settings should be reflected in the [wiki](https://github.com/qdm12/gluetun-wiki/)
|
* [ ] I am aware that any changes to settings should be reflected in the [wiki](https://github.com/qdm12/gluetun-wiki/)
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
name: Update servers list
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
provider:
|
||||||
|
description: "VPN Provider to update"
|
||||||
|
required: true
|
||||||
|
default: "all"
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- all
|
||||||
|
- airvpn
|
||||||
|
- cyberghost
|
||||||
|
- expressvpn
|
||||||
|
- fastestvpn
|
||||||
|
- giganews
|
||||||
|
- hidemyass
|
||||||
|
- ipvanish
|
||||||
|
- ivpn
|
||||||
|
- mullvad
|
||||||
|
- nordvpn
|
||||||
|
- perfect privacy
|
||||||
|
- privado
|
||||||
|
- private internet access
|
||||||
|
- privatevpn
|
||||||
|
- protonvpn
|
||||||
|
- purevpn
|
||||||
|
- slickvpn
|
||||||
|
- surfshark
|
||||||
|
- torguard
|
||||||
|
- vpnsecure
|
||||||
|
- vpn unlimited
|
||||||
|
- vyprvpn
|
||||||
|
- windscribe
|
||||||
|
schedule:
|
||||||
|
- cron: "11 3 1 */2 *" # Run at 03:11 on the 1st of every 2nd month
|
||||||
|
jobs:
|
||||||
|
update-servers-list:
|
||||||
|
if: github.repository == 'passteque/gluetun'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- uses: actions/setup-go@v6
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
- name: Update servers list
|
||||||
|
run: |
|
||||||
|
SELECTED_PROVIDER="${{ github.event.inputs.provider || 'all' }}"
|
||||||
|
|
||||||
|
if [ "$SELECTED_PROVIDER" = "all" ]; then
|
||||||
|
FLAGS="-all"
|
||||||
|
else
|
||||||
|
FLAGS="-providers $SELECTED_PROVIDER"
|
||||||
|
fi
|
||||||
|
|
||||||
|
go run ./cmd/gluetun/main.go update $FLAGS \
|
||||||
|
-maintainer \
|
||||||
|
-proton-email "${{ secrets.PROTON_EMAIL }}" \
|
||||||
|
-proton-password "${{ secrets.PROTON_PASSWORD }}"
|
||||||
|
|
||||||
|
- name: Check for changes
|
||||||
|
run: |
|
||||||
|
if git diff --exit-code internal/storage/servers.json >/dev/null; then
|
||||||
|
echo "Error: internal/storage/servers.json was not modified."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Check no other file changes
|
||||||
|
run: |
|
||||||
|
if ! git diff --exit-code --quiet ':!internal/storage/servers.json'; then
|
||||||
|
echo "Error: Unexpected changes detected in files other than servers.json"
|
||||||
|
git status --short
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Create Pull Request
|
||||||
|
id: createpr
|
||||||
|
uses: peter-evans/create-pull-request@v8
|
||||||
|
with:
|
||||||
|
branch-suffix: timestamp
|
||||||
|
branch: bot/update-servers-list
|
||||||
|
base: master
|
||||||
|
delete-branch: true
|
||||||
|
title: "feat(providers/${{ github.event.inputs.provider || 'all' }}): servers data update"
|
||||||
|
body: |
|
||||||
|
This PR was automatically generated by the [Update servers list](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) workflow run.
|
||||||
|
|
||||||
|
# - name: Merge Pull Request
|
||||||
|
# env:
|
||||||
|
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
# run: |
|
||||||
|
# gh pr merge ${{ steps.createpr.outputs.pull-request-number }} --auto -m -d
|
||||||
@@ -27,9 +27,10 @@ require (
|
|||||||
github.com/ti-mo/netfilter v0.5.3
|
github.com/ti-mo/netfilter v0.5.3
|
||||||
github.com/ulikunitz/xz v0.5.15
|
github.com/ulikunitz/xz v0.5.15
|
||||||
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a
|
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a
|
||||||
golang.org/x/net v0.55.0
|
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c
|
||||||
golang.org/x/sys v0.45.0
|
golang.org/x/net v0.53.0
|
||||||
golang.org/x/text v0.37.0
|
golang.org/x/sys v0.43.0
|
||||||
|
golang.org/x/text v0.36.0
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173
|
||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||||
gopkg.in/ini.v1 v1.67.1
|
gopkg.in/ini.v1 v1.67.1
|
||||||
@@ -56,11 +57,10 @@ require (
|
|||||||
github.com/prometheus/common v0.60.1 // indirect
|
github.com/prometheus/common v0.60.1 // indirect
|
||||||
github.com/prometheus/procfs v0.15.1 // indirect
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
|
||||||
golang.org/x/crypto v0.51.0 // indirect
|
golang.org/x/crypto v0.50.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
|
golang.org/x/mod v0.34.0 // indirect
|
||||||
golang.org/x/mod v0.35.0 // indirect
|
|
||||||
golang.org/x/sync v0.20.0 // indirect
|
golang.org/x/sync v0.20.0 // indirect
|
||||||
golang.org/x/tools v0.44.0 // indirect
|
golang.org/x/tools v0.43.0 // indirect
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
|
||||||
google.golang.org/protobuf v1.35.1 // indirect
|
google.golang.org/protobuf v1.35.1 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
|||||||
@@ -120,15 +120,15 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
|||||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||||
golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
|
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
|
||||||
golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
|
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
|
||||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
|
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
|
||||||
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
|
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
|
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
|
||||||
golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
|
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
@@ -136,8 +136,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
|
|||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||||
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
|
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
|
||||||
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
|
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -156,8 +156,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
|
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||||
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
@@ -167,8 +167,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
|
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
||||||
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
|
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
|
||||||
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
|
||||||
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
@@ -176,8 +176,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
|||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
|
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
|
||||||
golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
|
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package settings
|
package settings
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"maps"
|
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
"github.com/qdm12/gosettings/reader"
|
"github.com/qdm12/gosettings/reader"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
func readObsolete(r *reader.Reader) (warnings []string) {
|
func readObsolete(r *reader.Reader) (warnings []string) {
|
||||||
@@ -17,7 +17,7 @@ func readObsolete(r *reader.Reader) (warnings []string) {
|
|||||||
"DNS_KEEP_NAMESERVER": "DNS_KEEP_NAMESERVER is obsolete because you should use the built-in server which now " +
|
"DNS_KEEP_NAMESERVER": "DNS_KEEP_NAMESERVER is obsolete because you should use the built-in server which now " +
|
||||||
"forwards local names to private DNS resolvers found in /etc/resolv.conf at container start",
|
"forwards local names to private DNS resolvers found in /etc/resolv.conf at container start",
|
||||||
}
|
}
|
||||||
sortedKeys := slices.Collect(maps.Keys(keyToMessage))
|
sortedKeys := maps.Keys(keyToMessage)
|
||||||
slices.Sort(sortedKeys)
|
slices.Sort(sortedKeys)
|
||||||
warnings = make([]string, 0, len(keyToMessage))
|
warnings = make([]string, 0, len(keyToMessage))
|
||||||
for _, key := range sortedKeys {
|
for _, key := range sortedKeys {
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ func (p PortForwarding) Validate(vpnProvider string) (err error) {
|
|||||||
return errors.New("port forwarding password is empty")
|
return errors.New("port forwarding password is empty")
|
||||||
}
|
}
|
||||||
case providers.Protonvpn:
|
case providers.Protonvpn:
|
||||||
const maxPortsCount = 5
|
const maxPortsCount = 4
|
||||||
if p.PortsCount > maxPortsCount {
|
if p.PortsCount > maxPortsCount {
|
||||||
return fmt.Errorf("ports count too high: %d > %d", p.PortsCount, maxPortsCount)
|
return fmt.Errorf("ports count too high: %d > %d", p.PortsCount, maxPortsCount)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package iptables
|
package iptables
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@@ -96,24 +97,25 @@ func saveData(ctx context.Context, binary string) (data string, err error) {
|
|||||||
}
|
}
|
||||||
return "", fmt.Errorf("running %s-save: %w", binary, err)
|
return "", fmt.Errorf("running %s-save: %w", binary, err)
|
||||||
}
|
}
|
||||||
return filterData(output)
|
err = checkData(string(output))
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("checking saved data: %w", err)
|
||||||
|
}
|
||||||
|
return string(output), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterData(cmdOutput []byte) (filtered string, err error) {
|
func checkData(data string) error {
|
||||||
lines := strings.Split(string(cmdOutput), "\n")
|
scanner := bufio.NewScanner(strings.NewReader(data))
|
||||||
filteredLines := make([]string, 0, len(lines))
|
i := 0
|
||||||
for _, line := range lines {
|
for scanner.Scan() {
|
||||||
switch {
|
line := scanner.Text()
|
||||||
case strings.HasPrefix(line, ":DOCKER_OUTPUT"),
|
if strings.HasPrefix(line, "[unsupported") {
|
||||||
strings.HasPrefix(line, ":DOCKER_POSTROUTING"),
|
return fmt.Errorf("unsupported revision marker found in line %d: %s", i+1, line)
|
||||||
strings.HasPrefix(line, "-A DOCKER_OUTPUT"),
|
|
||||||
strings.HasPrefix(line, "-A DOCKER_POSTROUTING"):
|
|
||||||
// Do not touch (aka save and restore) NAT rules added by Docker
|
|
||||||
continue
|
|
||||||
case strings.Contains(line, "[unsupported revision]"):
|
|
||||||
return "", fmt.Errorf("mismatch container iptables-save and kernel: %s", line)
|
|
||||||
}
|
}
|
||||||
filteredLines = append(filteredLines, line)
|
i++
|
||||||
}
|
}
|
||||||
return strings.Join(filteredLines, "\n"), nil
|
if scanner.Err() != nil {
|
||||||
|
return fmt.Errorf("scanning data: %w", scanner.Err())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -278,6 +278,7 @@ func (c *Config) RedirectPort(ctx context.Context, intf string,
|
|||||||
appendOrDelete(remove), interfaceFlag, destinationPort),
|
appendOrDelete(remove), interfaceFlag, destinationPort),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
restore(ctx) // just in case
|
||||||
errMessage := err.Error()
|
errMessage := err.Error()
|
||||||
if strings.Contains(errMessage, "can't initialize ip6tables table `nat': Table does not exist") {
|
if strings.Contains(errMessage, "can't initialize ip6tables table `nat': Table does not exist") {
|
||||||
if !remove {
|
if !remove {
|
||||||
@@ -285,7 +286,6 @@ func (c *Config) RedirectPort(ctx context.Context, intf string,
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
restore(ctx)
|
|
||||||
return fmt.Errorf("redirecting IPv6 source port %d to destination port %d on interface %s: %w",
|
return fmt.Errorf("redirecting IPv6 source port %d to destination port %d on interface %s: %w",
|
||||||
sourcePort, destinationPort, intf, err)
|
sourcePort, destinationPort, intf, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,11 +15,7 @@ func runCommand(ctx context.Context, cmder Cmder, logger Logger,
|
|||||||
}
|
}
|
||||||
portsString := strings.Join(portStrings, ",")
|
portsString := strings.Join(portStrings, ",")
|
||||||
commandString := strings.ReplaceAll(commandTemplate, "{{PORTS}}", portsString)
|
commandString := strings.ReplaceAll(commandTemplate, "{{PORTS}}", portsString)
|
||||||
var firstPort string
|
commandString = strings.ReplaceAll(commandString, "{{PORT}}", portStrings[0])
|
||||||
if len(portStrings) > 0 {
|
|
||||||
firstPort = portStrings[0]
|
|
||||||
}
|
|
||||||
commandString = strings.ReplaceAll(commandString, "{{PORT}}", firstPort)
|
|
||||||
commandString = strings.ReplaceAll(commandString, "{{VPN_INTERFACE}}", vpnInterface)
|
commandString = strings.ReplaceAll(commandString, "{{VPN_INTERFACE}}", vpnInterface)
|
||||||
return cmder.RunAndLog(ctx, commandString, logger)
|
return cmder.RunAndLog(ctx, commandString, logger)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"slices"
|
"slices"
|
||||||
@@ -60,10 +59,6 @@ func (s *Service) SetPortsForwarded(ctx context.Context, ports []uint16) (err er
|
|||||||
s.portMutex.Lock()
|
s.portMutex.Lock()
|
||||||
defer s.portMutex.Unlock()
|
defer s.portMutex.Unlock()
|
||||||
|
|
||||||
if s.settings.PortForwarder != nil {
|
|
||||||
return errors.New("setting port forwarded at runtime is not supported with internally running port forwarding code")
|
|
||||||
}
|
|
||||||
|
|
||||||
slices.Sort(ports)
|
slices.Sort(ports)
|
||||||
if slices.Equal(s.ports, ports) {
|
if slices.Equal(s.ports, ports) {
|
||||||
return nil
|
return nil
|
||||||
@@ -83,5 +78,7 @@ func (s *Service) SetPortsForwarded(ctx context.Context, ports []uint16) (err er
|
|||||||
return fmt.Errorf("handling new ports: %w", err)
|
return fmt.Errorf("handling new ports: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.logger.Info("updated: " + portsToString(s.ports))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ func (s *Settings) Validate(forStartup bool) (err error) {
|
|||||||
return errors.New("password not set")
|
return errors.New("password not set")
|
||||||
}
|
}
|
||||||
case providers.Protonvpn:
|
case providers.Protonvpn:
|
||||||
const maxPortsCount = 5
|
const maxPortsCount = 4
|
||||||
if s.PortsCount > maxPortsCount {
|
if s.PortsCount > maxPortsCount {
|
||||||
return fmt.Errorf("ports count too high: %d > %d", s.PortsCount, maxPortsCount)
|
return fmt.Errorf("ports count too high: %d > %d", s.PortsCount, maxPortsCount)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,9 +92,13 @@ func (s *Service) onNewPorts(ctx context.Context, internalToExternalPorts map[ui
|
|||||||
s.logger.Info(portPairsToString(internalToExternalPorts))
|
s.logger.Info(portPairsToString(internalToExternalPorts))
|
||||||
|
|
||||||
externalPorts := slices.Collect(maps.Values(internalToExternalPorts))
|
externalPorts := slices.Collect(maps.Values(internalToExternalPorts))
|
||||||
|
autoRedirectionNeeded := false
|
||||||
externalToInternalPorts := make(map[uint16]uint16, len(internalToExternalPorts))
|
externalToInternalPorts := make(map[uint16]uint16, len(internalToExternalPorts))
|
||||||
for internal, external := range internalToExternalPorts {
|
for internal, external := range internalToExternalPorts {
|
||||||
externalToInternalPorts[external] = internal
|
externalToInternalPorts[external] = internal
|
||||||
|
if internal != external {
|
||||||
|
autoRedirectionNeeded = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
slices.Sort(externalPorts)
|
slices.Sort(externalPorts)
|
||||||
userRedirectionEnabled := !slices.Equal(s.settings.ListeningPorts, []uint16{0})
|
userRedirectionEnabled := !slices.Equal(s.settings.ListeningPorts, []uint16{0})
|
||||||
@@ -105,21 +109,23 @@ func (s *Service) onNewPorts(ctx context.Context, internalToExternalPorts map[ui
|
|||||||
return fmt.Errorf("allowing port in firewall: %w", err)
|
return fmt.Errorf("allowing port in firewall: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var destinationPort uint16
|
var sourcePort, destinationPort uint16
|
||||||
switch {
|
switch {
|
||||||
case userRedirectionEnabled: // precedence over auto redirection
|
case userRedirectionEnabled: // precedence over auto redirection
|
||||||
|
sourcePort = externalToInternalPorts[port]
|
||||||
destinationPort = s.settings.ListeningPorts[i]
|
destinationPort = s.settings.ListeningPorts[i]
|
||||||
case port != internalPort: // auto redirection needed, source and destination ports differ
|
case autoRedirectionNeeded:
|
||||||
|
sourcePort = externalToInternalPorts[port]
|
||||||
destinationPort = port
|
destinationPort = port
|
||||||
default:
|
default:
|
||||||
// No redirection needed, source and destination ports are the same.
|
// No redirection needed, source and destination ports are the same.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.portAllower.RedirectPort(ctx, s.settings.Interface, internalPort, destinationPort)
|
err = s.portAllower.RedirectPort(ctx, s.settings.Interface, sourcePort, destinationPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("redirecting port %d to %d in firewall: %w",
|
return fmt.Errorf("redirecting port %d to %d in firewall: %w",
|
||||||
internalPort, destinationPort, err)
|
sourcePort, destinationPort, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
"net/netip"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -13,14 +12,14 @@ import (
|
|||||||
"github.com/qdm12/gluetun/internal/provider/utils"
|
"github.com/qdm12/gluetun/internal/provider/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const nonSymmetricPortStart uint16 = 56789
|
||||||
|
|
||||||
// PortForward obtains a VPN server side port forwarded from ProtonVPN gateway.
|
// PortForward obtains a VPN server side port forwarded from ProtonVPN gateway.
|
||||||
func (p *Provider) PortForward(ctx context.Context, objects utils.PortForwardObjects) (
|
func (p *Provider) PortForward(ctx context.Context, objects utils.PortForwardObjects) (
|
||||||
internalToExternalPorts map[uint16]uint16, err error,
|
internalToExternalPorts map[uint16]uint16, err error,
|
||||||
) {
|
) {
|
||||||
if !objects.CanPortForward {
|
if !objects.CanPortForward {
|
||||||
return nil, errors.New("server does not support port forwarding")
|
return nil, errors.New("server does not support port forwarding")
|
||||||
} else if objects.PortsCount == 0 {
|
|
||||||
return nil, nil //nolint:nilnil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
client := natpmp.New()
|
client := natpmp.New()
|
||||||
@@ -40,75 +39,38 @@ func (p *Provider) PortForward(ctx context.Context, objects utils.PortForwardObj
|
|||||||
logger := objects.Logger
|
logger := objects.Logger
|
||||||
|
|
||||||
logger.Debug("gateway external IPv4 address is " + externalIPv4Address.String())
|
logger.Debug("gateway external IPv4 address is " + externalIPv4Address.String())
|
||||||
|
const externalPort = 0
|
||||||
p.internalToExternalPorts = make(map[uint16]uint16, objects.PortsCount)
|
|
||||||
const lifetime = 60 * time.Second
|
const lifetime = 60 * time.Second
|
||||||
|
|
||||||
// Only one port can be a symmetric mapping
|
p.internalToExternalPorts = make(map[uint16]uint16, objects.PortsCount)
|
||||||
const internalPort, externalPort = 0, 1
|
for i := range objects.PortsCount {
|
||||||
_, assignedExternalPort, err := addPortMappingTCPUDP(ctx,
|
internalPort := nonSymmetricPortStart + i
|
||||||
client, logger, objects.Gateway, internalPort, externalPort, lifetime)
|
protoToInternalPort := map[string]uint16{
|
||||||
// Note the returned assignedInternalPort is always 0 in this case
|
"udp": 0,
|
||||||
if err != nil {
|
"tcp": 0,
|
||||||
return nil, fmt.Errorf("adding first port mapping: %w", err)
|
}
|
||||||
|
protoToExternalPort := maps.Clone(protoToInternalPort)
|
||||||
|
for protocol := range protoToExternalPort {
|
||||||
|
_, assignedInternalPort, assignedExternalPort, assignedLifetime, err := client.AddPortMapping(
|
||||||
|
ctx, objects.Gateway, protocol, internalPort, externalPort, lifetime)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("adding %d/%d %s port mapping: %w",
|
||||||
|
i+1, objects.PortsCount, strings.ToUpper(protocol), err)
|
||||||
|
}
|
||||||
|
checkLifetime(logger, strings.ToUpper(protocol), lifetime, assignedLifetime)
|
||||||
|
checkInternalPort(logger, internalPort, assignedInternalPort)
|
||||||
|
protoToInternalPort[protocol] = assignedInternalPort
|
||||||
|
protoToExternalPort[protocol] = assignedExternalPort
|
||||||
}
|
}
|
||||||
p.internalToExternalPorts[assignedExternalPort] = assignedExternalPort
|
|
||||||
|
|
||||||
// Extra ports must be non-symmetric, meaning that the internal port is
|
checkInternalPorts(logger, protoToInternalPort["udp"], protoToInternalPort["tcp"])
|
||||||
// different from the external port.
|
checkExternalPorts(logger, protoToExternalPort["udp"], protoToExternalPort["tcp"])
|
||||||
const nonSymmetricPortStart = uint16(56789)
|
p.internalToExternalPorts[protoToInternalPort["tcp"]] = protoToExternalPort["tcp"]
|
||||||
nonSymmetricPortStartMinusOne := nonSymmetricPortStart - 1
|
|
||||||
if _, ok := p.internalToExternalPorts[nonSymmetricPortStart]; ok {
|
|
||||||
nonSymmetricPortStartMinusOne++
|
|
||||||
}
|
|
||||||
for i := uint16(1); i < objects.PortsCount; i++ {
|
|
||||||
internalPort := nonSymmetricPortStartMinusOne + i
|
|
||||||
const externalPort = 0
|
|
||||||
assignedInternalPort, assignedExternalPort, err := addPortMappingTCPUDP(ctx,
|
|
||||||
client, logger, objects.Gateway, internalPort, externalPort, lifetime)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("adding %d/%d port mapping: %w", i+1, objects.PortsCount, err)
|
|
||||||
}
|
|
||||||
p.internalToExternalPorts[assignedInternalPort] = assignedExternalPort
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return maps.Clone(p.internalToExternalPorts), nil
|
return maps.Clone(p.internalToExternalPorts), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addPortMappingTCPUDP(ctx context.Context, client *natpmp.Client, logger utils.Logger,
|
|
||||||
gateway netip.Addr, internalPort, externalPort uint16, lifetime time.Duration,
|
|
||||||
) (assignedInternalPort, assignedExternalPort uint16, err error) {
|
|
||||||
var assignedLifetime time.Duration
|
|
||||||
protocolToExternalPort := map[string]uint16{
|
|
||||||
"tcp": 0,
|
|
||||||
"udp": 0,
|
|
||||||
}
|
|
||||||
for _, protocol := range [...]string{"udp", "tcp"} {
|
|
||||||
protocolStr := strings.ToUpper(protocol)
|
|
||||||
_, assignedInternalPort, assignedExternalPort, assignedLifetime, err = client.AddPortMapping(
|
|
||||||
ctx, gateway, protocol, internalPort, externalPort, lifetime)
|
|
||||||
if err != nil {
|
|
||||||
return 0, 0, fmt.Errorf("adding %s port mapping: %w", protocolStr, err)
|
|
||||||
}
|
|
||||||
protocolToExternalPort[protocol] = assignedExternalPort
|
|
||||||
checkLifetime(logger, protocolStr, lifetime, assignedLifetime)
|
|
||||||
if internalPort != assignedInternalPort {
|
|
||||||
return 0, 0, fmt.Errorf("%s internal port requested as %d but received %d",
|
|
||||||
protocolStr, internalPort, assignedInternalPort)
|
|
||||||
} else if externalPort != 0 && externalPort != 1 && externalPort != assignedExternalPort {
|
|
||||||
return 0, 0, fmt.Errorf("%s external port requested as %d but received %d",
|
|
||||||
protocolStr, externalPort, assignedExternalPort)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if protocolToExternalPort["tcp"] != protocolToExternalPort["udp"] {
|
|
||||||
return 0, 0, fmt.Errorf("TCP and UDP external ports differ: %d and %d",
|
|
||||||
protocolToExternalPort["tcp"], protocolToExternalPort["udp"])
|
|
||||||
}
|
|
||||||
|
|
||||||
return assignedInternalPort, assignedExternalPort, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkLifetime(logger utils.Logger, protocol string,
|
func checkLifetime(logger utils.Logger, protocol string,
|
||||||
requested, actual time.Duration,
|
requested, actual time.Duration,
|
||||||
) {
|
) {
|
||||||
@@ -119,6 +81,27 @@ func checkLifetime(logger utils.Logger, protocol string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkInternalPort(logger utils.Logger, sent, received uint16) {
|
||||||
|
if sent != received {
|
||||||
|
logger.Warn(fmt.Sprintf("internal port assigned %d differs from requested internal port %d",
|
||||||
|
sent, received))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkInternalPorts(logger utils.Logger, udpPort, tcpPort uint16) {
|
||||||
|
if udpPort != tcpPort {
|
||||||
|
logger.Warn(fmt.Sprintf("UDP internal port %d differs from TCP internal port %d",
|
||||||
|
udpPort, tcpPort))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkExternalPorts(logger utils.Logger, udpPort, tcpPort uint16) {
|
||||||
|
if udpPort != tcpPort {
|
||||||
|
logger.Warn(fmt.Sprintf("UDP external port %d differs from TCP external port %d",
|
||||||
|
udpPort, tcpPort))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Provider) KeepPortForward(ctx context.Context,
|
func (p *Provider) KeepPortForward(ctx context.Context,
|
||||||
objects utils.PortForwardObjects,
|
objects utils.PortForwardObjects,
|
||||||
) (err error) {
|
) (err error) {
|
||||||
@@ -134,12 +117,22 @@ func (p *Provider) KeepPortForward(ctx context.Context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
objects.Logger.Debug("refreshing forwarded ports since 45 seconds have elapsed")
|
objects.Logger.Debug("refreshing forwarded ports since 45 seconds have elapsed")
|
||||||
|
networkProtocols := [...]string{"udp", "tcp"}
|
||||||
const lifetime = 60 * time.Second
|
const lifetime = 60 * time.Second
|
||||||
for internalPort, externalPort := range p.internalToExternalPorts {
|
for internalPort, externalPort := range p.internalToExternalPorts {
|
||||||
_, _, err := addPortMappingTCPUDP(ctx, client, logger, objects.Gateway, internalPort, externalPort, lifetime)
|
for _, networkProtocol := range networkProtocols {
|
||||||
|
_, assignedInternalPort, assignedExternalPort, assignedLiftetime, err := client.AddPortMapping(
|
||||||
|
ctx, objects.Gateway, networkProtocol, internalPort, externalPort, lifetime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("refreshing port mapping for internal port %d and external port %d: %w",
|
return fmt.Errorf("adding port mapping: %w", err)
|
||||||
internalPort, externalPort, err)
|
}
|
||||||
|
checkLifetime(logger, networkProtocol, lifetime, assignedLiftetime)
|
||||||
|
if externalPort != assignedExternalPort {
|
||||||
|
return fmt.Errorf("external port changed from %d to %d", externalPort, assignedExternalPort)
|
||||||
|
} else if internalPort != assignedInternalPort {
|
||||||
|
return fmt.Errorf("internal port changed from %d (for external port %d) to %d",
|
||||||
|
internalPort, externalPort, assignedInternalPort)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
objects.Logger.Debug(fmt.Sprintf("port forwarded %d maintained", externalPort))
|
objects.Logger.Debug(fmt.Sprintf("port forwarded %d maintained", externalPort))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,19 @@
|
|||||||
# Maintenance
|
# Maintenance
|
||||||
|
|
||||||
- Change `Run` methods to `Start`+`Stop`, returning channels rather than injecting them
|
- Change `Run` methods to `Start`+`Stop`, returning channels rather than injecting them
|
||||||
|
- Go 1.18
|
||||||
|
- gofumpt
|
||||||
|
- Use netip
|
||||||
|
- Split servers.json
|
||||||
- Common slice of Wireguard providers in config settings
|
- Common slice of Wireguard providers in config settings
|
||||||
- DNS block lists as LFS and built in image
|
- DNS block lists as LFS and built in image
|
||||||
- Add HTTP server v3 as json rpc
|
- Add HTTP server v3 as json rpc
|
||||||
- Use `github.com/qdm12/ddns-updater/pkg/publicip`
|
- Use `github.com/qdm12/ddns-updater/pkg/publicip`
|
||||||
|
- Windows and Darwin development support
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
- Authentication with the control server
|
||||||
- Get announcement from Github file
|
- Get announcement from Github file
|
||||||
- Support multiple connections in custom ovpn
|
- Support multiple connections in custom ovpn
|
||||||
- Automate IPv6 detection for OpenVPN
|
- Automate IPv6 detection for OpenVPN
|
||||||
|
|||||||
Reference in New Issue
Block a user