DNS Flood Protection V3.1

Problem this snippet solves:

This iRule may provide basic idea to protect against dns flood protection per source ip address. The "maxquery" is number of query allowed per second. The "holdtime" is the period that bad client will be blocked. Different in this version of the rule is the use of the static namespace for the variables in the RULE_INIT to prevent demotion, and the use of the table command to make the rule cleaner and simpler. This iRule is based on "DNS Flood Protection V3". It adds the ability to limit amount of memory used by blacklist and tracking table. By default, memory limit for tracking is disabled and memory limit for blacklist is enabled. (see more description in the comment part inside the iRule)

Code :

when RULE_INIT {
    # Maximum queries (or connections/requests per second) allowed per IP
    set static::maxquery 10
    # If traffic from IP has reached $maxquery, traffic from this IP
    # will be dropped for $holdtime seconds.
    set static::holdtime 6
    
    # Advance parameters

    # Prevent memory overload by limiting size of tracking table
    # If this is enabled and memory reached the limit, iRule may 
    # reject any new user
    # To enable, set this value to 1
    set static::tracking_memlimit 0
    # There are 256 subtables for query/connection tracking
    # Number of entry limit per each subtable
    set static::tracking_maxentry 20000
    
    # Prevent memory overload by limiting size of blacklist table
    # If this is enabled and the limit is reached, iRule still filter traffic
    # from IP which sends traffic more than $maxquery per second. However, 
    # the holdtime will not be activated. 
    # To enable, set this value to 1
    set static::blacklist_memlimit 1
    # There are 256 subtables for blacklist
    # Number of entry limit per each subtable
    set static::blacklist_maxentry 20000
    
    # each entry consume approximately 400 bytes
    log local0.info "Estimated memory usage for tracking:  [expr (160*256/1024) * \
        $static::tracking_maxentry  / 1000] MBytes"
    log local0.info "Estimated memory usage for blacklist: [expr (160*256/1024) * \
        $static::blacklist_maxentry / 1000] MBytes"
}
when CLIENT_ACCEPTED {
    set srcip [IP::remote_addr]
    set sub [getfield $srcip "." 4]
    # If there is a match, drop the request and exit the event
    if { [table lookup -subtable "blacklist:$sub" $srcip] != "" } {
        drop
        return
    }
    
    if { $static::tracking_memlimit == 1 } {
        set total [table keys -subtable $sub -count]
        if { $total > $static::tracking_maxentry } {
            drop
            return
        }
    }
    
    # set key to the sourceIP and current time
    set curtime [clock second]
    set key "count:$srcip:$curtime"

    # Keep a count of the entries in the table for this IP in the current second 
    # (ie 12
    set count [table incr -subtable $sub $key]

    # Time significance is 1s, so expire any entries after 2s (fudge factor) 
    # to conserve memory
    table lifetime -subtable $sub $key 2

    if { $count > $static::maxquery } {
        if { $static::blacklist_memlimit == 1 } {
            set total [table keys -subtable "blacklist:$sub" -count]
            if { $total > $static::blacklist_maxentry } {
                drop
                return
            }
        }
        
        # Add IP to the blacklist and set the lifetime to the holdtime variable 
        # so entry will automatically expire when desired.  The lifetime is used
        # instead of the timeout because the first thing the iRule does is lookup
        # the IP in the blacklist table, which would keep the timeout from expiring
        # the blacklist entry.
        table add -subtable "blacklist:$sub" $srcip "blocked" indef $static::holdtime

        # Since IP is on blacklist now, the count doesn't matter.  Delete to clean up.
        table delete -subtable $sub $key
        drop
        return
    }
}
# To get total number of table entries
# create http virtual and associate with the following iRule
# Then use browser or "GET http:///" command from BIG-IP shell
#when HTTP_REQUEST {
#    set g 0; set b 0
#    for { set sub 0 } { $sub < 256 } { incr sub } {
#        incr g [table keys -subtable $sub -count]
#        incr b [table keys -subtable "blacklist:$sub" -count]
#    }
#    HTTP::respond 200 content "tracking  = $g\r\nblacklist = $b"
#}
Published Mar 17, 2015
Version 1.0
No CommentsBe the first to comment