iptables: Read a List of IP Address From File And Block

How do I read a list of ip address (subnets) using a text file and block all of them using Linux iptables command?

You can create a file which contains the list of all blocked ip address or subnets per line. You can read a file line by line using while loop.

ADVERTISEMENTS

Example: iptables Read IPs / Subnets From The Text File

Create a text file – /root/firewall/badips.db as follows:

# Block db
# Added on Aug/19/2009
202.54.1.2
# Spammers 
203.1.2.3/29

The basic logic as follows to read a text file:

_input=/path/to/text.db
IPT=/sbin/iptables
$IPT -N droplist
egrep -v "^#|^$" x | while IFS= read -r ip
do
	$IPT -A droplist -i eth1 -s $ip -j LOG --log-prefix " myBad IP BlockList  "
	$IPT -A droplist -i eth1 -s $ip -j DROP
done < "$_input"
# Drop it 
$IPT -I INPUT -j droplist
$IPT -I OUTPUT -j droplist
$IPT -I FORWARD -j droplist

Here is a sample shell script:

#!/bin/bash
# Modify script as per your setup
# Usage: Sample firewall script
# ---------------------------
_input=/root/firewall/badips.db
_pub_if="eth1"
IPT=/sbin/iptables
 
# Die if file not found
[ ! -f "$_input" ] && { echo "$0: File $_input not found."; exit 1; }
 
# DROP and close everything
$IPT -P INPUT DROP
$IPT -P OUTPUT DROP
$IPT -P FORWARD DROP
 
# Unlimited lo access
$IPT -A INPUT -i lo -j ACCEPT
$IPT -A OUTPUT -o lo -j ACCEPT
 
# Allow all outgoing connection but no incoming stuff by default
$IPT -A OUTPUT -o ${_pub_if} -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
$IPT -A INPUT -i ${_pub_if} -m state --state ESTABLISHED,RELATED -j ACCEPT
 
 
### Setup our black list ###
# Create a new chain 
$IPT -N droplist
 
# Filter out comments and blank lines
# store each ip or subnet in $ip
egrep -v "^#|^$" x | while IFS= read -r ip
do
        # Append everything to droplist
	$IPT -A droplist -i ${_pub_if} -s $ip -j LOG --log-prefix " Drop Bad IP List "
	$IPT -A droplist -i ${_pub_if} -s $ip -j DROP
done <"${_input}"
 
# Finally, insert or append our black list 
$IPT -I INPUT -j droplist
$IPT -I OUTPUT -j droplist
$IPT -I FORWARD -j droplist
 
 
# Okay add your rest of $IPT commands here 
# Example: open port 53
#$IPT -A INPUT -i ${_pub_if} -s 0/0 -d 1.2.3.4 -p udp --dport 53 -j ACCEPT
#$IPT -A INPUT -i ${_pub_if} -s 0/0 -d 1.2.3.4 -p tcp --dport 53 -j ACCEPT
 
# Open port 80
# $IPT -A INPUT -i ${_pub_if} -s 0/0 -d 1.2.3.4 -p tcp --destination-port 80  -j ACCEPT
 
# Allow incoming ICMP ping pong stuff
# $IPT -A INPUT -i ${_pub_if} -p icmp --icmp-type 8 -m state --state NEW,ESTABLISHED,RELATED -m limit --limit 30/sec  -j ACCEPT
# $IPT -A INPUT -i ${_pub_if}  -p icmp -m icmp --icmp-type 3 -m limit --limit 30/sec -j ACCEPT
# $IPT -A INPUT -i ${_pub_if}  -p icmp -m icmp --icmp-type 5 -m limit --limit 30/sec -j ACCEPT
# $IPT -A INPUT -i ${_pub_if}  -p icmp -m icmp --icmp-type 11 -m limit --limit 30/sec -j ACCEPT
 
# drop and log everything else
$IPT -A INPUT -m limit --limit 5/m --limit-burst 7 -j LOG
$IPT -A INPUT -j DROP
🐧 Get the latest tutorials on SysAdmin, Linux/Unix, Open Source/DevOps topics:
CategoryList of Unix and Linux commands
File Managementcat
FirewallCentOS 8 OpenSUSE RHEL 8 Ubuntu 16.04 Ubuntu 18.04 Ubuntu 20.04
Network Utilitiesdig host ip nmap
OpenVPNCentOS 7 CentOS 8 Debian 10 Debian 8/9 Ubuntu 18.04 Ubuntu 20.04
Package Managerapk apt
Processes Managementbg chroot cron disown fg jobs killall kill pidof pstree pwdx time
Searchinggrep whereis which
User Informationgroups id lastcomm last lid/libuser-lid logname members users whoami who w
WireGuard VPNCentOS 8 Debian 10 Firewall Ubuntu 20.04

