New ebtables module wrapper

* configure.in: look for ebtables binary location if present
* src/Makefile.am: add the new module
* src/util/ebtables.[ch]: new module and internal APIs around
  the ebtables binary
* src/libvirt_private.syms: export the symbols only internally
This commit is contained in:
Gerhard Stenzel 2009-11-03 23:11:01 +01:00 committed by Daniel Veillard
parent 104fdbf038
commit 1fc3816d0f
5 changed files with 520 additions and 0 deletions

View File

@ -287,6 +287,9 @@ fi
AC_PATH_PROG([IPTABLES_PATH], [iptables], /sbin/iptables, [/usr/sbin:$PATH])
AC_DEFINE_UNQUOTED([IPTABLES_PATH], "$IPTABLES_PATH", [path to iptables binary])
AC_PATH_PROG([EBTABLES_PATH], [ebtables], /sbin/ebtables, [/usr/sbin:$PATH])
AC_DEFINE_UNQUOTED([EBTABLES_PATH], "$EBTABLES_PATH", [path to ebtables binary])
if test "$with_openvz" = "yes"; then
AC_DEFINE_UNQUOTED([WITH_OPENVZ], 1, [whether OpenVZ driver is enabled])
fi

View File

@ -51,6 +51,7 @@ UTIL_SOURCES = \
util/event.c util/event.h \
util/hash.c util/hash.h \
util/iptables.c util/iptables.h \
util/ebtables.c util/ebtables.h \
util/logging.c util/logging.h \
util/memory.c util/memory.h \
util/pci.c util/pci.h \

View File

@ -174,6 +174,14 @@ virDomainEventDispatch;
virDomainEventQueueDispatch;
# ebtables.h
ebtablesAddForwardAllowIn;
ebtablesAddForwardPolicyReject;
ebtablesContextNew;
ebtablesRemoveForwardAllowIn;
ebtablesSaveRules;
# event.h
virEventAddHandle;
virEventAddTimeout;
@ -213,6 +221,7 @@ virInterfaceObjListFree;
# interface_driver.h
interfaceRegister;
# iptables.h
iptablesAddForwardAllowCross;
iptablesAddForwardAllowIn;

442
src/util/ebtables.c Normal file
View File

