For each network we need the following iptables rules: 1) Allow frames to be forwarded from the bridge interface to other bridge ports: -I FORWARD -m physdev --physdev-in $(iface) -j ACCEPT 2) Allow IP packets from the bridge interface to be forwarded to other network interfaces: -I FORWARD -i $(iface) -j ACCEPT 3) Masquerade any outgoing packets, with the exception of those frames which are just being forwarded across a bridge: -t nat -I POSTROUTING -m physdev ! --physdev-is-bridged -j MASQUERADE 4) Allow IP packets be forwarded to the bridge interface from other network interfaces if they are part of an established connection: -I FORWARD -o $(iface) --match state --state ESTABLISHED,RELATED -j ACCEPT 5) Allow DHCP and DNS requests in from the bridge interface so that dnsmasq can handle them: -I INPUT -i vnet0 -p tcp --dport 67 -j ACCEPT -I INPUT -i vnet0 -p tcp --dport 53 -j ACCEPT -I INPUT -i vnet0 -p udp --dport 53 -j ACCEPT Of course, we also need to enable IP forwarding via /proc/sys/net/ipv4/ip_forward Also, for every TAP interface we enslave to a network's bridge, we must allow frames to be forwarded from that interface to other bridge ports as in (1). Note, all this has a fatal flaw - it does not attempt to integrate with any system tool which may be managing iptables rules. So, on Fedora, if you run "service iptables restart" all the rules added by qemud would be wiped out. For this reason we add two configure options --with-iptables-prefix and --with-iptables-dir so that we create our rules in a chains with the given prefix and save the rules in a file for each chain in the given directory. This would allow us to integrate in a scheme like the one proposed here: https://bugzilla.redhat.com/227011 Signed-off-by: Mark McLoughlin Index: libvirt-foo/qemud/Makefile.am =================================================================== --- libvirt-foo.orig/qemud/Makefile.am 2007-02-14 15:59:34.000000000 +0000 +++ libvirt-foo.orig/qemud/Makefile.am 2007-02-14 15:59:34.000000000 +0000 @@ -8,7 +8,8 @@ libvirt_qemud_SOURCES = qemud.c internal driver.c driver.h \ dispatch.c dispatch.h \ conf.c conf.h \ - bridge.c bridge.h + bridge.c bridge.h \ + iptables.c iptables.h #-D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_POSIX_C_SOURCE=199506L libvirt_qemud_CFLAGS = \ -I$(top_srcdir)/include -I$(top_builddir)/include $(LIBXML_CFLAGS) \ Index: libvirt-foo/qemud/qemud.c =================================================================== --- libvirt-foo.orig/qemud/qemud.c 2007-02-14 16:05:37.000000000 +0000 +++ libvirt-foo.orig/qemud/qemud.c 2007-02-14 16:05:37.000000000 +0000 @@ -50,6 +50,7 @@ #include "dispatch.h" #include "driver.h" #include "conf.h" +#include "iptables.h" static void reapchild(int sig ATTRIBUTE_UNUSED) { /* We explicitly waitpid the child later */ @@ -659,11 +660,10 @@ static int qemudVMData(struct qemud_serv } static void -qemudNetworkIfaceDisconnect(struct qemud_server *server ATTRIBUTE_UNUSED, +qemudNetworkIfaceDisconnect(struct qemud_server *server, struct qemud_vm *vm ATTRIBUTE_UNUSED, struct qemud_vm_net_def *net) { - /* FIXME: will be needed to remove iptables rules */ - net = NULL; + iptablesRemovePhysdevForward(server->iptables, net->dst.network.tapifname); } int qemudShutdownVMDaemon(struct qemud_server *server, struct qemud_vm *vm) { @@ -845,6 +845,129 @@ dhcpStartDhcpDaemon(struct qemud_server return ret; } +static int +qemudAddIptablesRules(struct qemud_server *server, + struct qemud_network *network) { + int err; + + if (!server->iptables && !(server->iptables = iptablesContextNew())) { + qemudReportError(server, VIR_ERR_NO_MEMORY, "iptables support"); + return 1; + } + + /* allow bridging from the bridge interface itself */ + if ((err = iptablesAddPhysdevForward(server->iptables, network->bridge))) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "failed to add iptables rule to allow bridging from '%s' : %s\n", + network->bridge, strerror(err)); + goto err1; + } + + /* allow forwarding packets from the bridge interface */ + if ((err = iptablesAddInterfaceForward(server->iptables, network->bridge))) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "failed to add iptables rule to allow forwarding from '%s' : %s\n", + network->bridge, strerror(err)); + goto err2; + } + + /* allow forwarding packets to the bridge interface if they are part of an existing connection */ + if ((err = iptablesAddStateForward(server->iptables, network->bridge))) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "failed to add iptables rule to allow forwarding to '%s' : %s\n", + network->bridge, strerror(err)); + goto err3; + } + + /* enable masquerading */ + if ((err = iptablesAddNonBridgedMasq(server->iptables))) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "failed to add iptables rule to enable masquerading : %s\n", + strerror(err)); + goto err4; + } + + /* allow DHCP requests through to dnsmasq */ + if ((err = iptablesAddTcpInput(server->iptables, network->bridge, 67))) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "failed to add iptables rule to allow DHCP requests from '%s' : %s\n", + network->bridge, strerror(err)); + goto err5; + } + + if ((err = iptablesAddUdpInput(server->iptables, network->bridge, 67))) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "failed to add iptables rule to allow DHCP requests from '%s' : %s\n", + network->bridge, strerror(err)); + goto err6; + } + + /* allow DNS requests through to dnsmasq */ + if ((err = iptablesAddTcpInput(server->iptables, network->bridge, 53))) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "failed to add iptables rule to allow DNS requests from '%s' : %s\n", + network->bridge, strerror(err)); + goto err7; + } + + if ((err = iptablesAddUdpInput(server->iptables, network->bridge, 53))) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "failed to add iptables rule to allow DNS requests from '%s' : %s\n", + network->bridge, strerror(err)); + goto err8; + } + + return 1; + + err8: + iptablesRemoveTcpInput(server->iptables, network->bridge, 53); + err7: + iptablesRemoveUdpInput(server->iptables, network->bridge, 67); + err6: + iptablesRemoveTcpInput(server->iptables, network->bridge, 67); + err5: + iptablesRemoveNonBridgedMasq(server->iptables); + err4: + iptablesRemoveStateForward(server->iptables, network->bridge); + err3: + iptablesRemoveInterfaceForward(server->iptables, network->bridge); + err2: + iptablesRemovePhysdevForward(server->iptables, network->bridge); + err1: + return 0; +} + +static void +qemudRemoveIptablesRules(struct qemud_server *server, + struct qemud_network *network) { + iptablesRemoveUdpInput(server->iptables, network->bridge, 53); + iptablesRemoveTcpInput(server->iptables, network->bridge, 53); + iptablesRemoveUdpInput(server->iptables, network->bridge, 67); + iptablesRemoveTcpInput(server->iptables, network->bridge, 67); + iptablesRemoveNonBridgedMasq(server->iptables); + iptablesRemoveStateForward(server->iptables, network->bridge); + iptablesRemoveInterfaceForward(server->iptables, network->bridge); + iptablesRemovePhysdevForward(server->iptables, network->bridge); +} + +static int +qemudEnableIpForwarding(void) +{ +#define PROC_IP_FORWARD "/proc/sys/net/ipv4/ip_forward" + + int fd; + + if ((fd = open(PROC_IP_FORWARD, O_WRONLY|O_TRUNC)) == -1 || + write(fd, "1\n", 2) < 0) + return 0; + + close (fd); + + return 1; + +#undef PROC_IP_FORWARD +} + int qemudStartNetworkDaemon(struct qemud_server *server, struct qemud_network *network) { const char *name; @@ -899,14 +1022,26 @@ int qemudStartNetworkDaemon(struct qemud goto err_delbr; } + if (!qemudAddIptablesRules(server, network)) + goto err_delbr1; + + if (!qemudEnableIpForwarding()) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "failed to enable IP forwarding : %s\n", strerror(err)); + goto err_delbr2; + } + if (network->def.ranges && dhcpStartDhcpDaemon(server, network) < 0) - goto err_delbr1; + goto err_delbr2; network->active = 1; return 0; + err_delbr2: + qemudRemoveIptablesRules(server, network); + err_delbr1: if (network->def.ipAddress[0] && (err = brSetInterfaceUp(server->brctl, network->bridge, 0))) { @@ -935,6 +1070,8 @@ int qemudShutdownNetworkDaemon(struct qe if (network->dnsmasqPid > 0) kill(network->dnsmasqPid, SIGTERM); + qemudRemoveIptablesRules(server, network); + if (network->def.ipAddress[0] && (err = brSetInterfaceUp(server->brctl, network->bridge, 0))) { printf("Damn! Failed to bring down bridge '%s' : %s\n", @@ -1182,6 +1319,8 @@ static void qemudCleanup(struct qemud_se } if (server->brctl) brShutdown(server->brctl); + if (server->iptables) + iptablesContextFree(server->iptables); free(server); } Index: libvirt-foo/qemud/conf.c =================================================================== --- libvirt-foo.orig/qemud/conf.c 2007-02-14 16:05:37.000000000 +0000 +++ libvirt-foo.orig/qemud/conf.c 2007-02-14 16:05:37.000000000 +0000 @@ -43,6 +43,7 @@ #include "internal.h" #include "conf.h" #include "driver.h" +#include "iptables.h" static int qemudParseUUID(const char *uuid, unsigned char *rawuuid) { @@ -860,6 +861,13 @@ qemudNetworkIfaceConnect(struct qemud_se goto error; } + if ((err = iptablesAddPhysdevForward(server->iptables, net->dst.network.tapifname))) { + qemudReportError(server, VIR_ERR_INTERNAL_ERROR, + "Failed to add iptables rule to allow bridging from '%s' :%s", + net->dst.network.tapifname, strerror(err)); + goto error; + } + snprintf(tapfdstr, sizeof(tapfdstr), "tap,fd=%d,script=", tapfd); if (!(retval = strdup(tapfdstr))) @@ -875,6 +883,7 @@ qemudNetworkIfaceConnect(struct qemud_se return retval; no_memory: + iptablesRemovePhysdevForward(server->iptables, net->dst.network.tapifname); qemudReportError(server, VIR_ERR_NO_MEMORY, "tapfds"); error: if (retval) Index: libvirt-foo/qemud/iptables.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -0,0 +1,699 @@ +/* + * Copyright (C) 2007 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 + * + * Authors: + * Mark McLoughlin + */ + +#include + +#include "iptables.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + ADD = 0, + REMOVE +}; + +enum { + WITH_ERRORS = 0, + NO_ERRORS +}; + +typedef struct +{ + char *table; + char *chain; + +#ifdef IPTABLES_DIR + + char dir[PATH_MAX]; + char path[PATH_MAX]; + + int nrules; + char **rules; + +#endif /* IPTABLES_DIR */ + +} iptRules; + +struct _iptablesContext +{ + iptRules *input_filter; + iptRules *forward_filter; + iptRules *nat_postrouting; +}; + +#ifdef IPTABLES_DIR +static int +writeRules(const char *path, + char * const *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], 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; +} + +static int +ensureDir(const char *path) +{ + struct stat st; + char parent[PATH_MAX]; + char *p; + int err; + + if (stat(path, &st) >= 0) + return 0; + + strncpy(parent, path, PATH_MAX); + parent[PATH_MAX - 1] = '\0'; + + if (!(p = strrchr(parent, '/'))) + return EINVAL; + + if (p == parent) + return EPERM; + + *p = '\0'; + + if ((err = ensureDir(parent))) + return err; + + if (mkdir(path, 0700) < 0 && errno != EEXIST) + return errno; + + return 0; +} + +static int +buildDir(const char *table, + char *path, + int maxlen) +{ + if (snprintf(path, maxlen, IPTABLES_DIR "/%s", table) >= maxlen) + return EINVAL; + else + return 0; +} + +static int +buildPath(const char *table, + const char *chain, + char *path, + int maxlen) +{ + if (snprintf(path, maxlen, IPTABLES_DIR "/%s/%s.chain", table, chain) >= maxlen) + return EINVAL; + else + return 0; +} + +static int +iptRulesAppend(iptRules *rules, + const char *rule) +{ + char **r; + int err; + + if (!(r = (char **)realloc(rules->rules, sizeof(char *) * (rules->nrules+1)))) + return ENOMEM; + + rules->rules = r; + + if (!(rules->rules[rules->nrules] = strdup(rule))) + return ENOMEM; + + rules->nrules++; + + if ((err = ensureDir(rules->dir))) + return err; + + if ((err = writeRules(rules->path, rules->rules, rules->nrules))) + return err; + + return 0; +} + +static int +iptRulesRemove(iptRules *rules, + const char *rule) +{ + int i; + int err; + + for (i = 0; i < rules->nrules; i++) + if (!strcmp(rules->rules[i], rule)) + break; + + if (i >= rules->nrules) + return EINVAL; + + free(rules->rules[i]); + + memmove(&rules->rules[i], + &rules->rules[i+1], + (rules->nrules - i - 1) * sizeof (char *)); + + rules->nrules--; + + if ((err = writeRules(rules->path, rules->rules, rules->nrules))) + return err; + + return 0; +} +#endif /* IPTABLES_DIR */ + +static void +iptRulesFree(iptRules *rules) +{ + if (rules->table) { + free(rules->chain); + rules->chain = NULL; + } + + if (rules->chain) { + free(rules->chain); + rules->chain = NULL; + } + +#ifdef IPTABLES_DIR + { + int i; + + rules->dir[0] = '\0'; + rules->path[0] = '\0'; + + for (i = 0; i < rules->nrules; i++) { + free(rules->rules[i]); + rules->rules[i] = NULL; + } + + rules->nrules = 0; + + if (rules->rules) { + free(rules->rules); + rules->rules = NULL; + } + } +#endif /* IPTABLES_DIR */ + + free(rules); +} + +static iptRules * +iptRulesNew(const char *table, + const char *chain) +{ + iptRules *rules; + + if (!(rules = (iptRules *)malloc(sizeof (iptRules)))) + return NULL; + + memset (rules, 0, sizeof (iptRules)); + + if (!(rules->table = strdup(table))) + goto error; + + if (!(rules->chain = strdup(chain))) + goto error; + +#ifdef IPTABLES_DIR + if (buildDir(table, rules->dir, sizeof(rules->dir))) + goto error; + + if (buildPath(table, chain, rules->path, sizeof(rules->path))) + goto error; + + rules->rules = NULL; + rules->nrules = 0; +#endif /* IPTABLES_DIR */ + + return rules; + + error: + iptRulesFree(rules); + return NULL; +} + +static int +iptablesSpawn(int errors, char * const *argv) +{ + pid_t pid, ret; + int status; + int null = -1; + + if (errors == NO_ERRORS && (null = open(_PATH_DEVNULL, O_RDONLY)) < 0) + return errno; + + pid = fork(); + if (pid == -1) { + if (errors == NO_ERRORS) + close(null); + return errno; + } + + if (pid == 0) { /* child */ + int i, open_max = sysconf(_SC_OPEN_MAX); + + for (i = 0; i < open_max; i++) { + if (i != STDOUT_FILENO && + i != STDERR_FILENO && + i != STDIN_FILENO) + close(i); + else if (errors == NO_ERRORS) + dup2(null, i); + } + + execvp(argv[0], argv); + + _exit (1); + } + + if (errors == NO_ERRORS) + close(null); + + while ((ret = waitpid(pid, &status, 0) == -1) && errno == EINTR); + if (ret == -1) + return errno; + + if (errors == NO_ERRORS) + return 0; + else + return (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? 0 : EINVAL; +} + +static int +iptablesAddRemoveChain(iptRules *rules, int action) +{ + char **argv; + int retval = ENOMEM; + int n; + + n = 1 + /* /sbin/iptables */ + 2 + /* --table foo */ + 2; /* --new-chain bar */ + + if (!(argv = (char **)malloc(sizeof(char *) * (n+1)))) + goto error; + + memset(argv, 0, sizeof(char *) * (n + 1)); + + n = 0; + + if (!(argv[n++] = strdup(IPTABLES_PATH))) + goto error; + + if (!(argv[n++] = strdup("--table"))) + goto error; + + if (!(argv[n++] = strdup(rules->table))) + goto error; + + if (!(argv[n++] = strdup(action == ADD ? "--new-chain" : "--delete-chain"))) + goto error; + + if (!(argv[n++] = strdup(rules->chain))) + goto error; + + retval = iptablesSpawn(NO_ERRORS, argv); + + error: + if (argv) { + n = 0; + while (argv[n]) + free(argv[n++]); + free(argv); + } + + return retval; +} + +static int +iptablesAddRemoveRule(iptRules *rules, int action, const char *arg, ...) +{ + va_list args; + int retval = ENOMEM; + char **argv; + char *rule = NULL, *p; + const char *s; + int n, rulelen; + + n = 1 + /* /sbin/iptables */ + 2 + /* --table foo */ + 2 + /* --insert bar */ + 1; /* arg */ + + rulelen = strlen(arg) + 1; + + va_start(args, arg); + while ((s = va_arg(args, const char *))) { + n++; + rulelen += strlen(s) + 1; + } + + va_end(args); + + if (!(argv = (char **)malloc(sizeof(char *) * (n + 1)))) + goto error; + + if (!(rule = (char *)malloc(rulelen))) + goto error; + + memset(argv, 0, sizeof(char *) * (n + 1)); + + n = 0; + + if (!(argv[n++] = strdup(IPTABLES_PATH))) + goto error; + + if (!(argv[n++] = strdup("--table"))) + goto error; + + if (!(argv[n++] = strdup(rules->table))) + goto error; + + if (!(argv[n++] = strdup(action == ADD ? "--insert" : "--delete"))) + goto error; + + if (!(argv[n++] = strdup(rules->chain))) + goto error; + + if (!(argv[n++] = strdup(arg))) + goto error; + + p = strcpy(rule, arg); + p += strlen(arg); + + va_start(args, arg); + + while ((s = va_arg(args, const char *))) { + if (!(argv[n++] = strdup(s))) + goto error; + + *(p++) = ' '; + strcpy(p, s); + p += strlen(s); + } + + va_end(args); + + *p = '\0'; + + if (action == ADD && + (retval = iptablesAddRemoveChain(rules, action))) + goto error; + + if ((retval = iptablesSpawn(WITH_ERRORS, argv))) + goto error; + + if (action == REMOVE && + (retval = iptablesAddRemoveChain(rules, action))) + goto error; + +#ifdef IPTABLES_DIR + if (action == ADD) + retval = iptRulesAppend(rules, rule); + else + retval = iptRulesRemove(rules, rule); +#endif /* IPTABLES_DIR */ + + error: + if (rule) + free(rule); + + if (argv) { + n = 0; + while (argv[n]) + free(argv[n++]); + free(argv); + } + + return retval; +} + +iptablesContext * +iptablesContextNew(void) +{ + iptablesContext *ctx; + + if (!(ctx = (iptablesContext *) malloc(sizeof (iptablesContext)))) + return NULL; + + if (!(ctx->input_filter = iptRulesNew("filter", IPTABLES_PREFIX "INPUT"))) + goto error; + + if (!(ctx->forward_filter = iptRulesNew("filter", IPTABLES_PREFIX "FORWARD"))) + goto error; + + if (!(ctx->nat_postrouting = iptRulesNew("nat", IPTABLES_PREFIX "POSTROUTING"))) + goto error; + + return ctx; + + error: + iptablesContextFree(ctx); + return NULL; +} + +void +iptablesContextFree(iptablesContext *ctx) +{ + iptRulesFree(ctx->input_filter); + iptRulesFree(ctx->forward_filter); + iptRulesFree(ctx->nat_postrouting); + free(ctx); +} + +static int +iptablesInput(iptablesContext *ctx, + const char *iface, + int port, + int action, + int tcp) +{ + char portstr[32]; + int ret; + + snprintf(portstr, sizeof(portstr), "%d", port); + portstr[sizeof(portstr) - 1] = '\0'; + + ret = iptablesAddRemoveRule(ctx->input_filter, + action, + "--in-interface", iface, + "--protocol", tcp ? "tcp" : "udp", + "--destination-port", portstr, + "--jump", "ACCEPT", + NULL); + + return ret; +} + +int +iptablesAddTcpInput(iptablesContext *ctx, + const char *iface, + int port) +{ + return iptablesInput(ctx, iface, port, ADD, 1); +} + +int +iptablesRemoveTcpInput(iptablesContext *ctx, + const char *iface, + int port) +{ + return iptablesInput(ctx, iface, port, REMOVE, 1); +} + +int +iptablesAddUdpInput(iptablesContext *ctx, + const char *iface, + int port) +{ + return iptablesInput(ctx, iface, port, ADD, 0); +} + +int +iptablesRemoveUdpInput(iptablesContext *ctx, + const char *iface, + int port) +{ + return iptablesInput(ctx, iface, port, REMOVE, 0); +} + +static int +iptablesPhysdevForward(iptablesContext *ctx, + const char *iface, + int action) +{ + return iptablesAddRemoveRule(ctx->forward_filter, + action, + "--match", "physdev", + "--physdev-in", iface, + "--jump", "ACCEPT", + NULL); +} + +int +iptablesAddPhysdevForward(iptablesContext *ctx, + const char *iface) +{ + return iptablesPhysdevForward(ctx, iface, ADD); +} + +int +iptablesRemovePhysdevForward(iptablesContext *ctx, + const char *iface) +{ + return iptablesPhysdevForward(ctx, iface, REMOVE); +} + +static int +iptablesInterfaceForward(iptablesContext *ctx, + const char *iface, + int action) +{ + return iptablesAddRemoveRule(ctx->forward_filter, + action, + "--in-interface", iface, + "--jump", "ACCEPT", + NULL); +} + +int +iptablesAddInterfaceForward(iptablesContext *ctx, + const char *iface) +{ + return iptablesInterfaceForward(ctx, iface, ADD); +} + +int +iptablesRemoveInterfaceForward(iptablesContext *ctx, + const char *iface) +{ + return iptablesInterfaceForward(ctx, iface, REMOVE); +} + +static int +iptablesStateForward(iptablesContext *ctx, + const char *iface, + int action) +{ + return iptablesAddRemoveRule(ctx->forward_filter, + action, + "--out-interface", iface, + "--match", "state", + "--state", "ESTABLISHED,RELATED", + "--jump", "ACCEPT", + NULL); +} + +int +iptablesAddStateForward(iptablesContext *ctx, + const char *iface) +{ + return iptablesStateForward(ctx, iface, ADD); +} + +int +iptablesRemoveStateForward(iptablesContext *ctx, + const char *iface) +{ + return iptablesStateForward(ctx, iface, REMOVE); +} + +static int +iptablesNonBridgedMasq(iptablesContext *ctx, + int action) +{ + return iptablesAddRemoveRule(ctx->nat_postrouting, + action, + "--match", "physdev", + "!", "--physdev-is-bridged", + "--jump", "MASQUERADE", + NULL); +} + +int +iptablesAddNonBridgedMasq(iptablesContext *ctx) +{ + return iptablesNonBridgedMasq(ctx, ADD); +} + +int +iptablesRemoveNonBridgedMasq(iptablesContext *ctx) +{ + return iptablesNonBridgedMasq(ctx, REMOVE); +} + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ Index: libvirt-foo/qemud/iptables.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2007 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 + * + * Authors: + * Mark McLoughlin + */ + +#ifndef __QEMUD_IPTABLES_H__ +#define __QEMUD_IPTABLES_H__ + +typedef struct _iptablesContext iptablesContext; + +iptablesContext *iptablesContextNew (void); +void iptablesContextFree (iptablesContext *ctx); + +int iptablesAddTcpInput (iptablesContext *ctx, + const char *iface, + int port); +int iptablesRemoveTcpInput (iptablesContext *ctx, + const char *iface, + int port); + +int iptablesAddUdpInput (iptablesContext *ctx, + const char *iface, + int port); +int iptablesRemoveUdpInput (iptablesContext *ctx, + const char *iface, + int port); + +int iptablesAddPhysdevForward (iptablesContext *ctx, + const char *iface); +int iptablesRemovePhysdevForward (iptablesContext *ctx, + const char *iface); + +int iptablesAddInterfaceForward (iptablesContext *ctx, + const char *iface); +int iptablesRemoveInterfaceForward (iptablesContext *ctx, + const char *iface); + +int iptablesAddStateForward (iptablesContext *ctx, + const char *iface); +int iptablesRemoveStateForward (iptablesContext *ctx, + const char *iface); + +int iptablesAddNonBridgedMasq (iptablesContext *ctx); +int iptablesRemoveNonBridgedMasq (iptablesContext *ctx); + +#endif /* __QEMUD_IPTABLES_H__ */ + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ Index: libvirt-foo/configure.in =================================================================== --- libvirt-foo.orig/configure.in 2007-02-14 15:59:02.000000000 +0000 +++ libvirt-foo.orig/configure.in 2007-02-14 15:59:02.000000000 +0000 @@ -79,6 +79,31 @@ dnl fi dnl +dnl allow the creation of iptables rules in chains with a +dnl specific prefix rather than in the standard toplevel chains +dnl +AC_ARG_WITH(iptables-prefix, + AC_HELP_STRING([--with-iptables-prefix=prefix], + [prefix used for iptables chains, default is to use standard toplevel chains]), + [IPTABLES_PREFIX=$withval]) +AC_DEFINE_UNQUOTED(IPTABLES_PREFIX, "$IPTABLES_PREFIX", [prefix used for iptables chains]) + +dnl +dnl also support saving the various chains to files +dnl in e.g. /etc/sysconfig/iptables.d +dnl +AC_ARG_WITH(iptables-dir, + AC_HELP_STRING([--with-iptables-dir=path], + [directory used to save iptables chains, defaults to not saving]), + [IPTABLES_DIR=$withval]) +if test x"$IPTABLES_DIR" != "x"; then + AC_DEFINE_UNQUOTED(IPTABLES_DIR, "$IPTABLES_DIR", [directory used for saving iptables chains]) +fi + +AC_PATH_PROG(IPTABLES_PATH, iptables, /sbin/iptables) +AC_DEFINE_UNQUOTED(IPTABLES_PATH, "$IPTABLES_PATH", [path to iptables binary]) + +dnl dnl Specify the xen-distribution directory to be able to compile on a dnl non-xenified host dnl Index: libvirt-foo/qemud/internal.h =================================================================== --- libvirt-foo.orig/qemud/internal.h 2007-02-14 16:05:37.000000000 +0000 +++ libvirt-foo.orig/qemud/internal.h 2007-02-14 16:05:37.000000000 +0000 @@ -31,6 +31,7 @@ #include "protocol.h" #include "bridge.h" +#include "iptables.h" #ifdef __GNUC__ #ifdef HAVE_ANSIDECL_H @@ -283,6 +284,7 @@ struct qemud_server { int ninactivenetworks; struct qemud_network *inactivenetworks; brControl *brctl; + iptablesContext *iptables; char configDir[PATH_MAX]; char networkConfigDir[PATH_MAX]; char errorMessage[QEMUD_MAX_ERROR_LEN]; --