Skip to content

Commit 2d0bc97

Browse files
authored
Merge pull request moby#50646 from robmry/nftables_no_enable_ip_forwarding
nftables: never enable IP forwarding on the host
2 parents feeaa16 + 2fff6b4 commit 2d0bc97

File tree

21 files changed

+225
-190
lines changed

21 files changed

+225
-190
lines changed

contrib/check-config.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,16 @@ check_device() {
128128
fi
129129
}
130130

131+
check_sysctl() {
132+
val=$(sysctl -n $1)
133+
want=$2
134+
if [ "$val" = "$want" ]; then
135+
wrap_good "sysctl $1" "enabled"
136+
else
137+
wrap_bad "sysctl $1" "disabled"
138+
fi
139+
}
140+
131141
if [ ! -e "$CONFIG" ]; then
132142
wrap_warning "warning: $CONFIG does not exist, searching other paths for kernel config ..."
133143
for tryConfig in $possibleConfigs; do
@@ -343,6 +353,10 @@ if ! is_set EXT4_FS || ! is_set EXT4_FS_POSIX_ACL || ! is_set EXT4_FS_SECURITY;
343353
fi
344354

345355
echo '- Network Drivers:'
356+
echo " - \"$(wrap_color 'bridge' blue)\":"
357+
check_sysctl net.ipv4.ip_forward 1 | sed 's/^/ - /'
358+
check_sysctl net.ipv6.conf.all.forwarding 1 | sed 's/^/ - /'
359+
check_sysctl net.ipv6.conf.default.forwarding 1 | sed 's/^/ - /'
346360
echo " - \"$(wrap_color 'overlay' blue)\":"
347361
check_flags VXLAN BRIDGE_VLAN_FILTERING | sed 's/^/ /'
348362
echo ' Optional (for encrypted networks):'

contrib/dockerd-rootless.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,5 +199,12 @@ else
199199
mount_directory /etc/ssl "--rbind"
200200
fi
201201

202+
# When running with --firewall-backend=nftables, IP forwarding needs to be enabled
203+
# because the daemon won't enable it. IP forwarding is harmless in the rootless
204+
# netns, there's only a single external interface and only Docker uses the netns.
205+
# So, always enable IPv4 and IPv6 forwarding.
206+
sysctl -w net.ipv4.ip_forward=1
207+
sysctl -w net.ipv6.conf.all.forwarding=1
208+
202209
exec "$dockerd" "$@"
203210
fi

daemon/libnetwork/drivers/bridge/bridge_linux.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ var newFirewaller = func(ctx context.Context, config firewaller.Config) (firewal
556556
// cleaner can't clean up network or port-specific rules that may have been added
557557
// to iptables built-in chains. So, if cleanup is needed, give the cleaner to
558558
// the nftabler. Then, it'll use it to delete old rules as networks are restored.
559-
fw.(firewaller.FirewallCleanerSetter).SetFirewallCleaner(iptabler.NewCleaner(ctx, config))
559+
fw.SetFirewallCleaner(iptabler.NewCleaner(ctx, config))
560560
return fw, nil
561561
}
562562

@@ -880,14 +880,28 @@ func (d *driver) createNetwork(ctx context.Context, config *networkConfiguration
880880
config.EnableIPv4 && d.config.EnableIPForwarding,
881881
"setupIPv4Forwarding",
882882
func(*networkConfiguration, *bridgeInterface) error {
883-
return setupIPv4Forwarding(d.firewaller, d.config.EnableIPTables && !d.config.DisableFilterForwardDrop)
883+
ffd, ok := d.firewaller.(filterForwardDropper)
884+
if !ok {
885+
// The firewaller can't drop non-Docker forwarding. It's up to the user to enable
886+
// forwarding on their host, and configure their firewall appropriately.
887+
return checkIPv4Forwarding()
888+
}
889+
// Enable forwarding and set a default-drop forwarding policy if necessary.
890+
return setupIPv4Forwarding(ffd, d.config.EnableIPTables && !d.config.DisableFilterForwardDrop)
884891
},
885892
},
886893
{
887894
config.EnableIPv6 && d.config.EnableIPForwarding,
888895
"setupIPv6Forwarding",
889896
func(*networkConfiguration, *bridgeInterface) error {
890-
return setupIPv6Forwarding(d.firewaller, d.config.EnableIP6Tables && !d.config.DisableFilterForwardDrop)
897+
ffd, ok := d.firewaller.(filterForwardDropper)
898+
if !ok {
899+
// The firewaller can't drop non-Docker forwarding. It's up to the user to enable
900+
// forwarding on their host, and configure their firewall appropriately.
901+
return checkIPv6Forwarding()
902+
}
903+
// Enable forwarding and set a default-drop forwarding policy if necessary.
904+
return setupIPv6Forwarding(ffd, d.config.EnableIP6Tables && !d.config.DisableFilterForwardDrop)
891905
},
892906
},
893907