ADVERTISEMENTS
12 comments… add one
  • Suren Jun 7, 2011 @ 17:17

    the script looks good, but when i run the script i get this message…
    egrep: x: No such file or directory

    • linzhe Jan 16, 2015 @ 1:40

      the script have som erro,it should be:

      egrep -v "^#|^$"  $_input | while IFS= read -r ip;
      do
      	$IPT -A droplist -i eth1 -s $ip -j LOG --log-prefix " myBad IP BlockList  "
      	$IPT -A droplist -i eth1 -s $ip -j DROP
      done
      
  • Alan Sep 2, 2011 @ 12:19

    just remove the egrep bit, I got the same message, its only required if you have whitespace in your list of banned IPs. Make sure it doesnt, and you can remove the egrep part, everything up to and including the pipe |

  • Marco Apr 9, 2012 @ 10:20

    Hi,
    I have an list.db and it looks like:

    #list of spamers
    14.192.76.0/22
    14.196.0.0/15
    

    ……etc
    when I try to run a script:

    #!/bin/bash
    _input=/root/list.db
    IPT=/sbin/iptables
    #$IPT -N droplist     // I already have BLACKLIST instead droplist
    egrep -v "^#|^$" x | while IFS= read -r ip
    do
    	$IPT -A BLACKLIST -s $ip -j LOG --log-prefix "spam_blacklist" --log-level 7
    done < "$_input"
    

    Im getting error for every entry which got netmask stated as /xx
    … looks like this:
    ‘ specified.4.4: invalid mask `21
    Try `iptables -h’ or ‘iptables –help’ for more information.

    How to alter the script??

  • Sukhjinder Dec 17, 2012 @ 19:09

    In case the list of IP address in text file contains duplicate IP address, how is your script will handle it?

  • Dara Apr 29, 2013 @ 9:37

    It’s not great since egrep doesn’t work and I need comments in the text file…

  • Mee Feb 8, 2014 @ 12:20

    Working code

    INTEX="eth1"
    
    # CHANGE THIS
    badip=/path/to/badip.db
    
    # [FLUSH OLD RULES]
    $IPT -F droplist
    # [DROP OLD CHAIN]
    $IPT -X droplist
    # [CREATE CHAIN]
    $IPT -N droplist
    
    /bin/egrep -v "^#|^$" $badip | while IFS= read -r ip
    
    do
            $IPT -A droplist -i $INTEX -s $ip -j LOG --log-prefix " myBad IP BlockList  "
            $IPT -A droplist -i $INTEX -s $ip -j DROP
    done < "$badip"
    
    # Drop it
    $IPT -I INPUT -j droplist
    $IPT -I OUTPUT -j droplist
    $IPT -I FORWARD -j droplist
    
    • Som Apr 6, 2014 @ 6:49

      I used the code above but when i execute the script for second time i get this error:
      iptables: Too many links
      iptables: Chain already exists
      and i think you forgot to insert IPT=/sbin/iptables

      • Som Apr 6, 2014 @ 7:23

        I added a few lines at the script:

        INTEX="eth1"
        # CHANGE THIS
        badip=/path/to/badip.db
        IPT=/sbin/iptables
        # delete previous droplist (INPUT,OUTPUT,FORWARD)
        $IPT -D INPUT -j droplist
        $IPT -D OUTPUT -j droplist
        $IPT -D FORWARD -j droplist
        # [FLUSH OLD RULES]
        $IPT -F droplist
        # [DROP OLD CHAIN]
        $IPT -X droplist
        # [CREATE CHAIN]
        $IPT -N droplist
        /bin/egrep -v "^#|^$" $badip | while IFS= read -r ip
        do
                $IPT -A droplist -i $INTEX -s $ip -j LOG --log-prefix " myBad IP BlockList  "
                $IPT -A droplist -i $INTEX -s $ip -j DROP
        done < "$badip"
        # Drop it
        $IPT -I INPUT -j droplist
        $IPT -I OUTPUT -j droplist
        $IPT -I FORWARD -j droplist
        
        • SOM Aug 23, 2016 @ 2:36

          i tried your script i got those errors

          : not foundk.sh: 6: ./masipblock.sh: iptables
          : not foundk.sh: 7: ./masipblock.sh: iptables
          : not foundk.sh: 8: ./masipblock.sh: iptables
          : not foundk.sh: 10: ./masipblock.sh: iptables
          : not foundk.sh: 12: ./masipblock.sh: iptables
          : not foundk.sh: 14: ./masipblock.sh: iptables
          ./masipblock.sh: 19: ./masipblock.sh: Syntax error: “done” unexpected (expecting “do”)

          run on ubuntu 15.04

  • uOY May 13, 2014 @ 1:36

    Why people add chain droplist to the OUTPUT chain.

    if you look at the iptables you will see the OUTPUT chain will also try to match the source ip as the bad ip. This will never happen.

    you have to create another loop and make the bad ip as ip destination for the OUTPUT chain.

  • Sam Mingolelli Sep 25, 2014 @ 17:17

    You can also setup a ipset and use iptables match set feature instead of adding all these individual IPs as standalone entries in your iptable’s table.

    $ iptables …… -A INPUT -m set –match-set blacklist src -j DROP

Leave a Reply

Your email address will not be published.

Use HTML <pre>...</pre>, <code>...</code> and <kbd>...</kbd> for code samples.