[libvirt] [PATCH] Add support for firewalld

Daniel P. Berrange berrange at redhat.com
Tue Apr 24 14:25:54 UTC 2012


On Mon, Apr 23, 2012 at 11:11:51PM +0200, Thomas Woerner wrote:
> 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@:>@]),

To go along with this, you should also modify the libvirt.spec.in file in
GIT, to add logic to turn on firewalld on Fedora >= 17 + RHEL >= 7 only,
forcably disabling elsewhere.

> 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

While technically correct, this is overkill - just let them be
included unconditionally.

> +
>  #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;

This cast is not required, since void * auto-casts to anything in C.

> +
> +    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);

No need to cast to void * here either.

> +    }
> +#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

As before can make this unconditional

> +
>  #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);

Need to check for & report OOM in virAsprintf.  I'm surprised we haven't
actually annotated it with ATTRIBUTE_RETURN_CHECK to catch this

> +        }
> +        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");

Need to check OOM on all 4 of thoses strdup()'s not just the first

> +    } else
> +#endif
>      if (!(argv[n++] = strdup(EBTABLES_PATH)))
>          goto error;

Not your fault, but this is a nice reminder to us that we need to convert
this code to virCommand.

>  
> 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",
> -- 



Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|




More information about the libvir-list mailing list