1

I've been using a bash shell script to set complex iptables rules for years. However, on Debian Stretch when I tried to use a script, it became sluggish and left iptables in a bad state.

When I tried to do an iptables -L -v it came back with an error...

Another app is currently holding the xtables lock; still -9s 0us time ahead to have a chance to grab the lock...

Google'ing led me to this bug which suggests using the "-w" switch. The man page doesn't really clear up how this switch might affect the issue.

My script uses a loop for admin convenience, which causes it to make a lot of calls to iptables.

# This actually sets the allowed incoming iptables lines
setincoming() {
    for port in ${2}; do
        for ip in ${1}; do
            if  [ `echo "$ip" | grep -P "(^|\s)[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}(/[0-9]*)*(\s*)$"` ]; then
                iptables -I INPUT  -p tcp  -s $ip --dport $port -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
            else
                ip6tables -I INPUT  -p tcp  -s $ip --dport $port -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
            fi
        done
    done
}

#####
# APIs
setincoming "123.123.123.10   123.123.123.11   fe80::xxxx:xxx:xxxx:xxxx" "4200 4300"

Can anyone help me understand how "-w" is used to fix this issue?

EDIT: For clarification I did, of course, look at the man page - and tried using the switches -w and combined as -w -W1 but this had no effect on the issue (neither fixed it nor changed the symptoms).

SO, I'm still at a loss as to how to resolve.

BurningKrome
  • 525
  • 2
  • 12
  • 22
  • Did you read the man page? – MadHatter Oct 12 '18 at 15:31
  • 1
    I did (I mentioned it in the body of the question). It really doesn't clear anything up, at least as to how it relates to this particular problem. I also tried adding a timeout using `-w1` (which, according to the man page, is the default anyway) and it made no difference to the breakage. So, I'm not sure how using `-w` would affect this issue and - if it does - how should I use it and why does it fix it? – BurningKrome Oct 12 '18 at 16:08
  • 1
    This is unnecessarily complex and creates unnecessarily complex and suboptimal rules. Have you considered using ipset to list allowed addresses and multiport match to match several ports? Or using just hash:ip,port or hash:net,port sets to match both? – Tomek Oct 12 '18 at 16:43
  • @Tomek I have used multiprts and, if that's the only solution, then I will again. I use this script mostly because I have lesser experienced admins that need to be able to edit the iptables, and I wanted to make it as user friendly (read: difficult to F-up) as possible. I.e. For someone to add rules, they just need to list the IPs and the ports. I'll look into ipset however. Maybe thats an easier solution for everyone. === I've never had any issues with this script running before - but now it seems to freeze up - only on Debian 9 Stretch. – BurningKrome Oct 12 '18 at 16:52
  • 1
    Adding IP/port pairs to ipset of hash:ip,port type is as easy as it can be. And you even shouldn't need to run any script to put it into service (if I am not mistaken). – Tomek Oct 12 '18 at 17:19
  • 1
    BTW, I am not familiar with Debian but is there any chance that the difference between the two is switching from traditional init.d startup to systemd? If so, systemd may be the culprit as it tries to run different services in parallel. – Tomek Oct 12 '18 at 17:21

1 Answers1

3

The -w option simply causes iptables to wait for the xtables lock rather than exit upon initial failure to obtain it. The option can work around race conditions where multiple processes are competing to obtain and release the xtables lock. If another process is not releasing the lock, or if too many processes are competing for the lock, this option may not help.

As Tomek recommended, I would modify your script to take advantage of ipset. It will certainly be more optimized since it relies on a hash table instead of going through your iptables rules serially. It will likely resolve your locking problem as well. Something along the lines of:

# Create ipset and connect it with iptables
ipset create foo hash:ip,port
iptables -I INPUT -m set --match-set foo src -j ACCEPT

# Add allowances as needed
ipset add foo 123.123.123.10,4200
ipset add foo 123.123.123.11,tcp:4300 # Specify protocol
ipset add foo 123.123.123.12,4400 timeout 600 # Set a timeout for this to disappear
ipset add foo 123.123.123.13,4500 -exist # Do not error if this already exists

Since you included both IPv4 and IPv6 in your examples, I'll also mention that you can use the family parameter when creating the ipset to support IPv6 in particular.

billyw
  • 1,572
  • 15
  • 26