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.
The slightly nasty bit is that rather than running something
like lokkit --remove-custom-rules, we have to grub around
in /etc/sysconfig/system-config-firewall to remove our
rules files.
Signed-off-by: Mark McLoughlin <markmc(a)redhat.com>
Index: libvirt/configure.in
===================================================================
--- libvirt.orig/configure.in 2008-01-04 14:48:49.000000000 +0000
+++ libvirt.orig/configure.in 2008-01-04 14:48:49.000000000 +0000
@@ -204,6 +204,20 @@ 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],
+ [enable registering libvirt's iptables rules with
Fedora's lokkit]),
+ [],[enable_iptables_lokkit=no])
+if test x"$enable_iptables_lokkit" = x"yes"; then
+ AC_DEFINE(ENABLE_IPTABLES_LOKKIT, [], [whether support for Fedora's lokkit is
enabled])
+ AC_PATH_PROG(LOKKIT_PATH, lokkit, /usr/sbin/lokkit)
+ 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])
Index: libvirt/src/iptables.c
===================================================================
--- libvirt.orig/src/iptables.c 2008-01-04 14:51:29.000000000 +0000
+++ libvirt.orig/src/iptables.c 2008-01-04 14:51:29.000000000 +0000
@@ -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
@@ -133,6 +138,108 @@ iptablesSpawn(int errors, char * const *
}
#ifdef IPTABLES_DIR
+#ifdef ENABLE_IPTABLES_LOKKIT
+static void
+notifyRulesUpdated(const char *table,
+ const char *path)
+{
+ char arg[PATH_MAX];
+ char *argv[4];
+ int retval;
+
+ 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 ((retval = iptablesSpawn(WITH_ERRORS, argv)))
+ qemudLog(QEMUD_WARN, "Failed to run '" LOKKIT_PATH " %s' :
%s",
+ arg, strerror(retval));
+}
+
+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,
@@ -231,6 +338,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;
@@ -264,6 +376,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;
--