Compare commits

..

8 Commits

Author SHA1 Message Date
Quentin McGaw 4a670635c4 log out json from dns leak test 2026-06-24 22:25:32 +00:00
Quentin McGaw b5f815640e SERVER_DEDICATED option 2026-06-24 22:12:30 +00:00
Quentin McGaw 506c9140ba PR feedback 2026-06-24 22:12:30 +00:00
Quentin McGaw 80763145dc Remove unneeded allow-compression asym 2026-06-24 22:12:30 +00:00
Quentin McGaw cfb8fcf00f Add missing "key-direction 1" 2026-06-24 22:12:30 +00:00
Quentin McGaw b9421221da Set TLS crypt for Singapore hostnames only 2026-06-24 22:12:30 +00:00
Quentin McGaw 83feb533de Add missing openvpn options
- CA
- TLS auth
- TLS crypt (for singapore)
- `allow-compression asym`
- `replay-window 256`
- remote-cert-tls server
- move aes256gcm as preferred cipher
2026-06-24 22:12:30 +00:00
Quentin McGaw 1b12dcb5b4 initial code 2026-06-24 22:12:29 +00:00
113 changed files with 1400 additions and 1622 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
FROM ghcr.io/qdm12/godevcontainer:v0.22-alpine FROM ghcr.io/qdm12/godevcontainer:v0.21-alpine
RUN apk add wireguard-tools htop openssl tcpdump iptables RUN apk add wireguard-tools htop openssl tcpdump iptables
RUN apk add nodejs npm && npm install markdownlint-cli2 --global && apk del npm RUN apk add nodejs npm && npm install markdownlint-cli2 --global && apk del npm
+1
View File
@@ -56,6 +56,7 @@ body:
- IVPN - IVPN
- Mullvad - Mullvad
- NordVPN - NordVPN
- OVPN
- Privado - Privado
- Private Internet Access - Private Internet Access
- PrivateVPN - PrivateVPN
+2
View File
@@ -64,6 +64,8 @@
color: "cfe8d4" color: "cfe8d4"
- name: "☁️ NordVPN" - name: "☁️ NordVPN"
color: "cfe8d4" color: "cfe8d4"
- name: "☁️ OVPN"
color: "cfe8d4"
- name: "☁️ Perfect Privacy" - name: "☁️ Perfect Privacy"
color: "cfe8d4" color: "cfe8d4"
- name: "☁️ PIA" - name: "☁️ PIA"
-6
View File
@@ -67,10 +67,6 @@ jobs:
-v "$(pwd)/coverage.txt:/tmp/gobuild/coverage.txt" \ -v "$(pwd)/coverage.txt:/tmp/gobuild/coverage.txt" \
test-container test-container
- name: Run integration tests in test container
run: |
docker run --rm --entrypoint go test-container test -tags=integration ./internal/restrictednet
- name: Verify dev cross platform compatibility - name: Verify dev cross platform compatibility
run: docker build --target xcompile . run: docker build --target xcompile .
@@ -241,5 +237,3 @@ jobs:
VERSION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }} VERSION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
push: true push: true
provenance: mode=max
sbom: true
-5
View File
@@ -50,7 +50,6 @@ Guidance for coding agents working in this repository.
- Prefer splitting a code line only when it triggers the `lll` linter, do not split a command or arguments list for each element - Prefer splitting a code line only when it triggers the `lll` linter, do not split a command or arguments list for each element
- Use `netip` types instead of `net` types whenever possible - Use `netip` types instead of `net` types whenever possible
- Use constants instead of variables whenever possible, especially function-local inline constants. - Use constants instead of variables whenever possible, especially function-local inline constants.
- Prefer using pure functions over methods when possible. Especially if the method does not need any fields from the receiving struct, it should be a pure function.
- Do not use `time.Sleep`, prefer using a `time.Timer` with a `select` statement also listening on a context cancelation - Do not use `time.Sleep`, prefer using a `time.Timer` with a `select` statement also listening on a context cancelation
- `panic`: - `panic`:
- should only be used when a programming error is encountered and you should NOT return errors for programming errors (such as passing nil objects) - should only be used when a programming error is encountered and you should NOT return errors for programming errors (such as passing nil objects)
@@ -116,7 +115,6 @@ Mocking works with the `go.uber.org/mock` library, and the `mockgen` tool.
- **Never** use `.AnyTimes()` on mocks. Always define the number of times a certain mock call should be called, with `.Times(3)` for example. - **Never** use `.AnyTimes()` on mocks. Always define the number of times a certain mock call should be called, with `.Times(3)` for example.
- **Always** set the `.Return(...)` on the mock if the function returns something. - **Always** set the `.Return(...)` on the mock if the function returns something.
- Avoid using **mock helpers** functions, prefer a bit of repetition than tight coupling and dependency - Avoid using **mock helpers** functions, prefer a bit of repetition than tight coupling and dependency
- Always define the gomock controller `ctrl` in the subtest and not in the parent test, or a subtest mock failing will crash all the other subtests.
### main.go ### main.go
@@ -129,7 +127,6 @@ The Go formatter used is gofumpt.
### Errors ### Errors
- Always prefer wrapping errors with some context with `fmt.Errorf("doing this: %w", err)` - Always prefer wrapping errors with some context with `fmt.Errorf("doing this: %w", err)`
- Use `errors.New("error message")` when creating a 'bottom' constant string error without additional context, instead of `fmt.Errorf`
- In rare cases, you can just use `return err` notably: - In rare cases, you can just use `return err` notably:
- If the function is called **recursively**, since we don't wrap the wrapping multiple times for each recursion - If the function is called **recursively**, since we don't wrap the wrapping multiple times for each recursion
- If the current function only statement is the call to another function, for example: - If the current function only statement is the call to another function, for example:
@@ -182,8 +179,6 @@ The Go formatter used is gofumpt.
- Do not use `http.DefaultClient`, use a custom `*http.Client` with a fixed timeout and share with dependency injections. - Do not use `http.DefaultClient`, use a custom `*http.Client` with a fixed timeout and share with dependency injections.
- Do not check for injected dependencies being `nil`, prefer to just panic on a nil pointer. By default it's fine to panic if a developer injects a dependency `nil`. `nil` does not mean use a default. - Do not check for injected dependencies being `nil`, prefer to just panic on a nil pointer. By default it's fine to panic if a developer injects a dependency `nil`. `nil` does not mean use a default.
- Prefer using a `switch { case ...}` statement over multiple consecutive `if` statements to have shorter code.
- Prefer using `[...]T` instead of `[]T` when the length is fixed and known at compile time, to avoid unnecessary allocations.
## Validation checklist ## Validation checklist
+5 -2
View File
@@ -3,7 +3,7 @@ ARG GO_ALPINE_VERSION=3.23
ARG GO_VERSION=1.25 ARG GO_VERSION=1.25
ARG XCPUTRANSLATE_VERSION=v0.9.0 ARG XCPUTRANSLATE_VERSION=v0.9.0
ARG GOLANGCI_LINT_VERSION=v2.4.0 ARG GOLANGCI_LINT_VERSION=v2.4.0
ARG MOCKGEN_VERSION=v0.6.0 ARG MOCKGEN_VERSION=v1.6.0
ARG BUILDPLATFORM=linux/amd64 ARG BUILDPLATFORM=linux/amd64
FROM --platform=${BUILDPLATFORM} ghcr.io/qdm12/xcputranslate:${XCPUTRANSLATE_VERSION} AS xcputranslate FROM --platform=${BUILDPLATFORM} ghcr.io/qdm12/xcputranslate:${XCPUTRANSLATE_VERSION} AS xcputranslate
@@ -186,12 +186,14 @@ ENV VPN_SERVICE_PROVIDER=pia \
# # ProtonVPN only: # # ProtonVPN only:
SECURE_CORE_ONLY= \ SECURE_CORE_ONLY= \
TOR_ONLY= \ TOR_ONLY= \
# # Surfshark only: # # Surfshark and ovpn only:
MULTIHOP_ONLY= \ MULTIHOP_ONLY= \
# # VPN Secure only: # # VPN Secure only:
PREMIUM_ONLY= \ PREMIUM_ONLY= \
# # PIA and ProtonVPN only: # # PIA and ProtonVPN only:
PORT_FORWARD_ONLY= \ PORT_FORWARD_ONLY= \
# # Ovpn only:
SERVER_DEDICATED=no \
# Firewall # Firewall
FIREWALL_ENABLED_DISABLING_IT_SHOOTS_YOU_IN_YOUR_FOOT=on \ FIREWALL_ENABLED_DISABLING_IT_SHOOTS_YOU_IN_YOUR_FOOT=on \
FIREWALL_VPN_INPUT_PORTS= \ FIREWALL_VPN_INPUT_PORTS= \
@@ -218,6 +220,7 @@ ENV VPN_SERVICE_PROVIDER=pia \
DNS_CACHING=on \ DNS_CACHING=on \
DNS_UPSTREAM_IPV6=off \ DNS_UPSTREAM_IPV6=off \
BLOCK_MALICIOUS=on \ BLOCK_MALICIOUS=on \
BLOCK_SURVEILLANCE=off \
BLOCK_ADS=off \ BLOCK_ADS=off \
DNS_UNBLOCK_HOSTNAMES= \ DNS_UNBLOCK_HOSTNAMES= \
DNS_REBINDING_PROTECTION_EXEMPT_HOSTNAMES= \ DNS_REBINDING_PROTECTION_EXEMPT_HOSTNAMES= \
+3 -3
View File
@@ -60,16 +60,16 @@ Lightweight swiss-army-knife-like VPN client to multiple VPN service providers
## Features ## Features
- Based on Alpine 3.23 for a small Docker image of 43.1MB - Based on Alpine 3.23 for a small Docker image of 43.1MB
- Supports: **AirVPN**, **Cyberghost**, **ExpressVPN**, **FastestVPN**, **Giganews**, **HideMyAss**, **IPVanish**, **IVPN**, **Mullvad** (Wireguard only), **NordVPN**, **Perfect Privacy**, **Privado**, **Private Internet Access**, **PrivateVPN**, **ProtonVPN**, **PureVPN**, **SlickVPN**, **Surfshark**, **TorGuard**, **VPNSecure.me**, **VPNUnlimited**, **Vyprvpn**, **Windscribe** servers - Supports: **AirVPN**, **Cyberghost**, **ExpressVPN**, **FastestVPN**, **Giganews**, **HideMyAss**, **IPVanish**, **IVPN**, **Mullvad** (Wireguard only), **NordVPN**, **Ovpn**, **Perfect Privacy**, **Privado**, **Private Internet Access**, **PrivateVPN**, **ProtonVPN**, **PureVPN**, **SlickVPN**, **Surfshark**, **TorGuard**, **VPNSecure.me**, **VPNUnlimited**, **Vyprvpn**, **Windscribe** servers
- Supports OpenVPN for all providers listed - Supports OpenVPN for all providers listed
- Supports Wireguard both kernelspace and userspace - Supports Wireguard both kernelspace and userspace
- For **AirVPN**, **FastestVPN**, **Ivpn**, **Mullvad**, **NordVPN**, **Perfect privacy**, **ProtonVPN**, **Surfshark** and **Windscribe** - For **AirVPN**, **FastestVPN**, **Ivpn**, **Mullvad**, **NordVPN**, **Ovpn**, **Perfect privacy**, **ProtonVPN**, **Surfshark** and **Windscribe**
- For **Cyberghost**, **Private Internet Access**, **PrivateVPN**, **PureVPN**, **Torguard**, **VPN Unlimited** and **VyprVPN** using [the custom provider](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/custom.md) - For **Cyberghost**, **Private Internet Access**, **PrivateVPN**, **PureVPN**, **Torguard**, **VPN Unlimited** and **VyprVPN** using [the custom provider](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/custom.md)
- For custom Wireguard configurations using [the custom provider](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/custom.md) - For custom Wireguard configurations using [the custom provider](https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/custom.md)
- More in progress, see [#134](https://github.com/passteque/gluetun/issues/134) - More in progress, see [#134](https://github.com/passteque/gluetun/issues/134)
- Supports AmneziaWG only with the custom provider for now - Supports AmneziaWG only with the custom provider for now
- DNS over TLS baked in with service provider(s) of your choice - DNS over TLS baked in with service provider(s) of your choice
- DNS fine blocking of malicious/ads hostnames and IP addresses, with live update every 24 hours - DNS fine blocking of malicious/ads/surveillance hostnames and IP addresses, with live update every 24 hours
- Choose the vpn network protocol, `udp` or `tcp` - Choose the vpn network protocol, `udp` or `tcp`
- Built in firewall kill switch to allow traffic only with needed the VPN servers and LAN devices - Built in firewall kill switch to allow traffic only with needed the VPN servers and LAN devices
- Built in Shadowsocks proxy server (protocol based on SOCKS5 with an encryption layer, tunnels TCP+UDP) - Built in Shadowsocks proxy server (protocol based on SOCKS5 with an encryption layer, tunnels TCP+UDP)
+2 -2
View File
@@ -7,6 +7,7 @@ require (
github.com/amnezia-vpn/amneziawg-go v0.2.18 github.com/amnezia-vpn/amneziawg-go v0.2.18
github.com/breml/rootcerts v0.3.4 github.com/breml/rootcerts v0.3.4
github.com/fatih/color v1.18.0 github.com/fatih/color v1.18.0
github.com/golang/mock v1.6.0
github.com/jsimonetti/rtnetlink v1.4.2 github.com/jsimonetti/rtnetlink v1.4.2
github.com/klauspost/compress v1.18.4 github.com/klauspost/compress v1.18.4
github.com/klauspost/pgzip v1.2.6 github.com/klauspost/pgzip v1.2.6
@@ -15,7 +16,7 @@ require (
github.com/miekg/dns v1.1.62 github.com/miekg/dns v1.1.62
github.com/pelletier/go-toml/v2 v2.2.4 github.com/pelletier/go-toml/v2 v2.2.4
github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260421173011-9de8e7fdbe3a github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260421173011-9de8e7fdbe3a
github.com/qdm12/gluetun-servers v0.1.0 github.com/qdm12/gluetun-servers v0.1.1-0.20260522005421-14277e92ce82
github.com/qdm12/goservices v0.1.1-0.20251104135713-6bee97bd4978 github.com/qdm12/goservices v0.1.1-0.20251104135713-6bee97bd4978
github.com/qdm12/gosettings v0.4.4 github.com/qdm12/gosettings v0.4.4
github.com/qdm12/goshutdown v0.3.0 github.com/qdm12/goshutdown v0.3.0
@@ -27,7 +28,6 @@ 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
go.uber.org/mock v0.6.0
golang.org/x/net v0.55.0 golang.org/x/net v0.55.0
golang.org/x/sys v0.45.0 golang.org/x/sys v0.45.0
golang.org/x/text v0.38.0 golang.org/x/text v0.38.0
+12 -4
View File
@@ -76,8 +76,8 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260421173011-9de8e7fdbe3a h1:TE157yPQmAbVruH0MWCQzs0vTT/6t96DkoWUXd6PVuc= github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260421173011-9de8e7fdbe3a h1:TE157yPQmAbVruH0MWCQzs0vTT/6t96DkoWUXd6PVuc=
github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260421173011-9de8e7fdbe3a/go.mod h1:98foWgXJZ+g8gJIuO+fdO+oWpFei5WShMFTeN4Im2lE= github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260421173011-9de8e7fdbe3a/go.mod h1:98foWgXJZ+g8gJIuO+fdO+oWpFei5WShMFTeN4Im2lE=
github.com/qdm12/gluetun-servers v0.1.0 h1:w9JLghKZwI0Gzpp9p5rNANgEYUUZ1dxdxsG6NKIojaY= github.com/qdm12/gluetun-servers v0.1.1-0.20260522005421-14277e92ce82 h1:tE44IEW7o9yPQaO8HBeoO9RxtTTxqhboIypegrQlVt8=
github.com/qdm12/gluetun-servers v0.1.0/go.mod h1:acttuyHyoFDu6GTbf3kAV+QXeiX8oJeh0MBic67/9z8= github.com/qdm12/gluetun-servers v0.1.1-0.20260522005421-14277e92ce82/go.mod h1:acttuyHyoFDu6GTbf3kAV+QXeiX8oJeh0MBic67/9z8=
github.com/qdm12/goservices v0.1.1-0.20251104135713-6bee97bd4978 h1:TRGpCU1l0lNwtogEUSs5U+RFceYxkAJUmrGabno7J5c= github.com/qdm12/goservices v0.1.1-0.20251104135713-6bee97bd4978 h1:TRGpCU1l0lNwtogEUSs5U+RFceYxkAJUmrGabno7J5c=
github.com/qdm12/goservices v0.1.1-0.20251104135713-6bee97bd4978/go.mod h1:D1Po4CRQLYjccnAR2JsVlN1sBMgQrcNLONbvyuzcdTg= github.com/qdm12/goservices v0.1.1-0.20251104135713-6bee97bd4978/go.mod h1:D1Po4CRQLYjccnAR2JsVlN1sBMgQrcNLONbvyuzcdTg=
github.com/qdm12/gosettings v0.4.4 h1:SM6tOZDf6k8qbjWU8KWyBF4mWIixfsKCfh9DGRLHlj4= github.com/qdm12/gosettings v0.4.4 h1:SM6tOZDf6k8qbjWU8KWyBF4mWIixfsKCfh9DGRLHlj4=
@@ -111,12 +111,12 @@ github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4= github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
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=
@@ -124,6 +124,7 @@ golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
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.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.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
@@ -131,12 +132,14 @@ golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
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=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
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.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
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-20220722155255-886fb9371eb4/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.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
@@ -144,6 +147,8 @@ golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -168,11 +173,14 @@ 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=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
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.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
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-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg=
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4= golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uIfPMv78iAJGcPKDeqAFnaLBropIC4=
+23 -29
View File
@@ -1,10 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/qdm12/gluetun/internal/amneziawg (interfaces: Logger) // Source: github.com/qdm12/gluetun/internal/amneziawg (interfaces: Logger)
//
// Generated by this command:
//
// mockgen -destination=log_mock_test.go -package amneziawg . Logger
//
// Package amneziawg is a generated GoMock package. // Package amneziawg is a generated GoMock package.
package amneziawg package amneziawg
@@ -12,14 +7,13 @@ package amneziawg
import ( import (
reflect "reflect" reflect "reflect"
gomock "go.uber.org/mock/gomock" gomock "github.com/golang/mock/gomock"
) )
// MockLogger is a mock of Logger interface. // MockLogger is a mock of Logger interface.
type MockLogger struct { type MockLogger struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockLoggerMockRecorder recorder *MockLoggerMockRecorder
isgomock struct{}
} }
// MockLoggerMockRecorder is the mock recorder for MockLogger. // MockLoggerMockRecorder is the mock recorder for MockLogger.
@@ -40,71 +34,71 @@ func (m *MockLogger) EXPECT() *MockLoggerMockRecorder {
} }
// Debug mocks base method. // Debug mocks base method.
func (m *MockLogger) Debug(s string) { func (m *MockLogger) Debug(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Debug", s) m.ctrl.Call(m, "Debug", arg0)
} }
// Debug indicates an expected call of Debug. // Debug indicates an expected call of Debug.
func (mr *MockLoggerMockRecorder) Debug(s any) *gomock.Call { func (mr *MockLoggerMockRecorder) Debug(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debug", reflect.TypeOf((*MockLogger)(nil).Debug), s) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debug", reflect.TypeOf((*MockLogger)(nil).Debug), arg0)
} }
// Debugf mocks base method. // Debugf mocks base method.
func (m *MockLogger) Debugf(format string, args ...any) { func (m *MockLogger) Debugf(arg0 string, arg1 ...interface{}) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
varargs := []any{format} varargs := []interface{}{arg0}
for _, a := range args { for _, a := range arg1 {
varargs = append(varargs, a) varargs = append(varargs, a)
} }
m.ctrl.Call(m, "Debugf", varargs...) m.ctrl.Call(m, "Debugf", varargs...)
} }
// Debugf indicates an expected call of Debugf. // Debugf indicates an expected call of Debugf.
func (mr *MockLoggerMockRecorder) Debugf(format any, args ...any) *gomock.Call { func (mr *MockLoggerMockRecorder) Debugf(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
varargs := append([]any{format}, args...) varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debugf", reflect.TypeOf((*MockLogger)(nil).Debugf), varargs...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debugf", reflect.TypeOf((*MockLogger)(nil).Debugf), varargs...)
} }
// Error mocks base method. // Error mocks base method.
func (m *MockLogger) Error(s string) { func (m *MockLogger) Error(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Error", s) m.ctrl.Call(m, "Error", arg0)
} }
// Error indicates an expected call of Error. // Error indicates an expected call of Error.
func (mr *MockLoggerMockRecorder) Error(s any) *gomock.Call { func (mr *MockLoggerMockRecorder) Error(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockLogger)(nil).Error), s) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockLogger)(nil).Error), arg0)
} }
// Errorf mocks base method. // Errorf mocks base method.
func (m *MockLogger) Errorf(format string, args ...any) { func (m *MockLogger) Errorf(arg0 string, arg1 ...interface{}) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
varargs := []any{format} varargs := []interface{}{arg0}
for _, a := range args { for _, a := range arg1 {
varargs = append(varargs, a) varargs = append(varargs, a)
} }
m.ctrl.Call(m, "Errorf", varargs...) m.ctrl.Call(m, "Errorf", varargs...)
} }
// Errorf indicates an expected call of Errorf. // Errorf indicates an expected call of Errorf.
func (mr *MockLoggerMockRecorder) Errorf(format any, args ...any) *gomock.Call { func (mr *MockLoggerMockRecorder) Errorf(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
varargs := append([]any{format}, args...) varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Errorf", reflect.TypeOf((*MockLogger)(nil).Errorf), varargs...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Errorf", reflect.TypeOf((*MockLogger)(nil).Errorf), varargs...)
} }
// Info mocks base method. // Info mocks base method.
func (m *MockLogger) Info(s string) { func (m *MockLogger) Info(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Info", s) m.ctrl.Call(m, "Info", arg0)
} }
// Info indicates an expected call of Info. // Info indicates an expected call of Info.
func (mr *MockLoggerMockRecorder) Info(s any) *gomock.Call { func (mr *MockLoggerMockRecorder) Info(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockLogger)(nil).Info), s) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockLogger)(nil).Info), arg0)
} }
+41 -47
View File
@@ -1,10 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/qdm12/gluetun/internal/amneziawg (interfaces: NetLinker) // Source: github.com/qdm12/gluetun/internal/amneziawg (interfaces: NetLinker)
//
// Generated by this command:
//
// mockgen -destination=netlinker_mock_test.go -package amneziawg . NetLinker
//
// Package amneziawg is a generated GoMock package. // Package amneziawg is a generated GoMock package.
package amneziawg package amneziawg
@@ -13,15 +8,14 @@ import (
netip "net/netip" netip "net/netip"
reflect "reflect" reflect "reflect"
gomock "github.com/golang/mock/gomock"
netlink "github.com/qdm12/gluetun/internal/netlink" netlink "github.com/qdm12/gluetun/internal/netlink"
gomock "go.uber.org/mock/gomock"
) )
// MockNetLinker is a mock of NetLinker interface. // MockNetLinker is a mock of NetLinker interface.
type MockNetLinker struct { type MockNetLinker struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockNetLinkerMockRecorder recorder *MockNetLinkerMockRecorder
isgomock struct{}
} }
// MockNetLinkerMockRecorder is the mock recorder for MockNetLinker. // MockNetLinkerMockRecorder is the mock recorder for MockNetLinker.
@@ -42,17 +36,17 @@ func (m *MockNetLinker) EXPECT() *MockNetLinkerMockRecorder {
} }
// AddrReplace mocks base method. // AddrReplace mocks base method.
func (m *MockNetLinker) AddrReplace(linkIndex uint32, addr netip.Prefix) error { func (m *MockNetLinker) AddrReplace(arg0 uint32, arg1 netip.Prefix) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddrReplace", linkIndex, addr) ret := m.ctrl.Call(m, "AddrReplace", arg0, arg1)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// AddrReplace indicates an expected call of AddrReplace. // AddrReplace indicates an expected call of AddrReplace.
func (mr *MockNetLinkerMockRecorder) AddrReplace(linkIndex, addr any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) AddrReplace(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrReplace", reflect.TypeOf((*MockNetLinker)(nil).AddrReplace), linkIndex, addr) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrReplace", reflect.TypeOf((*MockNetLinker)(nil).AddrReplace), arg0, arg1)
} }
// IsWireguardSupported mocks base method. // IsWireguardSupported mocks base method.
@@ -71,47 +65,47 @@ func (mr *MockNetLinkerMockRecorder) IsWireguardSupported() *gomock.Call {
} }
// LinkAdd mocks base method. // LinkAdd mocks base method.
func (m *MockNetLinker) LinkAdd(link netlink.Link) (uint32, error) { func (m *MockNetLinker) LinkAdd(arg0 netlink.Link) (uint32, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LinkAdd", link) ret := m.ctrl.Call(m, "LinkAdd", arg0)
ret0, _ := ret[0].(uint32) ret0, _ := ret[0].(uint32)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// LinkAdd indicates an expected call of LinkAdd. // LinkAdd indicates an expected call of LinkAdd.
func (mr *MockNetLinkerMockRecorder) LinkAdd(link any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) LinkAdd(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkAdd", reflect.TypeOf((*MockNetLinker)(nil).LinkAdd), link) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkAdd", reflect.TypeOf((*MockNetLinker)(nil).LinkAdd), arg0)
} }
// LinkByName mocks base method. // LinkByName mocks base method.
func (m *MockNetLinker) LinkByName(name string) (netlink.Link, error) { func (m *MockNetLinker) LinkByName(arg0 string) (netlink.Link, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LinkByName", name) ret := m.ctrl.Call(m, "LinkByName", arg0)
ret0, _ := ret[0].(netlink.Link) ret0, _ := ret[0].(netlink.Link)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// LinkByName indicates an expected call of LinkByName. // LinkByName indicates an expected call of LinkByName.
func (mr *MockNetLinkerMockRecorder) LinkByName(name any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) LinkByName(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkByName", reflect.TypeOf((*MockNetLinker)(nil).LinkByName), name) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkByName", reflect.TypeOf((*MockNetLinker)(nil).LinkByName), arg0)
} }
// LinkDel mocks base method. // LinkDel mocks base method.
func (m *MockNetLinker) LinkDel(linkIndex uint32) error { func (m *MockNetLinker) LinkDel(arg0 uint32) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LinkDel", linkIndex) ret := m.ctrl.Call(m, "LinkDel", arg0)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// LinkDel indicates an expected call of LinkDel. // LinkDel indicates an expected call of LinkDel.
func (mr *MockNetLinkerMockRecorder) LinkDel(linkIndex any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) LinkDel(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkDel", reflect.TypeOf((*MockNetLinker)(nil).LinkDel), linkIndex) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkDel", reflect.TypeOf((*MockNetLinker)(nil).LinkDel), arg0)
} }
// LinkList mocks base method. // LinkList mocks base method.
@@ -130,86 +124,86 @@ func (mr *MockNetLinkerMockRecorder) LinkList() *gomock.Call {
} }
// LinkSetDown mocks base method. // LinkSetDown mocks base method.
func (m *MockNetLinker) LinkSetDown(linkIndex uint32) error { func (m *MockNetLinker) LinkSetDown(arg0 uint32) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LinkSetDown", linkIndex) ret := m.ctrl.Call(m, "LinkSetDown", arg0)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// LinkSetDown indicates an expected call of LinkSetDown. // LinkSetDown indicates an expected call of LinkSetDown.
func (mr *MockNetLinkerMockRecorder) LinkSetDown(linkIndex any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) LinkSetDown(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkSetDown", reflect.TypeOf((*MockNetLinker)(nil).LinkSetDown), linkIndex) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkSetDown", reflect.TypeOf((*MockNetLinker)(nil).LinkSetDown), arg0)
} }
// LinkSetUp mocks base method. // LinkSetUp mocks base method.
func (m *MockNetLinker) LinkSetUp(linkIndex uint32) error { func (m *MockNetLinker) LinkSetUp(arg0 uint32) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LinkSetUp", linkIndex) ret := m.ctrl.Call(m, "LinkSetUp", arg0)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// LinkSetUp indicates an expected call of LinkSetUp. // LinkSetUp indicates an expected call of LinkSetUp.
func (mr *MockNetLinkerMockRecorder) LinkSetUp(linkIndex any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) LinkSetUp(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkSetUp", reflect.TypeOf((*MockNetLinker)(nil).LinkSetUp), linkIndex) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkSetUp", reflect.TypeOf((*MockNetLinker)(nil).LinkSetUp), arg0)
} }
// RouteAdd mocks base method. // RouteAdd mocks base method.
func (m *MockNetLinker) RouteAdd(route netlink.Route) error { func (m *MockNetLinker) RouteAdd(arg0 netlink.Route) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RouteAdd", route) ret := m.ctrl.Call(m, "RouteAdd", arg0)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// RouteAdd indicates an expected call of RouteAdd. // RouteAdd indicates an expected call of RouteAdd.
func (mr *MockNetLinkerMockRecorder) RouteAdd(route any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) RouteAdd(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RouteAdd", reflect.TypeOf((*MockNetLinker)(nil).RouteAdd), route) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RouteAdd", reflect.TypeOf((*MockNetLinker)(nil).RouteAdd), arg0)
} }
// RouteList mocks base method. // RouteList mocks base method.
func (m *MockNetLinker) RouteList(family uint8) ([]netlink.Route, error) { func (m *MockNetLinker) RouteList(arg0 byte) ([]netlink.Route, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RouteList", family) ret := m.ctrl.Call(m, "RouteList", arg0)
ret0, _ := ret[0].([]netlink.Route) ret0, _ := ret[0].([]netlink.Route)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// RouteList indicates an expected call of RouteList. // RouteList indicates an expected call of RouteList.
func (mr *MockNetLinkerMockRecorder) RouteList(family any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) RouteList(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RouteList", reflect.TypeOf((*MockNetLinker)(nil).RouteList), family) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RouteList", reflect.TypeOf((*MockNetLinker)(nil).RouteList), arg0)
} }
// RuleAdd mocks base method. // RuleAdd mocks base method.
func (m *MockNetLinker) RuleAdd(rule netlink.Rule) error { func (m *MockNetLinker) RuleAdd(arg0 netlink.Rule) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RuleAdd", rule) ret := m.ctrl.Call(m, "RuleAdd", arg0)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// RuleAdd indicates an expected call of RuleAdd. // RuleAdd indicates an expected call of RuleAdd.
func (mr *MockNetLinkerMockRecorder) RuleAdd(rule any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) RuleAdd(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RuleAdd", reflect.TypeOf((*MockNetLinker)(nil).RuleAdd), rule) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RuleAdd", reflect.TypeOf((*MockNetLinker)(nil).RuleAdd), arg0)
} }
// RuleDel mocks base method. // RuleDel mocks base method.
func (m *MockNetLinker) RuleDel(rule netlink.Rule) error { func (m *MockNetLinker) RuleDel(arg0 netlink.Rule) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RuleDel", rule) ret := m.ctrl.Call(m, "RuleDel", arg0)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// RuleDel indicates an expected call of RuleDel. // RuleDel indicates an expected call of RuleDel.
func (mr *MockNetLinkerMockRecorder) RuleDel(rule any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) RuleDel(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RuleDel", reflect.TypeOf((*MockNetLinker)(nil).RuleDel), rule) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RuleDel", reflect.TypeOf((*MockNetLinker)(nil).RuleDel), arg0)
} }
+1 -1
View File
@@ -4,8 +4,8 @@ import (
"errors" "errors"
"testing" "testing"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
) )
func Test_Cleanups(t *testing.T) { func Test_Cleanups(t *testing.T) {
+3 -9
View File
@@ -1,10 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/qdm12/gluetun/internal/cleanup (interfaces: Logger) // Source: github.com/qdm12/gluetun/internal/cleanup (interfaces: Logger)
//
// Generated by this command:
//
// mockgen -destination=mocks_test.go -package=cleanup . Logger
//
// Package cleanup is a generated GoMock package. // Package cleanup is a generated GoMock package.
package cleanup package cleanup
@@ -12,14 +7,13 @@ package cleanup
import ( import (
reflect "reflect" reflect "reflect"
gomock "go.uber.org/mock/gomock" gomock "github.com/golang/mock/gomock"
) )
// MockLogger is a mock of Logger interface. // MockLogger is a mock of Logger interface.
type MockLogger struct { type MockLogger struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockLoggerMockRecorder recorder *MockLoggerMockRecorder
isgomock struct{}
} }
// MockLoggerMockRecorder is the mock recorder for MockLogger. // MockLoggerMockRecorder is the mock recorder for MockLogger.
@@ -46,7 +40,7 @@ func (m *MockLogger) Debug(arg0 string) {
} }
// Debug indicates an expected call of Debug. // Debug indicates an expected call of Debug.
func (mr *MockLoggerMockRecorder) Debug(arg0 any) *gomock.Call { func (mr *MockLoggerMockRecorder) Debug(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debug", reflect.TypeOf((*MockLogger)(nil).Debug), arg0) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debug", reflect.TypeOf((*MockLogger)(nil).Debug), arg0)
} }
@@ -58,7 +52,7 @@ func (m *MockLogger) Error(arg0 string) {
} }
// Error indicates an expected call of Error. // Error indicates an expected call of Error.
func (mr *MockLoggerMockRecorder) Error(arg0 any) *gomock.Call { func (mr *MockLoggerMockRecorder) Error(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockLogger)(nil).Error), arg0) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockLogger)(nil).Error), arg0)
} }
+1 -7
View File
@@ -1,10 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: interfaces_local.go // Source: interfaces_local.go
//
// Generated by this command:
//
// mockgen -destination=mocks_local_test.go -package=command -source=interfaces_local.go
//
// Package command is a generated GoMock package. // Package command is a generated GoMock package.
package command package command
@@ -13,14 +8,13 @@ import (
io "io" io "io"
reflect "reflect" reflect "reflect"
gomock "go.uber.org/mock/gomock" gomock "github.com/golang/mock/gomock"
) )
// MockexecCmd is a mock of execCmd interface. // MockexecCmd is a mock of execCmd interface.
type MockexecCmd struct { type MockexecCmd struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockexecCmdMockRecorder recorder *MockexecCmdMockRecorder
isgomock struct{}
} }
// MockexecCmdMockRecorder is the mock recorder for MockexecCmd. // MockexecCmdMockRecorder is the mock recorder for MockexecCmd.
+1 -1
View File
@@ -4,9 +4,9 @@ import (
"errors" "errors"
"testing" "testing"
gomock "github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
gomock "go.uber.org/mock/gomock"
) )
func Test_run(t *testing.T) { func Test_run(t *testing.T) {
+1 -1
View File
@@ -7,9 +7,9 @@ import (
"strings" "strings"
"testing" "testing"
gomock "github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
gomock "go.uber.org/mock/gomock"
) )
func linesToReadCloser(lines []string) io.ReadCloser { func linesToReadCloser(lines []string) io.ReadCloser {
@@ -16,7 +16,6 @@ func readObsolete(r *reader.Reader) (warnings []string) {
"HEALTH_VPN_DURATION_ADDITION": "HEALTH_VPN_DURATION_ADDITION is obsolete", "HEALTH_VPN_DURATION_ADDITION": "HEALTH_VPN_DURATION_ADDITION is obsolete",
"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",
"BLOCK_SURVEILLANCE": "BLOCK_SURVEILLANCE is obsolete because its DNS block lists are not longer maintained",
} }
sortedKeys := slices.Collect(maps.Keys(keyToMessage)) sortedKeys := slices.Collect(maps.Keys(keyToMessage))
slices.Sort(sortedKeys) slices.Sort(sortedKeys)
@@ -16,6 +16,7 @@ import (
type DNSBlacklist struct { type DNSBlacklist struct {
BlockMalicious *bool BlockMalicious *bool
BlockAds *bool BlockAds *bool
BlockSurveillance *bool
AllowedHosts []string AllowedHosts []string
AddBlockedHosts []string AddBlockedHosts []string
AddBlockedIPs []netip.Addr AddBlockedIPs []netip.Addr
@@ -30,6 +31,7 @@ type DNSBlacklist struct {
func (b *DNSBlacklist) setDefaults() { func (b *DNSBlacklist) setDefaults() {
b.BlockMalicious = gosettings.DefaultPointer(b.BlockMalicious, true) b.BlockMalicious = gosettings.DefaultPointer(b.BlockMalicious, true)
b.BlockAds = gosettings.DefaultPointer(b.BlockAds, false) b.BlockAds = gosettings.DefaultPointer(b.BlockAds, false)
b.BlockSurveillance = gosettings.DefaultPointer(b.BlockSurveillance, true)
} }
var hostRegex = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9_][a-zA-Z0-9\-_]{0,61}[a-zA-Z0-9_])(\.([a-zA-Z0-9]|[a-zA-Z0-9_][a-zA-Z0-9\-_]{0,61}[a-zA-Z0-9]))*$`) //nolint:lll var hostRegex = regexp.MustCompile(`^([a-zA-Z0-9]|[a-zA-Z0-9_][a-zA-Z0-9\-_]{0,61}[a-zA-Z0-9_])(\.([a-zA-Z0-9]|[a-zA-Z0-9_][a-zA-Z0-9\-_]{0,61}[a-zA-Z0-9]))*$`) //nolint:lll
@@ -63,6 +65,7 @@ func (b DNSBlacklist) copy() (copied DNSBlacklist) {
return DNSBlacklist{ return DNSBlacklist{
BlockMalicious: gosettings.CopyPointer(b.BlockMalicious), BlockMalicious: gosettings.CopyPointer(b.BlockMalicious),
BlockAds: gosettings.CopyPointer(b.BlockAds), BlockAds: gosettings.CopyPointer(b.BlockAds),
BlockSurveillance: gosettings.CopyPointer(b.BlockSurveillance),
AllowedHosts: gosettings.CopySlice(b.AllowedHosts), AllowedHosts: gosettings.CopySlice(b.AllowedHosts),
AddBlockedHosts: gosettings.CopySlice(b.AddBlockedHosts), AddBlockedHosts: gosettings.CopySlice(b.AddBlockedHosts),
AddBlockedIPs: gosettings.CopySlice(b.AddBlockedIPs), AddBlockedIPs: gosettings.CopySlice(b.AddBlockedIPs),
@@ -74,6 +77,7 @@ func (b DNSBlacklist) copy() (copied DNSBlacklist) {
func (b *DNSBlacklist) overrideWith(other DNSBlacklist) { func (b *DNSBlacklist) overrideWith(other DNSBlacklist) {
b.BlockMalicious = gosettings.OverrideWithPointer(b.BlockMalicious, other.BlockMalicious) b.BlockMalicious = gosettings.OverrideWithPointer(b.BlockMalicious, other.BlockMalicious)
b.BlockAds = gosettings.OverrideWithPointer(b.BlockAds, other.BlockAds) b.BlockAds = gosettings.OverrideWithPointer(b.BlockAds, other.BlockAds)
b.BlockSurveillance = gosettings.OverrideWithPointer(b.BlockSurveillance, other.BlockSurveillance)
b.AllowedHosts = gosettings.OverrideWithSlice(b.AllowedHosts, other.AllowedHosts) b.AllowedHosts = gosettings.OverrideWithSlice(b.AllowedHosts, other.AllowedHosts)
b.AddBlockedHosts = gosettings.OverrideWithSlice(b.AddBlockedHosts, other.AddBlockedHosts) b.AddBlockedHosts = gosettings.OverrideWithSlice(b.AddBlockedHosts, other.AddBlockedHosts)
b.AddBlockedIPs = gosettings.OverrideWithSlice(b.AddBlockedIPs, other.AddBlockedIPs) b.AddBlockedIPs = gosettings.OverrideWithSlice(b.AddBlockedIPs, other.AddBlockedIPs)
@@ -89,6 +93,7 @@ func (b DNSBlacklist) ToBlockBuilderSettings(client *http.Client) (
Client: client, Client: client,
BlockMalicious: b.BlockMalicious, BlockMalicious: b.BlockMalicious,
BlockAds: b.BlockAds, BlockAds: b.BlockAds,
BlockSurveillance: b.BlockSurveillance,
AllowedHosts: b.AllowedHosts, AllowedHosts: b.AllowedHosts,
AddBlockedHosts: b.AddBlockedHosts, AddBlockedHosts: b.AddBlockedHosts,
AddBlockedIPs: b.AddBlockedIPs, AddBlockedIPs: b.AddBlockedIPs,
@@ -105,6 +110,7 @@ func (b DNSBlacklist) toLinesNode() (node *gotree.Node) {
node.Appendf("Block malicious: %s", gosettings.BoolToYesNo(b.BlockMalicious)) node.Appendf("Block malicious: %s", gosettings.BoolToYesNo(b.BlockMalicious))
node.Appendf("Block ads: %s", gosettings.BoolToYesNo(b.BlockAds)) node.Appendf("Block ads: %s", gosettings.BoolToYesNo(b.BlockAds))
node.Appendf("Block surveillance: %s", gosettings.BoolToYesNo(b.BlockSurveillance))
if len(b.AllowedHosts) > 0 { if len(b.AllowedHosts) > 0 {
allowedHostsNode := node.Append("Allowed hosts:") allowedHostsNode := node.Append("Allowed hosts:")
@@ -150,6 +156,12 @@ func (b *DNSBlacklist) read(r *reader.Reader) (err error) {
return err return err
} }
b.BlockSurveillance, err = r.BoolPtr("BLOCK_SURVEILLANCE",
reader.RetroKeys("BLOCK_NSA"))
if err != nil {
return err
}
b.BlockAds, err = r.BoolPtr("BLOCK_ADS") b.BlockAds, err = r.BoolPtr("BLOCK_ADS")
if err != nil { if err != nil {
return err return err
@@ -1,6 +1,6 @@
package settings package settings
import gomock "go.uber.org/mock/gomock" import gomock "github.com/golang/mock/gomock"
type sourceKeyValue struct { type sourceKeyValue struct {
key string key string
@@ -1,10 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/qdm12/gosettings/reader (interfaces: Source) // Source: github.com/qdm12/gosettings/reader (interfaces: Source)
//
// Generated by this command:
//
// mockgen -destination=mocks_reader_test.go -package=settings github.com/qdm12/gosettings/reader Source
//
// Package settings is a generated GoMock package. // Package settings is a generated GoMock package.
package settings package settings
@@ -12,14 +7,13 @@ package settings
import ( import (
reflect "reflect" reflect "reflect"
gomock "go.uber.org/mock/gomock" gomock "github.com/golang/mock/gomock"
) )
// MockSource is a mock of Source interface. // MockSource is a mock of Source interface.
type MockSource struct { type MockSource struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockSourceMockRecorder recorder *MockSourceMockRecorder
isgomock struct{}
} }
// MockSourceMockRecorder is the mock recorder for MockSource. // MockSourceMockRecorder is the mock recorder for MockSource.
@@ -40,32 +34,32 @@ func (m *MockSource) EXPECT() *MockSourceMockRecorder {
} }
// Get mocks base method. // Get mocks base method.
func (m *MockSource) Get(key string) (string, bool) { func (m *MockSource) Get(arg0 string) (string, bool) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Get", key) ret := m.ctrl.Call(m, "Get", arg0)
ret0, _ := ret[0].(string) ret0, _ := ret[0].(string)
ret1, _ := ret[1].(bool) ret1, _ := ret[1].(bool)
return ret0, ret1 return ret0, ret1
} }
// Get indicates an expected call of Get. // Get indicates an expected call of Get.
func (mr *MockSourceMockRecorder) Get(key any) *gomock.Call { func (mr *MockSourceMockRecorder) Get(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockSource)(nil).Get), key) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockSource)(nil).Get), arg0)
} }
// KeyTransform mocks base method. // KeyTransform mocks base method.
func (m *MockSource) KeyTransform(key string) string { func (m *MockSource) KeyTransform(arg0 string) string {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "KeyTransform", key) ret := m.ctrl.Call(m, "KeyTransform", arg0)
ret0, _ := ret[0].(string) ret0, _ := ret[0].(string)
return ret0 return ret0
} }
// KeyTransform indicates an expected call of KeyTransform. // KeyTransform indicates an expected call of KeyTransform.
func (mr *MockSourceMockRecorder) KeyTransform(key any) *gomock.Call { func (mr *MockSourceMockRecorder) KeyTransform(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KeyTransform", reflect.TypeOf((*MockSource)(nil).KeyTransform), key) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KeyTransform", reflect.TypeOf((*MockSource)(nil).KeyTransform), arg0)
} }
// String mocks base method. // String mocks base method.
+5 -11
View File
@@ -1,10 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/qdm12/gluetun/internal/configuration/settings (interfaces: Warner) // Source: github.com/qdm12/gluetun/internal/configuration/settings (interfaces: Warner)
//
// Generated by this command:
//
// mockgen -destination=mocks_test.go -package=settings . Warner
//
// Package settings is a generated GoMock package. // Package settings is a generated GoMock package.
package settings package settings
@@ -12,14 +7,13 @@ package settings
import ( import (
reflect "reflect" reflect "reflect"
gomock "go.uber.org/mock/gomock" gomock "github.com/golang/mock/gomock"
) )
// MockWarner is a mock of Warner interface. // MockWarner is a mock of Warner interface.
type MockWarner struct { type MockWarner struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockWarnerMockRecorder recorder *MockWarnerMockRecorder
isgomock struct{}
} }
// MockWarnerMockRecorder is the mock recorder for MockWarner. // MockWarnerMockRecorder is the mock recorder for MockWarner.
@@ -40,13 +34,13 @@ func (m *MockWarner) EXPECT() *MockWarnerMockRecorder {
} }
// Warn mocks base method. // Warn mocks base method.
func (m *MockWarner) Warn(message string) { func (m *MockWarner) Warn(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Warn", message) m.ctrl.Call(m, "Warn", arg0)
} }
// Warn indicates an expected call of Warn. // Warn indicates an expected call of Warn.
func (mr *MockWarnerMockRecorder) Warn(message any) *gomock.Call { func (mr *MockWarnerMockRecorder) Warn(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warn", reflect.TypeOf((*MockWarner)(nil).Warn), message) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warn", reflect.TypeOf((*MockWarner)(nil).Warn), arg0)
} }
@@ -70,7 +70,7 @@ func (o OpenVPNSelection) validate(vpnProvider string) (err error) {
switch vpnProvider { switch vpnProvider {
// no restriction on port // no restriction on port
case providers.Custom, providers.Cyberghost, providers.HideMyAss, case providers.Custom, providers.Cyberghost, providers.HideMyAss,
providers.Privatevpn, providers.Torguard: providers.Ovpn, providers.Privatevpn, providers.Torguard:
// no custom port allowed // no custom port allowed
case providers.Expressvpn, providers.Fastestvpn, case providers.Expressvpn, providers.Fastestvpn,
providers.Giganews, providers.Ipvanish, providers.Giganews, providers.Ipvanish,
@@ -49,6 +49,7 @@ func (p *Provider) validate(vpnType string, filterChoicesGetter FilterChoicesGet
providers.Ivpn, providers.Ivpn,
providers.Mullvad, providers.Mullvad,
providers.Nordvpn, providers.Nordvpn,
providers.Ovpn,
providers.Protonvpn, providers.Protonvpn,
providers.Surfshark, providers.Surfshark,
providers.Windscribe, providers.Windscribe,
@@ -3,9 +3,9 @@ package settings
import ( import (
"testing" "testing"
"github.com/golang/mock/gomock"
"github.com/qdm12/gosettings/reader" "github.com/qdm12/gosettings/reader"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
) )
func Test_PublicIP_read(t *testing.T) { func Test_PublicIP_read(t *testing.T) {
@@ -63,6 +63,9 @@ type ServerSelection struct {
// TorOnly is true if VPN servers without tor should // TorOnly is true if VPN servers without tor should
// be filtered. This is used with ProtonVPN. // be filtered. This is used with ProtonVPN.
TorOnly *bool `json:"tor_only"` TorOnly *bool `json:"tor_only"`
// Dedicated is true if dedicated VPN servers should be chosen only.
// This is used with OVPN.
Dedicated *bool `json:"dedicated"`
// OpenVPN contains settings to select OpenVPN servers // OpenVPN contains settings to select OpenVPN servers
// and the final connection. // and the final connection.
OpenVPN OpenVPNSelection `json:"openvpn"` OpenVPN OpenVPNSelection `json:"openvpn"`
@@ -272,6 +275,8 @@ func validateFeatureFilters(settings ServerSelection, vpnServiceProvider string)
return errors.New("secure core only filter is not supported") return errors.New("secure core only filter is not supported")
case *settings.TorOnly && vpnServiceProvider != providers.Protonvpn: case *settings.TorOnly && vpnServiceProvider != providers.Protonvpn:
return errors.New("tor only filter is not supported") return errors.New("tor only filter is not supported")
case *settings.Dedicated && vpnServiceProvider != providers.Ovpn:
return errors.New("dedicated filter is not supported")
default: default:
return nil return nil
} }
@@ -296,6 +301,7 @@ func (ss *ServerSelection) copy() (copied ServerSelection) {
TorOnly: gosettings.CopyPointer(ss.TorOnly), TorOnly: gosettings.CopyPointer(ss.TorOnly),
PortForwardOnly: gosettings.CopyPointer(ss.PortForwardOnly), PortForwardOnly: gosettings.CopyPointer(ss.PortForwardOnly),
MultiHopOnly: gosettings.CopyPointer(ss.MultiHopOnly), MultiHopOnly: gosettings.CopyPointer(ss.MultiHopOnly),
Dedicated: gosettings.CopyPointer(ss.Dedicated),
OpenVPN: ss.OpenVPN.copy(), OpenVPN: ss.OpenVPN.copy(),
Wireguard: ss.Wireguard.copy(), Wireguard: ss.Wireguard.copy(),
} }
@@ -319,6 +325,7 @@ func (ss *ServerSelection) overrideWith(other ServerSelection) {
ss.TorOnly = gosettings.OverrideWithPointer(ss.TorOnly, other.TorOnly) ss.TorOnly = gosettings.OverrideWithPointer(ss.TorOnly, other.TorOnly)
ss.MultiHopOnly = gosettings.OverrideWithPointer(ss.MultiHopOnly, other.MultiHopOnly) ss.MultiHopOnly = gosettings.OverrideWithPointer(ss.MultiHopOnly, other.MultiHopOnly)
ss.PortForwardOnly = gosettings.OverrideWithPointer(ss.PortForwardOnly, other.PortForwardOnly) ss.PortForwardOnly = gosettings.OverrideWithPointer(ss.PortForwardOnly, other.PortForwardOnly)
ss.Dedicated = gosettings.OverrideWithPointer(ss.Dedicated, other.Dedicated)
ss.OpenVPN.overrideWith(other.OpenVPN) ss.OpenVPN.overrideWith(other.OpenVPN)
ss.Wireguard.overrideWith(other.Wireguard) ss.Wireguard.overrideWith(other.Wireguard)
} }
@@ -335,6 +342,7 @@ func (ss *ServerSelection) setDefaults(vpnProvider string, portForwardingEnabled
defaultPortForwardOnly := portForwardingEnabled && defaultPortForwardOnly := portForwardingEnabled &&
helpers.IsOneOf(vpnProvider, providers.PrivateInternetAccess, providers.Protonvpn) helpers.IsOneOf(vpnProvider, providers.PrivateInternetAccess, providers.Protonvpn)
ss.PortForwardOnly = gosettings.DefaultPointer(ss.PortForwardOnly, defaultPortForwardOnly) ss.PortForwardOnly = gosettings.DefaultPointer(ss.PortForwardOnly, defaultPortForwardOnly)
ss.Dedicated = gosettings.DefaultPointer(ss.Dedicated, false)
ss.OpenVPN.setDefaults(vpnProvider) ss.OpenVPN.setDefaults(vpnProvider)
ss.Wireguard.setDefaults() ss.Wireguard.setDefaults()
} }
@@ -410,6 +418,10 @@ func (ss ServerSelection) toLinesNode() (node *gotree.Node) {
node.Appendf("Multi-hop only servers: yes") node.Appendf("Multi-hop only servers: yes")
} }
if *ss.Dedicated {
node.Appendf("Dedicated servers: yes")
}
if *ss.PortForwardOnly { if *ss.PortForwardOnly {
node.Appendf("Port forwarding only servers: yes") node.Appendf("Port forwarding only servers: yes")
} }
@@ -501,6 +513,12 @@ func (ss *ServerSelection) read(r *reader.Reader,
return err return err
} }
// Ovpn only
ss.Dedicated, err = r.BoolPtr("SERVER_DEDICATED")
if err != nil {
return err
}
err = ss.OpenVPN.read(r) err = ss.OpenVPN.read(r)
if err != nil { if err != nil {
return err return err
@@ -59,7 +59,8 @@ func Test_Settings_String(t *testing.T) {
| Update period: every 24h0m0s | Update period: every 24h0m0s
| DNS filtering settings: | DNS filtering settings:
| Block malicious: yes | Block malicious: yes
| Block ads: no | Block ads: no
| Block surveillance: yes
Firewall settings: Firewall settings:
| Enabled: yes | Enabled: yes
| Iptables settings: | Iptables settings:
@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"net/netip" "net/netip"
"github.com/qdm12/gluetun/internal/configuration/settings/helpers"
"github.com/qdm12/gluetun/internal/constants/providers" "github.com/qdm12/gluetun/internal/constants/providers"
"github.com/qdm12/gosettings" "github.com/qdm12/gosettings"
"github.com/qdm12/gosettings/reader" "github.com/qdm12/gosettings/reader"
@@ -22,7 +23,7 @@ type WireguardSelection struct {
// It can never be the zero value in the internal state. // It can never be the zero value in the internal state.
EndpointIP netip.Addr `json:"endpoint_ip"` EndpointIP netip.Addr `json:"endpoint_ip"`
// EndpointPort is a the server port to use for the VPN server. // EndpointPort is a the server port to use for the VPN server.
// It is optional for VPN providers IVPN, Mullvad, Surfshark // It is optional for VPN providers IVPN, Mullvad, Ovpn, Surfshark
// and Windscribe, and compulsory for the others. // and Windscribe, and compulsory for the others.
// When optional, it can be set to 0 to indicate not use // When optional, it can be set to 0 to indicate not use
// a custom endpoint port. It cannot be nil in the internal // a custom endpoint port. It cannot be nil in the internal
@@ -40,8 +41,9 @@ func (w WireguardSelection) validate(vpnProvider string) (err error) {
// Validate EndpointIP // Validate EndpointIP
switch vpnProvider { switch vpnProvider {
case providers.Airvpn, providers.Fastestvpn, providers.Ivpn, case providers.Airvpn, providers.Fastestvpn, providers.Ivpn,
providers.Mullvad, providers.Nordvpn, providers.Protonvpn, providers.Mullvad, providers.Nordvpn, providers.Ovpn,
providers.Surfshark, providers.Windscribe: providers.Protonvpn, providers.Surfshark,
providers.Windscribe:
// endpoint IP addresses are baked in // endpoint IP addresses are baked in
case providers.Custom: case providers.Custom:
if !w.EndpointIP.IsValid() || w.EndpointIP.IsUnspecified() { if !w.EndpointIP.IsValid() || w.EndpointIP.IsUnspecified() {
@@ -63,12 +65,16 @@ func (w WireguardSelection) validate(vpnProvider string) (err error) {
if *w.EndpointPort != 0 { if *w.EndpointPort != 0 {
return errors.New("endpoint port is set") return errors.New("endpoint port is set")
} }
case providers.Airvpn, providers.Ivpn, providers.Mullvad, providers.Windscribe: case providers.Airvpn, providers.Ivpn, providers.Mullvad,
providers.Ovpn, providers.Windscribe:
// EndpointPort is optional and can be 0 // EndpointPort is optional and can be 0
if *w.EndpointPort == 0 { if *w.EndpointPort == 0 {
break // no custom endpoint port set break // no custom endpoint port set
} }
if vpnProvider == providers.Mullvad { if helpers.IsOneOf(vpnProvider,
providers.Mullvad,
providers.Ovpn,
) {
break // no restriction on custom endpoint port value break // no restriction on custom endpoint port value
} }
var allowed []uint16 var allowed []uint16
@@ -92,7 +98,7 @@ func (w WireguardSelection) validate(vpnProvider string) (err error) {
// Validate PublicKey // Validate PublicKey
switch vpnProvider { switch vpnProvider {
case providers.Fastestvpn, providers.Ivpn, providers.Mullvad, case providers.Fastestvpn, providers.Ivpn, providers.Mullvad,
providers.Surfshark, providers.Windscribe: providers.Ovpn, providers.Surfshark, providers.Windscribe:
// public keys are baked in // public keys are baked in
case providers.Custom: case providers.Custom:
if w.PublicKey == "" { if w.PublicKey == "" {
@@ -15,6 +15,7 @@ const (
Ivpn = "ivpn" Ivpn = "ivpn"
Mullvad = "mullvad" Mullvad = "mullvad"
Nordvpn = "nordvpn" Nordvpn = "nordvpn"
Ovpn = "ovpn"
Perfectprivacy = "perfect privacy" Perfectprivacy = "perfect privacy"
Privado = "privado" Privado = "privado"
PrivateInternetAccess = "private internet access" PrivateInternetAccess = "private internet access"
@@ -43,6 +44,7 @@ func All() []string {
Ivpn, Ivpn,
Mullvad, Mullvad,
Nordvpn, Nordvpn,
Ovpn,
Perfectprivacy, Perfectprivacy,
Privado, Privado,
PrivateInternetAccess, PrivateInternetAccess,
+8 -4
View File
@@ -4,6 +4,7 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"math" "math"
"math/rand/v2" "math/rand/v2"
"net/http" "net/http"
@@ -84,11 +85,14 @@ func triggerDNSQuery(ctx context.Context, client *http.Client, session string) (
IP map[string]uint `json:"ip"` IP map[string]uint `json:"ip"`
} }
decoder := json.NewDecoder(response.Body) rawData, err := io.ReadAll(response.Body)
var data ipLeakData
err = decoder.Decode(&data)
if err != nil { if err != nil {
return nil, fmt.Errorf("decoding response: %w", err) return nil, fmt.Errorf("reading response body: %w", err)
}
var data ipLeakData
err = json.Unmarshal(rawData, &data)
if err != nil {
return nil, fmt.Errorf("decoding response %q: %w", rawData, err)
} else if data.Session != session { } else if data.Session != session {
return nil, fmt.Errorf("ipleak.net session mismatch: expected %s, got %s", session, data.Session) return nil, fmt.Errorf("ipleak.net session mismatch: expected %s, got %s", session, data.Session)
} }
-2
View File
@@ -28,8 +28,6 @@ type firewallImpl interface { //nolint:interfacebloat
AcceptIpv6MulticastOutput(ctx context.Context, intf string) error AcceptIpv6MulticastOutput(ctx context.Context, intf string) error
AcceptOutput(ctx context.Context, protocol, intf string, AcceptOutput(ctx context.Context, protocol, intf string,
ip netip.Addr, port uint16, remove bool) error ip netip.Addr, port uint16, remove bool) error
AcceptOutputFromIPPortToIPPort(ctx context.Context, protocol, intf string,
source, destination netip.AddrPort, remove bool) error
AcceptOutputFromIPToSubnet(ctx context.Context, intf string, assignedIP netip.Addr, AcceptOutputFromIPToSubnet(ctx context.Context, intf string, assignedIP netip.Addr,
subnet netip.Prefix, remove bool) error subnet netip.Prefix, remove bool) error
AcceptOutputThroughInterface(ctx context.Context, intf string, remove bool) error AcceptOutputThroughInterface(ctx context.Context, intf string, remove bool) error
@@ -5,7 +5,7 @@ import (
"os/exec" "os/exec"
"regexp" "regexp"
"go.uber.org/mock/gomock" "github.com/golang/mock/gomock"
) )
var _ gomock.Matcher = (*cmdMatcher)(nil) var _ gomock.Matcher = (*cmdMatcher)(nil)
+1 -1
View File
@@ -5,8 +5,8 @@ import (
"errors" "errors"
"testing" "testing"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
) )
func Test_isDeleteMatchInstruction(t *testing.T) { func Test_isDeleteMatchInstruction(t *testing.T) {
-24
View File
@@ -2,7 +2,6 @@ package iptables
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"net/netip" "net/netip"
@@ -178,29 +177,6 @@ func (c *Config) AcceptOutput(ctx context.Context,
return c.runIP6tablesInstruction(ctx, instruction) return c.runIP6tablesInstruction(ctx, instruction)
} }
func (c *Config) AcceptOutputFromIPPortToIPPort(ctx context.Context,
protocol, intf string, source, destination netip.AddrPort, remove bool,
) error {
if source.Addr().BitLen() != destination.Addr().BitLen() {
return errors.New("source and destination address families do not match")
}
interfaceFlag := "-o " + intf
if intf == "*" { // all interfaces
interfaceFlag = ""
}
instruction := fmt.Sprintf("%s OUTPUT %s -s %s -d %s -p %s -m %s --sport %d --dport %d -j ACCEPT",
appendOrDelete(remove), interfaceFlag, source.Addr(), destination.Addr(),
protocol, protocol, source.Port(), destination.Port())
if destination.Addr().Is4() {
return c.runIptablesInstruction(ctx, instruction)
} else if c.ip6Tables == "" {
return fmt.Errorf("accept output from %s to %s: %s", source, destination, needIP6Tables)
}
return c.runIP6tablesInstruction(ctx, instruction)
}
// AcceptOutputFromIPToSubnet accepts outgoing traffic from sourceIP to destinationSubnet // AcceptOutputFromIPToSubnet accepts outgoing traffic from sourceIP to destinationSubnet
// on the interface intf. If intf is empty, it is set to "*" which means all interfaces. // on the interface intf. If intf is empty, it is set to "*" which means all interfaces.
// If remove is true, the rule is removed instead of added. // If remove is true, the rule is removed instead of added.
+13 -20
View File
@@ -1,10 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/qdm12/gluetun/internal/firewall/iptables (interfaces: CmdRunner,Logger) // Source: github.com/qdm12/gluetun/internal/firewall/iptables (interfaces: CmdRunner,Logger)
//
// Generated by this command:
//
// mockgen -destination=mocks_test.go -package iptables . CmdRunner,Logger
//
// Package iptables is a generated GoMock package. // Package iptables is a generated GoMock package.
package iptables package iptables
@@ -13,14 +8,13 @@ import (
exec "os/exec" exec "os/exec"
reflect "reflect" reflect "reflect"
gomock "go.uber.org/mock/gomock" gomock "github.com/golang/mock/gomock"
) )
// MockCmdRunner is a mock of CmdRunner interface. // MockCmdRunner is a mock of CmdRunner interface.
type MockCmdRunner struct { type MockCmdRunner struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockCmdRunnerMockRecorder recorder *MockCmdRunnerMockRecorder
isgomock struct{}
} }
// MockCmdRunnerMockRecorder is the mock recorder for MockCmdRunner. // MockCmdRunnerMockRecorder is the mock recorder for MockCmdRunner.
@@ -41,25 +35,24 @@ func (m *MockCmdRunner) EXPECT() *MockCmdRunnerMockRecorder {
} }
// Run mocks base method. // Run mocks base method.
func (m *MockCmdRunner) Run(cmd *exec.Cmd) (string, error) { func (m *MockCmdRunner) Run(arg0 *exec.Cmd) (string, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Run", cmd) ret := m.ctrl.Call(m, "Run", arg0)
ret0, _ := ret[0].(string) ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// Run indicates an expected call of Run. // Run indicates an expected call of Run.
func (mr *MockCmdRunnerMockRecorder) Run(cmd any) *gomock.Call { func (mr *MockCmdRunnerMockRecorder) Run(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockCmdRunner)(nil).Run), cmd) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Run", reflect.TypeOf((*MockCmdRunner)(nil).Run), arg0)
} }
// MockLogger is a mock of Logger interface. // MockLogger is a mock of Logger interface.
type MockLogger struct { type MockLogger struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockLoggerMockRecorder recorder *MockLoggerMockRecorder
isgomock struct{}
} }
// MockLoggerMockRecorder is the mock recorder for MockLogger. // MockLoggerMockRecorder is the mock recorder for MockLogger.
@@ -80,25 +73,25 @@ func (m *MockLogger) EXPECT() *MockLoggerMockRecorder {
} }
// Debug mocks base method. // Debug mocks base method.
func (m *MockLogger) Debug(s string) { func (m *MockLogger) Debug(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Debug", s) m.ctrl.Call(m, "Debug", arg0)
} }
// Debug indicates an expected call of Debug. // Debug indicates an expected call of Debug.
func (mr *MockLoggerMockRecorder) Debug(s any) *gomock.Call { func (mr *MockLoggerMockRecorder) Debug(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debug", reflect.TypeOf((*MockLogger)(nil).Debug), s) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debug", reflect.TypeOf((*MockLogger)(nil).Debug), arg0)
} }
// Warn mocks base method. // Warn mocks base method.
func (m *MockLogger) Warn(s string) { func (m *MockLogger) Warn(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Warn", s) m.ctrl.Call(m, "Warn", arg0)
} }
// Warn indicates an expected call of Warn. // Warn indicates an expected call of Warn.
func (mr *MockLoggerMockRecorder) Warn(s any) *gomock.Call { func (mr *MockLoggerMockRecorder) Warn(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warn", reflect.TypeOf((*MockLogger)(nil).Warn), s) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warn", reflect.TypeOf((*MockLogger)(nil).Warn), arg0)
} }
+1 -1
View File
@@ -5,8 +5,8 @@ import (
"errors" "errors"
"testing" "testing"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
) )
func newAppendTestRuleMatcher(path string) *cmdMatcher { func newAppendTestRuleMatcher(path string) *cmdMatcher {
-7
View File
@@ -25,10 +25,3 @@ func (c *Config) AcceptOutput(ctx context.Context, protocol, intf string,
) error { ) error {
return c.impl.AcceptOutput(ctx, protocol, intf, ip, port, remove) return c.impl.AcceptOutput(ctx, protocol, intf, ip, port, remove)
} }
func (c *Config) AcceptOutputFromIPPortToIPPort(ctx context.Context,
protocol, intf string, source, destination netip.AddrPort, remove bool,
) error {
return c.impl.AcceptOutputFromIPPortToIPPort(ctx, protocol, intf,
source, destination, remove)
}
+6
View File
@@ -8,6 +8,7 @@ import (
"net" "net"
"net/netip" "net/netip"
"strings" "strings"
"sync"
"time" "time"
"github.com/qdm12/gluetun/internal/healthcheck/dns" "github.com/qdm12/gluetun/internal/healthcheck/dns"
@@ -23,6 +24,7 @@ type Checker struct {
icmpTargetIPs []netip.Addr icmpTargetIPs []netip.Addr
smallCheckType string smallCheckType string
startupOnFail bool startupOnFail bool
configMutex sync.Mutex
icmpNotPermitted *bool icmpNotPermitted *bool
@@ -53,6 +55,8 @@ func NewChecker(logger Logger) *Checker {
func (c *Checker) SetConfig(tlsDialAddrs []string, icmpTargets []netip.Addr, func (c *Checker) SetConfig(tlsDialAddrs []string, icmpTargets []netip.Addr,
smallCheckType string, startupOnFail bool, smallCheckType string, startupOnFail bool,
) { ) {
c.configMutex.Lock()
defer c.configMutex.Unlock()
c.tlsDialAddrs = tlsDialAddrs c.tlsDialAddrs = tlsDialAddrs
c.icmpTargetIPs = icmpTargets c.icmpTargetIPs = icmpTargets
c.smallCheckType = smallCheckType c.smallCheckType = smallCheckType
@@ -162,8 +166,10 @@ func (c *Checker) Stop() error {
} }
func (c *Checker) smallPeriodicCheck(ctx context.Context) error { func (c *Checker) smallPeriodicCheck(ctx context.Context) error {
c.configMutex.Lock()
icmpTargetIPs := make([]netip.Addr, len(c.icmpTargetIPs)) icmpTargetIPs := make([]netip.Addr, len(c.icmpTargetIPs))
copy(icmpTargetIPs, c.icmpTargetIPs) copy(icmpTargetIPs, c.icmpTargetIPs)
c.configMutex.Unlock()
tryTimeouts := []time.Duration{ tryTimeouts := []time.Duration{
5 * time.Second, 5 * time.Second,
5 * time.Second, 5 * time.Second,
+1 -1
View File
@@ -3,7 +3,7 @@ package httpserver
import ( import (
"regexp" "regexp"
gomock "go.uber.org/mock/gomock" gomock "github.com/golang/mock/gomock"
) )
var _ Logger = (*testLogger)(nil) var _ Logger = (*testLogger)(nil)
+13 -19
View File
@@ -1,10 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/qdm12/gluetun/internal/httpserver (interfaces: Logger) // Source: github.com/qdm12/gluetun/internal/httpserver (interfaces: Logger)
//
// Generated by this command:
//
// mockgen -destination=logger_mock_test.go -package httpserver . Logger
//
// Package httpserver is a generated GoMock package. // Package httpserver is a generated GoMock package.
package httpserver package httpserver
@@ -12,14 +7,13 @@ package httpserver
import ( import (
reflect "reflect" reflect "reflect"
gomock "go.uber.org/mock/gomock" gomock "github.com/golang/mock/gomock"
) )
// MockLogger is a mock of Logger interface. // MockLogger is a mock of Logger interface.
type MockLogger struct { type MockLogger struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockLoggerMockRecorder recorder *MockLoggerMockRecorder
isgomock struct{}
} }
// MockLoggerMockRecorder is the mock recorder for MockLogger. // MockLoggerMockRecorder is the mock recorder for MockLogger.
@@ -40,37 +34,37 @@ func (m *MockLogger) EXPECT() *MockLoggerMockRecorder {
} }
// Error mocks base method. // Error mocks base method.
func (m *MockLogger) Error(msg string) { func (m *MockLogger) Error(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Error", msg) m.ctrl.Call(m, "Error", arg0)
} }
// Error indicates an expected call of Error. // Error indicates an expected call of Error.
func (mr *MockLoggerMockRecorder) Error(msg any) *gomock.Call { func (mr *MockLoggerMockRecorder) Error(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockLogger)(nil).Error), msg) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockLogger)(nil).Error), arg0)
} }
// Info mocks base method. // Info mocks base method.
func (m *MockLogger) Info(msg string) { func (m *MockLogger) Info(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Info", msg) m.ctrl.Call(m, "Info", arg0)
} }
// Info indicates an expected call of Info. // Info indicates an expected call of Info.
func (mr *MockLoggerMockRecorder) Info(msg any) *gomock.Call { func (mr *MockLoggerMockRecorder) Info(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockLogger)(nil).Info), msg) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockLogger)(nil).Info), arg0)
} }
// Warn mocks base method. // Warn mocks base method.
func (m *MockLogger) Warn(msg string) { func (m *MockLogger) Warn(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Warn", msg) m.ctrl.Call(m, "Warn", arg0)
} }
// Warn indicates an expected call of Warn. // Warn indicates an expected call of Warn.
func (mr *MockLoggerMockRecorder) Warn(msg any) *gomock.Call { func (mr *MockLoggerMockRecorder) Warn(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warn", reflect.TypeOf((*MockLogger)(nil).Warn), msg) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warn", reflect.TypeOf((*MockLogger)(nil).Warn), arg0)
} }
+1 -1
View File
@@ -6,8 +6,8 @@ import (
"testing" "testing"
"time" "time"
gomock "github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
gomock "go.uber.org/mock/gomock"
) )
func Test_Server_Run_success(t *testing.T) { func Test_Server_Run_success(t *testing.T) {
+3
View File
@@ -34,8 +34,11 @@ type Server struct {
SecureCore bool `json:"secure_core,omitempty"` SecureCore bool `json:"secure_core,omitempty"`
Tor bool `json:"tor,omitempty"` Tor bool `json:"tor,omitempty"`
PortForward bool `json:"port_forward,omitempty"` PortForward bool `json:"port_forward,omitempty"`
Dedicated bool `json:"dedicated,omitempty"`
Keep bool `json:"keep,omitempty"` Keep bool `json:"keep,omitempty"`
IPs []netip.Addr `json:"ips,omitempty"` IPs []netip.Addr `json:"ips,omitempty"`
PortsTCP []uint16 `json:"ports_tcp,omitempty"`
PortsUDP []uint16 `json:"ports_udp,omitempty"`
} }
func (s *Server) HasMinimumInformation() (err error) { func (s *Server) HasMinimumInformation() (err error) {
+1 -1
View File
@@ -9,9 +9,9 @@ import (
"testing" "testing"
"time" "time"
gomock "github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
gomock "go.uber.org/mock/gomock"
) )
func isIPv6LocallySupported() bool { func isIPv6LocallySupported() bool {
+5 -11
View File
@@ -1,10 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/qdm12/gluetun/internal/netlink (interfaces: Firewall) // Source: github.com/qdm12/gluetun/internal/netlink (interfaces: Firewall)
//
// Generated by this command:
//
// mockgen -destination=mocks_test.go -package=netlink . Firewall
//
// Package netlink is a generated GoMock package. // Package netlink is a generated GoMock package.
package netlink package netlink
@@ -14,14 +9,13 @@ import (
netip "net/netip" netip "net/netip"
reflect "reflect" reflect "reflect"
gomock "go.uber.org/mock/gomock" gomock "github.com/golang/mock/gomock"
) )
// MockFirewall is a mock of Firewall interface. // MockFirewall is a mock of Firewall interface.
type MockFirewall struct { type MockFirewall struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockFirewallMockRecorder recorder *MockFirewallMockRecorder
isgomock struct{}
} }
// MockFirewallMockRecorder is the mock recorder for MockFirewall. // MockFirewallMockRecorder is the mock recorder for MockFirewall.
@@ -42,15 +36,15 @@ func (m *MockFirewall) EXPECT() *MockFirewallMockRecorder {
} }
// AcceptOutput mocks base method. // AcceptOutput mocks base method.
func (m *MockFirewall) AcceptOutput(ctx context.Context, protocol, intf string, ip netip.Addr, port uint16, remove bool) error { func (m *MockFirewall) AcceptOutput(arg0 context.Context, arg1, arg2 string, arg3 netip.Addr, arg4 uint16, arg5 bool) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AcceptOutput", ctx, protocol, intf, ip, port, remove) ret := m.ctrl.Call(m, "AcceptOutput", arg0, arg1, arg2, arg3, arg4, arg5)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// AcceptOutput indicates an expected call of AcceptOutput. // AcceptOutput indicates an expected call of AcceptOutput.
func (mr *MockFirewallMockRecorder) AcceptOutput(ctx, protocol, intf, ip, port, remove any) *gomock.Call { func (mr *MockFirewallMockRecorder) AcceptOutput(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcceptOutput", reflect.TypeOf((*MockFirewall)(nil).AcceptOutput), ctx, protocol, intf, ip, port, remove) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcceptOutput", reflect.TypeOf((*MockFirewall)(nil).AcceptOutput), arg0, arg1, arg2, arg3, arg4, arg5)
} }
+15 -21
View File
@@ -1,10 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/qdm12/gluetun/internal/pmtud/tcp (interfaces: Logger) // Source: github.com/qdm12/gluetun/internal/pmtud/tcp (interfaces: Logger)
//
// Generated by this command:
//
// mockgen -destination=mocks_test.go -package=tcp . Logger
//
// Package tcp is a generated GoMock package. // Package tcp is a generated GoMock package.
package tcp package tcp
@@ -12,14 +7,13 @@ package tcp
import ( import (
reflect "reflect" reflect "reflect"
gomock "go.uber.org/mock/gomock" gomock "github.com/golang/mock/gomock"
) )
// MockLogger is a mock of Logger interface. // MockLogger is a mock of Logger interface.
type MockLogger struct { type MockLogger struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockLoggerMockRecorder recorder *MockLoggerMockRecorder
isgomock struct{}
} }
// MockLoggerMockRecorder is the mock recorder for MockLogger. // MockLoggerMockRecorder is the mock recorder for MockLogger.
@@ -40,47 +34,47 @@ func (m *MockLogger) EXPECT() *MockLoggerMockRecorder {
} }
// Debug mocks base method. // Debug mocks base method.
func (m *MockLogger) Debug(msg string) { func (m *MockLogger) Debug(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Debug", msg) m.ctrl.Call(m, "Debug", arg0)
} }
// Debug indicates an expected call of Debug. // Debug indicates an expected call of Debug.
func (mr *MockLoggerMockRecorder) Debug(msg any) *gomock.Call { func (mr *MockLoggerMockRecorder) Debug(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debug", reflect.TypeOf((*MockLogger)(nil).Debug), msg) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debug", reflect.TypeOf((*MockLogger)(nil).Debug), arg0)
} }
// Debugf mocks base method. // Debugf mocks base method.
func (m *MockLogger) Debugf(msg string, args ...any) { func (m *MockLogger) Debugf(arg0 string, arg1 ...interface{}) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
varargs := []any{msg} varargs := []interface{}{arg0}
for _, a := range args { for _, a := range arg1 {
varargs = append(varargs, a) varargs = append(varargs, a)
} }
m.ctrl.Call(m, "Debugf", varargs...) m.ctrl.Call(m, "Debugf", varargs...)
} }
// Debugf indicates an expected call of Debugf. // Debugf indicates an expected call of Debugf.
func (mr *MockLoggerMockRecorder) Debugf(msg any, args ...any) *gomock.Call { func (mr *MockLoggerMockRecorder) Debugf(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
varargs := append([]any{msg}, args...) varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debugf", reflect.TypeOf((*MockLogger)(nil).Debugf), varargs...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debugf", reflect.TypeOf((*MockLogger)(nil).Debugf), varargs...)
} }
// Warnf mocks base method. // Warnf mocks base method.
func (m *MockLogger) Warnf(msg string, args ...any) { func (m *MockLogger) Warnf(arg0 string, arg1 ...interface{}) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
varargs := []any{msg} varargs := []interface{}{arg0}
for _, a := range args { for _, a := range arg1 {
varargs = append(varargs, a) varargs = append(varargs, a)
} }
m.ctrl.Call(m, "Warnf", varargs...) m.ctrl.Call(m, "Warnf", varargs...)
} }
// Warnf indicates an expected call of Warnf. // Warnf indicates an expected call of Warnf.
func (mr *MockLoggerMockRecorder) Warnf(msg any, args ...any) *gomock.Call { func (mr *MockLoggerMockRecorder) Warnf(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
varargs := append([]any{msg}, args...) varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warnf", reflect.TypeOf((*MockLogger)(nil).Warnf), varargs...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warnf", reflect.TypeOf((*MockLogger)(nil).Warnf), varargs...)
} }
+1 -1
View File
@@ -8,11 +8,11 @@ import (
"testing" "testing"
"time" "time"
gomock "github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/netlink" "github.com/qdm12/gluetun/internal/netlink"
"github.com/qdm12/gluetun/internal/pmtud/constants" "github.com/qdm12/gluetun/internal/pmtud/constants"
"github.com/qdm12/gluetun/internal/pmtud/ip" "github.com/qdm12/gluetun/internal/pmtud/ip"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
gomock "go.uber.org/mock/gomock"
) )
func Test_runTest(t *testing.T) { func Test_runTest(t *testing.T) {
-3
View File
@@ -99,7 +99,6 @@ func (l *Loop) run(runCtx context.Context, runDone chan<- struct{},
case partialUpdate := <-updateTrigger: case partialUpdate := <-updateTrigger:
updatedSettings, err := l.settings.updateWith(partialUpdate, *l.settings.VPNIsUp) updatedSettings, err := l.settings.updateWith(partialUpdate, *l.settings.VPNIsUp)
if err != nil { if err != nil {
l.logger.Debug(fmt.Sprintf("port forward loop: run: updateWith error %v", err))
updateResult <- err updateResult <- err
continue continue
} }
@@ -137,7 +136,6 @@ func (l *Loop) run(runCtx context.Context, runDone chan<- struct{},
if err != nil { if err != nil {
err = fmt.Errorf("starting port forwarding service: %w", err) err = fmt.Errorf("starting port forwarding service: %w", err)
} }
l.logger.Debug(fmt.Sprintf("port forward loop: Start: error is %v", err))
updateResult <- err updateResult <- err
} else if err != nil { } else if err != nil {
// Log the error and schedule a retry // Log the error and schedule a retry
@@ -152,7 +150,6 @@ func (l *Loop) UpdateWith(partialUpdate Settings) (err error) {
case l.updateTrigger <- partialUpdate: case l.updateTrigger <- partialUpdate:
select { select {
case err = <-l.updatedResult: case err = <-l.updatedResult:
l.logger.Debug(fmt.Sprintf("port forward loop: UpdateWith: received error %v", err))
return err return err
case <-l.runCtx.Done(): case <-l.runCtx.Done():
return l.runCtx.Err() return l.runCtx.Err()
+1 -1
View File
@@ -6,9 +6,9 @@ import (
"context" "context"
"testing" "testing"
gomock "github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/command" "github.com/qdm12/gluetun/internal/command"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
gomock "go.uber.org/mock/gomock"
) )
func Test_Service_runCommand(t *testing.T) { func Test_Service_runCommand(t *testing.T) {
+17 -23
View File
@@ -1,10 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/qdm12/gluetun/internal/portforward/service (interfaces: Logger) // Source: github.com/qdm12/gluetun/internal/portforward/service (interfaces: Logger)
//
// Generated by this command:
//
// mockgen -destination=mocks_test.go -package=service . Logger
//
// Package service is a generated GoMock package. // Package service is a generated GoMock package.
package service package service
@@ -12,14 +7,13 @@ package service
import ( import (
reflect "reflect" reflect "reflect"
gomock "go.uber.org/mock/gomock" gomock "github.com/golang/mock/gomock"
) )
// MockLogger is a mock of Logger interface. // MockLogger is a mock of Logger interface.
type MockLogger struct { type MockLogger struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockLoggerMockRecorder recorder *MockLoggerMockRecorder
isgomock struct{}
} }
// MockLoggerMockRecorder is the mock recorder for MockLogger. // MockLoggerMockRecorder is the mock recorder for MockLogger.
@@ -40,49 +34,49 @@ func (m *MockLogger) EXPECT() *MockLoggerMockRecorder {
} }
// Debug mocks base method. // Debug mocks base method.
func (m *MockLogger) Debug(s string) { func (m *MockLogger) Debug(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Debug", s) m.ctrl.Call(m, "Debug", arg0)
} }
// Debug indicates an expected call of Debug. // Debug indicates an expected call of Debug.
func (mr *MockLoggerMockRecorder) Debug(s any) *gomock.Call { func (mr *MockLoggerMockRecorder) Debug(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debug", reflect.TypeOf((*MockLogger)(nil).Debug), s) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debug", reflect.TypeOf((*MockLogger)(nil).Debug), arg0)
} }
// Error mocks base method. // Error mocks base method.
func (m *MockLogger) Error(s string) { func (m *MockLogger) Error(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Error", s) m.ctrl.Call(m, "Error", arg0)
} }
// Error indicates an expected call of Error. // Error indicates an expected call of Error.
func (mr *MockLoggerMockRecorder) Error(s any) *gomock.Call { func (mr *MockLoggerMockRecorder) Error(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockLogger)(nil).Error), s) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockLogger)(nil).Error), arg0)
} }
// Info mocks base method. // Info mocks base method.
func (m *MockLogger) Info(s string) { func (m *MockLogger) Info(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Info", s) m.ctrl.Call(m, "Info", arg0)
} }
// Info indicates an expected call of Info. // Info indicates an expected call of Info.
func (mr *MockLoggerMockRecorder) Info(s any) *gomock.Call { func (mr *MockLoggerMockRecorder) Info(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockLogger)(nil).Info), s) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockLogger)(nil).Info), arg0)
} }
// Warn mocks base method. // Warn mocks base method.
func (m *MockLogger) Warn(s string) { func (m *MockLogger) Warn(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Warn", s) m.ctrl.Call(m, "Warn", arg0)
} }
// Warn indicates an expected call of Warn. // Warn indicates an expected call of Warn.
func (mr *MockLoggerMockRecorder) Warn(s any) *gomock.Call { func (mr *MockLoggerMockRecorder) Warn(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warn", reflect.TypeOf((*MockLogger)(nil).Warn), s) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warn", reflect.TypeOf((*MockLogger)(nil).Warn), arg0)
} }
-2
View File
@@ -123,9 +123,7 @@ func (s *Service) onNewPorts(ctx context.Context, internalToExternalPorts map[ui
} }
} }
s.logger.Debug(fmt.Sprintf("writePortForwardedFile with externalPorts: %v", externalPorts))
err = s.writePortForwardedFile(externalPorts) err = s.writePortForwardedFile(externalPorts)
s.logger.Debug(fmt.Sprintf("writing port file: error is %v", err))
if err != nil { if err != nil {
_ = s.cleanup() _ = s.cleanup()
return fmt.Errorf("writing port file: %w", err) return fmt.Errorf("writing port file: %w", err)
-1
View File
@@ -58,7 +58,6 @@ func (s *Service) cleanup() (err error) {
s.ports = nil s.ports = nil
s.logger.Debug("writePortForwardedFile in cleanup")
err = s.writePortForwardedFile(nil) err = s.writePortForwardedFile(nil)
if err != nil { if err != nil {
return fmt.Errorf("clearing port file: %w", err) return fmt.Errorf("clearing port file: %w", err)
+1 -1
View File
@@ -3,7 +3,7 @@ package pprof
import ( import (
"regexp" "regexp"
gomock "go.uber.org/mock/gomock" gomock "github.com/golang/mock/gomock"
) )
func boolPtr(b bool) *bool { return &b } func boolPtr(b bool) *bool { return &b }
+13 -19
View File
@@ -1,10 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/qdm12/gluetun/internal/httpserver (interfaces: Logger) // Source: github.com/qdm12/gluetun/internal/httpserver (interfaces: Logger)
//
// Generated by this command:
//
// mockgen -destination=logger_mock_test.go -package pprof github.com/qdm12/gluetun/internal/httpserver Logger
//
// Package pprof is a generated GoMock package. // Package pprof is a generated GoMock package.
package pprof package pprof
@@ -12,14 +7,13 @@ package pprof
import ( import (
reflect "reflect" reflect "reflect"
gomock "go.uber.org/mock/gomock" gomock "github.com/golang/mock/gomock"
) )
// MockLogger is a mock of Logger interface. // MockLogger is a mock of Logger interface.
type MockLogger struct { type MockLogger struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockLoggerMockRecorder recorder *MockLoggerMockRecorder
isgomock struct{}
} }
// MockLoggerMockRecorder is the mock recorder for MockLogger. // MockLoggerMockRecorder is the mock recorder for MockLogger.
@@ -40,37 +34,37 @@ func (m *MockLogger) EXPECT() *MockLoggerMockRecorder {
} }
// Error mocks base method. // Error mocks base method.
func (m *MockLogger) Error(msg string) { func (m *MockLogger) Error(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Error", msg) m.ctrl.Call(m, "Error", arg0)
} }
// Error indicates an expected call of Error. // Error indicates an expected call of Error.
func (mr *MockLoggerMockRecorder) Error(msg any) *gomock.Call { func (mr *MockLoggerMockRecorder) Error(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockLogger)(nil).Error), msg) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockLogger)(nil).Error), arg0)
} }
// Info mocks base method. // Info mocks base method.
func (m *MockLogger) Info(msg string) { func (m *MockLogger) Info(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Info", msg) m.ctrl.Call(m, "Info", arg0)
} }
// Info indicates an expected call of Info. // Info indicates an expected call of Info.
func (mr *MockLoggerMockRecorder) Info(msg any) *gomock.Call { func (mr *MockLoggerMockRecorder) Info(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockLogger)(nil).Info), msg) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Info", reflect.TypeOf((*MockLogger)(nil).Info), arg0)
} }
// Warn mocks base method. // Warn mocks base method.
func (m *MockLogger) Warn(msg string) { func (m *MockLogger) Warn(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Warn", msg) m.ctrl.Call(m, "Warn", arg0)
} }
// Warn indicates an expected call of Warn. // Warn indicates an expected call of Warn.
func (mr *MockLoggerMockRecorder) Warn(msg any) *gomock.Call { func (mr *MockLoggerMockRecorder) Warn(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warn", reflect.TypeOf((*MockLogger)(nil).Warn), msg) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warn", reflect.TypeOf((*MockLogger)(nil).Warn), arg0)
} }
+1 -1
View File
@@ -7,10 +7,10 @@ import (
"testing" "testing"
"time" "time"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/httpserver" "github.com/qdm12/gluetun/internal/httpserver"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
) )
//go:generate mockgen -destination=logger_mock_test.go -package $GOPACKAGE github.com/qdm12/gluetun/internal/httpserver Logger //go:generate mockgen -destination=logger_mock_test.go -package $GOPACKAGE github.com/qdm12/gluetun/internal/httpserver Logger
+17 -26
View File
@@ -1,10 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/qdm12/gluetun/internal/provider/common (interfaces: ParallelResolver,Storage,Unzipper,Warner) // Source: github.com/qdm12/gluetun/internal/provider/common (interfaces: ParallelResolver,Storage,Unzipper,Warner)
//
// Generated by this command:
//
// mockgen -destination=mocks.go -package common . ParallelResolver,Storage,Unzipper,Warner
//
// Package common is a generated GoMock package. // Package common is a generated GoMock package.
package common package common
@@ -14,17 +9,16 @@ import (
netip "net/netip" netip "net/netip"
reflect "reflect" reflect "reflect"
gomock "github.com/golang/mock/gomock"
settings "github.com/qdm12/gluetun/internal/configuration/settings" settings "github.com/qdm12/gluetun/internal/configuration/settings"
models "github.com/qdm12/gluetun/internal/models" models "github.com/qdm12/gluetun/internal/models"
resolver "github.com/qdm12/gluetun/internal/updater/resolver" resolver "github.com/qdm12/gluetun/internal/updater/resolver"
gomock "go.uber.org/mock/gomock"
) )
// MockParallelResolver is a mock of ParallelResolver interface. // MockParallelResolver is a mock of ParallelResolver interface.
type MockParallelResolver struct { type MockParallelResolver struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockParallelResolverMockRecorder recorder *MockParallelResolverMockRecorder
isgomock struct{}
} }
// MockParallelResolverMockRecorder is the mock recorder for MockParallelResolver. // MockParallelResolverMockRecorder is the mock recorder for MockParallelResolver.
@@ -45,9 +39,9 @@ func (m *MockParallelResolver) EXPECT() *MockParallelResolverMockRecorder {
} }
// Resolve mocks base method. // Resolve mocks base method.
func (m *MockParallelResolver) Resolve(ctx context.Context, arg1 resolver.ParallelSettings) (map[string][]netip.Addr, []string, error) { func (m *MockParallelResolver) Resolve(arg0 context.Context, arg1 resolver.ParallelSettings) (map[string][]netip.Addr, []string, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Resolve", ctx, arg1) ret := m.ctrl.Call(m, "Resolve", arg0, arg1)
ret0, _ := ret[0].(map[string][]netip.Addr) ret0, _ := ret[0].(map[string][]netip.Addr)
ret1, _ := ret[1].([]string) ret1, _ := ret[1].([]string)
ret2, _ := ret[2].(error) ret2, _ := ret[2].(error)
@@ -55,16 +49,15 @@ func (m *MockParallelResolver) Resolve(ctx context.Context, arg1 resolver.Parall
} }
// Resolve indicates an expected call of Resolve. // Resolve indicates an expected call of Resolve.
func (mr *MockParallelResolverMockRecorder) Resolve(ctx, arg1 any) *gomock.Call { func (mr *MockParallelResolverMockRecorder) Resolve(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Resolve", reflect.TypeOf((*MockParallelResolver)(nil).Resolve), ctx, arg1) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Resolve", reflect.TypeOf((*MockParallelResolver)(nil).Resolve), arg0, arg1)
} }
// MockStorage is a mock of Storage interface. // MockStorage is a mock of Storage interface.
type MockStorage struct { type MockStorage struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockStorageMockRecorder recorder *MockStorageMockRecorder
isgomock struct{}
} }
// MockStorageMockRecorder is the mock recorder for MockStorage. // MockStorageMockRecorder is the mock recorder for MockStorage.
@@ -85,25 +78,24 @@ func (m *MockStorage) EXPECT() *MockStorageMockRecorder {
} }
// FilterServers mocks base method. // FilterServers mocks base method.
func (m *MockStorage) FilterServers(provider string, selection settings.ServerSelection) ([]models.Server, error) { func (m *MockStorage) FilterServers(arg0 string, arg1 settings.ServerSelection) ([]models.Server, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FilterServers", provider, selection) ret := m.ctrl.Call(m, "FilterServers", arg0, arg1)
ret0, _ := ret[0].([]models.Server) ret0, _ := ret[0].([]models.Server)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// FilterServers indicates an expected call of FilterServers. // FilterServers indicates an expected call of FilterServers.
func (mr *MockStorageMockRecorder) FilterServers(provider, selection any) *gomock.Call { func (mr *MockStorageMockRecorder) FilterServers(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FilterServers", reflect.TypeOf((*MockStorage)(nil).FilterServers), provider, selection) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FilterServers", reflect.TypeOf((*MockStorage)(nil).FilterServers), arg0, arg1)
} }
// MockUnzipper is a mock of Unzipper interface. // MockUnzipper is a mock of Unzipper interface.
type MockUnzipper struct { type MockUnzipper struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockUnzipperMockRecorder recorder *MockUnzipperMockRecorder
isgomock struct{}
} }
// MockUnzipperMockRecorder is the mock recorder for MockUnzipper. // MockUnzipperMockRecorder is the mock recorder for MockUnzipper.
@@ -124,25 +116,24 @@ func (m *MockUnzipper) EXPECT() *MockUnzipperMockRecorder {
} }
// FetchAndExtract mocks base method. // FetchAndExtract mocks base method.
func (m *MockUnzipper) FetchAndExtract(ctx context.Context, url string) (map[string][]byte, error) { func (m *MockUnzipper) FetchAndExtract(arg0 context.Context, arg1 string) (map[string][]byte, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FetchAndExtract", ctx, url) ret := m.ctrl.Call(m, "FetchAndExtract", arg0, arg1)
ret0, _ := ret[0].(map[string][]byte) ret0, _ := ret[0].(map[string][]byte)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// FetchAndExtract indicates an expected call of FetchAndExtract. // FetchAndExtract indicates an expected call of FetchAndExtract.
func (mr *MockUnzipperMockRecorder) FetchAndExtract(ctx, url any) *gomock.Call { func (mr *MockUnzipperMockRecorder) FetchAndExtract(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchAndExtract", reflect.TypeOf((*MockUnzipper)(nil).FetchAndExtract), ctx, url) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchAndExtract", reflect.TypeOf((*MockUnzipper)(nil).FetchAndExtract), arg0, arg1)
} }
// MockWarner is a mock of Warner interface. // MockWarner is a mock of Warner interface.
type MockWarner struct { type MockWarner struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockWarnerMockRecorder recorder *MockWarnerMockRecorder
isgomock struct{}
} }
// MockWarnerMockRecorder is the mock recorder for MockWarner. // MockWarnerMockRecorder is the mock recorder for MockWarner.
@@ -163,13 +154,13 @@ func (m *MockWarner) EXPECT() *MockWarnerMockRecorder {
} }
// Warn mocks base method. // Warn mocks base method.
func (m *MockWarner) Warn(s string) { func (m *MockWarner) Warn(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
m.ctrl.Call(m, "Warn", s) m.ctrl.Call(m, "Warn", arg0)
} }
// Warn indicates an expected call of Warn. // Warn indicates an expected call of Warn.
func (mr *MockWarnerMockRecorder) Warn(s any) *gomock.Call { func (mr *MockWarnerMockRecorder) Warn(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warn", reflect.TypeOf((*MockWarner)(nil).Warn), s) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warn", reflect.TypeOf((*MockWarner)(nil).Warn), arg0)
} }
@@ -5,6 +5,7 @@ import (
"net/netip" "net/netip"
"testing" "testing"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/configuration/settings" "github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/constants/providers" "github.com/qdm12/gluetun/internal/constants/providers"
@@ -12,7 +13,6 @@ import (
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/common" "github.com/qdm12/gluetun/internal/provider/common"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
) )
func Test_Provider_GetConnection(t *testing.T) { func Test_Provider_GetConnection(t *testing.T) {
@@ -7,13 +7,13 @@ import (
"testing" "testing"
"time" "time"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/common" "github.com/qdm12/gluetun/internal/provider/common"
"github.com/qdm12/gluetun/internal/updater/resolver" "github.com/qdm12/gluetun/internal/updater/resolver"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
) )
func Test_Updater_GetServers(t *testing.T) { func Test_Updater_GetServers(t *testing.T) {
+1 -1
View File
@@ -6,6 +6,7 @@ import (
"net/netip" "net/netip"
"testing" "testing"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/configuration/settings" "github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/constants/providers" "github.com/qdm12/gluetun/internal/constants/providers"
@@ -13,7 +14,6 @@ import (
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/common" "github.com/qdm12/gluetun/internal/provider/common"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
) )
func Test_Provider_GetConnection(t *testing.T) { func Test_Provider_GetConnection(t *testing.T) {
@@ -10,13 +10,13 @@ import (
"testing" "testing"
"time" "time"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/common" "github.com/qdm12/gluetun/internal/provider/common"
"github.com/qdm12/gluetun/internal/updater/resolver" "github.com/qdm12/gluetun/internal/updater/resolver"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
) )
func Test_Updater_GetServers(t *testing.T) { func Test_Updater_GetServers(t *testing.T) {
+1 -1
View File
@@ -6,6 +6,7 @@ import (
"net/netip" "net/netip"
"testing" "testing"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/configuration/settings" "github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/constants/providers" "github.com/qdm12/gluetun/internal/constants/providers"
@@ -13,7 +14,6 @@ import (
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/common" "github.com/qdm12/gluetun/internal/provider/common"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
) )
func Test_Provider_GetConnection(t *testing.T) { func Test_Provider_GetConnection(t *testing.T) {
+15
View File
@@ -0,0 +1,15 @@
package ovpn
import (
"github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/utils"
)
func (p *Provider) GetConnection(selection settings.ServerSelection, ipv6Supported bool) (
connection models.Connection, err error,
) {
defaults := utils.NewConnectionDefaults(443, 1194, 9929) //nolint:mnd
return utils.GetConnection(p.Name(),
p.storage, selection, defaults, ipv6Supported, p.connPicker)
}
+126
View File
@@ -0,0 +1,126 @@
package ovpn
import (
"errors"
"net/http"
"net/netip"
"testing"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/constants/providers"
"github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/common"
"github.com/stretchr/testify/assert"
)
func Test_Provider_GetConnection(t *testing.T) {
t.Parallel()
const provider = providers.Ovpn
errTest := errors.New("test error")
testCases := map[string]struct {
filteredServers []models.Server
storageErr error
selection settings.ServerSelection
ipv6Supported bool
connection models.Connection
errWrapped error
errMessage string
}{
"error": {
storageErr: errTest,
errWrapped: errTest,
errMessage: "filtering servers: test error",
},
"default_openvpn_tcp_port": {
filteredServers: []models.Server{
{IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}},
},
selection: settings.ServerSelection{
OpenVPN: settings.OpenVPNSelection{
Protocol: constants.TCP,
},
}.WithDefaults(provider),
connection: models.Connection{
Type: vpn.OpenVPN,
IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Port: 443,
Protocol: constants.TCP,
},
},
"default_openvpn_udp_port": {
filteredServers: []models.Server{
{IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}},
},
selection: settings.ServerSelection{
OpenVPN: settings.OpenVPNSelection{
Protocol: constants.UDP,
},
}.WithDefaults(provider),
connection: models.Connection{
Type: vpn.OpenVPN,
IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Port: 1194,
Protocol: constants.UDP,
},
},
"default_wireguard_port": {
filteredServers: []models.Server{
{IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}, WgPubKey: "x"},
},
selection: settings.ServerSelection{
VPN: vpn.Wireguard,
}.WithDefaults(provider),
connection: models.Connection{
Type: vpn.Wireguard,
IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Port: 9929,
Protocol: constants.UDP,
PubKey: "x",
},
},
"default_multihop_port": {
filteredServers: []models.Server{
{IPs: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})}, WgPubKey: "x", PortsUDP: []uint16{30044}},
},
selection: settings.ServerSelection{
VPN: vpn.Wireguard,
}.WithDefaults(provider),
connection: models.Connection{
Type: vpn.Wireguard,
IP: netip.AddrFrom4([4]byte{1, 1, 1, 1}),
Port: 30044,
Protocol: constants.UDP,
PubKey: "x",
},
},
}
for name, testCase := range testCases {
t.Run(name, func(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
storage := common.NewMockStorage(ctrl)
storage.EXPECT().FilterServers(provider, testCase.selection).
Return(testCase.filteredServers, testCase.storageErr)
client := (*http.Client)(nil)
provider := New(storage, client)
connection, err := provider.GetConnection(testCase.selection, testCase.ipv6Supported)
assert.ErrorIs(t, err, testCase.errWrapped)
if testCase.errWrapped != nil {
assert.EqualError(t, err, testCase.errMessage)
}
assert.Equal(t, testCase.connection, connection)
})
}
}
+38
View File
@@ -0,0 +1,38 @@
package ovpn
import (
"strings"
"github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/constants/openvpn"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/utils"
)
func (p *Provider) OpenVPNConfig(connection models.Connection,
settings settings.OpenVPN, ipv6Supported bool,
) (lines []string) {
providerSettings := utils.OpenVPNProviderSettings{
AuthUserPass: true,
RemoteCertTLS: true,
Ciphers: []string{
openvpn.AES256gcm,
openvpn.AES256cbc,
openvpn.AES128gcm,
openvpn.Chacha20Poly1305,
},
CAs: []string{
"MIIEfTCCA2WgAwIBAgIJAK2aIWqpLj1/MA0GCSqGSIb3DQEBBQUAMIGFMQswCQYDVQQGEwJTRTESMBAGA1UECBMJU3RvY2tob2xtMRIwEAYDVQQHEwlTdG9ja2hvbG0xHDAaBgNVBAsTE0Zpcm1hIERhdmlkIFdpYmVyZ2gxEzARBgNVBAMTCm92cG4uc2UgY2ExGzAZBgkqhkiG9w0BCQEWDGluZm9Ab3Zwbi5zZTAeFw0xNDA4MTcxODIxMjlaFw0zNDA4MTIxODIxMjlaMIGFMQswCQYDVQQGEwJTRTESMBAGA1UECBMJU3RvY2tob2xtMRIwEAYDVQQHEwlTdG9ja2hvbG0xHDAaBgNVBAsTE0Zpcm1hIERhdmlkIFdpYmVyZ2gxEzARBgNVBAMTCm92cG4uc2UgY2ExGzAZBgkqhkiG9w0BCQEWDGluZm9Ab3Zwbi5zZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMR+aP4GTuZwurZuOA2NYzMfqKyZi/TJcLEPlGTB/b4CWA9bTd8f0pHPrDAZsXIEayxxB58BIFNDNiybnbO15JN/QwlsqmA+aZX6mCSkScs/rRwasM6LDo8iGx+KmYEqAgzziONGbCMnlO+OaarXte7LhZ9X6Z/bryu4xq/i1v3raak13kXsrogtu4iDzxqJE/QhbNOi0yhCdlm5RYQjmlKGdPB9pNTgcakVI4HcngRYMzBlrGin0YkvWCdpx5FrDNeld7BSWrJMNYyvd+buaid0Fu1T9/P/Srj/8AiabKoaDyiGFbZdTnGfK+04lWRvwAmvazpqbUt5Omw634jJDuMCAwEAAaOB7TCB6jAdBgNVHQ4EFgQUEvJcHHcTiDtu7bAyZw+xaqg+xdIwgboGA1UdIwSBsjCBr4AUEvJcHHcTiDtu7bAyZw+xaqg+xdKhgYukgYgwgYUxCzAJBgNVBAYTAlNFMRIwEAYDVQQIEwlTdG9ja2hvbG0xEjAQBgNVBAcTCVN0b2NraG9sbTEcMBoGA1UECxMTRmlybWEgRGF2aWQgV2liZXJnaDETMBEGA1UEAxMKb3Zwbi5zZSBjYTEbMBkGCSqGSIb3DQEJARYMaW5mb0BvdnBuLnNlggkArZohaqkuPX8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAJmID6OyBJbV7ayPPgquojF+FICuDdOfGVKP828cyISxcbVA04VpD0QLYVb0k9pFUx0NbgX2SvRTiFhP7LcyS1HV9s+XLCb2WItPPsrdRTwtqU2n3TlCEzWA3WOcOCtT6JSkv1eelmx1JnP0gYJrDvDvRYBFctwWhtE0bineSQkZwN6980zkknADLAiHpeZSu/AMx7CGTwA6SmoFvpNBmHXDcfe/9ZqbbYfUfyPNe+0JbMrcv1elKi+6wlEkHFaEBphiZwGEbOX1CjUMcQFgW/cIp3n50Eiyx6ktuqimhyb59P4Nw8gqH452tTtE4MM/brA5y0Q0WFBRBojfZIbGWWQ==", //nolint:lll
},
TLSAuth: "81782767e4d59c4464cc5d1896f1cf6015017d53ac62e2e3b94b889e00b2c69ddc01944fe1c6d895b4d80540502eb71910b8d785c9efa9e3182343532adffe1cfbb7bb6eae39c502da2748edf0fb89b8a20b0a1085cc1f06135037881bc0c4ad8f2c0f4f72d2ab466fb54af3d8264c5fddeb0f21aa0ca41863678f5fc4c44de4ca0926b36dfddc42c6f2fabd1694bdc8215b2d223b9c21dc6734c2c778093187afb8c33403b228b9af68b540c284f6d183bcc88bd41d47bd717996e499ce1cbbfa768a9723c19c58314c4d19cfed82e543ee92e73d38ad26d4fbec231c0f9f3b30773a5c87792e9bc7c34e8d7611002ebedd044e48a0f1f96527bfdcc940aa09", //nolint:lll
KeyDirection: "1",
}
if strings.HasSuffix(connection.Hostname, "singapore.ovpn.com") {
providerSettings.TLSCrypt = providerSettings.TLSAuth
providerSettings.TLSAuth = ""
providerSettings.KeyDirection = ""
}
return utils.OpenVPNConfig(providerSettings, connection, settings, ipv6Supported)
}
+28
View File
@@ -0,0 +1,28 @@
package ovpn
import (
"net/http"
"github.com/qdm12/gluetun/internal/constants/providers"
"github.com/qdm12/gluetun/internal/provider/common"
"github.com/qdm12/gluetun/internal/provider/ovpn/updater"
"github.com/qdm12/gluetun/internal/provider/utils"
)
type Provider struct {
storage common.Storage
connPicker *utils.ConnectionPicker
common.Fetcher
}
func New(storage common.Storage, client *http.Client) *Provider {
return &Provider{
storage: storage,
connPicker: utils.NewConnectionPicker(),
Fetcher: updater.New(client),
}
}
func (p *Provider) Name() string {
return providers.Ovpn
}
+153
View File
@@ -0,0 +1,153 @@
package updater
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/netip"
"strings"
)
type apiData struct {
Success bool `json:"success"`
DataCenters []apiDataCenter `json:"datacenters"`
}
type apiDataCenter struct {
City string `json:"city"`
CountryName string `json:"country_name"`
Servers []apiServer `json:"servers"`
}
type apiServer struct {
IP netip.Addr `json:"ip"`
Ptr string `json:"ptr"` // hostname
Online bool `json:"online"`
// PublicKey is for the Standard Shared Entry Point
PublicKey string `json:"public_key"`
// PublicKeyIPv4 is for the Public / Dedicated IP Entry Point
PublicKeyIPv4 string `json:"public_key_ipv4"`
WireguardPorts []uint16 `json:"wireguard_ports"`
MultiHopOpenvpnPort uint16 `json:"multihop_openvpn_port"`
MultiHopWireguardPort uint16 `json:"multihop_wireguard_port"`
}
func fetchAPI(ctx context.Context, client *http.Client) (
data apiData, err error,
) {
const url = "https://www.ovpn.com/v2/api/client/entry"
request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return data, err
}
response, err := client.Do(request)
if err != nil {
return data, err
}
if response.StatusCode != http.StatusOK {
_ = response.Body.Close()
return data, fmt.Errorf("HTTP response status code is not OK: %d %s",
response.StatusCode, response.Status)
}
decoder := json.NewDecoder(response.Body)
err = decoder.Decode(&data)
if err != nil {
_ = response.Body.Close()
return data, fmt.Errorf("decoding response body: %w", err)
}
err = response.Body.Close()
if err != nil {
return data, fmt.Errorf("closing response body: %w", err)
}
return data, nil
}
func (a *apiDataCenter) validate() (err error) {
conditionalErrors := []conditionalError{
{err: "city is not set", condition: a.City == ""},
{err: "country name is not set", condition: a.CountryName == ""},
{err: "servers array is not set", condition: len(a.Servers) == 0},
}
err = collectErrors(conditionalErrors)
if err != nil {
var dataCenterSetFields []string
if a.CountryName != "" {
dataCenterSetFields = append(dataCenterSetFields, a.CountryName)
}
if a.City != "" {
dataCenterSetFields = append(dataCenterSetFields, a.City)
}
if len(dataCenterSetFields) == 0 {
return err
}
return fmt.Errorf("data center %s: %w",
strings.Join(dataCenterSetFields, ", "), err)
}
for i, server := range a.Servers {
err = server.validate()
if err != nil {
return fmt.Errorf("datacenter %s, %s: server %d of %d: %w",
a.CountryName, a.City, i+1, len(a.Servers), err)
}
}
return nil
}
func (a *apiServer) validate() (err error) {
const defaultWireguardPort = 9929
conditionalErrors := []conditionalError{
{err: "ip address is not set", condition: !a.IP.IsValid()},
{err: "hostname field is not set", condition: a.Ptr == ""},
{err: "public key field is not set", condition: a.PublicKey == ""},
{err: "public key IPv4 field is not set", condition: a.PublicKeyIPv4 == ""},
{err: "wireguard ports array is not set", condition: len(a.WireguardPorts) == 0},
{
err: "wireguard port is not the default 9929",
condition: len(a.WireguardPorts) != 1 || a.WireguardPorts[0] != defaultWireguardPort,
},
{err: "multihop OpenVPN port is not set", condition: a.MultiHopOpenvpnPort == 0},
{err: "multihop WireGuard port is not set", condition: a.MultiHopWireguardPort == 0},
}
err = collectErrors(conditionalErrors)
switch {
case err == nil:
return nil
case a.Ptr != "":
return fmt.Errorf("server %s: %w", a.Ptr, err)
case a.IP.IsValid():
return fmt.Errorf("server %s: %w", a.IP.String(), err)
default:
return err
}
}
type conditionalError struct {
err string
condition bool
}
func collectErrors(conditionalErrors []conditionalError) (err error) {
errs := make([]string, 0, len(conditionalErrors))
for _, conditionalError := range conditionalErrors {
if !conditionalError.condition {
continue
}
errs = append(errs, conditionalError.err)
}
if len(errs) == 0 {
return nil
}
return errors.New(strings.Join(errs, "; "))
}
+118
View File
@@ -0,0 +1,118 @@
package updater
import (
"context"
"errors"
"io"
"net/http"
"net/netip"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_fetchAPI(t *testing.T) {
t.Parallel()
testCases := map[string]struct {
responseStatus int
responseBody io.ReadCloser
data apiData
err error
}{
"http response status not ok": {
responseStatus: http.StatusNoContent,
err: errors.New("HTTP response status code is not OK: 204 No Content"),
},
"nil body": {
responseStatus: http.StatusOK,
err: errors.New("decoding response body: EOF"),
},
"no server": {
responseStatus: http.StatusOK,
responseBody: io.NopCloser(strings.NewReader(`{}`)),
},
"success": {
responseStatus: http.StatusOK,
responseBody: io.NopCloser(strings.NewReader(`{
"success": true,
"datacenters": [
{
"slug": "vienna",
"city": "Vienna",
"country": "AT",
"country_name": "Austria",
"pools": [
"pool-1.prd.at.vienna.ovpn.com"
],
"ping_address": "37.120.212.227",
"servers": [
{
"ip": "37.120.212.227",
"ptr": "vpn44.prd.vienna.ovpn.com",
"name": "VPN44 - Vienna",
"online": true,
"load": 8,
"public_key": "r83LIc0Q2F8s3dY9x5y17Yz8wTADJc7giW1t5eSmoXc=",
"public_key_ipv4": "wFbSRyjSXBmkjJodlqz7DoYn3WNDPYFUIXyIUS2QU2A=",
"wireguard_ports": [
9929
],
"multihop_openvpn_port": 20044,
"multihop_wireguard_port": 30044
}
]
}
]
}`)),
data: apiData{
Success: true,
DataCenters: []apiDataCenter{
{CountryName: "Austria", City: "Vienna", Servers: []apiServer{
{
IP: netip.MustParseAddr("37.120.212.227"),
Ptr: "vpn44.prd.vienna.ovpn.com",
Online: true,
PublicKey: "r83LIc0Q2F8s3dY9x5y17Yz8wTADJc7giW1t5eSmoXc=",
PublicKeyIPv4: "wFbSRyjSXBmkjJodlqz7DoYn3WNDPYFUIXyIUS2QU2A=",
WireguardPorts: []uint16{9929},
MultiHopOpenvpnPort: 20044,
MultiHopWireguardPort: 30044,
},
}},
},
},
},
}
for name, testCase := range testCases {
t.Run(name, func(t *testing.T) {
t.Parallel()
ctx := context.Background()
client := &http.Client{
Transport: roundTripFunc(func(r *http.Request) (*http.Response, error) {
assert.Equal(t, http.MethodGet, r.Method)
assert.Equal(t, r.URL.String(), "https://www.ovpn.com/v2/api/client/entry")
return &http.Response{
StatusCode: testCase.responseStatus,
Status: http.StatusText(testCase.responseStatus),
Body: testCase.responseBody,
}, nil
}),
}
data, err := fetchAPI(ctx, client)
assert.Equal(t, testCase.data, data)
if testCase.err != nil {
require.Error(t, err)
assert.Equal(t, testCase.err.Error(), err.Error())
} else {
assert.NoError(t, err)
}
})
}
}
@@ -0,0 +1,9 @@
package updater
import "net/http"
type roundTripFunc func(r *http.Request) (*http.Response, error)
func (f roundTripFunc) RoundTrip(r *http.Request) (*http.Response, error) {
return f(r)
}
+82
View File
@@ -0,0 +1,82 @@
package updater
import (
"context"
"errors"
"fmt"
"net/netip"
"sort"
"github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/common"
)
func (u *Updater) FetchServers(ctx context.Context, minServers int) (
servers []models.Server, err error,
) {
data, err := fetchAPI(ctx, u.client)
if err != nil {
return nil, fmt.Errorf("fetching API: %w", err)
} else if !data.Success {
return nil, errors.New("response success field is false")
}
for dataCenterIndex, dataCenter := range data.DataCenters {
err = dataCenter.validate()
if err != nil {
return nil, fmt.Errorf("validating data center %d of %d: %w",
dataCenterIndex+1, len(data.DataCenters), err)
}
for _, apiServer := range dataCenter.Servers {
if !apiServer.Online {
continue
}
baseServer := models.Server{
Country: dataCenter.CountryName,
City: dataCenter.City,
Hostname: apiServer.Ptr,
IPs: []netip.Addr{apiServer.IP},
}
openVPNServer := baseServer
openVPNServer.VPN = vpn.OpenVPN
openVPNServer.TCP = true
openVPNServer.UDP = true
multiHopOpenVPNServer := openVPNServer
multiHopOpenVPNServer.MultiHop = true
multiHopOpenVPNServer.PortsTCP = []uint16{apiServer.MultiHopOpenvpnPort}
multiHopOpenVPNServer.PortsUDP = []uint16{apiServer.MultiHopOpenvpnPort}
servers = append(servers, openVPNServer, multiHopOpenVPNServer)
wireguardServer := baseServer
wireguardServer.VPN = vpn.Wireguard
wireguardServer.WgPubKey = apiServer.PublicKey
multiHopWireguardServer := wireguardServer
multiHopWireguardServer.MultiHop = true
multiHopWireguardServer.PortsUDP = []uint16{apiServer.MultiHopWireguardPort}
dedicatedWireguardServer := wireguardServer
dedicatedWireguardServer.WgPubKey = apiServer.PublicKeyIPv4
dedicatedWireguardServer.Dedicated = true
dedicatedMultiHopWireguardServer := multiHopWireguardServer
dedicatedMultiHopWireguardServer.WgPubKey = apiServer.PublicKeyIPv4
dedicatedMultiHopWireguardServer.Dedicated = true
servers = append(servers,
wireguardServer,
multiHopWireguardServer,
dedicatedWireguardServer,
dedicatedMultiHopWireguardServer,
)
}
}
if len(servers) < minServers {
return nil, fmt.Errorf("%w: %d and expected at least %d",
common.ErrNotEnoughServers, len(servers), minServers)
}
sort.Sort(models.SortableServers(servers))
return servers, nil
}
@@ -0,0 +1,228 @@
package updater
import (
"context"
"io"
"net/http"
"net/netip"
"strings"
"testing"
"github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/common"
"github.com/stretchr/testify/assert"
)
func Test_Updater_FetchServers(t *testing.T) {
t.Parallel()
testCases := map[string]struct {
// Inputs
minServers int
// From API
responseStatus int
responseBody string
// Output
servers []models.Server
errWrapped error
errMessage string
}{
"http_response_error": {
responseStatus: http.StatusNoContent,
errMessage: "fetching API: HTTP response status code is not OK: 204 No Content",
},
"success_field_false": {
responseStatus: http.StatusOK,
responseBody: `{"success": false}`,
errMessage: "response success field is false",
},
"validation_failed": {
responseStatus: http.StatusOK,
responseBody: `{
"success": true,
"datacenters": [
{
"city": "Vienna",
"servers": [
{}
]
}
]
}`,
errMessage: "validating data center 1 of 1: data center Vienna: country name is not set",
},
"not_enough_servers": {
minServers: 7,
responseStatus: http.StatusOK,
responseBody: `{
"success": true,
"datacenters": [
{
"city": "Vienna",
"country_name": "Austria",
"servers": [
{
"ip": "37.120.212.227",
"ptr": "vpn44.prd.vienna.ovpn.com",
"online": true,
"public_key": "r83LIc0Q2F8s3dY9x5y17Yz8wTADJc7giW1t5eSmoXc=",
"public_key_ipv4": "wFbSRyjSXBmkjJodlqz7DoYn3WNDPYFUIXyIUS2QU2A=",
"wireguard_ports": [9929],
"multihop_openvpn_port": 20044,
"multihop_wireguard_port": 30044
}
]
}
]
}`,
errWrapped: common.ErrNotEnoughServers,
// Wireguard + dedicated Wireguard + Wireguard multi-hop +
// dedicated Wireguard multi-hop + OpenVPN + OpenVPN multi-hop
errMessage: "not enough servers found: 6 and expected at least 7",
},
"success": {
minServers: 4,
responseBody: `{
"success": true,
"datacenters": [
{
"slug": "vienna",
"city": "Vienna",
"country": "AT",
"country_name": "Austria",
"pools": [
"pool-1.prd.at.vienna.ovpn.com"
],
"ping_address": "37.120.212.227",
"servers": [
{
"ip": "37.120.212.227",
"ptr": "vpn44.prd.vienna.ovpn.com",
"name": "VPN44 - Vienna",
"online": true,
"load": 8,
"public_key": "r83LIc0Q2F8s3dY9x5y17Yz8wTADJc7giW1t5eSmoXc=",
"public_key_ipv4": "wFbSRyjSXBmkjJodlqz7DoYn3WNDPYFUIXyIUS2QU2A=",
"wireguard_ports": [
9929
],
"multihop_openvpn_port": 20044,
"multihop_wireguard_port": 30044
},
{
"ip": "37.120.212.228",
"ptr": "vpn45.prd.vienna.ovpn.com",
"online": false,
"public_key": "r93LIc0Q2F8s3dY9x5y17Yz8wTADJc7giW1t5eSmoXc=",
"public_key_ipv4": "wGbSRyjSXBmkjJodlqz7DoYn3WNDPYFUIXyIUS2QU2A=",
"wireguard_ports": [9929],
"multihop_openvpn_port": 20045,
"multihop_wireguard_port": 30045
}
]
}
]
}`,
responseStatus: http.StatusOK,
servers: []models.Server{
{
Country: "Austria",
City: "Vienna",
Hostname: "vpn44.prd.vienna.ovpn.com",
IPs: []netip.Addr{netip.MustParseAddr("37.120.212.227")},
VPN: vpn.OpenVPN,
UDP: true,
TCP: true,
},
{
Country: "Austria",
City: "Vienna",
Hostname: "vpn44.prd.vienna.ovpn.com",
IPs: []netip.Addr{netip.MustParseAddr("37.120.212.227")},
VPN: vpn.OpenVPN,
UDP: true,
TCP: true,
MultiHop: true,
PortsTCP: []uint16{20044},
PortsUDP: []uint16{20044},
},
{
Country: "Austria",
City: "Vienna",
Hostname: "vpn44.prd.vienna.ovpn.com",
IPs: []netip.Addr{netip.MustParseAddr("37.120.212.227")},
VPN: vpn.Wireguard,
WgPubKey: "r83LIc0Q2F8s3dY9x5y17Yz8wTADJc7giW1t5eSmoXc=",
},
{
Country: "Austria",
City: "Vienna",
Hostname: "vpn44.prd.vienna.ovpn.com",
IPs: []netip.Addr{netip.MustParseAddr("37.120.212.227")},
VPN: vpn.Wireguard,
WgPubKey: "r83LIc0Q2F8s3dY9x5y17Yz8wTADJc7giW1t5eSmoXc=",
MultiHop: true,
PortsUDP: []uint16{30044},
},
{
Country: "Austria",
City: "Vienna",
Hostname: "vpn44.prd.vienna.ovpn.com",
IPs: []netip.Addr{netip.MustParseAddr("37.120.212.227")},
VPN: vpn.Wireguard,
WgPubKey: "wFbSRyjSXBmkjJodlqz7DoYn3WNDPYFUIXyIUS2QU2A=",
Dedicated: true,
},
{
Country: "Austria",
City: "Vienna",
Hostname: "vpn44.prd.vienna.ovpn.com",
IPs: []netip.Addr{netip.MustParseAddr("37.120.212.227")},
VPN: vpn.Wireguard,
WgPubKey: "wFbSRyjSXBmkjJodlqz7DoYn3WNDPYFUIXyIUS2QU2A=",
MultiHop: true,
Dedicated: true,
PortsUDP: []uint16{30044},
},
},
},
}
for name, testCase := range testCases {
t.Run(name, func(t *testing.T) {
t.Parallel()
ctx := context.Background()
client := &http.Client{
Transport: roundTripFunc(func(r *http.Request) (*http.Response, error) {
assert.Equal(t, http.MethodGet, r.Method)
assert.Equal(t, r.URL.String(), "https://www.ovpn.com/v2/api/client/entry")
return &http.Response{
StatusCode: testCase.responseStatus,
Status: http.StatusText(testCase.responseStatus),
Body: io.NopCloser(strings.NewReader(testCase.responseBody)),
}, nil
}),
}
updater := &Updater{
client: client,
}
servers, err := updater.FetchServers(ctx, testCase.minServers)
assert.Equal(t, testCase.servers, servers)
if testCase.errMessage == "" {
assert.NoError(t, err)
} else {
assert.Contains(t, err.Error(), testCase.errMessage)
}
if testCase.errWrapped != nil {
assert.ErrorIs(t, err, testCase.errWrapped)
}
})
}
}
+15
View File
@@ -0,0 +1,15 @@
package updater
import (
"net/http"
)
type Updater struct {
client *http.Client
}
func New(client *http.Client) *Updater {
return &Updater{
client: client,
}
}
@@ -133,20 +133,6 @@ func (p *Provider) KeepPortForward(ctx context.Context,
case <-timer.C: case <-timer.C:
} }
_, externalIPv4Address, err := client.ExternalAddress(ctx, objects.Gateway)
if err != nil {
switch {
case strings.HasSuffix(err.Error(), "connection refused"):
err = fmt.Errorf("%w - make sure you have +pmp at the end of your OpenVPN username "+
"or that your Wireguard key is set to work with PMP", err)
case strings.Contains(err.Error(), "i/o timeout"):
err = fmt.Errorf("%w - make sure FIREWALL_OUTBOUND_SUBNETS does not conflict with "+
"the VPN gateway ip address %s", err, objects.Gateway)
}
logger.Error(fmt.Sprintf("getting external IPv4 address: %v", err))
}
logger.Debug("gateway external IPv4 address is " + externalIPv4Address.String())
objects.Logger.Debug("refreshing forwarded ports since 45 seconds have elapsed") objects.Logger.Debug("refreshing forwarded ports since 45 seconds have elapsed")
const lifetime = 60 * time.Second const lifetime = 60 * time.Second
for internalPort, externalPort := range p.internalToExternalPorts { for internalPort, externalPort := range p.internalToExternalPorts {
+2
View File
@@ -20,6 +20,7 @@ import (
"github.com/qdm12/gluetun/internal/provider/ivpn" "github.com/qdm12/gluetun/internal/provider/ivpn"
"github.com/qdm12/gluetun/internal/provider/mullvad" "github.com/qdm12/gluetun/internal/provider/mullvad"
"github.com/qdm12/gluetun/internal/provider/nordvpn" "github.com/qdm12/gluetun/internal/provider/nordvpn"
"github.com/qdm12/gluetun/internal/provider/ovpn"
"github.com/qdm12/gluetun/internal/provider/perfectprivacy" "github.com/qdm12/gluetun/internal/provider/perfectprivacy"
"github.com/qdm12/gluetun/internal/provider/privado" "github.com/qdm12/gluetun/internal/provider/privado"
"github.com/qdm12/gluetun/internal/provider/privateinternetaccess" "github.com/qdm12/gluetun/internal/provider/privateinternetaccess"
@@ -67,6 +68,7 @@ func NewProviders(storage Storage, timeNow func() time.Time,
providers.Ivpn: ivpn.New(storage, client, updaterWarner, parallelResolver), providers.Ivpn: ivpn.New(storage, client, updaterWarner, parallelResolver),
providers.Mullvad: mullvad.New(storage, client), providers.Mullvad: mullvad.New(storage, client),
providers.Nordvpn: nordvpn.New(storage, client, updaterWarner), providers.Nordvpn: nordvpn.New(storage, client, updaterWarner),
providers.Ovpn: ovpn.New(storage, client),
providers.Perfectprivacy: perfectprivacy.New(storage, unzipper, updaterWarner), providers.Perfectprivacy: perfectprivacy.New(storage, unzipper, updaterWarner),
providers.Privado: privado.New(storage, client, updaterWarner), providers.Privado: privado.New(storage, client, updaterWarner),
providers.PrivateInternetAccess: privateinternetaccess.New(storage, timeNow, client), providers.PrivateInternetAccess: privateinternetaccess.New(storage, timeNow, client),
+3 -2
View File
@@ -52,8 +52,6 @@ func GetConnection(provider string,
}) })
protocol := getProtocol(selection) protocol := getProtocol(selection)
port := getPort(selection, defaults.OpenVPNTCPPort,
defaults.OpenVPNUDPPort, defaults.WireguardPort)
connections := make([]models.Connection, 0, len(servers)) connections := make([]models.Connection, 0, len(servers))
for _, server := range servers { for _, server := range servers {
@@ -69,6 +67,9 @@ func GetConnection(provider string,
hostname = server.OvpnX509 hostname = server.OvpnX509
} }
port := getPort(selection, server, defaults.OpenVPNTCPPort,
defaults.OpenVPNUDPPort, defaults.WireguardPort)
connection := models.Connection{ connection := models.Connection{
Type: selection.VPN, Type: selection.VPN,
IP: ip, IP: ip,
+1 -1
View File
@@ -6,6 +6,7 @@ import (
"net/netip" "net/netip"
"testing" "testing"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/configuration/settings" "github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/constants/providers" "github.com/qdm12/gluetun/internal/constants/providers"
@@ -13,7 +14,6 @@ import (
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/common" "github.com/qdm12/gluetun/internal/provider/common"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
) )
func Test_GetConnection(t *testing.T) { func Test_GetConnection(t *testing.T) {
+16 -1
View File
@@ -6,29 +6,44 @@ import (
"github.com/qdm12/gluetun/internal/configuration/settings" "github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models"
) )
func getPort(selection settings.ServerSelection, func getPort(selection settings.ServerSelection, server models.Server,
defaultOpenVPNTCP, defaultOpenVPNUDP, defaultWireguard uint16, defaultOpenVPNTCP, defaultOpenVPNUDP, defaultWireguard uint16,
) (port uint16) { ) (port uint16) {
switch selection.VPN { switch selection.VPN {
case vpn.Wireguard: case vpn.Wireguard:
customPort := *selection.Wireguard.EndpointPort customPort := *selection.Wireguard.EndpointPort
if customPort > 0 { if customPort > 0 {
// Note: servers filtering ensures the custom port is within the
// server ports defined if any is set.
return customPort return customPort
} }
if len(server.PortsUDP) > 0 {
defaultWireguard = server.PortsUDP[0]
}
checkDefined("Wireguard", defaultWireguard) checkDefined("Wireguard", defaultWireguard)
return defaultWireguard return defaultWireguard
default: // OpenVPN default: // OpenVPN
customPort := *selection.OpenVPN.CustomPort customPort := *selection.OpenVPN.CustomPort
if customPort > 0 { if customPort > 0 {
// Note: servers filtering ensures the custom port is within the
// server ports defined if any is set.
return customPort return customPort
} }
if selection.OpenVPN.Protocol == constants.TCP { if selection.OpenVPN.Protocol == constants.TCP {
if len(server.PortsTCP) > 0 {
defaultOpenVPNTCP = server.PortsTCP[0]
}
checkDefined("OpenVPN TCP", defaultOpenVPNTCP) checkDefined("OpenVPN TCP", defaultOpenVPNTCP)
return defaultOpenVPNTCP return defaultOpenVPNTCP
} }
if len(server.PortsUDP) > 0 {
defaultOpenVPNUDP = server.PortsUDP[0]
}
checkDefined("OpenVPN UDP", defaultOpenVPNUDP) checkDefined("OpenVPN UDP", defaultOpenVPNUDP)
return defaultOpenVPNUDP return defaultOpenVPNUDP
} }
+45
View File
@@ -6,6 +6,7 @@ import (
"github.com/qdm12/gluetun/internal/configuration/settings" "github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/constants/vpn" "github.com/qdm12/gluetun/internal/constants/vpn"
"github.com/qdm12/gluetun/internal/models"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@@ -22,6 +23,7 @@ func Test_GetPort(t *testing.T) {
testCases := map[string]struct { testCases := map[string]struct {
selection settings.ServerSelection selection settings.ServerSelection
server models.Server
defaultOpenVPNTCP uint16 defaultOpenVPNTCP uint16
defaultOpenVPNUDP uint16 defaultOpenVPNUDP uint16
defaultWireguard uint16 defaultWireguard uint16
@@ -48,6 +50,20 @@ func Test_GetPort(t *testing.T) {
defaultWireguard: defaultWireguard, defaultWireguard: defaultWireguard,
port: defaultOpenVPNUDP, port: defaultOpenVPNUDP,
}, },
"OpenVPN_server_port_udp": {
selection: settings.ServerSelection{
VPN: vpn.OpenVPN,
OpenVPN: settings.OpenVPNSelection{
CustomPort: uint16Ptr(0),
Protocol: constants.UDP,
},
},
server: models.Server{
PortsUDP: []uint16{1234},
},
defaultOpenVPNUDP: defaultOpenVPNUDP,
port: 1234,
},
"OpenVPN UDP no default port defined": { "OpenVPN UDP no default port defined": {
selection: settings.ServerSelection{ selection: settings.ServerSelection{
VPN: vpn.OpenVPN, VPN: vpn.OpenVPN,
@@ -88,6 +104,20 @@ func Test_GetPort(t *testing.T) {
}, },
port: 1234, port: 1234,
}, },
"OpenVPN_server_port_tcp": {
selection: settings.ServerSelection{
VPN: vpn.OpenVPN,
OpenVPN: settings.OpenVPNSelection{
CustomPort: uint16Ptr(0),
Protocol: constants.TCP,
},
},
server: models.Server{
PortsTCP: []uint16{1234},
},
defaultOpenVPNTCP: defaultOpenVPNTCP,
port: 1234,
},
"Wireguard": { "Wireguard": {
selection: settings.ServerSelection{ selection: settings.ServerSelection{
VPN: vpn.Wireguard, VPN: vpn.Wireguard,
@@ -105,6 +135,19 @@ func Test_GetPort(t *testing.T) {
defaultWireguard: defaultWireguard, defaultWireguard: defaultWireguard,
port: 1234, port: 1234,
}, },
"Wireguard_server_port": {
selection: settings.ServerSelection{
VPN: vpn.Wireguard,
Wireguard: settings.WireguardSelection{
EndpointPort: uint16Ptr(0),
},
},
server: models.Server{
PortsUDP: []uint16{1234},
},
defaultWireguard: defaultWireguard,
port: 1234,
},
"Wireguard no default port defined": { "Wireguard no default port defined": {
selection: settings.ServerSelection{ selection: settings.ServerSelection{
VPN: vpn.Wireguard, VPN: vpn.Wireguard,
@@ -120,6 +163,7 @@ func Test_GetPort(t *testing.T) {
if testCase.panics != "" { if testCase.panics != "" {
assert.PanicsWithValue(t, testCase.panics, func() { assert.PanicsWithValue(t, testCase.panics, func() {
_ = getPort(testCase.selection, _ = getPort(testCase.selection,
testCase.server,
testCase.defaultOpenVPNTCP, testCase.defaultOpenVPNTCP,
testCase.defaultOpenVPNUDP, testCase.defaultOpenVPNUDP,
testCase.defaultWireguard) testCase.defaultWireguard)
@@ -128,6 +172,7 @@ func Test_GetPort(t *testing.T) {
} }
port := getPort(testCase.selection, port := getPort(testCase.selection,
testCase.server,
testCase.defaultOpenVPNTCP, testCase.defaultOpenVPNTCP,
testCase.defaultOpenVPNUDP, testCase.defaultOpenVPNUDP,
testCase.defaultWireguard) testCase.defaultWireguard)
@@ -7,10 +7,10 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/common" "github.com/qdm12/gluetun/internal/provider/common"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
"golang.org/x/net/html" "golang.org/x/net/html"
) )
@@ -6,6 +6,7 @@ import (
"net/netip" "net/netip"
"testing" "testing"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/configuration/settings" "github.com/qdm12/gluetun/internal/configuration/settings"
"github.com/qdm12/gluetun/internal/constants" "github.com/qdm12/gluetun/internal/constants"
"github.com/qdm12/gluetun/internal/constants/providers" "github.com/qdm12/gluetun/internal/constants/providers"
@@ -13,7 +14,6 @@ import (
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/provider/common" "github.com/qdm12/gluetun/internal/provider/common"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
) )
func Test_Provider_GetConnection(t *testing.T) { func Test_Provider_GetConnection(t *testing.T) {
-82
View File
@@ -1,82 +0,0 @@
package restrictednet
import (
"context"
"errors"
"fmt"
"net"
"net/http"
"net/netip"
"strconv"
"github.com/qdm12/dns/v2/pkg/provider"
)
// Client is a client for making restricted network requests,
// such as opening temporary firewall rules for HTTPS connections.
// It is not meant to be high performance, although it can be used for
// multiple requests and concurrently.
type Client struct {
outboundInterface string
ipv6Supported bool
firewall Firewall
dohServers []provider.DoHServer
}
func New(settings Settings) *Client {
if err := settings.validate(); err != nil {
panic(fmt.Sprintf("invalid settings: %v", err)) // programming error
}
dohServers := make([]provider.DoHServer, len(settings.UpstreamResolvers))
for i, upstreamResolver := range settings.UpstreamResolvers {
dohServers[i] = upstreamResolver.DoH
}
return &Client{
outboundInterface: settings.DefaultInterface,
ipv6Supported: *settings.IPv6Supported,
firewall: settings.Firewall,
dohServers: dohServers,
}
}
// OpenHTTPSByHostname opens an https connection through the firewall,
// to the hostname which in the format `host:port`. The returned cleanup
// function must be called to remove the temporary firewall rule and close connections.
// It first resolves the domain in hostname using DNS over HTTPS and then opens
// the restricted HTTPS connection to the resolved IP.
func (c *Client) OpenHTTPSByHostname(ctx context.Context, hostname string) (
httpClient *http.Client, cleanup func() error, err error,
) {
host, portStr, err := net.SplitHostPort(hostname)
if err != nil {
return nil, nil, fmt.Errorf("splitting host and port: %w", err)
}
resolvedIPs, err := c.ResolveName(ctx, host)
if err != nil {
return nil, nil, fmt.Errorf("resolving name: %w", err)
} else if len(resolvedIPs) == 0 {
return nil, nil, fmt.Errorf("no IP address found for name %q", host)
}
portUint, err := strconv.ParseUint(portStr, 10, 16)
if err != nil {
return nil, nil, fmt.Errorf("parsing port: %w", err)
} else if portUint == 0 {
return nil, nil, errors.New("destination port cannot be 0")
}
port := uint16(portUint)
errs := make([]error, 0, len(resolvedIPs))
for _, ip := range resolvedIPs {
addrPort := netip.AddrPortFrom(ip, port)
httpClient, cleanup, err := c.OpenHTTPS(ctx, host, addrPort)
if err != nil {
errs = append(errs, fmt.Errorf("for %s: %w", ip, err))
continue
}
return httpClient, cleanup, nil
}
return nil, nil, fmt.Errorf("opening HTTPS to %s: %w", hostname, errors.Join(errs...))
}
-7
View File
@@ -1,7 +0,0 @@
//go:build integration
package restrictednet
func ptrTo[T any](value T) *T {
return &value
}
-202
View File
@@ -1,202 +0,0 @@
package restrictednet
import (
"context"
"crypto/tls"
"errors"
"fmt"
"net"
"net/http"
"net/netip"
"os"
"time"
"github.com/jsimonetti/rtnetlink"
"github.com/qdm12/gluetun/internal/pmtud/constants"
)
// OpenHTTPS opens temporary restrictive firewall output for one HTTPS destination.
// The returned [*http.Client] must be used sequentially only, and each request must
// have its response body fully read/discarded and then closed.
// The returned cleanup function must be called to remove the temporary firewall rule and close connections.
func (c *Client) OpenHTTPS(ctx context.Context, destinationTLSName string, destinationAddrPort netip.AddrPort,
) (httpClient *http.Client, cleanup func() error, err error) {
fd, sourceAddrPort, err := bindSourceConnection(destinationAddrPort.Addr())
if err != nil {
return nil, nil, fmt.Errorf("binding source port: %w", err)
}
const remove = false
err = c.firewall.AcceptOutputFromIPPortToIPPort(ctx, "tcp", c.outboundInterface,
sourceAddrPort, destinationAddrPort, remove)
if err != nil {
closeFD(fd)
return nil, nil, fmt.Errorf("allowing output traffic through firewall: %w", err)
}
connection, err := connectSourceConnection(ctx, fd, destinationAddrPort)
if err != nil {
const remove = true
_ = c.firewall.AcceptOutputFromIPPortToIPPort(context.Background(), "tcp", c.outboundInterface,
sourceAddrPort, destinationAddrPort, remove)
return nil, nil, fmt.Errorf("connecting source socket: %w", err)
}
dial := makeDial(connection, destinationTLSName)
httpClient = newHTTPSClient(destinationTLSName, dial)
cleanup = func() error {
var errs []error
httpClient.CloseIdleConnections()
err := connection.Close()
if err != nil && !errors.Is(err, net.ErrClosed) {
errs = append(errs, fmt.Errorf("closing connection: %w", err))
}
const remove = true
err = c.firewall.AcceptOutputFromIPPortToIPPort(context.Background(), "tcp", c.outboundInterface,
sourceAddrPort, destinationAddrPort, remove)
if err != nil {
errs = append(errs, fmt.Errorf("removing output traffic rule: %w", err))
}
if len(errs) > 0 {
return errors.Join(errs...)
}
return nil
}
return httpClient, cleanup, nil
}
type dialFunc func(ctx context.Context, network, address string) (net.Conn, error)
func newHTTPSClient(destinationTLSName string, dial dialFunc) *http.Client {
const timeout = 5 * time.Second
transport := &http.Transport{
MaxIdleConns: 1,
MaxIdleConnsPerHost: 1,
MaxConnsPerHost: 1,
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
ServerName: destinationTLSName,
},
DialContext: dial,
}
return &http.Client{
Timeout: timeout,
Transport: transport,
}
}
func makeDial(connection net.Conn, tlsName string) dialFunc {
_, destinationPort, err := net.SplitHostPort(connection.RemoteAddr().String())
if err != nil {
panic(err) // connection remote address should always be in the form "host:port"
}
expectedAddress := net.JoinHostPort(tlsName, destinationPort)
used := false
return func(_ context.Context, network, address string) (net.Conn, error) {
if used {
return nil, errors.New("dial function called more than once")
}
used = true
switch network {
case "tcp", "tcp4", "tcp6":
default:
return nil, fmt.Errorf("unexpected dial network %q", network)
}
if address != expectedAddress {
return nil, fmt.Errorf("unexpected dial address %q (expected %q)", address, expectedAddress)
}
return connection, nil
}
}
func bindSourceConnection(destinationIP netip.Addr) (fd int, sourceAddr netip.AddrPort, err error) {
sourceIP, err := sourceIPForDestination(destinationIP)
if err != nil {
return 0, netip.AddrPort{}, fmt.Errorf("finding source IP: %w", err)
}
family := constants.AF_INET
if sourceIP.Is6() {
family = constants.AF_INET6
}
fd, err = newTCPSockStream(family)
if err != nil {
return 0, netip.AddrPort{}, fmt.Errorf("creating socket: %w", err)
}
bindAddrPort := netip.AddrPortFrom(sourceIP, 0)
err = bindFD(fd, bindAddrPort)
if err != nil {
closeFD(fd)
return 0, netip.AddrPort{}, fmt.Errorf("binding socket: %w", err)
}
sourceAddr, err = fdToSourceAddr(fd)
if err != nil {
closeFD(fd)
return 0, netip.AddrPort{}, fmt.Errorf("getting source address: %w", err)
}
return fd, sourceAddr, nil
}
func connectSourceConnection(ctx context.Context, fd int, destinationAddrPort netip.AddrPort) (
connection net.Conn, err error,
) {
err = connectFD(ctx, fd, destinationAddrPort)
if err != nil {
closeFD(fd)
return nil, fmt.Errorf("connecting socket: %w", err)
}
file := os.NewFile(uintptr(fd), "")
if file == nil {
closeFD(fd)
return nil, fmt.Errorf("creating socket file for destination %s", destinationAddrPort)
}
defer file.Close()
connection, err = net.FileConn(file)
if err != nil {
return nil, fmt.Errorf("wrapping socket connection: %w", err)
}
return connection, nil
}
func sourceIPForDestination(destinationIP netip.Addr) (srcIP netip.Addr, err error) {
conn, err := rtnetlink.Dial(nil)
if err != nil {
return netip.Addr{}, err
}
defer conn.Close()
family := uint8(constants.AF_INET)
if destinationIP.Is6() {
family = constants.AF_INET6
}
requestMessage := &rtnetlink.RouteMessage{
Family: family,
Attributes: rtnetlink.RouteAttributes{
Dst: destinationIP.AsSlice(),
},
}
messages, err := conn.Route.Get(requestMessage)
if err != nil {
return netip.Addr{}, fmt.Errorf("getting routes to %s: %w", destinationIP, err)
}
for _, message := range messages {
if message.Attributes.Src == nil {
continue
}
if message.Attributes.Src.To4() == nil {
return netip.AddrFrom16([16]byte(message.Attributes.Src)), nil
}
return netip.AddrFrom4([4]byte(message.Attributes.Src)), nil
}
return netip.Addr{}, fmt.Errorf("no route to %s", destinationIP)
}
@@ -1,117 +0,0 @@
//go:build integration
package restrictednet
import (
"context"
"fmt"
"io"
"net/http"
"net/netip"
"testing"
"github.com/qdm12/dns/v2/pkg/provider"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
)
type listenAddrPortMatcher struct {
expected netip.AddrPort
}
func (m listenAddrPortMatcher) Matches(x any) bool {
ip, ok := x.(netip.AddrPort)
if !ok {
return false
}
if m.expected.IsValid() {
return ip == m.expected
}
return ip.IsValid() && ip.Addr().IsValid() && ip.Port() > 0
}
func (m listenAddrPortMatcher) String() string {
if m.expected.IsValid() {
return "is the same as " + m.expected.String()
}
return "is a valid netip.AddrPort with a valid IP and non-zero port"
}
type destinationAddrPortMatcher struct {
expected netip.AddrPort
}
func (m destinationAddrPortMatcher) Matches(x any) bool {
ip, ok := x.(netip.AddrPort)
if !ok {
return false
}
if m.expected.IsValid() {
return ip == m.expected
}
return ip.IsValid() && ip.Port() == m.expected.Port()
}
func (m destinationAddrPortMatcher) String() string {
if m.expected.IsValid() {
return "is the same as " + m.expected.String()
}
return "matches the port " + fmt.Sprint(m.expected.Port())
}
func Test_Client_OpenHTTPS(t *testing.T) {
t.Parallel()
ctx := t.Context()
ctrl := gomock.NewController(t)
const destinationTLSName = "one.one.one.one"
destinationAddrPort := netip.AddrPortFrom(netip.AddrFrom4([4]byte{1, 1, 1, 1}), 443)
firewall := NewMockFirewall(ctrl)
sourceMatcher := listenAddrPortMatcher{}
firewall.EXPECT().AcceptOutputFromIPPortToIPPort(
ctx, "tcp", "eth0", sourceMatcher, destinationAddrPort, false,
).DoAndReturn(func(_ context.Context,
_, _ string, source, _ netip.AddrPort, _ bool,
) error {
sourceMatcher.expected = source
return nil
})
firewall.EXPECT().AcceptOutputFromIPPortToIPPort(
context.Background(), "tcp", "eth0", sourceMatcher, destinationAddrPort, true,
).Return(nil)
const ipv6Supported = false
upstreamResolvers := []provider.Provider{provider.Google()}
settings := Settings{
Firewall: firewall,
DefaultInterface: "eth0",
IPv6Supported: ptrTo(ipv6Supported),
UpstreamResolvers: upstreamResolvers,
}
client := New(settings)
httpClient, cleanup, err := client.OpenHTTPS(ctx, destinationTLSName, destinationAddrPort)
require.NoError(t, err)
require.NotNil(t, httpClient)
require.NotNil(t, cleanup)
const requests = 2
for range requests {
request, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://"+destinationTLSName, nil)
require.NoError(t, err)
response, err := httpClient.Do(request)
require.NoError(t, err)
_, err = io.Copy(io.Discard, response.Body)
require.NoError(t, err)
err = response.Body.Close()
require.NoError(t, err)
assert.Equal(t, http.StatusOK, response.StatusCode)
}
err = cleanup()
require.NoError(t, err)
}
-12
View File
@@ -1,12 +0,0 @@
package restrictednet
import (
"context"
"net/netip"
)
type Firewall interface {
AcceptOutputFromIPPortToIPPort(ctx context.Context,
protocol, intf string, source, destination netip.AddrPort, remove bool,
) error
}
-121
View File
@@ -1,121 +0,0 @@
//go:build linux
package restrictednet
import (
"context"
"errors"
"fmt"
"net/netip"
"time"
"golang.org/x/sys/unix"
)
func closeFD(fd int) {
unix.Close(fd)
}
func newTCPSockStream(family int) (fd int, err error) {
fd, err = unix.Socket(family, unix.SOCK_STREAM, unix.IPPROTO_TCP)
if err != nil {
return 0, err
}
err = unix.SetNonblock(fd, true)
if err != nil {
_ = unix.Close(fd)
return 0, err
}
return fd, nil
}
func bindFD(fd int, address netip.AddrPort) error {
bindAddr := makeSockAddr(address)
return unix.Bind(fd, bindAddr)
}
func connectFD(ctx context.Context, fd int, destination netip.AddrPort) error {
err := unix.Connect(fd, makeSockAddr(destination))
switch {
case err == nil:
return nil
case !errors.Is(err, unix.EINPROGRESS):
return err
}
for {
select {
case <-ctx.Done():
return ctx.Err()
default:
bitsIndex := fd / 64 //nolint:mnd
if bitsIndex >= len(unix.FdSet{}.Bits) {
return fmt.Errorf("fd %d exceeds unix.Select FdSet capacity", fd)
}
wset := &unix.FdSet{}
wset.Bits[bitsIndex] |= 1 << (uint64(fd) % 64) //nolint:gosec,mnd
eset := &unix.FdSet{}
eset.Bits[bitsIndex] |= 1 << (uint64(fd) % 64) //nolint:gosec,mnd
const selectTimeout = 50 * time.Millisecond
timeval := unix.NsecToTimeval(int64(selectTimeout))
// Wait for the FD to become writable or hit an error state
n, err := unix.Select(fd+1, nil, wset, eset, &timeval)
if err != nil {
if errors.Is(err, unix.EINTR) {
continue // Syscall interrupted, try again
}
return fmt.Errorf("select error: %w", err)
} else if n == 0 {
continue // no status change yet
}
// Check if the socket encountered an error
n, err = unix.GetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_ERROR)
if err != nil {
return fmt.Errorf("getsockopt error: %w", err)
} else if n != 0 {
return fmt.Errorf("connect failed asynchronously: %w", unix.Errno(n))
}
return nil
}
}
}
func fdToSourceAddr(fd int) (sourceAddrPort netip.AddrPort, err error) {
sockAddr, err := unix.Getsockname(fd)
if err != nil {
return netip.AddrPort{}, fmt.Errorf("getting sockname: %w", err)
}
sourceAddrPort, err = sockAddrToAddrPort(sockAddr)
if err != nil {
return netip.AddrPort{}, err
}
return sourceAddrPort, nil
}
func makeSockAddr(addressPort netip.AddrPort) unix.Sockaddr {
if addressPort.Addr().Is4() {
return &unix.SockaddrInet4{
Port: int(addressPort.Port()),
Addr: addressPort.Addr().As4(),
}
}
return &unix.SockaddrInet6{
Port: int(addressPort.Port()),
Addr: addressPort.Addr().As16(),
}
}
func sockAddrToAddrPort(sockAddr unix.Sockaddr) (addrPort netip.AddrPort, err error) {
switch typedSockAddr := sockAddr.(type) {
case *unix.SockaddrInet4:
return netip.AddrPortFrom(netip.AddrFrom4(typedSockAddr.Addr), uint16(typedSockAddr.Port)), nil //nolint:gosec
case *unix.SockaddrInet6:
return netip.AddrPortFrom(netip.AddrFrom16(typedSockAddr.Addr), uint16(typedSockAddr.Port)), nil //nolint:gosec
default:
return netip.AddrPort{}, fmt.Errorf("unexpected socket address type %T", typedSockAddr)
}
}
@@ -1,3 +0,0 @@
package restrictednet
//go:generate mockgen -destination=mocks_test.go -package=$GOPACKAGE . Firewall
-56
View File
@@ -1,56 +0,0 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/qdm12/gluetun/internal/restrictednet (interfaces: Firewall)
//
// Generated by this command:
//
// mockgen -destination=mocks_test.go -package=restrictednet . Firewall
//
// Package restrictednet is a generated GoMock package.
package restrictednet
import (
context "context"
netip "net/netip"
reflect "reflect"
gomock "go.uber.org/mock/gomock"
)
// MockFirewall is a mock of Firewall interface.
type MockFirewall struct {
ctrl *gomock.Controller
recorder *MockFirewallMockRecorder
isgomock struct{}
}
// MockFirewallMockRecorder is the mock recorder for MockFirewall.
type MockFirewallMockRecorder struct {
mock *MockFirewall
}
// NewMockFirewall creates a new mock instance.
func NewMockFirewall(ctrl *gomock.Controller) *MockFirewall {
mock := &MockFirewall{ctrl: ctrl}
mock.recorder = &MockFirewallMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockFirewall) EXPECT() *MockFirewallMockRecorder {
return m.recorder
}
// AcceptOutputFromIPPortToIPPort mocks base method.
func (m *MockFirewall) AcceptOutputFromIPPortToIPPort(ctx context.Context, protocol, intf string, source, destination netip.AddrPort, remove bool) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AcceptOutputFromIPPortToIPPort", ctx, protocol, intf, source, destination, remove)
ret0, _ := ret[0].(error)
return ret0
}
// AcceptOutputFromIPPortToIPPort indicates an expected call of AcceptOutputFromIPPortToIPPort.
func (mr *MockFirewallMockRecorder) AcceptOutputFromIPPortToIPPort(ctx, protocol, intf, source, destination, remove any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AcceptOutputFromIPPortToIPPort", reflect.TypeOf((*MockFirewall)(nil).AcceptOutputFromIPPortToIPPort), ctx, protocol, intf, source, destination, remove)
}
-28
View File
@@ -1,28 +0,0 @@
//go:build !linux
package restrictednet
import (
"context"
"net/netip"
)
func closeFD(fd int) {
panic("not implemented")
}
func newTCPSockStream(family int) (fd int, err error) {
panic("not implemented")
}
func bindFD(fd int, address netip.AddrPort) error {
panic("not implemented")
}
func connectFD(ctx context.Context, fd int, destination netip.AddrPort) error {
panic("not implemented")
}
func fdToSourceAddr(fd int) (sourceAddrPort netip.AddrPort, err error) {
panic("not implemented")
}
-201
View File
@@ -1,201 +0,0 @@
package restrictednet
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"net/http"
"net/netip"
"net/url"
"strconv"
"github.com/miekg/dns"
)
// ResolveName resolves the given host name to IP addresses using DoH servers,
// while opening temporary restrictive firewall rules for HTTPS traffic to DoH servers.
// The host must be a single well-formed domain name, without port or path.
func (c *Client) ResolveName(ctx context.Context, host string) (
resolvedAddresses []netip.Addr, err error,
) {
const maxTypes = 2
questionTypes := make([]uint16, 0, maxTypes)
if c.ipv6Supported {
questionTypes = append(questionTypes, dns.TypeAAAA)
}
questionTypes = append(questionTypes, dns.TypeA)
var addresses []netip.Addr
errs := make([]error, 0, len(questionTypes))
for _, questionType := range questionTypes {
answerAddresses, err := c.resolveOneQuestionType(ctx, host, questionType)
if err != nil {
errs = append(errs, err)
continue
}
addresses = append(addresses, answerAddresses...)
}
switch {
case len(addresses) > 0:
return addresses, nil
case len(errs) == 0:
return nil, nil // no address found
default: // errors
return nil, fmt.Errorf("resolving host %q: %w", host, errors.Join(errs...))
}
}
func (c *Client) resolveOneQuestionType(ctx context.Context,
host string, questionType uint16,
) (addresses []netip.Addr, err error) {
queryMessage := &dns.Msg{}
queryMessage.SetQuestion(dns.Fqdn(host), questionType)
queryWire, err := queryMessage.Pack()
if err != nil {
return nil, fmt.Errorf("packing DNS query: %w", err)
}
// Try every DoH server and every of each of their IP until we get a non-empty
// successful response.
errs := make([]error, 0)
for _, dohServer := range c.dohServers {
dohURL, err := url.Parse(dohServer.URL)
if err != nil {
errs = append(errs,
fmt.Errorf("parsing DoH server URL %s: %w", dohServer.URL, err))
continue
}
dohServerIPs := make([]netip.Addr, 0, len(dohServer.IPv4)+len(dohServer.IPv6))
if c.ipv6Supported {
// Prefer IPv6 addresses if IPv6 is supported
dohServerIPs = append(dohServerIPs, dohServer.IPv6...)
}
dohServerIPs = append(dohServerIPs, dohServer.IPv4...)
for _, dohServerIP := range dohServerIPs {
const defaultDoHPort uint16 = 443
port := defaultDoHPort
if portStr := dohURL.Port(); portStr != "" {
port, err = parseDestinationPort(portStr)
if err != nil {
errs = append(errs, fmt.Errorf("parsing DoH server port: %w", err))
continue
}
}
dohServerAddrPort := netip.AddrPortFrom(dohServerIP, port)
responseMessage, err := c.doHQuery(ctx, queryWire, dohURL, dohServerAddrPort)
switch {
case err != nil:
errs = append(errs, fmt.Errorf("querying DoH server %q (%s): %w",
dohServer.URL, dohServerAddrPort, err))
continue
case responseMessage.Rcode != dns.RcodeSuccess:
errs = append(errs, fmt.Errorf("querying DoH server %q (%s): DNS rcode %s",
dohServer.URL, dohServerAddrPort, dns.RcodeToString[responseMessage.Rcode]))
continue
}
addresses := answersToNetipAddrs(responseMessage)
if len(addresses) == 0 {
continue
}
return addresses, nil
}
}
if len(errs) == 0 {
return nil, nil
}
return nil, fmt.Errorf("resolving %s %s: %w",
dns.TypeToString[questionType], host, errors.Join(errs...))
}
func (c *Client) doHQuery(ctx context.Context, queryWire []byte,
dohURL *url.URL, dohServerAddrPort netip.AddrPort,
) (responseMessage *dns.Msg, err error) {
httpClient, cleanup, err := c.OpenHTTPS(ctx, dohURL.Hostname(), dohServerAddrPort)
if err != nil {
return nil, fmt.Errorf("opening https connection: %w", err)
}
defer func() {
closeErr := cleanup()
if err == nil && closeErr != nil {
err = fmt.Errorf("cleaning up https connection: %w", closeErr)
}
}()
requestBody := bytes.NewReader(queryWire)
request, err := http.NewRequestWithContext(ctx, http.MethodPost, dohURL.String(), requestBody)
if err != nil {
return nil, fmt.Errorf("creating request: %w", err)
}
request.Header.Set("Content-Type", "application/dns-message")
request.Header.Set("Accept", "application/dns-message")
response, err := httpClient.Do(request)
if err != nil {
return nil, err
}
responseData, err := io.ReadAll(response.Body)
if err != nil {
_ = response.Body.Close()
return nil, fmt.Errorf("reading response body: %w", err)
}
err = response.Body.Close()
if err != nil {
return nil, fmt.Errorf("closing response body: %w", err)
}
if response.StatusCode != http.StatusOK {
return nil, fmt.Errorf("response status code is %s (data length %d)",
response.Status, len(responseData))
}
responseMessage = new(dns.Msg)
err = responseMessage.Unpack(responseData)
if err != nil {
return nil, fmt.Errorf("parsing DoH response: %w", err)
}
return responseMessage, nil
}
func answersToNetipAddrs(message *dns.Msg) (addresses []netip.Addr) {
if message == nil {
return nil
}
addresses = make([]netip.Addr, 0, len(message.Answer))
for _, answer := range message.Answer {
switch record := answer.(type) {
case *dns.A:
address, ok := netip.AddrFromSlice(record.A)
if ok {
addresses = append(addresses, address.Unmap())
}
case *dns.AAAA:
address, ok := netip.AddrFromSlice(record.AAAA)
if ok {
addresses = append(addresses, address)
}
}
}
return addresses
}
func parseDestinationPort(portStr string) (port uint16, err error) {
portUint, err := strconv.ParseUint(portStr, 10, 16)
if err != nil {
return 0, err
}
if portUint == 0 {
return 0, errors.New("port cannot be 0")
}
return uint16(portUint), nil
}
@@ -1,110 +0,0 @@
//go:build integration
package restrictednet
import (
"context"
"net"
"net/netip"
"testing"
"github.com/miekg/dns"
"github.com/qdm12/dns/v2/pkg/provider"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
)
func Test_Client_ResolveName(t *testing.T) {
t.Parallel()
ctx := t.Context()
ctrl := gomock.NewController(t)
firewall := NewMockFirewall(ctrl)
sourceMatcher := listenAddrPortMatcher{}
destinationMatcher := destinationAddrPortMatcher{
expected: netip.AddrPortFrom(netip.Addr{}, 443),
}
// Add rule
firstCall := firewall.EXPECT().AcceptOutputFromIPPortToIPPort(
ctx, "tcp", "eth0", sourceMatcher, destinationMatcher, false,
).DoAndReturn(func(
_ context.Context, _, _ string, source, destination netip.AddrPort, _ bool,
) error {
sourceMatcher.expected = source
destinationMatcher.expected = destination
return nil
})
// Removal rule
firewall.EXPECT().AcceptOutputFromIPPortToIPPort(
context.Background(), "tcp", "eth0", sourceMatcher, destinationMatcher, true,
).Return(nil).After(firstCall)
settings := Settings{
DefaultInterface: "eth0",
IPv6Supported: ptrTo(false),
Firewall: firewall,
UpstreamResolvers: []provider.Provider{provider.Cloudflare()},
}
client := New(settings)
addresses, err := client.ResolveName(ctx, "github.com")
require.NoError(t, err)
assert.NotEmpty(t, addresses)
}
func Test_answersToNetipAddrs(t *testing.T) {
t.Parallel()
testCases := map[string]struct {
message *dns.Msg
expected []netip.Addr
}{
"nil_message": {},
"no_answers": {
message: &dns.Msg{},
expected: []netip.Addr{},
},
"a_record": {
message: &dns.Msg{Answer: []dns.RR{
&dns.A{
Hdr: dns.RR_Header{Name: "example.com.", Rrtype: dns.TypeA, Class: dns.ClassINET},
A: net.IP{1, 1, 1, 1},
},
}},
expected: []netip.Addr{netip.MustParseAddr("1.1.1.1")},
},
"aaaa_record": {
message: &dns.Msg{Answer: []dns.RR{
&dns.AAAA{
Hdr: dns.RR_Header{Name: "example.com.", Rrtype: dns.TypeAAAA, Class: dns.ClassINET},
AAAA: net.IP{0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0, 0, 0, 0, 0, 0, 0, 0, 0x88, 0x88},
},
}},
expected: []netip.Addr{netip.MustParseAddr("2001:4860:4860::8888")},
},
"mixed_records": {
message: &dns.Msg{Answer: []dns.RR{
&dns.A{
Hdr: dns.RR_Header{Name: "example.com.", Rrtype: dns.TypeA, Class: dns.ClassINET},
A: net.IP{1, 1, 1, 1},
},
&dns.AAAA{
Hdr: dns.RR_Header{Name: "example.com.", Rrtype: dns.TypeAAAA, Class: dns.ClassINET},
AAAA: net.IP{0x20, 0x01, 0x48, 0x60, 0x48, 0x60, 0, 0, 0, 0, 0, 0, 0, 0, 0x88, 0x88},
},
}},
expected: []netip.Addr{netip.MustParseAddr("1.1.1.1"), netip.MustParseAddr("2001:4860:4860::8888")},
},
}
for testName, testCase := range testCases {
t.Run(testName, func(t *testing.T) {
t.Parallel()
addresses := answersToNetipAddrs(testCase.message)
assert.Equal(t, testCase.expected, addresses)
})
}
}
-28
View File
@@ -1,28 +0,0 @@
package restrictednet
import (
"errors"
"github.com/qdm12/dns/v2/pkg/provider"
)
type Settings struct {
DefaultInterface string
IPv6Supported *bool
Firewall Firewall
UpstreamResolvers []provider.Provider
}
func (s *Settings) validate() error {
switch {
case s.DefaultInterface == "":
return errors.New("default interface is not set")
case s.IPv6Supported == nil:
return errors.New("IPv6 support field is not set")
case s.Firewall == nil:
return errors.New("firewall is not set")
case len(s.UpstreamResolvers) == 0:
return errors.New("no upstream resolvers provided")
}
return nil
}
+61 -67
View File
@@ -1,10 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/qdm12/gluetun/internal/routing (interfaces: NetLinker) // Source: github.com/qdm12/gluetun/internal/routing (interfaces: NetLinker)
//
// Generated by this command:
//
// mockgen -destination=mocks_test.go -package=routing . NetLinker
//
// Package routing is a generated GoMock package. // Package routing is a generated GoMock package.
package routing package routing
@@ -13,15 +8,14 @@ import (
netip "net/netip" netip "net/netip"
reflect "reflect" reflect "reflect"
gomock "github.com/golang/mock/gomock"
netlink "github.com/qdm12/gluetun/internal/netlink" netlink "github.com/qdm12/gluetun/internal/netlink"
gomock "go.uber.org/mock/gomock"
) )
// MockNetLinker is a mock of NetLinker interface. // MockNetLinker is a mock of NetLinker interface.
type MockNetLinker struct { type MockNetLinker struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockNetLinkerMockRecorder recorder *MockNetLinkerMockRecorder
isgomock struct{}
} }
// MockNetLinkerMockRecorder is the mock recorder for MockNetLinker. // MockNetLinkerMockRecorder is the mock recorder for MockNetLinker.
@@ -42,91 +36,91 @@ func (m *MockNetLinker) EXPECT() *MockNetLinkerMockRecorder {
} }
// AddrList mocks base method. // AddrList mocks base method.
func (m *MockNetLinker) AddrList(linkIndex uint32, family uint8) ([]netip.Prefix, error) { func (m *MockNetLinker) AddrList(arg0 uint32, arg1 byte) ([]netip.Prefix, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddrList", linkIndex, family) ret := m.ctrl.Call(m, "AddrList", arg0, arg1)
ret0, _ := ret[0].([]netip.Prefix) ret0, _ := ret[0].([]netip.Prefix)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// AddrList indicates an expected call of AddrList. // AddrList indicates an expected call of AddrList.
func (mr *MockNetLinkerMockRecorder) AddrList(linkIndex, family any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) AddrList(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrList", reflect.TypeOf((*MockNetLinker)(nil).AddrList), linkIndex, family) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrList", reflect.TypeOf((*MockNetLinker)(nil).AddrList), arg0, arg1)
} }
// AddrReplace mocks base method. // AddrReplace mocks base method.
func (m *MockNetLinker) AddrReplace(linkIndex uint32, prefix netip.Prefix) error { func (m *MockNetLinker) AddrReplace(arg0 uint32, arg1 netip.Prefix) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddrReplace", linkIndex, prefix) ret := m.ctrl.Call(m, "AddrReplace", arg0, arg1)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// AddrReplace indicates an expected call of AddrReplace. // AddrReplace indicates an expected call of AddrReplace.
func (mr *MockNetLinkerMockRecorder) AddrReplace(linkIndex, prefix any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) AddrReplace(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrReplace", reflect.TypeOf((*MockNetLinker)(nil).AddrReplace), linkIndex, prefix) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddrReplace", reflect.TypeOf((*MockNetLinker)(nil).AddrReplace), arg0, arg1)
} }
// LinkAdd mocks base method. // LinkAdd mocks base method.
func (m *MockNetLinker) LinkAdd(link netlink.Link) (uint32, error) { func (m *MockNetLinker) LinkAdd(arg0 netlink.Link) (uint32, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LinkAdd", link) ret := m.ctrl.Call(m, "LinkAdd", arg0)
ret0, _ := ret[0].(uint32) ret0, _ := ret[0].(uint32)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// LinkAdd indicates an expected call of LinkAdd. // LinkAdd indicates an expected call of LinkAdd.
func (mr *MockNetLinkerMockRecorder) LinkAdd(link any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) LinkAdd(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkAdd", reflect.TypeOf((*MockNetLinker)(nil).LinkAdd), link) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkAdd", reflect.TypeOf((*MockNetLinker)(nil).LinkAdd), arg0)
} }
// LinkByIndex mocks base method. // LinkByIndex mocks base method.
func (m *MockNetLinker) LinkByIndex(index uint32) (netlink.Link, error) { func (m *MockNetLinker) LinkByIndex(arg0 uint32) (netlink.Link, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LinkByIndex", index) ret := m.ctrl.Call(m, "LinkByIndex", arg0)
ret0, _ := ret[0].(netlink.Link) ret0, _ := ret[0].(netlink.Link)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// LinkByIndex indicates an expected call of LinkByIndex. // LinkByIndex indicates an expected call of LinkByIndex.
func (mr *MockNetLinkerMockRecorder) LinkByIndex(index any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) LinkByIndex(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkByIndex", reflect.TypeOf((*MockNetLinker)(nil).LinkByIndex), index) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkByIndex", reflect.TypeOf((*MockNetLinker)(nil).LinkByIndex), arg0)
} }
// LinkByName mocks base method. // LinkByName mocks base method.
func (m *MockNetLinker) LinkByName(name string) (netlink.Link, error) { func (m *MockNetLinker) LinkByName(arg0 string) (netlink.Link, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LinkByName", name) ret := m.ctrl.Call(m, "LinkByName", arg0)
ret0, _ := ret[0].(netlink.Link) ret0, _ := ret[0].(netlink.Link)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// LinkByName indicates an expected call of LinkByName. // LinkByName indicates an expected call of LinkByName.
func (mr *MockNetLinkerMockRecorder) LinkByName(name any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) LinkByName(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkByName", reflect.TypeOf((*MockNetLinker)(nil).LinkByName), name) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkByName", reflect.TypeOf((*MockNetLinker)(nil).LinkByName), arg0)
} }
// LinkDel mocks base method. // LinkDel mocks base method.
func (m *MockNetLinker) LinkDel(index uint32) error { func (m *MockNetLinker) LinkDel(arg0 uint32) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LinkDel", index) ret := m.ctrl.Call(m, "LinkDel", arg0)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// LinkDel indicates an expected call of LinkDel. // LinkDel indicates an expected call of LinkDel.
func (mr *MockNetLinkerMockRecorder) LinkDel(index any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) LinkDel(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkDel", reflect.TypeOf((*MockNetLinker)(nil).LinkDel), index) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkDel", reflect.TypeOf((*MockNetLinker)(nil).LinkDel), arg0)
} }
// LinkList mocks base method. // LinkList mocks base method.
@@ -145,129 +139,129 @@ func (mr *MockNetLinkerMockRecorder) LinkList() *gomock.Call {
} }
// LinkSetDown mocks base method. // LinkSetDown mocks base method.
func (m *MockNetLinker) LinkSetDown(index uint32) error { func (m *MockNetLinker) LinkSetDown(arg0 uint32) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LinkSetDown", index) ret := m.ctrl.Call(m, "LinkSetDown", arg0)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// LinkSetDown indicates an expected call of LinkSetDown. // LinkSetDown indicates an expected call of LinkSetDown.
func (mr *MockNetLinkerMockRecorder) LinkSetDown(index any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) LinkSetDown(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkSetDown", reflect.TypeOf((*MockNetLinker)(nil).LinkSetDown), index) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkSetDown", reflect.TypeOf((*MockNetLinker)(nil).LinkSetDown), arg0)
} }
// LinkSetUp mocks base method. // LinkSetUp mocks base method.
func (m *MockNetLinker) LinkSetUp(index uint32) error { func (m *MockNetLinker) LinkSetUp(arg0 uint32) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "LinkSetUp", index) ret := m.ctrl.Call(m, "LinkSetUp", arg0)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// LinkSetUp indicates an expected call of LinkSetUp. // LinkSetUp indicates an expected call of LinkSetUp.
func (mr *MockNetLinkerMockRecorder) LinkSetUp(index any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) LinkSetUp(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkSetUp", reflect.TypeOf((*MockNetLinker)(nil).LinkSetUp), index) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkSetUp", reflect.TypeOf((*MockNetLinker)(nil).LinkSetUp), arg0)
} }
// RouteAdd mocks base method. // RouteAdd mocks base method.
func (m *MockNetLinker) RouteAdd(route netlink.Route) error { func (m *MockNetLinker) RouteAdd(arg0 netlink.Route) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RouteAdd", route) ret := m.ctrl.Call(m, "RouteAdd", arg0)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// RouteAdd indicates an expected call of RouteAdd. // RouteAdd indicates an expected call of RouteAdd.
func (mr *MockNetLinkerMockRecorder) RouteAdd(route any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) RouteAdd(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RouteAdd", reflect.TypeOf((*MockNetLinker)(nil).RouteAdd), route) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RouteAdd", reflect.TypeOf((*MockNetLinker)(nil).RouteAdd), arg0)
} }
// RouteDel mocks base method. // RouteDel mocks base method.
func (m *MockNetLinker) RouteDel(route netlink.Route) error { func (m *MockNetLinker) RouteDel(arg0 netlink.Route) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RouteDel", route) ret := m.ctrl.Call(m, "RouteDel", arg0)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// RouteDel indicates an expected call of RouteDel. // RouteDel indicates an expected call of RouteDel.
func (mr *MockNetLinkerMockRecorder) RouteDel(route any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) RouteDel(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RouteDel", reflect.TypeOf((*MockNetLinker)(nil).RouteDel), route) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RouteDel", reflect.TypeOf((*MockNetLinker)(nil).RouteDel), arg0)
} }
// RouteList mocks base method. // RouteList mocks base method.
func (m *MockNetLinker) RouteList(family uint8) ([]netlink.Route, error) { func (m *MockNetLinker) RouteList(arg0 byte) ([]netlink.Route, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RouteList", family) ret := m.ctrl.Call(m, "RouteList", arg0)
ret0, _ := ret[0].([]netlink.Route) ret0, _ := ret[0].([]netlink.Route)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// RouteList indicates an expected call of RouteList. // RouteList indicates an expected call of RouteList.
func (mr *MockNetLinkerMockRecorder) RouteList(family any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) RouteList(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RouteList", reflect.TypeOf((*MockNetLinker)(nil).RouteList), family) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RouteList", reflect.TypeOf((*MockNetLinker)(nil).RouteList), arg0)
} }
// RouteReplace mocks base method. // RouteReplace mocks base method.
func (m *MockNetLinker) RouteReplace(route netlink.Route) error { func (m *MockNetLinker) RouteReplace(arg0 netlink.Route) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RouteReplace", route) ret := m.ctrl.Call(m, "RouteReplace", arg0)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// RouteReplace indicates an expected call of RouteReplace. // RouteReplace indicates an expected call of RouteReplace.
func (mr *MockNetLinkerMockRecorder) RouteReplace(route any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) RouteReplace(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RouteReplace", reflect.TypeOf((*MockNetLinker)(nil).RouteReplace), route) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RouteReplace", reflect.TypeOf((*MockNetLinker)(nil).RouteReplace), arg0)
} }
// RuleAdd mocks base method. // RuleAdd mocks base method.
func (m *MockNetLinker) RuleAdd(rule netlink.Rule) error { func (m *MockNetLinker) RuleAdd(arg0 netlink.Rule) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RuleAdd", rule) ret := m.ctrl.Call(m, "RuleAdd", arg0)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// RuleAdd indicates an expected call of RuleAdd. // RuleAdd indicates an expected call of RuleAdd.
func (mr *MockNetLinkerMockRecorder) RuleAdd(rule any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) RuleAdd(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RuleAdd", reflect.TypeOf((*MockNetLinker)(nil).RuleAdd), rule) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RuleAdd", reflect.TypeOf((*MockNetLinker)(nil).RuleAdd), arg0)
} }
// RuleDel mocks base method. // RuleDel mocks base method.
func (m *MockNetLinker) RuleDel(rule netlink.Rule) error { func (m *MockNetLinker) RuleDel(arg0 netlink.Rule) error {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RuleDel", rule) ret := m.ctrl.Call(m, "RuleDel", arg0)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
// RuleDel indicates an expected call of RuleDel. // RuleDel indicates an expected call of RuleDel.
func (mr *MockNetLinkerMockRecorder) RuleDel(rule any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) RuleDel(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RuleDel", reflect.TypeOf((*MockNetLinker)(nil).RuleDel), rule) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RuleDel", reflect.TypeOf((*MockNetLinker)(nil).RuleDel), arg0)
} }
// RuleList mocks base method. // RuleList mocks base method.
func (m *MockNetLinker) RuleList(family uint8) ([]netlink.Rule, error) { func (m *MockNetLinker) RuleList(arg0 byte) ([]netlink.Rule, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RuleList", family) ret := m.ctrl.Call(m, "RuleList", arg0)
ret0, _ := ret[0].([]netlink.Rule) ret0, _ := ret[0].([]netlink.Rule)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
// RuleList indicates an expected call of RuleList. // RuleList indicates an expected call of RuleList.
func (mr *MockNetLinkerMockRecorder) RuleList(family any) *gomock.Call { func (mr *MockNetLinkerMockRecorder) RuleList(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RuleList", reflect.TypeOf((*MockNetLinker)(nil).RuleList), family) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RuleList", reflect.TypeOf((*MockNetLinker)(nil).RuleList), arg0)
} }
+1 -1
View File
@@ -5,10 +5,10 @@ import (
"net/netip" "net/netip"
"testing" "testing"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/netlink" "github.com/qdm12/gluetun/internal/netlink"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
) )
func makeNetipPrefix(n byte) netip.Prefix { func makeNetipPrefix(n byte) netip.Prefix {
@@ -8,9 +8,9 @@ import (
"net/url" "net/url"
"testing" "testing"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
) )
func Test_authHandler_ServeHTTP(t *testing.T) { func Test_authHandler_ServeHTTP(t *testing.T) {
+11 -17
View File
@@ -1,10 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/qdm12/gluetun/internal/server/middlewares/auth (interfaces: DebugLogger) // Source: github.com/qdm12/gluetun/internal/server/middlewares/auth (interfaces: DebugLogger)
//
// Generated by this command:
//
// mockgen -destination=mocks_test.go -package=auth . DebugLogger
//
// Package auth is a generated GoMock package. // Package auth is a generated GoMock package.
package auth package auth
@@ -12,14 +7,13 @@ package auth
import ( import (
reflect "reflect" reflect "reflect"
gomock "go.uber.org/mock/gomock" gomock "github.com/golang/mock/gomock"
) )
// MockDebugLogger is a mock of DebugLogger interface. // MockDebugLogger is a mock of DebugLogger interface.
type MockDebugLogger struct { type MockDebugLogger struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockDebugLoggerMockRecorder recorder *MockDebugLoggerMockRecorder
isgomock struct{}
} }
// MockDebugLoggerMockRecorder is the mock recorder for MockDebugLogger. // MockDebugLoggerMockRecorder is the mock recorder for MockDebugLogger.
@@ -40,35 +34,35 @@ func (m *MockDebugLogger) EXPECT() *MockDebugLoggerMockRecorder {
} }
// Debugf mocks base method. // Debugf mocks base method.
func (m *MockDebugLogger) Debugf(format string, args ...any) { func (m *MockDebugLogger) Debugf(arg0 string, arg1 ...interface{}) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
varargs := []any{format} varargs := []interface{}{arg0}
for _, a := range args { for _, a := range arg1 {
varargs = append(varargs, a) varargs = append(varargs, a)
} }
m.ctrl.Call(m, "Debugf", varargs...) m.ctrl.Call(m, "Debugf", varargs...)
} }
// Debugf indicates an expected call of Debugf. // Debugf indicates an expected call of Debugf.
func (mr *MockDebugLoggerMockRecorder) Debugf(format any, args ...any) *gomock.Call { func (mr *MockDebugLoggerMockRecorder) Debugf(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
varargs := append([]any{format}, args...) varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debugf", reflect.TypeOf((*MockDebugLogger)(nil).Debugf), varargs...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Debugf", reflect.TypeOf((*MockDebugLogger)(nil).Debugf), varargs...)
} }
// Warnf mocks base method. // Warnf mocks base method.
func (m *MockDebugLogger) Warnf(format string, args ...any) { func (m *MockDebugLogger) Warnf(arg0 string, arg1 ...interface{}) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
varargs := []any{format} varargs := []interface{}{arg0}
for _, a := range args { for _, a := range arg1 {
varargs = append(varargs, a) varargs = append(varargs, a)
} }
m.ctrl.Call(m, "Warnf", varargs...) m.ctrl.Call(m, "Warnf", varargs...)
} }
// Warnf indicates an expected call of Warnf. // Warnf indicates an expected call of Warnf.
func (mr *MockDebugLoggerMockRecorder) Warnf(format any, args ...any) *gomock.Call { func (mr *MockDebugLoggerMockRecorder) Warnf(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
varargs := append([]any{format}, args...) varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warnf", reflect.TypeOf((*MockDebugLogger)(nil).Warnf), varargs...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warnf", reflect.TypeOf((*MockDebugLogger)(nil).Warnf), varargs...)
} }
+13 -19
View File
@@ -1,10 +1,5 @@
// Code generated by MockGen. DO NOT EDIT. // Code generated by MockGen. DO NOT EDIT.
// Source: github.com/qdm12/gluetun/internal/socks5 (interfaces: Logger) // Source: github.com/qdm12/gluetun/internal/socks5 (interfaces: Logger)
//
// Generated by this command:
//
// mockgen -destination=mocks_test.go -package=socks5 . Logger
//
// Package socks5 is a generated GoMock package. // Package socks5 is a generated GoMock package.
package socks5 package socks5
@@ -12,14 +7,13 @@ package socks5
import ( import (
reflect "reflect" reflect "reflect"
gomock "go.uber.org/mock/gomock" gomock "github.com/golang/mock/gomock"
) )
// MockLogger is a mock of Logger interface. // MockLogger is a mock of Logger interface.
type MockLogger struct { type MockLogger struct {
ctrl *gomock.Controller ctrl *gomock.Controller
recorder *MockLoggerMockRecorder recorder *MockLoggerMockRecorder
isgomock struct{}
} }
// MockLoggerMockRecorder is the mock recorder for MockLogger. // MockLoggerMockRecorder is the mock recorder for MockLogger.
@@ -40,35 +34,35 @@ func (m *MockLogger) EXPECT() *MockLoggerMockRecorder {
} }
// Infof mocks base method. // Infof mocks base method.
func (m *MockLogger) Infof(format string, a ...any) { func (m *MockLogger) Infof(arg0 string, arg1 ...interface{}) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
varargs := []any{format} varargs := []interface{}{arg0}
for _, a_2 := range a { for _, a := range arg1 {
varargs = append(varargs, a_2) varargs = append(varargs, a)
} }
m.ctrl.Call(m, "Infof", varargs...) m.ctrl.Call(m, "Infof", varargs...)
} }
// Infof indicates an expected call of Infof. // Infof indicates an expected call of Infof.
func (mr *MockLoggerMockRecorder) Infof(format any, a ...any) *gomock.Call { func (mr *MockLoggerMockRecorder) Infof(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
varargs := append([]any{format}, a...) varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Infof", reflect.TypeOf((*MockLogger)(nil).Infof), varargs...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Infof", reflect.TypeOf((*MockLogger)(nil).Infof), varargs...)
} }
// Warnf mocks base method. // Warnf mocks base method.
func (m *MockLogger) Warnf(format string, a ...any) { func (m *MockLogger) Warnf(arg0 string, arg1 ...interface{}) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
varargs := []any{format} varargs := []interface{}{arg0}
for _, a_2 := range a { for _, a := range arg1 {
varargs = append(varargs, a_2) varargs = append(varargs, a)
} }
m.ctrl.Call(m, "Warnf", varargs...) m.ctrl.Call(m, "Warnf", varargs...)
} }
// Warnf indicates an expected call of Warnf. // Warnf indicates an expected call of Warnf.
func (mr *MockLoggerMockRecorder) Warnf(format any, a ...any) *gomock.Call { func (mr *MockLoggerMockRecorder) Warnf(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper() mr.mock.ctrl.T.Helper()
varargs := append([]any{format}, a...) varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warnf", reflect.TypeOf((*MockLogger)(nil).Warnf), varargs...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Warnf", reflect.TypeOf((*MockLogger)(nil).Warnf), varargs...)
} }
+1 -1
View File
@@ -13,9 +13,9 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
) )
type noopLogger struct{} type noopLogger struct{}
@@ -12,10 +12,10 @@ import (
"testing" "testing"
"time" "time"
"github.com/golang/mock/gomock"
"github.com/miekg/dns" "github.com/miekg/dns"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
) )
func Test_udpRouter_ResolveGithubFromCloudflareDNS(t *testing.T) { func Test_udpRouter_ResolveGithubFromCloudflareDNS(t *testing.T) {
+4 -12
View File
@@ -1,23 +1,15 @@
package storage package storage
import ( import (
"net/netip" "slices"
"github.com/qdm12/gluetun/internal/models" "github.com/qdm12/gluetun/internal/models"
) )
func copyServer(server models.Server) (serverCopy models.Server) { func copyServer(server models.Server) (serverCopy models.Server) {
serverCopy = server serverCopy = server
serverCopy.IPs = copyIPs(server.IPs) serverCopy.IPs = slices.Clone(server.IPs)
serverCopy.PortsTCP = slices.Clone(server.PortsTCP)
serverCopy.PortsUDP = slices.Clone(server.PortsUDP)
return serverCopy return serverCopy
} }
func copyIPs(toCopy []netip.Addr) (copied []netip.Addr) {
if toCopy == nil {
return nil
}
copied = make([]netip.Addr, len(toCopy))
copy(copied, toCopy)
return copied
}
+5 -39
View File
@@ -21,43 +21,9 @@ func Test_copyServer(t *testing.T) {
assert.Equal(t, server, serverCopy) assert.Equal(t, server, serverCopy)
// Check for mutation // Check for mutation
serverCopy.IPs[0] = netip.AddrFrom4([4]byte{9, 9, 9, 9}) serverCopy.IPs[0] = netip.AddrFrom4([4]byte{9, 9, 9, 9})
assert.NotEqual(t, server, serverCopy) serverCopy.PortsTCP = []uint16{80}
} serverCopy.PortsUDP = []uint16{53}
assert.NotEqual(t, server.IPs, serverCopy.IPs)
func Test_copyIPs(t *testing.T) { assert.NotEqual(t, server.PortsTCP, serverCopy.PortsTCP)
t.Parallel() assert.NotEqual(t, server.PortsUDP, serverCopy.PortsUDP)
testCases := map[string]struct {
toCopy []netip.Addr
copied []netip.Addr
}{
"nil": {},
"empty": {
toCopy: []netip.Addr{},
copied: []netip.Addr{},
},
"single IP": {
toCopy: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})},
copied: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1})},
},
"two IPs": {
toCopy: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1}), netip.AddrFrom4([4]byte{2, 2, 2, 2})},
copied: []netip.Addr{netip.AddrFrom4([4]byte{1, 1, 1, 1}), netip.AddrFrom4([4]byte{2, 2, 2, 2})},
},
}
for name, testCase := range testCases {
t.Run(name, func(t *testing.T) {
t.Parallel()
copied := copyIPs(testCase.toCopy)
assert.Equal(t, testCase.copied, copied)
if len(copied) > 0 {
testCase.toCopy[0] = netip.AddrFrom4([4]byte{9, 9, 9, 9})
assert.NotEqual(t, testCase.toCopy[0], testCase.copied[0])
}
})
}
} }
+33
View File
@@ -3,6 +3,7 @@ package storage
import ( import (
"errors" "errors"
"fmt" "fmt"
"slices"
"strings" "strings"
"github.com/qdm12/gluetun/internal/configuration/settings" "github.com/qdm12/gluetun/internal/configuration/settings"
@@ -48,6 +49,7 @@ func (s *Storage) FilterServers(provider string, selection settings.ServerSelect
return servers, nil return servers, nil
} }
//nolint:gocognit,gocyclo
func filterServer(server models.Server, func filterServer(server models.Server,
selection settings.ServerSelection, selection settings.ServerSelection,
) (filtered bool) { ) (filtered bool) {
@@ -90,6 +92,11 @@ func filterServer(server models.Server,
return true return true
} }
if (*selection.Dedicated && !server.Dedicated) ||
(!*selection.Dedicated && server.Dedicated) {
return false
}
if filterByPossibilities(server.Country, selection.Countries) { if filterByPossibilities(server.Country, selection.Countries) {
return true return true
} }
@@ -122,6 +129,14 @@ func filterServer(server models.Server,
return true return true
} }
serverPorts := server.PortsUDP
if server.VPN == vpn.OpenVPN && server.TCP {
serverPorts = server.PortsTCP
}
if filterByPorts(selection, serverPorts) {
return true
}
// TODO filter port forward server for PIA // TODO filter port forward server for PIA
return false return false
@@ -165,3 +180,21 @@ func filterByProtocol(selection settings.ServerSelection,
return (wantTCP && !serverTCP) || (wantUDP && !serverUDP) return (wantTCP && !serverTCP) || (wantUDP && !serverUDP)
} }
} }
func filterByPorts(selection settings.ServerSelection,
serverPorts []uint16,
) (filtered bool) {
if len(serverPorts) == 0 {
return false
}
customPort := *selection.OpenVPN.CustomPort
if selection.VPN == vpn.Wireguard {
customPort = *selection.Wireguard.EndpointPort
}
if customPort == 0 {
return false
}
return !slices.Contains(serverPorts, customPort)
}
+10 -1
View File
@@ -14,7 +14,7 @@ func commaJoin(slice []string) string {
return strings.Join(slice, ", ") return strings.Join(slice, ", ")
} }
func noServerFoundError(selection settings.ServerSelection) (err error) { func noServerFoundError(selection settings.ServerSelection) (err error) { //nolint:gocyclo
var messageParts []string var messageParts []string
messageParts = append(messageParts, "VPN "+selection.VPN) messageParts = append(messageParts, "VPN "+selection.VPN)
@@ -155,6 +155,15 @@ func noServerFoundError(selection settings.ServerSelection) (err error) {
"target ip address "+targetIP.String()) "target ip address "+targetIP.String())
} }
customPort := *selection.OpenVPN.CustomPort
if selection.VPN == vpn.Wireguard {
customPort = *selection.Wireguard.EndpointPort
}
if customPort > 0 {
messageParts = append(messageParts,
fmt.Sprintf("%s endpoint port %d", selection.VPN, customPort))
}
message := "for " + strings.Join(messageParts, "; ") message := "for " + strings.Join(messageParts, "; ")
return fmt.Errorf("no server found: %s", message) return fmt.Errorf("no server found: %s", message)

Some files were not shown because too many files have changed in this diff Show More