Blame SOURCES/libvirt-network-set-firewalld-zone-of-bridges-to-libvirt-zone-when-appropriate.patch

edecca
From 8cc240a1652a465727d5b66d9fb6a5fa71656dba Mon Sep 17 00:00:00 2001
edecca
Message-Id: <8cc240a1652a465727d5b66d9fb6a5fa71656dba@dist-git>
edecca
From: Laine Stump <laine@redhat.com>
edecca
Date: Fri, 1 Feb 2019 20:29:31 -0500
edecca
Subject: [PATCH] network: set firewalld zone of bridges to "libvirt" zone when
edecca
 appropriate
edecca
MIME-Version: 1.0
edecca
Content-Type: text/plain; charset=UTF-8
edecca
Content-Transfer-Encoding: 8bit
edecca
edecca
This patch restores broken guest network connectivity after a host
edecca
firewalld is switched to using an nftables backend. It does this by
edecca
adding libvirt networks' bridge interfaces to the new "libvirt" zone
edecca
in firewalld.
edecca
edecca
After this patch, the bridge interface of any network created by
edecca
libvirt (when firewalld is active) will be added to the firewalld
edecca
zone called "libvirt" if it exists (regardless of the firewalld
edecca
backend setting). This behavior does *not* depend on whether or not
edecca
libvirt has installed the libvirt zone file (set with
edecca
"--with[out]-firewalld-zone" during the configure phase of the package
edecca
build).
edecca
edecca
If the libvirt zone doesn't exist (either because the package was
edecca
configured to not install it, or possibly it was installed, but
edecca
firewalld doesn't support rule priorities, resulting in a parse
edecca
error), the bridge will remain in firewalld's default zone, which
edecca
could be innocuous (in the case that the firewalld backend is
edecca
iptables, guest networking will still function properly with the
edecca
bridge in the default zone), or it could be disastrous (if the
edecca
firewalld backend is nftables, we can be assured that guest networking
edecca
will fail). In order to be unobtrusive in the former case, and
edecca
informative in the latter, when the libvirt zone doesn't exist we
edecca
then check the firewalld version to see if it's new enough to support
edecca
the nftables backend, and then if the backend is actually set to
edecca
nftables, before logging an error (and failing the net-start
edecca
operation, since the network couldn't possibly work anyway).
edecca
edecca
When the libvirt zone is used, network behavior is *slightly*
edecca
different from behavior of previous libvirt. In the past, libvirt
edecca
network behavior would be affected by the configuration of firewalld's
edecca
default zone (usually "public"), but now it is affected only by the
edecca
"libvirt" zone), and thus almost surely warrants a release note for
edecca
any distro upgrading to libvirt 5.1 or above. Although it's
edecca
unfortunate that we have to deal with a mandatory behavior change, the
edecca
architecture of multiple hooks makes it impossible to *not* change
edecca
behavior in some way, and the new behavior is arguably better (since
edecca
it will now be possible to manage access to the host from virtual
edecca
machines vs from public interfaces separately).
edecca
edecca
Creates-and-Resolves: https://bugzilla.redhat.com/1650320
edecca
Resolves: https://bugzilla.redhat.com/1638342
edecca
Signed-off-by: Laine Stump <laine@laine.org>
edecca
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
edecca
(cherry picked from commit ae05211a360077f56883cd0a6c0f82ed57f746cb)
edecca
Reviewed-by: Ján Tomko <jtomko@redhat.com>
edecca
---
edecca
 docs/firewall.html.in             | 33 +++++++++++++++++++++
edecca
 src/network/bridge_driver_linux.c | 48 +++++++++++++++++++++++++++++++
edecca
 2 files changed, 81 insertions(+)
edecca
edecca
diff --git a/docs/firewall.html.in b/docs/firewall.html.in
edecca
index 0a50687c26..5d584e582e 100644
edecca
--- a/docs/firewall.html.in
edecca
+++ b/docs/firewall.html.in
edecca
@@ -129,6 +129,39 @@ MASQUERADE all  --  *      *       192.168.122.0/24    !192.168.122.0/24
edecca
       
edecca
     
edecca
 
edecca
+    

firewalld and the virtual network driver

edecca
+    
edecca
+    

