mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
nftables: don't enable IP forwarding
For nftables only, never enable IP forwarding on the host. Instead, return an error on network creation if forwarding is not enabled, required by a bridge network, and --ip-forward=true. If IPv4 forwarding is not enabled when the daemon is started with nftables enabled and other config at defaults, the daemon will exit when it tries to create the default bridge. Otherwise, network creation will fail with an error if IPv4/IPv6 forwarding is not enabled when a network is created with IPv4/IPv6. It's the user's responsibility to configure and secure their host when they run Docker with nftables. Signed-off-by: Rob Murray <rob.murray@docker.com>
This commit is contained in:
@@ -880,14 +880,28 @@ func (d *driver) createNetwork(ctx context.Context, config *networkConfiguration
|
||||
config.EnableIPv4 && d.config.EnableIPForwarding,
|
||||
"setupIPv4Forwarding",
|
||||
func(*networkConfiguration, *bridgeInterface) error {
|
||||
return setupIPv4Forwarding(d.firewaller, d.config.EnableIPTables && !d.config.DisableFilterForwardDrop)
|
||||
ffd, ok := d.firewaller.(filterForwardDropper)
|
||||
if !ok {
|
||||
// The firewaller can't drop non-Docker forwarding. It's up to the user to enable
|
||||
// forwarding on their host, and configure their firewall appropriately.
|
||||
return checkIPv4Forwarding()
|
||||
}
|
||||
// Enable forwarding and set a default-drop forwarding policy if necessary.
|
||||
return setupIPv4Forwarding(ffd, d.config.EnableIPTables && !d.config.DisableFilterForwardDrop)
|
||||
},
|
||||
},
|
||||
{
|
||||
config.EnableIPv6 && d.config.EnableIPForwarding,
|
||||
"setupIPv6Forwarding",
|
||||
func(*networkConfiguration, *bridgeInterface) error {
|
||||
return setupIPv6Forwarding(d.firewaller, d.config.EnableIP6Tables && !d.config.DisableFilterForwardDrop)
|
||||
ffd, ok := d.firewaller.(filterForwardDropper)
|
||||
if !ok {
|
||||
// The firewaller can't drop non-Docker forwarding. It's up to the user to enable
|
||||
// forwarding on their host, and configure their firewall appropriately.
|
||||
return checkIPv6Forwarding()
|
||||
}
|
||||
// Enable forwarding and set a default-drop forwarding policy if necessary.
|
||||
return setupIPv6Forwarding(ffd, d.config.EnableIP6Tables && !d.config.DisableFilterForwardDrop)
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -76,9 +76,6 @@ type Firewaller interface {
|
||||
// NewNetwork returns an object that can be used to add published ports and legacy
|
||||
// links for a bridge network.
|
||||
NewNetwork(ctx context.Context, nc NetworkConfig) (Network, error)
|
||||
// FilterForwardDrop sets the default policy of the FORWARD chain in the filter
|
||||
// table to DROP.
|
||||
FilterForwardDrop(ctx context.Context, ipv IPVersion) error
|
||||
}
|
||||
|
||||
// Network can be used to manipulate firewall rules for a bridge network.
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
type StubFirewaller struct {
|
||||
Config
|
||||
Networks map[string]*StubFirewallerNetwork
|
||||
FFD map[IPVersion]bool // filter forward drop
|
||||
}
|
||||
|
||||
func NewStubFirewaller(config Config) *StubFirewaller {
|
||||
@@ -24,7 +23,6 @@ func NewStubFirewaller(config Config) *StubFirewaller {
|
||||
// A real Firewaller shouldn't hold on to its own networks, the bridge driver is doing that.
|
||||
// But, for unit tests cross-checking the driver, this is useful.
|
||||
Networks: make(map[string]*StubFirewallerNetwork),
|
||||
FFD: make(map[IPVersion]bool),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,11 +39,6 @@ func (fw *StubFirewaller) NewNetwork(_ context.Context, nc NetworkConfig) (Netwo
|
||||
return nw, nil
|
||||
}
|
||||
|
||||
func (fw *StubFirewaller) FilterForwardDrop(_ context.Context, ipv IPVersion) error {
|
||||
fw.FFD[ipv] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
type stubFirewallerLink struct {
|
||||
parentIP netip.Addr
|
||||
childIP netip.Addr
|
||||
|
||||
@@ -91,6 +91,7 @@ func NewIptabler(ctx context.Context, config firewaller.Config) (*Iptabler, erro
|
||||
return ipt, nil
|
||||
}
|
||||
|
||||
// FilterForwardDrop sets the default policy of the FORWARD chain in the filter table to DROP.
|
||||
func (ipt *Iptabler) FilterForwardDrop(ctx context.Context, ipv firewaller.IPVersion) error {
|
||||
var iptv iptables.IPVersion
|
||||
switch ipv {
|
||||
|
||||
@@ -85,21 +85,6 @@ func NewNftabler(ctx context.Context, config firewaller.Config) (*Nftabler, erro
|
||||
return nft, nil
|
||||
}
|
||||
|
||||
func (nft *Nftabler) getTable(ipv firewaller.IPVersion) nftables.TableRef {
|
||||
if ipv == firewaller.IPv4 {
|
||||
return nft.table4
|
||||
}
|
||||
return nft.table6
|
||||
}
|
||||
|
||||
func (nft *Nftabler) FilterForwardDrop(ctx context.Context, ipv firewaller.IPVersion) error {
|
||||
table := nft.getTable(ipv)
|
||||
if err := table.Chain(ctx, forwardChain).SetPolicy("drop"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nftApply(ctx, table)
|
||||
}
|
||||
|
||||
// init creates the bridge driver's nftables table for IPv4 or IPv6.
|
||||
func (nft *Nftabler) init(ctx context.Context, family nftables.Family) (nftables.TableRef, error) {
|
||||
// Instantiate the table.
|
||||
|
||||
@@ -4,6 +4,7 @@ package bridge
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
@@ -17,7 +18,24 @@ const (
|
||||
ipv6ForwardConfAll = "/proc/sys/net/ipv6/conf/all/forwarding"
|
||||
)
|
||||
|
||||
func setupIPv4Forwarding(fw firewaller.Firewaller, wantFilterForwardDrop bool) (retErr error) {
|
||||
type filterForwardDropper interface {
|
||||
FilterForwardDrop(context.Context, firewaller.IPVersion) error
|
||||
}
|
||||
|
||||
func checkIPv4Forwarding() error {
|
||||
enabled, err := getKernelBoolParam(ipv4ForwardConf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("checking IPv4 forwarding: %w", err)
|
||||
}
|
||||
if enabled {
|
||||
return nil
|
||||
}
|
||||
// It's the user's responsibility to enable forwarding and secure their host. Or,
|
||||
// start docker with --ip-forward=false to disable this check.
|
||||
return errors.New("IPv4 forwarding is disabled: check your host's firewalling and set sysctl net.ipv4.ip_forward=1, or disable this check using daemon option --ip-forward=false")
|
||||
}
|
||||
|
||||
func setupIPv4Forwarding(ffd filterForwardDropper, wantFilterForwardDrop bool) (retErr error) {
|
||||
changed, err := configureIPForwarding(ipv4ForwardConf, '1')
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -34,16 +52,35 @@ func setupIPv4Forwarding(fw firewaller.Firewaller, wantFilterForwardDrop bool) (
|
||||
|
||||
// When enabling ip_forward set the default policy on forward chain to drop.
|
||||
if changed && wantFilterForwardDrop {
|
||||
if err := fw.FilterForwardDrop(context.TODO(), firewaller.IPv4); err != nil {
|
||||
if err := ffd.FilterForwardDrop(context.TODO(), firewaller.IPv4); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupIPv6Forwarding(fw firewaller.Firewaller, wantFilterForwardDrop bool) (retErr error) {
|
||||
func checkIPv6Forwarding() error {
|
||||
enabledDef, err := getKernelBoolParam(ipv6ForwardConfDefault)
|
||||
if err != nil {
|
||||
return fmt.Errorf("checking IPv6 default forwarding: %w", err)
|
||||
}
|
||||
enabledAll, err := getKernelBoolParam(ipv6ForwardConfAll)
|
||||
if err != nil {
|
||||
return fmt.Errorf("checking IPv6 global forwarding: %w", err)
|
||||
}
|
||||
if enabledDef && enabledAll {
|
||||
return nil
|
||||
}
|
||||
|
||||
// It's the user's responsibility to enable forwarding and secure their host. Or,
|
||||
// start docker with --ip-forward=false to disable this check.
|
||||
return errors.New("IPv6 global forwarding is disabled: check your host's firewalling and set sysctls net.ipv6.conf.all.forwarding=1 and net.ipv6.conf.default.forwarding=1, or disable this check using daemon option --ip-forward=false")
|
||||
}
|
||||
|
||||
func setupIPv6Forwarding(ffd filterForwardDropper, wantFilterForwardDrop bool) (retErr error) {
|
||||
// Set IPv6 default.forwarding, if needed.
|
||||
// FIXME(robmry) - is it necessary to set this, setting "all" (below) does the job?
|
||||
// Setting "all" (below) sets "default" as well, but need to check that "default" is
|
||||
// set even if "all" is already set.
|
||||
changedDef, err := configureIPForwarding(ipv6ForwardConfDefault, '1')
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -74,7 +111,7 @@ func setupIPv6Forwarding(fw firewaller.Firewaller, wantFilterForwardDrop bool) (
|
||||
}
|
||||
|
||||
if (changedAll || changedDef) && wantFilterForwardDrop {
|
||||
if err := fw.FilterForwardDrop(context.TODO(), firewaller.IPv6); err != nil {
|
||||
if err := ffd.FilterForwardDrop(context.TODO(), firewaller.IPv6); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,19 +14,20 @@ import (
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
type ffdTestFirewaller struct {
|
||||
ffd firewaller.IPVersion
|
||||
}
|
||||
|
||||
// NewNetwork is part of interface [firewaller.Firewaller].
|
||||
func (f *ffdTestFirewaller) NewNetwork(_ context.Context, _ firewaller.NetworkConfig) (firewaller.Network, error) {
|
||||
return nil, nil
|
||||
type ffDropper struct {
|
||||
ffDrop4 bool
|
||||
ffDrop6 bool
|
||||
}
|
||||
|
||||
// FilterForwardDrop is part of interface [firewaller.Firewaller]. Just enough to check
|
||||
// it was called with the expected IPVersion.
|
||||
func (f *ffdTestFirewaller) FilterForwardDrop(_ context.Context, ipv firewaller.IPVersion) error {
|
||||
f.ffd = ipv
|
||||
func (f *ffDropper) FilterForwardDrop(_ context.Context, ipv firewaller.IPVersion) error {
|
||||
switch ipv {
|
||||
case firewaller.IPv4:
|
||||
f.ffDrop4 = true
|
||||
case firewaller.IPv6:
|
||||
f.ffDrop6 = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -36,21 +37,16 @@ func TestSetupIPForwarding(t *testing.T) {
|
||||
for _, wantFFD := range []bool{true, false} {
|
||||
t.Run(fmt.Sprintf("wantFFD=%v", wantFFD), func(t *testing.T) {
|
||||
// Disable IP Forwarding if enabled
|
||||
_, err := configureIPForwarding(ipv4ForwardConf, '0')
|
||||
assert.NilError(t, err)
|
||||
setForwarding(t, '0')
|
||||
|
||||
// Set IP Forwarding
|
||||
fw := &ffdTestFirewaller{}
|
||||
err = setupIPv4Forwarding(fw, wantFFD)
|
||||
ffd := &ffDropper{}
|
||||
err := setupIPv4Forwarding(ffd, wantFFD)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Check what the firewaller was told.
|
||||
if wantFFD {
|
||||
assert.Check(t, is.Equal(fw.ffd, firewaller.IPv4))
|
||||
} else {
|
||||
var noVer firewaller.IPVersion
|
||||
assert.Check(t, is.Equal(fw.ffd, noVer))
|
||||
}
|
||||
assert.Check(t, is.Equal(ffd.ffDrop4, wantFFD))
|
||||
assert.Check(t, !ffd.ffDrop6)
|
||||
|
||||
// Read new setting
|
||||
procSetting, err := os.ReadFile(ipv4ForwardConf)
|
||||
@@ -65,23 +61,15 @@ func TestSetupIP6Forwarding(t *testing.T) {
|
||||
|
||||
for _, wantFFD := range []bool{true, false} {
|
||||
t.Run(fmt.Sprintf("wantFFD=%v", wantFFD), func(t *testing.T) {
|
||||
_, err := configureIPForwarding(ipv6ForwardConfDefault, '0')
|
||||
assert.NilError(t, err)
|
||||
_, err = configureIPForwarding(ipv6ForwardConfAll, '0')
|
||||
assert.NilError(t, err)
|
||||
// Disable IP Forwarding if enabled
|
||||
setForwarding(t, '0')
|
||||
|
||||
// Set IP Forwarding
|
||||
fw := &ffdTestFirewaller{}
|
||||
err = setupIPv6Forwarding(fw, wantFFD)
|
||||
ffd := &ffDropper{}
|
||||
err := setupIPv6Forwarding(ffd, wantFFD)
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Check what the firewaller was told.
|
||||
if wantFFD {
|
||||
assert.Check(t, is.Equal(fw.ffd, firewaller.IPv6))
|
||||
} else {
|
||||
var noVer firewaller.IPVersion
|
||||
assert.Check(t, is.Equal(fw.ffd, noVer))
|
||||
}
|
||||
assert.Check(t, !ffd.ffDrop4)
|
||||
assert.Check(t, is.Equal(ffd.ffDrop6, wantFFD))
|
||||
|
||||
// Read new setting
|
||||
procSetting, err := os.ReadFile(ipv6ForwardConfDefault)
|
||||
@@ -93,3 +81,30 @@ func TestSetupIP6Forwarding(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckForwarding(t *testing.T) {
|
||||
defer netnsutils.SetupTestOSContext(t)()
|
||||
|
||||
setForwarding(t, '0')
|
||||
err := checkIPv4Forwarding()
|
||||
assert.Check(t, is.ErrorContains(err, "IPv4 forwarding is disabled"))
|
||||
err = checkIPv6Forwarding()
|
||||
assert.Check(t, is.ErrorContains(err, "IPv6 global forwarding is disabled"))
|
||||
|
||||
setForwarding(t, '1')
|
||||
err = checkIPv4Forwarding()
|
||||
assert.Check(t, err)
|
||||
err = checkIPv6Forwarding()
|
||||
assert.Check(t, err)
|
||||
}
|
||||
|
||||
func setForwarding(t *testing.T, val byte) {
|
||||
for _, sysctl := range []string{
|
||||
ipv4ForwardConf,
|
||||
ipv6ForwardConfDefault,
|
||||
ipv6ForwardConfAll,
|
||||
} {
|
||||
err := os.WriteFile(sysctl, []byte{val, '\n'}, 0o644)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,13 @@ fi
|
||||
|
||||
dockerd="dockerd"
|
||||
|
||||
# When running with the nftables backend, dockerd will not enable IP forwarding (by default, it
|
||||
# will error on network creation if forwarding is not enabled).
|
||||
if [ "$DOCKER_FIREWALL_BACKEND" = "nftables" ]; then
|
||||
sysctl -w net.ipv4.ip_forward=1 > /dev/null
|
||||
sysctl -w net.ipv6.conf.all.forwarding=1 > /dev/null
|
||||
fi
|
||||
|
||||
if [ -n "$DOCKER_ROOTLESS" ]; then
|
||||
if [ -z "$TEST_SKIP_INTEGRATION_CLI" ]; then
|
||||
echo >&2 '# DOCKER_ROOTLESS requires TEST_SKIP_INTEGRATION_CLI to be set'
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package networking
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -9,45 +8,29 @@ import (
|
||||
|
||||
"github.com/moby/moby/v2/testutil/daemon"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
"gotest.tools/v3/icmd"
|
||||
"gotest.tools/v3/poll"
|
||||
)
|
||||
|
||||
const (
|
||||
// The name of the bridge driver's nftables tables.
|
||||
nftTable = "docker-bridges"
|
||||
// The name of the filter-FORWARD chain in nftTable.
|
||||
nftFFChain = "filter-FORWARD"
|
||||
)
|
||||
|
||||
// Find the policy in, for example "Chain FORWARD (policy ACCEPT)".
|
||||
var rePolicy = regexp.MustCompile("policy ([A-Za-z]+)")
|
||||
|
||||
// SetFilterForwardPolicies sets the default policy for the FORWARD chain in
|
||||
// the filter tables for both IPv4 and IPv6. The original policy is restored
|
||||
// using t.Cleanup().
|
||||
// the iptables filter tables for both IPv4 and IPv6. The original policy is
|
||||
// restored using t.Cleanup().
|
||||
//
|
||||
// There's only one filter-FORWARD policy, so this won't behave well if used by
|
||||
// tests running in parallel in a single network namespace that expect different
|
||||
// behaviour.
|
||||
func SetFilterForwardPolicies(t *testing.T, firewallBackend string, policy string) {
|
||||
t.Helper()
|
||||
if strings.HasPrefix(firewallBackend, "iptables") {
|
||||
setIptablesFFP(t, policy)
|
||||
return
|
||||
}
|
||||
if strings.HasPrefix(firewallBackend, "nftables") {
|
||||
setNftablesFFP(t, policy)
|
||||
return
|
||||
}
|
||||
t.Fatalf("unknown firewall backend %s", firewallBackend)
|
||||
}
|
||||
|
||||
func setIptablesFFP(t *testing.T, policy string) {
|
||||
func SetFilterForwardPolicies(t *testing.T, policy string) {
|
||||
t.Helper()
|
||||
for _, iptablesCmd := range []string{"iptables", "ip6tables"} {
|
||||
origPolicy, err := getChainPolicy(t, exec.Command(iptablesCmd, "-L", "FORWARD"))
|
||||
assert.NilError(t, err, "failed to get iptables policy")
|
||||
out, err := exec.Command(iptablesCmd, "-L", "FORWARD").Output()
|
||||
assert.NilError(t, err, "failed to get %s policy", iptablesCmd)
|
||||
opMatch := rePolicy.FindSubmatch(out)
|
||||
assert.Assert(t, is.Len(opMatch, 2), "searching for policy: %w", err)
|
||||
origPolicy := string(opMatch[1])
|
||||
if origPolicy == policy {
|
||||
continue
|
||||
}
|
||||
@@ -62,42 +45,6 @@ func setIptablesFFP(t *testing.T, policy string) {
|
||||
}
|
||||
}
|
||||
|
||||
func setNftablesFFP(t *testing.T, policy string) {
|
||||
t.Helper()
|
||||
policy = strings.ToLower(policy)
|
||||
for _, family := range []string{"ip", "ip6"} {
|
||||
origPolicy, err := getChainPolicy(t, exec.Command("nft", "list", "chain", family, nftTable, nftFFChain))
|
||||
assert.NilError(t, err, "failed to get nftables policy")
|
||||
if origPolicy == policy {
|
||||
continue
|
||||
}
|
||||
cmd := func(p string) *exec.Cmd {
|
||||
return exec.Command("nft", "add", "chain", family, nftTable, nftFFChain, "{", "policy", p, ";", "}")
|
||||
}
|
||||
if err := cmd(policy).Run(); err != nil {
|
||||
t.Fatalf("Failed to set %s filter-FORWARD policy: %v", family, err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
if err := cmd(origPolicy).Run(); err != nil {
|
||||
t.Logf("Failed to restore %s filter-FORWARD policy: %v", family, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func getChainPolicy(t *testing.T, cmd *exec.Cmd) (string, error) {
|
||||
t.Helper()
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("getting policy: %w", err)
|
||||
}
|
||||
opMatch := rePolicy.FindSubmatch(out)
|
||||
if len(opMatch) != 2 {
|
||||
return "", fmt.Errorf("searching for policy: %w", err)
|
||||
}
|
||||
return string(opMatch[1]), nil
|
||||
}
|
||||
|
||||
// FirewalldRunning returns true if "firewall-cmd --state" reports "running".
|
||||
func FirewalldRunning() bool {
|
||||
state, err := exec.Command("firewall-cmd", "--state").CombinedOutput()
|
||||
|
||||
@@ -77,6 +77,8 @@ func (l3 *L3Segment) AddHost(t *testing.T, hostname, nsName, ifname string, addr
|
||||
l3.bridge.MustRun(t, "ip", "link", "set", hostname, "up", "master", l3.bridge.Iface)
|
||||
host.MustRun(t, "ip", "link", "set", host.Iface, "up")
|
||||
host.MustRun(t, "ip", "link", "set", "lo", "up")
|
||||
host.MustRun(t, "sysctl", "-w", "net.ipv4.ip_forward=1")
|
||||
host.MustRun(t, "sysctl", "-w", "net.ipv6.conf.all.forwarding=1")
|
||||
|
||||
for _, addr := range addrs {
|
||||
host.MustRun(t, "ip", "addr", "add", addr.String(), "dev", host.Iface, "nodad")
|
||||
|
||||
@@ -246,6 +246,8 @@ func TestIPRangeAt64BitLimit(t *testing.T) {
|
||||
func TestFilterForwardPolicy(t *testing.T) {
|
||||
skip.If(t, testEnv.IsRootless, "rootless has its own netns")
|
||||
skip.If(t, networking.FirewalldRunning(), "can't use firewalld in host netns to add rules in L3Segment")
|
||||
skip.If(t, strings.HasPrefix(testEnv.FirewallBackendDriver(), "nftables"), "no policy is set for nftables")
|
||||
|
||||
ctx := setupTest(t)
|
||||
|
||||
// Set up a netns for each test to avoid sysctl and iptables pollution.
|
||||
@@ -305,30 +307,17 @@ func TestFilterForwardPolicy(t *testing.T) {
|
||||
)
|
||||
host := l3.Hosts[hostname]
|
||||
|
||||
getFwdPolicy := func(usingNftables bool, fam string) string {
|
||||
getFwdPolicy := func(cmd string) string {
|
||||
t.Helper()
|
||||
if usingNftables {
|
||||
out := host.MustRun(t, "nft", "list chain "+fam+" docker-bridges filter-FORWARD")
|
||||
if strings.Contains(out, "policy accept") {
|
||||
return "ACCEPT"
|
||||
}
|
||||
if strings.Contains(out, "policy drop") {
|
||||
return "DROP"
|
||||
}
|
||||
t.Fatalf("Failed to determine nftables filter-FORWARD policy: %s", out)
|
||||
return ""
|
||||
} else {
|
||||
cmd := fam + "tables"
|
||||
out := host.MustRun(t, cmd, "-S", "FORWARD")
|
||||
if strings.HasPrefix(out, "-P FORWARD ACCEPT") {
|
||||
return "ACCEPT"
|
||||
}
|
||||
if strings.HasPrefix(out, "-P FORWARD DROP") {
|
||||
return "DROP"
|
||||
}
|
||||
t.Fatalf("Failed to determine %s FORWARD policy: %s", cmd, out)
|
||||
return ""
|
||||
out := host.MustRun(t, cmd, "-S", "FORWARD")
|
||||
if strings.HasPrefix(out, "-P FORWARD ACCEPT") {
|
||||
return "ACCEPT"
|
||||
}
|
||||
if strings.HasPrefix(out, "-P FORWARD DROP") {
|
||||
return "DROP"
|
||||
}
|
||||
t.Fatalf("Failed to determine %s FORWARD policy: %s", cmd, out)
|
||||
return ""
|
||||
}
|
||||
|
||||
type sysctls struct{ v4, v6def, v6all string }
|
||||
@@ -354,22 +343,21 @@ func TestFilterForwardPolicy(t *testing.T) {
|
||||
d.StartWithBusybox(ctx, t, tc.daemonArgs...)
|
||||
t.Cleanup(func() { d.Stop(t) })
|
||||
})
|
||||
usingNftables := d.FirewallBackendDriver(t) == "nftables"
|
||||
c := d.NewClientT(t)
|
||||
t.Cleanup(func() { c.Close() })
|
||||
|
||||
// If necessary, the IPv4 policy should have been updated when the default bridge network was created.
|
||||
assert.Check(t, is.Equal(getFwdPolicy(usingNftables, "ip"), tc.expPolicy))
|
||||
assert.Check(t, is.Equal(getFwdPolicy("iptables"), tc.expPolicy))
|
||||
// IPv6 policy should not have been updated yet.
|
||||
assert.Check(t, is.Equal(getFwdPolicy(usingNftables, "ip6"), "ACCEPT"))
|
||||
assert.Check(t, is.Equal(getFwdPolicy("ip6tables"), "ACCEPT"))
|
||||
assert.Check(t, is.Equal(getSysctls(), sysctls{tc.expForwarding, tc.initForwarding, tc.initForwarding}))
|
||||
|
||||
// If necessary, creating an IPv6 network should update the sysctls and policy.
|
||||
const netName = "testnetffp"
|
||||
network.CreateNoError(ctx, t, c, netName, network.WithIPv6())
|
||||
t.Cleanup(func() { network.RemoveNoError(ctx, t, c, netName) })
|
||||
assert.Check(t, is.Equal(getFwdPolicy(usingNftables, "ip"), tc.expPolicy))
|
||||
assert.Check(t, is.Equal(getFwdPolicy(usingNftables, "ip6"), tc.expPolicy))
|
||||
assert.Check(t, is.Equal(getFwdPolicy("iptables"), tc.expPolicy))
|
||||
assert.Check(t, is.Equal(getFwdPolicy("ip6tables"), tc.expPolicy))
|
||||
assert.Check(t, is.Equal(getSysctls(), sysctls{tc.expForwarding, tc.expForwarding, tc.expForwarding}))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -358,7 +358,6 @@ func TestBridgeINCRouted(t *testing.T) {
|
||||
d := daemon.New(t)
|
||||
d.StartWithBusybox(ctx, t)
|
||||
t.Cleanup(func() { d.Stop(t) })
|
||||
firewallBackend := d.FirewallBackendDriver(t)
|
||||
|
||||
c := d.NewClientT(t)
|
||||
t.Cleanup(func() { c.Close() })
|
||||
@@ -457,10 +456,12 @@ func TestBridgeINCRouted(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
for _, fwdPolicy := range []string{"ACCEPT", "DROP"} {
|
||||
networking.SetFilterForwardPolicies(t, firewallBackend, fwdPolicy)
|
||||
runTests := func(testName, policy string) {
|
||||
networking.FirewalldReload(t, d)
|
||||
t.Run(fwdPolicy, func(t *testing.T) {
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
if policy != "" {
|
||||
networking.SetFilterForwardPolicies(t, policy)
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name+"/v4/ping", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
@@ -497,6 +498,13 @@ func TestBridgeINCRouted(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if strings.HasPrefix(d.FirewallBackendDriver(t), "iptables") {
|
||||
runTests("iptables-ACCEPT", "ACCEPT")
|
||||
runTests("iptables-DROP", "DROP")
|
||||
} else {
|
||||
runTests("nftables", "")
|
||||
}
|
||||
}
|
||||
|
||||
// TestAccessToPublishedPort checks that a container in one network can
|
||||
|
||||
@@ -648,7 +648,6 @@ func TestDirectRoutingOpenPorts(t *testing.T) {
|
||||
d := daemon.New(t)
|
||||
d.StartWithBusybox(ctx, t)
|
||||
t.Cleanup(func() { d.Stop(t) })
|
||||
firewallBackend := d.FirewallBackendDriver(t)
|
||||
|
||||
c := d.NewClientT(t)
|
||||
t.Cleanup(func() { c.Close() })
|
||||
@@ -770,9 +769,11 @@ func TestDirectRoutingOpenPorts(t *testing.T) {
|
||||
// Run the ping and http tests in two parallel groups, rather than waiting for
|
||||
// ping/http timeouts separately. (The iptables filter-FORWARD policy affects the
|
||||
// whole host, so ACCEPT/DROP tests can't be parallelized).
|
||||
for _, fwdPolicy := range []string{"ACCEPT", "DROP"} {
|
||||
networking.SetFilterForwardPolicies(t, firewallBackend, fwdPolicy)
|
||||
t.Run(fwdPolicy, func(t *testing.T) {
|
||||
runTests := func(testName, policy string) {
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
if policy != "" {
|
||||
networking.SetFilterForwardPolicies(t, policy)
|
||||
}
|
||||
for gwMode := range networks {
|
||||
t.Run(gwMode+"/v4/ping", func(t *testing.T) {
|
||||
testPing(t, "ping", networks[gwMode].ipv4, expPingExit[gwMode])
|
||||
@@ -795,6 +796,13 @@ func TestDirectRoutingOpenPorts(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if strings.HasPrefix(d.FirewallBackendDriver(t), "iptables") {
|
||||
runTests("iptables-ACCEPT", "ACCEPT")
|
||||
runTests("iptables-DROP", "DROP")
|
||||
} else {
|
||||
runTests("nftables", "")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAcceptFwMark(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user