Docker SNAT iptables and ipv4.ip_local_port_range

Hi.

I have few servers with ubuntu + docker + iptables firewall rules.
I’m blocking all ports less 30000 by default and allowing 30000:65535. I have the following rule in raw table:

*raw
:PREROUTING DROP [0:0]
:OUTPUT ACCEPT [11585245:3037522309]

-A PREROUTING -p tcp -m tcp --dport 30000:65535 -j ACCEPT
-A PREROUTING -p udp -m udp --dport 30000:65535 -j ACCEPT
-A PREROUTING -j DROP

Systems are using ports from setting net.ipv4.ip_local_port_range for all ongoing connections:

net.ipv4.ip_local_port_range = 32768	60999

But when I use network_mode: bridge (not host), the system makes SNAT (Source Network Address Translation) and changes outgoing port from container’s to new one in system.
BUT SNAT doesn’t use net.ipv4.ip_local_port_range and sets outgoing port randomly from 1024 to 65535. So my app connects to another servers db port 5432, and db server is trying to send answer to my outgoing port which is smaller then 30000 and my iptables raw rules are blocking packets and I get connection timeout.

So, the question, how can I configure docker that SNAT uses ports from net.ipv4.ip_local_port_range for outgoing connections ?

Hope for someone’s help.
Thank you.

It looks like it is docker iptables rules bug. When docker adds iptables SNAT rules, it has to use port range from system’s ipv4.ip_local_port_range setting and set it for MASQUERADE

Current setting is using by default ports from 1024 for outgoing connections (but net.ipv4.ip_local_port_range starts from 32768 )

-A POSTROUTING -s 172.18.0.0/16 ! -o br-c4ab9377c689 -j MASQUERADE

So docker has to have some option to set ports range for SNAT ports translation

Add the new rule with the specific port range (default for linux 32768-60999)

-A POSTROUTING -s 172.18.0.0/16 ! -o br-c4ab9377c689 -j MASQUERADE --to-ports 32768-60999

If you think it’s a bug, you can report it to the developers at Moby Github. If it’s a feature, you can place it on the Docker roadmap.