iptables: use different approach for managing loadable extensions
authorJo-Philipp Wich <jo@mein.io>
Tue, 9 Aug 2016 09:00:45 +0000 (11:00 +0200)
committerJo-Philipp Wich <jo@mein.io>
Tue, 1 Nov 2016 13:00:02 +0000 (14:00 +0100)
Since musl libc does not support unloading libraries via dlclose() and since
we should not explicitely call library constructors we need to use an
alternative approach to track the match registrations performed by iptables
shared objects.

This commit changes the iptables glue code to keep a global registry of non-
builtin matches and targets.

We implement the bookkeeping by intercepting xtables_register_match() and
xtables_register_target() calls in order to record any extension registration
attempt performed by a loadable iptables library.

The code subsequently uses the global list of dynamically loaded extensions
to re-register dynamic matches and targets for each address family / table
combination.

As a consequence we can get rid of the lib vector in the iptables handle
and remove the dlclose() handling entirely. This simplifies the
load_extension() as well.

Fixes FS#31.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
iptables.c
iptables.h

index e54ea53..2a0d0ee 100644 (file)
@@ -37,6 +37,16 @@ static struct xtables_globals xtg6 = {
        .orig_opts = base_opts,
 };
 
+static struct {
+       bool retain;
+       int mcount, tcount;
+       struct xtables_match **matches;
+       struct xtables_target **targets;
+       void (*register_match)(struct xtables_match *);
+       void (*register_target)(struct xtables_target *);
+} xext;
+
+
 /* Required by certain extensions like SNAT and DNAT */
 int kernel_version = 0;
 
@@ -66,6 +76,7 @@ static void fw3_init_extensions(void)
 struct fw3_ipt_handle *
 fw3_ipt_open(enum fw3_family family, enum fw3_table table)
 {
+       int i;
        struct fw3_ipt_handle *h;
 
        h = fw3_alloc(sizeof(*h));
@@ -102,6 +113,14 @@ fw3_ipt_open(enum fw3_family family, enum fw3_table table)
        fw3_xt_reset();
        fw3_init_extensions();
 
+       if (xext.register_match)
+               for (i = 0; i < xext.mcount; i++)
+                       xext.register_match(xext.matches[i]);
+
+       if (xext.register_target)
+               for (i = 0; i < xext.tcount; i++)
+                       xext.register_target(xext.targets[i]);
+
        return h;
 }
 
@@ -467,17 +486,6 @@ fw3_ipt_commit(struct fw3_ipt_handle *h)
 void
 fw3_ipt_close(struct fw3_ipt_handle *h)
 {
-       if (h->libv)
-       {
-               while (h->libc > 0)
-               {
-                       h->libc--;
-                       dlclose(h->libv[h->libc]);
-               }
-
-               free(h->libv);
-       }
-
        free(h);
 }
 
@@ -525,9 +533,11 @@ static bool
 load_extension(struct fw3_ipt_handle *h, const char *name)
 {
        char path[256];
-       void *lib, **tmp;
+       void *lib;
        const char *pfx = (h->family == FW3_FAMILY_V6) ? "libip6t" : "libipt";
 
+       xext.retain = true;
+
        snprintf(path, sizeof(path), "/usr/lib/iptables/libxt_%s.so", name);
        if (!(lib = dlopen(path, RTLD_NOW)))
        {
@@ -535,18 +545,9 @@ load_extension(struct fw3_ipt_handle *h, const char *name)
                lib = dlopen(path, RTLD_NOW);
        }
 
-       if (!lib)
-               return false;
-
-       tmp = realloc(h->libv, sizeof(lib) * (h->libc + 1));
-
-       if (!tmp)
-               return false;
+       xext.retain = false;
 
-       h->libv = tmp;
-       h->libv[h->libc++] = lib;
-
-       return true;
+       return !!lib;
 }
 
 static struct xtables_match *
@@ -1642,3 +1643,63 @@ fw3_ipt_rule_create(struct fw3_ipt_handle *handle, struct fw3_protocol *proto,
 
        return r;
 }
+
+void
+xtables_register_match(struct xtables_match *me)
+{
+       int i;
+       static struct xtables_match **tmp;
+
+       if (!xext.register_match)
+               xext.register_match = dlsym(RTLD_NEXT, "xtables_register_match");
+
+       if (!xext.register_match)
+               return;
+
+       xext.register_match(me);
+
+       if (xext.retain)
+       {
+               for (i = 0; i < xext.mcount; i++)
+                       if (xext.matches[i] == me)
+                               return;
+
+               tmp = realloc(xext.matches, sizeof(me) * (xext.mcount + 1));
+
+               if (!tmp)
+                       return;
+
+               xext.matches = tmp;
+               xext.matches[xext.mcount++] = me;
+       }
+}
+
+void
+xtables_register_target(struct xtables_target *me)
+{
+       int i;
+       static struct xtables_target **tmp;
+
+       if (!xext.register_target)
+               xext.register_target = dlsym(RTLD_NEXT, "xtables_register_target");
+
+       if (!xext.register_target)
+               return;
+
+       xext.register_target(me);
+
+       if (xext.retain)
+       {
+               for (i = 0; i < xext.tcount; i++)
+                       if (xext.targets[i] == me)
+                               return;
+
+               tmp = realloc(xext.targets, sizeof(me) * (xext.tcount + 1));
+
+               if (!tmp)
+                       return;
+
+               xext.targets = tmp;
+               xext.targets[xext.tcount++] = me;
+       }
+}
index 5dfb54a..892a0d4 100644 (file)
@@ -55,9 +55,6 @@ struct fw3_ipt_handle {
        enum fw3_family family;
        enum fw3_table table;
        void *handle;
-
-       int libc;
-       void **libv;
 };
 
 struct fw3_ipt_rule {
@@ -165,4 +162,7 @@ fw3_ipt_rule_target(struct fw3_ipt_rule *r, const char *fmt, ...)
        fw3_ipt_rule_addarg(r, false, "-j", buf);
 }
 
+void xtables_register_match(struct xtables_match *me);
+void xtables_register_target(struct xtables_target *me);
+
 #endif