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 <laine(a)laine.org>
---
Change from V1: define VIR_FIREWALL_FIREWALLD_SERVICE in virfirewalldpriv.h,
since it should only be used by virfirewalld.c and unit test programs.
(no, I haven't done anything about the awkward error checking that was
already existing in the code I moved - not only is that a separate
issue, but there no existing way to fix it anyway - that would take
changes to firewalld)
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 fbbe2d5624..3c19ff5e2e 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -131,6 +131,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 e53ae0dbeb..d52e2412fa 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1921,6 +1921,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 4295babac3..aa5c6cbe03 100644
--- a/src/util/Makefile.inc.am
+++ b/src/util/Makefile.inc.am
@@ -64,6 +64,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 61b47d2be0..740f3b84b3 100644
--- a/src/util/virerror.c
+++ b/src/util/virerror.c
@@ -138,7 +138,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 0ed54d6228..7582ce5b5d 100644
--- a/src/util/virfirewall.c
+++ b/src/util/virfirewall.c
@@ -24,12 +24,12 @@
#define LIBVIRT_VIRFIREWALLPRIV_H_ALLOW
#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"
@@ -46,11 +46,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;
@@ -152,7 +147,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) {
@@ -712,81 +707,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
+ * <
http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <stdarg.h>
+
+#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
+ * <
http://www.gnu.org/licenses/>.
+ */
+
+#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
+ * <
http://www.gnu.org/licenses/>.
+ */
+
+#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 efa94a7da4..7c31d0680d 100644
--- a/src/util/virfirewallpriv.h
+++ b/src/util/virfirewallpriv.h
@@ -27,8 +27,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 5fde25d8f6..7c586877d3 100644
--- a/tests/virfirewalltest.c
+++ b/tests/virfirewalltest.c
@@ -27,6 +27,8 @@
# include "vircommandpriv.h"
# define LIBVIRT_VIRFIREWALLPRIV_H_ALLOW
# include "virfirewallpriv.h"
+# define LIBVIRT_VIRFIREWALLDPRIV_H_ALLOW
+# include "virfirewalldpriv.h"
# include "virmock.h"
# define LIBVIRT_VIRDBUSPRIV_H_ALLOW
# include "virdbuspriv.h"
--
2.20.1