Repository: moby/moby
File: daemon/libnetwork/firewall_linux.go (Go)

Code before:
package libnetwork

import (
	"context"
	"errors"
	"fmt"
	"os"

	"github.com/containerd/log"
	"github.com/docker/docker/daemon/libnetwork/internal/nftables"
	"github.com/docker/docker/daemon/libnetwork/iptables"
)

const userChain = "DOCKER-USER"

func ValidateFirewallBackend(val string) error {
	switch val {
	case "", "iptables", "nftables":
		return nil
	}
	return fmt.Errorf(`firewall-backend %q is invalid, allowed values are "iptables" and "nftables"`, val)
}

func (c *Controller) selectFirewallBackend() error {
	// If explicitly configured to use iptables, don't consider nftables.
	if c.cfg.FirewallBackend == "iptables" {
		return nil
	}
	// If configured to use nftables, but it can't be initialised, return an error.
	if c.cfg.FirewallBackend == "nftables" {
		// Don't try to enable nftables if firewalld is running.
		if iptables.UsingFirewalld() {
			return errors.New("firewall-backend is set to nftables, but firewalld is running")
		}
		if err := nftables.Enable(); err != nil {
			return fmt.Errorf("firewall-backend is set to nftables: %v", err)
		}
		return nil
	}
	// Default to nftables if enabled by env-var.
	// (Used for integration tests that launch their own daemons in CI.)
	if os.Getenv("DOCKER_FIREWALL_BACKEND") == "nftables" {
		if iptables.UsingFirewalld() {
			return errors.New("firewall-backend is not set and DOCKER_FIREWALL_BACKEND=nftables, but firewalld is running")
		}
		if err := nftables.Enable(); err != nil {
			return fmt.Errorf("firewall-backend is not set and DOCKER_FIREWALL_BACKEND=nftables: %v", err)
		}

Review comment (suggestion):
_ideally_ (not a blocker) we'd be able to have this check when running `dockerd --validate` to validate the config, but not sure if we want to import the iptables code in that part, so probably fine to leave that.

Code after:
package libnetwork

import (
	"context"
	"errors"
	"fmt"

	"github.com/containerd/log"
	"github.com/docker/docker/daemon/libnetwork/internal/nftables"
	"github.com/docker/docker/daemon/libnetwork/iptables"
)

const userChain = "DOCKER-USER"

func (c *Controller) selectFirewallBackend() error {
	// If explicitly configured to use iptables, don't consider nftables.
	if c.cfg.FirewallBackend == "iptables" {
		return nil
	}
	// If configured to use nftables, but it can't be initialised, return an error.
	if c.cfg.FirewallBackend == "nftables" {
		// Don't try to enable nftables if firewalld is running.
		if iptables.UsingFirewalld() {
			return errors.New("firewall-backend is set to nftables, but firewalld is running")
		}
		if err := nftables.Enable(); err != nil {
			return fmt.Errorf("firewall-backend is set to nftables: %v", err)
		}
		return nil
	}
	return nil
}

// Sets up the DOCKER-USER chain for each iptables version (IPv4, IPv6) that's
// enabled in the controller's configuration.
func (c *Controller) setupUserChains() {
	// There's no equivalent to DOCKER-USER in the nftables implementation.
	if nftables.Enabled() {
		return
	}

	setup := func() error {
		var errs []error
		for _, ipVersion := range c.enabledIptablesVersions() {
			errs = append(errs, setupUserChain(ipVersion))
		}
		return errors.Join(errs...)
	}