edecca
+      If firewalld is active on
edecca
+      the host, libvirt will attempt to place the bridge interface of
edecca
+      a libvirt virtual network into the firewalld zone named
edecca
+      "libvirt" (thus making all guest->host traffic on that network
edecca
+      subject to the rules of the "libvirt" zone). This is done
edecca
+      because, if firewalld is using its nftables backend (available
edecca
+      since firewalld 0.6.0) the default firewalld zone (which would
edecca
+      be used if libvirt didn't explicitly set the zone) prevents
edecca
+      forwarding traffic from guests through the bridge, as well as
edecca
+      preventing DHCP, DNS, and most other traffic from guests to
edecca
+      host. The zone named "libvirt" is installed into the firewalld
edecca
+      configuration by libvirt (not by firewalld), and allows
edecca
+      forwarded traffic through the bridge as well as DHCP, DNS, TFTP,
edecca
+      and SSH traffic to the host - depending on firewalld's backend
edecca
+      this will be implemented via either iptables or nftables
edecca
+      rules. libvirt's own rules outlined above will *always* be
edecca
+      iptables rules regardless of which backend is in use by
edecca
+      firewalld.
edecca
+    

edecca
+    

edecca
+      NB: Prior to libvirt 5.1.0, the firewalld "libvirt" zone did not
edecca
+      exist, and prior to firewalld 0.7.0 a feature crucial to making
edecca
+      the "libvirt" zone operate properly (rich rule priority
edecca
+      settings) was not implemented in firewalld. In cases where one
edecca
+      or the other of the two packages is missing the necessary
edecca
+      functionality, it's still possible to have functional guest
edecca
+      networking by setting the firewalld backend to "iptables" (in
edecca
+      firewalld prior to 0.6.0, this was the only backend available).
edecca
+    

edecca
+
edecca
     

The network filter driver

edecca
     
edecca
     

This driver provides a fully configurable network filtering capability

edecca
diff --git a/src/network/bridge_driver_linux.c b/src/network/bridge_driver_linux.c
edecca
index 3effcdce22..823d5a9742 100644
edecca
--- a/src/network/bridge_driver_linux.c
edecca
+++ b/src/network/bridge_driver_linux.c
edecca
@@ -29,6 +29,7 @@
edecca
 #include "virstring.h"
edecca
 #include "virlog.h"
edecca
 #include "virfirewall.h"
edecca
+#include "virfirewalld.h"
edecca
 
edecca
 #define VIR_FROM_THIS VIR_FROM_NONE
edecca
 
edecca
@@ -641,6 +642,53 @@ int networkAddFirewallRules(virNetworkDefPtr def)
edecca
     virFirewallPtr fw = NULL;
edecca
     int ret = -1;
edecca
 
edecca
+    /* if firewalld is active, try to set the "libvirt" zone. This is
edecca
+     * desirable (for consistency) if firewalld is using the iptables
edecca
+     * backend, but is necessary (for basic network connectivity) if
edecca
+     * firewalld is using the nftables backend
edecca
+     */
edecca
+    if (virFirewallDIsRegistered() == 0) {
edecca
+
edecca
+        /* if the "libvirt" zone exists, then set it. If not, and
edecca
+         * if firewalld is using the nftables backend, then we
edecca
+         * need to log an error because the combination of
edecca
+         * nftables + default zone means that traffic cannot be
edecca
+         * forwarded (and even DHCP and DNS from guest to host
edecca
+         * will probably no be permitted by the default zone
edecca
+         */
edecca
+        if (virFirewallDZoneExists("libvirt")) {
edecca
+            if (virFirewallDInterfaceSetZone(def->bridge, "libvirt") < 0)
edecca
+                goto cleanup;
edecca
+        } else {
edecca
+            unsigned long version;
edecca
+            int vresult = virFirewallDGetVersion(&version);
edecca
+
edecca
+            if (vresult < 0)
edecca
+                goto cleanup;
edecca
+
edecca
+            /* Support for nftables backend was added in firewalld
edecca
+             * 0.6.0. Support for rule priorities (required by the
edecca
+             * 'libvirt' zone, which should be installed by a
edecca
+             * libvirt package, *not* by firewalld) was not added
edecca
+             * until firewalld 0.7.0 (unless it was backported).
edecca
+             */
edecca
+            if (version >= 6000 &&
edecca
+                virFirewallDGetBackend() == VIR_FIREWALLD_BACKEND_NFTABLES) {
edecca
+                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
edecca
+                               _("firewalld is set to use the nftables "
edecca
+                                 "backend, but the required firewalld "
edecca
+                                 "'libvirt' zone is missing. Either set "
edecca
+                                 "the firewalld backend to 'iptables', or "
edecca
+                                 "ensure that firewalld has a 'libvirt' "
edecca
+                                 "zone by upgrading firewalld to a "
edecca
+                                 "version supporting rule priorities "
edecca
+                                 "(0.7.0+) and/or rebuilding "
edecca
+                                 "libvirt with --with-firewalld-zone"));
edecca
+                goto cleanup;
edecca
+            }
edecca
+        }
edecca
+    }
edecca
+
edecca
     fw = virFirewallNew();
edecca
 
edecca
     virFirewallStartTransaction(fw, 0);
edecca
-- 
edecca
2.20.1
edecca