2013-03-04 16:30:40 +00:00
|
|
|
/*
|
|
|
|
* virfirewall.c: integration with firewalls
|
|
|
|
*
|
2015-05-21 13:36:18 -04:00
|
|
|
* Copyright (C) 2013-2015 Red Hat, Inc.
|
2013-03-04 16:30:40 +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
|
|
|
|
* License along with this library. If not, see
|
|
|
|
* <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
2021-11-16 14:27:00 -05:00
|
|
|
#include "virfirewall.h"
|
2019-01-09 14:11:32 -05:00
|
|
|
#include "virfirewalld.h"
|
2019-04-01 16:28:05 +02:00
|
|
|
#include "viralloc.h"
|
2013-03-04 16:30:40 +00:00
|
|
|
#include "virerror.h"
|
|
|
|
#include "vircommand.h"
|
|
|
|
#include "virlog.h"
|
|
|
|
#include "virfile.h"
|
|
|
|
#include "virthread.h"
|
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_FIREWALL
|
|
|
|
|
|
|
|
VIR_LOG_INIT("util.firewall");
|
|
|
|
|
|
|
|
typedef struct _virFirewallGroup virFirewallGroup;
|
|
|
|
|
2019-01-20 11:04:56 -05:00
|
|
|
VIR_ENUM_DECL(virFirewallLayerCommand);
|
2019-03-16 14:20:32 -04:00
|
|
|
VIR_ENUM_IMPL(virFirewallLayerCommand,
|
|
|
|
VIR_FIREWALL_LAYER_LAST,
|
2021-09-14 10:40:42 +02:00
|
|
|
EBTABLES,
|
|
|
|
IPTABLES,
|
|
|
|
IP6TABLES,
|
2019-01-20 11:30:15 -05:00
|
|
|
);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
struct _virFirewallCmd {
|
2013-03-04 16:30:40 +00:00
|
|
|
virFirewallLayer layer;
|
|
|
|
|
|
|
|
virFirewallQueryCallback queryCB;
|
|
|
|
void *queryOpaque;
|
|
|
|
bool ignoreErrors;
|
|
|
|
|
|
|
|
size_t argsAlloc;
|
|
|
|
size_t argsLen;
|
|
|
|
char **args;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _virFirewallGroup {
|
|
|
|
unsigned int actionFlags;
|
|
|
|
unsigned int rollbackFlags;
|
|
|
|
|
|
|
|
size_t naction;
|
2024-04-19 22:19:42 -04:00
|
|
|
virFirewallCmd **action;
|
2013-03-04 16:30:40 +00:00
|
|
|
|
|
|
|
size_t nrollback;
|
2024-04-19 22:19:42 -04:00
|
|
|
virFirewallCmd **rollback;
|
2013-03-04 16:30:40 +00:00
|
|
|
|
|
|
|
bool addingRollback;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct _virFirewall {
|
|
|
|
int err;
|
|
|
|
|
|
|
|
size_t ngroups;
|
2021-03-11 08:16:13 +01:00
|
|
|
virFirewallGroup **groups;
|
2013-03-04 16:30:40 +00:00
|
|
|
size_t currentGroup;
|
|
|
|
};
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
static virMutex fwCmdLock = VIR_MUTEX_INITIALIZER;
|
2013-03-04 16:30:40 +00:00
|
|
|
|
2021-03-11 08:16:13 +01:00
|
|
|
static virFirewallGroup *
|
2013-03-04 16:30:40 +00:00
|
|
|
virFirewallGroupNew(void)
|
|
|
|
{
|
2021-10-22 10:56:01 +02:00
|
|
|
return g_new0(virFirewallGroup, 1);
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virFirewallNew:
|
|
|
|
*
|
|
|
|
* Creates a new firewall ruleset for changing rules
|
|
|
|
* of @layer. This should be followed by a call to
|
|
|
|
* virFirewallStartTransaction before adding
|
|
|
|
* any rules
|
|
|
|
*
|
|
|
|
* Returns the new firewall ruleset
|
|
|
|
*/
|
2021-03-11 08:16:13 +01:00
|
|
|
virFirewall *virFirewallNew(void)
|
2013-03-04 16:30:40 +00:00
|
|
|
{
|
2021-11-17 13:20:53 -05:00
|
|
|
virFirewall *firewall = g_new0(virFirewall, 1);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
|
|
|
return firewall;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2024-04-19 22:19:42 -04:00
|
|
|
virFirewallCmdFree(virFirewallCmd *fwCmd)
|
2013-03-04 16:30:40 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
if (!fwCmd)
|
2013-03-04 16:30:40 +00:00
|
|
|
return;
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
for (i = 0; i < fwCmd->argsLen; i++)
|
|
|
|
g_free(fwCmd->args[i]);
|
|
|
|
g_free(fwCmd->args);
|
|
|
|
g_free(fwCmd);
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2021-03-11 08:16:13 +01:00
|
|
|
virFirewallGroupFree(virFirewallGroup *group)
|
2013-03-04 16:30:40 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (!group)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < group->naction; i++)
|
2024-04-19 22:19:42 -04:00
|
|
|
virFirewallCmdFree(group->action[i]);
|
2021-02-03 14:32:34 -05:00
|
|
|
g_free(group->action);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
|
|
|
for (i = 0; i < group->nrollback; i++)
|
2024-04-19 22:19:42 -04:00
|
|
|
virFirewallCmdFree(group->rollback[i]);
|
2021-02-03 14:32:34 -05:00
|
|
|
g_free(group->rollback);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
2021-02-03 14:32:34 -05:00
|
|
|
g_free(group);
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virFirewallFree:
|
|
|
|
*
|
|
|
|
* Release all memory associated with the firewall
|
|
|
|
* ruleset
|
|
|
|
*/
|
2021-03-11 08:16:13 +01:00
|
|
|
void virFirewallFree(virFirewall *firewall)
|
2013-03-04 16:30:40 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (!firewall)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < firewall->ngroups; i++)
|
|
|
|
virFirewallGroupFree(firewall->groups[i]);
|
2021-02-03 14:32:34 -05:00
|
|
|
g_free(firewall->groups);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
2021-02-03 14:32:34 -05:00
|
|
|
g_free(firewall);
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|
|
|
|
|
2017-11-03 13:09:47 +01:00
|
|
|
#define VIR_FIREWALL_RETURN_IF_ERROR(firewall) \
|
|
|
|
do { \
|
|
|
|
if (!firewall || firewall->err) \
|
|
|
|
return; \
|
2013-03-04 16:30:40 +00:00
|
|
|
} while (0)
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
#define VIR_FIREWALL_CMD_RETURN_IF_ERROR(firewall, fwCmd)\
|
2017-11-03 13:09:47 +01:00
|
|
|
do { \
|
2024-04-19 22:19:42 -04:00
|
|
|
if (!firewall || firewall->err || !fwCmd) \
|
2017-11-03 13:09:47 +01:00
|
|
|
return; \
|
2013-03-04 16:30:40 +00:00
|
|
|
} while (0)
|
|
|
|
|
2017-11-03 13:09:47 +01:00
|
|
|
#define VIR_FIREWALL_RETURN_NULL_IF_ERROR(firewall) \
|
|
|
|
do { \
|
|
|
|
if (!firewall || firewall->err) \
|
|
|
|
return NULL; \
|
2013-03-04 16:30:40 +00:00
|
|
|
} while (0)
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
#define ADD_ARG(fwCmd, str) \
|
2017-11-03 13:09:47 +01:00
|
|
|
do { \
|
2024-04-19 22:19:42 -04:00
|
|
|
VIR_RESIZE_N(fwCmd->args, fwCmd->argsAlloc, fwCmd->argsLen, 1); \
|
|
|
|
fwCmd->args[fwCmd->argsLen++] = g_strdup(str); \
|
2013-03-04 16:30:40 +00:00
|
|
|
} while (0)
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
static virFirewallCmd *
|
|
|
|
virFirewallAddCmdFullV(virFirewall *firewall,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
bool ignoreErrors,
|
|
|
|
virFirewallQueryCallback cb,
|
|
|
|
void *opaque,
|
|
|
|
va_list args)
|
2013-03-04 16:30:40 +00:00
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virFirewallGroup *group;
|
2024-04-19 22:19:42 -04:00
|
|
|
virFirewallCmd *fwCmd;
|
2013-03-04 16:30:40 +00:00
|
|
|
char *str;
|
|
|
|
|
|
|
|
VIR_FIREWALL_RETURN_NULL_IF_ERROR(firewall);
|
|
|
|
|
|
|
|
if (firewall->ngroups == 0) {
|
2014-04-30 08:51:29 +02:00
|
|
|
firewall->err = EINVAL;
|
2013-03-04 16:30:40 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
group = firewall->groups[firewall->currentGroup];
|
|
|
|
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
fwCmd = g_new0(virFirewallCmd, 1);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
fwCmd->layer = layer;
|
|
|
|
fwCmd->queryCB = cb;
|
|
|
|
fwCmd->queryOpaque = opaque;
|
2013-03-04 16:30:40 +00:00
|
|
|
|
2014-11-13 15:28:18 +01:00
|
|
|
while ((str = va_arg(args, char *)) != NULL)
|
2024-04-19 22:19:42 -04:00
|
|
|
ADD_ARG(fwCmd, str);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
|
|
|
if (group->addingRollback) {
|
2024-04-19 22:19:42 -04:00
|
|
|
fwCmd->ignoreErrors = true; /* always ignore errors when rolling back */
|
2024-04-19 22:19:42 -04:00
|
|
|
VIR_APPEND_ELEMENT_COPY(group->rollback, group->nrollback, fwCmd);
|
2013-03-04 16:30:40 +00:00
|
|
|
} else {
|
2024-04-19 22:19:42 -04:00
|
|
|
/* when not rolling back, ignore errors if this group (transaction)
|
|
|
|
* was started with VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS *or*
|
|
|
|
* if this specific rule was created with ignoreErrors == true
|
|
|
|
*/
|
|
|
|
fwCmd->ignoreErrors = ignoreErrors || (group->actionFlags & VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
|
2024-04-19 22:19:42 -04:00
|
|
|
VIR_APPEND_ELEMENT_COPY(group->action, group->naction, fwCmd);
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
return fwCmd;
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2024-04-19 22:19:42 -04:00
|
|
|
* virFirewallAddCmdFull:
|
2013-03-04 16:30:40 +00:00
|
|
|
* @firewall: firewall ruleset to add to
|
|
|
|
* @layer: the firewall layer to change
|
|
|
|
* @ignoreErrors: true to ignore failure of the command
|
|
|
|
* @cb: callback to invoke with result of query
|
|
|
|
* @opaque: data passed into @cb
|
|
|
|
* @...: NULL terminated list of strings for the rule
|
|
|
|
*
|
|
|
|
* Add any type of rule to the firewall ruleset. Any output
|
|
|
|
* generated by the addition will be fed into the query
|
|
|
|
* callback @cb. This callback is permitted to create new
|
2024-04-19 22:19:42 -04:00
|
|
|
* rules by invoking the virFirewallAddCmd method, but
|
2013-03-04 16:30:40 +00:00
|
|
|
* is not permitted to start new transactions.
|
|
|
|
*
|
|
|
|
* If @ignoreErrors is set to TRUE, then any failure of
|
|
|
|
* the command is ignored. If it is set to FALSE, then
|
|
|
|
* the behaviour upon failure is determined by the flags
|
|
|
|
* set when the transaction was started.
|
|
|
|
*
|
|
|
|
* Returns the new rule
|
|
|
|
*/
|
2024-04-19 22:19:42 -04:00
|
|
|
virFirewallCmd *virFirewallAddCmdFull(virFirewall *firewall,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
bool ignoreErrors,
|
|
|
|
virFirewallQueryCallback cb,
|
|
|
|
void *opaque,
|
|
|
|
...)
|
2013-03-04 16:30:40 +00:00
|
|
|
{
|
2024-04-19 22:19:42 -04:00
|
|
|
virFirewallCmd *fwCmd;
|
2013-03-04 16:30:40 +00:00
|
|
|
va_list args;
|
|
|
|
va_start(args, opaque);
|
2024-04-19 22:19:42 -04:00
|
|
|
fwCmd = virFirewallAddCmdFullV(firewall, layer, ignoreErrors, cb, opaque, args);
|
2013-03-04 16:30:40 +00:00
|
|
|
va_end(args);
|
2024-04-19 22:19:42 -04:00
|
|
|
return fwCmd;
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2024-04-19 22:19:42 -04:00
|
|
|
* virFirewallRemoveCmd:
|
2013-03-04 16:30:40 +00:00
|
|
|
* @firewall: firewall ruleset to remove from
|
|
|
|
* @rule: the rule to remove
|
|
|
|
*
|
|
|
|
* Remove a rule from the current transaction
|
|
|
|
*/
|
2024-04-19 22:19:42 -04:00
|
|
|
void virFirewallRemoveCmd(virFirewall *firewall,
|
|
|
|
virFirewallCmd *fwCmd)
|
2013-03-04 16:30:40 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
2021-03-11 08:16:13 +01:00
|
|
|
virFirewallGroup *group;
|
2013-03-04 16:30:40 +00:00
|
|
|
|
|
|
|
/* Explicitly not checking firewall->err too,
|
|
|
|
* because if rule was partially created
|
|
|
|
* before hitting error we must still remove
|
|
|
|
* it to avoid leaking 'rule'
|
|
|
|
*/
|
|
|
|
if (!firewall)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (firewall->ngroups == 0)
|
|
|
|
return;
|
|
|
|
group = firewall->groups[firewall->currentGroup];
|
|
|
|
|
|
|
|
if (group->addingRollback) {
|
|
|
|
for (i = 0; i < group->nrollback; i++) {
|
2024-04-19 22:19:42 -04:00
|
|
|
if (group->rollback[i] == fwCmd) {
|
2013-03-04 16:30:40 +00:00
|
|
|
VIR_DELETE_ELEMENT(group->rollback,
|
|
|
|
i,
|
|
|
|
group->nrollback);
|
2024-04-19 22:19:42 -04:00
|
|
|
virFirewallCmdFree(fwCmd);
|
2013-03-04 16:30:40 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < group->naction; i++) {
|
2024-04-19 22:19:42 -04:00
|
|
|
if (group->action[i] == fwCmd) {
|
2013-03-04 16:30:40 +00:00
|
|
|
VIR_DELETE_ELEMENT(group->action,
|
|
|
|
i,
|
|
|
|
group->naction);
|
2024-04-19 22:19:42 -04:00
|
|
|
virFirewallCmdFree(fwCmd);
|
2013-03-04 16:30:40 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
void virFirewallCmdAddArg(virFirewall *firewall,
|
|
|
|
virFirewallCmd *fwCmd,
|
|
|
|
const char *arg)
|
2013-03-04 16:30:40 +00:00
|
|
|
{
|
2024-04-19 22:19:42 -04:00
|
|
|
VIR_FIREWALL_CMD_RETURN_IF_ERROR(firewall, fwCmd);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
ADD_ARG(fwCmd, arg);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
void virFirewallCmdAddArgFormat(virFirewall *firewall,
|
|
|
|
virFirewallCmd *fwCmd,
|
|
|
|
const char *fmt, ...)
|
2013-03-04 16:30:40 +00:00
|
|
|
{
|
2019-10-15 15:16:31 +02:00
|
|
|
g_autofree char *arg = NULL;
|
2013-03-04 16:30:40 +00:00
|
|
|
va_list list;
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
VIR_FIREWALL_CMD_RETURN_IF_ERROR(firewall, fwCmd);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
|
|
|
va_start(list, fmt);
|
2019-10-22 14:11:15 +02:00
|
|
|
arg = g_strdup_vprintf(fmt, list);
|
|
|
|
va_end(list);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
ADD_ARG(fwCmd, arg);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
void virFirewallCmdAddArgSet(virFirewall *firewall,
|
|
|
|
virFirewallCmd *fwCmd,
|
|
|
|
const char *const *args)
|
2013-03-04 16:30:40 +00:00
|
|
|
{
|
2024-04-19 22:19:42 -04:00
|
|
|
VIR_FIREWALL_CMD_RETURN_IF_ERROR(firewall, fwCmd);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
|
|
|
while (*args) {
|
2024-04-19 22:19:42 -04:00
|
|
|
ADD_ARG(fwCmd, *args);
|
2013-03-04 16:30:40 +00:00
|
|
|
args++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
void virFirewallCmdAddArgList(virFirewall *firewall,
|
|
|
|
virFirewallCmd *fwCmd,
|
|
|
|
...)
|
2013-03-04 16:30:40 +00:00
|
|
|
{
|
|
|
|
va_list list;
|
|
|
|
const char *str;
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
VIR_FIREWALL_CMD_RETURN_IF_ERROR(firewall, fwCmd);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
va_start(list, fwCmd);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
2014-11-13 15:28:18 +01:00
|
|
|
while ((str = va_arg(list, char *)) != NULL)
|
2024-04-19 22:19:42 -04:00
|
|
|
ADD_ARG(fwCmd, str);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
|
|
|
va_end(list);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
size_t virFirewallCmdGetArgCount(virFirewallCmd *fwCmd)
|
2013-03-04 16:30:40 +00:00
|
|
|
{
|
2024-04-19 22:19:42 -04:00
|
|
|
if (!fwCmd)
|
2013-03-04 16:30:40 +00:00
|
|
|
return 0;
|
2024-04-19 22:19:42 -04:00
|
|
|
return fwCmd->argsLen;
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virFirewallStartTransaction:
|
|
|
|
* @firewall: the firewall ruleset
|
|
|
|
* @flags: bitset of virFirewallTransactionFlags
|
|
|
|
*
|
|
|
|
* Start a new transaction with associated rollback
|
|
|
|
* block.
|
|
|
|
*
|
|
|
|
* Should be followed by calls to add various rules to
|
|
|
|
* the transaction. Then virFirwallStartRollback should
|
|
|
|
* be used to provide rules to rollback upon transaction
|
|
|
|
* failure
|
|
|
|
*/
|
2021-03-11 08:16:13 +01:00
|
|
|
void virFirewallStartTransaction(virFirewall *firewall,
|
2013-03-04 16:30:40 +00:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virFirewallGroup *group;
|
2013-03-04 16:30:40 +00:00
|
|
|
|
|
|
|
VIR_FIREWALL_RETURN_IF_ERROR(firewall);
|
|
|
|
|
2021-02-23 17:36:36 +01:00
|
|
|
group = virFirewallGroupNew();
|
2013-03-04 16:30:40 +00:00
|
|
|
group->actionFlags = flags;
|
|
|
|
|
2021-03-20 00:37:03 +01:00
|
|
|
VIR_EXPAND_N(firewall->groups, firewall->ngroups, 1);
|
2013-03-04 16:30:40 +00:00
|
|
|
firewall->groups[firewall->ngroups - 1] = group;
|
|
|
|
firewall->currentGroup = firewall->ngroups - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virFirewallBeginRollback:
|
|
|
|
* @firewall: the firewall ruleset
|
|
|
|
* @flags: bitset of virFirewallRollbackFlags
|
|
|
|
*
|
|
|
|
* Mark the beginning of a set of rules able to rollback
|
|
|
|
* changes in this and all earlier transactions.
|
|
|
|
*
|
|
|
|
* Should be followed by calls to add various rules needed
|
|
|
|
* to rollback state. Then virFirewallStartTransaction
|
|
|
|
* should be used to indicate the beginning of the next
|
|
|
|
* transactional ruleset.
|
|
|
|
*/
|
2021-03-11 08:16:13 +01:00
|
|
|
void virFirewallStartRollback(virFirewall *firewall,
|
2013-03-04 16:30:40 +00:00
|
|
|
unsigned int flags)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virFirewallGroup *group;
|
2013-03-04 16:30:40 +00:00
|
|
|
|
|
|
|
VIR_FIREWALL_RETURN_IF_ERROR(firewall);
|
|
|
|
|
|
|
|
if (firewall->ngroups == 0) {
|
2014-04-30 08:51:29 +02:00
|
|
|
firewall->err = EINVAL;
|
2013-03-04 16:30:40 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
group = firewall->groups[firewall->ngroups-1];
|
|
|
|
group->rollbackFlags = flags;
|
|
|
|
group->addingRollback = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-04-21 17:42:30 -04:00
|
|
|
char *
|
2024-04-19 22:19:42 -04:00
|
|
|
virFirewallCmdToString(const char *cmd,
|
|
|
|
virFirewallCmd *fwCmd)
|
2013-03-04 16:30:40 +00:00
|
|
|
{
|
2020-07-02 22:30:20 -04:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2013-03-04 16:30:40 +00:00
|
|
|
size_t i;
|
|
|
|
|
2022-04-21 17:42:30 -04:00
|
|
|
virBufferAdd(&buf, cmd, -1);
|
2024-04-19 22:19:42 -04:00
|
|
|
for (i = 0; i < fwCmd->argsLen; i++) {
|
2013-03-04 16:30:40 +00:00
|
|
|
virBufferAddLit(&buf, " ");
|
2024-04-19 22:19:42 -04:00
|
|
|
virBufferAdd(&buf, fwCmd->args[i], -1);
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
|
2022-04-21 17:42:30 -04:00
|
|
|
|
2013-03-04 16:30:40 +00:00
|
|
|
static int
|
2024-04-19 22:19:42 -04:00
|
|
|
virFirewallApplyCmdDirect(virFirewallCmd *fwCmd,
|
2024-04-19 22:19:42 -04:00
|
|
|
char **output)
|
2013-03-04 16:30:40 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
2024-04-19 22:19:42 -04:00
|
|
|
const char *bin = virFirewallLayerCommandTypeToString(fwCmd->layer);
|
2019-10-15 14:47:50 +02:00
|
|
|
g_autoptr(virCommand) cmd = NULL;
|
2022-03-13 14:21:02 -04:00
|
|
|
g_autofree char *cmdStr = NULL;
|
2013-03-04 16:30:40 +00:00
|
|
|
int status;
|
2019-10-15 15:16:31 +02:00
|
|
|
g_autofree char *error = NULL;
|
2013-03-04 16:30:40 +00:00
|
|
|
|
|
|
|
if (!bin) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2023-03-09 15:13:35 +01:00
|
|
|
_("Unknown firewall layer %1$d"),
|
2024-04-19 22:19:42 -04:00
|
|
|
fwCmd->layer);
|
2018-07-24 21:22:17 +05:30
|
|
|
return -1;
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cmd = virCommandNewArgList(bin, NULL);
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
/* lock to assure nobody else is messing with the tables while we are */
|
|
|
|
switch (fwCmd->layer) {
|
|
|
|
case VIR_FIREWALL_LAYER_ETHERNET:
|
|
|
|
virCommandAddArg(cmd, "--concurrent");
|
|
|
|
break;
|
|
|
|
case VIR_FIREWALL_LAYER_IPV4:
|
|
|
|
case VIR_FIREWALL_LAYER_IPV6:
|
|
|
|
virCommandAddArg(cmd, "-w");
|
|
|
|
break;
|
|
|
|
case VIR_FIREWALL_LAYER_LAST:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
for (i = 0; i < fwCmd->argsLen; i++)
|
|
|
|
virCommandAddArg(cmd, fwCmd->args[i]);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
2022-03-13 14:21:02 -04:00
|
|
|
cmdStr = virCommandToString(cmd, false);
|
2024-04-19 22:19:42 -04:00
|
|
|
VIR_INFO("Running firewall command '%s'", NULLSTR(cmdStr));
|
2022-03-13 14:21:02 -04:00
|
|
|
|
2013-03-04 16:30:40 +00:00
|
|
|
virCommandSetOutputBuffer(cmd, output);
|
|
|
|
virCommandSetErrorBuffer(cmd, &error);
|
|
|
|
|
|
|
|
if (virCommandRun(cmd, &status) < 0)
|
2018-07-24 21:22:17 +05:30
|
|
|
return -1;
|
2013-03-04 16:30:40 +00:00
|
|
|
|
|
|
|
if (status != 0) {
|
2024-04-19 22:19:42 -04:00
|
|
|
if (fwCmd->ignoreErrors) {
|
2013-03-04 16:30:40 +00:00
|
|
|
VIR_DEBUG("Ignoring error running command");
|
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2024-04-19 22:19:42 -04:00
|
|
|
_("Failed to run firewall command %1$s: %2$s"),
|
2022-03-13 14:21:02 -04:00
|
|
|
NULLSTR(cmdStr), NULLSTR(error));
|
2013-03-04 16:30:40 +00:00
|
|
|
VIR_FREE(*output);
|
2018-07-24 21:22:17 +05:30
|
|
|
return -1;
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-24 21:22:17 +05:30
|
|
|
return 0;
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2024-04-19 22:19:42 -04:00
|
|
|
virFirewallApplyCmd(virFirewall *firewall,
|
2024-04-19 22:19:42 -04:00
|
|
|
virFirewallCmd *fwCmd)
|
2013-03-04 16:30:40 +00:00
|
|
|
{
|
2019-10-15 15:16:31 +02:00
|
|
|
g_autofree char *output = NULL;
|
2020-12-01 09:21:32 +01:00
|
|
|
g_auto(GStrv) lines = NULL;
|
2013-03-04 16:30:40 +00:00
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
if (fwCmd->argsLen == 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Can't apply empty firewall command"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
if (virFirewallApplyCmdDirect(fwCmd, &output) < 0)
|
2013-03-04 16:30:40 +00:00
|
|
|
return -1;
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
if (fwCmd->queryCB && output) {
|
2021-02-05 18:35:07 +01:00
|
|
|
if (!(lines = g_strsplit(output, "\n", -1)))
|
2018-07-24 21:22:17 +05:30
|
|
|
return -1;
|
2013-03-04 16:30:40 +00:00
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
VIR_DEBUG("Invoking query %p with '%s'", fwCmd->queryCB, output);
|
|
|
|
if (fwCmd->queryCB(firewall, fwCmd->layer, (const char *const *)lines, fwCmd->queryOpaque) < 0)
|
2018-07-24 21:22:17 +05:30
|
|
|
return -1;
|
2013-03-04 16:30:40 +00:00
|
|
|
|
|
|
|
if (firewall->err) {
|
|
|
|
virReportSystemError(firewall->err, "%s",
|
2024-04-19 22:19:42 -04:00
|
|
|
_("Unable to create firewall command"));
|
2018-07-24 21:22:17 +05:30
|
|
|
return -1;
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-07-24 21:22:17 +05:30
|
|
|
return 0;
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2021-03-11 08:16:13 +01:00
|
|
|
virFirewallApplyGroup(virFirewall *firewall,
|
2013-03-04 16:30:40 +00:00
|
|
|
size_t idx)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virFirewallGroup *group = firewall->groups[idx];
|
2024-04-19 22:19:42 -04:00
|
|
|
|
2013-03-04 16:30:40 +00:00
|
|
|
size_t i;
|
|
|
|
|
2017-09-25 11:43:33 +01:00
|
|
|
VIR_INFO("Starting transaction for firewall=%p group=%p flags=0x%x",
|
2014-11-11 12:34:57 +00:00
|
|
|
firewall, group, group->actionFlags);
|
2013-03-04 16:30:40 +00:00
|
|
|
firewall->currentGroup = idx;
|
|
|
|
group->addingRollback = false;
|
|
|
|
for (i = 0; i < group->naction; i++) {
|
2024-04-19 22:19:42 -04:00
|
|
|
if (virFirewallApplyCmd(firewall, group->action[i]) < 0)
|
2013-03-04 16:30:40 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2021-03-11 08:16:13 +01:00
|
|
|
virFirewallRollbackGroup(virFirewall *firewall,
|
2013-03-04 16:30:40 +00:00
|
|
|
size_t idx)
|
|
|
|
{
|
2021-03-11 08:16:13 +01:00
|
|
|
virFirewallGroup *group = firewall->groups[idx];
|
2013-03-04 16:30:40 +00:00
|
|
|
size_t i;
|
|
|
|
|
|
|
|
VIR_INFO("Starting rollback for group %p", group);
|
|
|
|
firewall->currentGroup = idx;
|
|
|
|
group->addingRollback = true;
|
2024-04-19 22:19:42 -04:00
|
|
|
for (i = 0; i < group->nrollback; i++)
|
2024-04-19 22:19:42 -04:00
|
|
|
ignore_value(virFirewallApplyCmd(firewall, group->rollback[i]));
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2021-03-11 08:16:13 +01:00
|
|
|
virFirewallApply(virFirewall *firewall)
|
2013-03-04 16:30:40 +00:00
|
|
|
{
|
|
|
|
size_t i, j;
|
2024-04-19 22:19:42 -04:00
|
|
|
VIR_LOCK_GUARD lock = virLockGuardLock(&fwCmdLock);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
2021-02-23 17:39:50 +01:00
|
|
|
if (!firewall || firewall->err) {
|
2021-03-05 10:38:49 +01:00
|
|
|
int err = EINVAL;
|
|
|
|
|
|
|
|
if (firewall)
|
|
|
|
err = firewall->err;
|
|
|
|
|
2024-04-19 22:19:42 -04:00
|
|
|
virReportSystemError(err, "%s", _("Unable to create firewall command"));
|
2022-02-08 14:59:30 +01:00
|
|
|
return -1;
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VIR_DEBUG("Applying groups for %p", firewall);
|
|
|
|
for (i = 0; i < firewall->ngroups; i++) {
|
|
|
|
if (virFirewallApplyGroup(firewall, i) < 0) {
|
|
|
|
size_t first = i;
|
2018-12-06 12:33:39 -05:00
|
|
|
virErrorPtr saved_error;
|
|
|
|
|
2020-08-03 17:28:06 +02:00
|
|
|
VIR_DEBUG("Rolling back groups up to %zu for %p", i, firewall);
|
|
|
|
|
2018-12-06 12:33:39 -05:00
|
|
|
virErrorPreserveLast(&saved_error);
|
2013-03-04 16:30:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Look at any inheritance markers to figure out
|
|
|
|
* what the first rollback group we need to apply is
|
|
|
|
*/
|
|
|
|
for (j = 0; j < i; j++) {
|
|
|
|
VIR_DEBUG("Checking inheritance of group %zu", i - j);
|
|
|
|
if (firewall->groups[i - j]->rollbackFlags &
|
|
|
|
VIR_FIREWALL_ROLLBACK_INHERIT_PREVIOUS)
|
|
|
|
first = (i - j) - 1;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Now apply all rollback groups in order
|
|
|
|
*/
|
|
|
|
for (j = first; j <= i; j++) {
|
|
|
|
VIR_DEBUG("Rolling back group %zu", j);
|
|
|
|
virFirewallRollbackGroup(firewall, j);
|
|
|
|
}
|
|
|
|
|
2018-12-06 12:33:39 -05:00
|
|
|
virErrorRestore(&saved_error);
|
2013-03-04 16:30:40 +00:00
|
|
|
VIR_DEBUG("Done rolling back groups for %p", firewall);
|
2022-02-08 14:59:30 +01:00
|
|
|
return -1;
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
VIR_DEBUG("Done applying groups for %p", firewall);
|
|
|
|
|
2022-02-08 14:59:30 +01:00
|
|
|
return 0;
|
2013-03-04 16:30:40 +00:00
|
|
|
}
|