import CS git firewalld-0.9.11-11.el8_10

This commit is contained in:
AlmaLinux RelEng Bot 2026-05-26 12:16:34 -04:00
parent bcfc03d784
commit 260dd1051c
7 changed files with 853 additions and 1 deletions

View File

@ -0,0 +1,96 @@
From 84c7032bd1a744fc1c363d9836151b497064e402 Mon Sep 17 00:00:00 2001
From: Eric Garver <eric@garver.life>
Date: Tue, 28 Oct 2025 15:59:26 -0400
Subject: [PATCH 32/37] v2.4.0: chore(icmp): add all icmptypes to ICMP_TYPES
dict
We can then use this as a source of truth for types/codes.
(cherry picked from commit b121faab666faddf7181d21691ee6e8a13b30dbe)
---
src/firewall/core/icmp.py | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/src/firewall/core/icmp.py b/src/firewall/core/icmp.py
index ed030026a111..87f87ab1c49e 100644
--- a/src/firewall/core/icmp.py
+++ b/src/firewall/core/icmp.py
@@ -25,32 +25,42 @@ __all__ = [ "ICMP_TYPES", "ICMPV6_TYPES",
ICMP_TYPES = {
"echo-reply": "0/0",
"pong": "0/0",
+ "destination-unreachable": "3/0",
"network-unreachable": "3/0",
+ "tos-network-unreachable": "3/0",
"host-unreachable": "3/1",
+ "tos-host-unreachable": "3/1",
"protocol-unreachable": "3/2",
"port-unreachable": "3/3",
"fragmentation-needed": "3/4",
"source-route-failed": "3/5",
+ # RFC-1112 Section 3.2.2.1 defines type 3, code 6-12
"network-unknown": "3/6",
"host-unknown": "3/7",
"network-prohibited": "3/9",
"host-prohibited": "3/10",
"TOS-network-unreachable": "3/11",
"TOS-host-unreachable": "3/12",
+ # RFC-1812 Section 5.2.7.1 defines type 3, code 13-15
"communication-prohibited": "3/13",
"host-precedence-violation": "3/14",
"precedence-cutoff": "3/15",
"source-quench": "4/0",
"network-redirect": "5/0",
+ "redirect": "5/0",
"host-redirect": "5/1",
+ "tos-host-redirect": "5/1",
"TOS-network-redirect": "5/2",
+ "tos-network-redirect": "5/2",
"TOS-host-redirect": "5/3",
"echo-request": "8/0",
"ping": "8/0",
"router-advertisement": "9/0",
"router-solicitation": "10/0",
+ "time-exceeded": "11/0",
"ttl-zero-during-transit": "11/0",
"ttl-zero-during-reassembly": "11/1",
+ "parameter-problem": "12/0",
"ip-header-bad": "12/0",
"required-option-missing": "12/1",
"timestamp-request": "13/0",
@@ -60,13 +70,19 @@ ICMP_TYPES = {
}
ICMPV6_TYPES = {
+ "destination-unreachable": "1/0",
"no-route": "1/0",
"communication-prohibited": "1/1",
+ "beyond-scope": "1/2",
"address-unreachable": "1/3",
"port-unreachable": "1/4",
+ "failed-policy": "1/5",
+ "reject-route": "1/6",
"packet-too-big": "2/0",
+ "time-exceeded": "3/0",
"ttl-zero-during-transit": "3/0",
"ttl-zero-during-reassembly": "3/1",
+ "parameter-problem": "4/0",
"bad-header": "4/0",
"unknown-header-type": "4/1",
"unknown-option": "4/2",
@@ -81,6 +97,12 @@ ICMPV6_TYPES = {
"neighbour-advertisement": "136/0",
"neigbour-advertisement": "136/0",
"redirect": "137/0",
+ # MLD is RFC-2710
+ "mld-listener-query": "130/0",
+ "mld-listener-report": "131/0",
+ "mld-listener-done": "132/0",
+ # MLDv2 is RFC-9777
+ "mld2-listener-report": "143/0",
}
def check_icmp_name(_name):
--
2.52.0

View File

@ -0,0 +1,265 @@
From 3c9a81ac67bf2a25190233e3fd20c07e7d33ba97 Mon Sep 17 00:00:00 2001
From: Eric Garver <eric@garver.life>
Date: Wed, 29 Oct 2025 11:32:35 -0400
Subject: [PATCH 33/37] v2.4.0: chore(icmp): convert type/code map to tuple
This will make it easier to use/query.
(cherry picked from commit 6c33bbcdb60e257ec1102baaff128f5b345c67f8)
---
src/firewall/core/icmp.py | 158 +++++++++++++++++-----------------
src/firewall/core/io/ipset.py | 26 ++++--
2 files changed, 100 insertions(+), 84 deletions(-)
diff --git a/src/firewall/core/icmp.py b/src/firewall/core/icmp.py
index 87f87ab1c49e..db0398eee6fd 100644
--- a/src/firewall/core/icmp.py
+++ b/src/firewall/core/icmp.py
@@ -20,89 +20,91 @@
#
__all__ = [ "ICMP_TYPES", "ICMPV6_TYPES",
- "check_icmp_type", "check_icmpv6_type" ]
+ "check_icmp_type_code", "check_icmpv6_type_code" ]
ICMP_TYPES = {
- "echo-reply": "0/0",
- "pong": "0/0",
- "destination-unreachable": "3/0",
- "network-unreachable": "3/0",
- "tos-network-unreachable": "3/0",
- "host-unreachable": "3/1",
- "tos-host-unreachable": "3/1",
- "protocol-unreachable": "3/2",
- "port-unreachable": "3/3",
- "fragmentation-needed": "3/4",
- "source-route-failed": "3/5",
+ # "type": (type, code, backend omit code)
+ "echo-reply": (0, 0, True),
+ "pong": (0, 0, True),
+ "destination-unreachable": (3, 0, True),
+ "network-unreachable": (3, 0, False),
+ "tos-network-unreachable": (3, 0, False),
+ "host-unreachable": (3, 1, False),
+ "tos-host-unreachable": (3, 1, False),
+ "protocol-unreachable": (3, 2, False),
+ "port-unreachable": (3, 3, False),
+ "fragmentation-needed": (3, 4, False),
+ "source-route-failed": (3, 5, False),
# RFC-1112 Section 3.2.2.1 defines type 3, code 6-12
- "network-unknown": "3/6",
- "host-unknown": "3/7",
- "network-prohibited": "3/9",
- "host-prohibited": "3/10",
- "TOS-network-unreachable": "3/11",
- "TOS-host-unreachable": "3/12",
+ "network-unknown": (3, 6, False),
+ "host-unknown": (3, 7, False),
+ "network-prohibited": (3, 9, False),
+ "host-prohibited": (3, 10, False),
+ "TOS-network-unreachable": (3, 11, False),
+ "TOS-host-unreachable": (3, 12, False),
# RFC-1812 Section 5.2.7.1 defines type 3, code 13-15
- "communication-prohibited": "3/13",
- "host-precedence-violation": "3/14",
- "precedence-cutoff": "3/15",
- "source-quench": "4/0",
- "network-redirect": "5/0",
- "redirect": "5/0",
- "host-redirect": "5/1",
- "tos-host-redirect": "5/1",
- "TOS-network-redirect": "5/2",
- "tos-network-redirect": "5/2",
- "TOS-host-redirect": "5/3",
- "echo-request": "8/0",
- "ping": "8/0",
- "router-advertisement": "9/0",
- "router-solicitation": "10/0",
- "time-exceeded": "11/0",
- "ttl-zero-during-transit": "11/0",
- "ttl-zero-during-reassembly": "11/1",
- "parameter-problem": "12/0",
- "ip-header-bad": "12/0",
- "required-option-missing": "12/1",
- "timestamp-request": "13/0",
- "timestamp-reply": "14/0",
- "address-mask-request": "17/0",
- "address-mask-reply": "18/0",
+ "communication-prohibited": (3, 13, False),
+ "host-precedence-violation": (3, 14, False),
+ "precedence-cutoff": (3, 15, False),
+ "source-quench": (4, 0, True),
+ "network-redirect": (5, 0, False),
+ "redirect": (5, 0, True),
+ "host-redirect": (5, 1, False),
+ "tos-host-redirect": (5, 1, False),
+ "TOS-network-redirect": (5, 2, False),
+ "tos-network-redirect": (5, 2, False),
+ "TOS-host-redirect": (5, 3, False),
+ "echo-request": (8, 0, True),
+ "ping": (8, 0, True),
+ "router-advertisement": (9, 0, True),
+ "router-solicitation": (10, 0, True),
+ "time-exceeded": (11, 0, True),
+ "ttl-zero-during-transit": (11, 0, False),
+ "ttl-zero-during-reassembly": (11, 1, False),
+ "parameter-problem": (12, 0, True),
+ "ip-header-bad": (12, 0, False),
+ "required-option-missing": (12, 1, False),
+ "timestamp-request": (13, 0, True),
+ "timestamp-reply": (14, 0, True),
+ "address-mask-request": (17, 0, False),
+ "address-mask-reply": (18, 0, False),
}
ICMPV6_TYPES = {
- "destination-unreachable": "1/0",
- "no-route": "1/0",
- "communication-prohibited": "1/1",
- "beyond-scope": "1/2",
- "address-unreachable": "1/3",
- "port-unreachable": "1/4",
- "failed-policy": "1/5",
- "reject-route": "1/6",
- "packet-too-big": "2/0",
- "time-exceeded": "3/0",
- "ttl-zero-during-transit": "3/0",
- "ttl-zero-during-reassembly": "3/1",
- "parameter-problem": "4/0",
- "bad-header": "4/0",
- "unknown-header-type": "4/1",
- "unknown-option": "4/2",
- "echo-request": "128/0",
- "ping": "128/0",
- "echo-reply": "129/0",
- "pong": "129/0",
- "router-solicitation": "133/0",
- "router-advertisement": "134/0",
- "neighbour-solicitation": "135/0",
- "neigbour-solicitation": "135/0",
- "neighbour-advertisement": "136/0",
- "neigbour-advertisement": "136/0",
- "redirect": "137/0",
+ # "type": (type, code, backend omit code)
+ "destination-unreachable": (1, 0, True),
+ "no-route": (1, 0, False),
+ "communication-prohibited": (1, 1, False),
+ "beyond-scope": (1, 2, False),
+ "address-unreachable": (1, 3, False),
+ "port-unreachable": (1, 4, False),
+ "failed-policy": (1, 5, False),
+ "reject-route": (1, 6, False),
+ "packet-too-big": (2, 0, True),
+ "time-exceeded": (3, 0, True),
+ "ttl-zero-during-transit": (3, 0, False),
+ "ttl-zero-during-reassembly": (3, 1, False),
+ "parameter-problem": (4, 0, True),
+ "bad-header": (4, 0, False),
+ "unknown-header-type": (4, 1, False),
+ "unknown-option": (4, 2, False),
+ "echo-request": (128, 0, True),
+ "ping": (128, 0, True),
+ "echo-reply": (129, 0, True),
+ "pong": (129, 0, True),
+ "router-solicitation": (133, 0, True),
+ "router-advertisement": (134, 0, True),
+ "neighbour-solicitation": (135, 0, True),
+ "neigbour-solicitation": (135, 0, True),
+ "neighbour-advertisement": (136, 0, True),
+ "neigbour-advertisement": (136, 0, True),
+ "redirect": (137, 0, True),
# MLD is RFC-2710
- "mld-listener-query": "130/0",
- "mld-listener-report": "131/0",
- "mld-listener-done": "132/0",
+ "mld-listener-query": (130, 0, True),
+ "mld-listener-report": (131, 0, True),
+ "mld-listener-done": (132, 0, True),
# MLDv2 is RFC-9777
- "mld2-listener-report": "143/0",
+ "mld2-listener-report": (143, 0, True),
}
def check_icmp_name(_name):
@@ -110,8 +112,8 @@ def check_icmp_name(_name):
return True
return False
-def check_icmp_type(_type):
- if _type in ICMP_TYPES.values():
+def check_icmp_type_code(_type, _code):
+ if (_type, _code) in ICMP_TYPES.values():
return True
return False
@@ -120,7 +122,7 @@ def check_icmpv6_name(_name):
return True
return False
-def check_icmpv6_type(_type):
- if _type in ICMPV6_TYPES.values():
+def check_icmpv6_type_code(_type, _code):
+ if (_type, _code) in ICMPV6_TYPES.values():
return True
return False
diff --git a/src/firewall/core/io/ipset.py b/src/firewall/core/io/ipset.py
index 1222c588a345..edb19cc784b3 100644
--- a/src/firewall/core/io/ipset.py
+++ b/src/firewall/core/io/ipset.py
@@ -35,8 +35,8 @@ from firewall.functions import checkIP, checkIP6, checkIPnMask, \
from firewall.core.io.io_object import PY2, IO_Object, \
IO_Object_ContentHandler, IO_Object_XMLGenerator
from firewall.core.ipset import IPSET_TYPES, IPSET_CREATE_OPTIONS
-from firewall.core.icmp import check_icmp_name, check_icmp_type, \
- check_icmpv6_name, check_icmpv6_type
+from firewall.core.icmp import check_icmp_name, check_icmp_type_code, \
+ check_icmpv6_name, check_icmpv6_type_code
from firewall.core.logger import log
from firewall import errors
from firewall.errors import FirewallError
@@ -216,24 +216,38 @@ class IPSet(IO_Object):
errors.INVALID_ENTRY,
"invalid protocol for family '%s' in '%s'" % \
(family, entry))
- if not check_icmp_name(splits[1]) and not \
- check_icmp_type(splits[1]):
+ if not check_icmp_name(splits[1]) and "/" not in splits[1]:
raise FirewallError(
errors.INVALID_ENTRY,
"invalid icmp type '%s' in '%s'" % \
(splits[1], entry))
+ else:
+ (_type, _code) = splits[1].split("/")
+ if not check_icmp_type_code(_type, _code):
+ raise FirewallError(
+ errors.INVALID_ENTRY,
+ "invalid icmp type '%s' in '%s'"
+ % (splits[1], entry),
+ )
elif splits[0] in [ "icmpv6", "ipv6-icmp" ]:
if family != "ipv6":
raise FirewallError(
errors.INVALID_ENTRY,
"invalid protocol for family '%s' in '%s'" % \
(family, entry))
- if not check_icmpv6_name(splits[1]) and not \
- check_icmpv6_type(splits[1]):
+ if not check_icmpv6_name(splits[1]) and "/" not in splits[1]:
raise FirewallError(
errors.INVALID_ENTRY,
"invalid icmpv6 type '%s' in '%s'" % \
(splits[1], entry))
+ else:
+ (_type, _code) = splits[1].split("/")
+ if not check_icmpv6_type_code(_type, _code):
+ raise FirewallError(
+ errors.INVALID_ENTRY,
+ "invalid icmpv6 type '%s' in '%s'"
+ % (splits[1], entry),
+ )
elif splits[0] not in [ "tcp", "sctp", "udp", "udplite" ] \
and not checkProtocol(splits[0]):
raise FirewallError(
--
2.52.0

View File

@ -0,0 +1,139 @@
From 91b01b3d98853a38761a8c2ccd1227aec94a5972 Mon Sep 17 00:00:00 2001
From: Eric Garver <eric@garver.life>
Date: Wed, 29 Oct 2025 11:49:12 -0400
Subject: [PATCH 34/37] v2.4.0: chore(nftables): simplify icmp match fragments
We can use ICMP_TYPES/ICMPV6_TYPES to get the codes and make generating
the match code generic. This eliminates ICMP_TYPES_FRAGMENTS.
(cherry picked from commit d9c36de285fc3df1f1226972f8f9826d07e30921)
---
src/firewall/core/nftables.py | 89 +++++------------------------------
1 file changed, 11 insertions(+), 78 deletions(-)
diff --git a/src/firewall/core/nftables.py b/src/firewall/core/nftables.py
index 834176c09cbc..ef059150917b 100644
--- a/src/firewall/core/nftables.py
+++ b/src/firewall/core/nftables.py
@@ -32,6 +32,7 @@ from firewall.errors import FirewallError, UNKNOWN_ERROR, INVALID_RULE, \
INVALID_PORT
from firewall.core.rich import Rich_Accept, Rich_Reject, Rich_Drop, Rich_Mark, \
Rich_Masquerade, Rich_ForwardPort, Rich_IcmpBlock
+from firewall.core.icmp import ICMP_TYPES, ICMPV6_TYPES
from nftables.nftables import Nftables
TABLE_NAME = "firewalld"
@@ -90,78 +91,6 @@ def _icmp_types_fragments(protocol, type, code=None):
"right": code}})
return fragments
-# Most ICMP types are provided by nft, but for the codes we have to use numeric
-# values.
-#
-ICMP_TYPES_FRAGMENTS = {
- "ipv4": {
- "communication-prohibited": _icmp_types_fragments("icmp", "destination-unreachable", 13),
- "destination-unreachable": _icmp_types_fragments("icmp", "destination-unreachable"),
- "echo-reply": _icmp_types_fragments("icmp", "echo-reply"),
- "echo-request": _icmp_types_fragments("icmp", "echo-request"),
- "fragmentation-needed": _icmp_types_fragments("icmp", "destination-unreachable", 4),
- "host-precedence-violation": _icmp_types_fragments("icmp", "destination-unreachable", 14),
- "host-prohibited": _icmp_types_fragments("icmp", "destination-unreachable", 10),
- "host-redirect": _icmp_types_fragments("icmp", "redirect", 1),
- "host-unknown": _icmp_types_fragments("icmp", "destination-unreachable", 7),
- "host-unreachable": _icmp_types_fragments("icmp", "destination-unreachable", 1),
- "ip-header-bad": _icmp_types_fragments("icmp", "parameter-problem", 1),
- "network-prohibited": _icmp_types_fragments("icmp", "destination-unreachable", 8),
- "network-redirect": _icmp_types_fragments("icmp", "redirect", 0),
- "network-unknown": _icmp_types_fragments("icmp", "destination-unreachable", 6),
- "network-unreachable": _icmp_types_fragments("icmp", "destination-unreachable", 0),
- "parameter-problem": _icmp_types_fragments("icmp", "parameter-problem"),
- "port-unreachable": _icmp_types_fragments("icmp", "destination-unreachable", 3),
- "precedence-cutoff": _icmp_types_fragments("icmp", "destination-unreachable", 15),
- "protocol-unreachable": _icmp_types_fragments("icmp", "destination-unreachable", 2),
- "redirect": _icmp_types_fragments("icmp", "redirect"),
- "required-option-missing": _icmp_types_fragments("icmp", "parameter-problem", 1),
- "router-advertisement": _icmp_types_fragments("icmp", "router-advertisement"),
- "router-solicitation": _icmp_types_fragments("icmp", "router-solicitation"),
- "source-quench": _icmp_types_fragments("icmp", "source-quench"),
- "source-route-failed": _icmp_types_fragments("icmp", "destination-unreachable", 5),
- "time-exceeded": _icmp_types_fragments("icmp", "time-exceeded"),
- "timestamp-reply": _icmp_types_fragments("icmp", "timestamp-reply"),
- "timestamp-request": _icmp_types_fragments("icmp", "timestamp-request"),
- "tos-host-redirect": _icmp_types_fragments("icmp", "redirect", 3),
- "tos-host-unreachable": _icmp_types_fragments("icmp", "destination-unreachable", 12),
- "tos-network-redirect": _icmp_types_fragments("icmp", "redirect", 2),
- "tos-network-unreachable": _icmp_types_fragments("icmp", "destination-unreachable", 11),
- "ttl-zero-during-reassembly": _icmp_types_fragments("icmp", "time-exceeded", 1),
- "ttl-zero-during-transit": _icmp_types_fragments("icmp", "time-exceeded", 0),
- },
-
- "ipv6": {
- "address-unreachable": _icmp_types_fragments("icmpv6", "destination-unreachable", 3),
- "bad-header": _icmp_types_fragments("icmpv6", "parameter-problem", 0),
- "beyond-scope": _icmp_types_fragments("icmpv6", "destination-unreachable", 2),
- "communication-prohibited": _icmp_types_fragments("icmpv6", "destination-unreachable", 1),
- "destination-unreachable": _icmp_types_fragments("icmpv6", "destination-unreachable"),
- "echo-reply": _icmp_types_fragments("icmpv6", "echo-reply"),
- "echo-request": _icmp_types_fragments("icmpv6", "echo-request"),
- "failed-policy": _icmp_types_fragments("icmpv6", "destination-unreachable", 5),
- "mld-listener-done": _icmp_types_fragments("icmpv6", "mld-listener-done"),
- "mld-listener-query": _icmp_types_fragments("icmpv6", "mld-listener-query"),
- "mld-listener-report": _icmp_types_fragments("icmpv6", "mld-listener-report"),
- "mld2-listener-report": _icmp_types_fragments("icmpv6", "mld2-listener-report"),
- "neighbour-advertisement": _icmp_types_fragments("icmpv6", "nd-neighbor-advert"),
- "neighbour-solicitation": _icmp_types_fragments("icmpv6", "nd-neighbor-solicit"),
- "no-route": _icmp_types_fragments("icmpv6", "destination-unreachable", 0),
- "packet-too-big": _icmp_types_fragments("icmpv6", "packet-too-big"),
- "parameter-problem": _icmp_types_fragments("icmpv6", "parameter-problem"),
- "port-unreachable": _icmp_types_fragments("icmpv6", "destination-unreachable", 4),
- "redirect": _icmp_types_fragments("icmpv6", "nd-redirect"),
- "reject-route": _icmp_types_fragments("icmpv6", "destination-unreachable", 6),
- "router-advertisement": _icmp_types_fragments("icmpv6", "nd-router-advert"),
- "router-solicitation": _icmp_types_fragments("icmpv6", "nd-router-solicit"),
- "time-exceeded": _icmp_types_fragments("icmpv6", "time-exceeded"),
- "ttl-zero-during-reassembly": _icmp_types_fragments("icmpv6", "time-exceeded", 1),
- "ttl-zero-during-transit": _icmp_types_fragments("icmpv6", "time-exceeded", 0),
- "unknown-header-type": _icmp_types_fragments("icmpv6", "parameter-problem", 1),
- "unknown-option": _icmp_types_fragments("icmpv6", "parameter-problem", 2),
- }
-}
-
class nftables(object):
name = "nftables"
policies_supported = True
@@ -503,12 +432,12 @@ class nftables(object):
return rules
def supported_icmp_types(self, ipv=None):
- # nftables supports any icmp_type via arbitrary type/code matching.
- # We just need a translation for it in ICMP_TYPES_FRAGMENTS.
supported = set()
- for _ipv in [ipv] if ipv else ICMP_TYPES_FRAGMENTS.keys():
- supported.update(ICMP_TYPES_FRAGMENTS[_ipv].keys())
+ if ipv is None or ipv == "ipv4":
+ supported.update(ICMP_TYPES.keys())
+ if ipv is None or ipv == "ipv6":
+ supported.update(ICMPV6_TYPES.keys())
return list(supported)
@@ -1574,8 +1503,12 @@ class nftables(object):
return rules
def _icmp_types_to_nft_fragments(self, ipv, icmp_type):
- if icmp_type in ICMP_TYPES_FRAGMENTS[ipv]:
- return ICMP_TYPES_FRAGMENTS[ipv][icmp_type]
+ if ipv == "ipv4" and icmp_type in ICMP_TYPES:
+ _type, _code, _omit_code = ICMP_TYPES[icmp_type]
+ return _icmp_types_fragments("icmp", _type, None if _omit_code else _code)
+ elif ipv == "ipv6" and icmp_type in ICMPV6_TYPES:
+ _type, _code, _omit_code = ICMPV6_TYPES[icmp_type]
+ return _icmp_types_fragments("icmpv6", _type, None if _omit_code else _code)
else:
raise FirewallError(INVALID_ICMPTYPE,
"ICMP type '%s' not supported by %s for %s" % (icmp_type, self.name, ipv))
--
2.52.0