@ -0,0 +1,442 @@
/*
* Copyright (C) 2009 IBM Corp.
* Copyright (C) 2007-2009 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* based on iptables.c
* Authors:
* Gerhard Stenzel <gerhard.stenzel@de.ibm.com>
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#include "internal.h"
#include "ebtables.h"
#include "util.h"
#include "memory.h"
#include "virterror_internal.h"
#include "logging.h"
struct _ebtablesContext
{
ebtRules *input_filter;
ebtRules *forward_filter;
ebtRules *nat_postrouting;
};
enum {
ADD = 0,
REMOVE,
CREATE,
POLICY,
INSERT
};
static void
ebtRulesSave(ebtRules *rules)
{
(void) rules;
}
static void
ebtRuleFree(ebtRule *rule)
{
VIR_FREE(rule->rule);
if (rule->argv) {
int i = 0;
while (rule->argv[i])
VIR_FREE(rule->argv[i++]);
VIR_FREE(rule->argv);
}
}
static int
ebtRulesAppend(ebtRules *rules,
char *rule,
const char **argv,
int command_idx)
{
if (VIR_REALLOC_N(rules->rules, rules->nrules+1) < 0) {
int i = 0;
while (argv[i])
VIR_FREE(argv[i++]);
VIR_FREE(argv);
return ENOMEM;
}
rules->rules[rules->nrules].rule = rule;
rules->rules[rules->nrules].argv = argv;
rules->rules[rules->nrules].command_idx = command_idx;
rules->nrules++;
return 0;
}
static int
ebtRulesRemove(ebtRules *rules,
char *rule)
{
int i;
for (i = 0; i < rules->nrules; i++)
if (STREQ(rules->rules[i].rule, rule))
break;
if (i >= rules->nrules)
return EINVAL;
ebtRuleFree(&rules->rules[i]);
memmove(&rules->rules[i],
&rules->rules[i+1],
(rules->nrules - i - 1) * sizeof (ebtRule));
rules->nrules--;
return 0;
}
static void
ebtRulesFree(ebtRules *rules)
{
int i;
VIR_FREE(rules->table);
VIR_FREE(rules->chain);
if (rules->rules) {
for (i = 0; i < rules->nrules; i++)
ebtRuleFree(&rules->rules[i]);
VIR_FREE(rules->rules);
rules->nrules = 0;
}
VIR_FREE(rules);
}
static ebtRules *
ebtRulesNew(const char *table,
const char *chain)
{
ebtRules *rules;
if (VIR_ALLOC(rules) < 0)
return NULL;
if (!(rules->table = strdup(table)))
goto error;
if (!(rules->chain = strdup(chain)))
goto error;
rules->rules = NULL;
rules->nrules = 0;
return rules;
error:
ebtRulesFree(rules);
return NULL;
}
static int
ebtablesAddRemoveRule(ebtRules *rules, int action, const char *arg, ...)
{
va_list args;
int retval = ENOMEM;
const char **argv;
char *rule = NULL;
const char *s;
int n, command_idx;
n = 1 + /* /sbin/ebtables */
2 + /* --table foo */
2 + /* --insert bar */
1; /* arg */
va_start(args, arg);
while ((s = va_arg(args, const char *)))
n++;
va_end(args);
if (VIR_ALLOC_N(argv, n + 1) < 0)
goto error;
n = 0;
if (!(argv[n++] = strdup(EBTABLES_PATH)))
goto error;
command_idx = n;
if(action == ADD || action == REMOVE) {
if (!(argv[n++] = strdup("--insert")))
goto error;
if (!(argv[n++] = strdup(rules->chain)))
goto error;
}
if (!(argv[n++] = strdup(arg)))
goto error;
va_start(args, arg);
while ((s = va_arg(args, const char *)))
if (!(argv[n++] = strdup(s)))
goto error;
va_end(args);
if (!(rule = virArgvToString(&argv[command_idx])))
goto error;
if (action == REMOVE) {
VIR_FREE(argv[command_idx]);
if (!(argv[command_idx] = strdup("--delete")))
goto error;
}
if (virRun(NULL, argv, NULL) < 0) {
retval = errno;
goto error;
}
if (action == ADD || action == CREATE || action == POLICY ||
action == INSERT) {
retval = ebtRulesAppend(rules, rule, argv, command_idx);
rule = NULL;
argv = NULL;
} else {
retval = ebtRulesRemove(rules, rule);
}
error:
VIR_FREE(rule);
if (argv) {
n = 0;
while (argv[n])
VIR_FREE(argv[n++]);
VIR_FREE(argv);
}
return retval;
}
/**
* ebtablesContextNew:
*
* Create a new ebtable context
*
* Returns a pointer to the new structure or NULL in case of error
*/
ebtablesContext *
ebtablesContextNew(const char *driver)
{
ebtablesContext *ctx;
char chain[PATH_MAX];
if (VIR_ALLOC(ctx) < 0)
return NULL;
snprintf(chain, sizeof(chain), "libvirt_%s_INPUT", driver);
if (!(ctx->input_filter = ebtRulesNew("filter", chain)))
goto error;
snprintf(chain, sizeof(chain), "libvirt_%s_FORWARD", driver);
if (!(ctx->forward_filter = ebtRulesNew("filter", chain)))
goto error;
snprintf(chain, sizeof(chain), "libvirt_%s_POSTROUTING", driver);
if (!(ctx->nat_postrouting = ebtRulesNew("nat", chain)))
goto error;
return ctx;
error:
ebtablesContextFree(ctx);
return NULL;
}
/**
* ebtablesContextFree:
* @ctx: pointer to the EB table context
*
* Free the resources associated with an EB table context
*/
void
ebtablesContextFree(ebtablesContext *ctx)
{
if (ctx->input_filter)
ebtRulesFree(ctx->input_filter);
if (ctx->forward_filter)
ebtRulesFree(ctx->forward_filter);
if (ctx->nat_postrouting)
ebtRulesFree(ctx->nat_postrouting);
VIR_FREE(ctx);
}
/**
* ebtablesSaveRules:
* @ctx: pointer to the EB table context
*
* Saves all the EB table rules associated with a context
* to disk so that if ebtables is restarted, the rules
* will automatically be reload.
*/
void
ebtablesSaveRules(ebtablesContext *ctx)
{
ebtRulesSave(ctx->input_filter);
ebtRulesSave(ctx->forward_filter);
ebtRulesSave(ctx->nat_postrouting);
}
int
ebtablesAddForwardPolicyReject(ebtablesContext *ctx)
{
return ebtablesForwardPolicyReject(ctx, ADD);
}
int
ebtablesRemoveForwardPolicyReject(ebtablesContext *ctx)
{
return ebtablesForwardPolicyReject(ctx, REMOVE);
}
int
ebtablesForwardPolicyReject(ebtablesContext *ctx,
int action)
{
/* create it, if it does not exist */
if (action == ADD) {
ebtablesAddRemoveRule(ctx->forward_filter,
CREATE,
"--new-chain", ctx->forward_filter->chain, NULL,
NULL);
ebtablesAddRemoveRule(ctx->forward_filter,
INSERT,
"--insert", "FORWARD", "--jump",
ctx->forward_filter->chain, NULL);
}
return ebtablesAddRemoveRule(ctx->forward_filter,
POLICY,
"-P", ctx->forward_filter->chain, "DROP",
NULL);
}
/*
* 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)
{
return ebtablesAddRemoveRule(ctx->forward_filter,
action,
"--in-interface", iface,
"--source", macaddr,
"--jump", "ACCEPT",
NULL);
}
/**
* 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,
const unsigned char *mac)
{
char *macaddr;
if (virAsprintf(&macaddr,
"%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1],
mac[2], mac[3],
mac[4], mac[5]) < 0) {
return -1;
}
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,
const unsigned char *mac)
{
char *macaddr;
if (virAsprintf(&macaddr,
"%02x:%02x:%02x:%02x:%02x:%02x",
mac[0], mac[1],
mac[2], mac[3],
mac[4], mac[5]) < 0) {
return -1;
}
return ebtablesForwardAllowIn(ctx, iface, macaddr, REMOVE);
}

65
src/util/ebtables.h Normal file
View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2009 IBM Corp.
* Copyright (C) 2007, 2008 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* based on iptables.h
* Authors:
* Gerhard Stenzel <gerhard.stenzel@de.ibm.com>
*/
#ifndef __QEMUD_EBTABLES_H__
#define __QEMUD_EBTABLES_H__
typedef struct
{
char *rule;
const char **argv;
int command_idx;
} ebtRule;
typedef struct
{
char *table;
char *chain;
int nrules;
ebtRule *rules;
} ebtRules;
typedef struct _ebtablesContext ebtablesContext;
ebtablesContext *ebtablesContextNew (const char *driver);
void ebtablesContextFree (ebtablesContext *ctx);
void ebtablesSaveRules (ebtablesContext *ctx);
int ebtablesAddForwardAllowIn (ebtablesContext *ctx,
const char *iface,
const unsigned char *mac);
int ebtablesRemoveForwardAllowIn (ebtablesContext *ctx,
const char *iface,
const unsigned char *mac);
int ebtablesAddForwardPolicyReject(ebtablesContext *ctx);
int ebtablesRemoveForwardPolicyReject(ebtablesContext *ctx);
int ebtablesForwardPolicyReject(ebtablesContext *ctx,
int action);
#endif /* __QEMUD_ebtabLES_H__ */