9c6c51
From 477f1de37ff7c911048d8d5e7f7de32f12d30b5d Mon Sep 17 00:00:00 2001
9c6c51
Message-Id: <477f1de37ff7c911048d8d5e7f7de32f12d30b5d@dist-git>
9c6c51
From: Laine Stump <laine@laine.org>
9c6c51
Date: Fri, 1 Feb 2019 20:29:29 -0500
9c6c51
Subject: [PATCH] util: new virFirewallD APIs + docs
9c6c51
MIME-Version: 1.0
9c6c51
Content-Type: text/plain; charset=UTF-8
9c6c51
Content-Transfer-Encoding: 8bit
9c6c51
9c6c51
virFirewallDGetBackend() reports whether firewalld is currently using
9c6c51
an iptables or an nftables backend.
9c6c51
9c6c51
virFirewallDGetVersion() learns the version of the firewalld running
9c6c51
on this system and returns it as 1000000*major + 1000*minor + micro.
9c6c51
9c6c51
virFirewallDGetZones() gets a list of all currently active firewalld
9c6c51
zones.
9c6c51
9c6c51
virFirewallDInterfaceSetZone() sets the firewalld zone of the given
9c6c51
interface.
9c6c51
9c6c51
virFirewallDZoneExists() can be used to learn whether or not a
9c6c51
particular zone is present and active in firewalld.
9c6c51
9c6c51
Signed-off-by: Laine Stump <laine@laine.org>
9c6c51
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
9c6c51
(cherry picked from commit 3bba4825c291e51a8cd4d497d6e919ac2ee96ff0)
9c6c51
9c6c51
Conflicts: src/util/virfirewalld.c - had to remove VIR_AUTO_PTR(), which doesn't
9c6c51
   exist in libvirt 4.5.0, and replace with appropriately placed VIR_FREE()
9c6c51
9c6c51
https://bugzilla.redhat.com/1650320
9c6c51
9c6c51
Signed-off-by: Laine Stump <laine@laine.org>
9c6c51
Reviewed-by: Ján Tomko <jtomko@redhat.com>
9c6c51
---
9c6c51
 src/libvirt_private.syms |   5 +
9c6c51
 src/util/virfirewalld.c  | 223 +++++++++++++++++++++++++++++++++++++++
9c6c51
 src/util/virfirewalld.h  |  15 ++-
9c6c51
 3 files changed, 242 insertions(+), 1 deletion(-)
9c6c51
9c6c51
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
9c6c51
index 57948d8049..624151056a 100644
9c6c51
--- a/src/libvirt_private.syms
9c6c51
+++ b/src/libvirt_private.syms
9c6c51
@@ -1905,7 +1905,12 @@ virFirewallStartTransaction;
9c6c51
 
9c6c51
 # util/virfirewalld.h
9c6c51
 virFirewallDApplyRule;
9c6c51
+virFirewallDGetBackend;
9c6c51
+virFirewallDGetVersion;
9c6c51
+virFirewallDGetZones;
9c6c51
+virFirewallDInterfaceSetZone;
9c6c51
 virFirewallDIsRegistered;
9c6c51
+virFirewallDZoneExists;
9c6c51
 
9c6c51
 
9c6c51
 # util/virfirmware.h
9c6c51
diff --git a/src/util/virfirewalld.c b/src/util/virfirewalld.c
9c6c51
index f27ec9c124..8dd6ac2b8a 100644
9c6c51
--- a/src/util/virfirewalld.c
9c6c51
+++ b/src/util/virfirewalld.c
9c6c51
@@ -22,6 +22,7 @@
9c6c51
 
9c6c51
 #include <stdarg.h>
9c6c51
 
9c6c51
+#include "viralloc.h"
9c6c51
 #include "virfirewall.h"
9c6c51
 #include "virfirewalld.h"
9c6c51
 #define LIBVIRT_VIRFIREWALLDPRIV_H_ALLOW
9c6c51
@@ -46,6 +47,14 @@ VIR_ENUM_IMPL(virFirewallLayerFirewallD, VIR_FIREWALL_LAYER_LAST,
9c6c51
               );
9c6c51
 
9c6c51
 