View File

@ -0,0 +1,64 @@
From f5f299900f2247acc81f24554c9bfe6c8ae4d1d3 Mon Sep 17 00:00:00 2001
From: Eric Garver <eric@garver.life>
Date: Wed, 29 Oct 2025 11:51:18 -0400
Subject: [PATCH 35/37] v2.4.0: chore(nftables): move _icmp_types_fragments()
inside the class
It was the only function outside of the class and is not useful to any
other code. Put it inside the class with everything else.
(cherry picked from commit 69ad16a4435a0b49b4196aa1a99ee963b72c4b69)
---
src/firewall/core/nftables.py | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/src/firewall/core/nftables.py b/src/firewall/core/nftables.py
index ef059150917b..ba0aa7845838 100644
--- a/src/firewall/core/nftables.py
+++ b/src/firewall/core/nftables.py
@@ -81,16 +81,6 @@ IPTABLES_TO_NFT_HOOK = {
},
}
-def _icmp_types_fragments(protocol, type, code=None):
- fragments = [{"match": {"left": {"payload": {"protocol": protocol, "field": "type"}},
- "op": "==",
- "right": type}}]
- if code is not None:
- fragments.append({"match": {"left": {"payload": {"protocol": protocol, "field": "code"}},
- "op": "==",
- "right": code}})
- return fragments
-
class nftables(object):
name = "nftables"
policies_supported = True
@@ -1502,13 +1492,23 @@ class nftables(object):
return rules
+ def _icmp_types_fragments(self, protocol, type, code=None):
+ fragments = [{"match": {"left": {"payload": {"protocol": protocol, "field": "type"}},
+ "op": "==",
+ "right": type}}]
+ if code is not None:
+ fragments.append({"match": {"left": {"payload": {"protocol": protocol, "field": "code"}},
+ "op": "==",
+ "right": code}})
+ return fragments
+
def _icmp_types_to_nft_fragments(self, ipv, icmp_type):
if ipv == "ipv4" and icmp_type in ICMP_TYPES:
_type, _code, _omit_code = ICMP_TYPES[icmp_type]
- return _icmp_types_fragments("icmp", _type, None if _omit_code else _code)
+ return self._icmp_types_fragments("icmp", _type, None if _omit_code else _code)
elif ipv == "ipv6" and icmp_type in ICMPV6_TYPES:
_type, _code, _omit_code = ICMPV6_TYPES[icmp_type]
- return _icmp_types_fragments("icmpv6", _type, None if _omit_code else _code)
+ return self._icmp_types_fragments("icmpv6", _type, None if _omit_code else _code)
else:
raise FirewallError(INVALID_ICMPTYPE,
"ICMP type '%s' not supported by %s for %s" % (icmp_type, self.name, ipv))
--
2.52.0

