[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Libvir] [patch 12/12] Support creating iptables rules



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 <markmc redhat com>

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 <markmc redhat com>
+ */
+
+#include <config.h>
+
+#include "iptables.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 <paths.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+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 <markmc redhat com>
+ */
+
+#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];

-- 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]