From b9daf6d9ddbea043852795bf655e4436ccafd6fe Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Thu, 10 Jan 2008 13:54:02 +0000 Subject: [PATCH] Add support for integrating our iptables support with Fedora's iptables configuration using the lokkit --custom-rules command. Basically, we write out our rules to /var/lib/libvirt/iptables and run lokkit --custom-rules so that if e.g. iptables is restarted or the user edits their firewall configuration, then libvirt's rules get reloaded. --- ChangeLog | 15 +++++++ configure.in | 21 +++++++++ src/iptables.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+) diff --git a/ChangeLog b/ChangeLog index 3add06a58e..b0cda86679 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +Thu Jan 10 13:52:05 GMT 2008 Mark McLoughlin + + Add support for integrating our iptables support with + Fedora's iptables configuration using the lokkit --custom-rules + command. + + Basically, we write out our rules to /var/lib/libvirt/iptables + and run lokkit --custom-rules so that if e.g. iptables is + restarted or the user edits their firewall configuration, + then libvirt's rules get reloaded. + + * configure.in: Add --enable-iptables-lokkit + + * src/iptables.c: Add support for lokkit + Thu Jan 10 13:51:00 GMT 2008 Mark McLoughlin * src/iptables.c: Include the iptables command and chain diff --git a/configure.in b/configure.in index bc56c2c305..fe36718fb0 100644 --- a/configure.in +++ b/configure.in @@ -204,6 +204,27 @@ if test x"$IPTABLES_DIR" != "x"; then AC_DEFINE_UNQUOTED(IPTABLES_DIR, "$IPTABLES_DIR", [directory used for saving iptables chains]) fi +dnl +dnl ensure that Fedora's system-config-firewall knows +dnl about libvirt's iptables rules +dnl +AC_ARG_ENABLE(iptables-lokkit, + AC_HELP_STRING([--enable-iptables-lokkit=no/yes/check], + [enable registering libvirt's iptables rules with Fedora's lokkit]), + [],[enable_iptables_lokkit=check]) +if test x"$enable_iptables_lokkit" != x"no"; then + AC_PATH_PROG(LOKKIT_PATH, lokkit, [], [/usr/sbin:$PATH]) +fi + +if test x"$enable_iptables_lokkit" = x"yes" -a x"$LOKKIT_PATH" = x; then + AC_MSG_ERROR([Cannot find lokkit and --enable-iptables-lokkit specified]) +fi + +if test x"$LOKKIT_PATH" != x; then + AC_DEFINE(ENABLE_IPTABLES_LOKKIT, [], [whether support for Fedora's lokkit is enabled]) + AC_DEFINE_UNQUOTED(LOKKIT_PATH, "$LOKKIT_PATH", [path to lokkit binary]) +fi + AC_PATH_PROG(IPTABLES_PATH, iptables, /sbin/iptables) AC_DEFINE_UNQUOTED(IPTABLES_PATH, "$IPTABLES_PATH", [path to iptables binary]) diff --git a/src/iptables.c b/src/iptables.c index e66bc6495a..21363ba1a6 100644 --- a/src/iptables.c +++ b/src/iptables.c @@ -48,6 +48,11 @@ #define qemudLog(level, msg...) fprintf(stderr, msg) +#ifdef ENABLE_IPTABLES_LOKKIT +#undef IPTABLES_DIR +#define IPTABLES_DIR LOCAL_STATE_DIR "/lib/libvirt/iptables" +#endif + enum { ADD = 0, REMOVE @@ -85,6 +90,107 @@ struct _iptablesContext }; #ifdef IPTABLES_DIR +#ifdef ENABLE_IPTABLES_LOKKIT +static void +notifyRulesUpdated(const char *table, + const char *path) +{ + char arg[PATH_MAX]; + 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; + + if (virRun(NULL, argv, NULL) < 0) + qemudLog(QEMUD_WARN, "Failed to run '" LOKKIT_PATH " %s' : %s", + arg, strerror(errno)); +} + +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 || strncmp(s, line, p - s) != 0) { + s = ++p; + continue; + } + + ++p; + memmove(s, p, len - (p - str) + 1); + len -= p - s; + changed = 1; + } + + if (strcmp(s, line) == 0) { + *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) { + qemudLog(QEMUD_WARN, "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)) { + 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; + } + + free(content); + + return; + + write_error: + qemudLog(QEMUD_WARN, "Failed to write to " SYSCONF_DIR "/sysconfig/system-config-firewall : %s", + strerror(errno)); + if (f) + fclose(f); + free(content); + +#undef MAX_FILE_LEN +} +#endif /* ENABLE_IPTABLES_LOKKIT */ + static int writeRules(const char *path, const iptRule *rules, @@ -183,6 +289,11 @@ iptRulesAppend(iptRules *rules, if ((err = writeRules(rules->path, rules->rules, rules->nrules))) return err; } + +#ifdef ENABLE_IPTABLES_LOKKIT + notifyRulesUpdated(rules->table, rules->path); +#endif /* ENABLE_IPTABLES_LOKKIT */ + #endif /* IPTABLES_DIR */ return 0; @@ -216,6 +327,14 @@ iptRulesRemove(iptRules *rules, if ((err = writeRules(rules->path, rules->rules, rules->nrules))) return err; } + +#ifdef ENABLE_IPTABLES_LOKKIT + if (rules->nrules > 0) + notifyRulesUpdated(rules->table, rules->path); + else + notifyRulesRemoved(rules->table, rules->path); +#endif /* ENABLE_IPTABLES_LOKKIT */ + #endif /* IPTABLES_DIR */ return 0;