From da064c59cfc1f35f4638a9e05447c21fea88cb14 Mon Sep 17 00:00:00 2001 Message-Id: From: Laine Stump Date: Fri, 1 Feb 2019 20:29:28 -0500 Subject: [PATCH] util: move all firewalld-specific stuff into its own files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation for adding several other firewalld-specific functions, separate the code that's unique to firewalld from the more-generic "firewall" file. Signed-off-by: Laine Stump Reviewed-by: Daniel P. Berrangé (cherry picked from commit d8393b56e21708c219acc9bcd24a9c22ead4a3b4) Conflicts: src/util/virerror.c - ; added to end of MACRO in context upstream. https://bugzilla.redhat.com/1650320 Signed-off-by: Laine Stump Reviewed-by: Ján Tomko --- include/libvirt/virterror.h | 1 + src/libvirt_private.syms | 5 ++ src/util/Makefile.inc.am | 3 + src/util/virerror.c | 3 +- src/util/virfirewall.c | 86 +------------------- src/util/virfirewalld.c | 151 ++++++++++++++++++++++++++++++++++++ src/util/virfirewalld.h | 33 ++++++++ src/util/virfirewalldpriv.h | 30 +++++++ src/util/virfirewallpriv.h | 2 - tests/virfirewalltest.c | 2 + 10 files changed, 231 insertions(+), 85 deletions(-) create mode 100644 src/util/virfirewalld.c create mode 100644 src/util/virfirewalld.h create mode 100644 src/util/virfirewalldpriv.h diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 57aadb8d16..30197adc3b 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -133,6 +133,7 @@ typedef enum { VIR_FROM_PERF = 65, /* Error from perf */ VIR_FROM_LIBSSH = 66, /* Error from libssh connection transport */ VIR_FROM_RESCTRL = 67, /* Error from resource control */ + VIR_FROM_FIREWALLD = 68, /* Error from firewalld */ # ifdef VIR_ENUM_SENTINELS VIR_ERR_DOMAIN_LAST diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 86846f3b08..57948d8049 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1903,6 +1903,11 @@ virFirewallStartRollback; virFirewallStartTransaction; +# util/virfirewalld.h +virFirewallDApplyRule; +virFirewallDIsRegistered; + + # util/virfirmware.h virFirmwareFreeList; virFirmwareParse; diff --git a/src/util/Makefile.inc.am b/src/util/Makefile.inc.am index a22265606c..2cef465208 100644 --- a/src/util/Makefile.inc.am +++ b/src/util/Makefile.inc.am @@ -57,6 +57,9 @@ UTIL_SOURCES = \ util/virfirewall.c \ util/virfirewall.h \ util/virfirewallpriv.h \ + util/virfirewalld.c \ + util/virfirewalld.h \ + util/virfirewalldpriv.h \ util/virfirmware.c \ util/virfirmware.h \ util/virgettext.c \ diff --git a/src/util/virerror.c b/src/util/virerror.c index f198f27957..1d46fcdc82 100644 --- a/src/util/virerror.c +++ b/src/util/virerror.c @@ -140,7 +140,8 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST, "Perf", /* 65 */ "Libssh transport layer", "Resource control", - ) + "FirewallD", + ); /* diff --git a/src/util/virfirewall.c b/src/util/virfirewall.c index 10c370a2ae..4d084f6cbf 100644 --- a/src/util/virfirewall.c +++ b/src/util/virfirewall.c @@ -29,12 +29,12 @@ #include "viralloc.h" #include "virfirewallpriv.h" +#include "virfirewalld.h" #include "virerror.h" #include "virutil.h" #include "virstring.h" #include "vircommand.h" #include "virlog.h" -#include "virdbus.h" #include "virfile.h" #include "virthread.h" @@ -51,11 +51,6 @@ VIR_ENUM_IMPL(virFirewallLayerCommand, VIR_FIREWALL_LAYER_LAST, IPTABLES_PATH, IP6TABLES_PATH); -VIR_ENUM_DECL(virFirewallLayerFirewallD) -VIR_ENUM_IMPL(virFirewallLayerFirewallD, VIR_FIREWALL_LAYER_LAST, - "eb", "ipv4", "ipv6") - - struct _virFirewallRule { virFirewallLayer layer; @@ -158,7 +153,7 @@ virFirewallValidateBackend(virFirewallBackend backend) VIR_DEBUG("Validating backend %d", backend); if (backend == VIR_FIREWALL_BACKEND_AUTOMATIC || backend == VIR_FIREWALL_BACKEND_FIREWALLD) { - int rv = virDBusIsServiceRegistered(VIR_FIREWALL_FIREWALLD_SERVICE); + int rv = virFirewallDIsRegistered(); VIR_DEBUG("Firewalld is registered ? %d", rv); if (rv < 0) { @@ -726,81 +721,8 @@ virFirewallApplyRuleFirewallD(virFirewallRulePtr rule, bool ignoreErrors, char **output) { - const char *ipv = virFirewallLayerFirewallDTypeToString(rule->layer); - DBusConnection *sysbus = virDBusGetSystemBus(); - DBusMessage *reply = NULL; - virError error; - int ret = -1; - - if (!sysbus) - return -1; - - memset(&error, 0, sizeof(error)); - - if (!ipv) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Unknown firewall layer %d"), - rule->layer); - goto cleanup; - } - - if (virDBusCallMethod(sysbus, - &reply, - &error, - VIR_FIREWALL_FIREWALLD_SERVICE, - "/org/fedoraproject/FirewallD1", - "org.fedoraproject.FirewallD1.direct", - "passthrough", - "sa&s", - ipv, - (int)rule->argsLen, - rule->args) < 0) - goto cleanup; - - if (error.level == VIR_ERR_ERROR) { - /* - * As of firewalld-0.3.9.3-1.fc20.noarch the name and - * message fields in the error look like - * - * name="org.freedesktop.DBus.Python.dbus.exceptions.DBusException" - * message="COMMAND_FAILED: '/sbin/iptables --table filter --delete - * INPUT --in-interface virbr0 --protocol udp --destination-port 53 - * --jump ACCEPT' failed: iptables: Bad rule (does a matching rule - * exist in that chain?)." - * - * We'd like to only ignore DBus errors precisely related to the failure - * of iptables/ebtables commands. A well designed DBus interface would - * return specific named exceptions not the top level generic python dbus - * exception name. With this current scheme our only option is todo a - * sub-string match for 'COMMAND_FAILED' on the message. eg like - * - * if (ignoreErrors && - * STREQ(error.name, - * "org.freedesktop.DBus.Python.dbus.exceptions.DBusException") && - * STRPREFIX(error.message, "COMMAND_FAILED")) - * ... - * - * But this risks our error detecting code being broken if firewalld changes - * ever alter the message string, so we're avoiding doing that. - */ - if (ignoreErrors) { - VIR_DEBUG("Ignoring error '%s': '%s'", - error.str1, error.message); - } else { - virReportErrorObject(&error); - goto cleanup; - } - } else { - if (virDBusMessageRead(reply, "s", output) < 0) - goto cleanup; - } - - ret = 0; - - cleanup: - virResetError(&error); - virDBusMessageUnref(reply); - return ret; + /* wrapper necessary because virFirewallRule is a private struct */ + return virFirewallDApplyRule(rule->layer, rule->args, rule->argsLen, ignoreErrors, output); } static int diff --git a/src/util/virfirewalld.c b/src/util/virfirewalld.c new file mode 100644 index 0000000000..f27ec9c124 --- /dev/null +++ b/src/util/virfirewalld.c @@ -0,0 +1,151 @@ +/* + * virfirewalld.c: support for firewalld (https://firewalld.org) + * + * Copyright (C) 2019 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include + +#include + +#include "virfirewall.h" +#include "virfirewalld.h" +#define LIBVIRT_VIRFIREWALLDPRIV_H_ALLOW +#include "virfirewalldpriv.h" +#include "virerror.h" +#include "virutil.h" +#include "virlog.h" +#include "virdbus.h" + +#define VIR_FROM_THIS VIR_FROM_FIREWALLD + +VIR_LOG_INIT("util.firewalld"); + +/* used to convert virFirewallLayer enum values to strings + * understood by the firewalld.direct "passthrough" method + */ +VIR_ENUM_DECL(virFirewallLayerFirewallD); +VIR_ENUM_IMPL(virFirewallLayerFirewallD, VIR_FIREWALL_LAYER_LAST, + "eb", + "ipv4", + "ipv6", + ); + + +/** + * virFirewallDIsRegistered: + * + * Returns 0 if service is registered, -1 on fatal error, or -2 if service is not registered + */ +int +virFirewallDIsRegistered(void) +{ + return virDBusIsServiceRegistered(VIR_FIREWALL_FIREWALLD_SERVICE); +} + + +/** + * virFirewallDApplyRule: + * @layer: which layer to apply the rule to + * @args: list of args to send to this layer's passthrough command. + * @argsLen: number of items in @args + * @ignoreErrors: true to suppress logging of errors and return success + * false to log errors and return actual status + * @output: output of the direct passthrough command, if it was successful + */ +int +virFirewallDApplyRule(virFirewallLayer layer, + char **args, size_t argsLen, + bool ignoreErrors, + char **output) +{ + const char *ipv = virFirewallLayerFirewallDTypeToString(layer); + DBusConnection *sysbus = virDBusGetSystemBus(); + DBusMessage *reply = NULL; + virError error; + int ret = -1; + + if (!sysbus) + return -1; + + memset(&error, 0, sizeof(error)); + + if (!ipv) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown firewall layer %d"), + layer); + goto cleanup; + } + + if (virDBusCallMethod(sysbus, + &reply, + &error, + VIR_FIREWALL_FIREWALLD_SERVICE, + "/org/fedoraproject/FirewallD1", + "org.fedoraproject.FirewallD1.direct", + "passthrough", + "sa&s", + ipv, + (int)argsLen, + args) < 0) + goto cleanup; + + if (error.level == VIR_ERR_ERROR) { + /* + * As of firewalld-0.3.9.3-1.fc20.noarch the name and + * message fields in the error look like + * + * name="org.freedesktop.DBus.Python.dbus.exceptions.DBusException" + * message="COMMAND_FAILED: '/sbin/iptables --table filter --delete + * INPUT --in-interface virbr0 --protocol udp --destination-port 53 + * --jump ACCEPT' failed: iptables: Bad rule (does a matching rule + * exist in that chain?)." + * + * We'd like to only ignore DBus errors precisely related to the failure + * of iptables/ebtables commands. A well designed DBus interface would + * return specific named exceptions not the top level generic python dbus + * exception name. With this current scheme our only option is todo a + * sub-string match for 'COMMAND_FAILED' on the message. eg like + * + * if (ignoreErrors && + * STREQ(error.name, + * "org.freedesktop.DBus.Python.dbus.exceptions.DBusException") && + * STRPREFIX(error.message, "COMMAND_FAILED")) + * ... + * + * But this risks our error detecting code being broken if firewalld changes + * ever alter the message string, so we're avoiding doing that. + */ + if (ignoreErrors) { + VIR_DEBUG("Ignoring error '%s': '%s'", + error.str1, error.message); + } else { + virReportErrorObject(&error); + goto cleanup; + } + } else { + if (virDBusMessageRead(reply, "s", output) < 0) + goto cleanup; + } + + ret = 0; + + cleanup: + virResetError(&error); + virDBusMessageUnref(reply); + return ret; +} diff --git a/src/util/virfirewalld.h b/src/util/virfirewalld.h new file mode 100644 index 0000000000..83fe1149cc --- /dev/null +++ b/src/util/virfirewalld.h @@ -0,0 +1,33 @@ +/* + * virfirewalld.h: support for firewalld (https://firewalld.org) + * + * Copyright (C) 2019 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#ifndef LIBVIRT_VIRFIREWALLD_H +# define LIBVIRT_VIRFIREWALLD_H + +# define VIR_FIREWALL_FIREWALLD_SERVICE "org.fedoraproject.FirewallD1" + +int virFirewallDIsRegistered(void); + +int virFirewallDApplyRule(virFirewallLayer layer, + char **args, size_t argsLen, + bool ignoreErrors, + char **output); + +#endif /* LIBVIRT_VIRFIREWALLD_H */ diff --git a/src/util/virfirewalldpriv.h b/src/util/virfirewalldpriv.h new file mode 100644 index 0000000000..6c03b467c9 --- /dev/null +++ b/src/util/virfirewalldpriv.h @@ -0,0 +1,30 @@ +/* + * virfirewalldpriv.h: private APIs for firewalld + * + * Copyright (C) 2019 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#ifndef LIBVIRT_VIRFIREWALLDPRIV_H_ALLOW +# error "virfirewalldpriv.h may only be included by virfirewalld.c or test suites" +#endif /* LIBVIRT_VIRFIREWALLDPRIV_H_ALLOW */ + +#ifndef LIBVIRT_VIRFIREWALLDPRIV_H +# define LIBVIRT_VIRFIREWALLDPRIV_H + +# define VIR_FIREWALL_FIREWALLD_SERVICE "org.fedoraproject.FirewallD1" + +#endif /* LIBVIRT_VIRFIREWALLDPRIV_H */ diff --git a/src/util/virfirewallpriv.h b/src/util/virfirewallpriv.h index 130aaa1b73..bd6089bcc6 100644 --- a/src/util/virfirewallpriv.h +++ b/src/util/virfirewallpriv.h @@ -30,8 +30,6 @@ # include "virfirewall.h" -# define VIR_FIREWALL_FIREWALLD_SERVICE "org.fedoraproject.FirewallD1" - typedef enum { VIR_FIREWALL_BACKEND_AUTOMATIC, VIR_FIREWALL_BACKEND_DIRECT, diff --git a/tests/virfirewalltest.c b/tests/virfirewalltest.c index e6d68745ae..397abfcc60 100644 --- a/tests/virfirewalltest.c +++ b/tests/virfirewalltest.c @@ -30,6 +30,8 @@ # include "virbuffer.h" # include "vircommandpriv.h" # include "virfirewallpriv.h" +# define LIBVIRT_VIRFIREWALLDPRIV_H_ALLOW +# include "virfirewalldpriv.h" # include "virmock.h" # include "virdbuspriv.h" -- 2.20.1