This patch provides basic support for using firewalld's firewall-cmd
rather than then plain eb/ip(6)tables commands.
---
src/Makefile.am | 4
src/conf/nwfilter_conf.h | 1
src/libvirt_private.syms | 4
src/nwfilter/nwfilter_driver.c | 172 ++++++++++++++++++++++++++++--
src/nwfilter/nwfilter_driver.h | 2
src/nwfilter/nwfilter_ebiptables_driver.c | 144 +++++++++++++++++++++----
6 files changed, 292 insertions(+), 35 deletions(-)
Index: libvirt-firewalld/src/Makefile.am
===================================================================
--- libvirt-firewalld.orig/src/Makefile.am
+++ libvirt-firewalld/src/Makefile.am
@@ -1149,9 +1149,9 @@ noinst_LTLIBRARIES += libvirt_driver_nwf
#libvirt_la_BUILT_LIBADD += libvirt_driver_nwfilter.la
endif
libvirt_driver_nwfilter_la_CFLAGS = $(LIBPCAP_CFLAGS) \
- -I$(top_srcdir)/src/conf $(LIBNL_CFLAGS) $(AM_CFLAGS)
+ -I$(top_srcdir)/src/conf $(LIBNL_CFLAGS) $(AM_CFLAGS) $(DBUS_CFLAGS)
libvirt_driver_nwfilter_la_LDFLAGS = $(LD_AMFLAGS)
-libvirt_driver_nwfilter_la_LIBADD = $(LIBPCAP_LIBS) $(LIBNL_LIBS)
+libvirt_driver_nwfilter_la_LIBADD = $(LIBPCAP_LIBS) $(LIBNL_LIBS) $(DBUS_LIBS)
if WITH_DRIVER_MODULES
libvirt_driver_nwfilter_la_LIBADD += ../gnulib/lib/libgnu.la
libvirt_driver_nwfilter_la_LDFLAGS += -module -avoid-version
Index: libvirt-firewalld/src/nwfilter/nwfilter_driver.c
===================================================================
--- libvirt-firewalld.orig/src/nwfilter/nwfilter_driver.c
+++ libvirt-firewalld/src/nwfilter/nwfilter_driver.c
@@ -27,6 +27,9 @@
#include <config.h>
+#include "virdbus.h"
+#include "logging.h"
+
#include "internal.h"
#include "virterror_internal.h"
@@ -45,10 +48,24 @@
#define VIR_FROM_THIS VIR_FROM_NWFILTER
+#define DBUS_RULE_FWD_NAMEOWNERCHANGED \
+ "type='signal'" \
+ ",interface='"DBUS_INTERFACE_DBUS"'" \
+ ",member='NameOwnerChanged'" \
+ ",arg0='org.fedoraproject.FirewallD1'"
+
+#define DBUS_RULE_FWD_RELOADED \
+ "type='signal'" \
+ ",interface='org.fedoraproject.FirewallD1'" \
+ ",member='Reloaded'"
+
+
static virNWFilterDriverStatePtr driverState;
static int nwfilterDriverShutdown(void);
+static int nwfilterDriverReload(void);
+
static void nwfilterDriverLock(virNWFilterDriverStatePtr driver)
{
virMutexLock(&driver->lock);
@@ -58,6 +75,89 @@ static void nwfilterDriverUnlock(virNWFi
virMutexUnlock(&driver->lock);
}
+#if HAVE_FIREWALLD
+
+static DBusHandlerResult
+nwfilterFirewalldDBusFilter(DBusConnection *connection ATTRIBUTE_UNUSED,
+ DBusMessage *message,
+ void *user_data ATTRIBUTE_UNUSED)
+{
+ if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
+ "NameOwnerChanged") ||
+ dbus_message_is_signal(message, "org.fedoraproject.FirewallD1",
+ "Reloaded")) {
+ VIR_DEBUG("Reload in nwfilter_driver because of firewalld.");
+ nwfilterDriverReload();
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void
+nwfilterDriverRemoveDBusMatches(void)
+{
+ DBusConnection *sysbus;
+
+ sysbus = virDBusGetSystemBus();
+ if (sysbus) {
+ dbus_bus_remove_match(sysbus,
+ DBUS_RULE_FWD_NAMEOWNERCHANGED,
+ NULL);
+ dbus_bus_remove_match(sysbus,
+ DBUS_RULE_FWD_RELOADED,
+ NULL);
+ dbus_connection_remove_filter(sysbus, nwfilterFirewalldDBusFilter, NULL);
+ }
+}
+
+/**
+ * virNWFilterDriverInstallDBusMatches
+ *
+ * Startup DBus matches for monitoring the state of firewalld
+ */
+static int
+nwfilterDriverInstallDBusMatches(DBusConnection *sysbus)
+{
+ int ret = 0;
+
+ if (!sysbus) {
+ ret = -1;
+ } else {
+ /* add matches for
+ * NameOwnerChanged on org.freedesktop.DBus for firewalld start/stop
+ * Reloaded on org.fedoraproject.FirewallD1 for firewalld reload
+ */
+ dbus_bus_add_match(sysbus,
+ DBUS_RULE_FWD_NAMEOWNERCHANGED,
+ NULL);
+ dbus_bus_add_match(sysbus,
+ DBUS_RULE_FWD_RELOADED,
+ NULL);
+ if (!dbus_connection_add_filter(sysbus, nwfilterFirewalldDBusFilter,
+ NULL, NULL)) {
+ VIR_WARN(("Adding a filter to the DBus connection failed"));
+ nwfilterDriverRemoveDBusMatches();
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+#else /* HAVE_FIREWALLD */
+
+static void
+nwfilterDriverRemoveDBusMatches(void)
+{
+}
+
+static int
+nwfilterDriverInstallDBusMatches(DBusConnection *sysbus ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+#endif /* HAVE_FIREWALLD */
/**
* virNWFilterStartup:
@@ -65,14 +165,24 @@ static void nwfilterDriverUnlock(virNWFi
* Initialization function for the QEmu daemon
*/
static int
-nwfilterDriverStartup(int privileged) {
+nwfilterDriverStartup(int privileged)
+{
char *base = NULL;
+ DBusConnection *sysbus = virDBusGetSystemBus();
+
+ if (VIR_ALLOC(driverState) < 0)
+ goto alloc_err_exit;
+
+ if (virMutexInit(&driverState->lock) < 0)
+ goto err_free_driverstate;
+
+ driverState->watchingFirewallD = (sysbus != NULL);
if (!privileged)
return 0;
if (virNWFilterIPAddrMapInit() < 0)
- return -1;
+ goto err_free_driverstate;
if (virNWFilterLearnInit() < 0)
goto err_exit_ipaddrmapshutdown;
if (virNWFilterDHCPSnoopInit() < 0)
@@ -81,16 +191,26 @@ nwfilterDriverStartup(int privileged) {
virNWFilterTechDriversInit(privileged);
if (virNWFilterConfLayerInit(virNWFilterDomainFWUpdateCB) < 0)
- goto conf_init_err;
-
- if (VIR_ALLOC(driverState) < 0)
- goto alloc_err_exit;
-
- if (virMutexInit(&driverState->lock) < 0)
- goto alloc_err_exit;
+ goto err_techdrivers_shutdown;
nwfilterDriverLock(driverState);
+ /*
+ * startup the DBus late so we don't get a reload signal while
+ * initializing
+ */
+ if (nwfilterDriverInstallDBusMatches(sysbus) < 0) {
+ VIR_ERROR(_("DBus matches could not be installed. Disabling nwfilter "
+ "driver"));
+ /*
+ * unfortunately this is fatal since virNWFilterTechDriversInit
+ * may have caused the ebiptables driver to use the firewall tool
+ * but now that the watches don't work, we just disable the nwfilter
+ * driver
+ */
+ goto error;
+ }
+
if (privileged) {
if ((base = strdup (SYSCONFDIR "/libvirt")) == NULL)
goto out_of_memory;
@@ -124,9 +244,11 @@ error:
nwfilterDriverShutdown();
alloc_err_exit:
- virNWFilterConfLayerShutdown();
+ return -1;
-conf_init_err:
+ nwfilterDriverUnlock(driverState);
+
+err_techdrivers_shutdown:
virNWFilterTechDriversShutdown();
virNWFilterDHCPSnoopShutdown();
err_exit_learnshutdown:
@@ -134,6 +256,9 @@ err_exit_learnshutdown:
err_exit_ipaddrmapshutdown:
virNWFilterIPAddrMapShutdown();
+err_free_driverstate:
+ VIR_FREE(driverState);
+
return -1;
}
@@ -192,6 +317,29 @@ nwfilterDriverActive(void) {
nwfilterDriverLock(driverState);
ret = driverState->nwfilters.count ? 1 : 0;
+ ret |= driverState->watchingFirewallD;
+ nwfilterDriverUnlock(driverState);
+
+ return ret;
+}
+
+/**
+ * virNWFilterIsWatchingFirewallD:
+ *
+ * Checks if the nwfilter has the DBus watches for FirewallD installed.
+ *
+ * Returns true if it is watching firewalld, false otherwise
+ */
+bool
+virNWFilterDriverIsWatchingFirewallD(void)
+{
+ bool ret;
+
+ if (!driverState)
+ return false;
+
+ nwfilterDriverLock(driverState);
+ ret = driverState->watchingFirewallD;
nwfilterDriverUnlock(driverState);
return ret;
@@ -215,6 +363,8 @@ nwfilterDriverShutdown(void) {
nwfilterDriverLock(driverState);
+ nwfilterDriverRemoveDBusMatches();
+
/* free inactive nwfilters */
virNWFilterObjListFree(&driverState->nwfilters);
Index: libvirt-firewalld/src/nwfilter/nwfilter_ebiptables_driver.c
===================================================================
--- libvirt-firewalld.orig/src/nwfilter/nwfilter_ebiptables_driver.c
+++ libvirt-firewalld/src/nwfilter/nwfilter_ebiptables_driver.c
@@ -36,6 +36,7 @@
#include "virterror_internal.h"
#include "domain_conf.h"
#include "nwfilter_conf.h"
+#include "nwfilter_driver.h"
#include "nwfilter_gentech_driver.h"
#include "nwfilter_ebiptables_driver.h"
#include "virfile.h"
@@ -145,11 +146,11 @@ static const char ebiptables_script_set_
#define NWFILTER_FUNC_SET_IFS ebiptables_script_set_ifs
#define NWFILTER_SET_EBTABLES_SHELLVAR(BUFPTR) \
- virBufferAsprintf(BUFPTR, "EBT=%s\n", ebtables_cmd_path);
+ virBufferAsprintf(BUFPTR, "EBT=\"%s\"\n", ebtables_cmd_path);
#define NWFILTER_SET_IPTABLES_SHELLVAR(BUFPTR) \
- virBufferAsprintf(BUFPTR, "IPT=%s\n", iptables_cmd_path);
+ virBufferAsprintf(BUFPTR, "IPT=\"%s\"\n", iptables_cmd_path);
#define NWFILTER_SET_IP6TABLES_SHELLVAR(BUFPTR) \
- virBufferAsprintf(BUFPTR, "IPT=%s\n", ip6tables_cmd_path);
+ virBufferAsprintf(BUFPTR, "IPT=\"%s\"\n", ip6tables_cmd_path);
#define VIRT_IN_CHAIN "libvirt-in"
#define VIRT_OUT_CHAIN "libvirt-out"
@@ -4121,23 +4122,101 @@ virNWFilterTechDriver ebiptables_driver
.removeBasicRules = ebtablesRemoveBasicRules,
};
-
+/*
+ * ebiptablesDriverInitWithFirewallD
+ *
+ * Try to use firewall-cmd by testing it once; if it works, have ebtables
+ * and ip6tables commands use firewall-cmd.
+ */
static int
-ebiptablesDriverInit(bool privileged)
+ebiptablesDriverInitWithFirewallD(void)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
- char *errmsg = NULL;
+ char *firewall_cmd_path;
+ char *output = NULL;
+ int ret = -1;
- if (!privileged)
- return 0;
+ if (!virNWFilterDriverIsWatchingFirewallD())
+ return -1;
- if (virMutexInit(&execCLIMutex) < 0)
- return -EINVAL;
+ firewall_cmd_path = virFindFileInPath("firewall-cmd");
- gawk_cmd_path = virFindFileInPath("gawk");
- grep_cmd_path = virFindFileInPath("grep");
+ if (firewall_cmd_path) {
+ virBufferAsprintf(&buf, "FWC=%s\n", firewall_cmd_path);
+ virBufferAsprintf(&buf,
+ CMD_DEF("$FWC --state") CMD_SEPARATOR
+ CMD_EXEC
+ "%s",
+ CMD_STOPONERR(1));
+
+ if (ebiptablesExecCLI(&buf, NULL, &output) == 0 &&
+ strlen(output) == 0) {
+ VIR_DEBUG("Using firewall-cmd in nwfilter_ebiptables_driver.");
+ ebtables_cmd_path = NULL;
+ iptables_cmd_path = NULL;
+ ip6tables_cmd_path = NULL;
+
+ ignore_value(virAsprintf(&ebtables_cmd_path,
+ "%s --direct --passthrough eb",
+ firewall_cmd_path));
+ ignore_value(virAsprintf(&iptables_cmd_path,
+ "%s --direct --passthrough ipv4",
+ firewall_cmd_path));
+ ignore_value(virAsprintf(&ip6tables_cmd_path,
+ "%s --direct --passthrough ipv6",
+ firewall_cmd_path));
+
+ if (!ebtables_cmd_path || !iptables_cmd_path ||
+ !ip6tables_cmd_path) {
+ virReportOOMError();
+ VIR_FREE(ebtables_cmd_path);
+ VIR_FREE(iptables_cmd_path);
+ VIR_FREE(ip6tables_cmd_path);
+ ret = -1;
+ goto err_exit;
+ }
+ ret = 0;
+ }
+ }
+
+err_exit:
+ VIR_FREE(firewall_cmd_path);
+ VIR_FREE(output);
+
+ return ret;
+}
+static int
+ebiptablesDriverInitCLITools(void)
+{
ebtables_cmd_path = virFindFileInPath("ebtables");
+ if (!ebtables_cmd_path)
+ VIR_WARN("Could not find 'ebtables' executable");
+
+ iptables_cmd_path = virFindFileInPath("iptables");
+ if (!iptables_cmd_path)
+ VIR_WARN("Could not find 'iptables' executable");
+
+ ip6tables_cmd_path = virFindFileInPath("ip6tables");
+ if (!ip6tables_cmd_path)
+ VIR_WARN("Could not find 'ip6tables' executable");
+
+ return 0;
+}
+
+/*
+ * ebiptablesDriverTestCLITools
+ *
+ * Test the CLI tools. If one is found not to be working, free the buffer
+ * holding its path as a sign that the tool cannot be used.
+ */
+static int
+ebiptablesDriverTestCLITools(void)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ char *errmsg = NULL;
+ int ret = 0;
+
if (ebtables_cmd_path) {
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
/* basic probing */
@@ -4151,12 +4230,10 @@ ebiptablesDriverInit(bool privileged)
VIR_FREE(ebtables_cmd_path);
VIR_ERROR(_("Testing of ebtables command failed: %s"),
errmsg);
+ ret = -1;
}
- } else {
- VIR_WARN("Could not find 'ebtables' executable");
}
- iptables_cmd_path = virFindFileInPath("iptables");
if (iptables_cmd_path) {
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
@@ -4170,12 +4247,10 @@ ebiptablesDriverInit(bool privileged)
VIR_FREE(iptables_cmd_path);
VIR_ERROR(_("Testing of iptables command failed: %s"),
errmsg);
+ ret = -1;
}
- } else {
- VIR_WARN("Could not find 'iptables' executable");
}
- ip6tables_cmd_path = virFindFileInPath("ip6tables");
if (ip6tables_cmd_path) {
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
@@ -4189,11 +4264,38 @@ ebiptablesDriverInit(bool privileged)
VIR_FREE(ip6tables_cmd_path);
VIR_ERROR(_("Testing of ip6tables command failed: %s"),
errmsg);
+ ret = -1;
}
- } else {
- VIR_WARN("Could not find 'ip6tables' executable");
}
+ VIR_FREE(errmsg);
+
+ return ret;
+}
+
+static int
+ebiptablesDriverInit(bool privileged)
+{
+ if (!privileged)
+ return 0;
+
+ if (virMutexInit(&execCLIMutex) < 0)
+ return -EINVAL;
+
+ gawk_cmd_path = virFindFileInPath("gawk");
+ grep_cmd_path = virFindFileInPath("grep");
+
+ /*
+ * check whether we can run with firewalld's tools --
+ * if not, we just fall back to eb/iptables command
+ * line tools.
+ */
+ if (ebiptablesDriverInitWithFirewallD() < 0)
+ ebiptablesDriverInitCLITools();
+
+ /* make sure tools are available and work */
+ ebiptablesDriverTestCLITools();
+
/* ip(6)tables support needs gawk & grep, ebtables doesn't */
if ((iptables_cmd_path != NULL || ip6tables_cmd_path != NULL) &&
(!grep_cmd_path || !gawk_cmd_path)) {
@@ -4203,8 +4305,6 @@ ebiptablesDriverInit(bool privileged)
VIR_FREE(ip6tables_cmd_path);
}
- VIR_FREE(errmsg);
-
if (!ebtables_cmd_path && !iptables_cmd_path && !ip6tables_cmd_path)
{
VIR_ERROR(_("firewall tools were not found or cannot be used"));
ebiptablesDriverShutdown();
Index: libvirt-firewalld/src/conf/nwfilter_conf.h
===================================================================
--- libvirt-firewalld.orig/src/conf/nwfilter_conf.h
+++ libvirt-firewalld/src/conf/nwfilter_conf.h
@@ -563,6 +563,7 @@ struct _virNWFilterDriverState {
virNWFilterObjList nwfilters;
char *configDir;
+ bool watchingFirewallD;
};
Index: libvirt-firewalld/src/libvirt_private.syms
===================================================================
--- libvirt-firewalld.orig/src/libvirt_private.syms
+++ libvirt-firewalld/src/libvirt_private.syms
@@ -891,6 +891,10 @@ virNWFilterIPAddrMapInit;
virNWFilterIPAddrMapShutdown;
+# nwfilter_driver.h
+virNWFilterDriverIsWatchingFirewallD;
+
+
# nwfilter_params.h
virNWFilterHashTableCreate;
virNWFilterHashTableFree;
Index: libvirt-firewalld/src/nwfilter/nwfilter_driver.h
===================================================================
--- libvirt-firewalld.orig/src/nwfilter/nwfilter_driver.h
+++ libvirt-firewalld/src/nwfilter/nwfilter_driver.h
@@ -33,4 +33,6 @@
int nwfilterRegister(void);
+bool virNWFilterDriverIsWatchingFirewallD(void);
+
#endif /* __VIR_NWFILTER_DRIVER_H__ */