Finally, answering my own question.
After some research I have found that it was IP masquerading that caused Docker to recognize client addresses incorrectly.
The cause
In my case, firewalld is configured to share internet connection with other machines in local network. This is accomplished by setting zone to public
for the external interface (enp3s0
) and to internal
for the local interfaces (enp1s0
, enp2s0
), and by enabling IP masquerading for outgoing packages.
And that’s it. Masquerading is also applied to packages coming from public
network to docker networks, as if the package was going to (another) external interface.
Solution
As far as I understand all that iptables and Docker stuff, there is one acceptable workaround: add all virtual network interfaces created by Docker to the internal
zone, so masquerading rule is not applied to packages going to the corresponding networks. For example:
# firewall-cmd --permanent --zone=internal --change-interface=br-192821446c9a
To make the solution persistent, it is required to create the corresponding script in the /etc/sysconfig/network-scripts
directory. For example, for the br-192821446c9a
interface, a file /etc/sysconfig/network-scripts/ifcfg-br-192821446c9a
should be created, with the following content:
DEVICE=br-192821446c9a
TYPE=Bridge
BOOTPROTO=none
IPADDR=172.18.0.1
PREFIX=16
DEFROUTE=yes
IPV4_DNS_PRIORITY=100
NAME=br-192821446c9a
ONBOOT=no
ZONE=internal
Hope this answer will save somebody’s time.