Using (Abusing?) AWK For Rudimentary DoS Detection

sFlow(R)InMon’s sflowtool comes with an sample script, ipTopTalkers that uses awk to provide a list of toptalkers based on sflow sampled packets. All I’ve done here is build on their ipTopTalkers sample code to find which addresses are receiving >10,000 pps or >80 Mb/s, and send that information to a log file and reporting-script (not shown).

Converting the binary sflow feed to text, then piping it through awk to do basic math and sorting functions, is not exactly the most elegent solution. But hey, it works!

#!/usr/bin/mawk-cur -f

# ALK 2013-01-10
#
# for performance reasons, mawk is preferred to gawk
# newer versions of mawk include things like strftime that tradionally had been
# gawk-only features. code and builds of mawk-cur (cutting edge) can be found at:
#    http://invisible-island.net/mawk/
# (the features of mawk-cur aren't available in official debian packages of mawk)
#
# based on ipTopTalkers from InMon:
#
# Copyright (c) 2001 InMon Corp. Licensed under the terms of the InMon sFlow licence:
# http://www.inmon.com/technology/sflowlicense.txt

# usage: sflowtool | DoSTargets

BEGIN{
lastInt = 0;
report = "tee -a /var/log/ddos-report.log | dos-report.sh";
interval = 60; #1 minute window
BPSthreshold = 83886080; # alert threshold in bits per second i.e. 80 Mb/s
PPSthreshold = 10000; # alert threshold in packets per second i.e 10kpps
}
/unixSecondsUTC/{
currentInt = $2 - ($2 % interval);
if(currentInt != lastInt) {
for(i = 1; i < = 1000; i++) { # consider up to 1000 simultaneous targets
BPSmaxCount = 0;
BPSmaxKey = "";
for(BPSkey in BPScount) {
if(BPScount[BPSkey] > BPSmaxCount) {
BPSmaxCount = BPScount[BPSkey];
BPSmaxKey = BPSkey;
}
}
if(BPSmaxCount > (BPSthreshold * interval)) printf("%d %s %d %s", strftime("%s", lastInt), BPSmaxKey, sprintf("%d",(BPSmaxCount/1024/1024/interval)),"mbps\n") | report;
delete BPScount[BPSmaxKey];

PPSmaxCount = 0;
PPSmaxKey = "";
for(PPSkey in PPScount) {
if(PPScount[PPSkey] > PPSmaxCount) {
PPSmaxCount = PPScount[PPSkey];
PPSmaxKey = PPSkey;
}
}
if(PPSmaxCount > (PPSthreshold * interval)) printf("%d %s %d %s", strftime("%s", lastInt), PPSmaxKey, sprintf("%d",(PPSmaxCount/interval)),"pps\n") | report;
delete PPScount[PPSmaxKey];
}
fflush(stdout); # write out stdout buffer
close(report); # send the alert email
lastInt = currentInt;
delete BPScount;
delete PPScount;
}
}
/meanSkipCount/{ samplingInterval = $2; }
/sampledPacketSize/{ sampledPacketSize = $2; }
/dstIP/{ BPScount[$2] = BPScount[$2] + ( samplingInterval * sampledPacketSize * 8); PPScount[$2] = PPScount[$2] + samplingInterval; }
END{}