Blame SOURCES/libvirt-network-allow-configuring-firewalld-zone-for-virtual-network-bridge-device.patch

edecca
From 69de85ec80efd714528955e9c0ab67ee6811c824 Mon Sep 17 00:00:00 2001
edecca
Message-Id: <69de85ec80efd714528955e9c0ab67ee6811c824@dist-git>
edecca
From: Laine Stump <laine@laine.org>
edecca
Date: Fri, 1 Feb 2019 20:29:32 -0500
edecca
Subject: [PATCH] network: allow configuring firewalld zone for virtual network
edecca
 bridge device
edecca
MIME-Version: 1.0
edecca
Content-Type: text/plain; charset=UTF-8
edecca
Content-Transfer-Encoding: 8bit
edecca
edecca
Since we're setting the zone anyway, it will be useful to allow
edecca
setting a different (custom) zone for each network. This will be done
edecca
by adding a "zone" attribute to the "bridge" element, e.g.:
edecca
edecca
   ...
edecca
   <bridge name='virbr0' zone='myzone'/>
edecca
   ...
edecca
edecca
If a zone is specified in the config and it can't be honored, this
edecca
will be an error.
edecca
edecca
Signed-off-by: Laine Stump <laine@laine.org>
edecca
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
edecca
(cherry picked from commit 30a6f9168634f8ce269f1ef294c4a18d9c95939c)
edecca
edecca
Conflicts:
edecca
edecca
   src/conf/network_conf.c - upstream added a new bool called
edecca
     hasBridge that is the equivalent of all the comparisons in the
edecca
     if() just following the line that adds "zone='blah'" to the xml
edecca
     string.
edecca
edecca
https://bugzilla.redhat.com/1650320
edecca
edecca
Signed-off-by: Laine Stump <laine@laine.org>
edecca
Reviewed-by: Ján Tomko <jtomko@redhat.com>
edecca
---
edecca
 docs/firewall.html.in                      |  5 ++
edecca
 docs/formatnetwork.html.in                 | 17 ++++
edecca
 docs/schemas/basictypes.rng                |  6 ++
edecca
 docs/schemas/network.rng                   |  6 ++
edecca
 src/conf/network_conf.c                    | 14 +++-
edecca
 src/conf/network_conf.h                    |  1 +
edecca
 src/network/bridge_driver_linux.c          | 95 +++++++++++++---------
edecca
 tests/networkxml2xmlin/routed-network.xml  |  2 +-
edecca
 tests/networkxml2xmlout/routed-network.xml |  2 +-
edecca
 9 files changed, 106 insertions(+), 42 deletions(-)
edecca
edecca
diff --git a/docs/firewall.html.in b/docs/firewall.html.in
edecca
index 5d584e582e..e86ab0d974 100644
edecca
--- a/docs/firewall.html.in
edecca
+++ b/docs/firewall.html.in
edecca
@@ -151,6 +151,11 @@ MASQUERADE all  --  *      *       192.168.122.0/24    !192.168.122.0/24
edecca
       iptables rules regardless of which backend is in use by
edecca
       firewalld.
edecca
     

edecca
+    

edecca
+      NB: It is possible to manually set the firewalld zone for a
edecca
+      network's interface with the "zone" attribute of the network's
edecca
+      "bridge" element.
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
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
edecca
index 363a72bbc9..7ddcfee127 100644
edecca
--- a/docs/formatnetwork.html.in
edecca
+++ b/docs/formatnetwork.html.in
edecca
@@ -152,6 +152,23 @@
edecca
           Since 1.2.11, requires kernel 3.17 or
edecca
           newer
edecca
         

edecca
+
edecca
+        

edecca
+          The optional zone attribute of
edecca
+          the bridge element is used to specify
edecca
+          the firewalld
edecca
+          zone for the bridge of a network with forward
edecca
+          mode of "nat", "route", "open", or one with
edecca
+          no forward specified. By default, the bridges
edecca
+          of all virtual networks with these forward modes are placed
edecca
+          in the firewalld zone named "libvirt", which permits
edecca
+          incoming DNS, DHCP, TFTP, and SSH to the host from guests on
edecca
+          the network. This behavior can be changed either by
edecca
+          modifying the libvirt zone (using firewalld management
edecca
+          tools), or by placing the network in a different zone (which
edecca
+          will also be managed using firewalld tools).
edecca
+          Since 5.1.0
edecca
+        

