diff --git a/Dockerfile b/Dockerfile index a8034216..c6361300 100644 --- a/Dockerfile +++ b/Dockerfile @@ -74,6 +74,7 @@ ENV VPNSP=pia \ UNBLOCK= \ DNS_UPDATE_PERIOD=24h \ # Firewall + FIREWALL=on \ EXTRA_SUBNETS= \ # Tinyproxy TINYPROXY=off \ diff --git a/README.md b/README.md index a7a48cf6..6121a2e2 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,7 @@ That one is important if you want to connect to the container from your LAN for | Variable | Default | Choices | Description | | --- | --- | --- | --- | +| `FIREWALL` | `on` | `on` or `off` | Turn on or off the container built-in firewall. You should use it for **debugging purposes** only. | | `EXTRA_SUBNETS` | | i.e. `192.168.1.0/24,192.168.10.121,10.0.0.5/28` | Comma separated subnets allowed in the container firewall | ### Shadowsocks diff --git a/cmd/gluetun/main.go b/cmd/gluetun/main.go index c72ddb61..76ca6861 100644 --- a/cmd/gluetun/main.go +++ b/cmd/gluetun/main.go @@ -94,6 +94,10 @@ func _main(background context.Context, args []string) int { fatalOnError(err) logger.Info(allSettings.String()) + if !allSettings.Firewall.Enabled { + firewallConf.Disable() + } + err = alpineConf.CreateUser("nonrootuser", allSettings.System.UID) fatalOnError(err) err = fileManager.SetOwnership("/etc/unbound", allSettings.System.UID, allSettings.System.GID) diff --git a/internal/firewall/firewall.go b/internal/firewall/firewall.go index 1f85f0a4..326d52f2 100644 --- a/internal/firewall/firewall.go +++ b/internal/firewall/firewall.go @@ -22,11 +22,13 @@ type Configurator interface { AllowInputTrafficOnPort(ctx context.Context, device models.VPNDevice, port uint16) error AllowAnyIncomingOnPort(ctx context.Context, port uint16) error RunUserPostRules(ctx context.Context, fileManager files.FileManager, filepath string) error + Disable() } type configurator struct { commander command.Commander logger logging.Logger + disabled bool } // NewConfigurator creates a new Configurator instance @@ -36,3 +38,7 @@ func NewConfigurator(logger logging.Logger) Configurator { logger: logger.WithPrefix("firewall configurator: "), } } + +func (c *configurator) Disable() { + c.disabled = true +} diff --git a/internal/firewall/iptables.go b/internal/firewall/iptables.go index 4b420dca..78e92afb 100644 --- a/internal/firewall/iptables.go +++ b/internal/firewall/iptables.go @@ -41,6 +41,9 @@ func (c *configurator) runIptablesInstruction(ctx context.Context, instruction s } func (c *configurator) Clear(ctx context.Context) error { + if c.disabled { + return nil + } c.logger.Info("clearing all rules") return c.runIptablesInstructions(ctx, []string{ "--flush", @@ -51,6 +54,9 @@ func (c *configurator) Clear(ctx context.Context) error { } func (c *configurator) AcceptAll(ctx context.Context) error { + if c.disabled { + return nil + } c.logger.Info("accepting all traffic") return c.runIptablesInstructions(ctx, []string{ "-P INPUT ACCEPT", @@ -60,6 +66,9 @@ func (c *configurator) AcceptAll(ctx context.Context) error { } func (c *configurator) BlockAll(ctx context.Context) error { + if c.disabled { + return nil + } c.logger.Info("blocking all traffic") return c.runIptablesInstructions(ctx, []string{ "-P INPUT DROP", @@ -70,6 +79,9 @@ func (c *configurator) BlockAll(ctx context.Context) error { } func (c *configurator) CreateGeneralRules(ctx context.Context) error { + if c.disabled { + return nil + } c.logger.Info("creating general rules") return c.runIptablesInstructions(ctx, []string{ "-A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT", @@ -80,6 +92,9 @@ func (c *configurator) CreateGeneralRules(ctx context.Context) error { } func (c *configurator) CreateVPNRules(ctx context.Context, dev models.VPNDevice, defaultInterface string, connections []models.OpenVPNConnection) error { + if c.disabled { + return nil + } for _, connection := range connections { c.logger.Info("allowing output traffic to VPN server %s through %s on port %s %d", connection.IP, defaultInterface, connection.Protocol, connection.Port) @@ -96,6 +111,9 @@ func (c *configurator) CreateVPNRules(ctx context.Context, dev models.VPNDevice, } func (c *configurator) CreateLocalSubnetsRules(ctx context.Context, subnet net.IPNet, extraSubnets []net.IPNet, defaultInterface string) error { + if c.disabled { + return nil + } subnetStr := subnet.String() c.logger.Info("accepting input and output traffic for %s", subnetStr) if err := c.runIptablesInstructions(ctx, []string{ @@ -123,6 +141,9 @@ func (c *configurator) CreateLocalSubnetsRules(ctx context.Context, subnet net.I // Used for port forwarding func (c *configurator) AllowInputTrafficOnPort(ctx context.Context, device models.VPNDevice, port uint16) error { + if c.disabled { + return nil + } c.logger.Info("accepting input traffic through %s on port %d", device, port) return c.runIptablesInstructions(ctx, []string{ fmt.Sprintf("-A INPUT -i %s -p tcp --dport %d -j ACCEPT", device, port), @@ -131,6 +152,9 @@ func (c *configurator) AllowInputTrafficOnPort(ctx context.Context, device model } func (c *configurator) AllowAnyIncomingOnPort(ctx context.Context, port uint16) error { + if c.disabled { + return nil + } c.logger.Info("accepting any input traffic on port %d", port) return c.runIptablesInstructions(ctx, []string{ fmt.Sprintf("-A INPUT -p tcp --dport %d -j ACCEPT", port), diff --git a/internal/params/firewall.go b/internal/params/firewall.go index 984bef3b..30684a76 100644 --- a/internal/params/firewall.go +++ b/internal/params/firewall.go @@ -4,8 +4,15 @@ import ( "fmt" "net" "strings" + + libparams "github.com/qdm12/golibs/params" ) +// GetFirewall obtains if the firewall should be enabled from the environment variable FIREWALL +func (r *reader) GetFirewall() (enabled bool, err error) { + return r.envParams.GetOnOff("FIREWALL", libparams.Default("on")) +} + // GetExtraSubnets obtains the CIDR subnets from the comma separated list of the // environment variable EXTRA_SUBNETS func (r *reader) GetExtraSubnets() (extraSubnets []net.IPNet, err error) { diff --git a/internal/params/params.go b/internal/params/params.go index d75c030b..a4b10514 100644 --- a/internal/params/params.go +++ b/internal/params/params.go @@ -37,6 +37,7 @@ type Reader interface { GetIPStatusFilepath() (filepath models.Filepath, err error) // Firewall getters + GetFirewall() (enabled bool, err error) GetExtraSubnets() (extraSubnets []net.IPNet, err error) // VPN getters diff --git a/internal/settings/firewall.go b/internal/settings/firewall.go index 5ea25d83..f44b7412 100644 --- a/internal/settings/firewall.go +++ b/internal/settings/firewall.go @@ -10,6 +10,7 @@ import ( // Firewall contains settings to customize the firewall operation type Firewall struct { AllowedSubnets []net.IPNet + Enabled bool } func (f *Firewall) String() string { @@ -17,6 +18,9 @@ func (f *Firewall) String() string { for i := range f.AllowedSubnets { allowedSubnets[i] = f.AllowedSubnets[i].String() } + if !f.Enabled { + return "Firewall settings: disabled" + } settingsList := []string{ "Firewall settings:", "Allowed subnets: " + strings.Join(allowedSubnets, ", "), @@ -30,5 +34,9 @@ func GetFirewallSettings(paramsReader params.Reader) (settings Firewall, err err if err != nil { return settings, err } + settings.Enabled, err = paramsReader.GetFirewall() + if err != nil { + return settings, err + } return settings, nil }