229 lines
10 KiB
Diff
229 lines
10 KiB
Diff
From 4d8a10886f4dffd08fcf6a93694e12f76a2afd66 Mon Sep 17 00:00:00 2001
|
|
Message-Id: <4d8a10886f4dffd08fcf6a93694e12f76a2afd66@dist-git>
|
|
From: Laine Stump <laine@redhat.com>
|
|
Date: Fri, 15 Jan 2021 22:51:51 -0500
|
|
Subject: [PATCH] util: call iptables directly rather than via firewalld
|
|
|
|
When libvirt added support for firewalld, we were unable to use
|
|
firewalld's higher level rules, because they weren't detailed enough
|
|
and could not be applied to the iptables FORWARD or OUTPUT chains
|
|
(only to the INPUT chain). Instead we changed our code so that rather
|
|
than running the iptables/ip6tables/ebtables binaries ourselves, we
|
|
would send these commands to firewalld as "passthrough commands", and
|
|
firewalld would run the appropriate program on our behalf.
|
|
|
|
This was done under the assumption that firewalld was somehow tracking
|
|
all these rules, and that this tracking was benefitting proper
|
|
operation of firewalld and the system in general.
|
|
|
|
Several years later this came up in a discussion on IRC, and we
|
|
learned from the firewalld developers that, in fact, adding iptables
|
|
and ebtables rules with firewalld's passthrough commands actually has
|
|
*no* advantage; firewalld doesn't keep track of these rules in any
|
|
way, and doesn't use them to tailor the construction of its own rules.
|
|
|
|
Meanwhile, users have been complaining for some time that whenever
|
|
firewalld is restarted on a system with libvirt virtual networks
|
|
and/or nwfilter rules active, the system logs would be flooded with
|
|
warning messages whining that [lots of different rules] could not be
|
|
deleted because they didn't exist. For example:
|
|
|
|
firewalld[3536040]: WARNING: COMMAND_FAILED:
|
|
'/usr/sbin/iptables -w10 -w --table filter --delete LIBVIRT_OUT
|
|
--out-interface virbr4 --protocol udp --destination-port 68
|
|
--jump ACCEPT' failed: iptables: Bad rule
|
|
(does a matching rule exist in that chain?).
|
|
|
|
See:
|
|
|
|
https://bugzilla.redhat.com/1607929 (RHEL8)
|
|
https://bugzilla.redhat.com/1790837 (RHEL8-AV)
|
|
|
|
for many more examples and a discussion)
|
|
|
|
Note that these messages are created by iptables, but are logged by
|
|
firewalld - when an iptables/ebtables command fails, firewalld grabs
|
|
whatever is in stderr of the program, and spits it out to the system
|
|
log as a warning. We've requested that firewalld not do this (and
|
|
instead leave it up to the calling application to do the appropriate
|
|
logging), but this request has been respectfully denied.
|
|
|
|
But combining the two problems above ( 1) firewalld doesn't do
|
|
anything useful when you use it as a proxy to add/remove iptables
|
|
rules, 2) firewalld often insists on logging lots of
|
|
annoying/misleading/useless "error" messages when you use it as a
|
|
proxy to remove iptables rules that don't already exist), leads to a
|
|
solution - simply stop using firewalld to add and remove iptables
|
|
rules. Instead, exec iptables/ip6tables/ebtables directly in the same
|
|
way we do when firewalld isn't active.
|
|
|
|
We still need to keep track of whether or not firewalld is active, as
|
|
there are some things that must be done, e.g. we need to add some
|
|
actual firewalld rules in the firewalld "libvirt" zone, and we need to
|
|
take notice when firewalld restarts, so that we can reload all our
|
|
rules.
|
|
|
|
This patch doesn't remove the infrastructure that allows having
|
|
different firewall backends that perform their functions in different
|
|
ways, as that will very possibly come in handy in the future when we
|
|
want to have an nftables direct backend, and possibly a "pure"
|
|
firewalld backend (now that firewalld supports more complex rules, and
|
|
can add those rules to the FORWARD and OUTPUT chains). Instead, it
|
|
just changes the action when the selected backend is "firewalld" so
|
|
that it adds rules directly rather than through firewalld, while
|
|
leaving as much of the existing code intact as possible.
|
|
|
|
In order for tests to still pass, virfirewalltest also had to be
|
|
modified to behave in a different way (i.e. by capturing the generated
|
|
commandline as it does for the DIRECT backend, rather than capturing
|
|
dbus messages using a mocked dbus API).
|
|
|
|
Signed-off-by: Laine Stump <laine@redhat.com>
|
|
Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>
|
|
(cherry picked from commit b19863640d10b47b7c4a7cbadb21f196d61d96a2)
|
|
Message-Id: <20210116035151.1066734-9-laine@redhat.com>
|
|
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
|
|
---
|
|
src/util/virfirewall.c | 13 +++++++++++--
|
|
tests/virfirewalltest.c | 30 ++++++++++++++++++++----------
|
|
2 files changed, 31 insertions(+), 12 deletions(-)
|
|
|
|
diff --git a/src/util/virfirewall.c b/src/util/virfirewall.c
|
|
index 66d20d3f17..2ea821ec17 100644
|
|
--- a/src/util/virfirewall.c
|
|
+++ b/src/util/virfirewall.c
|
|
@@ -644,7 +644,7 @@ virFirewallApplyRuleDirect(virFirewallRulePtr rule,
|
|
}
|
|
|
|
|
|
-static int
|
|
+static int G_GNUC_UNUSED
|
|
virFirewallApplyRuleFirewallD(virFirewallRulePtr rule,
|
|
bool ignoreErrors,
|
|
char **output)
|
|
@@ -702,7 +702,16 @@ virFirewallApplyRule(virFirewallPtr firewall,
|
|
return -1;
|
|
break;
|
|
case VIR_FIREWALL_BACKEND_FIREWALLD:
|
|
- if (virFirewallApplyRuleFirewallD(rule, ignoreErrors, &output) < 0)
|
|
+ /* Since we are using raw iptables rules, there is no
|
|
+ * advantage to going through firewalld, so instead just add
|
|
+ * them directly rather that via dbus calls to firewalld. This
|
|
+ * has the useful side effect of eliminating extra unwanted
|
|
+ * warning messages in the system logs when trying to delete
|
|
+ * rules that don't exist (which is something that happens
|
|
+ * often when libvirtd is started, and *always* when firewalld
|
|
+ * is restarted)
|
|
+ */
|
|
+ if (virFirewallApplyRuleDirect(rule, ignoreErrors, &output) < 0)
|
|
return -1;
|
|
break;
|
|
|
|
diff --git a/tests/virfirewalltest.c b/tests/virfirewalltest.c
|
|
index 40e7f4f00b..1036353579 100644
|
|
--- a/tests/virfirewalltest.c
|
|
+++ b/tests/virfirewalltest.c
|
|
@@ -214,7 +214,8 @@ testFirewallSingleGroup(const void *opaque)
|
|
if (virFirewallSetBackend(data->tryBackend) < 0)
|
|
goto cleanup;
|
|
|
|
- if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT)
|
|
+ if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT ||
|
|
+ data->expectBackend == VIR_FIREWALL_BACKEND_FIREWALLD)
|
|
virCommandSetDryRun(&cmdbuf, NULL, NULL);
|
|
else
|
|
fwBuf = &cmdbuf;
|
|
@@ -271,7 +272,8 @@ testFirewallRemoveRule(const void *opaque)
|
|
if (virFirewallSetBackend(data->tryBackend) < 0)
|
|
goto cleanup;
|
|
|
|
- if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT)
|
|
+ if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT ||
|
|
+ data->expectBackend == VIR_FIREWALL_BACKEND_FIREWALLD)
|
|
virCommandSetDryRun(&cmdbuf, NULL, NULL);
|
|
else
|
|
fwBuf = &cmdbuf;
|
|
@@ -335,7 +337,8 @@ testFirewallManyGroups(const void *opaque G_GNUC_UNUSED)
|
|
if (virFirewallSetBackend(data->tryBackend) < 0)
|
|
goto cleanup;
|
|
|
|
- if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT)
|
|
+ if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT ||
|
|
+ data->expectBackend == VIR_FIREWALL_BACKEND_FIREWALLD)
|
|
virCommandSetDryRun(&cmdbuf, NULL, NULL);
|
|
else
|
|
fwBuf = &cmdbuf;
|
|
@@ -426,7 +429,8 @@ testFirewallIgnoreFailGroup(const void *opaque G_GNUC_UNUSED)
|
|
if (virFirewallSetBackend(data->tryBackend) < 0)
|
|
goto cleanup;
|
|
|
|
- if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT) {
|
|
+ if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT ||
|
|
+ data->expectBackend == VIR_FIREWALL_BACKEND_FIREWALLD) {
|
|
virCommandSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL);
|
|
} else {
|
|
fwBuf = &cmdbuf;
|
|
@@ -498,7 +502,8 @@ testFirewallIgnoreFailRule(const void *opaque G_GNUC_UNUSED)
|
|
if (virFirewallSetBackend(data->tryBackend) < 0)
|
|
goto cleanup;
|
|
|
|
- if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT) {
|
|
+ if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT ||
|
|
+ data->expectBackend == VIR_FIREWALL_BACKEND_FIREWALLD) {
|
|
virCommandSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL);
|
|
} else {
|
|
fwBuf = &cmdbuf;
|
|
@@ -567,7 +572,8 @@ testFirewallNoRollback(const void *opaque G_GNUC_UNUSED)
|
|
if (virFirewallSetBackend(data->tryBackend) < 0)
|
|
goto cleanup;
|
|
|
|
- if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT) {
|
|
+ if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT ||
|
|
+ data->expectBackend == VIR_FIREWALL_BACKEND_FIREWALLD) {
|
|
virCommandSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL);
|
|
} else {
|
|
fwBuf = &cmdbuf;
|
|
@@ -634,7 +640,8 @@ testFirewallSingleRollback(const void *opaque G_GNUC_UNUSED)
|
|
if (virFirewallSetBackend(data->tryBackend) < 0)
|
|
goto cleanup;
|
|
|
|
- if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT) {
|
|
+ if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT ||
|
|
+ data->expectBackend == VIR_FIREWALL_BACKEND_FIREWALLD) {
|
|
virCommandSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL);
|
|
} else {
|
|
fwError = true;
|
|
@@ -717,7 +724,8 @@ testFirewallManyRollback(const void *opaque G_GNUC_UNUSED)
|
|
if (virFirewallSetBackend(data->tryBackend) < 0)
|
|
goto cleanup;
|
|
|
|
- if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT) {
|
|
+ if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT ||
|
|
+ data->expectBackend == VIR_FIREWALL_BACKEND_FIREWALLD) {
|
|
virCommandSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL);
|
|
} else {
|
|
fwBuf = &cmdbuf;
|
|
@@ -808,7 +816,8 @@ testFirewallChainedRollback(const void *opaque G_GNUC_UNUSED)
|
|
if (virFirewallSetBackend(data->tryBackend) < 0)
|
|
goto cleanup;
|
|
|
|
- if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT) {
|
|
+ if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT ||
|
|
+ data->expectBackend == VIR_FIREWALL_BACKEND_FIREWALLD) {
|
|
virCommandSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL);
|
|
} else {
|
|
fwBuf = &cmdbuf;
|
|
@@ -1007,7 +1016,8 @@ testFirewallQuery(const void *opaque G_GNUC_UNUSED)
|
|
if (virFirewallSetBackend(data->tryBackend) < 0)
|
|
goto cleanup;
|
|
|
|
- if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT) {
|
|
+ if (data->expectBackend == VIR_FIREWALL_BACKEND_DIRECT ||
|
|
+ data->expectBackend == VIR_FIREWALL_BACKEND_FIREWALLD) {
|
|
virCommandSetDryRun(&cmdbuf, testFirewallQueryHook, NULL);
|
|
} else {
|
|
fwBuf = &cmdbuf;
|
|
--
|
|
2.30.0
|
|
|