This patch adds the files which implement the ebtables wrapper.
Signed-off-by: Gerhard Stenzel <gerhard.stenzel(a)de.ibm.com>
---
src/util/ebtables.c | 982 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/util/ebtables.h | 134 +++++++
2 files changed, 1116 insertions(+), 0 deletions(-)
create mode 100644 src/util/ebtables.c
create mode 100644 src/util/ebtables.h
diff --git a/src/util/ebtables.c b/src/util/ebtables.c
new file mode 100644
index 0000000..493b094
--- /dev/null
+++ b/src/util/ebtables.c
@@ -0,0 +1,982 @@
+/*
+ * 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(a)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"
+
+enum {
+ ADD = 0,
+ REMOVE,
+ CREATE,
+ POLICY,
+ INSERT
+};
+
+
+#ifdef ENABLE_EBTABLES_LOKKIT
+static void
+notifyRulesUpdated(const char *table,
+ const char *path)
+{
+ char arg[PATH_MAX];
+ const char *argv[4];
+
+ snprintf(arg, sizeof(arg), "--custom-rules=ipv4:%s:%s", table, path);
+
+ argv[0] = (char *) LOKKIT_PATH;
+ argv[1] = (char *) "--nostart";
+ argv[2] = arg;
+ argv[3] = NULL;
+
+ char ebuf[1024];
+ if (virRun(NULL, argv, NULL) < 0)
+ VIR_WARN(_("Failed to run '%s %s': %s"),
+ LOKKIT_PATH, arg, virStrerror(errno, ebuf, sizeof ebuf));
+}
+
+static int
+stripLine(char *str, int len, const char *line)
+{
+ char *s, *p;
+ int changed;
+
+ changed = 0;
+ s = str;
+
+ while ((p = strchr(s, '\n'))) {
+ if (p == s || STRNEQLEN(s, line, p - s)) {
+ s = ++p;
+ continue;
+ }
+
+ ++p;
+ memmove(s, p, len - (p - str) + 1);
+ len -= p - s;
+ changed = 1;
+ }
+
+ if (STREQ(s, line)) {
+ *s = '\0';
+ changed = 1;
+ }
+
+ return changed;
+}
+
+static void
+notifyRulesRemoved(const char *table,
+ const char *path)
+{
+/* 10 MB limit on config file size as a sanity check */
+#define MAX_FILE_LEN (1024*1024*10)
+
+ char arg[PATH_MAX];
+ char *content;
+ int len;
+ FILE *f = NULL;
+
+ len = virFileReadAll(SYSCONF_DIR "/sysconfig/system-config-firewall",
+ MAX_FILE_LEN, &content);
+ if (len < 0) {
+ VIR_WARN("%s", _("Failed to read " SYSCONF_DIR
+ "/sysconfig/system-config-firewall"));
+ return;
+ }
+
+ snprintf(arg, sizeof(arg), "--custom-rules=ipv4:%s:%s", table, path);
+
+ if (!stripLine(content, len, arg)) {
+ VIR_FREE(content);
+ return;
+ }
+
+ if (!(f = fopen(SYSCONF_DIR "/sysconfig/system-config-firewall",
"w")))
+ goto write_error;
+
+ if (fputs(content, f) == EOF)
+ goto write_error;
+
+ if (fclose(f) == EOF) {
+ f = NULL;
+ goto write_error;
+ }
+
+ VIR_FREE(content);
+
+ return;
+
+ write_error:;
+ char ebuf[1024];
+ VIR_WARN(_("Failed to write to " SYSCONF_DIR
+ "/sysconfig/system-config-firewall : %s"),
+ virStrerror(errno, ebuf, sizeof ebuf));
+ if (f)
+ fclose(f);
+ VIR_FREE(content);
+
+#undef MAX_FILE_LEN
+}
+
+static int
+writeRules(const char *path,
+ const ebtRule *rules,
+ int nrules)
+{
+ char tmp[PATH_MAX];
+ FILE *f;
+ int istmp;
+ int i;
+
+ if (nrules == 0 && unlink(path) == 0)
+ return 0;
+
+ if (snprintf(tmp, PATH_MAX, "%s.new", path) >= PATH_MAX)
+ return EINVAL;
+
+ istmp = 1;
+
+ if (!(f = fopen(tmp, "w"))) {
+ istmp = 0;
+ if (!(f = fopen(path, "w")))
+ return errno;
+ }
+
+ for (i = 0; i < nrules; i++) {
+ if (fputs(rules[i].rule, f) == EOF ||
+ fputc('\n', f) == EOF) {
+ fclose(f);
+ if (istmp)
+ unlink(tmp);
+ return errno;
+ }
+ }
+
+ fclose(f);
+
+ if (istmp && rename(tmp, path) < 0) {
+ unlink(tmp);
+ return errno;
+ }
+
+ if (istmp)
+ unlink(tmp);
+
+ return 0;
+}
+#endif /* ENABLE_EBTABLES_LOKKIT */
+
+static void
+ebtRulesSave(ebtRules *rules)
+{
+#ifdef ENABLE_EBTABLES_LOKKIT
+ int err;
+
+ char ebuf[1024];
+ if ((err = virFileMakePath(rules->dir))) {
+ VIR_WARN(_("Failed to create directory %s : %s"),
+ rules->dir, virStrerror(err, ebuf, sizeof ebuf));
+ return;
+ }
+
+ if ((err = writeRules(rules->path, rules->rules, rules->nrules))) {
+ VIR_WARN(_("Failed to saves ebtables rules to %s : %s"),
+ rules->path, virStrerror(err, ebuf, sizeof ebuf));
+ return;
+ }
+
+ if (rules->nrules > 0)
+ notifyRulesUpdated(rules->table, rules->path);
+ else
+ notifyRulesRemoved(rules->table, rules->path);
+#else
+ (void) rules;
+#endif /* ENABLE_EBTABLES_LOKKIT */
+}
+
+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;
+ }
+
+#ifdef ENABLE_EBTABLES_LOKKIT
+ rules->dir[0] = '\0';
+ rules->path[0] = '\0';
+#endif /* ENABLE_EBTABLES_LOKKIT */
+
+ 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;
+
+#ifdef ENABLE_EBTABLES_LOKKIT
+ if (virFileBuildPath(LOCAL_STATE_DIR "/lib/libvirt/ebtables", table, NULL,
+ rules->dir, sizeof(rules->dir)) < 0)
+ goto error;
+
+ if (virFileBuildPath(rules->dir, chain, ".chain", rules->path,
sizeof(rules->path)) < 0)
+ goto error;
+#endif /* ENABLE_EBTABLES_LOKKIT */
+
+ 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;
+
+/*
+ if (!(argv[n++] = strdup("--table")))
+ goto error;
+
+ if (!(argv[n++] = strdup(rules->table)))
+ 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 IP table context
+ *
+ * Free the resources associated with an IP 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 IP table context
+ *
+ * Saves all the IP 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);
+}
+
+static void
+ebtRulesReload(ebtRules *rules)
+{
+ int i;
+ char ebuf[1024];
+
+ for (i = 0; i < rules->nrules; i++) {
+ ebtRule *rule = &rules->rules[i];
+ const char *orig;
+
+ orig = rule->argv[rule->command_idx];
+ rule->argv[rule->command_idx] = (char *) "--delete";
+
+ if (virRun(NULL, rule->argv, NULL) < 0)
+ VIR_WARN(_("Failed to remove ebtables rule '%s'"
+ " from chain '%s' in table '%s': %s"),
+ rule->rule, rules->chain, rules->table,
+ virStrerror(errno, ebuf, sizeof ebuf));
+
+ rule->argv[rule->command_idx] = orig;
+ }
+
+ for (i = 0; i < rules->nrules; i++)
+ if (virRun(NULL, rules->rules[i].argv, NULL) < 0)
+ VIR_WARN(_("Failed to add ebtables rule '%s'"
+ " to chain '%s' in table '%s': %s"),
+ rules->rules[i].rule, rules->chain, rules->table,
+ virStrerror(errno, ebuf, sizeof ebuf));
+}
+
+/**
+ * ebtablesReloadRules:
+ * @ctx: pointer to the IP table context
+ *
+ * Reloads all the IP table rules associated to a context
+ */
+void
+ebtablesReloadRules(ebtablesContext *ctx)
+{
+ ebtRulesReload(ctx->input_filter);
+ ebtRulesReload(ctx->forward_filter);
+ ebtRulesReload(ctx->nat_postrouting);
+}
+
+/*
+static int
+ebtablesInput(ebtablesContext *ctx,
+ const char *iface,
+ int port,
+ int action,
+ int tcp)
+{
+ char portstr[32];
+
+ snprintf(portstr, sizeof(portstr), "%d", port);
+ portstr[sizeof(portstr) - 1] = '\0';
+
+ return ebtablesAddRemoveRule(ctx->input_filter,
+ action,
+ "--in-interface", iface,
+ "--protocol", tcp ? "tcp" :
"udp",
+ "--destination-port", portstr,
+ "--jump", "ACCEPT",
+ NULL);
+}
+*/
+/* Allow all traffic coming from the bridge, with a valid network address
+ * to proceed to WAN
+ */
+static int
+ebtablesForwardAllowOut(ebtablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev,
+ int action)
+{
+ if (physdev && physdev[0]) {
+ return ebtablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--source", network,
+ "--in-interface", iface,
+ "--out-interface", physdev,
+ "--jump", "ACCEPT",
+ NULL);
+ } else {
+ return ebtablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--source", network,
+ "--in-interface", iface,
+ "--jump", "ACCEPT",
+ NULL);
+ }
+}
+
+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);
+}
+
+/**
+ * ebtablesAddForwardAllowOut:
+ * @ctx: pointer to the IP table context
+ * @network: the source network name
+ * @iface: the source interface name
+ * @physdev: the physical output device
+ *
+ * Add a rule to the IP table context to allow the traffic for the
+ * network @network via interface @iface to be forwarded to
+ * @physdev device. This allow the outbound traffic on a bridge.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+ebtablesAddForwardAllowOut(ebtablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev)
+{
+ return ebtablesForwardAllowOut(ctx, network, iface, physdev, ADD);
+}
+
+/**
+ * ebtablesRemoveForwardAllowOut:
+ * @ctx: pointer to the IP table context
+ * @network: the source network name
+ * @iface: the source interface name
+ * @physdev: the physical output device
+ *
+ * Remove a rule from the IP table context hence forbidding forwarding
+ * of the traffic for the network @network via interface @iface
+ * to the @physdev device output. This stops the outbound traffic on a bridge.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+ebtablesRemoveForwardAllowOut(ebtablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev)
+{
+ return ebtablesForwardAllowOut(ctx, network, iface, physdev, REMOVE);
+}
+
+
+/* Allow all traffic destined to the bridge, with a valid network address
+ * and associated with an existing connection
+ */
+static int
+ebtablesForwardAllowRelatedIn(ebtablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev,
+ int action)
+{
+ if (physdev && physdev[0]) {
+ return ebtablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--destination", network,
+ "--in-interface", physdev,
+ "--out-interface", iface,
+ "--match", "state",
+ "--state",
"ESTABLISHED,RELATED",
+ "--jump", "ACCEPT",
+ NULL);
+ } else {
+ return ebtablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--destination", network,
+ "--out-interface", iface,
+ "--match", "state",
+ "--state",
"ESTABLISHED,RELATED",
+ "--jump", "ACCEPT",
+ NULL);
+ }
+}
+
+/**
+ * ebtablesAddForwardAllowRelatedIn:
+ * @ctx: pointer to the IP table context
+ * @network: the source network name
+ * @iface: the output interface name
+ * @physdev: the physical input device or NULL
+ *
+ * Add rules to the IP table context to allow the traffic for the
+ * network @network on @physdev device to be forwarded to
+ * interface @iface, if it is part of an existing connection.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+ebtablesAddForwardAllowRelatedIn(ebtablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev)
+{
+ return ebtablesForwardAllowRelatedIn(ctx, network, iface, physdev, ADD);
+}
+
+/**
+ * ebtablesRemoveForwardAllowRelatedIn:
+ * @ctx: pointer to the IP table context
+ * @network: the source network name
+ * @iface: the output interface name
+ * @physdev: the physical input device or NULL
+ *
+ * Remove rules from the IP table context hence forbidding the traffic for
+ * network @network on @physdev device to be forwarded to
+ * interface @iface, if it is part of an existing connection.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+ebtablesRemoveForwardAllowRelatedIn(ebtablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev)
+{
+ return ebtablesForwardAllowRelatedIn(ctx, network, iface, physdev, REMOVE);
+}
+
+/* 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,
+/* "--destination", network,*/
+/* "--insert", "FORWARD",*/
+ "--in-interface", iface,
+/* "--out-interface", network, */
+ "--source", macaddr,
+ "--jump", "ACCEPT",
+ NULL);
+}
+
+/**
+ * ebtablesAddForwardAllowIn:
+ * @ctx: pointer to the IP table context
+ * @network: the source network name
+ * @iface: the output interface name
+ * @physdev: the physical input device or NULL
+ *
+ * Add rules to the IP table context to allow the traffic for the
+ * network @network on @physdev device to be forwarded to
+ * interface @iface. This allow 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 char *physdev)
+{
+ return ebtablesForwardAllowIn(ctx, iface, physdev, ADD);
+}
+
+/**
+ * ebtablesRemoveForwardAllowIn:
+ * @ctx: pointer to the IP table context
+ * @network: the source network name
+ * @iface: the output interface name
+ * @physdev: the physical input device or NULL
+ *
+ * Remove rules from the IP table context hence forbidding the traffic for
+ * network @network on @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 char *physdev)
+{
+ return ebtablesForwardAllowIn(ctx, iface, physdev, REMOVE);
+}
+
+
+/* Allow all traffic between guests on the same bridge,
+ * with a valid network address
+ */
+static int
+ebtablesForwardAllowCross(ebtablesContext *ctx,
+ const char *iface,
+ int action)
+{
+ return ebtablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--in-interface", iface,
+ "--out-interface", iface,
+ "--jump", "ACCEPT",
+ NULL);
+}
+
+/**
+ * ebtablesAddForwardAllowCross:
+ * @ctx: pointer to the IP table context
+ * @iface: the input/output interface name
+ *
+ * Add rules to the IP table context to allow traffic to cross that
+ * interface. It allows all traffic between guests on the same bridge
+ * represented by that interface.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+ebtablesAddForwardAllowCross(ebtablesContext *ctx,
+ const char *iface) {
+ return ebtablesForwardAllowCross(ctx, iface, ADD);
+}
+
+/**
+ * ebtablesRemoveForwardAllowCross:
+ * @ctx: pointer to the IP table context
+ * @iface: the input/output interface name
+ *
+ * Remove rules to the IP table context to block traffic to cross that
+ * interface. It forbids traffic between guests on the same bridge
+ * represented by that interface.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+ebtablesRemoveForwardAllowCross(ebtablesContext *ctx,
+ const char *iface) {
+ return ebtablesForwardAllowCross(ctx, iface, REMOVE);
+}
+
+
+/* Drop all traffic trying to forward from the bridge.
+ * ie the bridge is the in interface
+ */
+static int
+ebtablesForwardRejectOut(ebtablesContext *ctx,
+ const char *iface,
+ int action)
+{
+ return ebtablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--in-interface", iface,
+ "--jump", "DROP",
+ NULL);
+}
+
+/**
+ * ebtablesAddForwardRejectOut:
+ * @ctx: pointer to the EB table context
+ * @iface: the output interface name
+ *
+ * Add rules to the EB table context to forbid all traffic to that
+ * interface. It forbids forwarding from the bridge to that interface.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+ebtablesAddForwardRejectOut(ebtablesContext *ctx,
+ const char *iface)
+{
+ return ebtablesForwardRejectOut(ctx, iface, ADD);
+}
+
+/**
+ * ebtablesRemoveForwardRejectOut:
+ * @ctx: pointer to the EB table context
+ * @iface: the output interface name
+ *
+ * Remove rules from the EB table context forbidding all traffic to that
+ * interface. It reallow forwarding from the bridge to that interface.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+ebtablesRemoveForwardRejectOut(ebtablesContext *ctx,
+ const char *iface)
+{
+ return ebtablesForwardRejectOut(ctx, iface, REMOVE);
+}
+
+
+
+
+/* Drop all traffic trying to forward to the bridge.
+ * ie the bridge is the out interface
+ */
+static int
+ebtablesForwardRejectIn(ebtablesContext *ctx,
+ const char *iface,
+ int action)
+{
+ return ebtablesAddRemoveRule(ctx->forward_filter,
+ action,
+ "--out-interface", iface,
+ "--jump", "DROP",
+ NULL);
+}
+
+/**
+ * ebtablesAddForwardRejectIn:
+ * @ctx: pointer to the IP table context
+ * @iface: the input interface name
+ *
+ * Add rules to the IP table context to forbid all traffic from that
+ * interface. It forbids forwarding from that interface to the bridge.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+ebtablesAddForwardRejectIn(ebtablesContext *ctx,
+ const char *iface)
+{
+ return ebtablesForwardRejectIn(ctx, iface, ADD);
+}
+
+/**
+ * ebtablesRemoveForwardRejectIn:
+ * @ctx: pointer to the IP table context
+ * @iface: the input interface name
+ *
+ * Remove rules from the IP table context forbidding all traffic from that
+ * interface. It allows forwarding from that interface to the bridge.
+ *
+ * Returns 0 in case of success or an error code otherwise
+ */
+int
+ebtablesRemoveForwardRejectIn(ebtablesContext *ctx,
+ const char *iface)
+{
+ return ebtablesForwardRejectIn(ctx, iface, REMOVE);
+}
diff --git a/src/util/ebtables.h b/src/util/ebtables.h
new file mode 100644
index 0000000..a3f403a
--- /dev/null
+++ b/src/util/ebtables.h
@@ -0,0 +1,134 @@
+/*
+ * 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(a)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;
+
+#ifdef ENABLE_EBTABLES_LOKKIT
+
+ char dir[PATH_MAX];
+ char path[PATH_MAX];
+
+#endif /* ENABLE_EBTABLES_LOKKIT */
+
+} ebtRules;
+
+struct _ebtablesContext
+{
+ ebtRules *input_filter;
+ ebtRules *forward_filter;
+ ebtRules *nat_postrouting;
+};
+
+typedef struct _ebtablesContext ebtablesContext;
+
+ebtablesContext *ebtablesContextNew (const char *driver);
+void ebtablesContextFree (ebtablesContext *ctx);
+
+void ebtablesSaveRules (ebtablesContext *ctx);
+void ebtablesReloadRules (ebtablesContext *ctx);
+
+int ebtablesAddTcpInput (ebtablesContext *ctx,
+ const char *iface,
+ int port);
+int ebtablesRemoveTcpInput (ebtablesContext *ctx,
+ const char *iface,
+ int port);
+
+int ebtablesAddUdpInput (ebtablesContext *ctx,
+ const char *iface,
+ int port);
+int ebtablesRemoveUdpInput (ebtablesContext *ctx,
+ const char *iface,
+ int port);
+
+int ebtablesAddForwardAllowOut (ebtablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev);
+int ebtablesRemoveForwardAllowOut (ebtablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev);
+
+int ebtablesAddForwardAllowRelatedIn(ebtablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev);
+int ebtablesRemoveForwardAllowRelatedIn(ebtablesContext *ctx,
+ const char *network,
+ const char *iface,
+ const char *physdev);
+
+int ebtablesAddForwardAllowIn (ebtablesContext *ctx,
+ const char *iface,
+ const char *physdev);
+int ebtablesRemoveForwardAllowIn (ebtablesContext *ctx,
+ const char *iface,
+ const char *physdev);
+
+int ebtablesAddForwardAllowCross (ebtablesContext *ctx,
+ const char *iface);
+int ebtablesRemoveForwardAllowCross (ebtablesContext *ctx,
+ const char *iface);
+
+int ebtablesAddForwardRejectOut (ebtablesContext *ctx,
+ const char *iface);
+int ebtablesRemoveForwardRejectOut (ebtablesContext *ctx,
+ const char *iface);
+
+int ebtablesAddForwardRejectIn (ebtablesContext *ctx,
+ const char *iface);
+int ebtablesRemoveForwardRejectIn (ebtablesContext *ctx,
+ const char *iface);
+
+int ebtablesAddForwardMasquerade (ebtablesContext *ctx,
+ const char *network,
+ const char *physdev);
+int ebtablesRemoveForwardMasquerade (ebtablesContext *ctx,
+ const char *network,
+ const char *physdev);
+
+int ebtablesAddForwardPolicyReject(ebtablesContext *ctx);
+
+int ebtablesRemoveForwardPolicyReject(ebtablesContext *ctx);
+
+int ebtablesForwardPolicyReject(ebtablesContext *ctx,
+ int action);
+
+#endif /* __QEMUD_ebtabLES_H__ */