Index: iptables-1.6.1/iptables/iptables-batch.c =================================================================== --- iptables-1.6.1.orig/iptables/iptables-batch.c +++ iptables-1.6.1/iptables/iptables-batch.c @@ -404,6 +404,34 @@ main(int argc, char *argv[]) tables[3].handle = NULL; current_table = &tables[0]; + /* + * we need to lock the complete batch processing against parallel + * modification by other processes. Otherwise we can end up with + * EAGAIN errors. + * + * the do_command{4,6} function already locks itself, but the + * complete call sequence needs to be locked until the commit is + * performed. + * + * sadly the xtables_lock() implementation is not very cooperative. + * There's no unlock() equivalent. The lock file descriptor is smiply + * left open until the process exits. Thus we'd have deadlocks when + * calling do_command{4,6} the second time. + * + * To prevent this, part of this patch adds logic to avoid taking the + * lock a second time in the same process in xtables_lock() + */ + + const struct timeval wait_interval = { + .tv_sec = 1, + }; + + if( xtables_lock(-1, &wait_interval) != true ) + { + fprintf(stderr, "failed to acquire the xtables lock\n"); + exit(1); + } + while((r = getline(&iline, &llen, fp)) != -1) { if(llen < 1 || !*iline) Index: iptables-1.6.1/iptables/xshared.c =================================================================== --- iptables-1.6.1.orig/iptables/xshared.c +++ iptables-1.6.1/iptables/xshared.c @@ -250,8 +250,14 @@ void xs_init_match(struct xtables_match bool xtables_lock(int wait, struct timeval *wait_interval) { struct timeval time_left, wait_time, waited_time; + static bool already_locked = false; int fd, i = 0; + if( already_locked ) { + // avoid dead-locks, see iptables-batch.c + return true; + } + time_left.tv_sec = wait; time_left.tv_usec = 0; waited_time.tv_sec = 0; @@ -262,8 +268,10 @@ bool xtables_lock(int wait, struct timev return true; while (1) { - if (flock(fd, LOCK_EX | LOCK_NB) == 0) + if (flock(fd, LOCK_EX | LOCK_NB) == 0) { + already_locked = true; return true; + } if (++i % 10 == 0) { if (wait != -1) fprintf(stderr, "Another app is currently holding the xtables lock; "