[libvirt] [PATCH] Add support for firewalld

Thomas Woerner twoerner at redhat.com
Mon Apr 23 21:11:51 UTC 2012


Add support for firewalld

* bridge_driver, nwfilter_driver: new dbus filters to get FirewallD1.Reloaded
  signal and DBus.NameOwnerChanged on org.fedoraproject.FirewallD1
* iptables, ebtables, nwfilter_ebiptables_driver: use firewall-cmd direct
  passthrough interface
---
 configure.ac                              |    9 ++++++
 src/Makefile.am                           |    8 ++---
 src/network/bridge_driver.c               |   50 +++++++++++++++++++++++++++++
 src/nwfilter/nwfilter_driver.c            |   49 ++++++++++++++++++++++++++++
 src/nwfilter/nwfilter_ebiptables_driver.c |   27 ++++++++++++++++
 src/util/ebtables.c                       |   32 ++++++++++++++++++
 src/util/iptables.c                       |   25 ++++++++++++---
 7 files changed, 192 insertions(+), 8 deletions(-)

diff --git a/configure.ac b/configure.ac
index 89fe818..41d9371 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1191,6 +1191,15 @@ AM_CONDITIONAL([HAVE_POLKIT1], [test "x$with_polkit1" = "xyes"])
 AC_SUBST([POLKIT_CFLAGS])
 AC_SUBST([POLKIT_LIBS])
 
+dnl firewalld
+AC_ARG_WITH([firewalld],
+  AC_HELP_STRING([--with-firewalld], [enable firewalld support]))
+if test "x$with_firewalld" = "xyes" ; then
+   AC_DEFINE_UNQUOTED([HAVE_FIREWALLD], [1], [whether firewalld support is enabled])
+fi
+AM_CONDITIONAL([HAVE_FIREWALLD], [test "x$with_firewalld" = "xyes"])
+
+
 dnl Avahi library
 AC_ARG_WITH([avahi],
   AC_HELP_STRING([--with-avahi], [use avahi to advertise remote daemon @<:@default=check@:>@]),
diff --git a/src/Makefile.am b/src/Makefile.am
index e48dfa5..e60a8af 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -941,9 +941,9 @@ noinst_LTLIBRARIES += libvirt_driver_network.la
 #libvirt_la_BUILT_LIBADD += libvirt_driver_network.la
 endif
 libvirt_driver_network_la_CFLAGS = \
-		-I$(top_srcdir)/src/conf $(AM_CFLAGS)
+		-I$(top_srcdir)/src/conf $(AM_CFLAGS) $(DBUS_CFLAGS)
 if WITH_DRIVER_MODULES
-libvirt_driver_network_la_LIBADD = ../gnulib/lib/libgnu.la
+libvirt_driver_network_la_LIBADD = ../gnulib/lib/libgnu.la  $(DBUS_LIBS)
 libvirt_driver_network_la_LDFLAGS = -module -avoid-version $(AM_LDFLAGS)
 endif
 libvirt_driver_network_la_SOURCES = $(NETWORK_DRIVER_SOURCES)
@@ -1086,9 +1086,9 @@ libvirt_la_BUILT_LIBADD += libvirt_driver_nwfilter.la
 noinst_LTLIBRARIES += libvirt_driver_nwfilter.la
 endif
 libvirt_driver_nwfilter_la_CFLAGS = $(LIBPCAP_CFLAGS) \
-		-I$(top_srcdir)/src/conf $(AM_CFLAGS)
+		-I$(top_srcdir)/src/conf $(AM_CFLAGS) $(DBUS_CFLAGS)
 libvirt_driver_nwfilter_la_LDFLAGS = $(LD_AMFLAGS)
-libvirt_driver_nwfilter_la_LIBADD = $(LIBPCAP_LIBS)
+libvirt_driver_nwfilter_la_LIBADD = $(LIBPCAP_LIBS) $(DBUS_LIBS)
 if WITH_DRIVER_MODULES
 libvirt_driver_nwfilter_la_LIBADD += ../gnulib/lib/libgnu.la
 libvirt_driver_nwfilter_la_LDFLAGS += -module -avoid-version
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index d82212f..094bbae 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -63,6 +63,11 @@
 #include "virnetdevbridge.h"
 #include "virnetdevtap.h"
 
+#if HAVE_FIREWALLD
+#include "virdbus.h"
+#include "logging.h"
+#endif
+
 #define NETWORK_PID_DIR LOCALSTATEDIR "/run/libvirt/network"
 #define NETWORK_STATE_DIR LOCALSTATEDIR "/lib/libvirt/network"
 
@@ -253,6 +258,24 @@ networkAutostartConfigs(struct network_driver *driver) {
     }
 }
 
