Shell script to read a file

349 Views Asked by At

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

2

There are 2 best solutions below

16
On BEST ANSWER
#!/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.

2
On

you could try

#!/bin/bash

ipadds="/home/asad/Downloads/blacklist"

while IFS='' read -r 
do 
    # check if the rule already exists - if not add it - and 
    # silently ignore warnings for rules that dont exist
    if ! iptables -C INPUT -s "$REPLY" -j DROP 2> /dev/null
    then 
        iptables -A INPUT -s "$REPLY" -j DROP
    fi

    if ! iptables -C FORWARD -s "$REPLY" -j DROP 2> /dev/null
    then 
        iptables -A FORWARD -s "$REPLY" -j DROP
    fi
# Please note proper syntax for process substitution
done < <(grep -Ev "^#" $ipadds)