103 Commits

Author SHA1 Message Date
Rob Murray
31f405932a Unmap IPv4 addresses loaded from store
When a endpoint's net.IPNet is loaded from store and converted
to a netip.Addr, unmap it so that iptables rules don't contain
IPv4-mapped IPv6 addresses.

Signed-off-by: Rob Murray <rob.murray@docker.com>
(cherry picked from commit 071e6472db)
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-08-27 19:48:31 +01:00
Matthieu MOREL
6d737371b8 fix comparison rule from errorlint
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>

Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2025-06-13 08:26:56 +00:00
Rob Murray
21a165de23 Use env-var DOCKER_FIREWALL_BACKEND=nftables to enable nftables
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-05-28 09:57:26 +01:00
Rob Murray
eeba428939 Make WSL2Mirrored a Firewaller param
The bridge driver should figure out whether it's running in
a mirrored WSL2 setup, and tell the firewaller.

So, move the WSL2-deciding code back into the bridge driver
and unit test it there. Use TestIptabler to check the rules
are constructed properly.

Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-05-14 09:38:32 +01:00
Rob Murray
ba0ad9e80f Unit test the bridge driver in terms of its firewaller
Don't inspect iptables rules, because the driver's Firewaller won't
always be an iptabler.

Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-05-13 18:27:55 +01:00
Rob Murray
cb38cc0fdd Merge pull request #49860 from robmry/firewaller_interface
Firewaller interface
2025-05-12 14:18:16 +01:00
Rob Murray
b0777be89e Use firewaller.IPVersion instead of iptables.IPVersion for gwmode
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-05-06 10:18:22 +01:00
Rob Murray
3cbb1ae736 Move filter-FORWARD DROP setting to the firewaller
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-05-06 10:18:22 +01:00
Rob Murray
44843d9917 Pass context to more places
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-05-06 10:18:22 +01:00
Rob Murray
a9bf151260 Put Iptabler behind a Firewaller interface.
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-05-06 10:18:22 +01:00
Matthieu MOREL
70139978d3 fix(ST1016): Use consistent method receiver names
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-05-01 14:30:52 +02:00
Rob Murray
44a3453d73 Add daemon option --allow-direct-routing
Per-network option com.docker.network.bridge.trusted-host-interfaces
accepts a list of interfaces that are allowed to route
directly to a container's published ports in a bridge
network with nat enabled.

This daemon level option disables direct access filtering,
enabling direct access to published ports on container
addresses in all bridge networks, via all host interfaces.

It overlaps with short-term env-var workaround:
  DOCKER_INSECURE_NO_IPTABLES_RAW=1
- it does not allow packets sent from outside the host to reach
  ports published only to 127.0.0.1
