chore(firewall): split apart iptables specific code in internal/firewall/iptables

This commit is contained in:
Quentin McGaw
2026-02-25 03:45:17 +00:00
parent 034f8f6331
commit d21953f62e
29 changed files with 209 additions and 103 deletions
+1 -1
View File
@@ -283,7 +283,7 @@ func _main(ctx context.Context, buildInfo models.BuildInformation,
err = printVersions(ctx, logger, []printVersionElement{
{name: "Alpine", getVersion: alpineConf.Version},
{name: "OpenVPN", getVersion: ovpnVersion},
{name: "IPtables", getVersion: firewallConf.Version},
{name: "Firewall", getVersion: firewallConf.Version},
})
if err != nil {
return err
+23 -23
View File
@@ -42,13 +42,13 @@ func (c *Config) SetEnabled(ctx context.Context, enabled bool) (err error) {
}
func (c *Config) disable(ctx context.Context) (err error) {
if err = c.clearAllRules(ctx); err != nil {
if err = c.impl.ClearAllRules(ctx); err != nil {
return fmt.Errorf("clearing all rules: %w", err)
}
if err = c.setIPv4AllPolicies(ctx, "ACCEPT"); err != nil {
if err = c.impl.SetIPv4AllPolicies(ctx, "ACCEPT"); err != nil {
return fmt.Errorf("setting ipv4 policies: %w", err)
}
if err = c.setIPv6AllPolicies(ctx, "ACCEPT"); err != nil {
if err = c.impl.SetIPv6AllPolicies(ctx, "ACCEPT"); err != nil {
return fmt.Errorf("setting ipv6 policies: %w", err)
}
@@ -72,33 +72,31 @@ func (c *Config) fallbackToDisabled(ctx context.Context) {
}
func (c *Config) enable(ctx context.Context) (err error) {
touched := false
if err = c.setIPv4AllPolicies(ctx, "DROP"); err != nil {
return err
}
touched = true
if err = c.setIPv6AllPolicies(ctx, "DROP"); err != nil {
if err = c.impl.SetIPv4AllPolicies(ctx, "DROP"); err != nil {
return err
}
const remove = false
if err = c.impl.SetIPv6AllPolicies(ctx, "DROP"); err != nil {
return err
}
defer func() {
if touched && err != nil {
if err != nil {
c.fallbackToDisabled(ctx)
}
}()
const remove = false
// Loopback traffic
if err = c.acceptInputThroughInterface(ctx, "lo", remove); err != nil {
if err = c.impl.AcceptInputThroughInterface(ctx, "lo", remove); err != nil {
return err
}
if err = c.acceptOutputThroughInterface(ctx, "lo", remove); err != nil {
if err = c.impl.AcceptOutputThroughInterface(ctx, "lo", remove); err != nil {
return err
}
if err = c.acceptEstablishedRelatedTraffic(ctx, remove); err != nil {
if err = c.impl.AcceptEstablishedRelatedTraffic(ctx, remove); err != nil {
return err
}
@@ -108,7 +106,9 @@ func (c *Config) enable(ctx context.Context) (err error) {
localInterfaces := make(map[string]struct{}, len(c.localNetworks))
for _, network := range c.localNetworks {
if err := c.acceptOutputFromIPToSubnet(ctx, network.InterfaceName, network.IP, network.IPNet, remove); err != nil {
err = c.impl.AcceptOutputFromIPToSubnet(ctx,
network.InterfaceName, network.IP, network.IPNet, remove)
if err != nil {
return err
}
@@ -117,7 +117,7 @@ func (c *Config) enable(ctx context.Context) (err error) {
continue
}
localInterfaces[network.InterfaceName] = struct{}{}
err = c.acceptIpv6MulticastOutput(ctx, network.InterfaceName, remove)
err = c.impl.AcceptIpv6MulticastOutput(ctx, network.InterfaceName, remove)
if err != nil {
return fmt.Errorf("accepting IPv6 multicast output: %w", err)
}
@@ -130,7 +130,7 @@ func (c *Config) enable(ctx context.Context) (err error) {
// Allows packets from any IP address to go through eth0 / local network
// to reach Gluetun.
for _, network := range c.localNetworks {
if err := c.acceptInputToSubnet(ctx, network.InterfaceName, network.IPNet, remove); err != nil {
if err := c.impl.AcceptInputToSubnet(ctx, network.InterfaceName, network.IPNet, remove); err != nil {
return err
}
}
@@ -144,7 +144,7 @@ func (c *Config) enable(ctx context.Context) (err error) {
return fmt.Errorf("redirecting ports: %w", err)
}
if err := c.runUserPostRules(ctx, c.customRulesPath, remove); err != nil {
if err := c.impl.RunUserPostRules(ctx, c.customRulesPath, remove); err != nil {
return fmt.Errorf("running user defined post firewall rules: %w", err)
}
@@ -164,7 +164,7 @@ func (c *Config) allowVPNIP(ctx context.Context) (err error) {
continue
}
interfacesSeen[defaultRoute.NetInterface] = struct{}{}
err = c.acceptOutputTrafficToVPN(ctx, defaultRoute.NetInterface, c.vpnConnection, remove)
err = c.impl.AcceptOutputTrafficToVPN(ctx, defaultRoute.NetInterface, c.vpnConnection, remove)
if err != nil {
return fmt.Errorf("accepting output traffic through VPN: %w", err)
}
@@ -186,7 +186,7 @@ func (c *Config) allowOutboundSubnets(ctx context.Context) (err error) {
firewallUpdated = true
const remove = false
err := c.acceptOutputFromIPToSubnet(ctx, defaultRoute.NetInterface,
err := c.impl.AcceptOutputFromIPToSubnet(ctx, defaultRoute.NetInterface,
defaultRoute.AssignedIP, subnet, remove)
if err != nil {
return err
@@ -204,7 +204,7 @@ func (c *Config) allowInputPorts(ctx context.Context) (err error) {
for port, netInterfaces := range c.allowedInputPorts {
for netInterface := range netInterfaces {
const remove = false
err = c.acceptInputToPort(ctx, netInterface, port, remove)
err = c.impl.AcceptInputToPort(ctx, netInterface, port, remove)
if err != nil {
return fmt.Errorf("accepting input port %d on interface %s: %w",
port, netInterface, err)
@@ -216,7 +216,7 @@ func (c *Config) allowInputPorts(ctx context.Context) (err error) {
func (c *Config) redirectPorts(ctx context.Context, remove bool) (err error) {
for _, portRedirection := range c.portRedirections {
err = c.redirectPort(ctx, portRedirection.interfaceName, portRedirection.sourcePort,
err = c.impl.RedirectPort(ctx, portRedirection.interfaceName, portRedirection.sourcePort,
portRedirection.destinationPort, remove)
if err != nil {
return err
+14 -21
View File
@@ -2,24 +2,23 @@ package firewall
import (
"context"
"fmt"
"net/netip"
"sync"
"github.com/qdm12/gluetun/internal/firewall/iptables"
"github.com/qdm12/gluetun/internal/models"
"github.com/qdm12/gluetun/internal/routing"
)
type Config struct {
runner CmdRunner
logger Logger
iptablesMutex sync.Mutex
ip6tablesMutex sync.Mutex
defaultRoutes []routing.DefaultRoute
localNetworks []routing.LocalNetwork
runner CmdRunner
logger Logger
defaultRoutes []routing.DefaultRoute
localNetworks []routing.LocalNetwork
// Fixed state
ipTables string
ip6Tables string
// Fixed
impl firewallImpl
customRulesPath string
// State
@@ -38,25 +37,19 @@ func NewConfig(ctx context.Context, logger Logger,
runner CmdRunner, defaultRoutes []routing.DefaultRoute,
localNetworks []routing.LocalNetwork,
) (config *Config, err error) {
iptables, err := checkIptablesSupport(ctx, runner, "iptables", "iptables-nft", "iptables-legacy")
impl, err := iptables.New(ctx, runner, logger)
if err != nil {
return nil, err
}
ip6tables, err := findIP6tablesSupported(ctx, runner)
if err != nil {
return nil, err
return nil, fmt.Errorf("creating iptables firewall: %w", err)
}
return &Config{
runner: runner,
logger: logger,
allowedInputPorts: make(map[uint16]map[string]struct{}),
ipTables: iptables,
ip6Tables: ip6tables,
customRulesPath: "/iptables/post-rules.txt",
// Obtained from routing
defaultRoutes: defaultRoutes,
localNetworks: localNetworks,
defaultRoutes: defaultRoutes,
localNetworks: localNetworks,
impl: impl,
customRulesPath: "/iptables/post-rules.txt",
}, nil
}
+29 -1
View File
@@ -1,6 +1,12 @@
package firewall
import "os/exec"
import (
"context"
"net/netip"
"os/exec"
"github.com/qdm12/gluetun/internal/models"
)
type CmdRunner interface {
Run(cmd *exec.Cmd) (output string, err error)
@@ -12,3 +18,25 @@ type Logger interface {
Warn(s string)
Error(s string)
}
type firewallImpl interface { //nolint:interfacebloat
AcceptEstablishedRelatedTraffic(ctx context.Context, remove bool) error
AcceptInputThroughInterface(ctx context.Context, intf string, remove bool) error
AcceptInputToPort(ctx context.Context, intf string, port uint16, remove bool) error
AcceptInputToSubnet(ctx context.Context, intf string, subnet netip.Prefix, remove bool) error
AcceptIpv6MulticastOutput(ctx context.Context, intf string, remove bool) error
AcceptOutputFromIPToSubnet(ctx context.Context, intf string, assignedIP netip.Addr,
subnet netip.Prefix, remove bool) error
AcceptOutputThroughInterface(ctx context.Context, intf string, remove bool) error
AcceptOutputTrafficToVPN(ctx context.Context, intf string,
connection models.Connection, remove bool) error
ClearAllRules(ctx context.Context) error
RedirectPort(ctx context.Context, intf string, sourcePort,
destinationPort uint16, remove bool) error
RunUserPostRules(ctx context.Context, customRulesPath string, remove bool) 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) (
revert func(ctx context.Context) error, err error)
Version(ctx context.Context) (version string, err error)
}
@@ -1,4 +1,4 @@
package firewall
package iptables
import (
"fmt"
@@ -1,4 +1,4 @@
package firewall
package iptables
import (
"context"
@@ -1,4 +1,4 @@
package firewall
package iptables
import (
"context"
+36
View File
@@ -0,0 +1,36 @@
package iptables
import (
"context"
"sync"
)
type Config struct {
runner CmdRunner
logger Logger
iptablesMutex sync.Mutex
ip6tablesMutex sync.Mutex
// Fixed state
ipTables string
ip6Tables string
}
func New(ctx context.Context, runner CmdRunner, logger Logger) (*Config, error) {
iptables, err := checkIptablesSupport(ctx, runner, "iptables", "iptables-nft", "iptables-legacy")
if err != nil {
return nil, err
}
ip6tables, err := findIP6tablesSupported(ctx, runner)
if err != nil {
return nil, err
}
return &Config{
runner: runner,
logger: logger,
ipTables: iptables,
ip6Tables: ip6tables,
}, nil
}
+14
View File
@@ -0,0 +1,14 @@
package iptables
import "os/exec"
type CmdRunner interface {
Run(cmd *exec.Cmd) (output string, err error)
}
type Logger interface {
Debug(s string)
Info(s string)
Warn(s string)
Error(s string)
}
@@ -1,4 +1,4 @@
package firewall
package iptables
import (
"context"
@@ -14,8 +14,8 @@ import (
func findIP6tablesSupported(ctx context.Context, runner CmdRunner) (
ip6tablesPath string, err error,
) {
ip6tablesPath, err = checkIptablesSupport(ctx, runner, "ip6tables", "ip6tables-nft", "ip6tables-legacy")
if errors.Is(err, ErrIPTablesNotSupported) {
ip6tablesPath, err = checkIptablesSupport(ctx, runner, "ip6tables", "ip6tables-legacy")
if errors.Is(err, ErrNotSupported) {
return "", nil
} else if err != nil {
return "", err
@@ -56,7 +56,7 @@ func (c *Config) runIP6tablesInstruction(ctx context.Context, instruction string
var ErrPolicyNotValid = errors.New("policy is not valid")
func (c *Config) setIPv6AllPolicies(ctx context.Context, policy string) error {
func (c *Config) SetIPv6AllPolicies(ctx context.Context, policy string) error {
switch policy {
case "ACCEPT", "DROP":
default:
@@ -1,4 +1,4 @@
package firewall
package iptables
import (
"context"
@@ -53,7 +53,7 @@ func (c *Config) Version(ctx context.Context) (string, error) {
if len(words) < minWords {
return "", fmt.Errorf("%w: %s", ErrIPTablesVersionTooShort, output)
}
return words[1], nil
return "iptables " + words[1], nil
}
func (c *Config) runIptablesInstructions(ctx context.Context, instructions []string) error {
@@ -84,7 +84,7 @@ func (c *Config) runIptablesInstruction(ctx context.Context, instruction string)
return nil
}
func (c *Config) clearAllRules(ctx context.Context) error {
func (c *Config) ClearAllRules(ctx context.Context) error {
tables := []string{"filter"}
for _, table := range tables {
return c.runMixedIptablesInstructions(ctx, []string{
@@ -95,7 +95,7 @@ func (c *Config) clearAllRules(ctx context.Context) error {
return nil
}
func (c *Config) setIPv4AllPolicies(ctx context.Context, policy string) error {
func (c *Config) SetIPv4AllPolicies(ctx context.Context, policy string) error {
switch policy {
case "ACCEPT", "DROP":
default:
@@ -108,13 +108,13 @@ func (c *Config) setIPv4AllPolicies(ctx context.Context, policy string) error {
})
}
func (c *Config) acceptInputThroughInterface(ctx context.Context, intf string, remove bool) error {
func (c *Config) AcceptInputThroughInterface(ctx context.Context, intf string, remove bool) error {
return c.runMixedIptablesInstruction(ctx, fmt.Sprintf(
"%s INPUT -i %s -j ACCEPT", appendOrDelete(remove), intf,
))
}
func (c *Config) acceptInputToSubnet(ctx context.Context, intf string,
func (c *Config) AcceptInputToSubnet(ctx context.Context, intf string,
destination netip.Prefix, remove bool,
) error {
interfaceFlag := "-i " + intf
@@ -134,20 +134,20 @@ func (c *Config) acceptInputToSubnet(ctx context.Context, intf string,
return c.runIP6tablesInstruction(ctx, instruction)
}
func (c *Config) acceptOutputThroughInterface(ctx context.Context, intf string, remove bool) error {
func (c *Config) AcceptOutputThroughInterface(ctx context.Context, intf string, remove bool) error {
return c.runMixedIptablesInstruction(ctx, fmt.Sprintf(
"%s OUTPUT -o %s -j ACCEPT", appendOrDelete(remove), intf,
))
}
func (c *Config) acceptEstablishedRelatedTraffic(ctx context.Context, remove bool) error {
func (c *Config) AcceptEstablishedRelatedTraffic(ctx context.Context, remove bool) error {
return c.runMixedIptablesInstructions(ctx, []string{
fmt.Sprintf("%s OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT", appendOrDelete(remove)),
fmt.Sprintf("%s INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT", appendOrDelete(remove)),
})
}
func (c *Config) acceptOutputTrafficToVPN(ctx context.Context,
func (c *Config) AcceptOutputTrafficToVPN(ctx context.Context,
defaultInterface string, connection models.Connection, remove bool,
) error {
protocol := connection.Protocol
@@ -165,8 +165,11 @@ func (c *Config) acceptOutputTrafficToVPN(ctx context.Context,
return c.runIP6tablesInstruction(ctx, instruction)
}
// AcceptOutputFromIPToSubnet accepts outgoing traffic from sourceIP to destinationSubnet
// on the interface intf. If intf is empty, it is set to "*" which means all interfaces.
// If remove is true, the rule is removed instead of added.
// Thanks to @npawelek.
func (c *Config) acceptOutputFromIPToSubnet(ctx context.Context,
func (c *Config) AcceptOutputFromIPToSubnet(ctx context.Context,
intf string, sourceIP netip.Addr, destinationSubnet netip.Prefix, remove bool,
) error {
doIPv4 := sourceIP.Is4() && destinationSubnet.Addr().Is4()
@@ -187,8 +190,11 @@ func (c *Config) acceptOutputFromIPToSubnet(ctx context.Context,
return c.runIP6tablesInstruction(ctx, instruction)
}
// NDP uses multicast address (theres no broadcast in IPv6 like ARP uses in IPv4).
func (c *Config) acceptIpv6MulticastOutput(ctx context.Context,
// AcceptIpv6MulticastOutput accepts outgoing traffic to the IPv6 multicast address
// ff02::1:ff00:0/104, which is used for NDP (Neighbor Discovery Protocol) to resolve
// IPv6 addresses to MAC addresses. If intf is empty, it is set to "*" which means
// all interfaces. If remove is true, the rule is removed instead of added.
func (c *Config) AcceptIpv6MulticastOutput(ctx context.Context,
intf string, remove bool,
) error {
interfaceFlag := "-o " + intf
@@ -200,8 +206,11 @@ func (c *Config) acceptIpv6MulticastOutput(ctx context.Context,
return c.runIP6tablesInstruction(ctx, instruction)
}
// Used for port forwarding, with intf set to tun.
func (c *Config) acceptInputToPort(ctx context.Context, intf string, port uint16, remove bool) error {
// AcceptInputToPort accepts incoming traffic on the specified port, for both TCP and UDP
// protocols, on the interface intf. If intf is empty, it is set to "*" which means all interfaces.
// If remove is true, the rule is removed instead of added. This is used for port forwarding, with
// intf set to the VPN tunnel interface.
func (c *Config) AcceptInputToPort(ctx context.Context, intf string, port uint16, remove bool) error {
interfaceFlag := "-i " + intf
if intf == "*" { // all interfaces
interfaceFlag = ""
@@ -212,8 +221,12 @@ func (c *Config) acceptInputToPort(ctx context.Context, intf string, port uint16
})
}
// Used for VPN server side port forwarding, with intf set to the VPN tunnel interface.
func (c *Config) redirectPort(ctx context.Context, intf string,
// RedirectPort redirects incoming traffic on the specified source port to the
// specified destination port, for both TCP and UDP protocols, on the interface intf.
// If intf is empty, it is set to "*" which means all interfaces. If remove is true,
// the redirection is removed instead of added. This is used for VPN server side
// port forwarding, with intf set to the VPN tunnel interface.
func (c *Config) RedirectPort(ctx context.Context, intf string,
sourcePort, destinationPort uint16, remove bool,
) (err error) {
interfaceFlag := "-i " + intf
@@ -260,7 +273,7 @@ func (c *Config) redirectPort(ctx context.Context, intf string,
return nil
}
func (c *Config) runUserPostRules(ctx context.Context, filepath string, remove bool) error {
func (c *Config) RunUserPostRules(ctx context.Context, filepath string, remove bool) error {
file, err := os.OpenFile(filepath, os.O_RDONLY, 0)
if os.IsNotExist(err) {
return nil
@@ -1,4 +1,4 @@
package firewall
package iptables
import (
"context"
@@ -1,4 +1,4 @@
package firewall
package iptables
import (
"errors"
@@ -1,4 +1,4 @@
package firewall
package iptables
import (
"net/netip"
@@ -1,3 +1,3 @@
package firewall
package iptables
//go:generate mockgen -destination=mocks_test.go -package $GOPACKAGE . CmdRunner,Logger
@@ -1,8 +1,8 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/qdm12/gluetun/internal/firewall (interfaces: CmdRunner,Logger)
// Source: github.com/qdm12/gluetun/internal/firewall/iptables (interfaces: CmdRunner,Logger)
// Package firewall is a generated GoMock package.
package firewall
// Package iptables is a generated GoMock package.
package iptables
import (
exec "os/exec"
@@ -1,4 +1,4 @@
package firewall
package iptables
import (
"errors"
@@ -1,4 +1,4 @@
package firewall
package iptables
import (
"net/netip"
@@ -1,4 +1,4 @@
package firewall
package iptables
import (
"context"
@@ -11,10 +11,10 @@ import (
)
var (
ErrNetAdminMissing = errors.New("NET_ADMIN capability is missing")
ErrTestRuleCleanup = errors.New("failed cleaning up test rule")
ErrInputPolicyNotFound = errors.New("input policy not found")
ErrIPTablesNotSupported = errors.New("no iptables supported found")
ErrNetAdminMissing = errors.New("NET_ADMIN capability is missing")
ErrTestRuleCleanup = errors.New("failed cleaning up test rule")
ErrInputPolicyNotFound = errors.New("input policy not found")
ErrNotSupported = errors.New("no iptables supported found")
)
func checkIptablesSupport(ctx context.Context, runner CmdRunner,
@@ -57,7 +57,7 @@ func checkIptablesSupport(ctx context.Context, runner CmdRunner,
}
return "", fmt.Errorf("%w: errors encountered are: %s",
ErrIPTablesNotSupported, strings.Join(allUnsupportedMessages, "; "))
ErrNotSupported, strings.Join(allUnsupportedMessages, "; "))
}
func testIptablesPath(ctx context.Context, path string,
@@ -1,4 +1,4 @@
package firewall
package iptables
import (
"context"
@@ -101,7 +101,7 @@ func Test_checkIptablesSupport(t *testing.T) {
return runner
},
iptablesPathsToTry: []string{"path1", "path2"},
errSentinel: ErrIPTablesNotSupported,
errSentinel: ErrNotSupported,
errMessage: "no iptables supported found: " +
"errors encountered are: " +
"path1: output 1 (exit code 4); " +
@@ -1,4 +1,4 @@
package firewall
package iptables
import (
"context"
+2 -2
View File
@@ -48,7 +48,7 @@ func (c *Config) removeOutboundSubnets(ctx context.Context, subnets []netip.Pref
}
firewallUpdated = true
err := c.acceptOutputFromIPToSubnet(ctx, defaultRoute.NetInterface,
err := c.impl.AcceptOutputFromIPToSubnet(ctx, defaultRoute.NetInterface,
defaultRoute.AssignedIP, subNet, remove)
if err != nil {
c.logger.Error("cannot remove outdated outbound subnet: " + err.Error())
@@ -77,7 +77,7 @@ func (c *Config) addOutboundSubnets(ctx context.Context, subnets []netip.Prefix)
}
firewallUpdated = true
err := c.acceptOutputFromIPToSubnet(ctx, defaultRoute.NetInterface,
err := c.impl.AcceptOutputFromIPToSubnet(ctx, defaultRoute.NetInterface,
defaultRoute.AssignedIP, subnet, remove)
if err != nil {
return err
+2 -2
View File
@@ -35,7 +35,7 @@ func (c *Config) SetAllowedPort(ctx context.Context, port uint16, intf string) (
c.logger.Info("setting allowed input port " + fmt.Sprint(port) + " through interface " + intf + "...")
const remove = false
if err := c.acceptInputToPort(ctx, intf, port, remove); err != nil {
if err := c.impl.AcceptInputToPort(ctx, intf, port, remove); err != nil {
return fmt.Errorf("allowing input to port %d through interface %s: %w",
port, intf, err)
}
@@ -68,7 +68,7 @@ func (c *Config) RemoveAllowedPort(ctx context.Context, port uint16) (err error)
const remove = true
for netInterface := range interfacesSet {
err := c.acceptInputToPort(ctx, netInterface, port, remove)
err := c.impl.AcceptInputToPort(ctx, netInterface, port, remove)
if err != nil {
return fmt.Errorf("removing allowed port %d on interface %s: %w",
port, netInterface, err)
+2 -2
View File
@@ -50,7 +50,7 @@ func (c *Config) RedirectPort(ctx context.Context, intf string, sourcePort,
return nil
case conflict != nil:
const remove = true
err = c.redirectPort(ctx, conflict.interfaceName, conflict.sourcePort,
err = c.impl.RedirectPort(ctx, conflict.interfaceName, conflict.sourcePort,
conflict.destinationPort, remove)
if err != nil {
return fmt.Errorf("removing conflicting redirection: %w", err)
@@ -60,7 +60,7 @@ func (c *Config) RedirectPort(ctx context.Context, intf string, sourcePort,
}
const remove = false
err = c.redirectPort(ctx, intf, sourcePort, destinationPort, remove)
err = c.impl.RedirectPort(ctx, intf, sourcePort, destinationPort, remove)
if err != nil {
return fmt.Errorf("redirecting port: %w", err)
}
+4 -4
View File
@@ -28,7 +28,7 @@ func (c *Config) SetVPNConnection(ctx context.Context,
remove := true
if c.vpnConnection.IP.IsValid() {
for _, defaultRoute := range c.defaultRoutes {
if err := c.acceptOutputTrafficToVPN(ctx, defaultRoute.NetInterface, c.vpnConnection, remove); err != nil {
if err := c.impl.AcceptOutputTrafficToVPN(ctx, defaultRoute.NetInterface, c.vpnConnection, remove); err != nil {
c.logger.Error("cannot remove outdated VPN connection rule: " + err.Error())
}
}
@@ -36,7 +36,7 @@ func (c *Config) SetVPNConnection(ctx context.Context,
c.vpnConnection = models.Connection{}
if c.vpnIntf != "" {
if err = c.acceptOutputThroughInterface(ctx, c.vpnIntf, remove); err != nil {
if err = c.impl.AcceptOutputThroughInterface(ctx, c.vpnIntf, remove); err != nil {
c.logger.Error("cannot remove outdated VPN interface rule: " + err.Error())
}
}
@@ -45,13 +45,13 @@ func (c *Config) SetVPNConnection(ctx context.Context,
remove = false
for _, defaultRoute := range c.defaultRoutes {
if err := c.acceptOutputTrafficToVPN(ctx, defaultRoute.NetInterface, connection, remove); err != nil {
if err := c.impl.AcceptOutputTrafficToVPN(ctx, defaultRoute.NetInterface, connection, remove); err != nil {
return fmt.Errorf("allowing output traffic through VPN connection: %w", err)
}
}
c.vpnConnection = connection
if err = c.acceptOutputThroughInterface(ctx, vpnIntf, remove); err != nil {
if err = c.impl.AcceptOutputThroughInterface(ctx, vpnIntf, remove); err != nil {
return fmt.Errorf("accepting output traffic through interface %s: %w", vpnIntf, err)
}
c.vpnIntf = vpnIntf
+21
View File
@@ -0,0 +1,21 @@
package firewall
import (
"context"
"net/netip"
)
func (c *Config) Version(ctx context.Context) (version string, err error) {
return c.impl.Version(ctx)
}
// TempDropOutputTCPRST temporarily drops outgoing TCP RST packets to the specified address and port,
// for any TCP packets not marked with the excludeMark given.
// This is necessary for TCP path MTU discovery to work, as the kernel will try to terminate the connection
// by sending a TCP RST packet, although we want to handle the connection manually.
func (c *Config) TempDropOutputTCPRST(ctx context.Context,
src, dst netip.AddrPort, excludeMark int) (
revert func(ctx context.Context) error, err error,
) {
return c.impl.TempDropOutputTCPRST(ctx, src, dst, excludeMark)
}
+2 -2
View File
@@ -7,7 +7,7 @@ import (
"net/netip"
"time"
"github.com/qdm12/gluetun/internal/firewall"
"github.com/qdm12/gluetun/internal/firewall/iptables"
"github.com/qdm12/gluetun/internal/pmtud/constants"
"github.com/qdm12/gluetun/internal/pmtud/icmp"
"github.com/qdm12/gluetun/internal/pmtud/tcp"
@@ -71,7 +71,7 @@ func PathMTUDiscover(ctx context.Context, icmpAddrs []netip.Addr, tcpAddrs []net
}
mtu, err = tcp.PathMTUDiscover(ctx, tcpAddrs, minMTU, maxPossibleMTU, tryTimeout, fw, logger)
if err != nil {
if errors.Is(err, firewall.ErrMarkMatchModuleMissing) {
if errors.Is(err, iptables.ErrMarkMatchModuleMissing) {
logger.Debugf("aborting TCP path MTU discovery: %s", err)
if icmpSuccess {
return maxPossibleMTU, nil // only rely on ICMP PMTUD results
+2 -1
View File
@@ -8,6 +8,7 @@ import (
"github.com/qdm12/gluetun/internal/command"
"github.com/qdm12/gluetun/internal/firewall"
"github.com/qdm12/gluetun/internal/firewall/iptables"
"github.com/qdm12/gluetun/internal/netlink"
"github.com/qdm12/gluetun/internal/pmtud/constants"
"github.com/qdm12/gluetun/internal/routing"
@@ -35,7 +36,7 @@ func getFirewall(t *testing.T) *firewall.Config {
cmder := command.New()
var err error
testFirewall, err = firewall.NewConfig(t.Context(), noopLogger, cmder, nil, nil)
if errors.Is(err, firewall.ErrIPTablesNotSupported) {
if errors.Is(err, iptables.ErrNotSupported) {
t.Skip("iptables not installed, skipping TCP PMTUD tests")
}
require.NoError(t, err, "creating firewall config")
+2 -2
View File
@@ -7,7 +7,7 @@ import (
"net/netip"
"time"
"github.com/qdm12/gluetun/internal/firewall"
"github.com/qdm12/gluetun/internal/firewall/iptables"
"github.com/qdm12/gluetun/internal/pmtud/constants"
"github.com/qdm12/gluetun/internal/pmtud/ip"
)
@@ -43,7 +43,7 @@ func findHighestMSSDestination(ctx context.Context, familyToFD map[int]fileDescr
if result.err != nil {
switch {
case err != nil: // error already occurred for another findMSS goroutine
case errors.Is(result.err, firewall.ErrMarkMatchModuleMissing):
case errors.Is(result.err, iptables.ErrMarkMatchModuleMissing):
err = fmt.Errorf("finding MSS for %s: %w", result.dst, result.err)
case dst.Addr().Is6() && errors.Is(result.err, ip.ErrNetworkUnreachable):
// silently discard IPv6 network unreachable errors since they are common