9c6c51
+VIR_ENUM_DECL(virFirewallDBackend);
9c6c51
+VIR_ENUM_IMPL(virFirewallDBackend, VIR_FIREWALLD_BACKEND_LAST,
9c6c51
+              "",
9c6c51
+              "iptables",
9c6c51
+              "nftables",
9c6c51
+              );
9c6c51
+
9c6c51
+
9c6c51
 /**
9c6c51
  * virFirewallDIsRegistered:
9c6c51
  *
9c6c51
@@ -57,6 +66,197 @@ virFirewallDIsRegistered(void)
9c6c51
     return virDBusIsServiceRegistered(VIR_FIREWALL_FIREWALLD_SERVICE);
9c6c51
 }
9c6c51
 
9c6c51
+/**
9c6c51
+ * virFirewallDGetVersion:
9c6c51
+ * @version: pointer to location to save version in the form of:
9c6c51
+ *           1000000 * major + 1000 * minor + micro
9c6c51
+ *
9c6c51
+ * queries the firewalld version property from dbus, and converts it
9c6c51
+ * from a string into a number.
9c6c51
+ *
9c6c51
+ * Returns 0 if version was successfully retrieved, or -1 on error
9c6c51
+ */
9c6c51
+int
9c6c51
+virFirewallDGetVersion(unsigned long *version)
9c6c51
+{
9c6c51
+    int ret = -1;
9c6c51
+    DBusConnection *sysbus = virDBusGetSystemBus();
9c6c51
+    DBusMessage *reply = NULL;
9c6c51
+    char * versionStr = NULL;
9c6c51
+
9c6c51
+    if (!sysbus)
9c6c51
+        return -1;
9c6c51
+
9c6c51
+    if (virDBusCallMethod(sysbus,
9c6c51
+                          &reply,
9c6c51
+                          NULL,
9c6c51
+                          VIR_FIREWALL_FIREWALLD_SERVICE,
9c6c51
+                          "/org/fedoraproject/FirewallD1",
9c6c51
+                          "org.freedesktop.DBus.Properties",
9c6c51
+                          "Get",
9c6c51
+                          "ss",
9c6c51
+                          "org.fedoraproject.FirewallD1",
9c6c51
+                          "version") < 0)
9c6c51
+        goto cleanup;
9c6c51
+
9c6c51
+    if (virDBusMessageRead(reply, "v", "s", &versionStr) < 0)
9c6c51
+        goto cleanup;
9c6c51
+
9c6c51
+    if (virParseVersionString(versionStr, version, false) < 0) {
9c6c51
+        virReportError(VIR_ERR_INTERNAL_ERROR,
9c6c51
+                       _("Failed to parse firewalld version '%s'"),
9c6c51
+                       versionStr);
9c6c51
+        goto cleanup;
9c6c51
+    }
9c6c51
+
9c6c51
+    VIR_DEBUG("FirewallD version: %s - %lu", versionStr, *version);
9c6c51
+
9c6c51
+    ret = 0;
9c6c51
+ cleanup:
9c6c51
+    VIR_FREE(versionStr);
9c6c51
+    virDBusMessageUnref(reply);
9c6c51
+    return ret;
9c6c51
+}
9c6c51
+
9c6c51
+/**
9c6c51
+ * virFirewallDGetBackend:
9c6c51
+ *
9c6c51
+ * Returns virVirewallDBackendType value representing which packet
9c6c51
+ * filtering backend is currently in use by firewalld, or -1 on error.
9c6c51
+ */
9c6c51
+int
9c6c51
+virFirewallDGetBackend(void)
9c6c51
+{
9c6c51
+    DBusConnection *sysbus = virDBusGetSystemBus();
9c6c51
+    DBusMessage *reply = NULL;
9c6c51
+    virError error;
9c6c51
+    char * backendStr = NULL;
9c6c51
+    int backend = -1;
9c6c51
+
9c6c51
+    if (!sysbus)
9c6c51
+        return -1;
9c6c51
+
9c6c51
+    memset(&error, 0, sizeof(error));
9c6c51
+
9c6c51
+    if (virDBusCallMethod(sysbus,
9c6c51
+                          &reply,
9c6c51
+                          &error,
9c6c51
+                          VIR_FIREWALL_FIREWALLD_SERVICE,
9c6c51
+                          "/org/fedoraproject/FirewallD1/config",
9c6c51
+                          "org.freedesktop.DBus.Properties",
9c6c51
+                          "Get",
9c6c51
+                          "ss",
9c6c51
+                          "org.fedoraproject.FirewallD1.config",
9c6c51
+                          "FirewallBackend") < 0)
9c6c51
+        goto cleanup;
9c6c51
+
9c6c51
+    if (error.level == VIR_ERR_ERROR) {
9c6c51
+        /* we don't want to log any error in the case that
9c6c51
+         * FirewallBackend isn't implemented in this firewalld, since
9c6c51
+         * that just means that it is an old version, and only has an
9c6c51
+         * iptables backend.
9c6c51
+         */
9c6c51
+        VIR_DEBUG("Failed to get FirewallBackend setting, assuming 'iptables'");
9c6c51
+        backend = VIR_FIREWALLD_BACKEND_IPTABLES;
9c6c51
+        goto cleanup;
9c6c51
+    }
9c6c51
+
9c6c51
+    if (virDBusMessageRead(reply, "v", "s", &backendStr) < 0)
9c6c51
+        goto cleanup;
9c6c51
+
9c6c51
+    VIR_DEBUG("FirewallD backend: %s", backendStr);
9c6c51
+
9c6c51
+    if ((backend = virFirewallDBackendTypeFromString(backendStr)) < 0) {
9c6c51
+        virReportError(VIR_ERR_INTERNAL_ERROR,
9c6c51
+                       _("Unrecognized firewalld backend type: %s"),
9c6c51
+                       backendStr);
9c6c51
+        goto cleanup;
9c6c51
+    }
9c6c51
+
9c6c51
+ cleanup:
9c6c51
+    VIR_FREE(backendStr);
9c6c51
+    virResetError(&error);
9c6c51
+    virDBusMessageUnref(reply);
9c6c51
+    return backend;
9c6c51
+}
9c6c51
+
9c6c51
+
9c6c51
+/**
9c6c51
+ * virFirewallDGetZones:
9c6c51
+ * @zones: array of char *, each entry is a null-terminated zone name
9c6c51
+ * @nzones: number of entries in @zones
9c6c51
+ *
9c6c51
+ * Get the number of currently active firewalld zones, and their names
9c6c51
+ * in an array of null-terminated strings. The memory pointed to by
9c6c51
+ * @zones will belong to the caller, and must be freed.
9c6c51
+ *
9c6c51
+ * Returns 0 on success, -1 (and failure logged) on error
9c6c51
+ */
9c6c51
+int
9c6c51
+virFirewallDGetZones(char ***zones, size_t *nzones)
9c6c51
+{
9c6c51
+    DBusConnection *sysbus = virDBusGetSystemBus();
9c6c51
+    DBusMessage *reply = NULL;
9c6c51
+    int ret = -1;
9c6c51
+
9c6c51
+    *nzones = 0;
9c6c51
+    *zones = NULL;
9c6c51
+
9c6c51
+    if (!sysbus)
9c6c51
+        return -1;
9c6c51
+
9c6c51
+    if (virDBusCallMethod(sysbus,
9c6c51
+                          &reply,
9c6c51
+                          NULL,
9c6c51
+                          VIR_FIREWALL_FIREWALLD_SERVICE,
9c6c51
+                          "/org/fedoraproject/FirewallD1",
9c6c51
+                          "org.fedoraproject.FirewallD1.zone",
9c6c51
+                          "getZones",
9c6c51
+                          NULL) < 0)
9c6c51
+        goto cleanup;
9c6c51
+
9c6c51
+    if (virDBusMessageRead(reply, "a&s", nzones, zones) < 0)
9c6c51
+        goto cleanup;
9c6c51
+
9c6c51
+    ret = 0;
9c6c51
+ cleanup:
9c6c51
+    virDBusMessageUnref(reply);
9c6c51
+    return ret;
9c6c51
+}
9c6c51
+
9c6c51
+
9c6c51
+/**
9c6c51
+ * virFirewallDZoneExists:
9c6c51
+ * @match: name of zone to look for
9c6c51
+ *
9c6c51
+ * Returns true if the requested zone exists, or false if it doesn't exist
9c6c51
+ */
9c6c51
+bool
9c6c51
+virFirewallDZoneExists(const char *match)
9c6c51
+{
9c6c51
+    size_t nzones = 0, i;
9c6c51
+    char **zones = NULL;
9c6c51
+    bool result = false;
9c6c51
+
9c6c51
+    return true;
9c6c51
+
9c6c51
+    if (virFirewallDGetZones(&zones, &nzones) < 0)
9c6c51
+        goto cleanup;
9c6c51
+
9c6c51
+    for (i = 0; i < nzones; i++) {
9c6c51
+        if (STREQ_NULLABLE(zones[i], match))
9c6c51
+            result = true;
9c6c51
+    }
9c6c51
+
9c6c51
+ cleanup:
9c6c51
+    VIR_DEBUG("Requested zone '%s' %s exist",
9c6c51
+              match, result ? "does" : "doesn't");
9c6c51
+    for (i = 0; i < nzones; i++)
9c6c51
+       VIR_FREE(zones[i]);
9c6c51
+    VIR_FREE(zones);
9c6c51
+    return result;
9c6c51
+}
9c6c51
+
9c6c51
 
