Fix: only run ip6tables if it is supported by the Kernel (#431)

- Fix #430
This commit is contained in:
Quentin McGaw
2021-04-19 14:35:29 -04:00
committed by GitHub
parent 44d8cf9d4e
commit e0e56595c6
3 changed files with 33 additions and 4 deletions

View File

@@ -42,6 +42,9 @@ type configurator struct { //nolint:maligned
localIP net.IP localIP net.IP
networkInfoMutex sync.Mutex networkInfoMutex sync.Mutex
// Fixed state
ip6Tables bool
// State // State
enabled bool enabled bool
vpnConnection models.OpenVPNConnection vpnConnection models.OpenVPNConnection
@@ -52,12 +55,14 @@ type configurator struct { //nolint:maligned
// NewConfigurator creates a new Configurator instance. // NewConfigurator creates a new Configurator instance.
func NewConfigurator(logger logging.Logger, routing routing.Routing, openFile os.OpenFileFunc) Configurator { func NewConfigurator(logger logging.Logger, routing routing.Routing, openFile os.OpenFileFunc) Configurator {
commander := command.NewCommander()
return &configurator{ return &configurator{
commander: command.NewCommander(), commander: commander,
logger: logger.NewChild(logging.SetPrefix("firewall: ")), logger: logger.NewChild(logging.SetPrefix("firewall: ")),
routing: routing, routing: routing,
openFile: openFile, openFile: openFile,
allowedInputPorts: make(map[uint16]string), allowedInputPorts: make(map[uint16]string),
ip6Tables: ip6tablesSupported(context.Background(), commander),
} }
} }

View File

@@ -5,12 +5,22 @@ import (
"errors" "errors"
"fmt" "fmt"
"strings" "strings"
"github.com/qdm12/golibs/command"
) )
var ( var (
ErrIP6Tables = errors.New("failed ip6tables command") ErrIP6Tables = errors.New("failed ip6tables command")
ErrIP6NotSupported = errors.New("ip6tables not supported")
) )
func ip6tablesSupported(ctx context.Context, commander command.Commander) (supported bool) {
if _, err := commander.Run(ctx, "ip6tables", "-L"); err != nil {
return false
}
return true
}
func (c *configurator) runIP6tablesInstructions(ctx context.Context, instructions []string) error { func (c *configurator) runIP6tablesInstructions(ctx context.Context, instructions []string) error {
for _, instruction := range instructions { for _, instruction := range instructions {
if err := c.runIP6tablesInstruction(ctx, instruction); err != nil { if err := c.runIP6tablesInstruction(ctx, instruction); err != nil {
@@ -21,6 +31,9 @@ func (c *configurator) runIP6tablesInstructions(ctx context.Context, instruction
} }
func (c *configurator) runIP6tablesInstruction(ctx context.Context, instruction string) error { func (c *configurator) runIP6tablesInstruction(ctx context.Context, instruction string) error {
if !c.ip6Tables {
return nil
}
c.ip6tablesMutex.Lock() // only one ip6tables command at once c.ip6tablesMutex.Lock() // only one ip6tables command at once
defer c.ip6tablesMutex.Unlock() defer c.ip6tablesMutex.Unlock()
if c.debug { if c.debug {

View File

@@ -18,6 +18,7 @@ var (
ErrPolicyUnknown = errors.New("unknown policy") ErrPolicyUnknown = errors.New("unknown policy")
ErrClearRules = errors.New("cannot clear all rules") ErrClearRules = errors.New("cannot clear all rules")
ErrSetIPtablesPolicies = errors.New("cannot set iptables policies") ErrSetIPtablesPolicies = errors.New("cannot set iptables policies")
ErrNeedIP6Tables = errors.New("ip6tables is required, please upgrade your kernel to support it")
) )
func appendOrDelete(remove bool) string { func appendOrDelete(remove bool) string {
@@ -125,6 +126,9 @@ func (c *configurator) acceptInputToSubnet(ctx context.Context, intf string, des
if isIP4Subnet { if isIP4Subnet {
return c.runIptablesInstruction(ctx, instruction) return c.runIptablesInstruction(ctx, instruction)
} }
if !c.ip6Tables {
return fmt.Errorf("accept input to subnet %s: %w", destination, ErrNeedIP6Tables)
}
return c.runIP6tablesInstruction(ctx, instruction) return c.runIP6tablesInstruction(ctx, instruction)
} }
@@ -149,6 +153,8 @@ func (c *configurator) acceptOutputTrafficToVPN(ctx context.Context,
isIPv4 := connection.IP.To4() != nil isIPv4 := connection.IP.To4() != nil
if isIPv4 { if isIPv4 {
return c.runIptablesInstruction(ctx, instruction) return c.runIptablesInstruction(ctx, instruction)
} else if !c.ip6Tables {
return fmt.Errorf("accept output to VPN server: %w", ErrNeedIP6Tables)
} }
return c.runIP6tablesInstruction(ctx, instruction) return c.runIP6tablesInstruction(ctx, instruction)
} }
@@ -168,6 +174,8 @@ func (c *configurator) acceptOutputFromIPToSubnet(ctx context.Context,
if doIPv4 { if doIPv4 {
return c.runIptablesInstruction(ctx, instruction) return c.runIptablesInstruction(ctx, instruction)
} else if !c.ip6Tables {
return fmt.Errorf("accept output from %s to %s: %w", sourceIP, destinationSubnet, ErrNeedIP6Tables)
} }
return c.runIP6tablesInstruction(ctx, instruction) return c.runIP6tablesInstruction(ctx, instruction)
} }
@@ -228,9 +236,12 @@ func (c *configurator) runUserPostRules(ctx context.Context, filepath string, re
rule = flipRule(rule) rule = flipRule(rule)
} }
if ipv4 { switch {
case ipv4:
err = c.runIptablesInstruction(ctx, rule) err = c.runIptablesInstruction(ctx, rule)
} else { case !c.ip6Tables:
err = fmt.Errorf("cannot run user ip6tables rule: %w", ErrNeedIP6Tables)
default: // ipv6
err = c.runIP6tablesInstruction(ctx, rule) err = c.runIP6tablesInstruction(ctx, rule)
} }
if err != nil { if err != nil {