Bug 1283479 - Port forwarding to a VM stops other VMs using the same port from reaching the net.
Port forwarding to a VM stops other VMs using the same port from reaching the...
Status: CLOSED EOL
Product: Fedora
Classification: Fedora
Component: firewalld (Show other bugs)
22
Unspecified Unspecified
unspecified Severity unspecified
: ---
: ---
Assigned To: Thomas Woerner
Fedora Extras Quality Assurance
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2015-11-19 00:24 EST by Andrew Haveland-Robinson
Modified: 2016-07-19 14:30 EDT (History)
3 users (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2016-07-19 14:30:27 EDT
Type: Bug
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)

  None (edit)
Description Andrew Haveland-Robinson 2015-11-19 00:24:34 EST
Description of problem:
Forwarding port 80 on a host machine to a VM appears to work, but other machines cannot connect to the net on the same port because the traffic is intercepted by a rogue rule

Version-Release number of selected component (if applicable):
firewalld-0.3.14.2-4.fc22.noarch

How reproducible:
Always, as far as I can tell.

Steps to Reproduce:
firewall-cmd --permanent --zone=FedoraServer --add-forward-port=port=80:proto=tcp:toaddr=192.168.122.2

firewall-cmd --permanent --zone=FedoraServer --add-forward-port=port=2222:proto=tcp:toaddr=192.168.122.164:toport=22



Actual results:
iptables -t mangle -S
...
-A PREROUTING_ZONES -i eno1 -g PRE_FedoraServer
-A PREROUTING_ZONES -g PRE_FedoraServer
-A PRE_FedoraServer -j PRE_FedoraServer_log
-A PRE_FedoraServer -j PRE_FedoraServer_deny
-A PRE_FedoraServer -j PRE_FedoraServer_allow
-A PRE_FedoraServer_allow -p tcp -m tcp --dport 2222 -j MARK --set-xmark 0x64/0xffffffff
-A PRE_FedoraServer_allow -p tcp -m tcp --dport 80 -j MARK --set-xmark 0x65/0xffffffff
...

Expected results:
...
-A PREROUTING_ZONES -i eno1 -g PRE_FedoraServer

**** should not be here! ****
-A PREROUTING_ZONES -g PRE_FedoraServer
*****************************

-A PRE_FedoraServer -j PRE_FedoraServer_log
-A PRE_FedoraServer -j PRE_FedoraServer_deny
-A PRE_FedoraServer -j PRE_FedoraServer_allow
-A PRE_FedoraServer_allow -p tcp -m tcp --dport 2222 -j MARK --set-xmark 0x64/0xffffffff
-A PRE_FedoraServer_allow -p tcp -m tcp --dport 80 -j MARK --set-xmark 0x65/0xffffffff
...

Additional info:

The extra rule is a wildcard for all interfaces:
-A PREROUTING_ZONES -g PRE_FedoraServer
It routes non-"eno1" traffic from other VMs connecting to any remote port 80 and the connections hang.

Deleting the rule solves the problem, but returns on firewalld restart.

I am probably missing something, but so far am not very impressed with this attempt to add yet another confusing and fragile layer of abstraction to iptables which I have used almost daily for the last 15 years and which just worked with thousands of rules.
Comment 1 Thomas Woerner 2015-11-19 06:19:09 EST
The rule "-A PREROUTING_ZONES -g PRE_FedoraServer" is there, because FedoraServer is the default zone on the machine.

You are using FedoraServer as the default zone and also for the interface eno1. Therefore this behaviour is expected. Changing the default zone to something else or using another zone for the eno1 interface should help in your case.
Comment 2 Andrew Haveland-Robinson 2015-11-19 22:13:54 EST
Thanks Thomas, I want to follow the new conventions for consistency and am still trying to make sense of the firewalld implementation without locking myself out.

eno1 is external and would be good in the External zone, virbr0 is obviously for the VMs - it's a new installation and a simple setup with a couple of forwarding rules, masquerading and a dynamic BANNED chain.