9c6c51
 /**
9c6c51
  * virFirewallDApplyRule:
9c6c51
@@ -149,3 +349,26 @@ virFirewallDApplyRule(virFirewallLayer layer,
9c6c51
     virDBusMessageUnref(reply);
9c6c51
     return ret;
9c6c51
 }
9c6c51
+
9c6c51
+
9c6c51
+int
9c6c51
+virFirewallDInterfaceSetZone(const char *iface,
9c6c51
+                             const char *zone)
9c6c51
+{
9c6c51
+    DBusConnection *sysbus = virDBusGetSystemBus();
9c6c51
+    DBusMessage *reply = NULL;
9c6c51
+
9c6c51
+    if (!sysbus)
9c6c51
+        return -1;
9c6c51
+
9c6c51
+    return virDBusCallMethod(sysbus,
9c6c51
+                             &reply,
9c6c51
+                             NULL,
9c6c51
+                             VIR_FIREWALL_FIREWALLD_SERVICE,
9c6c51
+                             "/org/fedoraproject/FirewallD1",
9c6c51
+                             "org.fedoraproject.FirewallD1.zone",
9c6c51
+                             "changeZoneOfInterface",
9c6c51
+                             "ss",
9c6c51
+                             zone,
9c6c51
+                             iface);
9c6c51
+}
9c6c51
diff --git a/src/util/virfirewalld.h b/src/util/virfirewalld.h
9c6c51
index 83fe1149cc..f05f5f2f08 100644
9c6c51
--- a/src/util/virfirewalld.h
9c6c51
+++ b/src/util/virfirewalld.h
9c6c51
@@ -23,11 +23,24 @@
9c6c51
 
9c6c51
 # define VIR_FIREWALL_FIREWALLD_SERVICE "org.fedoraproject.FirewallD1"
9c6c51
 
9c6c51
-int virFirewallDIsRegistered(void);
9c6c51
+typedef enum {
9c6c51
+    VIR_FIREWALLD_BACKEND_NONE,
9c6c51
+    VIR_FIREWALLD_BACKEND_IPTABLES,
9c6c51
+    VIR_FIREWALLD_BACKEND_NFTABLES,
9c6c51
+    VIR_FIREWALLD_BACKEND_LAST,
9c6c51
+} virFirewallDBackendType;
9c6c51
 
9c6c51
+int virFirewallDGetVersion(unsigned long *version);
9c6c51
+int virFirewallDGetBackend(void);
9c6c51
+int virFirewallDIsRegistered(void);
9c6c51
+int virFirewallDGetZones(char ***zones, size_t *nzones);
9c6c51
+bool virFirewallDZoneExists(const char *match);
9c6c51
 int virFirewallDApplyRule(virFirewallLayer layer,
9c6c51
                           char **args, size_t argsLen,
9c6c51
                           bool ignoreErrors,
9c6c51
                           char **output);
9c6c51
 
9c6c51
+int virFirewallDInterfaceSetZone(const char *iface,
9c6c51
+                                 const char *zone);
9c6c51
+
9c6c51
 #endif /* LIBVIRT_VIRFIREWALLD_H */
9c6c51
-- 
9c6c51
2.20.1
9c6c51