libvirt/src/util/virfirewall.h
Laine Stump 070690538a util: synchronize with firewalld before we start calling iptables directly
When it is starting up, firewalld will delete all existing iptables
rules and chains before adding its own rules. If libvirtd were to try
to directly add iptables rules during the time before firewalld has
finished initializing, firewalld would end up deleting the rules that
libvirtd has just added.

Currently this isn't a problem, since libvirtd only adds iptables
rules via the firewalld "passthrough command" API, and so firewalld is
able to properly serialize everything. However, we will soon be
changing libvirtd to add its iptables and ebtables rules by directly
calling iptables/ebtables rather than via firewalld, thus removing the
serialization of libvirtd adding rules vs. firewalld deleting rules.

This will especially apparent (if we don't fix it in advance, as this
patch does) when libvirtd is responding to the dbus NameOwnerChanged
event, which is used to learn when firewalld has been restarted. In
that case, dbus sends the event before firewalld has been able to
complete its initialization, so when libvirt responds to the event by
adding back its iptables rules (with direct calls to
/usr/bin/iptables), some of those rules are added before firewalld has
a chance to do its "remove everything" startup protocol. The usual
result of this is that libvirt will successfully add its private
chains (e.g. LIBVIRT_INP, etc), but then fail when it tries to add a
rule jumping to one of those chains (because in the interim, firewalld
has deleted the new chains).

The solution is for libvirt to preface it's direct calling to iptables
with a iptables command sent via firewalld's passthrough command
API. Since commands sent to firewalld are completed synchronously, and
since firewalld won't service them until it has completed its own
initialization, this will assure that by the time libvirt starts
calling iptables to add rules, that firewalld will not be following up
by deleting any of those rules.

To minimize the amount of extra overhead, we request the simplest
iptables command possible: "iptables -V" (and aside from logging a
debug message, we ignore the result, for good measure).

(This patch is being done *before* the patch that switches to calling
iptables directly, so that everything will function properly with any
fractional part of the series applied).

Signed-off-by: Laine Stump <laine@redhat.com>
Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>
2020-11-24 14:21:58 -05:00

117 lines
3.8 KiB
C

/*
* virfirewall.h: integration with firewalls
*
* Copyright (C) 2014 Red Hat, Inc.
*
* 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
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "internal.h"
typedef struct _virFirewall virFirewall;
typedef virFirewall *virFirewallPtr;
typedef struct _virFirewallRule virFirewallRule;
typedef virFirewallRule *virFirewallRulePtr;
typedef enum {
VIR_FIREWALL_LAYER_ETHERNET,
VIR_FIREWALL_LAYER_IPV4,
VIR_FIREWALL_LAYER_IPV6,
VIR_FIREWALL_LAYER_LAST,
} virFirewallLayer;
virFirewallPtr virFirewallNew(void);
void virFirewallFree(virFirewallPtr firewall);
/**
* virFirewallAddRule:
* @firewall: firewall ruleset to add to
* @layer: the firewall layer to change
* @...: NULL terminated list of strings for the rule
*
* Add any type of rule to the firewall ruleset.
*
* Returns the new rule
*/
#define virFirewallAddRule(firewall, layer, ...) \
virFirewallAddRuleFull(firewall, layer, false, NULL, NULL, __VA_ARGS__)
typedef int (*virFirewallQueryCallback)(virFirewallPtr firewall,
virFirewallLayer layer,
const char *const *lines,
void *opaque);
virFirewallRulePtr virFirewallAddRuleFull(virFirewallPtr firewall,
virFirewallLayer layer,
bool ignoreErrors,
virFirewallQueryCallback cb,
void *opaque,
...)
G_GNUC_NULL_TERMINATED;
void virFirewallRemoveRule(virFirewallPtr firewall,
virFirewallRulePtr rule);
void virFirewallRuleAddArg(virFirewallPtr firewall,
virFirewallRulePtr rule,
const char *arg)
ATTRIBUTE_NONNULL(3);
void virFirewallRuleAddArgFormat(virFirewallPtr firewall,
virFirewallRulePtr rule,
const char *fmt, ...)
ATTRIBUTE_NONNULL(3) G_GNUC_PRINTF(3, 4);
void virFirewallRuleAddArgSet(virFirewallPtr firewall,
virFirewallRulePtr rule,
const char *const *args)
ATTRIBUTE_NONNULL(3);
void virFirewallRuleAddArgList(virFirewallPtr firewall,
virFirewallRulePtr rule,
...)
G_GNUC_NULL_TERMINATED;
size_t virFirewallRuleGetArgCount(virFirewallRulePtr rule);
typedef enum {
/* Ignore all errors when applying rules, so no
* rollback block will be required */
VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS = (1 << 0),
} virFirewallTransactionFlags;
void virFirewallStartTransaction(virFirewallPtr firewall,
unsigned int flags);
typedef enum {
/* Execute previous rollback block before this
* one, to chain cleanup */
VIR_FIREWALL_ROLLBACK_INHERIT_PREVIOUS = (1 << 0),
} virFirewallRollbackFlags;
void virFirewallStartRollback(virFirewallPtr firewall,
unsigned int flags);
int virFirewallApply(virFirewallPtr firewall);
void virFirewallBackendSynchronize(void);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virFirewall, virFirewallFree);