View File

@ -0,0 +1,114 @@
From ec822d83e3877decb1ab4db80a8303a0bbb1bdd1 Mon Sep 17 00:00:00 2001
From: Eric Garver <eric@garver.life>
Date: Wed, 29 Oct 2025 16:33:17 -0400
Subject: [PATCH 36/37] v2.4.0: chore(ipXtables): simplify icmp match fragments
We can use ICMP_TYPES/ICMPV6_TYPES to get the codes and make rule
generation generic while also supporting more types that don't have name
support in iptables, e.g. mld.
(cherry picked from commit 1562687ae6ca3cbcf6ece25126af9116adfb897b)
---
src/firewall/core/ipXtables.py | 61 +++++++++++++++-------------------
1 file changed, 27 insertions(+), 34 deletions(-)
diff --git a/src/firewall/core/ipXtables.py b/src/firewall/core/ipXtables.py
index 0f9a1518380e..f20253b5f01b 100644
--- a/src/firewall/core/ipXtables.py
+++ b/src/firewall/core/ipXtables.py
@@ -27,9 +27,11 @@ from firewall.core.logger import log
from firewall.functions import tempFile, readfile, splitArgs, check_mac, portStr, \
check_single_address, check_address, normalizeIP6
from firewall import config
-from firewall.errors import FirewallError, INVALID_PASSTHROUGH, INVALID_RULE, UNKNOWN_ERROR, INVALID_ADDR
+from firewall.errors import FirewallError, INVALID_PASSTHROUGH, INVALID_RULE, UNKNOWN_ERROR, INVALID_ADDR, \
+ INVALID_ICMPTYPE
from firewall.core.rich import Rich_Accept, Rich_Reject, Rich_Drop, Rich_Mark, \
Rich_Masquerade, Rich_ForwardPort, Rich_IcmpBlock
+from firewall.core.icmp import ICMP_TYPES, ICMPV6_TYPES
import string
POLICY_CHAIN_PREFIX = ""
@@ -590,37 +592,14 @@ class ip4tables(object):
return rules
def supported_icmp_types(self, ipv=None):
- """Return ICMP types that are supported by the iptables/ip6tables command and kernel"""
- ret = [ ]
- output = ""
- try:
- output = self.__run(["-p",
- "icmp" if self.ipv == "ipv4" else "ipv6-icmp",
- "--help"])
- except ValueError as ex:
- if self.ipv == "ipv4":
- log.debug1("iptables error: %s" % ex)
- else:
- log.debug1("ip6tables error: %s" % ex)
- lines = output.splitlines()
-
- in_types = False
- for line in lines:
- #print(line)
- if in_types:
- line = line.strip().lower()
- splits = line.split()
- for split in splits:
- if split.startswith("(") and split.endswith(")"):
- x = split[1:-1]
- else:
- x = split
- if x not in ret:
- ret.append(x)
- if self.ipv == "ipv4" and line.startswith("Valid ICMP Types:") or \
- self.ipv == "ipv6" and line.startswith("Valid ICMPv6 Types:"):
- in_types = True
- return ret
+ supported = set()
+
+ if ipv is None or self.ipv == "ipv4":
+ supported.update(ICMP_TYPES.keys())
+ if ipv is None or self.ipv == "ipv6":
+ supported.update(ICMPV6_TYPES.keys())
+
+ return list(supported)
def build_default_tables(self):
# nothing to do, they always exist
@@ -1328,6 +1307,20 @@ class ip4tables(object):
return rules
+ def _icmp_types_fragment(self, icmp_type):
+ if self.ipv == "ipv4" and icmp_type in ICMP_TYPES:
+ _type, _code, _omit_code = ICMP_TYPES[icmp_type]
+ _type_str = str(_type) if _omit_code else str(_type) + "/" + str(_code)
+ return ["-m", "icmp", "--icmp-type", _type_str]
+ elif self.ipv == "ipv6" and icmp_type in ICMPV6_TYPES:
+ _type, _code, _omit_code = ICMPV6_TYPES[icmp_type]
+ _type_str = str(_type) if _omit_code else str(_type) + "/" + str(_code)
+ return ["-m", "icmp6", "--icmpv6-type", _type_str]
+ else:
+ raise FirewallError(
+ INVALID_ICMPTYPE, f"ICMP type {icmp_type} not supported by {self.name}"
+ )
+
def build_policy_icmp_block_rules(self, enable, policy, ict, rich_rule=None):
table = "filter"
_policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX)
@@ -1335,10 +1328,10 @@ class ip4tables(object):
if self.ipv == "ipv4":
proto = [ "-p", "icmp" ]
- match = [ "-m", "icmp", "--icmp-type", ict.name ]
+ match = self._icmp_types_fragment(ict.name)
else:
proto = [ "-p", "ipv6-icmp" ]
- match = [ "-m", "icmp6", "--icmpv6-type", ict.name ]
+ match = self._icmp_types_fragment(ict.name)
rules = []
if self._fw.policy.query_icmp_block_inversion(policy):
--
2.52.0