edecca
       
edecca
 
edecca
       
mtu
edecca
diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
edecca
index 1a18cd31b1..b45a7fcdc8 100644
edecca
--- a/docs/schemas/basictypes.rng
edecca
+++ b/docs/schemas/basictypes.rng
edecca
@@ -252,6 +252,12 @@
edecca
     </data>
edecca
   </define>
edecca
 
edecca
+  <define name="zoneName">
edecca
+    <data type="string">
edecca
+      <param name="pattern">[a-zA-Z0-9_\-]+</param>
edecca
+    </data>
edecca
+  </define>
edecca
+
edecca
   <define name="filePath">
edecca
     <data type="string">
edecca
       <param name="pattern">.+</param>
edecca
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
edecca
index f37c422bf3..2a6e3358fd 100644
edecca
--- a/docs/schemas/network.rng
edecca
+++ b/docs/schemas/network.rng
edecca
@@ -58,6 +58,12 @@
edecca
               </attribute>
edecca
             </optional>
edecca
 
edecca
+            <optional>
edecca
+              <attribute name="zone">
edecca
+                <ref name="zoneName"/>
edecca
+              </attribute>
edecca
+            </optional>
edecca
+
edecca
             <optional>
edecca
               <attribute name="stp">
edecca
                 <ref name="virOnOff"/>
edecca
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
edecca
index 630a87fc07..1e3650b70f 100644
edecca
--- a/src/conf/network_conf.c
edecca
+++ b/src/conf/network_conf.c
edecca
@@ -206,6 +206,7 @@ virNetworkDefFree(virNetworkDefPtr def)
edecca
 
edecca
     VIR_FREE(def->name);
edecca
     VIR_FREE(def->bridge);
edecca
+    VIR_FREE(def->bridgeZone);
edecca
     VIR_FREE(def->domain);
edecca
 
edecca
     virNetworkForwardDefClear(&def->forward);
edecca
@@ -1689,6 +1690,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
edecca
 
edecca
     /* Parse bridge information */
edecca
     def->bridge = virXPathString("string(./bridge[1]/@name)", ctxt);
edecca
+    def->bridgeZone = virXPathString("string(./bridge[1]/@zone)", ctxt);
edecca
     stp = virXPathString("string(./bridge[1]/@stp)", ctxt);
edecca
     def->stp = (stp && STREQ(stp, "off")) ? false : true;
edecca
 
edecca
@@ -1925,6 +1927,13 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
edecca
                            def->name);
edecca
             goto error;
edecca
         }
