Created attachment 699520 [details] Patch to stop default zone rules being applied to all zones Description of problem: Any traffic allowed in the default zone is allowed in all other zones unless explicitly denied in the relevent zone. Likewise any traffic denied in the default zone is denied in all other zones unless explicitly allowed in the relevent zone. Version-Release number of selected component (if applicable): firewalld-0.2.12-2.fc18.noarch How reproducible: Always Steps to Reproduce: 1. For example: # firewall-cmd --zone=public --list-services mdns dhcpv6-client ssh # firewall-cmd --zone=home --list-services ipp-client mdns dhcpv6-client ssh samba-client 2. From another host, attempt using ftp to an interface in the home zone: # ftp 192.168.0.10 ftp: connect: No route to host 3. Add ftp as allowed service in public zone: # firewall-cmd --zone=public --add-service=ftp 4. Again attempt to connect from another host to ftp via i/f in home zone # ftp 192.168.0.10 Connected to 192.168.0.10 (192.168.0.10). 220 (vsFTPd 3.0.2) Name (192.168.0.10:username): Actual results: ftp access is permitted via interface in home zone although ftp service is not permitted in home zone. Expected results: ftp access denied. Additional info: The ftp connection was being made via eth0.50. The reason the ftp access is permitted is due to the last entry in the INPUT_ZONES chain (see below). The way the chain is constructed is that each entry is checked in turn, even after the relevant interface has been matched. The "+" for the in interface in the last entry matches all interfaces, and so the IN_ZONE_public is called for all interfaces, unless the traffic has already been allowed or denied. Chain INPUT_ZONES (1 references) pkts bytes target prot opt in out source destination 988 107K IN_ZONE_public all -- eth1 * 0.0.0.0/0 0.0.0.0/0 856 78652 IN_ZONE_home all -- eth0.50 * 0.0.0.0/0 0.0.0.0/0 0.0.0.0/0 5461 514K IN_ZONE_public all -- + * 0.0.0.0/0 0.0.0.0/0 Not only is the above checking the public zone configuration for all zones, it is unnecessary to check subsequent entries in the chain once it has matched the interface. Rather than doing a JUMP (-j), it would be better to use a GOTO (-g) (it stops the final rule matching for all zones, and is more efficient). If this change is made, the final entry matching "+" is unnecessary, since explicit rules are created for all interfaces. It may be that the entry is there as a backstop in case for some reason a rule has not been created for a zone, but in that case the safe and secure approach would be to drop or reject the traffic, which will happen by default if the rule with + for the interface is omitted. The same applies for the FORWARD_ZONES chain. The attached patch changes the JUMPs to GOTOs in the INPUT_ZONES and FORWARD_ZONES chains, which fixes the problem identified, and improves the efficiency. The patch does not remove the final entry (two for FORWARD_ZONES) since I haven't worked out how to do that yet.
Thank you for the thorough investigation and description ! (In reply to comment #0) > Created attachment 699520 [details] > Patch to stop default zone rules being applied to all zones Pushed upstream http://git.fedorahosted.org/cgit/firewalld.git/commit/?id=3253df596ab6f5e43d22dff3049600fc0de9c41b with a little tweak: for example trusted zone has default target ACCEPT, which makes a '-A INPUT_ZONES -i <iface> -j ACCEPT' rule. We can't use -g ACCEPT therefore I've added that condition. > If this change is made, the final entry matching "+" is unnecessary, since > explicit rules are created for all interfaces. It may be that the entry is > there as a backstop in case for some reason a rule has not been created for > a zone, but in that case the safe and secure approach would be to drop or > reject the traffic, which will happen by default if the rule with + for the > interface is omitted. This was added with http://git.fedorahosted.org/cgit/firewalld.git/commit/?id=4ec98e390102b5c065f7b2855204e01c08af88c1 See for example bug #882736, comment #5 or bug #821938, comment #5 for background. > The patch does not remove the final entry (two for > FORWARD_ZONES) since I haven't worked out how to do that yet. You'd need to remove this piece of code http://git.fedorahosted.org/cgit/firewalld.git/commit/?id=8b7a4902b5c248bb03570d8a6d143d7f75972f29 but I'm afraid we need it ;-)
firewalld-0.2.12-3.fc18 has been submitted as an update for Fedora 18. https://admin.fedoraproject.org/updates/firewalld-0.2.12-3.fc18
Package firewalld-0.2.12-3.fc18: * should fix your issue, * was pushed to the Fedora 18 testing repository, * should be available at your local mirror within two days. Update it with: # su -c 'yum update --enablerepo=updates-testing firewalld-0.2.12-3.fc18' as soon as you are able to. Please go to the following url: https://admin.fedoraproject.org/updates/FEDORA-2013-2827/firewalld-0.2.12-3.fc18 then log in and leave karma (feedback).
firewalld-0.2.12-3.fc18 has been pushed to the Fedora 18 stable repository. If problems still persist, please make note of it in this bug report.
Yum update to firewalld-0.2.12-3.fc18 broke my pretty basic setup with only two ethernet interfaces: one internal (private IPv4 address) and one external (public IPv4 address) with IP masquerading. There seems to be missng some "-j ACCEPT" rule when going from the internal to the external interface. I "fixed" it with "firewall-cmd --direct --passthrough ipv4 -I FORWARD -j ACCEPT".
Created attachment 704807 [details] list of FORWARD chains from iptables -nvL Check the attached file broken-firewalld-0.2.12-3.fc18.txt - please note that the first rule in the FORWARD chain is the result of "firewall-cmd --direct --passthrough ipv4 -I FORWARD -j ACCEPT" which I had to add to make the IP masquerading work. I have <masquerade enabled="Yes"/> in /etc/firewalld/zones/external.xml and that was enough to make it work before firewalld-0.2.12-3.fc18.
Leoš, The change from jump to goto, although it fixed the problem reported, has introduced a problem in the FORWARD processing, as you identify. The problem is with the following chain: Chain FORWARD_ZONES (1 references) pkts bytes target prot opt in out source destination 0 0 FWDI_ZONE_internal all -- eth0 * 0.0.0.0/0 0.0.0.0/0 [goto] 0 0 FWDO_ZONE_internal all -- * eth0 0.0.0.0/0 0.0.0.0/0 [goto] 0 0 FWDI_ZONE_external all -- eth1 * 0.0.0.0/0 0.0.0.0/0 [goto] 0 0 FWDO_ZONE_external all -- * eth1 0.0.0.0/0 0.0.0.0/0 [goto] 0 0 FWDO_ZONE_public all -- * + 0.0.0.0/0 0.0.0.0/0 [goto] 0 0 FWDI_ZONE_public all -- + * 0.0.0.0/0 0.0.0.0/0 [goto] The [goto] entries mean the if, or example, a packet matches on eth0 input, then it will not check the out entry for eth1. The only way I can see to make this work would be the following iptables commands: iptables -Z FORWARD_ZONES iptables -A FORWARD_ZONES -i eth0 -j FWDI_ZONE_internal iptables -A FORWARD_ZONES -o eth0 -j FWDO_ZONE_internal iptables -A FORWARD_ZONES -i eth1 -j FWDI_ZONE_external iptables -A FORWARD_ZONES -o eth1 -j FWDO_ZONE_external iptables -A FORWARD_ZONES -i eth0 -j RETURN iptables -A FORWARD_ZONES -o eth0 -j RETURN iptables -A FORWARD_ZONES -i eth1 -j RETURN iptables -A FORWARD_ZONES -o eth1 -j RETURN iptables -A FORWARD_ZONES -o + -j FWDO_ZONE_public iptables -A FORWARD_ZONES -i + -j FWDI_ZONE_public This would then look like: Chain FORWARD_ZONES (1 references) pkts bytes target prot opt in out source destination 0 0 FWDI_ZONE_internal all -- eth0 * 0.0.0.0/0 0.0.0.0/0 0 0 FWDO_ZONE_internal all -- * eth0 0.0.0.0/0 0.0.0.0/0 0 0 FWDI_ZONE_external all -- eth1 * 0.0.0.0/0 0.0.0.0/0 0 0 FWDO_ZONE_external all -- * eth1 0.0.0.0/0 0.0.0.0/0 0 0 RETURN all -- eth0 * 0.0.0.0/0 0.0.0.0/0 0 0 RETURN all -- * eth0 0.0.0.0/0 0.0.0.0/0 0 0 RETURN all -- eth1 * 0.0.0.0/0 0.0.0.0/0 0 0 RETURN all -- * eth1 0.0.0.0/0 0.0.0.0/0 0 0 FWDO_ZONE_public all -- * + 0.0.0.0/0 0.0.0.0/0 0 0 FWDI_ZONE_public all -- + * 0.0.0.0/0 0.0.0.0/0 The same approach could be taken for the INPUT_ZONES and OUTPUT_ZONES chains, but with a loss of efficiency compared to the gotos.
Quentin, I was happily composing my own iptables rules before firewalld existed, and I guess that I will have to revert to that again. "rpm -e firewalld" seems to be the key command I need to execute. Another weirdness - why are there these two last rules in the FORWARD chain? 0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0 0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited This explains why traceroute was working for me, but everything else was not. That is just plain wrong...
Further to my comment #c7, on further investigation I cannot see any way to configure rules to be added into the FWDI_ZONE_* and FWDO_ZONE_* chains, although the full structure of the chains is set up. The changes I have outlined above are necessary though since the rule that allows outgoing traffic to the external zone is the ACCEPT in the FWDO_ZONE_external chain, and with the rules as they are that is never reached following the goto to FWDI_ZONE_external. Is it correct that it is not possible to configure allowing forwarding other than traffic forwarded out on the external zone? I also overlooked in my previous comment that there are no equivalent chains for filtering OUTPUT packets and so the comment regarding OUTPUT_ZONES isn't relevant.
Thomas has suggested: -A FORWARD_ZONES -i eth1 -j FWDI_ZONE_external -A FORWARD_ZONES -o eth1 -g FWDO_ZONE_external -A FORWARD_ZONES -i eth0 -j FWDI_ZONE_internal -A FORWARD_ZONES -o eth0 -g FWDO_ZONE_internal that way we wouldn't need the -j RETURN The patch would be something like: src/firewall/core/fw_zone.py @@ -275 - action = "-g" if "_ZONE_" in target else "-j" + action = "-g" if ("_ZONE_" in target and "FWDI" not in target) else "-j" What do you think Quentin ?
Jiri, Unfortunately I don't think that works. Consider the situation where a packet comes in on eth0 and goes out on eth1; the 3rd rule, covering the packet incoming, will not be hit due to the goto in the second rule. An alternative that is closer would be: -A FORWARD_ZONES -i eth1 -j FWDI_ZONE_external -A FORWARD_ZONES -i eth0 -j FWDI_ZONE_internal -A FORWARD_ZONES -o eth1 -g FWDO_ZONE_external -A FORWARD_ZONES -o eth0 -g FWDO_ZONE_internal so all the checks in one direction are done first with a jump, and then a goto for the second direction. This would ensure that the two chains that are supposed to be called are indeed called. The problem with this is that if a packet comes in on an interface other than eth0 or eth1, but leaves on, say eth1, then the final two rules, viz iptables -A FORWARD_ZONES -o + -j FWDO_ZONE_public iptables -A FORWARD_ZONES -i + -j FWDI_ZONE_public won't get hit, which I understand from earlier comments are needed. However, as per my initial bug report, it is essential that these last two rules aren't hit for a packet direction for which there has already been a match. Having thought about it further, my original suggestion in comment #7 has the same problem. I think what is needed is iptables -A FORWARD_ZONES -j FWDI_ZONES iptables -A FORWARD_ZONES -g FWDO_ZONES iptables -A FWDI_ZONES -i eth0 -g FWDI_ZONE_internal iptables -A FWDO_ZONES -o eth0 -g FWDO_ZONE_internal iptables -A FWDI_ZONES -i eth1 -g FWDI_ZONE_external iptables -A FWDO_ZONES -o eth1 -g FWDO_ZONE_external iptables -A FWDI_ZONES -i + -g FWDI_ZONE_public iptables -A FWDO_ZONES -o + -g FWDO_ZONE_public The above is probably the sequence you would want to generate it, but it would result in the following (note the one JUMP, the remaining are GOTOs): Chain FORWARD_ZONES (1 references) pkts bytes target prot opt in out source destination 0 0 FWDI_ZONES all -- * * 0.0.0.0/0 0.0.0.0/0 0 0 FWDO_ZONES all -- * * 0.0.0.0/0 0.0.0.0/0 [goto] Chain FWDI_ZONES (1 references) pkts bytes target prot opt in out source destination 0 0 FWDI_ZONE_internal all -- eth0 * 0.0.0.0/0 0.0.0.0/0 [goto] 0 0 FWDI_ZONE_external all -- eth1 * 0.0.0.0/0 0.0.0.0/0 [goto] 0 0 FWDI_ZONE_public all -- + * 0.0.0.0/0 0.0.0.0/0 [goto] Chain FWDO_ZONES (1 references) pkts bytes target prot opt in out source destination 0 0 FWDO_ZONE_internal all -- * eth0 0.0.0.0/0 0.0.0.0/0 [goto] 0 0 FWDO_ZONE_external all -- * eth1 0.0.0.0/0 0.0.0.0/0 [goto] 0 0 FWDO_ZONE_public all -- * + 0.0.0.0/0 0.0.0.0/0 [goto] I think that's about as neat as its going to get. As an aside, can you confirm whether I am right that at the moment, using the GUI or firewall-cmd, there is no way to configure any rules for forwarding, or for OUTPUT, in other words it isn't possible to generate any entries for the chains we are discussing above?
Created attachment 706135 [details] suggested patch Great idea ! This patch creates the following rules: -A FORWARD -j FORWARD_IN_ZONES -A FORWARD -j FORWARD_OUT_ZONES -A FORWARD_IN_ZONES -i eth1 -g FWDI_ZONE_external -A FORWARD_IN_ZONES -i eth0 -g FWDI_ZONE_internal -A FORWARD_IN_ZONES -g FWDI_ZONE_public -A FORWARD_OUT_ZONES -o eth1 -g FWDO_ZONE_external -A FORWARD_OUT_ZONES -o eth0 -g FWDO_ZONE_internal -A FORWARD_OUT_ZONES -g FWDO_ZONE_public which should be basically the same as you suggested.
(In reply to comment #11) > there is no way to configure any rules for > forwarding, or for OUTPUT, in other words it isn't possible to generate any > entries for the chains we are discussing above? I think no, there's no way yet, but I may be wrong. Thomas ?
(In reply to comment #12) > Created attachment 706135 [details] > suggested patch > > Great idea ! > > This patch creates the following rules: > > -A FORWARD -j FORWARD_IN_ZONES > -A FORWARD -j FORWARD_OUT_ZONES > -A FORWARD_IN_ZONES -i eth1 -g FWDI_ZONE_external > -A FORWARD_IN_ZONES -i eth0 -g FWDI_ZONE_internal > -A FORWARD_IN_ZONES -g FWDI_ZONE_public > -A FORWARD_OUT_ZONES -o eth1 -g FWDO_ZONE_external > -A FORWARD_OUT_ZONES -o eth0 -g FWDO_ZONE_internal > -A FORWARD_OUT_ZONES -g FWDO_ZONE_public > > which should be basically the same as you suggested. That looks good to me. It's nice to see the "+"s not there, since they are acting as "*", and the only other change as I see it is a change of the zone names that I used.
firewalld-0.2.12-4.fc18 has been submitted as an update for Fedora 18. https://admin.fedoraproject.org/updates/firewalld-0.2.12-4.fc18
Package firewalld-0.2.12-4.fc18: * should fix your issue, * was pushed to the Fedora 18 testing repository, * should be available at your local mirror within two days. Update it with: # su -c 'yum update --enablerepo=updates-testing firewalld-0.2.12-4.fc18' as soon as you are able to. Please go to the following url: https://admin.fedoraproject.org/updates/FEDORA-2013-3535/firewalld-0.2.12-4.fc18 then log in and leave karma (feedback).
firewalld-0.2.12-4.fc18 has been pushed to the Fedora 18 stable repository. If problems still persist, please make note of it in this bug report.