View File

@ -0,0 +1,165 @@
From 242e9d83840115260452b2ac48638f8f40d8ed3d Mon Sep 17 00:00:00 2001
From: Eric Garver <eric@garver.life>
Date: Mon, 27 Oct 2025 16:37:35 -0400
Subject: [PATCH 37/37] v2.4.0: fix(policy): allow-host-ipv6: allow MLD packets
RFC 4890 Section 4.4.1 makes it very clear that MLD packets must be
allowed by default.
Fixes: RHEL-54411
Fixes: RHEL-123703
(cherry picked from commit 3c42d02b770391686e6f7b202556ea4eee0722f5)
---
config/policies/allow-host-ipv6.xml | 16 +++++++++++++
src/tests/dbus/policy_permanent_functional.at | 4 ++--
src/tests/dbus/policy_runtime_functional.at | 2 +-
src/tests/features/policy.at | 24 +++++++++++++++++++
src/tests/regression/rhbz2222044.at | 2 +-
5 files changed, 44 insertions(+), 4 deletions(-)
diff --git a/config/policies/allow-host-ipv6.xml b/config/policies/allow-host-ipv6.xml
index 0de7629c3809..33b5d13206a6 100644
--- a/config/policies/allow-host-ipv6.xml
+++ b/config/policies/allow-host-ipv6.xml
@@ -20,4 +20,20 @@
<icmp-type name="redirect" />
<accept />
</rule>
+ <rule family="ipv6">
+ <icmp-type name="mld-listener-done" />
+ <accept />
+ </rule>
+ <rule family="ipv6">
+ <icmp-type name="mld-listener-query" />
+ <accept />
+ </rule>
+ <rule family="ipv6">
+ <icmp-type name="mld-listener-report" />
+ <accept />
+ </rule>
+ <rule family="ipv6">
+ <icmp-type name="mld2-listener-report" />
+ <accept />
+ </rule>
</policy>
diff --git a/src/tests/dbus/policy_permanent_functional.at b/src/tests/dbus/policy_permanent_functional.at
index a5e1af90cc1c..44b8ebeea18e 100644
--- a/src/tests/dbus/policy_permanent_functional.at
+++ b/src/tests/dbus/policy_permanent_functional.at
@@ -155,7 +155,7 @@ DBUS_CHECK([config/policy/${DBUS_BUILTIN_POLICY_OBJ}], [config.policy.getSetting
'ingress_zones': m4_escape([<['ANY']>])
'masquerade': <false>
'priority': <-15000>
- 'rich_rules': m4_escape([<['rule family="ipv6" icmp-type name="neighbour-advertisement" accept', 'rule family="ipv6" icmp-type name="neighbour-solicitation" accept', 'rule family="ipv6" icmp-type name="router-advertisement" accept', 'rule family="ipv6" icmp-type name="redirect" accept']>])
+ 'rich_rules': m4_escape([<['rule family="ipv6" icmp-type name="neighbour-advertisement" accept', 'rule family="ipv6" icmp-type name="neighbour-solicitation" accept', 'rule family="ipv6" icmp-type name="router-advertisement" accept', 'rule family="ipv6" icmp-type name="redirect" accept', 'rule family="ipv6" icmp-type name="mld-listener-done" accept', 'rule family="ipv6" icmp-type name="mld-listener-query" accept', 'rule family="ipv6" icmp-type name="mld-listener-report" accept', 'rule family="ipv6" icmp-type name="mld2-listener-report" accept']>])
'short': <'Allow host IPv6'>
'target': <'DROP'>
'version': <'1.2'>
@@ -168,7 +168,7 @@ DBUS_CHECK([config/policy/${DBUS_BUILTIN_POLICY_OBJ}], [config.policy.getSetting
'ingress_zones': m4_escape([<['ANY']>])
'masquerade': <false>
'priority': <-15000>
- 'rich_rules': m4_escape([<['rule family="ipv6" icmp-type name="neighbour-advertisement" accept', 'rule family="ipv6" icmp-type name="neighbour-solicitation" accept', 'rule family="ipv6" icmp-type name="router-advertisement" accept', 'rule family="ipv6" icmp-type name="redirect" accept']>])
+ 'rich_rules': m4_escape([<['rule family="ipv6" icmp-type name="neighbour-advertisement" accept', 'rule family="ipv6" icmp-type name="neighbour-solicitation" accept', 'rule family="ipv6" icmp-type name="router-advertisement" accept', 'rule family="ipv6" icmp-type name="redirect" accept', 'rule family="ipv6" icmp-type name="mld-listener-done" accept', 'rule family="ipv6" icmp-type name="mld-listener-query" accept', 'rule family="ipv6" icmp-type name="mld-listener-report" accept', 'rule family="ipv6" icmp-type name="mld2-listener-report" accept']>])
'short': <'Allow host IPv6'>
'target': <'CONTINUE'>
])
diff --git a/src/tests/dbus/policy_runtime_functional.at b/src/tests/dbus/policy_runtime_functional.at
index ab9a43dda8f3..08cb3b1051ff 100644
--- a/src/tests/dbus/policy_runtime_functional.at
+++ b/src/tests/dbus/policy_runtime_functional.at
@@ -11,7 +11,7 @@ DBUS_CHECK([], [policy.getPolicySettings], ["allow-host-ipv6"], 0, [dnl
'ingress_zones': m4_escape([<['ANY']>])
'masquerade': <false>
'priority': <-15000>
- 'rich_rules': m4_escape([<['rule family="ipv6" icmp-type name="neighbour-advertisement" accept', 'rule family="ipv6" icmp-type name="neighbour-solicitation" accept', 'rule family="ipv6" icmp-type name="router-advertisement" accept', 'rule family="ipv6" icmp-type name="redirect" accept']>])
+ 'rich_rules': m4_escape([<['rule family="ipv6" icmp-type name="neighbour-advertisement" accept', 'rule family="ipv6" icmp-type name="neighbour-solicitation" accept', 'rule family="ipv6" icmp-type name="router-advertisement" accept', 'rule family="ipv6" icmp-type name="redirect" accept', 'rule family="ipv6" icmp-type name="mld-listener-done" accept', 'rule family="ipv6" icmp-type name="mld-listener-query" accept', 'rule family="ipv6" icmp-type name="mld-listener-report" accept', 'rule family="ipv6" icmp-type name="mld2-listener-report" accept']>])
'short': <'Allow host IPv6'>
'target': <'CONTINUE'>
])
diff --git a/src/tests/features/policy.at b/src/tests/features/policy.at
index 9811330aee07..1db150d3c430 100644
--- a/src/tests/features/policy.at
+++ b/src/tests/features/policy.at
@@ -121,6 +121,10 @@ allow-host-ipv6 (active)
rule family="ipv6" icmp-type name="neighbour-solicitation" accept
rule family="ipv6" icmp-type name="router-advertisement" accept
rule family="ipv6" icmp-type name="redirect" accept
+ rule family="ipv6" icmp-type name="mld-listener-done" accept
+ rule family="ipv6" icmp-type name="mld-listener-query" accept
+ rule family="ipv6" icmp-type name="mld-listener-report" accept
+ rule family="ipv6" icmp-type name="mld2-listener-report" accept
])])
FWD_CHECK([--permanent --info-policy allow-host-ipv6 | TRIM_WHITESPACE], 0, [m4_strip([dnl
allow-host-ipv6 (active)
@@ -140,6 +144,10 @@ allow-host-ipv6 (active)
rule family="ipv6" icmp-type name="neighbour-solicitation" accept
rule family="ipv6" icmp-type name="router-advertisement" accept
rule family="ipv6" icmp-type name="redirect" accept
+ rule family="ipv6" icmp-type name="mld-listener-done" accept
+ rule family="ipv6" icmp-type name="mld-listener-query" accept
+ rule family="ipv6" icmp-type name="mld-listener-report" accept
+ rule family="ipv6" icmp-type name="mld2-listener-report" accept
])])
FWD_CHECK([--list-all-policies | TRIM_WHITESPACE], 0, [m4_strip([dnl
@@ -160,6 +168,10 @@ allow-host-ipv6 (active)
rule family="ipv6" icmp-type name="neighbour-solicitation" accept
rule family="ipv6" icmp-type name="router-advertisement" accept
rule family="ipv6" icmp-type name="redirect" accept
+ rule family="ipv6" icmp-type name="mld-listener-done" accept
+ rule family="ipv6" icmp-type name="mld-listener-query" accept
+ rule family="ipv6" icmp-type name="mld-listener-report" accept
+ rule family="ipv6" icmp-type name="mld2-listener-report" accept
])])
FWD_CHECK([--permanent --list-all-policies | TRIM_WHITESPACE], 0, [m4_strip([dnl
allow-host-ipv6 (active)
@@ -179,6 +191,10 @@ allow-host-ipv6 (active)
rule family="ipv6" icmp-type name="neighbour-solicitation" accept
rule family="ipv6" icmp-type name="router-advertisement" accept
rule family="ipv6" icmp-type name="redirect" accept
+ rule family="ipv6" icmp-type name="mld-listener-done" accept
+ rule family="ipv6" icmp-type name="mld-listener-query" accept
+ rule family="ipv6" icmp-type name="mld-listener-report" accept
+ rule family="ipv6" icmp-type name="mld2-listener-report" accept
])])
FWD_CHECK([--policy allow-host-ipv6 --list-all | TRIM_WHITESPACE], 0, [m4_strip([dnl
@@ -199,6 +215,10 @@ allow-host-ipv6 (active)
rule family="ipv6" icmp-type name="neighbour-solicitation" accept
rule family="ipv6" icmp-type name="router-advertisement" accept
rule family="ipv6" icmp-type name="redirect" accept
+ rule family="ipv6" icmp-type name="mld-listener-done" accept
+ rule family="ipv6" icmp-type name="mld-listener-query" accept
+ rule family="ipv6" icmp-type name="mld-listener-report" accept
+ rule family="ipv6" icmp-type name="mld2-listener-report" accept
])])
FWD_CHECK([--permanent --policy allow-host-ipv6 --list-all | TRIM_WHITESPACE], 0, [m4_strip([dnl
allow-host-ipv6 (active)
@@ -218,6 +238,10 @@ allow-host-ipv6 (active)
rule family="ipv6" icmp-type name="neighbour-solicitation" accept
rule family="ipv6" icmp-type name="router-advertisement" accept
rule family="ipv6" icmp-type name="redirect" accept
+ rule family="ipv6" icmp-type name="mld-listener-done" accept
+ rule family="ipv6" icmp-type name="mld-listener-query" accept
+ rule family="ipv6" icmp-type name="mld-listener-report" accept
+ rule family="ipv6" icmp-type name="mld2-listener-report" accept
])])
FWD_END_TEST
diff --git a/src/tests/regression/rhbz2222044.at b/src/tests/regression/rhbz2222044.at
index 9f3b1615b2f9..2e579c6315b0 100644
--- a/src/tests/regression/rhbz2222044.at
+++ b/src/tests/regression/rhbz2222044.at
@@ -6,7 +6,7 @@ dnl rules have not changed so rule count should not change
m4_define([check_rule_count], [
m4_if(nftables, FIREWALL_BACKEND, [
NS_CHECK([nft list table inet firewalld | wc -l], 0, [dnl
-237
+241
])
NS_CHECK([nft list table ip firewalld | wc -l], 0, [dnl
105
--
2.52.0

View File

@ -1,7 +1,7 @@
Summary: A firewall daemon with D-Bus interface providing a dynamic firewall
Name: firewalld
Version: 0.9.11
Release: 10%{?dist}
Release: 11%{?dist}
URL: http://www.firewalld.org
License: GPLv2+
Source0: https://github.com/firewalld/firewalld/releases/download/v%{version}/firewalld-%{version}.tar.gz
@ -36,6 +36,12 @@ Patch28: 0028-v2.0.0-chore-direct-add-has_runtime_configuration.patch
Patch29: 0029-v2.0.0-feat-direct-avoid-iptables-flush-if-using-nft.patch
Patch30: 0030-v2.0.0-test-direct-avoid-iptables-flush-if-using-nft.patch
Patch31: 0031-v2.2.0-fix-service-update-highest-port-number-for-ce.patch
Patch32: 0032-v2.4.0-chore-icmp-add-all-icmptypes-to-ICMP_TYPES-di.patch
Patch33: 0033-v2.4.0-chore-icmp-convert-type-code-map-to-tuple.patch
Patch34: 0034-v2.4.0-chore-nftables-simplify-icmp-match-fragments.patch
Patch35: 0035-v2.4.0-chore-nftables-move-_icmp_types_fragments-ins.patch
Patch36: 0036-v2.4.0-chore-ipXtables-simplify-icmp-match-fragments.patch
Patch37: 0037-v2.4.0-fix-policy-allow-host-ipv6-allow-MLD-packets.patch
BuildArch: noarch
BuildRequires: autoconf
@ -237,6 +243,9 @@ desktop-file-install --delete-original \
%{_mandir}/man1/firewall-config*.1*
%changelog
* Sat Mar 21 2026 Eric Garver <egarver@redhat.com> - 0.9.11-11
- fix(policy): allow-host-ipv6: allow MLD packets
* Tue Feb 04 2025 Eric Garver <egarver@redhat.com> - 0.9.11-10
- fix(service): update highest port number for ceph