2009-11-03 22:11:01 +00:00
|
|
|
/*
|
2012-12-12 16:48:24 +00:00
|
|
|
* virebtables.c: Helper APIs for managing ebtables
|
|
|
|
*
|
2014-02-20 00:32:19 +00:00
|
|
|
* Copyright (C) 2007-2014 Red Hat, Inc.
|
2010-04-29 03:31:16 +00:00
|
|
|
* Copyright (C) 2009 IBM Corp.
|
2009-11-03 22:11:01 +00:00
|
|
|
*
|
|
|
|
* 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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2009-11-03 22:11:01 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include "internal.h"
|
2012-12-12 16:48:24 +00:00
|
|
|
#include "virebtables.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2014-03-07 17:46:19 +00:00
|
|
|
#include "virfirewall.h"
|
network: use firewalld instead of iptables, when available
* configure.ac, spec file: firewalld defaults to enabled if dbus is
available, otherwise is disabled. If --with_firewalld is explicitly
requested and dbus is not available, configure will fail.
* bridge_driver: add dbus filters to get the FirewallD1.Reloaded
signal and DBus.NameOwnerChanged on org.fedoraproject.FirewallD1.
When these are encountered, reload all the iptables reuls of all
libvirt's virtual networks (similar to what happens when libvirtd is
restarted).
* iptables, ebtables: use firewall-cmd's direct passthrough interface
when available, otherwise use iptables and ebtables commands. This
decision is made once the first time libvirt calls
iptables/ebtables, and that decision is maintained for the life of
libvirtd.
* Note that the nwfilter part of this patch was separated out into
another patch by Stefan in V2, so that needs to be revised and
re-reviewed as well.
================
All the configure.ac and specfile changes are unchanged from Thomas'
V3.
V3 re-ran "firewall-cmd --state" every time a new rule was added,
which was extremely inefficient. V4 uses VIR_ONCE_GLOBAL_INIT to set
up a one-time initialization function.
The VIR_ONCE_GLOBAL_INIT(x) macro references a static function called
vir(Ip|Eb)OnceInit(), which will then be called the first time that
the static function vir(Ip|Eb)TablesInitialize() is called (that
function is defined for you by the macro). This is
thread-safe, so there is no chance of any race.
IMPORTANT NOTE: I've left the VIR_DEBUG messages in these two init
functions (one for iptables, on for ebtables) as VIR_WARN so that I
don't have to turn on all the other debug message just to see
these. Even if this patch doesn't need any other modification, those
messages need to be changed to VIR_DEBUG before pushing.
This one-time initialization works well. However, I've encountered
problems with testing:
1) Whenever I have enabled the firewalld service, *all* attempts to
call firewall-cmd from within libvirtd end with firewall-cmd hanging
internally somewhere. This is *not* the case if firewall-cmd returns
non-0 in response to "firewall-cmd --state" (i.e. *that* command runs
and returns to libvirt successfully.)
2) If I start libvirtd while firewalld is stopped, then start
firewalld later, this triggers libvirtd to reload its iptables rules,
however it also spits out a *ton* of complaints about deletion failing
(I suppose because firewalld has nuked all of libvirt's rules). I
guess we need to suppress those messages (which is a more annoying
problem to fix than you might think, but that's another story).
3) I noticed a few times during this long line of errors that
firewalld made a complaint about "Resource Temporarily
unavailable. Having libvirtd access iptables commands directly at the
same time as firewalld is doing so is apparently problematic.
4) In general, I'm concerned about the "set it once and never change
it" method - if firewalld is disabled at libvirtd startup, causing
libvirtd to always use iptables/ebtables directly, this won't cause
*terrible* problems, but if libvirtd decides to use firewall-cmd and
firewalld is later disabled, libvirtd will not be able to recover.
2012-08-14 18:59:52 +00:00
|
|
|
|
2013-05-24 07:19:51 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("util.ebtables");
|
|
|
|
|
2009-11-03 22:11:01 +00:00
|
|
|
struct _ebtablesContext
|
|
|
|
{
|
2014-03-07 17:03:51 +00:00
|
|
|
char *chain;
|
2009-11-03 22:11:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum {
|
|
|
|
ADD = 0,
|
|
|
|
REMOVE,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ebtablesContextNew:
|
|
|
|
*
|
|
|
|
* Create a new ebtable context
|
|
|
|
*
|
|
|
|
* Returns a pointer to the new structure or NULL in case of error
|
|
|
|
*/
|
|
|
|
ebtablesContext *
|
|
|
|
ebtablesContextNew(const char *driver)
|
|
|
|
{
|
2011-04-03 09:21:16 +00:00
|
|
|
ebtablesContext *ctx = NULL;
|
2009-11-03 22:11:01 +00:00
|
|
|
|
2020-10-05 17:12:37 +00:00
|
|
|
ctx = g_new0(ebtablesContext, 1);
|
2009-11-03 22:11:01 +00:00
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
ctx->chain = g_strdup_printf("libvirt_%s_FORWARD", driver);
|
2011-04-03 09:21:16 +00:00
|
|
|
|
|
|
|
return ctx;
|
2009-11-03 22:11:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ebtablesContextFree:
|
|
|
|
* @ctx: pointer to the EB table context
|
|
|
|
*
|
|
|
|
* Free the resources associated with an EB table context
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ebtablesContextFree(ebtablesContext *ctx)
|
|
|
|
{
|
2010-11-30 16:00:30 +00:00
|
|
|
if (!ctx)
|
|
|
|
return;
|
2021-02-03 19:32:34 +00:00
|
|
|
g_free(ctx->chain);
|
|
|
|
g_free(ctx);
|
2009-11-03 22:11:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-07 16:53:21 +00:00
|
|
|
int
|
|
|
|
ebtablesAddForwardPolicyReject(ebtablesContext *ctx)
|
|
|
|
{
|
2020-07-04 20:35:10 +00:00
|
|
|
g_autoptr(virFirewall) fw = virFirewallNew();
|
2014-03-07 17:46:19 +00:00
|
|
|
|
|
|
|
virFirewallStartTransaction(fw, VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
|
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"--new-chain", ctx->chain,
|
|
|
|
NULL);
|
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"--insert", "FORWARD",
|
|
|
|
"--jump", ctx->chain, NULL);
|
|
|
|
|
|
|
|
virFirewallStartTransaction(fw, 0);
|
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-P", ctx->chain, "DROP",
|
|
|
|
NULL);
|
|
|
|
|
2020-07-04 20:38:37 +00:00
|
|
|
return virFirewallApply(fw);
|
2014-03-07 16:53:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-11-03 22:11:01 +00:00
|
|
|
/*
|
|
|
|
* Allow all traffic destined to the bridge, with a valid network address
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
ebtablesForwardAllowIn(ebtablesContext *ctx,
|
|
|
|
const char *iface,
|
|
|
|
const char *macaddr,
|
|
|
|
int action)
|
|
|
|
{
|
2020-07-04 20:35:10 +00:00
|
|
|
g_autoptr(virFirewall) fw = virFirewallNew();
|
2014-03-07 17:46:19 +00:00
|
|
|
|
|
|
|
virFirewallStartTransaction(fw, 0);
|
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
action == ADD ? "--insert" : "--delete",
|
|
|
|
ctx->chain,
|
|
|
|
"--in-interface", iface,
|
|
|
|
"--source", macaddr,
|
|
|
|
"--jump", "ACCEPT",
|
|
|
|
NULL);
|
|
|
|
|
2020-07-04 20:38:37 +00:00
|
|
|
return virFirewallApply(fw);
|
2009-11-03 22:11:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ebtablesAddForwardAllowIn:
|
|
|
|
* @ctx: pointer to the EB table context
|
|
|
|
* @iface: the output interface name
|
|
|
|
* @physdev: the physical input device or NULL
|
|
|
|
*
|
|
|
|
* Add rules to the EB table context to allow the traffic on
|
|
|
|
* @physdev device to be forwarded to interface @iface. This allows
|
|
|
|
* the inbound traffic on a bridge.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an error code otherwise
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
ebtablesAddForwardAllowIn(ebtablesContext *ctx,
|
|
|
|
const char *iface,
|
maint: avoid 'const fooPtr' in several util files
'const fooPtr' is the same as 'foo * const' (the pointer won't
change, but it's contents can). But in general, if an interface
is trying to be const-correct, it should be using 'const foo *'
(the pointer is to data that can't be changed).
Fix up offenders in src/util outside of the virnet namespace.
Also, make a few virSocketAddr functions const-correct, for easier
conversions in future patches.
* src/util/virbuffer.h (virBufferError, virBufferUse)
(virBufferGetIndent): Use intended type.
* src/util/virmacaddr.h (virMacAddrCmp, virMacAddrCmpRaw)
(virMacAddrSet, virMcAddrFormat, virMacAddrIsUnicast)
(virMacAddrIsMulticast): Likewise.
* src/util/virebtables.h (ebtablesAddForwardAllowIn)
(ebtablesRemoveForwardAllowIn): Likewise.
* src/util/virsocketaddr.h (virSocketAddrSetIPv4Addr): Drop
incorrect const.
(virMacAddrGetRaw, virSocketAddrFormat, virSocketAddrFormatFull):
Make const-correct.
(virSocketAddrMask, virSocketAddrMaskByPrefix)
(virSocketAddrBroadcast, virSocketAddrBroadcastByPrefix)
(virSocketAddrGetNumNetmaskBits, virSocketAddrGetIpPrefix)
(virSocketAddrEqual, virSocketAddrIsPrivate)
(virSocketAddrIsWildcard): Use intended type.
* src/util/virbuffer.c (virBufferError, virBufferUse)
(virBufferGetIndent): Fix fallout.
* src/util/virmacaddr.c (virMacAddrCmp, virMacAddrCmpRaw)
(virMacAddrSet, virMcAddrFormat, virMacAddrIsUnicast)
(virMacAddrIsMulticast): Likewise.
* src/util/virebtables.c (ebtablesAddForwardAllowIn)
(ebtablesRemoveForwardAllowIn): Likewise.
* src/util/virsocketaddr.c (virSocketAddrMask, virMacAddrGetRaw)
(virSocketAddrMaskByPrefix, virSocketAddrBroadcast)
(virSocketAddrBroadcastByPrefix, virSocketAddrGetNumNetmaskBits)
(virSocketAddrGetIpPrefix, virSocketAddrEqual)
(virSocketAddrIsPrivate, virSocketAddrIsWildcard)
(virSocketAddrGetIPv4Addr, virSocketAddrGetIPv6Addr)
(virSocketAddrFormat, virSocketAddrFormatFull): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-10-05 15:51:55 +00:00
|
|
|
const virMacAddr *mac)
|
2009-11-03 22:11:01 +00:00
|
|
|
{
|
2013-03-26 11:21:33 +00:00
|
|
|
char macaddr[VIR_MAC_STRING_BUFLEN];
|
|
|
|
|
|
|
|
virMacAddrFormat(mac, macaddr);
|
2009-11-03 22:11:01 +00:00
|
|
|
return ebtablesForwardAllowIn(ctx, iface, macaddr, ADD);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ebtablesRemoveForwardAllowIn:
|
|
|
|
* @ctx: pointer to the EB table context
|
|
|
|
* @iface: the output interface name
|
|
|
|
* @physdev: the physical input device or NULL
|
|
|
|
*
|
|
|
|
* Remove rules from the EB table context hence forbidding the traffic
|
|
|
|
* on the @physdev device to be forwarded to interface @iface. This
|
|
|
|
* stops the inbound traffic on a bridge.
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success or an error code otherwise
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
ebtablesRemoveForwardAllowIn(ebtablesContext *ctx,
|
|
|
|
const char *iface,
|
maint: avoid 'const fooPtr' in several util files
'const fooPtr' is the same as 'foo * const' (the pointer won't
change, but it's contents can). But in general, if an interface
is trying to be const-correct, it should be using 'const foo *'
(the pointer is to data that can't be changed).
Fix up offenders in src/util outside of the virnet namespace.
Also, make a few virSocketAddr functions const-correct, for easier
conversions in future patches.
* src/util/virbuffer.h (virBufferError, virBufferUse)
(virBufferGetIndent): Use intended type.
* src/util/virmacaddr.h (virMacAddrCmp, virMacAddrCmpRaw)
(virMacAddrSet, virMcAddrFormat, virMacAddrIsUnicast)
(virMacAddrIsMulticast): Likewise.
* src/util/virebtables.h (ebtablesAddForwardAllowIn)
(ebtablesRemoveForwardAllowIn): Likewise.
* src/util/virsocketaddr.h (virSocketAddrSetIPv4Addr): Drop
incorrect const.
(virMacAddrGetRaw, virSocketAddrFormat, virSocketAddrFormatFull):
Make const-correct.
(virSocketAddrMask, virSocketAddrMaskByPrefix)
(virSocketAddrBroadcast, virSocketAddrBroadcastByPrefix)
(virSocketAddrGetNumNetmaskBits, virSocketAddrGetIpPrefix)
(virSocketAddrEqual, virSocketAddrIsPrivate)
(virSocketAddrIsWildcard): Use intended type.
* src/util/virbuffer.c (virBufferError, virBufferUse)
(virBufferGetIndent): Fix fallout.
* src/util/virmacaddr.c (virMacAddrCmp, virMacAddrCmpRaw)
(virMacAddrSet, virMcAddrFormat, virMacAddrIsUnicast)
(virMacAddrIsMulticast): Likewise.
* src/util/virebtables.c (ebtablesAddForwardAllowIn)
(ebtablesRemoveForwardAllowIn): Likewise.
* src/util/virsocketaddr.c (virSocketAddrMask, virMacAddrGetRaw)
(virSocketAddrMaskByPrefix, virSocketAddrBroadcast)
(virSocketAddrBroadcastByPrefix, virSocketAddrGetNumNetmaskBits)
(virSocketAddrGetIpPrefix, virSocketAddrEqual)
(virSocketAddrIsPrivate, virSocketAddrIsWildcard)
(virSocketAddrGetIPv4Addr, virSocketAddrGetIPv6Addr)
(virSocketAddrFormat, virSocketAddrFormatFull): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-10-05 15:51:55 +00:00
|
|
|
const virMacAddr *mac)
|
2009-11-03 22:11:01 +00:00
|
|
|
{
|
2013-03-26 11:21:33 +00:00
|
|
|
char macaddr[VIR_MAC_STRING_BUFLEN];
|
|
|
|
|
|
|
|
virMacAddrFormat(mac, macaddr);
|
2009-11-03 22:11:01 +00:00
|
|
|
return ebtablesForwardAllowIn(ctx, iface, macaddr, REMOVE);
|
|
|
|
}
|