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 <laine@xxxxxxxxx> --- Change from V1: define several new functions (previously was just a single function, now there are 5) src/libvirt_private.syms | 5 + src/util/virfirewalld.c | 222 +++++++++++++++++++++++++++++++++++++++ src/util/virfirewalld.h | 15 ++- 3 files changed, 241 insertions(+), 1 deletion(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d52e2412fa..bfae73878f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1923,7 +1923,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..89cfaddd9a 100644 --- a/src/util/virfirewalld.c +++ b/src/util/virfirewalld.c @@ -46,6 +46,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 +65,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; + VIR_AUTOFREE(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: + 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; + VIR_AUTOFREE(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); + } + + cleanup: + 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. + * + * 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++) { + VIR_DEBUG("FirewallD zone: %s", zones[i]); + if (STREQ_NULLABLE(zones[i], match)) + result = true; + } + + cleanup: + /* NB: zones points to memory inside reply, so it is cleaned + * up by virDBusMessageUnref, and doesn't need to be freed + */ + 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 +348,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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list