Bug 1940928
| Summary: | Firewalld direct rule ordering issue. | |||
|---|---|---|---|---|
| Product: | Red Hat Enterprise Linux 7 | Reporter: | Justin <jherron> | |
| Component: | firewalld | Assignee: | Eric Garver <egarver> | |
| Status: | CLOSED WONTFIX | QA Contact: | qe-baseos-daemons | |
| Severity: | medium | Docs Contact: | ||
| Priority: | unspecified | |||
| Version: | 7.9 | CC: | snemec, todoleza | |
| Target Milestone: | rc | Keywords: | Upstream | |
| Target Release: | --- | Flags: | pm-rhel:
mirror+
|
|
| Hardware: | All | |||
| OS: | Linux | |||
| Whiteboard: | ||||
| Fixed In Version: | Doc Type: | If docs needed, set a value | ||
| Doc Text: | Story Points: | --- | ||
| Clone Of: | ||||
| : | 1949552 (view as bug list) | Environment: | ||
| Last Closed: | 2021-04-14 14:23:30 UTC | Type: | Bug | |
| Regression: | --- | Mount Type: | --- | |
| Documentation: | --- | CRM: | ||
| Verified Versions: | Category: | --- | ||
| oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | ||
| Cloudforms Team: | --- | Target Upstream Version: | ||
| Embargoed: | ||||
| Bug Depends On: | ||||
| Bug Blocks: | 1949552 | |||
This issue was introduced in commit 3451763190a7 ("firewall.core.ipXtables: Split up source and dest addresses for transaction"). That commit was to work around a limitation in iptables-restore which doesn't support -s/-d with multiple addresses.
A simple work around is to split direct rules with multiple addresses in -s and -d into multiple direct rules.
e.g.
instead of
# firewall-cmd --direct --add-rule ipv4 filter OUTPUT 2 -p udp -d 10.0.0.0/8,172.16.0.0/16,192.168.0.0/24 -j ACCEPT
use three rules
# firewall-cmd --direct --add-rule ipv4 filter OUTPUT 2 -p udp -d 10.0.0.0/8 -j ACCEPT
# firewall-cmd --direct --add-rule ipv4 filter OUTPUT 2 -p udp -d 172.16.0.0/16 -j ACCEPT
# firewall-cmd --direct --add-rule ipv4 filter OUTPUT 2 -p udp -d 192.168.0.0/24 -j ACCEPT
Ahh Okay,
Good to know I was in the right area so to speak, but I proposed two workarounds as well to the case I have open, but the documentation ( ie man-pages ) as well as the a few kcs articles we have that point to the man pages ( ie man 5 firewall.direct and man 8 iptables ) which imply this is a valid configuration (ie Using a list of subnets or host addresses with the -d argument ).
I could be somewhat off base, but If we don't plan to fix this due to the adoption of nftables, are we able to make an amendment in man 5 firewalld.direct advising when using iptables as a backend? I was planning on making a KCS article addressing this if not already made.
------------------------------------------
Documentation
------------------------------------------
man 5 firewalld.direct
Direct configuration gives a more direct access to the firewall. It requires user to know basic ip(6)tables/ebtables concepts, i.e. table
(filter/mangle/nat/...), chain (INPUT/OUTPUT/FORWARD/...), commands (-A/-D/-I/...), parameters (-p/-s/-d/-j/...) and targets (ACCEPT/DROP/REJECT/...). Direct
configuration should be used only as a last resort when it's not possible to use firewalld.zone(5). See also Direct Options in firewall-cmd(1).
man 8 iptables
[!] -d, --destination address[/mask][,...]
Destination specification. See the description of the -s (source) flag for a detailed description of the syntax. The flag --dst is an alias for this
option.
------------------------------------------
WORKAROUNDS
------------------------------------------
[1] Don't use a list of addresses or networks with the -d argument, which will give you the correct ordering.
]# firewall-cmd --perm --direct --add-rule ipv4 filter OUTPUT 0 -m state --state ESTABLISHED,RELATED -j ACCEPT
]# firewall-cmd --perm --direct --add-rule ipv4 filter OUTPUT 2 -p udp -d 10.0.0.0/8 -j ACCEPT
]# firewall-cmd --perm --direct --add-rule ipv4 filter OUTPUT 2 -p udp -d 172.16.0.0/16 -j ACCEPT
]# firewall-cmd --perm --direct --add-rule ipv4 filter OUTPUT 2 -p udp -d 192.168.0.0/24 -j ACCEPT
]# firewall-cmd --perm --direct --add-rule ipv4 filter OUTPUT 2 -p tcp -d 10.0.0.0/8 -j ACCEPT
]# firewall-cmd --perm --direct --add-rule ipv4 filter OUTPUT 2 -p tcp -d 172.16.0.0/16 -j ACCEPT
]# firewall-cmd --perm --direct --add-rule ipv4 filter OUTPUT 2 -p tcp -d 192.168.0.0/24 -j ACCEPT
]# firewall-cmd --perm --direct --add-rule ipv4 filter OUTPUT 9 -j DROP
]# iptables -t filter -nvL OUTPUT_direct
Chain OUTPUT_direct (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
0 0 ACCEPT udp -- * * 0.0.0.0/0 10.0.0.0/8
0 0 ACCEPT udp -- * * 0.0.0.0/0 172.16.0.0/16
0 0 ACCEPT udp -- * * 0.0.0.0/0 192.168.0.0/24
0 0 ACCEPT tcp -- * * 0.0.0.0/0 10.0.0.0/8
0 0 ACCEPT tcp -- * * 0.0.0.0/0 172.16.0.0/16
0 0 ACCEPT tcp -- * * 0.0.0.0/0 192.168.0.0/24
8 608 DROP all -- * * 0.0.0.0/0 0.0.0.0/0
[2] Use ipset lists
Setting and Controlling IP sets using firewalld
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-setting_and_controlling_ip_sets_using_firewalld
firewall-cmd --permanent --new-ipset=allowed_out --type=hash:net
printf "172.16.0.0/16\n192.168.0.0/24\n10.0.0.0/8\n" > allowed.txt
firewall-cmd --permanent --ipset=allowed_out --add-entries-from-file=allowed.txt
/* Then create the rules.
firewall-cmd --permanent --direct --add-rule ipv4 filter OUTPUT 0 -m state --state RELATED,ESTABLISHED -j ACCEPT
firewall-cmd --permanent --direct --add-rule ipv4 filter OUTPUT 1 -m set --match-set allowed_out src -j ACCEPT
firewall-cmd --permanent --direct --add-rule ipv4 filter OUTPUT 9 -j DROP
firewall-cmd --reload
iptables -t filter -nvL OUTPUT_direct
Chain OUTPUT_direct (1 references)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 match-set allowed_out src
0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0
firewalld]# ipset -L
Name: allowed_out
Type: hash:net
Revision: 6
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 568
References: 1
Number of entries: 3
Members:
172.16.0.0/16
192.168.0.0/24
10.0.0.0/8
(In reply to Justin from comment #4) > Ahh Okay, > > Good to know I was in the right area so to speak, but I proposed two > workarounds as well to the case I have open, but the documentation ( ie > man-pages ) as well as the a few kcs articles we have that point to the man > pages ( ie man 5 firewall.direct and man 8 iptables ) which imply this is a > valid configuration (ie Using a list of subnets or host addresses with the > -d argument ). > > I could be somewhat off base, but If we don't plan to fix this due to the > adoption of nftables, are we able to make an amendment in man 5 > firewalld.direct advising when using iptables as a backend? I was planning > on making a KCS article addressing this if not already made. I will investigate fixing this. direct rules are still applicable when using the nftables backend. Although given the easy workaround I'm not sure the fix would be eligible for RHEL-7. Ack Quality Engineering Management has reviewed and declined this request. You may appeal this decision by reopening this request. |
Description of problem: Not sure if this has been reported yet but I found an ordering issue to affect all chains in any table when using firewalld direct interface. An ordering issue occurs in firewalld direct rules when using the argument -d subnet/mask,[.../..] (multiple network addresses or multiple single host addresses). I have tracked this down to /usr/lib/python2.7/site-packages/firewall/core/fw_direct.py To demonstrate this, going to just stick the private networks defined in RFC1918 10.0.0.0/8,172.16.0.0/16,192.168.0.0/24 in the example below. [1] firewall-cmd --direct --add-rule ipv4 filter OUTPUT 0 -m state --state ESTABLISHED,RELATED -j ACCEPT [2] firewall-cmd --direct --add-rule ipv4 filter OUTPUT 2 -p tcp -d 10.0.0.0/8,172.16.0.0/16,192.168.0.0/24 -j ACCEPT [3] firewall-cmd --direct --add-rule ipv4 filter OUTPUT 2 -p udp -d 10.0.0.0/8,172.16.0.0/16,192.168.0.0/24 -j ACCEPT [4] firewall-cmd --direct --add-rule ipv4 filter OUTPUT 9 -j DROP The above results in the below rulesets being injected into iptables in like below, we we can see the DROP rules is in the wrong place ( ie position 4 when it should be position 8) ]# iptables -t filter -nvL OUTPUT_direct Chain OUTPUT_direct (1 references) pkts bytes target prot opt in out source destination 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED 0 0 ACCEPT tcp -- * * 0.0.0.0/0 192.168.0.0/24 0 0 ACCEPT udp -- * * 0.0.0.0/0 192.168.0.0/24 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 0 0 ACCEPT udp -- * * 0.0.0.0/0 172.16.0.0/16 0 0 ACCEPT udp -- * * 0.0.0.0/0 10.0.0.0/8 0 0 ACCEPT tcp -- * * 0.0.0.0/0 172.16.0.0/16 0 0 ACCEPT tcp -- * * 0.0.0.0/0 10.0.0.0/8 But if you change the input order to something like below in [5-8] firewall-cmd --direct --remove-rules ipv4 filter OUTPUT [5] firewall-cmd --direct --add-rule ipv4 filter OUTPUT 0 -m state --state ESTABLISHED,RELATED -j ACCEPT [6] firewall-cmd --direct --add-rule ipv4 filter OUTPUT 9 -j DROP [7] firewall-cmd --direct --add-rule ipv4 filter OUTPUT 2 -p udp -d 10.0.0.0/8,172.16.0.0/16,192.168.0.0/24 -j ACCEPT [8] firewall-cmd --direct --add-rule ipv4 filter OUTPUT 2 -p tcp -d 10.0.0.0/8,172.16.0.0/16,192.168.0.0/24 -j ACCEPT You get the expected ordering iptables -t filter -nvL OUTPUT_direct Chain OUTPUT_direct (1 references) pkts bytes target prot opt in out source destination 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED 0 0 ACCEPT tcp -- * * 0.0.0.0/0 192.168.0.0/24 0 0 ACCEPT udp -- * * 0.0.0.0/0 192.168.0.0/24 0 0 ACCEPT udp -- * * 0.0.0.0/0 172.16.0.0/16 0 0 ACCEPT udp -- * * 0.0.0.0/0 10.0.0.0/8 0 0 ACCEPT tcp -- * * 0.0.0.0/0 172.16.0.0/16 0 0 ACCEPT tcp -- * * 0.0.0.0/0 10.0.0.0/8 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 This confirms a segmentation in how the rules are interpreted in firewalld --direct vs iptables. Meaning firewalld sees [1-4] or [5-8] as 4 direct rules but iptables sees [1-4] or [5-8] as eight individual rules. But this doesn't just affect the output chain in the filter table. This affects all tables and chains with iptables as a result of how firewalld passes the direct rule sets into iptables. I was also able to confirm this same behavior in RHEL 8 using iptables as the default backend. A more verbose output with debug logs. [1] firewall-cmd --direct --add-rule ipv4 filter OUTPUT 0 -m state --state ESTABLISHED,RELATED -j ACCEPT 2021-03-19 10:41:50 DEBUG2: <class 'firewall.core.ipXtables.ip4tables'>: /usr/sbin/iptables-restore /run/firewalld/temp.2TyrMn: 81 1: *filter 2: -I OUTPUT_direct 1 -m state --state ESTABLISHED,RELATED -j ACCEPT 3: COMMIT 2021-03-19 10:41:50 DEBUG4: <class 'firewall.core.fw_transaction.FirewallTransaction'>.post() 2021-03-19 10:41:50 DEBUG4: <class 'firewall.core.fw_transaction.FirewallTransaction'>.post() 2021-03-19 10:41:50 DEBUG1: direct.RuleAdded('ipv4', 'filter', 'OUTPUT', 0, '-m','state','--state','ESTABLISHED,RELATED','-j','ACCEPT') [2] firewall-cmd --direct --add-rule ipv4 filter OUTPUT 2 -p tcp -d 10.0.0.0/8,172.16.0.0/16,192.168.0.0/24 -j ACCEPT 2021-03-19 10:42:22 DEBUG4: <class 'firewall.core.fw_transaction.FirewallTransaction'>.pre() 2021-03-19 10:42:22 DEBUG2: <class 'firewall.core.ipXtables.ip4tables'>: /usr/sbin/iptables-restore /run/firewalld/temp.gumOoO: 172 1: *filter 2: -I OUTPUT_direct 2 -p tcp -d 10.0.0.0/8 -j ACCEPT 3: -I OUTPUT_direct 2 -p tcp -d 172.16.0.0/16 -j ACCEPT 4: -I OUTPUT_direct 2 -p tcp -d 192.168.0.0/24 -j ACCEPT 5: COMMIT 2021-03-19 10:42:22 DEBUG4: <class 'firewall.core.fw_transaction.FirewallTransaction'>.post() 2021-03-19 10:42:22 DEBUG4: <class 'firewall.core.fw_transaction.FirewallTransaction'>.post() 2021-03-19 10:42:22 DEBUG1: direct.RuleAdded('ipv4', 'filter', 'OUTPUT', 2, '-p','tcp','-d','10.0.0.0/8,172.16.0.0/16,192.168.0.0/24','-j','ACCEPT') [3] firewall-cmd --direct --add-rule ipv4 filter OUTPUT 2 -p udp -d 10.0.0.0/8,172.16.0.0/16,192.168.0.0/24 -j ACCEPT 2021-03-19 10:43:23 DEBUG2: <class 'firewall.core.ipXtables.ip4tables'>: /usr/sbin/iptables-restore /run/firewalld/temp.C4Gf08: 172 1: *filter 2: -I OUTPUT_direct 3 -p udp -d 10.0.0.0/8 -j ACCEPT 3: -I OUTPUT_direct 3 -p udp -d 172.16.0.0/16 -j ACCEPT 4: -I OUTPUT_direct 3 -p udp -d 192.168.0.0/24 -j ACCEPT 5: COMMIT 2021-03-19 10:43:23 DEBUG4: <class 'firewall.core.fw_transaction.FirewallTransaction'>.post() 2021-03-19 10:43:23 DEBUG4: <class 'firewall.core.fw_transaction.FirewallTransaction'>.post() 2021-03-19 10:43:23 DEBUG1: direct.RuleAdded('ipv4', 'filter', 'OUTPUT', 2, '-p','udp','-d','10.0.0.0/8,172.16.0.0/16,192.168.0.0/24','-j','ACCEPT') [4] firewall-cmd --direct --add-rule ipv4 filter OUTPUT 9 -j DROP 2021-03-19 10:43:49 DEBUG2: <class 'firewall.core.ipXtables.ip4tables'>: /usr/sbin/iptables-restore /run/firewalld/temp.4Vfavc: 42 1: *filter 2: -I OUTPUT_direct 4 -j DROP 3: COMMIT 2021-03-19 10:43:49 DEBUG4: <class 'firewall.core.fw_transaction.FirewallTransaction'>.post() 2021-03-19 10:43:49 DEBUG4: <class 'firewall.core.fw_transaction.FirewallTransaction'>.post() 2021-03-19 10:43:49 DEBUG1: direct.RuleAdded('ipv4', 'filter', 'OUTPUT', 9, '-j','DROP') iptables -t filter -nvL OUTPUT_direct Chain OUTPUT_direct (1 references) pkts bytes target prot opt in out source destination 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED 0 0 ACCEPT tcp -- * * 0.0.0.0/0 192.168.0.0/24 0 0 ACCEPT udp -- * * 0.0.0.0/0 192.168.0.0/24 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 0 0 ACCEPT udp -- * * 0.0.0.0/0 172.16.0.0/16 0 0 ACCEPT udp -- * * 0.0.0.0/0 10.0.0.0/8 0 0 ACCEPT tcp -- * * 0.0.0.0/0 172.16.0.0/16 0 0 ACCEPT tcp -- * * 0.0.0.0/0 10.0.0.0/8