mirror of
https://github.com/qdm12/gluetun.git
synced 2026-07-09 03:59:53 +02:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cd9ba54b37 | |||
| 781e74f77a | |||
| fa0941a529 | |||
| e87d915f15 |
@@ -1,2 +1,2 @@
|
|||||||
FROM ghcr.io/qdm12/godevcontainer:v0.21-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 nftables
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
name: Update servers list
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
provider:
|
|
||||||
description: "VPN Provider to update"
|
|
||||||
required: true
|
|
||||||
default: "all"
|
|
||||||
type: choice
|
|
||||||
options:
|
|
||||||
- all
|
|
||||||
- airvpn
|
|
||||||
- cyberghost
|
|
||||||
- expressvpn
|
|
||||||
- fastestvpn
|
|
||||||
- giganews
|
|
||||||
- hidemyass
|
|
||||||
- ipvanish
|
|
||||||
- ivpn
|
|
||||||
- mullvad
|
|
||||||
- nordvpn
|
|
||||||
- perfect privacy
|
|
||||||
- privado
|
|
||||||
- private internet access
|
|
||||||
- privatevpn
|
|
||||||
- protonvpn
|
|
||||||
- purevpn
|
|
||||||
- slickvpn
|
|
||||||
- surfshark
|
|
||||||
- torguard
|
|
||||||
- vpnsecure
|
|
||||||
- vpn unlimited
|
|
||||||
- vyprvpn
|
|
||||||
- windscribe
|
|
||||||
schedule:
|
|
||||||
- cron: "11 3 1 */2 *" # Run at 03:11 on the 1st of every 2nd month
|
|
||||||
jobs:
|
|
||||||
update-servers-list:
|
|
||||||
if: github.repository == 'qdm12/gluetun'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
actions: read
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- uses: actions/setup-go@v6
|
|
||||||
with:
|
|
||||||
go-version-file: go.mod
|
|
||||||
|
|
||||||
- name: Update servers list
|
|
||||||
run: |
|
|
||||||
SELECTED_PROVIDER="${{ github.event.inputs.provider || 'all' }}"
|
|
||||||
|
|
||||||
if [ "$SELECTED_PROVIDER" = "all" ]; then
|
|
||||||
FLAGS="-all"
|
|
||||||
else
|
|
||||||
FLAGS="-providers $SELECTED_PROVIDER"
|
|
||||||
fi
|
|
||||||
|
|
||||||
go run ./cmd/gluetun/main.go update $FLAGS \
|
|
||||||
-maintainer \
|
|
||||||
-proton-email "${{ secrets.PROTON_EMAIL }}" \
|
|
||||||
-proton-password "${{ secrets.PROTON_PASSWORD }}"
|
|
||||||
|
|
||||||
- name: Check for changes
|
|
||||||
run: |
|
|
||||||
if git diff --exit-code internal/storage/servers.json >/dev/null; then
|
|
||||||
echo "Error: internal/storage/servers.json was not modified."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Check no other file changes
|
|
||||||
run: |
|
|
||||||
if ! git diff --exit-code --quiet ':!internal/storage/servers.json'; then
|
|
||||||
echo "Error: Unexpected changes detected in files other than servers.json"
|
|
||||||
git status --short
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Create Pull Request
|
|
||||||
id: createpr
|
|
||||||
uses: peter-evans/create-pull-request@v7
|
|
||||||
with:
|
|
||||||
branch-suffix: timestamp
|
|
||||||
branch: bot/update-servers-list
|
|
||||||
base: master
|
|
||||||
delete-branch: true
|
|
||||||
|
|
||||||
# - name: Merge Pull Request
|
|
||||||
# env:
|
|
||||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
# run: |
|
|
||||||
# gh pr merge ${{ steps.createpr.outputs.pull-request-number }} --auto -m -d
|
|
||||||
@@ -7,11 +7,12 @@ require (
|
|||||||
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/golang/mock v1.6.0
|
||||||
|
github.com/google/nftables v0.3.0
|
||||||
github.com/jsimonetti/rtnetlink v1.4.2
|
github.com/jsimonetti/rtnetlink v1.4.2
|
||||||
github.com/klauspost/compress v1.18.1
|
github.com/klauspost/compress v1.18.1
|
||||||
github.com/klauspost/pgzip v1.2.6
|
github.com/klauspost/pgzip v1.2.6
|
||||||
github.com/mdlayher/genetlink v1.3.2
|
github.com/mdlayher/genetlink v1.3.2
|
||||||
github.com/mdlayher/netlink v1.7.2
|
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42
|
||||||
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.20260216151239-36b3306f2205
|
github.com/qdm12/dns/v2 v2.0.0-rc9.0.20260216151239-36b3306f2205
|
||||||
github.com/qdm12/gosettings v0.4.4
|
github.com/qdm12/gosettings v0.4.4
|
||||||
@@ -42,7 +43,6 @@ require (
|
|||||||
github.com/cronokirby/saferith v0.33.0 // indirect
|
github.com/cronokirby/saferith v0.33.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/google/go-cmp v0.7.0 // indirect
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
github.com/josharian/native v1.1.0 // indirect
|
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mdlayher/socket v0.5.1 // indirect
|
github.com/mdlayher/socket v0.5.1 // indirect
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
|||||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
github.com/google/nftables v0.3.0 h1:bkyZ0cbpVeMHXOrtlFc8ISmfVqq5gPJukoYieyVmITg=
|
||||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
github.com/google/nftables v0.3.0/go.mod h1:BCp9FsrbF1Fn/Yu6CLUc9GGZFw/+hsxfluNXXmxBfRM=
|
||||||
github.com/jsimonetti/rtnetlink v1.4.2 h1:Df9w9TZ3npHTyDn0Ev9e1uzmN2odmXd0QX+J5GTEn90=
|
github.com/jsimonetti/rtnetlink v1.4.2 h1:Df9w9TZ3npHTyDn0Ev9e1uzmN2odmXd0QX+J5GTEn90=
|
||||||
github.com/jsimonetti/rtnetlink v1.4.2/go.mod h1:92s6LJdE+1iOrw+F2/RO7LYI2Qd8pPpFNNUYW06gcoM=
|
github.com/jsimonetti/rtnetlink v1.4.2/go.mod h1:92s6LJdE+1iOrw+F2/RO7LYI2Qd8pPpFNNUYW06gcoM=
|
||||||
github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
|
github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
|
||||||
@@ -49,8 +49,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
|||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
|
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
|
||||||
github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o=
|
github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o=
|
||||||
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 h1:A1Cq6Ysb0GM0tpKMbdCXCIfBclan4oHk1Jb+Hrejirg=
|
||||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42/go.mod h1:BB4YCPDOzfy7FniQ/lxuYQ3dgmM2cZumHbK8RpTjN2o=
|
||||||
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
|
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
|
||||||
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
|
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
|
||||||
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
|
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
|
||||||
@@ -99,6 +99,8 @@ github.com/ti-mo/netfilter v0.5.3 h1:ikzduvnaUMwre5bhbNwWOd6bjqLMVb33vv0XXbK0xGQ
|
|||||||
github.com/ti-mo/netfilter v0.5.3/go.mod h1:08SyBCg6hu1qyQk4s3DjjJKNrm3RTb32nm6AzyT972E=
|
github.com/ti-mo/netfilter v0.5.3/go.mod h1:08SyBCg6hu1qyQk4s3DjjJKNrm3RTb32nm6AzyT972E=
|
||||||
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
|
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/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||||
|
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||||
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.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ func (o OpenVPNSelection) validate(vpnProvider string) (err error) {
|
|||||||
providers.Giganews,
|
providers.Giganews,
|
||||||
providers.Ipvanish,
|
providers.Ipvanish,
|
||||||
providers.Perfectprivacy,
|
providers.Perfectprivacy,
|
||||||
|
providers.Privado,
|
||||||
providers.Vyprvpn,
|
providers.Vyprvpn,
|
||||||
) {
|
) {
|
||||||
return fmt.Errorf("%w: for VPN service provider %s",
|
return fmt.Errorf("%w: for VPN service provider %s",
|
||||||
@@ -74,8 +75,8 @@ func (o OpenVPNSelection) validate(vpnProvider string) (err error) {
|
|||||||
providers.Privatevpn, providers.Torguard:
|
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, providers.Nordvpn,
|
||||||
providers.Nordvpn, providers.Purevpn,
|
providers.Privado, providers.Purevpn,
|
||||||
providers.Surfshark, providers.VPNSecure,
|
providers.Surfshark, providers.VPNSecure,
|
||||||
providers.VPNUnlimited, providers.Vyprvpn:
|
providers.VPNUnlimited, providers.Vyprvpn:
|
||||||
return fmt.Errorf("%w: for VPN service provider %s",
|
return fmt.Errorf("%w: for VPN service provider %s",
|
||||||
@@ -98,9 +99,6 @@ func (o OpenVPNSelection) validate(vpnProvider string) (err error) {
|
|||||||
case providers.Perfectprivacy:
|
case providers.Perfectprivacy:
|
||||||
allowedTCP = []uint16{44, 443, 4433}
|
allowedTCP = []uint16{44, 443, 4433}
|
||||||
allowedUDP = []uint16{44, 443, 4433}
|
allowedUDP = []uint16{44, 443, 4433}
|
||||||
case providers.Privado:
|
|
||||||
allowedTCP = []uint16{443, 1194, 8080, 8443}
|
|
||||||
allowedUDP = []uint16{443, 1194, 8080, 8443}
|
|
||||||
case providers.PrivateInternetAccess:
|
case providers.PrivateInternetAccess:
|
||||||
allowedTCP = []uint16{80, 110, 443}
|
allowedTCP = []uint16{80, 110, 443}
|
||||||
allowedUDP = []uint16{53, 1194, 1197, 1198, 8080, 9201}
|
allowedUDP = []uint16{53, 1194, 1197, 1198, 8080, 9201}
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
package providers
|
package providers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_All(t *testing.T) {
|
func Test_All(t *testing.T) {
|
||||||
@@ -24,33 +21,3 @@ func Test_AllWithCustom(t *testing.T) {
|
|||||||
assert.Contains(t, all, Custom)
|
assert.Contains(t, all, Custom)
|
||||||
assert.Len(t, all, len(All())+1)
|
assert.Len(t, all, len(All())+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWorkflowHasAll(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
const path = "../../../.github/workflows/update-servers-list.yml"
|
|
||||||
file, err := os.Open(path)
|
|
||||||
require.NoError(t, err)
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
var data struct {
|
|
||||||
On struct {
|
|
||||||
WorkflowDispatch struct {
|
|
||||||
Inputs struct {
|
|
||||||
Provider struct {
|
|
||||||
Options []string `yaml:"options"`
|
|
||||||
} `yaml:"provider"`
|
|
||||||
} `yaml:"inputs"`
|
|
||||||
} `yaml:"workflow_dispatch"`
|
|
||||||
} `yaml:"on"`
|
|
||||||
}
|
|
||||||
decoder := yaml.NewDecoder(file)
|
|
||||||
err = decoder.Decode(&data)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
providers := All()
|
|
||||||
expected := make([]string, len(providers)+1)
|
|
||||||
expected[0] = "all"
|
|
||||||
copy(expected[1:], providers)
|
|
||||||
assert.Equal(t, expected, data.On.WorkflowDispatch.Inputs.Provider.Options)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -51,11 +51,7 @@ func (c *Config) enable(ctx context.Context) (err error) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if err = c.impl.SetIPv4AllPolicies(ctx, "DROP"); err != nil {
|
if err = c.impl.SetBaseChainsPolicy(ctx, "DROP"); err != nil {
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = c.impl.SetIPv6AllPolicies(ctx, "DROP"); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,8 +34,7 @@ type firewallImpl interface { //nolint:interfacebloat
|
|||||||
RedirectPort(ctx context.Context, intf string, sourcePort,
|
RedirectPort(ctx context.Context, intf string, sourcePort,
|
||||||
destinationPort uint16, remove bool) error
|
destinationPort uint16, remove bool) error
|
||||||
RunUserPostRules(ctx context.Context, customRulesPath string) error
|
RunUserPostRules(ctx context.Context, customRulesPath string) error
|
||||||
SetIPv4AllPolicies(ctx context.Context, policy string) error
|
SetBaseChainsPolicy(ctx context.Context, policy string) error
|
||||||
SetIPv6AllPolicies(ctx context.Context, policy string) error
|
|
||||||
TempDropOutputTCPRST(ctx context.Context, src, dst netip.AddrPort, excludeMark int) (
|
TempDropOutputTCPRST(ctx context.Context, src, dst netip.AddrPort, excludeMark int) (
|
||||||
revert func(ctx context.Context) error, err error)
|
revert func(ctx context.Context) error, err error)
|
||||||
Version(ctx context.Context) (version string, err error)
|
Version(ctx context.Context) (version string, err error)
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package iptables
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/qdm12/gluetun/internal/mod"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@@ -14,6 +16,8 @@ type Config struct {
|
|||||||
// Fixed state
|
// Fixed state
|
||||||
ipTables string
|
ipTables string
|
||||||
ip6Tables string
|
ip6Tables string
|
||||||
|
nftables bool
|
||||||
|
xtMark bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(ctx context.Context, runner CmdRunner, logger Logger) (*Config, error) {
|
func New(ctx context.Context, runner CmdRunner, logger Logger) (*Config, error) {
|
||||||
@@ -27,10 +31,21 @@ func New(ctx context.Context, runner CmdRunner, logger Logger) (*Config, error)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
modules := map[string]bool{
|
||||||
|
"xt_mark": false,
|
||||||
|
"nf_tables": false,
|
||||||
|
}
|
||||||
|
for module := range modules {
|
||||||
|
err := mod.Probe(module)
|
||||||
|
modules[module] = err == nil
|
||||||
|
}
|
||||||
|
|
||||||
return &Config{
|
return &Config{
|
||||||
runner: runner,
|
runner: runner,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
ipTables: iptables,
|
ipTables: iptables,
|
||||||
ip6Tables: ip6tables,
|
ip6Tables: ip6tables,
|
||||||
|
nftables: modules["nf_tables"],
|
||||||
|
xtMark: modules["xt_mark"],
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,18 +81,3 @@ func (c *Config) runIP6tablesInstructionNoSave(ctx context.Context, instruction
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var ErrPolicyNotValid = errors.New("policy is not valid")
|
|
||||||
|
|
||||||
func (c *Config) SetIPv6AllPolicies(ctx context.Context, policy string) error {
|
|
||||||
switch policy {
|
|
||||||
case "ACCEPT", "DROP":
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("%w: %s", ErrPolicyNotValid, policy)
|
|
||||||
}
|
|
||||||
return c.runIP6tablesInstructions(ctx, []string{
|
|
||||||
"--policy INPUT " + policy,
|
|
||||||
"--policy OUTPUT " + policy,
|
|
||||||
"--policy FORWARD " + policy,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -98,13 +98,14 @@ func (c *Config) runIptablesInstructionNoSave(ctx context.Context, instruction s
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) SetIPv4AllPolicies(ctx context.Context, policy string) error {
|
func (c *Config) SetBaseChainsPolicy(ctx context.Context, policy string) error {
|
||||||
|
policy = strings.ToUpper(policy)
|
||||||
switch policy {
|
switch policy {
|
||||||
case "ACCEPT", "DROP":
|
case "ACCEPT", "DROP":
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("%w: %s", ErrPolicyUnknown, policy)
|
return fmt.Errorf("%w: %s", ErrPolicyUnknown, policy)
|
||||||
}
|
}
|
||||||
return c.runIptablesInstructions(ctx, []string{
|
return c.runMixedIptablesInstructions(ctx, []string{
|
||||||
"--policy INPUT " + policy,
|
"--policy INPUT " + policy,
|
||||||
"--policy OUTPUT " + policy,
|
"--policy OUTPUT " + policy,
|
||||||
"--policy FORWARD " + policy,
|
"--policy FORWARD " + policy,
|
||||||
@@ -151,6 +152,9 @@ func (c *Config) AcceptOutputTrafficToVPN(ctx context.Context,
|
|||||||
defaultInterface string, connection models.Connection, remove bool,
|
defaultInterface string, connection models.Connection, remove bool,
|
||||||
) error {
|
) error {
|
||||||
protocol := connection.Protocol
|
protocol := connection.Protocol
|
||||||
|
if protocol == "tcp-client" {
|
||||||
|
protocol = "tcp"
|
||||||
|
}
|
||||||
instruction := fmt.Sprintf("%s OUTPUT -d %s -o %s -p %s -m %s --dport %d -j ACCEPT",
|
instruction := fmt.Sprintf("%s OUTPUT -d %s -o %s -p %s -m %s --dport %d -j ACCEPT",
|
||||||
appendOrDelete(remove), connection.IP, defaultInterface, protocol,
|
appendOrDelete(remove), connection.IP, defaultInterface, protocol,
|
||||||
protocol, connection.Port)
|
protocol, connection.Port)
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type tcpFlags struct {
|
type tcpFlags struct {
|
||||||
@@ -74,8 +73,7 @@ func (c *Config) TempDropOutputTCPRST(ctx context.Context,
|
|||||||
src, dst netip.AddrPort, excludeMark int) (
|
src, dst netip.AddrPort, excludeMark int) (
|
||||||
revert func(ctx context.Context) error, err error,
|
revert func(ctx context.Context) error, err error,
|
||||||
) {
|
) {
|
||||||
_, err = os.Stat("/usr/lib/xtables/libxt_mark.so")
|
if !c.nftables && !c.xtMark {
|
||||||
if err != nil && errors.Is(err, os.ErrNotExist) {
|
|
||||||
return nil, fmt.Errorf("%w", ErrMarkMatchModuleMissing)
|
return nil, fmt.Errorf("%w", ErrMarkMatchModuleMissing)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
package nftables
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/google/nftables"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SaveAndRestore saves the current nftables tree and returns a restore function that
|
||||||
|
// can be called to restore the saved tree.
|
||||||
|
func (f *Firewall) SaveAndRestore(_ context.Context) (restore func(context.Context), err error) {
|
||||||
|
f.mutex.Lock()
|
||||||
|
defer f.mutex.Unlock()
|
||||||
|
|
||||||
|
conn, err := nftables.New()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("creating nftables connection: %w", err)
|
||||||
|
}
|
||||||
|
tables, err := saveTables(conn)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("saving nftables state: %w", err)
|
||||||
|
}
|
||||||
|
return func(_ context.Context) {
|
||||||
|
conn, err := nftables.New()
|
||||||
|
if err != nil {
|
||||||
|
f.logger.Warnf("creating nftables connection for restore: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = restoreTables(conn, tables)
|
||||||
|
if err != nil {
|
||||||
|
f.logger.Warnf("restoring nftables state: %s", err)
|
||||||
|
}
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type savedTable struct {
|
||||||
|
table *nftables.Table
|
||||||
|
chains []savedChain
|
||||||
|
}
|
||||||
|
|
||||||
|
type savedChain struct {
|
||||||
|
chain *nftables.Chain
|
||||||
|
rules []*nftables.Rule
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveTables(conn *nftables.Conn) ([]savedTable, error) {
|
||||||
|
tables, err := conn.ListTables()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
savedTables := make([]savedTable, len(tables))
|
||||||
|
for i, table := range tables {
|
||||||
|
savedTables[i].table = table
|
||||||
|
|
||||||
|
chains, err := conn.ListChains()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, chain := range chains {
|
||||||
|
if chain.Table.Name != table.Name ||
|
||||||
|
chain.Table.Family != table.Family {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
rules, err := conn.GetRules(table, chain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("getting rules for chain %s in table %s: %w", chain.Name, table.Name, err)
|
||||||
|
}
|
||||||
|
savedChain := savedChain{chain: chain, rules: rules}
|
||||||
|
savedTables[i].chains = append(savedTables[i].chains, savedChain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return savedTables, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func restoreTables(conn *nftables.Conn, savedTables []savedTable) error {
|
||||||
|
conn.FlushRuleset()
|
||||||
|
|
||||||
|
for _, savedTable := range savedTables {
|
||||||
|
table := conn.AddTable(savedTable.table)
|
||||||
|
for _, savedChain := range savedTable.chains {
|
||||||
|
// Make the [nftables.Chain.Table] points to the new [nftables.Table]
|
||||||
|
// created in this connection.
|
||||||
|
savedChain.chain.Table = table
|
||||||
|
savedChain.chain = conn.AddChain(savedChain.chain)
|
||||||
|
|
||||||
|
for _, rule := range savedChain.rules {
|
||||||
|
rule.Table = table
|
||||||
|
rule.Chain = savedChain.chain
|
||||||
|
conn.AddRule(rule)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn.Flush()
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package nftables
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/nftables"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrPolicyUnknown = errors.New("unknown policy")
|
||||||
|
|
||||||
|
// SetBaseChainsPolicy sets the policy of all the base chains (INPUT, FORWARD, or OUTPUT)
|
||||||
|
// for the filter table to the given policy (accept or drop).
|
||||||
|
func (f *Firewall) SetBaseChainsPolicy(_ context.Context, policy string) error {
|
||||||
|
f.mutex.Lock()
|
||||||
|
defer f.mutex.Unlock()
|
||||||
|
|
||||||
|
var chainPolicy nftables.ChainPolicy
|
||||||
|
switch strings.ToLower(policy) {
|
||||||
|
case "accept":
|
||||||
|
chainPolicy = nftables.ChainPolicyAccept
|
||||||
|
case "drop":
|
||||||
|
chainPolicy = nftables.ChainPolicyDrop
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("%w: %s", ErrPolicyUnknown, policy)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := nftables.New()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("creating nftables connection: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, inputChain, forwardChain, outputChain := setupFilterWithBaseChains(conn)
|
||||||
|
inputChain.Policy = &chainPolicy
|
||||||
|
forwardChain.Policy = &chainPolicy
|
||||||
|
outputChain.Policy = &chainPolicy
|
||||||
|
|
||||||
|
conn.AddChain(inputChain)
|
||||||
|
conn.AddChain(forwardChain)
|
||||||
|
conn.AddChain(outputChain)
|
||||||
|
|
||||||
|
err = conn.Flush()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("flushing nftables changes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package nftables
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/google/nftables"
|
||||||
|
"github.com/google/nftables/expr"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (f *Firewall) AcceptEstablishedRelatedTraffic(_ context.Context) error {
|
||||||
|
f.mutex.Lock()
|
||||||
|
defer f.mutex.Unlock()
|
||||||
|
|
||||||
|
conn, err := nftables.New()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("creating nftables connection: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
table, inputChain, _, outputChain := setupFilterWithBaseChains(conn)
|
||||||
|
|
||||||
|
ctStateExprs := []expr.Any{
|
||||||
|
&expr.Ct{
|
||||||
|
Key: expr.CtKeySTATE,
|
||||||
|
Register: 1,
|
||||||
|
},
|
||||||
|
&expr.Bitwise{
|
||||||
|
SourceRegister: 1,
|
||||||
|
DestRegister: 1,
|
||||||
|
Len: 4, //nolint:mnd
|
||||||
|
Mask: []byte{byte(expr.CtStateBitESTABLISHED | expr.CtStateBitRELATED), 0x00, 0x00, 0x00},
|
||||||
|
Xor: []byte{0x00, 0x00, 0x00, 0x00},
|
||||||
|
},
|
||||||
|
&expr.Cmp{
|
||||||
|
Op: expr.CmpOpNeq,
|
||||||
|
Register: 1,
|
||||||
|
Data: []byte{0x00, 0x00, 0x00, 0x00},
|
||||||
|
},
|
||||||
|
&expr.Verdict{
|
||||||
|
Kind: expr.VerdictAccept,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.AddRule(&nftables.Rule{
|
||||||
|
Table: table,
|
||||||
|
Chain: inputChain,
|
||||||
|
Exprs: ctStateExprs,
|
||||||
|
})
|
||||||
|
|
||||||
|
conn.AddRule(&nftables.Rule{
|
||||||
|
Table: table,
|
||||||
|
Chain: outputChain,
|
||||||
|
Exprs: ctStateExprs,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err := conn.Flush(); err != nil {
|
||||||
|
return fmt.Errorf("flushing: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package nftables
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/google/nftables"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errRuleToDeleteNotFound = errors.New("rule not found for removal")
|
||||||
|
|
||||||
|
func (f *Firewall) deleteRule(conn *nftables.Conn, rule *nftables.Rule) error {
|
||||||
|
for i, existing := range f.rules {
|
||||||
|
if !reflect.DeepEqual(existing, rule) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err := conn.DelRule(existing)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("deleting rule: %w", err)
|
||||||
|
}
|
||||||
|
f.rules[i], f.rules[len(f.rules)-1] = f.rules[len(f.rules)-1], f.rules[i]
|
||||||
|
f.rules = f.rules[:len(f.rules)-1]
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fmt.Errorf("%w: %#v", errRuleToDeleteNotFound, rule)
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package nftables
|
||||||
|
|
||||||
|
import "github.com/google/nftables"
|
||||||
|
|
||||||
|
func setupFilterWithBaseChains(conn *nftables.Conn) (table *nftables.Table,
|
||||||
|
inputChain, forwardChain, outputChain *nftables.Chain,
|
||||||
|
) {
|
||||||
|
table = conn.AddTable(&nftables.Table{
|
||||||
|
Family: nftables.TableFamilyINet,
|
||||||
|
Name: "filter",
|
||||||
|
})
|
||||||
|
|
||||||
|
inputChain = conn.AddChain(&nftables.Chain{
|
||||||
|
Name: "input",
|
||||||
|
Table: table,
|
||||||
|
Type: nftables.ChainTypeFilter,
|
||||||
|
Hooknum: nftables.ChainHookInput,
|
||||||
|
Priority: nftables.ChainPriorityFilter,
|
||||||
|
})
|
||||||
|
|
||||||
|
forwardChain = conn.AddChain(&nftables.Chain{
|
||||||
|
Name: "forward",
|
||||||
|
Table: table,
|
||||||
|
Type: nftables.ChainTypeFilter,
|
||||||
|
Hooknum: nftables.ChainHookForward,
|
||||||
|
Priority: nftables.ChainPriorityFilter,
|
||||||
|
})
|
||||||
|
|
||||||
|
outputChain = conn.AddChain(&nftables.Chain{
|
||||||
|
Name: "output",
|
||||||
|
Table: table,
|
||||||
|
Type: nftables.ChainTypeFilter,
|
||||||
|
Hooknum: nftables.ChainHookOutput,
|
||||||
|
Priority: nftables.ChainPriorityFilter,
|
||||||
|
})
|
||||||
|
|
||||||
|
return table, inputChain, forwardChain, outputChain
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package nftables
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/google/nftables"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Firewall struct {
|
||||||
|
logger Logger
|
||||||
|
|
||||||
|
// rules are only rules added and tracked for later removal.
|
||||||
|
// Not all rules added are tracked for removal.
|
||||||
|
rules []*nftables.Rule
|
||||||
|
mutex sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(logger Logger) *Firewall {
|
||||||
|
return &Firewall{
|
||||||
|
logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
package nftables
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/netip"
|
||||||
|
|
||||||
|
"github.com/google/nftables"
|
||||||
|
"github.com/google/nftables/expr"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (f *Firewall) AcceptInputThroughInterface(_ context.Context, intf string) error {
|
||||||
|
f.mutex.Lock()
|
||||||
|
defer f.mutex.Unlock()
|
||||||
|
|
||||||
|
conn, err := nftables.New()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("creating nftables connection: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
table, inputChain, _, _ := setupFilterWithBaseChains(conn)
|
||||||
|
|
||||||
|
rule := &nftables.Rule{
|
||||||
|
Table: table,
|
||||||
|
Chain: inputChain,
|
||||||
|
Exprs: []expr.Any{
|
||||||
|
&expr.Meta{
|
||||||
|
Key: expr.MetaKeyIIFNAME,
|
||||||
|
Register: 1,
|
||||||
|
},
|
||||||
|
&expr.Cmp{
|
||||||
|
Op: expr.CmpOpEq,
|
||||||
|
Register: 1,
|
||||||
|
Data: []byte(intf + "\x00"),
|
||||||
|
},
|
||||||
|
&expr.Verdict{
|
||||||
|
Kind: expr.VerdictAccept,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.AddRule(rule)
|
||||||
|
|
||||||
|
err = conn.Flush()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("flushing: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AcceptInputToPort accepts incoming traffic on the specified port, for both TCP and UDP
|
||||||
|
// protocols, on the interface intf. If intf is empty or "*", the interface is not used as a filter.
|
||||||
|
// If remove is true, the rule is removed instead of added. This is used for port forwarding, with
|
||||||
|
// intf set to the VPN tunnel interface.
|
||||||
|
func (f *Firewall) AcceptInputToPort(_ context.Context, intf string, port uint16, remove bool) error {
|
||||||
|
f.mutex.Lock()
|
||||||
|
defer f.mutex.Unlock()
|
||||||
|
|
||||||
|
conn, err := nftables.New()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("creating nftables connection: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
table, inputChain, _, _ := setupFilterWithBaseChains(conn)
|
||||||
|
portBytes := []byte{byte(port >> 8), byte(port)} //nolint:mnd
|
||||||
|
const tcp, udp uint8 = 6, 17
|
||||||
|
protocols := []uint8{tcp, udp}
|
||||||
|
|
||||||
|
for _, protocol := range protocols {
|
||||||
|
const maxExprsLen = 7
|
||||||
|
exprs := make([]expr.Any, 0, maxExprsLen)
|
||||||
|
if intf != "" && intf != "*" {
|
||||||
|
exprs = append(exprs,
|
||||||
|
&expr.Meta{Key: expr.MetaKeyIIFNAME, Register: 1},
|
||||||
|
&expr.Cmp{Op: expr.CmpOpEq, Register: 1, Data: []byte(intf + "\x00")},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
exprs = append(exprs,
|
||||||
|
&expr.Payload{DestRegister: 1, Base: expr.PayloadBaseNetworkHeader, Offset: 9, Len: 1}, //nolint:mnd
|
||||||
|
&expr.Cmp{Op: expr.CmpOpEq, Register: 1, Data: []byte{protocol}},
|
||||||
|
&expr.Payload{DestRegister: 1, Base: expr.PayloadBaseTransportHeader, Offset: 2, Len: 2}, //nolint:mnd
|
||||||
|
&expr.Cmp{Op: expr.CmpOpEq, Register: 1, Data: portBytes},
|
||||||
|
&expr.Verdict{Kind: expr.VerdictAccept},
|
||||||
|
)
|
||||||
|
|
||||||
|
rule := &nftables.Rule{
|
||||||
|
Table: table,
|
||||||
|
Chain: inputChain,
|
||||||
|
Exprs: exprs,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !remove {
|
||||||
|
conn.AddRule(rule)
|
||||||
|
f.rules = append(f.rules, rule)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err = f.deleteRule(conn, rule)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("deleting rule: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = conn.Flush()
|
||||||
|
if err != nil {
|
||||||
|
f.rules = f.rules[:len(f.rules)-len(protocols)]
|
||||||
|
return fmt.Errorf("flushing: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Firewall) AcceptInputToSubnet(_ context.Context, intf string, subnet netip.Prefix) error {
|
||||||
|
f.mutex.Lock()
|
||||||
|
defer f.mutex.Unlock()
|
||||||
|
|
||||||
|
conn, err := nftables.New()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("creating nftables connection: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
table, inputChain, _, _ := setupFilterWithBaseChains(conn)
|
||||||
|
|
||||||
|
const maxExprsLen = 5
|
||||||
|
exprs := make([]expr.Any, 0, maxExprsLen)
|
||||||
|
|
||||||
|
if intf != "" && intf != "*" {
|
||||||
|
exprs = append(exprs,
|
||||||
|
&expr.Meta{Key: expr.MetaKeyIIFNAME, Register: 1},
|
||||||
|
&expr.Cmp{Op: expr.CmpOpEq, Register: 1, Data: []byte(intf + "\x00")},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
var payloadOffset uint32
|
||||||
|
if subnet.Addr().Is4() {
|
||||||
|
payloadOffset = 16
|
||||||
|
} else {
|
||||||
|
payloadOffset = 24
|
||||||
|
}
|
||||||
|
|
||||||
|
exprs = append(exprs,
|
||||||
|
&expr.Payload{
|
||||||
|
DestRegister: 1,
|
||||||
|
Base: expr.PayloadBaseNetworkHeader,
|
||||||
|
Offset: payloadOffset,
|
||||||
|
Len: uint32(len(subnet.Addr().AsSlice())), //nolint:gosec
|
||||||
|
},
|
||||||
|
&expr.Cmp{
|
||||||
|
Op: expr.CmpOpEq,
|
||||||
|
Register: 1,
|
||||||
|
Data: subnet.Addr().AsSlice(),
|
||||||
|
},
|
||||||
|
&expr.Verdict{Kind: expr.VerdictAccept},
|
||||||
|
)
|
||||||
|
|
||||||
|
rule := &nftables.Rule{
|
||||||
|
Table: table,
|
||||||
|
Chain: inputChain,
|
||||||
|
Exprs: exprs,
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.AddRule(rule)
|
||||||
|
|
||||||
|
err = conn.Flush()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("flushing: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package nftables
|
||||||
|
|
||||||
|
type Logger interface {
|
||||||
|
Warnf(format string, args ...any)
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package nftables
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/google/nftables"
|
||||||
|
"github.com/google/nftables/expr"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (f *Firewall) AcceptIpv6MulticastOutput(_ context.Context, intf string) error {
|
||||||
|
f.mutex.Lock()
|
||||||
|
defer f.mutex.Unlock()
|
||||||
|
|
||||||
|
conn, err := nftables.New()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("creating nftables connection: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
table, _, _, outputChain := setupFilterWithBaseChains(conn)
|
||||||
|
|
||||||
|
const maxExprsLen = 6
|
||||||
|
exprs := make([]expr.Any, 0, maxExprsLen)
|
||||||
|
|
||||||
|
if intf != "" && intf != "*" {
|
||||||
|
exprs = append(exprs,
|
||||||
|
&expr.Meta{Key: expr.MetaKeyOIFNAME, Register: 1},
|
||||||
|
&expr.Cmp{Op: expr.CmpOpEq, Register: 1, Data: []byte(intf + "\x00")},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ff02::1:ff00:0/104 mask is 13 bytes of 0xff
|
||||||
|
mask := []byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
|
||||||
|
} //nolint:mnd
|
||||||
|
addr := []byte{
|
||||||
|
0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00,
|
||||||
|
} //nolint:mnd
|
||||||
|
|
||||||
|
exprs = append(exprs,
|
||||||
|
&expr.Payload{
|
||||||
|
DestRegister: 1,
|
||||||
|
Base: expr.PayloadBaseNetworkHeader,
|
||||||
|
Offset: 24, // IPv6 Destination Address offset //nolint:mnd
|
||||||
|
Len: 16, //nolint:mnd
|
||||||
|
},
|
||||||
|
&expr.Bitwise{
|
||||||
|
SourceRegister: 1,
|
||||||
|
DestRegister: 1,
|
||||||
|
Len: 16, //nolint:mnd
|
||||||
|
Mask: mask,
|
||||||
|
Xor: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //nolint:mnd
|
||||||
|
},
|
||||||
|
&expr.Cmp{
|
||||||
|
Op: expr.CmpOpEq,
|
||||||
|
Register: 1,
|
||||||
|
Data: addr,
|
||||||
|
},
|
||||||
|
&expr.Verdict{Kind: expr.VerdictAccept},
|
||||||
|
)
|
||||||
|
|
||||||
|
rule := &nftables.Rule{
|
||||||
|
Table: table,
|
||||||
|
Chain: outputChain,
|
||||||
|
Exprs: exprs,
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.AddRule(rule)
|
||||||
|
|
||||||
|
err = conn.Flush()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("flushing: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package nftables
|
||||||
|
|
||||||
|
import "github.com/google/nftables"
|
||||||
|
|
||||||
|
func IsSupported() bool {
|
||||||
|
conn, err := nftables.New()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_, err = conn.ListTable("filter")
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package mod
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errBuiltinModuleNotFound = errors.New("builtin module not found")
|
||||||
|
|
||||||
|
func checkModulesBuiltin(modulesPath, moduleName string) error {
|
||||||
|
f, err := os.Open(filepath.Join(modulesPath, "modules.builtin"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
moduleName = strings.TrimSuffix(moduleName, ".ko")
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(f)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
line = strings.TrimSuffix(line, ".ko")
|
||||||
|
if strings.HasSuffix(line, "/"+moduleName) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("%w: %s", errBuiltinModuleNotFound, moduleName)
|
||||||
|
}
|
||||||
@@ -76,51 +76,28 @@ func checkProcConfig(moduleName string) error {
|
|||||||
|
|
||||||
func moduleNameToKernelFeatureGroups(moduleName string) (featureGroups [][]string, ok bool) {
|
func moduleNameToKernelFeatureGroups(moduleName string) (featureGroups [][]string, ok bool) {
|
||||||
moduleMap := map[string][][]string{
|
moduleMap := map[string][][]string{
|
||||||
"x_tables": {{"CONFIG_NETFILTER_XTABLES"}},
|
|
||||||
"nf_tables": {{"CONFIG_NF_TABLES"}},
|
"nf_tables": {{"CONFIG_NF_TABLES"}},
|
||||||
|
|
||||||
// Netfilter Matches
|
// Netfilter Matches
|
||||||
"xt_conntrack": {
|
"xt_conntrack": {{"CONFIG_NETFILTER_XT_MATCH_CONNTRACK"}},
|
||||||
{"CONFIG_NETFILTER_XT_MATCH_CONNTRACK"},
|
|
||||||
{"CONFIG_IP_NF_MATCH_CONNTRACK"}, // old kernels
|
|
||||||
},
|
|
||||||
"xt_connmark": {
|
"xt_connmark": {
|
||||||
{"CONFIG_NETFILTER_XT_CONNMARK"},
|
{"CONFIG_NETFILTER_XT_CONNMARK"},
|
||||||
{"CONFIG_NETFILTER_XT_MATCH_CONNMARK", "CONFIG_NETFILTER_XT_TARGET_CONNMARK"},
|
{"CONFIG_NETFILTER_XT_MATCH_CONNMARK", "CONFIG_NETFILTER_XT_TARGET_CONNMARK"},
|
||||||
},
|
},
|
||||||
"xt_mark": {
|
"xt_mark": {
|
||||||
{"CONFIG_NETFILTER_XT_MARK"},
|
{"CONFIG_NETFILTER_XT_MARK"},
|
||||||
{"CONFIG_NETFILTER_XT_MATCH_MARK"},
|
{"CONFIG_NETFILTER_XT_MATCH_MARK", "CONFIG_NETFILTER_XT_TARGET_MARK"},
|
||||||
},
|
},
|
||||||
"nf_conntrack": {{"CONFIG_NF_CONNTRACK"}},
|
|
||||||
"nf_conntrack_ipv4": {{"CONFIG_NF_CONNTRACK_IPV4"}},
|
|
||||||
"nf_conntrack_ipv6": {{"CONFIG_NF_CONNTRACK_IPV6"}},
|
|
||||||
"nf_conntrack_netlink": {{"CONFIG_NF_CT_NETLINK"}},
|
"nf_conntrack_netlink": {{"CONFIG_NF_CT_NETLINK"}},
|
||||||
|
"nf_reject_ipv4": {{"CONFIG_NF_REJECT_IPV4"}},
|
||||||
// Nftables
|
|
||||||
"nft_compat": {{"CONFIG_NFT_COMPAT"}},
|
|
||||||
"nft_ct": {{"CONFIG_NFT_CT"}},
|
|
||||||
"nft_connmark": {{"CONFIG_NFT_CONNMARK"}},
|
|
||||||
"nft_chain_filter": {{"CONFIG_NFT_CHAIN_FILTER_IPV4"}},
|
|
||||||
"nft_chain_filter_ipv4": {{"CONFIG_NFT_CHAIN_FILTER_IPV4"}},
|
|
||||||
"nft_chain_filter_ipv6": {{"CONFIG_NFT_CHAIN_FILTER_IPV6"}},
|
|
||||||
"nft_chain_mangle_ipv4": {{"CONFIG_NFT_CHAIN_MANGLE_IPV4"}},
|
|
||||||
"nft_chain_mangle_ipv6": {{"CONFIG_NFT_CHAIN_MANGLE_IPV6"}},
|
|
||||||
"nft_reject": {{"CONFIG_NFT_REJECT_INET"}, {"CONFIG_NFT_REJECT_IPV4"}},
|
|
||||||
|
|
||||||
// Iptables
|
|
||||||
"iptable_filter": {{"CONFIG_IP_NF_FILTER"}},
|
|
||||||
"ip6table_filter": {{"CONFIG_IP6_NF_FILTER"}},
|
|
||||||
"ip_tables": {{"CONFIG_IP_NF_IPTABLES"}},
|
|
||||||
"ip6_tables": {{"CONFIG_IP6_NF_IPTABLES"}},
|
|
||||||
|
|
||||||
// Common Netfilter Targets
|
// Common Netfilter Targets
|
||||||
"xt_LOG": {{"CONFIG_NETFILTER_XT_TARGET_LOG"}},
|
"xt_log": {{"CONFIG_NETFILTER_XT_TARGET_LOG"}},
|
||||||
"xt_REJECT": {
|
"xt_reject": {
|
||||||
{"CONFIG_IP_NF_TARGET_REJECT", "CONFIG_NF_REJECT_IPV4"},
|
{"CONFIG_IP_NF_TARGET_REJECT", "CONFIG_NF_REJECT_IPV4"},
|
||||||
{"CONFIG_NETFILTER_XT_TARGET_REJECT", "CONFIG_NF_REJECT_IPV4"},
|
{"CONFIG_NETFILTER_XT_TARGET_REJECT", "CONFIG_NF_REJECT_IPV4"},
|
||||||
},
|
},
|
||||||
"xt_MASQUERADE": {{"CONFIG_NETFILTER_XT_TARGET_MASQUERADE"}},
|
"xt_masquerade": {{"CONFIG_NETFILTER_XT_TARGET_MASQUERADE"}},
|
||||||
|
|
||||||
// Additional Netfilter Matches
|
// Additional Netfilter Matches
|
||||||
"xt_addrtype": {{"CONFIG_NETFILTER_XT_MATCH_ADDRTYPE"}},
|
"xt_addrtype": {{"CONFIG_NETFILTER_XT_MATCH_ADDRTYPE"}},
|
||||||
@@ -141,7 +118,7 @@ func moduleNameToKernelFeatureGroups(moduleName string) (featureGroups [][]strin
|
|||||||
"fuse": {{"CONFIG_FUSE_FS"}},
|
"fuse": {{"CONFIG_FUSE_FS"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
featureGroups, ok = moduleMap[moduleName]
|
featureGroups, ok = moduleMap[strings.ToLower(moduleName)]
|
||||||
return featureGroups, ok
|
return featureGroups, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ import (
|
|||||||
// It first tries to locate the modules directory in [getModulesPath].
|
// It first tries to locate the modules directory in [getModulesPath].
|
||||||
// If it fails (like on WSL), it then only checks for the kernel feature
|
// If it fails (like on WSL), it then only checks for the kernel feature
|
||||||
// in /proc/config.gz with [checkProcConfig].
|
// in /proc/config.gz with [checkProcConfig].
|
||||||
// Otherwise, it then runs the classic [modProbe] behavior,
|
// Otherwise, it first checks if the modules directory modules.builtin
|
||||||
|
// file contains the given module name in [checkModulesBuiltin].
|
||||||
|
// If the module is not found, it then runs the classic [modProbe] behavior,
|
||||||
// trying to load the module in the kernel.
|
// trying to load the module in the kernel.
|
||||||
// If this fails, it does one final try running [checkProcConfig].
|
// If this fails, it does one final try running [checkProcConfig].
|
||||||
func Probe(moduleName string) error {
|
func Probe(moduleName string) error {
|
||||||
@@ -26,6 +28,8 @@ func Probe(moduleName string) error {
|
|||||||
return fmt.Errorf("getting modules path: %w", err)
|
return fmt.Errorf("getting modules path: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = checkModulesBuiltin(modulesPath, moduleName)
|
||||||
|
if err != nil {
|
||||||
err = modProbe(modulesPath, moduleName)
|
err = modProbe(modulesPath, moduleName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = checkProcConfig(moduleName)
|
err = checkProcConfig(moduleName)
|
||||||
@@ -33,6 +37,7 @@ func Probe(moduleName string) error {
|
|||||||
return fmt.Errorf("checking /proc/config.gz: %w", err)
|
return fmt.Errorf("checking /proc/config.gz: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,10 @@ func extractDataFromLine(line string) (
|
|||||||
return ip, 0, "", nil
|
return ip, 0, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var errProtoLineFieldsCount = errors.New("proto line has not 2 fields as expected")
|
var (
|
||||||
|
errProtoLineFieldsCount = errors.New("proto line has not 2 fields as expected")
|
||||||
|
errProtocolNotSupported = errors.New("network protocol not supported")
|
||||||
|
)
|
||||||
|
|
||||||
func extractProto(line string) (protocol string, err error) {
|
func extractProto(line string) (protocol string, err error) {
|
||||||
fields := strings.Fields(line)
|
fields := strings.Fields(line)
|
||||||
@@ -89,25 +92,13 @@ func extractProto(line string) (protocol string, err error) {
|
|||||||
return "", fmt.Errorf("%w: %s", errProtoLineFieldsCount, line)
|
return "", fmt.Errorf("%w: %s", errProtoLineFieldsCount, line)
|
||||||
}
|
}
|
||||||
|
|
||||||
return parseProto(fields[1])
|
switch fields[1] {
|
||||||
}
|
case "tcp", "tcp4", "tcp6", "tcp-client", "udp", "udp4", "udp6":
|
||||||
|
|
||||||
var errProtocolNotSupported = errors.New("network protocol not supported")
|
|
||||||
|
|
||||||
func parseProto(field string) (protocol string, err error) {
|
|
||||||
switch field {
|
|
||||||
case "tcp", "tcp4", "tcp6", "tcp-client":
|
|
||||||
// tcp4, tcp6 can be assimilated as tcp since the IP version is
|
|
||||||
// determined by the remote IP address version.
|
|
||||||
// tcp-client is a synonym of tcp for OpenVPN 2.5+ acting in client mode.
|
|
||||||
return constants.TCP, nil
|
|
||||||
case "udp", "udp4", "udp6":
|
|
||||||
// udp4, udp6 can be assimilated as udp since the IP version is
|
|
||||||
// determined by the remote IP address version.
|
|
||||||
return constants.UDP, nil
|
|
||||||
default:
|
default:
|
||||||
return "", fmt.Errorf("%w: %s", errProtocolNotSupported, field)
|
return "", fmt.Errorf("%w: %s", errProtocolNotSupported, fields[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return fields[1], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -145,9 +136,11 @@ func extractRemote(line string) (ip netip.Addr, port uint16,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if n > 3 { //nolint:mnd
|
if n > 3 { //nolint:mnd
|
||||||
protocol, err = parseProto(fields[3])
|
switch fields[3] {
|
||||||
if err != nil {
|
case "tcp", "udp":
|
||||||
return netip.Addr{}, 0, "", fmt.Errorf("parsing protocol from remote line: %w", err)
|
protocol = fields[3]
|
||||||
|
default:
|
||||||
|
return netip.Addr{}, 0, "", fmt.Errorf("%w: %s", errProtocolNotSupported, fields[3])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ func Test_extractDataFromLine(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"tcp-client": {
|
"tcp-client": {
|
||||||
line: "proto tcp-client",
|
line: "proto tcp-client",
|
||||||
protocol: constants.TCP,
|
protocol: "tcp-client",
|
||||||
},
|
},
|
||||||
"extract remote error": {
|
"extract remote error": {
|
||||||
line: "remote bad",
|
line: "remote bad",
|
||||||
@@ -239,7 +239,7 @@ func Test_extractRemote(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"invalid protocol": {
|
"invalid protocol": {
|
||||||
line: "remote 1.2.3.4 8000 bad",
|
line: "remote 1.2.3.4 8000 bad",
|
||||||
err: errors.New("parsing protocol from remote line: network protocol not supported: bad"),
|
err: errors.New("network protocol not supported: bad"),
|
||||||
},
|
},
|
||||||
"IP host and port and protocol": {
|
"IP host and port and protocol": {
|
||||||
line: "remote 1.2.3.4 8000 udp",
|
line: "remote 1.2.3.4 8000 udp",
|
||||||
|
|||||||
@@ -18,10 +18,7 @@ func (p *Provider) OpenVPNConfig(connection models.Connection,
|
|||||||
openvpn.AES256gcm, openvpn.AES256cbc, openvpn.AES128gcm,
|
openvpn.AES256gcm, openvpn.AES256cbc, openvpn.AES128gcm,
|
||||||
},
|
},
|
||||||
Auth: openvpn.SHA512,
|
Auth: openvpn.SHA512,
|
||||||
CAs: []string{
|
CAs: []string{"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"}, //nolint:lll
|
||||||
"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", //nolint:lll
|
|
||||||
"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", //nolint:lll
|
|
||||||
}, //nolint:lll
|
|
||||||
Cert: "MIIDTjCCAregAwIBAgIDKzZvMA0GCSqGSIb3DQEBCwUAMIGFMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFTATBgNVBAcTDFNhbkZyYW5jaXNjbzEVMBMGA1UEChMMRm9ydC1GdW5zdG9uMRgwFgYDVQQDEw9Gb3J0LUZ1bnN0b24gQ0ExITAfBgkqhkiG9w0BCQEWEm1lQG15aG9zdC5teWRvbWFpbjAgFw0xNjExMDMwMzA2MThaGA8yMDY2MTEwMzAzMDYxOFowgYoxCzAJBgNVBAYTAlZHMQwwCgYDVQQIDANCVkkxEzARBgNVBAoMCkV4cHJlc3NWUE4xEzARBgNVBAsMCkV4cHJlc3NWUE4xHDAaBgNVBAMME2V4cHJlc3N2cG5fY3VzdG9tZXIxJTAjBgkqhkiG9w0BCQEWFnN1cHBvcnRAZXhwcmVzc3Zwbi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrOYt/KOi2uMDGev3pXg8j1SO4J/4EVWDF7vJcKr2jrZlqD/zuAFx2W1YWvwumPO6PKH4PU9621aNdiumaUkv/RplCfznnnxqobhJuTE2oA+rS1bOq+9OhHwF9jgNXNVk+XX4d0toST5uGE6Z3OdmPBur8o5AlCf78PDSAwpFOw5HrgLqOEU4hTweC1/czX2VsvsHv22HRI6JMZgP8gGQii/p9iukqfaJvGdPciL5p1QRBUQIi8P8pNvEp1pVIpxYj7/LOUqb2DxFvgmp2v1IQ0Yu88SWsFk84+xAYHzfkLyS31Sqj5uLRBnJqx3fIlOihQ50GI72fwPMwo+OippvVAgMBAAGjPzA9MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgSwMB0GA1UdDgQWBBSkBM1TCX9kBgFsv2RmOzudMXa9njANBgkqhkiG9w0BAQsFAAOBgQA+2e4b+33zFmA+1ZQ46kWkfiB+fEeDyMwMLeYYyDS2d8mZhNZKdOw7dy4Ifz9Vqzp4aKuQ6j61c6k1UaQQL0tskqWVzslSFvs9NZyUAJLLdGUc5TT2MiLwiXQwd4UvH6bGeePdhvB4+ZbW7VMD7TE8hZhjhAL4F6yAP1EQvg3LDA==", //nolint:lll
|
Cert: "MIIDTjCCAregAwIBAgIDKzZvMA0GCSqGSIb3DQEBCwUAMIGFMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFTATBgNVBAcTDFNhbkZyYW5jaXNjbzEVMBMGA1UEChMMRm9ydC1GdW5zdG9uMRgwFgYDVQQDEw9Gb3J0LUZ1bnN0b24gQ0ExITAfBgkqhkiG9w0BCQEWEm1lQG15aG9zdC5teWRvbWFpbjAgFw0xNjExMDMwMzA2MThaGA8yMDY2MTEwMzAzMDYxOFowgYoxCzAJBgNVBAYTAlZHMQwwCgYDVQQIDANCVkkxEzARBgNVBAoMCkV4cHJlc3NWUE4xEzARBgNVBAsMCkV4cHJlc3NWUE4xHDAaBgNVBAMME2V4cHJlc3N2cG5fY3VzdG9tZXIxJTAjBgkqhkiG9w0BCQEWFnN1cHBvcnRAZXhwcmVzc3Zwbi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrOYt/KOi2uMDGev3pXg8j1SO4J/4EVWDF7vJcKr2jrZlqD/zuAFx2W1YWvwumPO6PKH4PU9621aNdiumaUkv/RplCfznnnxqobhJuTE2oA+rS1bOq+9OhHwF9jgNXNVk+XX4d0toST5uGE6Z3OdmPBur8o5AlCf78PDSAwpFOw5HrgLqOEU4hTweC1/czX2VsvsHv22HRI6JMZgP8gGQii/p9iukqfaJvGdPciL5p1QRBUQIi8P8pNvEp1pVIpxYj7/LOUqb2DxFvgmp2v1IQ0Yu88SWsFk84+xAYHzfkLyS31Sqj5uLRBnJqx3fIlOihQ50GI72fwPMwo+OippvVAgMBAAGjPzA9MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgSwMB0GA1UdDgQWBBSkBM1TCX9kBgFsv2RmOzudMXa9njANBgkqhkiG9w0BAQsFAAOBgQA+2e4b+33zFmA+1ZQ46kWkfiB+fEeDyMwMLeYYyDS2d8mZhNZKdOw7dy4Ifz9Vqzp4aKuQ6j61c6k1UaQQL0tskqWVzslSFvs9NZyUAJLLdGUc5TT2MiLwiXQwd4UvH6bGeePdhvB4+ZbW7VMD7TE8hZhjhAL4F6yAP1EQvg3LDA==", //nolint:lll
|
||||||
RSAKey: "MIIEpAIBAAKCAQEAqzmLfyjotrjAxnr96V4PI9UjuCf+BFVgxe7yXCq9o62Zag/87gBcdltWFr8Lpjzujyh+D1PettWjXYrpmlJL/0aZQn85558aqG4SbkxNqAPq0tWzqvvToR8BfY4DVzVZPl1+HdLaEk+bhhOmdznZjwbq/KOQJQn+/Dw0gMKRTsOR64C6jhFOIU8Hgtf3M19lbL7B79th0SOiTGYD/IBkIov6fYrpKn2ibxnT3Ii+adUEQVECIvD/KTbxKdaVSKcWI+/yzlKm9g8Rb4Jqdr9SENGLvPElrBZPOPsQGB835C8kt9Uqo+bi0QZyasd3yJTooUOdBiO9n8DzMKPjoqab1QIDAQABAoIBAHgsekC0SKi+AOcNOZqJ3pxqophE0V7fQX2KWGXhxZnUZMFxGTc936deMYzjZ1y0lUa6x8cgOUcfqHol3hDmw9oWBckLHGv5Wi9umdb6DOLoZO62+FQATSdfaJ9jheq2Ub2YxsRN0apaXzB6KDKz0oM0+sZ4Udn9Kw6DfuIELRIWwEx4w0v3gKW7YLC4Jkc4AwLkPK03xEA/qImfkCmaMPLhrgVQt+IFfP8bXzL7CCC04rNU/IS8pyjex+iUolnQZlbXntF7Bm4V2mz0827ZVqrgAb/hEQRlsTW3rRkVh+rrdoUE7BCZRTFmRCbLoShjN6XuSf4sAus8ch4UEN12gN0CgYEA4o/tSvij1iPaXLmt4KOEuxqmSGB8MLKhFde8lBbNdrDgxiIH9bH7khKx15XRTX0qLDbs8b2/UJygZG0Aa1kIBqZTXTgeMAuxPRTesALJPdqQ/ROnbJcdFkI7gllrAG8VB0fH4wTRsRd0vWEB6YlCdE107u6LEsLAHxOj9Q5819cCgYEAwXjx9RkQ2qITBx5Ewib8YsltA0n3cmRomPicLlsnKV5DfvyCLpFIsZ1h3f9dUpfxRLwzp8wcoLiq9cCoOGdu1udw/yBTqmhaXWhUK/g77f9Ze2ZB1OEhuyKLYJ1vW/h/Z/a1aPCMxZqsDTPCePsuO8Cez5gqs8LjM3W7EyzRxDMCgYEAvhHrDFt975fSiLoJgo0MPIAGAnBXn+8sLwv3m/FpW+rWF8LTFK/Fku12H5wDpNOdvswxijkauIE+GiJMGMLvdcyx4WHECaC1h73reJRNykOEIZ0Md5BrCZJ1JEzp9Mo8RQhWTEFtvfkkqgApP4g0pSeaMx0StaGG1kt+4IbP+68CgYBrZdQKlquAck/Vt7u7eyDHRcE5/ilaWtqlb/xizz7h++3D5C/v4b5UumTFcyg+3RGVclPKZcfOgDSGzzeSd/hTW46iUTOgeOUQzQVMkzPRXdoyYgVRQtgSpY5xR3O1vjAbahwx8LZ0SvQPMBhYSDbV/Isr+fBacWjl/AipEEwxeQKBgQDdrAEnVlOFoCLw4sUjsPoxkLjhTAgI7CYk5NNxX67Rnj0tp+Y49+sGUhl5sCGfMKkLShiON5P2oxZa+B0aPtQjsdnsFPa1uaZkK4c++SS6AetzYRpVDLmLp7/1CulE0z3O0sBekpwiuaqLJ9ZccC81g4+2j8j6c50rIAct3hxIxw==", //nolint:lll
|
RSAKey: "MIIEpAIBAAKCAQEAqzmLfyjotrjAxnr96V4PI9UjuCf+BFVgxe7yXCq9o62Zag/87gBcdltWFr8Lpjzujyh+D1PettWjXYrpmlJL/0aZQn85558aqG4SbkxNqAPq0tWzqvvToR8BfY4DVzVZPl1+HdLaEk+bhhOmdznZjwbq/KOQJQn+/Dw0gMKRTsOR64C6jhFOIU8Hgtf3M19lbL7B79th0SOiTGYD/IBkIov6fYrpKn2ibxnT3Ii+adUEQVECIvD/KTbxKdaVSKcWI+/yzlKm9g8Rb4Jqdr9SENGLvPElrBZPOPsQGB835C8kt9Uqo+bi0QZyasd3yJTooUOdBiO9n8DzMKPjoqab1QIDAQABAoIBAHgsekC0SKi+AOcNOZqJ3pxqophE0V7fQX2KWGXhxZnUZMFxGTc936deMYzjZ1y0lUa6x8cgOUcfqHol3hDmw9oWBckLHGv5Wi9umdb6DOLoZO62+FQATSdfaJ9jheq2Ub2YxsRN0apaXzB6KDKz0oM0+sZ4Udn9Kw6DfuIELRIWwEx4w0v3gKW7YLC4Jkc4AwLkPK03xEA/qImfkCmaMPLhrgVQt+IFfP8bXzL7CCC04rNU/IS8pyjex+iUolnQZlbXntF7Bm4V2mz0827ZVqrgAb/hEQRlsTW3rRkVh+rrdoUE7BCZRTFmRCbLoShjN6XuSf4sAus8ch4UEN12gN0CgYEA4o/tSvij1iPaXLmt4KOEuxqmSGB8MLKhFde8lBbNdrDgxiIH9bH7khKx15XRTX0qLDbs8b2/UJygZG0Aa1kIBqZTXTgeMAuxPRTesALJPdqQ/ROnbJcdFkI7gllrAG8VB0fH4wTRsRd0vWEB6YlCdE107u6LEsLAHxOj9Q5819cCgYEAwXjx9RkQ2qITBx5Ewib8YsltA0n3cmRomPicLlsnKV5DfvyCLpFIsZ1h3f9dUpfxRLwzp8wcoLiq9cCoOGdu1udw/yBTqmhaXWhUK/g77f9Ze2ZB1OEhuyKLYJ1vW/h/Z/a1aPCMxZqsDTPCePsuO8Cez5gqs8LjM3W7EyzRxDMCgYEAvhHrDFt975fSiLoJgo0MPIAGAnBXn+8sLwv3m/FpW+rWF8LTFK/Fku12H5wDpNOdvswxijkauIE+GiJMGMLvdcyx4WHECaC1h73reJRNykOEIZ0Md5BrCZJ1JEzp9Mo8RQhWTEFtvfkkqgApP4g0pSeaMx0StaGG1kt+4IbP+68CgYBrZdQKlquAck/Vt7u7eyDHRcE5/ilaWtqlb/xizz7h++3D5C/v4b5UumTFcyg+3RGVclPKZcfOgDSGzzeSd/hTW46iUTOgeOUQzQVMkzPRXdoyYgVRQtgSpY5xR3O1vjAbahwx8LZ0SvQPMBhYSDbV/Isr+fBacWjl/AipEEwxeQKBgQDdrAEnVlOFoCLw4sUjsPoxkLjhTAgI7CYk5NNxX67Rnj0tp+Y49+sGUhl5sCGfMKkLShiON5P2oxZa+B0aPtQjsdnsFPa1uaZkK4c++SS6AetzYRpVDLmLp7/1CulE0z3O0sBekpwiuaqLJ9ZccC81g4+2j8j6c50rIAct3hxIxw==", //nolint:lll
|
||||||
TLSAuth: "48d9999bd71095b10649c7cb471c1051b1afdece597cea06909b99303a18c67401597b12c04a787e98cdb619ee960d90a0165529dc650f3a5c6fbe77c91c137dcf55d863fcbe314df5f0b45dbe974d9bde33ef5b4803c3985531c6c23ca6906d6cd028efc8585d1b9e71003566bd7891b9cc9212bcba510109922eed87f5c8e66d8e59cbd82575261f02777372b2cd4ca5214c4a6513ff26dd568f574fd40d6cd450fc788160ff68434ce2bf6afb00e710a3198538f14c4d45d84ab42637872e778a6b35a124e700920879f1d003ba93dccdb953cdf32bea03f365760b0ed8002098d4ce20d045b45a83a8432cc737677aed27125592a7148d25c87fdbe0a3f6", //nolint:lll
|
TLSAuth: "48d9999bd71095b10649c7cb471c1051b1afdece597cea06909b99303a18c67401597b12c04a787e98cdb619ee960d90a0165529dc650f3a5c6fbe77c91c137dcf55d863fcbe314df5f0b45dbe974d9bde33ef5b4803c3985531c6c23ca6906d6cd028efc8585d1b9e71003566bd7891b9cc9212bcba510109922eed87f5c8e66d8e59cbd82575261f02777372b2cd4ca5214c4a6513ff26dd568f574fd40d6cd450fc788160ff68434ce2bf6afb00e710a3198538f14c4d45d84ab42637872e778a6b35a124e700920879f1d003ba93dccdb953cdf32bea03f365760b0ed8002098d4ce20d045b45a83a8432cc737677aed27125592a7148d25c87fdbe0a3f6", //nolint:lll
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
func (p *Provider) GetConnection(selection settings.ServerSelection, ipv6Supported bool) (
|
func (p *Provider) GetConnection(selection settings.ServerSelection, ipv6Supported bool) (
|
||||||
connection models.Connection, err error,
|
connection models.Connection, err error,
|
||||||
) {
|
) {
|
||||||
defaults := utils.NewConnectionDefaults(1194, 1194, 0) //nolint:mnd
|
defaults := utils.NewConnectionDefaults(0, 1194, 0) //nolint:mnd
|
||||||
return utils.GetConnection(p.Name(),
|
return utils.GetConnection(p.Name(),
|
||||||
p.storage, selection, defaults, ipv6Supported, p.randSource)
|
p.storage, selection, defaults, ipv6Supported, p.randSource)
|
||||||
}
|
}
|
||||||
|
|||||||
+1840
-2296
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user