Created
September 15, 2012 21:46
-
-
Save lrhazi/3729931 to your computer and use it in GitHub Desktop.
F5 BIGIP DNS Rate Limiting iRule
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 15 | |
# 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] | |
if { [table lookup -subtable "dns_drop" $client_ip] != "" } { | |
drop | |
#log local0.debug "Dropped client: $client_ip" | |
return | |
} | |
} | |
when DNS_RESPONSE { | |
#log local0.debug "dns_drop: [table keys -subtable "dns_drop" -count]" | |
#log local0.debug "dns_queries: [table keys -subtable "dns_queries" -count]" | |
if { [table keys -subtable "dns_drop" -count] >= $static::max_drop_entries } { | |
#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 } { | |
#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 $key | |
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 | |
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
#43 table delete $key >> table delete $ckey