edecca
+        if (def->bridgeZone) {
edecca
+            virReportError(VIR_ERR_XML_ERROR,
edecca
+                           _("bridge zone not allowed in %s mode (network '%s')"),
edecca
+                           virNetworkForwardTypeToString(def->forward.type),
edecca
+                           def->name);
edecca
+            goto error;
edecca
+        }
edecca
         if (def->macTableManager) {
edecca
             virReportError(VIR_ERR_XML_ERROR,
edecca
                            _("bridge macTableManager setting not allowed "
edecca
@@ -1936,9 +1945,9 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
edecca
         ATTRIBUTE_FALLTHROUGH;
edecca
 
edecca
     case VIR_NETWORK_FORWARD_BRIDGE:
edecca
-        if (def->delay || stp) {
edecca
+        if (def->delay || stp || def->bridgeZone) {
edecca
             virReportError(VIR_ERR_XML_ERROR,
edecca
-                           _("bridge delay/stp options only allowed in "
edecca
+                           _("bridge delay/stp/zone options only allowed in "
edecca
                              "route, nat, and isolated mode, not in %s "
edecca
                              "(network '%s')"),
edecca
                            virNetworkForwardTypeToString(def->forward.type),
edecca
@@ -2478,6 +2487,7 @@ virNetworkDefFormatBuf(virBufferPtr buf,
edecca
 
edecca
         virBufferAddLit(buf, "
edecca
         virBufferEscapeString(buf, " name='%s'", def->bridge);
edecca
+        virBufferEscapeString(buf, " zone='%s'", def->bridgeZone);
edecca
         if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
edecca
             def->forward.type == VIR_NETWORK_FORWARD_NAT ||
edecca
             def->forward.type == VIR_NETWORK_FORWARD_ROUTE ||
edecca
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
edecca
index 54c8ed1c4c..415792166f 100644
edecca
--- a/src/conf/network_conf.h
edecca
+++ b/src/conf/network_conf.h
edecca
@@ -237,6 +237,7 @@ struct _virNetworkDef {
edecca
     int   connections; /* # of guest interfaces connected to this network */
edecca
 
edecca
     char *bridge;       /* Name of bridge device */
edecca
+    char *bridgeZone;  /* name of firewalld zone for bridge */
edecca
     int  macTableManager; /* enum virNetworkBridgeMACTableManager */
edecca
     char *domain;
edecca
     int domainLocalOnly; /* enum virTristateBool: yes disables dns forwarding */
edecca
diff --git a/src/network/bridge_driver_linux.c b/src/network/bridge_driver_linux.c
edecca
index 823d5a9742..121d42b646 100644
edecca
--- a/src/network/bridge_driver_linux.c
edecca
+++ b/src/network/bridge_driver_linux.c
edecca
@@ -642,49 +642,68 @@ 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
+    if (def->bridgeZone) {
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
+        /* if a firewalld zone has been specified, fail/log an error
edecca
+         * if we can't honor it
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
+        if (virFirewallDIsRegistered() < 0) {
edecca
+            virReportError(VIR_ERR_INTERNAL_ERROR,
edecca
+                           _("zone %s requested for network %s "
edecca
+                             "but firewalld is not active"),
edecca
+                           def->bridgeZone, def->name);
edecca
+            goto cleanup;
edecca
+        }
edecca
 
edecca
-            if (vresult < 0)
edecca
-                goto cleanup;
edecca
+        if (virFirewallDInterfaceSetZone(def->bridge, def->bridgeZone) < 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
+    } else {
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 (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
+            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
diff --git a/tests/networkxml2xmlin/routed-network.xml b/tests/networkxml2xmlin/routed-network.xml
edecca
index ab5e15b1f6..fce01df132 100644
edecca
--- a/tests/networkxml2xmlin/routed-network.xml
edecca
+++ b/tests/networkxml2xmlin/routed-network.xml
edecca
@@ -1,7 +1,7 @@
edecca
 <network>
edecca
   <name>local</name>
edecca
   <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
edecca
-  <bridge name="virbr1"/>
edecca
+  <bridge name="virbr1" zone="myzone"/>
edecca
   <mac address='12:34:56:78:9A:BC'/>
edecca
   <forward mode="route" dev="eth1"/>
edecca
   <ip address="192.168.122.1" netmask="255.255.255.0">
edecca
diff --git a/tests/networkxml2xmlout/routed-network.xml b/tests/networkxml2xmlout/routed-network.xml
edecca
index 81abf06e9f..2e13cf4ffa 100644
edecca
--- a/tests/networkxml2xmlout/routed-network.xml
edecca
+++ b/tests/networkxml2xmlout/routed-network.xml
edecca
@@ -4,7 +4,7 @@
edecca
   <forward dev='eth1' mode='route'>
edecca
     <interface dev='eth1'/>
edecca
   </forward>
edecca
-  <bridge name='virbr1' stp='on' delay='0'/>
edecca
+  <bridge name='virbr1' zone='myzone' stp='on' delay='0'/>
edecca
   <mac address='12:34:56:78:9a:bc'/>
edecca
   <ip address='192.168.122.1' netmask='255.255.255.0'>
edecca
   </ip>
edecca
-- 
edecca
2.20.1
edecca