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 e54ea53f2c39d48cf5e0ab3234e5c36e5d2cfbe8..2a0d0ee29f453dba28025a269c917e76f9f7bb2c 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 5dfb54a9d8276c2fe5bdfbc005024c9f2d3adba9..892a0d45e31abb92cd4490cdd9ea1aada2c3c4e6 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