I have a modified log file listing all the IP addresses which have accessed my server.
Next to the IP address on each line is a date/time stamp.
In my quest to filter bots and malicious activity, I would like to check if any IP addresses have made more than 5 requests in less than 15 seconds.
I have already posted a question on how to measure this from the first request, but I would like to take this further.
I am currently learning (G)AWK, and I would like to learn more. If possible, I would like this to be completed in (G)AWK and explained as explicitly as possible, so that I can study the script and, hopefully in the future, I will be able to write similar scripts myself.
While I understand this can most likely be done in Python, I am not currently learning Python.
Sample input
Here is a full (working) modified (to obfuscate the IP addresses) version of my log file: log-file.csv.
And, below is a [further modified] sample of the file, in case you prefer to test your results against that instead:
03/Nov/2020:06:33:09|000.000.000.001|200|/page-1/
03/Nov/2020:07:12:21|000.000.000.002|200|/page-2/
03/Nov/2020:07:24:52|000.000.000.003|200|/page-3/
03/Nov/2020:07:30:50|000.000.000.004|200|/page-4/
03/Nov/2020:07:47:29|000.000.000.005|200|/page-5/
03/Nov/2020:07:52:42|000.000.000.006|200|/page-6/
03/Nov/2020:07:52:55|000.000.000.007|200|/page-7/
03/Nov/2020:08:00:11|000.000.000.008|200|/page-8/
03/Nov/2020:08:05:00|000.000.000.009|200|/page-9/
03/Nov/2020:08:05:06|000.000.000.010|301|/page-10/
03/Nov/2020:08:05:32|000.000.000.007|200|/page-11/
03/Nov/2020:09:02:49|000.000.000.011|304|/page-12/
03/Nov/2020:09:02:49|000.000.000.011|404|/page-13/
03/Nov/2020:09:13:18|000.000.000.011|304|/page-14/
03/Nov/2020:09:13:19|000.000.000.011|404|/page-15/
03/Nov/2020:09:14:20|000.000.000.012|200|/page-16/
03/Nov/2020:09:23:48|000.000.000.011|304|/page-17/
03/Nov/2020:09:23:49|000.000.000.011|404|/page-18/
03/Nov/2020:09:34:19|000.000.000.011|304|/page-19/
03/Nov/2020:09:34:19|000.000.000.011|404|/page-20/
03/Nov/2020:09:35:42|000.000.000.013|301|/page-21/
03/Nov/2020:09:35:42|000.000.000.013|404|/page-22/
03/Nov/2020:09:44:49|000.000.000.011|304|/page-23/
03/Nov/2020:09:44:49|000.000.000.011|404|/page-24/
03/Nov/2020:09:53:38|000.000.000.014|200|/page-25/
03/Nov/2020:09:55:19|000.000.000.011|304|/page-26/
03/Nov/2020:09:55:19|000.000.000.011|404|/page-27/
03/Nov/2020:10:05:49|000.000.000.011|304|/page-28/
03/Nov/2020:10:05:49|000.000.000.011|404|/page-29/
03/Nov/2020:10:06:27|000.000.000.005|200|/page-30/
03/Nov/2020:10:16:19|000.000.000.011|304|/page-31/
03/Nov/2020:10:16:19|000.000.000.011|404|/page-32/
03/Nov/2020:10:17:21|000.000.000.015|200|/page-33/
03/Nov/2020:10:20:35|000.000.000.016|200|/page-34/
03/Nov/2020:10:20:37|000.000.000.017|404|/page-35/
03/Nov/2020:10:20:42|000.000.000.017|404|/page-39/
03/Nov/2020:10:20:49|000.000.000.016|200|/page-40/
03/Nov/2020:10:20:55|000.000.000.017|404|/page-41/
03/Nov/2020:10:21:01|000.000.000.017|404|/page-42/
03/Nov/2020:10:21:03|000.000.000.017|404|/page-43/
03/Nov/2020:10:21:05|000.000.000.017|404|/page-44/
03/Nov/2020:10:21:06|000.000.000.017|404|/page-45/
03/Nov/2020:10:21:11|000.000.000.017|404|/page-46/
03/Nov/2020:10:21:14|000.000.000.016|200|/page-47/
03/Nov/2020:10:21:34|000.000.000.016|200|/page-48/
03/Nov/2020:10:21:47|000.000.000.016|200|/page-49/
03/Nov/2020:10:22:14|000.000.000.016|200|/page-50/
03/Nov/2020:10:22:15|000.000.000.016|200|/page-51/
03/Nov/2020:10:22:15|000.000.000.016|200|/page-52/
03/Nov/2020:10:22:16|000.000.000.016|200|/page-52/
03/Nov/2020:10:22:17|000.000.000.016|200|/page-53/
03/Nov/2020:10:22:18|000.000.000.019|200|/page-1/
03/Nov/2020:10:22:20|000.000.000.016|200|/page-55/
03/Nov/2020:10:22:20|000.000.000.016|200|/page-56/
The desired output
I would like you to produce a document named bot-list.txt
, containing a list of IP addresses which have made 5 requests or more in less than 15 seconds at any time (not necessarily the first 5). I may want to adjust the frequency/duration at a later date.
Because the log file is large, I don't feel it would be appropriate to post the whole thing here. However, the output of the (modified) sample above is only 2 IP addresses. Thus, it will be considerably more reliable to test the full log file.
000.000.000.017
000.000.000.016
Please be explicit in how you achieved the result. As an added bonus, if you do use any obscure technique/function, I would be pleased if you can point to a reference where I can learn more about this technique.
So, to be clear:
- Search for each unique IP in
log-file.csv
- Where there are 5 or more instances of this IP, calculate the difference in seconds between them using the date/time stamp on each line.
- Isolate IP addresses where 5 pages (or more) are accessed in less than 15 seconds.
- Append these IP address to
bot-list.txt
. - If possible, complete the task in a single (G)AWK script.
Further advice on how to improve on this concept would be welcome.
What I have tried
I honestly don't know how to compare rows in GAWK, but it is clear from some of the answers in my previous question, that it is possible.
Currently, I am reading through the book "Effective AWK Programming". It is very interesting, but I struggle with some of it. I am also looking into associative arrays, but as I don't come from a programming background, I am picking this knowledge up slowly.
I cannot find anything which solves my specific problem and videos on this subject are few and far between.
If anyone can point to helpful resources which can help me to solve problems like this, I would be appreciative.
My attempt at comparing the dates:
egrep "000.111.000.111" log-file.csv | awk 'BEGIN{FS="|"; ORS=" "} NR==1 || NR==5 {print $1,$2}' | sed -e 's/[\/:]/\ /g' -e 's/Jan/1/g' -e 's/Feb/2/g' -e 's/Mar/3/g' -e 's/Apr/4/g' -e 's/May/5/g' -e 's/Jun/6/g' -e 's/Jul/7/g' -e 's/Aug/8/g' -e 's/Sep/9/g' -e 's/Oct/10/g' -e 's/Nov/11/g' -e 's/Dec/12/g' | awk '{print $3,$2,$1,$4,$5,$6 "," $10,$9,$8,$11,$12,$13","$14}' | awk -F, '{d2=mktime($2);d1=mktime($1);print d2-d1, $3}' | awk '{if($1<15)print $2}' >> bot-list.txt
Unfortunately, as you can see, I could not do the whole thing in (G)AWK, but I would appreciate it if you can.
(This is my second time using Stack Exchange. I have attempted to follow advice on how to lay out my question, I am happy to receive further advice if I have made any errors).
Thank you.
it will be considerably more reliable to test the full log file.
but you didn't tell us what the expected output would be for the full log file so we can't know if a text passed or failed. The script in my answer output 126 IP addresses from your full log file but idk if that's the right or wrong number we should get.