Search code examples
bashshellshiptables

Shell script to read a file


I have written a shell script to read a file which consists of IP addresses and then block them with the help of iptables. It works fine, But when I run the script for second time, it writes the rule again (duplicated). I want it to check if IP is already blocked then ignore it otherwise block. here is the script:

#!/bin/bash
ipadds="/home/asad/Downloads/blacklist"
dropit=$(grep -Ev "^#" $ipadds)
for i in $dropit; do
 iptables -A INPUT -s $i -j DROP
 iptables -A FORWARD -s $i -j DROP
done

Output after first time script run:

root@ubuntu:/home/asad/Downloads# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
DROP       all  --  192.168.248.2        anywhere
DROP       all  --  192.168.232.20       anywhere
DROP       all  --  192.168.232.5        anywhere
DROP       all  --  192.168.232.190      anywhere
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
DROP       all  --  192.168.248.2        anywhere
DROP       all  --  192.168.232.20       anywhere
DROP       all  --  192.168.232.5        anywhere
DROP       all  --  192.168.232.190      anywhere
Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Output after second time script run:

root@ubuntu:/home/asad/Downloads# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
DROP       all  --  192.168.248.2        anywhere
DROP       all  --  192.168.232.20       anywhere
DROP       all  --  192.168.232.5        anywhere
DROP       all  --  192.168.232.190      anywhere
DROP       all  --  192.168.248.2        anywhere
DROP       all  --  192.168.232.20       anywhere
DROP       all  --  192.168.232.5        anywhere
DROP       all  --  192.168.232.190      anywhere
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
DROP       all  --  192.168.248.2        anywhere
DROP       all  --  192.168.232.20       anywhere
DROP       all  --  192.168.232.5        anywhere
DROP       all  --  192.168.232.190      anywhere
DROP       all  --  192.168.248.2        anywhere
DROP       all  --  192.168.232.20       anywhere
DROP       all  --  192.168.232.5        anywhere
DROP       all  --  192.168.232.190      anywhere
Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

how to avoid this duplication? any help please


Solution

  • #!/bin/bash
    ipadds=/home/asad/Downloads/blacklist
    grep -v "^#" $ipadds | while read i; do
     if ! iptables -nL INPUT | grep -Fq "$i" ; then
       iptables -A INPUT -s "$i" -j DROP
       iptables -A FORWARD -s "$i" -j DROP
     fi
    done
    

    Or (maybe this makes little difference to you)

    #!/bin/bash
    ipadds=/home/asad/Downloads/blacklist
    while read i; do
     if ! iptables -nL INPUT | grep -Fq "$i" ; then
       iptables -A INPUT -s "$i" -j DROP
       iptables -A FORWARD -s "$i" -j DROP
     fi
    done < <(grep -v "^#" $ipadds)
    

    Please note that the -E flag for grep is not needed in this case. It is crucial to pass the -n flag to iptables -L in order to get IP’s and not hostnames; it also improves performance. I assume that your INPUT and FORWARD chains are kept in sync, therefore I only check one of them. If this is not the case, one should check both, of course.

    The exact semantics of the above script is: “don’t insert a new candidate IP if it’s already mentioned anywhere in the INPUT chain” which is a little different from “... if it’s already blocked”. A more efficient solution based on iptables -C would look for a particular rule, but not for other mentions of the IP in the chain. I can think of scenarios where either approach is preferable.

    If you have lots of IP’s in your iptables chains, scanning a whole chain to check if a candidate IP is already there might be inefficient. If this becomes a problem, there are various ways to build an external index for more efficient IP lookups, but OTOH the whole system would become more difficult to maintain, so I’d experiment without external indexes for a start.