mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-23 13:05:27 +00:00
nwfilter: provide basic support for firewalld
This patch provides basic support for using firewalld's firewall-cmd rather than then plain eb/ip(6)tables commands.
This commit is contained in:
parent
bf156385a0
commit
4efde75fab
@ -1156,9 +1156,9 @@ noinst_LTLIBRARIES += libvirt_driver_nwfilter.la
|
||||
#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
|
||||
|
@ -560,6 +560,7 @@ struct _virNWFilterDriverState {
|
||||
virNWFilterObjList nwfilters;
|
||||
|
||||
char *configDir;
|
||||
bool watchingFirewallD;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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(virNWFilterDriverStatePtr driver)
|
||||
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(virNWFilterDriverStatePtr driver)
|
||||
* 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);
|
||||
|
||||
|
@ -33,4 +33,6 @@
|
||||
|
||||
int nwfilterRegister(void);
|
||||
|
||||
bool virNWFilterDriverIsWatchingFirewallD(void);
|
||||
|
||||
#endif /* __VIR_NWFILTER_DRIVER_H__ */
|
||||
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* nwfilter_ebiptables_driver.c: driver for ebtables/iptables on tap devices
|
||||
*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
* Copyright (C) 2010 IBM Corp.
|
||||
* Copyright (C) 2010 Stefan Berger
|
||||
* Copyright (C) 2011-2012 Red Hat, Inc.
|
||||
* Copyright (C) 2010-2012 IBM Corp.
|
||||
* Copyright (C) 2010-2012 Stefan Berger
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -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"
|
||||
@ -151,11 +152,11 @@ static const char ebiptables_script_set_ifs[] =
|
||||
#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"
|
||||
@ -4127,23 +4128,98 @@ 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
|
||||
ebiptablesDriverInitWithFirewallD(void)
|
||||
{
|
||||
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||
char *firewall_cmd_path;
|
||||
char *output = NULL;
|
||||
int ret = -1;
|
||||
|
||||
if (!virNWFilterDriverIsWatchingFirewallD())
|
||||
return -1;
|
||||
|
||||
firewall_cmd_path = virFindFileInPath("firewall-cmd");
|
||||
|
||||
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.");
|
||||
|
||||
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
|
||||
ebiptablesDriverInit(bool privileged)
|
||||
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 (!privileged)
|
||||
return 0;
|
||||
|
||||
if (virMutexInit(&execCLIMutex) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
gawk_cmd_path = virFindFileInPath("gawk");
|
||||
grep_cmd_path = virFindFileInPath("grep");
|
||||
|
||||
ebtables_cmd_path = virFindFileInPath("ebtables");
|
||||
if (ebtables_cmd_path) {
|
||||
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
|
||||
/* basic probing */
|
||||
@ -4157,12 +4233,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);
|
||||
|
||||
@ -4176,12 +4250,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);
|
||||
|
||||
@ -4195,11 +4267,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)) {
|
||||
@ -4209,8 +4308,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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user