mirror of
https://github.com/qdm12/gluetun.git
synced 2026-05-06 20:10:11 +02:00
chore(firewall): split apart iptables specific code in internal/firewall/iptables
This commit is contained in:
+1
-1
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
-1
@@ -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"
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
-1
@@ -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"
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user