It appears that restarting firewalld clears and loads all rules instead of making delta changes to save time and leave custom rules intact. Defeats the object to restart firewalld and then have to run another script to undo errors and readd custom rules!
(libvirtd for example, which drives me nuts rejecting packets at the beginning of the forward chain instead of putting them in a subchain at the end)

It looks tedious for managing hundreds of rules, and am far more inclined to edit the xml files directly and use direct rules, but that makes it more difficult to do what I already do using these aliases to edit iptables:

alias lif='iptables -S FORWARD | tail -n +2 | cat -n'
alias lip='iptables -S INPUT | tail -n +2 | cat -n'
alias lop='iptables -S OUTPUT | tail -n +2 | cat -n'
alias lpost='iptables -t nat -S POSTROUTING | tail -n +2 | cat -n'
alias lpre='iptables -t nat -S PREROUTING | tail -n +2 | cat -n'

They are more immediate and show the data in the same format they are used to define, together with rule numbers to be able to insert rules quickly.

A hierarchical editor allowing everything to be viewed in order and edited and committed directly would be useful - long and pedantic command lines specified in a different format to that displayed by iptables involves a lot of editing and rearranging of concepts!

Another gripe was iptables lack of locking, as rules can be updated in real time by intrusion detectors which can cause iptables commands to fail if executed simultaneously. I solved this using flock as a wrapper which I think ought to be built in to iptables.
flock -w 5 /var/lock/iptables -c "/sbin/iptables -A $rule"
One for the wishlist!

Anyway, I hope my rant was useful - I'll go through all the documentation again and try to set it up as a model case, without hacks.
Comment 3 Andrew Haveland-Robinson 2015-11-21 12:38:42 EST
OK, on a different and freshly installed system:

firewall-cmd --set-default-zone=external
firewall-cmd --reload

iptables -S | grep FORWARD
...
-A FORWARD_IN_ZONES -i enp2s0 -g FWDI_external
-A FORWARD_IN_ZONES -g FWDI_external
-A FORWARD_OUT_ZONES -o enp2s0 -g FWDO_external
-A FORWARD_OUT_ZONES -g FWDO_external
...
Interface enp2s0 moves into external, and gives same problem:
same chains both get called regardless of interface.

Trying another approach to implement your suggestion:
firewall-cmd --zone=external --remove-interface=enp2s0
firewall-cmd --set-default-zone=FedoraWorkstation
firewall-cmd --zone=external --add-interface=enp2s0
firewall-cmd --reload

iptables -S | grep FORWARD
...
-A FORWARD_IN_ZONES -i enp2s0 -g FWDI_external
-A FORWARD_IN_ZONES -g FWDI_FedoraWorkstation
-A FORWARD_OUT_ZONES -o enp2s0 -g FWDO_external
-A FORWARD_OUT_ZONES -g FWDO_FedoraWorkstation
...

Success!
However, I fail to see the logic of having to set an unused zone to be a default in order for forwarding to work correctly and not catch unintended packets.
This is quite unintuitive.

If FWDI_FedoraWorkstation is unused and empty, then rule
-A FORWARD_IN_ZONES -g FWDI_FedoraWorkstation
doesn't need to exist!

Perhaps a check could be made to avoid this condition?

Regards, Andy.
Comment 4 Fedora End Of Life 2016-07-19 14:30:27 EDT
Fedora 22 changed to end-of-life (EOL) status on 2016-07-19. Fedora 22 is
no longer maintained, which means that it will not receive any further
security or bug fix updates. As a result we are closing this bug.

If you can reproduce this bug against a currently maintained version of
Fedora please feel free to reopen this bug against that version. If you
are unable to reopen this bug, please file a new report against the
current release. If you experience problems, please add a comment to this
bug.

Thank you for reporting this bug and we are sorry it could not be fixed.

Note You need to log in before you can comment on or make changes to this bug.