+#if HAVE_FIREWALLD
+static DBusHandlerResult
+firewalld_dbus_filter_bridge(DBusConnection *connection ATTRIBUTE_UNUSED, DBusMessage *message, void *user_data) {
+    struct network_driver *_driverState = (struct network_driver *) user_data;
+
+    if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
+                               "NameOwnerChanged") ||
+        dbus_message_is_signal(message, "org.fedoraproject.FirewallD1",
+                               "Reloaded"))
+    {
+        VIR_DEBUG("Reload in bridge_driver because of firewalld.");
+        networkReloadIptablesRules(_driverState);
+    }
+
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+#endif
+
 /**
  * networkStartup:
  *
@@ -262,6 +285,9 @@ static int
 networkStartup(int privileged) {
     uid_t uid = geteuid();
     char *base = NULL;
+#ifdef HAVE_FIREWALLD
+    DBusConnection *sysbus = NULL;
+#endif
 
     if (VIR_ALLOC(driverState) < 0)
         goto error;
@@ -326,6 +352,30 @@ networkStartup(int privileged) {
 
     networkDriverUnlock(driverState);
 
+#ifdef HAVE_FIREWALLD
+    if (!(sysbus = virDBusGetSystemBus())) {
+        virErrorPtr err = virGetLastError();
+        VIR_WARN("DBus not available, disabling firewalld support in bridge_driver: %s", err->message);
+    } 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,
+                           "type='signal'"
+                           ",interface='"DBUS_INTERFACE_DBUS"'"
+                           ",member='NameOwnerChanged'"
+                           ",arg0='org.fedoraproject.FirewallD1'",
+                           NULL);
+        dbus_bus_add_match(sysbus,
+                           "type='signal'"
+                           ",interface='org.fedoraproject.FirewallD1'"
+                           ",member='Reloaded'",
+                           NULL);
+        dbus_connection_add_filter(sysbus, firewalld_dbus_filter_bridge, (void *)driverState, NULL);
+    }
+#endif
+
     return 0;
 
 out_of_memory:
diff --git a/src/nwfilter/nwfilter_driver.c b/src/nwfilter/nwfilter_driver.c
index ffb4b5d..da9f4a0 100644
--- a/src/nwfilter/nwfilter_driver.c
+++ b/src/nwfilter/nwfilter_driver.c
@@ -27,6 +27,11 @@
 
 #include <config.h>
 
+#if HAVE_FIREWALLD
+#include "virdbus.h"
+#include "logging.h"
+#endif
+
 #include "internal.h"
 
 #include "virterror_internal.h"
@@ -47,6 +52,8 @@ static virNWFilterDriverStatePtr driverState;
 
 static int nwfilterDriverShutdown(void);
 
+static int nwfilterDriverReload(void);
+
 static void nwfilterDriverLock(virNWFilterDriverStatePtr driver)
 {
     virMutexLock(&driver->lock);
@@ -57,6 +64,22 @@ static void nwfilterDriverUnlock(virNWFilterDriverStatePtr driver)
 }
 
 
+#if HAVE_FIREWALLD
+static DBusHandlerResult
+firewalld_dbus_filter_nwfilter(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;
+}
+#endif
+
 /**
  * virNWFilterStartup:
  *
@@ -66,6 +89,32 @@ static int
 nwfilterDriverStartup(int privileged) {
     char *base = NULL;
 
+#ifdef HAVE_FIREWALLD
+    DBusConnection *sysbus = NULL;
+
+    if (!(sysbus = virDBusGetSystemBus())) {
+        virErrorPtr err = virGetLastError();
+        VIR_WARN("DBus not available, disabling firewalld support in nwfilter_driver: %s", err->message);
+    } 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,
+                           "type='signal'"
+                           ",interface='"DBUS_INTERFACE_DBUS"'"
+                           ",member='NameOwnerChanged'"
+                           ",arg0='org.fedoraproject.FirewallD1'",
+                           NULL);
+        dbus_bus_add_match(sysbus,
+                           "type='signal'"
+                           ",interface='org.fedoraproject.FirewallD1'"
+                           ",member='Reloaded'",
+                           NULL);
+        dbus_connection_add_filter(sysbus, firewalld_dbus_filter_nwfilter, NULL, NULL);
+    }
+#endif
+
     if (virNWFilterLearnInit() < 0)
         return -1;
 
diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c
index 8e4436f..0cd047a 100644
--- a/src/nwfilter/nwfilter_ebiptables_driver.c
+++ b/src/nwfilter/nwfilter_ebiptables_driver.c
@@ -4051,6 +4051,7 @@ ebiptablesDriverInit(bool privileged)
 {
     virBuffer buf = VIR_BUFFER_INITIALIZER;
     char *errmsg = NULL;
+    char *firewall_cmd_path = NULL;
 
     if (!privileged)
         return 0;
@@ -4061,6 +4062,30 @@ ebiptablesDriverInit(bool privileged)
     gawk_cmd_path = virFindFileInPath("gawk");
     grep_cmd_path = virFindFileInPath("grep");
 
+    firewall_cmd_path = virFindFileInPath("firewall-cmd");
+    if (firewall_cmd_path) {
+        virBufferAsprintf(&buf, "IPT=%s\n", firewall_cmd_path);
+        /* basic probing */
+        virBufferAsprintf(&buf,
+                          CMD_DEF("$IPT --state") CMD_SEPARATOR
+                          CMD_EXEC
+                          "%s",
+                          CMD_STOPONERR(1));
+
+        if (ebiptablesExecCLI(&buf, NULL, NULL) >= 0) {
+            VIR_DEBUG("Using firewall-cmd in nwfilter_ebiptables_driver.");
+            ebtables_cmd_path = NULL;
+            iptables_cmd_path = NULL;
+            ip6tables_cmd_path = NULL;
+            virAsprintf(&ebtables_cmd_path, "%s --direct --passthrough eb", firewall_cmd_path);
+            virAsprintf(&iptables_cmd_path, "%s --direct --passthrough ipv4", firewall_cmd_path);
+            virAsprintf(&ip6tables_cmd_path, "%s --direct --passthrough ipv6", firewall_cmd_path);
+        }
+        VIR_FREE(firewall_cmd_path);
+    }
+    if (ebtables_cmd_path == NULL || iptables_cmd_path == NULL ||
+        ip6tables_cmd_path == NULL) {
+
     ebtables_cmd_path = virFindFileInPath("ebtables");
     if (ebtables_cmd_path) {
         NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
@@ -4099,6 +4124,8 @@ ebiptablesDriverInit(bool privileged)
         VIR_WARN("Could not find 'iptables' executable");
     }
 
+    }
+
     ip6tables_cmd_path = virFindFileInPath("ip6tables");
     if (ip6tables_cmd_path) {
         NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
diff --git a/src/util/ebtables.c b/src/util/ebtables.c
index dcb3eb9..b7773ea 100644
--- a/src/util/ebtables.c
+++ b/src/util/ebtables.c
@@ -176,11 +176,34 @@ ebtablesAddRemoveRule(ebtRules *rules, int action, const char *arg, ...)
     const char *s;
     int n, command_idx;
 
+#if HAVE_FIREWALLD
+    int ret;
+    char *firewall_cmd_path = NULL;
+    virCommandPtr cmd = NULL;
+
+    firewall_cmd_path = virFindFileInPath("firewall-cmd");
+    if (firewall_cmd_path) {
+        cmd = virCommandNew(firewall_cmd_path);
+        virCommandAddArgList(cmd, "--state", NULL);
+        ret = virCommandRun(cmd, NULL);
+        if (ret != 0) {
+            VIR_FREE(firewall_cmd_path);
+            firewall_cmd_path = NULL;
+        }
+        virCommandFree(cmd);
+    }
+#endif
+
     n = 1 + /* /sbin/ebtables  */
         2 + /*   --table foo   */
         2 + /*   --insert bar  */
         1;  /*   arg           */
 
+#if HAVE_FIREWALLD
+    if (firewall_cmd_path)
+        n += 3; /* --direct --passthrough eb */
+#endif
+
     va_start(args, arg);
     while (va_arg(args, const char *))
         n++;
@@ -192,6 +215,15 @@ ebtablesAddRemoveRule(ebtRules *rules, int action, const char *arg, ...)
 
     n = 0;
 
+#if HAVE_FIREWALLD
+    if (firewall_cmd_path) {
+        if (!(argv[n++] = strdup(firewall_cmd_path)))
+            goto error;
+        argv[n++] = strdup("--direct");
+        argv[n++] = strdup("--passthrough");
+        argv[n++] = strdup("eb");
+    } else
+#endif
     if (!(argv[n++] = strdup(EBTABLES_PATH)))
         goto error;
 
diff --git a/src/util/iptables.c b/src/util/iptables.c
index 3023900..0cb3293 100644
--- a/src/util/iptables.c
+++ b/src/util/iptables.c
@@ -104,11 +104,28 @@ iptablesAddRemoveRule(iptRules *rules, int family, int action,
 {
     va_list args;
     int ret;
-    virCommandPtr cmd;
+    virCommandPtr cmd = NULL;
     const char *s;
-
-    cmd = virCommandNew((family == AF_INET6)
-                        ? IP6TABLES_PATH : IPTABLES_PATH);
+    char *firewall_cmd_path = NULL;
+
+#if HAVE_FIREWALLD
+    firewall_cmd_path = virFindFileInPath("firewall-cmd");
+    if (firewall_cmd_path) {
+        cmd = virCommandNew(firewall_cmd_path);
+        virCommandAddArgList(cmd, "--state", NULL);
+        ret = virCommandRun(cmd, NULL);
+        if (ret == 0) {
+            cmd = virCommandNew(firewall_cmd_path);
+            virCommandAddArgList(cmd, "--direct", "--passthrough",
+                                 (family == AF_INET6) ? "ipv6" : "ipv4", NULL);
+        } else
+            cmd = NULL;
+        VIR_FREE(firewall_cmd_path);
+    }
+    if (!cmd)
+#endif
+        cmd = virCommandNew((family == AF_INET6)
+                            ? IP6TABLES_PATH : IPTABLES_PATH);
 
     virCommandAddArgList(cmd, "--table", rules->table,
                          action == ADD ? "--insert" : "--delete",
-- 
1.7.10




More information about the libvir-list mailing list