daemon/libnetwork/drivers/bridge/bridge_store.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
"github.com/containerd/log"
1414
"github.com/moby/moby/v2/daemon/internal/otelutil"
1515
"github.com/moby/moby/v2/daemon/libnetwork/datastore"
16-
"github.com/moby/moby/v2/daemon/libnetwork/drivers/bridge/internal/firewaller"
16+
"github.com/moby/moby/v2/daemon/libnetwork/drivers/bridge/internal/nftabler"
1717
"github.com/moby/moby/v2/daemon/libnetwork/portmapperapi"
1818
"github.com/moby/moby/v2/daemon/libnetwork/types"
1919
"go.opentelemetry.io/otel"
@@ -43,8 +43,8 @@ func (d *driver) initStore() error {
4343

4444
// If there's a firewall cleaner, it's done its job by cleaning up rules
4545
// belonging to the restored networks. So, drop it.
46-
if fcs, ok := d.firewaller.(firewaller.FirewallCleanerSetter); ok {
47-
fcs.SetFirewallCleaner(nil)
46+
if nft, ok := d.firewaller.(*nftabler.Nftabler); ok {
47+
nft.SetFirewallCleaner(nil)
4848
}
4949

5050
return nil

daemon/libnetwork/drivers/bridge/internal/firewaller/firewaller.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,6 @@ type Firewaller interface {
7676
// NewNetwork returns an object that can be used to add published ports and legacy
7777
// links for a bridge network.
7878
NewNetwork(ctx context.Context, nc NetworkConfig) (Network, error)
79-
// FilterForwardDrop sets the default policy of the FORWARD chain in the filter
80-
// table to DROP.
81-
FilterForwardDrop(ctx context.Context, ipv IPVersion) error
8279
}
8380

8481
// Network can be used to manipulate firewall rules for a bridge network.
@@ -110,12 +107,6 @@ type Network interface {
110107
DelLink(ctx context.Context, parentIP, childIP netip.Addr, ports []types.TransportPort)
111108
}
112109

113-
// FirewallCleanerSetter is an optional interface for a Firewaller.
114-
type FirewallCleanerSetter interface {
115-
// SetFirewallCleaner replaces the FirewallCleaner (possibly with 'nil').
116-
SetFirewallCleaner(FirewallCleaner)
117-
}
118-
119110
// FirewallCleaner is used to delete rules created by previous incarnations of
120111
// the daemon. On startup, once a Firewaller implementation has been selected, if
121112
// rules may have been left behind by a different Firewaller implementation, get

daemon/libnetwork/drivers/bridge/internal/firewaller/stub.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
type StubFirewaller struct {
1616
Config
1717
Networks map[string]*StubFirewallerNetwork
18-
FFD map[IPVersion]bool // filter forward drop
1918
}
2019

2120
func NewStubFirewaller(config Config) *StubFirewaller {
@@ -24,7 +23,6 @@ func NewStubFirewaller(config Config) *StubFirewaller {
2423
// A real Firewaller shouldn't hold on to its own networks, the bridge driver is doing that.
2524
// But, for unit tests cross-checking the driver, this is useful.
2625
Networks: make(map[string]*StubFirewallerNetwork),
27-
FFD: make(map[IPVersion]bool),
2826
}
2927
}
3028

@@ -41,11 +39,6 @@ func (fw *StubFirewaller) NewNetwork(_ context.Context, nc NetworkConfig) (Netwo
4139
return nw, nil
4240
}
4341

44-
func (fw *StubFirewaller) FilterForwardDrop(_ context.Context, ipv IPVersion) error {
45-
fw.FFD[ipv] = true
46-
return nil
47-
}
48-
4942
type stubFirewallerLink struct {
5043
parentIP netip.Addr
5144
childIP netip.Addr

daemon/libnetwork/drivers/bridge/internal/iptabler/cleaner.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type iptablesCleaner struct {
1717
}
1818

1919
// NewCleaner checks for iptables rules left behind by an old daemon that was using
20-
// the iptabler.
20+
// the Iptabler.
2121
//
2222
// If there are old rules present, it deletes as much as possible straight away
2323
// (user-defined chains and jumps from the built-in chains).
@@ -46,6 +46,13 @@ func NewCleaner(ctx context.Context, config firewaller.Config) firewaller.Firewa
4646
_ = t.DeleteJumpRule(iptables.Filter, "FORWARD", DockerForwardChain)
4747
_ = deleteLegacyTopLevelRules(ctx, t, ipv)
4848
removeIPChains(ctx, ipv)
49+
// The iptables chains will no longer have Docker's ACCEPT rules. So, if the
50+
// filter-FORWARD chain has policy DROP (possibly set by Docker when it enabled
51+
// IP forwarding), packets accepted by nftables chains will still be processed by
52+
// iptables and dropped. It's the user's responsibility to sort that out.
53+
if t.HasPolicy("filter", "FORWARD", iptables.Drop) {
54+
log.G(ctx).WithField("ipv", ipv).Warn("Network traffic for published ports may be dropped, iptables chain FORWARD has policy DROP.")
55+
}
4956
return true
5057
}
5158
cleaned4 := clean(iptables.IPv4, config.IPv4)
@@ -62,7 +69,7 @@ func (ic iptablesCleaner) DelNetwork(ctx context.Context, nc firewaller.NetworkC
6269
}
6370
n := network{
6471
config: nc,
65-
ipt: &iptabler{config: ic.config},
72+
ipt: &Iptabler{config: ic.config},
6673
}
6774
if ic.config.IPv4 && nc.Config4.Prefix.IsValid() {
6875
_ = deleteLegacyFilterRules(iptables.IPv4, nc.IfName)
@@ -77,7 +84,7 @@ func (ic iptablesCleaner) DelNetwork(ctx context.Context, nc firewaller.NetworkC
7784
func (ic iptablesCleaner) DelEndpoint(ctx context.Context, nc firewaller.NetworkConfig, epIPv4, epIPv6 netip.Addr) {
7885
n := network{
7986
config: nc,
80-
ipt: &iptabler{config: ic.config},
87+
ipt: &Iptabler{config: ic.config},
8188
}
8289
if n.ipt.config.IPv4 && epIPv4.IsValid() {
8390
_ = n.filterDirectAccess(ctx, iptables.IPv4, n.config.Config4, epIPv4, false)
@@ -90,7 +97,7 @@ func (ic iptablesCleaner) DelEndpoint(ctx context.Context, nc firewaller.Network
9097
func (ic iptablesCleaner) DelPorts(ctx context.Context, nc firewaller.NetworkConfig, pbs []types.PortBinding) {
9198
n := network{
9299
config: nc,
93-
ipt: &iptabler{config: ic.config},
100+
ipt: &Iptabler{config: ic.config},
94101
}
95102
_ = n.DelPorts(ctx, pbs)
96103
}

daemon/libnetwork/drivers/bridge/internal/iptabler/iptabler.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@ const (
3535
isolationChain2 = "DOCKER-ISOLATION-STAGE-2"
3636
)
3737

38-
type iptabler struct {
38+
type Iptabler struct {
3939
config firewaller.Config
4040
}
4141

42-
func NewIptabler(ctx context.Context, config firewaller.Config) (firewaller.Firewaller, error) {
43-
ipt := &iptabler{config: config}
42+
func NewIptabler(ctx context.Context, config firewaller.Config) (*Iptabler, error) {
43+
ipt := &Iptabler{config: config}
4444

4545
if ipt.config.IPv4 {
4646
removeIPChains(ctx, iptables.IPv4)
@@ -91,7 +91,8 @@ func NewIptabler(ctx context.Context, config firewaller.Config) (firewaller.Fire
9191
return ipt, nil
9292
}
9393

94-
func (ipt *iptabler) FilterForwardDrop(ctx context.Context, ipv firewaller.IPVersion) error {
94+
// FilterForwardDrop sets the default policy of the FORWARD chain in the filter table to DROP.
95+
func (ipt *Iptabler) FilterForwardDrop(ctx context.Context, ipv firewaller.IPVersion) error {
9596
var iptv iptables.IPVersion
9697
switch ipv {
9798
case firewaller.IPv4:

daemon/libnetwork/drivers/bridge/internal/iptabler/network.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ type (
2222

2323
type network struct {
2424
config firewaller.NetworkConfig
25-
ipt *iptabler
25+
ipt *Iptabler
2626
cleanFuncs iptablesCleanFuncs
2727
}
2828

29-
func (ipt *iptabler) NewNetwork(ctx context.Context, nc firewaller.NetworkConfig) (_ firewaller.Network, retErr error) {
29+
func (ipt *Iptabler) NewNetwork(ctx context.Context, nc firewaller.NetworkConfig) (_ firewaller.Network, retErr error) {
3030
n := &network{
3131
ipt: ipt,
3232
config: nc,

daemon/libnetwork/drivers/bridge/internal/nftabler/cleaner.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"github.com/moby/moby/v2/daemon/libnetwork/internal/nftables"
1212
)
1313

14-
// Cleanup deletes all rules created by nftabler; it's intended to be used
14+
// Cleanup deletes all rules created by Nftabler; it's intended to be used
1515
// during startup, to clean up rules created by an old incarnation of the daemon
1616
// after switching to a different Firewaller implementation.
1717
func Cleanup(ctx context.Context, config firewaller.Config) {
@@ -31,6 +31,6 @@ func Cleanup(ctx context.Context, config firewaller.Config) {
3131
}
3232
}
3333

34-
func (nft *nftabler) SetFirewallCleaner(fc firewaller.FirewallCleaner) {
34+
func (nft *Nftabler) SetFirewallCleaner(fc firewaller.FirewallCleaner) {
3535
nft.cleaner = fc
3636
}

0 commit comments

Comments
 (0)