From 93587a04d0f2511e108bbc4d87a8b9d28a5c5dd8 Mon Sep 17 00:00:00 2001 From: Phil Oester Date: Fri, 31 May 2013 09:07:04 -0400 Subject: ip[6]tables: Add locking to prevent concurrent instances There have been numerous complaints and bug reports over the years when admins attempt to run more than one instance of iptables simultaneously. Currently open bug reports which are related: 325: Parallel execution of the iptables is impossible 758: Retry iptables command on transient failure 764: Doing -Z twice in parallel breaks counters 822: iptables shows negative or other bad packet/byte counts As Patrick notes in 325: "Since this has been a problem people keep running into, I'd suggest to simply add some locking to iptables to catch the most common case." I started looking into alternatives to add locking, and of course the most common/obvious solution is to use a pidfile. But this has various downsides, such as if the application is terminated abnormally and the pidfile isn't cleaned up. And this also requires a writable filesystem. Using a UNIX domain socket file (e.g. in /var/run) has similar issues. Starting in 2.2, Linux added support for abstract sockets. These sockets require no filesystem, and automatically disappear once the application terminates. This is the locking solution I chose to implement in ip[6]tables. As an added bonus, since each network namespace has its own socket pool, an ip[6]tables instance running in one namespace will not lock out an ip[6]tables instance running in another namespace. A filesystem approach would have to recognize and handle multiple network namespaces. Signed-off-by: Phil Oester Signed-off-by: Pablo Neira Ayuso --- iptables/xshared.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'iptables/xshared.c') diff --git a/iptables/xshared.c b/iptables/xshared.c index e61c28c8..6c9992ed 100644 --- a/iptables/xshared.c +++ b/iptables/xshared.c @@ -6,9 +6,15 @@ #include #include #include +#include +#include +#include #include #include "xshared.h" +#define XT_SOCKET_NAME "xtables" +#define XT_SOCKET_LEN 8 + /* * Print out any special helps. A user might like to be able to add a --help * to the commandline, and see expected results. So we call help for all @@ -236,3 +242,30 @@ void xs_init_match(struct xtables_match *match) if (match->init != NULL) match->init(match->m); } + +bool xtables_lock(bool wait) +{ + int i = 0, ret, xt_socket; + struct sockaddr_un xt_addr; + + memset(&xt_addr, 0, sizeof(xt_addr)); + xt_addr.sun_family = AF_UNIX; + strcpy(xt_addr.sun_path+1, XT_SOCKET_NAME); + xt_socket = socket(AF_UNIX, SOCK_STREAM, 0); + /* If we can't even create a socket, fall back to prior (lockless) behavior */ + if (xt_socket < 0) + return true; + + while (1) { + ret = bind(xt_socket, (struct sockaddr*)&xt_addr, + offsetof(struct sockaddr_un, sun_path)+XT_SOCKET_LEN); + if (ret == 0) + return true; + else if (wait == false) + return false; + if (++i % 2 == 0) + fprintf(stderr, "Another app is currently holding the xtables lock; " + "waiting for it to exit...\n"); + sleep(1); + } +} -- cgit v1.2.3