How to make iptables rules expire?

Solution 1:

If you mean for iptables to completely remove the rule by itself you won't be able to do it, as far as I know. What's the purpose of this? If you need some kind of automatic temporary banning the standard solution is fail2ban.

Alternatively you can use a cron job to remove the rule you're adding, or, better if you want to do it interactively, an at job:

iptables -I INPUT -s 192.168.1.100 -j DROP
echo "iptables -D INPUT -s 192.168.1.100 -j DROP" | at @10pm 

Also take a look at the recent module of iptables. This with its --seconds option may be of help, depending on your actual needs. man iptables for more information.

Solution 2:

Put a comment with a timestamp (probably seconds since the epoch) in the rules. Periodically sweep for expired rules.

Note that the most recent linux kernel has support for dynamic loading of IP addresses into a cache consulted by iptable rules instead of as direct iptables rules.

Example:

iptables  -A INPUT -s 192.168.200.100/32 -m comment --comment "expire=`date -d '+ 5 min' +%s`" -j DROP 
iptables -L INPUT -n --line-numbers | tac | perl -ne 'next unless /(^\d+).*expire=(\d+)/; if ($2 < time) { print "iptables -D INPUT $1\n"; }'

You can of course iptables -D INPUT $1 instead of printing the command.


Solution 3:

iptables has a method for automatically adding IP addresses to a list if user defined conditions are met. I use the following to help avoid automated hack attempts to my ssh port:

iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --name ssh --seconds 60 --reap -j DROP

This helps to limit automated attempts to gain access to the server by limiting connection attempts from the same IP address to one every 60 seconds.

If you want to allow a set number of attempts in a time frame, such as 4 in 5 minutes, and on failure then blacklist them for a longer period, such as 24 hours, you can do something like:

iptables -X black
iptables -N black
iptables -A black   -m recent --set   --name blacklist   -j DROP

iptables -X ssh
iptables -N ssh
iptables -I ssh 1   -m recent --update    --name blacklist   --reap   --seconds 86400     -j DROP
iptables -I ssh 2   -m recent --update    --name timer       --reap   --seconds   600     --hitcount 4   -j black
iptables -I ssh 3   -m recent --set       --name timer   -j ACCEPT

iptables -A INPUT   -p TCP --dport ssh   -m state --state NEW -j ssh

In the above, we create 2 chains; "ssh" and "black", and 2 lists; "timer", and "blacklist".

Briefly; the last chain shown above is the "doorway" into the ssh chain.

  • Rule 1 in the ssh chain checks to see if the source IP is in the list "blacklist". If so, the connection is dropped and the 24 hour blacklist timer is restarted. If rule 1 is false, then we go to rule 2.
  • Rule 2 in the ssh chain checks to see if the source IP has made more than 4 connection attempts in 5 minutes. If so, it sends the packet to the chain "black" where it is added to the list "blacklist". The chain "black" then DROPs the connection, and we're done.
  • Rule 3 in the chain "ssh" is only reached if rules 1 and 2 are false. If so, the packet is ACCEPTed and the source IP is added to the list "timer" so we can monitor connection attempt frequency.

The "--reap" option tells the kernel to search through the list and purge any items that are older than the set time limit; 5 minutes for the list "timer", and 24 hours for the list "blacklist".

note: the extra spaces are for readability, and are optional in your shell script.


Solution 4:

IPTables has a feature made expressly for this: IP Set. You make the rule once and it persists as usual but it checks in a set of ips (or ports) for matches. The cool thing is that this set can be dynamically and efficiently updated without disturbing the rest of the firewall.

The main website, examples.

So, to use it, you would still have to use at or cron to schedule the removal.


Solution 5:

You can use fail2ban to ban ip addresses and configure the length of time an address will be banned for.