- it will outlive iptables (the workaround was initially intended
  for hosts that do not have kernel support for the "raw" iptables
  table).

Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-04-30 20:59:28 +01:00
Rob Murray
a94643a1b3 bridge: add option com.docker.network.bridge.trusted_host_interfaces
trusted_host_interface have access to published ports on container
addresses - enabling direct routing to the container via those
interfaces.

Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-04-30 20:59:28 +01:00
Rob Murray
a0ff0a361e iptables: Direct routing DROP rules per-container, not per-port
Commit 27adcd5 ("libnet/d/bridge: drop connections to lo mappings, and
direct remote connections") introduced an iptables rule to drop 'direct'
remote connections made to the container's IP address - for each
published port on the container.

The normal filter-FORWARD rules would then drop packets sent directly to
unpublished ports. This rule was only created along with the rest of port
publishing (when a container's endpoint was selected as its gateway). Until
then, all packets addressed directly to the container's ports were dropped
by the filter-FORWARD rules.

But, the rule doesn't need to be per-port. Just drop packets sent
directly to a container's address unless they originate on the host.

That means fewer rules, that can be created along with the endpoint (then
directly-routed get dropped at the same point whether or not the endpoint
is currently the gateway - very slightly earlier than when it's not the
gateway).

Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-04-24 12:00:44 +01:00
Rob Murray
282b3f7b97 Move bridge driver iptables code into its own package
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-04-23 10:41:15 +01:00
Rob Murray
75c60598b7 Move clearConntrackEntries to bridge_linux.go
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-04-23 10:41:14 +01:00
Rob Murray
57bf7a8c70 bridge: Add a missing error check for firewaller setup
It got lost in commit 29e0db2 ("Factor out top-level iptables
setup into its own object").

Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-04-15 12:05:10 +01:00
Rob Murray
29e0db25e7 Factor out top-level iptables setup into its own object
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-04-09 10:54:14 +01:00
Albin Kerouanton
667c7d70b3 libnet/d/bridge: trace network setup steps
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-04-09 08:45:33 +02:00
Albin Kerouanton
eaae4b5fb6 libnet/d/bridge: put span prefix in var
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-04-09 08:45:33 +02:00
Albin Kerouanton
78be7ebad7 libnet/d/bridge: trace createNetwork
Plumb context from the API down to libnet driver method `CreateNetwork`,
and add an OTel span to the bridge driver's `createNetwork` method.
Include a few attributes describing the network configuration (e.g.
IPv4/IPv6, ICC, internal and MTU).

A new util function, `RecordStatus`, is added to the `otelutil` package
to easily record any error, and update the span status accordingly.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-04-09 08:45:33 +02:00
Rob Murray
a527e5a546 Restore iptables for current networks on firewalld reload
Using iptables.OnReloaded to restore individual per-network rules
on firewalld reload means rules for deleted networks pop back in
to existence (because there was no way to delete the callbacks on
network-delete).

So, on firewalld reload, walk over current networks and ask them
to restore their iptables rules.

Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-04-08 10:26:41 +01:00
Rob Murray
7243860557 Include per-port rules in iptablesNetwork
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-03-31 17:04:17 +01:00
Rob Murray
0b5e1f904a Use netip.Addr instead of net.IP for legacy links
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-03-31 11:52:16 +01:00
Rob Murray
725e699741 Simplify iptables setup for legacy links
Include legacy link setup in IptablesNetwork, with the other
per-network rules.

Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-03-31 11:52:16 +01:00
Rob Murray
409707b633 bridge: factor out creation of network-level iptables rules
Create an iptablesNetwork containing all the info needed to
set up per-network iptables rules, give it methods to do
create the rules, and use it instead of per-rule-type calls
from driver.createNetwork().

Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-03-28 16:57:16 +00:00
Rob Murray
fce915897c Combine firewalld reload callbacks for IPv4/IPv6
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-03-17 10:30:45 +00:00
Rob Murray
76417bf763 Don't use ipset
Commit 0546d90 introduced the use of ipset to reduce the number
of rules that need to be processed per-packet, and make the code
a bit simpler.

But, docker's used on embedded kernels compiled without support
for ipset, so the change is too disruptive.

Replace the two ipset rules with a new chain that writes out the
rule's actions long-hand. So ..

This rule:
  -A FORWARD -m set --match-set docker-ext-bridges-v4 dst \
    -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
Is transformed into a per-bridge rule in new chain DOCKER-CT:
  -A DOCKER-FORWARD -j DOCKER-CT
  -A DOCKER-CT -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
  -A DOCKER-CT -o bridge1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

And:
  -A FORWARD -m set --match-set docker-ext-bridges-v4 dst -j DOCKER
Is transformed into a per-bridge rule in new chain DOCKER-BRIDGE:
  -A DOCKER-FORWARD -j DOCKER-BRIDGE
  -A DOCKER-BRIDGE -o docker0 -j DOCKER
  -A DOCKER-BRIDGE -o bridge1 -j DOCKER

Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-02-25 15:24:25 +00:00
Rob Murray
8cc4d1d4a2 Fix daemon startup on a no-IPv6 host
With ip6tables enabled (by default), the daemon should start on a
host with IPv6 disabled - then error if IPv6 network creation is
attempted.

That regressed in commit 255fff4 - so, only try to set up network
isolation rules for a network if it's IPv6-enabled.

Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-02-24 17:41:44 +00:00
Rob Murray
a92d20bcc4 Better error message for missing ip_set kernel modules
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-02-24 12:18:36 +00:00
Albin Kerouanton
56a7817b2d libnet: add support for custom interface names
To support this, a new netlabel is added: `com.docker.network.endpoint.ifname`.

It gives the ability to specify the interface name to be set by
netdrivers when the interface is added / moved into the container's
network namespace.

All builtin netdrivers support it.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-02-06 17:00:29 +01:00
Rob Murray
9fdcde7618 Add bridge gateway mode "isolated"
It can only be set on a "--internal" network, and the only difference is
that no address is assigned to the bridge. So, there's no route to a
host address.

Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-01-29 10:28:55 +00:00
Sebastiaan van Stijn
bbaa8af8f3 libnetwork/drivers/bridge: un-export errors
These errors implement errdefs interfaces, and are only used internally
for convenience. Un-export their implemetations because the types themselves
are not used as sentinel errors.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-01-28 19:12:42 +01:00
Sebastiaan van Stijn
47f6d4e1bc libnetwork/drivers/bridge: internalize ErrInvalidGateway
It's a generic errdefs.ErrInvalidParameter, and the type itself is not
used as sentinel error anywhere.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-01-28 19:10:14 +01:00
Sebastiaan van Stijn
3a9f4e0146 libnetwork/drivers/bridge: remove ErrInvalidMtu
It's a generic errdefs.ErrInvalidParameter, and the type itself is not
used as sentinel error anywhere.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-01-28 19:10:14 +01:00
Sebastiaan van Stijn
59c2d2a4b3 libnetwork/drivers/bridge: remove ErrInvalidDriverConfig
It's a generic error, doesn't implement an errdefs type, is poorly formatted,
and not used as sentinel error anywhere. Let's remove it, and update the error
produced to be slightly more informative (include the invalid type). Worth
noting that there's no need to include the name of the driver in the error,
because the only uses of the error (in `registerNetworkDrivers`) already
decorates it; 5fd7ed2937/libnetwork/drivers_linux.go (L34-L36)

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-01-28 19:10:11 +01:00
Rob Murray
65120d586b Create bridge veth in container netns
Since commit 933fcc9 (Re-remove the SetKey OCI prestart hook),
the network namespace will be set up before endpoints are
created in most cases, apart from build containers.

So, when possible, create the veth with one end in that netns
to save moving it in later. On my host, that saves about 20ms
for each bridge network a container is connected to.

Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-01-24 18:43:51 +00:00
Rob Murray
94444587d4 Merge pull request #48808 from robmry/v6only/gratuitous_arp
IPv6 only: use random MAC addresses
2025-01-22 18:52:21 +00:00
Rob Murray
bc130f367d bridge/macvlan endpoints always use a random MAC address
Now a gratuitous/unsolicted ARP is sent, there's no need to
use an IPv4-based MAC address to preserve arp-cache mappings
between an endpoint's IP addresses and its MAC addresses.

Because a random MAC address is used for the default bridge,
it no longer makes sense to derive container IPv6 addresses
from the MAC address. This "postIPv6" behaviour was needed
before IPv6 addresses could be configured, but not now. So,
IPv6 addresses will now be IPAM-allocated on the default
bridge network, just as they are for user-defined bridges.

Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-01-22 16:59:27 +00:00
Rob Murray
eaa84bc8f4 Send unsolicited ARP/NA requests when bringing up interfaces
Co-authored-by: Cory Snider <csnider@mirantis.com>
Co-authored-by: Rob Murray <rob.murray@docker.com>
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-01-22 16:59:27 +00:00
Sebastiaan van Stijn
2f84e2b208 libnetwork/drivers/bridge: driver.configure: move vars close to where used
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-01-22 12:53:37 +01:00
Rob Murray
22c02219de Bridge: on network delete, make sure it's deleted from store
Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-01-17 21:56:02 +00:00
Sebastiaan van Stijn
57c597203a Merge pull request #49261 from robmry/ask_driver_if_gw_needed
Ask network drivers if they'll use a gateway address
2025-01-16 13:22:05 +01:00
Albin Kerouanton
d560704c91 libnet/d/bridge: init driver.nlh in newDriver
This field was initialized by `driver.createNetwork` instead of being
initialized by the `newDriver` constructor. That's currently the single
place where it's initialized -- no tests override it, so it seems the
'current' netns is always used.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2025-01-13 17:36:15 +01:00
Rob Murray
43f71fb582 Bridge - skip gateway allocation if no gateway is needed
An "--internal" bridge network will never set up a default route
and, with "-o com.docker.network.bridge.inhibit_ipv4", no Gateway
address will be assigned to the bridge.

So, implement the SkipGwAlloc interface in the bridge driver, and
use it to to indicate that no Gateway address is required in this
specific case.

Signed-off-by: Rob Murray <rob.murray@docker.com>
2025-01-13 10:28:55 +00:00
Sebastiaan van Stijn
ea00e72c21 libnetwork/drivers/bridge: processIPAM: remove unused arg
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-01-08 15:15:11 +01:00
Sebastiaan van Stijn
1f4c9f23c3 libnetwork/drivers/bridge: format errors with '%v' for consistency
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-01-02 22:05:38 +01:00
Albin Kerouanton
e5bf6d8ba0 libnet: pass store as an arg to netdrivers
Before that change, we were passing the datastore to network drivers
through a `map[string]interface{}`. Then, each driver that needed the
store would cast the datastore to the correct type.

This was not a good design, as it was not clear which drivers were using
the store and which were not. Not all unit tests were passing the store,
leading to logs about uninitialized store being written.

This change makes the store a parameter of the `RegisterX` functions.
All unit tests are now passing a valid datastore to the drivers. A new
testutil func is added for that purpose.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2024-12-20 17:51:53 +01:00
Albin Kerouanton
820dea0d2b libnet/d/bridge: hardcode chain names
Signed-off-by: Albin Kerouanton <albinker@gmail.com>
2024-12-17 12:31:35 +01:00
Rob Murray
f2e1f52a04 Try to load kernel module ip6_tables, when necessary.
Signed-off-by: Rob Murray <rob.murray@docker.com>
2024-12-06 10:27:24 +00:00