Compare commits

..

9 Commits

Author SHA1 Message Date
qdm12 eb0938ad81 [create-pull-request] automated change 2026-03-04 19:44:54 +00:00
Quentin McGaw 4ac25b9dd1 hotfix(ci): fix file changes detection in update servers workflow 2026-03-04 19:43:39 +00:00
Quentin McGaw 4bcbd29fb9 chore(ci): allow to specify provider to update servers data on dispatch 2026-03-04 19:24:53 +00:00
Dennis Nienhuis a8ee1d7a63 fix(expressvpn): add new CA3 certificate to fix TLS handshake failure (#3184) 2026-03-04 20:01:24 +01:00
Quentin McGaw c6c3a2bf1b fix(openvpn/extract): restrict custom openvpn config protocol to tcp or udp internally
- Fix #3179
- I believe specifying tcp4, tcp6 or tcp-client does not change anything versus tcp + remote ip address
- I believe specifying udp4 or udp6 does not change anything versus tcp + remote ip address
- Simplify firewall code to not account for tcp-client etc.
2026-03-04 18:58:33 +00:00
Quentin McGaw e7b25a0d5e chore(mod): simplify code and add more kernel config constants 2026-03-03 00:32:08 +00:00
shwoop 11cd62f6b1 feat(ci): periodic workflow to update the maintainers servers list with pull requests (#3010) 2026-03-03 01:32:05 +01:00
Quentin McGaw ed26957a1a fix(privado): allow additional OpenVPN ports 443, 8080 and 8443 for both tcp and udp 2026-03-01 11:59:03 +00:00
Quentin McGaw 54b55c594f fix(privado): allow OpenVPN TCP protocol 2026-03-01 11:58:16 +00:00
30 changed files with 2527 additions and 2507 deletions
+1 -1
View File
@@ -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 nftables RUN apk add wireguard-tools htop openssl tcpdump iptables
+95
View File
@@ -0,0 +1,95 @@
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
+2 -2
View File
@@ -7,12 +7,11 @@ 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.3-0.20250113171957-fbb4dce95f42 github.com/mdlayher/netlink v1.7.2
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
@@ -43,6 +42,7 @@ 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
+4 -6
View File
@@ -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/google/nftables v0.3.0 h1:bkyZ0cbpVeMHXOrtlFc8ISmfVqq5gPJukoYieyVmITg= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
github.com/google/nftables v0.3.0/go.mod h1:BCp9FsrbF1Fn/Yu6CLUc9GGZFw/+hsxfluNXXmxBfRM= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
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.3-0.20250113171957-fbb4dce95f42 h1:A1Cq6Ysb0GM0tpKMbdCXCIfBclan4oHk1Jb+Hrejirg= github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42/go.mod h1:BB4YCPDOzfy7FniQ/lxuYQ3dgmM2cZumHbK8RpTjN2o= github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
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,8 +99,6 @@ 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,7 +60,6 @@ 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",
@@ -75,8 +74,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.Nordvpn, providers.Giganews, providers.Ipvanish,
providers.Privado, providers.Purevpn, providers.Nordvpn, 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",
@@ -99,6 +98,9 @@ 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,9 +1,12 @@
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) {
@@ -21,3 +24,33 @@ 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)
}
+5 -1
View File
@@ -51,7 +51,11 @@ func (c *Config) enable(ctx context.Context) (err error) {
} }
}() }()
if err = c.impl.SetBaseChainsPolicy(ctx, "DROP"); err != nil { if err = c.impl.SetIPv4AllPolicies(ctx, "DROP"); err != nil {
return err
}
if err = c.impl.SetIPv6AllPolicies(ctx, "DROP"); err != nil {
return err return err
} }
+2 -1
View File
@@ -34,7 +34,8 @@ 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
SetBaseChainsPolicy(ctx context.Context, policy string) error SetIPv4AllPolicies(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)
-15
View File
@@ -3,8 +3,6 @@ package iptables
import ( import (
"context" "context"
"sync" "sync"
"github.com/qdm12/gluetun/internal/mod"
) )
type Config struct { type Config struct {
@@ -16,8 +14,6 @@ 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) {
@@ -31,21 +27,10 @@ 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
} }
+15
View File
@@ -81,3 +81,18 @@ 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,
})
}
+2 -6
View File
@@ -98,14 +98,13 @@ func (c *Config) runIptablesInstructionNoSave(ctx context.Context, instruction s
return nil return nil
} }
func (c *Config) SetBaseChainsPolicy(ctx context.Context, policy string) error { func (c *Config) SetIPv4AllPolicies(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.runMixedIptablesInstructions(ctx, []string{ return c.runIptablesInstructions(ctx, []string{
"--policy INPUT " + policy, "--policy INPUT " + policy,
"--policy OUTPUT " + policy, "--policy OUTPUT " + policy,
"--policy FORWARD " + policy, "--policy FORWARD " + policy,
@@ -152,9 +151,6 @@ 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)
+3 -1
View File
@@ -5,6 +5,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"net/netip" "net/netip"
"os"
) )
type tcpFlags struct { type tcpFlags struct {
@@ -73,7 +74,8 @@ 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,
) { ) {
if !c.nftables && !c.xtMark { _, err = os.Stat("/usr/lib/xtables/libxt_mark.so")
if err != nil && errors.Is(err, os.ErrNotExist) {
return nil, fmt.Errorf("%w", ErrMarkMatchModuleMissing) return nil, fmt.Errorf("%w", ErrMarkMatchModuleMissing)
} }
-99
View File
@@ -1,99 +0,0 @@
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()
}
-50
View File
@@ -1,50 +0,0 @@
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
}
-61
View File
@@ -1,61 +0,0 @@
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
}
-27
View File
@@ -1,27 +0,0 @@
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)
}
-38
View File
@@ -1,38 +0,0 @@
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
}
-22
View File
@@ -1,22 +0,0 @@
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,
}
}
-170
View File
@@ -1,170 +0,0 @@
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
}
-5
View File
@@ -1,5 +0,0 @@
package nftables
type Logger interface {
Warnf(format string, args ...any)
}
-78
View File
@@ -1,78 +0,0 @@
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
}
-12
View File
@@ -1,12 +0,0 @@
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
}
-33
View File
@@ -1,33 +0,0 @@
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)
}
+30 -7
View File
@@ -76,28 +76,51 @@ 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": {{"CONFIG_NETFILTER_XT_MATCH_CONNTRACK"}}, "xt_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_TARGET_MARK"}, {"CONFIG_NETFILTER_XT_MATCH_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"}},
@@ -118,7 +141,7 @@ func moduleNameToKernelFeatureGroups(moduleName string) (featureGroups [][]strin
"fuse": {{"CONFIG_FUSE_FS"}}, "fuse": {{"CONFIG_FUSE_FS"}},
} }
featureGroups, ok = moduleMap[strings.ToLower(moduleName)] featureGroups, ok = moduleMap[moduleName]
return featureGroups, ok return featureGroups, ok
} }
+4 -9
View File
@@ -10,9 +10,7 @@ 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 first checks if the modules directory modules.builtin // Otherwise, it then runs the classic [modProbe] behavior,
// 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 {
@@ -28,14 +26,11 @@ 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) err = modProbe(modulesPath, moduleName)
if err != nil { if err != nil {
err = modProbe(modulesPath, moduleName) err = checkProcConfig(moduleName)
if err != nil { if err != nil {
err = checkProcConfig(moduleName) return fmt.Errorf("checking /proc/config.gz: %w", err)
if err != nil {
return fmt.Errorf("checking /proc/config.gz: %w", err)
}
} }
} }
return nil return nil
+22 -15
View File
@@ -81,10 +81,7 @@ func extractDataFromLine(line string) (
return ip, 0, "", nil return ip, 0, "", nil
} }
var ( var errProtoLineFieldsCount = errors.New("proto line has not 2 fields as expected")
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)
@@ -92,13 +89,25 @@ func extractProto(line string) (protocol string, err error) {
return "", fmt.Errorf("%w: %s", errProtoLineFieldsCount, line) return "", fmt.Errorf("%w: %s", errProtoLineFieldsCount, line)
} }
switch fields[1] { return parseProto(fields[1])
case "tcp", "tcp4", "tcp6", "tcp-client", "udp", "udp4", "udp6": }
default:
return "", fmt.Errorf("%w: %s", errProtocolNotSupported, fields[1])
}
return fields[1], nil 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:
return "", fmt.Errorf("%w: %s", errProtocolNotSupported, field)
}
} }
var ( var (
@@ -136,11 +145,9 @@ func extractRemote(line string) (ip netip.Addr, port uint16,
} }
if n > 3 { //nolint:mnd if n > 3 { //nolint:mnd
switch fields[3] { protocol, err = parseProto(fields[3])
case "tcp", "udp": if err != nil {
protocol = fields[3] return netip.Addr{}, 0, "", fmt.Errorf("parsing protocol from remote line: %w", err)
default:
return netip.Addr{}, 0, "", fmt.Errorf("%w: %s", errProtocolNotSupported, fields[3])
} }
} }
+2 -2
View File
@@ -105,7 +105,7 @@ func Test_extractDataFromLine(t *testing.T) {
}, },
"tcp-client": { "tcp-client": {
line: "proto tcp-client", line: "proto tcp-client",
protocol: "tcp-client", protocol: constants.TCP,
}, },
"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("network protocol not supported: bad"), err: errors.New("parsing protocol from remote line: 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",
+4 -1
View File
@@ -18,7 +18,10 @@ 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{"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"}, //nolint:lll CAs: []string{
"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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
+1 -1
View File
@@ -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(0, 1194, 0) //nolint:mnd defaults := utils.NewConnectionDefaults(1194, 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)
} }
+2297 -1841
View File
File diff suppressed because it is too large Load Diff