import firewalld-0.9.3-7.el8_5.1
This commit is contained in:
parent
7cd19c503f
commit
8b1b3dbb32
@ -0,0 +1,140 @@
|
||||
From 3eb0f3239b9b35a1c388a91fc2e546b1e87cb020 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Garver <eric@garver.life>
|
||||
Date: Tue, 30 Nov 2021 14:54:20 -0500
|
||||
Subject: [PATCH 37/39] fix(ipset): reduce cost of entry overlap detection
|
||||
|
||||
This increases peak memory usage to reduce the duration it takes to
|
||||
apply the set entries. Building the list of IPv4Network objects up front
|
||||
means we don't have to build them multiple times inside the for loop.
|
||||
|
||||
Fixes: #881
|
||||
(cherry picked from commit 7f5b736378c0133f46470c42e0c1fb3b95087de5)
|
||||
---
|
||||
src/firewall/client.py | 10 ++++------
|
||||
src/firewall/core/fw_ipset.py | 9 +++------
|
||||
src/firewall/core/ipset.py | 27 ++++++++++++++++++++++-----
|
||||
src/firewall/server/config_ipset.py | 10 ++++------
|
||||
4 files changed, 33 insertions(+), 23 deletions(-)
|
||||
|
||||
diff --git a/src/firewall/client.py b/src/firewall/client.py
|
||||
index 3715ffd29316..fdc88ac7946b 100644
|
||||
--- a/src/firewall/client.py
|
||||
+++ b/src/firewall/client.py
|
||||
@@ -34,7 +34,8 @@ from firewall.core.base import DEFAULT_ZONE_TARGET, DEFAULT_POLICY_TARGET, DEFAU
|
||||
from firewall.dbus_utils import dbus_to_python
|
||||
from firewall.functions import b2u
|
||||
from firewall.core.rich import Rich_Rule
|
||||
-from firewall.core.ipset import normalize_ipset_entry, check_entry_overlaps_existing
|
||||
+from firewall.core.ipset import normalize_ipset_entry, check_entry_overlaps_existing, \
|
||||
+ check_for_overlapping_entries
|
||||
from firewall import errors
|
||||
from firewall.errors import FirewallError
|
||||
|
||||
@@ -1617,11 +1618,8 @@ class FirewallClientIPSetSettings(object):
|
||||
if "timeout" in self.settings[4] and \
|
||||
self.settings[4]["timeout"] != "0":
|
||||
raise FirewallError(errors.IPSET_WITH_TIMEOUT)
|
||||
- _entries = set()
|
||||
- for _entry in dbus_to_python(entries, list):
|
||||
- check_entry_overlaps_existing(_entry, _entries)
|
||||
- _entries.add(normalize_ipset_entry(_entry))
|
||||
- self.settings[5] = list(_entries)
|
||||
+ check_for_overlapping_entries(entries)
|
||||
+ self.settings[5] = entries
|
||||
@handle_exceptions
|
||||
def addEntry(self, entry):
|
||||
if "timeout" in self.settings[4] and \
|
||||
diff --git a/src/firewall/core/fw_ipset.py b/src/firewall/core/fw_ipset.py
|
||||
index a285fd4a4aab..d7878c01921e 100644
|
||||
--- a/src/firewall/core/fw_ipset.py
|
||||
+++ b/src/firewall/core/fw_ipset.py
|
||||
@@ -25,7 +25,8 @@ __all__ = [ "FirewallIPSet" ]
|
||||
|
||||
from firewall.core.logger import log
|
||||
from firewall.core.ipset import remove_default_create_options as rm_def_cr_opts, \
|
||||
- normalize_ipset_entry, check_entry_overlaps_existing
|
||||
+ normalize_ipset_entry, check_entry_overlaps_existing, \
|
||||
+ check_for_overlapping_entries
|
||||
from firewall.core.io.ipset import IPSet
|
||||
from firewall import errors
|
||||
from firewall.errors import FirewallError
|
||||
@@ -244,11 +245,7 @@ class FirewallIPSet(object):
|
||||
def set_entries(self, name, entries):
|
||||
obj = self.get_ipset(name, applied=True)
|
||||
|
||||
- _entries = set()
|
||||
- for _entry in entries:
|
||||
- check_entry_overlaps_existing(_entry, _entries)
|
||||
- _entries.add(normalize_ipset_entry(_entry))
|
||||
- entries = list(_entries)
|
||||
+ check_for_overlapping_entries(entries)
|
||||
|
||||
for entry in entries:
|
||||
IPSet.check_entry(entry, obj.options, obj.type)
|
||||
diff --git a/src/firewall/core/ipset.py b/src/firewall/core/ipset.py
|
||||
index d6defa395241..66ea4335536d 100644
|
||||
--- a/src/firewall/core/ipset.py
|
||||
+++ b/src/firewall/core/ipset.py
|
||||
@@ -309,9 +309,26 @@ def check_entry_overlaps_existing(entry, entries):
|
||||
if len(entry.split(",")) > 1:
|
||||
return
|
||||
|
||||
+ try:
|
||||
+ entry_network = ipaddress.ip_network(entry, strict=False)
|
||||
+ except ValueError:
|
||||
+ # could not parse the new IP address, maybe a MAC
|
||||
+ return
|
||||
+
|
||||
for itr in entries:
|
||||
- try:
|
||||
- if ipaddress.ip_network(itr, strict=False).overlaps(ipaddress.ip_network(entry, strict=False)):
|
||||
- raise FirewallError(errors.INVALID_ENTRY, "Entry '{}' overlaps with existing entry '{}'".format(itr, entry))
|
||||
- except ValueError:
|
||||
- pass
|
||||
+ if entry_network.overlaps(ipaddress.ip_network(itr, strict=False)):
|
||||
+ raise FirewallError(errors.INVALID_ENTRY, "Entry '{}' overlaps with existing entry '{}'".format(entry, itr))
|
||||
+
|
||||
+def check_for_overlapping_entries(entries):
|
||||
+ """ Check if any entry overlaps any entry in the list of entries """
|
||||
+ try:
|
||||
+ entries = [ipaddress.ip_network(x, strict=False) for x in entries]
|
||||
+ except ValueError:
|
||||
+ # at least one entry can not be parsed
|
||||
+ return
|
||||
+
|
||||
+ while entries:
|
||||
+ entry = entries.pop()
|
||||
+ for itr in entries:
|
||||
+ if entry.overlaps(itr):
|
||||
+ raise FirewallError(errors.INVALID_ENTRY, "Entry '{}' overlaps entry '{}'".format(entry, itr))
|
||||
diff --git a/src/firewall/server/config_ipset.py b/src/firewall/server/config_ipset.py
|
||||
index f33c2a02926f..499ffcb9227a 100644
|
||||
--- a/src/firewall/server/config_ipset.py
|
||||
+++ b/src/firewall/server/config_ipset.py
|
||||
@@ -34,7 +34,8 @@ from firewall.dbus_utils import dbus_to_python, \
|
||||
dbus_introspection_add_properties
|
||||
from firewall.core.io.ipset import IPSet
|
||||
from firewall.core.ipset import IPSET_TYPES, normalize_ipset_entry, \
|
||||
- check_entry_overlaps_existing
|
||||
+ check_entry_overlaps_existing, \
|
||||
+ check_for_overlapping_entries
|
||||
from firewall.core.logger import log
|
||||
from firewall.server.decorators import handle_exceptions, \
|
||||
dbus_handle_exceptions, dbus_service_method
|
||||
@@ -407,11 +408,8 @@ class FirewallDConfigIPSet(slip.dbus.service.Object):
|
||||
in_signature='as')
|
||||
@dbus_handle_exceptions
|
||||
def setEntries(self, entries, sender=None):
|
||||
- _entries = set()
|
||||
- for _entry in dbus_to_python(entries, list):
|
||||
- check_entry_overlaps_existing(_entry, _entries)
|
||||
- _entries.add(normalize_ipset_entry(_entry))
|
||||
- entries = list(_entries)
|
||||
+ entries = dbus_to_python(entries, list)
|
||||
+ check_for_overlapping_entries(entries)
|
||||
log.debug1("%s.setEntries('[%s]')", self._log_prefix,
|
||||
",".join(entries))
|
||||
self.parent.accessCheck(sender)
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,56 @@
|
||||
From 976260a0d74009cea18f3c60e4b03e7f41de8fa9 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Garver <eric@garver.life>
|
||||
Date: Tue, 30 Nov 2021 14:50:17 -0500
|
||||
Subject: [PATCH 38/39] test(ipset): huge set of entries benchmark
|
||||
|
||||
Coverage: #881
|
||||
(cherry picked from commit 114936c71ab1b12a5598d06805b7e9e13f7ee190)
|
||||
---
|
||||
src/tests/regression/gh881.at | 25 +++++++++++++++++++++++++
|
||||
src/tests/regression/regression.at | 1 +
|
||||
2 files changed, 26 insertions(+)
|
||||
create mode 100644 src/tests/regression/gh881.at
|
||||
|
||||
diff --git a/src/tests/regression/gh881.at b/src/tests/regression/gh881.at
|
||||
new file mode 100644
|
||||
index 000000000000..c7326805b555
|
||||
--- /dev/null
|
||||
+++ b/src/tests/regression/gh881.at
|
||||
@@ -0,0 +1,25 @@
|
||||
+FWD_START_TEST([ipset entry overlap detect perf])
|
||||
+AT_KEYWORDS(ipset gh881)
|
||||
+
|
||||
+dnl build a large ipset
|
||||
+dnl
|
||||
+AT_DATA([./deny_cidr], [])
|
||||
+NS_CHECK([sh -c '
|
||||
+for I in $(seq 10); do
|
||||
+ for J in $(seq 250); do
|
||||
+ echo "10.${I}.${J}.0/24" >> ./deny_cidr
|
||||
+ done
|
||||
+done
|
||||
+'])
|
||||
+
|
||||
+dnl verify non-overlapping does not error
|
||||
+dnl
|
||||
+FWD_CHECK([--permanent --new-ipset=deny_set --type=hash:net --option=family=inet --option=hashsize=16384 --option=maxelem=20000], 0, [ignore])
|
||||
+NS_CHECK([time timeout 300 firewall-cmd --permanent --ipset=deny_set --add-entries-from-file=./deny_cidr], 0, [ignore], [ignore])
|
||||
+
|
||||
+dnl verify overlap detection actually detects an overlap
|
||||
+dnl
|
||||
+NS_CHECK([echo "10.1.0.0/16" >> ./deny_cidr])
|
||||
+NS_CHECK([time timeout 300 firewall-cmd --permanent --ipset=deny_set --add-entries-from-file=./deny_cidr], 136, [ignore], [ignore])
|
||||
+
|
||||
+FWD_END_TEST()
|
||||
diff --git a/src/tests/regression/regression.at b/src/tests/regression/regression.at
|
||||
index aadd948a459f..6ef6579434b1 100644
|
||||
--- a/src/tests/regression/regression.at
|
||||
+++ b/src/tests/regression/regression.at
|
||||
@@ -42,3 +42,4 @@ m4_include([regression/ipset_netmask_allowed.at])
|
||||
m4_include([regression/rhbz1940928.at])
|
||||
m4_include([regression/rhbz1936896.at])
|
||||
m4_include([regression/rhbz1914935.at])
|
||||
+m4_include([regression/gh881.at])
|
||||
--
|
||||
2.31.1
|
||||
|
@ -0,0 +1,150 @@
|
||||
From e61807c71c8532cfd23f9946d903beec7f496abc Mon Sep 17 00:00:00 2001
|
||||
From: Eric Garver <eric@garver.life>
|
||||
Date: Tue, 25 Jan 2022 09:29:32 -0500
|
||||
Subject: [PATCH 39/39] fix(ipset): further reduce cost of entry overlap
|
||||
detection
|
||||
|
||||
This makes the complexity linear by sorting the networks ahead of time.
|
||||
|
||||
Fixes: #881
|
||||
Fixes: rhbz2043289
|
||||
(cherry picked from commit 36c170db265265e838a089858be4b20dbbd582eb)
|
||||
---
|
||||
src/firewall/core/ipset.py | 59 ++++++++++++++++++++++++++++++++---
|
||||
src/tests/regression/gh881.at | 42 ++++++++++++++++++++++---
|
||||
2 files changed, 92 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/src/firewall/core/ipset.py b/src/firewall/core/ipset.py
|
||||
index 66ea4335536d..b160d8345669 100644
|
||||
--- a/src/firewall/core/ipset.py
|
||||
+++ b/src/firewall/core/ipset.py
|
||||
@@ -327,8 +327,57 @@ def check_for_overlapping_entries(entries):
|
||||
# at least one entry can not be parsed
|
||||
return
|
||||
|
||||
- while entries:
|
||||
- entry = entries.pop()
|
||||
- for itr in entries:
|
||||
- if entry.overlaps(itr):
|
||||
- raise FirewallError(errors.INVALID_ENTRY, "Entry '{}' overlaps entry '{}'".format(entry, itr))
|
||||
+ # We can take advantage of some facts of IPv4Network/IPv6Network and
|
||||
+ # how Python sorts the networks to quickly detect overlaps.
|
||||
+ #
|
||||
+ # Facts:
|
||||
+ #
|
||||
+ # 1. IPv{4,6}Network are normalized to remove host bits, e.g.
|
||||
+ # 10.1.1.0/16 will become 10.1.0.0/16.
|
||||
+ #
|
||||
+ # 2. IPv{4,6}Network objects are sorted by:
|
||||
+ # a. IP address (network bits)
|
||||
+ # then
|
||||
+ # b. netmask (significant bits count)
|
||||
+ #
|
||||
+ # Because of the above we have these properties:
|
||||
+ #
|
||||
+ # 1. big networks (netA) are sorted before smaller networks (netB)
|
||||
+ # that overlap the big network (netA)
|
||||
+ # - e.g. 10.1.128.0/17 (netA) sorts before 10.1.129.0/24 (netB)
|
||||
+ # 2. same value addresses (network bits) are grouped together even
|
||||
+ # if the number of network bits vary. e.g. /16 vs /24
|
||||
+ # - recall that address are normalized to remove host bits
|
||||
+ # - e.g. 10.1.128.0/17 (netA) sorts before 10.1.128.0/24 (netC)
|
||||
+ # 3. non-overlapping networks (netD, netE) are always sorted before or
|
||||
+ # after networks that overlap (netB, netC) the current one (netA)
|
||||
+ # - e.g. 10.1.128.0/17 (netA) sorts before 10.2.128.0/16 (netD)
|
||||
+ # - e.g. 10.1.128.0/17 (netA) sorts after 9.1.128.0/17 (netE)
|
||||
+ # - e.g. 9.1.128.0/17 (netE) sorts before 10.1.129.0/24 (netB)
|
||||
+ #
|
||||
+ # With this we know the sorted list looks like:
|
||||
+ #
|
||||
+ # list: [ netE, netA, netB, netC, netD ]
|
||||
+ #
|
||||
+ # netE = non-overlapping network
|
||||
+ # netA = big network
|
||||
+ # netB = smaller network that overlaps netA (subnet)
|
||||
+ # netC = smaller network that overlaps netA (subnet)
|
||||
+ # netD = non-overlapping network
|
||||
+ #
|
||||
+ # If networks netB and netC exist in the list, they overlap and are
|
||||
+ # adjacent to netA.
|
||||
+ #
|
||||
+ # Checking for overlaps on a sorted list is thus:
|
||||
+ #
|
||||
+ # 1. compare adjacent elements in the list for overlaps
|
||||
+ #
|
||||
+ # Recall that we only need to detect a single overlap. We do not need to
|
||||
+ # detect them all.
|
||||
+ #
|
||||
+ entries.sort()
|
||||
+ prev_network = entries.pop(0)
|
||||
+ for current_network in entries:
|
||||
+ if prev_network.overlaps(current_network):
|
||||
+ raise FirewallError(errors.INVALID_ENTRY, "Entry '{}' overlaps entry '{}'".format(prev_network, current_network))
|
||||
+ prev_network = current_network
|
||||
diff --git a/src/tests/regression/gh881.at b/src/tests/regression/gh881.at
|
||||
index c7326805b555..a5cf7e4eb912 100644
|
||||
--- a/src/tests/regression/gh881.at
|
||||
+++ b/src/tests/regression/gh881.at
|
||||
@@ -5,21 +5,55 @@ dnl build a large ipset
|
||||
dnl
|
||||
AT_DATA([./deny_cidr], [])
|
||||
NS_CHECK([sh -c '
|
||||
-for I in $(seq 10); do
|
||||
+for I in $(seq 250); do
|
||||
for J in $(seq 250); do
|
||||
echo "10.${I}.${J}.0/24" >> ./deny_cidr
|
||||
done
|
||||
done
|
||||
'])
|
||||
+NS_CHECK([echo "10.254.0.0/16" >> ./deny_cidr])
|
||||
|
||||
dnl verify non-overlapping does not error
|
||||
dnl
|
||||
FWD_CHECK([--permanent --new-ipset=deny_set --type=hash:net --option=family=inet --option=hashsize=16384 --option=maxelem=20000], 0, [ignore])
|
||||
-NS_CHECK([time timeout 300 firewall-cmd --permanent --ipset=deny_set --add-entries-from-file=./deny_cidr], 0, [ignore], [ignore])
|
||||
+NS_CHECK([time firewall-cmd --permanent --ipset=deny_set --add-entries-from-file=./deny_cidr], 0, [ignore], [ignore])
|
||||
+
|
||||
+dnl still no overlap
|
||||
+dnl
|
||||
+AT_DATA([./deny_cidr], [
|
||||
+9.0.0.0/8
|
||||
+11.1.0.0/16
|
||||
+])
|
||||
+NS_CHECK([time firewall-cmd --permanent --ipset=deny_set --add-entries-from-file=./deny_cidr], 0, [ignore], [ignore])
|
||||
|
||||
dnl verify overlap detection actually detects an overlap
|
||||
dnl
|
||||
-NS_CHECK([echo "10.1.0.0/16" >> ./deny_cidr])
|
||||
-NS_CHECK([time timeout 300 firewall-cmd --permanent --ipset=deny_set --add-entries-from-file=./deny_cidr], 136, [ignore], [ignore])
|
||||
+AT_DATA([./deny_cidr], [
|
||||
+10.1.0.0/16
|
||||
+10.2.0.0/16
|
||||
+10.250.0.0/16
|
||||
+])
|
||||
+NS_CHECK([time firewall-cmd --permanent --ipset=deny_set --add-entries-from-file=./deny_cidr], 136, [ignore], [ignore])
|
||||
+
|
||||
+AT_DATA([./deny_cidr], [
|
||||
+10.253.0.0/16
|
||||
+10.253.128.0/17
|
||||
+])
|
||||
+NS_CHECK([time firewall-cmd --permanent --ipset=deny_set --add-entries-from-file=./deny_cidr], 136, [ignore], [ignore])
|
||||
+
|
||||
+AT_DATA([./deny_cidr], [
|
||||
+10.1.1.1/32
|
||||
+])
|
||||
+NS_CHECK([time firewall-cmd --permanent --ipset=deny_set --add-entries-from-file=./deny_cidr], 136, [ignore], [ignore])
|
||||
+
|
||||
+AT_DATA([./deny_cidr], [
|
||||
+10.0.0.0/8
|
||||
+10.0.0.0/25
|
||||
+])
|
||||
+NS_CHECK([time firewall-cmd --permanent --ipset=deny_set --add-entries-from-file=./deny_cidr], 136, [ignore], [ignore])
|
||||
+
|
||||
+dnl empty file, no additions, but previous ones will remain
|
||||
+AT_DATA([./deny_cidr], [])
|
||||
+FWD_CHECK([--permanent --ipset=deny_set --add-entries-from-file=./deny_cidr], 0, [ignore], [ignore])
|
||||
|
||||
FWD_END_TEST()
|
||||
--
|
||||
2.31.1
|
||||
|
@ -1,7 +1,7 @@
|
||||
Summary: A firewall daemon with D-Bus interface providing a dynamic firewall
|
||||
Name: firewalld
|
||||
Version: 0.9.3
|
||||
Release: 7%{?dist}
|
||||
Release: 7%{?dist}.1
|
||||
URL: http://www.firewalld.org
|
||||
License: GPLv2+
|
||||
Source0: https://github.com/firewalld/firewalld/releases/download/v%{version}/firewalld-%{version}.tar.gz
|
||||
@ -41,6 +41,9 @@ Patch33: 0033-fix-policy-warn-instead-of-error-for-overlapping-por.patch
|
||||
Patch34: 0034-test-zone-verify-overlapping-ports-don-t-halt-zone-l.patch
|
||||
Patch35: v1.0.0-0035-fix-ipset-normalize-entries-in-CIDR-notation.patch
|
||||
Patch36: v1.0.0-0036-fix-ipset-disallow-overlapping-entries.patch
|
||||
Patch37: v1.0.0-0037-fix-ipset-reduce-cost-of-entry-overlap-detection.patch
|
||||
Patch38: v1.0.0-0038-test-ipset-huge-set-of-entries-benchmark.patch
|
||||
Patch39: v1.0.0-0039-fix-ipset-further-reduce-cost-of-entry-overlap-detec.patch
|
||||
|
||||
BuildArch: noarch
|
||||
BuildRequires: autoconf
|
||||
@ -242,6 +245,9 @@ desktop-file-install --delete-original \
|
||||
%{_mandir}/man1/firewall-config*.1*
|
||||
|
||||
%changelog
|
||||
* Thu Feb 03 2022 Eric Garver <egarver@redhat.com> - 0.9.3-7.el8_5.1
|
||||
- fix(ipset): reduce cost of entry overlap detection
|
||||
|
||||
* Tue Jul 13 2021 Eric Garver <egarver@redhat.com> - 0.9.3-7
|
||||
- fix(ipset): disallow overlapping entries
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user