mirror of
https://github.com/qdm12/gluetun.git
synced 2026-07-05 10:09:51 +02:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eb0938ad81 | |||
| 4ac25b9dd1 | |||
| 4bcbd29fb9 | |||
| a8ee1d7a63 | |||
| c6c3a2bf1b | |||
| e7b25a0d5e | |||
| 11cd62f6b1 | |||
| ed26957a1a | |||
| 54b55c594f | |||
| ec24ffdfd8 | |||
| b9d49e0661 |
@@ -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
|
||||||
+5
-1
@@ -227,7 +227,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
firewallLogger.Patch(log.SetLevel(log.LevelDebug))
|
firewallLogger.Patch(log.SetLevel(log.LevelDebug))
|
||||||
}
|
}
|
||||||
firewallConf, err := firewall.NewConfig(ctx, firewallLogger, cmder,
|
firewallConf, err := firewall.NewConfig(ctx, firewallLogger, cmder,
|
||||||
netLinker, defaultRoutes, localNetworks)
|
defaultRoutes, localNetworks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -237,6 +237,10 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = netLinker.FlushConntrack()
|
||||||
|
if err != nil {
|
||||||
|
logger.Warnf("flushing conntrack failed: %s", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO run this in a loop or in openvpn to reload from file without restarting
|
// TODO run this in a loop or in openvpn to reload from file without restarting
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ go 1.25.0
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/ProtonMail/go-srp v0.0.7
|
github.com/ProtonMail/go-srp v0.0.7
|
||||||
github.com/breml/rootcerts v0.3.3
|
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/jsimonetti/rtnetlink v1.4.2
|
github.com/jsimonetti/rtnetlink v1.4.2
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ github.com/ProtonMail/go-srp v0.0.7 h1:Sos3Qk+th4tQR64vsxGIxYpN3rdnG9Wf9K4ZloC1J
|
|||||||
github.com/ProtonMail/go-srp v0.0.7/go.mod h1:giCp+7qRnMIcCvI6V6U3S1lDDXDQYx2ewJ6F/9wdlJk=
|
github.com/ProtonMail/go-srp v0.0.7/go.mod h1:giCp+7qRnMIcCvI6V6U3S1lDDXDQYx2ewJ6F/9wdlJk=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/breml/rootcerts v0.3.3 h1://GnaRtQ/9BY2+GtMk2wtWxVdCRysiaPr5/xBwl7NKw=
|
github.com/breml/rootcerts v0.3.4 h1:9i7WNl/ctd9OEAOaTfLy//Wrlfxq/tRQ7v4okYFN9Ys=
|
||||||
github.com/breml/rootcerts v0.3.3/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
|
github.com/breml/rootcerts v0.3.4/go.mod h1:S/PKh+4d1HUn4HQovEB8hPJZO6pUZYrIhmXBhsegfXw=
|
||||||
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -45,6 +45,12 @@ func (c *Config) enable(ctx context.Context) (err error) {
|
|||||||
return fmt.Errorf("saving firewall rules: %w", err)
|
return fmt.Errorf("saving firewall rules: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
c.restore(context.Background())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if err = c.impl.SetIPv4AllPolicies(ctx, "DROP"); err != nil {
|
if err = c.impl.SetIPv4AllPolicies(ctx, "DROP"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -53,12 +59,6 @@ func (c *Config) enable(ctx context.Context) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
c.restore(context.Background())
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Loopback traffic
|
// Loopback traffic
|
||||||
if err = c.impl.AcceptInputThroughInterface(ctx, "lo"); err != nil {
|
if err = c.impl.AcceptInputThroughInterface(ctx, "lo"); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -69,11 +69,6 @@ func (c *Config) enable(ctx context.Context) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.flushExistingConnections(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("flushing existing connections: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = c.impl.AcceptEstablishedRelatedTraffic(ctx); err != nil {
|
if err = c.impl.AcceptEstablishedRelatedTraffic(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import (
|
|||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
runner CmdRunner
|
runner CmdRunner
|
||||||
netlinker Netlinker
|
|
||||||
logger Logger
|
logger Logger
|
||||||
defaultRoutes []routing.DefaultRoute
|
defaultRoutes []routing.DefaultRoute
|
||||||
localNetworks []routing.LocalNetwork
|
localNetworks []routing.LocalNetwork
|
||||||
@@ -36,8 +35,8 @@ type Config struct {
|
|||||||
// NewConfig creates a new Config instance and returns an error
|
// NewConfig creates a new Config instance and returns an error
|
||||||
// if no iptables implementation is available.
|
// if no iptables implementation is available.
|
||||||
func NewConfig(ctx context.Context, logger Logger,
|
func NewConfig(ctx context.Context, logger Logger,
|
||||||
runner CmdRunner, netlinker Netlinker,
|
runner CmdRunner, defaultRoutes []routing.DefaultRoute,
|
||||||
defaultRoutes []routing.DefaultRoute, localNetworks []routing.LocalNetwork,
|
localNetworks []routing.LocalNetwork,
|
||||||
) (config *Config, err error) {
|
) (config *Config, err error) {
|
||||||
impl, err := iptables.New(ctx, runner, logger)
|
impl, err := iptables.New(ctx, runner, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -46,7 +45,6 @@ func NewConfig(ctx context.Context, logger Logger,
|
|||||||
|
|
||||||
return &Config{
|
return &Config{
|
||||||
runner: runner,
|
runner: runner,
|
||||||
netlinker: netlinker,
|
|
||||||
logger: logger,
|
logger: logger,
|
||||||
allowedInputPorts: make(map[uint16]map[string]struct{}),
|
allowedInputPorts: make(map[uint16]map[string]struct{}),
|
||||||
// Obtained from routing
|
// Obtained from routing
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
package firewall
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/qdm12/gluetun/internal/firewall/iptables"
|
|
||||||
"github.com/qdm12/gluetun/internal/netlink"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Config) flushExistingConnections(ctx context.Context) error {
|
|
||||||
tries := []struct {
|
|
||||||
name string
|
|
||||||
f func(ctx context.Context) error
|
|
||||||
}{
|
|
||||||
{name: "flushing conntrack", f: func(_ context.Context) error {
|
|
||||||
return c.netlinker.FlushConntrack()
|
|
||||||
}},
|
|
||||||
{name: "marking and filtering unmarked packets", f: c.impl.AcceptOutputPublicOnlyNewTraffic},
|
|
||||||
{name: "rejecting connections for one second", f: c.rejectOutputTrafficTemporarily},
|
|
||||||
{name: "dropping connections for one second", f: c.dropOutputTrafficTemporarily},
|
|
||||||
}
|
|
||||||
errs := make([]error, 0, len(tries))
|
|
||||||
for i, try := range tries {
|
|
||||||
if i > 0 {
|
|
||||||
c.logger.Debugf("falling back to %s because %s failed: %s", try.name, tries[i-1].name, errs[i-1])
|
|
||||||
}
|
|
||||||
err := try.f(ctx)
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
err = fmt.Errorf("%s: %w", try.name, err)
|
|
||||||
if !errors.Is(err, iptables.ErrKernelModuleMissing) && !errors.Is(err, netlink.ErrConntrackNetlinkNotSupported) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
return fmt.Errorf("all tries failed: %v", errs) //nolint:err113
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) rejectOutputTrafficTemporarily(ctx context.Context) error {
|
|
||||||
return setupThenRevert(ctx, c.impl.RejectOutputPublicTraffic)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) dropOutputTrafficTemporarily(ctx context.Context) error {
|
|
||||||
return setupThenRevert(ctx, c.impl.DropOutputPublicTraffic)
|
|
||||||
}
|
|
||||||
|
|
||||||
// setupThenRevert is a helper function to run a setup function that takes a remove boolean argument,
|
|
||||||
// and then run the same function with remove set to true after one second or when the context is canceled,
|
|
||||||
// whichever comes first.
|
|
||||||
func setupThenRevert(ctx context.Context, f func(ctx context.Context, remove bool) error) error {
|
|
||||||
remove := false
|
|
||||||
err := f(ctx, remove)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("setting up: %w", err)
|
|
||||||
}
|
|
||||||
timer := time.NewTimer(time.Second)
|
|
||||||
select {
|
|
||||||
case <-timer.C:
|
|
||||||
case <-ctx.Done():
|
|
||||||
timer.Stop()
|
|
||||||
}
|
|
||||||
remove = true
|
|
||||||
// Use [context.Background] to make sure this is removed, even if the context
|
|
||||||
// passed to this function is canceled.
|
|
||||||
err = f(context.Background(), remove)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("reverting: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -14,23 +14,15 @@ type CmdRunner interface {
|
|||||||
|
|
||||||
type Logger interface {
|
type Logger interface {
|
||||||
Debug(s string)
|
Debug(s string)
|
||||||
Debugf(format string, args ...any)
|
|
||||||
Info(s string)
|
Info(s string)
|
||||||
Warn(s string)
|
Warn(s string)
|
||||||
Error(s string)
|
Error(s string)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Netlinker interface {
|
|
||||||
FlushConntrack() error
|
|
||||||
}
|
|
||||||
|
|
||||||
type firewallImpl interface { //nolint:interfacebloat
|
type firewallImpl interface { //nolint:interfacebloat
|
||||||
SaveAndRestore(ctx context.Context) (restore func(context.Context), err error)
|
SaveAndRestore(ctx context.Context) (restore func(context.Context), err error)
|
||||||
AcceptOutputPublicOnlyNewTraffic(ctx context.Context) error
|
|
||||||
RejectOutputPublicTraffic(ctx context.Context, remove bool) error
|
|
||||||
DropOutputPublicTraffic(ctx context.Context, remove bool) error
|
|
||||||
AcceptInputThroughInterface(ctx context.Context, intf string) error
|
|
||||||
AcceptEstablishedRelatedTraffic(ctx context.Context) error
|
AcceptEstablishedRelatedTraffic(ctx context.Context) error
|
||||||
|
AcceptInputThroughInterface(ctx context.Context, intf string) error
|
||||||
AcceptInputToPort(ctx context.Context, intf string, port uint16, remove bool) error
|
AcceptInputToPort(ctx context.Context, intf string, port uint16, remove bool) error
|
||||||
AcceptInputToSubnet(ctx context.Context, intf string, subnet netip.Prefix) error
|
AcceptInputToSubnet(ctx context.Context, intf string, subnet netip.Prefix) error
|
||||||
AcceptIpv6MulticastOutput(ctx context.Context, intf string) error
|
AcceptIpv6MulticastOutput(ctx context.Context, intf string) error
|
||||||
|
|||||||
@@ -2,12 +2,9 @@ package iptables
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrKernelModuleMissing = errors.New("kernel module is missing for this operation")
|
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
runner CmdRunner
|
runner CmdRunner
|
||||||
logger Logger
|
logger Logger
|
||||||
|
|||||||
@@ -76,9 +76,6 @@ func (c *Config) runIP6tablesInstructionNoSave(ctx context.Context, instruction
|
|||||||
cmd := exec.CommandContext(ctx, c.ip6Tables, flags...) // #nosec G204
|
cmd := exec.CommandContext(ctx, c.ip6Tables, flags...) // #nosec G204
|
||||||
c.logger.Debug(cmd.String())
|
c.logger.Debug(cmd.String())
|
||||||
if output, err := c.runner.Run(cmd); err != nil {
|
if output, err := c.runner.Run(cmd); err != nil {
|
||||||
if strings.Contains(output, "missing kernel module") {
|
|
||||||
err = ErrKernelModuleMissing
|
|
||||||
}
|
|
||||||
return fmt.Errorf("command failed: \"%s %s\": %s: %w",
|
return fmt.Errorf("command failed: \"%s %s\": %s: %w",
|
||||||
c.ip6Tables, instruction, output, err)
|
c.ip6Tables, instruction, output, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,9 +92,6 @@ func (c *Config) runIptablesInstructionNoSave(ctx context.Context, instruction s
|
|||||||
cmd := exec.CommandContext(ctx, c.ipTables, flags...) // #nosec G204
|
cmd := exec.CommandContext(ctx, c.ipTables, flags...) // #nosec G204
|
||||||
c.logger.Debug(cmd.String())
|
c.logger.Debug(cmd.String())
|
||||||
if output, err := c.runner.Run(cmd); err != nil {
|
if output, err := c.runner.Run(cmd); err != nil {
|
||||||
if strings.Contains(output, "missing kernel module") {
|
|
||||||
err = ErrKernelModuleMissing
|
|
||||||
}
|
|
||||||
return fmt.Errorf("command failed: \"%s %s\": %s: %w",
|
return fmt.Errorf("command failed: \"%s %s\": %s: %w",
|
||||||
c.ipTables, instruction, output, err)
|
c.ipTables, instruction, output, err)
|
||||||
}
|
}
|
||||||
@@ -150,143 +147,10 @@ func (c *Config) AcceptEstablishedRelatedTraffic(ctx context.Context) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// AcceptOutputPublicOnlyNewTraffic adds rules to mark new output connections, and to accept
|
|
||||||
// established or related packets with this mark only. This effectively forces
|
|
||||||
// previously established or related traffic to be blocked.
|
|
||||||
// If remove is true, the rules are removed instead of appended.
|
|
||||||
// If the relevant kernel modules are not available, it returns an error indicating
|
|
||||||
// which kernel module is missing.
|
|
||||||
func (c *Config) AcceptOutputPublicOnlyNewTraffic(ctx context.Context) error {
|
|
||||||
ipv4Instructions, ipv6Instructions := makeCreatePublicIPChainInstructions()
|
|
||||||
appendToBoth := func(instruction string) {
|
|
||||||
ipv4Instructions = append(ipv4Instructions, instruction)
|
|
||||||
ipv6Instructions = append(ipv6Instructions, instruction)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark new connections with mark 0x567
|
|
||||||
appendToBoth("-A PUBLIC_ONLY -m conntrack --ctstate NEW -j CONNMARK --set-mark 0x567")
|
|
||||||
// Drop related/established connections that made it through; marked connections would
|
|
||||||
// be directly accepted by the first rule in the OUTPUT chain (see below)
|
|
||||||
appendToBoth("-A PUBLIC_ONLY -m conntrack --ctstate RELATED,ESTABLISHED -j DROP")
|
|
||||||
// Set the PUBLIC_ONLY chain as the second rule in the OUTPUT chain, so that it is evaluated
|
|
||||||
// after the accept rule below, for performance reasons.
|
|
||||||
appendToBoth("-I OUTPUT -j PUBLIC_ONLY")
|
|
||||||
appendToBoth("-I OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -m connmark --mark 0x567 -j ACCEPT")
|
|
||||||
|
|
||||||
c.iptablesMutex.Lock()
|
|
||||||
c.ip6tablesMutex.Lock()
|
|
||||||
defer c.iptablesMutex.Unlock()
|
|
||||||
defer c.ip6tablesMutex.Unlock()
|
|
||||||
|
|
||||||
restore, err := c.saveAndRestore(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = c.runIptablesInstructionsNoSave(ctx, ipv4Instructions)
|
|
||||||
if err != nil {
|
|
||||||
restore(ctx)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = c.runIP6tablesInstructionsNoSave(ctx, ipv6Instructions)
|
|
||||||
if err != nil {
|
|
||||||
restore(ctx)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) RejectOutputPublicTraffic(ctx context.Context, remove bool) error {
|
|
||||||
return c.targetOutputPublicTraffic(ctx, "REJECT", remove)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) DropOutputPublicTraffic(ctx context.Context, remove bool) error {
|
|
||||||
return c.targetOutputPublicTraffic(ctx, "DROP", remove)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) targetOutputPublicTraffic(ctx context.Context, target string, remove bool) error {
|
|
||||||
removeInstructions := []string{
|
|
||||||
"-D OUTPUT -j PUBLIC_ONLY",
|
|
||||||
"-F PUBLIC_ONLY",
|
|
||||||
"-X PUBLIC_ONLY",
|
|
||||||
}
|
|
||||||
if remove {
|
|
||||||
return c.runMixedIptablesInstructions(ctx, removeInstructions)
|
|
||||||
}
|
|
||||||
|
|
||||||
ipv4Instructions, ipv6Instructions := makeCreatePublicIPChainInstructions()
|
|
||||||
appendToBoth := func(instruction string) {
|
|
||||||
ipv4Instructions = append(ipv4Instructions, instruction)
|
|
||||||
ipv6Instructions = append(ipv6Instructions, instruction)
|
|
||||||
}
|
|
||||||
|
|
||||||
if target == "REJECT" {
|
|
||||||
// Block TCP by sending back TCP RST packets.
|
|
||||||
appendToBoth("-A PUBLIC_ONLY -p tcp -m conntrack --ctstate RELATED,ESTABLISHED " +
|
|
||||||
"-j REJECT --reject-with tcp-reset")
|
|
||||||
// Block UDP and ICMP, sending back ICMP port unreachable.
|
|
||||||
appendToBoth("-A PUBLIC_ONLY -m conntrack --ctstate RELATED,ESTABLISHED -j REJECT")
|
|
||||||
} else {
|
|
||||||
appendToBoth("-A PUBLIC_ONLY -m conntrack --ctstate RELATED,ESTABLISHED -j " + target)
|
|
||||||
}
|
|
||||||
appendToBoth("-I OUTPUT -j PUBLIC_ONLY")
|
|
||||||
|
|
||||||
err := c.runIptablesInstructions(ctx, ipv4Instructions)
|
|
||||||
if err != nil {
|
|
||||||
if strings.Contains(err.Error(), " support") {
|
|
||||||
return fmt.Errorf("%w: %w", ErrKernelModuleMissing, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = c.runIP6tablesInstructions(ctx, ipv6Instructions)
|
|
||||||
if err != nil {
|
|
||||||
_ = c.runIptablesInstructions(ctx, removeInstructions)
|
|
||||||
if strings.Contains(err.Error(), " support") {
|
|
||||||
return fmt.Errorf("%w: %w", ErrKernelModuleMissing, err)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeCreatePublicIPChainInstructions() (ipv4Instructions, ipv6Instructions []string) {
|
|
||||||
ipv4PrivatePrefixes := []netip.Prefix{
|
|
||||||
netip.MustParsePrefix("10.0.0.0/8"),
|
|
||||||
netip.MustParsePrefix("172.16.0.0/12"),
|
|
||||||
netip.MustParsePrefix("192.168.0.0/16"),
|
|
||||||
netip.MustParsePrefix("127.0.0.0/8"),
|
|
||||||
}
|
|
||||||
ipv6PrivatePrefixes := []netip.Prefix{
|
|
||||||
netip.MustParsePrefix("fc00::/7"),
|
|
||||||
netip.MustParsePrefix("fe80::/10"),
|
|
||||||
netip.MustParsePrefix("::1/128"),
|
|
||||||
}
|
|
||||||
|
|
||||||
ipv4Instructions = append(ipv4Instructions, "-N PUBLIC_ONLY")
|
|
||||||
ipv6Instructions = append(ipv6Instructions, "-N PUBLIC_ONLY")
|
|
||||||
|
|
||||||
for _, prefix := range ipv4PrivatePrefixes {
|
|
||||||
ipv4Instructions = append(ipv4Instructions, fmt.Sprintf(
|
|
||||||
"-A PUBLIC_ONLY -d %s -j RETURN", prefix))
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, prefix := range ipv6PrivatePrefixes {
|
|
||||||
ipv6Instructions = append(ipv6Instructions, fmt.Sprintf(
|
|
||||||
"-A PUBLIC_ONLY -d %s -j RETURN", prefix))
|
|
||||||
}
|
|
||||||
|
|
||||||
return ipv4Instructions, ipv6Instructions
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) AcceptOutputTrafficToVPN(ctx context.Context,
|
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)
|
||||||
@@ -470,11 +334,11 @@ func (c *Config) RunUserPostRules(ctx context.Context, filepath string) error {
|
|||||||
|
|
||||||
switch {
|
switch {
|
||||||
case ipv4:
|
case ipv4:
|
||||||
err = c.runIptablesInstruction(ctx, rule)
|
err = c.runIptablesInstructionNoSave(ctx, rule)
|
||||||
case c.ip6Tables == "":
|
case c.ip6Tables == "":
|
||||||
err = fmt.Errorf("running user ip6tables rule: %w", ErrNeedIP6Tables)
|
err = fmt.Errorf("running user ip6tables rule: %w", ErrNeedIP6Tables)
|
||||||
default: // ipv6
|
default: // ipv6
|
||||||
err = c.runIP6tablesInstruction(ctx, rule)
|
err = c.runIP6tablesInstructionNoSave(ctx, rule)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
restore(ctx)
|
restore(ctx)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ func (c *Config) runMixedIptablesInstruction(ctx context.Context, instruction st
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = c.runIptablesInstructionNoSave(ctx, instruction)
|
err = c.runMixedIptablesInstructionNoSave(ctx, instruction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
restore(ctx)
|
restore(ctx)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,9 +33,6 @@ type chainRule struct {
|
|||||||
ctstate []string // for example ["RELATED","ESTABLISHED"]. Can be empty.
|
ctstate []string // for example ["RELATED","ESTABLISHED"]. Can be empty.
|
||||||
tcpFlags tcpFlags
|
tcpFlags tcpFlags
|
||||||
mark mark
|
mark mark
|
||||||
connMark mark
|
|
||||||
setMark uint
|
|
||||||
rejectWith string // for example "tcp-reset", only used for REJECT targets
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type mark struct {
|
type mark struct {
|
||||||
@@ -222,6 +219,10 @@ func parseChainRuleField(fieldIndex int, field string, rule *chainRule) (err err
|
|||||||
return fmt.Errorf("parsing bytes: %w", err)
|
return fmt.Errorf("parsing bytes: %w", err)
|
||||||
}
|
}
|
||||||
case targetIndex:
|
case targetIndex:
|
||||||
|
err = checkTarget(field)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("checking target: %w", err)
|
||||||
|
}
|
||||||
rule.target = field
|
rule.target = field
|
||||||
case protocolIndex:
|
case protocolIndex:
|
||||||
rule.protocol, err = parseProtocol(field)
|
rule.protocol, err = parseProtocol(field)
|
||||||
@@ -292,33 +293,6 @@ func parseChainRuleOptionalFields(optionalFields []string, rule *chainRule) (err
|
|||||||
}
|
}
|
||||||
rule.mark = mark
|
rule.mark = mark
|
||||||
i += consumed
|
i += consumed
|
||||||
case "reject-with":
|
|
||||||
i++
|
|
||||||
rule.rejectWith = optionalFields[i] // for example "tcp-reset"
|
|
||||||
i++
|
|
||||||
case "connmark":
|
|
||||||
i++
|
|
||||||
connMark, consumed, err := parseMark(optionalFields[i:])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("parsing connmark: %w", err)
|
|
||||||
}
|
|
||||||
rule.connMark = connMark
|
|
||||||
i += consumed
|
|
||||||
case "CONNMARK":
|
|
||||||
i++
|
|
||||||
switch optionalFields[i] {
|
|
||||||
case "set":
|
|
||||||
i++
|
|
||||||
value, err := parseAny32bNumber(optionalFields[i])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("parsing CONNMARK set value: %w", err)
|
|
||||||
}
|
|
||||||
rule.setMark = value
|
|
||||||
i++
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("%w: unexpected %q after CONNMARK",
|
|
||||||
ErrChainRuleMalformed, optionalFields[i])
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("%w: unexpected optional field: %s",
|
return fmt.Errorf("%w: unexpected optional field: %s",
|
||||||
ErrChainRuleMalformed, optionalFields[i])
|
ErrChainRuleMalformed, optionalFields[i])
|
||||||
@@ -448,6 +422,8 @@ func parsePortsCSV(s string) (ports []uint16, err error) {
|
|||||||
return ports, nil
|
return ports, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errMarkValueMalformed = errors.New("mark value is malformed")
|
||||||
|
|
||||||
func parseMark(optionalFields []string) (m mark, consumed int, err error) {
|
func parseMark(optionalFields []string) (m mark, consumed int, err error) {
|
||||||
switch optionalFields[consumed] {
|
switch optionalFields[consumed] {
|
||||||
case "match":
|
case "match":
|
||||||
@@ -457,11 +433,13 @@ func parseMark(optionalFields []string) (m mark, consumed int, err error) {
|
|||||||
consumed++
|
consumed++
|
||||||
}
|
}
|
||||||
|
|
||||||
value, err := parseAny32bNumber(optionalFields[consumed])
|
const base = 0 // auto-detect
|
||||||
|
const bits = 32
|
||||||
|
value, err := strconv.ParseUint(optionalFields[consumed], base, bits)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return mark{}, 0, fmt.Errorf("value malformed: %w", err)
|
return mark{}, 0, fmt.Errorf("%w: %s", errMarkValueMalformed, optionalFields[consumed])
|
||||||
}
|
}
|
||||||
m.value = value
|
m.value = uint(value)
|
||||||
consumed++
|
consumed++
|
||||||
default:
|
default:
|
||||||
return mark{}, 0, fmt.Errorf("%w: unexpected mark mode field: %s",
|
return mark{}, 0, fmt.Errorf("%w: unexpected mark mode field: %s",
|
||||||
|
|||||||
@@ -9,19 +9,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type operation uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
opNone operation = iota
|
|
||||||
opAppend
|
|
||||||
opDelete
|
|
||||||
opInsert
|
|
||||||
opReplace
|
|
||||||
)
|
|
||||||
|
|
||||||
type iptablesInstruction struct {
|
type iptablesInstruction struct {
|
||||||
table string // defaults to "filter", and can be "nat" for example.
|
table string // defaults to "filter", and can be "nat" for example.
|
||||||
operation operation
|
append bool
|
||||||
chain string // for example INPUT, PREROUTING. Cannot be empty.
|
chain string // for example INPUT, PREROUTING. Cannot be empty.
|
||||||
target string // for example ACCEPT. Can be empty.
|
target string // for example ACCEPT. Can be empty.
|
||||||
protocol string // "tcp" or "udp" or "" for all protocols.
|
protocol string // "tcp" or "udp" or "" for all protocols.
|
||||||
@@ -35,9 +25,6 @@ type iptablesInstruction struct {
|
|||||||
ctstate []string // if empty, there is no ctstate
|
ctstate []string // if empty, there is no ctstate
|
||||||
tcpFlags tcpFlags
|
tcpFlags tcpFlags
|
||||||
mark mark
|
mark mark
|
||||||
connMark mark
|
|
||||||
setMark uint // only used for jump CONNMARK --set-mark
|
|
||||||
rejectWith string // only used for REJECT targets
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *iptablesInstruction) setDefaults() {
|
func (i *iptablesInstruction) setDefaults() {
|
||||||
@@ -78,12 +65,6 @@ func (i *iptablesInstruction) equalToRule(table, chain string, rule chainRule) (
|
|||||||
return false
|
return false
|
||||||
case i.mark != rule.mark:
|
case i.mark != rule.mark:
|
||||||
return false
|
return false
|
||||||
case i.connMark != rule.connMark:
|
|
||||||
return false
|
|
||||||
case i.setMark != rule.setMark:
|
|
||||||
return false
|
|
||||||
case i.rejectWith != rule.rejectWith:
|
|
||||||
return false
|
|
||||||
default:
|
default:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -132,20 +113,13 @@ func parseInstructionFlag(fields []string, instruction *iptablesInstruction) (co
|
|||||||
case "-t", "--table":
|
case "-t", "--table":
|
||||||
instruction.table = value
|
instruction.table = value
|
||||||
case "-D", "--delete":
|
case "-D", "--delete":
|
||||||
instruction.operation = opDelete
|
instruction.append = false
|
||||||
instruction.chain = value
|
instruction.chain = value
|
||||||
case "-A", "--append":
|
case "-A", "--append":
|
||||||
instruction.operation = opAppend
|
instruction.append = true
|
||||||
instruction.chain = value
|
|
||||||
case "-I", "--insert":
|
|
||||||
instruction.operation = opInsert
|
|
||||||
instruction.chain = value
|
instruction.chain = value
|
||||||
case "-j", "--jump":
|
case "-j", "--jump":
|
||||||
subConsumed, err := parseJumpFlag(fields[1:], instruction)
|
instruction.target = value
|
||||||
if err != nil {
|
|
||||||
return 0, fmt.Errorf("parsing jump flag: %w", err)
|
|
||||||
}
|
|
||||||
consumed += subConsumed
|
|
||||||
case "-p", "--protocol":
|
case "-p", "--protocol":
|
||||||
instruction.protocol = value
|
instruction.protocol = value
|
||||||
case "-m", "--match":
|
case "-m", "--match":
|
||||||
@@ -154,11 +128,13 @@ func parseInstructionFlag(fields []string, instruction *iptablesInstruction) (co
|
|||||||
return 0, fmt.Errorf("parsing match module: %w", err)
|
return 0, fmt.Errorf("parsing match module: %w", err)
|
||||||
}
|
}
|
||||||
case "--mark":
|
case "--mark":
|
||||||
n, err := parseAny32bNumber(value)
|
const base = 0 // auto-detect
|
||||||
|
const bits = 32
|
||||||
|
value, err := strconv.ParseUint(value, base, bits)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("parsing mark value %q: %w", value, err)
|
return 0, fmt.Errorf("parsing mark value %q: %w", fields[2], err)
|
||||||
}
|
}
|
||||||
instruction.mark.value = n
|
instruction.mark.value = uint(value)
|
||||||
case "-i", "--in-interface":
|
case "-i", "--in-interface":
|
||||||
instruction.inputInterface = value
|
instruction.inputInterface = value
|
||||||
case "-o", "--out-interface":
|
case "-o", "--out-interface":
|
||||||
@@ -196,8 +172,6 @@ func parseInstructionFlag(fields []string, instruction *iptablesInstruction) (co
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("parsing TCP flags: %w", err)
|
return 0, fmt.Errorf("parsing TCP flags: %w", err)
|
||||||
}
|
}
|
||||||
case "--reject-with":
|
|
||||||
instruction.rejectWith = value // for example "tcp-reset"
|
|
||||||
default:
|
default:
|
||||||
return 0, fmt.Errorf("%w: unknown key %q", ErrIptablesCommandMalformed, flag)
|
return 0, fmt.Errorf("%w: unknown key %q", ErrIptablesCommandMalformed, flag)
|
||||||
}
|
}
|
||||||
@@ -208,7 +182,7 @@ func preCheckInstructionFields(fields []string) (consumed int, err error) {
|
|||||||
flag := fields[0]
|
flag := fields[0]
|
||||||
// All flags use one value after the flag, except the following:
|
// All flags use one value after the flag, except the following:
|
||||||
switch flag {
|
switch flag {
|
||||||
case "--tcp-flags":
|
case "--tcp-flags": // -m can have 1 or 2 values
|
||||||
const expected = 3
|
const expected = 3
|
||||||
if len(fields) < expected {
|
if len(fields) < expected {
|
||||||
return 0, fmt.Errorf("%w: flag %q requires at least 2 values, but got %s",
|
return 0, fmt.Errorf("%w: flag %q requires at least 2 values, but got %s",
|
||||||
@@ -225,34 +199,6 @@ func preCheckInstructionFields(fields []string) (consumed int, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseJumpFlag(fields []string, instruction *iptablesInstruction) (consumed int, err error) {
|
|
||||||
instruction.target = fields[0]
|
|
||||||
// consumed in the caller already takes fields[0] into account
|
|
||||||
if instruction.target != "CONNMARK" {
|
|
||||||
return consumed, nil
|
|
||||||
}
|
|
||||||
// consumed already accounts for the "CONNMARK" value
|
|
||||||
const expectedFields = 3
|
|
||||||
if len(fields) < expectedFields {
|
|
||||||
return 0, fmt.Errorf("%w: jump CONNMARK requires at least two additional values",
|
|
||||||
ErrIptablesCommandMalformed)
|
|
||||||
}
|
|
||||||
switch fields[1] {
|
|
||||||
case "--set-mark":
|
|
||||||
n, err := parseAny32bNumber(fields[2])
|
|
||||||
if err != nil {
|
|
||||||
return 0, fmt.Errorf("parsing connmark mark value %q: %w", fields[2], err)
|
|
||||||
}
|
|
||||||
consumed++
|
|
||||||
instruction.setMark = n
|
|
||||||
default:
|
|
||||||
return consumed, fmt.Errorf("%w: unsupported jump CONNMARK with value: %s",
|
|
||||||
ErrIptablesCommandMalformed, fields[1])
|
|
||||||
}
|
|
||||||
consumed++
|
|
||||||
return consumed, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseIPPrefix(value string) (prefix netip.Prefix, err error) {
|
func parseIPPrefix(value string) (prefix netip.Prefix, err error) {
|
||||||
slashIndex := strings.Index(value, "/")
|
slashIndex := strings.Index(value, "/")
|
||||||
if slashIndex >= 0 {
|
if slashIndex >= 0 {
|
||||||
@@ -275,13 +221,6 @@ func parsePort(value string) (port uint16, err error) {
|
|||||||
return uint16(portValue), nil
|
return uint16(portValue), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseAny32bNumber(mark string) (value uint, err error) {
|
|
||||||
const base = 0 // auto-detect
|
|
||||||
const bits = 32
|
|
||||||
n, err := strconv.ParseUint(mark, base, bits)
|
|
||||||
return uint(n), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseMatchModule(fields []string, instruction *iptablesInstruction) (
|
func parseMatchModule(fields []string, instruction *iptablesInstruction) (
|
||||||
consumed int, err error,
|
consumed int, err error,
|
||||||
) {
|
) {
|
||||||
@@ -295,30 +234,14 @@ func parseMatchModule(fields []string, instruction *iptablesInstruction) (
|
|||||||
// parse it twice.
|
// parse it twice.
|
||||||
case "mark":
|
case "mark":
|
||||||
consumed++
|
consumed++
|
||||||
switch {
|
switch fields[consumed] {
|
||||||
case len(fields[consumed:]) == 0 || strings.HasPrefix(fields[consumed], "-"):
|
case "!":
|
||||||
// end or another flag
|
|
||||||
return consumed, nil
|
|
||||||
case fields[consumed] == "!":
|
|
||||||
consumed++
|
consumed++
|
||||||
instruction.mark.invert = true
|
instruction.mark.invert = true
|
||||||
default:
|
default:
|
||||||
return consumed, fmt.Errorf("%w: unsupported match mark with value: %s",
|
return consumed, fmt.Errorf("%w: unsupported match mark with value: %s",
|
||||||
ErrIptablesCommandMalformed, fields[2])
|
ErrIptablesCommandMalformed, fields[2])
|
||||||
}
|
}
|
||||||
case "connmark":
|
|
||||||
consumed++
|
|
||||||
switch {
|
|
||||||
case len(fields[consumed:]) == 0 || strings.HasPrefix(fields[consumed], "-"):
|
|
||||||
// end or another flag
|
|
||||||
return consumed, nil
|
|
||||||
case fields[consumed] == "!":
|
|
||||||
consumed++
|
|
||||||
instruction.connMark.invert = true
|
|
||||||
default:
|
|
||||||
return consumed, fmt.Errorf("%w: unsupported match connmark with value: %s",
|
|
||||||
ErrIptablesCommandMalformed, fields[2])
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return 0, fmt.Errorf("%w: unknown match value: %s",
|
return 0, fmt.Errorf("%w: unknown match value: %s",
|
||||||
ErrIptablesCommandMalformed, fields[consumed])
|
ErrIptablesCommandMalformed, fields[consumed])
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ func Test_parseIptablesInstruction(t *testing.T) {
|
|||||||
instruction: iptablesInstruction{
|
instruction: iptablesInstruction{
|
||||||
table: "filter",
|
table: "filter",
|
||||||
chain: "INPUT",
|
chain: "INPUT",
|
||||||
operation: opAppend,
|
append: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"instruction_A": {
|
"instruction_A": {
|
||||||
@@ -43,7 +43,7 @@ func Test_parseIptablesInstruction(t *testing.T) {
|
|||||||
instruction: iptablesInstruction{
|
instruction: iptablesInstruction{
|
||||||
table: "filter",
|
table: "filter",
|
||||||
chain: "INPUT",
|
chain: "INPUT",
|
||||||
operation: opAppend,
|
append: true,
|
||||||
inputInterface: "tun0",
|
inputInterface: "tun0",
|
||||||
protocol: "tcp",
|
protocol: "tcp",
|
||||||
source: netip.MustParsePrefix("1.2.3.4/32"),
|
source: netip.MustParsePrefix("1.2.3.4/32"),
|
||||||
@@ -57,7 +57,7 @@ func Test_parseIptablesInstruction(t *testing.T) {
|
|||||||
instruction: iptablesInstruction{
|
instruction: iptablesInstruction{
|
||||||
table: "nat",
|
table: "nat",
|
||||||
chain: "PREROUTING",
|
chain: "PREROUTING",
|
||||||
operation: opDelete,
|
append: false,
|
||||||
inputInterface: "tun0",
|
inputInterface: "tun0",
|
||||||
protocol: "tcp",
|
protocol: "tcp",
|
||||||
destinationPort: 43716,
|
destinationPort: 43716,
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ func parseTCPFlag(s string) (tcpFlag, error) {
|
|||||||
return 0, fmt.Errorf("%w: %s", errTCPFlagUnknown, s)
|
return 0, fmt.Errorf("%w: %s", errTCPFlagUnknown, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
var ErrMarkMatchModuleMissing = errors.New("libxt_mark.so module is missing")
|
var ErrMarkMatchModuleMissing = errors.New("kernel is missing the mark module libxt_mark.so")
|
||||||
|
|
||||||
// TempDropOutputTCPRST temporarily drops outgoing TCP RST packets to the specified address and port,
|
// TempDropOutputTCPRST temporarily drops outgoing TCP RST packets to the specified address and port,
|
||||||
// for any TCP packets not marked with the excludeMark given.
|
// for any TCP packets not marked with the excludeMark given.
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,8 +26,6 @@ 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)
|
||||||
@@ -37,7 +33,6 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +1,38 @@
|
|||||||
package netlink
|
package netlink
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/mdlayher/netlink"
|
"github.com/mdlayher/netlink"
|
||||||
"github.com/ti-mo/netfilter"
|
"github.com/ti-mo/netfilter"
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrConntrackNetlinkNotSupported = errors.New("nf_conntrack_netlink is not supported by the kernel")
|
|
||||||
|
|
||||||
func (n *NetLink) FlushConntrack() error {
|
func (n *NetLink) FlushConntrack() error {
|
||||||
conn, err := netfilter.Dial(nil)
|
conn, err := netfilter.Dial(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !n.conntrackNetlink {
|
|
||||||
err = fmt.Errorf("%w: %w", err, ErrConntrackNetlinkNotSupported)
|
|
||||||
}
|
|
||||||
return fmt.Errorf("dialing netfilter: %w", err)
|
return fmt.Errorf("dialing netfilter: %w", err)
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
const ipCtnlMsgCtDelete = netfilter.MessageType(2)
|
families := [...]netfilter.ProtoFamily{netfilter.ProtoIPv4, netfilter.ProtoIPv6}
|
||||||
header := netfilter.Header{
|
for _, family := range families {
|
||||||
|
const IPCtnlMsgCtDelete = 2
|
||||||
|
request, err := netfilter.MarshalNetlink(
|
||||||
|
netfilter.Header{
|
||||||
SubsystemID: netfilter.NFSubsysCTNetlink,
|
SubsystemID: netfilter.NFSubsysCTNetlink,
|
||||||
MessageType: ipCtnlMsgCtDelete,
|
MessageType: netfilter.MessageType(IPCtnlMsgCtDelete),
|
||||||
Family: unix.AF_UNSPEC,
|
Family: family,
|
||||||
Flags: netlink.Request | netlink.Acknowledge,
|
Flags: netlink.Request | netlink.Acknowledge,
|
||||||
}
|
},
|
||||||
request, err := netfilter.MarshalNetlink(header, nil)
|
nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("encoding netlink request: %w", err)
|
return fmt.Errorf("encoding netlink request: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = conn.Query(request)
|
_, err = conn.Query(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !n.conntrackNetlink {
|
|
||||||
err = fmt.Errorf("%w: %w", err, ErrConntrackNetlinkNotSupported)
|
|
||||||
}
|
|
||||||
return fmt.Errorf("querying netlink request: %w", err)
|
return fmt.Errorf("querying netlink request: %w", err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,6 @@
|
|||||||
|
|
||||||
package netlink
|
package netlink
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
var ErrConntrackNetlinkNotSupported = errors.New("error not implemented")
|
|
||||||
|
|
||||||
func (n *NetLink) FlushConntrack() error {
|
func (n *NetLink) FlushConntrack() error {
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,14 @@
|
|||||||
package netlink
|
package netlink
|
||||||
|
|
||||||
import (
|
import "github.com/qdm12/log"
|
||||||
"github.com/qdm12/gluetun/internal/mod"
|
|
||||||
"github.com/qdm12/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NetLink struct {
|
type NetLink struct {
|
||||||
debugLogger DebugLogger
|
debugLogger DebugLogger
|
||||||
|
|
||||||
// Fixed state
|
|
||||||
conntrackNetlink bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(debugLogger DebugLogger) *NetLink {
|
func New(debugLogger DebugLogger) *NetLink {
|
||||||
conntrackNetlink := mod.Probe("nf_conntrack_netlink") == nil
|
|
||||||
return &NetLink{
|
return &NetLink{
|
||||||
debugLogger: debugLogger,
|
debugLogger: debugLogger,
|
||||||
conntrackNetlink: conntrackNetlink,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ func PathMTUDiscover(ctx context.Context, icmpAddrs []netip.Addr, tcpAddrs []net
|
|||||||
}
|
}
|
||||||
mtu, err = tcp.PathMTUDiscover(ctx, tcpAddrs, minMTU, maxPossibleMTU, tryTimeout, fw, logger)
|
mtu, err = tcp.PathMTUDiscover(ctx, tcpAddrs, minMTU, maxPossibleMTU, tryTimeout, fw, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, iptables.ErrKernelModuleMissing) {
|
if errors.Is(err, iptables.ErrMarkMatchModuleMissing) {
|
||||||
logger.Debugf("aborting TCP path MTU discovery: %s", err)
|
logger.Debugf("aborting TCP path MTU discovery: %s", err)
|
||||||
if icmpSuccess {
|
if icmpSuccess {
|
||||||
return maxPossibleMTU, nil // only rely on ICMP PMTUD results
|
return maxPossibleMTU, nil // only rely on ICMP PMTUD results
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ func getFirewall(t *testing.T) *firewall.Config {
|
|||||||
noopLogger := &noopLogger{}
|
noopLogger := &noopLogger{}
|
||||||
cmder := command.New()
|
cmder := command.New()
|
||||||
var err error
|
var err error
|
||||||
testFirewall, err = firewall.NewConfig(t.Context(), noopLogger, cmder, nil, nil, nil)
|
testFirewall, err = firewall.NewConfig(t.Context(), noopLogger, cmder, nil, nil)
|
||||||
if errors.Is(err, iptables.ErrNotSupported) {
|
if errors.Is(err, iptables.ErrNotSupported) {
|
||||||
t.Skip("iptables not installed, skipping TCP PMTUD tests")
|
t.Skip("iptables not installed, skipping TCP PMTUD tests")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func findHighestMSSDestination(ctx context.Context, familyToFD map[int]fileDescr
|
|||||||
if result.err != nil {
|
if result.err != nil {
|
||||||
switch {
|
switch {
|
||||||
case err != nil: // error already occurred for another findMSS goroutine
|
case err != nil: // error already occurred for another findMSS goroutine
|
||||||
case errors.Is(result.err, iptables.ErrKernelModuleMissing):
|
case errors.Is(result.err, iptables.ErrMarkMatchModuleMissing):
|
||||||
err = fmt.Errorf("finding MSS for %s: %w", result.dst, result.err)
|
err = fmt.Errorf("finding MSS for %s: %w", result.dst, result.err)
|
||||||
case dst.Addr().Is6() && errors.Is(result.err, ip.ErrNetworkUnreachable):
|
case dst.Addr().Is6() && errors.Is(result.err, ip.ErrNetworkUnreachable):
|
||||||
// silently discard IPv6 network unreachable errors since they are common
|
// silently discard IPv6 network unreachable errors since they are common
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user