Created
March 19, 2014 01:00
-
-
Save lrhazi/9633485 to your computer and use it in GitHub Desktop.
F5 GTM iRule: An attempt at RRL Response Rate Limiting
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
when RULE_INIT { | |
# Max queries per second, per client ip | |
set static::maxconn 100 | |
# Max identical responses per second, per client ip | |
set static::maxresp 20 | |
# Number of seconds to drop traffic from infringing client ip. | |
set static::holdtime 15 | |
# Maximum entries in dns_drop session table. | |
set static::max_drop_entries 1000000 | |
# Maximum per client, per query, table size. | |
set static::max_query_entries 1000000 | |
} | |
when CLIENT_DATA { | |
set client_ip [IP::remote_addr] | |
set vip [IP::local_addr] | |
set hsl [HSL::open -proto UDP -pool splunk_pool] | |
if { [table lookup -subtable "dns_drop" $client_ip] != "" } { | |
drop | |
#log local0.debug "Dropped client: $client_ip" | |
return | |
} | |
} | |
when DNS_RESPONSE { | |
if { [table keys -subtable "dns_drop" -count] >= $static::max_drop_entries } { | |
HSL::send $hsl "<190>GTM|RRL disabled! Reached max_drop_entries: $static::max_drop_entries\n" | |
#log local0.debug "RRL disabled! Reached max_drop_entries: $static::max_drop_entries" | |
return | |
} | |
if { [table keys -subtable "dns_queries" -count] >= $static::max_query_entries } { | |
HSL::send $hsl "<190>GTM|RRL disabled! Reached max_query_entries: $static::max_query_entries\n" | |
#log local0.debug "RRL disabled! Reached max_query_entries: $static::max_query_entries" | |
return | |
} | |
set curtime [clock second] | |
set ckey [b64encode [md5 "c:$client_ip:$curtime"]] | |
set ccount [table incr -subtable "dns_queries" $ckey] | |
table lifetime -subtable "dns_queries" $ckey 2 | |
if { $ccount > $static::maxconn } { | |
table add -subtable "dns_drop" $client_ip "c" indef $static::holdtime | |
table delete $ckey | |
HSL::send $hsl "<190>GTM|RRL Excessive queries max=$static::maxconn v=$vip c=$client_ip\n" | |
#log local0.debug "Excessive queries max=$static::maxconn v=$vip c=$client_ip" | |
drop | |
return | |
} | |
set answer "" | |
set rrs [DNS::answer] | |
for {set i 1} {$i<=[llength $rrs]} {incr i} { | |
set rr [lindex $rrs [expr {$i-1}]] | |
append answer [DNS::name $rr] " " | |
append answer [DNS::ttl $rr] " " | |
append answer [DNS::class $rr] " " | |
append answer [DNS::type $rr] " " | |
set rdata [DNS::rdata $rr] | |
append answer $rdata " " | |
} | |
set rcode [DNS::header rcode] | |
if { $rcode != "NOERROR" } { | |
set rkey [b64encode [md5 "a:$client_ip:$curtime:$rcode"]] | |
} else { | |
set rkey [b64encode [md5 "a:$client_ip:$curtime:$answer"]] | |
} | |
set rcount [table incr -subtable "dns_queries" $rkey] | |
table lifetime -subtable "dns_queries" $rkey 2 | |
if { $rcount > $static::maxresp } { | |
table add -subtable "dns_drop" $client_ip "a" indef $static::holdtime | |
table delete $rkey | |
HSL::send $hsl "<190>GTM|RRL Excessive identical responses max=$static::maxresp v=$vip c=$client_ip n=[DNS::question name] t=[DNS::question type] r=$rcode\n" | |
#log local0.debug "Excessive identical responses max=$static::maxresp v=$vip c=$client_ip n=[DNS::question name] t=[DNS::question type] r=$rcode" | |
drop | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment