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