Search code examples
bashawkiptables

Block IPs that requested more than N times per minute from a log file


I want to block IPs that requested more than N times/min using iptables .
I've sorted the log file using this script:
cat $log_path | awk '{print $1, $4}' | sort -n -k 1,4 | sed "s/\[//g"

10.200.3.120 20/May/2021:21:05:04
10.200.3.120 20/May/2021:21:05:17
10.200.3.120 20/May/2021:21:05:18
10.200.3.120 20/May/2021:21:05:19
10.200.3.120 20/May/2021:21:05:20
10.200.3.120 20/May/2021:22:05:39
104.131.19.181 20/May/2021:19:05:31
107.23.7.76 20/May/2021:20:05:16
119.252.76.162 20/May/2021:22:05:00
119.252.76.162 20/May/2021:22:05:01
119.252.76.162 20/May/2021:22:05:01
119.252.76.162 20/May/2021:22:05:04
119.252.76.162 20/May/2021:22:05:04
119.252.76.162 20/May/2021:21:05:10
119.252.76.162 20/May/2021:21:05:44
⋮

In the example log above, two IPs requested more than 4 times in a minute (10.200.3.120, 119.252.76.162) and they should be blocked.
How can I get the number of requests in a time interval for each IP and block those IPs?


Solution

  • You can try this solution:

    awk '
    {
       gsub(/\[|:[0-9]+$/, "", $4)
       ++fq[$4,$1]
    }
    END {
       for (i in fq)
          if (fq[i] >= 4) {
             sub(".*" SUBSEP, "", i)
             print "iptables -A INPUT -s", i, "-j DROP"
          }
    }' "$log_path" | sh
    

    Here:

    • gsub function strips starting [ and seconds value from timestamp
    • ++fq[$4,$1] increments array element fq by 1 where each element is composite key $4,$1 i.e. $4 SUBSEP $1 string
    • In the END block we loop through fq array. When fq[i] >= 4 we remove starting text followed by SUBSEP from array index to leave only IP.
    • Finally we print full iptables command line using the ip we just extracted
    • Finally we pipe awk output to sh to run all commands